Make >=2.12 <3.0.0 compatible with dart 3 (#3572)
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart index 36f8047..2683cdf 100644 --- a/lib/src/entrypoint.dart +++ b/lib/src/entrypoint.dart
@@ -20,7 +20,6 @@ import 'exceptions.dart'; import 'executable.dart'; import 'io.dart'; -import 'language_version.dart'; import 'lock_file.dart'; import 'log.dart' as log; import 'package.dart'; @@ -281,7 +280,8 @@ await lockFile.packageConfigFile( cache, entrypoint: entrypointName, - entrypointSdkConstraint: root.pubspec.sdkConstraints[sdk.identifier], + entrypointSdkConstraint: + root.pubspec.sdkConstraints[sdk.identifier]?.effectiveConstraint, relativeFrom: isGlobal ? null : root.dir, ), ); @@ -816,9 +816,7 @@ try { // Load `pubspec.yaml` and extract language version to compare with the // language version from `package_config.json`. - final languageVersion = LanguageVersion.fromSdkConstraint( - cache.load(id).pubspec.sdkConstraints[sdk.identifier], - ); + final languageVersion = cache.load(id).pubspec.languageVersion; if (pkg.languageVersion != languageVersion) { final relativePubspecPath = p.join( cache.getDirectory(id, relativeFrom: '.'), @@ -874,7 +872,7 @@ /// /// We don't allow unknown sdks. void _checkSdkConstraint(Pubspec pubspec) { - final dartSdkConstraint = pubspec.sdkConstraints['dart']; + final dartSdkConstraint = pubspec.dartSdkConstraint.effectiveConstraint; if (dartSdkConstraint is! VersionRange || dartSdkConstraint.min == null) { // Suggest version range '>=2.10.0 <3.0.0', we avoid using: // [CompatibleWithVersionRange] because some pub versions don't support
diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart index bb97023..d8cdef6 100644 --- a/lib/src/global_packages.dart +++ b/lib/src/global_packages.dart
@@ -362,7 +362,9 @@ dataError('${log.bold(name)} ${entrypoint.root.version} requires ' 'unknown SDK "$name".'); } else if (sdkName == 'dart') { - if (constraint.allows((sdk as DartSdk).version)) return; + if (constraint.effectiveConstraint.allows((sdk as DartSdk).version)) { + return; + } dataError("${log.bold(name)} ${entrypoint.root.version} doesn't " 'support Dart ${sdk.version}.'); } else {
diff --git a/lib/src/lock_file.dart b/lib/src/lock_file.dart index f133172..6c66224 100644 --- a/lib/src/lock_file.dart +++ b/lib/src/lock_file.dart
@@ -306,12 +306,11 @@ rootUri = p.toUri(rootPath); } final pubspec = await cache.describe(id); - final sdkConstraint = pubspec.sdkConstraints[sdk.identifier]; entries.add(PackageConfigEntry( name: name, rootUri: rootUri, packageUri: p.toUri('lib/'), - languageVersion: LanguageVersion.fromSdkConstraint(sdkConstraint), + languageVersion: pubspec.languageVersion, )); }
diff --git a/lib/src/null_safety_analysis.dart b/lib/src/null_safety_analysis.dart index fe89b55..284e845 100644 --- a/lib/src/null_safety_analysis.dart +++ b/lib/src/null_safety_analysis.dart
@@ -91,7 +91,7 @@ } }, sources: _systemCache.sources, - sdkConstraints: {'dart': rootPubspec.sdkConstraints['dart']!})); + sdkConstraints: {'dart': rootPubspec.dartSdkConstraint})); final rootLanguageVersion = rootPubspec.languageVersion; if (!rootLanguageVersion.supportsNullSafety) {
diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart index 6e1d566..69b5557 100644 --- a/lib/src/pubspec.dart +++ b/lib/src/pubspec.dart
@@ -120,6 +120,9 @@ Map<String, PackageRange>? _devDependencies; + /// The Dart sdk version this is parsed against. + final Version _dartSdkVersion; + /// The dependency constraints that this package overrides when it is the /// root package. /// @@ -163,13 +166,13 @@ Map<String, PackageRange>? _dependencyOverrides; - /// A map from SDK identifiers to constraints on those SDK versions. - Map<String, VersionConstraint> get sdkConstraints { - _ensureEnvironment(); - return _sdkConstraints!; - } + SdkConstraint get dartSdkConstraint => sdkConstraints['dart']!; - Map<String, VersionConstraint>? _sdkConstraints; + /// A map from SDK identifiers to constraints on those SDK versions. + late final Map<String, SdkConstraint> sdkConstraints = + _givenSdkConstraints ?? UnmodifiableMapView(_parseEnvironment(fields)); + + final Map<String, SdkConstraint>? _givenSdkConstraints; /// Whether or not to apply the [_defaultUpperBoundsSdkConstraint] to this /// pubspec. @@ -177,41 +180,8 @@ /// Whether or not the SDK version was overridden from <2.0.0 to /// <2.0.0-dev.infinity. - bool get dartSdkWasOverridden => _dartSdkWasOverridden; - bool _dartSdkWasOverridden = false; - - /// The original Dart SDK constraint as written in the pubspec. - /// - /// If [dartSdkWasOverridden] is `false`, this will be identical to - /// `sdkConstraints["dart"]`. - VersionConstraint get originalDartSdkConstraint { - _ensureEnvironment(); - return _originalDartSdkConstraint ?? sdkConstraints['dart']!; - } - - VersionConstraint? _originalDartSdkConstraint; - - /// Ensures that the top-level "environment" field has been parsed and - /// [_sdkConstraints] is set accordingly. - void _ensureEnvironment() { - if (_sdkConstraints != null) return; - - var sdkConstraints = _parseEnvironment(fields); - var parsedDartSdkConstraint = sdkConstraints['dart']; - - if (parsedDartSdkConstraint is VersionRange && - _shouldEnableCurrentSdk(parsedDartSdkConstraint)) { - _originalDartSdkConstraint = parsedDartSdkConstraint; - _dartSdkWasOverridden = true; - sdkConstraints['dart'] = VersionRange( - min: parsedDartSdkConstraint.min, - includeMin: parsedDartSdkConstraint.includeMin, - max: sdk.version, - includeMax: true); - } - - _sdkConstraints = UnmodifiableMapView(sdkConstraints); - } + bool get dartSdkWasOverridden => _dartSdkWasOverriddenToAllowPrerelease; + bool _dartSdkWasOverriddenToAllowPrerelease = false; /// Whether or not we should override [sdkConstraint] to be <= the user's /// current SDK version. @@ -227,12 +197,12 @@ /// patch versions as the user's current SDK. bool _shouldEnableCurrentSdk(VersionRange sdkConstraint) { if (!_allowPreReleaseSdk) return false; - if (!sdk.version.isPreRelease) return false; + if (!_dartSdkVersion.isPreRelease) return false; if (sdkConstraint.includeMax) return false; var minSdkConstraint = sdkConstraint.min; if (minSdkConstraint != null && minSdkConstraint.isPreRelease && - equalsIgnoringPreRelease(sdkConstraint.min!, sdk.version)) { + equalsIgnoringPreRelease(sdkConstraint.min!, _dartSdkVersion)) { return false; } var maxSdkConstraint = sdkConstraint.max; @@ -241,54 +211,121 @@ !maxSdkConstraint.isFirstPreRelease) { return false; } - return equalsIgnoringPreRelease(maxSdkConstraint, sdk.version); + return equalsIgnoringPreRelease(maxSdkConstraint, _dartSdkVersion); + } + + SdkConstraint _interpretDartSdkConstraint( + VersionConstraint originalConstraint, { + required VersionConstraint? defaultUpperBoundConstraint, + }) { + VersionConstraint constraint = originalConstraint; + if (constraint is VersionRange && _shouldEnableCurrentSdk(constraint)) { + _dartSdkWasOverriddenToAllowPrerelease = true; + constraint = VersionRange( + min: constraint.min, + includeMin: constraint.includeMin, + max: _dartSdkVersion, + includeMax: true); + } + if (defaultUpperBoundConstraint != null && + constraint is VersionRange && + constraint.max == null && + defaultUpperBoundConstraint.allowsAny(constraint)) { + constraint = VersionConstraint.intersection( + [constraint, defaultUpperBoundConstraint]); + } + // If a package is null safe it should also be compatible with dart 3. + // Therefore we rewrite a null-safety enabled constraint with the upper + // bound <3.0.0 to be have upper bound <4.0.0 + if (constraint is VersionRange && + LanguageVersion.fromSdkConstraint(constraint) >= + LanguageVersion.firstVersionWithNullSafety && + // <3.0.0 is parsed into a max of 3.0.0-0, so that is what we look for + // here. + constraint.max == Version(3, 0, 0).firstPreRelease && + constraint.includeMax == false) { + constraint = VersionRange( + min: constraint.min, + includeMin: constraint.includeMin, + // We don't have to use .firstPreRelease as the constructor will do that + // if needed. + max: Version(4, 0, 0), + ); + } + return SdkConstraint(constraint, originalConstraint: originalConstraint); + } + + // Flutter constraints get special treatment, as Flutter won't be using + // semantic versioning to mark breaking releases. We simply ignore upper + // bounds. + SdkConstraint _interpretFlutterSdkConstraint(VersionConstraint constraint) { + if (constraint is VersionRange) { + return SdkConstraint( + VersionRange(min: constraint.min, includeMin: constraint.includeMin), + originalConstraint: constraint, + ); + } + return SdkConstraint(constraint); } /// Parses the "environment" field in [parent] and returns a map from SDK /// identifiers to constraints on those SDKs. - Map<String, VersionConstraint> _parseEnvironment(YamlMap parent) { + Map<String, SdkConstraint> _parseEnvironment(YamlMap parent) { var yaml = parent['environment']; + final VersionConstraint originalDartSdkConstraint; if (yaml == null) { - return { - 'dart': _includeDefaultSdkConstraint - ? _defaultUpperBoundSdkConstraint - : VersionConstraint.any - }; - } - - if (yaml is! YamlMap) { + originalDartSdkConstraint = _includeDefaultSdkConstraint + ? _defaultUpperBoundSdkConstraint + : VersionConstraint.any; + } else if (yaml is! YamlMap) { _error('"environment" field must be a map.', parent.nodes['environment']!.span); + } else { + originalDartSdkConstraint = _parseVersionConstraint( + yaml.nodes['sdk'], + _packageName, + _FileType.pubspec, + ); } var constraints = { - 'dart': _parseVersionConstraint( - yaml.nodes['sdk'], _packageName, _FileType.pubspec, - defaultUpperBoundConstraint: _includeDefaultSdkConstraint - ? _defaultUpperBoundSdkConstraint - : null) + 'dart': _interpretDartSdkConstraint( + originalDartSdkConstraint, + defaultUpperBoundConstraint: _includeDefaultSdkConstraint + ? _defaultUpperBoundSdkConstraint + : null, + ) }; - yaml.nodes.forEach((name, constraint) { - if (name.value is! String) { - _error('SDK names must be strings.', name.span); - } else if (name.value == 'dart') { - _error('Use "sdk" to for Dart SDK constraints.', name.span); - } - if (name.value == 'sdk') return; - constraints[name.value as String] = - _parseVersionConstraint(constraint, _packageName, _FileType.pubspec, - // Flutter constraints get special treatment, as Flutter won't be - // using semantic versioning to mark breaking releases. - ignoreUpperBound: name.value == 'flutter'); - }); + if (yaml is YamlMap) { + yaml.nodes.forEach((nameNode, constraintNode) { + final name = nameNode.value; + if (name is! String) { + _error('SDK names must be strings.', nameNode.span); + } else if (name == 'dart') { + _error('Use "sdk" to for Dart SDK constraints.', nameNode.span); + } + if (name == 'sdk') return; + final constraint = _parseVersionConstraint( + constraintNode, + _packageName, + _FileType.pubspec, + ); + constraints[name] = name == 'flutter' + ? _interpretFlutterSdkConstraint(constraint) + : SdkConstraint(constraint); + }); + } return constraints; } /// The language version implied by the sdk constraint. - LanguageVersion get languageVersion => - LanguageVersion.fromSdkConstraint(originalDartSdkConstraint); + LanguageVersion get languageVersion { + return LanguageVersion.fromSdkConstraint( + dartSdkConstraint.originalConstraint, + ); + } /// Loads the pubspec for a package located in [packageDir]. /// @@ -332,7 +369,8 @@ Iterable<PackageRange>? dependencyOverrides, Map? fields, SourceRegistry? sources, - Map<String, VersionConstraint>? sdkConstraints, + Map<String, SdkConstraint>? sdkConstraints, + Version? dartSdkVersion, }) : _dependencies = dependencies == null ? null : Map.fromIterable(dependencies, key: (range) => range.name), @@ -342,12 +380,13 @@ _dependencyOverrides = dependencyOverrides == null ? null : Map.fromIterable(dependencyOverrides, key: (range) => range.name), - _sdkConstraints = sdkConstraints ?? - UnmodifiableMapView({'dart': VersionConstraint.any}), + _givenSdkConstraints = sdkConstraints ?? + UnmodifiableMapView({'dart': SdkConstraint(VersionConstraint.any)}), _includeDefaultSdkConstraint = false, _sources = sources ?? ((String? name) => throw StateError('No source registry given')), _overridesFileFields = null, + _dartSdkVersion = dartSdkVersion ?? sdk.version, super( fields == null ? YamlMap() : YamlMap.wrap(fields), name: name, @@ -361,10 +400,17 @@ /// field, this will throw a [PubspecError]. /// /// [location] is the location from which this pubspec was loaded. - Pubspec.fromMap(Map fields, this._sources, - {YamlMap? overridesFields, String? expectedName, Uri? location}) - : _overridesFileFields = overridesFields, + Pubspec.fromMap( + Map fields, + this._sources, { + YamlMap? overridesFields, + String? expectedName, + Uri? location, + Version? dartSdkVersion, + }) : _overridesFileFields = overridesFields, _includeDefaultSdkConstraint = true, + _givenSdkConstraints = null, + _dartSdkVersion = dartSdkVersion ?? sdk.version, super(fields is YamlMap ? fields : YamlMap.wrap(fields, sourceUrl: location)) { @@ -390,6 +436,7 @@ Uri? location, String? overridesFileContents, Uri? overridesLocation, + Version? dartSdkVersion, }) { late final YamlMap pubspecMap; YamlMap? overridesFileMap; @@ -403,10 +450,14 @@ throw SourceSpanApplicationException(error.message, error.span); } - return Pubspec.fromMap(pubspecMap, sources, - overridesFields: overridesFileMap, - expectedName: expectedName, - location: location); + return Pubspec.fromMap( + pubspecMap, + sources, + overridesFields: overridesFileMap, + expectedName: expectedName, + location: location, + dartSdkVersion: dartSdkVersion, + ); } /// Ensures that [node] is a mapping. @@ -445,7 +496,7 @@ collectError(() => publishTo); collectError(() => executables); collectError(() => falseSecrets); - collectError(_ensureEnvironment); + collectError(() => sdkConstraints); return errors; } } @@ -558,17 +609,13 @@ /// Parses [node] to a [VersionConstraint]. /// -/// If or [defaultUpperBoundConstraint] is specified then it will be set as -/// the max constraint if the original constraint doesn't have an upper -/// bound and it is compatible with [defaultUpperBoundConstraint]. -/// -/// If [ignoreUpperBound] the max constraint is ignored. +/// If or [defaultUpperBoundConstraint] is specified then it will be set as the +/// max constraint if the original constraint doesn't have an upper bound and it +/// is compatible with [defaultUpperBoundConstraint]. VersionConstraint _parseVersionConstraint( - YamlNode? node, String? packageName, _FileType fileType, - {VersionConstraint? defaultUpperBoundConstraint, - bool ignoreUpperBound = false}) { + YamlNode? node, String? packageName, _FileType fileType) { if (node?.value == null) { - return defaultUpperBoundConstraint ?? VersionConstraint.any; + return VersionConstraint.any; } if (node!.value is! String) { _error('A version constraint must be a string.', node.span); @@ -576,17 +623,6 @@ return _wrapFormatException('version constraint', node.span, () { var constraint = VersionConstraint.parse(node.value); - if (defaultUpperBoundConstraint != null && - constraint is VersionRange && - constraint.max == null && - defaultUpperBoundConstraint.allowsAny(constraint)) { - constraint = VersionConstraint.intersection( - [constraint, defaultUpperBoundConstraint]); - } - if (ignoreUpperBound && constraint is VersionRange) { - return VersionRange( - min: constraint.min, includeMin: constraint.includeMin); - } return constraint; }, packageName, fileType); } @@ -643,3 +679,40 @@ return 'pubspec override'; } } + +/// There are special rules or interpreting SDK constraints, we take care to +/// save the original constraint as found in pubspec.yaml. +class SdkConstraint { + /// The constraint as written in the pubspec.yaml. + final VersionConstraint originalConstraint; + + /// The constraint as interpreted by pub. + final VersionConstraint effectiveConstraint; + + SdkConstraint(this.effectiveConstraint, + {VersionConstraint? originalConstraint}) + : originalConstraint = originalConstraint ?? effectiveConstraint; + + /// The language version of a constraint is determined from how it is written. + LanguageVersion get languageVersion => + LanguageVersion.fromSdkConstraint(originalConstraint); + + // We currently don't call this anywhere - so this is only for debugging + // purposes. + @override + String toString() { + if (effectiveConstraint != originalConstraint) { + return '$originalConstraint (interpreted as $effectiveConstraint)'; + } + return effectiveConstraint.toString(); + } + + @override + operator ==(other) => + other is SdkConstraint && + other.effectiveConstraint == effectiveConstraint && + other.originalConstraint == originalConstraint; + + @override + int get hashCode => Object.hash(effectiveConstraint, originalConstraint); +}
diff --git a/lib/src/solver/package_lister.dart b/lib/src/solver/package_lister.dart index 1597e73..f3b63b6 100644 --- a/lib/src/solver/package_lister.dart +++ b/lib/src/solver/package_lister.dart
@@ -218,8 +218,11 @@ for (var sdk in sdks.values) { if (!_matchesSdkConstraint(pubspec, sdk)) { return [ - Incompatibility([Term(depender, true)], - SdkCause(pubspec.sdkConstraints[sdk.identifier], sdk)) + Incompatibility( + [Term(depender, true)], + SdkCause( + pubspec.sdkConstraints[sdk.identifier]?.effectiveConstraint, + sdk)) ]; } } @@ -321,12 +324,13 @@ alwaysIncludeMaxPreRelease: true); _knownInvalidVersions = incompatibleVersions.union(_knownInvalidVersions); - var sdkConstraint = await foldAsync( + var sdkConstraint = await foldAsync<VersionConstraint, PackageId>( slice(versions, bounds.first, bounds.last + 1), VersionConstraint.empty, - (dynamic previous, dynamic version) async { + (previous, version) async { var pubspec = await _describeSafe(version); return previous.union( - pubspec.sdkConstraints[sdk.identifier] ?? VersionConstraint.any); + pubspec.sdkConstraints[sdk.identifier]?.effectiveConstraint ?? + VersionConstraint.any); }); return Incompatibility( @@ -428,6 +432,7 @@ var constraint = pubspec.sdkConstraints[sdk.identifier]; if (constraint == null) return true; - return sdk.isAvailable && constraint.allows(sdk.version!); + return sdk.isAvailable && + constraint.effectiveConstraint.allows(sdk.version!); } }
diff --git a/lib/src/solver/result.dart b/lib/src/solver/result.dart index 7d57c36..df3aa4a 100644 --- a/lib/src/solver/result.dart +++ b/lib/src/solver/result.dart
@@ -63,7 +63,7 @@ var sdkConstraints = <String, VersionConstraint>{}; for (var pubspec in nonOverrides) { pubspec.sdkConstraints.forEach((identifier, constraint) { - sdkConstraints[identifier] = constraint + sdkConstraints[identifier] = constraint.effectiveConstraint .intersect(sdkConstraints[identifier] ?? VersionConstraint.any); }); }
diff --git a/lib/src/validator.dart b/lib/src/validator.dart index 82de012..cbf930f 100644 --- a/lib/src/validator.dart +++ b/lib/src/validator.dart
@@ -75,7 +75,7 @@ void validateSdkConstraint(Version firstSdkVersion, String message) { // If the SDK constraint disallowed all versions before [firstSdkVersion], // no error is necessary. - if (entrypoint.root.pubspec.originalDartSdkConstraint + if (entrypoint.root.pubspec.dartSdkConstraint.originalConstraint .intersect(VersionRange(max: firstSdkVersion)) .isEmpty) { return; @@ -96,7 +96,8 @@ ? firstSdkVersion.nextPatch : firstSdkVersion.nextBreaking); - var newSdkConstraint = entrypoint.root.pubspec.originalDartSdkConstraint + var newSdkConstraint = entrypoint + .root.pubspec.dartSdkConstraint.originalConstraint .intersect(allowedSdks); if (newSdkConstraint.isEmpty) newSdkConstraint = allowedSdks;
diff --git a/lib/src/validator/flutter_plugin_format.dart b/lib/src/validator/flutter_plugin_format.dart index a56f7df..00160ca 100644 --- a/lib/src/validator/flutter_plugin_format.dart +++ b/lib/src/validator/flutter_plugin_format.dart
@@ -46,7 +46,7 @@ final flutterConstraint = pubspec.sdkConstraints['flutter']; if (usesNewPluginFormat && (flutterConstraint == null || - flutterConstraint.allowsAny(VersionRange( + flutterConstraint.effectiveConstraint.allowsAny(VersionRange( min: Version.parse('0.0.0'), max: Version.parse('1.10.0'), includeMin: true,
diff --git a/test/dart3_sdk_constraint_hack_test.dart b/test/dart3_sdk_constraint_hack_test.dart new file mode 100644 index 0000000..7df3ee8 --- /dev/null +++ b/test/dart3_sdk_constraint_hack_test.dart
@@ -0,0 +1,111 @@ +// Copyright (c) 2020, 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. + +import 'package:test/test.dart'; + +import 'descriptor.dart' as d; +import 'test_pub.dart'; + +void main() { + test('The bound of ">=2.11.0 <3.0.0" is not modified', () async { + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'environment': {'sdk': '>=2.11.0 <3.0.0'} + }), + ]).create(); + + await pubGet( + error: contains( + 'Because myapp requires SDK version >=2.11.0 <3.0.0, version solving failed'), + environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'}, + ); + }); + test('The bound of ">=2.12.0 <3.1.0" is not modified', () async { + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'environment': {'sdk': '>=2.12.0 <3.1.0'} + }), + ]).create(); + + await pubGet( + error: contains( + 'Because myapp requires SDK version >=2.12.0 <3.1.0, version solving failed'), + environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'}, + ); + }); + + test('The bound of ">=2.11.0 <2.999.0" is not modified', () async { + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'environment': {'sdk': '>=2.11.0 <2.999.0'} + }), + ]).create(); + + await pubGet( + error: contains( + 'Because myapp requires SDK version >=2.11.0 <2.999.0, version solving failed'), + environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'}, + ); + }); + + test('The bound of ">=2.11.0 <3.0.0-0.0" is not modified', () async { + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'environment': {'sdk': '>=2.11.0 <3.0.0-0.0'} + }), + ]).create(); + + await pubGet( + error: contains( + 'Because myapp requires SDK version >=2.11.0 <3.0.0-0.0, version solving failed'), + environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'}, + ); + }); + + test('The bound of ">=2.12.0 <3.0.0" is modified', () async { + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'environment': {'sdk': '>=2.12.0 <3.0.0'} + }), + ]).create(); + + await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'}); + }); + + test('The bound of ">=2.12.0 <3.0.0-0" is modified', () async { + // For the upper bound <3.0.0 is treated as <3.0.0-0, so they both have + // the rewrite applied. + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'environment': {'sdk': '>=2.12.0 <3.0.0-0'} + }), + ]).create(); + + await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'}); + }); + + test( + 'The bound of ">=2.12.0 <3.0.0" is not compatible with prereleases of dart 4', + () async { + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'environment': {'sdk': '>=2.12.0 <3.0.0'} + }), + ]).create(); + + await pubGet( + environment: {'_PUB_TEST_SDK_VERSION': '4.0.0-alpha'}, + error: contains( + 'Because myapp requires SDK version >=2.12.0 <4.0.0, version solving failed.', + ), + ); + }); +}
diff --git a/test/pubspec_test.dart b/test/pubspec_test.dart index 1a9ac48..23079c5 100644 --- a/test/pubspec_test.dart +++ b/test/pubspec_test.dart
@@ -6,7 +6,6 @@ import 'package:pub/src/exceptions.dart'; import 'package:pub/src/pubspec.dart'; -import 'package:pub/src/sdk.dart'; import 'package:pub/src/source/hosted.dart'; import 'package:pub/src/system_cache.dart'; import 'package:pub_semver/pub_semver.dart'; @@ -495,36 +494,23 @@ }); group('environment', () { - /// Checking for the default SDK constraint based on the current SDK. - void expectDefaultSdkConstraint(Pubspec pubspec) { - var sdkVersionString = sdk.version.toString(); - if (sdkVersionString.startsWith('2.0.0') && sdk.version.isPreRelease) { - expect( - pubspec.sdkConstraints, - containsPair( - 'dart', - VersionConstraint.parse( - '${pubspec.sdkConstraints["dart"]} <=$sdkVersionString'))); - } else { - expect( - pubspec.sdkConstraints, - containsPair( - 'dart', - VersionConstraint.parse( - "${pubspec.sdkConstraints["dart"]} <2.0.0"))); - } - } - test('allows an omitted environment', () { var pubspec = Pubspec.parse('name: testing', sources); - expectDefaultSdkConstraint(pubspec); + expect( + pubspec.dartSdkConstraint.effectiveConstraint, + VersionConstraint.parse('<2.0.0'), + ); + expect(pubspec.sdkConstraints, isNot(contains('flutter'))); expect(pubspec.sdkConstraints, isNot(contains('fuchsia'))); }); test('default SDK constraint can be omitted with empty environment', () { var pubspec = Pubspec.parse('', sources); - expectDefaultSdkConstraint(pubspec); + expect( + pubspec.dartSdkConstraint.effectiveConstraint, + VersionConstraint.parse('<2.0.0'), + ); expect(pubspec.sdkConstraints, isNot(contains('flutter'))); expect(pubspec.sdkConstraints, isNot(contains('fuchsia'))); }); @@ -535,7 +521,10 @@ environment: sdk: ">1.0.0" ''', sources); - expectDefaultSdkConstraint(pubspec); + expect( + pubspec.dartSdkConstraint.effectiveConstraint, + VersionConstraint.parse('>1.0.0 <2.0.0'), + ); expect(pubspec.sdkConstraints, isNot(contains('flutter'))); expect(pubspec.sdkConstraints, isNot(contains('fuchsia'))); }); @@ -547,8 +536,12 @@ environment: sdk: ">3.0.0" ''', sources); - expect(pubspec.sdkConstraints, - containsPair('dart', VersionConstraint.parse('>3.0.0'))); + expect( + pubspec.sdkConstraints, + containsPair( + 'dart', + SdkConstraint(VersionConstraint.parse('>3.0.0')), + )); expect(pubspec.sdkConstraints, isNot(contains('flutter'))); expect(pubspec.sdkConstraints, isNot(contains('fuchsia'))); }); @@ -565,12 +558,23 @@ flutter: ^0.1.2 fuchsia: ^5.6.7 ''', sources); - expect(pubspec.sdkConstraints, - containsPair('dart', VersionConstraint.parse('>=1.2.3 <2.3.4'))); - expect(pubspec.sdkConstraints, - containsPair('flutter', VersionConstraint.parse('>=0.1.2'))); - expect(pubspec.sdkConstraints, - containsPair('fuchsia', VersionConstraint.parse('^5.6.7'))); + expect( + pubspec.sdkConstraints, + containsPair('dart', + SdkConstraint(VersionConstraint.parse('>=1.2.3 <2.3.4')))); + expect( + pubspec.sdkConstraints, + containsPair( + 'flutter', + SdkConstraint( + VersionConstraint.parse('>=0.1.2'), + originalConstraint: VersionConstraint.parse('^0.1.2'), + ))); + expect( + pubspec.sdkConstraints, + containsPair( + 'fuchsia', SdkConstraint(VersionConstraint.parse('^5.6.7'))), + ); }); test("throws if the sdk isn't a string", () {
diff --git a/test/upgrade/upgrade_null_safety_test.dart b/test/upgrade/upgrade_null_safety_test.dart index 557c589..ad210d8 100644 --- a/test/upgrade/upgrade_null_safety_test.dart +++ b/test/upgrade/upgrade_null_safety_test.dart
@@ -441,7 +441,7 @@ }, error: allOf( contains('Because myapp depends on has_conflict >=2.0.0 which'), - contains('requires SDK version >=2.13.0 <3.0.0,'), + contains('requires SDK version >=2.13.0 <4.0.0,'), contains('version solving failed.'), ), );
diff --git a/test/version_solver_test.dart b/test/version_solver_test.dart index 69489a3..8ade3f6 100644 --- a/test/version_solver_test.dart +++ b/test/version_solver_test.dart
@@ -1172,7 +1172,7 @@ await expectResolves( environment: {'_PUB_TEST_SDK_VERSION': '2.0.0-dev.99'}, - // Log output should mention the PUB_ALLOW_RELEASE_SDK environment + // Log output should mention the PUB_ALLOW_PRERELEASE_SDK environment // variable and mention the foo and bar packages specifically. output: allOf(contains('PUB_ALLOW_PRERELEASE_SDK'), anyOf(contains('bar, foo'))),