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 }