This commit is contained in:
Eden Kirin
2025-10-31 19:04:40 +01:00
parent ca10b01fb0
commit 4e4827d640
12 changed files with 2612 additions and 10 deletions

View File

@ -0,0 +1,319 @@
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)
}
}