...

Source file src/cuelang.org/go/tools/trim/trim_test.go

Documentation: cuelang.org/go/tools/trim

     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 trim
    16  
    17  import (
    18  	"testing"
    19  
    20  	"cuelang.org/go/cue"
    21  	"cuelang.org/go/cue/ast"
    22  	"cuelang.org/go/cue/cuecontext"
    23  	"cuelang.org/go/cue/errors"
    24  	"cuelang.org/go/cue/format"
    25  	"cuelang.org/go/cue/parser"
    26  	"cuelang.org/go/internal/cuetxtar"
    27  	"golang.org/x/tools/txtar"
    28  )
    29  
    30  func TestFiles(t *testing.T) {
    31  	testCases := []struct {
    32  		name string
    33  		in   string
    34  		out  string
    35  	}{{
    36  		name: "optional does not remove required",
    37  		in: `
    38  		a: ["aFoo"]: 3
    39  		a: aFoo:     _
    40  
    41  		a: {
    42  			{["aFoo"]: 3}
    43  			aFoo:     _
    44  		}
    45  
    46  		["aFoo"]: 3
    47  		aFoo:     _
    48  		`,
    49  		out: `a: ["aFoo"]: 3
    50  a: aFoo:     _
    51  
    52  a: {
    53  	{["aFoo"]: 3}
    54  	aFoo: _
    55  }
    56  
    57  ["aFoo"]: 3
    58  aFoo:     _
    59  `,
    60  	}, {
    61  		// TODO: make this optional
    62  		name: "defaults can remove non-defaults",
    63  		in: `
    64  		foo: [string]: a: *1 | int
    65  		foo: b: a: 1
    66  		`,
    67  		out: `foo: [string]: a: *1 | int
    68  foo: b: {}
    69  `,
    70  	}, {
    71  		name: "remove top-level struct",
    72  		in: `
    73  		a: b: 3
    74  		for k, v in a {
    75  			c: "\(k)": v
    76  		}
    77  		c: b: 3
    78  
    79  		z: {
    80  
    81  			a: b: 3
    82  			for k, v in a {
    83  				c: "\(k)": v
    84  			}
    85  			c: b: 3
    86  		}
    87  		`,
    88  		out: `a: b: 3
    89  for k, v in a {
    90  	c: "\(k)": v
    91  }
    92  
    93  z: {
    94  
    95  	a: b: 3
    96  	for k, v in a {
    97  		c: "\(k)": v
    98  	}
    99  }
   100  `,
   101  	}, {
   102  		name: "do not remove field",
   103  		in: `
   104  		{[_]: x: "hello"}
   105  		a: x: "hello"
   106  		`,
   107  		out: `
   108  {[_]: x: "hello"}
   109  a: {}
   110  `,
   111  	}, {
   112  		name: "issue303",
   113  		in: `
   114  		foo: c: true
   115  		foo: #M
   116  		#M: c?: bool
   117  		`,
   118  		out: `foo: c: true
   119  foo: #M
   120  #M: c?: bool
   121  `,
   122  	}, {
   123  		name: "remove due to simplification",
   124  		in: `
   125  foo: [string]: {
   126  	t: [string]: {
   127  		x: >=0 & <=5
   128  	}
   129  }
   130  
   131  foo: multipath: {
   132  	t: [string]: {
   133  		// Combined with the other constraints, we know the value must be 5 and
   134  		// thus the entry below can be eliminated.
   135  		x: >=5 & <=8 & int
   136  	}
   137  
   138  	t: u: { x: 5 }
   139  }
   140  
   141  group: {
   142  	for k, v in foo {
   143  		comp: "\(k)": v
   144  	}
   145  }
   146  
   147  		`,
   148  		out: `foo: [string]: {
   149  	t: [string]: {
   150  		x: >=0 & <=5
   151  	}
   152  }
   153  
   154  foo: multipath: {
   155  	t: [string]: {
   156  
   157  		x: >=5 & <=8 & int
   158  	}
   159  
   160  	t: u: {}
   161  }
   162  
   163  group: {
   164  	for k, v in foo {
   165  		comp: "\(k)": v
   166  	}
   167  }
   168  `,
   169  	}, {
   170  		name: "list removal",
   171  		in: `
   172  		service: [string]: {
   173  			ports: [{a: 1}, {a: 1}, ...{ extra: 3 }]
   174  		}
   175  		service: a: {
   176  			ports: [{a: 1}, {a: 1, extra: 3}, {}, { extra: 3 }]
   177  		}
   178  `,
   179  		out: `service: [string]: {
   180  	ports: [{a: 1}, {a: 1}, ...{extra: 3}]
   181  }
   182  service: a: {
   183  	ports: [{}, {extra: 3}, {}, {}]
   184  }
   185  `,
   186  	}, {
   187  		name: "list removal",
   188  		in: `
   189  		service: [string]: {
   190  			ports: [{a: 1}, {a: 1}, ...{ extra: 3 }]
   191  		}
   192  		service: a: {
   193  			ports: [{a: 1}, {a: 1,}]
   194  		}
   195  		`,
   196  		out: `service: [string]: {
   197  	ports: [{a: 1}, {a: 1}, ...{extra: 3}]
   198  }
   199  service: a: {
   200  }
   201  `,
   202  	}, {
   203  		name: "do not overmark comprehension",
   204  		in: `
   205  foo: multipath: {
   206  	t: [string]: { x: 5 }
   207  
   208  	// Don't remove u!
   209  	t: u: { x: 5 }
   210  }
   211  
   212  group: {
   213  	for k, v in foo {
   214  		comp: "\(k)": v
   215  	}
   216  }
   217  
   218  	`,
   219  		out: `foo: multipath: {
   220  	t: [string]: {x: 5}
   221  
   222  	t: u: {}
   223  }
   224  
   225  group: {
   226  	for k, v in foo {
   227  		comp: "\(k)": v
   228  	}
   229  }
   230  `,
   231  	}, {
   232  		name: "remove implied interpolations",
   233  		in: `
   234  				foo: [string]: {
   235  					a: string
   236  					b: "--\(a)--"
   237  				}
   238  				foo: entry: {
   239  					a: "insert"
   240  					b: "--insert--"
   241  				}
   242  				`,
   243  		out: `foo: [string]: {
   244  	a: string
   245  	b: "--\(a)--"
   246  }
   247  foo: entry: {
   248  	a: "insert"
   249  }
   250  `,
   251  	}}
   252  	for _, tc := range testCases {
   253  		t.Run(tc.name, func(t *testing.T) {
   254  			f, err := parser.ParseFile("test", tc.in)
   255  			if err != nil {
   256  				t.Fatal(err)
   257  			}
   258  			r := cuecontext.New()
   259  			v := r.BuildFile(f)
   260  			if err := v.Err(); err != nil {
   261  				t.Fatal(err)
   262  			}
   263  			err = Files([]*ast.File{f}, v, &Config{Trace: false})
   264  			if err != nil {
   265  				t.Fatal(err)
   266  			}
   267  
   268  			out := formatNode(t, f)
   269  			if got := string(out); got != tc.out {
   270  				t.Errorf("\ngot:\n%s\nwant:\n%s", got, tc.out)
   271  			}
   272  		})
   273  	}
   274  }
   275  
   276  const trace = false
   277  
   278  func TestData(t *testing.T) {
   279  	test := cuetxtar.TxTarTest{
   280  		Root: "./testdata",
   281  		Name: "trim",
   282  	}
   283  
   284  	test.Run(t, func(t *cuetxtar.Test) {
   285  
   286  		a := t.Instance()
   287  		val := cuecontext.New().BuildInstance(a)
   288  		// Note: don't check val.Err because there are deliberate
   289  		// errors in some tests.
   290  
   291  		files := a.Files
   292  
   293  		err := Files(files, val, &Config{Trace: trace})
   294  		if err != nil {
   295  			t.WriteErrors(errors.Promote(err, ""))
   296  		}
   297  
   298  		for _, f := range files {
   299  			t.WriteFile(f)
   300  		}
   301  	})
   302  }
   303  
   304  func formatNode(t *testing.T, n ast.Node) []byte {
   305  	t.Helper()
   306  
   307  	b, err := format.Node(n)
   308  	if err != nil {
   309  		t.Fatal(err)
   310  	}
   311  	return b
   312  }
   313  
   314  // For debugging, do not remove.
   315  func TestX(t *testing.T) {
   316  	in := `
   317  -- in.cue --
   318  `
   319  
   320  	t.Skip()
   321  
   322  	a := txtar.Parse([]byte(in))
   323  	instances := cuetxtar.Load(a, t.TempDir())
   324  
   325  	inst := cue.Build(instances)[0]
   326  	if inst.Err != nil {
   327  		t.Fatal(inst.Err)
   328  	}
   329  
   330  	files := instances[0].Files
   331  
   332  	Debug = true
   333  
   334  	err := Files(files, inst, &Config{
   335  		Trace: true,
   336  	})
   337  	if err != nil {
   338  		t.Fatal(err)
   339  	}
   340  
   341  	for _, f := range files {
   342  		b := formatNode(t, f)
   343  		t.Error(string(b))
   344  	}
   345  }
   346  

View as plain text