Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
2 changes: 1 addition & 1 deletion CSF.Extensions.WebDriver/Identification/BrowserVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
/// Initialises a new instance of <see cref="BrowserVersion"/>.
/// </summary>
/// <param name="isPresumed">Whether or not this is a presumed version; see <see cref="IsPresumedVersion"/>.</param>
protected internal BrowserVersion(bool isPresumed = false)

Check warning on line 60 in CSF.Extensions.WebDriver/Identification/BrowserVersion.cs

View workflow job for this annotation

GitHub Actions / Build, test & package

Change the visibility of this constructor to 'private protected'.

Check warning on line 60 in CSF.Extensions.WebDriver/Identification/BrowserVersion.cs

View workflow job for this annotation

GitHub Actions / Build, test & package

Change the visibility of this constructor to 'private protected'.

Check warning on line 60 in CSF.Extensions.WebDriver/Identification/BrowserVersion.cs

View workflow job for this annotation

GitHub Actions / Build, test & package

Change the visibility of this constructor to 'private protected'.

Check warning on line 60 in CSF.Extensions.WebDriver/Identification/BrowserVersion.cs

View workflow job for this annotation

GitHub Actions / Build, test & package

Change the visibility of this constructor to 'private protected'.

Check warning on line 60 in CSF.Extensions.WebDriver/Identification/BrowserVersion.cs

View workflow job for this annotation

GitHub Actions / Build, test & package

Change the visibility of this constructor to 'private protected'.

Check warning on line 60 in CSF.Extensions.WebDriver/Identification/BrowserVersion.cs

View workflow job for this annotation

GitHub Actions / Build, test & package

Change the visibility of this constructor to 'private protected'.
{
IsPresumedVersion = isPresumed;
}
Expand Down Expand Up @@ -166,7 +166,7 @@
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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ namespace CSF.Extensions.WebDriver.Identification
/// <item><description>It permits any amount of leading and trailing non-numeric characters</description></item>
/// <item><description>It permits any number of 'version' components, not just a maximum of 3 as is the case with SemVer</description></item>
/// </list>
/// <para>
/// The implementations of <see cref="CompareTo(BrowserVersion)"/> and <see cref="Equals(BrowserVersion)"/> include special-case logic for comparing/equating
/// dotted numeric versions with <see cref="SemanticBrowserVersion"/> 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 <see cref="SemanticBrowserVersion.ToDottedNumericBrowserVersion"/>.
/// The methods then proceed according to their usual logic, with the resulting converted version.
/// </para>
/// </remarks>
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<int> components;

Expand All @@ -33,8 +39,13 @@ public sealed class DottedNumericBrowserVersion : BrowserVersion
/// <inheritdoc/>
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++)
{
Expand All @@ -54,10 +65,10 @@ public override int CompareTo(BrowserVersion other)

/// <inheritdoc/>
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);

/// <inheritdoc/>
public override bool Equals(object obj) => obj is BrowserVersion ver && Equals(ver);

/// <inheritdoc/>
public override int GetHashCode() => VersionComponents.Aggregate(17, HashFunction);
Expand Down
34 changes: 28 additions & 6 deletions CSF.Extensions.WebDriver/Identification/SemanticBrowserVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ namespace CSF.Extensions.WebDriver.Identification
/// to permit some common improper representations of a semantic version. The <c>TryParse</c> function in this class
/// uses <see cref="SemVersionStyles.Any"/> to enable very generous parsing.
/// </para>
/// <para>
/// The implementations of <see cref="CompareTo(BrowserVersion)"/> and <see cref="Equals(BrowserVersion)"/> include special-case logic for comparing/equating
/// semantic versions with <see cref="DottedNumericBrowserVersion"/> 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 <see cref="ToDottedNumericBrowserVersion"/>.
/// The equality/comparison methods then make use of <see cref="DottedNumericBrowserVersion.CompareTo(BrowserVersion)"/> and
/// <see cref="DottedNumericBrowserVersion.Equals(BrowserVersion)"/> accordingly, performing using the comparison functions from the converted version instead.
/// </para>
/// </remarks>
public sealed class SemanticBrowserVersion : BrowserVersion
{
Expand All @@ -28,16 +35,31 @@ public sealed class SemanticBrowserVersion : BrowserVersion
/// <inheritdoc/>
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;
}

/// <inheritdoc/>
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);

/// <inheritdoc/>
public override bool Equals(object obj) => obj is BrowserVersion ver && Equals(ver);

/// <summary>
/// Converts the current <see cref="SemanticBrowserVersion"/> into an instance of <see cref="DottedNumericBrowserVersion"/>.
/// </summary>
/// <remarks>
/// <para>
/// 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.
/// </para>
/// </remarks>
/// <returns>A dotted numeric browser version, created from the major, minor and patch components of this semantic version.</returns>
public DottedNumericBrowserVersion ToDottedNumericBrowserVersion()
=> new DottedNumericBrowserVersion(new [] {Version.Major, Version.Minor, Version.Patch}, IsPresumedVersion);

/// <inheritdoc/>
public override int GetHashCode() => Version.GetHashCode();
Expand Down
Loading