From 4d541f688aace10efc9af81e12a03ced8dda3506 Mon Sep 17 00:00:00 2001 From: Sarah French Date: Fri, 31 Oct 2025 16:49:55 +0000 Subject: [PATCH 1/3] Update test for autocompletion of top-level commands --- main_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/main_test.go b/main_test.go index addd07dfebaa..9ba45894dc61 100644 --- a/main_test.go +++ b/main_test.go @@ -4,10 +4,13 @@ package main import ( + "errors" "fmt" "os" "reflect" + "strings" "testing" + "time" "github.com/hashicorp/cli" ) @@ -279,26 +282,67 @@ func TestMain_autoComplete(t *testing.T) { oldArgs := os.Args defer func() { os.Args = oldArgs }() + // Restore stdout + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + defer func() { os.Stdout = old }() + // Set up test command and restore that Commands = make(map[string]cli.CommandFactory) defer func() { Commands = nil }() - - // Set up test command and restore that - Commands["foo"] = func() (cli.Command, error) { + Commands["version"] = func() (cli.Command, error) { return &testCommandCLI{}, nil } + // Run command that should get autocomplete suggestion "version" os.Setenv("COMP_LINE", "terraform versio") defer os.Unsetenv("COMP_LINE") - - // Run it! os.Args = []string{"terraform", "terraform", "versio"} exit := realMain() if exit != 0 { t.Fatalf("unexpected exit status %d; want 0", exit) } + + // Check autocomplete suggestion + expectedAutocomplete := "version" + b := make([]byte, 25) + n, err := r.Read(b) + if err != nil { + t.Fatal(err) + } + output := string(b[0:n]) + output = strings.ReplaceAll(output, "\n", "") + if output != expectedAutocomplete { + t.Fatalf("expected autocompletion to return %q, but got %q", expectedAutocomplete, output) + } + + // Run command that should NOT get an autocomplete suggestion + r, w, _ = os.Pipe() + os.Stdout = w + + os.Setenv("COMP_LINE", "terraform zzz") + defer os.Unsetenv("COMP_LINE") + os.Args = []string{"terraform", "terraform", "zzz"} + exit = realMain() + if exit != 0 { + t.Fatalf("unexpected exit status %d; want 0", exit) + } + + // Avoid infinite blocking in this case, where no autocomplete suggestions are returned + r.SetReadDeadline(time.Now().Add(time.Duration(1 * time.Second))) + + // Check autocomplete suggestion + b = make([]byte, 25) + n, err = r.Read(b) + if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { + t.Fatal(err) + } + if n != 0 { + t.Fatalf("expected autocompletion to return 0 bytes, but got %d: %q", n, b[0:n]) + } } type testCommandCLI struct { From 305581f882cffc68767bf62dfc80e6e1b4765a7c Mon Sep 17 00:00:00 2001 From: Sarah French Date: Fri, 31 Oct 2025 16:50:26 +0000 Subject: [PATCH 2/3] Add test coverage for autocompletion of workspace names in `workspace select` subcommand --- main_test.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/main_test.go b/main_test.go index 9ba45894dc61..2c35543c6b85 100644 --- a/main_test.go +++ b/main_test.go @@ -345,6 +345,82 @@ func TestMain_autoComplete(t *testing.T) { } } +// Test the autocompleting the workspace name during `terraform workspace select` +func TestMain_autoComplete_workspaceName(t *testing.T) { + // Restore original CLI args + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + + // Restore stdout + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + defer func() { os.Stdout = old }() + + t.Run("can autocomplete from 'd' to 'default'", func(t *testing.T) { + // Auto complete in a working directory with no config; + // an implied local backend is used, which will report the default backend exists. + td := t.TempDir() + t.Chdir(td) + + // Set up trigger for command-line autocompletion feature + // We expect "d" to autocomplete to "default" + expectedAutocomplete := "default" + os.Setenv("COMP_LINE", "terraform workspace select d") + defer os.Unsetenv("COMP_LINE") + + // Run it! + os.Args = []string{"terraform", "terraform", "workspace", "select", "d"} + exit := realMain() + if exit != 0 { + t.Fatalf("unexpected exit status %d; want 0", exit) + } + + b := make([]byte, 25) + n, err := r.Read(b) + if err != nil { + t.Fatal(err) + } + output := string(b[0:n]) + output = strings.ReplaceAll(output, "\n", "") + + if string(output) != expectedAutocomplete { + t.Fatalf("expected autocompletion to return %q, but got %q", expectedAutocomplete, output) + } + }) + + t.Run("can handle autocomplete returning no results", func(t *testing.T) { + // Auto complete in a working directory with no config; + // an implied local backend is used, which will report the default backend exists. + td := t.TempDir() + t.Chdir(td) + + // Set up trigger for command-line autocompletion feature + // We expect "z" to not autocomplete to anything, as only 'default' exists. + os.Setenv("COMP_LINE", "terraform workspace select z") + defer os.Unsetenv("COMP_LINE") + + // Run it! + os.Args = []string{"terraform", "terraform", "workspace", "select", "z"} + exit := realMain() + if exit != 0 { + t.Fatalf("unexpected exit status %d; want 0", exit) + } + + // Avoid infinite blocking in this test case, where no autocomplete suggestions are returned + r.SetReadDeadline(time.Now().Add(time.Duration(1 * time.Second))) + + b := make([]byte, 25) + n, err := r.Read(b) + if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { + t.Fatal(err) + } + if n != 0 { + t.Fatalf("expected autocompletion to return 0 bytes, but got %d: %q", n, b[0:n]) + } + }) +} + type testCommandCLI struct { Args []string } From b04c76755b9967f4421b6950a9f13c86328e02ff Mon Sep 17 00:00:00 2001 From: Sarah French Date: Fri, 31 Oct 2025 17:04:27 +0000 Subject: [PATCH 3/3] Remove autocompletion tests for workspace select --- main_test.go | 76 ---------------------------------------------------- 1 file changed, 76 deletions(-) diff --git a/main_test.go b/main_test.go index 2c35543c6b85..9ba45894dc61 100644 --- a/main_test.go +++ b/main_test.go @@ -345,82 +345,6 @@ func TestMain_autoComplete(t *testing.T) { } } -// Test the autocompleting the workspace name during `terraform workspace select` -func TestMain_autoComplete_workspaceName(t *testing.T) { - // Restore original CLI args - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - - // Restore stdout - old := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w - defer func() { os.Stdout = old }() - - t.Run("can autocomplete from 'd' to 'default'", func(t *testing.T) { - // Auto complete in a working directory with no config; - // an implied local backend is used, which will report the default backend exists. - td := t.TempDir() - t.Chdir(td) - - // Set up trigger for command-line autocompletion feature - // We expect "d" to autocomplete to "default" - expectedAutocomplete := "default" - os.Setenv("COMP_LINE", "terraform workspace select d") - defer os.Unsetenv("COMP_LINE") - - // Run it! - os.Args = []string{"terraform", "terraform", "workspace", "select", "d"} - exit := realMain() - if exit != 0 { - t.Fatalf("unexpected exit status %d; want 0", exit) - } - - b := make([]byte, 25) - n, err := r.Read(b) - if err != nil { - t.Fatal(err) - } - output := string(b[0:n]) - output = strings.ReplaceAll(output, "\n", "") - - if string(output) != expectedAutocomplete { - t.Fatalf("expected autocompletion to return %q, but got %q", expectedAutocomplete, output) - } - }) - - t.Run("can handle autocomplete returning no results", func(t *testing.T) { - // Auto complete in a working directory with no config; - // an implied local backend is used, which will report the default backend exists. - td := t.TempDir() - t.Chdir(td) - - // Set up trigger for command-line autocompletion feature - // We expect "z" to not autocomplete to anything, as only 'default' exists. - os.Setenv("COMP_LINE", "terraform workspace select z") - defer os.Unsetenv("COMP_LINE") - - // Run it! - os.Args = []string{"terraform", "terraform", "workspace", "select", "z"} - exit := realMain() - if exit != 0 { - t.Fatalf("unexpected exit status %d; want 0", exit) - } - - // Avoid infinite blocking in this test case, where no autocomplete suggestions are returned - r.SetReadDeadline(time.Now().Add(time.Duration(1 * time.Second))) - - b := make([]byte, 25) - n, err := r.Read(b) - if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { - t.Fatal(err) - } - if n != 0 { - t.Fatalf("expected autocompletion to return 0 bytes, but got %d: %q", n, b[0:n]) - } - }) -} - type testCommandCLI struct { Args []string }