Files
2026-02-19 02:09:36 +01:00

112 lines
3.8 KiB
C#

using System.Reflection;
using FluentAssertions;
using Moq;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Calendar;
using Wino.Core.Integration.Processors;
using Wino.Services;
using Xunit;
namespace Wino.Core.Tests.Synchronizers;
public class CalDavEventTimeMappingTests
{
[Fact]
public void ParseCalendarData_UtcEvent_AssignsUtcTimeZone()
{
const string ics = """
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Wino Mail//Tests//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
UID:utc-event
DTSTAMP:20260201T000000Z
DTSTART:20260219T010000Z
DTEND:20260219T020000Z
SUMMARY:UTC Event
END:VEVENT
END:VCALENDAR
""";
var events = ParseEvents(ics);
events.Should().ContainSingle();
events[0].StartTimeZone.Should().Be(TimeZoneInfo.Utc.Id);
events[0].EndTimeZone.Should().Be(TimeZoneInfo.Utc.Id);
}
[Fact]
public async Task ManageCalendarEventAsync_PersistsWallClockTimeForSourceTimeZone()
{
var calendar = new AccountCalendar
{
Id = Guid.NewGuid(),
Name = "Calendar"
};
var remoteEvent = new CalDavCalendarEvent
{
RemoteEventId = "event-1",
Title = "Wall Clock Event",
Start = new DateTimeOffset(2026, 2, 19, 1, 0, 0, TimeSpan.FromHours(1)),
End = new DateTimeOffset(2026, 2, 19, 2, 0, 0, TimeSpan.FromHours(1)),
StartTimeZone = "Europe/Berlin",
EndTimeZone = "Europe/Berlin"
};
CalendarItem? capturedItem = null;
var calendarService = new Mock<ICalendarService>();
calendarService
.Setup(x => x.GetCalendarItemAsync(calendar.Id, remoteEvent.RemoteEventId))
.ReturnsAsync((CalendarItem?)null);
calendarService
.Setup(x => x.CreateNewCalendarItemAsync(It.IsAny<CalendarItem>(), It.IsAny<List<CalendarEventAttendee>>()))
.Callback<CalendarItem, List<CalendarEventAttendee>>((item, _) => capturedItem = item)
.Returns(Task.CompletedTask);
calendarService
.Setup(x => x.SaveRemindersAsync(It.IsAny<Guid>(), It.IsAny<List<Reminder>>()))
.Returns(Task.CompletedTask);
var sut = new ImapChangeProcessor(
Mock.Of<IDatabaseService>(),
Mock.Of<IFolderService>(),
Mock.Of<IMailService>(),
Mock.Of<IAccountService>(),
calendarService.Object,
Mock.Of<IMimeFileService>(),
Mock.Of<ICalendarIcsFileService>());
await sut.ManageCalendarEventAsync(remoteEvent, calendar, organizerAccount: null);
capturedItem.Should().NotBeNull();
var savedItem = capturedItem!;
savedItem.StartDate.Should().Be(new DateTime(2026, 2, 19, 1, 0, 0));
savedItem.DurationInSeconds.Should().Be(3600);
savedItem.StartTimeZone.Should().Be("Europe/Berlin");
savedItem.EndTimeZone.Should().Be("Europe/Berlin");
}
private static List<CalDavCalendarEvent> ParseEvents(string icsContent)
{
var parseMethod = typeof(CalDavClient).GetMethod(
"ParseCalendarData",
BindingFlags.NonPublic | BindingFlags.Static);
parseMethod.Should().NotBeNull();
var result = parseMethod!.Invoke(
null,
[
icsContent,
"https://calendar.example.com/event.ics",
"\"etag\"",
new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero),
new DateTimeOffset(2026, 12, 31, 23, 59, 59, TimeSpan.Zero)
]);
return result.Should().BeOfType<List<CalDavCalendarEvent>>().Subject;
}
}