blob: 84ada609cfb4f06cc753fd70cc0c54a61a2464ae [file] [edit]
// 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:convert' show jsonDecode;
import 'package:checks/checks.dart';
import 'package:package_config/package_config_types.dart';
import 'package:test/scaffolding.dart';
import 'src/checks.dart';
import 'src/util.dart';
void main() {
var unique = Object();
var root = Uri.file('/tmp/root/');
group('LanguageVersion', () {
test('minimal', () {
var version = LanguageVersion(3, 5);
check(version.major).equals(3);
check(version.minor).equals(5);
});
test('negative major', () {
check(() => LanguageVersion(-1, 1))
.throws<RangeError>()
.has((e) => e.name, 'name')
.isNotNull()
.contains('major');
});
test('negative minor', () {
check(() => LanguageVersion(1, -1))
.throws<RangeError>()
.has((e) => e.name, 'name')
.isNotNull()
.contains('minor');
});
test('minimal parse', () {
var version = LanguageVersion.parse('3.5');
check(version.major).equals(3);
check(version.minor).equals(5);
});
void failParse(String name, String input) {
test('$name - error', () {
check(() => LanguageVersion.parse(input)).throws<PackageConfigError>();
check(() => LanguageVersion.parse(input)).throws<FormatException>();
var failed = false;
var actual = LanguageVersion.parse(
input,
onError: (_) {
failed = true;
},
);
check(failed).isTrue();
check(actual).isA<LanguageVersion>();
});
}
failParse('Leading zero major', '01.1');
failParse('Leading zero minor', '1.01');
failParse('Sign+ major', '+1.1');
failParse('Sign- major', '-1.1');
failParse('Sign+ minor', '1.+1');
failParse('Sign- minor', '1.-1');
failParse('WhiteSpace 1', ' 1.1');
failParse('WhiteSpace 2', '1 .1');
failParse('WhiteSpace 3', '1. 1');
failParse('WhiteSpace 4', '1.1 ');
test('compareTo valid', () {
var version = LanguageVersion(3, 5);
void comparesBefore(Subject<int> comparison) => comparison.isLessThan(0);
void comparesAfter(Subject<int> comparison) =>
comparison.isGreaterThan(0);
void comparesEqual(Subject<int> comparison) => comparison.equals(0);
for (var (otherVersion, checkOrder) in [
(version, comparesEqual), // Identical.
(LanguageVersion(3, 5), comparesEqual), // Same major, same minor.
(LanguageVersion(3, 4), comparesAfter), // Same major, lower minor.
(LanguageVersion(3, 6), comparesBefore), // Same major, greater minor.
(LanguageVersion(2, 5), comparesAfter), // Lower major, same minor.
(LanguageVersion(2, 4), comparesAfter), // Lower major, lower minor.
(LanguageVersion(2, 6), comparesAfter), // Lower major, greater minor.
(LanguageVersion(4, 5), comparesBefore), // Greater major, same minor.
(LanguageVersion(4, 4), comparesBefore), // Greater major, lower minor.
(
LanguageVersion(4, 6),
comparesBefore,
), // Greater major, greater minor.
]) {
checkOrder(check(version).compareTo(otherVersion));
}
});
test('compareTo invalid', () {
var validVersion = LanguageVersion(3, 5);
var invalidVersion = LanguageVersion.parse('', onError: (_) {});
check(invalidVersion).isNotValid;
check(validVersion).compareTo(invalidVersion).isGreaterThan(0);
check(invalidVersion).compareTo(validVersion).isLessThan(0);
});
test('relational valid', () {
/// Test that the relational comparisons between two valid versions
/// match the results of `compareTo`.
void testComparisons(
LanguageVersion version,
LanguageVersion otherVersion,
) {
check(
version == otherVersion,
).equals(version.compareTo(otherVersion) == 0);
check(
version < otherVersion,
).equals(version.compareTo(otherVersion) < 0);
check(
version <= otherVersion,
).equals(version.compareTo(otherVersion) <= 0);
check(
version > otherVersion,
).equals(version.compareTo(otherVersion) > 0);
check(
version >= otherVersion,
).equals(version.compareTo(otherVersion) >= 0);
}
var version = LanguageVersion(3, 5);
// Check relational comparisons of a version to itself.
testComparisons(version, version);
// Check relational comparisons of a version to versions with all
// possible combinations of minor and major versions that are
// the same, lower, and greater.
for (final major in [2, 3, 4]) {
for (final minor in [4, 5, 6]) {
testComparisons(version, LanguageVersion(major, minor));
}
}
});
test('relational operators', () {
var v1 = LanguageVersion(2, 6);
var v2 = LanguageVersion(3, 5);
check(v1 == v1, because: 'v1 == v1').isTrue();
check(v1 == v2, because: 'v1 == v2').isFalse();
check(v2 == v1, because: 'v2 == v1').isFalse();
check(v2 == v2, because: 'v2 == v2').isTrue();
check(v1 < v1, because: 'v1 < v1').isFalse();
check(v1 < v2, because: 'v1 < v2').isTrue();
check(v2 < v1, because: 'v2 < v1').isFalse();
check(v2 < v2, because: 'v2 < v2').isFalse();
check(v1 <= v1, because: 'v1 <= v1').isTrue();
check(v1 <= v2, because: 'v1 <= v2').isTrue();
check(v2 <= v1, because: 'v2 <= v1').isFalse();
check(v2 <= v2, because: 'v2 <= v2').isTrue();
check(v1 > v1, because: 'v1 > v1').isFalse();
check(v1 > v2, because: 'v1 > v2').isFalse();
check(v2 > v1, because: 'v2 > v1').isTrue();
check(v2 > v2, because: 'v2 > v2').isFalse();
check(v1 >= v1, because: 'v1 >= v1').isTrue();
check(v1 >= v2, because: 'v1 >= v2').isFalse();
check(v2 >= v1, because: 'v2 >= v1').isTrue();
check(v2 >= v2, because: 'v2 >= v2').isTrue();
});
test('relational invalid', () {
void testComparisonsWithInvalid(
LanguageVersion version,
LanguageVersion otherVersion,
) {
check(version == otherVersion).equals(identical(version, otherVersion));
check(() => version < otherVersion).throws<UnsupportedError>();
check(() => version <= otherVersion).throws<UnsupportedError>();
check(() => version > otherVersion).throws<UnsupportedError>();
check(() => version >= otherVersion).throws<UnsupportedError>();
}
var validVersion = LanguageVersion(3, 5);
check(validVersion).isValid;
var invalidVersion = LanguageVersion.parse('', onError: (_) {});
check(invalidVersion).isNotValid;
var differentInvalidVersion = LanguageVersion.parse('-', onError: (_) {});
check(differentInvalidVersion).isNotValid;
check(invalidVersion).notIdenticalTo(differentInvalidVersion);
testComparisonsWithInvalid(validVersion, invalidVersion);
testComparisonsWithInvalid(invalidVersion, validVersion);
testComparisonsWithInvalid(invalidVersion, invalidVersion);
testComparisonsWithInvalid(invalidVersion, differentInvalidVersion);
});
});
group('Package', () {
test('minimal', () {
var package = Package('name', root, extraData: unique);
check(package.name).equals('name');
check(package.root).equals(root);
check(package.packageUriRoot).equals(root);
check(package.languageVersion).isNull();
check(package.extraData).identicalTo(unique);
});
test('absolute package root', () {
var version = LanguageVersion(1, 1);
var absolute = root.resolve('foo/bar/');
var package = Package(
'name',
root,
packageUriRoot: absolute,
relativeRoot: false,
languageVersion: version,
extraData: unique,
);
check(package.name).equals('name');
check(package.root).equals(root);
check(package.packageUriRoot).equals(absolute);
check(package.languageVersion).equals(version);
check(package.extraData).identicalTo(unique);
check(package.relativeRoot).isFalse();
});
test('relative package root', () {
var relative = Uri.parse('foo/bar/');
var absolute = root.resolveUri(relative);
var package = Package(
'name',
root,
packageUriRoot: relative,
relativeRoot: true,
extraData: unique,
);
check(package.name).equals('name');
check(package.root).equals(root);
check(package.packageUriRoot).equals(absolute);
check(package.relativeRoot).isTrue();
check(package.languageVersion).isNull();
check(package.extraData).identicalTo(unique);
});
for (var badName in ['a/z', 'a:z', '', '...']) {
test("Invalid name '$badName'", () {
check(() => Package(badName, root)).throws<PackageConfigError>();
});
}
test('Invalid root, not absolute', () {
check(
() => Package('name', Uri.parse('/foo/')),
).throws<PackageConfigError>();
});
test('Invalid root, not ending in slash', () {
check(
() => Package('name', Uri.parse('file:///foo')),
).throws<PackageConfigError>();
});
test('invalid package root, not ending in slash', () {
check(
() => Package('name', root, packageUriRoot: Uri.parse('foo')),
).throws<PackageConfigError>();
});
test('invalid package root, not inside root', () {
check(
() => Package('name', root, packageUriRoot: Uri.parse('../baz/')),
).throws<PackageConfigError>();
});
});
group('package config', () {
test('empty', () {
var empty = PackageConfig([], extraData: unique);
check(empty.version).equals(2);
check(empty.packages).isEmpty();
check(empty.extraData).identicalTo(unique);
check(empty.resolve(pkg('a', 'b'))).isNull();
});
test('single', () {
var package = Package('name', root);
var single = PackageConfig([package], extraData: unique);
check(single.version).equals(2);
check(single.packages).length.equals(1);
check(single.extraData).identicalTo(unique);
check(single.resolve(pkg('a', 'b'))).isNull();
var resolved = single.resolve(pkg('name', 'a/b'));
check(resolved).equals(root.resolve('a/b'));
});
});
test('writeString', () {
var config = PackageConfig(
[
Package(
'foo',
Uri.parse('file:///pkg/foo/'),
packageUriRoot: Uri.parse('file:///pkg/foo/lib/'),
relativeRoot: false,
languageVersion: LanguageVersion(2, 4),
extraData: {'foo': 'foo!'},
),
Package(
'bar',
Uri.parse('file:///pkg/bar/'),
packageUriRoot: Uri.parse('file:///pkg/bar/lib/'),
relativeRoot: true,
extraData: {'bar': 'bar!'},
),
],
extraData: {'extra': 'data'},
);
var buffer = StringBuffer();
PackageConfig.writeString(config, buffer, Uri.parse('file:///pkg/'));
var text = buffer.toString();
var json = jsonDecode(text); // Is valid JSON.
check(json).isA<Map<String, dynamic>>()
..['configVersion'].equals(2)
..['extra'].equals('data')
..['packages'].isA<Iterable<Object?>>().unorderedMatches([
(Subject<Object?> s) => s.isA<Map<Object?, Object?>>().deepEquals({
'name': 'foo',
'rootUri': 'file:///pkg/foo/',
'packageUri': 'lib/',
'languageVersion': '2.4',
'foo': 'foo!',
}),
(Subject<Object?> s) => s.isA<Map<Object?, Object?>>().deepEquals({
'name': 'bar',
'rootUri': 'bar/',
'packageUri': 'lib/',
'bar': 'bar!',
}),
]);
});
}