blob: fd88dd66c0a490bd0205d5d57f4c94fe77a2847a [file] [log] [blame]
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +02001// 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
15package validate
16
17import (
18 "fmt"
19 "strings"
20 "testing"
21
22 "cuelang.org/go/cue/errors"
23 "cuelang.org/go/cue/parser"
24 "cuelang.org/go/internal/core/adt"
25 "cuelang.org/go/internal/core/compile"
26 "cuelang.org/go/internal/core/eval"
27 "cuelang.org/go/internal/core/runtime"
28 "github.com/google/go-cmp/cmp"
29)
30
31func TestValidate(t *testing.T) {
32 testCases := []struct {
33 desc string
34 in string
35 out string
36 lookup string
37 cfg *Config
38 }{{
39 desc: "no error, but not concrete, even with definition label",
40 cfg: &Config{Concrete: true},
41 in: `
42 #foo: { use: string }
43 `,
44 lookup: "#foo",
Marcel van Lohuizen651d3792020-07-20 10:36:31 +020045 out: "incomplete\n#foo.use: incomplete value string",
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +020046 }, {
47 desc: "definitions not considered for completeness",
48 cfg: &Config{Concrete: true},
49 in: `
50 #foo: { use: string }
51 `,
52 }, {
53 desc: "hidden fields not considered for completeness",
54 cfg: &Config{Concrete: true},
55 in: `
56 _foo: { use: string }
57 `,
58 }, {
59 desc: "hidden fields not considered for completeness",
60 in: `
61 _foo: { use: string }
62 `,
63 }, {
64 desc: "evaluation error at top",
65 in: `
66 1 & 2
67 `,
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +020068 out: "eval\nconflicting values 2 and 1:\n test:2:3\n test:2:7",
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +020069 }, {
70 desc: "evaluation error in field",
71 in: `
72 x: 1 & 2
73 `,
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +020074 out: "eval\nx: conflicting values 2 and 1:\n test:2:6\n test:2:10",
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +020075 }, {
76 desc: "first error",
77 in: `
78 x: 1 & 2
79 y: 2 & 4
80 `,
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +020081 out: "eval\nx: conflicting values 2 and 1:\n test:2:6\n test:2:10",
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +020082 }, {
83 desc: "all errors",
84 cfg: &Config{AllErrors: true},
85 in: `
86 x: 1 & 2
87 y: 2 & 4
88 `,
89 out: `eval
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +020090x: conflicting values 2 and 1:
91 test:2:6
92 test:2:10
93y: conflicting values 4 and 2:
94 test:3:6
95 test:3:10`,
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +020096 }, {
97 desc: "incomplete",
98 cfg: &Config{Concrete: true},
99 in: `
100 y: 2 + x
101 x: string
102 `,
Marcel van Lohuizen651d3792020-07-20 10:36:31 +0200103 out: "incomplete\ny: non-concrete value string in operand to +:\n test:2:6",
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +0200104 }, {
105 desc: "allowed incomplete cycle",
106 in: `
107 y: x
108 x: y
109 `,
110 }, {
111 desc: "allowed incomplete when disallowing cycles",
112 cfg: &Config{DisallowCycles: true},
113 in: `
114 y: string
115 x: y
116 `,
117 }, {
118 desc: "disallow cycle",
119 cfg: &Config{DisallowCycles: true},
120 in: `
121 y: x + 1
122 x: y - 1
123 `,
124 out: "cycle\ncycle error",
125 }, {
126 desc: "disallow cycle",
127 cfg: &Config{DisallowCycles: true},
128 in: `
129 a: b - 100
130 b: a + 100
131 c: [c[1], c[0]] `,
132 out: "cycle\ncycle error",
133 }, {
134 desc: "treat cycles as incomplete when not disallowing",
135 cfg: &Config{},
136 in: `
137 y: x + 1
138 x: y - 1
139 `,
140 }, {
141 // Note: this is already handled by evaluation, as terminal errors
142 // are percolated up.
143 desc: "catch most serious error",
144 cfg: &Config{Concrete: true},
145 in: `
146 y: string
147 x: 1 & 2
148 `,
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200149 out: "eval\nx: conflicting values 2 and 1:\n test:3:6\n test:3:10",
Marcel van Lohuizen765f87e2020-07-20 18:40:16 +0200150 }, {
151 desc: "consider defaults for concreteness",
152 cfg: &Config{Concrete: true},
153 in: `
154 x: *1 | 2
155 `,
Marcel van Lohuizen489eb902020-07-25 13:49:07 +0200156 }, {
157 desc: "allow non-concrete in definitions in concrete mode",
158 cfg: &Config{Concrete: true},
159 in: `
160 x: 2
161 #d: {
162 b: int
163 c: b + b
164 }
165 `,
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +0200166 }}
167
168 r := runtime.New()
169 ctx := eval.NewContext(r, nil)
170
171 for _, tc := range testCases {
172 t.Run(tc.desc, func(t *testing.T) {
173 f, err := parser.ParseFile("test", tc.in)
174 if err != nil {
175 t.Fatal(err)
176 }
Marcel van Lohuizenb4aa96d2020-10-04 18:09:37 +0200177 v, err := compile.Files(nil, r, "", f)
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +0200178 if err != nil {
179 t.Fatal(err)
180 }
181 ctx.Unify(ctx, v, adt.Finalized)
182 if tc.lookup != "" {
Marcel van Lohuizenb4aa96d2020-10-04 18:09:37 +0200183 v = v.Lookup(adt.MakeIdentLabel(r, tc.lookup, "main"))
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +0200184 }
185
Marcel van Lohuizen651d3792020-07-20 10:36:31 +0200186 b := Validate(ctx, v, tc.cfg)
Marcel van Lohuizen38a19f82020-06-27 13:06:51 +0200187
188 w := &strings.Builder{}
189 if b != nil {
190 fmt.Fprintln(w, b.Code)
191 errors.Print(w, b.Err, nil)
192 }
193
194 got := strings.TrimSpace(w.String())
195 if tc.out != got {
196 t.Error(cmp.Diff(tc.out, got))
197 }
198 })
199 }
200}