github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/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 "os" 20 "path/filepath" 21 "strconv" 22 "strings" 23 "testing" 24 "text/template" 25 "unicode" 26 27 "github.com/kylelemons/godebug/diff" 28 29 "github.com/joomcode/cue/cue" 30 "github.com/joomcode/cue/cue/format" 31 "github.com/joomcode/cue/internal/str" 32 ) 33 34 // TestLoad is an end-to-end test. 35 func TestLoad(t *testing.T) { 36 cwd, err := os.Getwd() 37 if err != nil { 38 t.Fatal(err) 39 } 40 testdataDir := filepath.Join(cwd, testdata) 41 dirCfg := &Config{ 42 Dir: testdataDir, 43 Tools: true, 44 } 45 46 args := str.StringList 47 testCases := []struct { 48 cfg *Config 49 args []string 50 want string 51 }{{ 52 // Even though the directory is called testdata, the last path in 53 // the module is test. So "package test" is correctly the default 54 // package of this directory. 55 cfg: dirCfg, 56 args: nil, 57 want: ` 58 path: example.org/test 59 module: example.org/test 60 root: $CWD/testdata 61 dir: $CWD/testdata 62 display:. 63 files: 64 $CWD/testdata/test.cue 65 imports: 66 example.org/test/sub: $CWD/testdata/sub/sub.cue`, 67 }, { 68 // Even though the directory is called testdata, the last path in 69 // the module is test. So "package test" is correctly the default 70 // package of this directory. 71 cfg: dirCfg, 72 args: args("."), 73 want: ` 74 path: example.org/test 75 module: example.org/test 76 root: $CWD/testdata 77 dir: $CWD/testdata 78 display:. 79 files: 80 $CWD/testdata/test.cue 81 imports: 82 example.org/test/sub: $CWD/testdata/sub/sub.cue`, 83 }, { 84 // TODO: 85 // - path incorrect, should be example.org/test/other:main. 86 cfg: dirCfg, 87 args: args("./other/..."), 88 want: ` 89 err: import failed: relative import paths not allowed ("./file") 90 path: "" 91 module: example.org/test 92 root: $CWD/testdata 93 dir: $CWD/testdata/cue.mod/gen 94 display:`, 95 }, { 96 cfg: dirCfg, 97 args: args("./anon"), 98 want: ` 99 err: build constraints exclude all CUE files in ./anon: 100 anon/anon.cue: no package name 101 path: example.org/test/anon 102 module: example.org/test 103 root: $CWD/testdata 104 dir: $CWD/testdata/anon 105 display:./anon`, 106 }, { 107 // TODO: 108 // - paths are incorrect, should be example.org/test/other:main. 109 cfg: dirCfg, 110 args: args("./other"), 111 want: ` 112 err: import failed: relative import paths not allowed ("./file") 113 path: example.org/test/other:main 114 module: example.org/test 115 root: $CWD/testdata 116 dir: $CWD/testdata/other 117 display:./other 118 files: 119 $CWD/testdata/other/main.cue`, 120 }, { 121 // TODO: 122 // - incorrect path, should be example.org/test/hello:test 123 cfg: dirCfg, 124 args: args("./hello"), 125 want: ` 126 path: example.org/test/hello:test 127 module: example.org/test 128 root: $CWD/testdata 129 dir: $CWD/testdata/hello 130 display:./hello 131 files: 132 $CWD/testdata/test.cue 133 $CWD/testdata/hello/test.cue 134 imports: 135 example.org/test/sub: $CWD/testdata/sub/sub.cue`, 136 }, { 137 // TODO: 138 // - incorrect path, should be example.org/test/hello:test 139 cfg: dirCfg, 140 args: args("example.org/test/hello:test"), 141 want: ` 142 path: example.org/test/hello:test 143 module: example.org/test 144 root: $CWD/testdata 145 dir: $CWD/testdata/hello 146 display:example.org/test/hello:test 147 files: 148 $CWD/testdata/test.cue 149 $CWD/testdata/hello/test.cue 150 imports: 151 example.org/test/sub: $CWD/testdata/sub/sub.cue`, 152 }, { 153 // TODO: 154 // - incorrect path, should be example.org/test/hello:test 155 cfg: dirCfg, 156 args: args("example.org/test/hello:nonexist"), 157 want: ` 158 err: build constraints exclude all CUE files in example.org/test/hello:nonexist: 159 anon.cue: no package name 160 test.cue: package is test, want nonexist 161 hello/test.cue: package is test, want nonexist 162 path: example.org/test/hello:nonexist 163 module: example.org/test 164 root: $CWD/testdata 165 dir: $CWD/testdata/hello 166 display:example.org/test/hello:nonexist`, 167 }, { 168 cfg: dirCfg, 169 args: args("./anon.cue", "./other/anon.cue"), 170 want: ` 171 path: "" 172 module: "" 173 root: $CWD/testdata 174 dir: $CWD/testdata 175 display:command-line-arguments 176 files: 177 $CWD/testdata/anon.cue 178 $CWD/testdata/other/anon.cue`, 179 }, { 180 cfg: dirCfg, 181 // Absolute file is normalized. 182 args: args(filepath.Join(cwd, "testdata", "anon.cue")), 183 want: ` 184 path: "" 185 module: "" 186 root: $CWD/testdata 187 dir: $CWD/testdata 188 display:command-line-arguments 189 files: 190 $CWD/testdata/anon.cue`, 191 }, { 192 cfg: dirCfg, 193 args: args("-"), 194 want: ` 195 path: "" 196 module: "" 197 root: $CWD/testdata 198 dir: $CWD/testdata 199 display:command-line-arguments 200 files: 201 -`, 202 }, { 203 // NOTE: dir should probably be set to $CWD/testdata, but either way. 204 cfg: dirCfg, 205 args: args("non-existing"), 206 want: ` 207 err: cannot find package "non-existing" 208 path: non-existing 209 module: example.org/test 210 root: $CWD/testdata 211 dir: $CWD/testdata/cue.mod/gen/non-existing 212 display:non-existing`, 213 }, { 214 cfg: dirCfg, 215 args: args("./empty"), 216 want: ` 217 err: no CUE files in ./empty 218 path: example.org/test/empty 219 module: example.org/test 220 root: $CWD/testdata 221 dir: $CWD/testdata/empty 222 display:./empty`, 223 }, { 224 cfg: dirCfg, 225 args: args("./imports"), 226 want: ` 227 path: example.org/test/imports 228 module: example.org/test 229 root: $CWD/testdata 230 dir: $CWD/testdata/imports 231 display:./imports 232 files: 233 $CWD/testdata/imports/imports.cue 234 imports: 235 acme.com/catch: $CWD/testdata/cue.mod/pkg/acme.com/catch/catch.cue 236 acme.com/helper:helper1: $CWD/testdata/cue.mod/pkg/acme.com/helper/helper1.cue`, 237 }, { 238 cfg: dirCfg, 239 args: args("./toolonly"), 240 want: ` 241 path: example.org/test/toolonly:foo 242 module: example.org/test 243 root: $CWD/testdata 244 dir: $CWD/testdata/toolonly 245 display:./toolonly 246 files: 247 $CWD/testdata/toolonly/foo_tool.cue`, 248 }, { 249 cfg: &Config{ 250 Dir: testdataDir, 251 }, 252 args: args("./toolonly"), 253 want: ` 254 err: build constraints exclude all CUE files in ./toolonly: 255 anon.cue: no package name 256 test.cue: package is test, want foo 257 toolonly/foo_tool.cue: _tool.cue files excluded in non-cmd mode 258 path: example.org/test/toolonly:foo 259 module: example.org/test 260 root: $CWD/testdata 261 dir: $CWD/testdata/toolonly 262 display:./toolonly`, 263 }, { 264 cfg: &Config{ 265 Dir: testdataDir, 266 Tags: []string{"prod"}, 267 }, 268 args: args("./tags"), 269 want: ` 270 path: example.org/test/tags 271 module: example.org/test 272 root: $CWD/testdata 273 dir: $CWD/testdata/tags 274 display:./tags 275 files: 276 $CWD/testdata/tags/prod.cue`, 277 }, { 278 cfg: &Config{ 279 Dir: testdataDir, 280 Tags: []string{"prod", "foo=bar"}, 281 }, 282 args: args("./tags"), 283 want: ` 284 path: example.org/test/tags 285 module: example.org/test 286 root: $CWD/testdata 287 dir: $CWD/testdata/tags 288 display:./tags 289 files: 290 $CWD/testdata/tags/prod.cue`, 291 }, { 292 cfg: &Config{ 293 Dir: testdataDir, 294 Tags: []string{"prod"}, 295 }, 296 args: args("./tagsbad"), 297 want: ` 298 err: multiple @if attributes (and 2 more errors) 299 path: example.org/test/tagsbad 300 module: example.org/test 301 root: $CWD/testdata 302 dir: $CWD/testdata/tagsbad 303 display:./tagsbad`, 304 }} 305 for i, tc := range testCases { 306 t.Run(strconv.Itoa(i)+"/"+strings.Join(tc.args, ":"), func(t *testing.T) { 307 pkgs := Instances(tc.args, tc.cfg) 308 309 buf := &bytes.Buffer{} 310 err := pkgInfo.Execute(buf, pkgs) 311 if err != nil { 312 t.Fatal(err) 313 } 314 315 got := strings.TrimSpace(buf.String()) 316 got = strings.Replace(got, cwd, "$CWD", -1) 317 // Make test work with Windows. 318 got = strings.Replace(got, string(filepath.Separator), "/", -1) 319 320 want := strings.TrimSpace(tc.want) 321 want = strings.Replace(want, "\t", " ", -1) 322 if got != want { 323 t.Errorf("\n%s", diff.Diff(want, got)) 324 t.Logf("\n%s", got) 325 } 326 }) 327 } 328 } 329 330 var pkgInfo = template.Must(template.New("pkg").Parse(` 331 {{- range . -}} 332 {{- if .Err}}err: {{.Err}}{{end}} 333 path: {{if .ImportPath}}{{.ImportPath}}{{else}}""{{end}} 334 module: {{if .Module}}{{.Module}}{{else}}""{{end}} 335 root: {{.Root}} 336 dir: {{.Dir}} 337 display:{{.DisplayPath}} 338 {{if .Files -}} 339 files: 340 {{- range .Files}} 341 {{.Filename}} 342 {{- end -}} 343 {{- end}} 344 {{if .Imports -}} 345 imports: 346 {{- range .Dependencies}} 347 {{.ImportPath}}:{{range .Files}} {{.Filename}}{{end}} 348 {{- end}} 349 {{end -}} 350 {{- end -}} 351 `)) 352 353 func TestOverlays(t *testing.T) { 354 cwd, _ := os.Getwd() 355 abs := func(path string) string { 356 return filepath.Join(cwd, path) 357 } 358 c := &Config{ 359 Overlay: map[string]Source{ 360 // Not necessary, but nice to add. 361 abs("cue.mod"): FromString(`module: "acme.com"`), 362 363 abs("dir/top.cue"): FromBytes([]byte(` 364 package top 365 msg: "Hello" 366 `)), 367 abs("dir/b/foo.cue"): FromString(` 368 package foo 369 370 a: <= 5 371 `), 372 abs("dir/b/bar.cue"): FromString(` 373 package foo 374 375 a: >= 5 376 `), 377 }, 378 } 379 want := []string{ 380 `{msg:"Hello"}`, 381 `{a:5}`, 382 } 383 rmSpace := func(r rune) rune { 384 if unicode.IsSpace(r) { 385 return -1 386 } 387 return r 388 } 389 for i, inst := range cue.Build(Instances([]string{"./dir/..."}, c)) { 390 if inst.Err != nil { 391 t.Error(inst.Err) 392 continue 393 } 394 b, err := format.Node(inst.Value().Syntax(cue.Final())) 395 if err != nil { 396 t.Error(err) 397 continue 398 } 399 if got := string(bytes.Map(rmSpace, b)); got != want[i] { 400 t.Errorf("%s: got %s; want %s", inst.Dir, got, want[i]) 401 } 402 } 403 }