package csv import ( "os" "path/filepath" "strings" "testing" ) func TestLoadCSVFromReader(t *testing.T) { t.Run("successful load", func(t *testing.T) { input := `Name,Age,City Alice,30,NYC Bob,25,LA` reader := strings.NewReader(input) csv, err := LoadCSVFromReader(reader) if err != nil { t.Fatalf("expected no error, got %v", err) } if len(csv.Header) != 3 { t.Fatalf("expected 3 header columns, got %d", len(csv.Header)) } expectedHeaders := []string{"Name", "Age", "City"} for i, expected := range expectedHeaders { if csv.Header[i] != expected { t.Errorf("header[%d]: expected %q, got %q", i, expected, csv.Header[i]) } } if len(csv.Data) != 2 { t.Fatalf("expected 2 data rows, got %d", len(csv.Data)) } if csv.Data[0][0] != "Alice" { t.Errorf("expected first row name to be 'Alice', got %q", csv.Data[0][0]) } if csv.Data[1][0] != "Bob" { t.Errorf("expected second row name to be 'Bob', got %q", csv.Data[1][0]) } }) t.Run("empty CSV", func(t *testing.T) { input := `Header` reader := strings.NewReader(input) csv, err := LoadCSVFromReader(reader) if err != nil { t.Fatalf("expected no error, got %v", err) } if len(csv.Header) != 1 { t.Fatalf("expected 1 header column, got %d", len(csv.Header)) } if csv.Header[0] != "Header" { t.Errorf("expected header 'Header', got %q", csv.Header[0]) } if len(csv.Data) != 0 { t.Errorf("expected empty data, got %d rows", len(csv.Data)) } }) t.Run("CSV with quoted fields", func(t *testing.T) { input := `Name,Description "John Doe","A person with a comma, in description"` reader := strings.NewReader(input) csv, err := LoadCSVFromReader(reader) if err != nil { t.Fatalf("expected no error, got %v", err) } if csv.Data[0][0] != "John Doe" { t.Errorf("expected quoted name 'John Doe', got %q", csv.Data[0][0]) } if csv.Data[0][1] != "A person with a comma, in description" { t.Errorf("expected quoted description, got %q", csv.Data[0][1]) } }) t.Run("malformed CSV", func(t *testing.T) { input := `Name,Age Alice,30 Bob,25,ExtraField` reader := strings.NewReader(input) csv, err := LoadCSVFromReader(reader) if err == nil { t.Fatal("expected error for malformed CSV, got nil") } if csv != nil { t.Error("expected nil CSV on error") } }) t.Run("empty input", func(t *testing.T) { reader := strings.NewReader("") csv, err := LoadCSVFromReader(reader) if err == nil { t.Fatal("expected error for empty input, got nil") } if csv != nil { t.Error("expected nil CSV on error") } }) } func TestLoadCSVFromFile(t *testing.T) { t.Run("successful load from file", func(t *testing.T) { tmpDir := t.TempDir() filePath := filepath.Join(tmpDir, "test.csv") content := `Name,Age Alice,30 Bob,25` err := os.WriteFile(filePath, []byte(content), 0644) if err != nil { t.Fatalf("failed to create test file: %v", err) } file, err := os.Open(filePath) if err != nil { t.Fatalf("failed to open test file: %v", err) } defer file.Close() csv, err := LoadCSVFromFile(file) if err != nil { t.Fatalf("expected no error, got %v", err) } if len(csv.Header) != 2 { t.Fatalf("expected 2 header columns, got %d", len(csv.Header)) } if csv.Header[0] != "Name" || csv.Header[1] != "Age" { t.Errorf("unexpected headers: %v", csv.Header) } if len(csv.Data) != 2 { t.Fatalf("expected 2 data rows, got %d", len(csv.Data)) } }) t.Run("load from nil file uses stdin", func(t *testing.T) { // This test documents the behavior - passing nil uses stdin // We can't easily test stdin, so we just verify it doesn't panic // The actual assertion is in the LoadCSVFromFile function defer func() { if r := recover(); r != nil { t.Errorf("unexpected panic: %v", r) } }() // Note: This will try to read from stdin and likely error or hang // In a real scenario, we would mock stdin // For now, we just test with an actual file }) t.Run("file with single header", func(t *testing.T) { tmpDir := t.TempDir() filePath := filepath.Join(tmpDir, "test.csv") content := `SingleColumn` err := os.WriteFile(filePath, []byte(content), 0644) if err != nil { t.Fatalf("failed to create test file: %v", err) } file, err := os.Open(filePath) if err != nil { t.Fatalf("failed to open test file: %v", err) } defer file.Close() csv, err := LoadCSVFromFile(file) if err != nil { t.Fatalf("expected no error, got %v", err) } if len(csv.Header) != 1 || csv.Header[0] != "SingleColumn" { t.Errorf("unexpected header: %v", csv.Header) } if len(csv.Data) != 0 { t.Errorf("expected no data rows, got %d", len(csv.Data)) } }) }