blob: c46d9450341529e4bddb11d0dd0cafb698d6cdca [file] [log] [blame]
// Copyright 2014 The Flutter Authors. 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:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/deferred_component.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/flutter_manifest.dart';
import '../src/common.dart';
void main() {
late BufferLogger logger;
setUpAll(() {
Cache.flutterRoot = getFlutterRoot();
});
setUp(() {
logger = BufferLogger.test();
});
testWithoutContext('FlutterManifest is empty when the pubspec.yaml file is empty', () async {
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
'',
logger: logger,
)!;
expect(flutterManifest.isEmpty, true);
expect(flutterManifest.appName, '');
expect(flutterManifest.usesMaterialDesign, false);
expect(flutterManifest.fontsDescriptor, isEmpty);
expect(flutterManifest.fonts, isEmpty);
expect(flutterManifest.assets, isEmpty);
expect(flutterManifest.additionalLicenses, isEmpty);
});
testWithoutContext('FlutterManifest is null when the pubspec.yaml file is not a map', () async {
expect(FlutterManifest.createFromString(
'Not a map',
logger: logger,
), isNull);
expect(logger.errorText, contains('Expected YAML map'));
});
testWithoutContext('FlutterManifest has no fonts or assets when the "flutter" section is empty', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest, isNotNull);
expect(flutterManifest.isEmpty, false);
expect(flutterManifest.appName, 'test');
expect(flutterManifest.usesMaterialDesign, false);
expect(flutterManifest.fontsDescriptor, isEmpty);
expect(flutterManifest.fonts, isEmpty);
expect(flutterManifest.assets, isEmpty);
});
testWithoutContext('FlutterManifest knows if Material Design is used', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.usesMaterialDesign, true);
});
testWithoutContext('FlutterManifest knows if generate is provided', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
generate: true
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.generateSyntheticPackage, true);
});
testWithoutContext('FlutterManifest can parse invalid generate key', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
generate: "invalid"
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.generateSyntheticPackage, false);
});
testWithoutContext('FlutterManifest knows if generate is disabled', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
generate: false
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.generateSyntheticPackage, false);
});
testWithoutContext('FlutterManifest has one font family with one asset', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
fonts:
- family: foo
fonts:
- asset: a/bar
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.fonts, hasLength(1));
expect(flutterManifest.fonts.single, matchesFont(
familyName: 'foo',
descriptor: <String, Object>{
'family': 'foo',
'fonts': <Object>[
<String, Object>{'asset': 'a/bar'},
],
},
fontAssets: <Matcher>[
matchesFontAsset(assetUri: Uri.parse('a/bar')),
],
));
});
testWithoutContext('FlutterManifest has one font family with a simple asset '
'and one with weight', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
fonts:
- family: foo
fonts:
- asset: a/bar
- asset: a/bar
weight: 400
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.fonts, hasLength(1));
expect(flutterManifest.fonts.single, matchesFont(
familyName: 'foo',
descriptor: <String, Object>{
'family': 'foo',
'fonts': <Object>[
<String, Object>{'asset': 'a/bar'},
<String, Object>{'weight': 400, 'asset': 'a/bar'},
],
},
fontAssets: <Matcher>[
matchesFontAsset(assetUri: Uri.parse('a/bar')),
matchesFontAsset(assetUri: Uri.parse('a/bar'), weight: 400),
])
);
});
testWithoutContext('FlutterManifest has one font family with a simple asset '
'and one with weight and style', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
fonts:
- family: foo
fonts:
- asset: a/bar
- asset: a/bar
weight: 400
style: italic
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.fonts, hasLength(1));
expect(flutterManifest.fonts.single, matchesFont(
familyName: 'foo',
descriptor: <String, Object>{
'family': 'foo',
'fonts': <Object>[
<String, Object>{'asset': 'a/bar'},
<String, Object>{'weight': 400, 'style': 'italic', 'asset': 'a/bar'},
],
},
fontAssets: <Matcher>[
matchesFontAsset(assetUri: Uri.parse('a/bar')),
matchesFontAsset(assetUri: Uri.parse('a/bar'), weight: 400, style: 'italic'),
],
));
});
testWithoutContext('FlutterManifest has two font families, each with one '
'simple asset and one with weight and style', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
fonts:
- family: foo
fonts:
- asset: a/bar
- asset: a/bar
weight: 400
style: italic
- family: bar
fonts:
- asset: a/baz
- weight: 400
asset: a/baz
style: italic
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.fonts, hasLength(2));
expect(flutterManifest.fonts, containsAll(<Matcher>[
matchesFont(
familyName: 'foo',
descriptor: <String, Object>{
'family': 'foo',
'fonts': <Object>[
<String, Object>{'asset': 'a/bar'},
<String, Object>{'weight': 400, 'style': 'italic', 'asset': 'a/bar'},
],
},
fontAssets: <Matcher>[
matchesFontAsset(assetUri: Uri.parse('a/bar')),
matchesFontAsset(assetUri: Uri.parse('a/bar'), weight: 400, style: 'italic'),
],
),
matchesFont(
familyName: 'bar',
descriptor: <String, Object>{
'family': 'bar',
'fonts': <Object>[
<String, Object>{'asset': 'a/baz'},
<String, Object>{'weight': 400, 'style': 'italic', 'asset': 'a/baz'},
],
},
fontAssets: <Matcher>[
matchesFontAsset(assetUri: Uri.parse('a/baz')),
matchesFontAsset(assetUri: Uri.parse('a/baz'), weight: 400, style: 'italic'),
],
),
]));
});
testWithoutContext('FlutterManifest.fontsDescriptor combines descriptors from '
'individual fonts', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
fonts:
- family: foo
fonts:
- asset: a/bar
- asset: a/bar
weight: 400
style: italic
- family: bar
fonts:
- asset: a/baz
- weight: 400
asset: a/baz
style: italic
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.fontsDescriptor, <Object>[
<String, Object>{
'family': 'foo',
'fonts': <Object>[
<String, Object>{'asset': 'a/bar'},
<String, Object>{'weight': 400, 'style': 'italic', 'asset': 'a/bar'},
],
},
<String, Object>{
'family': 'bar',
'fonts': <Object>[
<String, Object>{'asset': 'a/baz'},
<String, Object>{'weight': 400, 'style': 'italic', 'asset': 'a/baz'},
],
},
]);
});
testWithoutContext('FlutterManifest has only one of two font families when '
'one declaration is missing the "family" option', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
fonts:
- family: foo
fonts:
- asset: a/bar
- asset: a/bar
weight: 400
style: italic
- fonts:
- asset: a/baz
- asset: a/baz
weight: 400
style: italic
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.fonts, hasLength(1));
expect(flutterManifest.fonts, containsAll(<Matcher>[
matchesFont(
familyName: 'foo',
descriptor: <String, Object>{
'family': 'foo',
'fonts': <Object>[
<String, Object>{'asset': 'a/bar'},
<String, Object>{'weight': 400, 'style': 'italic', 'asset': 'a/bar'},
],
},
fontAssets: <Matcher>[
matchesFontAsset(assetUri: Uri.parse('a/bar')),
matchesFontAsset(assetUri: Uri.parse('a/bar'), weight: 400, style: 'italic'),
],
),
]));
});
testWithoutContext('FlutterManifest has only one of two font families when '
'one declaration is missing the "fonts" option', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
fonts:
- family: foo
fonts:
- asset: a/bar
- asset: a/bar
weight: 400
style: italic
- family: bar
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.fonts, hasLength(1));
expect(flutterManifest.fonts, containsAll(<Matcher>[
matchesFont(
familyName: 'foo',
descriptor: <String, Object>{
'family': 'foo',
'fonts': <Object>[
<String, Object>{'asset': 'a/bar'},
<String, Object>{'weight': 400, 'style': 'italic', 'asset': 'a/bar'},
],
},
fontAssets: <Matcher>[
matchesFontAsset(assetUri: Uri.parse('a/bar')),
matchesFontAsset(assetUri: Uri.parse('a/bar'), weight: 400, style: 'italic'),
],
),
]));
});
testWithoutContext('FlutterManifest has no font family when declaration is '
'missing the "asset" option', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
fonts:
- family: foo
fonts:
- weight: 400
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.fontsDescriptor, isEmpty);
expect(flutterManifest.fonts, isEmpty);
});
testWithoutContext('FlutterManifest allows a blank flutter section', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.isEmpty, false);
expect(flutterManifest.isModule, false);
expect(flutterManifest.isPlugin, false);
expect(flutterManifest.androidPackage, null);
expect(flutterManifest.usesAndroidX, false);
});
testWithoutContext('FlutterManifest allows a module declaration', () {
const String manifest = '''
name: test
flutter:
module:
androidPackage: com.example
androidX: true
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.isModule, true);
expect(flutterManifest.androidPackage, 'com.example');
expect(flutterManifest.usesAndroidX, true);
});
testWithoutContext('FlutterManifest allows a legacy plugin declaration', () {
const String manifest = '''
name: test
flutter:
plugin:
androidPackage: com.example
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.isPlugin, true);
expect(flutterManifest.androidPackage, 'com.example');
});
testWithoutContext('FlutterManifest allows a multi-plat plugin declaration '
'with android only', () {
const String manifest = '''
name: test
flutter:
plugin:
platforms:
android:
package: com.example
pluginClass: TestPlugin
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.isPlugin, true);
expect(flutterManifest.androidPackage, 'com.example');
});
testWithoutContext('FlutterManifest allows a multi-plat plugin declaration '
'with ios only', () {
const String manifest = '''
name: test
flutter:
plugin:
platforms:
ios:
pluginClass: HelloPlugin
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.isPlugin, true);
expect(flutterManifest.androidPackage, isNull);
});
testWithoutContext('FlutterManifest handles an invalid plugin declaration', () {
const String manifest = '''
name: test
flutter:
plugin:
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText,
contains('Expected "plugin" to be an object, but got null'));
});
testWithoutContext('FlutterManifest parses major.minor.patch+build version clause 1', () {
const String manifest = '''
name: test
version: 1.0.0+2
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, matchesManifest(
appVersion: '1.0.0+2',
buildName: '1.0.0',
buildNumber: '2',
));
});
testWithoutContext('FlutterManifest parses major.minor.patch with no build version', () {
const String manifest = '''
name: test
version: 0.0.1
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, matchesManifest(
appVersion: '0.0.1',
buildName: '0.0.1',
));
});
testWithoutContext('FlutterManifest parses major.minor.patch+build version clause 2', () {
const String manifest = '''
name: test
version: 1.0.0-beta+exp.sha.5114f85
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, matchesManifest(
appVersion: '1.0.0-beta+exp.sha.5114f85',
buildName: '1.0.0-beta',
buildNumber: 'exp.sha.5114f85',
));
});
testWithoutContext('FlutterManifest parses major.minor+build version clause', () {
const String manifest = '''
name: test
version: 1.0.0+2
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, matchesManifest(
appVersion: '1.0.0+2',
buildName: '1.0.0',
buildNumber: '2',
));
});
testWithoutContext('FlutterManifest parses empty version clause', () {
const String manifest = '''
name: test
version:
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, matchesManifest());
});
testWithoutContext('FlutterManifest parses no version clause', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, matchesManifest());
});
// Regression test for https://github.com/flutter/flutter/issues/31764
testWithoutContext('FlutterManifest returns proper error when font detail is malformed', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
fonts:
- family: foo
fonts:
-asset: a/bar
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText,
contains('Expected "fonts" to either be null or a list.'));
});
testWithoutContext('FlutterManifest ignores empty list of fonts', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
fonts: []
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, isNotNull);
expect(flutterManifest!.fonts.length, 0);
});
testWithoutContext('FlutterManifest returns proper error when font detail is '
'not a list of maps', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
fonts:
- family: foo
fonts:
- asset
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText,
contains('Expected "fonts" to be a list of maps.'));
});
testWithoutContext('FlutterManifest returns proper error when font is a map '
'instead of a list', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
fonts:
family: foo
fonts:
-asset: a/bar
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, contains('Expected "fonts" to be a list'));
});
testWithoutContext('FlutterManifest returns proper error when second font '
'family is invalid', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
uses-material-design: true
fonts:
- family: foo
fonts:
- asset: a/bar
- string
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, contains('Expected a map.'));
});
testWithoutContext('FlutterManifest returns proper error when flutter is a '
'list instead of a map', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
- uses-material-design: true
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText,
contains(
'Expected "flutter" section to be an object or null, but got '
'[{uses-material-design: true}].',
),
);
});
testWithoutContext('FlutterManifest can parse manifest on posix filesystem', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FileSystem fileSystem = MemoryFileSystem.test();
fileSystem.file('pubspec.yaml').writeAsStringSync(manifest);
final FlutterManifest flutterManifest = FlutterManifest.createFromPath(
'pubspec.yaml',
fileSystem: fileSystem,
logger: logger,
)!;
expect(flutterManifest.isEmpty, false);
});
testWithoutContext('FlutterManifest can parse manifest on windows filesystem', () {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows);
fileSystem.file('pubspec.yaml').writeAsStringSync(manifest);
final FlutterManifest flutterManifest = FlutterManifest.createFromPath(
'pubspec.yaml',
fileSystem: fileSystem,
logger: logger,
)!;
expect(flutterManifest.isEmpty, false);
});
testWithoutContext('FlutterManifest getSupportedPlatforms return null if runs on legacy format', () {
const String manifest = '''
name: test
flutter:
plugin:
androidPackage: com.example
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.isPlugin, true);
expect(flutterManifest.supportedPlatforms, null);
});
testWithoutContext('FlutterManifest validSupportedPlatforms return null if the platform keys are not valid', () {
const String manifest = '''
name: test
flutter:
plugin:
platforms:
some_platform:
pluginClass: SomeClass
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.isPlugin, true);
expect(flutterManifest.validSupportedPlatforms, null);
});
testWithoutContext('FlutterManifest validSupportedPlatforms only returns valid platforms', () {
const String manifest = '''
name: test
flutter:
plugin:
platforms:
some_platform:
pluginClass: SomeClass
ios:
pluginClass: SomeClass
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.isPlugin, true);
final Map<String, dynamic> validSupportedPlatforms = flutterManifest.validSupportedPlatforms!;
expect(validSupportedPlatforms['ios'],
<String, dynamic>{'pluginClass': 'SomeClass'});
expect(validSupportedPlatforms['some_platform'],
isNull);
});
testWithoutContext('FlutterManifest getSupportedPlatforms returns valid platforms.', () {
const String manifest = '''
name: test
flutter:
plugin:
platforms:
android:
package: com.example
pluginClass: SomeClass
ios:
pluginClass: SomeClass
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.isPlugin, true);
final Map<String, dynamic> validSupportedPlatforms = flutterManifest.validSupportedPlatforms!;
expect(validSupportedPlatforms['ios'], <String, dynamic>{'pluginClass': 'SomeClass'});
expect(validSupportedPlatforms['android'], <String, dynamic>{
'pluginClass': 'SomeClass',
'package': 'com.example',
});
});
testWithoutContext('FlutterManifest validates a platform section that is a list '
'instead of a map', () {
const String manifest = '''
name: test
flutter:
plugin:
platforms:
- android
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText,
contains('flutter.plugin.platforms should be a map with the platform name as the key'));
});
testWithoutContext('FlutterManifest validates plugin format not support.', () {
const String manifest = '''
name: test
flutter:
plugin:
android:
package: com.example
pluginClass: SomeClass
ios:
pluginClass: SomeClass
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText,
contains('Cannot find the `flutter.plugin.platforms` key in the `pubspec.yaml` file. '));
});
testWithoutContext('FlutterManifest handles empty licenses list', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
licenses: []
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, isNotNull);
expect(flutterManifest!.additionalLicenses.length, 0);
});
testWithoutContext('FlutterManifest can specify additional LICENSE files', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
licenses:
- foo.txt
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.additionalLicenses, <String>['foo.txt']);
});
testWithoutContext('FlutterManifest can validate incorrect licenses key', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
licenses: foo.txt
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Expected "licenses" to be a list of files, but got foo.txt (String).\n');
});
testWithoutContext('FlutterManifest validates individual list items', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
licenses:
- foo.txt
- bar: fizz
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Expected "licenses" to be a list of files, but '
'element at index 1 was a YamlMap.\n');
});
testWithoutContext('FlutterManifest parses single deferred components', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- name: component1
libraries:
- lib1
assets:
- path/to/asset.jpg
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest, isNotNull);
final List<DeferredComponent> deferredComponents = flutterManifest.deferredComponents!;
expect(deferredComponents.length, 1);
expect(deferredComponents[0].name, 'component1');
expect(deferredComponents[0].libraries.length, 1);
expect(deferredComponents[0].libraries[0], 'lib1');
expect(deferredComponents[0].assets.length, 1);
expect(deferredComponents[0].assets[0].uri.path, 'path/to/asset.jpg');
});
testWithoutContext('FlutterManifest parses multiple deferred components', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- name: component1
libraries:
- lib1
assets:
- path/to/asset.jpg
- name: component2
libraries:
- lib2
- lib3
assets:
- path/to/asset2.jpg
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest, isNotNull);
final List<DeferredComponent> deferredComponents = flutterManifest.deferredComponents!;
expect(deferredComponents.length, 2);
expect(deferredComponents[0].name, 'component1');
expect(deferredComponents[0].libraries.length, 1);
expect(deferredComponents[0].libraries[0], 'lib1');
expect(deferredComponents[0].assets.length, 1);
expect(deferredComponents[0].assets[0].uri.path, 'path/to/asset.jpg');
expect(deferredComponents[1].name, 'component2');
expect(deferredComponents[1].libraries.length, 2);
expect(deferredComponents[1].libraries[0], 'lib2');
expect(deferredComponents[1].libraries[1], 'lib3');
expect(deferredComponents[1].assets.length, 1);
expect(deferredComponents[1].assets[0].uri.path, 'path/to/asset2.jpg');
});
testWithoutContext('FlutterManifest parses empty deferred components', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest, isNotNull);
expect(flutterManifest.deferredComponents!.length, 0);
});
testWithoutContext('FlutterManifest deferred component requires name', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- libraries:
- lib1
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Expected the 0 element in "deferred-components" to have required key "name" of type String\n');
});
testWithoutContext('FlutterManifest deferred component is list', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components: blah
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Expected "deferred-components" to be a list, but got blah (String).\n');
});
testWithoutContext('FlutterManifest deferred component libraries is list', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- name: blah
libraries: blah
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Expected "libraries" key in the element at '
'index 0 of "deferred-components" to be a list of String, but '
'got blah (String).\n');
});
testWithoutContext('FlutterManifest deferred component libraries is string', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- name: blah
libraries:
- not-a-string:
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Expected "libraries" key in the element at '
'index 0 of "deferred-components" to be a list of String, but '
'element at index 0 was a YamlMap.\n');
});
testWithoutContext('FlutterManifest deferred component assets is string', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- name: blah
assets:
- not-a-string:
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Asset manifest entry is malformed. Expected asset entry to be either a string or a map containing a "path" entry. Got Null instead.\n');
});
testWithoutContext('FlutterManifest deferred component multiple assets is string', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- name: blah
assets:
- path/to/file.so
- also-not-a-string:
- woo
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Asset manifest entry is malformed. Expected asset entry to be either a string or a map containing a "path" entry. Got Null instead.\n');
});
testWithoutContext('FlutterManifest multiple deferred components assets is string', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- name: blah
assets:
- path/to/file.so
- name: blah2
assets:
- path/to/other/file.so
- not-a-string:
- woo
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Asset manifest entry is malformed. Expected asset entry to be either a string or a map containing a "path" entry. Got Null instead.\n');
});
testWithoutContext('FlutterManifest deferred component assets is list', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- name: blah
assets: blah
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest, null);
expect(logger.errorText, 'Expected "assets" to be a list, but got blah (String).\n');
});
testWithoutContext('FlutterManifest parses asset-only deferred components', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
deferred-components:
- name: component1
assets:
- path/to/asset1.jpg
- path/to/asset2.jpg
- path/to/asset3.jpg
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest, isNotNull);
final List<DeferredComponent> deferredComponents = flutterManifest.deferredComponents!;
expect(deferredComponents.length, 1);
expect(deferredComponents[0].name, 'component1');
expect(deferredComponents[0].libraries.length, 0);
expect(deferredComponents[0].assets.length, 3);
expect(deferredComponents[0].assets[0].uri.path, 'path/to/asset1.jpg');
expect(deferredComponents[0].assets[1].uri.path, 'path/to/asset2.jpg');
expect(deferredComponents[0].assets[2].uri.path, 'path/to/asset3.jpg');
});
testWithoutContext('FlutterManifest can parse empty dependencies', () async {
const String manifest = '''
name: test
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: BufferLogger.test(),
);
expect(flutterManifest, isNotNull);
expect(flutterManifest!.dependencies, isEmpty);
});
testWithoutContext('FlutterManifest knows if Swift Package Manager is disabled', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
disable-swift-package-manager: true
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.disabledSwiftPackageManager, true);
});
testWithoutContext('FlutterManifest does not disable Swift Package Manager if missing', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
''';
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
)!;
expect(flutterManifest.disabledSwiftPackageManager, false);
});
}
Matcher matchesManifest({
String? appVersion,
String? buildName,
String? buildNumber,
}) {
return isA<FlutterManifest>()
.having((FlutterManifest manifest) => manifest.appVersion, 'appVersion', appVersion)
.having((FlutterManifest manifest) => manifest.buildName, 'buildName', buildName)
.having((FlutterManifest manifest) => manifest.buildNumber, 'buildNumber', buildNumber);
}
Matcher matchesFontAsset({
required Uri assetUri,
int? weight,
String? style,
}) {
return isA<FontAsset>()
.having((FontAsset fontAsset) => fontAsset.assetUri, 'assetUri', assetUri)
.having((FontAsset fontAsset) => fontAsset.weight, 'weight', weight)
.having((FontAsset fontAsset) => fontAsset.style, 'style', style);
}
Matcher matchesFont({
required Map<String, Object> descriptor,
required String familyName,
required List<Matcher> fontAssets,
}) {
return isA<Font>()
.having((Font font) => font.descriptor, 'descriptor', descriptor)
.having((Font font) => font.familyName, 'familyName', familyName)
.having((Font font) => font.fontAssets, 'fontAssets', containsAll(fontAssets));
}