...

Source file src/cuelang.org/go/cue/ast/astutil/apply_test.go

Documentation: cuelang.org/go/cue/ast/astutil

     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/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  		// This should pass
    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