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