From cf425da609e0756445467d02509937fb435f1db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=BCller?= Date: Sun, 25 Feb 2024 09:44:36 +0100 Subject: [PATCH] Added VersionStringComparer --- AMWD.Common/Comparer/VersionStringComparer.cs | 86 +++++++++++++++++++ CHANGELOG.md | 1 + .../Comparer/VersionStringComparerTests.cs | 67 +++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 AMWD.Common/Comparer/VersionStringComparer.cs create mode 100644 UnitTests/Common/Comparer/VersionStringComparerTests.cs diff --git a/AMWD.Common/Comparer/VersionStringComparer.cs b/AMWD.Common/Comparer/VersionStringComparer.cs new file mode 100644 index 0000000..aa5e1b2 --- /dev/null +++ b/AMWD.Common/Comparer/VersionStringComparer.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace AMWD.Common.Comparer +{ + /// + /// Defines a method to compare two strings. + /// +#if NET8_0_OR_GREATER + public partial class VersionStringComparer : IComparer + { + private readonly Regex _versionRegex = VersionRegex(); +#else + + public class VersionStringComparer : IComparer + { + private readonly Regex _versionRegex = new("([0-9.]+)"); +#endif + + /// + /// Compares two strings and returns a value indicating + /// whether one is less than, equal to, or greater than the other. + /// + /// The first version string. + /// The second version string. + /// + /// A signed integer that indicates the relative values of x and y, as shown in the following table: + /// + /// + /// Value + /// Meaning + /// + /// + /// -1 + /// x is less than y + /// + /// + /// 0 + /// x equals y + /// + /// + /// 1 + /// x is greater than y + /// + /// + /// + public int Compare(string x, string y) + { + if (string.IsNullOrWhiteSpace(x) && string.IsNullOrWhiteSpace(y)) + return 0; + + if (string.IsNullOrWhiteSpace(x)) + return -1; + + if (string.IsNullOrWhiteSpace(y)) + return 1; + + string xMainVersion = _versionRegex.Match(x).Groups[1].Value; + string yMainVersion = _versionRegex.Match(y).Groups[1].Value; + + string xAppendix = x.ReplaceStart(xMainVersion, ""); + string yAppendix = y.ReplaceStart(yMainVersion, ""); + + if (xMainVersion.IndexOf('.') < 0) + xMainVersion += ".0"; + + if (yMainVersion.IndexOf('.') < 0) + yMainVersion += ".0"; + + var xVersion = Version.Parse(xMainVersion); + var yVersion = Version.Parse(yMainVersion); + + int versionResult = xVersion.CompareTo(yVersion); + if (versionResult != 0) + return versionResult; + + return xAppendix.CompareTo(yAppendix); + } + +#if NET8_0_OR_GREATER + [GeneratedRegex("([0-9.]+)")] + private static partial Regex VersionRegex(); +#endif + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e8b6cc..cb6784f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ArReader` and `ArWriter` for Unix archives - `TarReader` and `TarWriter` for TAR archives +- `VersionStringComparer` to compare version strings (SemVer) ### Changed diff --git a/UnitTests/Common/Comparer/VersionStringComparerTests.cs b/UnitTests/Common/Comparer/VersionStringComparerTests.cs new file mode 100644 index 0000000..a24d496 --- /dev/null +++ b/UnitTests/Common/Comparer/VersionStringComparerTests.cs @@ -0,0 +1,67 @@ +using AMWD.Common.Comparer; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace UnitTests.Common.Comparer +{ + [TestClass] + public class VersionStringComparerTests + { + [DataTestMethod] + [DataRow(null, "0")] + [DataRow("", "0")] + [DataRow("0", "1")] + [DataRow("1.0", "1.1")] + [DataRow("1.0.0", "1.0.1")] + [DataRow("1.0.0.0", "1.0.0.1")] + [DataRow("1.0.0.0-RC1", "1.0.0.0-RC2")] + public void ShouldBeLessThan(string x, string y) + { + // Arrange + var comparer = new VersionStringComparer(); + + // Act + int result = comparer.Compare(x, y); + + // Assert + Assert.AreEqual(-1, result); + } + + [DataTestMethod] + [DataRow("0", null)] + [DataRow("0", "")] + [DataRow("1", "0")] + [DataRow("1.1", "1.0")] + [DataRow("1.0.1", "1.0.0")] + [DataRow("1.0.0.1", "1.0.0.0")] + [DataRow("1.0.0.0-RC2", "1.0.0.0-RC1")] + public void ShouldBeGreaterThan(string x, string y) + { + // Arrange + var comparer = new VersionStringComparer(); + + // Act + int result = comparer.Compare(x, y); + + // Assert + Assert.AreEqual(1, result); + } + + [DataTestMethod] + [DataRow(null, null)] + [DataRow("", "")] + [DataRow("1", "1")] + [DataRow("1.2.3", "1.2.3")] + [DataRow("1.2.3-alpha", "1.2.3-alpha")] + public void ShouldBeEqual(string x, string y) + { + // Arrange + var comparer = new VersionStringComparer(); + + // Act + int result = comparer.Compare(x, y); + + // Assert + Assert.AreEqual(0, result); + } + } +}