cuelang.org/go@v0.13.0/cue/load/loader_test.go (about) 1 // Copyright 2018 The 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 load 16 17 import ( 18 "bytes" 19 "fmt" 20 "os" 21 "path/filepath" 22 "strings" 23 "sync" 24 "testing" 25 "text/template" 26 "unicode" 27 28 "github.com/go-quicktest/qt" 29 30 "cuelang.org/go/cue" 31 "cuelang.org/go/cue/cuecontext" 32 "cuelang.org/go/cue/errors" 33 "cuelang.org/go/cue/format" 34 "cuelang.org/go/internal/tdtest" 35 ) 36 37 func init() { 38 // The user running `go test` might have a broken environment, 39 // such as an invalid $CUE_REGISTRY like the one below, 40 // or a broken $DOCKER_CONFIG/config.json due to syntax errors. 41 // Go tests should be hermetic by explicitly setting load.Config.Env; 42 // catch any that do not by leaving a broken $CUE_REGISTRY in os.Environ. 43 os.Setenv("CUE_REGISTRY", "inline:{") 44 } 45 46 // TestLoad is an end-to-end test. 47 func TestLoad(t *testing.T) { 48 cwd, err := os.Getwd() 49 if err != nil { 50 t.Fatal(err) 51 } 52 testdataDir := testdata("testmod") 53 dirCfg := &Config{ 54 Dir: testdataDir, 55 Tools: true, 56 } 57 badModCfg := &Config{ 58 Dir: testdata("badmod"), 59 } 60 type loadTest struct { 61 name string 62 cfg *Config 63 args []string 64 want string 65 } 66 67 testCases := []loadTest{{ 68 name: "BadModuleFile", 69 cfg: badModCfg, 70 args: []string{"."}, 71 want: `err: module: 2 errors in empty disjunction: 72 module: conflicting values 123 and "" (mismatched types int and string): 73 $CWD/testdata/badmod/cue.mod/module.cue:2:9 74 cuelang.org/go/mod/modfile/schema.cue:56:22 75 module: conflicting values 123 and string (mismatched types int and string): 76 $CWD/testdata/badmod/cue.mod/module.cue:2:9 77 cuelang.org/go/mod/modfile/schema.cue:98:12 78 path: "" 79 module: "" 80 root: "" 81 dir: "" 82 display:""`, 83 }, { 84 name: "DefaultPackage", 85 // Even though the directory is called testdata, the last path in 86 // the module is test. So "package test" is correctly the default 87 // package of this directory. 88 cfg: dirCfg, 89 args: nil, 90 want: `path: mod.test/test@v0 91 module: mod.test/test@v0 92 root: $CWD/testdata/testmod 93 dir: $CWD/testdata/testmod 94 display:. 95 files: 96 $CWD/testdata/testmod/test.cue 97 imports: 98 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 99 name: "DefaultPackageWithExplicitDotArgument", 100 // Even though the directory is called testdata, the last path in 101 // the module is test. So "package test" is correctly the default 102 // package of this directory. 103 cfg: dirCfg, 104 args: []string{"."}, 105 want: `path: mod.test/test@v0 106 module: mod.test/test@v0 107 root: $CWD/testdata/testmod 108 dir: $CWD/testdata/testmod 109 display:. 110 files: 111 $CWD/testdata/testmod/test.cue 112 imports: 113 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 114 name: "RelativeImportPathWildcard", 115 cfg: dirCfg, 116 args: []string{"./other/..."}, 117 want: `err: import failed: relative import paths not allowed ("./file"): 118 $CWD/testdata/testmod/other/main.cue:6:2 119 path: "" 120 module: mod.test/test@v0 121 root: $CWD/testdata/testmod 122 dir: "" 123 display:""`}, { 124 name: "NoMatchingPackageName", 125 cfg: dirCfg, 126 args: []string{"./anon"}, 127 want: `err: build constraints exclude all CUE files in ./anon: 128 anon/anon.cue: no package name 129 path: mod.test/test/anon@v0 130 module: mod.test/test@v0 131 root: $CWD/testdata/testmod 132 dir: $CWD/testdata/testmod/anon 133 display:./anon`}, { 134 name: "RelativeImportPathSingle", 135 cfg: dirCfg, 136 args: []string{"./other"}, 137 want: `err: import failed: relative import paths not allowed ("./file"): 138 $CWD/testdata/testmod/other/main.cue:6:2 139 path: mod.test/test/other@v0:main 140 module: mod.test/test@v0 141 root: $CWD/testdata/testmod 142 dir: $CWD/testdata/testmod/other 143 display:./other 144 files: 145 $CWD/testdata/testmod/other/main.cue`}, { 146 name: "RelativePathSuccess", 147 cfg: dirCfg, 148 args: []string{"./hello"}, 149 want: `path: mod.test/test/hello@v0:test 150 module: mod.test/test@v0 151 root: $CWD/testdata/testmod 152 dir: $CWD/testdata/testmod/hello 153 display:./hello 154 files: 155 $CWD/testdata/testmod/test.cue 156 $CWD/testdata/testmod/hello/test.cue 157 imports: 158 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 159 name: "ExplicitPackageIdentifier", 160 cfg: dirCfg, 161 args: []string{"mod.test/test/hello:test"}, 162 want: `path: mod.test/test/hello:test 163 module: mod.test/test@v0 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 name: "NoPackageName", 173 cfg: dirCfg, 174 args: []string{"mod.test/test/hello:nonexist"}, 175 want: `err: cannot find package "mod.test/test/hello": no files in package directory with package name "nonexist" 176 path: mod.test/test/hello:nonexist 177 module: "" 178 root: $CWD/testdata/testmod 179 dir: "" 180 display:mod.test/test/hello:nonexist`, 181 }, { 182 name: "ExplicitNonPackageFiles", 183 cfg: dirCfg, 184 args: []string{"./anon.cue", "./other/anon.cue"}, 185 want: `path: "" 186 module: "" 187 root: $CWD/testdata/testmod 188 dir: $CWD/testdata/testmod 189 display:command-line-arguments 190 files: 191 $CWD/testdata/testmod/anon.cue 192 $CWD/testdata/testmod/other/anon.cue`, 193 }, { 194 name: "AbsoluteFileIsNormalized", // TODO(rogpeppe) what is this actually testing? 195 cfg: dirCfg, 196 // Absolute file is normalized. 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 name: "StandardInput", 206 cfg: dirCfg, 207 args: []string{"-"}, 208 want: `path: "" 209 module: "" 210 root: $CWD/testdata/testmod 211 dir: $CWD/testdata/testmod 212 display:command-line-arguments 213 files: 214 -`}, { 215 name: "BadIdentifier", 216 cfg: dirCfg, 217 args: []string{"foo.com/bad-identifier"}, 218 want: `err: cannot determine package name for "foo.com/bad-identifier"; set it explicitly with ':' 219 cannot find package "foo.com/bad-identifier": cannot find module providing package foo.com/bad-identifier 220 path: foo.com/bad-identifier 221 module: "" 222 root: $CWD/testdata/testmod 223 dir: "" 224 display:foo.com/bad-identifier`, 225 }, { 226 name: "NonexistentStdlibImport", 227 cfg: dirCfg, 228 args: []string{"nonexisting"}, 229 want: `err: standard library import path "nonexisting" cannot be imported as a CUE package 230 path: nonexisting 231 module: "" 232 root: $CWD/testdata/testmod 233 dir: "" 234 display:nonexisting`, 235 }, { 236 name: "ExistingStdlibImport", 237 cfg: dirCfg, 238 args: []string{"strconv"}, 239 want: `err: standard library import path "strconv" cannot be imported as a CUE package 240 path: strconv 241 module: "" 242 root: $CWD/testdata/testmod 243 dir: "" 244 display:strconv`, 245 }, { 246 name: "EmptyPackageDirectory", 247 cfg: dirCfg, 248 args: []string{"./empty"}, 249 want: `err: no CUE files in ./empty 250 path: mod.test/test/empty@v0 251 module: mod.test/test@v0 252 root: $CWD/testdata/testmod 253 dir: $CWD/testdata/testmod/empty 254 display:./empty`, 255 }, { 256 name: "PackageWithImports", 257 cfg: dirCfg, 258 args: []string{"./imports"}, 259 want: `path: mod.test/test/imports@v0 260 module: mod.test/test@v0 261 root: $CWD/testdata/testmod 262 dir: $CWD/testdata/testmod/imports 263 display:./imports 264 files: 265 $CWD/testdata/testmod/imports/imports.cue 266 imports: 267 mod.test/catch: $CWD/testdata/testmod/cue.mod/pkg/mod.test/catch/catch.cue 268 mod.test/helper:helper1: $CWD/testdata/testmod/cue.mod/pkg/mod.test/helper/helper1.cue`}, { 269 name: "PackageWithImportsWithSkipImportsConfig", 270 cfg: &Config{ 271 Dir: testdataDir, 272 Tools: true, 273 SkipImports: true, 274 }, 275 args: []string{"./imports"}, 276 want: `path: mod.test/test/imports@v0 277 module: mod.test/test@v0 278 root: $CWD/testdata/testmod 279 dir: $CWD/testdata/testmod/imports 280 display:./imports 281 files: 282 $CWD/testdata/testmod/imports/imports.cue`}, { 283 name: "OnlyToolFiles", 284 cfg: dirCfg, 285 args: []string{"./toolonly"}, 286 want: `path: mod.test/test/toolonly@v0:foo 287 module: mod.test/test@v0 288 root: $CWD/testdata/testmod 289 dir: $CWD/testdata/testmod/toolonly 290 display:./toolonly 291 files: 292 $CWD/testdata/testmod/toolonly/foo_tool.cue`}, { 293 name: "OnlyToolFilesWithToolsDisabledInConfig", 294 cfg: &Config{ 295 Dir: testdataDir, 296 }, 297 args: []string{"./toolonly"}, 298 want: `err: build constraints exclude all CUE files in ./toolonly: 299 test.cue: package is test, want foo 300 toolonly/foo_tool.cue: _tool.cue files excluded in non-cmd mode 301 path: mod.test/test/toolonly@v0:foo 302 module: mod.test/test@v0 303 root: $CWD/testdata/testmod 304 dir: $CWD/testdata/testmod/toolonly 305 display:./toolonly`}, { 306 name: "WithBoolTag", 307 cfg: &Config{ 308 Dir: testdataDir, 309 Tags: []string{"prod"}, 310 }, 311 args: []string{"./tags"}, 312 want: `path: mod.test/test/tags@v0 313 module: mod.test/test@v0 314 root: $CWD/testdata/testmod 315 dir: $CWD/testdata/testmod/tags 316 display:./tags 317 files: 318 $CWD/testdata/testmod/tags/prod.cue`}, { 319 name: "WithAttrValTag", 320 cfg: &Config{ 321 Dir: testdataDir, 322 Tags: []string{"prod", "foo=bar"}, 323 }, 324 args: []string{"./tags"}, 325 want: `path: mod.test/test/tags@v0 326 module: mod.test/test@v0 327 root: $CWD/testdata/testmod 328 dir: $CWD/testdata/testmod/tags 329 display:./tags 330 files: 331 $CWD/testdata/testmod/tags/prod.cue`}, { 332 name: "UnusedTag", 333 cfg: &Config{ 334 Dir: testdataDir, 335 Tags: []string{"prod"}, 336 }, 337 args: []string{"./tagsbad"}, 338 want: `err: tag "prod" not used in any file 339 previous declaration here: 340 $CWD/testdata/testmod/tagsbad/prod.cue:1:1 341 multiple @if attributes: 342 $CWD/testdata/testmod/tagsbad/prod.cue:2:1 343 path: mod.test/test/tagsbad@v0 344 module: mod.test/test@v0 345 root: $CWD/testdata/testmod 346 dir: $CWD/testdata/testmod/tagsbad 347 display:./tagsbad`}, { 348 name: "ImportCycle", 349 cfg: &Config{ 350 Dir: testdataDir, 351 }, 352 args: []string{"./cycle"}, 353 want: `err: import failed: import failed: import failed: package import cycle not allowed: 354 $CWD/testdata/testmod/cycle/cycle.cue:3:8 355 $CWD/testdata/testmod/cue.mod/pkg/mod.test/cycle/bar/bar.cue:3:8 356 $CWD/testdata/testmod/cue.mod/pkg/mod.test/cycle/foo/foo.cue:3:8 357 path: mod.test/test/cycle@v0 358 module: mod.test/test@v0 359 root: $CWD/testdata/testmod 360 dir: $CWD/testdata/testmod/cycle 361 display:./cycle 362 files: 363 $CWD/testdata/testmod/cycle/cycle.cue`}, { 364 name: "AcceptLegacyModuleWithLegacyModule", 365 cfg: &Config{ 366 Dir: testdata("testmod_legacy"), 367 AcceptLegacyModules: true, 368 }, 369 want: `path: test.example/foo@v0 370 module: test.example/foo@v0 371 root: $CWD/testdata/testmod_legacy 372 dir: $CWD/testdata/testmod_legacy 373 display:. 374 files: 375 $CWD/testdata/testmod_legacy/foo.cue`}, { 376 name: "AcceptLegacyModuleWithNonLegacyModule", 377 cfg: &Config{ 378 Dir: testdataDir, 379 Tools: true, 380 AcceptLegacyModules: true, 381 }, 382 args: []string{"./imports"}, 383 want: `path: mod.test/test/imports@v0 384 module: mod.test/test@v0 385 root: $CWD/testdata/testmod 386 dir: $CWD/testdata/testmod/imports 387 display:./imports 388 files: 389 $CWD/testdata/testmod/imports/imports.cue 390 imports: 391 mod.test/catch: $CWD/testdata/testmod/cue.mod/pkg/mod.test/catch/catch.cue 392 mod.test/helper:helper1: $CWD/testdata/testmod/cue.mod/pkg/mod.test/helper/helper1.cue`}, { 393 name: "MismatchedModulePathInConfig", 394 cfg: &Config{ 395 Dir: testdataDir, 396 Tools: true, 397 Module: "wrong.test@v0", 398 }, 399 args: []string{"./imports"}, 400 want: `err: inconsistent modules: got "mod.test/test@v0", want "wrong.test@v0" 401 path: "" 402 module: wrong.test@v0 403 root: "" 404 dir: "" 405 display:""`}, { 406 name: "ModulePathInConfigWithoutMajorVersion", 407 cfg: &Config{ 408 Dir: testdataDir, 409 Tools: true, 410 Module: "mod.test/test", 411 }, 412 args: []string{"./imports"}, 413 want: `err: inconsistent modules: got "mod.test/test@v0", want "mod.test/test" 414 path: "" 415 module: mod.test/test 416 root: "" 417 dir: "" 418 display:""`}, { 419 name: "ModulePathInConfigWithoutMajorVersionAndMismatchedPath", 420 cfg: &Config{ 421 Dir: testdataDir, 422 Tools: true, 423 Module: "mod.test/wrong", 424 }, 425 args: []string{"./imports"}, 426 want: `err: inconsistent modules: got "mod.test/test@v0", want "mod.test/wrong" 427 path: "" 428 module: mod.test/wrong 429 root: "" 430 dir: "" 431 display:""`}, { 432 name: "ExplicitPackageWithUnqualifiedImportPath#1", 433 cfg: &Config{ 434 Dir: filepath.Join(testdataDir, "multi"), 435 Package: "main", 436 }, 437 args: []string{"."}, 438 want: `path: mod.test/test/multi@v0:main 439 module: mod.test/test@v0 440 root: $CWD/testdata/testmod 441 dir: $CWD/testdata/testmod/multi 442 display:. 443 files: 444 $CWD/testdata/testmod/multi/file.cue`}, { 445 name: "ExplicitPackageWithUnqualifiedImportPath#2", 446 // This test replicates the failure reported in https://cuelang.org/issue/3213 447 cfg: &Config{ 448 Dir: filepath.Join(testdataDir, "multi2"), 449 Package: "other", 450 }, 451 args: []string{"."}, 452 want: `path: mod.test/test/multi2@v0:other 453 module: mod.test/test@v0 454 root: $CWD/testdata/testmod 455 dir: $CWD/testdata/testmod/multi2 456 display:. 457 files: 458 $CWD/testdata/testmod/multi2/other.cue 459 imports: 460 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 461 name: "ExplicitPackageWithUnqualifiedImportPath#3", 462 cfg: &Config{ 463 Dir: filepath.Join(testdataDir, "multi3"), 464 Package: "other", 465 }, 466 args: []string{"."}, 467 want: `path: mod.test/test/multi3@v0:other 468 module: mod.test/test@v0 469 root: $CWD/testdata/testmod 470 dir: $CWD/testdata/testmod/multi3 471 display:. 472 files: 473 $CWD/testdata/testmod/multi3/other.cue 474 imports: 475 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 476 // Test that we can explicitly ask for non-package 477 // CUE files by setting Config.Package to "_". 478 name: "ExplicitPackageWithUnqualifiedImportPath#4", 479 cfg: &Config{ 480 Dir: filepath.Join(testdataDir, "multi4"), 481 Package: "_", 482 }, 483 args: []string{"."}, 484 want: `path: mod.test/test/multi4@v0:_ 485 module: mod.test/test@v0 486 root: $CWD/testdata/testmod 487 dir: $CWD/testdata/testmod/multi4 488 display:. 489 files: 490 $CWD/testdata/testmod/multi4/nopackage1.cue 491 $CWD/testdata/testmod/multi4/nopackage2.cue`}, { 492 // Test what happens when there's a single CUE file 493 // with an explicit `package _` directive. 494 name: "ExplicitPackageWithUnqualifiedImportPath#5", 495 cfg: &Config{ 496 Dir: filepath.Join(testdataDir, "multi5"), 497 Package: "_", 498 }, 499 args: []string{"."}, 500 want: `path: mod.test/test/multi5@v0:_ 501 module: mod.test/test@v0 502 root: $CWD/testdata/testmod 503 dir: $CWD/testdata/testmod/multi5 504 display:. 505 files: 506 $CWD/testdata/testmod/multi5/nopackage.cue`}, { 507 // Check that imports are only considered from files 508 // that match the build paths. 509 name: "BuildTagsWithImports#1", 510 cfg: &Config{ 511 Dir: filepath.Join(testdataDir, "tagswithimports"), 512 Tags: []string{"prod"}, 513 }, 514 args: []string{"."}, 515 want: `path: mod.test/test/tagswithimports@v0 516 module: mod.test/test@v0 517 root: $CWD/testdata/testmod 518 dir: $CWD/testdata/testmod/tagswithimports 519 display:. 520 files: 521 $CWD/testdata/testmod/tagswithimports/prod.cue 522 imports: 523 mod.test/test/hello:test: $CWD/testdata/testmod/test.cue $CWD/testdata/testmod/hello/test.cue 524 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 525 // Check that imports are only considered from files 526 // that match the build paths. When we don't have the prod 527 // tag, the bad import path mentioned in testdata/testmod/tagswithimports/nonprod.cue 528 // surfaces in the errors. 529 name: "BuildTagsWithImports#2", 530 cfg: &Config{ 531 Dir: filepath.Join(testdataDir, "tagswithimports"), 532 }, 533 args: []string{"."}, 534 want: `err: mod.test/test/tagswithimports@v0: import failed: cannot find package "bad-import.example/foo": cannot find module providing package bad-import.example/foo: 535 $CWD/testdata/testmod/tagswithimports/nonprod.cue:5:8 536 path: mod.test/test/tagswithimports@v0 537 module: mod.test/test@v0 538 root: $CWD/testdata/testmod 539 dir: $CWD/testdata/testmod/tagswithimports 540 display:. 541 files: 542 $CWD/testdata/testmod/tagswithimports/nonprod.cue`}, { 543 name: "ModuleFileNonDirectory", 544 cfg: &Config{ 545 Dir: testdata("testmod_legacymodfile"), 546 }, 547 args: []string{"."}, 548 want: `err: cue.mod files are no longer supported; use cue.mod/module.cue 549 path: "" 550 module: "" 551 root: "" 552 dir: "" 553 display:""`}, { 554 // This test checks that files in parent directories 555 // do not result in irrelevant instances appearing 556 // in the result of Instances. 557 name: "Issue3306", 558 cfg: &Config{ 559 Dir: testdataDir, 560 Package: "*", 561 SkipImports: true, 562 }, 563 args: []string{"./issue3306/..."}, 564 want: `path: mod.test/test/issue3306@v0:x 565 module: mod.test/test@v0 566 root: $CWD/testdata/testmod 567 dir: $CWD/testdata/testmod/issue3306 568 display:./issue3306 569 files: 570 $CWD/testdata/testmod/issue3306/x.cue 571 572 path: mod.test/test/issue3306/a@v0:a 573 module: mod.test/test@v0 574 root: $CWD/testdata/testmod 575 dir: $CWD/testdata/testmod/issue3306/a 576 display:./issue3306/a 577 files: 578 $CWD/testdata/testmod/issue3306/a/a.cue 579 580 path: mod.test/test/issue3306/a@v0:b 581 module: mod.test/test@v0 582 root: $CWD/testdata/testmod 583 dir: $CWD/testdata/testmod/issue3306/a 584 display:./issue3306/a 585 files: 586 $CWD/testdata/testmod/issue3306/a/b.cue 587 588 path: mod.test/test/issue3306/a@v0:x 589 module: mod.test/test@v0 590 root: $CWD/testdata/testmod 591 dir: $CWD/testdata/testmod/issue3306/a 592 display:./issue3306/a 593 files: 594 $CWD/testdata/testmod/issue3306/x.cue 595 $CWD/testdata/testmod/issue3306/a/x.cue 596 597 path: mod.test/test/issue3306/x@v0:x 598 module: mod.test/test@v0 599 root: $CWD/testdata/testmod 600 dir: $CWD/testdata/testmod/issue3306/x 601 display:./issue3306/x 602 files: 603 $CWD/testdata/testmod/issue3306/x.cue 604 $CWD/testdata/testmod/issue3306/x/x.cue`}, { 605 // This test checks that when we use Package: "*", 606 // we can still use imported packages. 607 name: "AllPackagesWithImports", 608 cfg: &Config{ 609 Dir: testdataDir, 610 Package: "*", 611 }, 612 args: []string{"."}, 613 want: `path: mod.test/test@v0:_ 614 module: mod.test/test@v0 615 root: $CWD/testdata/testmod 616 dir: $CWD/testdata/testmod 617 display:. 618 files: 619 $CWD/testdata/testmod/anon.cue 620 621 path: mod.test/test@v0:test 622 module: mod.test/test@v0 623 root: $CWD/testdata/testmod 624 dir: $CWD/testdata/testmod 625 display:. 626 files: 627 $CWD/testdata/testmod/test.cue 628 imports: 629 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 630 // This tests that we can load a CUE package by pointing Dir to it 631 // even when the package's directory name ends with ".cue". 632 name: "DirWithCUEFileExtension", 633 cfg: &Config{ 634 Dir: filepath.Join(testdataDir, "testdir.cue"), 635 }, 636 args: []string{"."}, 637 want: `path: mod.test/test/testdir.cue@v0:testdir 638 module: mod.test/test@v0 639 root: $CWD/testdata/testmod 640 dir: $CWD/testdata/testmod/testdir.cue 641 display:. 642 files: 643 $CWD/testdata/testmod/testdir.cue/test.cue`, 644 }} 645 tdtest.Run(t, testCases, func(t *tdtest.T, tc *loadTest) { 646 pkgs := Instances(tc.args, tc.cfg) 647 648 buf := &bytes.Buffer{} 649 err := pkgInfo.Execute(buf, pkgs) 650 if err != nil { 651 t.Fatal(err) 652 } 653 654 got := strings.TrimSpace(buf.String()) 655 got = strings.Replace(got, cwd, "$CWD", -1) 656 // Errors are printed with slashes, so replace 657 // the slash-separated form of CWD too. 658 got = strings.Replace(got, filepath.ToSlash(cwd), "$CWD", -1) 659 // Make test work with Windows. 660 got = strings.Replace(got, string(filepath.Separator), "/", -1) 661 662 t.Equal(got, tc.want) 663 }) 664 } 665 666 var pkgInfo = template.Must(template.New("pkg").Funcs(template.FuncMap{ 667 "errordetails": func(err error) string { 668 s := errors.Details(err, &errors.Config{ 669 ToSlash: true, 670 }) 671 s = strings.TrimSuffix(s, "\n") 672 return s 673 }}).Parse(` 674 {{- range . -}} 675 {{- if .Err}}err: {{errordetails .Err}}{{end}} 676 path: {{if .ImportPath}}{{.ImportPath}}{{else}}""{{end}} 677 module: {{with .Module}}{{.}}{{else}}""{{end}} 678 root: {{with .Root}}{{.}}{{else}}""{{end}} 679 dir: {{with .Dir}}{{.}}{{else}}""{{end}} 680 display:{{with .DisplayPath}}{{.}}{{else}}""{{end}} 681 {{if .Files -}} 682 files: 683 {{- range .Files}} 684 {{.Filename}} 685 {{- end -}} 686 {{- end}} 687 {{if .Imports -}} 688 imports: 689 {{- range .Dependencies}} 690 {{.ImportPath}}:{{range .Files}} {{.Filename}}{{end}} 691 {{- end}} 692 {{end -}} 693 {{- end -}} 694 `)) 695 696 func TestOverlays(t *testing.T) { 697 cwd, _ := os.Getwd() 698 abs := func(path string) string { 699 return filepath.Join(cwd, path) 700 } 701 c := &Config{ 702 Overlay: map[string]Source{ 703 // Not necessary, but nice to add. 704 abs("cue.mod/module.cue"): FromString(`module: "mod.test", language: version: "v0.9.0"`), 705 706 abs("dir/top.cue"): FromBytes([]byte(` 707 package top 708 msg: "Hello" 709 `)), 710 abs("dir/b/foo.cue"): FromString(` 711 package foo 712 713 a: <= 5 714 `), 715 abs("dir/b/bar.cue"): FromString(` 716 package foo 717 718 a: >= 5 719 `), 720 }, 721 } 722 want := []string{ 723 `{msg:"Hello"}`, 724 `{a:5}`, 725 } 726 rmSpace := func(r rune) rune { 727 if unicode.IsSpace(r) { 728 return -1 729 } 730 return r 731 } 732 ctx := cuecontext.New() 733 insts, err := ctx.BuildInstances(Instances([]string{"./dir/..."}, c)) 734 if err != nil { 735 t.Fatal(err) 736 } 737 for i, inst := range insts { 738 if err := inst.Err(); err != nil { 739 t.Error(err) 740 continue 741 } 742 b, err := format.Node(inst.Value().Syntax(cue.Final())) 743 if err != nil { 744 t.Error(err) 745 continue 746 } 747 if got := string(bytes.Map(rmSpace, b)); got != want[i] { 748 t.Errorf("%s: got %s; want %s", inst.BuildInstance().Dir, got, want[i]) 749 } 750 } 751 } 752 753 func TestLoadOrder(t *testing.T) { 754 testDir := t.TempDir() 755 letters := "abcdefghij" 756 757 for _, c := range letters { 758 contents := fmt.Sprintf(` 759 package %s 760 761 x: 1 762 `, string(c)) 763 err := os.WriteFile(filepath.Join(testDir, string(c)+".cue"), []byte(contents), 0o666) 764 qt.Assert(t, qt.IsNil(err)) 765 } 766 767 insts := Instances([]string{"."}, &Config{ 768 Package: "*", 769 Dir: testDir, 770 }) 771 772 var actualFiles = []string{} 773 for _, inst := range insts { 774 for _, f := range inst.BuildFiles { 775 if strings.Contains(f.Filename, testDir) { 776 actualFiles = append(actualFiles, filepath.Base(f.Filename)) 777 } 778 } 779 } 780 var expectedFiles []string 781 for _, c := range letters { 782 expectedFiles = append(expectedFiles, string(c)+".cue") 783 } 784 qt.Assert(t, qt.DeepEquals(actualFiles, expectedFiles)) 785 } 786 787 func TestLoadInstancesConcurrent(t *testing.T) { 788 // This test is designed to fail when run with the race detector 789 // if there's an underlying race condition. 790 // See https://cuelang.org/issue/1746 791 race(t, func() error { 792 _, err := getInst(".", testdata("testmod", "hello")) 793 return err 794 }) 795 } 796 797 func race(t *testing.T, f func() error) { 798 var wg sync.WaitGroup 799 for i := 0; i < 2; i++ { 800 wg.Add(1) 801 go func() { 802 if err := f(); err != nil { 803 t.Error(err) 804 } 805 wg.Done() 806 }() 807 } 808 wg.Wait() 809 }