package prompt import ( "io" "os" "path/filepath" "strings" "testing" ) // mockReader implements the Reader interface for testing type mockReader struct { input string pos int } func (m *mockReader) ReadString(delim byte) (string, error) { if m.pos >= len(m.input) { return "", io.EOF } idx := strings.IndexByte(m.input[m.pos:], delim) if idx == -1 { result := m.input[m.pos:] m.pos = len(m.input) return result, nil } result := m.input[m.pos : m.pos+idx+1] m.pos += idx + 1 return result, nil } func TestPromptStringWithReader(t *testing.T) { tests := []struct { name string input string defaultValue string required bool expected string expectError bool }{ { name: "user enters value", input: "testvalue\n", defaultValue: "default", required: false, expected: "testvalue", expectError: false, }, { name: "user accepts default", input: "\n", defaultValue: "default", required: false, expected: "default", expectError: false, }, { name: "required field empty then filled", input: "\nactualvalue\n", defaultValue: "", required: true, expected: "actualvalue", expectError: false, }, { name: "optional empty field", input: "\n", defaultValue: "", required: false, expected: "", expectError: false, }, { name: "whitespace trimmed", input: " test \n", defaultValue: "", required: false, expected: "test", expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { reader := &mockReader{input: tt.input} result, err := promptStringWithReader(reader, "Test Label", tt.defaultValue, tt.required) if (err != nil) != tt.expectError { t.Errorf("Expected error: %v, got: %v", tt.expectError, err) } if result != tt.expected { t.Errorf("Expected %q, got %q", tt.expected, result) } }) } } func TestPromptIntWithReader(t *testing.T) { tests := []struct { name string input string defaultValue int required bool expected int expectError bool }{ { name: "user enters valid number", input: "42\n", defaultValue: 0, required: false, expected: 42, expectError: false, }, { name: "user accepts default", input: "\n", defaultValue: 5432, required: false, expected: 5432, expectError: false, }, { name: "invalid then valid number", input: "abc\n123\n", defaultValue: 0, required: false, expected: 123, expectError: false, }, { name: "required field empty then filled", input: "\n999\n", defaultValue: 0, required: true, expected: 999, expectError: false, }, { name: "zero value", input: "0\n", defaultValue: 10, required: false, expected: 0, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { reader := &mockReader{input: tt.input} result, err := promptIntWithReader(reader, "Test Label", tt.defaultValue, tt.required) if (err != nil) != tt.expectError { t.Errorf("Expected error: %v, got: %v", tt.expectError, err) } if result != tt.expected { t.Errorf("Expected %d, got %d", tt.expected, result) } }) } } func TestValidateDirectory(t *testing.T) { // Create a temporary directory for testing tmpDir := t.TempDir() tests := []struct { name string path string setup func() string expectError bool }{ { name: "existing directory", setup: func() string { return tmpDir }, expectError: false, }, { name: "non-existent directory gets created", setup: func() string { return filepath.Join(tmpDir, "newdir") }, expectError: false, }, { name: "nested directory gets created", setup: func() string { return filepath.Join(tmpDir, "level1", "level2", "level3") }, expectError: false, }, { name: "file exists at path", setup: func() string { filePath := filepath.Join(tmpDir, "testfile") os.WriteFile(filePath, []byte("test"), 0644) return filePath }, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { path := tt.setup() err := ValidateDirectory(path) if (err != nil) != tt.expectError { t.Errorf("Expected error: %v, got: %v", tt.expectError, err) } // If no error expected, verify directory exists if !tt.expectError { info, err := os.Stat(path) if err != nil { t.Errorf("Directory should exist: %v", err) } if !info.IsDir() { t.Errorf("Path should be a directory") } } }) } } func TestPrintFunctions(t *testing.T) { // These functions write to stdout, so we just ensure they don't panic // Testing colored output is complex due to terminal color codes tests := []struct { name string fn func() }{ {"PrintHeader", func() { PrintHeader("Test Header") }}, {"PrintSuccess", func() { PrintSuccess("Success message") }}, {"PrintError", func() { PrintError("Error message") }}, {"PrintInfo", func() { PrintInfo("Info message") }}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Just ensure the function doesn't panic defer func() { if r := recover(); r != nil { t.Errorf("Function panicked: %v", r) } }() tt.fn() }) } } func TestPromptDirectory(t *testing.T) { tmpDir := t.TempDir() tests := []struct { name string input string defaultValue string required bool expectError bool }{ { name: "valid directory path", input: tmpDir + "\n", defaultValue: "", required: true, expectError: false, }, { name: "creates new directory", input: filepath.Join(tmpDir, "newdir") + "\n", defaultValue: "", required: true, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Note: This test would require refactoring PromptDirectory to accept a reader // For now, we test ValidateDirectory which is the core logic if tt.input != "" { path := strings.TrimSpace(tt.input[:len(tt.input)-1]) err := ValidateDirectory(path) if (err != nil) != tt.expectError { t.Errorf("Expected error: %v, got: %v", tt.expectError, err) } } }) } } // Benchmark tests func BenchmarkPromptStringWithReader(b *testing.B) { reader := &mockReader{input: strings.Repeat("test\n", b.N)} b.ResetTimer() for i := 0; i < b.N; i++ { promptStringWithReader(reader, "Label", "default", false) } } func BenchmarkPromptIntWithReader(b *testing.B) { reader := &mockReader{input: strings.Repeat("42\n", b.N)} b.ResetTimer() for i := 0; i < b.N; i++ { promptIntWithReader(reader, "Label", 0, false) } }