github.com/solo-io/cue@v0.4.7/internal/diff/diff_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 diff
    16  
    17  import (
    18  	"bytes"
    19  	"testing"
    20  
    21  	"github.com/solo-io/cue/cue"
    22  )
    23  
    24  func TestDiff(t *testing.T) {
    25  	testCases := []struct {
    26  		name    string
    27  		x, y    string
    28  		kind    Kind
    29  		diff    string
    30  		profile *Profile
    31  	}{{
    32  		name: "identity struct",
    33  		x: `{
    34  			a: {
    35  				b: 1
    36  				c: 2
    37  			}
    38  			l: {
    39  				d: 1
    40  			}
    41  		}`,
    42  		y: `{
    43  			a: {
    44  				c: 2
    45  				b: 1
    46  			}
    47  			l: {
    48  				d: 1
    49  			}
    50  		}`,
    51  	}, {
    52  		name: "identity list",
    53  		x:    `[1, 2, 3]`,
    54  		y:    `[1, 2, 3]`,
    55  	}, {
    56  		name: "identity value",
    57  		x:    `"foo"`,
    58  		y:    `"foo"`,
    59  	}, {
    60  		name: "modified value",
    61  		x:    `"foo"`,
    62  		y:    `"bar"`,
    63  		kind: Modified,
    64  		diff: `- "foo",
    65  + "bar",
    66  `,
    67  	}, {
    68  		name: "basics",
    69  		x: `{
    70  			a: int
    71  			b: 2
    72  			s: 4
    73  			d: 1
    74  			e: null
    75  		}
    76  		`,
    77  		y: `
    78  		{
    79  			a: string
    80  			c: 3
    81  			s: 4
    82  			d: int
    83  			e: null
    84  		}
    85  		`,
    86  		kind: Modified,
    87  		diff: `  {
    88  -     a: int
    89  +     a: string
    90  -     b: 2
    91  +     c: 3
    92        s: 4
    93  -     d: 1
    94  +     d: int
    95        e: null
    96    }
    97  `,
    98  	}, {
    99  		name: "basics 2",
   100  		x: `{
   101  			ls: [2, 3, 4]
   102  			"foo-bar": 2
   103  			s: 4
   104  			lm1: [2, 3, 5]
   105  			lm2: [6]
   106  		}
   107  		`,
   108  		y: `
   109  		{
   110  			ls: [2, 3, 4]
   111  			"foo-bar": 3
   112  			s: 4
   113  			lm1: [2, 3, 4, 6]
   114  			lm2: []
   115  			la: [2, 3, 4]
   116  		}
   117  		`,
   118  		kind: Modified,
   119  		diff: `  {
   120        ls: [2, 3, 4]
   121  -     "foo-bar": 2
   122  +     "foo-bar": 3
   123        s: 4
   124        lm1: [
   125            2,
   126            3,
   127  -         5,
   128  +         4,
   129  +         6,
   130        ]
   131        lm2: [
   132  -         6,
   133        ]
   134  +     la: [2, 3, 4]
   135    }
   136  `,
   137  	}, {
   138  		name: "interupted run 1",
   139  		x: `{
   140  	a: 1
   141  	b: 2
   142  	c: 3
   143  	d: 4
   144  	e: 10
   145  	f: 6
   146  	g: 7
   147  	h: 8
   148  	i: 9
   149  	j: 10
   150  }
   151  `,
   152  		y: `
   153  {
   154  	a: 1
   155  	b: 2
   156  	c: 3
   157  	d: 4
   158  	e: 5
   159  	f: 6
   160  	g: 7
   161  	h: 8
   162  	i: 9
   163  	j: 10
   164  }
   165  `,
   166  		kind: Modified,
   167  		diff: `  {
   168        ... // 2 identical elements
   169        c: 3
   170        d: 4
   171  -     e: 10
   172  +     e: 5
   173        f: 6
   174        g: 7
   175        ... // 3 identical elements
   176    }
   177  `,
   178  	}, {
   179  		name: "interupted run 2",
   180  		x: `{
   181  			a: -1
   182  			b: 2
   183  			c: 3
   184  			d: 4
   185  			e: 5
   186  			f: 6
   187  			g: 7
   188  			h: 8
   189  			i: 9
   190  			j: -10
   191  		}`,
   192  		y: `{
   193  			a: 1
   194  			b: 2
   195  			c: 3
   196  			d: 4
   197  			e: 5
   198  			f: 6
   199  			g: 7
   200  			h: 8
   201  			i: 9
   202  			j: 10
   203  		}
   204  		`,
   205  		kind: Modified,
   206  		diff: `  {
   207  -     a: -1
   208  +     a: 1
   209        b: 2
   210        c: 3
   211        ... // 4 identical elements
   212        h: 8
   213        i: 9
   214  -     j: -10
   215  +     j: 10
   216    }
   217  `,
   218  	}, {
   219  		name: "recursion",
   220  		x: `{
   221  		s: {
   222  			a: 1
   223  			b: 3
   224  			d: 4
   225  		}
   226  		l: [
   227  			[3, 4]
   228  		]
   229  	}`,
   230  		y: `{
   231  		s: {
   232  			a: 2
   233  			b: 3
   234  			c: 4
   235  		}
   236  		l: [
   237  			[3, 5, 6]
   238  		]
   239  	}
   240  	`,
   241  		kind: Modified,
   242  		diff: `  {
   243        s: {
   244  -         a: 1
   245  +         a: 2
   246            b: 3
   247  -         d: 4
   248  +         c: 4
   249        }
   250        l: [
   251            [
   252                3,
   253  -             4,
   254  +             5,
   255  +             6,
   256            ]
   257        ]
   258    }
   259  `,
   260  	}, {
   261  		name: "optional and definitions",
   262  		x: `{
   263  	#s: {
   264  		#a: 1
   265  		b: 2
   266  	}
   267  	o?: 3
   268  	#od?: 1
   269  	oc?: 5
   270  }`,
   271  		y: `{
   272  	#s: {
   273  		a: 2
   274  		#b: 2
   275  	}
   276  	o?: 4
   277  	#od: 1
   278  	#oc?: 5
   279  }
   280  `,
   281  		kind: Modified,
   282  		diff: `  {
   283        #s: {
   284  -         #a: 1
   285  -         b: 2
   286  +         a: 2
   287  +         #b: 2
   288        }
   289  -     o?: 3
   290  +     o?: 4
   291  -     #od?: 1
   292  +     #od: 1
   293  -     oc?: 5
   294  +     #oc?: 5
   295    }
   296  `,
   297  	}, {
   298  		name: "bulk optional",
   299  		x: `{[_]: x: "hello"}
   300  
   301  a: x: "hello"
   302  		`,
   303  		y: `[_]: x: "hello"
   304  
   305  		`,
   306  		kind: Modified,
   307  		diff: `  {
   308  -     a: {
   309  -     	x: "hello"
   310  -     }
   311    }
   312  `,
   313  	}, {
   314  		x: `
   315  		#Directory: {
   316  			{
   317  					// Directory from another directory (e.g. subdirectory)
   318  					from: #Directory
   319  			} | {
   320  					// Reference to remote directory
   321  					ref: string
   322  			} | {
   323  					// Use a local directory
   324  					local: string
   325  			}
   326  			path: string | *"/"
   327  	}
   328  		`,
   329  		y: `
   330  	#Directory: {
   331          {
   332                  // Directory from another directory (e.g. subdirectory)
   333                  from: #Directory
   334          } | {
   335                  // Reference to remote directory
   336                  ref: string
   337          } | {
   338                  // Use a local directory
   339                  local: string
   340          }
   341          path: string | *"/"
   342  	}
   343  	`,
   344  		profile: Final,
   345  	}, {
   346  		x: `
   347  		#Directory: {
   348  			{
   349  					// Directory from another directory (e.g. subdirectory)
   350  					from: #Directory
   351  			} | {
   352  					// Reference to remote directory
   353  					ref: string
   354  			} | {
   355  					// Use a local directory
   356  					local: string
   357  			}
   358  			path: string | *"/"
   359  	}
   360  		`,
   361  		y: `
   362  	#Directory: {
   363          {
   364                  // Directory from another directory (e.g. subdirectory)
   365                  from: #Directory
   366          } | {
   367                  // Reference to remote directory
   368                  ref: string
   369          } | {
   370                  // Use a local directory
   371                  local: string
   372          }
   373          path: string | *"/"
   374  	}
   375  	`,
   376  	}}
   377  	for _, tc := range testCases {
   378  		t.Run(tc.name, func(t *testing.T) {
   379  			var r cue.Runtime
   380  			x, err := r.Compile("x", tc.x)
   381  			if err != nil {
   382  				t.Fatal(err)
   383  			}
   384  			y, err := r.Compile("y", tc.y)
   385  			if err != nil {
   386  				t.Fatal(err)
   387  			}
   388  			p := tc.profile
   389  			if p == nil {
   390  				p = Schema
   391  			}
   392  			kind, script := p.Diff(x.Value(), y.Value())
   393  			if kind != tc.kind {
   394  				t.Fatalf("got %d; want %d", kind, tc.kind)
   395  			}
   396  			if script != nil {
   397  				w := &bytes.Buffer{}
   398  				err = Print(w, script)
   399  				if err != nil {
   400  					t.Fatal(err)
   401  				}
   402  				if got := w.String(); got != tc.diff {
   403  					t.Errorf("\ngot\n%s;\nwant\n%s", got, tc.diff)
   404  				}
   405  			}
   406  		})
   407  	}
   408  }
   409  
   410  func TestX(t *testing.T) {
   411  	t.Skip()
   412  
   413  	tc := struct {
   414  		x, y string
   415  		kind Kind
   416  		diff string
   417  	}{
   418  		x: `{
   419  		}
   420  		`,
   421  		y: `
   422  		{
   423  		}
   424  		`,
   425  		kind: Modified,
   426  		diff: ``,
   427  	}
   428  	var r cue.Runtime
   429  	x, err := r.Compile("x", tc.x)
   430  	if err != nil {
   431  		t.Fatal(err)
   432  	}
   433  	y, err := r.Compile("y", tc.y)
   434  	if err != nil {
   435  		t.Fatal(err)
   436  	}
   437  	kind, script := Diff(x.Value(), y.Value())
   438  	if kind != tc.kind {
   439  		t.Fatalf("got %d; want %d", kind, tc.kind)
   440  	}
   441  	w := &bytes.Buffer{}
   442  	err = Print(w, script)
   443  	if err != nil {
   444  		t.Fatal(err)
   445  	}
   446  	if got := w.String(); got != tc.diff {
   447  		t.Errorf("got\n%s;\nwant\n%s", got, tc.diff)
   448  	}
   449  }