Skip to content

Commit 2e3fe85

Browse files
authored
Test: Run recurrence test cases from the libical project and introduce generic file-based test cases. (#617)
* Copy icalrecur_test.out from https://github.com/libical/libical/blob/cfd401b9d043214395888de1d9daf52263e3245b/src/test/icalrecur_test.out * Test: Introduce tests based on the RRULE test cases from the libical project. 14/70 failing. * icalrecur_test: Deactivate failing tests for now. * Test: Introduce file-based recurrence test cases with an example test.
1 parent 2146ea0 commit 2e3fe85

File tree

8 files changed

+540
-2
lines changed

8 files changed

+540
-2
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Monday and Thursday, 3 times.
2+
RRULE:FREQ=WEEKLY;BYDAY=MO,TH;COUNT=3
3+
DTSTART:20241024
4+
INSTANCES:20241024,20241028,20241031

Ical.Net.Tests/Ical.Net.Tests.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
<ProjectReference Include="..\Ical.Net\Ical.Net.csproj" />
1919
</ItemGroup>
2020
<ItemGroup>
21-
<EmbeddedResource Include="Calendars\**\*.ics" />
21+
<EmbeddedResource Include="Calendars\**\*" />
22+
</ItemGroup>
23+
<ItemGroup>
24+
<EmbeddedResource Include="contrib\libical\icalrecur_test.out" />
2225
</ItemGroup>
2326
<ItemGroup>
2427
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />

Ical.Net.Tests/IcsFiles.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,5 +158,10 @@ internal static string ReadStream(string manifestResource)
158158
internal static string YearlyCountByMonth1 => ReadStream("Ical.Net.Tests.Calendars.Recurrence.YearlyCountByMonth1.ics");
159159
internal static string YearlyCountByYearDay1 => ReadStream("Ical.Net.Tests.Calendars.Recurrence.YearlyCountByYearDay1.ics");
160160
internal static string YearlyInterval1 => ReadStream("Ical.Net.Tests.Calendars.Recurrence.YearlyInterval1.ics");
161+
162+
internal static string RecurrrenceTestCases => ReadStream("Ical.Net.Tests.Calendars.Recurrence.RecurrenceTestCases.txt");
163+
164+
internal static string LibicalIcalrecurTest => ReadStream("Ical.Net.Tests.contrib.libical.icalrecur_test.out");
165+
161166
}
162167
}

Ical.Net.Tests/RecurrenceTests.cs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3677,5 +3677,116 @@ public void InclusiveRruleUntil()
36773677
var occurrences = firstEvent.GetOccurrences(startSearch, endSearch);
36783678
Assert.That(occurrences, Has.Count.EqualTo(5));
36793679
}
3680+
3681+
public class RecurrenceTestCase
3682+
{
3683+
public int LineNumber { get; set; }
3684+
3685+
public string RRule { get; set; }
3686+
3687+
public CalDateTime DtStart { get; set; }
3688+
3689+
public CalDateTime StartAt { get; set; }
3690+
3691+
public IReadOnlyList<CalDateTime> Instances { get; set; }
3692+
3693+
public override string ToString()
3694+
=> $"Line {LineNumber}: {DtStart}, {RRule}";
3695+
}
3696+
3697+
private static IEnumerable<RecurrenceTestCase> ParseTestCaseFile(string fileContent)
3698+
{
3699+
RecurrenceTestCase current = null;
3700+
3701+
var rd = new StringReader(fileContent);
3702+
var lineNo = 0;
3703+
3704+
for (string line = rd.ReadLine(); line != null; line = rd.ReadLine())
3705+
{
3706+
lineNo++;
3707+
3708+
if (string.IsNullOrEmpty(line))
3709+
{
3710+
if (current != null)
3711+
{
3712+
yield return current;
3713+
current = null;
3714+
}
3715+
continue;
3716+
}
3717+
3718+
if (line.StartsWith("#"))
3719+
continue;
3720+
3721+
current = current ?? new RecurrenceTestCase();
3722+
3723+
var m = Regex.Match(line, @"^(?<h>[A-Z-]+):(?<v>.*)$");
3724+
if (!m.Success)
3725+
continue;
3726+
3727+
var hdr = m.Groups["h"].Value;
3728+
var val = m.Groups["v"].Value;
3729+
3730+
switch (hdr)
3731+
{
3732+
case "RRULE":
3733+
current.RRule = val;
3734+
current.LineNumber = lineNo;
3735+
break;
3736+
3737+
case "DTSTART":
3738+
current.DtStart = new CalDateTime(val) { TzId = "UTC" };
3739+
break;
3740+
3741+
case "START-AT":
3742+
current.StartAt = new CalDateTime(val) { TzId = "UTC" };
3743+
break;
3744+
3745+
case "INSTANCES":
3746+
current.Instances = val.Split(',').Select(dt => new CalDateTime(dt) { TzId = "UTC" }).ToList();
3747+
break;
3748+
}
3749+
}
3750+
3751+
if (current != null)
3752+
yield return current;
3753+
}
3754+
3755+
private static IEnumerable<RecurrenceTestCase> TestLibicalTestCasesSource
3756+
=> ParseTestCaseFile(IcsFiles.LibicalIcalrecurTest);
3757+
3758+
[TestCaseSource(nameof(TestLibicalTestCasesSource))]
3759+
public void TestLibicalTestCases(RecurrenceTestCase testCase)
3760+
=> ExecuteRecurrenceTestCase(testCase);
3761+
3762+
private static IEnumerable<RecurrenceTestCase> TestFileBasedRecurrenceTestCaseSource
3763+
=> ParseTestCaseFile(IcsFiles.RecurrrenceTestCases);
3764+
3765+
[TestCaseSource(nameof(TestFileBasedRecurrenceTestCaseSource))]
3766+
public void TestFileBasedRecurrenceTestCase(RecurrenceTestCase testCase)
3767+
=> ExecuteRecurrenceTestCase(testCase);
3768+
3769+
public void ExecuteRecurrenceTestCase(RecurrenceTestCase testCase)
3770+
{
3771+
Calendar cal = new Calendar();
3772+
3773+
CalendarEvent evt = cal.Create<CalendarEvent>();
3774+
evt.Summary = "Event summary";
3775+
3776+
// Start at midnight, UTC time
3777+
evt.Start = testCase.DtStart;
3778+
evt.RecurrenceRules.Add(new RecurrencePattern(testCase.RRule)
3779+
{
3780+
RestrictionType = RecurrenceRestrictionType.NoRestriction,
3781+
});
3782+
3783+
var occurrences = evt.GetOccurrences(testCase.StartAt?.Value ?? DateTime.MinValue, DateTime.MaxValue)
3784+
.OrderBy(x => x)
3785+
.ToList();
3786+
3787+
var startDates = occurrences.Select(x => x.Period.StartTime).ToList();
3788+
3789+
Assert.That(startDates, Is.EqualTo(testCase.Instances));
3790+
}
36803791
}
36813792
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
libical is distributed under two licenses.
2+
You may choose the terms of either:
3+
4+
* The Mozilla Public License (MPL) v2.0
5+
6+
or
7+
8+
* The GNU Lesser General Public License (LGPL) v2.1
9+
10+
----------------------------------------------------------------------
11+
12+
Software distributed under these licenses is distributed on an "AS
13+
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14+
implied. See the License for the specific language governing rights
15+
and limitations under the License.
16+
Libical is distributed under both the LGPL and the MPL. The MPL
17+
notice, reproduced below, covers the use of either of the licenses.
18+
19+
----------------------------------------------------------------------
20+
21+
The Original Code is libical.
22+
23+
The Initial Developer of the Original Code is Eric Busboom
24+
25+
All Rights Reserved.
26+
27+
Contributor(s): See individual source files.
28+
29+
Copyright: The libical developers
30+
31+
32+
The project that contains this LICENSE.txt file (ICal.Net) uses the code under the
33+
Mozilla Public License (MPL) v2.0.

0 commit comments

Comments
 (0)