Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IntersectWith method to KspVersionRange #1958

Merged
merged 2 commits into from
Dec 16, 2016
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
54 changes: 54 additions & 0 deletions Core/Versioning/KspVersionBound.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;

namespace CKAN.Versioning
{
Expand Down Expand Up @@ -72,4 +73,57 @@ public override int GetHashCode()
return !Equals(left, right);
}
}

public sealed partial class KspVersionBound
{
/// <summary>
/// Returns the lowest of a set of <see cref="KspVersionBound"/> objects. Analagous to
/// <see cref="KspVersion.Min(KspVersion[])"/> but does not produce a stable sort because in the event of a
/// tie inclusive bounds are treated as both lower and higher than equivalent exclusive bounds.
/// </summary>
/// <param name="versionBounds">The set of <see cref="KspVersionBound"/> objects to compare.</param>
/// <returns>The lowest value in <see cref="versionBounds"/>.</returns>
public static KspVersionBound Lowest(params KspVersionBound[] versionBounds)
{
if (versionBounds == null)
throw new ArgumentNullException("versionBounds");

if (!versionBounds.Any())
throw new ArgumentException("Value cannot be empty.", "versionBounds");

if (versionBounds.Any(i => i == null))
throw new ArgumentException("Value cannot contain null.", "versionBounds");

return versionBounds
.OrderBy(i => i == Unbounded)
.ThenBy(i => i.Value)
.ThenBy(i => i.Inclusive)
.First();
}

/// <summary>
/// Returns the highest of a set of <see cref="KspVersionBound"/> objects. Analagous to
/// <see cref="KspVersion.Max(KspVersion[])"/> but does not produce a stable sort because in the event of a
/// tie inclusive bounds are treated as both lower and higher than equivalent exclusive bounds.
/// </summary>
/// <param name="versionBounds">The set of <see cref="KspVersionBound"/> objects to compare.</param>
/// <returns>The highest value in <see cref="versionBounds"/>.</returns>
public static KspVersionBound Highest(params KspVersionBound[] versionBounds)
{
if (versionBounds == null)
throw new ArgumentNullException("versionBounds");

if (!versionBounds.Any())
throw new ArgumentException("Value cannot be empty.", "versionBounds");

if (versionBounds.Any(i => i == null))
throw new ArgumentException("Value cannot contain null.", "versionBounds");

return versionBounds
.OrderBy(i => i == Unbounded)
.ThenByDescending(i => i.Value)
.ThenBy(i => i.Inclusive)
.First();
}
}
}
17 changes: 17 additions & 0 deletions Core/Versioning/KspVersionRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ public override string ToString()
return _string;
}

public KspVersionRange IntersectWith(KspVersionRange other)
{
if (ReferenceEquals(other, null))
throw new ArgumentNullException("other");

var highestLow = KspVersionBound.Highest(Lower, other.Lower);
var lowestHigh = KspVersionBound.Lowest(Upper, other.Upper);

return IsEmpty(highestLow, lowestHigh) ? null : new KspVersionRange(highestLow, lowestHigh);
}

public bool IsSupersetOf(KspVersionRange other)
{
if (ReferenceEquals(other, null))
Expand All @@ -48,6 +59,12 @@ public bool IsSupersetOf(KspVersionRange other)
return lowerIsOkay && upperIsOkay;
}

private static bool IsEmpty(KspVersionBound lower, KspVersionBound upper)
{
return upper.Value < lower.Value ||
(lower.Value == upper.Value && (!lower.Inclusive || !upper.Inclusive));
}

private static string DeriveString(KspVersionRange versionRange)
{
var sb = new StringBuilder();
Expand Down
259 changes: 258 additions & 1 deletion Tests/Core/Versioning/KspVersionRangeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,253 @@ public sealed class KspVersionRangeTests
}
};

private static readonly object[] IntersectWithCases =
{
new object[]
{
new KspVersionRange(new KspVersionBound(), new KspVersionBound()),
new KspVersionRange(new KspVersionBound(), new KspVersionBound()),
new KspVersionRange(new KspVersionBound(), new KspVersionBound()),
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 2, 3, 4), true),
new KspVersionBound(new KspVersion(1, 2, 3, 4), true)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 2, 3, 4), true),
new KspVersionBound(new KspVersion(1, 2, 3, 4), true)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 2, 3, 4), true),
new KspVersionBound(new KspVersion(1, 2, 3, 4), true)
),
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 2, 3, 4), false),
new KspVersionBound(new KspVersion(1, 2, 3, 4), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 2, 3, 4), false),
new KspVersionBound(new KspVersion(1, 2, 3, 4), false)
),
null
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 2, 3, 4), false),
new KspVersionBound(new KspVersion(1, 2, 3, 4), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 2, 3, 4), true),
new KspVersionBound(new KspVersion(1, 2, 3, 4), true)
),
null
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 0, 0), true),
new KspVersionBound(new KspVersion(1, 1, 0, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 5, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 5, 0), false)
),
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 1, 0, 0), true),
new KspVersionBound(new KspVersion(1, 2, 0, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 5, 0), false)
),
null
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true),
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true),
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true),
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true)
),
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 1235), true),
new KspVersionBound(new KspVersion(1, 0, 4, 1235), true)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true),
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true)
),
null
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 5, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true),
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true),
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true)
),
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true),
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 5, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true),
new KspVersionBound(new KspVersion(1, 0, 4, 1234), true)
),
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 4, 0), true)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 5, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 4, 0), true)
),
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 0, 0), true),
new KspVersionBound(new KspVersion(1, 1, 0, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 0, 0), true),
new KspVersionBound(new KspVersion(1, 1, 0, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 0, 0), true),
new KspVersionBound(new KspVersion(1, 1, 0, 0), false)
),
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 1, 0, 0), true),
new KspVersionBound(new KspVersion(1, 2, 0, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 1, 0, 0), true),
new KspVersionBound(new KspVersion(1, 2, 0, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 1, 0, 0), true),
new KspVersionBound(new KspVersion(1, 2, 0, 0), false)
),
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 1, 0, 0), true),
new KspVersionBound(new KspVersion(1, 2, 0, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 0, 0), true),
new KspVersionBound(new KspVersion(1, 1, 0, 0), false)
),
null
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 0, 0), true),
new KspVersionBound(new KspVersion(1, 1, 0, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 1, 0, 0), true),
new KspVersionBound(new KspVersion(1, 2, 0, 0), false)
),
null
},
new object[]
{
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound()
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 5, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 5, 0), false)
)
},
new object[]
{
new KspVersionRange(
new KspVersionBound(),
new KspVersionBound(new KspVersion(1, 0, 4, 0), true)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 5, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 4, 0), true),
new KspVersionBound(new KspVersion(1, 0, 4, 0), true)
)
},
new object[]
{
new KspVersionRange(
new KspVersionBound(),
new KspVersionBound(new KspVersion(1, 0, 4, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 3, 0), true),
new KspVersionBound(new KspVersion(1, 0, 4, 0), false)
),
new KspVersionRange(
new KspVersionBound(new KspVersion(1, 0, 3, 0), true),
new KspVersionBound(new KspVersion(1, 0, 4, 0), false)
)
}
};

private static readonly object[] IsSupersetOfCases =
{
new object[]
Expand Down Expand Up @@ -174,7 +421,7 @@ public sealed class KspVersionRangeTests
new KspVersionBound(new KspVersion(2, 0, 0, 0), true)
),
true
}
},
};

[Test]
Expand Down Expand Up @@ -226,6 +473,16 @@ public void ToStringWorksCorrectly(KspVersionRange vr, string expected)
Assert.That(result, Is.EqualTo(expected));
}

[TestCaseSource("IntersectWithCases")]
public void IntersectWithWorksCorrectly(KspVersionRange left, KspVersionRange right, KspVersionRange expected)
{
// Act
var result = left.IntersectWith(right);

// Assert
Assert.That(result, Is.EqualTo(expected));
}

[TestCaseSource("IsSupersetOfCases")]
public void IsSupersetOfWorksCorrectly(KspVersionRange left, KspVersionRange right, bool expected)
{
Expand Down