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