github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/command/flag/path_test.go (about) 1 package flag_test 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 9 "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" 10 . "code.cloudfoundry.org/cli/command/flag" 11 flags "github.com/jessevdk/go-flags" 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 ) 15 16 var _ = Describe("path types", func() { 17 type completable interface { 18 Complete(string) []flags.Completion 19 } 20 21 var ( 22 currentDir string 23 tempDir string 24 ) 25 26 testComplete := func(subject completable) { 27 Describe("Complete", func() { 28 When("the prefix is empty", func() { 29 It("returns all files and directories", func() { 30 matches := subject.Complete("") 31 Expect(matches).To(ConsistOf( 32 flags.Completion{Item: "abc"}, 33 flags.Completion{Item: "abd"}, 34 flags.Completion{Item: fmt.Sprintf("~add%c", os.PathSeparator)}, 35 flags.Completion{Item: "~abd"}, 36 flags.Completion{Item: fmt.Sprintf("add%c", os.PathSeparator)}, 37 flags.Completion{Item: fmt.Sprintf("aee%c", os.PathSeparator)}, 38 flags.Completion{Item: "tfg"}, 39 flags.Completion{Item: "ABCD"}, 40 )) 41 }) 42 }) 43 44 When("the prefix is not empty", func() { 45 When("there are matching paths", func() { 46 It("returns the matching paths", func() { 47 matches := subject.Complete("a") 48 Expect(matches).To(ConsistOf( 49 flags.Completion{Item: "abc"}, 50 flags.Completion{Item: "abd"}, 51 flags.Completion{Item: fmt.Sprintf("add%c", os.PathSeparator)}, 52 flags.Completion{Item: fmt.Sprintf("aee%c", os.PathSeparator)}, 53 )) 54 }) 55 56 It("is case sensitive", func() { 57 matches := subject.Complete("A") 58 Expect(matches).To(ConsistOf( 59 flags.Completion{Item: "ABCD"}, 60 )) 61 }) 62 63 It("finds files starting with '~'", func() { 64 matches := subject.Complete("~") 65 Expect(matches).To(ConsistOf( 66 flags.Completion{Item: "~abd"}, 67 flags.Completion{Item: fmt.Sprintf("~add%c", os.PathSeparator)}, 68 )) 69 }) 70 }) 71 72 When("there are no matching paths", func() { 73 It("returns no matches", func() { 74 Expect(subject.Complete("z")).To(BeEmpty()) 75 }) 76 }) 77 }) 78 79 When("the prefix is ~/", func() { 80 var prevHome string 81 82 BeforeEach(func() { 83 prevHome = os.Getenv("HOME") 84 }) 85 86 AfterEach(func() { 87 os.Setenv("HOME", prevHome) 88 }) 89 90 When("$HOME is set", func() { 91 var ( 92 tempDir string 93 err error 94 ) 95 96 BeforeEach(func() { 97 tempDir, err = ioutil.TempDir("", "") 98 Expect(err).ToNot(HaveOccurred()) 99 os.Setenv("HOME", tempDir) 100 101 for _, filename := range []string{"abc", "def"} { 102 err = ioutil.WriteFile(filepath.Join(tempDir, filename), []byte{}, 0400) 103 Expect(err).ToNot(HaveOccurred()) 104 } 105 106 for _, dir := range []string{"adir", "bdir"} { 107 err = os.Mkdir(filepath.Join(tempDir, dir), 0700) 108 Expect(err).ToNot(HaveOccurred()) 109 } 110 }) 111 112 AfterEach(func() { 113 err = os.RemoveAll(tempDir) 114 Expect(err).ToNot(HaveOccurred()) 115 }) 116 117 It("returns matching paths in $HOME", func() { 118 matches := subject.Complete(fmt.Sprintf("~%c", os.PathSeparator)) 119 Expect(matches).To(ConsistOf( 120 flags.Completion{Item: fmt.Sprintf("~%cabc", os.PathSeparator)}, 121 flags.Completion{Item: fmt.Sprintf("~%cdef", os.PathSeparator)}, 122 flags.Completion{Item: fmt.Sprintf("~%cadir%c", os.PathSeparator, os.PathSeparator)}, 123 flags.Completion{Item: fmt.Sprintf("~%cbdir%c", os.PathSeparator, os.PathSeparator)}, 124 )) 125 }) 126 }) 127 }) 128 129 When("the prefix starts with ~/", func() { 130 var prevHome string 131 132 BeforeEach(func() { 133 prevHome = os.Getenv("HOME") 134 }) 135 136 AfterEach(func() { 137 os.Setenv("HOME", prevHome) 138 }) 139 140 When("$HOME is set", func() { 141 var ( 142 tempDir string 143 err error 144 ) 145 146 BeforeEach(func() { 147 tempDir, err = ioutil.TempDir("", "") 148 Expect(err).ToNot(HaveOccurred()) 149 os.Setenv("HOME", tempDir) 150 151 for _, filename := range []string{"abc", "def"} { 152 err = ioutil.WriteFile(filepath.Join(tempDir, filename), []byte{}, 0400) 153 Expect(err).ToNot(HaveOccurred()) 154 } 155 156 for _, dir := range []string{"adir", "bdir"} { 157 err = os.Mkdir(filepath.Join(tempDir, dir), 0700) 158 Expect(err).ToNot(HaveOccurred()) 159 } 160 }) 161 162 AfterEach(func() { 163 err = os.RemoveAll(tempDir) 164 Expect(err).ToNot(HaveOccurred()) 165 }) 166 167 It("returns matching paths in $HOME", func() { 168 matches := subject.Complete(fmt.Sprintf("~%ca", os.PathSeparator)) 169 Expect(matches).To(ConsistOf( 170 flags.Completion{Item: fmt.Sprintf("~%cabc", os.PathSeparator)}, 171 flags.Completion{Item: fmt.Sprintf("~%cadir%c", os.PathSeparator, os.PathSeparator)}, 172 )) 173 }) 174 }) 175 }) 176 }) 177 } 178 179 BeforeEach(func() { 180 var err error 181 currentDir, err = os.Getwd() 182 Expect(err).ToNot(HaveOccurred()) 183 184 tempDir, err = ioutil.TempDir("", "") 185 Expect(err).ToNot(HaveOccurred()) 186 187 err = os.Chdir(tempDir) 188 Expect(err).ToNot(HaveOccurred()) 189 190 for _, filename := range []string{"abc", "abd", "~abd", "tfg", "ABCD"} { 191 err = ioutil.WriteFile(filename, []byte{}, 0400) 192 Expect(err).ToNot(HaveOccurred()) 193 } 194 195 for _, dir := range []string{"~add", "add", "aee"} { 196 err := os.Mkdir(dir, 0700) 197 Expect(err).ToNot(HaveOccurred()) 198 } 199 }) 200 201 AfterEach(func() { 202 err := os.Chdir(currentDir) 203 Expect(err).ToNot(HaveOccurred()) 204 err = os.RemoveAll(tempDir) 205 Expect(err).ToNot(HaveOccurred()) 206 }) 207 208 Describe("Path", func() { 209 var path Path 210 testComplete(path) 211 }) 212 213 Describe("PathWithExistenceCheck", func() { 214 var pathWithExistenceCheck PathWithExistenceCheck 215 216 BeforeEach(func() { 217 pathWithExistenceCheck = PathWithExistenceCheck("") 218 }) 219 220 testComplete(pathWithExistenceCheck) 221 222 Describe("UnmarshalFlag", func() { 223 When("the path does not exist", func() { 224 It("returns a path does not exist error", func() { 225 err := pathWithExistenceCheck.UnmarshalFlag("./some-dir/some-file") 226 Expect(err).To(MatchError(&flags.Error{ 227 Type: flags.ErrRequired, 228 Message: "The specified path './some-dir/some-file' does not exist.", 229 })) 230 }) 231 }) 232 233 When("the path exists", func() { 234 When("the path is relative", func() { 235 It("expands the path", func() { 236 fullPath := filepath.Join(tempDir, "abc") 237 err := pathWithExistenceCheck.UnmarshalFlag("abc") 238 Expect(err).ToNot(HaveOccurred()) 239 Expect(string(pathWithExistenceCheck)).To(matchers.MatchPath(fullPath)) 240 }) 241 }) 242 243 When("the path is absolute", func() { 244 It("preserves the path", func() { 245 err := pathWithExistenceCheck.UnmarshalFlag(filepath.Join(tempDir, "abc")) 246 Expect(err).ToNot(HaveOccurred()) 247 Expect(pathWithExistenceCheck).To(BeEquivalentTo(filepath.Join(tempDir, "abc"))) 248 }) 249 }) 250 }) 251 }) 252 }) 253 254 Describe("ManifestPathWithExistenceCheck", func() { 255 var manifestPathWithExistenceCheck ManifestPathWithExistenceCheck 256 257 BeforeEach(func() { 258 manifestPathWithExistenceCheck = ManifestPathWithExistenceCheck("") 259 }) 260 261 testComplete(manifestPathWithExistenceCheck) 262 263 Describe("UnmarshalFlag", func() { 264 When("the path does not exist", func() { 265 It("returns a path does not exist error", func() { 266 err := manifestPathWithExistenceCheck.UnmarshalFlag("./some-dir/some-file") 267 Expect(err).To(MatchError(&flags.Error{ 268 Type: flags.ErrRequired, 269 Message: "The specified path './some-dir/some-file' does not exist.", 270 })) 271 }) 272 }) 273 274 When("the path is a directory, and exists, but does not contain a manifest.{yml,yaml} file", func() { 275 It("returns a path does not exist error", func() { 276 err := manifestPathWithExistenceCheck.UnmarshalFlag(tempDir) 277 Expect(err).To(MatchError(&flags.Error{ 278 Type: flags.ErrRequired, 279 Message: "The specified directory '" + tempDir + "' does not contain a file named 'manifest.yml'.", 280 })) 281 }) 282 }) 283 284 When("the path exists", func() { 285 It("sets the path", func() { 286 err := manifestPathWithExistenceCheck.UnmarshalFlag("abc") 287 Expect(err).ToNot(HaveOccurred()) 288 Expect(manifestPathWithExistenceCheck).To(BeEquivalentTo("abc")) 289 }) 290 }) 291 }) 292 }) 293 294 Describe("JSONOrFileWithValidation", func() { 295 var jsonOrFile JSONOrFileWithValidation 296 297 BeforeEach(func() { 298 jsonOrFile = JSONOrFileWithValidation{} 299 }) 300 301 testComplete(jsonOrFile) 302 303 Describe("UnmarshalFlag", func() { 304 When("the file exists", func() { 305 var tempPath string 306 307 When("the file has valid JSON", func() { 308 BeforeEach(func() { 309 tempPath = tempFile(`{"this is":"valid JSON"}`) 310 }) 311 312 It("reads and unmarshals the JSON from the file", func() { 313 err := jsonOrFile.UnmarshalFlag(tempPath) 314 Expect(err).ToNot(HaveOccurred()) 315 Expect(jsonOrFile).To(Equal(JSONOrFileWithValidation{ 316 IsSet: true, 317 Value: map[string]interface{}{ 318 "this is": "valid JSON", 319 }, 320 })) 321 }) 322 }) 323 324 When("the file has invalid JSON", func() { 325 BeforeEach(func() { 326 tempPath = tempFile(`{"this is":"invalid JSON"`) 327 }) 328 329 It("errors with the invalid configuration error", func() { 330 err := jsonOrFile.UnmarshalFlag(tempPath) 331 Expect(err).To(Equal(&flags.Error{ 332 Type: flags.ErrRequired, 333 Message: "Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object.", 334 })) 335 }) 336 }) 337 }) 338 339 When("the JSON is invalid", func() { 340 It("errors with the invalid configuration error", func() { 341 err := jsonOrFile.UnmarshalFlag(`{"this is":"invalid JSON"`) 342 Expect(err).To(Equal(&flags.Error{ 343 Type: flags.ErrRequired, 344 Message: "Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object.", 345 })) 346 }) 347 }) 348 349 When("the JSON is valid", func() { 350 It("reads and unmarshals the JSON", func() { 351 err := jsonOrFile.UnmarshalFlag(`{"this is":"valid JSON"}`) 352 Expect(err).ToNot(HaveOccurred()) 353 Expect(jsonOrFile).To(Equal(JSONOrFileWithValidation{ 354 IsSet: true, 355 Value: map[string]interface{}{ 356 "this is": "valid JSON", 357 }, 358 })) 359 }) 360 }) 361 }) 362 }) 363 364 Describe("PathWithExistenceCheckOrURL", func() { 365 var pathWithExistenceCheckOrURL PathWithExistenceCheckOrURL 366 367 BeforeEach(func() { 368 pathWithExistenceCheckOrURL = PathWithExistenceCheckOrURL("") 369 }) 370 371 testComplete(pathWithExistenceCheckOrURL) 372 373 Describe("UnmarshalFlag", func() { 374 When("the path is a URL", func() { 375 It("sets the path if it starts with 'http://'", func() { 376 err := pathWithExistenceCheckOrURL.UnmarshalFlag("http://example.com/payload.tgz") 377 Expect(err).ToNot(HaveOccurred()) 378 Expect(pathWithExistenceCheckOrURL).To(BeEquivalentTo("http://example.com/payload.tgz")) 379 }) 380 381 It("sets the path if it starts with 'https://'", func() { 382 err := pathWithExistenceCheckOrURL.UnmarshalFlag("https://example.com/payload.tgz") 383 Expect(err).ToNot(HaveOccurred()) 384 Expect(pathWithExistenceCheckOrURL).To(BeEquivalentTo("https://example.com/payload.tgz")) 385 }) 386 }) 387 388 When("the path does not exist", func() { 389 It("returns a path does not exist error", func() { 390 err := pathWithExistenceCheckOrURL.UnmarshalFlag("./some-dir/some-file") 391 Expect(err).To(MatchError(&flags.Error{ 392 Type: flags.ErrRequired, 393 Message: "The specified path './some-dir/some-file' does not exist.", 394 })) 395 }) 396 }) 397 398 When("the path exists", func() { 399 It("sets the path", func() { 400 err := pathWithExistenceCheckOrURL.UnmarshalFlag("abc") 401 Expect(err).ToNot(HaveOccurred()) 402 Expect(pathWithExistenceCheckOrURL).To(BeEquivalentTo("abc")) 403 }) 404 }) 405 }) 406 }) 407 408 Describe("PathWithAt", func() { 409 var pathWithAt PathWithAt 410 411 Describe("Complete", func() { 412 When("the prefix is empty", func() { 413 It("returns no matches", func() { 414 Expect(pathWithAt.Complete("")).To(BeEmpty()) 415 }) 416 }) 417 418 When("the prefix doesn't start with @", func() { 419 It("returns no matches", func() { 420 Expect(pathWithAt.Complete("a@b")).To(BeEmpty()) 421 }) 422 }) 423 424 When("the prefix starts with @", func() { 425 When("there are no characters after the @", func() { 426 It("returns all files and directories", func() { 427 matches := pathWithAt.Complete("@") 428 Expect(matches).To(ConsistOf( 429 flags.Completion{Item: "@abc"}, 430 flags.Completion{Item: "@abd"}, 431 flags.Completion{Item: fmt.Sprintf("@~add%c", os.PathSeparator)}, 432 flags.Completion{Item: "@~abd"}, 433 flags.Completion{Item: fmt.Sprintf("@add%c", os.PathSeparator)}, 434 flags.Completion{Item: fmt.Sprintf("@aee%c", os.PathSeparator)}, 435 flags.Completion{Item: "@tfg"}, 436 flags.Completion{Item: "@ABCD"}, 437 )) 438 }) 439 }) 440 441 When("there are characters after the @", func() { 442 When("there are matching paths", func() { 443 It("returns the matching paths", func() { 444 matches := pathWithAt.Complete("@a") 445 Expect(matches).To(ConsistOf( 446 flags.Completion{Item: "@abc"}, 447 flags.Completion{Item: "@abd"}, 448 flags.Completion{Item: fmt.Sprintf("@add%c", os.PathSeparator)}, 449 flags.Completion{Item: fmt.Sprintf("@aee%c", os.PathSeparator)}, 450 )) 451 }) 452 453 It("is case sensitive", func() { 454 matches := pathWithAt.Complete("@A") 455 Expect(matches).To(ConsistOf( 456 flags.Completion{Item: "@ABCD"}, 457 )) 458 }) 459 }) 460 461 When("there are no matching paths", func() { 462 It("returns no matches", func() { 463 Expect(pathWithAt.Complete("@z")).To(BeEmpty()) 464 }) 465 }) 466 }) 467 }) 468 469 When("the prefix is @~/", func() { 470 var prevHome string 471 472 BeforeEach(func() { 473 prevHome = os.Getenv("HOME") 474 }) 475 476 AfterEach(func() { 477 os.Setenv("HOME", prevHome) 478 }) 479 480 When("$HOME is set", func() { 481 var ( 482 tempDir string 483 err error 484 ) 485 486 BeforeEach(func() { 487 tempDir, err = ioutil.TempDir("", "") 488 Expect(err).ToNot(HaveOccurred()) 489 os.Setenv("HOME", tempDir) 490 491 for _, filename := range []string{"abc", "def"} { 492 err = ioutil.WriteFile(filepath.Join(tempDir, filename), []byte{}, 0400) 493 Expect(err).ToNot(HaveOccurred()) 494 } 495 496 for _, dir := range []string{"adir", "bdir"} { 497 err = os.Mkdir(filepath.Join(tempDir, dir), 0700) 498 Expect(err).ToNot(HaveOccurred()) 499 } 500 }) 501 502 AfterEach(func() { 503 err = os.RemoveAll(tempDir) 504 Expect(err).ToNot(HaveOccurred()) 505 }) 506 507 It("returns matching paths in $HOME", func() { 508 matches := pathWithAt.Complete(fmt.Sprintf("@~%c", os.PathSeparator)) 509 Expect(matches).To(ConsistOf( 510 flags.Completion{Item: fmt.Sprintf("@~%cabc", os.PathSeparator)}, 511 flags.Completion{Item: fmt.Sprintf("@~%cdef", os.PathSeparator)}, 512 flags.Completion{Item: fmt.Sprintf("@~%cadir%c", os.PathSeparator, os.PathSeparator)}, 513 flags.Completion{Item: fmt.Sprintf("@~%cbdir%c", os.PathSeparator, os.PathSeparator)}, 514 )) 515 }) 516 }) 517 }) 518 519 When("the prefix starts with @~/", func() { 520 var prevHome string 521 522 BeforeEach(func() { 523 prevHome = os.Getenv("HOME") 524 }) 525 526 AfterEach(func() { 527 os.Setenv("HOME", prevHome) 528 }) 529 530 When("$HOME is set", func() { 531 var ( 532 tempDir string 533 err error 534 ) 535 536 BeforeEach(func() { 537 tempDir, err = ioutil.TempDir("", "") 538 Expect(err).ToNot(HaveOccurred()) 539 os.Setenv("HOME", tempDir) 540 541 for _, filename := range []string{"abc", "def"} { 542 err = ioutil.WriteFile(filepath.Join(tempDir, filename), []byte{}, 0400) 543 Expect(err).ToNot(HaveOccurred()) 544 } 545 546 for _, dir := range []string{"adir", "bdir"} { 547 err = os.Mkdir(filepath.Join(tempDir, dir), 0700) 548 Expect(err).ToNot(HaveOccurred()) 549 } 550 }) 551 552 AfterEach(func() { 553 err = os.RemoveAll(tempDir) 554 Expect(err).ToNot(HaveOccurred()) 555 }) 556 557 It("returns matching paths in $HOME", func() { 558 matches := pathWithAt.Complete(fmt.Sprintf("@~%ca", os.PathSeparator)) 559 Expect(matches).To(ConsistOf( 560 flags.Completion{Item: fmt.Sprintf("@~%cabc", os.PathSeparator)}, 561 flags.Completion{Item: fmt.Sprintf("@~%cadir%c", os.PathSeparator, os.PathSeparator)}, 562 )) 563 }) 564 }) 565 }) 566 }) 567 }) 568 569 Describe("PathWithBool", func() { 570 var pathWithBool PathWithBool 571 572 Describe("Complete", func() { 573 When("the prefix is empty", func() { 574 It("returns bool choices and all files and directories", func() { 575 matches := pathWithBool.Complete("") 576 Expect(matches).To(ConsistOf( 577 flags.Completion{Item: "true"}, 578 flags.Completion{Item: "false"}, 579 flags.Completion{Item: "abc"}, 580 flags.Completion{Item: "abd"}, 581 flags.Completion{Item: fmt.Sprintf("add%c", os.PathSeparator)}, 582 flags.Completion{Item: "~abd"}, 583 flags.Completion{Item: fmt.Sprintf("~add%c", os.PathSeparator)}, 584 flags.Completion{Item: fmt.Sprintf("aee%c", os.PathSeparator)}, 585 flags.Completion{Item: "tfg"}, 586 flags.Completion{Item: "ABCD"}, 587 )) 588 }) 589 }) 590 591 When("the prefix is not empty", func() { 592 When("there are matching bool/paths", func() { 593 It("returns the matching bool/paths", func() { 594 matches := pathWithBool.Complete("t") 595 Expect(matches).To(ConsistOf( 596 flags.Completion{Item: "true"}, 597 flags.Completion{Item: "tfg"}, 598 )) 599 }) 600 601 It("paths are case sensitive", func() { 602 matches := pathWithBool.Complete("A") 603 Expect(matches).To(ConsistOf( 604 flags.Completion{Item: "ABCD"}, 605 )) 606 }) 607 608 It("bools are not case sensitive", func() { 609 matches := pathWithBool.Complete("Tr") 610 Expect(matches).To(ConsistOf( 611 flags.Completion{Item: "true"}, 612 )) 613 }) 614 }) 615 616 When("there are no matching bool/paths", func() { 617 It("returns no matches", func() { 618 Expect(pathWithBool.Complete("z")).To(BeEmpty()) 619 }) 620 }) 621 }) 622 }) 623 }) 624 })