package staff import ( "testing" "github.com/breakpilot/edu-search-service/internal/database" ) func TestParseName_FullName_WithTitle(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string fullName string expectedFirst string expectedLast string expectedTitle bool }{ { name: "Prof. Dr. with first and last name", fullName: "Prof. Dr. Hans Müller", expectedFirst: "Hans", expectedLast: "Müller", expectedTitle: true, }, { name: "Dr. with first and last name", fullName: "Dr. Maria Schmidt", expectedFirst: "Maria", expectedLast: "Schmidt", expectedTitle: true, }, { name: "Simple name without title", fullName: "Thomas Weber", expectedFirst: "Thomas", expectedLast: "Weber", expectedTitle: false, }, { name: "Multiple first names", fullName: "Prof. Dr. Hans-Peter Meier", expectedFirst: "Hans-Peter", expectedLast: "Meier", expectedTitle: true, }, { name: "Single name", fullName: "Müller", expectedFirst: "", expectedLast: "Müller", expectedTitle: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { person := &database.UniversityStaff{} crawler.parseName(tt.fullName, person) firstName := "" if person.FirstName != nil { firstName = *person.FirstName } if firstName != tt.expectedFirst { t.Errorf("First name: expected %q, got %q", tt.expectedFirst, firstName) } if person.LastName != tt.expectedLast { t.Errorf("Last name: expected %q, got %q", tt.expectedLast, person.LastName) } hasTitle := person.Title != nil && *person.Title != "" if hasTitle != tt.expectedTitle { t.Errorf("Has title: expected %v, got %v", tt.expectedTitle, hasTitle) } }) } } func TestClassifyPosition_Professor(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string position string expected string }{ {"Full Professor", "Professor für Informatik", "professor"}, {"Prof abbreviation", "Prof. Dr. Müller", "professor"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.classifyPosition(tt.position) if result == nil { t.Errorf("Expected %q, got nil for position %q", tt.expected, tt.position) return } if *result != tt.expected { t.Errorf("Expected %q, got %q for position %q", tt.expected, *result, tt.position) } }) } } func TestClassifyPosition_Postdoc(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string position string expected string }{ {"Postdoc", "Postdoc in Machine Learning", "postdoc"}, {"Post-Doc hyphenated", "Post-Doc", "postdoc"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.classifyPosition(tt.position) if result == nil { t.Errorf("Expected %q, got nil for position %q", tt.expected, tt.position) return } if *result != tt.expected { t.Errorf("Expected %q, got %q for position %q", tt.expected, *result, tt.position) } }) } } func TestClassifyPosition_PhDStudent(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string position string expected string }{ {"Doktorand", "Doktorand", "phd_student"}, {"PhD Student", "PhD Student", "phd_student"}, {"Promovend", "Promovend", "phd_student"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.classifyPosition(tt.position) if result == nil { t.Errorf("Expected %q, got nil for position %q", tt.expected, tt.position) return } if *result != tt.expected { t.Errorf("Expected %q, got %q for position %q", tt.expected, *result, tt.position) } }) } } func TestClassifyPosition_Admin(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string position string expected string }{ {"Sekretariat", "Sekretärin", "admin"}, {"Verwaltung", "Verwaltung", "admin"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.classifyPosition(tt.position) if result == nil { t.Errorf("Expected %q, got nil for position %q", tt.expected, tt.position) return } if *result != tt.expected { t.Errorf("Expected %q, got %q for position %q", tt.expected, *result, tt.position) } }) } } func TestClassifyPosition_Researcher(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string position string expected string }{ {"Wissenschaftlicher Mitarbeiter", "Wissenschaftlicher Mitarbeiter", "researcher"}, {"Researcher", "Senior Researcher", "researcher"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.classifyPosition(tt.position) if result == nil { t.Errorf("Expected %q, got nil for position %q", tt.expected, tt.position) return } if *result != tt.expected { t.Errorf("Expected %q, got %q for position %q", tt.expected, *result, tt.position) } }) } } func TestClassifyPosition_Student(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string position string expected string }{ {"Studentische Hilfskraft", "Studentische Hilfskraft", "student"}, {"HiWi", "Student (HiWi)", "student"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.classifyPosition(tt.position) if result == nil { t.Errorf("Expected %q, got nil for position %q", tt.expected, tt.position) return } if *result != tt.expected { t.Errorf("Expected %q, got %q for position %q", tt.expected, *result, tt.position) } }) } } func TestIsProfessor_True(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string position string }{ {"Professor keyword", "Professor für Mathematik"}, {"Prof. abbreviation", "Prof. Dr. Müller"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.isProfessor(tt.position) if !result { t.Errorf("Expected true for position=%q", tt.position) } }) } } func TestIsProfessor_False(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string position string }{ {"Dr. only", "Dr. Wissenschaftlicher Mitarbeiter"}, {"Doktorand", "Doktorand"}, {"Technical staff", "Laboringenieur"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.isProfessor(tt.position) if result { t.Errorf("Expected false for position=%q", tt.position) } }) } } func TestLooksLikePosition_True(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string text string }{ {"Professor", "Professor für Informatik"}, {"Wissenschaftlicher Mitarbeiter", "Wissenschaftlicher Mitarbeiter"}, {"Doktorand", "Doktorand"}, {"Sekretär", "Sekretärin"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.looksLikePosition(tt.text) if !result { t.Errorf("Expected true for text=%q", tt.text) } }) } } func TestLooksLikePosition_False(t *testing.T) { crawler := &StaffCrawler{} tests := []struct { name string text string }{ {"Name", "Hans Müller"}, {"Email", "test@example.com"}, {"Random text", "Room 123"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := crawler.looksLikePosition(tt.text) if result { t.Errorf("Expected false for text=%q", tt.text) } }) } } func TestResolveURL(t *testing.T) { tests := []struct { name string baseURL string href string expected string }{ {"Absolute URL", "https://example.com", "https://other.com/page", "https://other.com/page"}, {"Relative path", "https://example.com/team", "/person/123", "https://example.com/person/123"}, {"Relative no slash", "https://example.com/team/", "member", "https://example.com/team/member"}, {"Empty href", "https://example.com", "", ""}, {"Root relative", "https://example.com/a/b/c", "/root", "https://example.com/root"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := resolveURL(tt.baseURL, tt.href) if result != tt.expected { t.Errorf("resolveURL(%q, %q) = %q, expected %q", tt.baseURL, tt.href, result, tt.expected) } }) } }