this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cue/testdata/eval: convert eval txtar tests to inline @test format

Convert the remaining eval testdata files from golden-file format to
inline @test(...) annotations. Each converted file gets:
- @test(eq, ...) on fields with expected values
- @test(err, code=..., pos=[...]) on error-bearing fields
- a #-prefixed header comment explaining what the test covers
- out/errors.txt section for documentary error output

Also update CLAUDE.md guidelines for inline test conversion and
cue/testdata/readme.md to reflect the new annotation style.

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: I718878e340a8dbdb3f3bcce8506f0da1f38e538c
Reviewed-on: https://cue.gerrithub.io/c/cue-lang/cue/+/1234945
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>

+295 -722
+61
CLAUDE.md
··· 90 90 - The `CUE_UPDATE=1` environment variable updates golden files with actual output 91 91 - Prefer adding test cases to an existing txtar file that is appropriate for the type of reproducer 92 92 93 + ### Converting txtar tests to inline `@test(...)` format 94 + 95 + When converting a txtar test from golden-file format to inline annotations: 96 + 97 + 1. **Section ordering**: The `-- out/errors.txt --` section must directly follow the 98 + last input section (e.g., `-- in.cue --`), before `-- out/compile --` and 99 + `-- out/eval/stats --`. 100 + 101 + 2. **Error annotations**: Always include position information using a `pos=[]` 102 + placeholder; `CUE_UPDATE=1` fills it in automatically. Positions are matched 103 + order-independently; commas between specs are optional. Example: 104 + ``` 105 + x: bad @test(err, code=eval, contains="...", pos=[]) 106 + ``` 107 + 108 + 3. **Multiple sub-errors**: When an error has multiple sub-errors (e.g., from a 109 + failed disjunction), use `suberr=(...)` to match individual sub-errors instead 110 + of a single flat `contains=`: 111 + ``` 112 + x: a | b @test(err, suberr=(code=eval, contains="..."), suberr=(code=eval, contains="...")) 113 + ``` 114 + 115 + 4. **Files with compile-time errors**: CUE source files that themselves produce 116 + compile errors (e.g., arithmetic on abstract types like `string + ":" + string`, 117 + or comparisons like `string == number`) **cannot** be converted to inline test 118 + format. The inline runner must be able to compile the source. Leave these files 119 + in their original golden-file format. 120 + 121 + 5. **Definition references in `@test(leq, ...)`**: Definition names (e.g., 122 + `#MyDef`) are not in scope when the expected constraint expression is compiled. 123 + Use the structural equivalent (e.g., `{field: string}`) with `@test(closed)`. 124 + 125 + 6. **Remove `out/eval` and `out/evalalpha` sections** after conversion, but keep 126 + the `out/eval/stats` section (promote v3 stats from `out/evalalpha/stats` if 127 + needed). 128 + 129 + 7. **Add `out/errors.txt`** if any errors e xist in the test (leave empty initially; 130 + `CUE_UPDATE=1` fills it in automatically). 131 + 132 + 8. **Add `out/todo.txt`** if there are noteworthy differences 133 + between the v2 and v3 evaluator results. 134 + 135 + 9. **File header comment**: For files that reference a GitHub issue (e.g., 136 + `issue1886.txtar`), add a `#`-prefixed comment block at the very top of the 137 + txtar file (before the first `-- section --`) explaining what the original 138 + issue was about and how the test covers its essence. Example: 139 + ``` 140 + # Tests that string interpolation with an abstract type reports "incomplete" 141 + # errors correctly regardless of declaration order. Issue: evalv2 gave wrong 142 + # "was already used" errors when a field was referenced before being defined. 143 + ``` 144 + 145 + 10. **DO NOT** introduce any flags in new @test(err) directives. Only maintainers 146 + of the CUE project should do so. 147 + 148 + 11. **@test(eq, ...) placement**: Prefer placing the eq directive attribute 149 + either directly after a field for single field test, or as a field decl 150 + at the end of a struct of a test that is struct based. Do NOT place `@test` 151 + as a field attribute after a closing `}` — e.g., `} @test(eq, ...)` is 152 + wrong; move it inside the struct as a trailing decl attribute instead. 153 + 93 154 ### Contribution Model 94 155 - Single commit per PR/CL model 95 156 - Uses `git codereview` workflow for managing changes
+26 -135
cue/testdata/eval/conflicts.txtar
··· 1 - #todo:inline: medium — multiple error cases; annotate with @test(err) per field 2 1 -- in.cue -- 3 2 i: int 4 3 s: string 5 4 6 5 t0: { 6 + @test(err, code=eval, at=v, 7 + contains="conflicting values", 8 + args=[int, string], 9 + pos=[-3:4, -2:4, 1:5, 1:9]) 7 10 v: i & s 8 11 } 9 12 10 13 t1: { 14 + @test(err, code=eval, at=x.a.b, 15 + contains="conflicting values", 16 + args=[3, 4], 17 + pos=[2:9, 6:9, 9:5, 9:11]) 11 18 #d1: { 12 19 a: b: 3 13 20 } ··· 17 24 } 18 25 19 26 x: #d1 & #d2 27 + @test(eq, { 28 + #d1: a: b: 3 29 + #d2: a: b: 4 30 + x: a: b: _|_ 31 + }) 20 32 } 33 + -- out/errors.txt -- 34 + [eval] t0.v: conflicting values string and int (mismatched types string and int): 35 + ./in.cue:1:4 36 + ./in.cue:2:4 37 + ./in.cue:5:5 38 + ./in.cue:5:9 39 + [eval] t1.x.a.b: conflicting values 4 and 3: 40 + ./in.cue:10:9 41 + ./in.cue:14:9 42 + ./in.cue:17:5 43 + ./in.cue:17:11 21 44 -- out/eval/stats -- 22 45 Leaks: 0 23 46 Freed: 15 ··· 28 51 Unifications: 15 29 52 Conjuncts: 23 30 53 Disjuncts: 15 31 - -- out/evalalpha -- 32 - Errors: 33 - t0.v: conflicting values string and int (mismatched types string and int): 34 - ./in.cue:1:4 35 - ./in.cue:2:4 36 - ./in.cue:5:5 37 - ./in.cue:5:9 38 - t1.x.a.b: conflicting values 4 and 3: 39 - ./in.cue:10:9 40 - ./in.cue:14:9 41 - ./in.cue:17:5 42 - ./in.cue:17:11 43 - 44 - Result: 45 - (_|_){ 46 - // [eval] 47 - i: (int){ int } 48 - s: (string){ string } 49 - t0: (_|_){ 50 - // [eval] 51 - v: (_|_){ 52 - // [eval] t0.v: conflicting values string and int (mismatched types string and int): 53 - // ./in.cue:1:4 54 - // ./in.cue:2:4 55 - // ./in.cue:5:5 56 - // ./in.cue:5:9 57 - } 58 - } 59 - t1: (_|_){ 60 - // [eval] 61 - #d1: (#struct){ 62 - a: (#struct){ 63 - b: (int){ 3 } 64 - } 65 - } 66 - #d2: (#struct){ 67 - a: (#struct){ 68 - b: (int){ 4 } 69 - } 70 - } 71 - x: (_|_){ 72 - // [eval] 73 - a: (_|_){ 74 - // [eval] 75 - b: (_|_){ 76 - // [eval] t1.x.a.b: conflicting values 4 and 3: 77 - // ./in.cue:10:9 78 - // ./in.cue:14:9 79 - // ./in.cue:17:5 80 - // ./in.cue:17:11 81 - } 82 - } 83 - } 84 - } 85 - } 86 - -- diff/-out/evalalpha<==>+out/eval -- 87 - diff old new 88 - --- old 89 - +++ new 90 - @@ -1,7 +1,8 @@ 91 - Errors: 92 - -t0.v: conflicting values int and string (mismatched types int and string): 93 - +t0.v: conflicting values string and int (mismatched types string and int): 94 - ./in.cue:1:4 95 - ./in.cue:2:4 96 - + ./in.cue:5:5 97 - ./in.cue:5:9 98 - t1.x.a.b: conflicting values 4 and 3: 99 - ./in.cue:10:9 100 - @@ -17,9 +18,10 @@ 101 - t0: (_|_){ 102 - // [eval] 103 - v: (_|_){ 104 - - // [eval] t0.v: conflicting values int and string (mismatched types int and string): 105 - + // [eval] t0.v: conflicting values string and int (mismatched types string and int): 106 - // ./in.cue:1:4 107 - // ./in.cue:2:4 108 - + // ./in.cue:5:5 109 - // ./in.cue:5:9 110 - } 111 - } 112 - -- out/eval -- 113 - Errors: 114 - t0.v: conflicting values int and string (mismatched types int and string): 115 - ./in.cue:1:4 116 - ./in.cue:2:4 117 - ./in.cue:5:9 118 - t1.x.a.b: conflicting values 4 and 3: 119 - ./in.cue:10:9 120 - ./in.cue:14:9 121 - ./in.cue:17:5 122 - ./in.cue:17:11 123 - 124 - Result: 125 - (_|_){ 126 - // [eval] 127 - i: (int){ int } 128 - s: (string){ string } 129 - t0: (_|_){ 130 - // [eval] 131 - v: (_|_){ 132 - // [eval] t0.v: conflicting values int and string (mismatched types int and string): 133 - // ./in.cue:1:4 134 - // ./in.cue:2:4 135 - // ./in.cue:5:9 136 - } 137 - } 138 - t1: (_|_){ 139 - // [eval] 140 - #d1: (#struct){ 141 - a: (#struct){ 142 - b: (int){ 3 } 143 - } 144 - } 145 - #d2: (#struct){ 146 - a: (#struct){ 147 - b: (int){ 4 } 148 - } 149 - } 150 - x: (_|_){ 151 - // [eval] 152 - a: (_|_){ 153 - // [eval] 154 - b: (_|_){ 155 - // [eval] t1.x.a.b: conflicting values 4 and 3: 156 - // ./in.cue:10:9 157 - // ./in.cue:14:9 158 - // ./in.cue:17:5 159 - // ./in.cue:17:11 160 - } 161 - } 162 - } 163 - } 164 - } 54 + -- out/todo.txt -- 55 + v3 reports the argument order differently (string/int vs int/string in v2) and includes an additional error position (5:5) for the assignment in t0.v. 165 56 -- out/compile -- 166 57 --- in.cue 167 58 {
+5 -37
cue/testdata/eval/deref.txtar
··· 1 - #todo:inline: medium — comprehension; may need @test(final) for incomplete fields 2 1 -- in.cue -- 3 2 issue4011: full: { 4 3 let _hugoEnvironments = { ··· 22 21 } 23 22 24 23 site: [_]: hugo: production: {} 24 + @test(eq, {site: cls: { 25 + fs: Create: config: Contents: {} 26 + hugo: production: {} 27 + }}) 25 28 } 26 29 issue4011: reduced: { 30 + @test(eq, {result: foo: true, envs: foo: {}}) 27 31 result: { 28 32 for envName in ["foo"] 29 33 let env = envs[envName] ··· 47 51 MisalignedConjunct: 4 48 52 49 53 NumCloseIDs: 2 50 - -- out/evalalpha -- 51 - (struct){ 52 - issue4011: (struct){ 53 - full: (struct){ 54 - let _hugoEnvironments#1 = (struct){ 55 - default: (string){ "_default" } 56 - production: (string){ "production" } 57 - } 58 - site: (struct){ 59 - cls: (struct){ 60 - fs: (struct){ 61 - Create: (struct){ 62 - config: (struct){ 63 - Contents: (struct){ 64 - } 65 - } 66 - } 67 - } 68 - hugo: (struct){ 69 - production: (struct){ 70 - } 71 - } 72 - } 73 - } 74 - } 75 - reduced: (struct){ 76 - result: (struct){ 77 - foo: (bool){ true } 78 - } 79 - envs: (struct){ 80 - foo: (struct){ 81 - } 82 - } 83 - } 84 - } 85 - } 86 54 -- out/compile -- 87 55 --- in.cue 88 56 {
+3 -28
cue/testdata/eval/discontinuous.txtar
··· 1 1 This test tests a case where a child node needs to be evaluated 2 2 before evaluating a parent has completed. 3 - #todo:inline: medium — comprehension; may need @test(final) for incomplete fields 4 3 -- in.cue -- 5 4 a: [for c in foo.bar.baz { 6 5 c 7 6 }] 8 7 9 - a: [{name: "http"}] 8 + a: [{name: "http"}] @test(eq, [{name: "http", port: 8080}]) 10 9 11 10 foo: { 12 11 x.D 13 12 14 13 bar: baz: [{port: 8080}] 14 + @test(eq, {bar: {baz: [{port: 8080}]}}) 15 15 } 16 16 17 17 x: { 18 18 D: bar: DSpec 19 19 DSpec: {} 20 + @test(eq, {D: bar: {}, DSpec: {}}) 20 21 } 21 22 -- out/compile -- 22 23 --- in.cue ··· 58 59 Unifications: 14 59 60 Conjuncts: 23 60 61 Disjuncts: 23 61 - -- out/evalalpha -- 62 - (struct){ 63 - a: (#list){ 64 - 0: (struct){ 65 - name: (string){ "http" } 66 - port: (int){ 8080 } 67 - } 68 - } 69 - foo: (struct){ 70 - bar: (struct){ 71 - baz: (#list){ 72 - 0: (struct){ 73 - port: (int){ 8080 } 74 - } 75 - } 76 - } 77 - } 78 - x: (struct){ 79 - D: (struct){ 80 - bar: (struct){ 81 - } 82 - } 83 - DSpec: (struct){ 84 - } 85 - } 86 - }
+8 -53
cue/testdata/eval/errunifiy.txtar
··· 1 1 Incomplete errors should not unify with values. 2 - #todo:inline: medium — multiple error cases; annotate with @test(err) per field 3 2 -- in.cue -- 4 - a: or([]) 3 + a: or([]) @test(err, code=incomplete, contains="empty list", pos=[0:4]) 5 4 a: "t" 6 5 7 - b: _|_ 6 + b: _|_ @test(err, code=user, contains="explicit error", pos=[0:4]) 8 7 b: "t" 9 - -- out/evalalpha/stats -- 8 + -- out/errors.txt -- 9 + [incomplete] a: error in call to or: empty list in call to or: 10 + ./in.cue:1:4 11 + [user] explicit error (_|_ literal) in source: 12 + ./in.cue:4:4 13 + -- out/eval/stats -- 10 14 Leaks: 0 11 15 Freed: 4 12 16 Reused: 0 ··· 16 20 Unifications: 4 17 21 Conjuncts: 6 18 22 Disjuncts: 0 19 - -- diff/-out/evalalpha/stats<==>+out/eval/stats -- 20 - diff old new 21 - --- old 22 - +++ new 23 - @@ -1,9 +1,9 @@ 24 - -Leaks: 5 25 - -Freed: 3 26 - -Reused: 1 27 - -Allocs: 7 28 - -Retain: 5 29 - +Leaks: 0 30 - +Freed: 4 31 - +Reused: 0 32 - +Allocs: 4 33 - +Retain: 0 34 - 35 - -Unifications: 8 36 - -Conjuncts: 14 37 - -Disjuncts: 8 38 - +Unifications: 4 39 - +Conjuncts: 6 40 - +Disjuncts: 0 41 - -- out/eval/stats -- 42 - Leaks: 5 43 - Freed: 3 44 - Reused: 1 45 - Allocs: 7 46 - Retain: 5 47 - 48 - Unifications: 8 49 - Conjuncts: 14 50 - Disjuncts: 8 51 - -- out/evalalpha -- 52 - Errors: 53 - explicit error (_|_ literal) in source: 54 - ./in.cue:4:4 55 - 56 - Result: 57 - (_|_){ 58 - // [user] 59 - a: (_|_){ 60 - // [incomplete] a: error in call to or: empty list in call to or: 61 - // ./in.cue:1:4 62 - } 63 - b: (_|_){ 64 - // [user] explicit error (_|_ literal) in source: 65 - // ./in.cue:4:4 66 - } 67 - } 68 23 -- out/compile -- 69 24 --- in.cue 70 25 {
+8 -32
cue/testdata/eval/fields.txtar
··· 1 - #todo:inline: medium — multiple error cases; annotate with @test(err) per field 2 1 -- in.cue -- 3 2 bulkToSelf: { 4 3 a: { 5 4 foo: [string]: int 6 - foo: bar: "3" // error 5 + foo: bar: "3" @test(err, any, code=eval, contains="conflicting values") 7 6 } 8 7 } 9 8 intField: { 9 + @test(err, code=eval, contains="integer fields not supported", pos=[1:3]) 10 10 (2): string 11 11 } 12 + -- out/errors.txt -- 13 + [eval] bulkToSelf.a.foo.bar: conflicting values "3" and int (mismatched types string and int): 14 + ./in.cue:3:18 15 + ./in.cue:4:18 16 + [eval] intField: integer fields not supported: 17 + ./in.cue:8:3 12 18 -- out/compile -- 13 19 --- in.cue 14 20 { ··· 36 42 Unifications: 7 37 43 Conjuncts: 9 38 44 Disjuncts: 7 39 - -- out/evalalpha -- 40 - Errors: 41 - bulkToSelf.a.foo.bar: conflicting values "3" and int (mismatched types string and int): 42 - ./in.cue:3:18 43 - ./in.cue:4:18 44 - intField: integer fields not supported: 45 - ./in.cue:8:3 46 - 47 - Result: 48 - (_|_){ 49 - // [eval] 50 - bulkToSelf: (_|_){ 51 - // [eval] 52 - a: (_|_){ 53 - // [eval] 54 - foo: (_|_){ 55 - // [eval] 56 - bar: (_|_){ 57 - // [eval] bulkToSelf.a.foo.bar: conflicting values "3" and int (mismatched types string and int): 58 - // ./in.cue:3:18 59 - // ./in.cue:4:18 60 - } 61 - } 62 - } 63 - } 64 - intField: (_|_){ 65 - // [eval] intField: integer fields not supported: 66 - // ./in.cue:8:3 67 - } 68 - }
+13 -57
cue/testdata/eval/issue1640.txtar
··· 1 - #todo:inline: easy — general eval; straightforward @test(eq, ...) for concrete fields 1 + # Tests that evaluation of multi-file packages is deterministic regardless of 2 + # field declaration order across files. The two input files a1.cue and a2.cue 3 + # define the same fields x and y but in opposite orders; both must yield the same 4 + # result. Also tests that #MCS (MultiCaseString, with uc: lc) correctly propagates 5 + # concrete values when fact1 and fact2 cross-reference each other. 2 6 -- a1.cue -- 3 7 package bug 4 8 ··· 13 17 package bug 14 18 15 19 fact1: #MCS & { 20 + @test(eq, {lc: "foo", uc: "foo"}) 21 + @test(closed) 16 22 lc: fact2.lc 17 23 } 18 24 fact2: #MCS & { 25 + @test(eq, {lc: "foo", uc: "foo"}) 26 + @test(closed) 19 27 lc: "foo" 20 28 } 21 29 22 - #MCS: #MultiCaseString 30 + #MCS: #MultiCaseString @test(eq, {lc: string, uc: string}) @test(closed) @test(shareID=MCS) 23 31 #MultiCaseString: { 32 + @test(shareID=MCS) 33 + @test(eq, {lc: string, uc: string}) 34 + @test(closed) 24 35 lc: string 25 36 uc: lc 26 37 } ··· 59 70 Unifications: 15 60 71 Conjuncts: 45 61 72 Disjuncts: 31 62 - -- out/evalalpha -- 63 - (struct){ 64 - y: (string){ "foo" } 65 - x: (string){ "foo" } 66 - fact1: (#struct){ 67 - lc: (string){ "foo" } 68 - uc: (string){ "foo" } 69 - } 70 - fact2: (#struct){ 71 - lc: (string){ "foo" } 72 - uc: (string){ "foo" } 73 - } 74 - #MCS: ~(#MultiCaseString) 75 - #MultiCaseString: (#struct){ 76 - lc: (string){ string } 77 - uc: (string){ string } 78 - } 79 - } 80 - -- diff/-out/evalalpha<==>+out/eval -- 81 - diff old new 82 - --- old 83 - +++ new 84 - @@ -9,10 +9,7 @@ 85 - lc: (string){ "foo" } 86 - uc: (string){ "foo" } 87 - } 88 - - #MCS: (#struct){ 89 - - lc: (string){ string } 90 - - uc: (string){ string } 91 - - } 92 - + #MCS: ~(#MultiCaseString) 93 - #MultiCaseString: (#struct){ 94 - lc: (string){ string } 95 - uc: (string){ string } 96 - -- out/eval -- 97 - (struct){ 98 - y: (string){ "foo" } 99 - x: (string){ "foo" } 100 - fact1: (#struct){ 101 - lc: (string){ "foo" } 102 - uc: (string){ "foo" } 103 - } 104 - fact2: (#struct){ 105 - lc: (string){ "foo" } 106 - uc: (string){ "foo" } 107 - } 108 - #MCS: (#struct){ 109 - lc: (string){ string } 110 - uc: (string){ string } 111 - } 112 - #MultiCaseString: (#struct){ 113 - lc: (string){ string } 114 - uc: (string){ string } 115 - } 116 - }
+58 -53
cue/testdata/eval/issue1886.txtar
··· 1 - #todo:inline: hard — cycle semantics require @test(err, code=cycle) and careful scoping 1 + # Tests cycles and incomplete errors. The cycle struct covers resolvable cycles 2 + # (x=200, x=y+100, y=x-100 resolves because x is grounded at 200) and 3 + # unresolvable ones (a=b+100, b=a-100 — cycle error). The incompleteOne and 4 + # incompleteTwo cases verify that string interpolation with an abstract type 5 + # parameter reports "incomplete" errors correctly regardless of whether the 6 + # hidden template field _t appears before or after its usage site. 2 7 -- in.cue -- 3 8 cycle: { 4 - x: 200 9 + x: 200 @test(eq, 200) 5 10 x: y + 100 6 - y: x - 100 11 + y: x - 100 @test(eq, 100) 7 12 8 - a: b + 100 9 - b: a - 100 13 + a: b + 100 @test(err, code=cycle, 14 + suberr=(pos=[0:5], args=[b]), 15 + suberr=(pos=[1:5], args=[a]), 16 + ) 17 + b: a - 100 @test(err, code=cycle, 18 + suberr=(pos=[-1:5], args=[b]), 19 + suberr=(pos=[0:5], args=[a]), 20 + ) 10 21 } 11 22 12 23 incompleteOne: { 24 + @test(err, code=incomplete, pos=[2:7, 3:3, 8:5], at=r) 13 25 _t: { 14 26 #p: string 15 27 """ ··· 20 32 r: """ 21 33 \(_t) 22 34 """ 35 + // TODO: we current cannot check for errors on hidden fields. 36 + @test(debugOutput, """ 37 + (struct){ 38 + _t: (_|_){ 39 + // [incomplete] incompleteOne._t: invalid interpolation: non-concrete value string (type string): 40 + // in.cue:13:3 41 + // in.cue:12:7 42 + #p: (string){ string } 43 + } 44 + r: (_|_){ 45 + // [incomplete] incompleteOne._t: invalid interpolation: invalid interpolation: non-concrete value string (type string): 46 + // in.cue:18:5 47 + // in.cue:12:7 48 + // in.cue:13:3 49 + } 50 + } 51 + """) 23 52 } 24 53 25 54 incompleteTwo: { 26 55 r: """ 27 56 \(_t) 28 - """ 57 + """ @test(err, code=incomplete) 29 58 30 59 _t: { 31 60 #p: string ··· 34 63 """ 35 64 } 36 65 } 37 - -- out/evalalpha -- 38 - (struct){ 39 - cycle: (struct){ 40 - x: (int){ 200 } 41 - y: (int){ 100 } 42 - a: (_|_){ 43 - // [cycle] cycle.a: cycle with field: b: 44 - // ./in.cue:6:5 45 - // cycle.b: cycle with field: a: 46 - // ./in.cue:7:5 47 - } 48 - b: (_|_){ 49 - // [cycle] cycle.a: cycle with field: b: 50 - // ./in.cue:6:5 51 - // cycle.b: cycle with field: a: 52 - // ./in.cue:7:5 53 - } 54 - } 55 - incompleteOne: (struct){ 56 - _t: (_|_){ 57 - // [incomplete] incompleteOne._t: invalid interpolation: non-concrete value string (type string): 58 - // ./in.cue:13:3 59 - // ./in.cue:12:7 60 - #p: (string){ string } 61 - } 62 - r: (_|_){ 63 - // [incomplete] incompleteOne._t: invalid interpolation: invalid interpolation: non-concrete value string (type string): 64 - // ./in.cue:18:5 65 - // ./in.cue:12:7 66 - // ./in.cue:13:3 67 - } 68 - } 69 - incompleteTwo: (struct){ 70 - r: (_|_){ 71 - // [incomplete] incompleteTwo._t: invalid interpolation: invalid interpolation: non-concrete value string (type string): 72 - // ./in.cue:24:5 73 - // ./in.cue:29:7 74 - // ./in.cue:30:3 75 - } 76 - _t: (_|_){ 77 - // [incomplete] incompleteTwo._t: invalid interpolation: non-concrete value string (type string): 78 - // ./in.cue:30:3 79 - // ./in.cue:29:7 80 - #p: (string){ string } 81 - } 82 - } 83 - } 66 + -- out/errors.txt -- 67 + [cycle] cycle.a: cycle with field: b: 68 + ./in.cue:6:5 69 + cycle.b: cycle with field: a: 70 + ./in.cue:7:5 71 + [cycle] cycle.a: cycle with field: b: 72 + ./in.cue:6:5 73 + cycle.b: cycle with field: a: 74 + ./in.cue:7:5 75 + [incomplete] incompleteOne._t: invalid interpolation: non-concrete value string (type string): 76 + ./in.cue:13:3 77 + ./in.cue:12:7 78 + [incomplete] incompleteOne._t: invalid interpolation: invalid interpolation: non-concrete value string (type string): 79 + ./in.cue:18:5 80 + ./in.cue:12:7 81 + ./in.cue:13:3 82 + [incomplete] incompleteTwo._t: invalid interpolation: invalid interpolation: non-concrete value string (type string): 83 + ./in.cue:24:5 84 + ./in.cue:29:7 85 + ./in.cue:30:3 86 + [incomplete] incompleteTwo._t: invalid interpolation: non-concrete value string (type string): 87 + ./in.cue:30:3 88 + ./in.cue:29:7 84 89 -- out/compile -- 85 90 --- in.cue 86 91 {
+24 -111
cue/testdata/eval/issue2337.txtar
··· 1 - #todo:inline: medium — comprehension; may need @test(final) for incomplete fields 1 + # evalv2 reported "x: was already used" instead of "conflicting values" for the 2 + # simple.x case. The issue2473 cases test that comprehension guards do not prevent 3 + # fields referenced in the guard from being further constrained in the outer scope 4 + # — env2 should remain "prod" even after being used as a comprehension condition. 5 + # The "one" variant broke on v0.6.0; the "two" variant also failed on v0.5.0. 2 6 -- in.cue -- 3 7 // evalv2 failed with the confusing error "x: was already used" 4 8 // rather than a friendlier "conflicting values" error. 5 9 simple: { 6 - x: "x" 10 + x: "x" @test(err, code=eval, 11 + contains="conflicting values", 12 + args=["foo", "x"], 13 + pos=[in.cue:4:5, in.cue:6:7]) 14 + 7 15 (x): "foo" 8 16 } 9 - 10 17 // Worked on CUE v0.5.0, broke on v0.6.0 with "was already used". 11 18 // Should succeed, as the comprehension does not change env2. 12 19 issue2473: one: { ··· 22 29 example: c.env2 23 30 } 24 31 } 32 + @test(eq, { 33 + c: {env: "prod", env2: "prod"}, 34 + example: "prod"} 35 + ) 25 36 } 26 37 // A variant of the above which failed on v0.5.0 as well. 27 38 issue2473: two: { ··· 35 46 example: env2 36 47 } 37 48 } 49 + @test(eq, { 50 + env: "prod" 51 + env2: "prod" 52 + example: "prod" 53 + }) 38 54 } 55 + -- out/errors.txt -- 56 + [eval] simple.x: conflicting values "foo" and "x": 57 + ./in.cue:4:5 58 + ./in.cue:6:7 39 59 -- out/compile -- 40 60 --- in.cue 41 61 { ··· 88 108 MisalignedConjunct: 5 89 109 90 110 NumCloseIDs: 2 91 - -- out/evalalpha -- 92 - Errors: 93 - simple.x: conflicting values "foo" and "x": 94 - ./in.cue:4:7 95 - ./in.cue:5:7 96 111 97 - Result: 98 - (_|_){ 99 - // [eval] 100 - simple: (_|_){ 101 - // [eval] 102 - x: (_|_){ 103 - // [eval] simple.x: conflicting values "foo" and "x": 104 - // ./in.cue:4:7 105 - // ./in.cue:5:7 106 - } 107 - } 108 - issue2473: (struct){ 109 - one: (struct){ 110 - c: (struct){ 111 - env: (string){ "prod" } 112 - env2: (string){ "prod" } 113 - } 114 - example: (string){ "prod" } 115 - } 116 - two: (struct){ 117 - env: (string){ "prod" } 118 - env2: (string){ "prod" } 119 - example: (string){ "prod" } 120 - } 121 - } 122 - } 123 - -- diff/-out/evalalpha<==>+out/eval -- 124 - diff old new 125 - --- old 126 - +++ new 127 - @@ -1,25 +1,28 @@ 128 - -(struct){ 129 - +Errors: 130 - +simple.x: conflicting values "foo" and "x": 131 - + ./in.cue:4:7 132 - + ./in.cue:5:7 133 - + 134 - +Result: 135 - +(_|_){ 136 - + // [eval] 137 - simple: (_|_){ 138 - - // [incomplete] simple: cannot add field x: was already used: 139 - - // ./in.cue:5:2 140 - - x: (string){ "x" } 141 - + // [eval] 142 - + x: (_|_){ 143 - + // [eval] simple.x: conflicting values "foo" and "x": 144 - + // ./in.cue:4:7 145 - + // ./in.cue:5:7 146 - + } 147 - } 148 - issue2473: (struct){ 149 - one: (struct){ 150 - - c: (_|_){ 151 - - // [incomplete] issue2473.one: cannot add field env2: was already used: 152 - - // ./in.cue:19:7 153 - + c: (struct){ 154 - env: (string){ "prod" } 155 - env2: (string){ "prod" } 156 - } 157 - - example: (_|_){ 158 - - // [incomplete] issue2473.one: cannot add field env2: was already used: 159 - - // ./in.cue:19:7 160 - - } 161 - - } 162 - - two: (_|_){ 163 - - // [incomplete] issue2473.two: cannot add field env2: was already used: 164 - - // ./in.cue:32:4 165 - + example: (string){ "prod" } 166 - + } 167 - + two: (struct){ 168 - env: (string){ "prod" } 169 - env2: (string){ "prod" } 170 - example: (string){ "prod" } 171 - -- out/eval -- 172 - (struct){ 173 - simple: (_|_){ 174 - // [incomplete] simple: cannot add field x: was already used: 175 - // ./in.cue:5:2 176 - x: (string){ "x" } 177 - } 178 - issue2473: (struct){ 179 - one: (struct){ 180 - c: (_|_){ 181 - // [incomplete] issue2473.one: cannot add field env2: was already used: 182 - // ./in.cue:19:7 183 - env: (string){ "prod" } 184 - env2: (string){ "prod" } 185 - } 186 - example: (_|_){ 187 - // [incomplete] issue2473.one: cannot add field env2: was already used: 188 - // ./in.cue:19:7 189 - } 190 - } 191 - two: (_|_){ 192 - // [incomplete] issue2473.two: cannot add field env2: was already used: 193 - // ./in.cue:32:4 194 - env: (string){ "prod" } 195 - env2: (string){ "prod" } 196 - example: (string){ "prod" } 197 - } 198 - } 199 - } 112 +
+11 -41
cue/testdata/eval/issue2550.txtar
··· 1 - #todo:inline: medium — comprehension; may need @test(final) for incomplete fields 1 + # Tests that accessing an undefined field (bar.missing) on a closed empty struct 2 + # (bar: close({})) inside a comprehension guard correctly reports "undefined 3 + # field" rather than panicking or producing a wrong result. The let binding 4 + # (let _bar = bar) inside the comprehension body verifies that let bindings in 5 + # comprehensions interacting with closed structs do not affect the error behavior. 2 6 -- in.cue -- 3 - foo: string 4 - bar: close({}) 7 + foo: string @test(eq, string) 8 + bar: close({}) @test(eq, {}) @test(closed) 5 9 6 10 if bar.missing == "x" { 7 11 let _bar = bar 8 12 foo: _bar 9 13 } 14 + @test(err, code=eval, contains="undefined field", args=[missing], pos=[in.cue:4:8]) 15 + -- out/errors.txt -- 16 + [eval] undefined field: missing: 17 + ./in.cue:4:8 10 18 -- out/compile -- 11 19 --- in.cue 12 20 { ··· 29 37 Disjuncts: 6 30 38 31 39 NumCloseIDs: 1 32 - -- out/eval -- 33 - Errors: 34 - undefined field: missing: 35 - ./in.cue:4:8 36 40 37 - Result: 38 - (_|_){ 39 - // [eval] undefined field: missing: 40 - // ./in.cue:4:8 41 - foo: (string){ string } 42 - bar: (#struct){ 43 - } 44 - let _bar#1 = (_){ _ } 45 - } 46 - -- out/evalalpha -- 47 - Errors: 48 - undefined field: missing: 49 - ./in.cue:4:8 50 - 51 - Result: 52 - (_|_){ 53 - // [eval] undefined field: missing: 54 - // ./in.cue:4:8 55 - foo: (string){ string } 56 - bar: (#struct){ 57 - } 58 - let _bar#1multi = 〈1;bar〉 59 - } 60 - -- diff/-out/evalalpha<==>+out/eval -- 61 - diff old new 62 - --- old 63 - +++ new 64 - @@ -9,5 +9,5 @@ 65 - foo: (string){ string } 66 - bar: (#struct){ 67 - } 68 - - let _bar#1 = (_){ _ } 69 - + let _bar#1multi = 〈1;bar〉 70 - }
+12 -23
cue/testdata/eval/issue3301.txtar
··· 1 - #todo:inline: medium — comprehension; may need @test(final) for incomplete fields 1 + # Tests that closedness is correctly propagated through multiple levels of 2 + # embedded definitions with optional fields and conditional comprehensions. 3 + # #Leaf embeds #Mid (which embeds #Base), all with optional fields. The nested 4 + # if comprehensions inside #Leaf reference optional fields without triggering 5 + # spurious closedness errors. 2 6 -- in.cue -- 3 - object: #Leaf & {} 7 + object: #Leaf & {} @test(eq, {extra?: {}, more?: int}) @test(closed) 4 8 5 9 #Base: { 6 10 extra?: {...} 11 + @test(eq, {extra?: {}}) 12 + @test(closed) 7 13 } 8 14 9 15 #Mid: { 10 16 #Base 17 + @test(eq, {extra?: {}}) 18 + @test(closed) 11 19 } 12 20 13 21 #Leaf: { ··· 19 27 foo: "bar" 20 28 } 21 29 } 22 - } 23 - -- out/evalalpha -- 24 - (struct){ 25 - object: (#struct){ 26 - extra?: (#struct){ 27 - } 28 - more?: (int){ int } 29 - } 30 - #Base: (#struct){ 31 - extra?: (#struct){ 32 - } 33 - } 34 - #Mid: (#struct){ 35 - extra?: (#struct){ 36 - } 37 - } 38 - #Leaf: (#struct){ 39 - extra?: (#struct){ 40 - } 41 - more?: (int){ int } 42 - } 30 + @test(eq, {extra?: {}, more?: int}) 31 + @test(closed) 43 32 } 44 33 -- out/eval/stats -- 45 34 Leaks: 0
+35 -87
cue/testdata/eval/issue3688.txtar
··· 1 - # This test is important in locking in the behaviour of evalv3, 2 - # which fixed some closedness bugs present in the older evalv2. 3 - #todo:inline: medium — multiple error cases; annotate with @test(err) per field 1 + # Tests that #fun1 with a hidden field _in: #TypeA (where #TypeA: string | 2 + # {foo: int}) correctly computes out using comprehensions that select based on 3 + # whether _in is a string or has field foo. evalv2 had closedness bugs where eg2 4 + # (input {foo: 5}) failed to select "foo" and eg3 (input {foo: 5, bar: "test"}) 5 + # failed to fall through to "impossible". evalv3 fixed these bugs. 4 6 -- x.cue -- 5 7 package x 6 8 ··· 26 28 res: (#fun1 & {_in: in, _}).out 27 29 } 28 30 29 - examples: eg1: in: "test" 30 - examples: eg2: in: { 31 - foo: 5 31 + examples: eg1: { 32 + in: "test" 33 + @test(eq, {in: "test", res: "test"}) 34 + } 35 + examples: eg2: { 36 + in: { 37 + foo: 5 38 + } 39 + @test(eq, {in: {foo: 5}, res: "foo"}) 32 40 } 33 - examples: eg3: in: { 34 - foo: 5 35 - bar: "test" 41 + examples: eg3: { 42 + in: { 43 + foo: 5 44 + bar: "test" 45 + } 46 + @test(eq, { 47 + in: {foo: 5, bar: "test"} 48 + res: "impossible" 49 + }) 36 50 } 51 + -- out/eval/stats -- 52 + Leaks: 8 53 + Freed: 82 54 + Reused: 63 55 + Allocs: 27 56 + Retain: 0 57 + 58 + Unifications: 41 59 + Conjuncts: 139 60 + Disjuncts: 22 61 + 62 + NumCloseIDs: 43 37 63 -- out/compile -- 38 64 --- x.cue 39 65 { ··· 82 108 } 83 109 } 84 110 } 85 - -- out/evalalpha/stats -- 86 - Leaks: 8 87 - Freed: 82 88 - Reused: 63 89 - Allocs: 27 90 - Retain: 0 91 - 92 - Unifications: 41 93 - Conjuncts: 139 94 - Disjuncts: 22 95 - 96 - NumCloseIDs: 43 97 - -- diff/-out/evalalpha/stats<==>+out/eval/stats -- 98 - diff old new 99 - --- old 100 - +++ new 101 - @@ -1,9 +1,11 @@ 102 - -Leaks: 15 103 - -Freed: 105 104 - -Reused: 99 105 - -Allocs: 21 106 - -Retain: 37 107 - - 108 - -Unifications: 82 109 - -Conjuncts: 246 110 - -Disjuncts: 139 111 - +Leaks: 8 112 - +Freed: 82 113 - +Reused: 63 114 - +Allocs: 27 115 - +Retain: 0 116 - + 117 - +Unifications: 41 118 - +Conjuncts: 139 119 - +Disjuncts: 22 120 - + 121 - +NumCloseIDs: 43 122 - -- out/eval/stats -- 123 - Leaks: 15 124 - Freed: 105 125 - Reused: 99 126 - Allocs: 21 127 - Retain: 37 128 - 129 - Unifications: 82 130 - Conjuncts: 246 131 - Disjuncts: 139 132 - -- out/evalalpha -- 133 - (struct){ 134 - #TypeA: ((string|struct)){ |((string){ string }, (#struct){ 135 - foo: (int){ int } 136 - }) } 137 - #fun1: (#struct){ 138 - _in(:x): ((string|struct)){ |((string){ string }, (#struct){ 139 - foo: (int){ int } 140 - }) } 141 - out: (string){ "impossible" } 142 - } 143 - examples: (struct){ 144 - eg1: (struct){ 145 - in: (string){ "test" } 146 - res: (string){ "test" } 147 - } 148 - eg2: (struct){ 149 - in: (struct){ 150 - foo: (int){ 5 } 151 - } 152 - res: (string){ "foo" } 153 - } 154 - eg3: (struct){ 155 - in: (struct){ 156 - foo: (int){ 5 } 157 - bar: (string){ "test" } 158 - } 159 - res: (string){ "impossible" } 160 - } 161 - } 162 - }
+4 -20
cue/testdata/eval/lists.txtar
··· 1 - #todo:inline: medium — comprehension; may need @test(final) for incomplete fields 2 1 -- in.cue -- 3 2 a: [...int] 4 3 a: [1, 2, 3, 5] 5 - a: [1, 2, 3, d] 4 + a: [1, 2, 3, d] @test(eq, [1, 2, 3, 5]) 6 5 7 - b: a[3] 8 - d: 5 6 + b: a[3] @test(eq, 5) 7 + d: 5 @test(eq, 5) 9 8 10 - c: [for x in [[1, 2]][0] {x + d}] 9 + c: [for x in [[1, 2]][0] {x + d}] @test(eq, [6, 7]) 11 10 -- out/eval/stats -- 12 11 Leaks: 4 13 12 Freed: 11 ··· 18 17 Unifications: 15 19 18 Conjuncts: 29 20 19 Disjuncts: 13 21 - -- out/evalalpha -- 22 - (struct){ 23 - a: (#list){ 24 - 0: (int){ 1 } 25 - 1: (int){ 2 } 26 - 2: (int){ 3 } 27 - 3: (int){ 5 } 28 - } 29 - b: (int){ 5 } 30 - d: (int){ 5 } 31 - c: (#list){ 32 - 0: (int){ 6 } 33 - 1: (int){ 7 } 34 - } 35 - } 36 20 -- out/compile -- 37 21 --- in.cue 38 22 {
+6 -42
cue/testdata/eval/merge.txtar
··· 1 - TODO: image field is not pre-evaluated (not a huge deal) 2 - TODO: allow dynamic fields 3 - #todo:inline: medium — comprehension; may need @test(final) for incomplete fields 1 + # TODO: image field is not pre-evaluated (not a huge deal) 2 + # TODO: allow dynamic fields 4 3 -- in.cue -- 5 - key: "app01" 4 + key: "app01" @test(eq, "app01") 6 5 manifests: [ 7 6 { 8 7 deployment: #map: [string]: {name: string, image: string, desc: string} ··· 15 14 }, 16 15 ] 17 16 // unify 18 - results: _ 17 + results: _ @test(eq, {deployment: #map: { 18 + app01: {image: "image01", name: "app01", desc: string} 19 + }}) 19 20 for _, manifest in manifests { 20 21 results: manifest 21 22 } ··· 33 34 MisalignedConjunct: 9 34 35 35 36 NumCloseIDs: 1 36 - -- out/evalalpha -- 37 - (struct){ 38 - key: (string){ "app01" } 39 - manifests: (#list){ 40 - 0: (struct){ 41 - deployment: (struct){ 42 - #map: (#struct){ 43 - app01: (#struct){ 44 - name: (string){ "app01" } 45 - image: (string){ string } 46 - desc: (string){ string } 47 - } 48 - } 49 - } 50 - } 51 - 1: (struct){ 52 - deployment: (struct){ 53 - #map: (#struct){ 54 - app01: (#struct){ 55 - image: (string){ "image01" } 56 - } 57 - } 58 - } 59 - } 60 - } 61 - results: (struct){ 62 - deployment: (struct){ 63 - #map: (#struct){ 64 - app01: (#struct){ 65 - image: (string){ "image01" } 66 - name: (string){ "app01" } 67 - desc: (string){ string } 68 - } 69 - } 70 - } 71 - } 72 - } 73 37 -- out/compile -- 74 38 --- in.cue 75 39 {
+21 -3
cue/testdata/readme.md
··· 141 141 | `code=<c>` | error code must match (`cycle`, `eval`, `incomplete`, …) | 142 142 | `contains="s"` | error message must contain substring `s` | 143 143 | `any` | at least one *descendant* has the error (requires `code=`) | 144 - | `path=(p\|q)` | error exists at one of the listed paths | 144 + | `at=<path>` | navigate to sub-path before checking error (e.g. `at=a.b`) | 145 145 | `pos=[...]` | error positions must match (see below) | 146 146 | `args=[...]` | Msg() args must contain the listed values (see below) | 147 147 | `suberr=(...)` | sub-error spec for multi-error values (see below) | 148 148 149 + #### `at=<path>` — assert error at sub-path 150 + 151 + Navigates to the given CUE path (relative to the annotated field) before 152 + checking for the error. Useful when the error occurs in a nested field that 153 + cannot be directly annotated: 154 + 155 + ```cue 156 + outer: { 157 + inner: bad: string & int 158 + } @test(err, at=inner.bad, code=eval, contains="conflicting values") 159 + ``` 160 + 161 + The path must not include hidden fields (identifiers beginning with `_`); hidden 162 + fields cannot be accessed via `cue.ParsePath` and are silently skipped by the 163 + annotation infrastructure. 164 + 149 165 #### `pos=[...]` — error positions 150 166 151 167 Specifies expected error positions. Each position is written as `deltaLine:col` 152 168 relative to the `@test` attribute line, or `file:line:col` for positions in 153 - other files: 169 + other files. Positions are matched **order-independently** — the order of specs 170 + does not need to match the order of actual positions. Commas between specs are 171 + optional: 154 172 155 173 ```cue 156 - bad: x & y @test(err, code=eval, pos=[0:5 0:9]) 174 + bad: x & y @test(err, code=eval, pos=[0:5, 0:9]) 157 175 ``` 158 176 159 177 `pos=[]` is a fill-in placeholder. Running with `CUE_UPDATE=1` writes the