Skip to content

Commit 0037f5d

Browse files
ig-sinicynandrewvk
authored andcommitted
+ DateTimeCode (#91)
1 parent 70aa608 commit 0037f5d

22 files changed

+1037
-73
lines changed

Build/T4/DebugCodeGenerator.ttinclude

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44

55
private void Run()
66
{
7-
WriteLine(@"using static CodeJam.DebugCode;");
8-
WriteLine("");
9-
107
const string message =
118
"The name of the template should follow the pattern 'Debug' + AssertionFile + '.tt'. " +
129
"The name of the assertion class should be suffixed with 'Code'. " +
@@ -21,8 +18,19 @@
2118
}
2219

2320
var oldClassName = newClassName.Substring("Debug".Length);
24-
Transform(
21+
Run(
2522
oldClassName + ".cs",
23+
oldClassName,
24+
newClassName);
25+
}
26+
27+
private void Run(string fileName, string oldClassName, string newClassName)
28+
{
29+
WriteLine(@"using static CodeJam.DebugCode;");
30+
WriteLine("");
31+
32+
Transform(
33+
fileName,
2634
new ReplaceInfo // Rename the class (add Debug prefix to the name)
2735
{
2836
Pattern = "class " + oldClassName,

Build/T4/Transform.ttinclude

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,24 @@
1010
Normal, Swap, Ignore
1111
}
1212

13+
internal enum MatchMode
14+
{
15+
Normal, WholeWord, WholeLine
16+
}
17+
1318
internal class ReplaceInfo
1419
{
1520
public string Pattern { get; set; }
1621
public string Replacement { get; set; }
1722
public bool ThrowOnFail { get; set; }
18-
public bool WholeWord { get; set; }
1923
public bool EscapePattern { get; set; }
20-
public ReplaceMode Mode { get; set; }
24+
public ReplaceMode Replace { get; set; }
25+
public MatchMode Match { get; set; }
2126

22-
public bool SwapMode => Mode == ReplaceMode.Swap;
23-
public bool IgnoreMode => Mode == ReplaceMode.Ignore;
27+
public bool SwapMode => Replace == ReplaceMode.Swap;
28+
public bool IgnoreMode => Replace == ReplaceMode.Ignore;
29+
public bool WholeWordMode => Match == MatchMode.WholeWord;
30+
public bool WholeLineMode => Match == MatchMode.WholeLine;
2431
}
2532

2633
// ReSharper disable UnusedMember.Local
@@ -43,15 +50,10 @@
4350
var placeholderReplaces = new ConcurrentDictionary<string, string>();
4451
Func<string, ReplaceInfo, string> replaceWithPlaceholdersCore = (text, replaceInfo) =>
4552
{
46-
var pattern = replaceInfo.SwapMode ? replaceInfo.Replacement : replaceInfo.Pattern;
53+
var pattern = PreparePattern(
54+
replaceInfo.SwapMode ? replaceInfo.Replacement : replaceInfo.Pattern,
55+
replaceInfo);
4756
var replacement = replaceInfo.SwapMode ? replaceInfo.Pattern : null;
48-
if (replaceInfo.SwapMode || replaceInfo.EscapePattern)
49-
{
50-
pattern = Regex.Escape(pattern);
51-
}
52-
pattern = replaceInfo.WholeWord
53-
? @"(?<=\W|^)" + pattern + @"(?=\W|$)"
54-
: pattern;
5557

5658
var newText = Regex.Replace(
5759
text,
@@ -66,16 +68,11 @@
6668

6769
Func<string, ReplaceInfo, string> replaceCore = (text, replaceInfo) =>
6870
{
69-
var pattern = replaceInfo.Pattern;
70-
if (replaceInfo.SwapMode || replaceInfo.EscapePattern)
71-
{
72-
pattern = Regex.Escape(pattern);
73-
}
74-
pattern = replaceInfo.WholeWord
75-
? @"(?<=\W|^)" + pattern + @"(?=\W|$)"
76-
: pattern;
77-
78-
var newText = Regex.Replace(text, pattern, replaceInfo.Replacement);
71+
var pattern = PreparePattern(replaceInfo.Pattern, replaceInfo);
72+
var replacement = replaceInfo.Replacement;
73+
74+
var newText = Regex.Replace(text, pattern, replacement);
75+
7976
if (replaceInfo.ThrowOnFail && newText == text)
8077
throw new InvalidOperationException("The match for " + pattern + " not found");
8178

@@ -104,4 +101,22 @@
104101

105102
Write(sourceText);
106103
}
104+
105+
private string PreparePattern(string pattern, ReplaceInfo replaceInfo)
106+
{
107+
if (replaceInfo.SwapMode || replaceInfo.EscapePattern)
108+
{
109+
pattern = Regex.Escape(pattern);
110+
}
111+
112+
pattern = replaceInfo.WholeWordMode
113+
? @"(?<=\W|^)" + pattern + @"(?=\W|$)"
114+
: pattern;
115+
116+
pattern = replaceInfo.WholeLineMode
117+
? @".*" + pattern + @".*[\r\n]+"
118+
: pattern;
119+
120+
return pattern;
121+
}
107122
#>
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
using System;
2+
using System.Diagnostics.CodeAnalysis;
3+
4+
using NUnit.Framework;
5+
6+
namespace CodeJam.Dates
7+
{
8+
[TestFixture(Category = "Assertions")]
9+
[SuppressMessage("ReSharper", "NotResolvedInText")]
10+
public class DateTimeCodeTests
11+
{
12+
[Test]
13+
public void TestDateOnlyAssertion()
14+
{
15+
var dateTimeNow = DateTime.Now;
16+
var dateTimeOffsetNow = DateTimeOffset.Now;
17+
18+
var ex = Assert.Throws<ArgumentException>(() => DateTimeCode.DateOnly(dateTimeNow, "arg00"));
19+
Assert.That(ex.Message, Does.Contain("arg00"));
20+
Assert.That(ex.Message, Does.Contain("argument should be a date without time component"));
21+
22+
ex = Assert.Throws<ArgumentException>(() => DateTimeCode.DateOnly(dateTimeOffsetNow, "arg00"));
23+
Assert.That(ex.Message, Does.Contain("arg00"));
24+
Assert.That(ex.Message, Does.Contain("argument should be a date without time component"));
25+
26+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeNow.Date, "arg00"));
27+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeOffsetNow.Date, "arg00"));
28+
}
29+
30+
[Test]
31+
public void TestDebugDateOnlyAssertion()
32+
{
33+
var dateTimeNow = DateTime.Now;
34+
var dateTimeOffsetNow = DateTimeOffset.Now;
35+
#if DEBUG
36+
var ex = Assert.Throws<ArgumentException>(() => DebugDateTimeCode.DateOnly(dateTimeNow, "arg00"));
37+
Assert.That(ex.Message, Does.Contain("arg00"));
38+
Assert.That(ex.Message, Does.Contain("argument should be a date without time component"));
39+
40+
ex = Assert.Throws<ArgumentException>(() => DebugDateTimeCode.DateOnly(dateTimeOffsetNow, "arg00"));
41+
Assert.That(ex.Message, Does.Contain("arg00"));
42+
Assert.That(ex.Message, Does.Contain("argument should be a date without time component"));
43+
#else
44+
// ReSharper disable once InvocationIsSkipped
45+
Assert.DoesNotThrow(() => DebugDateTimeCode.DateOnly(dateTimeNow, "arg00"));
46+
Assert.DoesNotThrow(() => DebugDateTimeCode.DateOnly(dateTimeOffsetNow, "arg00"));
47+
#endif
48+
49+
// ReSharper disable once InvocationIsSkipped
50+
Assert.DoesNotThrow(() => DebugDateTimeCode.DateOnly(dateTimeNow.Date, "arg00"));
51+
}
52+
53+
54+
[Test]
55+
public void TestIsUtcAssertion()
56+
{
57+
var dateTimeNow = DateTime.Now;
58+
var dateTimeOffsetNow = DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(1));
59+
60+
var ex = Assert.Throws<ArgumentException>(() => DateTimeCode.IsUtc(dateTimeNow, "arg00"));
61+
Assert.That(ex.Message, Does.Contain("arg00"));
62+
Assert.That(ex.Message, Does.Contain("argument should be in UTC"));
63+
64+
ex = Assert.Throws<ArgumentException>(() => DateTimeCode.IsUtc(dateTimeOffsetNow, "arg00"));
65+
Assert.That(ex.Message, Does.Contain("arg00"));
66+
Assert.That(ex.Message, Does.Contain("argument should be in UTC"));
67+
68+
Assert.DoesNotThrow(() => DateTimeCode.IsUtc(dateTimeNow.ToUniversalTime(), "arg00"));
69+
Assert.DoesNotThrow(() => DateTimeCode.IsUtc(dateTimeOffsetNow.ToUniversalTime(), "arg00"));
70+
}
71+
72+
[Test]
73+
public void TestIsUtcAndDateOnlyAssertion()
74+
{
75+
var dateTimeNow = DateTime.Now;
76+
var dateTimeOffsetNow = DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(1));
77+
78+
var ex = Assert.Throws<ArgumentException>(() => DateTimeCode.IsUtcAndDateOnly(dateTimeNow, "arg00"));
79+
Assert.That(ex.Message, Does.Contain("arg00"));
80+
Assert.That(ex.Message, Does.Contain("argument should be in UTC"));
81+
82+
ex = Assert.Throws<ArgumentException>(() => DateTimeCode.IsUtcAndDateOnly(dateTimeOffsetNow, "arg00"));
83+
Assert.That(ex.Message, Does.Contain("arg00"));
84+
Assert.That(ex.Message, Does.Contain("argument should be in UTC"));
85+
86+
ex = Assert.Throws<ArgumentException>(() => DateTimeCode.IsUtcAndDateOnly(dateTimeNow.ToUniversalTime(), "arg00"));
87+
Assert.That(ex.Message, Does.Contain("arg00"));
88+
Assert.That(ex.Message, Does.Contain("argument should be a date without time component"));
89+
90+
ex = Assert.Throws<ArgumentException>(() => DateTimeCode.IsUtcAndDateOnly(dateTimeOffsetNow.ToUniversalTime(), "arg00"));
91+
Assert.That(ex.Message, Does.Contain("arg00"));
92+
Assert.That(ex.Message, Does.Contain("argument should be a date without time component"));
93+
94+
Assert.DoesNotThrow(() => DateTimeCode.IsUtcAndDateOnly(dateTimeNow.ToUniversalTime().Date, "arg00"));
95+
Assert.DoesNotThrow(() => DateTimeCode.IsUtcAndDateOnly(dateTimeOffsetNow.ToUniversalTime().TruncateTime(), "arg00"));
96+
}
97+
98+
[Test]
99+
public void TestFirstDayOfMonth()
100+
{
101+
var dateTimeNow = DateTime.Now;
102+
var dateTimeOffsetNow = DateTimeOffset.Now;
103+
104+
var ex = Assert.Throws<ArgumentException>(() => DateTimeCode.FirstDayOfMonth(dateTimeNow, "arg00"));
105+
Assert.That(ex.Message, Does.Contain("arg00"));
106+
Assert.That(ex.Message, Does.Contain("argument should be a first day of month"));
107+
108+
ex = Assert.Throws<ArgumentException>(() => DateTimeCode.FirstDayOfMonth(dateTimeOffsetNow, "arg00"));
109+
Assert.That(ex.Message, Does.Contain("arg00"));
110+
Assert.That(ex.Message, Does.Contain("argument should be a first day of month"));
111+
112+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeNow.Date.FirstDayOfMonth(), "arg00"));
113+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeOffsetNow.Date.FirstDayOfMonth(), "arg00"));
114+
}
115+
116+
[Test]
117+
public void TestFirstDayOfYear()
118+
{
119+
var dateTimeNow = DateTime.Now;
120+
var dateTimeOffsetNow = DateTimeOffset.Now;
121+
122+
var ex = Assert.Throws<ArgumentException>(() => DateTimeCode.FirstDayOfYear(dateTimeNow, "arg00"));
123+
Assert.That(ex.Message, Does.Contain("arg00"));
124+
Assert.That(ex.Message, Does.Contain("argument should be a first day of year"));
125+
126+
ex = Assert.Throws<ArgumentException>(() => DateTimeCode.FirstDayOfYear(dateTimeOffsetNow, "arg00"));
127+
Assert.That(ex.Message, Does.Contain("arg00"));
128+
Assert.That(ex.Message, Does.Contain("argument should be a first day of year"));
129+
130+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeNow.Date.FirstDayOfYear(), "arg00"));
131+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeOffsetNow.Date.FirstDayOfYear(), "arg00"));
132+
}
133+
134+
[Test]
135+
public void TestLastDayOfMonth()
136+
{
137+
var dateTimeNow = DateTime.Now;
138+
var dateTimeOffsetNow = DateTimeOffset.Now;
139+
140+
var ex = Assert.Throws<ArgumentException>(() => DateTimeCode.LastDayOfMonth(dateTimeNow, "arg00"));
141+
Assert.That(ex.Message, Does.Contain("arg00"));
142+
Assert.That(ex.Message, Does.Contain("argument should be a last day of month"));
143+
144+
ex = Assert.Throws<ArgumentException>(() => DateTimeCode.LastDayOfMonth(dateTimeOffsetNow, "arg00"));
145+
Assert.That(ex.Message, Does.Contain("arg00"));
146+
Assert.That(ex.Message, Does.Contain("argument should be a last day of month"));
147+
148+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeNow.Date.LastDayOfMonth(), "arg00"));
149+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeOffsetNow.Date.LastDayOfMonth(), "arg00"));
150+
}
151+
152+
[Test]
153+
public void TestLastDayOfYear()
154+
{
155+
var dateTimeNow = DateTime.Now;
156+
var dateTimeOffsetNow = DateTimeOffset.Now;
157+
158+
var ex = Assert.Throws<ArgumentException>(() => DateTimeCode.LastDayOfYear(dateTimeNow, "arg00"));
159+
Assert.That(ex.Message, Does.Contain("arg00"));
160+
Assert.That(ex.Message, Does.Contain("argument should be a last day of year"));
161+
162+
ex = Assert.Throws<ArgumentException>(() => DateTimeCode.LastDayOfYear(dateTimeOffsetNow, "arg00"));
163+
Assert.That(ex.Message, Does.Contain("arg00"));
164+
Assert.That(ex.Message, Does.Contain("argument should be a last day of year"));
165+
166+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeNow.Date.LastDayOfYear(), "arg00"));
167+
Assert.DoesNotThrow(() => DateTimeCode.DateOnly(dateTimeOffsetNow.Date.LastDayOfYear(), "arg00"));
168+
}
169+
}
170+
}

CodeJam.Main.Tests/Dates/DateTimeExtensionsTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,25 @@ public static void TestDateTimeExtensions()
3636
AreEqual(d.GetYearRange().CountOfDays(), d.DaysInYear());
3737
}
3838

39+
[Test]
40+
public static void TestIsUtc()
41+
{
42+
var now = DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(1));
43+
var utcNow = DateTimeOffset.UtcNow;
44+
IsFalse(now.IsUtc());
45+
IsTrue(utcNow.IsUtc());
46+
IsTrue(now.ToUniversalTime().IsUtc());
47+
}
48+
49+
[Test]
50+
public static void TestTruncateTime()
51+
{
52+
var now = DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(1));
53+
var utcNow = DateTimeOffset.UtcNow;
54+
AreEqual(now.TruncateTime(), now - now.TimeOfDay);
55+
AreEqual(utcNow.TruncateTime(), utcNow - utcNow.TimeOfDay);
56+
}
57+
3958
[Test]
4059
public static void TestDateTimeOffsetExtensions()
4160
{

CodeJam.Main/Assertions/CodeExceptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static ArgumentNullException ArgumentNull([NotNull, InvokerParameterName]
2222
return new ArgumentNullException(argumentName).LogToCodeTraceSourceBeforeThrow();
2323
}
2424

25-
/// <summary>Creates <see cref="ArgumentNullException"/>.</summary>
25+
/// <summary>Creates <see cref="ArgumentException"/> for null collection item.</summary>
2626
/// <param name="argumentName">Name of the argument.</param>
2727
/// <returns>Initialized instance of <see cref="ArgumentException"/>.</returns>
2828
[DebuggerHidden, NotNull, MustUseReturnValue]

0 commit comments

Comments
 (0)