1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using Xunit;
6 
7 namespace System.Net.Mime.Tests
8 {
9     public class SmtpDateTimeTest
10     {
11         private static readonly DateTime s_validDateStringDateTimeEquivalent = new DateTime(2009, 5, 17, 15, 34, 07, DateTimeKind.Utc);
12 
13         private const string UnspecifiedTimeZone = "-0000";
14         private const string ValidDateStringDateTimeEquivalentString = "Sun, 17 May 2009 15:34:07 +0000";
15         private const string ValidCompleteDateString = "Sun, 17 May 2009 15:34:07 +0000";
16         private const string ValidDateStringWithNoDayOfWeek = "17 May 2009 15:34:07 +0000";
17         private const string ValidDateStringWithKnownShortHandTimeZone = "Sun, 17 May 2009 15:34:07 GMT";
18         private const string ValidDateStringWithUnknownButValidShortHandTimeZone = "Sun, 17 May 2009 15:34:07 BST";
19         private const string ValidDateStringWithOnlyTabsAsWhitespace = "Sun,\t17 May\t2009\t15:34:07\tGMT";
20         private const string ValidDateStringWithMixedTabsAndSpacesAsWhitespace = "Sun,\t17 May\t 2009 \t15:34:07 \t GMT  \t ";
21         private const string ValidDateStringWithTrailingWhitespaceAndCommentAfterTimeZone = "Sun,\t17 May\t2009 15:34:07\tGMT\t \"comment\"";
22         private const string InvalidDateStringWithBadDayOfWeek = "Thursday, 17 May 2009 15:34:07 +0000";
23         private const string InvalidDateStringWithBadDay = "Sun, 37 May 2009 15:34:07 +0000";
24         private const string InvalidDateStringWithBadMonth = "Sun, 17 Smarch 2009 15:34:07 +0000";
25         private const string InvalidDateStringWithBadYear = "Sun, 17 May 20099 15:34:07 +0000";
26         private const string InvalidDateStringWithBadTimeHours = "Sun, 17 May 2009 27:34:07 +0000";
27         private const string InvalidDateStringWithBadTimeMinutes = "Sun, 17 May 2009 15:88:07 +0000";
28         private const string InvalidDateStringWithBadTimeSeconds = "Sun, 17 May 2009 15:34:87 +0000";
29         private const string InvalidDateStringWithInvalidTimeZone = "Sun, 17 May 2009 15:34:07 7M-Gte";
30 
31         [Fact]
SmtpDateTime_WithInvalidTimeZone_ShouldParseDateCorrectly()32         public void SmtpDateTime_WithInvalidTimeZone_ShouldParseDateCorrectly()
33         {
34             var smtpDt = new SmtpDateTime(DateTime.Now);
35             string timeZoneOffset;
36             DateTime result = smtpDt.ParseValue(InvalidDateStringWithInvalidTimeZone, out timeZoneOffset);
37 
38             Assert.Equal("7M-Gte", timeZoneOffset);
39             Assert.Equal(new DateTime(2009, 5, 17, 15, 34, 07), result);
40         }
41 
42         [Theory]
43         [InlineData(InvalidDateStringWithBadTimeSeconds)]
44         [InlineData(InvalidDateStringWithBadTimeMinutes)]
45         [InlineData(InvalidDateStringWithBadTimeHours)]
46         [InlineData(InvalidDateStringWithBadYear)]
47         [InlineData(InvalidDateStringWithBadDay)]
48         [InlineData(InvalidDateStringWithBadMonth)]
49         [InlineData(InvalidDateStringWithBadDayOfWeek)]
SmtpDateTime_InvalidInput_ShouldThrowException(string input)50         public void SmtpDateTime_InvalidInput_ShouldThrowException(string input)
51         {
52             var smtpDt = new SmtpDateTime(DateTime.Now);
53             Assert.Throws<FormatException>(() =>
54             {
55                 string timeZoneOffset;
56                 DateTime results = smtpDt.ParseValue(input, out timeZoneOffset);
57             });
58         }
59 
60         [Fact]
SmtpDateTime_WithDateThatHasUnspecifiedKind_ShouldSetTimeZoneCorrectly()61         public void SmtpDateTime_WithDateThatHasUnspecifiedKind_ShouldSetTimeZoneCorrectly()
62         {
63             DateTime date = new DateTime(2008, 1, 1, 12, 00, 00, DateTimeKind.Unspecified);
64             var smtpDt = new SmtpDateTime(date);
65 
66             Assert.Equal(date, smtpDt.Date);
67             Assert.Equal(DateTimeKind.Unspecified, smtpDt.Date.Kind);
68         }
69 
70         [Fact]
SmtpDateTime_WithDateThatHasKindSetToLocal_ShouldSetTimeZoneCorrectly()71         public void SmtpDateTime_WithDateThatHasKindSetToLocal_ShouldSetTimeZoneCorrectly()
72         {
73             var date = new DateTime(2008, 1, 1, 12, 00, 00, DateTimeKind.Local);
74             var smtpDt = new SmtpDateTime(date);
75             Assert.Equal(date, smtpDt.Date);
76         }
77 
78         [Theory]
79         [InlineData(ValidCompleteDateString, 2009, 5, 17, 15, 34, 7, "GMT", DateTimeKind.Unspecified)]
80         [InlineData(ValidDateStringWithKnownShortHandTimeZone, 2009, 5, 17, 15, 34, 7, "GMT", DateTimeKind.Unspecified)]
81         [InlineData(ValidDateStringWithNoDayOfWeek, 2009, 5, 17, 15, 34, 7, "GMT", DateTimeKind.Unspecified)]
82         [InlineData(ValidDateStringWithOnlyTabsAsWhitespace, 2009, 5, 17, 15, 34, 7, "GMT", DateTimeKind.Unspecified)]
83         [InlineData(ValidDateStringWithTrailingWhitespaceAndCommentAfterTimeZone, 2009, 5, 17, 15, 34, 7, "GMT", DateTimeKind.Unspecified)]
84         [InlineData(ValidDateStringWithMixedTabsAndSpacesAsWhitespace, 2009, 5, 17, 15, 34, 7, "GMT", DateTimeKind.Unspecified)]
SmtpDateTime_CreatedFromDateTimeString_ShouldParseCorrectly( string input, int expectedYear, int expectedMonth, int expectedDay, int expectedHour, int expectedMinut, int expectedSecond, string expectedTimeZoneOffset, DateTimeKind expectedKind)85         public void SmtpDateTime_CreatedFromDateTimeString_ShouldParseCorrectly(
86             string input,
87             int expectedYear, int expectedMonth, int expectedDay,
88             int expectedHour, int expectedMinut, int expectedSecond,
89             string expectedTimeZoneOffset, DateTimeKind expectedKind)
90         {
91             var smtpDt = new SmtpDateTime(DateTime.Now);
92 
93             string timeZoneOffset;
94             DateTime result = smtpDt.ParseValue(ValidDateStringWithKnownShortHandTimeZone, out timeZoneOffset);
95 
96             Assert.Equal(expectedYear, result.Year);
97             Assert.Equal(expectedMonth, result.Month);
98             Assert.Equal(expectedDay, result.Day);
99             Assert.Equal(expectedHour, result.Hour);
100             Assert.Equal(expectedMinut, result.Minute);
101             Assert.Equal(expectedSecond, result.Second);
102             Assert.Equal(expectedTimeZoneOffset, timeZoneOffset);
103         }
104 
105         [Fact]
SmtpDate_ToString_ShouldOutputCorrectDateString()106         public void SmtpDate_ToString_ShouldOutputCorrectDateString()
107         {
108             var smtpDt = new SmtpDateTime(s_validDateStringDateTimeEquivalent);
109             Assert.Equal(ValidDateStringDateTimeEquivalentString, smtpDt.ToString());
110         }
111 
112         [Fact]
SmtpDate_ValidateTimeZoneShortHandValue_WithValidShortHand_ShouldReturnTrue()113         public void SmtpDate_ValidateTimeZoneShortHandValue_WithValidShortHand_ShouldReturnTrue()
114         {
115             var smtpDt = new SmtpDateTime(DateTime.Now);
116             smtpDt.ValidateTimeZoneShortHandValue("GMT");
117         }
118 
119         [Fact]
SmtpDate_ValidateTimeZoneShortHandValue_WithInvalidShortHand_ShouldReturnFalse()120         public void SmtpDate_ValidateTimeZoneShortHandValue_WithInvalidShortHand_ShouldReturnFalse()
121         {
122             var smtpDt = new SmtpDateTime(DateTime.Now);
123             Assert.Throws<FormatException>(() => smtpDt.ValidateTimeZoneShortHandValue("7M-GTE"));
124         }
125 
126         [Fact]
SmtpDate_ValidateTimeZoneOffsetValue_WithValidAndInvalidOffsets_ShouldReturnCorrectly()127         public void SmtpDate_ValidateTimeZoneOffsetValue_WithValidAndInvalidOffsets_ShouldReturnCorrectly()
128         {
129             var smtpDt = new SmtpDateTime(DateTime.Now);
130 
131             bool positive;
132             int hours;
133             int minutes;
134 
135             smtpDt.ValidateAndGetTimeZoneOffsetValues("+0000", out positive, out hours, out minutes);
136             smtpDt.ValidateAndGetTimeZoneOffsetValues("+9959", out positive, out hours, out minutes);
137             smtpDt.ValidateAndGetTimeZoneOffsetValues("-9959", out positive, out hours, out minutes);
138             smtpDt.ValidateAndGetTimeZoneOffsetValues("+0900", out positive, out hours, out minutes);
139 
140             Assert.Throws<FormatException>(() => smtpDt.ValidateAndGetTimeZoneOffsetValues("+0080", out positive, out hours, out minutes));
141             Assert.Throws<FormatException>(() => smtpDt.ValidateAndGetTimeZoneOffsetValues("+-0045", out positive, out hours, out minutes));
142             Assert.Throws<FormatException>(() => smtpDt.ValidateAndGetTimeZoneOffsetValues("+10000", out positive, out hours, out minutes));
143             Assert.Throws<FormatException>(() => smtpDt.ValidateAndGetTimeZoneOffsetValues("-A000", out positive, out hours, out minutes));
144         }
145 
146         [Fact]
SmtpDate_WithCompletelyInvalidDateString_ShouldThrowException()147         public void SmtpDate_WithCompletelyInvalidDateString_ShouldThrowException()
148         {
149             Assert.Throws<FormatException>(() => new SmtpDateTime("asdiwefhn m.sdf,m,sdfl\""));
150         }
151 
152         [Fact]
SmtpDate_TimeSpanToOffset_ShouldConvertCorrectly()153         public void SmtpDate_TimeSpanToOffset_ShouldConvertCorrectly()
154         {
155             var smtpDt = new SmtpDateTime(DateTime.Now);
156             TimeSpan timeZone = TimeZoneInfo.Utc.GetUtcOffset(DateTime.Now);
157             string timeZoneToString = timeZone.ToString();
158             string result = smtpDt.TimeSpanToOffset(timeZone);
159             Assert.Equal("+0000", result);
160         }
161 
162         [Fact]
SmtpDate_TimeSpanToOffset_WithNonGmtOffset_ShouldConvertCorrectly()163         public void SmtpDate_TimeSpanToOffset_WithNonGmtOffset_ShouldConvertCorrectly()
164         {
165             var smtpDt = new SmtpDateTime(DateTime.Now);
166             Assert.Equal("-0800", smtpDt.TimeSpanToOffset(new TimeSpan(-8, 0, 0)));
167             Assert.Equal("-1000", smtpDt.TimeSpanToOffset(new TimeSpan(-10, 0, 0)));
168             Assert.Equal("+1000", smtpDt.TimeSpanToOffset(new TimeSpan(10, 0, 0)));
169             Assert.Equal("+0400", smtpDt.TimeSpanToOffset(new TimeSpan(4, 0, 0)));
170         }
171 
172         [Fact]
SmtpDate_TryParseTimeZoneString_WithValidShortHand_ShouldReturnCorrectOffset()173         public void SmtpDate_TryParseTimeZoneString_WithValidShortHand_ShouldReturnCorrectOffset()
174         {
175             var smtpDt = new SmtpDateTime(DateTime.Now);
176             TimeSpan span;
177             Assert.True(smtpDt.TryParseTimeZoneString("GMT", out span));
178             Assert.Equal(TimeSpan.Zero, span);
179         }
180 
181         [Fact]
SmtpDate_TryParseTimeZoneString_WithUnknownShortHand_ShouldReturnFalse()182         public void SmtpDate_TryParseTimeZoneString_WithUnknownShortHand_ShouldReturnFalse()
183         {
184             var smtpDt = new SmtpDateTime(DateTime.Now);
185             TimeSpan span;
186             Assert.False(smtpDt.TryParseTimeZoneString("ABCD", out span));
187         }
188 
189         [Fact]
SmtpDate_TryParseTimeZoneString_WithInvalidShortHand_ShouldThrowException()190         public void SmtpDate_TryParseTimeZoneString_WithInvalidShortHand_ShouldThrowException()
191         {
192             var smtpDt = new SmtpDateTime(DateTime.Now);
193             TimeSpan span;
194             Assert.Throws<FormatException>(() => smtpDt.TryParseTimeZoneString("7mGTE", out span));
195         }
196     }
197 }
198