cuelang.org/go@v0.13.0/internal/core/adt/eval_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 "flag" 19 "fmt" 20 "path/filepath" 21 "strings" 22 "testing" 23 24 "golang.org/x/tools/txtar" 25 26 "cuelang.org/go/cue" 27 "cuelang.org/go/cue/ast" 28 "cuelang.org/go/cue/cuecontext" 29 "cuelang.org/go/cue/errors" 30 "cuelang.org/go/cue/stats" 31 "cuelang.org/go/cue/token" 32 "cuelang.org/go/internal" 33 "cuelang.org/go/internal/core/adt" 34 "cuelang.org/go/internal/core/debug" 35 "cuelang.org/go/internal/core/eval" 36 "cuelang.org/go/internal/core/runtime" 37 "cuelang.org/go/internal/core/validate" 38 "cuelang.org/go/internal/cuedebug" 39 "cuelang.org/go/internal/cuetxtar" 40 _ "cuelang.org/go/pkg" 41 ) 42 43 var ( 44 todo = flag.Bool("todo", false, "run tests marked with #todo-compile") 45 ) 46 47 // TestEvalV2 tests the old implementation of the evaluator. 48 func TestEvalV2(t *testing.T) { 49 test := cuetxtar.TxTarTest{ 50 Root: "../../../cue/testdata", 51 Name: "eval", 52 } 53 54 cuedebug.Init() 55 flags := cuedebug.Flags 56 57 if *todo { 58 test.ToDo = nil 59 } 60 61 test.Run(t, func(tc *cuetxtar.Test) { 62 runEvalTest(tc, internal.EvalV2, flags) 63 }) 64 } 65 66 func TestEvalV3(t *testing.T) { 67 // TODO: remove use of externalDeps for processing. Currently, enabling 68 // this would fix some issues, but also introduce some closedness bugs. 69 // As a first step, we should ensure that the temporary hack of using 70 // externalDeps to agitate pending dependencies is replaced with a 71 // dedicated mechanism. 72 // 73 adt.DebugDeps = true // check unmatched dependencies. 74 75 cuedebug.Init() 76 flags := cuedebug.Flags 77 78 test := cuetxtar.TxTarTest{ 79 Root: "../../../cue/testdata", 80 Name: "evalalpha", 81 Fallback: "eval", // Allow eval golden files to pass these tests. 82 } 83 84 if *todo { 85 test.ToDo = nil 86 } 87 88 var ran, skipped, errorCount int 89 90 test.Run(t, func(t *cuetxtar.Test) { 91 if reason := skipFiles(t.Instance().Files...); reason != "" { 92 skipped++ 93 t.Skip(reason) 94 } 95 ran++ 96 97 errorCount += runEvalTest(t, internal.EvalV3, flags) 98 }) 99 100 t.Logf("ran: %d, skipped: %d, nodeErrors: %d", 101 ran, skipped, errorCount) 102 } 103 104 // skipFiles returns true if the given files contain CUE that is not yet handled 105 // by the development version of the evaluator. 106 func skipFiles(a ...*ast.File) (reason string) { 107 // Skip disjunctions. 108 fn := func(n ast.Node) bool { 109 switch x := n.(type) { 110 case *ast.BinaryExpr: 111 if x.Op == token.OR { 112 // Uncomment to disable disjunction testing. 113 // NOTE: keep around until implementation of disjunctions 114 // is complete. 115 // reason = "disjunctions" 116 } 117 } 118 return true 119 } 120 for _, f := range a { 121 ast.Walk(f, fn, nil) 122 } 123 return reason 124 } 125 126 func runEvalTest(t *cuetxtar.Test, version internal.EvaluatorVersion, flags cuedebug.Config) (errorCount int) { 127 a := t.Instance() 128 r := runtime.NewWithSettings(version, flags) 129 130 v, err := r.Build(nil, a) 131 if err != nil { 132 t.WriteErrors(err) 133 return 134 } 135 136 e := eval.New(r) 137 ctx := e.NewContext(v) 138 ctx.Version = version 139 ctx.Config = flags 140 v.Finalize(ctx) 141 142 switch counts := ctx.Stats(); { 143 case version == internal.DevVersion: 144 for _, f := range t.Archive.Files { 145 if f.Name != "out/eval/stats" { 146 continue 147 } 148 c := cuecontext.New() 149 v := c.CompileBytes(f.Data) 150 var orig stats.Counts 151 v.Decode(&orig) 152 153 // TODO: do something more principled. 154 switch { 155 case orig.Disjuncts < counts.Disjuncts, 156 orig.Disjuncts > counts.Disjuncts*5 && 157 counts.Disjuncts > 20, 158 orig.Conjuncts > counts.Conjuncts*2, 159 counts.CloseIDElems > 1000: 160 // For now, we only care about disjuncts. 161 // TODO: add triggers once the disjunction issues have bene 162 // solved. 163 w := t.Writer("stats") 164 fmt.Fprintln(w, counts) 165 } 166 break 167 } 168 169 default: 170 w := t.Writer("stats") 171 fmt.Fprintln(w, counts) 172 } 173 174 // if n := stats.Leaks(); n > 0 { 175 // t.Skipf("%d leaks reported", n) 176 // } 177 178 if b := validate.Validate(ctx, v, &validate.Config{ 179 AllErrors: true, 180 }); b != nil { 181 fmt.Fprintln(t, "Errors:") 182 t.WriteErrors(b.Err) 183 fmt.Fprintln(t, "") 184 fmt.Fprintln(t, "Result:") 185 } 186 187 if v == nil { 188 return 189 } 190 191 t.Write(debug.AppendNode(nil, r, v, &debug.Config{Cwd: t.Dir})) 192 fmt.Fprintln(t) 193 194 return 195 } 196 197 // TestX is for debugging. Do not delete. 198 func TestX(t *testing.T) { 199 adt.DebugDeps = true 200 // adt.OpenGraphs = true 201 202 flags := cuedebug.Config{ 203 Sharing: true, // Uncomment to turn sharing off. 204 LogEval: 1, // Uncomment to turn logging off 205 } 206 207 version := internal.DefaultVersion 208 version = internal.DevVersion // comment to use default implementation. 209 210 in := ` 211 -- cue.mod/module.cue -- 212 module: "mod.test" 213 214 language: version: "v0.9.0" 215 216 -- in.cue -- 217 ` 218 219 if strings.HasSuffix(strings.TrimSpace(in), ".cue --") { 220 t.Skip() 221 } 222 223 a := txtar.Parse([]byte(in)) 224 instance := cuetxtar.Load(a, t.TempDir())[0] 225 if instance.Err != nil { 226 t.Fatal(instance.Err) 227 } 228 229 r := runtime.NewWithSettings(version, flags) 230 231 v, err := r.Build(nil, instance) 232 if err != nil { 233 t.Fatal(err) 234 } 235 236 e := eval.New(r) 237 ctx := e.NewContext(v) 238 ctx.Config = flags 239 v.Finalize(ctx) 240 241 out := debug.NodeString(r, v, nil) 242 if adt.OpenGraphs { 243 for p, g := range ctx.ErrorGraphs { 244 path := filepath.Join(".debug/TestX", p) 245 adt.OpenNodeGraph("TestX", path, in, out, g) 246 } 247 } 248 249 if b := validate.Validate(ctx, v, &validate.Config{ 250 AllErrors: true, 251 }); b != nil { 252 t.Log(errors.Details(b.Err, nil)) 253 } 254 255 t.Error(out) 256 257 t.Log(ctx.Stats()) 258 } 259 260 func BenchmarkUnifyAPI(b *testing.B) { 261 for i := 0; i < b.N; i++ { 262 b.StopTimer() 263 ctx := cuecontext.New() 264 v := ctx.CompileString("") 265 for j := 0; j < 500; j++ { 266 if j == 400 { 267 b.StartTimer() 268 } 269 v = v.FillPath(cue.ParsePath(fmt.Sprintf("i_%d", i)), i) 270 } 271 } 272 } 273 274 func TestIssue2293(t *testing.T) { 275 ctx := cuecontext.New() 276 c := `a: {}, a` 277 v1 := ctx.CompileString(c) 278 v2 := ctx.CompileString(c) 279 280 v1.Unify(v2) 281 }