Fix Package constructor not accepting relative packageUriRoot. (#82)
* Fix Package constructor not accepting relative packageUriRoot.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3015523..6dcae80 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.9.3
+
+- Fix `Package` constructor not accepting relative `packageUriRoot`.
+
## 1.9.2
- Updated to support new rules for picking `package_config.json` over
diff --git a/lib/src/package_config.dart b/lib/src/package_config.dart
index 364df75..30c758a 100644
--- a/lib/src/package_config.dart
+++ b/lib/src/package_config.dart
@@ -219,7 +219,7 @@
/// The [packageUriRoot], if provided, must be either an absolute
/// directory URI or a relative URI reference which is then resolved
/// relative to [root]. It must then also be a subdirectory of [root],
- /// or the same directory.
+ /// or the same directory, and must end with `/`.
/// If [languageVersion] is supplied, it must be a valid Dart language
/// version, which means two decimal integer literals separated by a `.`,
/// where the integer literals have no leading zeros unless they are
diff --git a/lib/src/package_config_impl.dart b/lib/src/package_config_impl.dart
index f68a9ea..9e23af0 100644
--- a/lib/src/package_config_impl.dart
+++ b/lib/src/package_config_impl.dart
@@ -214,7 +214,10 @@
root = root.replace(path: root.path + "/");
}
}
- if (!fatalError) {
+ if (packageUriRoot == null) {
+ packageUriRoot = root;
+ } else if (!fatalError) {
+ packageUriRoot = root.resolveUri(packageUriRoot);
if (!isAbsoluteDirectoryUri(packageUriRoot)) {
onError(PackageConfigArgumentError(
packageUriRoot,
diff --git a/pubspec.yaml b/pubspec.yaml
index 3f5ec27..b7d5969 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: package_config
-version: 1.9.2
+version: 1.9.3
description: Support for working with Package Configuration files.
homepage: https://github.com/dart-lang/package_config
diff --git a/test/package_config_impl_test.dart b/test/package_config_impl_test.dart
new file mode 100644
index 0000000..6921118
--- /dev/null
+++ b/test/package_config_impl_test.dart
@@ -0,0 +1,145 @@
+// 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:package_config/package_config_types.dart";
+import "package:test/test.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);
+ expect(version.major, 3);
+ expect(version.minor, 5);
+ });
+
+ test("negative major", () {
+ expect(() => LanguageVersion(-1, 1), throwsArgumentError);
+ });
+
+ test("negative minor", () {
+ expect(() => LanguageVersion(1, -1), throwsArgumentError);
+ });
+
+ test("minimal parse", () {
+ var version = LanguageVersion.parse("3.5");
+ expect(version.major, 3);
+ expect(version.minor, 5);
+ });
+
+ void failParse(String name, String input) {
+ test("$name - error", () {
+ expect(() => LanguageVersion.parse(input),
+ throwsA(TypeMatcher<PackageConfigError>()));
+ expect(() => LanguageVersion.parse(input), throwsFormatException);
+ var failed = false;
+ var actual = LanguageVersion.parse(input, onError: (_) {
+ failed = true;
+ });
+ expect(failed, true);
+ expect(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 ");
+ });
+
+ group("Package", () {
+ test("minimal", () {
+ var package = Package("name", root, extraData: unique);
+ expect(package.name, "name");
+ expect(package.root, root);
+ expect(package.packageUriRoot, root);
+ expect(package.languageVersion, null);
+ expect(package.extraData, same(unique));
+ });
+
+ test("absolute package root", () {
+ var version = LanguageVersion(1, 1);
+ var absolute = root.resolve("foo/bar/");
+ var package = Package("name", root,
+ packageUriRoot: absolute,
+ languageVersion: version,
+ extraData: unique);
+ expect(package.name, "name");
+ expect(package.root, root);
+ expect(package.packageUriRoot, absolute);
+ expect(package.languageVersion, version);
+ expect(package.extraData, same(unique));
+ });
+
+ test("relative package root", () {
+ var relative = Uri.parse("foo/bar/");
+ var absolute = root.resolveUri(relative);
+ var package =
+ Package("name", root, packageUriRoot: relative, extraData: unique);
+ expect(package.name, "name");
+ expect(package.root, root);
+ expect(package.packageUriRoot, absolute);
+ expect(package.languageVersion, null);
+ expect(package.extraData, same(unique));
+ });
+
+ for (var badName in ["a/z", "a:z", "", "..."]) {
+ test("Invalid name '$badName'", () {
+ expect(() => Package(badName, root), throwsPackageConfigError);
+ });
+ }
+
+ test("Invalid root, not absolute", () {
+ expect(
+ () => Package("name", Uri.parse("/foo/")), throwsPackageConfigError);
+ });
+
+ test("Invalid root, not ending in slash", () {
+ expect(() => Package("name", Uri.parse("file:///foo")),
+ throwsPackageConfigError);
+ });
+
+ test("invalid package root, not ending in slash", () {
+ expect(() => Package("name", root, packageUriRoot: Uri.parse("foo")),
+ throwsPackageConfigError);
+ });
+
+ test("invalid package root, not inside root", () {
+ expect(() => Package("name", root, packageUriRoot: Uri.parse("../baz/")),
+ throwsPackageConfigError);
+ });
+ });
+
+ group("package config", () {
+ test("emtpy", () {
+ var empty = PackageConfig([], extraData: unique);
+ expect(empty.version, 2);
+ expect(empty.packages, isEmpty);
+ expect(empty.extraData, same(unique));
+ expect(empty.resolve(pkg("a", "b")), isNull);
+ });
+
+ test("single", () {
+ var package = Package("name", root);
+ var single = PackageConfig([package], extraData: unique);
+ expect(single.version, 2);
+ expect(single.packages, hasLength(1));
+ expect(single.extraData, same(unique));
+ expect(single.resolve(pkg("a", "b")), isNull);
+ var resolved = single.resolve(pkg("name", "a/b"));
+ expect(resolved, root.resolve("a/b"));
+ });
+ });
+}
+
+final Matcher throwsPackageConfigError = throwsA(isA<PackageConfigError>());