Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type of RecurrencePattern.Until is CalDateTime #723

Merged
merged 1 commit into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ INSTANCES:20241024,20241028,20241031

# Illegal rule part with multiple '='
RRULE:FREQ=WEEKLY;BYDAY=MO=;COUNT=3
EXCEPTION:System.ArgumentException
EXCEPTION:System.ArgumentOutOfRangeException

# The first date belongs to 2009, so after 6 years it will be 2015, which has a week 53.
RRULE:FREQ=YEARLY;BYWEEKNO=53;BYDAY=TU,SA;INTERVAL=6;UNTIL=20170101T000000Z
Expand Down
14 changes: 8 additions & 6 deletions Ical.Net.Tests/MatchTimeZoneTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System;
using System.Linq;
using Ical.Net.DataTypes;
using Ical.Net.Utility;
using NUnit.Framework;

namespace Ical.Net.Tests;
Expand Down Expand Up @@ -36,7 +37,7 @@ public void MatchTimeZone_LocalTimeUsaWithTimeZone()
var evt = calendar.Events.First();
var until = evt.RecurrenceRules.First().Until;

var expectedUntil = new DateTime(2023, 11, 05, 13, 00, 00, DateTimeKind.Utc);
var expectedUntil = new CalDateTime(2023, 11, 05, 13, 00, 00, CalDateTime.UtcTzId);
var occurrences = evt.GetOccurrences(new CalDateTime(2023, 11, 01), new CalDateTime(2023, 11, 06));

Assert.Multiple(() =>
Expand Down Expand Up @@ -85,7 +86,8 @@ public void MatchTimeZone_LocalTimeAustraliaWithTimeZone(string inputUntil, int
var expectedUntil = DateTime.ParseExact(inputUntil, "yyyyMMddTHHmmssZ",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.AssumeUniversal |
System.Globalization.DateTimeStyles.AdjustToUniversal);
System.Globalization.DateTimeStyles.AdjustToUniversal).AsCalDateTime();

var occurrences = evt.GetOccurrences(new CalDateTime(2024, 10, 01), new CalDateTime(2024, 10, 07));

Assert.Multiple(() =>
Expand Down Expand Up @@ -130,7 +132,7 @@ public void MatchTimeZone_UTCTime()
var evt = calendar.Events.First();
var until = evt.RecurrenceRules.First().Until;

var expectedUntil = new DateTime(2023, 11, 05, 09, 00, 00, DateTimeKind.Utc);
var expectedUntil = new CalDateTime(2023, 11, 05, 09, 00, 00, CalDateTime.UtcTzId);
var occurrences = evt.GetOccurrences(new CalDateTime(2023, 11, 01), new CalDateTime(2023, 11, 06));

Assert.Multiple(() =>
Expand Down Expand Up @@ -163,7 +165,7 @@ public void MatchTimeZone_FloatingTime()
var evt = calendar.Events.First();
var until = evt.RecurrenceRules.First().Until;

var expectedUntil = new DateTime(2023, 11, 05, 09, 00, 00, DateTimeKind.Unspecified);
var expectedUntil = new CalDateTime(2023, 11, 05, 09, 00, 00, null);
var occurrences = evt.GetOccurrences(new CalDateTime(2023, 11, 01), new CalDateTime(2023, 11, 06));

Assert.Multiple(() =>
Expand Down Expand Up @@ -197,7 +199,7 @@ public void MatchTimeZone_LocalTimeNoTimeZone()
var evt = calendar.Events.First();
var until = evt.RecurrenceRules.First().Until;

var expectedUntil = new DateTime(2023, 11, 05, 09, 00, 00, DateTimeKind.Unspecified);
var expectedUntil = new CalDateTime(2023, 11, 05, 09, 00, 00, null);
var occurrences = evt.GetOccurrences(new CalDateTime(2023, 11, 01), new CalDateTime(2023, 11, 06));

Assert.Multiple(() =>
Expand Down Expand Up @@ -230,7 +232,7 @@ public void MatchTimeZone_DateOnly()
var evt = calendar.Events.First();
var until = evt.RecurrenceRules.First().Until;

var expectedUntil = new DateTime(2023, 11, 05, 00, 00, 00, DateTimeKind.Unspecified);
var expectedUntil = new CalDateTime(2023, 11, 05);
var occurrences = evt.GetOccurrences(new CalDateTime(2023, 11, 01), new CalDateTime(2023, 11, 06));

Assert.Multiple(() =>
Expand Down
129 changes: 48 additions & 81 deletions Ical.Net.Tests/RecurrenceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
new CalDateTime(2006, 1, 1),
new CalDateTime(2011, 1, 1)).OrderBy(o => o.Period.StartTime).ToList();

CalDateTime dt = new CalDateTime(2007, 1, 1, 8, 30, 0, _tzid);
var dt = new CalDateTime(2007, 1, 1, 8, 30, 0, _tzid);
var i = 0;

while (dt.Year < 2011)
Expand Down Expand Up @@ -153,7 +153,7 @@
new CalDateTime(1997, 9, 1),
new CalDateTime(1998, 1, 1)).OrderBy(o => o.Period.StartTime).ToList();

CalDateTime dt = new CalDateTime(1997, 9, 2, 9, 0, 0, _tzid);
var dt = new CalDateTime(1997, 9, 2, 9, 0, 0, _tzid);
var i = 0;
while (dt.Year < 1998)
{
Expand Down Expand Up @@ -325,7 +325,7 @@
new CalDateTime(1998, 1, 1),
new CalDateTime(2000, 12, 31)).OrderBy(o => o.Period.StartTime).ToList();

CalDateTime dt = new CalDateTime(1998, 1, 1, 9, 0, 0, _tzid);
var dt = new CalDateTime(1998, 1, 1, 9, 0, 0, _tzid);
var i = 0;
while (dt.Year < 2001)
{
Expand Down Expand Up @@ -2659,18 +2659,16 @@
[Test, Category("Recurrence")]
public void Bug3119920()
{
using (var sr = new StringReader("FREQ=WEEKLY;UNTIL=20251126T120000;INTERVAL=1;BYDAY=MO"))
{
var start = new CalDateTime(2010, 11, 27, 9, 0, 0);
var serializer = new RecurrencePatternSerializer();
var rp = (RecurrencePattern)serializer.Deserialize(sr);
var rpe = new RecurrencePatternEvaluator(rp);
var recurringPeriods = rpe.Evaluate(new CalDateTime(start), start, rp.Until?.AsCalDateTime(), false).ToList();
using var sr = new StringReader("FREQ=WEEKLY;UNTIL=20251126T120000;INTERVAL=1;BYDAY=MO");
var start = new CalDateTime(2010, 11, 27, 9, 0, 0);
var serializer = new RecurrencePatternSerializer();
var rp = (RecurrencePattern)serializer.Deserialize(sr);
var rpe = new RecurrencePatternEvaluator(rp);
var recurringPeriods = rpe.Evaluate(start, start, rp.Until, false).ToList();

var period = recurringPeriods.ElementAt(recurringPeriods.Count - 1);
var period = recurringPeriods.ElementAt(recurringPeriods.Count - 1);

Assert.That(period.StartTime, Is.EqualTo(new CalDateTime(2025, 11, 24, 9, 0, 0)));
}
Assert.That(period.StartTime, Is.EqualTo(new CalDateTime(2025, 11, 24, 9, 0, 0)));
}

/// <summary>
Expand All @@ -2690,7 +2688,7 @@
var pattern = new RecurrencePattern
{
Frequency = FrequencyType.Monthly,
Until = new DateTime(2011, 12, 25, 0, 0, 0, DateTimeKind.Utc),
Until = new CalDateTime(2011, 12, 25, 0, 0, 0, CalDateTime.UtcTzId),
FirstDayOfWeek = DayOfWeek.Sunday,
ByMonthDay = new List<int>(new[] { 29 })
};
Expand All @@ -2708,14 +2706,12 @@
[Test, Category("Recurrence")]
public void Bug3292737()
{
using (var sr = new StringReader("FREQ=WEEKLY;UNTIL=20251126"))
{
var serializer = new RecurrencePatternSerializer();
var rp = (RecurrencePattern)serializer.Deserialize(sr);
using var sr = new StringReader("FREQ=WEEKLY;UNTIL=20251126");
var serializer = new RecurrencePatternSerializer();
var rp = (RecurrencePattern)serializer.Deserialize(sr);

Assert.That(rp, Is.Not.Null);
Assert.That(rp.Until, Is.EqualTo(new DateTime(2025, 11, 26)));
}
Assert.That(rp, Is.Not.Null);
Assert.That(rp.Until, Is.EqualTo(new CalDateTime(2025, 11, 26)));
}

/// <summary>
Expand All @@ -2728,7 +2724,7 @@
var rrule = new RecurrencePattern
{
Frequency = FrequencyType.Daily,
Until = DateTime.Today.AddMonths(4),
Until = CalDateTime.Today.AddMonths(4)
};
var vEvent = new CalendarEvent
{
Expand Down Expand Up @@ -2842,9 +2838,9 @@
[TestCase("DAILY", 24 * 3600, false)]
public void Evaluate1(string freq, int secsPerInterval, bool hasTime)
{
Calendar cal = new Calendar();
var cal = new Calendar();

CalendarEvent evt = cal.Create<CalendarEvent>();
var evt = cal.Create<CalendarEvent>();
evt.Summary = "Event summary";

// Start at midnight, UTC time
Expand Down Expand Up @@ -2931,8 +2927,8 @@
[Test, Category("Recurrence")]
public void GetOccurrences1()
{
Calendar cal = new Calendar();
CalendarEvent evt = cal.Create<CalendarEvent>();
var cal = new Calendar();
var evt = cal.Create<CalendarEvent>();
evt.Start = new CalDateTime(2009, 11, 18, 5, 0, 0);
evt.End = new CalDateTime(2009, 11, 18, 5, 10, 0);
evt.RecurrenceRules.Add(new RecurrencePattern(FrequencyType.Daily));
Expand Down Expand Up @@ -2976,12 +2972,12 @@
[Test, Category("Recurrence")]
public void Test1()
{
Calendar cal = new Calendar();
CalendarEvent evt = cal.Create<CalendarEvent>();
var cal = new Calendar();
var evt = cal.Create<CalendarEvent>();
evt.Summary = "Event summary";
evt.Start = new CalDateTime(DateTime.SpecifyKind(DateTime.Today, DateTimeKind.Utc));

RecurrencePattern recur = new RecurrencePattern();
var recur = new RecurrencePattern();
evt.RecurrenceRules.Add(recur);

Assert.That(() =>
Expand All @@ -2993,12 +2989,12 @@
[Test, Category("Recurrence")]
public void Test2()
{
Calendar cal = new Calendar();
CalendarEvent evt = cal.Create<CalendarEvent>();
var cal = new Calendar();
var evt = cal.Create<CalendarEvent>();
evt.Summary = "Event summary";
evt.Start = new CalDateTime(DateTime.SpecifyKind(DateTime.Today, DateTimeKind.Utc));

RecurrencePattern recur = new RecurrencePattern();
var recur = new RecurrencePattern();
recur.Frequency = FrequencyType.Daily;
recur.Count = 3;
recur.ByDay.Add(new WeekDay(DayOfWeek.Monday));
Expand All @@ -3015,14 +3011,14 @@
[Test, Category("Recurrence")]
public void Test4()
{
RecurrencePattern rpattern = new RecurrencePattern();
var rpattern = new RecurrencePattern();
rpattern.ByDay.Add(new WeekDay(DayOfWeek.Saturday));
rpattern.ByDay.Add(new WeekDay(DayOfWeek.Sunday));

rpattern.Frequency = FrequencyType.Weekly;

CalDateTime evtStart = new CalDateTime(2006, 12, 1);
CalDateTime evtEnd = new CalDateTime(2007, 1, 1);
var evtStart = new CalDateTime(2006, 12, 1);
var evtEnd = new CalDateTime(2007, 1, 1);

var evaluator = rpattern.GetService(typeof(IEvaluator)) as IEvaluator;
Assert.That(evaluator, Is.Not.Null);
Expand Down Expand Up @@ -3587,52 +3583,23 @@
});
}

[Test, TestCaseSource(nameof(UntilTimeZoneSerializationTestCases))]
public void UntilTimeZoneSerializationTests(string tzId, DateTimeKind expectedKind)
[TestCase(null, false)]
[TestCase(CalDateTime.UtcTzId, false)]
[TestCase("America/New_York", true)]
public void DisallowedUntilShouldThrow(string? tzId, bool shouldThrow)

Check warning on line 3589 in Ical.Net.Tests/RecurrenceTests.cs

View workflow job for this annotation

GitHub Actions / tests

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 3589 in Ical.Net.Tests/RecurrenceTests.cs

View workflow job for this annotation

GitHub Actions / tests

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 3589 in Ical.Net.Tests/RecurrenceTests.cs

View workflow job for this annotation

GitHub Actions / tests

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 3589 in Ical.Net.Tests/RecurrenceTests.cs

View workflow job for this annotation

GitHub Actions / coverage

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 3589 in Ical.Net.Tests/RecurrenceTests.cs

View workflow job for this annotation

GitHub Actions / coverage

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 3589 in Ical.Net.Tests/RecurrenceTests.cs

View workflow job for this annotation

GitHub Actions / coverage

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
var now = DateTime.SpecifyKind(DateTime.Parse("2017-11-08 10:30:00"), expectedKind);
var later = now.AddHours(1);
var dt = new CalDateTime(2025, 11, 08, 10, 30, 00, tzId);
var recPattern = new RecurrencePattern(FrequencyType.Daily, 1);

var until = DateTime.SpecifyKind(now.AddDays(7), expectedKind);

var rrule = new RecurrencePattern(FrequencyType.Daily)
if (shouldThrow)
{
Until = until,
};
var e = new CalendarEvent
{
Start = new CalDateTime(now, tzId),
End = new CalDateTime(later, tzId)
};
e.RecurrenceRules.Add(rrule);
var calendar = new Calendar
Assert.Throws<ArgumentOutOfRangeException>(() => recPattern.Until = dt);
}
else
{
Events = { e },
};

var serializer = new CalendarSerializer();
var serialized = serializer.SerializeToString(calendar);

const string contains = "20171108T103000";
var expectedContains = expectedKind == DateTimeKind.Unspecified
? $"{contains}{SerializationConstants.LineBreak}"
: $"{contains}Z{SerializationConstants.LineBreak}";

Assert.That(serialized.Contains(expectedContains), Is.True);

var deserializedKind = Calendar.Load(serialized).Events.First().RecurrenceRules.First().Until?.Kind;

Assert.That(deserializedKind, Is.EqualTo(expectedKind));
}

public static IEnumerable UntilTimeZoneSerializationTestCases()
{
yield return new TestCaseData("America/New_York", DateTimeKind.Unspecified)
.SetName("IANA time time zone results in a local DateTimeKind");
yield return new TestCaseData("Eastern Standard Time", DateTimeKind.Unspecified)
.SetName("BCL time zone results in a Local DateTimeKind");
yield return new TestCaseData("UTC", DateTimeKind.Utc)
.SetName("UTC results in DateTimeKind.Utc");
recPattern.Until = dt;
Assert.That(recPattern.Until, Is.EqualTo(dt));
}
}

[Test]
Expand Down Expand Up @@ -3693,7 +3660,7 @@
var rd = new StringReader(fileContent);
var lineNo = 0;

for (string line = rd.ReadLine(); line != null; line = rd.ReadLine())
for (var line = rd.ReadLine(); line != null; line = rd.ReadLine())
{
lineNo++;

Expand Down Expand Up @@ -3766,17 +3733,17 @@

public void ExecuteRecurrenceTestCase(RecurrenceTestCase testCase)
{
Calendar cal = new Calendar();
var cal = new Calendar();

CalendarEvent evt = cal.Create<CalendarEvent>();
var evt = cal.Create<CalendarEvent>();
evt.Summary = "Event summary";

// Start at midnight, UTC time
evt.Start = testCase.DtStart;

if (testCase.Exception != null)
{
var exceptionType = Type.GetType(testCase.Exception);
var exceptionType = Type.GetType(testCase.Exception)!;
Assert.Throws(exceptionType, () => new RecurrencePattern(testCase.RRule));
return;
}
Expand Down
Loading
Loading