//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 room import ( "htwkalender/model" "reflect" "testing" "time" "github.com/pocketbase/pocketbase/tools/types" ) func Test_anonymizeRooms(t *testing.T) { type args struct { events []model.Event } tests := []struct { name string args args want []model.AnonymizedEventDTO }{ { name: "anonymize single event", args: args{ events: []model.Event{ { UUID: "testUUID", Day: "Montag", Week: "52", Start: types.DateTime{}, End: types.DateTime{}, Name: "Secret", EventType: "V", Prof: "Prof. Dr. Secret", Rooms: "Room", Notes: "Secret", BookedAt: "Secret", Course: "42INM-3", Semester: "ws", Compulsory: "p", }, }, }, want: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "Room", Free: false, }, }, }, { name: "anonymize empty list", args: args{ events: []model.Event{}, }, want: nil, }, { name: "anonymize multiple events", args: args{ events: []model.Event{ { UUID: "testUUID1", Day: "Montag", Week: "51", Start: types.DateTime{}, End: types.DateTime{}, Name: "Incognito", EventType: "V", Prof: "Prof. Dr. Incognito", Rooms: "Room", Notes: "Incognito", BookedAt: "Incognito", Course: "69INM-2", Semester: "sose", Compulsory: "p", }, { UUID: "testUUID2", Day: "Dienstag", Week: "52", Start: types.DateTime{}, End: types.DateTime{}, Name: "Private", EventType: "S", Prof: "Prof.In. Dr.-Ing. Private", Rooms: "Room", Notes: "Private", BookedAt: "Private", Course: "42MIM-3", Semester: "ws", Compulsory: "w", }, }, }, want: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "51", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "Room", Free: false, }, { Day: "Dienstag", Week: "52", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "Room", Free: false, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := anonymizeRooms(tt.args.events); !reflect.DeepEqual(got, tt.want) { t.Errorf("anonymizeRooms() = %v, want %v", got, tt.want) } }) } } func Test_isRoomInSchedule(t *testing.T) { type args struct { room string schedule []model.Event } tests := []struct { name string args args want bool }{ { name: "room is in schedule", args: args{ room: "Room", schedule: []model.Event{ { UUID: "testUUID", Day: "Montag", Week: "52", Start: types.DateTime{}, End: types.DateTime{}, Name: "Secret", EventType: "V", Prof: "Prof. Dr. Secret", Rooms: "Room", Notes: "Secret", }, }, }, want: true, }, { name: "room is not in schedule", args: args{ room: "Z324", schedule: []model.Event{ { UUID: "testUUID", Day: "Montag", Week: "52", Start: types.DateTime{}, End: types.DateTime{}, Name: "Secret", EventType: "V", Prof: "Prof. Dr. Bond", Rooms: "LI007", Notes: "Keine Zeit für die Uni", }, }, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := isRoomInSchedule(tt.args.room, tt.args.schedule); got != tt.want { t.Errorf("isRoomInSchedule() = %v, want %v", got, tt.want) } }) } } func Test_getFreeRooms(t *testing.T) { type args struct { rooms []string schedule []model.Event } tests := []struct { name string args args want []string }{ { name: "remove room1 from list", args: args{ rooms: []string{ "Room1", "Room2", "Room3", }, schedule: []model.Event{ { UUID: "testUUID", Day: "Montag", Week: "52", Start: types.DateTime{}, End: types.DateTime{}, Name: "Secret", EventType: "V", Prof: "Prof. Dr. Secret", Rooms: "Room1", Notes: "Secret", }, }, }, want: []string{ "Room2", "Room3", }, }, { name: "remove room2 from list", args: args{ rooms: []string{ "Room1", "Room2", "Room3", }, schedule: []model.Event{ { UUID: "testUUID", Day: "Montag", Week: "52", Start: types.DateTime{}, End: types.DateTime{}, Name: "Secret", EventType: "V", Prof: "Prof. Dr. Secret", Rooms: "Room3", Notes: "Secret", }, }, }, want: []string{ "Room1", "Room2", }, }, { name: "remove no room from list", args: args{ rooms: []string{ "Room1", "Room2", "Room3", }, schedule: []model.Event{ { UUID: "testUUID", Day: "Montag", Week: "52", Start: types.DateTime{}, End: types.DateTime{}, Name: "Secret", EventType: "V", Prof: "Prof. Dr. Secret", Rooms: "Room4", Notes: "Secret", }, }, }, want: []string{ "Room1", "Room2", "Room3", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := removeRoomsThatHaveEvents(tt.args.rooms, tt.args.schedule); !reflect.DeepEqual(got, tt.want) { t.Errorf("removeRoomsThatHaveEvents() = %v, want %v", got, tt.want) } }) } } func Test_encodeRoomSchedule(t *testing.T) { testTime, _ := time.Parse(time.RFC3339, "2024-12-24T12:00:00Z") testDateTime, _ := types.ParseDateTime(testTime) testDateTime_m15, _ := types.ParseDateTime(testTime.Add(-time.Minute * 15)) testDateTime_p10, _ := types.ParseDateTime(testTime.Add(time.Minute * 10)) testDateTime_p15, _ := types.ParseDateTime(testTime.Add(time.Minute * 15)) testDateTime_p30, _ := types.ParseDateTime(testTime.Add(time.Minute * 30)) testDateTime_p45, _ := types.ParseDateTime(testTime.Add(time.Minute * 45)) testDateTime_late, _ := types.ParseDateTime(testTime.Add(time.Hour * 100)) type args struct { roomSchedule []model.AnonymizedEventDTO start time.Time granularity int blockCount int } tests := []struct { name string args args want []byte wantErr bool }{ { name: "encode event without length", args: args{ roomSchedule: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: testDateTime_p10, End: testDateTime_p10, Rooms: "Room", Free: false, }, }, start: testTime, granularity: 15, blockCount: 4, }, want: []byte{ 0x00, }, wantErr: false, }, { name: "ignore event with start time after end time", args: args{ roomSchedule: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: testDateTime_p30, End: testDateTime_p10, Rooms: "Room", Free: false, }, }, start: testTime, granularity: 15, blockCount: 4, }, want: []byte{ 0x00, }, wantErr: false, }, { name: "encode time table without length", args: args{ roomSchedule: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: testDateTime, End: testDateTime_p10, Rooms: "Room", Free: false, }, }, start: testTime, granularity: 15, blockCount: 0, }, want: []byte{}, wantErr: false, }, { name: "encode time table without events", args: args{ roomSchedule: []model.AnonymizedEventDTO{}, start: testTime, granularity: 15, blockCount: 24, }, want: []byte{ 0x00, 0x00, 0x00, }, wantErr: false, }, { name: "encode time table with single event", args: args{ roomSchedule: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: testDateTime_p30, End: testDateTime_late, Rooms: "Room", Free: false, }, }, start: testTime, granularity: 30, blockCount: 50, }, want: []byte{ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, }, }, { name: "ignore free event", args: args{ roomSchedule: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: testDateTime_p15, End: testDateTime_p45, Rooms: "Room", Free: false, }, { Day: "Montag", Week: "52", Start: testDateTime, End: testDateTime_p30, Rooms: "Room", Free: true, }, }, start: testTime, granularity: 15, blockCount: 50, }, want: []byte{ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, }, { name: "encode time table with multiple events", args: args{ roomSchedule: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: testDateTime, End: testDateTime_p15, Rooms: "Room", Free: false, }, { Day: "Montag", Week: "52", Start: testDateTime_p30, End: testDateTime_p45, Rooms: "Room", Free: false, }, }, start: testTime, granularity: 15, blockCount: 4, }, want: []byte{ 0xA0, }, }, { name: "encode time table with multiple unordered events", args: args{ roomSchedule: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: testDateTime_p30, End: testDateTime_p45, Rooms: "Room", Free: false, }, { Day: "Montag", Week: "52", Start: testDateTime, End: testDateTime_p15, Rooms: "Room", Free: false, }, }, start: testTime, granularity: 15, blockCount: 4, }, want: []byte{ 0xA0, }, }, { name: "encode time table with overlapping events", args: args{ roomSchedule: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: testDateTime_p15, End: testDateTime_p30, Rooms: "Room", Free: false, }, { Day: "Montag", Week: "52", Start: testDateTime, End: testDateTime_p45, Rooms: "Room", Free: false, }, }, start: testTime, granularity: 15, blockCount: 4, }, want: []byte{ 0xE0, }, }, { name: "consider events starting before the start time", args: args{ roomSchedule: []model.AnonymizedEventDTO{ { Day: "Montag", Week: "52", Start: testDateTime_m15, End: testDateTime_p15, Rooms: "Room", Free: false, }, }, start: testTime, granularity: 15, blockCount: 4, }, want: []byte{ 0x80, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := encodeRoomSchedule(tt.args.roomSchedule, tt.args.start, tt.args.granularity, tt.args.blockCount) if (err != nil) != tt.wantErr { t.Errorf("encodeRoomSchedule() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("encodeRoomSchedule() = %v, want %v", got, tt.want) } }) } }