diff --git a/CSF.Extensions.WebDriver.Tests/Identification/BrowserVersionIntegrationTests.cs b/CSF.Extensions.WebDriver.Tests/Identification/BrowserVersionIntegrationTests.cs new file mode 100644 index 0000000..76fe0c2 --- /dev/null +++ b/CSF.Extensions.WebDriver.Tests/Identification/BrowserVersionIntegrationTests.cs @@ -0,0 +1,41 @@ +namespace CSF.Extensions.WebDriver.Identification; + +[TestFixture, Parallelizable] +public class BrowserVersionIntegrationTests +{ + [Test] + public void ALowerVersionShouldBeLessThanAHigherOneWithMoreComponents() + { + var first = BrowserVersion.Create("95.0.4638"); + var second = BrowserVersion.Create("95.1.1234.5678"); + + Assert.That(first, Is.LessThan(second), "First version is less than second version"); + } + + [Test] + public void AHigherVersionShouldBeGreaterThanALowerOneWithMoreComponents() + { + var first = BrowserVersion.Create("95.2.4638"); + var second = BrowserVersion.Create("95.1.1234.5678"); + + Assert.That(first, Is.GreaterThan(second), "First version is greater than second version"); + } + + [Test] + public void ALowerVersionShouldBeLessThanAHigherOneWithFewerComponents() + { + var first = BrowserVersion.Create("95.0.4638.1234"); + var second = BrowserVersion.Create("95.1"); + + Assert.That(first, Is.LessThan(second), "First version is less than second version"); + } + + [Test] + public void AHigherVersionShouldBeGreaterThanALowerOneWithFewerComponents() + { + var first = BrowserVersion.Create("95.2.4638.1234"); + var second = BrowserVersion.Create("95.1"); + + Assert.That(first, Is.GreaterThan(second), "First version is greater than second version"); + } +} \ No newline at end of file diff --git a/CSF.Extensions.WebDriver.Tests/Identification/DottedNumericBrowserVersionTests.cs b/CSF.Extensions.WebDriver.Tests/Identification/DottedNumericBrowserVersionTests.cs index ca3d1fa..c235347 100644 --- a/CSF.Extensions.WebDriver.Tests/Identification/DottedNumericBrowserVersionTests.cs +++ b/CSF.Extensions.WebDriver.Tests/Identification/DottedNumericBrowserVersionTests.cs @@ -61,4 +61,36 @@ public void TryParseShouldReturnFalseForAnInvalidVersion() { Assert.That(DottedNumericBrowserVersion.TryParse("Elephants", out _), Is.False); } + + [Test, AutoMoqData] + public void GetHashCodeShouldReturnTheSameResultForTwoEqualInstances() + { + var one = new DottedNumericBrowserVersion([1, 2, 3]); + var two = new DottedNumericBrowserVersion([1, 2, 3]); + + Assert.That(one.GetHashCode(), Is.EqualTo(two.GetHashCode())); + } + + [Test, AutoMoqData] + public void EqualsObjectShouldReturnTrueForTwoEqualInstances() + { + object one = new DottedNumericBrowserVersion([1, 2, 3]); + object two = new DottedNumericBrowserVersion([1, 2, 3]); + +#pragma warning disable NUnit2010 // Use EqualConstraint - not doing this to explicitly show what I'm testing + Assert.That(one.Equals(two), Is.True); +#pragma warning restore NUnit2010 + } + + [Test, AutoMoqData] + public void ConstructorShouldThrowForAnEmptyListOfComponents() + { + Assert.That(() => new DottedNumericBrowserVersion([]), Throws.ArgumentException); + } + + [Test, AutoMoqData] + public void ConstructorShouldThrowForANullListOfComponents() + { + Assert.That(() => new DottedNumericBrowserVersion(null), Throws.ArgumentNullException); + } } \ No newline at end of file diff --git a/CSF.Extensions.WebDriver/Identification/BrowserVersion.cs b/CSF.Extensions.WebDriver/Identification/BrowserVersion.cs index 80a387c..731cf56 100644 --- a/CSF.Extensions.WebDriver/Identification/BrowserVersion.cs +++ b/CSF.Extensions.WebDriver/Identification/BrowserVersion.cs @@ -166,7 +166,7 @@ public static BrowserVersion Create(string version, string requestedVersion = nu if (SemanticBrowserVersion.TryParse(version, out var semVersion)) return semVersion; if (DottedNumericBrowserVersion.TryParse(version, out var numericVersion)) return numericVersion; if (SemanticBrowserVersion.TryParse(requestedVersion, out var requestedSemVersion, true)) return requestedSemVersion; - if (DottedNumericBrowserVersion.TryParse(requestedVersion, out var requestedNumericVersion)) return requestedNumericVersion; + if (DottedNumericBrowserVersion.TryParse(requestedVersion, out var requestedNumericVersion, true)) return requestedNumericVersion; if (UnrecognisedBrowserVersion.TryParse(version, out var unrecognisedVersion)) return unrecognisedVersion; if (UnrecognisedBrowserVersion.TryParse(requestedVersion, out var requestedUnrecognisedVersion)) return requestedUnrecognisedVersion; diff --git a/CSF.Extensions.WebDriver/Identification/DottedNumericVersion.cs b/CSF.Extensions.WebDriver/Identification/DottedNumericBrowserVersion.cs similarity index 80% rename from CSF.Extensions.WebDriver/Identification/DottedNumericVersion.cs rename to CSF.Extensions.WebDriver/Identification/DottedNumericBrowserVersion.cs index d815220..836e222 100644 --- a/CSF.Extensions.WebDriver/Identification/DottedNumericVersion.cs +++ b/CSF.Extensions.WebDriver/Identification/DottedNumericBrowserVersion.cs @@ -16,11 +16,17 @@ namespace CSF.Extensions.WebDriver.Identification /// It permits any amount of leading and trailing non-numeric characters /// It permits any number of 'version' components, not just a maximum of 3 as is the case with SemVer /// + /// + /// The implementations of and include special-case logic for comparing/equating + /// dotted numeric versions with instances. If these methods (from this type) are used with a semantic version + /// then that semantic version is converted into a dotted numeric version first, using . + /// The methods then proceed according to their usual logic, with the resulting converted version. + /// /// public sealed class DottedNumericBrowserVersion : BrowserVersion { const string parserPattern = @"(\d+)(?:\.(\d+))*"; - static readonly Regex parser = new Regex(parserPattern, RegexOptions.Compiled | RegexOptions.CultureInvariant); + static readonly Regex parser = new Regex(parserPattern, RegexOptions.Compiled | RegexOptions.CultureInvariant, TimeSpan.FromMilliseconds(50)); readonly IReadOnlyList components; @@ -33,8 +39,13 @@ public sealed class DottedNumericBrowserVersion : BrowserVersion /// public override int CompareTo(BrowserVersion other) { - if (other is null || !(other is DottedNumericBrowserVersion version)) return 1; + if(other is DottedNumericBrowserVersion dotVersion) return CompareTo(dotVersion); + if(other is SemanticBrowserVersion semVersion) return CompareTo(semVersion.ToDottedNumericBrowserVersion()); + return 1; + } + int CompareTo(DottedNumericBrowserVersion version) + { var theirCount = version.VersionComponents.Count; for (var i = 0; i < VersionComponents.Count; i++) { @@ -54,10 +65,10 @@ public override int CompareTo(BrowserVersion other) /// public override bool Equals(BrowserVersion other) - { - if (other is null || !(other is DottedNumericBrowserVersion version)) return false; - return VersionComponents.SequenceEqual(version.VersionComponents); - } + => other is DottedNumericBrowserVersion dotVersion && VersionComponents.SequenceEqual(dotVersion.VersionComponents); + + /// + public override bool Equals(object obj) => obj is BrowserVersion ver && Equals(ver); /// public override int GetHashCode() => VersionComponents.Aggregate(17, HashFunction); diff --git a/CSF.Extensions.WebDriver/Identification/SemanticBrowserVersion.cs b/CSF.Extensions.WebDriver/Identification/SemanticBrowserVersion.cs index 8433b39..34d38c5 100644 --- a/CSF.Extensions.WebDriver/Identification/SemanticBrowserVersion.cs +++ b/CSF.Extensions.WebDriver/Identification/SemanticBrowserVersion.cs @@ -17,6 +17,13 @@ namespace CSF.Extensions.WebDriver.Identification /// to permit some common improper representations of a semantic version. The TryParse function in this class /// uses to enable very generous parsing. /// + /// + /// The implementations of and include special-case logic for comparing/equating + /// semantic versions with instances. If these methods (from this type) are used with a dotted numeric version + /// then the current instance is converted into a dotted numeric version first, using . + /// The equality/comparison methods then make use of and + /// accordingly, performing using the comparison functions from the converted version instead. + /// /// public sealed class SemanticBrowserVersion : BrowserVersion { @@ -28,16 +35,31 @@ public sealed class SemanticBrowserVersion : BrowserVersion /// public override int CompareTo(BrowserVersion other) { - if (other is null || !(other is SemanticBrowserVersion semVersion)) return 1; - return Version.CompareSortOrderTo(semVersion.Version); + if(other is SemanticBrowserVersion semVersion) return Version.CompareSortOrderTo(semVersion.Version); + if(other is DottedNumericBrowserVersion dotVersion) return ToDottedNumericBrowserVersion().CompareTo(dotVersion); + return 1; } /// public override bool Equals(BrowserVersion other) - { - if (other is null || !(other is SemanticBrowserVersion semVersion)) return false; - return Version.Equals(semVersion.Version); - } + => other is SemanticBrowserVersion semVersion && Version.Equals(semVersion.Version); + + /// + public override bool Equals(object obj) => obj is BrowserVersion ver && Equals(ver); + + /// + /// Converts the current into an instance of . + /// + /// + /// + /// This is useful in situations where the current version must be compared with a dotted numeric version. + /// Note that only the Major, Minor and Patch version components are converted. Any prerelease information or build + /// metadata are omitted from this conversion process. + /// + /// + /// A dotted numeric browser version, created from the major, minor and patch components of this semantic version. + public DottedNumericBrowserVersion ToDottedNumericBrowserVersion() + => new DottedNumericBrowserVersion(new [] {Version.Major, Version.Minor, Version.Patch}, IsPresumedVersion); /// public override int GetHashCode() => Version.GetHashCode();