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