package migration import ( "strings" "testing" ) func TestParseRosterCSVWithHeader(t *testing.T) { csv := `email,display_name,alternate_emails alice@corp.com,Alice Corp,alice.old@corp.com;bob.alias@corp.com bob@corp.com,Bob, ` rows, err := ParseRosterCSV(strings.NewReader(csv)) if err != nil { t.Fatalf("parse: %v", err) } if len(rows) != 2 { t.Fatalf("expected 2 rows, got %d", len(rows)) } if rows[0].Email != "alice@corp.com" || rows[0].DisplayName != "Alice Corp" { t.Fatalf("row0: %#v", rows[0]) } if len(rows[0].AlternateEmails) != 2 { t.Fatalf("row0 alternates: %#v", rows[0].AlternateEmails) } if rows[1].Email != "bob@corp.com" || rows[1].DisplayName != "Bob" { t.Fatalf("row1: %#v", rows[1]) } } func TestParseRosterCSVWithoutHeader(t *testing.T) { csv := "alice@corp.com,Alice\nbob@corp.com\n" rows, err := ParseRosterCSV(strings.NewReader(csv)) if err != nil { t.Fatalf("parse: %v", err) } if len(rows) != 2 { t.Fatalf("expected 2 rows, got %d", len(rows)) } if rows[0].DisplayName != "Alice" { t.Fatalf("display name: %#v", rows[0]) } if rows[1].DisplayName != "" { t.Fatalf("row1 display: %#v", rows[1]) } } func TestParseRosterCSVInvalidEmail(t *testing.T) { _, err := ParseRosterCSV(strings.NewReader("not-an-email,Someone\n")) if err == nil { t.Fatal("expected invalid email error") } } func TestParseAlternateEmailsField(t *testing.T) { got := parseAlternateEmailsField(`a@x.com; b@x.com | c@x.com`) if len(got) != 3 { t.Fatalf("got %#v", got) } } func TestLooksLikeRosterHeader(t *testing.T) { if !looksLikeRosterHeader([]string{"Email", "Name"}) { t.Fatal("expected header detection") } if looksLikeRosterHeader([]string{"alice@corp.com", "Alice"}) { t.Fatal("data row should not be header") } }