package cmd import ( "bytes" "io" "os" "strings" "testing" ) func TestNewRuneVar(t *testing.T) { var r rune runeVar := newRuneVar(&r) if runeVar == nil { t.Fatal("newRuneVar returned nil") } } func TestRuneValue_String(t *testing.T) { tests := []struct { name string runeVal rune expected string }{ { name: "simple character", runeVal: 'a', expected: "a", }, { name: "special character", runeVal: '\n', expected: "\n", }, { name: "unicode character", runeVal: 'ñ', expected: "ñ", }, { name: "zero rune", runeVal: 0, expected: string(rune(0)), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { runeVal := runeValue(tt.runeVal) result := runeVal.String() if result != tt.expected { t.Errorf("runeValue.String() = %q, want %q", result, tt.expected) } }) } } func TestRuneValue_Set(t *testing.T) { tests := []struct { name string input string expected rune expectError bool }{ { name: "simple character", input: "a", expected: 'a', expectError: false, }, { name: "newline escape", input: "\\n", expected: '\n', expectError: false, }, { name: "tab escape", input: "\\t", expected: '\t', expectError: false, }, { name: "carriage return escape", input: "\\r", expected: '\r', expectError: false, }, { name: "form feed escape", input: "\\f", expected: '\f', expectError: false, }, { name: "vertical tab escape", input: "\\v", expected: '\v', expectError: false, }, { name: "empty string", input: "", expected: 0, expectError: true, }, { name: "multiple characters", input: "ab", expected: 0, expectError: true, }, { name: "special character", input: "ñ", expected: 'ñ', expectError: true, // This will fail because the Set function checks len(val) != 1 }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var r rune runeVal := newRuneVar(&r) err := runeVal.Set(tt.input) if tt.expectError { if err == nil { t.Errorf("Expected error for input %q, but got none", tt.input) } } else { if err != nil { t.Errorf("Unexpected error for input %q: %v", tt.input, err) } if r != tt.expected { t.Errorf("Expected rune %q (%d), got %q (%d)", string(tt.expected), tt.expected, string(r), r) } } }) } } func TestRuneValue_Set_ErrorMessages(t *testing.T) { tests := []struct { name string input string expectedError string }{ { name: "empty string error", input: "", expectedError: "[] is not a valid character. Must be length 1 was 0", }, { name: "multiple characters error", input: "abc", expectedError: "[abc] is not a valid character. Must be length 1 was 3", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var r rune runeVal := newRuneVar(&r) err := runeVal.Set(tt.input) if err == nil { t.Errorf("Expected error for input %q, but got none", tt.input) return } if !strings.Contains(err.Error(), tt.expectedError) { t.Errorf("Expected error message to contain %q, got %q", tt.expectedError, err.Error()) } }) } } func TestRuneValue_Type(t *testing.T) { var r rune runeVal := newRuneVar(&r) result := runeVal.Type() expected := "char" if result != expected { t.Errorf("runeValue.Type() = %q, want %q", result, expected) } } func TestNew(t *testing.T) { rootCmd := New() if rootCmd == nil { t.Fatal("New() returned nil") return } // Test basic command properties if rootCmd.Use != "yq" { t.Errorf("Expected Use to be 'yq', got %q", rootCmd.Use) } if rootCmd.Short == "" { t.Error("Expected Short description to be non-empty") } if rootCmd.Long == "" { t.Error("Expected Long description to be non-empty") } // Test that the command has the expected subcommands expectedCommands := []string{"eval", "eval-all", "completion"} actualCommands := make([]string, 0, len(rootCmd.Commands())) for _, cmd := range rootCmd.Commands() { actualCommands = append(actualCommands, cmd.Name()) } for _, expected := range expectedCommands { found := false for _, actual := range actualCommands { if actual == expected { found = true break } } if !found { t.Errorf("Expected command %q not found in actual commands: %v", expected, actualCommands) } } } func TestNew_FlagCompletions(t *testing.T) { rootCmd := New() // Test that flag completion functions are registered // This is a basic smoke test - we can't easily test the actual completion logic // without more complex setup flags := []string{ "output-format", "input-format", "xml-attribute-prefix", "xml-content-name", "xml-proc-inst-prefix", "xml-directive-name", "lua-prefix", "lua-suffix", "properties-separator", "indent", "front-matter", "expression", "split-exp", } for _, flagName := range flags { flag := rootCmd.PersistentFlags().Lookup(flagName) if flag == nil { t.Errorf("Expected flag %q to exist", flagName) } } } func TestFishCompletionDoesNotEvalCompletionRequest(t *testing.T) { output := captureStdout(t, func() { rootCmd := New() rootCmd.SetArgs([]string{"completion", "fish"}) if err := rootCmd.Execute(); err != nil { t.Fatalf("completion fish failed: %v", err) } }) if strings.Contains(output, "set -l results (eval $requestComp") { t.Fatal("fish completion script should not eval the completion request") } if !strings.Contains(output, "set -l requestComp $args[1] __complete $args[2..-1] $lastArg") { t.Fatal("fish completion script should build the completion request as a fish argument list") } if !strings.Contains(output, "set -l results ($requestComp 2> /dev/null)") { t.Fatal("fish completion script should invoke the completion request directly") } } func captureStdout(t *testing.T, run func()) string { t.Helper() originalStdout := os.Stdout reader, writer, err := os.Pipe() if err != nil { t.Fatalf("failed to create stdout pipe: %v", err) } os.Stdout = writer defer func() { os.Stdout = originalStdout }() run() if err := writer.Close(); err != nil { t.Fatalf("failed to close stdout writer: %v", err) } var output bytes.Buffer if _, err := io.Copy(&output, reader); err != nil { t.Fatalf("failed to read stdout pipe: %v", err) } if err := reader.Close(); err != nil { t.Fatalf("failed to close stdout reader: %v", err) } return output.String() }