| // Copyright (c) 2018, 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:io'; |
| |
| import 'package:pub_semver/pub_semver.dart'; |
| import 'package:pubspec_parse/pubspec_parse.dart'; |
| import 'package:test/test.dart'; |
| |
| import 'test_utils.dart'; |
| |
| void main() { |
| group('hosted', _hostedDependency); |
| group('git', _gitDependency); |
| group('sdk', _sdkDependency); |
| group('path', _pathDependency); |
| |
| group('errors', () { |
| test('List', () { |
| _expectThrows( |
| [], |
| r''' |
| line 4, column 10: Unsupported value for "dep". Not a valid dependency value. |
| ╷ |
| 4 │ "dep": [] |
| │ ^^ |
| ╵''', |
| ); |
| }); |
| |
| test('int', () { |
| _expectThrows( |
| 42, |
| r''' |
| line 4, column 10: Unsupported value for "dep". Not a valid dependency value. |
| ╷ |
| 4 │ "dep": 42 |
| │ ┌──────────^ |
| 5 │ │ } |
| │ └─^ |
| ╵''', |
| ); |
| }); |
| |
| test('map with too many keys', () { |
| _expectThrows( |
| {'path': 'a', 'git': 'b'}, |
| r''' |
| line 6, column 11: Unsupported value for "git". A dependency may only have one source. |
| ╷ |
| 6 │ "git": "b" |
| │ ^^^ |
| ╵''', |
| ); |
| }); |
| |
| test('map with unsupported keys', () { |
| _expectThrows( |
| {'bob': 'a', 'jones': 'b'}, |
| r''' |
| line 5, column 4: Unrecognized keys: [bob]; supported keys: [sdk, git, path, hosted] |
| ╷ |
| 5 │ "bob": "a", |
| │ ^^^^^ |
| ╵''', |
| ); |
| }); |
| }); |
| } |
| |
| void _hostedDependency() { |
| test('null', () async { |
| final dep = await _dependency<HostedDependency>(null); |
| expect(dep.version.toString(), 'any'); |
| expect(dep.hosted, isNull); |
| expect(dep.toString(), 'HostedDependency: any'); |
| }); |
| |
| test('empty map', () async { |
| final dep = await _dependency<HostedDependency>({}); |
| expect(dep.hosted, isNull); |
| expect(dep.toString(), 'HostedDependency: any'); |
| }); |
| |
| test('string version', () async { |
| final dep = await _dependency<HostedDependency>('^1.0.0'); |
| expect(dep.version.toString(), '^1.0.0'); |
| expect(dep.hosted, isNull); |
| expect(dep.toString(), 'HostedDependency: ^1.0.0'); |
| }); |
| |
| test('bad string version', () { |
| _expectThrows( |
| 'not a version', |
| r''' |
| line 4, column 10: Unsupported value for "dep". Could not parse version "not a version". Unknown text at "not a version". |
| ╷ |
| 4 │ "dep": "not a version" |
| │ ^^^^^^^^^^^^^^^ |
| ╵''', |
| ); |
| }); |
| |
| test('map w/ just version', () async { |
| final dep = await _dependency<HostedDependency>({'version': '^1.0.0'}); |
| expect(dep.version.toString(), '^1.0.0'); |
| expect(dep.hosted, isNull); |
| expect(dep.toString(), 'HostedDependency: ^1.0.0'); |
| }); |
| |
| test('map w/ version and hosted as Map', () async { |
| final dep = await _dependency<HostedDependency>({ |
| 'version': '^1.0.0', |
| 'hosted': {'name': 'hosted_name', 'url': 'https://hosted_url'}, |
| }); |
| expect(dep.version.toString(), '^1.0.0'); |
| expect(dep.hosted!.name, 'hosted_name'); |
| expect(dep.hosted!.url.toString(), 'https://hosted_url'); |
| expect(dep.toString(), 'HostedDependency: ^1.0.0'); |
| }); |
| |
| test('map /w hosted as a map without name', () async { |
| final dep = await _dependency<HostedDependency>( |
| { |
| 'version': '^1.0.0', |
| 'hosted': {'url': 'https://hosted_url'}, |
| }, |
| skipTryPub: true, // todo: Unskip once pub supports this syntax |
| ); |
| expect(dep.version.toString(), '^1.0.0'); |
| expect(dep.hosted!.declaredName, isNull); |
| expect(dep.hosted!.name, 'dep'); |
| expect(dep.hosted!.url.toString(), 'https://hosted_url'); |
| expect(dep.toString(), 'HostedDependency: ^1.0.0'); |
| }); |
| |
| test('map w/ bad version value', () { |
| _expectThrows( |
| { |
| 'version': 'not a version', |
| 'hosted': {'name': 'hosted_name', 'url': 'hosted_url'}, |
| }, |
| r''' |
| line 5, column 15: Unsupported value for "version". Could not parse version "not a version". Unknown text at "not a version". |
| ╷ |
| 5 │ "version": "not a version", |
| │ ^^^^^^^^^^^^^^^ |
| ╵''', |
| ); |
| }); |
| |
| test('map w/ extra keys should fail', () { |
| _expectThrows( |
| { |
| 'version': '^1.0.0', |
| 'hosted': {'name': 'hosted_name', 'url': 'hosted_url'}, |
| 'not_supported': null, |
| }, |
| r''' |
| line 10, column 4: Unrecognized keys: [not_supported]; supported keys: [sdk, git, path, hosted] |
| ╷ |
| 10 │ "not_supported": null |
| │ ^^^^^^^^^^^^^^^ |
| ╵''', |
| ); |
| }); |
| |
| test('map w/ version and hosted as String', () async { |
| final dep = await _dependency<HostedDependency>( |
| {'version': '^1.0.0', 'hosted': 'hosted_url'}, |
| skipTryPub: true, // todo: Unskip once put supports this |
| ); |
| expect(dep.version.toString(), '^1.0.0'); |
| expect(dep.hosted!.declaredName, isNull); |
| expect(dep.hosted!.name, 'dep'); |
| expect(dep.hosted!.url, Uri.parse('hosted_url')); |
| expect(dep.toString(), 'HostedDependency: ^1.0.0'); |
| }); |
| |
| test('map w/ hosted as String', () async { |
| final dep = await _dependency<HostedDependency>({'hosted': 'hosted_url'}); |
| expect(dep.version, VersionConstraint.any); |
| expect(dep.hosted!.declaredName, isNull); |
| expect(dep.hosted!.name, 'dep'); |
| expect(dep.hosted!.url, Uri.parse('hosted_url')); |
| expect(dep.toString(), 'HostedDependency: any'); |
| }); |
| |
| test('map w/ null hosted should error', () { |
| _expectThrows( |
| {'hosted': null}, |
| r''' |
| line 5, column 4: These keys had `null` values, which is not allowed: [hosted] |
| ╷ |
| 5 │ "hosted": null |
| │ ^^^^^^^^ |
| ╵''', |
| ); |
| }); |
| |
| test('map w/ null version is fine', () async { |
| final dep = await _dependency<HostedDependency>({'version': null}); |
| expect(dep.version, VersionConstraint.any); |
| expect(dep.hosted, isNull); |
| expect(dep.toString(), 'HostedDependency: any'); |
| }); |
| } |
| |
| void _sdkDependency() { |
| test('without version', () async { |
| final dep = await _dependency<SdkDependency>({'sdk': 'flutter'}); |
| expect(dep.sdk, 'flutter'); |
| expect(dep.version, VersionConstraint.any); |
| expect(dep.toString(), 'SdkDependency: flutter'); |
| }); |
| |
| test('with version', () async { |
| final dep = await _dependency<SdkDependency>( |
| {'sdk': 'flutter', 'version': '>=1.2.3 <2.0.0'}, |
| ); |
| expect(dep.sdk, 'flutter'); |
| expect(dep.version.toString(), '>=1.2.3 <2.0.0'); |
| expect(dep.toString(), 'SdkDependency: flutter'); |
| }); |
| |
| test('null content', () { |
| _expectThrowsContaining( |
| {'sdk': null}, |
| r"type 'Null' is not a subtype of type 'String'", |
| ); |
| }); |
| |
| test('number content', () { |
| _expectThrowsContaining( |
| {'sdk': 42}, |
| r"type 'int' is not a subtype of type 'String'", |
| ); |
| }); |
| } |
| |
| void _gitDependency() { |
| test('string', () async { |
| final dep = await _dependency<GitDependency>({'git': 'url'}); |
| expect(dep.url.toString(), 'url'); |
| expect(dep.path, isNull); |
| expect(dep.ref, isNull); |
| expect(dep.toString(), 'GitDependency: url@url'); |
| }); |
| |
| test('string with version key is ignored', () async { |
| // Regression test for https://github.com/dart-lang/pubspec_parse/issues/13 |
| final dep = |
| await _dependency<GitDependency>({'git': 'url', 'version': '^1.2.3'}); |
| expect(dep.url.toString(), 'url'); |
| expect(dep.path, isNull); |
| expect(dep.ref, isNull); |
| expect(dep.toString(), 'GitDependency: url@url'); |
| }); |
| |
| test('string with user@ URL', () async { |
| final skipTryParse = Platform.environment.containsKey('TRAVIS'); |
| if (skipTryParse) { |
| print('FYI: not validating git@ URI on travis due to failure'); |
| } |
| final dep = await _dependency<GitDependency>( |
| {'git': 'git@localhost:dep.git'}, |
| skipTryPub: skipTryParse, |
| ); |
| expect(dep.url.toString(), 'ssh://git@localhost/dep.git'); |
| expect(dep.path, isNull); |
| expect(dep.ref, isNull); |
| expect(dep.toString(), 'GitDependency: url@ssh://git@localhost/dep.git'); |
| }); |
| |
| test('string with random extra key fails', () { |
| _expectThrows( |
| {'git': 'url', 'bob': '^1.2.3'}, |
| r''' |
| line 6, column 4: Unrecognized keys: [bob]; supported keys: [sdk, git, path, hosted] |
| ╷ |
| 6 │ "bob": "^1.2.3" |
| │ ^^^^^ |
| ╵''', |
| ); |
| }); |
| |
| test('map', () async { |
| final dep = await _dependency<GitDependency>({ |
| 'git': {'url': 'url', 'path': 'path', 'ref': 'ref'}, |
| }); |
| expect(dep.url.toString(), 'url'); |
| expect(dep.path, 'path'); |
| expect(dep.ref, 'ref'); |
| expect(dep.toString(), 'GitDependency: url@url'); |
| }); |
| |
| test('git - null content', () { |
| _expectThrows( |
| {'git': null}, |
| r''' |
| line 5, column 11: Unsupported value for "git". Must be a String or a Map. |
| ╷ |
| 5 │ "git": null |
| │ ┌───────────^ |
| 6 │ │ } |
| │ └──^ |
| ╵''', |
| ); |
| }); |
| |
| test('git - int content', () { |
| _expectThrows( |
| {'git': 42}, |
| r''' |
| line 5, column 11: Unsupported value for "git". Must be a String or a Map. |
| ╷ |
| 5 │ "git": 42 |
| │ ┌───────────^ |
| 6 │ │ } |
| │ └──^ |
| ╵''', |
| ); |
| }); |
| |
| test('git - empty map', () { |
| _expectThrowsContaining( |
| {'git': <String, dynamic>{}}, |
| r"type 'Null' is not a subtype of type 'String'", |
| ); |
| }); |
| |
| test('git - null url', () { |
| _expectThrowsContaining( |
| { |
| 'git': {'url': null}, |
| }, |
| r"type 'Null' is not a subtype of type 'String'", |
| ); |
| }); |
| |
| test('git - int url', () { |
| _expectThrowsContaining( |
| { |
| 'git': {'url': 42}, |
| }, |
| r"type 'int' is not a subtype of type 'String'", |
| ); |
| }); |
| } |
| |
| void _pathDependency() { |
| test('valid', () async { |
| final dep = await _dependency<PathDependency>({'path': '../path'}); |
| expect(dep.path, '../path'); |
| expect(dep.toString(), 'PathDependency: path@../path'); |
| }); |
| |
| test('valid with version key is ignored', () async { |
| final dep = await _dependency<PathDependency>( |
| {'path': '../path', 'version': '^1.2.3'}, |
| ); |
| expect(dep.path, '../path'); |
| expect(dep.toString(), 'PathDependency: path@../path'); |
| }); |
| |
| test('valid with random extra key fails', () { |
| _expectThrows( |
| {'path': '../path', 'bob': '^1.2.3'}, |
| r''' |
| line 6, column 4: Unrecognized keys: [bob]; supported keys: [sdk, git, path, hosted] |
| ╷ |
| 6 │ "bob": "^1.2.3" |
| │ ^^^^^ |
| ╵''', |
| ); |
| }); |
| |
| test('null content', () { |
| _expectThrows( |
| {'path': null}, |
| r''' |
| line 5, column 12: Unsupported value for "path". Must be a String. |
| ╷ |
| 5 │ "path": null |
| │ ┌────────────^ |
| 6 │ │ } |
| │ └──^ |
| ╵''', |
| ); |
| }); |
| |
| test('int content', () { |
| _expectThrows( |
| {'path': 42}, |
| r''' |
| line 5, column 12: Unsupported value for "path". Must be a String. |
| ╷ |
| 5 │ "path": 42 |
| │ ┌────────────^ |
| 6 │ │ } |
| │ └──^ |
| ╵''', |
| ); |
| }); |
| } |
| |
| void _expectThrows(Object content, String expectedError) { |
| expectParseThrows( |
| { |
| 'name': 'sample', |
| 'dependencies': {'dep': content}, |
| }, |
| expectedError, |
| ); |
| } |
| |
| void _expectThrowsContaining(Object content, String errorText) { |
| expectParseThrowsContaining( |
| { |
| 'name': 'sample', |
| 'dependencies': {'dep': content}, |
| }, |
| errorText, |
| ); |
| } |
| |
| Future<T> _dependency<T extends Dependency>( |
| Object? content, { |
| bool skipTryPub = false, |
| }) async { |
| final value = await parse( |
| { |
| ...defaultPubspec, |
| 'dependencies': {'dep': content}, |
| }, |
| skipTryPub: skipTryPub, |
| ); |
| expect(value.name, 'sample'); |
| expect(value.dependencies, hasLength(1)); |
| |
| final entry = value.dependencies.entries.single; |
| expect(entry.key, 'dep'); |
| |
| return entry.value as T; |
| } |