Skip to content

Commit 8672357

Browse files
committed
Failing to calculate Period.EffectiveEndTime throw EvaluationOutOfRangeException
This exception is more accurate than System.ArgumentOutOfRangeException
1 parent 7d5d6d8 commit 8672357

File tree

3 files changed

+26
-21
lines changed

3 files changed

+26
-21
lines changed

Ical.Net.Tests/RecurrenceTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3097,7 +3097,7 @@ public void Test4()
30973097
RDATE;TZID=America/Chicago:99991231T221000
30983098
END:VEVENT
30993099
END:VCALENDAR
3100-
""")]
3100+
""", true)]
31013101

31023102
// y10k exceeded due to the event duration
31033103
[TestCase("""
@@ -3108,7 +3108,7 @@ public void Test4()
31083108
RRULE:FREQ=DAILY;BYHOUR=22,23;COUNT=2
31093109
END:VEVENT
31103110
END:VCALENDAR
3111-
""")]
3111+
""", false)]
31123112

31133113
// Events are merged in different places than individual RRULES of a single event
31143114
[TestCase("""
@@ -3120,11 +3120,11 @@ public void Test4()
31203120
DTSTART;TZID=America/Chicago:99991231T221000
31213121
END:VEVENT
31223122
END:VCALENDAR
3123-
""")]
3124-
public void Recurrence_WithOutOfBoundsUtc_ShouldFailWithCorrectException(string ical)
3123+
""", true)]
3124+
public void Recurrence_WithOutOfBoundsUtc_ShouldFailWithCorrectException(string ical, bool shouldThrow)
31253125
{
31263126
var cal = Calendar.Load(ical)!;
3127-
Assert.That(() => cal.GetOccurrences().ToList(), Throws.InstanceOf<EvaluationOutOfRangeException>());
3127+
Assert.That(() => cal.GetOccurrences().ToList(), shouldThrow ? Throws.InstanceOf<EvaluationOutOfRangeException>() : Throws.Nothing);
31283128
}
31293129

31303130
[Test, Category("Recurrence")]
@@ -3790,7 +3790,7 @@ Type LoadType(string name) =>
37903790

37913791
if (testCase.ExceptionStep == RecurrenceTestExceptionStep.Enumeration)
37923792
{
3793-
Assert.That(() => EnumerateOccurrences(), throwsConstraint);
3793+
Assert.That(() => EnumerateOccurrences().Last().Period.EffectiveEndTime, throwsConstraint);
37943794
return;
37953795
}
37963796

Ical.Net/DataTypes/Period.cs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55

66
using System;
7+
using Ical.Net.Evaluation;
78
using Ical.Net.Serialization.DataTypes;
89

910
namespace Ical.Net.DataTypes;
@@ -164,17 +165,27 @@ public override int GetHashCode()
164165
/// </summary>
165166
public virtual CalDateTime? EffectiveEndTime
166167
{
167-
get
168-
{
169-
var effectiveDuration = EffectiveDuration;
170-
return _endTime switch
168+
get =>
169+
_endTime switch
171170
{
172171
null when _duration is null => null,
173172
{ } endTime => endTime,
174-
_ => effectiveDuration is not null
175-
? _startTime.Add(effectiveDuration.Value)
176-
: null
173+
_ => CalculateEndTime()
177174
};
175+
}
176+
177+
private CalDateTime CalculateEndTime()
178+
{
179+
try
180+
{
181+
// When invoked, _duration is not null, so EffectiveDuration
182+
// is guaranteed to be non-null
183+
return _startTime.Add(EffectiveDuration!.Value);
184+
}
185+
catch (ArgumentOutOfRangeException)
186+
{
187+
// intentionally don't include the outer exception
188+
throw new EvaluationOutOfRangeException($"Calculating the end time of the period from start time '{_startTime}' and effective duration '{EffectiveDuration}' resulted in an out-of-range value.");
178189
}
179190
}
180191

@@ -191,17 +202,15 @@ public virtual CalDateTime? EffectiveEndTime
191202
/// </summary>
192203
public virtual Duration? EffectiveDuration
193204
{
194-
get
195-
{
196-
return _duration switch
205+
get =>
206+
_duration switch
197207
{
198208
null when _endTime is null => null,
199209
{ } d => d,
200210
_ => _endTime is { } endTime
201211
? endTime.Subtract(_startTime)
202212
: null
203213
};
204-
}
205214
}
206215

207216
internal string? TzId => _startTime.TzId; // same timezone for start and end

Ical.Net/Evaluation/EventEvaluator.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,6 @@ and it may differ from the time span added to the period start time.
7979
start: period.StartTime,
8080
duration: duration.Value);
8181

82-
// Ensure that adding the duration to the start time
83-
// results in a representable date/time
84-
_ = newPeriod.EffectiveEndTime;
85-
8682
return newPeriod;
8783
}
8884
catch (ArgumentOutOfRangeException)

0 commit comments

Comments
 (0)