github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/cue/ast/astutil/apply_test.go (about) 1 // Copyright 2019 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package astutil_test 16 17 import ( 18 "strings" 19 "testing" 20 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/require" 23 24 "github.com/joomcode/cue/cue/ast" 25 "github.com/joomcode/cue/cue/ast/astutil" 26 "github.com/joomcode/cue/cue/format" 27 "github.com/joomcode/cue/cue/parser" 28 "github.com/joomcode/cue/cue/token" 29 ) 30 31 func TestApply(t *testing.T) { 32 testCases := []struct { 33 name string 34 in string 35 out string 36 before func(astutil.Cursor) bool 37 after func(astutil.Cursor) bool 38 }{{ 39 // This should pass 40 }, { 41 name: "insert before", 42 in: ` 43 // foo is a 44 foo: { 45 a: 3 46 } 47 `, 48 out: ` 49 iam: new 50 51 // foo is a 52 foo: { 53 iam: new 54 a: 3 55 } 56 `, 57 before: func(c astutil.Cursor) bool { 58 switch c.Node().(type) { 59 case *ast.Field: 60 c.InsertBefore(&ast.Field{ 61 Label: ast.NewIdent("iam"), 62 Value: ast.NewIdent("new"), 63 }) 64 } 65 return true 66 }, 67 }, { 68 name: "insert after", 69 in: ` 70 foo: { 71 a: 3 @test() 72 } 73 `, 74 out: ` 75 foo: { 76 a: 3 @test() 77 iam: new 78 } 79 iam: new 80 `, 81 before: func(c astutil.Cursor) bool { 82 switch c.Node().(type) { 83 case *ast.Field: 84 c.InsertAfter(&ast.Field{ 85 Label: ast.NewIdent("iam"), 86 Value: ast.NewIdent("new"), 87 }) 88 } 89 return true 90 }, 91 }, { 92 name: "insert after recursive", 93 in: ` 94 foo: { 95 a: 3 @test() 96 } 97 `, 98 out: ` 99 foo: { 100 a: 3 @test() 101 iam: { 102 here: new 103 there: new 104 } 105 everywhere: new 106 } 107 iam: { 108 here: new 109 there: new 110 } 111 everywhere: new 112 `, 113 before: func(c astutil.Cursor) bool { 114 switch x := c.Node().(type) { 115 case *ast.Field: 116 switch x.Label.(*ast.Ident).Name { 117 default: 118 c.InsertAfter(astutil.ApplyRecursively(&ast.Field{ 119 Label: ast.NewIdent("iam"), 120 Value: ast.NewStruct(ast.NewIdent("here"), ast.NewIdent("new")), 121 })) 122 case "iam": 123 c.InsertAfter(&ast.Field{ 124 Label: ast.NewIdent("everywhere"), 125 Value: ast.NewIdent("new"), 126 }) 127 case "here": 128 c.InsertAfter(&ast.Field{ 129 Label: ast.NewIdent("there"), 130 Value: ast.NewIdent("new"), 131 }) 132 case "everywhere": 133 } 134 } 135 return true 136 }}, { 137 name: "templates", 138 in: ` 139 foo: { 140 a: [string]: c: 3 141 } 142 `, 143 out: ` 144 foo: { 145 a: [string]: { 146 c: 3 147 iam: new 148 } 149 } 150 `, 151 before: func(c astutil.Cursor) bool { 152 switch x := c.Node().(type) { 153 case *ast.Field: 154 if _, ok := x.Value.(*ast.StructLit); !ok { 155 c.InsertAfter(&ast.Field{ 156 Label: ast.NewIdent("iam"), 157 Value: ast.NewIdent("new"), 158 }) 159 } 160 } 161 return true 162 }, 163 }, { 164 name: "replace", 165 in: ` 166 // keep comment 167 a: "string" // and this one 168 b: 3 169 c: [ 1, 2, 8, 4 ] 170 d: "\(foo) is \(0)" 171 `, 172 out: ` 173 // keep comment 174 a: s // and this one 175 b: 4 176 c: [4, 4, 4, 4] 177 d: "\(foo) is \(4)" 178 `, 179 before: func(c astutil.Cursor) bool { 180 switch x := c.Node().(type) { 181 case *ast.BasicLit: 182 switch x.Kind { 183 case token.STRING: 184 if c.Index() < 0 { 185 c.Replace(ast.NewIdent("s")) 186 } 187 case token.INT: 188 c.Replace(ast.NewLit(token.INT, "4")) 189 } 190 } 191 return true 192 }, 193 }, { 194 name: "delete", 195 in: ` 196 z: 0 197 a: "foo" 198 b: 3 199 b: "bar" 200 c: 2 201 `, 202 out: ` 203 a: "foo" 204 b: "bar" 205 `, 206 before: func(c astutil.Cursor) bool { 207 f, ok := c.Node().(*ast.Field) 208 if !ok { 209 return true 210 } 211 switch x := f.Value.(type) { 212 case *ast.BasicLit: 213 switch x.Kind { 214 case token.INT: 215 c.Delete() 216 } 217 } 218 return true 219 }, 220 }, { 221 name: "comments", 222 in: ` 223 // test 224 a: "string" 225 `, 226 out: ` 227 // 1, 2, 3 228 a: "string" 229 `, 230 before: func(c astutil.Cursor) bool { 231 switch c.Node().(type) { 232 case *ast.Comment: 233 c.Replace(&ast.Comment{Text: "// 1, 2, 3"}) 234 } 235 return true 236 }, 237 }, { 238 name: "comments after", 239 in: ` 240 // test 241 a: "string" 242 `, 243 out: ` 244 // 1, 2, 3 245 a: "string" 246 `, 247 after: func(c astutil.Cursor) bool { 248 switch c.Node().(type) { 249 case *ast.Comment: 250 c.Replace(&ast.Comment{Text: "// 1, 2, 3"}) 251 } 252 return true 253 }, 254 }, { 255 name: "imports add", 256 in: ` 257 a: "string" 258 `, 259 out: ` 260 import list6c6973 "list" 261 262 a: list6c6973 263 `, 264 after: func(c astutil.Cursor) bool { 265 switch c.Node().(type) { 266 case *ast.BasicLit: 267 c.Replace(c.Import("list")) 268 } 269 return true 270 }, 271 }, { 272 name: "imports add to", 273 in: `package foo 274 275 import "math" 276 277 a: 3 278 `, 279 out: `package foo 280 281 import ( 282 "math" 283 list6c6973 "list" 284 ) 285 286 a: list6c6973 287 `, 288 after: func(c astutil.Cursor) bool { 289 switch x := c.Node().(type) { 290 case *ast.BasicLit: 291 if x.Kind == token.INT { 292 c.Replace(c.Import("list")) 293 } 294 } 295 return true 296 }, 297 }, { 298 name: "imports duplicate", 299 in: `package foo 300 301 import "list" 302 303 a: 3 304 `, 305 out: `package foo 306 307 import ( 308 "list" 309 list6c6973 "list" 310 ) 311 312 a: list6c6973 313 `, 314 after: func(c astutil.Cursor) bool { 315 switch x := c.Node().(type) { 316 case *ast.BasicLit: 317 if x.Kind == token.INT { 318 c.Replace(c.Import("list")) 319 } 320 } 321 return true 322 }, 323 }} 324 for _, tc := range testCases { 325 t.Run(tc.name, func(t *testing.T) { 326 f, err := parser.ParseFile(tc.name, tc.in, parser.ParseComments) 327 if err != nil { 328 t.Fatal(err) 329 } 330 331 n := astutil.Apply(f, tc.before, tc.after) 332 333 b, err := format.Node(n) 334 require.NoError(t, err) 335 got := strings.TrimSpace(string(b)) 336 want := strings.TrimSpace(tc.out) 337 assert.Equal(t, want, got) 338 }) 339 } 340 }