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