Skip to content

Commit f876d89

Browse files
Copilotjeffhandley
andcommitted
Add comprehensive tests for endOfDayFrag (24:00:00) support in XsdDateTime
Co-authored-by: jeffhandley <1031940+jeffhandley@users.noreply.github.com>
1 parent 4ef3b50 commit f876d89

File tree

2 files changed

+245
-0
lines changed

2 files changed

+245
-0
lines changed

src/libraries/System.Private.Xml/tests/System.Private.Xml.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
<Compile Include="XmlConvert\SqlXmlConvertTests3.cs" />
148148
<Compile Include="XmlConvert\ToTypeTests.cs" />
149149
<Compile Include="XmlConvert\VerifyNameTests1.cs" />
150+
<Compile Include="XmlConvert\XmlConvertEndOfDayTests.cs" />
150151
<Compile Include="XmlConvert\VerifyNameTests2.cs" />
151152
<Compile Include="XmlConvert\VerifyNameTests3.cs" />
152153
<Compile Include="XmlConvert\VerifyNameTests4.cs" />
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
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+
4+
using System.IO;
5+
using System.Xml.Schema;
6+
using Xunit;
7+
8+
namespace System.Xml.Tests
9+
{
10+
public class XmlConvertEndOfDayTests
11+
{
12+
// ==================== XmlConvert.ToDateTime Tests ====================
13+
14+
[Theory]
15+
[InlineData("2007-04-05T24:00:00", XmlDateTimeSerializationMode.RoundtripKind, 2007, 4, 6, 0, 0, 0)]
16+
[InlineData("2000-01-01T24:00:00", XmlDateTimeSerializationMode.RoundtripKind, 2000, 1, 2, 0, 0, 0)]
17+
[InlineData("2000-12-31T24:00:00", XmlDateTimeSerializationMode.RoundtripKind, 2001, 1, 1, 0, 0, 0)]
18+
[InlineData("2000-02-28T24:00:00", XmlDateTimeSerializationMode.RoundtripKind, 2000, 2, 29, 0, 0, 0)] // leap year
19+
[InlineData("2001-02-28T24:00:00", XmlDateTimeSerializationMode.RoundtripKind, 2001, 3, 1, 0, 0, 0)] // non-leap year
20+
[InlineData("2007-04-05T24:00:00Z", XmlDateTimeSerializationMode.RoundtripKind, 2007, 4, 6, 0, 0, 0)]
21+
[InlineData("2007-04-05T24:00:00", XmlDateTimeSerializationMode.Utc, 2007, 4, 6, 0, 0, 0)]
22+
[InlineData("2007-04-05T24:00:00", XmlDateTimeSerializationMode.Unspecified, 2007, 4, 6, 0, 0, 0)]
23+
public static void ToDateTime_EndOfDay_Valid(string input, XmlDateTimeSerializationMode mode, int year, int month, int day, int hour, int minute, int second)
24+
{
25+
DateTime result = XmlConvert.ToDateTime(input, mode);
26+
Assert.Equal(new DateTime(year, month, day, hour, minute, second), new DateTime(result.Year, result.Month, result.Day, result.Hour, result.Minute, result.Second));
27+
}
28+
29+
[Theory]
30+
[InlineData("2007-04-05T24:00:00.0000000")]
31+
[InlineData("2007-04-05T24:00:00.0")]
32+
public static void ToDateTime_EndOfDay_ZeroFraction_Valid(string input)
33+
{
34+
DateTime result = XmlConvert.ToDateTime(input, XmlDateTimeSerializationMode.RoundtripKind);
35+
Assert.Equal(2007, result.Year);
36+
Assert.Equal(4, result.Month);
37+
Assert.Equal(6, result.Day);
38+
Assert.Equal(0, result.Hour);
39+
Assert.Equal(0, result.Minute);
40+
Assert.Equal(0, result.Second);
41+
}
42+
43+
[Theory]
44+
[InlineData("2007-04-05T24:01:00")]
45+
[InlineData("2007-04-05T24:00:01")]
46+
[InlineData("2007-04-05T24:00:00.0000001")]
47+
[InlineData("2007-04-05T24:59:59")]
48+
[InlineData("9999-12-31T24:00:00")]
49+
public static void ToDateTime_EndOfDay_Invalid(string input)
50+
{
51+
Assert.Throws<FormatException>(() => XmlConvert.ToDateTime(input, XmlDateTimeSerializationMode.RoundtripKind));
52+
}
53+
54+
// ==================== XmlConvert.ToDateTimeOffset Tests ====================
55+
56+
[Theory]
57+
[InlineData("2007-04-05T24:00:00", 2007, 4, 6, 0, 0, 0)]
58+
[InlineData("2000-01-01T24:00:00", 2000, 1, 2, 0, 0, 0)]
59+
[InlineData("2000-12-31T24:00:00", 2001, 1, 1, 0, 0, 0)]
60+
[InlineData("2000-02-28T24:00:00", 2000, 2, 29, 0, 0, 0)] // leap year
61+
[InlineData("2001-02-28T24:00:00", 2001, 3, 1, 0, 0, 0)] // non-leap year
62+
public static void ToDateTimeOffset_EndOfDay_Valid(string input, int year, int month, int day, int hour, int minute, int second)
63+
{
64+
DateTimeOffset result = XmlConvert.ToDateTimeOffset(input);
65+
Assert.Equal(year, result.Year);
66+
Assert.Equal(month, result.Month);
67+
Assert.Equal(day, result.Day);
68+
Assert.Equal(hour, result.Hour);
69+
Assert.Equal(minute, result.Minute);
70+
Assert.Equal(second, result.Second);
71+
}
72+
73+
[Theory]
74+
[InlineData("2007-04-05T24:00:00Z")]
75+
[InlineData("2007-04-05T24:00:00+05:30")]
76+
[InlineData("2007-04-05T24:00:00-08:00")]
77+
public static void ToDateTimeOffset_EndOfDay_WithTimeZone_Valid(string input)
78+
{
79+
DateTimeOffset result = XmlConvert.ToDateTimeOffset(input);
80+
Assert.Equal(6, result.Day);
81+
Assert.Equal(0, result.Hour);
82+
}
83+
84+
[Theory]
85+
[InlineData("2007-04-05T24:01:00")]
86+
[InlineData("2007-04-05T24:00:01")]
87+
[InlineData("2007-04-05T24:00:00.0000001")]
88+
[InlineData("9999-12-31T24:00:00")]
89+
public static void ToDateTimeOffset_EndOfDay_Invalid(string input)
90+
{
91+
Assert.Throws<FormatException>(() => XmlConvert.ToDateTimeOffset(input));
92+
}
93+
94+
// ==================== xs:time Tests ====================
95+
96+
[Theory]
97+
[InlineData("24:00:00")]
98+
[InlineData("24:00:00Z")]
99+
public static void ToDateTime_TimeOnly_EndOfDay_Valid(string input)
100+
{
101+
DateTime result = XmlConvert.ToDateTime(input, XmlDateTimeSerializationMode.RoundtripKind);
102+
Assert.Equal(0, result.Hour);
103+
Assert.Equal(0, result.Minute);
104+
Assert.Equal(0, result.Second);
105+
}
106+
107+
[Theory]
108+
[InlineData("24:00:00+05:30")]
109+
[InlineData("24:00:00-08:00")]
110+
public static void ToDateTime_TimeOnly_EndOfDay_WithOffset_Valid(string input)
111+
{
112+
// Parsing should succeed; the time zone offset conversion may shift the hour and minute
113+
DateTime result = XmlConvert.ToDateTime(input, XmlDateTimeSerializationMode.RoundtripKind);
114+
Assert.Equal(0, result.Second);
115+
}
116+
117+
[Theory]
118+
[InlineData("24:01:00")]
119+
[InlineData("24:00:01")]
120+
[InlineData("24:00:00.0000001")]
121+
public static void ToDateTime_TimeOnly_EndOfDay_Invalid(string input)
122+
{
123+
Assert.Throws<FormatException>(() => XmlConvert.ToDateTime(input, XmlDateTimeSerializationMode.RoundtripKind));
124+
}
125+
126+
// ==================== XmlReader Schema Validation Tests ====================
127+
128+
[Fact]
129+
public static void XmlSchemaValidation_DateTime_EndOfDay_Valid()
130+
{
131+
string xsd = @"<?xml version=""1.0"" encoding=""utf-8""?>
132+
<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema"" targetNamespace=""endOfDate"" xmlns:tns=""endOfDate"" elementFormDefault=""qualified"">
133+
<xs:element name=""root"" type=""xs:dateTime""/>
134+
</xs:schema>";
135+
136+
string xml = @"<?xml version=""1.0"" encoding=""utf-8""?>
137+
<root xmlns=""endOfDate"">2007-04-05T24:00:00</root>";
138+
139+
var settings = new XmlReaderSettings
140+
{
141+
ValidationType = ValidationType.Schema,
142+
};
143+
settings.Schemas.Add("endOfDate", XmlReader.Create(new StringReader(xsd)));
144+
145+
using XmlReader reader = XmlReader.Create(new StringReader(xml), settings);
146+
var doc = new XmlDocument();
147+
doc.Load(reader); // should not throw
148+
}
149+
150+
[Fact]
151+
public static void XmlSchemaValidation_DateTime_EndOfDay_WithTimeZone_Valid()
152+
{
153+
string xsd = @"<?xml version=""1.0"" encoding=""utf-8""?>
154+
<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema"" targetNamespace=""endOfDate"" xmlns:tns=""endOfDate"" elementFormDefault=""qualified"">
155+
<xs:element name=""root"" type=""xs:dateTime""/>
156+
</xs:schema>";
157+
158+
string xml = @"<?xml version=""1.0"" encoding=""utf-8""?>
159+
<root xmlns=""endOfDate"">2007-04-05T24:00:00Z</root>";
160+
161+
var settings = new XmlReaderSettings
162+
{
163+
ValidationType = ValidationType.Schema,
164+
};
165+
settings.Schemas.Add("endOfDate", XmlReader.Create(new StringReader(xsd)));
166+
167+
using XmlReader reader = XmlReader.Create(new StringReader(xml), settings);
168+
var doc = new XmlDocument();
169+
doc.Load(reader); // should not throw
170+
}
171+
172+
[Fact]
173+
public static void XmlSchemaValidation_Time_EndOfDay_Valid()
174+
{
175+
string xsd = @"<?xml version=""1.0"" encoding=""utf-8""?>
176+
<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema"" targetNamespace=""endOfDate"" xmlns:tns=""endOfDate"" elementFormDefault=""qualified"">
177+
<xs:element name=""root"" type=""xs:time""/>
178+
</xs:schema>";
179+
180+
string xml = @"<?xml version=""1.0"" encoding=""utf-8""?>
181+
<root xmlns=""endOfDate"">24:00:00</root>";
182+
183+
var settings = new XmlReaderSettings
184+
{
185+
ValidationType = ValidationType.Schema,
186+
};
187+
settings.Schemas.Add("endOfDate", XmlReader.Create(new StringReader(xsd)));
188+
189+
using XmlReader reader = XmlReader.Create(new StringReader(xml), settings);
190+
var doc = new XmlDocument();
191+
doc.Load(reader); // should not throw
192+
}
193+
194+
[Fact]
195+
public static void XmlSchemaValidation_DateTime_EndOfDay_NonZeroMinute_Invalid()
196+
{
197+
string xsd = @"<?xml version=""1.0"" encoding=""utf-8""?>
198+
<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema"" targetNamespace=""endOfDate"" xmlns:tns=""endOfDate"" elementFormDefault=""qualified"">
199+
<xs:element name=""root"" type=""xs:dateTime""/>
200+
</xs:schema>";
201+
202+
string xml = @"<?xml version=""1.0"" encoding=""utf-8""?>
203+
<root xmlns=""endOfDate"">2007-04-05T24:01:00</root>";
204+
205+
var settings = new XmlReaderSettings
206+
{
207+
ValidationType = ValidationType.Schema,
208+
};
209+
settings.Schemas.Add("endOfDate", XmlReader.Create(new StringReader(xsd)));
210+
211+
bool validationErrorOccurred = false;
212+
settings.ValidationEventHandler += (sender, e) =>
213+
{
214+
validationErrorOccurred = true;
215+
};
216+
217+
using XmlReader reader = XmlReader.Create(new StringReader(xml), settings);
218+
var doc = new XmlDocument();
219+
doc.Load(reader);
220+
Assert.True(validationErrorOccurred);
221+
}
222+
223+
// ==================== Regression: existing hour values still work ====================
224+
225+
[Theory]
226+
[InlineData("2007-04-05T00:00:00", 2007, 4, 5, 0, 0, 0)]
227+
[InlineData("2007-04-05T23:59:59", 2007, 4, 5, 23, 59, 59)]
228+
[InlineData("2007-04-05T12:30:45", 2007, 4, 5, 12, 30, 45)]
229+
[InlineData("2007-04-05T01:00:00", 2007, 4, 5, 1, 0, 0)]
230+
public static void ToDateTime_ExistingHours_StillWork(string input, int year, int month, int day, int hour, int minute, int second)
231+
{
232+
DateTime result = XmlConvert.ToDateTime(input, XmlDateTimeSerializationMode.RoundtripKind);
233+
Assert.Equal(new DateTime(year, month, day, hour, minute, second), new DateTime(result.Year, result.Month, result.Day, result.Hour, result.Minute, result.Second));
234+
}
235+
236+
[Theory]
237+
[InlineData("2007-04-05T25:00:00")]
238+
[InlineData("2007-04-05T99:00:00")]
239+
public static void ToDateTime_HourAbove24_Invalid(string input)
240+
{
241+
Assert.Throws<FormatException>(() => XmlConvert.ToDateTime(input, XmlDateTimeSerializationMode.RoundtripKind));
242+
}
243+
}
244+
}

0 commit comments

Comments
 (0)