Skip to content

Commit fb18177

Browse files
authored
Make RecurrencePattern.Count, .Interval and WeekDay.Offset nullable to avoid using MinValue as magic number. (#667)
* Make `RucrrencePattern.Count` nullable to avoid using magic number `int.MinValue`. * Make `RucrrencePattern.Interval` nullable to avoid using magic number `int.MinValue`. * Make `WeekDay.Offset` nullable to avoid using `int.MinValue` as magic number. * Remove obsolete method `RecurrencePatternSerializer.CheckRange` * Test: Add WeekDay-related tests.
1 parent 7e451ba commit fb18177

File tree

8 files changed

+78
-35
lines changed

8 files changed

+78
-35
lines changed

Ical.Net.Tests/DataTypeTest.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Licensed under the MIT license.
44
//
55

6+
using System.Collections.Generic;
67
using Ical.Net.DataTypes;
78
using NUnit.Framework;
89

@@ -23,4 +24,35 @@ public void AttachmentConstructorMustAcceptNull()
2324
Assert.DoesNotThrow(() => { var o = new Attachment((byte[]) null); });
2425
Assert.DoesNotThrow(() => { var o = new Attachment((string) null); });
2526
}
26-
}
27+
28+
public static IEnumerable<TestCaseData> TestWeekDayEqualsTestCases => [
29+
new(new WeekDay("MO"), new WeekDay("1MO")),
30+
new(new WeekDay("1TU"), new WeekDay("-1TU")),
31+
new(new WeekDay("2WE"), new WeekDay("-2WE")),
32+
new(new WeekDay("TH"), new WeekDay("FR")),
33+
new(new WeekDay("-5FR"), new WeekDay("FR")),
34+
new(new WeekDay("SA"), null),
35+
];
36+
37+
[Test, TestCaseSource(nameof(TestWeekDayEqualsTestCases)), Category("DataType")]
38+
public void TestWeekDayEquals(WeekDay w1, WeekDay w2)
39+
{
40+
Assert.Multiple(() =>
41+
{
42+
Assert.That(w1.Equals(w1), Is.True);
43+
Assert.That(w1.Equals(w2), Is.False);
44+
});
45+
}
46+
47+
[Test, TestCaseSource(nameof(TestWeekDayEqualsTestCases)), Category("DataType")]
48+
public void TestWeekDayCompareTo(WeekDay w1, WeekDay w2)
49+
{
50+
Assert.Multiple(() =>
51+
{
52+
Assert.That(w1.CompareTo(w1), Is.EqualTo(0));
53+
54+
if (w2 != null)
55+
Assert.That(w1.CompareTo(w2), Is.Not.EqualTo(0));
56+
});
57+
}
58+
}

Ical.Net/Constants.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,6 @@ public enum FrequencyType
211211
/// </summary>
212212
public enum FrequencyOccurrence
213213
{
214-
None = int.MinValue,
215214
Last = -1,
216215
SecondToLast = -2,
217216
ThirdToLast = -3,
@@ -374,4 +373,4 @@ public static class RegexDefaults
374373
/// The default timeout for regular expressions.
375374
/// </summary>
376375
public static readonly TimeSpan Timeout = TimeSpan.FromMilliseconds(TimeoutMilliseconds);
377-
}
376+
}

Ical.Net/DataTypes/RecurrencePattern.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace Ical.Net.DataTypes;
2020
/// </summary>
2121
public class RecurrencePattern : EncodableDataType
2222
{
23-
private int _interval = int.MinValue;
23+
private int? _interval;
2424
#pragma warning disable 0618
2525
private RecurrenceRestrictionType? _restrictionType;
2626
private RecurrenceEvaluationModeType? _evaluationMode;
@@ -29,7 +29,7 @@ public class RecurrencePattern : EncodableDataType
2929

3030
public DateTime? Until { get; set; }
3131

32-
public int Count { get; set; } = int.MinValue;
32+
public int? Count { get; set; }
3333

3434
/// <summary>
3535
/// Specifies how often the recurrence should repeat.
@@ -39,9 +39,7 @@ public class RecurrencePattern : EncodableDataType
3939
/// </summary>
4040
public int Interval
4141
{
42-
get => _interval == int.MinValue
43-
? 1
44-
: _interval;
42+
get => _interval ?? 1;
4543
set => _interval = value;
4644
}
4745

@@ -181,7 +179,7 @@ public override int GetHashCode()
181179
#pragma warning restore 0618
182180
hashCode = (hashCode * 397) ^ (int) Frequency;
183181
hashCode = (hashCode * 397) ^ Until.GetHashCode();
184-
hashCode = (hashCode * 397) ^ Count;
182+
hashCode = (hashCode * 397) ^ (Count ?? 0);
185183
hashCode = (hashCode * 397) ^ (int) FirstDayOfWeek;
186184
hashCode = (hashCode * 397) ^ CollectionHelpers.GetHashCode(BySecond);
187185
hashCode = (hashCode * 397) ^ CollectionHelpers.GetHashCode(ByMinute);

Ical.Net/DataTypes/WeekDay.cs

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

66
using System;
7+
using System.Collections.Generic;
78
using System.IO;
89
using Ical.Net.Serialization.DataTypes;
910

@@ -14,14 +15,12 @@ namespace Ical.Net.DataTypes;
1415
/// </summary>
1516
public class WeekDay : EncodableDataType
1617
{
17-
public virtual int Offset { get; set; } = int.MinValue;
18+
public virtual int? Offset { get; set; }
1819

1920
public virtual DayOfWeek DayOfWeek { get; set; }
2021

2122
public WeekDay()
22-
{
23-
Offset = int.MinValue;
24-
}
23+
{ }
2524

2625
public WeekDay(DayOfWeek day) : this()
2726
{
@@ -52,7 +51,7 @@ public override bool Equals(object obj)
5251
return ds.Offset == Offset && ds.DayOfWeek == DayOfWeek;
5352
}
5453

55-
public override int GetHashCode() => Offset.GetHashCode() ^ DayOfWeek.GetHashCode();
54+
public override int GetHashCode() => (Offset ?? 0).GetHashCode() ^ DayOfWeek.GetHashCode();
5655

5756
/// <inheritdoc/>
5857
public override void CopyFrom(ICopyable obj)
@@ -81,8 +80,8 @@ public int CompareTo(object obj)
8180
var compare = DayOfWeek.CompareTo(weekday.DayOfWeek);
8281
if (compare == 0)
8382
{
84-
compare = Offset.CompareTo(weekday.Offset);
83+
compare = Comparer<int?>.Default.Compare(Offset, weekday.Offset);
8584
}
8685
return compare;
8786
}
88-
}
87+
}

Ical.Net/Evaluation/RecurrencePatternEvaluator.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,14 +221,18 @@ private IEnumerable<DateTime> GetDates(IDateTime seed, DateTime? periodStart, Da
221221

222222
// optimize the start time for selecting candidates
223223
// (only applicable where a COUNT is not specified)
224-
if (pattern.Count == int.MinValue)
224+
if (pattern.Count is null)
225225
{
226226
var incremented = seedCopy;
227227
while (incremented < periodStart)
228228
{
229229
seedCopy = incremented;
230230
IncrementDate(ref incremented, pattern, pattern.Interval);
231231
}
232+
} else
233+
{
234+
if (pattern.Count < 1)
235+
throw new Exception("Count must be greater than 0");
232236
}
233237

234238
// Do the enumeration in a separate method, as it is a generator method that is
@@ -256,7 +260,7 @@ private IEnumerable<DateTime> EnumerateDates(DateTime originalDate, DateTime see
256260
break;
257261
}
258262

259-
if (pattern.Count >= 1 && dateCount >= pattern.Count)
263+
if (dateCount >= pattern.Count)
260264
{
261265
break;
262266
}
@@ -281,7 +285,7 @@ private IEnumerable<DateTime> EnumerateDates(DateTime originalDate, DateTime see
281285
// from the previous year.
282286
//
283287
// exclude candidates that start at the same moment as periodEnd if the period is a range but keep them if targeting a specific moment
284-
if (pattern.Count >= 1 && dateCount >= pattern.Count)
288+
if (dateCount >= pattern.Count)
285289
{
286290
break;
287291
}
@@ -747,9 +751,9 @@ private static int GetWeekDayOffset(DateTime date, DayOfWeek startOfWeek)
747751
/// </summary>
748752
/// <param name="dates">The list from which to extract the element.</param>
749753
/// <param name="offset">The position of the element to extract.</param>
750-
private List<DateTime> GetOffsetDates(List<DateTime> dates, int offset)
754+
private List<DateTime> GetOffsetDates(List<DateTime> dates, int? offset)
751755
{
752-
if (offset == int.MinValue)
756+
if (offset is null)
753757
{
754758
return dates;
755759
}
@@ -758,11 +762,11 @@ private List<DateTime> GetOffsetDates(List<DateTime> dates, int offset)
758762
var size = dates.Count;
759763
if (offset < 0 && offset >= -size)
760764
{
761-
offsetDates.Add(dates[size + offset]);
765+
offsetDates.Add(dates[size + offset.Value]);
762766
}
763767
else if (offset > 0 && offset <= size)
764768
{
765-
offsetDates.Add(dates[offset - 1]);
769+
offsetDates.Add(dates[offset.Value - 1]);
766770
}
767771
return offsetDates;
768772
}

Ical.Net/Evaluation/TodoEvaluator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private void DetermineStartingRecurrence(PeriodList rdate, ref IDateTime referen
6565

6666
private void DetermineStartingRecurrence(RecurrencePattern recur, ref IDateTime referenceDateTime)
6767
{
68-
if (recur.Count != int.MinValue)
68+
if (recur.Count.HasValue)
6969
{
7070
referenceDateTime = Todo.Start.Copy<IDateTime>();
7171
}

Ical.Net/Serialization/DataTypes/RecurrencePatternSerializer.cs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,24 @@ public virtual void CheckRange(string name, int value, int min, int max)
6464
CheckRange(name, value, min, max, allowZero);
6565
}
6666

67+
public virtual void CheckRange(string name, int? value, int min, int max)
68+
{
69+
var allowZero = min == 0 || max == 0;
70+
CheckRange(name, value, min, max, allowZero);
71+
}
72+
6773
public virtual void CheckRange(string name, int value, int min, int max, bool allowZero)
6874
{
69-
if (value != int.MinValue && (value < min || value > max || (!allowZero && value == 0)))
75+
if ((value < min || value > max || (!allowZero && value == 0)))
76+
{
77+
throw new ArgumentException(name + " value " + value + " is out of range. Valid values are between " + min + " and " + max +
78+
(allowZero ? "" : ", excluding zero (0)") + ".");
79+
}
80+
}
81+
82+
public virtual void CheckRange(string name, int? value, int min, int max, bool allowZero)
83+
{
84+
if (value != null && (value < min || value > max || (!allowZero && value == 0)))
7085
{
7186
throw new ArgumentException(name + " value " + value + " is out of range. Valid values are between " + min + " and " + max +
7287
(allowZero ? "" : ", excluding zero (0)") + ".");
@@ -133,11 +148,6 @@ public override string SerializeToString(object obj)
133148
//every week for a WEEKLY rule, every month for a MONTHLY rule and
134149
//every year for a YEARLY rule.
135150
var interval = recur.Interval;
136-
if (interval == int.MinValue)
137-
{
138-
interval = 1;
139-
}
140-
141151
if (interval != 1)
142152
{
143153
values.Add("INTERVAL=" + interval);
@@ -160,7 +170,7 @@ public override string SerializeToString(object obj)
160170
values.Add("WKST=" + Enum.GetName(typeof(DayOfWeek), recur.FirstDayOfWeek).ToUpper().Substring(0, 2));
161171
}
162172

163-
if (recur.Count != int.MinValue)
173+
if (recur.Count.HasValue)
164174
{
165175
values.Add("COUNT=" + recur.Count);
166176
}
@@ -410,11 +420,12 @@ public override object Deserialize(TextReader tr)
410420
}
411421
else if ((match = RelativeDaysOfWeek.Match(item)).Success)
412422
{
413-
var num = int.MinValue;
423+
int? num = null;
414424
if (match.Groups["Num"].Success)
415425
{
416-
if (int.TryParse(match.Groups["Num"].Value, out num))
426+
if (int.TryParse(match.Groups["Num"].Value, out var n))
417427
{
428+
num = n;
418429
if (match.Groups["Last"].Success)
419430
{
420431
// Make number negative

Ical.Net/Serialization/DataTypes/WeekDaySerializer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public override string SerializeToString(object obj)
2626
}
2727

2828
var value = string.Empty;
29-
if (ds.Offset != int.MinValue)
29+
if (ds.Offset.HasValue)
3030
{
3131
value += ds.Offset;
3232
}
@@ -64,4 +64,4 @@ public override object Deserialize(TextReader tr)
6464
ds.DayOfWeek = RecurrencePatternSerializer.GetDayOfWeek(match.Groups[3].Value);
6565
return ds;
6666
}
67-
}
67+
}

0 commit comments

Comments
 (0)