github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/lang/funcs/filesystem_test.go (about) 1 package funcs 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "testing" 7 8 homedir "github.com/mitchellh/go-homedir" 9 "github.com/zclconf/go-cty/cty" 10 "github.com/zclconf/go-cty/cty/function" 11 ) 12 13 func TestFile(t *testing.T) { 14 tests := []struct { 15 Path cty.Value 16 Want cty.Value 17 Err bool 18 }{ 19 { 20 cty.StringVal("testdata/hello.txt"), 21 cty.StringVal("Hello World"), 22 false, 23 }, 24 { 25 cty.StringVal("testdata/icon.png"), 26 cty.NilVal, 27 true, // Not valid UTF-8 28 }, 29 { 30 cty.StringVal("testdata/missing"), 31 cty.NilVal, 32 true, // no file exists 33 }, 34 } 35 36 for _, test := range tests { 37 t.Run(fmt.Sprintf("File(\".\", %#v)", test.Path), func(t *testing.T) { 38 got, err := File(".", test.Path) 39 40 if test.Err { 41 if err == nil { 42 t.Fatal("succeeded; want error") 43 } 44 return 45 } else if err != nil { 46 t.Fatalf("unexpected error: %s", err) 47 } 48 49 if !got.RawEquals(test.Want) { 50 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 51 } 52 }) 53 } 54 } 55 56 func TestTemplateFile(t *testing.T) { 57 tests := []struct { 58 Path cty.Value 59 Vars cty.Value 60 Want cty.Value 61 Err bool 62 }{ 63 { 64 cty.StringVal("testdata/hello.txt"), 65 cty.EmptyObjectVal, 66 cty.StringVal("Hello World"), 67 false, 68 }, 69 { 70 cty.StringVal("testdata/icon.png"), 71 cty.EmptyObjectVal, 72 cty.NilVal, 73 true, // Not valid UTF-8 74 }, 75 { 76 cty.StringVal("testdata/missing"), 77 cty.EmptyObjectVal, 78 cty.NilVal, 79 true, // no file exists 80 }, 81 { 82 cty.StringVal("testdata/hello.tmpl"), 83 cty.MapVal(map[string]cty.Value{ 84 "name": cty.StringVal("Jodie"), 85 }), 86 cty.StringVal("Hello, Jodie!"), 87 false, 88 }, 89 { 90 cty.StringVal("testdata/hello.tmpl"), 91 cty.ObjectVal(map[string]cty.Value{ 92 "name": cty.StringVal("Jimbo"), 93 }), 94 cty.StringVal("Hello, Jimbo!"), 95 false, 96 }, 97 { 98 cty.StringVal("testdata/hello.tmpl"), 99 cty.EmptyObjectVal, 100 cty.NilVal, 101 true, // "name" is missing from the vars map 102 }, 103 { 104 cty.StringVal("testdata/func.tmpl"), 105 cty.ObjectVal(map[string]cty.Value{ 106 "list": cty.ListVal([]cty.Value{ 107 cty.StringVal("a"), 108 cty.StringVal("b"), 109 cty.StringVal("c"), 110 }), 111 }), 112 cty.StringVal("The items are a, b, c"), 113 false, 114 }, 115 { 116 cty.StringVal("testdata/recursive.tmpl"), 117 cty.MapValEmpty(cty.String), 118 cty.NilVal, 119 true, // recursive templatefile call not allowed 120 }, 121 { 122 cty.StringVal("testdata/list.tmpl"), 123 cty.ObjectVal(map[string]cty.Value{ 124 "list": cty.ListVal([]cty.Value{ 125 cty.StringVal("a"), 126 cty.StringVal("b"), 127 cty.StringVal("c"), 128 }), 129 }), 130 cty.StringVal("- a\n- b\n- c\n"), 131 false, 132 }, 133 { 134 cty.StringVal("testdata/list.tmpl"), 135 cty.ObjectVal(map[string]cty.Value{ 136 "list": cty.True, 137 }), 138 cty.NilVal, 139 true, // iteration over non-iterable value 140 }, 141 { 142 cty.StringVal("testdata/bare.tmpl"), 143 cty.ObjectVal(map[string]cty.Value{ 144 "val": cty.True, 145 }), 146 cty.True, // since this template contains only an interpolation, its true value shines through 147 false, 148 }, 149 } 150 151 templateFileFn := MakeTemplateFileFunc(".", func() map[string]function.Function { 152 return map[string]function.Function{ 153 "join": JoinFunc, 154 "templatefile": MakeFileFunc(".", false), // just a placeholder, since templatefile itself overrides this 155 } 156 }) 157 158 for _, test := range tests { 159 t.Run(fmt.Sprintf("TemplateFile(%#v, %#v)", test.Path, test.Vars), func(t *testing.T) { 160 got, err := templateFileFn.Call([]cty.Value{test.Path, test.Vars}) 161 162 if argErr, ok := err.(function.ArgError); ok { 163 if argErr.Index < 0 || argErr.Index > 1 { 164 t.Errorf("ArgError index %d is out of range for templatefile (must be 0 or 1)", argErr.Index) 165 } 166 } 167 168 if test.Err { 169 if err == nil { 170 t.Fatal("succeeded; want error") 171 } 172 return 173 } else if err != nil { 174 t.Fatalf("unexpected error: %s", err) 175 } 176 177 if !got.RawEquals(test.Want) { 178 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 179 } 180 }) 181 } 182 } 183 184 func TestFileExists(t *testing.T) { 185 tests := []struct { 186 Path cty.Value 187 Want cty.Value 188 Err bool 189 }{ 190 { 191 cty.StringVal("testdata/hello.txt"), 192 cty.BoolVal(true), 193 false, 194 }, 195 { 196 cty.StringVal(""), // empty path 197 cty.BoolVal(false), 198 true, 199 }, 200 { 201 cty.StringVal("testdata/missing"), 202 cty.BoolVal(false), 203 false, // no file exists 204 }, 205 } 206 207 for _, test := range tests { 208 t.Run(fmt.Sprintf("FileExists(\".\", %#v)", test.Path), func(t *testing.T) { 209 got, err := FileExists(".", test.Path) 210 211 if test.Err { 212 if err == nil { 213 t.Fatal("succeeded; want error") 214 } 215 return 216 } else if err != nil { 217 t.Fatalf("unexpected error: %s", err) 218 } 219 220 if !got.RawEquals(test.Want) { 221 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 222 } 223 }) 224 } 225 } 226 227 func TestFileSet(t *testing.T) { 228 tests := []struct { 229 Path cty.Value 230 Pattern cty.Value 231 Want cty.Value 232 Err bool 233 }{ 234 { 235 cty.StringVal("."), 236 cty.StringVal("testdata*"), 237 cty.SetValEmpty(cty.String), 238 false, 239 }, 240 { 241 cty.StringVal("."), 242 cty.StringVal("testdata"), 243 cty.SetValEmpty(cty.String), 244 false, 245 }, 246 { 247 cty.StringVal("."), 248 cty.StringVal("{testdata,missing}"), 249 cty.SetValEmpty(cty.String), 250 false, 251 }, 252 { 253 cty.StringVal("."), 254 cty.StringVal("testdata/missing"), 255 cty.SetValEmpty(cty.String), 256 false, 257 }, 258 { 259 cty.StringVal("."), 260 cty.StringVal("testdata/missing*"), 261 cty.SetValEmpty(cty.String), 262 false, 263 }, 264 { 265 cty.StringVal("."), 266 cty.StringVal("*/missing"), 267 cty.SetValEmpty(cty.String), 268 false, 269 }, 270 { 271 cty.StringVal("."), 272 cty.StringVal("**/missing"), 273 cty.SetValEmpty(cty.String), 274 false, 275 }, 276 { 277 cty.StringVal("."), 278 cty.StringVal("testdata/*.txt"), 279 cty.SetVal([]cty.Value{ 280 cty.StringVal("testdata/hello.txt"), 281 }), 282 false, 283 }, 284 { 285 cty.StringVal("."), 286 cty.StringVal("testdata/hello.txt"), 287 cty.SetVal([]cty.Value{ 288 cty.StringVal("testdata/hello.txt"), 289 }), 290 false, 291 }, 292 { 293 cty.StringVal("."), 294 cty.StringVal("testdata/hello.???"), 295 cty.SetVal([]cty.Value{ 296 cty.StringVal("testdata/hello.txt"), 297 }), 298 false, 299 }, 300 { 301 cty.StringVal("."), 302 cty.StringVal("testdata/hello*"), 303 cty.SetVal([]cty.Value{ 304 cty.StringVal("testdata/hello.tmpl"), 305 cty.StringVal("testdata/hello.txt"), 306 }), 307 false, 308 }, 309 { 310 cty.StringVal("."), 311 cty.StringVal("testdata/hello.{tmpl,txt}"), 312 cty.SetVal([]cty.Value{ 313 cty.StringVal("testdata/hello.tmpl"), 314 cty.StringVal("testdata/hello.txt"), 315 }), 316 false, 317 }, 318 { 319 cty.StringVal("."), 320 cty.StringVal("*/hello.txt"), 321 cty.SetVal([]cty.Value{ 322 cty.StringVal("testdata/hello.txt"), 323 }), 324 false, 325 }, 326 { 327 cty.StringVal("."), 328 cty.StringVal("*/*.txt"), 329 cty.SetVal([]cty.Value{ 330 cty.StringVal("testdata/hello.txt"), 331 }), 332 false, 333 }, 334 { 335 cty.StringVal("."), 336 cty.StringVal("*/hello*"), 337 cty.SetVal([]cty.Value{ 338 cty.StringVal("testdata/hello.tmpl"), 339 cty.StringVal("testdata/hello.txt"), 340 }), 341 false, 342 }, 343 { 344 cty.StringVal("."), 345 cty.StringVal("**/hello*"), 346 cty.SetVal([]cty.Value{ 347 cty.StringVal("testdata/hello.tmpl"), 348 cty.StringVal("testdata/hello.txt"), 349 }), 350 false, 351 }, 352 { 353 cty.StringVal("."), 354 cty.StringVal("**/hello.{tmpl,txt}"), 355 cty.SetVal([]cty.Value{ 356 cty.StringVal("testdata/hello.tmpl"), 357 cty.StringVal("testdata/hello.txt"), 358 }), 359 false, 360 }, 361 { 362 cty.StringVal("."), 363 cty.StringVal("["), 364 cty.SetValEmpty(cty.String), 365 true, 366 }, 367 { 368 cty.StringVal("."), 369 cty.StringVal("\\"), 370 cty.SetValEmpty(cty.String), 371 true, 372 }, 373 { 374 cty.StringVal("testdata"), 375 cty.StringVal("missing"), 376 cty.SetValEmpty(cty.String), 377 false, 378 }, 379 { 380 cty.StringVal("testdata"), 381 cty.StringVal("missing*"), 382 cty.SetValEmpty(cty.String), 383 false, 384 }, 385 { 386 cty.StringVal("testdata"), 387 cty.StringVal("*.txt"), 388 cty.SetVal([]cty.Value{ 389 cty.StringVal("hello.txt"), 390 }), 391 false, 392 }, 393 { 394 cty.StringVal("testdata"), 395 cty.StringVal("hello.txt"), 396 cty.SetVal([]cty.Value{ 397 cty.StringVal("hello.txt"), 398 }), 399 false, 400 }, 401 { 402 cty.StringVal("testdata"), 403 cty.StringVal("hello.???"), 404 cty.SetVal([]cty.Value{ 405 cty.StringVal("hello.txt"), 406 }), 407 false, 408 }, 409 { 410 cty.StringVal("testdata"), 411 cty.StringVal("hello*"), 412 cty.SetVal([]cty.Value{ 413 cty.StringVal("hello.tmpl"), 414 cty.StringVal("hello.txt"), 415 }), 416 false, 417 }, 418 } 419 420 for _, test := range tests { 421 t.Run(fmt.Sprintf("FileSet(\".\", %#v, %#v)", test.Path, test.Pattern), func(t *testing.T) { 422 got, err := FileSet(".", test.Path, test.Pattern) 423 424 if test.Err { 425 if err == nil { 426 t.Fatal("succeeded; want error") 427 } 428 return 429 } else if err != nil { 430 t.Fatalf("unexpected error: %s", err) 431 } 432 433 if !got.RawEquals(test.Want) { 434 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 435 } 436 }) 437 } 438 } 439 440 func TestFileBase64(t *testing.T) { 441 tests := []struct { 442 Path cty.Value 443 Want cty.Value 444 Err bool 445 }{ 446 { 447 cty.StringVal("testdata/hello.txt"), 448 cty.StringVal("SGVsbG8gV29ybGQ="), 449 false, 450 }, 451 { 452 cty.StringVal("testdata/icon.png"), 453 cty.StringVal("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAq1BMVEX///9cTuVeUeRcTuZcTuZcT+VbSe1cTuVdT+MAAP9JSbZcT+VcTuZAQLFAQLJcTuVcTuZcUuBBQbA/P7JAQLJaTuRcT+RcTuVGQ7xAQLJVVf9cTuVcTuVGRMFeUeRbTeJcTuU/P7JeTeZbTOVcTeZAQLJBQbNAQLNaUORcTeZbT+VcTuRAQLNAQLRdTuRHR8xgUOdgUN9cTuVdTeRdT+VZTulcTuVAQLL///8+GmETAAAANnRSTlMApibw+osO6DcBB3fIX87+oRk3yehB0/Nj/gNs7nsTRv3dHmu//JYUMLVr3bssjxkgEK5CaxeK03nIAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAADoQAAA6EBvJf9gwAAAAd0SU1FB+EEBRIQDxZNTKsAAACCSURBVBjTfc7JFsFQEATQQpCYxyBEzJ55rvf/f0ZHcyQLvelTd1GngEwWycs5+UISyKLraSi9geWKK9Gr1j7AeqOJVtt2XtD1Bchef2BjQDAcCTC0CsA4mihMtXw2XwgsV2sFw812F+4P3y2GdI6nn3FGSs//4HJNAXDzU4Dg/oj/E+bsEbhf5cMsAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA0LTA1VDE4OjE2OjE1KzAyOjAws5bLVQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNC0wNVQxODoxNjoxNSswMjowMMLLc+kAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAC3RFWHRUaXRsZQBHcm91cJYfIowAAABXelRYdFJhdyBwcm9maWxlIHR5cGUgaXB0YwAAeJzj8gwIcVYoKMpPy8xJ5VIAAyMLLmMLEyMTS5MUAxMgRIA0w2QDI7NUIMvY1MjEzMQcxAfLgEigSi4A6hcRdPJCNZUAAAAASUVORK5CYII="), 454 false, 455 }, 456 { 457 cty.StringVal("testdata/missing"), 458 cty.NilVal, 459 true, // no file exists 460 }, 461 } 462 463 for _, test := range tests { 464 t.Run(fmt.Sprintf("FileBase64(\".\", %#v)", test.Path), func(t *testing.T) { 465 got, err := FileBase64(".", test.Path) 466 467 if test.Err { 468 if err == nil { 469 t.Fatal("succeeded; want error") 470 } 471 return 472 } else if err != nil { 473 t.Fatalf("unexpected error: %s", err) 474 } 475 476 if !got.RawEquals(test.Want) { 477 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 478 } 479 }) 480 } 481 } 482 483 func TestBasename(t *testing.T) { 484 tests := []struct { 485 Path cty.Value 486 Want cty.Value 487 Err bool 488 }{ 489 { 490 cty.StringVal("testdata/hello.txt"), 491 cty.StringVal("hello.txt"), 492 false, 493 }, 494 { 495 cty.StringVal("hello.txt"), 496 cty.StringVal("hello.txt"), 497 false, 498 }, 499 { 500 cty.StringVal(""), 501 cty.StringVal("."), 502 false, 503 }, 504 } 505 506 for _, test := range tests { 507 t.Run(fmt.Sprintf("Basename(%#v)", test.Path), func(t *testing.T) { 508 got, err := Basename(test.Path) 509 510 if test.Err { 511 if err == nil { 512 t.Fatal("succeeded; want error") 513 } 514 return 515 } else if err != nil { 516 t.Fatalf("unexpected error: %s", err) 517 } 518 519 if !got.RawEquals(test.Want) { 520 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 521 } 522 }) 523 } 524 } 525 526 func TestDirname(t *testing.T) { 527 tests := []struct { 528 Path cty.Value 529 Want cty.Value 530 Err bool 531 }{ 532 { 533 cty.StringVal("testdata/hello.txt"), 534 cty.StringVal("testdata"), 535 false, 536 }, 537 { 538 cty.StringVal("testdata/foo/hello.txt"), 539 cty.StringVal("testdata/foo"), 540 false, 541 }, 542 { 543 cty.StringVal("hello.txt"), 544 cty.StringVal("."), 545 false, 546 }, 547 { 548 cty.StringVal(""), 549 cty.StringVal("."), 550 false, 551 }, 552 } 553 554 for _, test := range tests { 555 t.Run(fmt.Sprintf("Dirname(%#v)", test.Path), func(t *testing.T) { 556 got, err := Dirname(test.Path) 557 558 if test.Err { 559 if err == nil { 560 t.Fatal("succeeded; want error") 561 } 562 return 563 } else if err != nil { 564 t.Fatalf("unexpected error: %s", err) 565 } 566 567 if !got.RawEquals(test.Want) { 568 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 569 } 570 }) 571 } 572 } 573 574 func TestPathExpand(t *testing.T) { 575 homePath, err := homedir.Dir() 576 if err != nil { 577 t.Fatalf("Error getting home directory: %v", err) 578 } 579 580 tests := []struct { 581 Path cty.Value 582 Want cty.Value 583 Err bool 584 }{ 585 { 586 cty.StringVal("~/test-file"), 587 cty.StringVal(filepath.Join(homePath, "test-file")), 588 false, 589 }, 590 { 591 cty.StringVal("~/another/test/file"), 592 cty.StringVal(filepath.Join(homePath, "another/test/file")), 593 false, 594 }, 595 { 596 cty.StringVal("/root/file"), 597 cty.StringVal("/root/file"), 598 false, 599 }, 600 { 601 cty.StringVal("/"), 602 cty.StringVal("/"), 603 false, 604 }, 605 } 606 607 for _, test := range tests { 608 t.Run(fmt.Sprintf("Dirname(%#v)", test.Path), func(t *testing.T) { 609 got, err := Pathexpand(test.Path) 610 611 if test.Err { 612 if err == nil { 613 t.Fatal("succeeded; want error") 614 } 615 return 616 } else if err != nil { 617 t.Fatalf("unexpected error: %s", err) 618 } 619 620 if !got.RawEquals(test.Want) { 621 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 622 } 623 }) 624 } 625 }