cuelang.org/go@v0.10.1/internal/core/adt/export_test.go (about) 1 // Copyright 2023 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 16 17 import "strings" 18 19 // The functions and types in this file are use to construct test cases for 20 // fields_test.go and constraints_test. 21 22 // MatchPatternValue exports matchPatternValue for testing. 23 func MatchPatternValue(ctx *OpContext, p Value, f Feature, label Value) bool { 24 return matchPatternValue(ctx, p, f, label) 25 } 26 27 // FieldTester is used low-level testing of field insertion. It simulates 28 // how the evaluator inserts fields. This allows the closedness algorithm to be 29 // tested independently of the underlying evaluator implementation. 30 type FieldTester struct { 31 *OpContext 32 n *nodeContext 33 cc *closeContext 34 Root *Vertex 35 } 36 37 func NewFieldTester(r Runtime) *FieldTester { 38 v := &Vertex{} 39 ctx := New(v, &Config{Runtime: r}) 40 n := v.getNodeContext(ctx, 1) 41 42 return &FieldTester{ 43 OpContext: ctx, 44 n: n, 45 cc: v.rootCloseContext(ctx), 46 Root: v, 47 } 48 } 49 50 func (x *FieldTester) Error() string { 51 if b := x.n.node.Bottom(); b != nil && b.Err != nil { 52 return b.Err.Error() 53 } 54 var errs []string 55 for _, a := range x.n.node.Arcs { 56 if b := a.Bottom(); b != nil && b.Err != nil { 57 errs = append(errs, b.Err.Error()) 58 } 59 } 60 return strings.Join(errs, "\n") 61 } 62 63 type declaration func(cc *closeContext) 64 65 // Run simulates a CUE evaluation of the given declarations. 66 func (x *FieldTester) Run(sub ...declaration) { 67 x.cc.incDependent(x.n.ctx, TEST, nil) 68 for i, s := range sub { 69 // We want to have i around for debugging purposes. Use i to avoid 70 // compiler error. 71 _ = i 72 s(x.cc) 73 } 74 x.cc.decDependent(x.n.ctx, TEST, nil) 75 x.cc.decDependent(x.n.ctx, ROOT, nil) // REF(decrement:nodeDone) 76 } 77 78 // Def represents fields that define a definition, such that 79 // Def(Field("a", "foo"), Field("b", "bar")) represents: 80 // 81 // #D: { 82 // a: "foo" 83 // b: "bar" 84 // } 85 // 86 // For some unique #D. 87 func (x *FieldTester) Def(sub ...declaration) declaration { 88 return x.spawn(closeDef, sub...) 89 } 90 91 func (x *FieldTester) spawn(t closeNodeType, sub ...declaration) declaration { 92 return func(cc *closeContext) { 93 ci := CloseInfo{cc: cc} 94 ci, dc := ci.spawnCloseContext(x.n.ctx, t) 95 96 dc.incDependent(x.n.ctx, TEST, nil) 97 for _, sfn := range sub { 98 sfn(dc) 99 } 100 dc.decDependent(x.n.ctx, TEST, nil) 101 } 102 } 103 104 // Embed represents fields embedded within the current node, such that 105 // Embed(Field("a", "foo"), Def(Field("b", "bar"))) represents: 106 // 107 // { 108 // { 109 // a: "foo" 110 // #D 111 // } 112 // } 113 // 114 // For some #D: b: "bar". 115 func (x *FieldTester) Embed(sub ...declaration) declaration { 116 return x.spawn(closeEmbed, sub...) 117 } 118 119 // Group represents fields and embeddings within a single set of curly braces. 120 // This is used to test that an embedding of a closed value closes the struct 121 // in which it is embedded. 122 func (x *FieldTester) Group(sub ...declaration) declaration { 123 return x.spawn(0, sub...) 124 } 125 126 // EmbedDef represents fields that define a struct and embedded within the 127 // current node. 128 func (x *FieldTester) EmbedDef(sub ...declaration) declaration { 129 return x.Embed(x.Def(sub...)) 130 } 131 132 // Field defines a field declaration such that Field("a", "foo") represents 133 // 134 // a: "foo" 135 // 136 // The value can be of type string, int64, bool, or Expr. 137 // Duplicate values (conjuncts) are retained as the deduplication check is 138 // bypassed for this. 139 func (x *FieldTester) Field(label string, a any) declaration { 140 return x.field(label, a, false) 141 } 142 143 // FieldDedup is like Field, but enables conjunct deduplication. 144 func (x *FieldTester) FieldDedup(label string, a any) declaration { 145 return x.field(label, a, true) 146 } 147 148 func (x *FieldTester) field(label string, a any, dedup bool) declaration { 149 f := x.StringLabel(label) 150 151 var v Expr 152 switch a := a.(type) { 153 case Expr: 154 v = a 155 case string: 156 v = x.NewString(a) 157 case int: 158 v = x.NewInt64(int64(a)) 159 case bool: 160 v = x.newBool(a) 161 default: 162 panic("type not supported") 163 } 164 165 return func(cc *closeContext) { 166 var c Conjunct 167 c.Env = &Environment{Vertex: x.Root} 168 c.CloseInfo.cc = cc 169 c.x = v 170 c.CloseInfo.FromDef = cc.isDef 171 c.CloseInfo.FromEmbed = cc.isEmbed 172 173 x.n.insertArc(f, ArcMember, c, c.CloseInfo, dedup) 174 } 175 } 176 177 // Pat represents a pattern constraint, such that Pat(`<"a"`, "foo") represents 178 // 179 // [<"a"]: "foo" 180 func (x *FieldTester) Pat(pattern Value, v Expr) declaration { 181 if pattern == nil { 182 panic("nil pattern") 183 } 184 if v == nil { 185 panic("nil expr") 186 } 187 return func(cc *closeContext) { 188 var c Conjunct 189 c.Env = &Environment{Vertex: x.Root} 190 c.CloseInfo.cc = cc 191 c.x = v 192 c.CloseInfo.FromDef = cc.isDef 193 c.CloseInfo.FromEmbed = cc.isEmbed 194 195 x.n.insertPattern(pattern, c) 196 } 197 }