From a4049ce720b5fe85eeab5f2841846fd5bf6ed00d Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 22 Nov 2023 11:49:42 -0500 Subject: [PATCH 1/2] Fix FormatException error message when parsing invalid UTF8 inputs --- .../src/System/Number.Parsing.cs | 23 ++++++++++++++++++- .../System.Runtime.Tests/System/ByteTests.cs | 15 +++++++++++- .../System/DecimalTests.cs | 15 +++++++++++- .../System/DoubleTests.cs | 15 +++++++++++- .../System.Runtime.Tests/System/HalfTests.cs | 15 +++++++++++- .../System/Int128Tests.cs | 15 +++++++++++- .../System.Runtime.Tests/System/Int16Tests.cs | 15 +++++++++++- .../System.Runtime.Tests/System/Int32Tests.cs | 15 +++++++++++- .../System.Runtime.Tests/System/Int64Tests.cs | 15 +++++++++++- .../System/IntPtrTests.cs | 15 +++++++++++- .../System.Runtime.Tests/System/SByteTests.cs | 15 +++++++++++- .../System/SingleTests.cs | 15 +++++++++++- .../System/UInt128Tests.cs | 15 +++++++++++- .../System/UInt16Tests.cs | 15 +++++++++++- .../System/UInt32Tests.cs | 15 +++++++++++- .../System/UInt64Tests.cs | 15 +++++++++++- .../System/UIntPtrTests.cs | 15 +++++++++++- 17 files changed, 246 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs index 77164243594258..0a39cf2c0ae3cf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using System.Text.Unicode; namespace System { @@ -1388,7 +1389,27 @@ internal static void ThrowOverflowOrFormatException(ParsingStat internal static void ThrowFormatException(ReadOnlySpan value) where TChar : unmanaged, IUtfChar { - throw new FormatException(SR.Format(SR.Format_InvalidStringWithValue, value.ToString())); + string errorMessage; + + if (typeof(TChar) == typeof(byte)) + { + // Decode the UTF8 value into a string we can include in the error message. We're here + // because we failed to parse, which also means the bytes might not be valid UTF8, + // so fallback to a message that doesn't include the value if the bytes are invalid. + // It's possible after we check the bytes for validity that they could be concurrently + // mutated, but if that's happening, all bets are off, anyway, and it simply impacts + // which exception is thrown. + ReadOnlySpan bytes = MemoryMarshal.Cast(value); + errorMessage = Utf8.IsValid(bytes) ? + SR.Format(SR.Format_InvalidStringWithValue, Encoding.UTF8.GetString(bytes)) : + SR.Format_InvalidString; + } + else + { + errorMessage = SR.Format(SR.Format_InvalidStringWithValue, value.ToString()); + } + + throw new FormatException(errorMessage); } [DoesNotReturn] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.cs index 3593c9b4f470e2..96df8fc909f443 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.cs @@ -405,13 +405,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0u, result); } - Assert.Throws(exceptionType, () => byte.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => byte.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(byte.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0u, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => byte.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(byte i, string format, IFormatProvider provider, string expected) => diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalTests.cs index 3a8c9a344d02cd..5b51bc926b3b32 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalTests.cs @@ -1037,13 +1037,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor if (value != null) { ReadOnlySpan valueUtf8 = Encoding.UTF8.GetBytes(value); - Assert.Throws(exceptionType, () => decimal.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => decimal.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(decimal.TryParse(valueUtf8, style, provider, out decimal result)); Assert.Equal(0, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => decimal.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + public static IEnumerable Remainder_Valid_TestData() { decimal NegativeZero = new decimal(0, 0, 0, true, 0); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs index 3c159c0534e7e1..dcfe71c4722822 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs @@ -658,13 +658,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor if (value != null) { ReadOnlySpan valueUtf8 = Encoding.UTF8.GetBytes(value); - Assert.Throws(exceptionType, () => double.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => double.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(double.TryParse(valueUtf8, style, provider, out double result)); Assert.Equal(0, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => double.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Fact] public static void PositiveInfinity() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs index e5b68dfd0bc0d7..f7c769f2c88c34 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs @@ -921,13 +921,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor if (value != null) { ReadOnlySpan valueUtf8 = Encoding.UTF8.GetBytes(value); - Assert.Throws(exceptionType, () => float.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => Half.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(float.TryParse(valueUtf8, style, provider, out float result)); Assert.Equal(0, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => Half.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + public static IEnumerable ToString_TestData() { yield return new object[] { -4570.0f, "G", null, "-4570" }; diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs index 26fba082e64a83..d3767b224fef65 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs @@ -476,13 +476,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0, result); } - Assert.Throws(exceptionType, () => Int128.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => Int128.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(Int128.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => Int128.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(Int128 i, string format, IFormatProvider provider, string expected) => diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.cs index 150b035dccb5fc..42e7b39a6a3f61 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.cs @@ -430,13 +430,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0, result); } - Assert.Throws(exceptionType, () => short.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => short.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(short.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => short.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(short i, string format, IFormatProvider provider, string expected) => diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs index 0b5f7c8250efe3..cbfbfa9830b97f 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs @@ -864,13 +864,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0, result); } - Assert.Throws(exceptionType, () => int.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => int.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(int.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => int.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [InlineData("N")] [InlineData("F")] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.cs index 07b79d94333006..991ac565e04a0e 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.cs @@ -458,13 +458,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0, result); } - Assert.Throws(exceptionType, () => long.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => long.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(long.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => long.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(long i, string format, IFormatProvider provider, string expected) => diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.cs index f4a16159467f7e..72856049494038 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.cs @@ -1021,13 +1021,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(default, result); } - Assert.Throws(exceptionType, () => int.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => nint.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(nint.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(default, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => nint.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [InlineData("N")] [InlineData("F")] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.cs index 0f18bb2e61e02a..15891fd2f1b30c 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.cs @@ -424,13 +424,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0, result); } - Assert.Throws(exceptionType, () => sbyte.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => sbyte.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(sbyte.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => sbyte.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(sbyte i, string format, IFormatProvider provider, string expected) => diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs index 459bdd843f5a9f..8c13a66a84449d 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs @@ -597,13 +597,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor if (value != null) { ReadOnlySpan valueUtf8 = Encoding.UTF8.GetBytes(value); - Assert.Throws(exceptionType, () => float.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => float.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(float.TryParse(valueUtf8, style, provider, out float result)); Assert.Equal(0, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => float.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Fact] public static void PositiveInfinity() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs index f17444e678da0b..19168cf4244d9c 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs @@ -463,13 +463,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0u, result); } - Assert.Throws(exceptionType, () => UInt128.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => UInt128.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(UInt128.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0u, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => UInt128.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(UInt128 i, string format, IFormatProvider provider, string expected) => diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.cs index 25b4c3b944678e..4e47d10a09354e 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.cs @@ -402,13 +402,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0u, result); } - Assert.Throws(exceptionType, () => ushort.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => ushort.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(ushort.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0u, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => ushort.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(ushort i, string format, IFormatProvider provider, string expected) => diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.cs index f912fbd03434a6..7c09e75b9830ed 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.cs @@ -432,13 +432,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0u, result); } - Assert.Throws(exceptionType, () => uint.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => uint.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(uint.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0u, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => uint.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(uint i, string format, IFormatProvider provider, string expected) => diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.cs index e47286dca51b27..13ca15f2e7f4f7 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.cs @@ -445,13 +445,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(0u, result); } - Assert.Throws(exceptionType, () => ulong.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => ulong.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(ulong.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(0u, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => ulong.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(ulong i, string format, IFormatProvider provider, string expected) => diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.cs index 6e1f5d3b460945..9ade4514251fea 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.cs @@ -584,13 +584,26 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor Assert.Equal(default, result); } - Assert.Throws(exceptionType, () => nuint.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + Exception e = Assert.Throws(exceptionType, () => nuint.Parse(Encoding.UTF8.GetBytes(value), style, provider)); + if (e is FormatException fe) + { + Assert.Contains(value, fe.Message); + } Assert.False(nuint.TryParse(valueUtf8, style, provider, out result)); Assert.Equal(default, result); } } + [Fact] + public static void Parse_Utf8Span_InvalidUtf8() + { + FormatException fe = Assert.Throws(() => nuint.Parse([0xA0])); + Assert.DoesNotContain("A0", fe.Message); + Assert.DoesNotContain("ReadOnlySpan", fe.Message); + Assert.DoesNotContain("\uFFFD", fe.Message); + } + [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat(nuint i, string format, IFormatProvider provider, string expected) => From 0d92b6c634c5927888aed371829242921c0d93b4 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 11 Dec 2023 12:02:47 -0500 Subject: [PATCH 2/2] Use Ordinal comparison in Assert.DoesNotContain calls --- .../tests/System.Runtime.Tests/System/ByteTests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/DecimalTests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/DoubleTests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/HalfTests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/Int128Tests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/Int16Tests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/Int32Tests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/Int64Tests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/IntPtrTests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/SByteTests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/SingleTests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/UInt128Tests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/UInt16Tests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/UInt32Tests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/UInt64Tests.cs | 6 +++--- .../tests/System.Runtime.Tests/System/UIntPtrTests.cs | 6 +++--- 16 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.cs index 96df8fc909f443..0325507355adae 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.cs @@ -420,9 +420,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => byte.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalTests.cs index 5b51bc926b3b32..cf62bd32354494 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalTests.cs @@ -1052,9 +1052,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => decimal.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } public static IEnumerable Remainder_Valid_TestData() diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs index dcfe71c4722822..bf5e2261995ee0 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs @@ -673,9 +673,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => double.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Fact] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs index f7c769f2c88c34..1e7f06602c0ec7 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs @@ -936,9 +936,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => Half.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } public static IEnumerable ToString_TestData() diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs index d3767b224fef65..8c1910e2fbd8dc 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs @@ -491,9 +491,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => Int128.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.cs index 42e7b39a6a3f61..60414f96e1a8b6 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.cs @@ -445,9 +445,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => short.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs index cbfbfa9830b97f..b0e33fc98783eb 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs @@ -879,9 +879,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => int.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.cs index 991ac565e04a0e..ac902ebdbd7c85 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.cs @@ -473,9 +473,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => long.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.cs index 72856049494038..9b2d96e9797fea 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.cs @@ -1036,9 +1036,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => nint.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.cs index 15891fd2f1b30c..7b92f123fd498e 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.cs @@ -439,9 +439,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => sbyte.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs index 8c13a66a84449d..25f8d230c80c03 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs @@ -612,9 +612,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => float.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Fact] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs index 19168cf4244d9c..e3d2c474bcd46b 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs @@ -478,9 +478,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => UInt128.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.cs index 4e47d10a09354e..6ddf7c3bfbaab1 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.cs @@ -417,9 +417,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => ushort.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.cs index 7c09e75b9830ed..c2f80bba01dda7 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.cs @@ -447,9 +447,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => uint.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.cs index 13ca15f2e7f4f7..de44a6f175884f 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.cs @@ -460,9 +460,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => ulong.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.cs index 9ade4514251fea..6978b9e44eb590 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.cs @@ -599,9 +599,9 @@ public static void Parse_Utf8Span_Invalid(string value, NumberStyles style, IFor public static void Parse_Utf8Span_InvalidUtf8() { FormatException fe = Assert.Throws(() => nuint.Parse([0xA0])); - Assert.DoesNotContain("A0", fe.Message); - Assert.DoesNotContain("ReadOnlySpan", fe.Message); - Assert.DoesNotContain("\uFFFD", fe.Message); + Assert.DoesNotContain("A0", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("ReadOnlySpan", fe.Message, StringComparison.Ordinal); + Assert.DoesNotContain("\uFFFD", fe.Message, StringComparison.Ordinal); } [Theory]