TestWriteDevboxShellrcZDOTDIRWithSpaces guards against a regression where the `[ -f ]` guard around sourcing the user's shellrc was unquoted. When ZDOTDIR contains spaces (e.g. ".../Application Support/..."), the unquoted path expands to multiple words and `[` fails with "too many arguments",
(t *testing.T)
| 495 | // path expands to multiple words and `[` fails with "too many arguments", so |
| 496 | // the user's real shellrc never gets sourced. |
| 497 | func TestWriteDevboxShellrcZDOTDIRWithSpaces(t *testing.T) { |
| 498 | // A ZDOTDIR with a space, like the one some terminal integrations inject. |
| 499 | zdotdir := filepath.Join(t.TempDir(), "Application Support", "zsh") |
| 500 | if err := os.MkdirAll(zdotdir, 0o755); err != nil { |
| 501 | t.Fatal(err) |
| 502 | } |
| 503 | t.Setenv("ZDOTDIR", zdotdir) |
| 504 | |
| 505 | zshrcPath := filepath.Join(zdotdir, ".zshrc") |
| 506 | if err := os.WriteFile(zshrcPath, []byte("# user zshrc"), 0o644); err != nil { |
| 507 | t.Fatalf("Failed to create test .zshrc: %v", err) |
| 508 | } |
| 509 | |
| 510 | shell := initShellBinaryFields("/usr/bin/zsh") |
| 511 | shell.devbox = &Devbox{projectDir: "/test/project"} |
| 512 | shell.projectDir = "/test/project" |
| 513 | |
| 514 | shellrcPath, err := shell.writeDevboxShellrc() |
| 515 | if err != nil { |
| 516 | t.Fatalf("Failed to write devbox shellrc: %v", err) |
| 517 | } |
| 518 | content, err := os.ReadFile(shellrcPath) |
| 519 | if err != nil { |
| 520 | t.Fatalf("Failed to read generated shellrc: %v", err) |
| 521 | } |
| 522 | contentStr := string(content) |
| 523 | |
| 524 | // The guard must quote the path so the space doesn't split into words. |
| 525 | wantGuard := `if [ -f "` + zshrcPath + `" ]; then` |
| 526 | if !strings.Contains(contentStr, wantGuard) { |
| 527 | t.Errorf("expected quoted guard %q in generated shellrc:\n%s", wantGuard, contentStr) |
| 528 | } |
| 529 | |
| 530 | // Run the actual generated guard line through /bin/sh to prove it doesn't |
| 531 | // error with "too many arguments" on a space-containing path. |
| 532 | var guardLine string |
| 533 | for _, line := range strings.Split(contentStr, "\n") { |
| 534 | if strings.HasPrefix(strings.TrimSpace(line), "if [ -f ") { |
| 535 | guardLine = strings.TrimSpace(line) + " echo sourced; fi" |
| 536 | break |
| 537 | } |
| 538 | } |
| 539 | if guardLine == "" { |
| 540 | t.Fatalf("could not find guard line in generated shellrc:\n%s", contentStr) |
| 541 | } |
| 542 | out, err := exec.Command("/bin/sh", "-c", guardLine).CombinedOutput() |
| 543 | if err != nil { |
| 544 | t.Fatalf("guard line failed to execute (%v): %s\nline: %s", err, out, guardLine) |
| 545 | } |
| 546 | if strings.TrimSpace(string(out)) != "sourced" { |
| 547 | t.Errorf("guard line did not take the true branch; output: %q\nline: %s", out, guardLine) |
| 548 | } |
| 549 | } |
nothing calls this directly
no test coverage detected