1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package load
16
17 import (
18 "bytes"
19 "os"
20 "path/filepath"
21 "strings"
22 "sync"
23 "testing"
24 "text/template"
25 "unicode"
26
27 "cuelang.org/go/cue"
28 "cuelang.org/go/cue/errors"
29 "cuelang.org/go/cue/format"
30 "cuelang.org/go/internal/cueexperiment"
31 "cuelang.org/go/internal/tdtest"
32 )
33
34 func init() {
35
36
37
38 os.Setenv("CUE_EXPERIMENT", "")
39
40
41
42 cueexperiment.Init()
43
44
45
46
47
48
49 os.Setenv("CUE_REGISTRY", "inline:{")
50 }
51
52
53 func TestLoad(t *testing.T) {
54 cwd, err := os.Getwd()
55 if err != nil {
56 t.Fatal(err)
57 }
58 testdataDir := testdata("testmod")
59 dirCfg := &Config{
60 Dir: testdataDir,
61 Tools: true,
62 }
63 badModCfg := &Config{
64 Dir: testdata("badmod"),
65 }
66 type loadTest struct {
67 cfg *Config
68 args []string
69 want string
70 }
71
72 testCases := []loadTest{{
73 cfg: badModCfg,
74 args: []string{"."},
75 want: `err: module: cannot use value 123 (type int) as string:
76 $CWD/testdata/badmod/cue.mod/module.cue:2:9
77 path: ""
78 module: ""
79 root: ""
80 dir: ""
81 display:""`,
82 }, {
83
84
85
86 cfg: dirCfg,
87 args: nil,
88 want: `path: mod.test/test
89 module: mod.test/test
90 root: $CWD/testdata/testmod
91 dir: $CWD/testdata/testmod
92 display:.
93 files:
94 $CWD/testdata/testmod/test.cue
95 imports:
96 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, {
97
98
99
100 cfg: dirCfg,
101 args: []string{"."},
102 want: `path: mod.test/test
103 module: mod.test/test
104 root: $CWD/testdata/testmod
105 dir: $CWD/testdata/testmod
106 display:.
107 files:
108 $CWD/testdata/testmod/test.cue
109 imports:
110 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, {
111
112
113 cfg: dirCfg,
114 args: []string{"./other/..."},
115 want: `err: import failed: relative import paths not allowed ("./file"):
116 $CWD/testdata/testmod/other/main.cue:6:2
117 path: ""
118 module: mod.test/test
119 root: $CWD/testdata/testmod
120 dir: ""
121 display:""`}, {
122 cfg: dirCfg,
123 args: []string{"./anon"},
124 want: `err: build constraints exclude all CUE files in ./anon:
125 anon/anon.cue: no package name
126 path: mod.test/test/anon
127 module: mod.test/test
128 root: $CWD/testdata/testmod
129 dir: $CWD/testdata/testmod/anon
130 display:./anon`}, {
131
132
133 cfg: dirCfg,
134 args: []string{"./other"},
135 want: `err: import failed: relative import paths not allowed ("./file"):
136 $CWD/testdata/testmod/other/main.cue:6:2
137 path: mod.test/test/other:main
138 module: mod.test/test
139 root: $CWD/testdata/testmod
140 dir: $CWD/testdata/testmod/other
141 display:./other
142 files:
143 $CWD/testdata/testmod/other/main.cue`}, {
144
145
146 cfg: dirCfg,
147 args: []string{"./hello"},
148 want: `path: mod.test/test/hello:test
149 module: mod.test/test
150 root: $CWD/testdata/testmod
151 dir: $CWD/testdata/testmod/hello
152 display:./hello
153 files:
154 $CWD/testdata/testmod/test.cue
155 $CWD/testdata/testmod/hello/test.cue
156 imports:
157 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, {
158
159
160 cfg: dirCfg,
161 args: []string{"mod.test/test/hello:test"},
162 want: `path: mod.test/test/hello:test
163 module: mod.test/test
164 root: $CWD/testdata/testmod
165 dir: $CWD/testdata/testmod/hello
166 display:mod.test/test/hello:test
167 files:
168 $CWD/testdata/testmod/test.cue
169 $CWD/testdata/testmod/hello/test.cue
170 imports:
171 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, {
172
173
174 cfg: dirCfg,
175 args: []string{"mod.test/test/hello:nonexist"},
176 want: `err: build constraints exclude all CUE files in mod.test/test/hello:nonexist:
177 anon.cue: no package name
178 test.cue: package is test, want nonexist
179 hello/test.cue: package is test, want nonexist
180 path: mod.test/test/hello:nonexist
181 module: mod.test/test
182 root: $CWD/testdata/testmod
183 dir: $CWD/testdata/testmod/hello
184 display:mod.test/test/hello:nonexist`}, {
185 cfg: dirCfg,
186 args: []string{"./anon.cue", "./other/anon.cue"},
187 want: `path: ""
188 module: ""
189 root: $CWD/testdata/testmod
190 dir: $CWD/testdata/testmod
191 display:command-line-arguments
192 files:
193 $CWD/testdata/testmod/anon.cue
194 $CWD/testdata/testmod/other/anon.cue`}, {
195 cfg: dirCfg,
196
197 args: []string{filepath.Join(cwd, testdata("testmod", "anon.cue"))},
198 want: `path: ""
199 module: ""
200 root: $CWD/testdata/testmod
201 dir: $CWD/testdata/testmod
202 display:command-line-arguments
203 files:
204 $CWD/testdata/testmod/anon.cue`}, {
205 cfg: dirCfg,
206 args: []string{"-"},
207 want: `path: ""
208 module: ""
209 root: $CWD/testdata/testmod
210 dir: $CWD/testdata/testmod
211 display:command-line-arguments
212 files:
213 -`}, {
214
215 cfg: dirCfg,
216 args: []string{"non-existing"},
217 want: `err: implied package identifier "non-existing" from import path "non-existing" is not valid
218 path: non-existing
219 module: mod.test/test
220 root: $CWD/testdata/testmod
221 dir: $CWD/testdata/testmod/cue.mod/gen/non-existing
222 display:non-existing`,
223 }, {
224 cfg: dirCfg,
225 args: []string{"./empty"},
226 want: `err: no CUE files in ./empty
227 path: mod.test/test/empty
228 module: mod.test/test
229 root: $CWD/testdata/testmod
230 dir: $CWD/testdata/testmod/empty
231 display:./empty`,
232 }, {
233 cfg: dirCfg,
234 args: []string{"./imports"},
235 want: `path: mod.test/test/imports
236 module: mod.test/test
237 root: $CWD/testdata/testmod
238 dir: $CWD/testdata/testmod/imports
239 display:./imports
240 files:
241 $CWD/testdata/testmod/imports/imports.cue
242 imports:
243 mod.test/catch: $CWD/testdata/testmod/cue.mod/pkg/mod.test/catch/catch.cue
244 mod.test/helper:helper1: $CWD/testdata/testmod/cue.mod/pkg/mod.test/helper/helper1.cue`}, {
245 cfg: dirCfg,
246 args: []string{"./toolonly"},
247 want: `path: mod.test/test/toolonly:foo
248 module: mod.test/test
249 root: $CWD/testdata/testmod
250 dir: $CWD/testdata/testmod/toolonly
251 display:./toolonly
252 files:
253 $CWD/testdata/testmod/toolonly/foo_tool.cue`}, {
254 cfg: &Config{
255 Dir: testdataDir,
256 },
257 args: []string{"./toolonly"},
258 want: `err: build constraints exclude all CUE files in ./toolonly:
259 anon.cue: no package name
260 test.cue: package is test, want foo
261 toolonly/foo_tool.cue: _tool.cue files excluded in non-cmd mode
262 path: mod.test/test/toolonly:foo
263 module: mod.test/test
264 root: $CWD/testdata/testmod
265 dir: $CWD/testdata/testmod/toolonly
266 display:./toolonly`}, {
267 cfg: &Config{
268 Dir: testdataDir,
269 Tags: []string{"prod"},
270 },
271 args: []string{"./tags"},
272 want: `path: mod.test/test/tags
273 module: mod.test/test
274 root: $CWD/testdata/testmod
275 dir: $CWD/testdata/testmod/tags
276 display:./tags
277 files:
278 $CWD/testdata/testmod/tags/prod.cue`}, {
279 cfg: &Config{
280 Dir: testdataDir,
281 Tags: []string{"prod", "foo=bar"},
282 },
283 args: []string{"./tags"},
284 want: `path: mod.test/test/tags
285 module: mod.test/test
286 root: $CWD/testdata/testmod
287 dir: $CWD/testdata/testmod/tags
288 display:./tags
289 files:
290 $CWD/testdata/testmod/tags/prod.cue`}, {
291 cfg: &Config{
292 Dir: testdataDir,
293 Tags: []string{"prod"},
294 },
295 args: []string{"./tagsbad"},
296 want: `err: tag "prod" not used in any file
297 previous declaration here:
298 $CWD/testdata/testmod/tagsbad/prod.cue:1:1
299 multiple @if attributes:
300 $CWD/testdata/testmod/tagsbad/prod.cue:2:1
301 path: mod.test/test/tagsbad
302 module: mod.test/test
303 root: $CWD/testdata/testmod
304 dir: $CWD/testdata/testmod/tagsbad
305 display:./tagsbad`}, {
306 cfg: &Config{
307 Dir: testdataDir,
308 },
309 args: []string{"./cycle"},
310 want: `err: import failed: import failed: import failed: package import cycle not allowed:
311 $CWD/testdata/testmod/cycle/cycle.cue:3:8
312 $CWD/testdata/testmod/cue.mod/pkg/mod.test/cycle/bar/bar.cue:3:8
313 $CWD/testdata/testmod/cue.mod/pkg/mod.test/cycle/foo/foo.cue:3:8
314 path: mod.test/test/cycle
315 module: mod.test/test
316 root: $CWD/testdata/testmod
317 dir: $CWD/testdata/testmod/cycle
318 display:./cycle
319 files:
320 $CWD/testdata/testmod/cycle/cycle.cue`}}
321 tdtest.Run(t, testCases, func(t *tdtest.T, tc *loadTest) {
322 pkgs := Instances(tc.args, tc.cfg)
323
324 buf := &bytes.Buffer{}
325 err := pkgInfo.Execute(buf, pkgs)
326 if err != nil {
327 t.Fatal(err)
328 }
329
330 got := strings.TrimSpace(buf.String())
331 got = strings.Replace(got, cwd, "$CWD", -1)
332
333
334 got = strings.Replace(got, filepath.ToSlash(cwd), "$CWD", -1)
335
336 got = strings.Replace(got, string(filepath.Separator), "/", -1)
337
338 t.Equal(got, tc.want)
339 })
340 }
341
342 var pkgInfo = template.Must(template.New("pkg").Funcs(template.FuncMap{
343 "errordetails": func(err error) string {
344 s := errors.Details(err, &errors.Config{
345 ToSlash: true,
346 })
347 s = strings.TrimSuffix(s, "\n")
348 return s
349 }}).Parse(`
350 {{- range . -}}
351 {{- if .Err}}err: {{errordetails .Err}}{{end}}
352 path: {{if .ImportPath}}{{.ImportPath}}{{else}}""{{end}}
353 module: {{with .Module}}{{.}}{{else}}""{{end}}
354 root: {{with .Root}}{{.}}{{else}}""{{end}}
355 dir: {{with .Dir}}{{.}}{{else}}""{{end}}
356 display:{{with .DisplayPath}}{{.}}{{else}}""{{end}}
357 {{if .Files -}}
358 files:
359 {{- range .Files}}
360 {{.Filename}}
361 {{- end -}}
362 {{- end}}
363 {{if .Imports -}}
364 imports:
365 {{- range .Dependencies}}
366 {{.ImportPath}}:{{range .Files}} {{.Filename}}{{end}}
367 {{- end}}
368 {{end -}}
369 {{- end -}}
370 `))
371
372 func TestOverlays(t *testing.T) {
373 cwd, _ := os.Getwd()
374 abs := func(path string) string {
375 return filepath.Join(cwd, path)
376 }
377 c := &Config{
378 Overlay: map[string]Source{
379
380 abs("cue.mod"): FromString(`module: "mod.test"`),
381
382 abs("dir/top.cue"): FromBytes([]byte(`
383 package top
384 msg: "Hello"
385 `)),
386 abs("dir/b/foo.cue"): FromString(`
387 package foo
388
389 a: <= 5
390 `),
391 abs("dir/b/bar.cue"): FromString(`
392 package foo
393
394 a: >= 5
395 `),
396 },
397 }
398 want := []string{
399 `{msg:"Hello"}`,
400 `{a:5}`,
401 }
402 rmSpace := func(r rune) rune {
403 if unicode.IsSpace(r) {
404 return -1
405 }
406 return r
407 }
408 for i, inst := range cue.Build(Instances([]string{"./dir/..."}, c)) {
409 if inst.Err != nil {
410 t.Error(inst.Err)
411 continue
412 }
413 b, err := format.Node(inst.Value().Syntax(cue.Final()))
414 if err != nil {
415 t.Error(err)
416 continue
417 }
418 if got := string(bytes.Map(rmSpace, b)); got != want[i] {
419 t.Errorf("%s: got %s; want %s", inst.Dir, got, want[i])
420 }
421 }
422 }
423
424 func TestLoadInstancesConcurrent(t *testing.T) {
425
426
427
428 race(func() {
429 Instances([]string{"."}, nil)
430 })
431 }
432
433 func race(f func()) {
434 var wg sync.WaitGroup
435 for i := 0; i < 2; i++ {
436 wg.Add(1)
437 go func() {
438 f()
439 wg.Done()
440 }()
441 }
442 wg.Wait()
443 }
444
View as plain text