From 3d164a9f60e9e5dda8e6702068723ffc18397278 Mon Sep 17 00:00:00 2001 From: "rnystrom@google.com" <rnystrom@google.com> Date: Wed, 1 Oct 2014 17:57:05 +0000 Subject: [PATCH] Use pub_semver package in pub. R=nweiz@google.com Review URL: https://codereview.chromium.org//602253002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge@40849 260f80e4-7a28-3924-810f-c04153c831b5 --- lib/src/barback.dart | 3 +- lib/src/cached_package.dart | 2 +- lib/src/command/cache_add.dart | 3 +- lib/src/command/global_activate.dart | 3 +- lib/src/global_packages.dart | 2 +- lib/src/lock_file.dart | 2 +- lib/src/package.dart | 4 +- lib/src/preprocess.dart | 3 +- lib/src/pubspec.dart | 2 +- lib/src/sdk.dart | 2 +- lib/src/solver/backtracking_solver.dart | 3 +- lib/src/solver/solve_report.dart | 3 +- lib/src/solver/version_solver.dart | 4 +- lib/src/source.dart | 3 +- lib/src/source/hosted.dart | 2 +- lib/src/validator/dependency.dart | 3 +- lib/src/version.dart | 592 --------------------- test/implicit_barback_dependency_test.dart | 3 +- test/implicit_dependency_test.dart | 3 +- test/lock_file_test.dart | 2 +- test/preprocess_test.dart | 2 +- test/pubspec_test.dart | 2 +- test/serve_packages.dart | 2 +- test/test_pub.dart | 2 +- test/version_solver_test.dart | 2 +- test/version_test.dart | 558 ------------------- 26 files changed, 34 insertions(+), 1178 deletions(-) delete mode 100644 lib/src/version.dart delete mode 100644 test/version_test.dart diff --git a/lib/src/barback.dart b/lib/src/barback.dart index fb4ff51d..33c77542 100644 --- a/lib/src/barback.dart +++ b/lib/src/barback.dart @@ -6,8 +6,7 @@ library pub.barback; import 'package:barback/barback.dart'; import 'package:path/path.dart' as p; - -import 'version.dart'; +import 'package:pub_semver/pub_semver.dart'; /// The currently supported versions of packages that this version of pub works /// with. diff --git a/lib/src/cached_package.dart b/lib/src/cached_package.dart index 6fac594d..94a500ed 100644 --- a/lib/src/cached_package.dart +++ b/lib/src/cached_package.dart @@ -5,13 +5,13 @@ library pub.cached_package; import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; import 'package:yaml/yaml.dart'; import 'barback/transformer_config.dart'; import 'io.dart'; import 'package.dart'; import 'pubspec.dart'; -import 'version.dart'; /// A [Package] whose `lib` directory has been precompiled and cached. /// diff --git a/lib/src/command/cache_add.dart b/lib/src/command/cache_add.dart index 8c8b4d8a..7a2b4f2b 100644 --- a/lib/src/command/cache_add.dart +++ b/lib/src/command/cache_add.dart @@ -6,11 +6,12 @@ library pub.command.cache_add; import 'dart:async'; +import 'package:pub_semver/pub_semver.dart'; + import '../command.dart'; import '../log.dart' as log; import '../package.dart'; import '../utils.dart'; -import '../version.dart'; /// Handles the `cache add` pub command. class CacheAddCommand extends PubCommand { diff --git a/lib/src/command/global_activate.dart b/lib/src/command/global_activate.dart index e78641b4..ea8172af 100644 --- a/lib/src/command/global_activate.dart +++ b/lib/src/command/global_activate.dart @@ -6,9 +6,10 @@ library pub.command.global_activate; import 'dart:async'; +import 'package:pub_semver/pub_semver.dart'; + import '../command.dart'; import '../utils.dart'; -import '../version.dart'; /// Handles the `global activate` pub command. class GlobalActivateCommand extends PubCommand { diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart index c51e545e..73a0c0ab 100644 --- a/lib/src/global_packages.dart +++ b/lib/src/global_packages.dart @@ -9,6 +9,7 @@ import 'dart:io'; import 'package:path/path.dart' as p; import 'package:barback/barback.dart'; +import 'package:pub_semver/pub_semver.dart'; import 'barback/asset_environment.dart'; import 'entrypoint.dart'; @@ -25,7 +26,6 @@ import 'source/git.dart'; import 'source/path.dart'; import 'system_cache.dart'; import 'utils.dart'; -import 'version.dart'; /// Matches the package name that a binstub was created for inside the contents /// of the shell script. diff --git a/lib/src/lock_file.dart b/lib/src/lock_file.dart index 7501951b..99b23327 100644 --- a/lib/src/lock_file.dart +++ b/lib/src/lock_file.dart @@ -5,6 +5,7 @@ library pub.lock_file; import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; import 'package:source_span/source_span.dart'; import 'package:yaml/yaml.dart'; @@ -12,7 +13,6 @@ import 'io.dart'; import 'package.dart'; import 'source_registry.dart'; import 'utils.dart'; -import 'version.dart'; /// A parsed and validated `pubspec.lock` file. class LockFile { diff --git a/lib/src/package.dart b/lib/src/package.dart index af0c750f..d59a0945 100644 --- a/lib/src/package.dart +++ b/lib/src/package.dart @@ -6,8 +6,9 @@ library pub.package; import 'dart:io'; -import 'package:path/path.dart' as p; import 'package:barback/barback.dart'; +import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; import 'barback/transformer_id.dart'; import 'io.dart'; @@ -15,7 +16,6 @@ import 'git.dart' as git; import 'pubspec.dart'; import 'source_registry.dart'; import 'utils.dart'; -import 'version.dart'; final _README_REGEXP = new RegExp(r"^README($|\.)", caseSensitive: false); diff --git a/lib/src/preprocess.dart b/lib/src/preprocess.dart index ff14738c..a77b9bd2 100644 --- a/lib/src/preprocess.dart +++ b/lib/src/preprocess.dart @@ -4,10 +4,9 @@ library pub.preprocess; +import 'package:pub_semver/pub_semver.dart'; import 'package:string_scanner/string_scanner.dart'; -import 'version.dart'; - /// Runs a simple preprocessor over [input] to remove sections that are /// incompatible with the available barback version. /// diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart index fad03b2a..55b2df7b 100644 --- a/lib/src/pubspec.dart +++ b/lib/src/pubspec.dart @@ -5,6 +5,7 @@ library pub.pubspec; import 'package:path/path.dart' as path; +import 'package:pub_semver/pub_semver.dart'; import 'package:source_span/source_span.dart'; import 'package:yaml/yaml.dart'; @@ -14,7 +15,6 @@ import 'io.dart'; import 'package.dart'; import 'source_registry.dart'; import 'utils.dart'; -import 'version.dart'; /// The parsed contents of a pubspec file. /// diff --git a/lib/src/sdk.dart b/lib/src/sdk.dart index d47cb52a..3d09163b 100644 --- a/lib/src/sdk.dart +++ b/lib/src/sdk.dart @@ -8,9 +8,9 @@ library pub.sdk; import 'dart:io'; import 'package:path/path.dart' as path; +import 'package:pub_semver/pub_semver.dart'; import 'io.dart'; -import 'version.dart'; /// Gets the path to the root directory of the SDK. /// diff --git a/lib/src/solver/backtracking_solver.dart b/lib/src/solver/backtracking_solver.dart index 8f19a662..241fcb6a 100644 --- a/lib/src/solver/backtracking_solver.dart +++ b/lib/src/solver/backtracking_solver.dart @@ -38,6 +38,8 @@ library pub.solver.backtracking_solver; import 'dart:async'; import 'dart:collection' show Queue; +import 'package:pub_semver/pub_semver.dart'; + import '../barback.dart' as barback; import '../exceptions.dart'; import '../lock_file.dart'; @@ -48,7 +50,6 @@ import '../sdk.dart' as sdk; import '../source_registry.dart'; import '../source/unknown.dart'; import '../utils.dart'; -import '../version.dart'; import 'dependency_queue.dart'; import 'version_queue.dart'; import 'version_solver.dart'; diff --git a/lib/src/solver/solve_report.dart b/lib/src/solver/solve_report.dart index 76278a29..2a089b5d 100644 --- a/lib/src/solver/solve_report.dart +++ b/lib/src/solver/solve_report.dart @@ -4,12 +4,13 @@ library pub.solver.solve_report; +import 'package:pub_semver/pub_semver.dart'; + import '../lock_file.dart'; import '../log.dart' as log; import '../package.dart'; import '../source_registry.dart'; import '../utils.dart'; -import '../version.dart'; import 'version_solver.dart'; /// Unlike [SolveResult], which is the static data describing a resolution, diff --git a/lib/src/solver/version_solver.dart b/lib/src/solver/version_solver.dart index 5991c9bd..bc2dfb12 100644 --- a/lib/src/solver/version_solver.dart +++ b/lib/src/solver/version_solver.dart @@ -7,6 +7,7 @@ library pub.solver.version_solver; import 'dart:async'; import "dart:convert"; +import 'package:pub_semver/pub_semver.dart'; import 'package:stack_trace/stack_trace.dart'; import '../exceptions.dart'; @@ -15,7 +16,6 @@ import '../log.dart' as log; import '../package.dart'; import '../pubspec.dart'; import '../source_registry.dart'; -import '../version.dart'; import '../utils.dart'; import 'backtracking_solver.dart'; import 'solve_report.dart'; @@ -226,7 +226,7 @@ class PubspecCache { return source.getVersions(package.name, package.description) .then((versions) { // Sort by priority so we try preferred versions first. - versions.sort(_type == SolveType.DOWNGRADE ? Version.antiPrioritize : + versions.sort(_type == SolveType.DOWNGRADE ? Version.antiprioritize : Version.prioritize); var ids = versions.reversed.map( diff --git a/lib/src/source.dart b/lib/src/source.dart index 4152384e..7affb689 100644 --- a/lib/src/source.dart +++ b/lib/src/source.dart @@ -6,10 +6,11 @@ library pub.source; import 'dart:async'; +import 'package:pub_semver/pub_semver.dart'; + import 'package.dart'; import 'pubspec.dart'; import 'system_cache.dart'; -import 'version.dart'; /// A source from which to get packages. /// diff --git a/lib/src/source/hosted.dart b/lib/src/source/hosted.dart index 2c12dd8c..3bb0ea14 100644 --- a/lib/src/source/hosted.dart +++ b/lib/src/source/hosted.dart @@ -10,6 +10,7 @@ import "dart:convert"; import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; +import 'package:pub_semver/pub_semver.dart'; import '../exceptions.dart'; import '../http.dart'; @@ -18,7 +19,6 @@ import '../log.dart' as log; import '../package.dart'; import '../pubspec.dart'; import '../utils.dart'; -import '../version.dart'; import 'cached.dart'; /// A package source that gets packages from a package hosting site that uses diff --git a/lib/src/validator/dependency.dart b/lib/src/validator/dependency.dart index ac66d324..19f571d1 100644 --- a/lib/src/validator/dependency.dart +++ b/lib/src/validator/dependency.dart @@ -6,11 +6,12 @@ library pub.validator.dependency; import 'dart:async'; +import 'package:pub_semver/pub_semver.dart'; + import '../entrypoint.dart'; import '../log.dart' as log; import '../package.dart'; import '../validator.dart'; -import '../version.dart'; /// A validator that validates a package's dependencies. class DependencyValidator extends Validator { diff --git a/lib/src/version.dart b/lib/src/version.dart deleted file mode 100644 index b68c3eda..00000000 --- a/lib/src/version.dart +++ /dev/null @@ -1,592 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// Handles version numbers, following the [Semantic Versioning][semver] spec. -/// -/// [semver]: http://semver.org/ -library pub.version; - -import 'dart:math'; - -import 'package:collection/equality.dart'; - -/// Regex that matches a version number at the beginning of a string. -final _START_VERSION = new RegExp( - r'^' // Start at beginning. - r'(\d+).(\d+).(\d+)' // Version number. - r'(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?' // Pre-release. - r'(\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?'); // Build. - -/// Like [_START_VERSION] but matches the entire string. -final _COMPLETE_VERSION = new RegExp("${_START_VERSION.pattern}\$"); - -/// Parses a comparison operator ("<", ">", "<=", or ">=") at the beginning of -/// a string. -final _START_COMPARISON = new RegExp(r"^[<>]=?"); - -/// The equality operator to use for comparing version components. -final _equality = const IterableEquality(); - -/// A parsed semantic version number. -class Version implements Comparable<Version>, VersionConstraint { - /// No released version: i.e. "0.0.0". - static Version get none => new Version(0, 0, 0); - - /// Compares [a] and [b] to see which takes priority over the other. - /// - /// Returns `1` if [a] takes priority over [b] and `-1` if vice versa. If - /// [a] and [b] are equivalent, returns `0`. - /// - /// Unlike [compareTo], which *orders* versions, this determines which - /// version a user is likely to prefer. In particular, it prioritizes - /// pre-release versions lower than stable versions, regardless of their - /// version numbers. - /// - /// When used to sort a list, orders in ascending priority so that the - /// highest priority version is *last* in the result. - static int prioritize(Version a, Version b) { - // Sort all prerelease versions after all normal versions. This way - // the solver will prefer stable packages over unstable ones. - if (a.isPreRelease && !b.isPreRelease) return -1; - if (!a.isPreRelease && b.isPreRelease) return 1; - - return a.compareTo(b); - } - - /// Like [proiritize], but lower version numbers are considered greater than - /// higher version numbers. - /// - /// This still considers prerelease versions to be lower than non-prerelease - /// versions. - static int antiPrioritize(Version a, Version b) { - if (a.isPreRelease && !b.isPreRelease) return -1; - if (!a.isPreRelease && b.isPreRelease) return 1; - - return b.compareTo(a); - } - - /// The major version number: "1" in "1.2.3". - final int major; - - /// The minor version number: "2" in "1.2.3". - final int minor; - - /// The patch version number: "3" in "1.2.3". - final int patch; - - /// The pre-release identifier: "foo" in "1.2.3-foo". - /// - /// This is split into a list of components, each of which may be either a - /// string or a non-negative integer. It may also be empty, indicating that - /// this version has no pre-release identifier. - final List preRelease; - - /// The build identifier: "foo" in "1.2.3+foo". - /// - /// This is split into a list of components, each of which may be either a - /// string or a non-negative integer. It may also be empty, indicating that - /// this version has no build identifier. - final List build; - - /// The original string representation of the version number. - /// - /// This preserves textual artifacts like leading zeros that may be left out - /// of the parsed version. - final String _text; - - Version._(this.major, this.minor, this.patch, String preRelease, String build, - this._text) - : preRelease = preRelease == null ? [] : _splitParts(preRelease), - build = build == null ? [] : _splitParts(build) { - if (major < 0) throw new ArgumentError( - 'Major version must be non-negative.'); - if (minor < 0) throw new ArgumentError( - 'Minor version must be non-negative.'); - if (patch < 0) throw new ArgumentError( - 'Patch version must be non-negative.'); - } - - /// Creates a new [Version] object. - factory Version(int major, int minor, int patch, {String pre, String build}) { - var text = "$major.$minor.$patch"; - if (pre != null) text += "-$pre"; - if (build != null) text += "+$build"; - - return new Version._(major, minor, patch, pre, build, text); - } - - /// Creates a new [Version] by parsing [text]. - factory Version.parse(String text) { - final match = _COMPLETE_VERSION.firstMatch(text); - if (match == null) { - throw new FormatException('Could not parse "$text".'); - } - - try { - int major = int.parse(match[1]); - int minor = int.parse(match[2]); - int patch = int.parse(match[3]); - - String preRelease = match[5]; - String build = match[8]; - - return new Version._(major, minor, patch, preRelease, build, text); - } on FormatException catch (ex) { - throw new FormatException('Could not parse "$text".'); - } - } - - /// Returns the primary version out of a list of candidates. - /// - /// This is the highest-numbered stable (non-prerelease) version. If there - /// are no stable versions, it's just the highest-numbered version. - static Version primary(List<Version> versions) { - var primary; - for (var version in versions) { - if (primary == null || (!version.isPreRelease && primary.isPreRelease) || - (version.isPreRelease == primary.isPreRelease && version > primary)) { - primary = version; - } - } - return primary; - } - - /// Splits a string of dot-delimited identifiers into their component parts. - /// - /// Identifiers that are numeric are converted to numbers. - static List _splitParts(String text) { - return text.split('.').map((part) { - try { - return int.parse(part); - } on FormatException catch (ex) { - // Not a number. - return part; - } - }).toList(); - } - - bool operator ==(other) { - if (other is! Version) return false; - return major == other.major && minor == other.minor && - patch == other.patch && - _equality.equals(preRelease, other.preRelease) && - _equality.equals(build, other.build); - } - - int get hashCode => major ^ minor ^ patch ^ _equality.hash(preRelease) ^ - _equality.hash(build); - - bool operator <(Version other) => compareTo(other) < 0; - bool operator >(Version other) => compareTo(other) > 0; - bool operator <=(Version other) => compareTo(other) <= 0; - bool operator >=(Version other) => compareTo(other) >= 0; - - bool get isAny => false; - bool get isEmpty => false; - - /// Whether or not this is a pre-release version. - bool get isPreRelease => preRelease.isNotEmpty; - - /// Gets the next major version number that follows this one. - /// - /// If this version is a pre-release of a major version release (i.e. the - /// minor and patch versions are zero), then it just strips the pre-release - /// suffix. Otherwise, it increments the major version and resets the minor - /// and patch. - Version get nextMajor { - if (isPreRelease && minor == 0 && patch == 0) { - return new Version(major, minor, patch); - } - - return new Version(major + 1, 0, 0); - } - - /// Gets the next minor version number that follows this one. - /// - /// If this version is a pre-release of a minor version release (i.e. the - /// patch version is zero), then it just strips the pre-release suffix. - /// Otherwise, it increments the minor version and resets the patch. - Version get nextMinor { - if (isPreRelease && patch == 0) { - return new Version(major, minor, patch); - } - - return new Version(major, minor + 1, 0); - } - - /// Gets the next patch version number that follows this one. - /// - /// If this version is a pre-release, then it just strips the pre-release - /// suffix. Otherwise, it increments the patch version. - Version get nextPatch { - if (isPreRelease) { - return new Version(major, minor, patch); - } - - return new Version(major, minor, patch + 1); - } - - /// Tests if [other] matches this version exactly. - bool allows(Version other) => this == other; - - VersionConstraint intersect(VersionConstraint other) { - if (other.isEmpty) return other; - - // Intersect a version and a range. - if (other is VersionRange) return other.intersect(this); - - // Intersecting two versions only works if they are the same. - if (other is Version) { - return this == other ? this : VersionConstraint.empty; - } - - throw new ArgumentError( - 'Unknown VersionConstraint type $other.'); - } - - int compareTo(Version other) { - if (major != other.major) return major.compareTo(other.major); - if (minor != other.minor) return minor.compareTo(other.minor); - if (patch != other.patch) return patch.compareTo(other.patch); - - // Pre-releases always come before no pre-release string. - if (!isPreRelease && other.isPreRelease) return 1; - if (!other.isPreRelease && isPreRelease) return -1; - - var comparison = _compareLists(preRelease, other.preRelease); - if (comparison != 0) return comparison; - - // Builds always come after no build string. - if (build.isEmpty && other.build.isNotEmpty) return -1; - if (other.build.isEmpty && build.isNotEmpty) return 1; - return _compareLists(build, other.build); - } - - String toString() => _text; - - /// Compares a dot-separated component of two versions. - /// - /// This is used for the pre-release and build version parts. This follows - /// Rule 12 of the Semantic Versioning spec (v2.0.0-rc.1). - int _compareLists(List a, List b) { - for (var i = 0; i < max(a.length, b.length); i++) { - var aPart = (i < a.length) ? a[i] : null; - var bPart = (i < b.length) ? b[i] : null; - - if (aPart == bPart) continue; - - // Missing parts come before present ones. - if (aPart == null) return -1; - if (bPart == null) return 1; - - if (aPart is num) { - if (bPart is num) { - // Compare two numbers. - return aPart.compareTo(bPart); - } else { - // Numbers come before strings. - return -1; - } - } else { - if (bPart is num) { - // Strings come after numbers. - return 1; - } else { - // Compare two strings. - return aPart.compareTo(bPart); - } - } - } - - // The lists are entirely equal. - return 0; - } -} - -/// A [VersionConstraint] is a predicate that can determine whether a given -/// version is valid or not. -/// -/// For example, a ">= 2.0.0" constraint allows any version that is "2.0.0" or -/// greater. Version objects themselves implement this to match a specific -/// version. -abstract class VersionConstraint { - /// A [VersionConstraint] that allows all versions. - static VersionConstraint any = new VersionRange(); - - /// A [VersionConstraint] that allows no versions: i.e. the empty set. - static VersionConstraint empty = const _EmptyVersion(); - - /// Parses a version constraint. - /// - /// This string is either "any" or a series of version parts. Each part can - /// be one of: - /// - /// * A version string like `1.2.3`. In other words, anything that can be - /// parsed by [Version.parse()]. - /// * A comparison operator (`<`, `>`, `<=`, or `>=`) followed by a version - /// string. - /// - /// Whitespace is ignored. - /// - /// Examples: - /// - /// any - /// 1.2.3-alpha - /// <=5.1.4 - /// >2.0.4 <= 2.4.6 - factory VersionConstraint.parse(String text) { - // Handle the "any" constraint. - if (text.trim() == "any") return new VersionRange(); - - var originalText = text; - var constraints = <VersionConstraint>[]; - - void skipWhitespace() { - text = text.trim(); - } - - // Try to parse and consume a version number. - Version matchVersion() { - var version = _START_VERSION.firstMatch(text); - if (version == null) return null; - - text = text.substring(version.end); - return new Version.parse(version[0]); - } - - // Try to parse and consume a comparison operator followed by a version. - VersionConstraint matchComparison() { - var comparison = _START_COMPARISON.firstMatch(text); - if (comparison == null) return null; - - var op = comparison[0]; - text = text.substring(comparison.end); - skipWhitespace(); - - var version = matchVersion(); - if (version == null) { - throw new FormatException('Expected version number after "$op" in ' - '"$originalText", got "$text".'); - } - - switch (op) { - case '<=': - return new VersionRange(max: version, includeMax: true); - case '<': - return new VersionRange(max: version, includeMax: false); - case '>=': - return new VersionRange(min: version, includeMin: true); - case '>': - return new VersionRange(min: version, includeMin: false); - } - throw "Unreachable."; - } - - while (true) { - skipWhitespace(); - if (text.isEmpty) break; - - var version = matchVersion(); - if (version != null) { - constraints.add(version); - continue; - } - - var comparison = matchComparison(); - if (comparison != null) { - constraints.add(comparison); - continue; - } - - // If we got here, we couldn't parse the remaining string. - throw new FormatException('Could not parse version "$originalText". ' - 'Unknown text at "$text".'); - } - - if (constraints.isEmpty) { - throw new FormatException('Cannot parse an empty string.'); - } - - return new VersionConstraint.intersection(constraints); - } - - /// Creates a new version constraint that is the intersection of - /// [constraints]. - /// - /// It only allows versions that all of those constraints allow. If - /// constraints is empty, then it returns a VersionConstraint that allows - /// all versions. - factory VersionConstraint.intersection( - Iterable<VersionConstraint> constraints) { - var constraint = new VersionRange(); - for (var other in constraints) { - constraint = constraint.intersect(other); - } - return constraint; - } - - /// Returns `true` if this constraint allows no versions. - bool get isEmpty; - - /// Returns `true` if this constraint allows all versions. - bool get isAny; - - /// Returns `true` if this constraint allows [version]. - bool allows(Version version); - - /// Creates a new [VersionConstraint] that only allows [Version]s allowed by - /// both this and [other]. - VersionConstraint intersect(VersionConstraint other); -} - -/// Constrains versions to a fall within a given range. -/// -/// If there is a minimum, then this only allows versions that are at that -/// minimum or greater. If there is a maximum, then only versions less than -/// that are allowed. In other words, this allows `>= min, < max`. -class VersionRange implements VersionConstraint { - final Version min; - final Version max; - final bool includeMin; - final bool includeMax; - - VersionRange({this.min, this.max, - this.includeMin: false, this.includeMax: false}) { - if (min != null && max != null && min > max) { - throw new ArgumentError( - 'Minimum version ("$min") must be less than maximum ("$max").'); - } - } - - bool operator ==(other) { - if (other is! VersionRange) return false; - - return min == other.min && - max == other.max && - includeMin == other.includeMin && - includeMax == other.includeMax; - } - - bool get isEmpty => false; - - bool get isAny => min == null && max == null; - - /// Tests if [other] matches falls within this version range. - bool allows(Version other) { - if (min != null) { - if (other < min) return false; - if (!includeMin && other == min) return false; - } - - if (max != null) { - if (other > max) return false; - if (!includeMax && other == max) return false; - - // If the max isn't itself a pre-release, don't allow any pre-release - // versions of the max. - // - // See: https://www.npmjs.org/doc/misc/semver.html - if (!includeMax && - !max.isPreRelease && other.isPreRelease && - other.major == max.major && other.minor == max.minor && - other.patch == max.patch) { - return false; - } - } - - return true; - } - - VersionConstraint intersect(VersionConstraint other) { - if (other.isEmpty) return other; - - // A range and a Version just yields the version if it's in the range. - if (other is Version) { - return allows(other) ? other : VersionConstraint.empty; - } - - if (other is VersionRange) { - // Intersect the two ranges. - var intersectMin = min; - var intersectIncludeMin = includeMin; - var intersectMax = max; - var intersectIncludeMax = includeMax; - - if (other.min == null) { - // Do nothing. - } else if (intersectMin == null || intersectMin < other.min) { - intersectMin = other.min; - intersectIncludeMin = other.includeMin; - } else if (intersectMin == other.min && !other.includeMin) { - // The edges are the same, but one is exclusive, make it exclusive. - intersectIncludeMin = false; - } - - if (other.max == null) { - // Do nothing. - } else if (intersectMax == null || intersectMax > other.max) { - intersectMax = other.max; - intersectIncludeMax = other.includeMax; - } else if (intersectMax == other.max && !other.includeMax) { - // The edges are the same, but one is exclusive, make it exclusive. - intersectIncludeMax = false; - } - - if (intersectMin == null && intersectMax == null) { - // Open range. - return new VersionRange(); - } - - // If the range is just a single version. - if (intersectMin == intersectMax) { - // If both ends are inclusive, allow that version. - if (intersectIncludeMin && intersectIncludeMax) return intersectMin; - - // Otherwise, no versions. - return VersionConstraint.empty; - } - - if (intersectMin != null && intersectMax != null && - intersectMin > intersectMax) { - // Non-overlapping ranges, so empty. - return VersionConstraint.empty; - } - - // If we got here, there is an actual range. - return new VersionRange(min: intersectMin, max: intersectMax, - includeMin: intersectIncludeMin, includeMax: intersectIncludeMax); - } - - throw new ArgumentError( - 'Unknown VersionConstraint type $other.'); - } - - String toString() { - var buffer = new StringBuffer(); - - if (min != null) { - buffer.write(includeMin ? '>=' : '>'); - buffer.write(min); - } - - if (max != null) { - if (min != null) buffer.write(' '); - buffer.write(includeMax ? '<=' : '<'); - buffer.write(max); - } - - if (min == null && max == null) buffer.write('any'); - return buffer.toString(); - } -} - -class _EmptyVersion implements VersionConstraint { - const _EmptyVersion(); - - bool get isEmpty => true; - bool get isAny => false; - bool allows(Version other) => false; - VersionConstraint intersect(VersionConstraint other) => this; - String toString() => '<empty>'; -} diff --git a/test/implicit_barback_dependency_test.dart b/test/implicit_barback_dependency_test.dart index 6965fcde..9b787747 100644 --- a/test/implicit_barback_dependency_test.dart +++ b/test/implicit_barback_dependency_test.dart @@ -2,10 +2,11 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:pub_semver/pub_semver.dart'; + import 'descriptor.dart' as d; import 'test_pub.dart'; import '../lib/src/barback.dart' as barback; -import '../lib/src/version.dart'; main() { initConfig(); diff --git a/test/implicit_dependency_test.dart b/test/implicit_dependency_test.dart index 34e133f8..0a675667 100644 --- a/test/implicit_dependency_test.dart +++ b/test/implicit_dependency_test.dart @@ -2,10 +2,11 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:pub_semver/pub_semver.dart'; + import 'descriptor.dart' as d; import 'test_pub.dart'; import '../lib/src/barback.dart' as barback; -import '../lib/src/version.dart'; main() { initConfig(); diff --git a/test/lock_file_test.dart b/test/lock_file_test.dart index 68d04ce0..a2ce2f7a 100644 --- a/test/lock_file_test.dart +++ b/test/lock_file_test.dart @@ -6,6 +6,7 @@ library lock_file_test; import 'dart:async'; +import 'package:pub_semver/pub_semver.dart'; import 'package:unittest/unittest.dart'; import 'package:yaml/yaml.dart'; @@ -14,7 +15,6 @@ import '../lib/src/package.dart'; import '../lib/src/pubspec.dart'; import '../lib/src/source.dart'; import '../lib/src/source_registry.dart'; -import '../lib/src/version.dart'; import 'test_pub.dart'; class MockSource extends Source { diff --git a/test/preprocess_test.dart b/test/preprocess_test.dart index 98aef17b..4f43dd81 100644 --- a/test/preprocess_test.dart +++ b/test/preprocess_test.dart @@ -4,10 +4,10 @@ library pub.test.preprocess_test; +import 'package:pub_semver/pub_semver.dart'; import 'package:unittest/unittest.dart'; import '../lib/src/preprocess.dart'; -import '../lib/src/version.dart'; import 'test_pub.dart'; main() { diff --git a/test/pubspec_test.dart b/test/pubspec_test.dart index fec3077d..67f92766 100644 --- a/test/pubspec_test.dart +++ b/test/pubspec_test.dart @@ -6,13 +6,13 @@ library pubspec_test; import 'dart:async'; +import 'package:pub_semver/pub_semver.dart'; import 'package:unittest/unittest.dart'; import '../lib/src/package.dart'; import '../lib/src/pubspec.dart'; import '../lib/src/source.dart'; import '../lib/src/source_registry.dart'; -import '../lib/src/version.dart'; import 'test_pub.dart'; class MockSource extends Source { diff --git a/test/serve_packages.dart b/test/serve_packages.dart index 92a319ee..607efd38 100644 --- a/test/serve_packages.dart +++ b/test/serve_packages.dart @@ -8,12 +8,12 @@ import 'dart:async'; import 'dart:convert'; import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; import 'package:scheduled_test/scheduled_test.dart'; import 'package:yaml/yaml.dart'; import '../lib/src/io.dart'; import '../lib/src/utils.dart'; -import '../lib/src/version.dart'; import 'descriptor.dart' as d; import 'test_pub.dart'; diff --git a/test/test_pub.dart b/test/test_pub.dart index c60d1bbe..6a6fec12 100644 --- a/test/test_pub.dart +++ b/test/test_pub.dart @@ -16,6 +16,7 @@ import 'dart:math'; import 'package:http/testing.dart'; import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; import 'package:scheduled_test/scheduled_process.dart'; import 'package:scheduled_test/scheduled_server.dart'; import 'package:scheduled_test/scheduled_stream.dart'; @@ -43,7 +44,6 @@ import '../lib/src/source_registry.dart'; import '../lib/src/system_cache.dart'; import '../lib/src/utils.dart'; import '../lib/src/validator.dart'; -import '../lib/src/version.dart'; import 'descriptor.dart' as d; import 'serve_packages.dart'; diff --git a/test/version_solver_test.dart b/test/version_solver_test.dart index 7673fde1..cdadb67f 100644 --- a/test/version_solver_test.dart +++ b/test/version_solver_test.dart @@ -6,6 +6,7 @@ library pub_upgrade_test; import 'dart:async'; +import 'package:pub_semver/pub_semver.dart'; import 'package:unittest/unittest.dart'; import '../lib/src/lock_file.dart'; @@ -16,7 +17,6 @@ import '../lib/src/sdk.dart' as sdk; import '../lib/src/source/cached.dart'; import '../lib/src/system_cache.dart'; import '../lib/src/utils.dart'; -import '../lib/src/version.dart'; import '../lib/src/solver/version_solver.dart'; import 'test_pub.dart'; diff --git a/test/version_test.dart b/test/version_test.dart deleted file mode 100644 index 0bfe60eb..00000000 --- a/test/version_test.dart +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -library version_test; - -import 'package:unittest/unittest.dart'; -import 'test_pub.dart'; -import '../lib/src/version.dart'; - -main() { - initConfig(); - - final v114 = new Version.parse('1.1.4'); - final v123 = new Version.parse('1.2.3'); - final v124 = new Version.parse('1.2.4'); - final v130 = new Version.parse('1.3.0'); - final v140 = new Version.parse('1.4.0'); - final v200 = new Version.parse('2.0.0'); - final v201 = new Version.parse('2.0.1'); - final v234 = new Version.parse('2.3.4'); - final v250 = new Version.parse('2.5.0'); - final v300 = new Version.parse('3.0.0'); - - group('Version', () { - test('none', () { - expect(Version.none.toString(), equals('0.0.0')); - }); - - group('constructor', () { - test('throws on negative numbers', () { - throwsIllegalArg(() => new Version(-1, 1, 1)); - throwsIllegalArg(() => new Version(1, -1, 1)); - throwsIllegalArg(() => new Version(1, 1, -1)); - }); - }); - - group('comparison', () { - // A correctly sorted list of versions. - var versions = [ - '1.0.0-alpha', - '1.0.0-alpha.1', - '1.0.0-beta.2', - '1.0.0-beta.11', - '1.0.0-rc.1', - '1.0.0-rc.1+build.1', - '1.0.0', - '1.0.0+0.3.7', - '1.3.7+build', - '1.3.7+build.2.b8f12d7', - '1.3.7+build.11.e0f985a', - '2.0.0', - '2.1.0', - '2.2.0', - '2.11.0', - '2.11.1' - ]; - - test('compareTo()', () { - // Ensure that every pair of versions compares in the order that it - // appears in the list. - for (var i = 0; i < versions.length; i++) { - for (var j = 0; j < versions.length; j++) { - var a = new Version.parse(versions[i]); - var b = new Version.parse(versions[j]); - var expectation = i.compareTo(j); - expect(a.compareTo(b), equals(expectation)); - } - } - }); - - test('operators', () { - for (var i = 0; i < versions.length; i++) { - for (var j = 0; j < versions.length; j++) { - var a = new Version.parse(versions[i]); - var b = new Version.parse(versions[j]); - expect(a < b, equals(i < j)); - expect(a > b, equals(i > j)); - expect(a <= b, equals(i <= j)); - expect(a >= b, equals(i >= j)); - expect(a == b, equals(i == j)); - expect(a != b, equals(i != j)); - } - } - }); - - test('equality', () { - expect(new Version.parse('01.2.3'), equals(new Version.parse('1.2.3'))); - expect(new Version.parse('1.02.3'), equals(new Version.parse('1.2.3'))); - expect(new Version.parse('1.2.03'), equals(new Version.parse('1.2.3'))); - expect(new Version.parse('1.2.3-01'), - equals(new Version.parse('1.2.3-1'))); - expect(new Version.parse('1.2.3+01'), - equals(new Version.parse('1.2.3+1'))); - }); - }); - - test('allows()', () { - expect(v123.allows(v123), isTrue); - expect(v123.allows(v114), isFalse); - expect(v123.allows(v124), isFalse); - }); - - test('intersect()', () { - // Intersecting the same version returns the version. - expect(v123.intersect(v123), equals(v123)); - - // Intersecting a different version allows no versions. - expect(v123.intersect(v114).isEmpty, isTrue); - - // Intersecting a range returns the version if the range allows it. - expect(v123.intersect(new VersionRange(min: v114, max: v124)), - equals(v123)); - - // Intersecting a range allows no versions if the range doesn't allow it. - expect(v114.intersect(new VersionRange(min: v123, max: v124)).isEmpty, - isTrue); - }); - - test('isEmpty', () { - expect(v123.isEmpty, isFalse); - }); - - test('nextMajor', () { - expect(v123.nextMajor, equals(v200)); - expect(v114.nextMajor, equals(v200)); - expect(v200.nextMajor, equals(v300)); - - // Ignores pre-release if not on a major version. - expect(new Version.parse('1.2.3-dev').nextMajor, equals(v200)); - - // Just removes it if on a major version. - expect(new Version.parse('2.0.0-dev').nextMajor, equals(v200)); - - // Strips build suffix. - expect(new Version.parse('1.2.3+patch').nextMajor, equals(v200)); - }); - - test('nextMinor', () { - expect(v123.nextMinor, equals(v130)); - expect(v130.nextMinor, equals(v140)); - - // Ignores pre-release if not on a minor version. - expect(new Version.parse('1.2.3-dev').nextMinor, equals(v130)); - - // Just removes it if on a minor version. - expect(new Version.parse('1.3.0-dev').nextMinor, equals(v130)); - - // Strips build suffix. - expect(new Version.parse('1.2.3+patch').nextMinor, equals(v130)); - }); - - test('nextPatch', () { - expect(v123.nextPatch, equals(v124)); - expect(v200.nextPatch, equals(v201)); - - // Just removes pre-release version if present. - expect(new Version.parse('1.2.4-dev').nextPatch, equals(v124)); - - // Strips build suffix. - expect(new Version.parse('1.2.3+patch').nextPatch, equals(v124)); - }); - - test('parse()', () { - expect(new Version.parse('0.0.0'), equals(new Version(0, 0, 0))); - expect(new Version.parse('12.34.56'), equals(new Version(12, 34, 56))); - - expect(new Version.parse('1.2.3-alpha.1'), equals( - new Version(1, 2, 3, pre: 'alpha.1'))); - expect(new Version.parse('1.2.3-x.7.z-92'), equals( - new Version(1, 2, 3, pre: 'x.7.z-92'))); - - expect(new Version.parse('1.2.3+build.1'), equals( - new Version(1, 2, 3, build: 'build.1'))); - expect(new Version.parse('1.2.3+x.7.z-92'), equals( - new Version(1, 2, 3, build: 'x.7.z-92'))); - - expect(new Version.parse('1.0.0-rc-1+build-1'), equals( - new Version(1, 0, 0, pre: 'rc-1', build: 'build-1'))); - - expect(() => new Version.parse('1.0'), throwsFormatException); - expect(() => new Version.parse('1.2.3.4'), throwsFormatException); - expect(() => new Version.parse('1234'), throwsFormatException); - expect(() => new Version.parse('-2.3.4'), throwsFormatException); - expect(() => new Version.parse('1.3-pre'), throwsFormatException); - expect(() => new Version.parse('1.3+build'), throwsFormatException); - expect(() => new Version.parse('1.3+bu?!3ild'), throwsFormatException); - }); - - test('toString()', () { - expect(new Version(0, 0, 0).toString(), equals('0.0.0')); - expect(new Version(12, 34, 56).toString(), equals('12.34.56')); - - expect(new Version(1, 2, 3, pre: 'alpha.1').toString(), equals( - '1.2.3-alpha.1')); - expect(new Version(1, 2, 3, pre: 'x.7.z-92').toString(), equals( - '1.2.3-x.7.z-92')); - - expect(new Version(1, 2, 3, build: 'build.1').toString(), equals( - '1.2.3+build.1')); - expect(new Version(1, 2, 3, pre: 'pre', build: 'bui').toString(), equals( - '1.2.3-pre+bui')); - }); - }); - - group('VersionRange', () { - group('constructor', () { - test('takes a min and max', () { - var range = new VersionRange(min: v123, max: v124); - expect(range.isAny, isFalse); - expect(range.min, equals(v123)); - expect(range.max, equals(v124)); - }); - - test('allows omitting max', () { - var range = new VersionRange(min: v123); - expect(range.isAny, isFalse); - expect(range.min, equals(v123)); - expect(range.max, isNull); - }); - - test('allows omitting min and max', () { - var range = new VersionRange(); - expect(range.isAny, isTrue); - expect(range.min, isNull); - expect(range.max, isNull); - }); - - test('takes includeMin', () { - var range = new VersionRange(min: v123, includeMin: true); - expect(range.includeMin, isTrue); - }); - - test('includeMin defaults to false if omitted', () { - var range = new VersionRange(min: v123); - expect(range.includeMin, isFalse); - }); - - test('takes includeMax', () { - var range = new VersionRange(max: v123, includeMax: true); - expect(range.includeMax, isTrue); - }); - - test('includeMax defaults to false if omitted', () { - var range = new VersionRange(max: v123); - expect(range.includeMax, isFalse); - }); - - test('throws if min > max', () { - throwsIllegalArg(() => new VersionRange(min: v124, max: v123)); - }); - }); - - group('allows()', () { - test('version must be greater than min', () { - var range = new VersionRange(min: v123); - - expect(range.allows(new Version.parse('1.2.2')), isFalse); - expect(range.allows(new Version.parse('1.2.3')), isFalse); - expect(range.allows(new Version.parse('1.3.3')), isTrue); - expect(range.allows(new Version.parse('2.3.3')), isTrue); - }); - - test('version must be min or greater if includeMin', () { - var range = new VersionRange(min: v123, includeMin: true); - - expect(range.allows(new Version.parse('1.2.2')), isFalse); - expect(range.allows(new Version.parse('1.2.3')), isTrue); - expect(range.allows(new Version.parse('1.3.3')), isTrue); - expect(range.allows(new Version.parse('2.3.3')), isTrue); - }); - - test('pre-release versions of inclusive min are excluded', () { - var range = new VersionRange(min: v123, includeMin: true); - - expect(range.allows(new Version.parse('1.2.3-dev')), isFalse); - expect(range.allows(new Version.parse('1.2.4-dev')), isTrue); - }); - - test('version must be less than max', () { - var range = new VersionRange(max: v234); - - expect(range.allows(new Version.parse('2.3.3')), isTrue); - expect(range.allows(new Version.parse('2.3.4')), isFalse); - expect(range.allows(new Version.parse('2.4.3')), isFalse); - }); - - test('pre-release versions of non-pre-release max are excluded', () { - var range = new VersionRange(max: v234); - - expect(range.allows(new Version.parse('2.3.3')), isTrue); - expect(range.allows(new Version.parse('2.3.4-dev')), isFalse); - expect(range.allows(new Version.parse('2.3.4')), isFalse); - }); - - test('pre-release versions of pre-release max are included', () { - var range = new VersionRange(max: new Version.parse('2.3.4-dev.2')); - - expect(range.allows(new Version.parse('2.3.4-dev.1')), isTrue); - expect(range.allows(new Version.parse('2.3.4-dev.2')), isFalse); - expect(range.allows(new Version.parse('2.3.4-dev.3')), isFalse); - }); - - test('version must be max or less if includeMax', () { - var range = new VersionRange(min: v123, max: v234, includeMax: true); - - expect(range.allows(new Version.parse('2.3.3')), isTrue); - expect(range.allows(new Version.parse('2.3.4')), isTrue); - expect(range.allows(new Version.parse('2.4.3')), isFalse); - - // Pre-releases of the max are allowed. - expect(range.allows(new Version.parse('2.3.4-dev')), isTrue); - }); - - test('has no min if one was not set', () { - var range = new VersionRange(max: v123); - - expect(range.allows(new Version.parse('0.0.0')), isTrue); - expect(range.allows(new Version.parse('1.2.3')), isFalse); - }); - - test('has no max if one was not set', () { - var range = new VersionRange(min: v123); - - expect(range.allows(new Version.parse('1.2.3')), isFalse); - expect(range.allows(new Version.parse('1.3.3')), isTrue); - expect(range.allows(new Version.parse('999.3.3')), isTrue); - }); - - test('allows any version if there is no min or max', () { - var range = new VersionRange(); - - expect(range.allows(new Version.parse('0.0.0')), isTrue); - expect(range.allows(new Version.parse('999.99.9')), isTrue); - }); - }); - - 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.min, equals(v200)); - expect(intersect.max, equals(v250)); - expect(intersect.includeMin, isFalse); - expect(intersect.includeMax, isFalse); - }); - - test('a non-overlapping range allows no versions', () { - var a = new VersionRange(min: v114, max: v124); - var b = new VersionRange(min: v200, max: v250); - expect(a.intersect(b).isEmpty, isTrue); - }); - - test('adjacent ranges allow no versions if exclusive', () { - var a = new VersionRange(min: v114, max: v124, includeMax: false); - var b = new VersionRange(min: v124, max: v200, includeMin: true); - expect(a.intersect(b).isEmpty, isTrue); - }); - - test('adjacent ranges allow version if inclusive', () { - var a = new VersionRange(min: v114, max: v124, includeMax: true); - var b = new VersionRange(min: v124, max: v200, includeMin: true); - expect(a.intersect(b), equals(v124)); - }); - - test('with an open range', () { - var open = new VersionRange(); - var a = new VersionRange(min: v114, max: v124); - expect(open.intersect(open), equals(open)); - expect(a.intersect(open), equals(a)); - }); - - test('returns the version if the range allows it', () { - expect(new VersionRange(min: v114, max: v124).intersect(v123), - equals(v123)); - expect(new VersionRange(min: v123, max: v124).intersect(v114).isEmpty, - isTrue); - }); - }); - - test('isEmpty', () { - expect(new VersionRange().isEmpty, isFalse); - expect(new VersionRange(min: v123, max: v124).isEmpty, isFalse); - }); - }); - - group('VersionConstraint', () { - test('any', () { - expect(VersionConstraint.any.isAny, isTrue); - expect(VersionConstraint.any, allows([ - new Version.parse('0.0.0-blah'), - new Version.parse('1.2.3'), - new Version.parse('12345.678.90')])); - }); - - test('empty', () { - expect(VersionConstraint.empty.isEmpty, isTrue); - expect(VersionConstraint.empty.isAny, isFalse); - expect(VersionConstraint.empty, doesNotAllow([ - new Version.parse('0.0.0-blah'), - new Version.parse('1.2.3'), - new Version.parse('12345.678.90')])); - }); - - group('parse()', () { - test('parses an exact version', () { - var constraint = new VersionConstraint.parse('1.2.3-alpha'); - expect(constraint is Version, isTrue); - expect(constraint, equals(new Version(1, 2, 3, pre: 'alpha'))); - }); - - test('parses "any"', () { - var constraint = new VersionConstraint.parse('any'); - expect(constraint is VersionConstraint, isTrue); - expect(constraint, allows([ - new Version.parse('0.0.0'), - new Version.parse('1.2.3'), - new Version.parse('12345.678.90')])); - }); - - test('parses a ">" minimum version', () { - expect(new VersionConstraint.parse('>1.2.3'), allows([ - new Version.parse('1.2.3+foo'), - new Version.parse('1.2.4')])); - expect(new VersionConstraint.parse('>1.2.3'), doesNotAllow([ - new Version.parse('1.2.1'), - new Version.parse('1.2.3-build'), - new Version.parse('1.2.3')])); - }); - - test('parses a ">=" minimum version', () { - expect(new VersionConstraint.parse('>=1.2.3'), allows([ - new Version.parse('1.2.3'), - new Version.parse('1.2.3+foo'), - new Version.parse('1.2.4')])); - expect(new VersionConstraint.parse('>=1.2.3'), doesNotAllow([ - new Version.parse('1.2.1'), - new Version.parse('1.2.3-build')])); - }); - - test('parses a "<" maximum version', () { - expect(new VersionConstraint.parse('<1.2.3'), allows([ - new Version.parse('1.2.1'), - new Version.parse('1.2.2+foo')])); - expect(new VersionConstraint.parse('<1.2.3'), doesNotAllow([ - new Version.parse('1.2.3'), - new Version.parse('1.2.3+foo'), - new Version.parse('1.2.4')])); - }); - - test('parses a "<=" maximum version', () { - expect(new VersionConstraint.parse('<=1.2.3'), allows([ - new Version.parse('1.2.1'), - new Version.parse('1.2.3-build'), - new Version.parse('1.2.3')])); - expect(new VersionConstraint.parse('<=1.2.3'), doesNotAllow([ - new Version.parse('1.2.3+foo'), - new Version.parse('1.2.4')])); - }); - - test('parses a series of space-separated constraints', () { - var constraint = new VersionConstraint.parse('>1.0.0 >=1.2.3 <1.3.0'); - expect(constraint, allows([ - new Version.parse('1.2.3'), - new Version.parse('1.2.5')])); - expect(constraint, doesNotAllow([ - new Version.parse('1.2.3-pre'), - new Version.parse('1.3.0'), - new Version.parse('3.4.5')])); - }); - - test('ignores whitespace around operators', () { - var constraint = new VersionConstraint.parse(' >1.0.0>=1.2.3 < 1.3.0'); - expect(constraint, allows([ - new Version.parse('1.2.3'), - new Version.parse('1.2.5')])); - expect(constraint, doesNotAllow([ - new Version.parse('1.2.3-pre'), - new Version.parse('1.3.0'), - new Version.parse('3.4.5')])); - }); - - test('does not allow "any" to be mixed with other constraints', () { - expect(() => new VersionConstraint.parse('any 1.0.0'), - throwsFormatException); - }); - - test('throws FormatException on a bad string', () { - var bad = [ - "", " ", // Empty string. - "foo", // Bad text. - ">foo", // Bad text after operator. - "1.0.0 foo", "1.0.0foo", // Bad text after version. - "anything", // Bad text after "any". - "<>1.0.0", // Multiple operators. - "1.0.0<" // Trailing operator. - ]; - - for (var text in bad) { - expect(() => new VersionConstraint.parse(text), - throwsFormatException); - } - }); - }); - }); -} - -class VersionConstraintMatcher implements Matcher { - final List<Version> _expected; - final bool _allow; - - VersionConstraintMatcher(this._expected, this._allow); - - bool matches(item, Map matchState) => (item is VersionConstraint) && - _expected.every((version) => item.allows(version) == _allow); - - Description describe(Description description) => - description.add(' ${_allow ? "allows" : "does not allow"} versions'); - - Description describeMismatch(item, Description mismatchDescription, - Map matchState, bool verbose) { - if (item is! VersionConstraint) { - mismatchDescription.add('was not a VersionConstraint'); - return mismatchDescription; - } - - bool first = true; - for (var version in _expected) { - if (item.allows(version) != _allow) { - if (first) { - if (_allow) { - mismatchDescription.addDescriptionOf(item).add('did not allow '); - } else { - mismatchDescription.addDescriptionOf(item).add('allowed '); - } - } else { - mismatchDescription.add(' and '); - } - first = false; - - mismatchDescription.add(version.toString()); - } - } - - return mismatchDescription; - } -} - -Matcher allows(List<Version> versions) => - new VersionConstraintMatcher(versions, true); - -Matcher doesNotAllow(List<Version> versions) => - new VersionConstraintMatcher(versions, false); - -throwsIllegalArg(function) { - expect(function, throwsA((e) => e is ArgumentError)); -} -- GitLab