diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 3a90210..e3f1820 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -9,7 +9,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: windows-latest strategy: matrix: @@ -17,14 +17,50 @@ jobs: name: .NET ${{ matrix.dotnet }} steps: - - uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: 'zulu' # Alternative distribution options are available. + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ matrix.dotnet }} + - name: Cache SonarQube Cloud packages + uses: actions/cache@v4 + with: + path: ~\sonar\cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + - name: Cache SonarQube Cloud scanner + id: cache-sonar-scanner + uses: actions/cache@v4 + with: + path: .\.sonar\scanner + key: ${{ runner.os }}-sonar-scanner + restore-keys: ${{ runner.os }}-sonar-scanner + - name: Install SonarQube Cloud scanner + if: steps.cache-sonar-scanner.outputs.cache-hit != 'true' + shell: powershell + run: | + New-Item -Path .\.sonar\scanner -ItemType Directory + dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner - name: Restore dependencies run: dotnet restore + - name: SonarCloudPrepare + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: .\.sonar\scanner\dotnet-sonarscanner begin /k:"TensionDev_UUIDUtil" /o:"tensiondev" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.scanner.scanAll=false /d:sonar.cs.opencover.reportsPaths=**/coverage.opencover.xml - name: Build run: dotnet build --no-restore - name: Test - run: dotnet test --no-build --verbosity normal + run: dotnet test --no-build --verbosity normal --collect "XPlat Code Coverage;Format=opencover" + - name: SonarCloudAnalyze + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" diff --git a/UUIDUtil/UUIDUtil.csproj b/UUIDUtil/UUIDUtil.csproj index f271cb2..d1ea94e 100644 --- a/UUIDUtil/UUIDUtil.csproj +++ b/UUIDUtil/UUIDUtil.csproj @@ -7,7 +7,7 @@ true true TensionDev.UUID - 2.1.0 + 2.1.1 TensionDev amsga TensionDev TensionDev.UUID @@ -21,8 +21,6 @@ Change in license to Apache License 2.0. Release with UUID / GUID Version 1, Version 3, Version 4 and Version 5, and Draft Versions 6 and 7. en-SG - 2.1.0.0 - 2.1.0.0 true snupkg README.md diff --git a/UUIDUtil/UUIDv1.cs b/UUIDUtil/UUIDv1.cs index 7165ff5..c581caa 100644 --- a/UUIDUtil/UUIDv1.cs +++ b/UUIDUtil/UUIDv1.cs @@ -30,6 +30,10 @@ public class UUIDv1 protected internal static readonly Object s_initLock = new Object(); protected internal static readonly Object s_clockLock = new Object(); + protected UUIDv1() + { + } + /// /// Initialises a new GUID/UUID based on Version 1 (date-time and MAC address) /// diff --git a/UUIDUtil/UUIDv3.cs b/UUIDUtil/UUIDv3.cs index 97b8f92..8a4d0c5 100644 --- a/UUIDUtil/UUIDv3.cs +++ b/UUIDUtil/UUIDv3.cs @@ -25,6 +25,10 @@ namespace TensionDev.UUID /// public class UUIDv3 { + protected UUIDv3() + { + } + /// /// Initialises a new GUID/UUID based on Version 3 (MD5 namespace name-based) /// diff --git a/UUIDUtil/UUIDv4.cs b/UUIDUtil/UUIDv4.cs index fbfdcde..91f1a0a 100644 --- a/UUIDUtil/UUIDv4.cs +++ b/UUIDUtil/UUIDv4.cs @@ -23,6 +23,10 @@ namespace TensionDev.UUID /// public class UUIDv4 { + protected UUIDv4() + { + } + /// /// Initialises a new GUID/UUID based on Version 4 (random) /// diff --git a/UUIDUtil/UUIDv5.cs b/UUIDUtil/UUIDv5.cs index e6a5551..e7d86f9 100644 --- a/UUIDUtil/UUIDv5.cs +++ b/UUIDUtil/UUIDv5.cs @@ -25,6 +25,10 @@ namespace TensionDev.UUID /// public class UUIDv5 { + protected UUIDv5() + { + } + /// /// Initialises a new GUID/UUID based on Version 5 (SHA-1 namespace name-based) /// diff --git a/UUIDUtil/UUIDv6.cs b/UUIDUtil/UUIDv6.cs index 81424c4..2d052b8 100644 --- a/UUIDUtil/UUIDv6.cs +++ b/UUIDUtil/UUIDv6.cs @@ -29,6 +29,10 @@ public class UUIDv6 protected internal static readonly Object s_initLock = new Object(); protected internal static readonly Object s_clockLock = new Object(); + protected UUIDv6() + { + } + /// /// Initialises a new GUID/UUID based on Version 6 (date-time) /// diff --git a/UUIDUtil/UUIDv7.cs b/UUIDUtil/UUIDv7.cs index ef173db..90f08f9 100644 --- a/UUIDUtil/UUIDv7.cs +++ b/UUIDUtil/UUIDv7.cs @@ -29,6 +29,10 @@ public class UUIDv7 protected internal static UInt16 s_counter = 0; protected internal static readonly Object s_counterLock = new Object(); + protected UUIDv7() + { + } + public enum GenerationMethod { /// diff --git a/UUIDUtil/Uuid.cs b/UUIDUtil/Uuid.cs index 9842b4e..9b2426b 100644 --- a/UUIDUtil/Uuid.cs +++ b/UUIDUtil/Uuid.cs @@ -22,12 +22,14 @@ namespace TensionDev.UUID { public sealed class Uuid : IComparable, IEquatable { - private uint _time_low; - private ushort _time_mid; - private ushort _time_hi_and_version; + private const string INVALID_FORMAT_STRING = "The format of s is invalid"; + private const string HEX_FORMAT_STRING = "{0:x2}"; + private readonly uint _time_low; + private readonly ushort _time_mid; + private readonly ushort _time_hi_and_version; private byte _clock_seq_hi_and_reserved; - private byte _clock_seq_low; - private byte[] _node; + private readonly byte _clock_seq_low; + private readonly byte[] _node; /// /// A read-only instance of the Uuid object whose value is all zeros. @@ -37,7 +39,7 @@ public sealed class Uuid : IComparable, IEquatable /// /// A read-only instance of the Uuid object whose value is all ones. /// - public static readonly Uuid Max = new Uuid(uint.MaxValue, ushort.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}); + public static readonly Uuid Max = new Uuid(uint.MaxValue, ushort.MaxValue, ushort.MaxValue, byte.MaxValue, byte.MaxValue, new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }); public Uuid() { @@ -84,20 +86,17 @@ public Uuid(byte[] b) : this() /// The format of s is invalid public Uuid(string s) : this() { - if (s == null) - throw new ArgumentNullException(nameof(s)); - if (String.IsNullOrEmpty(s)) - throw new FormatException("The format of s is invalid"); + throw new ArgumentNullException(nameof(s), INVALID_FORMAT_STRING); if (s.Length != 32 && s.Length != 36 && s.Length != 38) - throw new FormatException("The format of s is invalid"); + throw new FormatException(INVALID_FORMAT_STRING); - if (s.Length == 38) + if (s.Length == 38 && + !(s.StartsWith("{") && s.EndsWith("}")) && + !(s.StartsWith("(") && s.EndsWith(")"))) { - if (!(s.StartsWith("{") && s.EndsWith("}")) && - !(s.StartsWith("(") && s.EndsWith(")"))) - throw new FormatException("The format of s is invalid"); + throw new FormatException(INVALID_FORMAT_STRING); } string vs = s.Replace("{", ""); @@ -107,15 +106,15 @@ public Uuid(string s) : this() if (vs.Length == 36) { - Regex regex = new Regex(@"\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b", RegexOptions.IgnoreCase); + Regex regex = new Regex(@"\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(100)); MatchCollection matches = regex.Matches(vs); if (matches.Count == 0) - throw new FormatException("The format of s is invalid"); + throw new FormatException(INVALID_FORMAT_STRING); } vs = vs.Replace("-", ""); if (vs.Length != 32) - throw new FormatException("The format of s is invalid"); + throw new FormatException(INVALID_FORMAT_STRING); Byte[] b = new Byte[16]; for (Int32 i = 0; i < vs.Length; i += 2) @@ -126,11 +125,11 @@ public Uuid(string s) : this() } catch (FormatException) { - throw new FormatException("The format of s is invalid"); + throw new FormatException(INVALID_FORMAT_STRING); } catch (OverflowException) { - throw new OverflowException("The format of s is invalid"); + throw new OverflowException(INVALID_FORMAT_STRING); } } @@ -356,9 +355,10 @@ public Guid ToVariant2() { byte newClockSeq = (byte)(_clock_seq_hi_and_reserved & 0x1F); newClockSeq = (byte)(newClockSeq | 0xC0); - Uuid variant2 = new Uuid(this.ToByteArray()); - - variant2._clock_seq_hi_and_reserved = newClockSeq; + Uuid variant2 = new Uuid(this.ToByteArray()) + { + _clock_seq_hi_and_reserved = newClockSeq + }; return variant2.ToGuid(); } @@ -370,10 +370,13 @@ public Guid ToVariant2() /// A TensionDev.UUID.Uuid object. public static Uuid ToVariant1(Guid guid) { - Uuid variant1 = new Uuid(guid.ToString()); - byte newClockSeq = (byte)(variant1._clock_seq_hi_and_reserved & 0x3F); + Uuid variant2 = new Uuid(guid.ToString()); + byte newClockSeq = (byte)(variant2._clock_seq_hi_and_reserved & 0x3F); newClockSeq = (byte)(newClockSeq | 0x80); - variant1._clock_seq_hi_and_reserved = newClockSeq; + Uuid variant1 = new Uuid(variant2.ToByteArray()) + { + _clock_seq_hi_and_reserved = newClockSeq + }; return variant1; } @@ -432,8 +435,8 @@ private string ToStringCannonical() sb.Append("-"); sb.Append(BitConverter.ToString(BitConverter.GetBytes(_time_hi_and_version)).Replace("-", "")); sb.Append("-"); - sb.AppendFormat("{0:x2}", _clock_seq_hi_and_reserved); - sb.AppendFormat("{0:x2}", _clock_seq_low); + sb.AppendFormat(HEX_FORMAT_STRING, _clock_seq_hi_and_reserved); + sb.AppendFormat(HEX_FORMAT_STRING, _clock_seq_low); sb.Append("-"); sb.Append(BitConverter.ToString(_node).Replace("-", "")); @@ -447,8 +450,8 @@ private string ToHexString() sb.Append(BitConverter.ToString(BitConverter.GetBytes(_time_low)).Replace("-", "")); sb.Append(BitConverter.ToString(BitConverter.GetBytes(_time_mid)).Replace("-", "")); sb.Append(BitConverter.ToString(BitConverter.GetBytes(_time_hi_and_version)).Replace("-", "")); - sb.AppendFormat("{0:x2}", _clock_seq_hi_and_reserved); - sb.AppendFormat("{0:x2}", _clock_seq_low); + sb.AppendFormat(HEX_FORMAT_STRING, _clock_seq_hi_and_reserved); + sb.AppendFormat(HEX_FORMAT_STRING, _clock_seq_low); sb.Append(BitConverter.ToString(_node).Replace("-", "")); return sb.ToString().ToLower(); diff --git a/XUnitTestProjectUUID/UnitTestUUIDv1.cs b/XUnitTestProjectUUID/UnitTestUUIDv1.cs index 0bf192c..19996fa 100644 --- a/XUnitTestProjectUUID/UnitTestUUIDv1.cs +++ b/XUnitTestProjectUUID/UnitTestUUIDv1.cs @@ -12,7 +12,8 @@ public class UnitTestUUIDv1 [Fact] public void TestGetNodeID() { - IList expectedNodeIDs = new List(); + List expectedNodeIDs = new List(); + int expectedLength = 6; NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface nic in nics) { @@ -24,7 +25,7 @@ public void TestGetNodeID() if (nics.Length > 0) Assert.Contains(nodeID, expectedNodeIDs); else - Assert.True(nodeID.Length == 6); + Assert.Equal(expectedLength, nodeID.Length); } [Fact] diff --git a/XUnitTestProjectUUID/UnitTestUUIDv6.cs b/XUnitTestProjectUUID/UnitTestUUIDv6.cs index 740fe2e..0611f94 100644 --- a/XUnitTestProjectUUID/UnitTestUUIDv6.cs +++ b/XUnitTestProjectUUID/UnitTestUUIDv6.cs @@ -11,9 +11,10 @@ public class UnitTestUUIDv6 [Fact] public void TestGetNodeID() { + int expectedLength = 6; byte[] nodeID = TensionDev.UUID.UUIDv6.GetNodeID(); - Assert.True(nodeID.Length == 6); + Assert.Equal(expectedLength, nodeID.Length); } [Fact] @@ -64,7 +65,7 @@ public void TestGetClockSequence() [Fact] public void TestUUIDVariantField() { - IList expectedVariantField = new List() { '8', '9', 'a', 'b' }; + List expectedVariantField = new List() { '8', '9', 'a', 'b' }; ConcurrentBag concurrentBag = new ConcurrentBag(); diff --git a/XUnitTestProjectUUID/UnitTestUuid.cs b/XUnitTestProjectUUID/UnitTestUuid.cs index 273b3fe..e550153 100644 --- a/XUnitTestProjectUUID/UnitTestUuid.cs +++ b/XUnitTestProjectUUID/UnitTestUuid.cs @@ -5,18 +5,36 @@ namespace XUnitTestProjectUUID { public class UnitTestUuid { + [Fact] + public void TestEmptyUUID() + { + string expectedUUID = "00000000-0000-0000-0000-000000000000"; + + TensionDev.UUID.Uuid uuid = TensionDev.UUID.Uuid.Empty; + Assert.Equal(expectedUUID, uuid.ToString()); + } + + [Fact] + public void TestMaxUUID() + { + string expectedUUID = "ffffffff-ffff-ffff-ffff-ffffffffffff"; + + TensionDev.UUID.Uuid uuid = TensionDev.UUID.Uuid.Max; + Assert.Equal(expectedUUID, uuid.ToString()); + } + [Fact] public void TestConstructorByteArray1() { byte[] vs = null; - ArgumentNullException ex = Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(vs); }); + Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(vs); }); } [Fact] public void TestConstructorByteArray2() { byte[] vs = new byte[17]; - ArgumentException ex = Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(vs); }); + Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(vs); }); } [Fact] @@ -33,14 +51,14 @@ public void TestConstructorByteArray3() public void TestConstructorString1() { string vs = null; - ArgumentNullException ex = Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(vs); }); + Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(vs); }); } [Fact] public void TestConstructorString2() { string vs = "(7d444840-9dc0-11d1-b245-5ffdce74fad2}"; - FormatException ex = Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(vs); }); + Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(vs); }); } [Fact] @@ -62,7 +80,7 @@ public void TestConstructorComponents1() byte d = byte.MaxValue; byte e = byte.MaxValue; byte[] f = null; - ArgumentNullException ex = Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(a, b, c, d, e, f); }); + Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(a, b, c, d, e, f); }); } [Fact] @@ -74,7 +92,7 @@ public void TestConstructorComponents2() byte d = byte.MinValue; byte e = byte.MinValue; byte[] f = new byte[5]; - ArgumentException ex = Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(a, b, c, d, e, f); }); + Assert.Throws(() => { TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(a, b, c, d, e, f); }); } [Fact] @@ -301,7 +319,7 @@ public void TestToString7() byte[] vs = new byte[] { 0x7d, 0x44, 0x48, 0x40, 0x9d, 0xc0, 0x11, 0xd1, 0xb2, 0x45, 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2 }; TensionDev.UUID.Uuid uuid = new TensionDev.UUID.Uuid(vs); - FormatException ex = Assert.Throws(() => { string actual = uuid.ToString("C"); }); + Assert.Throws(() => { uuid.ToString("C"); }); } } }