Handle pre-release semantics by adjusting the max version of ranges (#28)
Rather than adding special-cases to each operation, we now just modify
the upper bound of version ranges when the special pre-release
semantics would come into play.
Closes dart-lang/pub#1885
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f2e5e62..0efa0ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,25 @@
+# 1.4.0
+
+* Add a `Version.firstPreRelease` getter that returns the first possible
+ pre-release of a version.
+
+* Add a `Version.isFirstPreRelease` getter that returns whether a version is the
+ first possible pre-release.
+
+* `new VersionRange()` with an exclusive maximum now replaces the maximum with
+ its first pre-release version. This matches the existing semantics, where an
+ exclusive maximum would exclude pre-release versions of that maximum.
+
+ Explicitly representing this by changing the maximum version ensures that all
+ operations behave correctly with respect to the special pre-release semantics.
+ In particular, it fixes bugs where, for example,
+ `(>=1.0.0 <2.0.0-dev).union(>=2.0.0-dev <2.0.0)` and
+ `(>=1.0.0 <3.0.0).difference(^1.0.0)` wouldn't include `2.0.0-dev`.
+
+* Add an `alwaysIncludeMaxPreRelease` parameter to `new VersionRange()`, which
+ disables the replacement described above and allows users to create ranges
+ that do include the pre-release versions of an exclusive max version.
+
# 1.3.7
* Fix more bugs with `VersionRange.intersect()`, `VersionRange.difference()`,
diff --git a/lib/pub_semver.dart b/lib/pub_semver.dart
index bfb7d8b..4b6487c 100644
--- a/lib/pub_semver.dart
+++ b/lib/pub_semver.dart
@@ -4,5 +4,5 @@
export 'src/version.dart';
export 'src/version_constraint.dart';
-export 'src/version_range.dart';
+export 'src/version_range.dart' hide CompatibleWithVersionRange;
export 'src/version_union.dart';
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 55025a0..60617f2 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -30,12 +30,6 @@
if (range1.max == null) return range2.max != null;
if (range2.max == null) return false;
- // `<1.0.0-dev.1` allows higher versions than `<1.0.0`, such as `1.0.0-dev.0`.
- if (disallowedByPreRelease(range2, range1.max)) return true;
-
- // `<1.0.0` doesn't allow any versions higher than `<1.0.0-dev`.
- if (disallowedByPreRelease(range1, range2.max)) return false;
-
var comparison = range1.max.compareTo(range2.max);
if (comparison == 1) return true;
if (comparison == -1) return false;
@@ -47,11 +41,6 @@
bool strictlyLower(VersionRange range1, VersionRange range2) {
if (range1.max == null || range2.min == null) return false;
- // `<1.0.0` doesn't allow any versions allowed by `>=1.0.0-dev.0`.
- if (disallowedByPreRelease(range1, range2.min)) return true;
-
- //if (disallowedByPreRelease(range2, range1.min)) return true;
-
var comparison = range1.max.compareTo(range2.min);
if (comparison == -1) return true;
if (comparison == 1) return false;
@@ -63,40 +52,7 @@
bool strictlyHigher(VersionRange range1, VersionRange range2) =>
strictlyLower(range2, range1);
-// Returns whether [other] is disallowed by [range] because we disallow
-// pre-release versions that have the same major, minor, and patch version as
-// the max of a range, but only if neither the max nor the min is a pre-release
-// of that version.
-//
-// This ensures that `^1.2.3` doesn't include `2.0.0-pre`, while also allowing
-// both `>=2.0.0-pre.2 <2.0.0` and `>=1.2.3 <2.0.0-pre.7` to match
-// `2.0.0-pre.5`.
-//
-// It's worth noting that this is different than [NPM's semantics][]. NPM
-// disallows **all** pre-release versions unless their major, minor, and
-// patch numbers match those of a prerelease min or max. This ensures that
-// no prerelease versions will ever be selected if the user doesn't
-// explicitly allow them.
-//
-// [NPM's semantics]: https://www.npmjs.org/doc/misc/semver.html#prerelease-tags
-//
-// Instead, we ensure that release versions will always be preferred over
-// prerelease versions by ordering the release versions first in
-// [Version.prioritize]. This means that constraints like `any` or
-// `>1.2.3` can still match prerelease versions if they're the only things
-// available.
-bool disallowedByPreRelease(VersionRange range, Version other) {
- var maxIsReleaseOfOther = !range.includeMax &&
- !range.max.isPreRelease &&
- other.isPreRelease &&
- _equalsWithoutPreRelease(other, range.max);
- var minIsPreReleaseOfOther = range.min != null &&
- range.min.isPreRelease &&
- _equalsWithoutPreRelease(other, range.min);
- return maxIsReleaseOfOther && !minIsPreReleaseOfOther;
-}
-
-bool _equalsWithoutPreRelease(Version version1, Version version2) =>
+bool equalsWithoutPreRelease(Version version1, Version version2) =>
version1.major == version2.major &&
version1.minor == version2.minor &&
version1.patch == version2.patch;
diff --git a/lib/src/version.dart b/lib/src/version.dart
index 6665873..19ae962 100644
--- a/lib/src/version.dart
+++ b/lib/src/version.dart
@@ -239,6 +239,12 @@
return _incrementMajor();
}
+ /// Returns the first possible pre-release of this version.
+ Version get firstPreRelease => new Version(major, minor, patch, pre: "0");
+
+ /// Returns whether this is the first possible pre-release of its version.
+ bool get isFirstPreRelease => preRelease.length == 1 && preRelease.first == 0;
+
Version _incrementMajor() => new Version(major + 1, 0, 0);
Version _incrementMinor() => new Version(major, minor + 1, 0);
Version _incrementPatch() => new Version(major, minor, patch + 1);
@@ -262,7 +268,8 @@
min: other.min,
max: other.max,
includeMin: true,
- includeMax: other.includeMax);
+ includeMax: other.includeMax,
+ alwaysIncludeMaxPreRelease: true);
}
if (other.max == this) {
@@ -270,7 +277,8 @@
min: other.min,
max: other.max,
includeMin: other.includeMin,
- includeMax: true);
+ includeMax: true,
+ alwaysIncludeMaxPreRelease: true);
}
}
diff --git a/lib/src/version_constraint.dart b/lib/src/version_constraint.dart
index 670a928..67093f7 100644
--- a/lib/src/version_constraint.dart
+++ b/lib/src/version_constraint.dart
@@ -84,7 +84,10 @@
case '<=':
return new VersionRange(max: version, includeMax: true);
case '<':
- return new VersionRange(max: version, includeMax: false);
+ return new VersionRange(
+ max: version,
+ includeMax: false,
+ alwaysIncludeMaxPreRelease: true);
case '>=':
return new VersionRange(min: version, includeMin: true);
case '>':
@@ -175,7 +178,7 @@
/// are greater than or equal to [version], but less than the next breaking
/// version ([Version.nextBreaking]) of [version].
factory VersionConstraint.compatibleWith(Version version) =>
- new _CompatibleWithVersionRange(version);
+ new CompatibleWithVersionRange(version);
/// Creates a new version constraint that is the intersection of
/// [constraints].
@@ -278,14 +281,3 @@
VersionConstraint difference(VersionConstraint other) => this;
String toString() => '<empty>';
}
-
-class _CompatibleWithVersionRange extends VersionRange {
- _CompatibleWithVersionRange(Version version)
- : super(
- min: version,
- includeMin: true,
- max: version.nextBreaking,
- includeMax: false);
-
- String toString() => '^$min';
-}
diff --git a/lib/src/version_range.dart b/lib/src/version_range.dart
index ec15de4..99dc718 100644
--- a/lib/src/version_range.dart
+++ b/lib/src/version_range.dart
@@ -53,14 +53,36 @@
///
/// If [includeMin] is `true`, then the minimum end of the range is inclusive.
/// Likewise, passing [includeMax] as `true` makes the upper end inclusive.
- VersionRange(
- {this.min, this.max, this.includeMin: false, this.includeMax: false}) {
+ ///
+ /// If [alwaysIncludeMaxPreRelease] is `true`, this will always include
+ /// pre-release versions of an exclusive [max]. Otherwise, it will use the
+ /// default behavior for pre-release versions of [max].
+ factory VersionRange(
+ {Version min,
+ Version max,
+ bool includeMin: false,
+ bool includeMax: false,
+ bool alwaysIncludeMaxPreRelease: false}) {
if (min != null && max != null && min > max) {
throw new ArgumentError(
'Minimum version ("$min") must be less than maximum ("$max").');
}
+
+ if (!alwaysIncludeMaxPreRelease &&
+ !includeMax &&
+ max != null &&
+ !max.isPreRelease &&
+ (min == null ||
+ !min.isPreRelease ||
+ !equalsWithoutPreRelease(min, max))) {
+ max = max.firstPreRelease;
+ }
+
+ return new VersionRange._(min, max, includeMin, includeMax);
}
+ VersionRange._(this.min, this.max, this.includeMin, this.includeMax);
+
bool operator ==(other) {
if (other is! VersionRange) return false;
@@ -90,7 +112,6 @@
if (max != null) {
if (other > max) return false;
if (!includeMax && other == max) return false;
- if (disallowedByPreRelease(this, other)) return false;
}
return true;
@@ -177,7 +198,8 @@
min: intersectMin,
max: intersectMax,
includeMin: intersectIncludeMin,
- includeMax: intersectIncludeMax);
+ includeMax: intersectIncludeMax,
+ alwaysIncludeMaxPreRelease: true);
}
throw new ArgumentError('Unknown VersionConstraint type $other.');
@@ -192,7 +214,8 @@
min: this.min,
max: this.max,
includeMin: true,
- includeMax: this.includeMax);
+ includeMax: this.includeMax,
+ alwaysIncludeMaxPreRelease: true);
}
if (other == max) {
@@ -200,7 +223,8 @@
min: this.min,
max: this.max,
includeMin: this.includeMin,
- includeMax: true);
+ includeMax: true,
+ alwaysIncludeMaxPreRelease: true);
}
return new VersionConstraint.unionOf([this, other]);
@@ -239,7 +263,8 @@
min: unionMin,
max: unionMax,
includeMin: unionIncludeMin,
- includeMax: unionIncludeMax);
+ includeMax: unionIncludeMax,
+ alwaysIncludeMaxPreRelease: true);
}
return new VersionConstraint.unionOf([this, other]);
@@ -254,20 +279,36 @@
if (other == min) {
if (!includeMin) return this;
return new VersionRange(
- min: min, max: max, includeMin: false, includeMax: includeMax);
+ min: min,
+ max: max,
+ includeMin: false,
+ includeMax: includeMax,
+ alwaysIncludeMaxPreRelease: true);
}
if (other == max) {
if (!includeMax) return this;
return new VersionRange(
- min: min, max: max, includeMin: includeMin, includeMax: false);
+ min: min,
+ max: max,
+ includeMin: includeMin,
+ includeMax: false,
+ alwaysIncludeMaxPreRelease: true);
}
return new VersionUnion.fromRanges([
new VersionRange(
- min: min, max: other, includeMin: includeMin, includeMax: false),
+ min: min,
+ max: other,
+ includeMin: includeMin,
+ includeMax: false,
+ alwaysIncludeMaxPreRelease: true),
new VersionRange(
- min: other, max: max, includeMin: false, includeMax: includeMax)
+ min: other,
+ max: max,
+ includeMin: false,
+ includeMax: includeMax,
+ alwaysIncludeMaxPreRelease: true)
]);
} else if (other is VersionRange) {
if (!allowsAny(other)) return this;
@@ -284,7 +325,8 @@
min: min,
max: other.min,
includeMin: includeMin,
- includeMax: !other.includeMin);
+ includeMax: !other.includeMin,
+ alwaysIncludeMaxPreRelease: true);
}
VersionRange after;
@@ -299,7 +341,8 @@
min: other.max,
max: max,
includeMin: !other.includeMax,
- includeMax: includeMax);
+ includeMax: includeMax,
+ alwaysIncludeMaxPreRelease: true);
}
if (before == null && after == null) return VersionConstraint.empty;
@@ -379,11 +422,36 @@
if (max != null) {
if (min != null) buffer.write(' ');
- buffer.write(includeMax ? '<=' : '<');
- buffer.write(max);
+ if (includeMax) {
+ buffer.write('<=');
+ buffer.write(max);
+ } else {
+ buffer.write('<');
+ if (max.isFirstPreRelease) {
+ // Since `"<$max"` would parse the same as `"<$max-0"`, we just emit
+ // `<$max` to avoid confusing "-0" suffixes.
+ buffer.write("${max.major}.${max.minor}.${max.patch}");
+ } else {
+ buffer.write(max);
+
+ // If `">=$min <$max"` would parse as `">=$min <$max-0"`, add `-*` to
+ // indicate that actually does allow pre-release versions.
+ var minIsPreReleaseOfMax = min != null &&
+ min.isPreRelease &&
+ equalsWithoutPreRelease(min, max);
+ if (!max.isPreRelease && !minIsPreReleaseOfMax) buffer.write("-∞");
+ }
+ }
}
if (min == null && max == null) buffer.write('any');
return buffer.toString();
}
}
+
+class CompatibleWithVersionRange extends VersionRange {
+ CompatibleWithVersionRange(Version version)
+ : super._(version, version.nextBreaking.firstPreRelease, true, false);
+
+ String toString() => '^$min';
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index 1b738d7..a537788 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: pub_semver
-version: 1.3.7
+version: 1.4.0
author: Dart Team <misc@dartlang.org>
description: >
Versions and version constraints implementing pub's versioning policy. This
diff --git a/test/utils.dart b/test/utils.dart
index 9b28c6a..8ecd8f5 100644
--- a/test/utils.dart
+++ b/test/utils.dart
@@ -22,6 +22,10 @@
final v250 = new Version.parse('2.5.0');
final v300 = new Version.parse('3.0.0');
+/// A range that allows pre-release versions of its max version.
+final includeMaxPreReleaseRange =
+ new VersionRange(max: v200, alwaysIncludeMaxPreRelease: true);
+
/// A [Matcher] that tests if a [VersionConstraint] allows or does not allow a
/// given list of [Version]s.
class _VersionConstraintMatcher implements Matcher {
diff --git a/test/version_range_test.dart b/test/version_range_test.dart
index 63cf302..4bdc21c 100644
--- a/test/version_range_test.dart
+++ b/test/version_range_test.dart
@@ -14,7 +14,25 @@
var range = new VersionRange(min: v123, max: v124);
expect(range.isAny, isFalse);
expect(range.min, equals(v123));
- expect(range.max, equals(v124));
+ expect(range.max, equals(v124.firstPreRelease));
+ });
+
+ group("doesn't make the max a pre-release if", () {
+ test("it's already a pre-release", () {
+ expect(new VersionRange(max: new Version.parse("1.2.4-pre")).max,
+ equals(new Version.parse("1.2.4-pre")));
+ });
+
+ test("includeMax is true", () {
+ expect(new VersionRange(max: v124, includeMax: true).max, equals(v124));
+ });
+
+ test("min is a prerelease of max", () {
+ expect(
+ new VersionRange(min: new Version.parse("1.2.4-pre"), max: v124)
+ .max,
+ equals(v124));
+ });
});
test('allows omitting max', () {
@@ -158,6 +176,10 @@
expect(range,
allows(new Version.parse('0.0.0'), new Version.parse('999.99.9')));
});
+
+ test('allows pre-releases of the max with includeMaxPreRelease', () {
+ expect(includeMaxPreReleaseRange, allows(new Version.parse('2.0.0-dev')));
+ });
});
group('allowsAll()', () {
@@ -247,6 +269,13 @@
isFalse);
});
+ test('of non-pre-release max are included with includeMaxPreRelease', () {
+ expect(
+ includeMaxPreReleaseRange
+ .allowsAll(new VersionConstraint.parse('<2.0.0-dev')),
+ isTrue);
+ });
+
test(
'of non-pre-release max are included if min is a pre-release of the '
'same version', () {
@@ -388,6 +417,13 @@
isFalse);
});
+ test('of non-pre-release max are included with includeMaxPreRelease', () {
+ expect(
+ includeMaxPreReleaseRange
+ .allowsAny(new VersionConstraint.parse('>2.0.0-dev')),
+ isTrue);
+ });
+
test(
'of non-pre-release max are included if min is a pre-release of the '
'same version', () {
@@ -419,15 +455,10 @@
group('intersect()', () {
test('two overlapping ranges', () {
- var a = new VersionRange(min: v123, max: v250);
- var b = new VersionRange(min: v200, max: v300);
- var intersect = a.intersect(b);
- expect(intersect, new isInstanceOf<VersionRange>());
- var intersectRange = intersect as VersionRange;
- expect(intersectRange.min, equals(v200));
- expect(intersectRange.max, equals(v250));
- expect(intersectRange.includeMin, isFalse);
- expect(intersectRange.includeMax, isFalse);
+ expect(
+ new VersionRange(min: v123, max: v250)
+ .intersect(new VersionRange(min: v200, max: v300)),
+ equals(new VersionRange(min: v200, max: v250)));
});
test('a non-overlapping range allows no versions', () {
@@ -476,6 +507,48 @@
.intersect(new VersionConstraint.parse("<2.0.0-dev")),
equals(new VersionRange(max: v200)));
});
+
+ group("with includeMaxPreRelease", () {
+ test('preserves includeMaxPreRelease if the max version is included', () {
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(new VersionConstraint.parse("<1.0.0")),
+ equals(new VersionConstraint.parse("<1.0.0")));
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(new VersionConstraint.parse("<2.0.0")),
+ equals(new VersionConstraint.parse("<2.0.0")));
+ expect(includeMaxPreReleaseRange.intersect(includeMaxPreReleaseRange),
+ equals(includeMaxPreReleaseRange));
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(new VersionConstraint.parse("<3.0.0")),
+ equals(includeMaxPreReleaseRange));
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(new VersionConstraint.parse(">1.1.4")),
+ equals(new VersionRange(
+ min: v114, max: v200, alwaysIncludeMaxPreRelease: true)));
+ });
+
+ test(
+ "and a range with a pre-release min, returns "
+ "an intersection", () {
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(new VersionConstraint.parse(">=2.0.0-dev")),
+ equals(new VersionConstraint.parse(">=2.0.0-dev <2.0.0")));
+ });
+
+ test(
+ "and a range with a pre-release max, returns "
+ "the narrower constraint", () {
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(new VersionConstraint.parse("<2.0.0-dev")),
+ equals(new VersionConstraint.parse("<2.0.0-dev")));
+ });
+ });
});
group('union()', () {
@@ -485,7 +558,10 @@
});
test("with a version on the edge of the range, expands the range", () {
- expect(new VersionRange(min: v114, max: v124).union(v124),
+ expect(
+ new VersionRange(
+ min: v114, max: v124, alwaysIncludeMaxPreRelease: true)
+ .union(v124),
equals(new VersionRange(min: v114, max: v124, includeMax: true)));
expect(new VersionRange(min: v114, max: v124).union(v114),
equals(new VersionRange(min: v114, max: v124, includeMin: true)));
@@ -533,7 +609,8 @@
.union(new VersionRange(min: v114, max: v200));
expect(result, equals(new VersionRange(min: v003, max: v200)));
- result = new VersionRange(min: v003, max: v114)
+ result = new VersionRange(
+ min: v003, max: v114, alwaysIncludeMaxPreRelease: true)
.union(new VersionRange(min: v114, max: v200, includeMin: true));
expect(result, equals(new VersionRange(min: v003, max: v200)));
@@ -541,8 +618,9 @@
.union(new VersionRange(min: v003, max: v114, includeMax: true));
expect(result, equals(new VersionRange(min: v003, max: v200)));
- result = new VersionRange(min: v114, max: v200, includeMin: true)
- .union(new VersionRange(min: v003, max: v114));
+ result = new VersionRange(min: v114, max: v200, includeMin: true).union(
+ new VersionRange(
+ min: v003, max: v114, alwaysIncludeMaxPreRelease: true));
expect(result, equals(new VersionRange(min: v003, max: v200)));
});
@@ -573,6 +651,39 @@
.union(new VersionConstraint.parse("<2.0.0-dev")),
equals(new VersionConstraint.parse("<2.0.0-dev")));
});
+
+ group("with includeMaxPreRelease", () {
+ test('adds includeMaxPreRelease if the max version is included', () {
+ expect(
+ includeMaxPreReleaseRange
+ .union(new VersionConstraint.parse("<1.0.0")),
+ equals(includeMaxPreReleaseRange));
+ expect(includeMaxPreReleaseRange.union(includeMaxPreReleaseRange),
+ equals(includeMaxPreReleaseRange));
+ expect(
+ includeMaxPreReleaseRange
+ .union(new VersionConstraint.parse("<2.0.0")),
+ equals(includeMaxPreReleaseRange));
+ expect(
+ includeMaxPreReleaseRange
+ .union(new VersionConstraint.parse("<3.0.0")),
+ equals(new VersionConstraint.parse("<3.0.0")));
+ });
+
+ test("and a range with a pre-release min, returns any", () {
+ expect(
+ includeMaxPreReleaseRange
+ .union(new VersionConstraint.parse(">=2.0.0-dev")),
+ equals(VersionConstraint.any));
+ });
+
+ test("and a range with a pre-release max, returns the original", () {
+ expect(
+ includeMaxPreReleaseRange
+ .union(new VersionConstraint.parse("<2.0.0-dev")),
+ equals(includeMaxPreReleaseRange));
+ });
+ });
});
group('difference()', () {
@@ -592,7 +703,8 @@
expect(
new VersionRange(min: v003, max: v114).difference(v072),
equals(new VersionConstraint.unionOf([
- new VersionRange(min: v003, max: v072),
+ new VersionRange(
+ min: v003, max: v072, alwaysIncludeMaxPreRelease: true),
new VersionRange(min: v072, max: v114)
])));
});
@@ -601,7 +713,8 @@
expect(
new VersionRange(min: v003, max: v114, includeMax: true)
.difference(v114),
- equals(new VersionRange(min: v003, max: v114)));
+ equals(new VersionRange(
+ min: v003, max: v114, alwaysIncludeMaxPreRelease: true)));
});
test("with the min version makes the min exclusive", () {
@@ -630,11 +743,11 @@
expect(
new VersionRange(min: v080, max: v130)
.difference(new VersionRange(min: v010, max: v114)),
- equals(new VersionRange(min: v114, max: v130, includeMin: true)));
+ equals(new VersionConstraint.parse(">=1.1.4-0 <1.3.0")));
expect(
new VersionRange(min: v080, max: v130)
.difference(new VersionRange(max: v114)),
- equals(new VersionRange(min: v114, max: v130, includeMin: true)));
+ equals(new VersionConstraint.parse(">=1.1.4-0 <1.3.0")));
expect(
new VersionRange(min: v080, max: v130).difference(
new VersionRange(min: v010, max: v114, includeMax: true)),
@@ -646,7 +759,7 @@
expect(
new VersionRange(min: v080, max: v130, includeMax: true)
.difference(new VersionRange(min: v080, max: v130)),
- equals(v130));
+ equals(new VersionConstraint.parse(">=1.3.0-0 <=1.3.0")));
});
test("with a range at the end cuts off the end of the range", () {
@@ -661,11 +774,13 @@
expect(
new VersionRange(min: v080, max: v130).difference(
new VersionRange(min: v114, max: v140, includeMin: true)),
- equals(new VersionRange(min: v080, max: v114)));
+ equals(new VersionRange(
+ min: v080, max: v114, alwaysIncludeMaxPreRelease: true)));
expect(
new VersionRange(min: v080, max: v130, includeMax: true).difference(
new VersionRange(min: v130, max: v140, includeMin: true)),
- equals(new VersionRange(min: v080, max: v130)));
+ equals(new VersionRange(
+ min: v080, max: v130, alwaysIncludeMaxPreRelease: true)));
expect(
new VersionRange(min: v080, max: v130, includeMin: true)
.difference(new VersionRange(min: v080, max: v130)),
@@ -678,7 +793,7 @@
.difference(new VersionRange(min: v072, max: v114)),
equals(new VersionConstraint.unionOf([
new VersionRange(min: v003, max: v072, includeMax: true),
- new VersionRange(min: v114, max: v130, includeMin: true)
+ new VersionConstraint.parse(">=1.1.4-0 <1.3.0")
])));
});
@@ -715,8 +830,7 @@
new VersionRange(min: v080, max: v123),
new VersionRange(min: v130, max: v200)
])),
- equals(new VersionRange(
- min: v123, max: v130, includeMin: true, includeMax: true)));
+ equals(new VersionConstraint.parse(">=1.2.3-0 <=1.3.0")));
});
test("with a version union that intersects the middle, chops it up", () {
@@ -724,9 +838,12 @@
new VersionRange(min: v114, max: v140)
.difference(new VersionConstraint.unionOf([v123, v124, v130])),
equals(new VersionConstraint.unionOf([
- new VersionRange(min: v114, max: v123),
- new VersionRange(min: v123, max: v124),
- new VersionRange(min: v124, max: v130),
+ new VersionRange(
+ min: v114, max: v123, alwaysIncludeMaxPreRelease: true),
+ new VersionRange(
+ min: v123, max: v124, alwaysIncludeMaxPreRelease: true),
+ new VersionRange(
+ min: v124, max: v130, alwaysIncludeMaxPreRelease: true),
new VersionRange(min: v130, max: v140)
])));
});
@@ -752,6 +869,84 @@
.difference(new VersionConstraint.parse("<2.0.0-dev")),
equals(VersionConstraint.empty));
});
+
+ group("with includeMaxPreRelease", () {
+ group("for the minuend", () {
+ test("preserves includeMaxPreRelease if the max version is included",
+ () {
+ expect(
+ includeMaxPreReleaseRange
+ .difference(new VersionConstraint.parse("<1.0.0")),
+ equals(new VersionRange(
+ min: new Version.parse("1.0.0-0"),
+ max: v200,
+ includeMin: true,
+ alwaysIncludeMaxPreRelease: true)));
+ expect(
+ includeMaxPreReleaseRange
+ .difference(new VersionConstraint.parse("<2.0.0")),
+ equals(new VersionRange(
+ min: v200.firstPreRelease,
+ max: v200,
+ includeMin: true,
+ alwaysIncludeMaxPreRelease: true)));
+ expect(
+ includeMaxPreReleaseRange.difference(includeMaxPreReleaseRange),
+ equals(VersionConstraint.empty));
+ expect(
+ includeMaxPreReleaseRange
+ .difference(new VersionConstraint.parse("<3.0.0")),
+ equals(VersionConstraint.empty));
+ });
+
+ test("with a range with a pre-release min, adjusts the max", () {
+ expect(
+ includeMaxPreReleaseRange
+ .difference(new VersionConstraint.parse(">=2.0.0-dev")),
+ equals(new VersionConstraint.parse("<2.0.0-dev")));
+ });
+
+ test("with a range with a pre-release max, adjusts the min", () {
+ expect(
+ includeMaxPreReleaseRange
+ .difference(new VersionConstraint.parse("<2.0.0-dev")),
+ equals(new VersionConstraint.parse(">=2.0.0-dev <2.0.0")));
+ });
+ });
+
+ group("for the subtrahend", () {
+ group("doesn't create a pre-release minimum", () {
+ test("when cutting off the bottom", () {
+ expect(
+ new VersionConstraint.parse("<3.0.0")
+ .difference(includeMaxPreReleaseRange),
+ equals(
+ new VersionRange(min: v200, max: v300, includeMin: true)));
+ });
+
+ test("with splitting down the middle", () {
+ expect(
+ new VersionConstraint.parse("<4.0.0").difference(
+ new VersionRange(
+ min: v200,
+ max: v300,
+ includeMin: true,
+ alwaysIncludeMaxPreRelease: true)),
+ equals(new VersionConstraint.unionOf([
+ new VersionRange(max: v200, alwaysIncludeMaxPreRelease: true),
+ new VersionConstraint.parse(">=3.0.0 <4.0.0")
+ ])));
+ });
+
+ test("can leave a single version", () {
+ expect(
+ new VersionConstraint.parse("<=2.0.0")
+ .difference(includeMaxPreReleaseRange),
+ equals(v200));
+ });
+ });
+ });
+ });
});
test('isEmpty', () {
@@ -786,6 +981,11 @@
new VersionRange(min: v003, max: v080, includeMax: true));
});
+ test("includeMaxPreRelease comes after !includeMaxPreRelease", () {
+ _expectComparesSmaller(
+ new VersionRange(max: v200), includeMaxPreReleaseRange);
+ });
+
test("no minimum comes before small minimum", () {
_expectComparesSmaller(
new VersionRange(max: v010), new VersionRange(min: v003, max: v010));
diff --git a/test/version_test.dart b/test/version_test.dart
index fc6dfef..448435a 100644
--- a/test/version_test.dart
+++ b/test/version_test.dart
@@ -190,8 +190,14 @@
});
test("with a range with the version on the edge, expands the range", () {
- expect(v124.union(new VersionRange(min: v114, max: v124)),
+ expect(
+ v124.union(new VersionRange(
+ min: v114, max: v124, alwaysIncludeMaxPreRelease: true)),
equals(new VersionRange(min: v114, max: v124, includeMax: true)));
+ expect(
+ v124.firstPreRelease.union(new VersionRange(min: v114, max: v124)),
+ equals(new VersionRange(
+ min: v114, max: v124.firstPreRelease, includeMax: true)));
expect(v114.union(new VersionRange(min: v114, max: v124)),
equals(new VersionRange(min: v114, max: v124, includeMin: true)));
});
diff --git a/test/version_union_test.dart b/test/version_union_test.dart
index f948832..f629c83 100644
--- a/test/version_union_test.dart
+++ b/test/version_union_test.dart
@@ -101,25 +101,32 @@
new VersionConstraint.unionOf([
new VersionRange(min: v003, max: v072, includeMax: true),
new VersionRange(min: v072, max: v080),
- new VersionRange(min: v114, max: v124),
- new VersionRange(min: v124, max: v130, includeMin: true)
+ new VersionRange(
+ min: v114, max: v124, alwaysIncludeMaxPreRelease: true),
+ new VersionRange(min: v124, max: v130, includeMin: true),
+ new VersionRange(
+ min: v130.firstPreRelease, max: v200, includeMin: true)
]),
equals(new VersionConstraint.unionOf([
new VersionRange(min: v003, max: v080),
- new VersionRange(min: v114, max: v130)
+ new VersionRange(min: v114, max: v200)
])));
});
test("doesn't merge not-quite-adjacent ranges", () {
expect(
new VersionConstraint.unionOf([
+ new VersionRange(min: v114, max: v124),
+ new VersionRange(min: v124, max: v130, includeMin: true)
+ ]),
+ isNot(equals(new VersionRange(min: v114, max: v130))));
+
+ expect(
+ new VersionConstraint.unionOf([
new VersionRange(min: v003, max: v072),
new VersionRange(min: v072, max: v080)
]),
- equals(new VersionConstraint.unionOf([
- new VersionRange(min: v003, max: v072),
- new VersionRange(min: v072, max: v080)
- ])));
+ isNot(equals(new VersionRange(min: v003, max: v080))));
});
test("merges version numbers into ranges", () {
@@ -139,16 +146,30 @@
test("merges adjacent version numbers into ranges", () {
expect(
new VersionConstraint.unionOf([
- new VersionRange(min: v003, max: v072),
+ new VersionRange(
+ min: v003, max: v072, alwaysIncludeMaxPreRelease: true),
v072,
v114,
- new VersionRange(min: v114, max: v124)
+ new VersionRange(min: v114, max: v124),
+ v124.firstPreRelease
]),
equals(new VersionConstraint.unionOf([
new VersionRange(min: v003, max: v072, includeMax: true),
- new VersionRange(min: v114, max: v124, includeMin: true)
+ new VersionRange(
+ min: v114,
+ max: v124.firstPreRelease,
+ includeMin: true,
+ includeMax: true)
])));
});
+
+ test("doesn't merge not-quite-adjacent version numbers into ranges", () {
+ expect(
+ new VersionConstraint.unionOf(
+ [new VersionRange(min: v003, max: v072), v072]),
+ isNot(equals(
+ new VersionRange(min: v003, max: v072, includeMax: true))));
+ });
});
test('isEmpty returns false', () {
@@ -424,7 +445,8 @@
new VersionRange(min: v124)
])),
equals(new VersionConstraint.unionOf([
- new VersionRange(min: v072, max: v080, includeMin: true),
+ new VersionRange(
+ min: v072.firstPreRelease, max: v080, includeMin: true),
new VersionRange(min: v123, max: v124, includeMax: true)
])));
});
@@ -436,8 +458,10 @@
new VersionRange(min: v130, max: v200)
]).difference(new VersionConstraint.unionOf([v072, v080])),
equals(new VersionConstraint.unionOf([
- new VersionRange(min: v010, max: v072),
- new VersionRange(min: v072, max: v080),
+ new VersionRange(
+ min: v010, max: v072, alwaysIncludeMaxPreRelease: true),
+ new VersionRange(
+ min: v072, max: v080, alwaysIncludeMaxPreRelease: true),
new VersionRange(min: v080, max: v114),
new VersionRange(min: v130, max: v200)
])));
@@ -455,7 +479,8 @@
equals(new VersionConstraint.unionOf([
new VersionRange(min: v010, max: v072),
new VersionRange(min: v080, max: v114, includeMax: true),
- new VersionRange(min: v201, max: v234, includeMin: true),
+ new VersionRange(
+ min: v201.firstPreRelease, max: v234, includeMin: true),
new VersionRange(min: v250, max: v300)
])));
});