Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTanner Gooding <tagoo@outlook.com>2020-04-24 00:27:23 +0300
committerGitHub <noreply@github.com>2020-04-24 00:27:23 +0300
commit0ce44af8241fafb5c6080b111cc00391308db681 (patch)
tree4cd4e2cfb44fa5ba30281afbce6c9f4e7602e087
parent88c069b819bdfb87afeea4f09c78577e56ea06fa (diff)
[release/5.0-preview4] Add new IntPtr/UIntPtr API surface (#35248)
* Add new IntPtr/UIntPtr API surface (#307) * Add new IntPtr surface * Add new UIntPtr API surface * Add sequential layout to match [U]Int32 * Add interfaces and sequential layout * Add interfaces * Add namespaces * Add namespaces * Update UIntPtr.cs * Update IntPtr.cs * Change style * make non versionable, elide copy * fix style, elide copy, make non versionable * Fix syntax error * Fix style issues * Fix style issues * Update IntPtr.cs * Update UIntPtr.cs * Update ref assembly * Allow comparison of intptr/uintptr in Array * Fixed ELEMENT_TYPE cases, added tests based on Int32/UInt32 tests * Fixes * Update Array.cs * Update Array.cs * Update Array.cs * Update ArrayTests.cs * Update ArrayTests.cs * Update UIntPtrTests.cs * Update ArrayTests.cs * fix instance methods?? * fixes * Fixwa * fix tests * Add non versionables * fix compare methods * Fix comparison error * fix boundary * fix compares * fix maxvals * remove xunit buggy data * silly var name error * Update src/libraries/System.Private.CoreLib/src/Resources/Strings.resx Co-Authored-By: Tanner Gooding <tagoo@outlook.com> * Fix ToString Co-authored-by: Tanner Gooding <tagoo@outlook.com> * Remove the explicit IEquatable implementation from the IntPtr/UIntPtr reference API Co-authored-by: John <johnkellyoxford@gmail.com>
-rw-r--r--src/libraries/System.Private.CoreLib/src/Resources/Strings.resx6
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/Array.cs32
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/IntPtr.cs67
-rw-r--r--src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs65
-rw-r--r--src/libraries/System.Runtime/ref/System.Runtime.cs41
-rw-r--r--src/libraries/System.Runtime/tests/System/ArrayTests.cs57
-rw-r--r--src/libraries/System.Runtime/tests/System/IntPtrTests.cs714
-rw-r--r--src/libraries/System.Runtime/tests/System/UIntPtrTests.cs291
8 files changed, 1238 insertions, 35 deletions
diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
index 74ea5902d7e..4fabff5d4eb 100644
--- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
+++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
@@ -523,6 +523,9 @@
<data name="Arg_MustBeInt64" xml:space="preserve">
<value>Object must be of type Int64.</value>
</data>
+ <data name="Arg_MustBeIntPtr" xml:space="preserve">
+ <value>Object must be of type IntPtr.</value>
+ </data>
<data name="Arg_MustBeInterface" xml:space="preserve">
<value>Type passed must be an interface.</value>
</data>
@@ -562,6 +565,9 @@
<data name="Arg_MustBeUInt64" xml:space="preserve">
<value>Object must be of type UInt64.</value>
</data>
+ <data name="Arg_MustBeUIntPtr" xml:space="preserve">
+ <value>Object must be of type UIntPtr.</value>
+ </data>
<data name="Arg_MustBeVersion" xml:space="preserve">
<value>Object must be of type Version.</value>
</data>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Array.cs b/src/libraries/System.Private.CoreLib/src/System/Array.cs
index 5e22383eb1d..2411ba2546a 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Array.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Array.cs
@@ -510,9 +510,7 @@ namespace System
if (comparer == Comparer.Default)
{
CorElementType et = array.GetCorElementTypeOfElementType();
- if (et.IsPrimitiveType()
- // IntPtr/UIntPtr does not implement IComparable
- && (et != CorElementType.ELEMENT_TYPE_I) && (et != CorElementType.ELEMENT_TYPE_U))
+ if (et.IsPrimitiveType())
{
if (value == null)
return ~index;
@@ -538,15 +536,27 @@ namespace System
result = GenericBinarySearch<ushort>(array, adjustedIndex, length, value);
break;
case CorElementType.ELEMENT_TYPE_I4:
+#if TARGET_32BIT
+ case CorElementType.ELEMENT_TYPE_I:
+#endif
result = GenericBinarySearch<int>(array, adjustedIndex, length, value);
break;
case CorElementType.ELEMENT_TYPE_U4:
+#if TARGET_32BIT
+ case CorElementType.ELEMENT_TYPE_U:
+#endif
result = GenericBinarySearch<uint>(array, adjustedIndex, length, value);
break;
case CorElementType.ELEMENT_TYPE_I8:
+#if TARGET_64BIT
+ case CorElementType.ELEMENT_TYPE_I:
+#endif
result = GenericBinarySearch<long>(array, adjustedIndex, length, value);
break;
case CorElementType.ELEMENT_TYPE_U8:
+#if TARGET_64BIT
+ case CorElementType.ELEMENT_TYPE_U:
+#endif
result = GenericBinarySearch<ulong>(array, adjustedIndex, length, value);
break;
case CorElementType.ELEMENT_TYPE_R4:
@@ -1674,15 +1684,27 @@ namespace System
GenericSort<ushort>(keys, items, adjustedIndex, length);
return;
case CorElementType.ELEMENT_TYPE_I4:
+#if TARGET_32BIT
+ case CorElementType.ELEMENT_TYPE_I:
+#endif
GenericSort<int>(keys, items, adjustedIndex, length);
return;
case CorElementType.ELEMENT_TYPE_U4:
+#if TARGET_32BIT
+ case CorElementType.ELEMENT_TYPE_U:
+#endif
GenericSort<uint>(keys, items, adjustedIndex, length);
return;
case CorElementType.ELEMENT_TYPE_I8:
+#if TARGET_64BIT
+ case CorElementType.ELEMENT_TYPE_I:
+#endif
GenericSort<long>(keys, items, adjustedIndex, length);
return;
case CorElementType.ELEMENT_TYPE_U8:
+#if TARGET_64BIT
+ case CorElementType.ELEMENT_TYPE_U:
+#endif
GenericSort<ulong>(keys, items, adjustedIndex, length);
return;
case CorElementType.ELEMENT_TYPE_R4:
@@ -1691,10 +1713,6 @@ namespace System
case CorElementType.ELEMENT_TYPE_R8:
GenericSort<double>(keys, items, adjustedIndex, length);
return;
- case CorElementType.ELEMENT_TYPE_I:
- case CorElementType.ELEMENT_TYPE_U:
- // IntPtr/UIntPtr does not implement IComparable
- break;
}
static void GenericSort<T>(Array keys, Array? items, int adjustedIndex, int length) where T: struct
diff --git a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs
index e14dbc752f6..d82c18f1fa7 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs
@@ -4,8 +4,10 @@
using System.Globalization;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
+using Internal.Runtime.CompilerServices;
#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
#if TARGET_64BIT
@@ -17,8 +19,9 @@ using nint = System.Int32;
namespace System
{
[Serializable]
+ [StructLayout(LayoutKind.Sequential)]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- public readonly struct IntPtr : IEquatable<IntPtr>, ISerializable
+ public readonly struct IntPtr : IEquatable<IntPtr>, IComparable, IComparable<IntPtr>, IFormattable, ISerializable
{
// WARNING: We allow diagnostic tools to directly inspect this member (_value).
// See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details.
@@ -74,9 +77,6 @@ namespace System
obj is IntPtr other &&
_value == other._value;
- unsafe bool IEquatable<IntPtr>.Equals(IntPtr other) =>
- _value == other._value;
-
public override unsafe int GetHashCode()
{
#if TARGET_64BIT
@@ -169,10 +169,61 @@ namespace System
[NonVersionable]
public unsafe void* ToPointer() => _value;
- public override unsafe string ToString() =>
- ((nint)_value).ToString(CultureInfo.InvariantCulture);
+ public static IntPtr MaxValue
+ {
+ [NonVersionable]
+ get => (IntPtr)nint.MaxValue;
+ }
+
+ public static IntPtr MinValue
+ {
+ [NonVersionable]
+ get => (IntPtr)nint.MinValue;
+ }
+
+ // Don't just delegate to nint.CompareTo as it needs to throw when not IntPtr
+ public unsafe int CompareTo(object? value)
+ {
+ if (value is null)
+ {
+ return 1;
+ }
+ if (value is IntPtr o)
+ {
+ nint i = (nint)o;
+ if ((nint)_value < i) return -1;
+ if ((nint)_value > i) return 1;
+ return 0;
+ }
+
+ throw new ArgumentException(SR.Arg_MustBeIntPtr);
+ }
+
+ public unsafe int CompareTo(IntPtr value) => ((nint)_value).CompareTo((nint)value);
+
+ [NonVersionable]
+ public unsafe bool Equals(IntPtr other) => (nint)_value == (nint)other;
+
+ public unsafe override string ToString() => ((nint)_value).ToString();
+ public unsafe string ToString(string? format) => ((nint)_value).ToString(format);
+ public unsafe string ToString(IFormatProvider? provider) => ((nint)_value).ToString(provider);
+ public unsafe string ToString(string? format, IFormatProvider? provider) => ((nint)_value).ToString(format, provider);
+
+ public static IntPtr Parse(string s) => (IntPtr)nint.Parse(s);
+ public static IntPtr Parse(string s, NumberStyles style) => (IntPtr)nint.Parse(s, style);
+ public static IntPtr Parse(string s, IFormatProvider? provider) => (IntPtr)nint.Parse(s, provider);
+ public static IntPtr Parse(string s, NumberStyles style, IFormatProvider? provider) => (IntPtr)nint.Parse(s, style, provider);
- public unsafe string ToString(string format) =>
- ((nint)_value).ToString(format, CultureInfo.InvariantCulture);
+ public static bool TryParse(string? s, out IntPtr result)
+ {
+ Unsafe.SkipInit(out result);
+ return nint.TryParse(s, out Unsafe.As<IntPtr, nint>(ref result));
+ }
+
+ public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out IntPtr result)
+ {
+ Unsafe.SkipInit(out result);
+ return nint.TryParse(s, style, provider, out Unsafe.As<IntPtr, nint>(ref result));
+ }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs
index 217e1566cb3..99eb0cf7590 100644
--- a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs
@@ -4,8 +4,10 @@
using System.Globalization;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
+using Internal.Runtime.CompilerServices;
#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
#if TARGET_64BIT
@@ -18,8 +20,9 @@ namespace System
{
[Serializable]
[CLSCompliant(false)]
+ [StructLayout(LayoutKind.Sequential)]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- public readonly struct UIntPtr : IEquatable<UIntPtr>, ISerializable
+ public readonly struct UIntPtr : IEquatable<UIntPtr>, IComparable, IComparable<UIntPtr>, IFormattable, ISerializable
{
private readonly unsafe void* _value; // Do not rename (binary serialization)
@@ -75,9 +78,6 @@ namespace System
return false;
}
- unsafe bool IEquatable<UIntPtr>.Equals(UIntPtr other) =>
- _value == other._value;
-
public override unsafe int GetHashCode()
{
#if TARGET_64BIT
@@ -162,7 +162,60 @@ namespace System
[NonVersionable]
public unsafe void* ToPointer() => _value;
- public override unsafe string ToString() =>
- ((nuint)_value).ToString(CultureInfo.InvariantCulture);
+ public static UIntPtr MaxValue
+ {
+ [NonVersionable]
+ get => (UIntPtr)nuint.MaxValue;
+ }
+
+ public static UIntPtr MinValue
+ {
+ [NonVersionable]
+ get => (UIntPtr)nuint.MinValue;
+ }
+
+ public unsafe int CompareTo(object? value)
+ {
+ if (value is null)
+ {
+ return 1;
+ }
+ if (value is UIntPtr o)
+ {
+ nuint i = (nuint)o;
+ if ((nuint)_value < i) return -1;
+ if ((nuint)_value > i) return 1;
+ return 0;
+ }
+
+ throw new ArgumentException(SR.Arg_MustBeUIntPtr);
+ }
+
+ public unsafe int CompareTo(UIntPtr value) => ((nuint)_value).CompareTo((nuint)value);
+
+ [NonVersionable]
+ public unsafe bool Equals(UIntPtr other) => (nuint)_value == (nuint)other;
+
+ public unsafe override string ToString() => ((nuint)_value).ToString();
+ public unsafe string ToString(string? format) => ((nuint)_value).ToString(format);
+ public unsafe string ToString(IFormatProvider? provider) => ((nuint)_value).ToString(provider);
+ public unsafe string ToString(string? format, IFormatProvider? provider) => ((nuint)_value).ToString(format, provider);
+
+ public static UIntPtr Parse(string s) => (UIntPtr)nuint.Parse(s);
+ public static UIntPtr Parse(string s, NumberStyles style) => (UIntPtr)nuint.Parse(s, style);
+ public static UIntPtr Parse(string s, IFormatProvider? provider) => (UIntPtr)nuint.Parse(s, provider);
+ public static UIntPtr Parse(string s, NumberStyles style, IFormatProvider? provider) => (UIntPtr)nuint.Parse(s, style, provider);
+
+ public static bool TryParse(string? s, out UIntPtr result)
+ {
+ Unsafe.SkipInit(out result);
+ return nuint.TryParse(s, out Unsafe.As<UIntPtr, nuint>(ref result));
+ }
+
+ public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out UIntPtr result)
+ {
+ Unsafe.SkipInit(out result);
+ return nuint.TryParse(s, style, provider, out Unsafe.As<UIntPtr, nuint>(ref result));
+ }
}
}
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index 92c33cee8bb..e34f9431ec0 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -2388,7 +2388,7 @@ namespace System
public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int64 result) { throw null; }
public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Int64 result) { throw null; }
}
- public readonly partial struct IntPtr : System.IEquatable<System.IntPtr>, System.Runtime.Serialization.ISerializable
+ public readonly partial struct IntPtr : System.IComparable, System.IComparable<System.IntPtr>, System.IEquatable<System.IntPtr>, System.IFormattable, System.Runtime.Serialization.ISerializable
{
private readonly int _dummyPrimitive;
public static readonly System.IntPtr Zero;
@@ -2396,8 +2396,13 @@ namespace System
public IntPtr(long value) { throw null; }
[System.CLSCompliantAttribute(false)]
public unsafe IntPtr(void* value) { throw null; }
+ public static System.IntPtr MaxValue { get { throw null; } }
+ public static System.IntPtr MinValue { get { throw null; } }
public static int Size { get { throw null; } }
public static System.IntPtr Add(System.IntPtr pointer, int offset) { throw null; }
+ public int CompareTo(System.IntPtr value) { throw null; }
+ public int CompareTo(object? value) { throw null; }
+ public bool Equals(System.IntPtr other) { throw null; }
public override bool Equals(object? obj) { throw null; }
public override int GetHashCode() { throw null; }
public static System.IntPtr operator +(System.IntPtr pointer, int offset) { throw null; }
@@ -2412,15 +2417,22 @@ namespace System
public unsafe static explicit operator System.IntPtr (void* value) { throw null; }
public static bool operator !=(System.IntPtr value1, System.IntPtr value2) { throw null; }
public static System.IntPtr operator -(System.IntPtr pointer, int offset) { throw null; }
+ public static System.IntPtr Parse(string s) { throw null; }
+ public static System.IntPtr Parse(string s, System.Globalization.NumberStyles style) { throw null; }
+ public static System.IntPtr Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; }
+ public static System.IntPtr Parse(string s, System.IFormatProvider? provider) { throw null; }
public static System.IntPtr Subtract(System.IntPtr pointer, int offset) { throw null; }
- bool System.IEquatable<System.IntPtr>.Equals(System.IntPtr other) { throw null; }
void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public int ToInt32() { throw null; }
public long ToInt64() { throw null; }
[System.CLSCompliantAttribute(false)]
public unsafe void* ToPointer() { throw null; }
public override string ToString() { throw null; }
- public string ToString(string format) { throw null; }
+ public string ToString(System.IFormatProvider? provider) { throw null; }
+ public string ToString(string? format) { throw null; }
+ public string ToString(string? format, System.IFormatProvider? provider) { throw null; }
+ public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.IntPtr result) { throw null; }
+ public static bool TryParse(string? s, out System.IntPtr result) { throw null; }
}
public partial class InvalidCastException : System.SystemException
{
@@ -4342,16 +4354,21 @@ namespace System
public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.UInt64 result) { throw null; }
}
[System.CLSCompliantAttribute(false)]
- public readonly partial struct UIntPtr : System.IEquatable<System.UIntPtr>, System.Runtime.Serialization.ISerializable
+ public readonly partial struct UIntPtr : System.IComparable, System.IComparable<System.UIntPtr>, System.IEquatable<System.UIntPtr>, System.IFormattable, System.Runtime.Serialization.ISerializable
{
private readonly int _dummyPrimitive;
public static readonly System.UIntPtr Zero;
public UIntPtr(uint value) { throw null; }
public UIntPtr(ulong value) { throw null; }
public unsafe UIntPtr(void* value) { throw null; }
+ public static System.UIntPtr MaxValue { get { throw null; } }
+ public static System.UIntPtr MinValue { get { throw null; } }
public static int Size { get { throw null; } }
public static System.UIntPtr Add(System.UIntPtr pointer, int offset) { throw null; }
+ public int CompareTo(object? value) { throw null; }
+ public int CompareTo(System.UIntPtr value) { throw null; }
public override bool Equals(object? obj) { throw null; }
+ public bool Equals(System.UIntPtr other) { throw null; }
public override int GetHashCode() { throw null; }
public static System.UIntPtr operator +(System.UIntPtr pointer, int offset) { throw null; }
public static bool operator ==(System.UIntPtr value1, System.UIntPtr value2) { throw null; }
@@ -4363,13 +4380,21 @@ namespace System
public unsafe static explicit operator System.UIntPtr (void* value) { throw null; }
public static bool operator !=(System.UIntPtr value1, System.UIntPtr value2) { throw null; }
public static System.UIntPtr operator -(System.UIntPtr pointer, int offset) { throw null; }
+ public static System.UIntPtr Parse(string s) { throw null; }
+ public static System.UIntPtr Parse(string s, System.Globalization.NumberStyles style) { throw null; }
+ public static System.UIntPtr Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; }
+ public static System.UIntPtr Parse(string s, System.IFormatProvider? provider) { throw null; }
public static System.UIntPtr Subtract(System.UIntPtr pointer, int offset) { throw null; }
- bool System.IEquatable<System.UIntPtr>.Equals(System.UIntPtr other) { throw null; }
void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public unsafe void* ToPointer() { throw null; }
public override string ToString() { throw null; }
+ public string ToString(System.IFormatProvider? provider) { throw null; }
+ public string ToString(string? format) { throw null; }
+ public string ToString(string? format, System.IFormatProvider? provider) { throw null; }
public uint ToUInt32() { throw null; }
public ulong ToUInt64() { throw null; }
+ public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UIntPtr result) { throw null; }
+ public static bool TryParse(string? s, out System.UIntPtr result) { throw null; }
}
public partial class UnauthorizedAccessException : System.SystemException
{
@@ -5402,10 +5427,10 @@ namespace System.Diagnostics
public static void Close() { }
[System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute]
[System.Diagnostics.ConditionalAttribute("DEBUG")]
- public static void Fail(string? message) => throw null;
+ public static void Fail(string? message) => throw null;
[System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute]
[System.Diagnostics.ConditionalAttribute("DEBUG")]
- public static void Fail(string? message, string? detailMessage) => throw null;
+ public static void Fail(string? message, string? detailMessage) => throw null;
[System.Diagnostics.ConditionalAttribute("DEBUG")]
public static void Flush() { }
[System.Diagnostics.ConditionalAttribute("DEBUG")]
@@ -9196,7 +9221,7 @@ namespace System.Runtime.ExceptionServices
[System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute]
public void Throw() => throw null;
[System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute]
- public static void Throw(System.Exception source) => throw null;
+ public static void Throw(System.Exception source) => throw null;
}
public partial class FirstChanceExceptionEventArgs : System.EventArgs
{
diff --git a/src/libraries/System.Runtime/tests/System/ArrayTests.cs b/src/libraries/System.Runtime/tests/System/ArrayTests.cs
index b3e350af78a..d18f0e5a2a9 100644
--- a/src/libraries/System.Runtime/tests/System/ArrayTests.cs
+++ b/src/libraries/System.Runtime/tests/System/ArrayTests.cs
@@ -264,6 +264,39 @@ namespace System.Tests
yield return new object[] { new ulong[0], 0, 0, (ulong)0, null, -1 };
+ // // [ActiveIssue("https://github.com/xunit/xunit/issues/1771")]
+ // // IntPtr
+
+ // IntPtr[] intPtrArray = new IntPtr[] { IntPtr.MinValue, (IntPtr)0, (IntPtr)0, IntPtr.MaxValue };
+
+ // yield return new object[] { intPtrArray, 0, 4, IntPtr.MinValue, null, 0 };
+ // yield return new object[] { intPtrArray, 0, 4, (IntPtr)0, null, 1 };
+ // yield return new object[] { intPtrArray, 0, 4, IntPtr.MaxValue, null, 3 };
+ // yield return new object[] { intPtrArray, 0, 4, (IntPtr)1, null, -4 };
+
+ // yield return new object[] { intPtrArray, 0, 1, IntPtr.MinValue, null, 0 };
+ // yield return new object[] { intPtrArray, 1, 3, IntPtr.MaxValue, null, 3 };
+ // yield return new object[] { intPtrArray, 1, 3, IntPtr.MinValue, null, -2 };
+ // yield return new object[] { intPtrArray, 1, 0, (IntPtr)0, null, -2 };
+
+ // yield return new object[] { new IntPtr[0], 0, 0, (IntPtr)0, null, -1 };
+
+ // // UIntPtr
+
+ // UIntPtr[] uintPtrArray = new UIntPtr[] { UIntPtr.MinValue, (UIntPtr)5, (UIntPtr)5, UIntPtr.MaxValue };
+
+ // yield return new object[] { uintPtrArray, 0, 4, UIntPtr.MinValue, null, 0 };
+ // yield return new object[] { uintPtrArray, 0, 4, (UIntPtr)5, null, 1 };
+ // yield return new object[] { uintPtrArray, 0, 4, UIntPtr.MaxValue, null, 3 };
+ // yield return new object[] { uintPtrArray, 0, 4, (UIntPtr)1, null, -2 };
+
+ // yield return new object[] { uintPtrArray, 0, 1, UIntPtr.MinValue, null, 0 };
+ // yield return new object[] { uintPtrArray, 1, 3, UIntPtr.MaxValue, null, 3 };
+ // yield return new object[] { uintPtrArray, 1, 3, UIntPtr.MinValue, null, -2 };
+ // yield return new object[] { uintPtrArray, 1, 0, (UIntPtr)5, null, -2 };
+
+ // yield return new object[] { new UIntPtr[0], 0, 0, (UIntPtr)0, null, -1 };
+
// Char
char[] charArray = new char[] { char.MinValue, (char)5, (char)5, char.MaxValue };
@@ -440,10 +473,6 @@ namespace System.Tests
// Type does not implement IComparable
yield return new object[] { new object[] { new object() }, new object() };
- // IntPtr and UIntPtr are not supported
- yield return new object[] { new IntPtr[] { IntPtr.Zero }, IntPtr.Zero };
- yield return new object[] { new UIntPtr[] { UIntPtr.Zero }, UIntPtr.Zero };
-
// Conversion between primitives is not allowed
yield return new object[] { new sbyte[] { 0 }, 0 };
yield return new object[] { new char[] { '\0' }, (ushort)0 };
@@ -3326,6 +3355,24 @@ namespace System.Tests
yield return new object[] { new ulong[1], 0, 1, null, new ulong[1] };
yield return new object[] { new ulong[0], 0, 0, null, new ulong[0] };
+ // IntPtr
+ yield return new object[] { new IntPtr[] { (IntPtr)3, (IntPtr)5, (IntPtr)6, (IntPtr)6 }, 0, 4, null, new IntPtr[] { (IntPtr)3, (IntPtr)5, (IntPtr)6, (IntPtr)6 } };
+ yield return new object[] { new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 }, 0, 4, null, new IntPtr[] { (IntPtr)3, (IntPtr)5, (IntPtr)6, (IntPtr)6 } };
+ yield return new object[] { new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 }, 0, 4, null, new IntPtr[] { (IntPtr)3, (IntPtr)5, (IntPtr)6, (IntPtr)6 } };
+ yield return new object[] { new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 }, 1, 2, null, new IntPtr[] { (IntPtr)5, (IntPtr)3, (IntPtr)6, (IntPtr)6 } };
+ yield return new object[] { new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 }, 0, 0, null, new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 } };
+ yield return new object[] { new IntPtr[1], 0, 1, null, new IntPtr[1] };
+ yield return new object[] { new IntPtr[0], 0, 0, null, new IntPtr[0] };
+
+ // UIntPtr
+ yield return new object[] { new UIntPtr[] { (UIntPtr)3, (UIntPtr)5, (UIntPtr)6, (UIntPtr)6 }, 0, 4, null, new UIntPtr[] { (UIntPtr)3, (UIntPtr)5, (UIntPtr)6, (UIntPtr)6 } };
+ yield return new object[] { new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 }, 0, 4, null, new UIntPtr[] { (UIntPtr)3, (UIntPtr)5, (UIntPtr)6, (UIntPtr)6 } };
+ yield return new object[] { new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 }, 0, 4, null, new UIntPtr[] { (UIntPtr)3, (UIntPtr)5, (UIntPtr)6, (UIntPtr)6 } };
+ yield return new object[] { new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 }, 1, 2, null, new UIntPtr[] { (UIntPtr)5, (UIntPtr)3, (UIntPtr)6, (UIntPtr)6 } };
+ yield return new object[] { new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 }, 0, 0, null, new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 } };
+ yield return new object[] { new UIntPtr[1], 0, 1, null, new UIntPtr[1] };
+ yield return new object[] { new UIntPtr[0], 0, 0, null, new UIntPtr[0] };
+
// Int64
yield return new object[] { new long[] { 3, 5, 6, 6 }, 0, 4, null, new long[] { 3, 5, 6, 6 } };
yield return new object[] { new long[] { 5, 6, 3, 6 }, 0, 4, null, new long[] { 3, 5, 6, 6 } };
@@ -3493,8 +3540,6 @@ namespace System.Tests
public static IEnumerable<object[]> Sort_NotComparable_TestData()
{
yield return new object[] { new object[] { "1", 2, new object() } };
- yield return new object[] { new IntPtr[2] };
- yield return new object[] { new UIntPtr[2] };
}
[Theory]
diff --git a/src/libraries/System.Runtime/tests/System/IntPtrTests.cs b/src/libraries/System.Runtime/tests/System/IntPtrTests.cs
index 90bdf0c8e89..2744e8dd886 100644
--- a/src/libraries/System.Runtime/tests/System/IntPtrTests.cs
+++ b/src/libraries/System.Runtime/tests/System/IntPtrTests.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using Xunit;
namespace System.Tests
@@ -177,5 +178,718 @@ namespace System.Tests
Assert.False(ptr == new IntPtr(expected + 1));
Assert.True(ptr != new IntPtr(expected + 1));
}
+
+
+ public static IntPtr RealMax => Is64Bit ? (IntPtr)long.MaxValue : (IntPtr)int.MaxValue;
+ public static IntPtr RealMin => Is64Bit ? (IntPtr)long.MinValue : (IntPtr)int.MinValue;
+
+ [Fact]
+ public static void Ctor_Empty()
+ {
+ var i = new IntPtr();
+ Assert.Equal(default, i);
+ }
+
+ [Fact]
+ public static void Ctor_Value()
+ {
+ IntPtr i = (IntPtr)41;
+ Assert.Equal((IntPtr)041, i);
+ }
+
+ [Fact]
+ public static void MaxValue()
+ {
+ Assert.Equal(RealMax, IntPtr.MaxValue);
+ }
+
+ [Fact]
+ public static void MinValue()
+ {
+ Assert.Equal(RealMin, IntPtr.MinValue);
+ }
+
+ [Theory]
+ [InlineData(234, 234, 0)]
+ [InlineData(234, int.MinValue, 1)]
+ [InlineData(-234, int.MinValue, 1)]
+ [InlineData(int.MinValue, int.MinValue, 0)]
+ [InlineData(234, -123, 1)]
+ [InlineData(234, 0, 1)]
+ [InlineData(234, 123, 1)]
+ [InlineData(234, 456, -1)]
+ [InlineData(234, int.MaxValue, -1)]
+ [InlineData(-234, int.MaxValue, -1)]
+ [InlineData(int.MaxValue, int.MaxValue, 0)]
+ [InlineData(-234, -234, 0)]
+ [InlineData(-234, 234, -1)]
+ [InlineData(-234, -432, 1)]
+ [InlineData(234, null, 1)]
+ public static void CompareTo_Other_ReturnsExpected(int l, object value, int expected)
+ {
+ var i = (IntPtr)l;
+ if (value is int intValue)
+ {
+ var intPtrValue = (IntPtr)intValue;
+ Assert.Equal(expected, Math.Sign(i.CompareTo(intPtrValue)));
+ Assert.Equal(-expected, Math.Sign(intPtrValue.CompareTo(i)));
+
+ Assert.Equal(expected, Math.Sign(i.CompareTo((object)intPtrValue)));
+ }
+ else
+ {
+ Assert.Equal(expected, Math.Sign(i.CompareTo(value)));
+ }
+ }
+
+ [Theory]
+ [InlineData("a")]
+ [InlineData((long)234)]
+ public static void CompareTo_ObjectNotIntPtr_ThrowsArgumentException(object value)
+ {
+ AssertExtensions.Throws<ArgumentException>(null, () => ((IntPtr)123).CompareTo(value));
+ }
+
+ public static IEnumerable<object[]> ToString_TestData()
+ {
+ foreach (NumberFormatInfo defaultFormat in new[] { null, NumberFormatInfo.CurrentInfo })
+ {
+ foreach (string defaultSpecifier in new[] { "G", "G\0", "\0N222", "\0", "" })
+ {
+ yield return new object[] { IntPtr.MinValue, defaultSpecifier, defaultFormat, Is64Bit ? "-9223372036854775808" : "-2147483648" };
+ yield return new object[] { (IntPtr)(-4567), defaultSpecifier, defaultFormat, "-4567" };
+ yield return new object[] { (IntPtr)0, defaultSpecifier, defaultFormat, "0" };
+ yield return new object[] { (IntPtr)4567, defaultSpecifier, defaultFormat, "4567" };
+ yield return new object[] { IntPtr.MaxValue, defaultSpecifier, defaultFormat, Is64Bit ? "9223372036854775807" : "2147483647" };
+ }
+
+ yield return new object[] { (IntPtr)4567, "D", defaultFormat, "4567" };
+ yield return new object[] { (IntPtr)4567, "D99", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" };
+ yield return new object[] { (IntPtr)4567, "D99\09", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" };
+ yield return new object[] { (IntPtr)(-4567), "D99\09", defaultFormat, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" };
+
+ yield return new object[] { (IntPtr)0x2468, "x", defaultFormat, "2468" };
+ yield return new object[] { (IntPtr)(-0x2468), "x", defaultFormat, Is64Bit ? "ffffffffffffdb98" : "ffffdb98" };
+ yield return new object[] { (IntPtr)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) };
+ }
+
+ var customFormat = new NumberFormatInfo()
+ {
+ NegativeSign = "#",
+ NumberDecimalSeparator = "~",
+ NumberGroupSeparator = "*",
+ PositiveSign = "&",
+ NumberDecimalDigits = 2,
+ PercentSymbol = "@",
+ PercentGroupSeparator = ",",
+ PercentDecimalSeparator = ".",
+ PercentDecimalDigits = 5
+ };
+ yield return new object[] { (IntPtr)(-2468), "N", customFormat, "#2*468~00" };
+ yield return new object[] { (IntPtr)2468, "N", customFormat, "2*468~00" };
+ yield return new object[] { (IntPtr)123, "E", customFormat, "1~230000E&002" };
+ yield return new object[] { (IntPtr)123, "F", customFormat, "123~00" };
+ yield return new object[] { (IntPtr)123, "P", customFormat, "12,300.00000 @" };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void ToStringTest(IntPtr i, string format, IFormatProvider provider, string expected)
+ {
+ // Format is case insensitive
+ string upperFormat = format.ToUpperInvariant();
+ string lowerFormat = format.ToLowerInvariant();
+
+ string upperExpected = expected.ToUpperInvariant();
+ string lowerExpected = expected.ToLowerInvariant();
+
+ bool isDefaultProvider = (provider == null || provider == NumberFormatInfo.CurrentInfo);
+ if (string.IsNullOrEmpty(format) || format.ToUpperInvariant() == "G")
+ {
+ if (isDefaultProvider)
+ {
+ Assert.Equal(upperExpected, i.ToString());
+ Assert.Equal(upperExpected, i.ToString((IFormatProvider)null));
+ }
+ Assert.Equal(upperExpected, i.ToString(provider));
+ }
+ if (isDefaultProvider)
+ {
+ Assert.Equal(upperExpected, i.ToString(upperFormat));
+ Assert.Equal(lowerExpected, i.ToString(lowerFormat));
+ Assert.Equal(upperExpected, i.ToString(upperFormat, null));
+ Assert.Equal(lowerExpected, i.ToString(lowerFormat, null));
+ }
+ Assert.Equal(upperExpected, i.ToString(upperFormat, provider));
+ Assert.Equal(lowerExpected, i.ToString(lowerFormat, provider));
+ }
+
+ [Fact]
+ public static void ToString_InvalidFormat_ThrowsFormatException()
+ {
+ IntPtr i = (IntPtr)123;
+ Assert.Throws<FormatException>(() => i.ToString("r")); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("r", null)); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("R")); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("R", null)); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("Y")); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("Y", null)); // Invalid format
+ }
+
+ public static IEnumerable<object[]> Parse_Valid_TestData()
+ {
+ NumberFormatInfo samePositiveNegativeFormat = new NumberFormatInfo()
+ {
+ PositiveSign = "|",
+ NegativeSign = "|"
+ };
+
+ NumberFormatInfo emptyPositiveFormat = new NumberFormatInfo() { PositiveSign = "" };
+ NumberFormatInfo emptyNegativeFormat = new NumberFormatInfo() { NegativeSign = "" };
+
+ // None
+ yield return new object[] { "0", NumberStyles.None, null, (IntPtr)0 };
+ yield return new object[] { "0000000000000000000000000000000000000000000000000000000000", NumberStyles.None, null, (IntPtr)0 };
+ yield return new object[] { "0000000000000000000000000000000000000000000000000000000001", NumberStyles.None, null, (IntPtr)1 };
+ yield return new object[] { "2147483647", NumberStyles.None, null, (IntPtr)2147483647 };
+ yield return new object[] { "02147483647", NumberStyles.None, null, (IntPtr)2147483647 };
+ yield return new object[] { "00000000000000000000000000000000000000000000000002147483647", NumberStyles.None, null, (IntPtr)2147483647 };
+ yield return new object[] { "123\0\0", NumberStyles.None, null, (IntPtr)123 };
+
+ // All lengths decimal
+ foreach (bool neg in new[] { false, true })
+ {
+ string s = neg ? "-" : "";
+ var result = 0;
+ for (var i = 1; i <= 10; i++)
+ {
+ result = result * 10 + (i % 10);
+ s += (i % 10).ToString();
+ yield return new object[] { s, NumberStyles.Integer, null, (IntPtr)(neg ? result * -1 : result) };
+ }
+ }
+
+ // All lengths hexadecimal
+ {
+ string s = "";
+ var result = 0;
+ for (var i = 1; i <= 8; i++)
+ {
+ result = (result * 16) + (i % 16);
+ s += (i % 16).ToString("X");
+ yield return new object[] { s, NumberStyles.HexNumber, null, (IntPtr)result };
+ }
+ }
+
+ // HexNumber
+ yield return new object[] { "123", NumberStyles.HexNumber, null, (IntPtr)0x123 };
+ yield return new object[] { "abc", NumberStyles.HexNumber, null, (IntPtr)0xabc };
+ yield return new object[] { "ABC", NumberStyles.HexNumber, null, (IntPtr)0xabc };
+ yield return new object[] { "12", NumberStyles.HexNumber, null, (IntPtr)0x12 };
+
+
+ if (Is64Bit)
+ {
+ yield return new object[] { "8000000000000000", NumberStyles.HexNumber, null, IntPtr.MinValue };
+ yield return new object[] { "7FFFFFFFFFFFFFFF", NumberStyles.HexNumber, null, IntPtr.MaxValue };
+ }
+ else
+ {
+ yield return new object[] { "80000000", NumberStyles.HexNumber, null, IntPtr.MinValue };
+ yield return new object[] { "7FFFFFFF", NumberStyles.HexNumber, null, IntPtr.MaxValue };
+ }
+
+ // Currency
+ NumberFormatInfo currencyFormat = new NumberFormatInfo()
+ {
+ CurrencySymbol = "$",
+ CurrencyGroupSeparator = "|",
+ NumberGroupSeparator = "/"
+ };
+ yield return new object[] { "$1|000", NumberStyles.Currency, currencyFormat, (IntPtr)1000 };
+ yield return new object[] { "$1000", NumberStyles.Currency, currencyFormat, (IntPtr)1000 };
+ yield return new object[] { "$ 1000", NumberStyles.Currency, currencyFormat, (IntPtr)1000 };
+ yield return new object[] { "1000", NumberStyles.Currency, currencyFormat, (IntPtr)1000 };
+ yield return new object[] { "$(1000)", NumberStyles.Currency, currencyFormat, (IntPtr)(-1000) };
+ yield return new object[] { "($1000)", NumberStyles.Currency, currencyFormat, (IntPtr)(-1000) };
+ yield return new object[] { "$-1000", NumberStyles.Currency, currencyFormat, (IntPtr)(-1000) };
+ yield return new object[] { "-$1000", NumberStyles.Currency, currencyFormat, (IntPtr)(-1000) };
+
+ NumberFormatInfo emptyCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "" };
+ yield return new object[] { "100", NumberStyles.Currency, emptyCurrencyFormat, (IntPtr)100 };
+
+ // If CurrencySymbol and Negative are the same, NegativeSign is preferred
+ NumberFormatInfo sameCurrencyNegativeSignFormat = new NumberFormatInfo()
+ {
+ NegativeSign = "|",
+ CurrencySymbol = "|"
+ };
+ yield return new object[] { "|1000", NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, (IntPtr)(-1000) };
+
+ // Any
+ yield return new object[] { "123", NumberStyles.Any, null, (IntPtr)123 };
+
+ // AllowLeadingSign
+ yield return new object[] { "-2147483648", NumberStyles.AllowLeadingSign, null, (IntPtr)(-2147483648) };
+ yield return new object[] { "-123", NumberStyles.AllowLeadingSign, null, (IntPtr)(-123) };
+ yield return new object[] { "+0", NumberStyles.AllowLeadingSign, null, (IntPtr)0 };
+ yield return new object[] { "-0", NumberStyles.AllowLeadingSign, null, (IntPtr)0 };
+ yield return new object[] { "+123", NumberStyles.AllowLeadingSign, null, (IntPtr)123 };
+
+ // If PositiveSign and NegativeSign are the same, PositiveSign is preferred
+ yield return new object[] { "|123", NumberStyles.AllowLeadingSign, samePositiveNegativeFormat, (IntPtr)123 };
+
+ // Empty PositiveSign or NegativeSign
+ yield return new object[] { "100", NumberStyles.AllowLeadingSign, emptyPositiveFormat, (IntPtr)100 };
+ yield return new object[] { "100", NumberStyles.AllowLeadingSign, emptyNegativeFormat, (IntPtr)100 };
+
+ // AllowTrailingSign
+ yield return new object[] { "123", NumberStyles.AllowTrailingSign, null, (IntPtr)123 };
+ yield return new object[] { "123+", NumberStyles.AllowTrailingSign, null, (IntPtr)123 };
+ yield return new object[] { "123-", NumberStyles.AllowTrailingSign, null, (IntPtr)(-123) };
+
+ // If PositiveSign and NegativeSign are the same, PositiveSign is preferred
+ yield return new object[] { "123|", NumberStyles.AllowTrailingSign, samePositiveNegativeFormat, (IntPtr)123 };
+
+ // Empty PositiveSign or NegativeSign
+ yield return new object[] { "100", NumberStyles.AllowTrailingSign, emptyPositiveFormat, (IntPtr)100 };
+ yield return new object[] { "100", NumberStyles.AllowTrailingSign, emptyNegativeFormat, (IntPtr)100 };
+
+ // AllowLeadingWhite and AllowTrailingWhite
+ yield return new object[] { " 123", NumberStyles.AllowLeadingWhite, null, (IntPtr)123 };
+ yield return new object[] { " 123 ", NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)123 };
+ yield return new object[] { "123 ", NumberStyles.AllowTrailingWhite, null, (IntPtr)123 };
+ yield return new object[] { "123 \0\0", NumberStyles.AllowTrailingWhite, null, (IntPtr)123 };
+ yield return new object[] { " 2147483647 ", NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)2147483647 };
+ yield return new object[] { " -2147483648 ", NumberStyles.Integer, null, (IntPtr)(-2147483648) };
+ foreach (char c in new[] { (char)0x9, (char)0xA, (char)0xB, (char)0xC, (char)0xD })
+ {
+ string cs = c.ToString();
+ yield return new object[] { cs + cs + "123" + cs + cs, NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)123 };
+ }
+ yield return new object[] { " 0 ", NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)0 };
+ yield return new object[] { " 000000000 ", NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)0 };
+
+ // AllowThousands
+ NumberFormatInfo thousandsFormat = new NumberFormatInfo() { NumberGroupSeparator = "|" };
+ yield return new object[] { "1000", NumberStyles.AllowThousands, thousandsFormat, (IntPtr)1000 };
+ yield return new object[] { "1|0|0|0", NumberStyles.AllowThousands, thousandsFormat, (IntPtr)1000 };
+ yield return new object[] { "1|||", NumberStyles.AllowThousands, thousandsFormat, (IntPtr)1 };
+
+ NumberFormatInfo IntegerNumberSeparatorFormat = new NumberFormatInfo() { NumberGroupSeparator = "1" };
+ yield return new object[] { "1111", NumberStyles.AllowThousands, IntegerNumberSeparatorFormat, (IntPtr)1111 };
+
+ // AllowExponent
+ yield return new object[] { "1E2", NumberStyles.AllowExponent, null, (IntPtr)100 };
+ yield return new object[] { "1E+2", NumberStyles.AllowExponent, null, (IntPtr)100 };
+ yield return new object[] { "1e2", NumberStyles.AllowExponent, null, (IntPtr)100 };
+ yield return new object[] { "1E0", NumberStyles.AllowExponent, null, (IntPtr)1 };
+ yield return new object[] { "(1E2)", NumberStyles.AllowExponent | NumberStyles.AllowParentheses, null, (IntPtr)(-100) };
+ yield return new object[] { "-1E2", NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, null, (IntPtr)(-100) };
+
+ NumberFormatInfo negativeFormat = new NumberFormatInfo() { PositiveSign = "|" };
+ yield return new object[] { "1E|2", NumberStyles.AllowExponent, negativeFormat, (IntPtr)100 };
+
+ // AllowParentheses
+ yield return new object[] { "123", NumberStyles.AllowParentheses, null, (IntPtr)123 };
+ yield return new object[] { "(123)", NumberStyles.AllowParentheses, null, (IntPtr)(-123) };
+
+ // AllowDecimalPoint
+ NumberFormatInfo decimalFormat = new NumberFormatInfo() { NumberDecimalSeparator = "|" };
+ yield return new object[] { "67|", NumberStyles.AllowDecimalPoint, decimalFormat, (IntPtr)67 };
+
+ // NumberFormatInfo has a custom property with length > (IntPtr)1
+ NumberFormatInfo IntegerCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "123" };
+ yield return new object[] { "123123", NumberStyles.AllowCurrencySymbol, IntegerCurrencyFormat, (IntPtr)123 };
+
+ yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { PositiveSign = "1" }, (IntPtr)23123 };
+ yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "1" }, (IntPtr)(-23123) };
+ yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { PositiveSign = "123" }, (IntPtr)123 };
+ yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "123" }, (IntPtr)(-123) };
+ yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { PositiveSign = "12312" }, (IntPtr)3 };
+ yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "12312" }, (IntPtr)(-3) };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Valid_TestData))]
+ public static void Parse_Valid(string value, NumberStyles style, IFormatProvider provider, IntPtr expected)
+ {
+ IntPtr result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(IntPtr.TryParse(value, out result));
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, IntPtr.Parse(value));
+ }
+
+ // Default provider
+ if (provider == null)
+ {
+ Assert.Equal(expected, IntPtr.Parse(value, style));
+
+ // Substitute default NumberFormatInfo
+ Assert.True(IntPtr.TryParse(value, style, new NumberFormatInfo(), out result));
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, IntPtr.Parse(value, style, new NumberFormatInfo()));
+ }
+
+ // Default style
+ if (style == NumberStyles.Integer)
+ {
+ Assert.Equal(expected, IntPtr.Parse(value, provider));
+ }
+
+ // Full overloads
+ Assert.True(IntPtr.TryParse(value, style, provider, out result));
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, IntPtr.Parse(value, style, provider));
+ }
+
+ public static IEnumerable<object[]> Parse_Invalid_TestData()
+ {
+ // String is null, empty or entirely whitespace
+ yield return new object[] { null, NumberStyles.Integer, null, typeof(ArgumentNullException) };
+ yield return new object[] { null, NumberStyles.Any, null, typeof(ArgumentNullException) };
+
+ // String contains is null, empty or enitrely whitespace.
+ foreach (NumberStyles style in new[] { NumberStyles.Integer, NumberStyles.HexNumber, NumberStyles.Any })
+ {
+ yield return new object[] { null, style, null, typeof(ArgumentNullException) };
+ yield return new object[] { "", style, null, typeof(FormatException) };
+ yield return new object[] { " \t \n \r ", style, null, typeof(FormatException) };
+ yield return new object[] { " \0\0", style, null, typeof(FormatException) };
+ }
+
+ // Leading or trailing chars for which char.IsWhiteSpace is true but that's not valid for leading/trailing whitespace
+ foreach (string c in new[] { "\x0085", "\x00A0", "\x1680", "\x2000", "\x2001", "\x2002", "\x2003", "\x2004", "\x2005", "\x2006", "\x2007", "\x2008", "\x2009", "\x200A", "\x2028", "\x2029", "\x202F", "\x205F", "\x3000" })
+ {
+ yield return new object[] { c + "123", NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { "123" + c, NumberStyles.Integer, null, typeof(FormatException) };
+ }
+
+ // String contains garbage
+ foreach (NumberStyles style in new[] { NumberStyles.Integer, NumberStyles.HexNumber, NumberStyles.Any })
+ {
+ yield return new object[] { "Garbage", style, null, typeof(FormatException) };
+ yield return new object[] { "g", style, null, typeof(FormatException) };
+ yield return new object[] { "g1", style, null, typeof(FormatException) };
+ yield return new object[] { "1g", style, null, typeof(FormatException) };
+ yield return new object[] { "123g", style, null, typeof(FormatException) };
+ yield return new object[] { "g123", style, null, typeof(FormatException) };
+ yield return new object[] { "214748364g", style, null, typeof(FormatException) };
+ }
+
+ // String has leading zeros
+ yield return new object[] { "\0\0123", NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { "\0\0123", NumberStyles.Any, null, typeof(FormatException) };
+
+ // String has IntPtrernal zeros
+ yield return new object[] { "1\023", NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { "1\023", NumberStyles.Any, null, typeof(FormatException) };
+
+ // String has trailing zeros but with whitespace after
+ yield return new object[] { "123\0\0 ", NumberStyles.Integer, null, typeof(FormatException) };
+
+ // Integer doesn't allow hex, exponents, paretheses, currency, thousands, decimal
+ yield return new object[] { "abc", NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { "1E23", NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { "(123)", NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { 1000.ToString("C0"), NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { 1000.ToString("N0"), NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { 678.90.ToString("F2"), NumberStyles.Integer, null, typeof(FormatException) };
+
+ // HexNumber
+ yield return new object[] { "0xabc", NumberStyles.HexNumber, null, typeof(FormatException) };
+ yield return new object[] { "&habc", NumberStyles.HexNumber, null, typeof(FormatException) };
+ yield return new object[] { "G1", NumberStyles.HexNumber, null, typeof(FormatException) };
+ yield return new object[] { "g1", NumberStyles.HexNumber, null, typeof(FormatException) };
+ yield return new object[] { "+abc", NumberStyles.HexNumber, null, typeof(FormatException) };
+ yield return new object[] { "-abc", NumberStyles.HexNumber, null, typeof(FormatException) };
+
+ // None doesn't allow hex or leading or trailing whitespace
+ yield return new object[] { "abc", NumberStyles.None, null, typeof(FormatException) };
+ yield return new object[] { "123 ", NumberStyles.None, null, typeof(FormatException) };
+ yield return new object[] { " 123", NumberStyles.None, null, typeof(FormatException) };
+ yield return new object[] { " 123 ", NumberStyles.None, null, typeof(FormatException) };
+
+ // AllowLeadingSign
+ yield return new object[] { "+", NumberStyles.AllowLeadingSign, null, typeof(FormatException) };
+ yield return new object[] { "-", NumberStyles.AllowLeadingSign, null, typeof(FormatException) };
+ yield return new object[] { "+-123", NumberStyles.AllowLeadingSign, null, typeof(FormatException) };
+ yield return new object[] { "-+123", NumberStyles.AllowLeadingSign, null, typeof(FormatException) };
+ yield return new object[] { "- 123", NumberStyles.AllowLeadingSign, null, typeof(FormatException) };
+ yield return new object[] { "+ 123", NumberStyles.AllowLeadingSign, null, typeof(FormatException) };
+
+ // AllowTrailingSign
+ yield return new object[] { "123-+", NumberStyles.AllowTrailingSign, null, typeof(FormatException) };
+ yield return new object[] { "123+-", NumberStyles.AllowTrailingSign, null, typeof(FormatException) };
+ yield return new object[] { "123 -", NumberStyles.AllowTrailingSign, null, typeof(FormatException) };
+ yield return new object[] { "123 +", NumberStyles.AllowTrailingSign, null, typeof(FormatException) };
+
+ // Parentheses has priority over CurrencySymbol and PositiveSign
+ NumberFormatInfo currencyNegativeParenthesesFormat = new NumberFormatInfo()
+ {
+ CurrencySymbol = "(",
+ PositiveSign = "))"
+ };
+ yield return new object[] { "(100))", NumberStyles.AllowParentheses | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowTrailingSign, currencyNegativeParenthesesFormat, typeof(FormatException) };
+
+ // AllowTrailingSign and AllowLeadingSign
+ yield return new object[] { "+123+", NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign, null, typeof(FormatException) };
+ yield return new object[] { "+123-", NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign, null, typeof(FormatException) };
+ yield return new object[] { "-123+", NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign, null, typeof(FormatException) };
+ yield return new object[] { "-123-", NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign, null, typeof(FormatException) };
+
+ // AllowLeadingSign and AllowParentheses
+ yield return new object[] { "-(1000)", NumberStyles.AllowLeadingSign | NumberStyles.AllowParentheses, null, typeof(FormatException) };
+ yield return new object[] { "(-1000)", NumberStyles.AllowLeadingSign | NumberStyles.AllowParentheses, null, typeof(FormatException) };
+
+ // AllowLeadingWhite
+ yield return new object[] { "1 ", NumberStyles.AllowLeadingWhite, null, typeof(FormatException) };
+ yield return new object[] { " 1 ", NumberStyles.AllowLeadingWhite, null, typeof(FormatException) };
+
+ // AllowTrailingWhite
+ yield return new object[] { " 1 ", NumberStyles.AllowTrailingWhite, null, typeof(FormatException) };
+ yield return new object[] { " 1", NumberStyles.AllowTrailingWhite, null, typeof(FormatException) };
+
+ // AllowThousands
+ NumberFormatInfo thousandsFormat = new NumberFormatInfo() { NumberGroupSeparator = "|" };
+ yield return new object[] { "|||1", NumberStyles.AllowThousands, null, typeof(FormatException) };
+
+ // AllowExponent
+ yield return new object[] { "65E", NumberStyles.AllowExponent, null, typeof(FormatException) };
+ yield return new object[] { "65E19", NumberStyles.AllowExponent, null, typeof(OverflowException) };
+ yield return new object[] { "65E+19", NumberStyles.AllowExponent, null, typeof(OverflowException) };
+ yield return new object[] { "65E-1", NumberStyles.AllowExponent, null, typeof(OverflowException) };
+
+ // AllowDecimalPoint
+ NumberFormatInfo decimalFormat = new NumberFormatInfo() { NumberDecimalSeparator = "." };
+ yield return new object[] { "67.9", NumberStyles.AllowDecimalPoint, decimalFormat, typeof(OverflowException) };
+
+ // Parsing Integers doesn't allow NaN, PositiveInfinity or NegativeInfinity
+ NumberFormatInfo doubleFormat = new NumberFormatInfo()
+ {
+ NaNSymbol = "NaN",
+ PositiveInfinitySymbol = "Infinity",
+ NegativeInfinitySymbol = "-Infinity"
+ };
+ yield return new object[] { "NaN", NumberStyles.Any, doubleFormat, typeof(FormatException) };
+ yield return new object[] { "Infinity", NumberStyles.Any, doubleFormat, typeof(FormatException) };
+ yield return new object[] { "-Infinity", NumberStyles.Any, doubleFormat, typeof(FormatException) };
+
+ // Only has a leading sign
+ yield return new object[] { "+", NumberStyles.AllowLeadingSign, null, typeof(FormatException) };
+ yield return new object[] { "-", NumberStyles.AllowLeadingSign, null, typeof(FormatException) };
+ yield return new object[] { " +", NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { " -", NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { "+ ", NumberStyles.Integer, null, typeof(FormatException) };
+ yield return new object[] { "- ", NumberStyles.Integer, null, typeof(FormatException) };
+
+ // NumberFormatInfo has a custom property with length > (IntPtr)1
+ NumberFormatInfo IntegerCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "123" };
+ yield return new object[] { "123", NumberStyles.AllowCurrencySymbol, IntegerCurrencyFormat, typeof(FormatException) };
+ yield return new object[] { "123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { PositiveSign = "123" }, typeof(FormatException) };
+ yield return new object[] { "123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "123" }, typeof(FormatException) };
+
+ // Decimals not in range of IntPtr32
+ foreach (string s in new[]
+ {
+
+ "9223372036854775808", // long.MaxValue + 1
+ "9223372036854775810", // 10s digit incremented above long.MaxValue
+ "10000000000000000000", // extra digit after long.MaxValue
+
+ "18446744073709551616", // ulong.MaxValue + 1
+ "18446744073709551620", // 10s digit incremented above ulong.MaxValue
+ "100000000000000000000", // extra digit after ulong.MaxValue
+
+ "-9223372036854775809", // long.MinValue - 1
+ "-9223372036854775810", // 10s digit decremented below long.MinValue
+ "-10000000000000000000", // extra digit after long.MinValue
+
+ "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000", // really big
+ "-100000000000000000000000000000000000000000000000000000000000000000000000000000000000000" // really small
+ })
+ {
+ foreach (NumberStyles styles in new[] { NumberStyles.Any, NumberStyles.Integer })
+ {
+ yield return new object[] { s, styles, null, typeof(OverflowException) };
+ yield return new object[] { s + " ", styles, null, typeof(OverflowException) };
+ yield return new object[] { s + " " + "\0\0\0", styles, null, typeof(OverflowException) };
+
+ yield return new object[] { s + "g", styles, null, typeof(FormatException) };
+ yield return new object[] { s + "\0g", styles, null, typeof(FormatException) };
+ yield return new object[] { s + " g", styles, null, typeof(FormatException) };
+ }
+ }
+
+ // Hexadecimals not in range of IntPtr32
+ foreach (string s in new[]
+ {
+ "10000000000000000", // ulong.MaxValue + (IntPtr)1
+ "FFFFFFFFFFFFFFFF0", // extra digit after ulong.MaxValue
+
+ "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000" // really big
+ })
+ {
+ yield return new object[] { s, NumberStyles.HexNumber, null, typeof(OverflowException) };
+ yield return new object[] { s + " ", NumberStyles.HexNumber, null, typeof(OverflowException) };
+ yield return new object[] { s + " " + "\0\0", NumberStyles.HexNumber, null, typeof(OverflowException) };
+
+ yield return new object[] { s + "g", NumberStyles.HexNumber, null, typeof(FormatException) };
+ yield return new object[] { s + "\0g", NumberStyles.HexNumber, null, typeof(FormatException) };
+ yield return new object[] { s + " g", NumberStyles.HexNumber, null, typeof(FormatException) };
+ }
+
+ yield return new object[] { "9223372036854775809-", NumberStyles.AllowTrailingSign, null, typeof(OverflowException) };
+ yield return new object[] { "(9223372036854775809)", NumberStyles.AllowParentheses, null, typeof(OverflowException) };
+ yield return new object[] { "2E19", NumberStyles.AllowExponent, null, typeof(OverflowException) };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ if (2 == 2E10) { }
+ IntPtr result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(IntPtr.TryParse(value, out result));
+ Assert.Equal(default, result);
+ Assert.Throws(exceptionType, () => IntPtr.Parse(value));
+ }
+
+ // Default provider
+ if (provider == null)
+ {
+ Assert.Throws(exceptionType, () => IntPtr.Parse(value, style));
+
+ // Substitute default NumberFormatInfo
+ Assert.False(IntPtr.TryParse(value, style, new NumberFormatInfo(), out result));
+ Assert.Equal(default, result);
+ Assert.Throws(exceptionType, () => IntPtr.Parse(value, style, new NumberFormatInfo()));
+ }
+
+ // Default style
+ if (style == NumberStyles.Integer)
+ {
+ Assert.Throws(exceptionType, () => IntPtr.Parse(value, provider));
+ }
+
+ // Full overloads
+ Assert.False(IntPtr.TryParse(value, style, provider, out result));
+ Assert.Equal(default, result);
+ Assert.Throws(exceptionType, () => IntPtr.Parse(value, style, provider));
+ }
+
+ [Theory]
+ [InlineData(NumberStyles.HexNumber | NumberStyles.AllowParentheses, null)]
+ [InlineData(unchecked((NumberStyles)0xFFFFFC00), "style")]
+ public static void TryParse_InvalidNumberStyle_ThrowsArgumentException(NumberStyles style, string paramName)
+ {
+ IntPtr result = (IntPtr)0;
+ AssertExtensions.Throws<ArgumentException>(paramName, () => IntPtr.TryParse("1", style, null, out result));
+ Assert.Equal(default(IntPtr), result);
+
+ AssertExtensions.Throws<ArgumentException>(paramName, () => IntPtr.Parse("1", style));
+ AssertExtensions.Throws<ArgumentException>(paramName, () => IntPtr.Parse("1", style, null));
+ }
+
+ [Theory]
+ [InlineData("N")]
+ [InlineData("F")]
+ public static void ToString_N_F_EmptyNumberGroup_Success(string specifier)
+ {
+ var nfi = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone();
+ nfi.NumberGroupSizes = new int[0];
+ nfi.NumberGroupSeparator = ",";
+ Assert.Equal("1234", ((IntPtr)1234).ToString($"{specifier}0", nfi));
+ }
+
+ [Fact]
+ public static void ToString_P_EmptyPercentGroup_Success()
+ {
+ var nfi = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone();
+ nfi.PercentGroupSizes = new int[0];
+ nfi.PercentSymbol = "%";
+ Assert.Equal("123400 %", ((IntPtr)1234).ToString("P0", nfi));
+ }
+
+ [Fact]
+ public static void ToString_C_EmptyPercentGroup_Success()
+ {
+ var nfi = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone();
+ nfi.CurrencyGroupSizes = new int[0];
+ nfi.CurrencySymbol = "$";
+ Assert.Equal("$1234", ((IntPtr)1234).ToString("C0", nfi));
+ }
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], (IntPtr)0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ NumberFormatInfo samePositiveNegativeFormat = new NumberFormatInfo()
+ {
+ PositiveSign = "|",
+ NegativeSign = "|"
+ };
+
+ NumberFormatInfo emptyPositiveFormat = new NumberFormatInfo() { PositiveSign = "" };
+ NumberFormatInfo emptyNegativeFormat = new NumberFormatInfo() { NegativeSign = "" };
+
+ // None
+ yield return new object[] { "2147483647", (IntPtr)1, (IntPtr)9, NumberStyles.None, null, (IntPtr)147483647 };
+ yield return new object[] { "2147483647", (IntPtr)1, (IntPtr)1, NumberStyles.None, null, (IntPtr)1 };
+ yield return new object[] { "123\0\0", (IntPtr)2, (IntPtr)2, NumberStyles.None, null, (IntPtr)3 };
+
+ // Hex
+ yield return new object[] { "abc", (IntPtr)0, (IntPtr)1, NumberStyles.HexNumber, null, (IntPtr)0xa };
+ yield return new object[] { "ABC", (IntPtr)1, (IntPtr)1, NumberStyles.HexNumber, null, (IntPtr)0xB };
+ yield return new object[] { "FFFFFFFF", (IntPtr)6, (IntPtr)2, NumberStyles.HexNumber, null, (IntPtr)0xFF };
+ yield return new object[] { "FFFFFFFF", (IntPtr)0, (IntPtr)1, NumberStyles.HexNumber, null, (IntPtr)0xF };
+
+ // Currency
+ yield return new object[] { "-$1000", (IntPtr)1, (IntPtr)5, NumberStyles.Currency, new NumberFormatInfo()
+ {
+ CurrencySymbol = "$",
+ CurrencyGroupSeparator = "|",
+ NumberGroupSeparator = "/"
+ }, (IntPtr)1000 };
+
+ NumberFormatInfo emptyCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "" };
+ yield return new object[] { "100", (IntPtr)1, (IntPtr)2, NumberStyles.Currency, emptyCurrencyFormat, (IntPtr)0 };
+ yield return new object[] { "100", (IntPtr)0, (IntPtr)1, NumberStyles.Currency, emptyCurrencyFormat, (IntPtr)1 };
+
+ // If CurrencySymbol and Negative are the same, NegativeSign is preferred
+ NumberFormatInfo sameCurrencyNegativeSignFormat = new NumberFormatInfo()
+ {
+ NegativeSign = "|",
+ CurrencySymbol = "|"
+ };
+ yield return new object[] { "1000", (IntPtr)1, (IntPtr)3, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, (IntPtr)0 };
+ yield return new object[] { "|1000", (IntPtr)0, (IntPtr)2, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, -1 };
+
+ // Any
+ yield return new object[] { "123", (IntPtr)0, (IntPtr)2, NumberStyles.Any, null, (IntPtr)12 };
+
+ // AllowLeadingSign
+ yield return new object[] { "-2147483648", (IntPtr)0, (IntPtr)10, NumberStyles.AllowLeadingSign, null, -214748364 };
+
+ // AllowTrailingSign
+ yield return new object[] { "123-", (IntPtr)0, (IntPtr)3, NumberStyles.AllowTrailingSign, null, (IntPtr)123 };
+
+ // AllowExponent
+ yield return new object[] { "1E2", (IntPtr)0, (IntPtr)1, NumberStyles.AllowExponent, null, (IntPtr)1 };
+ yield return new object[] { "1E+2", (IntPtr)3, (IntPtr)1, NumberStyles.AllowExponent, null, (IntPtr)2 };
+ yield return new object[] { "(1E2)", (IntPtr)1, (IntPtr)3, NumberStyles.AllowExponent | NumberStyles.AllowParentheses, null, (IntPtr)1E2 };
+ yield return new object[] { "-1E2", (IntPtr)1, (IntPtr)3, NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, null, (IntPtr)1E2 };
+ }
}
}
diff --git a/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs b/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs
index 5881af78988..07b3532f5dd 100644
--- a/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs
+++ b/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs
@@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.CompilerServices;
using Xunit;
namespace System.Tests
@@ -172,5 +174,294 @@ namespace System.Tests
Assert.False(ptr == new UIntPtr(expected + 1));
Assert.True(ptr != new UIntPtr(expected + 1));
}
+
+ [Fact]
+ public static void Ctor_Empty()
+ {
+ var i = new UIntPtr();
+ Assert.Equal((UIntPtr)0, i);
+ }
+
+ [Fact]
+ public static void Ctor_Value()
+ {
+ UIntPtr i = (UIntPtr)41;
+ Assert.Equal((UIntPtr)41, i);
+ }
+
+ [Fact]
+ public static void MaxValue()
+ {
+ Assert.Equal(UIntPtr.Size == 4 ? (UIntPtr)uint.MaxValue : (UIntPtr)ulong.MaxValue, UIntPtr.MaxValue);
+ }
+
+ [Fact]
+ public static void MinValue()
+ {
+ Assert.Equal((UIntPtr)0, UIntPtr.MinValue);
+ }
+
+ [Theory]
+ [InlineData(234u, 234u, 0)]
+ [InlineData(234u, uint.MinValue, 1)]
+ [InlineData(234u, 123u, 1)]
+ [InlineData(234u, 456u, -1)]
+ [InlineData(234u, uint.MaxValue, -1)]
+ [InlineData(234u, null, 1)]
+ public static void CompareTo_Other_ReturnsExpected(uint i0, object value, int expected)
+ {
+ var i = (UIntPtr)i0;
+ if (value is uint uintValue)
+ {
+ var uintPtrValue = (UIntPtr)uintValue;
+ Assert.Equal(expected, Math.Sign(i.CompareTo(uintPtrValue)));
+
+ Assert.Equal(expected, Math.Sign(i.CompareTo((object)uintPtrValue)));
+ }
+ else
+ {
+ Assert.Equal(expected, Math.Sign(i.CompareTo(value)));
+ }
+ }
+
+ [Theory]
+ [InlineData("a")]
+ [InlineData(234)]
+ public static void CompareTo_ObjectNotUIntPtr_ThrowsArgumentException(object value)
+ {
+ AssertExtensions.Throws<ArgumentException>(null, () => ((UIntPtr)123).CompareTo(value));
+ }
+
+ public static IEnumerable<object[]> ToString_TestData()
+ {
+ foreach (NumberFormatInfo defaultFormat in new[] { null, NumberFormatInfo.CurrentInfo })
+ {
+ foreach (string defaultSpecifier in new[] { "G", "G\0", "\0N222", "\0", "" })
+ {
+ yield return new object[] { (UIntPtr)0, defaultSpecifier, defaultFormat, "0" };
+ yield return new object[] { (UIntPtr)4567, defaultSpecifier, defaultFormat, "4567" };
+ yield return new object[] { UIntPtr.MaxValue, defaultSpecifier, defaultFormat, Is64Bit ? "18446744073709551615" : "4294967295" };
+ }
+
+ yield return new object[] { (UIntPtr)4567, "D", defaultFormat, "4567" };
+ yield return new object[] { (UIntPtr)4567, "D18", defaultFormat, "000000000000004567" };
+
+ yield return new object[] { (UIntPtr)0x2468, "x", defaultFormat, "2468" };
+ yield return new object[] { (UIntPtr)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) };
+ }
+
+ var customFormat = new NumberFormatInfo()
+ {
+ NegativeSign = "#",
+ NumberDecimalSeparator = "~",
+ NumberGroupSeparator = "*",
+ PositiveSign = "&",
+ NumberDecimalDigits = 2,
+ PercentSymbol = "@",
+ PercentGroupSeparator = ",",
+ PercentDecimalSeparator = ".",
+ PercentDecimalDigits = 5
+ };
+ yield return new object[] { (UIntPtr)2468, "N", customFormat, "2*468~00" };
+ yield return new object[] { (UIntPtr)123, "E", customFormat, "1~230000E&002" };
+ yield return new object[] { (UIntPtr)123, "F", customFormat, "123~00" };
+ yield return new object[] { (UIntPtr)123, "P", customFormat, "12,300.00000 @" };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_TestData))]
+ public static void ToStringTest(UIntPtr i, string format, IFormatProvider provider, string expected)
+ {
+ // Format is case insensitive
+ string upperFormat = format.ToUpperInvariant();
+ string lowerFormat = format.ToLowerInvariant();
+
+ string upperExpected = expected.ToUpperInvariant();
+ string lowerExpected = expected.ToLowerInvariant();
+
+ bool isDefaultProvider = (provider == null || provider == NumberFormatInfo.CurrentInfo);
+ if (string.IsNullOrEmpty(format) || format.ToUpperInvariant() == "G")
+ {
+ if (isDefaultProvider)
+ {
+ Assert.Equal(upperExpected, i.ToString());
+ Assert.Equal(upperExpected, i.ToString((IFormatProvider)null));
+ }
+ Assert.Equal(upperExpected, i.ToString(provider));
+ }
+ if (isDefaultProvider)
+ {
+ Assert.Equal(upperExpected, i.ToString(upperFormat));
+ Assert.Equal(lowerExpected, i.ToString(lowerFormat));
+ Assert.Equal(upperExpected, i.ToString(upperFormat, null));
+ Assert.Equal(lowerExpected, i.ToString(lowerFormat, null));
+ }
+ Assert.Equal(upperExpected, i.ToString(upperFormat, provider));
+ Assert.Equal(lowerExpected, i.ToString(lowerFormat, provider));
+ }
+
+ [Fact]
+ public static void ToString_InvalidFormat_ThrowsFormatException()
+ {
+ UIntPtr i = (UIntPtr)123;
+ Assert.Throws<FormatException>(() => i.ToString("r")); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("r", null)); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("R")); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("R", null)); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("Y")); // Invalid format
+ Assert.Throws<FormatException>(() => i.ToString("Y", null)); // Invalid format
+ }
+
+ public static IEnumerable<object[]> Parse_Valid_TestData()
+ {
+ // Reuse all IntPtr test data that's relevant
+ foreach (object[] objs in IntPtrTests.Parse_Valid_TestData())
+ {
+ if ((long)(IntPtr)objs[3] < 0) continue;
+ var intPtr = (IntPtr)objs[3];
+ yield return new object[] { objs[0], objs[1], objs[2], Unsafe.As<IntPtr, UIntPtr>(ref intPtr) };
+ }
+
+ // All lengths decimal
+ {
+ string s = "";
+ uint result = 0;
+ for (int i = 1; i <= 10; i++)
+ {
+ result = (uint)(result * 10 + (i % 10));
+ s += (i % 10).ToString();
+ yield return new object[] { s, NumberStyles.Integer, null, (UIntPtr)result };
+ }
+ }
+
+ // All lengths hexadecimal
+ {
+ string s = "";
+ uint result = 0;
+ for (uint i = 1; i <= 8; i++)
+ {
+ result = ((result * 16) + (i % 16));
+ s += (i % 16).ToString("X");
+ yield return new object[] { s, NumberStyles.HexNumber, null, result };
+ }
+ }
+
+ // And test boundary conditions for IntPtr
+ yield return new object[] { Is64Bit ? "18446744073709551615" : "4294967295", NumberStyles.Integer, null, UIntPtr.MaxValue };
+ yield return new object[] { Is64Bit ? "+18446744073709551615" : "+4294967295", NumberStyles.Integer, null, UIntPtr.MaxValue };
+ yield return new object[] { Is64Bit ? " +18446744073709551615 " : " +4294967295 ", NumberStyles.Integer, null, UIntPtr.MaxValue };
+ yield return new object[] { Is64Bit ? "FFFFFFFFFFFFFFFF" : "FFFFFFFF", NumberStyles.HexNumber, null, UIntPtr.MaxValue };
+ yield return new object[] { Is64Bit ? " FFFFFFFFFFFFFFFF " : " FFFFFFFF ", NumberStyles.HexNumber, null, UIntPtr.MaxValue };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Valid_TestData))]
+ public static void Parse_Valid(string value, NumberStyles style, IFormatProvider provider, UIntPtr expected)
+ {
+ UIntPtr result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.True(UIntPtr.TryParse(value, out result));
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, UIntPtr.Parse(value));
+ }
+
+ // Default provider
+ if (provider == null)
+ {
+ Assert.Equal(expected, UIntPtr.Parse(value, style));
+
+ // Substitute default NumberFormatInfo
+ Assert.True(UIntPtr.TryParse(value, style, new NumberFormatInfo(), out result));
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, UIntPtr.Parse(value, style, new NumberFormatInfo()));
+ }
+
+ // Default style
+ if (style == NumberStyles.Integer)
+ {
+ Assert.Equal(expected, UIntPtr.Parse(value, provider));
+ }
+
+ // Full overloads
+ Assert.True(UIntPtr.TryParse(value, style, provider, out result));
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, UIntPtr.Parse(value, style, provider));
+ }
+
+ public static IEnumerable<object[]> Parse_Invalid_TestData()
+ {
+ // > max value
+ yield return new object[] { "18446744073709551616", NumberStyles.Integer, null, typeof(OverflowException) };
+ yield return new object[] { "10000000000000000", NumberStyles.HexNumber, null, typeof(OverflowException) };
+ }
+
+ [Theory]
+ [MemberData(nameof(Parse_Invalid_TestData))]
+ public static void Parse_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType)
+ {
+ UIntPtr result;
+
+ // Default style and provider
+ if (style == NumberStyles.Integer && provider == null)
+ {
+ Assert.False(UIntPtr.TryParse(value, out result));
+ Assert.Equal(default, result);
+ Assert.Throws(exceptionType, () => UIntPtr.Parse(value));
+ }
+
+ // Default provider
+ if (provider == null)
+ {
+ Assert.Throws(exceptionType, () => UIntPtr.Parse(value, style));
+
+ // Substitute default NumberFormatInfo
+ Assert.False(UIntPtr.TryParse(value, style, new NumberFormatInfo(), out result));
+ Assert.Equal(default, result);
+ Assert.Throws(exceptionType, () => UIntPtr.Parse(value, style, new NumberFormatInfo()));
+ }
+
+ // Default style
+ if (style == NumberStyles.Integer)
+ {
+ Assert.Throws(exceptionType, () => UIntPtr.Parse(value, provider));
+ }
+
+ // Full overloads
+ Assert.False(UIntPtr.TryParse(value, style, provider, out result));
+ Assert.Equal(default, result);
+ Assert.Throws(exceptionType, () => UIntPtr.Parse(value, style, provider));
+ }
+
+ [Theory]
+ [InlineData(NumberStyles.HexNumber | NumberStyles.AllowParentheses, null)]
+ [InlineData(unchecked((NumberStyles)0xFFFFFC00), "style")]
+ public static void TryParse_InvalidNumberStyle_ThrowsArgumentException(NumberStyles style, string paramName)
+ {
+ UIntPtr result = (UIntPtr)0;
+ AssertExtensions.Throws<ArgumentException>(paramName, () => UIntPtr.TryParse("1", style, null, out result));
+ Assert.Equal(default(UIntPtr), result);
+
+ AssertExtensions.Throws<ArgumentException>(paramName, () => UIntPtr.Parse("1", style));
+ AssertExtensions.Throws<ArgumentException>(paramName, () => UIntPtr.Parse("1", style, null));
+ }
+
+ public static IEnumerable<object[]> Parse_ValidWithOffsetCount_TestData()
+ {
+ foreach (object[] inputs in Parse_Valid_TestData())
+ {
+ yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] };
+ }
+
+ yield return new object[] { "123", 0, 2, NumberStyles.Integer, null, (UIntPtr)12 };
+ yield return new object[] { "123", 1, 2, NumberStyles.Integer, null, (UIntPtr)23 };
+ yield return new object[] { "4294967295", 0, 1, NumberStyles.Integer, null, 4 };
+ yield return new object[] { "4294967295", 9, 1, NumberStyles.Integer, null, 5 };
+ yield return new object[] { "12", 0, 1, NumberStyles.HexNumber, null, (UIntPtr)0x1 };
+ yield return new object[] { "12", 1, 1, NumberStyles.HexNumber, null, (UIntPtr)0x2 };
+ yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (UIntPtr)10 };
+ }
}
}