cuelang.org/go@v0.13.0/internal/core/adt/closed_test.go (about)

     1  // Copyright 2020 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 adt_test
    16  
    17  import (
    18  	"testing"
    19  
    20  	"cuelang.org/go/cue/parser"
    21  	"cuelang.org/go/internal"
    22  	"cuelang.org/go/internal/core/adt"
    23  	"cuelang.org/go/internal/core/compile"
    24  	"cuelang.org/go/internal/core/eval"
    25  	"cuelang.org/go/internal/core/runtime"
    26  )
    27  
    28  // TestClosedness is a bootstrap and debugging test for developing the
    29  // closedness algorithm. Most details of closedness is tested in the standard
    30  // test suite.
    31  func TestClosedness(t *testing.T) {
    32  	r := runtime.New()
    33  	ctx := eval.NewContext(r, nil)
    34  	if ctx.Version == internal.EvalV3 {
    35  		t.Skip("TODO: fix these tests on evalv3")
    36  	}
    37  	mkStruct := func(info adt.CloseInfo, s string) *adt.StructInfo {
    38  		x, err := parser.ParseExpr("", s)
    39  		if err != nil {
    40  			t.Fatal(err)
    41  		}
    42  		expr, err := compile.Expr(nil, r, "", x)
    43  		if err != nil {
    44  			t.Fatal(err)
    45  		}
    46  		st := expr.Elem().(*adt.StructLit)
    47  		st.Init(ctx)
    48  
    49  		return &adt.StructInfo{
    50  			StructLit: st,
    51  			CloseInfo: info,
    52  		}
    53  	}
    54  
    55  	mkRef := func(s string) adt.Expr {
    56  		f := adt.MakeIdentLabel(r, s, "")
    57  		return &adt.FieldReference{Label: f}
    58  	}
    59  
    60  	type test struct {
    61  		f     string
    62  		found bool
    63  	}
    64  
    65  	testCases := []struct {
    66  		desc     string
    67  		n        func() *adt.Vertex
    68  		tests    []test
    69  		required bool
    70  	}{{
    71  		desc: "simple embedding",
    72  		// test: {
    73  		//     a: 1
    74  		//     c: 1
    75  		//
    76  		//     def
    77  		// }
    78  		// def: {
    79  		//     c: 1
    80  		//     d: 1
    81  		// }
    82  		n: func() *adt.Vertex {
    83  			var (
    84  				root  adt.CloseInfo
    85  				embed = root.SpawnEmbed(mkRef("dummy"))
    86  				def   = embed.SpawnRef(nil, false, mkRef("def"))
    87  			)
    88  			return &adt.Vertex{
    89  				Structs: []*adt.StructInfo{
    90  					mkStruct(root, "{a: 1, c: 1}"),
    91  					mkStruct(def, "{c: 1, d: 1}"),
    92  				},
    93  			}
    94  		},
    95  		tests: []test{
    96  			{"a", true},
    97  			{"c", true},
    98  			{"d", true},
    99  			{"e", false}, // allowed, but not found
   100  		},
   101  		required: false,
   102  	}, {
   103  		desc: "closing embedding",
   104  		// test: {
   105  		//     a: 1
   106  		//     c: 1
   107  		//
   108  		//     #def
   109  		// }
   110  		// #def: {
   111  		//     c: 1
   112  		//     d: 1
   113  		// }
   114  		n: func() *adt.Vertex {
   115  			var (
   116  				root  adt.CloseInfo
   117  				embed = root.SpawnEmbed(mkRef("dummy"))
   118  				def   = embed.SpawnRef(nil, true, mkRef("#def"))
   119  			)
   120  			return &adt.Vertex{
   121  				Structs: []*adt.StructInfo{
   122  					mkStruct(root, "{a: 1, c: 1}"),
   123  					mkStruct(def, "{c: 1, d: 1}"),
   124  				},
   125  			}
   126  		},
   127  		tests: []test{
   128  			{"a", true},
   129  			{"c", true},
   130  			{"d", true},
   131  			{"e", false},
   132  		},
   133  		required: true,
   134  	}, {
   135  		desc: "narrow down definitions in subfields",
   136  		// test: #foo
   137  		// test: {
   138  		//     a: 1
   139  		//     b: 1
   140  		// }
   141  		// #foo: {
   142  		//     c: #bar
   143  		//     c: #baz
   144  		//     c: d: 1
   145  		//     c: e: 1
   146  		// }
   147  		// #bar: {
   148  		//     d: 1
   149  		//     e: 1
   150  		// }
   151  		// #baz: {
   152  		//     d: 1
   153  		//     f: 1
   154  		// }
   155  		n: func() *adt.Vertex {
   156  			var (
   157  				root adt.CloseInfo
   158  				foo  = root.SpawnRef(nil, true, mkRef("#foo"))
   159  				bar  = foo.SpawnRef(nil, true, mkRef("#bar"))
   160  				baz  = foo.SpawnRef(nil, true, mkRef("#baz"))
   161  			)
   162  			return &adt.Vertex{
   163  				Structs: []*adt.StructInfo{
   164  					mkStruct(root, "{a: 1, b:1}"),
   165  					mkStruct(foo, "{d: 1, e: 1}"),
   166  					mkStruct(bar, "{d: 1, e: 1}"),
   167  					mkStruct(baz, "{d: 1, f: 1}"),
   168  				},
   169  			}
   170  		},
   171  		tests: []test{
   172  			{"a", false},
   173  			{"b", false},
   174  			{"d", true},
   175  			{"e", false},
   176  			{"f", false},
   177  		},
   178  		required: true,
   179  	}, {
   180  		desc: "chained references",
   181  		// test: foo
   182  		// test: {
   183  		//     a: 1
   184  		//     b: 1
   185  		// }
   186  		// foo: bar
   187  		// bar: {
   188  		//     #baz
   189  		//     e: 1
   190  		// }
   191  		// #baz: {
   192  		//     c: 1
   193  		//     d: 1
   194  		// }
   195  		n: func() *adt.Vertex {
   196  			var (
   197  				root adt.CloseInfo
   198  				foo  = root.SpawnRef(nil, false, mkRef("foo"))
   199  				bar  = foo.SpawnRef(nil, false, mkRef("bar"))
   200  				baz  = bar.SpawnEmbed(mkRef("#baz"))
   201  				def  = baz.SpawnRef(nil, true, mkRef("#baz"))
   202  			)
   203  			return &adt.Vertex{
   204  				Structs: []*adt.StructInfo{
   205  					mkStruct(bar, "{e: 1}"),
   206  					mkStruct(def, "{c: 1, d: 1}"),
   207  					mkStruct(root, "{a: 1, c: 1}"),
   208  				},
   209  			}
   210  		},
   211  		tests: []test{
   212  			{"a", false},
   213  			{"c", true},
   214  			{"d", true},
   215  			{"e", true},
   216  			{"f", false},
   217  		},
   218  		required: true,
   219  	}, {
   220  		desc: "conjunction embedding",
   221  		// test: foo
   222  		// test: {
   223  		//     a: 1
   224  		//     b: 1
   225  		// }
   226  		// foo: {
   227  		//     #bar & #baz
   228  		//     f: 1
   229  		// }
   230  		// #bar: {
   231  		//     c: 1
   232  		//     d: 1
   233  		// }
   234  		// #baz: {
   235  		//     d: 1
   236  		// }
   237  		// #baz: {
   238  		//     e: 1
   239  		// }
   240  		n: func() *adt.Vertex {
   241  			var (
   242  				root  adt.CloseInfo
   243  				foo   = root.SpawnRef(nil, false, mkRef("foo"))
   244  				embed = foo.SpawnEmbed(mkRef("dummy"))
   245  				bar   = embed.SpawnRef(nil, true, mkRef("#bar"))
   246  				baz   = embed.SpawnRef(nil, true, mkRef("#baz"))
   247  			)
   248  			return &adt.Vertex{
   249  				Structs: []*adt.StructInfo{
   250  					mkStruct(root, "{a: 1, c: 1}"),
   251  					mkStruct(foo, "{f: 1}"),
   252  					mkStruct(bar, "{c: 1, d: 1}"),
   253  					mkStruct(baz, "{d: 1}"),
   254  					mkStruct(baz, "{e: 1}"),
   255  				},
   256  			}
   257  		},
   258  		tests: []test{
   259  			{"a", false},
   260  			{"c", false},
   261  			{"d", true},
   262  			{"e", false},
   263  			{"f", true},
   264  			{"g", false},
   265  		},
   266  		required: true,
   267  	}, {
   268  		desc: "local closing",
   269  		// test: {
   270  		//     #def
   271  		//     a: 1
   272  		//     b: 1
   273  		// }
   274  		// test: {
   275  		//     c: 1
   276  		//     d: 1
   277  		// }
   278  		// #def: {
   279  		//     c: 1
   280  		//     e: 1
   281  		// }
   282  		n: func() *adt.Vertex {
   283  			var (
   284  				root adt.CloseInfo
   285  				// isolate local struct.
   286  				spawned = root.SpawnRef(nil, false, mkRef("dummy"))
   287  				embed   = spawned.SpawnEmbed(mkRef("dummy"))
   288  				def     = embed.SpawnRef(nil, true, mkRef("#def"))
   289  			)
   290  			return &adt.Vertex{
   291  				Structs: []*adt.StructInfo{
   292  					mkStruct(spawned, "{a: 1, b: 1}"),
   293  					mkStruct(root, "{c: 1, d: 1}"),
   294  					mkStruct(def, "{c: 1, e: 1}"),
   295  				},
   296  			}
   297  		},
   298  		tests: []test{
   299  			{"d", false},
   300  			{"a", true},
   301  			{"c", true},
   302  			{"e", true},
   303  			{"f", false},
   304  		},
   305  		required: true,
   306  	}, {
   307  		desc: "local closing of def",
   308  		// #test: {
   309  		//     #def
   310  		//     a: 1
   311  		//     b: 1
   312  		// }
   313  		// #test: {
   314  		//     c: 1
   315  		//     d: 1
   316  		// }
   317  		// #def: {
   318  		//     c: 1
   319  		//     e: 1
   320  		// }
   321  		n: func() *adt.Vertex {
   322  			var (
   323  				root adt.CloseInfo
   324  				test = root.SpawnRef(nil, true, mkRef("#test"))
   325  				// isolate local struct.
   326  				spawned = test.SpawnRef(nil, false, mkRef("dummy"))
   327  				embed   = spawned.SpawnEmbed(mkRef("dummy"))
   328  				def     = embed.SpawnRef(nil, true, mkRef("#def"))
   329  			)
   330  			return &adt.Vertex{
   331  				Structs: []*adt.StructInfo{
   332  					mkStruct(spawned, "{a: 1, b: 1}"),
   333  					mkStruct(test, "{c: 1, d: 1}"),
   334  					mkStruct(def, "{c: 1, e: 1}"),
   335  				},
   336  			}
   337  		},
   338  		tests: []test{
   339  			{"a", true},
   340  			{"d", false},
   341  			{"c", true},
   342  			{"e", true},
   343  			{"f", false},
   344  		},
   345  		required: true,
   346  	}, {
   347  		desc: "branching",
   348  		// test: #foo
   349  		// #foo: {
   350  		//     c: #bar1
   351  		//     c: #bar2
   352  		// }
   353  		// #bar1: {
   354  		//     d: #baz1
   355  		//     d: #baz2
   356  		// }
   357  		// #bar2: {
   358  		//     d: #baz3
   359  		//     d: {#baz4}
   360  		// }
   361  		// #baz1: e: 1
   362  		// #baz2: e: 1
   363  		// #baz3: e: 1
   364  		// #baz4: e: 1
   365  		n: func() *adt.Vertex {
   366  			var (
   367  				root adt.CloseInfo
   368  				foo  = root.SpawnRef(nil, true, mkRef("#foo"))
   369  				bar1 = foo.SpawnRef(nil, true, mkRef("#bar1"))
   370  				bar2 = foo.SpawnRef(nil, true, mkRef("#bar2"))
   371  				baz1 = bar1.SpawnRef(nil, true, mkRef("#baz1"))
   372  				baz2 = bar1.SpawnRef(nil, true, mkRef("#baz2"))
   373  				baz3 = bar2.SpawnRef(nil, true, mkRef("#baz3"))
   374  				spw3 = bar2.SpawnRef(nil, false, mkRef("spw3"))
   375  				emb2 = spw3.SpawnEmbed(mkRef("emb"))
   376  				baz4 = emb2.SpawnRef(nil, true, mkRef("#baz4"))
   377  			)
   378  			return &adt.Vertex{
   379  				Structs: []*adt.StructInfo{
   380  					mkStruct(root, "{}"),
   381  					mkStruct(foo, "{}"),
   382  					mkStruct(bar1, "{}"),
   383  					mkStruct(bar2, "{}"),
   384  					mkStruct(baz1, "{e: 1, f: 1, g: 1}"),
   385  					mkStruct(baz2, "{e: 1, f: 1, g: 1}"),
   386  					mkStruct(baz3, "{e: 1, g: 1}"),
   387  					mkStruct(baz4, "{e: 1, f: 1}"),
   388  				},
   389  			}
   390  		},
   391  		tests: []test{
   392  			{"a", false},
   393  			{"e", true},
   394  			{"f", false},
   395  			{"g", false},
   396  		},
   397  		required: true,
   398  	}}
   399  	// TODO:
   400  	// dt1: {
   401  	// 	#Test: {
   402  	// 		#SSH:   !~"^ssh://"
   403  	// 		source: #SSH | #Test
   404  	// 	}
   405  
   406  	// 	foo: #Test & {
   407  	// 		source: "http://blablabla"
   408  	// 	}
   409  
   410  	// 	bar: #Test & {
   411  	// 		source: foo
   412  	// 	}
   413  	// }
   414  	//
   415  	// -----
   416  	for _, tc := range testCases {
   417  		t.Run(tc.desc, func(t *testing.T) {
   418  			n := tc.n()
   419  			for _, sub := range tc.tests {
   420  				t.Run(sub.f, func(t *testing.T) {
   421  					f := adt.MakeIdentLabel(r, sub.f, "")
   422  
   423  					ok, required := adt.Accept(ctx, n, f)
   424  					if ok != sub.found || required != tc.required {
   425  						t.Errorf("got (%v, %v); want (%v, %v)",
   426  							ok, required, sub.found, tc.required)
   427  					}
   428  				})
   429  			}
   430  		})
   431  	}
   432  }