diff --git a/Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj b/Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj index 7ede25bb..4b9ae628 100644 --- a/Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj +++ b/Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj @@ -24,6 +24,7 @@ + @@ -47,4 +48,4 @@ - + \ No newline at end of file diff --git a/Tests/NFUnitTestTypes/UnitTestGuid.cs b/Tests/NFUnitTestTypes/UnitTestGuid.cs new file mode 100644 index 00000000..f9ed9c39 --- /dev/null +++ b/Tests/NFUnitTestTypes/UnitTestGuid.cs @@ -0,0 +1,140 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using nanoFramework.TestFramework; + +namespace NFUnitTestTypes +{ + [TestClass] + class UnitTestGuid + { + [TestMethod] + public void Guid_Compare_To_Empty() + { + var empty = Guid.Empty; + var notEmpty = Guid.NewGuid(); + Assert.IsFalse(empty == notEmpty); + } + + [TestMethod] + public void Guid_Empty_IsAllZeros() + { + var empty = Guid.Empty; + var bytes = empty.ToByteArray(); + foreach (var b in bytes) + { + Assert.AreEqual((byte)0, b); + } + } + + [TestMethod] + public void Guid_Constructor_ByteArray_RoundTrip() + { + var original = Guid.NewGuid(); + var bytes = original.ToByteArray(); + var roundTrip = new Guid(bytes); + Assert.AreEqual(original, roundTrip); + } + + [TestMethod] + public void Guid_Equals_And_Operator() + { + var g1 = Guid.NewGuid(); + var g2 = new Guid(g1.ToByteArray()); + Assert.IsTrue(g1.Equals(g2)); + Assert.IsTrue(g1 == g2); + Assert.IsFalse(g1 != g2); + } + + [TestMethod] + public void Guid_NotEquals_And_Operator() + { + var g1 = Guid.NewGuid(); + var g2 = Guid.NewGuid(); + Assert.IsFalse(g1.Equals(g2)); + Assert.IsFalse(g1 == g2); + Assert.IsTrue(g1 != g2); + } + + [TestMethod] + public void Guid_ToString_And_Parse() + { + var g1 = Guid.NewGuid(); + var str = g1.ToString(); + var g2 = new Guid(str); + Assert.AreEqual(g1, g2); + } + + [TestMethod] + public void Guid_GetHashCode_Consistent() + { + var g1 = Guid.NewGuid(); + var g2 = new Guid(g1.ToByteArray()); + Assert.AreEqual(g1.GetHashCode(), g2.GetHashCode()); + } + + [TestMethod] + public void Guid_CompareTo_Object_And_Self() + { + var g1 = Guid.NewGuid(); + var g2 = new Guid(g1.ToByteArray()); + Assert.AreEqual(0, g1.CompareTo(g2)); + Assert.AreEqual(0, g1.CompareTo((object)g2)); + Assert.AreEqual(1, g1.CompareTo(null)); + } + + [TestMethod] + public void Guid_CompareTo_InvalidType_Throws() + { + var g1 = Guid.NewGuid(); + Assert.ThrowsException(typeof(ArgumentException), () => + { + g1.CompareTo("not a guid"); + }); + } + + [TestMethod] + public void Guid_TryParseGuidWithDashes_Valid() + { + var g1 = Guid.NewGuid(); + var str = g1.ToString(); + bool parsed = Guid.TryParseGuidWithDashes(str, out var g2); + Assert.IsTrue(parsed); + Assert.AreEqual(g1, g2); + } + + [TestMethod] + public void Guid_TryParseGuidWithDashes_Invalid() + { + bool parsed = Guid.TryParseGuidWithDashes("invalid-guid", out var g2); + Assert.IsFalse(parsed); + Assert.AreEqual(Guid.Empty, g2); + } + + [TestMethod] + public void Guid_Constructor_String_WithBraces() + { + var g1 = Guid.NewGuid(); + var str = "{" + g1.ToString() + "}"; + var g2 = new Guid(str); + Assert.AreEqual(g1, g2); + } + + [TestMethod] + public void Guid_Constructor_String_Invalid_Throws() + { + Assert.ThrowsException(typeof(ArgumentException), () => + { + var g = new Guid("invalid-guid"); + }); + } + + [TestMethod] + public void Guid_GetHashCode_Empty() + { + var empty = Guid.Empty; + Assert.AreEqual(0, empty.GetHashCode()); + } + } +} diff --git a/nanoFramework.CoreLibrary/System/AssemblyInfo.cs b/nanoFramework.CoreLibrary/System/AssemblyInfo.cs index 1d1984ee..49310cca 100644 --- a/nanoFramework.CoreLibrary/System/AssemblyInfo.cs +++ b/nanoFramework.CoreLibrary/System/AssemblyInfo.cs @@ -10,4 +10,4 @@ [assembly: AssemblyProduct(".NET nanoFramework mscorlib")] [assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] -[assembly: AssemblyNativeVersion("100.5.0.24")] +[assembly: AssemblyNativeVersion("100.5.0.25")] diff --git a/nanoFramework.CoreLibrary/System/Guid.cs b/nanoFramework.CoreLibrary/System/Guid.cs index 75e2f066..03e2bfe9 100644 --- a/nanoFramework.CoreLibrary/System/Guid.cs +++ b/nanoFramework.CoreLibrary/System/Guid.cs @@ -18,6 +18,12 @@ public struct Guid /// public static readonly Guid Empty = new Guid(new byte[16]); + public Guid() + { + // All zeros + _data = new int[4]; + } + /// /// Initializes a new instance of the structure by using the specified integers and bytes. /// @@ -163,26 +169,32 @@ public int CompareTo(object value) if (value == null) { return 1; - } -#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one - if (value is not Guid) + } + if (value is not Guid other) { throw new ArgumentException(); } -#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one - int[] other = ((Guid)value)._data; - other ??= new int[4]; + return CompareTo(other); + } + /// + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// + /// An object to compare with this instance. + /// A value that indicates the relative order of the objects being compared. + public int CompareTo(Guid other) + { + _data ??= new int[4]; + other._data ??= new int[4]; for (int i = 0; i < 4; i++) { - if (_data[i] != other[i]) + if (_data[i] != other._data[i]) { - return _data[i] - other[i]; + return _data[i] - other._data[i]; } } - return 0; } @@ -201,6 +213,9 @@ public int CompareTo(object value) /// public byte[] ToByteArray() { + // Initialize if null (treat as Empty) + _data ??= new int[4]; + byte[] buffer = new byte[16]; int index = 0; @@ -289,10 +304,19 @@ public override bool Equals(object o) return false; } - int[] other = ((Guid)o)._data; - other ??= new int[4]; + return o is Guid other && Equals(other); + } - return (_data[0] == other[0]) && (_data[1] == other[1]) && (_data[2] == other[2]) && (_data[3] == other[3]); + /// + /// Indicates whether the current object is equal to another object of the same type. + /// + /// An object to compare with this object. + /// true if the current object is equal to the other parameter; otherwise, false. + public bool Equals(Guid other) + { + _data ??= new int[4]; + other._data ??= new int[4]; + return (_data[0] == other._data[0]) && (_data[1] == other._data[1]) && (_data[2] == other._data[2]) && (_data[3] == other._data[3]); } /// @@ -301,6 +325,8 @@ public override bool Equals(object o) /// The hash code for this instance. public override int GetHashCode() { + // Initialize if null (treat as Empty) + _data ??= new int[4]; return _data[0] ^ _data[1] ^ _data[2] ^ _data[3]; } @@ -447,5 +473,34 @@ private static long HexStringToLong(string str, ref int parsePos, int requiredLe parsePos += requiredLength; return result; } + + /// + /// Determines whether two specified instances of are equal. + /// + /// The first to compare. + /// The second to compare. + /// if equals ; otherwise, . + public static bool operator ==(Guid a, Guid b) + { + // Defensive null handling, though _data should always be initialized + a._data ??= new int[4]; + b._data ??= new int[4]; + + return (a._data[0] == b._data[0]) && + (a._data[1] == b._data[1]) && + (a._data[2] == b._data[2]) && + (a._data[3] == b._data[3]); + } + + /// + /// Determines whether two specified instances of are not equal. + /// + /// The first to compare. + /// The second to compare. + /// if does not equal ; otherwise, . + public static bool operator !=(Guid a, Guid b) + { + return !(a == b); + } } }