blob: 5570b60a01c9018fac7836cf9dcbc6e2796cfb57 [file] [log] [blame]
// 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.
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: lines_longer_than_80_chars
import 'package:pub_semver/pub_semver.dart';
import 'package:test/test.dart';
import 'test_utils.dart';
void main() {
test('minimal set values', () async {
final value = await parse(defaultPubspec);
expect(value.name, 'sample');
expect(value.version, isNull);
expect(value.publishTo, isNull);
expect(value.description, isNull);
expect(value.homepage, isNull);
expect(value.author, isNull);
expect(value.authors, isEmpty);
expect(
value.environment,
{'sdk': VersionConstraint.parse('>=2.12.0 <3.0.0')},
);
expect(value.documentation, isNull);
expect(value.dependencies, isEmpty);
expect(value.devDependencies, isEmpty);
expect(value.dependencyOverrides, isEmpty);
expect(value.flutter, isNull);
expect(value.repository, isNull);
expect(value.issueTracker, isNull);
expect(value.screenshots, isEmpty);
expect(value.workspace, isNull);
expect(value.resolution, isNull);
});
test('all fields set', () async {
final version = Version.parse('1.2.3');
final sdkConstraint = VersionConstraint.parse('>=3.6.0 <4.0.0');
final value = await parse(
{
'name': 'sample',
'version': version.toString(),
'publish_to': 'none',
'author': 'name@example.com',
'environment': {'sdk': sdkConstraint.toString()},
'description': 'description',
'homepage': 'homepage',
'documentation': 'documentation',
'repository': 'https://github.com/example/repo',
'issue_tracker': 'https://github.com/example/repo/issues',
'funding': [
'https://patreon.com/example',
],
'topics': ['widget', 'button'],
'ignored_advisories': ['111', '222'],
'screenshots': [
{'description': 'my screenshot', 'path': 'path/to/screenshot'},
],
'workspace': [
'pkg1',
'pkg2',
],
'resolution': 'workspace',
},
skipTryPub: true,
);
expect(value.name, 'sample');
expect(value.version, version);
expect(value.publishTo, 'none');
expect(value.description, 'description');
expect(value.homepage, 'homepage');
expect(value.author, 'name@example.com');
expect(value.authors, ['name@example.com']);
expect(value.environment, hasLength(1));
expect(value.environment, containsPair('sdk', sdkConstraint));
expect(value.documentation, 'documentation');
expect(value.dependencies, isEmpty);
expect(value.devDependencies, isEmpty);
expect(value.dependencyOverrides, isEmpty);
expect(value.repository, Uri.parse('https://github.com/example/repo'));
expect(
value.issueTracker,
Uri.parse('https://github.com/example/repo/issues'),
);
expect(value.funding, hasLength(1));
expect(value.funding!.single.toString(), 'https://patreon.com/example');
expect(value.topics, hasLength(2));
expect(value.topics!.first, 'widget');
expect(value.topics!.last, 'button');
expect(value.ignoredAdvisories, hasLength(2));
expect(value.ignoredAdvisories!.first, '111');
expect(value.ignoredAdvisories!.last, '222');
expect(value.screenshots, hasLength(1));
expect(value.screenshots!.first.description, 'my screenshot');
expect(value.screenshots!.first.path, 'path/to/screenshot');
expect(value.workspace, hasLength(2));
expect(value.workspace!.first, 'pkg1');
expect(value.workspace!.last, 'pkg2');
expect(value.resolution, 'workspace');
});
test('environment values can be null', () async {
final value = await parse(
{
'name': 'sample',
'environment': {
'sdk': '>=2.12.0 <3.0.0',
'bob': null,
},
},
skipTryPub: true,
);
expect(value.name, 'sample');
expect(value.environment, hasLength(2));
expect(value.environment, containsPair('bob', isNull));
});
group('publish_to', () {
for (var entry in {
42: "Unsupported value for \"publish_to\". type 'int' is not a subtype of type 'String?'",
'##not a uri!': r'''
line 3, column 16: Unsupported value for "publish_to". Must be an http or https URL.
3 │ "publish_to": "##not a uri!"
│ ^^^^^^^^^^^^^^
╵''',
'/cool/beans': r'''
line 3, column 16: Unsupported value for "publish_to". Must be an http or https URL.
3 │ "publish_to": "/cool/beans"
│ ^^^^^^^^^^^^^
╵''',
'file:///Users/kevmoo/': r'''
line 3, column 16: Unsupported value for "publish_to". Must be an http or https URL.
3 │ "publish_to": "file:///Users/kevmoo/"
│ ^^^^^^^^^^^^^^^^^^^^^^^
╵''',
}.entries) {
test('cannot be `${entry.key}`', () {
expectParseThrowsContaining(
{'name': 'sample', 'publish_to': entry.key},
entry.value,
skipTryPub: true,
);
});
}
for (var entry in {
null: null,
'http': 'http://example.com',
'https': 'https://example.com',
'none': 'none',
}.entries) {
test('can be ${entry.key}', () async {
final value = await parse({
...defaultPubspec,
'publish_to': entry.value,
});
expect(value.publishTo, entry.value);
});
}
});
group('author, authors', () {
test('one author', () async {
final value = await parse({
...defaultPubspec,
'author': 'name@example.com',
});
expect(value.author, 'name@example.com');
expect(value.authors, ['name@example.com']);
});
test('one author, via authors', () async {
final value = await parse({
...defaultPubspec,
'authors': ['name@example.com'],
});
expect(value.author, 'name@example.com');
expect(value.authors, ['name@example.com']);
});
test('many authors', () async {
final value = await parse({
...defaultPubspec,
'authors': ['name@example.com', 'name2@example.com'],
});
expect(value.author, isNull);
expect(value.authors, ['name@example.com', 'name2@example.com']);
});
test('author and authors', () async {
final value = await parse({
...defaultPubspec,
'author': 'name@example.com',
'authors': ['name2@example.com'],
});
expect(value.author, isNull);
expect(value.authors, ['name@example.com', 'name2@example.com']);
});
test('duplicate author values', () async {
final value = await parse({
...defaultPubspec,
'author': 'name@example.com',
'authors': ['name@example.com', 'name@example.com'],
});
expect(value.author, 'name@example.com');
expect(value.authors, ['name@example.com']);
});
test('flutter', () async {
final value = await parse({
...defaultPubspec,
'flutter': {'key': 'value'},
});
expect(value.flutter, {'key': 'value'});
});
});
group('invalid', () {
test('null', () {
expectParseThrows(
null,
r'''
line 1, column 1: Not a map
1 │ null
│ ^^^^
╵''',
);
});
test('empty string', () {
expectParseThrows(
'',
r'''
line 1, column 1: Not a map
1 │ ""
│ ^^
╵''',
);
});
test('array', () {
expectParseThrows(
[],
r'''
line 1, column 1: Not a map
1 │ []
│ ^^
╵''',
);
});
test('missing name', () {
expectParseThrowsContaining(
{},
"Missing key \"name\". type 'Null' is not a subtype of type 'String'",
);
});
test('null name value', () {
expectParseThrowsContaining(
{'name': null},
"Unsupported value for \"name\". type 'Null' is not a subtype of type 'String'",
);
});
test('empty name value', () {
expectParseThrows(
{'name': ''},
r'''
line 2, column 10: Unsupported value for "name". "name" cannot be empty.
2 │ "name": ""
│ ^^
╵''',
);
});
test('"dart" is an invalid environment key', () {
expectParseThrows(
{
'name': 'sample',
'environment': {'dart': 'cool'},
},
r'''
line 4, column 3: Use "sdk" to for Dart SDK constraints.
4 │ "dart": "cool"
│ ^^^^^^
╵''',
);
});
test('environment values cannot be int', () {
expectParseThrows(
{
'name': 'sample',
'environment': {'sdk': 42},
},
r'''
line 4, column 10: Unsupported value for "sdk". `42` is not a String.
4 │ "sdk": 42
│ ┌──────────^
5 │ │ }
│ └─^
╵''',
);
});
test('version', () {
expectParseThrows(
{'name': 'sample', 'version': 'invalid'},
r'''
line 3, column 13: Unsupported value for "version". Could not parse "invalid".
3 │ "version": "invalid"
│ ^^^^^^^^^
╵''',
);
});
test('invalid environment value', () {
expectParseThrows(
{
'name': 'sample',
'environment': {'sdk': 'silly'},
},
r'''
line 4, column 10: Unsupported value for "sdk". Could not parse version "silly". Unknown text at "silly".
4 │ "sdk": "silly"
│ ^^^^^^^
╵''',
);
});
test('bad repository url', () {
expectParseThrowsContaining(
{
...defaultPubspec,
'repository': {'x': 'y'},
},
"Unsupported value for \"repository\". type 'YamlMap' is not a subtype of type 'String'",
skipTryPub: true,
);
});
test('bad issue_tracker url', () {
expectParseThrowsContaining(
{
'name': 'sample',
'issue_tracker': {'x': 'y'},
},
"Unsupported value for \"issue_tracker\". type 'YamlMap' is not a subtype of type 'String'",
skipTryPub: true,
);
});
});
group('funding', () {
test('not a list', () {
expectParseThrowsContaining(
{
...defaultPubspec,
'funding': 1,
},
"Unsupported value for \"funding\". type 'int' is not a subtype of type 'List<dynamic>?'",
skipTryPub: true,
);
});
test('not an uri', () {
expectParseThrowsContaining(
{
...defaultPubspec,
'funding': [1],
},
"Unsupported value for \"funding\". type 'int' is not a subtype of type 'String'",
skipTryPub: true,
);
});
test('not an uri', () {
expectParseThrows(
{
...defaultPubspec,
'funding': ['ht tps://example.com/'],
},
r'''
line 6, column 13: Unsupported value for "funding". Illegal scheme character at offset 2.
6 │ "funding": [
│ ┌─────────────^
7 │ │ "ht tps://example.com/"
8 │ └ ]
╵''',
skipTryPub: true,
);
});
});
group('topics', () {
test('not a list', () {
expectParseThrowsContaining(
{
...defaultPubspec,
'topics': 1,
},
"Unsupported value for \"topics\". type 'int' is not a subtype of type 'List<dynamic>?'",
skipTryPub: true,
);
});
test('not a string', () {
expectParseThrowsContaining(
{
...defaultPubspec,
'topics': [1],
},
"Unsupported value for \"topics\". type 'int' is not a subtype of type 'String'",
skipTryPub: true,
);
});
test('invalid data - lenient', () async {
final value = await parse(
{
...defaultPubspec,
'topics': [1],
},
skipTryPub: true,
lenient: true,
);
expect(value.name, 'sample');
expect(value.topics, isNull);
});
});
group('ignored_advisories', () {
test('not a list', () {
expectParseThrowsContaining(
{
...defaultPubspec,
'ignored_advisories': 1,
},
"Unsupported value for \"ignored_advisories\". type 'int' is not a subtype of type 'List<dynamic>?'",
skipTryPub: true,
);
});
test('not a string', () {
expectParseThrowsContaining(
{
...defaultPubspec,
'ignored_advisories': [1],
},
"Unsupported value for \"ignored_advisories\". type 'int' is not a subtype of type 'String'",
skipTryPub: true,
);
});
test('invalid data - lenient', () async {
final value = await parse(
{
...defaultPubspec,
'ignored_advisories': [1],
},
skipTryPub: true,
lenient: true,
);
expect(value.name, 'sample');
expect(value.ignoredAdvisories, isNull);
});
});
group('screenshots', () {
test('one screenshot', () async {
final value = await parse({
...defaultPubspec,
'screenshots': [
{'description': 'my screenshot', 'path': 'path/to/screenshot'},
],
});
expect(value.screenshots, hasLength(1));
expect(value.screenshots!.first.description, 'my screenshot');
expect(value.screenshots!.first.path, 'path/to/screenshot');
});
test('many screenshots', () async {
final value = await parse({
...defaultPubspec,
'screenshots': [
{'description': 'my screenshot', 'path': 'path/to/screenshot'},
{
'description': 'my second screenshot',
'path': 'path/to/screenshot2',
},
],
});
expect(value.screenshots, hasLength(2));
expect(value.screenshots!.first.description, 'my screenshot');
expect(value.screenshots!.first.path, 'path/to/screenshot');
expect(value.screenshots!.last.description, 'my second screenshot');
expect(value.screenshots!.last.path, 'path/to/screenshot2');
});
test('one screenshot plus invalid entries', () async {
final value = await parse({
...defaultPubspec,
'screenshots': [
42,
{
'description': 'my screenshot',
'path': 'path/to/screenshot',
'extraKey': 'not important',
},
'not a screenshot',
],
});
expect(value.screenshots, hasLength(1));
expect(value.screenshots!.first.description, 'my screenshot');
expect(value.screenshots!.first.path, 'path/to/screenshot');
});
test('invalid entries', () async {
final value = await parse({
...defaultPubspec,
'screenshots': [
42,
'not a screenshot',
],
});
expect(value.screenshots, isEmpty);
});
test('missing key `dessription', () {
expectParseThrows(
{
...defaultPubspec,
'screenshots': [
{'path': 'my/path'},
],
},
r'''
line 7, column 3: Missing key "description". Missing required key `description`
7 │ ┌ {
8 │ │ "path": "my/path"
9 │ └ }
╵''',
skipTryPub: true,
);
});
test('missing key `path`', () {
expectParseThrows(
{
...defaultPubspec,
'screenshots': [
{'description': 'my screenshot'},
],
},
r'''
line 7, column 3: Missing key "path". Missing required key `path`
7 │ ┌ {
8 │ │ "description": "my screenshot"
9 │ └ }
╵''',
skipTryPub: true,
);
});
test('Value of description not a String`', () {
expectParseThrows(
{
...defaultPubspec,
'screenshots': [
{'description': 42},
],
},
r'''
line 8, column 19: Unsupported value for "description". `42` is not a String
8 │ "description": 42
│ ┌───────────────────^
9 │ │ }
│ └──^
╵''',
skipTryPub: true,
);
});
test('Value of path not a String`', () {
expectParseThrows(
{
...defaultPubspec,
'screenshots': [
{
'description': '',
'path': 42,
},
],
},
r'''
line 9, column 12: Unsupported value for "path". `42` is not a String
9 │ "path": 42
│ ┌────────────^
10 │ │ }
│ └──^
╵''',
skipTryPub: true,
);
});
test('invalid screenshot - lenient', () async {
final value = await parse(
{
...defaultPubspec,
'screenshots': 'Invalid value',
},
lenient: true,
);
expect(value.name, 'sample');
expect(value.screenshots, isEmpty);
});
});
group('lenient', () {
test('null', () {
expectParseThrows(
null,
r'''
line 1, column 1: Not a map
1 │ null
│ ^^^^
╵''',
lenient: true,
);
});
test('empty string', () {
expectParseThrows(
'',
r'''
line 1, column 1: Not a map
1 │ ""
│ ^^
╵''',
lenient: true,
);
});
test('name cannot be empty', () {
expectParseThrowsContaining(
{},
"Missing key \"name\". type 'Null' is not a subtype of type 'String'",
lenient: true,
);
});
test('bad repository url', () async {
final value = await parse(
{
...defaultPubspec,
'repository': {'x': 'y'},
},
lenient: true,
);
expect(value.name, 'sample');
expect(value.repository, isNull);
});
test('bad issue_tracker url', () async {
final value = await parse(
{
...defaultPubspec,
'issue_tracker': {'x': 'y'},
},
lenient: true,
);
expect(value.name, 'sample');
expect(value.issueTracker, isNull);
});
test('multiple bad values', () async {
final value = await parse(
{
...defaultPubspec,
'repository': {'x': 'y'},
'issue_tracker': {'x': 'y'},
},
lenient: true,
);
expect(value.name, 'sample');
expect(value.repository, isNull);
expect(value.issueTracker, isNull);
});
test('deep error throws with lenient', () {
expect(
() => parse(
{
'name': 'sample',
'dependencies': {
'foo': {
'git': {'url': 1},
},
},
'issue_tracker': {'x': 'y'},
},
skipTryPub: true,
lenient: true,
),
throwsException,
);
});
});
group('workspaces', () {
test('workspace key must be a list', () {
expectParseThrowsContaining(
{
...defaultPubspec,
'workspace': 42,
},
'Unsupported value for "workspace". type \'int\' is not a subtype of type \'List<dynamic>?\' in type cast',
skipTryPub: true,
);
});
test('workspace key must be a list of strings', () {
expectParseThrowsContaining(
{
...defaultPubspec,
'workspace': [42],
},
'Unsupported value for "workspace". type \'int\' is not a subtype of type \'String\' in type cast',
skipTryPub: true,
);
});
test('resolution key must be a string', () {
expectParseThrowsContaining(
{
'name': 'sample',
'environment': {'sdk': '^3.6.0'},
'resolution': 42,
},
'Unsupported value for "resolution". type \'int\' is not a subtype of type \'String?\' in type cast',
skipTryPub: true,
);
});
});
}