//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format. //Copyright (C) 2024 HTWKalender support@htwkalender.de //This program is free software: you can redistribute it and/or modify //it under the terms of the GNU Affero General Public License as published by //the Free Software Foundation, either version 3 of the License, or //(at your option) any later version. //This program is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU Affero General Public License for more details. //You should have received a copy of the GNU Affero General Public License //along with this program. If not, see . package v1 import ( "fmt" "github.com/pocketbase/pocketbase/tools/types" "htwkalender/data-manager/model" "os" "reflect" "sort" "testing" "time" ) func TestExtractSemesterAndYear(t *testing.T) { type args struct { semesterString string } tests := []struct { name string args args want string want1 string }{ { name: "Test 1", args: args{ semesterString: "Wintersemester 2023/24 (Planungszeitraum 01.09.2023 bis 03.03.2024)", }, want: "ws", want1: "2023", }, { name: "Test 2", args: args{ semesterString: "Sommersemester 2023 (Planungszeitraum 06.03. bis 31.08.2023)", }, want: "ss", want1: "2023", }, { name: "Test 3", args: args{ semesterString: "Sommersemester 2010 (Planungszeitraum 06.03. bis 31.08.2023)", }, want: "ss", want1: "2010", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, got1 := extractSemesterAndYear(tt.args.semesterString) if got != tt.want { t.Errorf("extractSemesterAndYear() got = %v, want %v", got, tt.want) } if got1 != tt.want1 { t.Errorf("extractSemesterAndYear() got1 = %v, want %v", got1, tt.want1) } }) } } func TestReplaceEmptyEventNames(t *testing.T) { type args struct { group model.SeminarGroup } tests := []struct { name string args args want model.SeminarGroup }{ { name: "Test 1", args: args{ group: model.SeminarGroup{ Events: []model.Event{ { Name: "Test", }, }, }, }, want: model.SeminarGroup{ Events: []model.Event{ { Name: "Test", }, }, }, }, { name: "Test 1", args: args{ group: model.SeminarGroup{ Events: []model.Event{ { Name: "", }, }, }, }, want: model.SeminarGroup{ Events: []model.Event{ { Name: "Sonderveranstaltungen", }, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := ReplaceEmptyEventNames(tt.args.group); !reflect.DeepEqual(got, tt.want) { t.Errorf("ReplaceEmptyEventNames() = %v, want %v", got, tt.want) } }) } } func TestSplitEventType(t *testing.T) { type args struct { events []model.Event } tests := []struct { name string args args want []model.Event }{ { name: "Test 1", args: args{ events: []model.Event{ { EventType: "V", }, }, }, want: []model.Event{ { EventType: "V", Compulsory: "", }, }, }, { name: "Test 2", args: args{ events: []model.Event{ { EventType: "Vw", }, }, }, want: []model.Event{ { EventType: "V", Compulsory: "w", }, }, }, { name: "Test 3", args: args{ events: []model.Event{ { EventType: "Sperr", }, }, }, want: []model.Event{ { EventType: "Sperr", Compulsory: "", }, }, }, { name: "Test 4", args: args{ events: []model.Event{ { EventType: "Sperr", }, { EventType: "Vw", }, }, }, want: []model.Event{ { EventType: "Sperr", Compulsory: "", }, { EventType: "V", Compulsory: "w", }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got, _ := SplitEventType(tt.args.events); !reflect.DeepEqual(got, tt.want) { t.Errorf("SplitEventType() = %v, want %v", got, tt.want) } }) } } func TestGenerateUUIDs(t *testing.T) { type args struct { events []model.Event course string } tests := []struct { name string args args want []model.Event }{ { name: "Test 1", args: args{ events: []model.Event{ { Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS", }, }, course: "21BIB-2a", }, want: []model.Event{ { Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS", UUID: "3720afdc-10c7-5b72-9489-cffb70cb0c13", }, }, }, { name: "Test 2", args: args{ events: []model.Event{ { Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS", }, }, course: "21BIB-2b", }, want: []model.Event{ { Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS", UUID: "81083480-bcf1-5452-af84-bb27d79282d8", }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := generateUUIDs(tt.args.events, tt.args.course); !reflect.DeepEqual(got, tt.want) { t.Errorf("generateUUIDs() = %v, want %v", got, tt.want) } }) } } func TestCreateTimeFromHourAndMinuteString(t *testing.T) { type args struct { tableTime string } tests := []struct { name string args args want time.Time }{ { name: "Test 1", args: args{ tableTime: "08:00", }, want: time.Date(0, 0, 0, 8, 0, 0, 0, time.UTC), }, { name: "Test 2", args: args{ tableTime: "08:15", }, want: time.Date(0, 0, 0, 8, 15, 0, 0, time.UTC), }, { name: "Test 3", args: args{ tableTime: "08:30", }, want: time.Date(0, 0, 0, 8, 30, 0, 0, time.UTC), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := createTimeFromHourAndMinuteString(tt.args.tableTime); !reflect.DeepEqual(got, tt.want) { t.Errorf("createTimeFromHourAndMinuteString() = %v, want %v", got, tt.want) } }) } } func TestReplaceTimeInDate(t *testing.T) { type args struct { date time.Time time time.Time } tests := []struct { name string args args want time.Time }{ { name: "Test 1", args: args{ date: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), time: time.Date(0, 0, 0, 8, 0, 0, 0, time.UTC), }, want: time.Date(2021, 1, 1, 8, 0, 0, 0, time.UTC), }, { name: "Test 2", args: args{ date: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), time: time.Date(0, 0, 0, 8, 15, 0, 0, time.UTC), }, want: time.Date(2021, 1, 1, 8, 15, 0, 0, time.UTC), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := replaceTimeForDate(tt.args.date, tt.args.time); !reflect.DeepEqual(got, tt.want) { t.Errorf("addTimeToDate() = %v, want %v", got, tt.want) } }) } } func TestConvertWeeksToDates(t *testing.T) { type args struct { events []model.Event semester string year string } returnDateTime := func(date time.Time) types.DateTime { dateTime, err := types.ParseDateTime(date) if err != nil { fmt.Println(err) } return dateTime } tests := []struct { name string args args want []model.Event }{ { name: "Test Wintertime", args: args{ events: []model.Event{ { Week: "1", Day: "Montag", Start: returnDateTime(time.Date(0, 0, 0, 7, 30, 0, 0, time.UTC)), End: returnDateTime(time.Date(0, 0, 0, 9, 0, 0, 0, time.UTC)), }, }, semester: "ws", year: "2021", }, want: []model.Event{ { Week: "1", Day: "Montag", Start: returnDateTime(time.Date(2021, 1, 4, 6, 30, 0, 0, time.UTC)), End: returnDateTime(time.Date(2021, 1, 4, 8, 0, 0, 0, time.UTC)), Semester: "ws", }, }, }, { name: "Test Summertime", args: args{ events: []model.Event{ { Week: "30", Day: "Donnerstag", Start: returnDateTime(time.Date(0, 0, 0, 7, 30, 0, 0, time.UTC)), End: returnDateTime(time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC)), }, }, semester: "ws", year: "2023", }, want: []model.Event{ { Week: "30", Day: "Donnerstag", Start: returnDateTime(time.Date(2023, 7, 27, 5, 30, 0, 0, time.UTC)), End: returnDateTime(time.Date(2023, 7, 27, 22, 0, 0, 0, time.UTC)), Semester: "ws", }, }, }, { name: "Test NextDay", args: args{ events: []model.Event{ { Week: "45", Day: "Donnerstag", Start: returnDateTime(time.Date(0, 0, 0, 7, 30, 0, 0, time.UTC)), End: returnDateTime(time.Date(0, 0, 0, 4, 0, 0, 0, time.UTC)), }, }, semester: "ws", year: "2023", }, want: []model.Event{ { Week: "45", Day: "Donnerstag", Start: returnDateTime(time.Date(2023, 11, 9, 6, 30, 0, 0, time.UTC)), End: returnDateTime(time.Date(2023, 11, 10, 3, 0, 0, 0, time.UTC)), Semester: "ws", }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := convertWeeksToDates(tt.args.events, tt.args.semester, tt.args.year); !reflect.DeepEqual(got, tt.want) { t.Errorf("convertWeeksToDates() = %v, want %v", got, tt.want) } }) } } func TestReplaceTimeForDate(t *testing.T) { type args struct { date time.Time replacementTime time.Time } tests := []struct { name string args args want time.Time }{ { name: "Replace Hour", args: args{ date: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), replacementTime: time.Date(0, 0, 0, 8, 0, 0, 0, time.UTC), }, want: time.Date(2021, 1, 1, 8, 0, 0, 0, time.UTC), }, { name: "Replace Hour and Minute", args: args{ date: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), replacementTime: time.Date(0, 0, 0, 8, 15, 0, 0, time.UTC), }, want: time.Date(2021, 1, 1, 8, 15, 0, 0, time.UTC), }, { name: "Replace Hour and Minute", args: args{ date: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), replacementTime: time.Date(0, 0, 0, 8, 30, 0, 0, time.UTC), }, want: time.Date(2021, 1, 1, 8, 30, 0, 0, time.UTC), }, { name: "Replace Hour and Minute without Year, Month, Day", args: args{ date: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), replacementTime: time.Date(2023, 10, 3, 8, 30, 0, 0, time.UTC), }, want: time.Date(2021, 1, 1, 8, 30, 0, 0, time.UTC), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := replaceTimeForDate(tt.args.date, tt.args.replacementTime); !reflect.DeepEqual(got, tt.want) { t.Errorf("replaceTimeForDate() = %v, want %v", got, tt.want) } }) } } func TestIsSummerSemester(t *testing.T) { type args struct { month time.Month } tests := []struct { name string args args want bool }{ { name: "Test Summer March", args: args{ month: time.March, }, want: true, }, { name: "Test Summer September", args: args{ month: time.September, }, want: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := isSummerSemester(tt.args.month); got != tt.want { t.Errorf("isSummerSemester() = %v, want %v", got, tt.want) } }) } } func TestIsWinterSemester(t *testing.T) { type args struct { month time.Month } tests := []struct { name string args args want bool }{ { name: "Test Winter March", args: args{ month: time.March, }, want: true, }, { name: "Test Winter September", args: args{ month: time.September, }, want: true, }, { name: "Test Winter November", args: args{ month: time.November, }, want: true, }, { name: "Test Winter February", args: args{ month: time.February, }, want: true, }, { name: "Test Winter June", args: args{ month: time.June, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := isWinterSemester(tt.args.month); got != tt.want { t.Errorf("isWinterSemester() = %v, want %v", got, tt.want) } }) } } func Test_parseSeminarGroup(t *testing.T) { type args struct { result string semester string } //read string from fil byteArray, err := os.ReadFile("tests/seminarGroup.html") if err != nil { t.Errorf("Error reading file: %v", err) } htmlString := string(byteArray) tests := []struct { name string args args want model.SeminarGroup }{ { name: "Test 1", args: args{ result: htmlString, semester: "ws", }, want: model.SeminarGroup{ Course: "23SAM", University: "HTWK Leipzig", Semester: "ws", Events: []model.Event{ { UUID: "6ebe83db-f29e-5ddd-ae8f-8724b5ba8959", Day: "Donnerstag", Week: "44", Start: parseDateTime("2024-10-31 06:00:00.000Z"), End: parseDateTime("2024-10-31 23:00:00.000Z"), Name: "Feiertage und lehrveranstaltungsfreie Tage", Notes: "Reformationstag", Prof: " ", Rooms: " ", BookedAt: "30/07/2024", Course: "23SAM", EventType: "Sperr", Compulsory: "", Semester: "ws", }, { UUID: "6ebe83db-f29e-5ddd-ae8f-8724b5ba8959", Day: "Freitag", Week: "44", Start: parseDateTime("2024-11-01 06:00:00.000Z"), End: parseDateTime("2024-11-01 23:00:00.000Z"), Name: "Feiertage und lehrveranstaltungsfreie Tage", Notes: "Brückentag Reformationstag", Prof: " ", Rooms: " ", BookedAt: "30/07/2024", Course: "23SAM", EventType: "Sperr", Compulsory: "", Semester: "ws", }, { UUID: "15e6d285-5ecd-5039-b4b2-d6fcc3dbc1a7", Day: "Dienstag", Week: "42", Start: parseDateTime("2024-10-15 09:15:00.000Z"), End: parseDateTime("2024-10-15 10:45:00.000Z"), Name: "3.2 Leitungskompetenzen II SA-M 3. FS (pf)", Notes: "Leitungshandeln", Prof: "Prof. Dr. phil. Grit Behse-Bartels", Rooms: "LI119-S", BookedAt: "13/06/2024", Course: "23SAM", EventType: "S", Compulsory: "p", Semester: "ws", }, { UUID: "15e6d285-5ecd-5039-b4b2-d6fcc3dbc1a7", Day: "Dienstag", Week: "43", Start: parseDateTime("2024-10-22 09:15:00.000Z"), End: parseDateTime("2024-10-22 10:45:00.000Z"), Name: "3.2 Leitungskompetenzen II SA-M 3. FS (pf)", Notes: "Leitungshandeln", Prof: "Prof. Dr. phil. Grit Behse-Bartels", Rooms: "LI119-S", BookedAt: "13/06/2024", Course: "23SAM", EventType: "S", Compulsory: "p", Semester: "ws", }, { UUID: "15e6d285-5ecd-5039-b4b2-d6fcc3dbc1a7", Day: "Dienstag", Week: "44", Start: parseDateTime("2024-10-29 10:15:00.000Z"), End: parseDateTime("2024-10-29 11:45:00.000Z"), Name: "3.2 Leitungskompetenzen II SA-M 3. FS (pf)", Notes: "Leitungshandeln", Prof: "Prof. Dr. phil. Grit Behse-Bartels", Rooms: "LI119-S", BookedAt: "13/06/2024", Course: "23SAM", EventType: "S", Compulsory: "p", Semester: "ws", }, { UUID: "15e6d285-5ecd-5039-b4b2-d6fcc3dbc1a7", Day: "Dienstag", Week: "54", Start: parseDateTime("2025-01-07 10:15:00.000Z"), End: parseDateTime("2025-01-07 11:45:00.000Z"), Name: "3.2 Leitungskompetenzen II SA-M 3. FS (pf)", Notes: "Leitungshandeln", Prof: "Prof. Dr. phil. Grit Behse-Bartels", Rooms: "LI119-S", BookedAt: "13/06/2024", Course: "23SAM", EventType: "S", Compulsory: "p", Semester: "ws", }, { UUID: "15e6d285-5ecd-5039-b4b2-d6fcc3dbc1a7", Day: "Dienstag", Week: "55", Start: parseDateTime("2025-01-14 10:15:00.000Z"), End: parseDateTime("2025-01-14 11:45:00.000Z"), Name: "3.2 Leitungskompetenzen II SA-M 3. FS (pf)", Notes: "Leitungshandeln", Prof: "Prof. Dr. phil. Grit Behse-Bartels", Rooms: "LI119-S", BookedAt: "13/06/2024", Course: "23SAM", EventType: "S", Compulsory: "p", Semester: "ws", }, { UUID: "6ebe83db-f29e-5ddd-ae8f-8724b5ba8959", Day: "Mittwoch", Week: "47", Start: parseDateTime("2024-11-20 06:00:00.000Z"), End: parseDateTime("2024-11-20 23:00:00.000Z"), Name: "Feiertage und lehrveranstaltungsfreie Tage", Notes: "Buß- und Bettag", Prof: " ", Rooms: " ", BookedAt: "30/07/2024", Course: "23SAM", EventType: "Sperr", Compulsory: "", Semester: "ws", }, { UUID: "703e19b7-06ab-543d-a759-4ef72627594c", Day: "Mittwoch", Week: "43", Start: parseDateTime("2024-10-23 07:30:00.000Z"), End: parseDateTime("2024-10-23 10:45:00.000Z"), Name: "3.5 Ausgew. Thema aus dem Thema Fachdiskurs Soz. Arbeit SA-M 3. FS (pf)", Notes: "LBA Sarah Otto", Rooms: "LI016-S", Prof: " ", BookedAt: "27/08/2024", Course: "23SAM", EventType: "S", Compulsory: "p", Semester: "ws", }, { UUID: "703e19b7-06ab-543d-a759-4ef72627594c", Day: "Mittwoch", Week: "46", Start: parseDateTime("2024-11-13 08:30:00.000Z"), End: parseDateTime("2024-11-13 11:45:00.000Z"), Name: "3.5 Ausgew. Thema aus dem Thema Fachdiskurs Soz. Arbeit SA-M 3. FS (pf)", Notes: "LBA Sarah Otto", Rooms: "LI115-L", Prof: " ", BookedAt: "18/09/2024", Course: "23SAM", EventType: "S", Compulsory: "p", Semester: "ws", }, { UUID: "703e19b7-06ab-543d-a759-4ef72627594c", Day: "Mittwoch", Week: "48", Start: parseDateTime("2024-11-27 08:30:00.000Z"), End: parseDateTime("2024-11-27 11:45:00.000Z"), Name: "3.5 Ausgew. Thema aus dem Thema Fachdiskurs Soz. Arbeit SA-M 3. FS (pf)", Prof: " ", Notes: "LBA Sarah Otto", Rooms: "LI201-S", BookedAt: "18/09/2024", Course: "23SAM", EventType: "S", Compulsory: "p", Semester: "ws", }, { UUID: "02d01aad-1542-574d-b597-aa5ac9ff0179", Day: "Mittwoch", Week: "42", Start: parseDateTime("2024-10-16 11:45:00.000Z"), End: parseDateTime("2024-10-16 18:30:00.000Z"), Name: "zentrale Gremienzeit", Notes: " ", Prof: " ", Rooms: " ", BookedAt: "09/09/2024", Course: "23SAM", EventType: "Sperr", Compulsory: "", Semester: "ws", }, { UUID: "02d01aad-1542-574d-b597-aa5ac9ff0179", Day: "Mittwoch", Week: "44", Start: parseDateTime("2024-10-30 12:45:00.000Z"), End: parseDateTime("2024-10-30 19:30:00.000Z"), Name: "zentrale Gremienzeit", Notes: " ", Prof: " ", Rooms: " ", BookedAt: "09/09/2024", Course: "23SAM", EventType: "Sperr", Compulsory: "", Semester: "ws", }, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { //sort Arrays by StartDate sortEventsByStartDate(tt.want.Events) got := parseSeminarGroup(tt.args.result, tt.args.semester) sortEventsByStartDate(got.Events) if !reflect.DeepEqual(got, tt.want) { t.Errorf("parseSeminarGroup() = %v, want %v", got, tt.want) } }) } } func parseDateTime(timeString string) types.DateTime { dateTime, err := types.ParseDateTime(timeString) if err != nil { fmt.Println(err) } return dateTime } func sortEventsByStartDate(events []model.Event) { sort.Slice(events, func(i, j int) bool { return events[i].Start.Time().Before(events[j].Start.Time()) }) }