diff --git a/DateTimeOnly.Tests/ArgumentValidationTests.cs b/DateTimeOnly.Tests/ArgumentValidationTests.cs index 1676763..d000725 100644 --- a/DateTimeOnly.Tests/ArgumentValidationTests.cs +++ b/DateTimeOnly.Tests/ArgumentValidationTests.cs @@ -77,6 +77,12 @@ public void DateOnlyTryParseValidationWorkedTest() Assert.False(DateOnly.TryParse("aa-bb-cc", out dateOnly)); Assert.Equal(default, dateOnly); + + Assert.Equal(StyleArgumentName, Assert.Throws( + () => DateOnly.TryParse("aa-bb-cc".AsSpan(), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateOnly)).ParamName); + + Assert.Equal(StyleArgumentName, Assert.Throws( + () => DateOnly.TryParse("aa-bb-cc", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateOnly)).ParamName); } [Fact] @@ -131,13 +137,17 @@ public void DateOnlyTryParseExactValidationWorkedTest() DateTimeStyles.AllowWhiteSpaces, out dateOnly)); Assert.Equal(default, dateOnly); - Assert.False(DateOnly.TryParseExact( - string.Empty, string.Empty, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out dateOnly)); - Assert.Equal(default, dateOnly); + Assert.Equal(StyleArgumentName, Assert.Throws( + () => DateOnly.TryParseExact( + string.Empty, string.Empty, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out dateOnly)).ParamName); - Assert.False(DateOnly.TryParseExact( - new ReadOnlySpan(), string.Empty.AsSpan(), CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out dateOnly)); - Assert.Equal(default, dateOnly); + Assert.Equal(StyleArgumentName, Assert.Throws( + () => DateOnly.TryParseExact( + new ReadOnlySpan(), string.Empty.AsSpan(), CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out dateOnly)).ParamName); + + Assert.Equal(StyleArgumentName, Assert.Throws( + () => DateOnly.TryParseExact( + string.Empty, [string.Empty], CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out dateOnly)).ParamName); Assert.False(DateOnly.TryParseExact("aa-bb-cc", "dd-MM-YY", out dateOnly)); Assert.Equal(default, dateOnly); @@ -201,6 +211,12 @@ public void TimeOnlyTryParseValidationWorkedTest() Assert.False(TimeOnly.TryParse("aa:bb", out timeOnly)); Assert.Equal(default, timeOnly); + + Assert.Equal(StyleArgumentName, Assert.Throws( + () => TimeOnly.TryParse("aa:bb".AsSpan(), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out timeOnly)).ParamName); + + Assert.Equal(StyleArgumentName, Assert.Throws( + () => TimeOnly.TryParse("aa:bb", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out timeOnly)).ParamName); } [Fact] @@ -255,13 +271,17 @@ public void TimeOnlyTryParseExactValidationWorkedTest() DateTimeStyles.AllowWhiteSpaces, out timeOnly)); Assert.Equal(default, timeOnly); - Assert.False(TimeOnly.TryParseExact( - string.Empty, string.Empty, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out timeOnly)); - Assert.Equal(default, timeOnly); + Assert.Equal(StyleArgumentName, Assert.Throws( + () => TimeOnly.TryParseExact( + string.Empty, string.Empty, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out timeOnly)).ParamName); - Assert.False(TimeOnly.TryParseExact( - new ReadOnlySpan(), string.Empty.AsSpan(), CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out timeOnly)); - Assert.Equal(default, timeOnly); + Assert.Equal(StyleArgumentName, Assert.Throws( + () => TimeOnly.TryParseExact( + new ReadOnlySpan(), string.Empty.AsSpan(), CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out timeOnly)).ParamName); + + Assert.Equal(StyleArgumentName, Assert.Throws( + () => TimeOnly.TryParseExact( + string.Empty, [string.Empty], CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out timeOnly)).ParamName); Assert.False(TimeOnly.TryParseExact("aa-bb-cc", "dd-MM-YY", out timeOnly)); Assert.Equal(default, timeOnly); diff --git a/DateTimeOnly.Tests/DateOnlyTests.cs b/DateTimeOnly.Tests/DateOnlyTests.cs index bc77ded..f2c31f4 100644 --- a/DateTimeOnly.Tests/DateOnlyTests.cs +++ b/DateTimeOnly.Tests/DateOnlyTests.cs @@ -353,13 +353,13 @@ public static void BasicFormatParseTest() Assert.Equal(dateOnly, parsedDateOnly); Assert.Equal(dateOnly, parsedDateOnly1); - Assert.False(DateOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out parsedDateOnly1)); + Assert.Throws(() => DateOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out parsedDateOnly1)); Assert.Throws(() => DateOnly.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal)); - Assert.False(DateOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out parsedDateOnly1)); + Assert.Throws(() => DateOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out parsedDateOnly1)); Assert.Throws(() => DateOnly.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal)); - Assert.False(DateOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out parsedDateOnly1)); + Assert.Throws(() => DateOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out parsedDateOnly1)); Assert.Throws(() => DateOnly.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal)); - Assert.False(DateOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out parsedDateOnly1)); + Assert.Throws(() => DateOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out parsedDateOnly1)); Assert.Throws(() => DateOnly.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault)); s = " " + s + " "; diff --git a/DateTimeOnly.Tests/TimeOnlyTests.cs b/DateTimeOnly.Tests/TimeOnlyTests.cs index e6c74de..334ef7f 100644 --- a/DateTimeOnly.Tests/TimeOnlyTests.cs +++ b/DateTimeOnly.Tests/TimeOnlyTests.cs @@ -391,13 +391,13 @@ public static void BasicFormatParseTest() Assert.True(TimeOnly.TryParse(s.AsSpan(), CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedTimeOnly1)); Assert.Equal(parsedTimeOnly, parsedTimeOnly1); - Assert.False(TimeOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out parsedTimeOnly1)); + AssertExtensions.Throws("style", () => TimeOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out parsedTimeOnly1)); AssertExtensions.Throws("style", () => TimeOnly.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal)); - Assert.False(TimeOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out parsedTimeOnly1)); + AssertExtensions.Throws("style", () => TimeOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out parsedTimeOnly1)); AssertExtensions.Throws("style", () => TimeOnly.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal)); - Assert.False(TimeOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out parsedTimeOnly1)); + AssertExtensions.Throws("style", () => TimeOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out parsedTimeOnly1)); AssertExtensions.Throws("style", () => TimeOnly.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal)); - Assert.False(TimeOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out parsedTimeOnly1)); + AssertExtensions.Throws("style", () => TimeOnly.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out parsedTimeOnly1)); AssertExtensions.Throws("style", () => TimeOnly.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault)); s = " " + s + " "; diff --git a/DateTimeOnly/DateOnly.cs b/DateTimeOnly/DateOnly.cs index e6045e6..56e6eda 100644 --- a/DateTimeOnly/DateOnly.cs +++ b/DateTimeOnly/DateOnly.cs @@ -436,7 +436,15 @@ public static DateOnly ParseExact(string s, [StringSyntax(StringSyntaxAttribute. /// A bitwise combination of enumeration values that indicates the permitted format of s. A typical value to specify is None. /// When this method returns, contains the DateOnly value equivalent to the date contained in s, if the conversion succeeded, or MinValue if the conversion failed. The conversion fails if the s parameter is empty string, or does not contain a valid string representation of a date. This parameter is passed uninitialized. /// true if the s parameter was converted successfully; otherwise, false. - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) => TryParseInternal(s, provider, style, out result) == ParseFailureKind.None; + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) + { + if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0) + { + throw new ArgumentException(SR.Argument_InvalidDateStyles, nameof(style)); + } + + return TryParseInternal(s, provider, style, out result) == ParseFailureKind.None; + } private static ParseFailureKind TryParseInternal(ReadOnlySpan s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) { @@ -485,8 +493,15 @@ private static ParseFailureKind TryParseInternal(ReadOnlySpan s, IFormatPr /// A bitwise combination of one or more enumeration values that indicate the permitted format of s. /// When this method returns, contains the DateOnly value equivalent to the date contained in s, if the conversion succeeded, or MinValue if the conversion failed. The conversion fails if the s is empty string, or does not contain a date that correspond to the pattern specified in format. This parameter is passed uninitialized. /// true if s was converted successfully; otherwise, false. - public static bool TryParseExact(ReadOnlySpan s, [StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) => - TryParseExactInternal(s, format, provider, style, out result) == ParseFailureKind.None; + public static bool TryParseExact(ReadOnlySpan s, [StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) + { + if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0) + { + throw new ArgumentException(SR.Argument_InvalidDateStyles, nameof(style)); + } + + return TryParseExactInternal(s, format, provider, style, out result) == ParseFailureKind.None; + } private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) { if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0) @@ -549,8 +564,15 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, Read /// A bitwise combination of enumeration values that defines how to interpret the parsed date. A typical value to specify is None. /// When this method returns, contains the DateOnly value equivalent to the date contained in s, if the conversion succeeded, or MinValue if the conversion failed. The conversion fails if the s parameter is Empty, or does not contain a valid string representation of a date. This parameter is passed uninitialized. /// true if the s parameter was converted successfully; otherwise, false. - public static bool TryParseExact(ReadOnlySpan s, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) => - TryParseExactInternal(s, formats, provider, style, out result) == ParseFailureKind.None; + public static bool TryParseExact(ReadOnlySpan s, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) + { + if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0) + { + throw new ArgumentException(SR.Argument_InvalidDateStyles, nameof(style)); + } + + return TryParseExactInternal(s, formats, provider, style, out result) == ParseFailureKind.None; + } private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) { diff --git a/DateTimeOnly/TimeOnly.cs b/DateTimeOnly/TimeOnly.cs index 2e592ad..ec572fb 100644 --- a/DateTimeOnly/TimeOnly.cs +++ b/DateTimeOnly/TimeOnly.cs @@ -603,8 +603,15 @@ public static TimeOnly ParseExact(string s, [StringSyntax(StringSyntaxAttribute. /// When this method returns, contains the TimeOnly value equivalent to the time contained in s, if the conversion succeeded, or MinValue if the conversion failed. The conversion fails if the s parameter is empty string, or does not contain a valid string representation of a date. This parameter is passed uninitialized. /// true if the s parameter was converted successfully; otherwise, false. /// - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) => - TryParseInternal(s, provider, style, out result) == ParseFailureKind.None; + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) + { + if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0) + { + throw new ArgumentException(SR.Argument_InvalidDateStyles, nameof(style)); + } + + return TryParseInternal(s, provider, style, out result) == ParseFailureKind.None; + } private static ParseFailureKind TryParseInternal(ReadOnlySpan s, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) { if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0) @@ -654,8 +661,15 @@ private static ParseFailureKind TryParseInternal(ReadOnlySpan s, IFormatPr /// A bitwise combination of one or more enumeration values that indicate the permitted format of s. /// When this method returns, contains the TimeOnly value equivalent to the time contained in s, if the conversion succeeded, or MinValue if the conversion failed. The conversion fails if the s is empty string, or does not contain a time that correspond to the pattern specified in format. This parameter is passed uninitialized. /// true if s was converted successfully; otherwise, false. - public static bool TryParseExact(ReadOnlySpan s, [StringSyntax(StringSyntaxAttribute.TimeOnlyFormat)] ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) => - TryParseExactInternal(s, format, provider, style, out result) == ParseFailureKind.None; + public static bool TryParseExact(ReadOnlySpan s, [StringSyntax(StringSyntaxAttribute.TimeOnlyFormat)] ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) + { + if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0) + { + throw new ArgumentException(SR.Argument_InvalidDateStyles, nameof(style)); + } + + return TryParseExactInternal(s, format, provider, style, out result) == ParseFailureKind.None; + } private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) { @@ -719,8 +733,15 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, Read /// A bitwise combination of enumeration values that defines how to interpret the parsed time. A typical value to specify is None. /// When this method returns, contains the TimeOnly value equivalent to the time contained in s, if the conversion succeeded, or MinValue if the conversion failed. The conversion fails if the s parameter is Empty, or does not contain a valid string representation of a time. This parameter is passed uninitialized. /// true if the s parameter was converted successfully; otherwise, false. - public static bool TryParseExact(ReadOnlySpan s, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeOnlyFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) => - TryParseExactInternal(s, formats, provider, style, out result) == ParseFailureKind.None; + public static bool TryParseExact(ReadOnlySpan s, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeOnlyFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) + { + if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0) + { + throw new ArgumentException(SR.Argument_InvalidDateStyles, nameof(style)); + } + + return TryParseExactInternal(s, formats, provider, style, out result) == ParseFailureKind.None; + } private static ParseFailureKind TryParseExactInternal(ReadOnlySpan s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) {