Don't allow non-null-safety constraints in the root pubspec (#3800)
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart index afd6c8a..d18f6e2 100644 --- a/lib/src/entrypoint.dart +++ b/lib/src/entrypoint.dart
@@ -19,6 +19,7 @@ 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'; @@ -938,21 +939,21 @@ /// We don't allow unknown sdks. void _checkSdkConstraint(Pubspec pubspec) { final dartSdkConstraint = pubspec.dartSdkConstraint.effectiveConstraint; - if (dartSdkConstraint is! VersionRange || dartSdkConstraint.min == null) { - // Suggest an sdk constraint giving the same language version as the - // current sdk. - var suggestedConstraint = VersionConstraint.compatibleWith( - Version(sdk.version.major, sdk.version.minor, 0), + // Suggest an sdk constraint giving the same language version as the + // current sdk. + var suggestedConstraint = VersionConstraint.compatibleWith( + Version(sdk.version.major, sdk.version.minor, 0), + ); + // But if somehow that doesn't work, we fallback to safe sanity, mostly + // important for tests, or if we jump to 3.x without patching this code. + if (!suggestedConstraint.allows(sdk.version)) { + suggestedConstraint = VersionRange( + min: sdk.version, + max: sdk.version.nextBreaking, + includeMin: true, ); - // But if somehow that doesn't work, we fallback to safe sanity, mostly - // important for tests, or if we jump to 3.x without patching this code. - if (!suggestedConstraint.allows(sdk.version)) { - suggestedConstraint = VersionRange( - min: sdk.version, - max: sdk.version.nextBreaking, - includeMin: true, - ); - } + } + if (dartSdkConstraint is! VersionRange || dartSdkConstraint.min == null) { throw DataException(''' $pubspecPath has no lower-bound SDK constraint. You should edit $pubspecPath to contain an SDK constraint: @@ -963,6 +964,24 @@ See https://dart.dev/go/sdk-constraint '''); } + if (!LanguageVersion.fromSdkConstraint(dartSdkConstraint) + .supportsNullSafety) { + throw DataException(''' +The lower bound of "sdk: '$dartSdkConstraint'" must be 2.12.0' +or higher to enable null safety. + +The current version of the Dart SDK (${sdk.version}) does not support non-null +safety code. + +Consider using an older, compatible Dart SDK or try the following sdk +constraint: + +environment: + sdk: '${suggestedConstraint.asCompatibleWithIfPossible()}' + +For details, see https://dart.dev/null-safety +'''); + } for (final sdk in pubspec.sdkConstraints.keys) { if (!sdks.containsKey(sdk)) { final environment = pubspec.fields.nodes['environment'] as YamlMap;
diff --git a/lib/src/sdk.dart b/lib/src/sdk.dart index 7da78c1..bc1c6c9 100644 --- a/lib/src/sdk.dart +++ b/lib/src/sdk.dart
@@ -31,9 +31,6 @@ /// The SDK's version number, or `null` if the SDK is unavailable. Version? get version; - /// The version of pub that added support for this SDK. - Version get firstPubVersion; - /// A message to indicate to the user how to make this SDK available. /// /// This is printed after a version solve where the SDK wasn't found. It may
diff --git a/lib/src/sdk/dart.dart b/lib/src/sdk/dart.dart index 75cf6f9..19af627 100644 --- a/lib/src/sdk/dart.dart +++ b/lib/src/sdk/dart.dart
@@ -20,8 +20,6 @@ bool get isAvailable => true; @override String? get installMessage => null; - @override - Version get firstPubVersion => Version.none; static final String _rootDirectory = () { if (runningFromDartRepo) return p.join(dartRepoRoot, 'sdk');
diff --git a/lib/src/sdk/flutter.dart b/lib/src/sdk/flutter.dart index c9f1914..2151e87 100644 --- a/lib/src/sdk/flutter.dart +++ b/lib/src/sdk/flutter.dart
@@ -15,8 +15,6 @@ String get name => 'Flutter'; @override bool get isAvailable => _isAvailable; - @override - Version get firstPubVersion => Version.parse('1.19.0'); // We only consider the Flutter SDK to present if we find a root directory // and the root directory contains a valid 'version' file.
diff --git a/lib/src/sdk/fuchsia.dart b/lib/src/sdk/fuchsia.dart index 3b884a4..e0f551b 100644 --- a/lib/src/sdk/fuchsia.dart +++ b/lib/src/sdk/fuchsia.dart
@@ -15,8 +15,6 @@ String get name => 'Fuchsia'; @override bool get isAvailable => _isAvailable; - @override - Version get firstPubVersion => Version.parse('2.0.0-dev.51.0'); static final bool _isAvailable = _rootDirectory != null; static final String? _rootDirectory =
diff --git a/lib/src/validator.dart b/lib/src/validator.dart index 5a03d7b..6fcab2a 100644 --- a/lib/src/validator.dart +++ b/lib/src/validator.dart
@@ -23,7 +23,6 @@ import 'validator/flutter_constraint.dart'; import 'validator/flutter_plugin_format.dart'; import 'validator/gitignore.dart'; -import 'validator/language_version.dart'; import 'validator/leak_detection.dart'; import 'validator/license.dart'; import 'validator/name.dart'; @@ -156,7 +155,6 @@ StrictDependenciesValidator(), FlutterConstraintValidator(), FlutterPluginFormatValidator(), - LanguageVersionValidator(), RelativeVersionNumberingValidator(), PubspecTypoValidator(), LeakDetectionValidator(),
diff --git a/lib/src/validator/dependency.dart b/lib/src/validator/dependency.dart index 939d9be..ebfa101 100644 --- a/lib/src/validator/dependency.dart +++ b/lib/src/validator/dependency.dart
@@ -10,18 +10,11 @@ import '../log.dart' as log; import '../package_name.dart'; import '../sdk.dart'; -import '../source/git.dart'; import '../source/hosted.dart'; import '../source/path.dart'; import '../source/sdk.dart'; import '../validator.dart'; -/// The first Dart SDK version that supported caret constraints. -final _firstCaretVersion = Version.parse('1.8.0-dev.3.0'); - -/// The first Dart SDK version that supported Git path dependencies. -final _firstGitPathVersion = Version.parse('2.0.0-dev.1.0'); - /// A validator that validates a package's dependencies. class DependencyValidator extends Validator { @override @@ -38,11 +31,6 @@ errors.add('Unknown SDK "$identifier" for dependency "${dep.name}".'); return; } - - validateSdkConstraint( - sdk.firstPubVersion, - "Older versions of pub don't support the ${sdk.name} SDK.", - ); } /// Warn that dependencies should use the hosted source. @@ -195,14 +183,6 @@ warnAboutSdkSource(dependency); } else if (dependency.source is! HostedSource) { await warnAboutSource(dependency); - - final description = dependency.description; - if (description is GitDescription && description.path != '.') { - validateSdkConstraint( - _firstGitPathVersion, - "Older versions of pub don't support Git path dependencies.", - ); - } } else { if (constraint.isAny) { warnAboutNoConstraint(dependency); @@ -224,12 +204,5 @@ } await validateDependencies(entrypoint.root.pubspec.dependencies.values); - - if (hasCaretDep) { - validateSdkConstraint( - _firstCaretVersion, - "Older versions of pub don't support ^ version constraints.", - ); - } } }
diff --git a/lib/src/validator/language_version.dart b/lib/src/validator/language_version.dart deleted file mode 100644 index ab2d868..0000000 --- a/lib/src/validator/language_version.dart +++ /dev/null
@@ -1,55 +0,0 @@ -// 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 'dart:async'; - -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:path/path.dart' as p; -import 'package:stack_trace/stack_trace.dart'; - -import '../dart.dart'; -import '../language_version.dart'; -import '../log.dart' as log; -import '../utils.dart'; -import '../validator.dart'; - -/// Validates that libraries do not opt into newer language versions than what -/// they declare in their pubspec. -class LanguageVersionValidator extends Validator { - @override - Future validate() async { - var packagePath = p.normalize(p.absolute(entrypoint.root.dir)); - final analysisContextManager = AnalysisContextManager(packagePath); - - final declaredLanguageVersion = entrypoint.root.pubspec.languageVersion; - - for (final path in ['lib', 'bin'].expand((path) { - return filesBeneath(path, recursive: true) - .where((file) => p.extension(file) == '.dart'); - })) { - CompilationUnit unit; - try { - unit = analysisContextManager.parse(path); - } on AnalyzerErrorGroup catch (e, s) { - // Ignore files that do not parse. - log.fine(getErrorMessage(e)); - log.fine(Chain.forTrace(s).terse); - continue; - } - - final unitLanguageVersionToken = unit.languageVersionToken; - if (unitLanguageVersionToken != null) { - final unitLanguageVersion = - LanguageVersion.fromLanguageVersionToken(unitLanguageVersionToken); - if (unitLanguageVersion > declaredLanguageVersion) { - final relativePath = p.relative(path); - errors.add('$relativePath is declaring language version ' - '$unitLanguageVersion that is newer than the SDK ' - 'constraint $declaredLanguageVersion declared in ' - '`pubspec.yaml`.'); - } - } - } - } -}
diff --git a/lib/src/validator/sdk_constraint.dart b/lib/src/validator/sdk_constraint.dart index 729981e..c95cd91 100644 --- a/lib/src/validator/sdk_constraint.dart +++ b/lib/src/validator/sdk_constraint.dart
@@ -6,7 +6,6 @@ import 'package:pub_semver/pub_semver.dart'; -import '../sdk.dart'; import '../validator.dart'; /// A validator of the SDK constraint. @@ -62,15 +61,5 @@ '''); } } - - for (var sdk in sdks.values) { - if (sdk.identifier == 'dart') continue; - if (entrypoint.root.pubspec.sdkConstraints.containsKey(sdk.identifier)) { - validateSdkConstraint( - sdk.firstPubVersion, - "Older versions of pub don't support ${sdk.name} SDK constraints.", - ); - } - } } }
diff --git a/test/dart3_sdk_constraint_hack_test.dart b/test/dart3_sdk_constraint_hack_test.dart index e8e18ab..5771ff6 100644 --- a/test/dart3_sdk_constraint_hack_test.dart +++ b/test/dart3_sdk_constraint_hack_test.dart
@@ -2,6 +2,7 @@ // 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/src/exit_codes.dart'; import 'package:test/test.dart'; import 'descriptor.dart' as d; @@ -18,9 +19,10 @@ await pubGet( error: contains( - 'Because myapp doesn\'t support null safety, version solving failed', + 'The current version of the Dart SDK (3.5.0) does not support non-null\nsafety code.', ), environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'}, + exitCode: DATA, ); }); test('The bound of ">=2.12.0 <3.1.0" is not modified', () async { @@ -49,9 +51,10 @@ await pubGet( error: contains( - 'Because myapp doesn\'t support null safety, version solving failed', + 'The current version of the Dart SDK (3.5.0) does not support non-null\nsafety code.', ), environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'}, + exitCode: DATA, ); }); @@ -65,9 +68,10 @@ await pubGet( error: contains( - 'Because myapp doesn\'t support null safety, version solving failed', + 'The current version of the Dart SDK (3.5.0) does not support non-null\nsafety code.', ), environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'}, + exitCode: DATA, ); });
diff --git a/test/get/sdk_constraint_required_test.dart b/test/get/sdk_constraint_required_test.dart index 992abcc..50c6420 100644 --- a/test/get/sdk_constraint_required_test.dart +++ b/test/get/sdk_constraint_required_test.dart
@@ -34,4 +34,43 @@ d.nothing('.dart_tool/package_config.json'), ]).validate(); }); + + test('pub get fails with an non-null-safety SDK constraint', () async { + await d.dir(appPath, [ + d.rawPubspec( + { + 'name': 'myapp', + 'environment': {'sdk': '>=2.9.0 <4.0.0'} + }, + ), + ]).create(); + + await pubGet( + error: ''' +The lower bound of "sdk: '>=2.9.0 <4.0.0'" must be 2.12.0' +or higher to enable null safety. + +The current version of the Dart SDK (3.1.2+3) does not support non-null +safety code. + +Consider using an older, compatible Dart SDK or try the following sdk +constraint: + +environment: + sdk: '^3.1.0' + +For details, see https://dart.dev/null-safety +''', + exitCode: exit_codes.DATA, + ); + + await d.dir(appPath, [ + // The lockfile should not be created. + d.nothing('pubspec.lock'), + // The "packages" directory should not have been generated. + d.nothing('packages'), + // The package config file should not have been created. + d.nothing('.dart_tool/package_config.json'), + ]).validate(); + }); }
diff --git a/test/hosted/short_syntax_test.dart b/test/hosted/short_syntax_test.dart index 6ea6851..eb1003f 100644 --- a/test/hosted/short_syntax_test.dart +++ b/test/hosted/short_syntax_test.dart
@@ -18,7 +18,7 @@ 'foo', '1.2.3', pubspec: { - 'environment': {'sdk': '^2.0.0'} + 'environment': {'sdk': '^2.12.0'} }, ); }); @@ -73,15 +73,11 @@ deps: { 'foo': {'hosted': 'foo', 'version': '^1.2.3'} }, - sdk: '^2.0.0', + sdk: '^2.14.0', ), ]).create(); - await pubCommand( - command, - exitCode: 0, - environment: {'_PUB_TEST_SDK_VERSION': '2.15.0'}, - ); + await pubCommand(command); final lockFile = loadYaml( await File(p.join(d.sandbox, appPath, 'pubspec.lock')).readAsString(),
diff --git a/test/must_pub_get_test.dart b/test/must_pub_get_test.dart index 7663401..4eace86 100644 --- a/test/must_pub_get_test.dart +++ b/test/must_pub_get_test.dart
@@ -258,7 +258,7 @@ 'foo', '3.0.0', pubspec: { - 'environment': {'sdk': '>=1.0.0 <2.0.0'} + 'environment': {'sdk': '>=3.0.0 <3.1.0'} }, ); @@ -267,12 +267,12 @@ 'name': 'myapp', 'dependencies': {'foo': '3.0.0'}, 'environment': { - 'sdk': '>=1.0.0 <2.0.0', + 'sdk': '>=3.0.0 <3.1.0', }, }), ]).create(); - await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '1.2.3+4'}); + await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '3.0.0'}); }); _requiresPubGet("Dart 3.1.2+3 is incompatible with your dependencies' "
diff --git a/test/run/enable_experiments_test.dart b/test/run/enable_experiments_test.dart deleted file mode 100644 index a21fee3..0000000 --- a/test/run/enable_experiments_test.dart +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright (c) 2014, 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('Succeeds running experimental code.', () async { - await d.dir(appPath, [ - d.pubspec({ - 'name': 'myapp', - 'environment': {'sdk': '>=2.10.0 <=3.0.0'}, - }), - d.dir('bin', [ - d.file('script.dart', ''' - main() { - int? a = int.tryParse('123'); - } -''') - ]) - ]).create(); - await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '2.10.0'}); - await runPub( - args: ['run', '--enable-experiment=non-nullable', 'bin/script.dart'], - environment: {'_PUB_TEST_SDK_VERSION': '2.10.0'}, - ); - }); -}
diff --git a/test/validator/analyze_test.dart b/test/validator/analyze_test.dart index a20f4cd..1ce8b4f 100644 --- a/test/validator/analyze_test.dart +++ b/test/validator/analyze_test.dart
@@ -7,50 +7,30 @@ import '../descriptor.dart' as d; import '../test_pub.dart'; - -Future<void> expectValidation( - error, - int exitCode, { - List<String> extraArgs = const [], - Map<String, String> environment = const {}, - String? workingDirectory, -}) async { - await runPub( - error: error, - args: ['publish', '--dry-run', ...extraArgs], - environment: {'_PUB_TEST_SDK_VERSION': '1.12.0', ...environment}, - workingDirectory: workingDirectory ?? d.path(appPath), - exitCode: exitCode, - ); -} +import 'utils.dart'; void main() { test('should consider a package valid if it contains no warnings or errors', () async { await d.dir(appPath, [ - d.libPubspec('test_pkg', '1.0.0', sdk: '>=1.8.0 <=2.0.0'), + d.validPubspec(), d.file('LICENSE', 'Eh, do what you want.'), d.file('README.md', "This package isn't real."), d.file('CHANGELOG.md', '# 1.0.0\nFirst version\n'), d.dir('lib', [d.file('test_pkg.dart', 'int i = 1;')]) ]).create(); - - await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'}); - - await expectValidation(contains('Package has 0 warnings.'), 0); + await expectValidation(); }); test('should handle having no code in the analyzed directories', () async { await d.dir(appPath, [ - d.libPubspec('test_pkg', '1.0.0', sdk: '>=1.8.0 <=2.0.0'), + d.validPubspec(), d.file('LICENSE', 'Eh, do what you want.'), d.file('README.md', "This package isn't real."), d.file('CHANGELOG.md', '# 1.0.0\nFirst version\n'), ]).create(); - await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'}); - - await expectValidation(contains('Package has 0 warnings.'), 0); + await expectValidation(); }); test( @@ -59,7 +39,7 @@ await d.dir(appPath, [ d.libPubspec( 'test_pkg', '1.0.0', - sdk: '>=1.8.0 <=2.0.0', + sdk: '^3.0.0', // Using http where https is recommended. extras: {'repository': 'http://repo.org/'}, ), @@ -73,16 +53,14 @@ ''') ]).create(); - await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'}); - await expectValidation( - allOf([ + error: allOf([ contains( "The 'http' protocol shouldn't be used because it isn't secure. Try using a secure protocol, such as 'https'.", ), contains('Package has 1 warning.'), ]), - DATA, + exitCode: DATA, ); }); @@ -90,7 +68,7 @@ 'should consider a package valid even if it contains errors in the example/ sub-folder', () async { await d.dir(appPath, [ - d.libPubspec('test_pkg', '1.0.0', sdk: '>=1.8.0 <=2.0.0'), + d.validPubspec(), d.file('LICENSE', 'Eh, do what you want.'), d.file('README.md', "This package isn't real."), d.file('CHANGELOG.md', '# 1.0.0\nFirst version\n'), @@ -104,16 +82,14 @@ ]) ]).create(); - await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'}); - - await expectValidation(contains('Package has 0 warnings.'), 0); + await expectValidation(); }); test( 'should warn if package contains errors in bin/, and works with --directory', () async { await d.dir(appPath, [ - d.libPubspec('test_pkg', '1.0.0', sdk: '>=1.8.0 <=2.0.0'), + d.validPubspec(), d.file('LICENSE', 'Eh, do what you want.'), d.file('README.md', "This package isn't real."), d.file('CHANGELOG.md', '# 1.0.0\nFirst version\n'), @@ -126,17 +102,15 @@ ]) ]).create(); - await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'}); - await expectValidation( - allOf([ + error: allOf([ contains('`dart analyze` found the following issue(s):'), contains('Analyzing lib, bin, pubspec.yaml...'), contains('error -'), contains("Expected to find '}'."), contains('Package has 1 warning.') ]), - DATA, + exitCode: DATA, extraArgs: ['--directory', appPath], workingDirectory: d.sandbox, ); @@ -144,7 +118,7 @@ test('should warn if package contains infos in test folder', () async { await d.dir(appPath, [ - d.libPubspec('test_pkg', '1.0.0', sdk: '>=1.8.0 <=2.0.0'), + d.validPubspec(), d.file('LICENSE', 'Eh, do what you want.'), d.file('README.md', "This package isn't real."), d.file('CHANGELOG.md', '# 1.0.0\nFirst version\n'), @@ -158,17 +132,15 @@ ]), ]).create(); - await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'}); - await expectValidation( - allOf([ + error: allOf([ contains('`dart analyze` found the following issue(s):'), contains('Analyzing lib, test, pubspec.yaml...'), contains('info -'), contains("The value of the local variable 'a' isn't used"), contains('Package has 1 warning.') ]), - DATA, + exitCode: DATA, ); }); }
diff --git a/test/validator/dependency_test.dart b/test/validator/dependency_test.dart index 6d8349e..dead156 100644 --- a/test/validator/dependency_test.dart +++ b/test/validator/dependency_test.dart
@@ -93,12 +93,6 @@ await expectValidation(); }); - test('has a ^ constraint with an appropriate SDK constraint', () async { - (await servePackages()).serve('foo', '1.2.3', sdk: '^1.8.3'); - await package(deps: {'foo': '^1.2.3'}, sdk: '^1.8.3').create(); - await expectValidation(environment: {'_PUB_TEST_SDK_VERSION': '1.18.0'}); - }); - test('with a dependency on a pre-release while being one', () async { (await servePackages()).serve('foo', '1.2.3-dev'); await package(version: '1.0.0-dev', deps: {'foo': '^1.2.3-dev'}).create(); @@ -109,7 +103,7 @@ () async { await servePackages(); await d.git('foo', [ - d.dir('subdir', [d.libPubspec('foo', '1.0.0', sdk: '^2.0.0')]), + d.dir('subdir', [d.libPubspec('foo', '1.0.0')]), ]).create(); await package( deps: { @@ -117,7 +111,6 @@ 'git': {'url': '../foo', 'path': 'subdir'} } }, - sdk: '>=2.0.0 <3.0.0', ).create(); // We should get a warning for using a git dependency, but not an error. @@ -127,25 +120,20 @@ contains("Publishable packages can't have 'git' dependencies"), ]), count: 2, - environment: {'_PUB_TEST_SDK_VERSION': '2.0.0'}, ); }); test('depends on Flutter from an SDK source', () async { await d.dir('flutter', [d.file('version', '1.2.3')]).create(); - await flutterPackage('flutter', sdk: '>=1.19.0 <2.0.0').create(); + await flutterPackage('flutter').create(); await package( deps: { 'flutter': {'sdk': 'flutter'} }, - sdk: '>=1.19.0 <2.0.0', ).create(); await expectValidation( - environment: { - '_PUB_TEST_SDK_VERSION': '1.19.0', - 'FLUTTER_ROOT': path.join(d.sandbox, 'flutter') - }, + environment: {'FLUTTER_ROOT': path.join(d.sandbox, 'flutter')}, ); }); @@ -153,18 +141,16 @@ 'depends on a package from Flutter with an appropriate Dart SDK constraint', () async { await d.dir('flutter', [d.file('version', '1.2.3')]).create(); - await flutterPackage('foo', sdk: '^1.0.0').create(); + await flutterPackage('foo').create(); await d.dir('flutter', [d.file('version', '1.2.3')]).create(); await package( deps: { 'foo': {'sdk': 'flutter', 'version': '>=1.2.3 <2.0.0'}, }, - sdk: '>=1.19.0 <2.0.0', ).create(); await expectValidation( environment: { - '_PUB_TEST_SDK_VERSION': '1.19.0', 'FLUTTER_ROOT': path.join(d.sandbox, 'flutter'), }, ); @@ -174,9 +160,8 @@ test( 'depends on a package from Fuchsia with an appropriate Dart SDK constraint', () async { - await fuschiaPackage('foo', sdk: '>=2.0.0 <3.0.0').create(); + await fuschiaPackage('foo', sdk: '^3.0.0').create(); await package( - sdk: '>=2.0.0 <3.0.0', deps: { 'foo': {'sdk': 'fuchsia', 'version': '>=1.2.3 <2.0.0'} }, @@ -185,7 +170,6 @@ await expectValidation( environment: { 'FUCHSIA_DART_SDK_ROOT': path.join(d.sandbox, 'fuchsia'), - '_PUB_TEST_SDK_VERSION': '2.12.0', }, ); }, @@ -199,16 +183,14 @@ group('where a hosted version exists', () { test('and should suggest the hosted primary version', () async { await d.dir('foo', [ - d.libPubspec('foo', '1.2.3', sdk: 'any'), + d.libPubspec('foo', '1.2.3'), ]).create(); await setUpDependency( - sdk: '^1.8.0', {'path': path.join(d.sandbox, 'foo')}, hostedVersions: ['3.0.0-pre', '2.0.0', '1.0.0'], ); await expectValidationError( ' foo: ^2.0.0', - environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'}, ); }); @@ -216,32 +198,28 @@ "and should suggest the hosted prerelease version if it's the only version available", () async { await d.dir('foo', [ - d.libPubspec('foo', '1.2.3', sdk: 'any'), + d.libPubspec('foo', '1.2.3'), ]).create(); await setUpDependency( - sdk: '^1.8.0', {'path': path.join(d.sandbox, 'foo')}, hostedVersions: ['3.0.0-pre', '2.0.0-pre'], ); await expectValidationError( ' foo: ^3.0.0-pre', - environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'}, ); }); test('and should suggest a tighter constraint if primary is pre-1.0.0', () async { await d.dir('foo', [ - d.libPubspec('foo', '1.2.3', sdk: 'any'), + d.libPubspec('foo', '1.2.3'), ]).create(); await setUpDependency( - sdk: '^1.8.0', {'path': path.join(d.sandbox, 'foo')}, hostedVersions: ['0.0.1', '0.0.2'], ); await expectValidationError( ' foo: ^0.0.2', - environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'}, ); }); }); @@ -249,15 +227,14 @@ group('where no hosted version exists', () { test("and should use the other source's version", () async { await d.dir('foo', [ - d.libPubspec('foo', '1.2.3', sdk: 'any'), + d.libPubspec('foo', '1.2.3'), ]).create(); - await setUpDependency(sdk: '^1.8.0', { + await setUpDependency({ 'path': path.join(d.sandbox, 'foo'), 'version': '>=1.0.0 <2.0.0' }); await expectValidationError( ' foo: ">=1.0.0 <2.0.0"', - environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'}, ); }); @@ -265,15 +242,13 @@ "and should use the other source's unquoted version if " 'concrete', () async { await d.dir('foo', [ - d.libPubspec('foo', '0.2.3', sdk: '^1.8.0'), + d.libPubspec('foo', '0.2.3'), ]).create(); await setUpDependency( - sdk: '^1.8.0', {'path': path.join(d.sandbox, 'foo'), 'version': '0.2.3'}, ); await expectValidationError( ' foo: 0.2.3', - environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'}, ); }); }); @@ -318,20 +293,18 @@ }); test('with a dependency on a pre-release without being one', () async { - (await servePackages()).serve('foo', '1.2.3-dev', sdk: '^1.8.0'); + (await servePackages()).serve('foo', '1.2.3-dev'); await d.dir(appPath, [ d.libPubspec( 'test_pkg', '1.0.0', deps: {'foo': '^1.2.3-dev'}, - sdk: '>=1.8.0 <2.0.0', ) ]).create(); await expectValidationWarning( 'Packages dependent on a pre-release', - environment: {'_PUB_TEST_SDK_VERSION': '1.8.0'}, ); }); test( @@ -427,157 +400,6 @@ await expectValidationWarning(' foo: ">1.2.3 <2.0.0"'); }); }); - - group('has a ^ dependency', () { - test('with a too-broad SDK constraint', () async { - (await servePackages()).serve('foo', '1.2.3', sdk: '^1.4.0'); - await d.dir(appPath, [ - d.libPubspec( - 'test_pkg', - '1.0.0', - deps: {'foo': '^1.2.3'}, - sdk: '>=1.5.0 <2.0.0', - ) - ]).create(); - - await expectValidationError( - ' sdk: "^1.8.0"', - environment: {'_PUB_TEST_SDK_VERSION': '1.5.0'}, - ); - }); - }); - - group('has a git path dependency', () { - test('without an SDK constraint', () async { - // Ensure we don't report anything from the real pub.dev. - await setUpDependency({}); - await d.git('foo', [ - d.dir('subdir', [ - d.libPubspec('foo', '1.0.0', extras: {'dependencies': {}}) - ]), - ]).create(); - await d.dir(appPath, [ - d.libPubspec( - 'integration_pkg', - '1.0.0', - deps: { - 'foo': { - 'git': {'url': d.path('foo'), 'path': 'subdir'} - }, - }, - sdk: '>=1.0.0 <4.0.0', - ) - ]).create(); - - await expectValidation( - error: allOf( - contains(' sdk: "^2.0.0"'), - contains(' foo: any'), - ), - exitCode: DATA, - ); - }); - - test('with a too-broad SDK constraint', () async { - // Ensure we don't report anything from the real pub.dev. - await setUpDependency({}); - await d.git('foo', [ - d.dir( - 'subdir', - [d.libPubspec('foo', '1.0.0', sdk: '>=0.0.0 <3.0.0')], - ), - ]).create(); - await d.dir(appPath, [ - d.libPubspec( - 'integration_pkg', - '1.0.0', - deps: { - 'foo': { - 'git': {'url': d.path('foo'), 'path': 'subdir'} - } - }, - sdk: '>=1.24.0 <3.0.0', - ) - ]).create(); - - await expectValidation( - error: allOf([ - contains(' sdk: "^2.0.0"'), - contains(' foo: any'), - ]), - environment: {'_PUB_TEST_SDK_VERSION': '1.24.0'}, - exitCode: DATA, - ); - }); - }); - - test('depends on Flutter from a non-SDK source', () async { - (await servePackages()).serve('flutter', '1.5.0'); - await d.dir(appPath, [ - d.libPubspec('test_pkg', '1.0.0', deps: {'flutter': '>=1.2.3 <2.0.0'}) - ]).create(); - - await expectValidationError('sdk: >=1.2.3 <2.0.0'); - }); - - test('depends on a Flutter package with a too-broad SDK constraint', - () async { - await d.dir('flutter', [d.file('version', '1.2.3')]).create(); - await flutterPackage('foo', sdk: 'any').create(); - await package( - deps: { - 'foo': {'sdk': 'flutter', 'version': '>=1.2.3 <2.0.0'} - }, - sdk: '>=1.18.0 <2.0.0', - ).create(); - - await expectValidationError( - 'sdk: "^1.19.0"', - environment: { - '_PUB_TEST_SDK_VERSION': '1.19.0', - 'FLUTTER_ROOT': path.join(d.sandbox, 'flutter'), - }, - ); - }); - - test('depends on a Flutter package with no SDK constraint', () async { - await d.dir('flutter', [d.file('version', '1.2.3')]).create(); - await flutterPackage('foo', sdk: '>=0.0.0 <1.0.0').create(); - await package( - sdk: '>=0.0.0 <=0.0.1', - deps: { - 'foo': {'sdk': 'flutter', 'version': '>=1.2.3 <2.0.0'} - }, - ).create(); - - await expectValidationError( - 'sdk: "^1.19.0"', - environment: { - '_PUB_TEST_SDK_VERSION': '0.0.0', - 'FLUTTER_ROOT': path.join(d.sandbox, 'flutter'), - }, - ); - }); - - test('depends on a Fuchsia package with a too-broad SDK constraint', - () async { - await fuschiaPackage('foo', sdk: '>=0.0.0 <3.0.0').create(); - - await package( - sdk: '>=2.0.0-dev.50.0 <2.0.2', - deps: { - 'foo': {'sdk': 'fuchsia', 'version': '>=1.2.3 <2.0.0'} - }, - ).create(); - - await expectValidationError( - 'sdk: ">=2.0.0 <2.0.2"', - environment: { - 'FUCHSIA_DART_SDK_ROOT': path.join(d.sandbox, 'fuchsia'), - '_PUB_TEST_SDK_VERSION': '2.0.1-dev.51.0', - }, - ); - }); }); } @@ -599,13 +421,12 @@ d.Descriptor flutterPackage( String name, { Map<String, String> deps = const {}, - String? sdk, }) { return d.dir('flutter', [ d.dir('packages', [ d.dir(name, [ d.libDir(name, 'f(x) => 2 * x;'), - d.libPubspec(name, '1.5.0', deps: deps, sdk: sdk), + d.libPubspec(name, '1.5.0', deps: deps), ]), ]), ]);
diff --git a/test/validator/flutter_constraint_test.dart b/test/validator/flutter_constraint_test.dart index f477038..815e6e4 100644 --- a/test/validator/flutter_constraint_test.dart +++ b/test/validator/flutter_constraint_test.dart
@@ -12,7 +12,6 @@ error: error, args: ['publish', '--dry-run'], environment: { - '_PUB_TEST_SDK_VERSION': '2.12.0', 'FLUTTER_ROOT': fakeFlutterRoot.io.path, }, workingDirectory: d.path(appPath), @@ -36,16 +35,13 @@ 'homepage': 'https://example.com/', 'version': '1.0.0', 'environment': { - 'sdk': '>=2.9.0 <3.0.0', + 'sdk': '^3.0.0', if (flutterConstraint != null) 'flutter': flutterConstraint }, }), ]).create(); await pubGet( - environment: { - '_PUB_TEST_SDK_VERSION': '2.12.0', - 'FLUTTER_ROOT': fakeFlutterRoot.io.path - }, + environment: {'FLUTTER_ROOT': fakeFlutterRoot.io.path}, ); }
diff --git a/test/validator/language_version_test.dart b/test/validator/language_version_test.dart index cfcb0d8..9832fd2 100644 --- a/test/validator/language_version_test.dart +++ b/test/validator/language_version_test.dart
@@ -2,78 +2,74 @@ // 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/src/validator.dart'; -import 'package:pub/src/validator/language_version.dart'; import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; import 'utils.dart'; -Validator validator() => LanguageVersionValidator(); - Future<void> setup({ required String sdkConstraint, String? libraryLanguageVersion, }) async { await d.validPackage.create(); await d.dir(appPath, [ - d.pubspec({ - 'name': 'test_pkg', - 'version': '1.0.0', - 'environment': {'sdk': sdkConstraint}, - }), + d.validPubspec( + extras: { + 'environment': {'sdk': sdkConstraint}, + }, + ), d.dir('lib', [ if (libraryLanguageVersion != null) d.file('library.dart', '// @dart = $libraryLanguageVersion\n'), ]) ]).create(); - await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '2.7.0'}); } void main() { group('should consider a package valid if it', () { test('has no library-level language version annotations', () async { - await setup(sdkConstraint: '>=2.4.0 <3.0.0'); - await expectValidationDeprecated(validator); + await setup(sdkConstraint: '^3.0.0'); + await expectValidation(); }); test('opts in to older language versions', () async { await setup( - sdkConstraint: '>=2.4.0 <3.0.0', - libraryLanguageVersion: '2.0', + sdkConstraint: '^3.0.0', + libraryLanguageVersion: '2.14', ); - await d.dir(appPath, []).create(); - await expectValidationDeprecated(validator); + await expectValidation(); }); test('opts in to same language versions', () async { await setup( - sdkConstraint: '>=2.4.0 <3.0.0', - libraryLanguageVersion: '2.4', + sdkConstraint: '^3.0.0', + libraryLanguageVersion: '3.0', ); - await d.dir(appPath, []).create(); - await expectValidationDeprecated(validator); + await expectValidation(); }); test('opts in to older language version, with non-range constraint', () async { - await setup(sdkConstraint: '2.7.0', libraryLanguageVersion: '2.3'); - await d.dir(appPath, []).create(); - await expectValidationDeprecated(validator); + await setup(sdkConstraint: '3.1.2+3', libraryLanguageVersion: '2.18'); + await expectValidation(); }); }); - group('should error if it', () { + group('should warn if it', () { test('opts in to a newer version.', () async { await setup( - sdkConstraint: '>=2.4.1 <3.0.0', - libraryLanguageVersion: '2.5', + sdkConstraint: '^3.0.0', + libraryLanguageVersion: '3.1', ); - await expectValidationDeprecated(validator, errors: isNotEmpty); + await expectValidationWarning( + 'The language version override can\'t specify a version greater than the latest known language version', + ); }); test('opts in to a newer version, with non-range constraint.', () async { - await setup(sdkConstraint: '2.7.0', libraryLanguageVersion: '2.8'); - await expectValidationDeprecated(validator, errors: isNotEmpty); + await setup(sdkConstraint: '3.1.2+3', libraryLanguageVersion: '3.2'); + await expectValidationWarning( + 'The language version override can\'t specify a version greater than the latest known language version', + ); }); }); }
diff --git a/test/validator/relative_version_numbering_test.dart b/test/validator/relative_version_numbering_test.dart index 34dc23d..6b73dff 100644 --- a/test/validator/relative_version_numbering_test.dart +++ b/test/validator/relative_version_numbering_test.dart
@@ -27,44 +27,6 @@ void main() { group('should consider a package valid if it', () { - test('is not opting in to null-safety with previous non-null-safe version', - () async { - final server = await servePackages(); - server.serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ); - - await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - await expectValidationDeprecated(validator); - }); - - test( - 'is not opting in to null-safety with previous non-null-safe version. ' - 'Even with a later null-safe version', () async { - await servePackages() - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '2.0.0', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ); - - await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - await expectValidationDeprecated(validator); - }); - test('is opting in to null-safety with previous null-safe version', () async { final server = await servePackages(); @@ -125,36 +87,6 @@ await expectValidationDeprecated(validator); }); - test('is not opting in to null-safety with no existing versions', () async { - await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - await servePackages(); - - await expectValidationDeprecated(validator); - }); - - test( - 'is not opting in to null-safety with previous null-safe stable version. ' - 'With an in-between not null-safe prerelease', () async { - await servePackages() - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '0.0.2-dev', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ); - - await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - await expectValidationDeprecated(validator); - }); - test( 'opts in to null-safety, with previous stable version not-null-safe. ' 'With an in-between non-null-safe prerelease', () async { @@ -196,44 +128,6 @@ }); test( - 'is not opting in to null-safety with no existing stable versions. ' - 'With a previous in-between null-safe prerelease', () async { - await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - final server = await servePackages(); - server.serve( - 'test_pkg', - '0.0.2-dev', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ); - - await expectValidationDeprecated(validator, hints: isNotEmpty); - }); - test( - 'is not opting in to null-safety with previous non-null-safe stable version. ' - 'With an in-between null-safe prerelease', () async { - await servePackages() - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '0.0.2-dev', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ); - - await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - await expectValidationDeprecated(validator, hints: isNotEmpty); - }); - - test( 'opts in to null-safety, with previous version not-null-safe. ' 'Even with a later null-safe version', () async { await servePackages() @@ -256,44 +150,6 @@ await expectValidationDeprecated(validator, hints: isNotEmpty); }); - test('is not opting in to null-safety with previous null-safe version', - () async { - final server = await servePackages(); - server.serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ); - - await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - await expectValidationDeprecated(validator, hints: isNotEmpty); - }); - - test( - 'is not opting in to null-safety with previous null-safe version. ' - 'Even with a later non-null-safe version', () async { - await servePackages() - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '2.0.0', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ); - - await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - await expectValidationDeprecated(validator, hints: isNotEmpty); - }); - test( 'is opting in to null-safety with previous null-safe stable version. ' 'with an in-between non-null-safe prerelease', () async {
diff --git a/test/validator/sdk_constraint_test.dart b/test/validator/sdk_constraint_test.dart index 4f0e2db..b050c72 100644 --- a/test/validator/sdk_constraint_test.dart +++ b/test/validator/sdk_constraint_test.dart
@@ -94,66 +94,6 @@ ); }); - test( - 'has a Flutter SDK constraint with a too-broad SDK ' - 'constraint', () async { - await d.dir(appPath, [ - d.pubspec({ - 'name': 'test_pkg', - 'version': '1.0.0', - 'environment': {'sdk': '>=1.18.0 <1.50.0', 'flutter': '^1.2.3'} - }) - ]).create(); - await expectValidationDeprecated( - sdkConstraint, - errors: anyElement(contains('">=1.19.0 <1.50.0"')), - ); - }); - - test('has a Flutter SDK constraint with no SDK constraint', () async { - await d.dir(appPath, [ - d.rawPubspec({ - 'name': 'test_pkg', - 'version': '1.0.0', - 'environment': {'flutter': '^1.2.3'} - }) - ]).create(); - await expectValidationDeprecated( - sdkConstraint, - errors: anyElement(contains('"^1.19.0"')), - ); - }); - - test( - 'has a Fuchsia SDK constraint with a too-broad SDK ' - 'constraint', () async { - await d.dir(appPath, [ - d.rawPubspec({ - 'name': 'test_pkg', - 'version': '1.0.0-dev.1', - 'environment': {'sdk': '>=2.0.0-dev.50.0 <2.0.0', 'fuchsia': '^1.2.3'} - }) - ]).create(); - await expectValidationDeprecated( - sdkConstraint, - errors: anyElement(contains('"^2.0.0"')), - ); - }); - - test('has a Fuchsia SDK constraint with no SDK constraint', () async { - await d.dir(appPath, [ - d.rawPubspec({ - 'name': 'test_pkg', - 'version': '1.0.0', - 'environment': {'fuchsia': '^1.2.3'} - }) - ]).create(); - await expectValidationDeprecated( - sdkConstraint, - errors: anyElement(contains('"^2.0.0"')), - ); - }); - test('depends on a pre-release sdk from a non-pre-release', () async { await d.dir(appPath, [ d.libPubspec('test_pkg', '1.0.0', sdk: '>=1.8.0-dev.1 <2.0.0')
diff --git a/test/validator/utils.dart b/test/validator/utils.dart index ffbe892..2262a55 100644 --- a/test/validator/utils.dart +++ b/test/validator/utils.dart
@@ -28,13 +28,16 @@ error, int exitCode = 0, Map<String, String> environment = const {}, + List<String>? extraArgs, + String? workingDirectory, }) async { await runPub( error: error ?? contains('Package has 0 warnings.'), - args: ['publish', '--dry-run'], + args: ['publish', '--dry-run', ...?extraArgs], // workingDirectory: d.path(appPath), exitCode: exitCode, environment: environment, + workingDirectory: workingDirectory, ); }