@@ -18,11 +18,25 @@ public class TimeUnitTests
18
18
[ "10m" , new TimeSpan ( 0 , 10 , 0 ) ] ,
19
19
[ "10h" , new TimeSpan ( 10 , 0 , 0 ) ] ,
20
20
[ "10d" , new TimeSpan ( 10 , 0 , 0 , 0 ) ] ,
21
+ [ "1w" , new TimeSpan ( 7 , 0 , 0 , 0 ) ] ,
22
+ [ "2w" , new TimeSpan ( 14 , 0 , 0 , 0 ) ] ,
23
+ [ "-1w" , new TimeSpan ( - 7 , 0 , 0 , 0 ) ] ,
24
+ [ "1M" , new TimeSpan ( ( int ) TimeSpanExtensions . AvgDaysInAMonth , 0 , 0 , 0 ) ] ,
25
+ [ "2M" , new TimeSpan ( ( int ) ( 2 * TimeSpanExtensions . AvgDaysInAMonth ) , 0 , 0 , 0 ) ] ,
26
+ [ "-1M" , new TimeSpan ( ( int ) ( - 1 * TimeSpanExtensions . AvgDaysInAMonth ) , 0 , 0 , 0 ) ] ,
27
+ [ "1y" , new TimeSpan ( ( int ) TimeSpanExtensions . AvgDaysInAYear , 0 , 0 , 0 ) ] ,
28
+ [ "2y" , new TimeSpan ( ( int ) ( 2 * TimeSpanExtensions . AvgDaysInAYear ) , 0 , 0 , 0 ) ] ,
29
+ [ "-1y" , new TimeSpan ( ( int ) ( - 1 * TimeSpanExtensions . AvgDaysInAYear ) , 0 , 0 , 0 ) ] ,
30
+ // Whitespace trimming tests
31
+ [ " 1y " , new TimeSpan ( ( int ) TimeSpanExtensions . AvgDaysInAYear , 0 , 0 , 0 ) ] ,
32
+ [ " 2M " , new TimeSpan ( ( int ) ( 2 * TimeSpanExtensions . AvgDaysInAMonth ) , 0 , 0 , 0 ) ] ,
33
+ [ "\t 3w\t " , new TimeSpan ( 21 , 0 , 0 , 0 ) ] ,
34
+ [ " -1y " , new TimeSpan ( ( int ) ( - 1 * TimeSpanExtensions . AvgDaysInAYear ) , 0 , 0 , 0 ) ] ,
21
35
} ;
22
36
23
37
[ Theory ]
24
38
[ MemberData ( nameof ( TestData ) ) ]
25
- public void CanParse ( string value , TimeSpan expected )
39
+ public void Parse_ValidInput_ReturnsExpectedTimeSpan ( string value , TimeSpan expected )
26
40
{
27
41
Assert . Equal ( expected , TimeUnit . Parse ( value ) ) ;
28
42
}
@@ -33,7 +47,14 @@ public void CanParse(string value, TimeSpan expected)
33
47
[ InlineData ( "1234" ) ] // missing unit
34
48
[ InlineData ( "12unknownunit" ) ]
35
49
[ InlineData ( "12h." ) ]
36
- public void VerifyParseFailure ( string value )
50
+ [ InlineData ( "" ) ] // empty string
51
+ [ InlineData ( " " ) ] // whitespace only
52
+ [ InlineData ( "\t \t " ) ] // tabs only
53
+ [ InlineData ( "1y@" ) ] // special character after unit
54
+ [ InlineData ( "1M!" ) ] // special character after unit
55
+ [ InlineData ( "1w#" ) ] // special character after unit
56
+ [ InlineData ( "1@y" ) ] // special character in middle
57
+ public void Parse_InvalidInput_ThrowsException ( string value )
37
58
{
38
59
Assert . ThrowsAny < Exception > ( ( ) => TimeUnit . Parse ( value ) ) ;
39
60
}
@@ -50,15 +71,121 @@ public void VerifyParseFailure(string value)
50
71
[ InlineData ( "10m" , true ) ]
51
72
[ InlineData ( "10h" , true ) ]
52
73
[ InlineData ( "10d" , true ) ]
74
+ [ InlineData ( "1w" , true ) ]
75
+ [ InlineData ( "2w" , true ) ]
76
+ [ InlineData ( "-1w" , true ) ]
77
+ [ InlineData ( "1M" , true ) ]
78
+ [ InlineData ( "2M" , true ) ]
79
+ [ InlineData ( "-1M" , true ) ]
80
+ [ InlineData ( "1y" , true ) ]
81
+ [ InlineData ( "2y" , true ) ]
82
+ [ InlineData ( "-1y" , true ) ]
83
+ // Whitespace tests
84
+ [ InlineData ( " 1y " , true ) ]
85
+ [ InlineData ( " 2M " , true ) ]
86
+ [ InlineData ( "\t 3w\t " , true ) ]
87
+ [ InlineData ( " -1M " , true ) ]
88
+ // Special character and edge case tests
89
+ [ InlineData ( "" , false ) ]
90
+ [ InlineData ( " " , false ) ]
91
+ [ InlineData ( "\t \t " , false ) ]
92
+ [ InlineData ( "1y@" , false ) ]
93
+ [ InlineData ( "1M!" , false ) ]
94
+ [ InlineData ( "1w#" , false ) ]
95
+ [ InlineData ( "1@y" , false ) ]
53
96
[ InlineData ( null , false ) ]
54
97
[ InlineData ( "1.234h" , false ) ] // fractional time
55
98
[ InlineData ( "1234" , false ) ] // missing unit
56
99
[ InlineData ( "12unknownunit" , false ) ]
57
100
[ InlineData ( "12h." , false ) ]
58
101
[ InlineData ( "Blah/Blahs" , false ) ]
59
- public void VerifyTryParse ( string value , bool expected )
102
+ public void TryParse_VariousInputs_ReturnsExpectedResult ( string value , bool expected )
60
103
{
61
104
bool success = TimeUnit . TryParse ( value , out var result ) ;
62
105
Assert . Equal ( expected , success ) ;
63
106
}
107
+
108
+ [ Fact ]
109
+ public void Parse_UppercaseM_ParsesAsMonths ( )
110
+ {
111
+ // Arrange
112
+ var input = "1M" ;
113
+ var expectedDays = ( int ) TimeSpanExtensions . AvgDaysInAMonth ;
114
+ var expected = new TimeSpan ( expectedDays , 0 , 0 , 0 ) ;
115
+
116
+ // Act
117
+ var result = TimeUnit . Parse ( input ) ;
118
+
119
+ // Assert
120
+ Assert . Equal ( expected , result ) ;
121
+ }
122
+
123
+ [ Fact ]
124
+ public void Parse_LowercaseM_ParsesAsMinutes ( )
125
+ {
126
+ // Arrange
127
+ var input = "1m" ;
128
+ var expected = new TimeSpan ( 0 , 1 , 0 ) ;
129
+
130
+ // Act
131
+ var result = TimeUnit . Parse ( input ) ;
132
+
133
+ // Assert
134
+ Assert . Equal ( expected , result ) ;
135
+ }
136
+
137
+ [ Fact ]
138
+ public void Parse_MonthsAndMinutes_ProduceDifferentResults ( )
139
+ {
140
+ // Act
141
+ var monthResult = TimeUnit . Parse ( "1M" ) ;
142
+ var minuteResult = TimeUnit . Parse ( "1m" ) ;
143
+
144
+ // Assert
145
+ Assert . NotEqual ( monthResult , minuteResult ) ;
146
+ }
147
+
148
+ [ Theory ]
149
+ [ InlineData ( "1y" ) ]
150
+ [ InlineData ( "2y" ) ]
151
+ [ InlineData ( "-1y" ) ]
152
+ public void Parse_YearUnit_ReturnsExpectedDays ( string input )
153
+ {
154
+ // Act
155
+ var result = TimeUnit . Parse ( input ) ;
156
+ var expectedDays = int . Parse ( input . Substring ( 0 , input . Length - 1 ) ) * TimeSpanExtensions . AvgDaysInAYear ;
157
+
158
+ // Assert
159
+ Assert . True ( Math . Abs ( result . TotalDays - expectedDays ) < 1 ,
160
+ $ "Year conversion should be close to { expectedDays } days, got { result . TotalDays } ") ;
161
+ }
162
+
163
+ [ Theory ]
164
+ [ InlineData ( "1M" ) ]
165
+ [ InlineData ( "3M" ) ]
166
+ [ InlineData ( "-1M" ) ]
167
+ public void Parse_MonthUnit_ReturnsExpectedDays ( string input )
168
+ {
169
+ // Act
170
+ var result = TimeUnit . Parse ( input ) ;
171
+ var expectedDays = int . Parse ( input . Substring ( 0 , input . Length - 1 ) ) * TimeSpanExtensions . AvgDaysInAMonth ;
172
+
173
+ // Assert
174
+ Assert . True ( Math . Abs ( result . TotalDays - expectedDays ) < 1 ,
175
+ $ "Month conversion should be close to { expectedDays } days, got { result . TotalDays } ") ;
176
+ }
177
+
178
+ [ Theory ]
179
+ [ InlineData ( "1w" , 7 ) ]
180
+ [ InlineData ( "2w" , 14 ) ]
181
+ [ InlineData ( "4w" , 28 ) ]
182
+ [ InlineData ( "-1w" , - 7 ) ]
183
+ public void Parse_WeekUnit_ReturnsExpectedDays ( string input , int expectedDays )
184
+ {
185
+ // Act
186
+ var result = TimeUnit . Parse ( input ) ;
187
+
188
+ // Assert
189
+ Assert . Equal ( expectedDays , result . TotalDays ) ;
190
+ }
64
191
}
0 commit comments