[flutter_tools] refactor FlutterManifest to be context-free (#54555)
diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart index c2c33d1..6db13de 100644 --- a/packages/flutter_tools/lib/src/asset.dart +++ b/packages/flutter_tools/lib/src/asset.dart
@@ -128,7 +128,11 @@ packagesPath ??= globals.fs.path.absolute(PackageMap.globalPackagesPath); FlutterManifest flutterManifest; try { - flutterManifest = FlutterManifest.createFromPath(manifestPath); + flutterManifest = FlutterManifest.createFromPath( + manifestPath, + logger: globals.logger, + fileSystem: globals.fs, + ); } on Exception catch (e) { globals.printStatus('Error detected in pubspec.yaml:', emphasis: true); globals.printError('$e'); @@ -187,7 +191,11 @@ final Uri packageUri = package.packageUriRoot; if (packageUri != null && packageUri.scheme == 'file') { final String packageManifestPath = globals.fs.path.fromUri(packageUri.resolve('../pubspec.yaml')); - final FlutterManifest packageFlutterManifest = FlutterManifest.createFromPath(packageManifestPath); + final FlutterManifest packageFlutterManifest = FlutterManifest.createFromPath( + packageManifestPath, + logger: globals.logger, + fileSystem: globals.fs, + ); if (packageFlutterManifest == null) { continue; }
diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart index b86ca76..aa3e9b4 100644 --- a/packages/flutter_tools/lib/src/flutter_manifest.dart +++ b/packages/flutter_tools/lib/src/flutter_manifest.dart
@@ -7,42 +7,45 @@ import 'package:yaml/yaml.dart'; import 'base/file_system.dart'; +import 'base/logger.dart'; import 'base/user_messages.dart'; import 'base/utils.dart'; import 'cache.dart'; -import 'globals.dart' as globals; import 'plugins.dart'; /// A wrapper around the `flutter` section in the `pubspec.yaml` file. class FlutterManifest { - FlutterManifest._(); + FlutterManifest._(this._logger); /// Returns an empty manifest. - static FlutterManifest empty() { - final FlutterManifest manifest = FlutterManifest._(); + factory FlutterManifest.empty({ @required Logger logger }) { + final FlutterManifest manifest = FlutterManifest._(logger); manifest._descriptor = const <String, dynamic>{}; manifest._flutterDescriptor = const <String, dynamic>{}; return manifest; } /// Returns null on invalid manifest. Returns empty manifest on missing file. - static FlutterManifest createFromPath(String path) { - if (path == null || !globals.fs.isFileSync(path)) { - return _createFromYaml(null); + static FlutterManifest createFromPath(String path, { + @required FileSystem fileSystem, + @required Logger logger, + }) { + if (path == null || !fileSystem.isFileSync(path)) { + return _createFromYaml(null, logger); } - final String manifest = globals.fs.file(path).readAsStringSync(); - return createFromString(manifest); + final String manifest = fileSystem.file(path).readAsStringSync(); + return FlutterManifest.createFromString(manifest, logger: logger); } /// Returns null on missing or invalid manifest @visibleForTesting - static FlutterManifest createFromString(String manifest) { - return _createFromYaml(loadYaml(manifest) as YamlMap); + static FlutterManifest createFromString(String manifest, { @required Logger logger }) { + return _createFromYaml(loadYaml(manifest) as YamlMap, logger); } - static FlutterManifest _createFromYaml(YamlMap yamlDocument) { - final FlutterManifest pubspec = FlutterManifest._(); - if (yamlDocument != null && !_validate(yamlDocument)) { + static FlutterManifest _createFromYaml(YamlMap yamlDocument, Logger logger) { + final FlutterManifest pubspec = FlutterManifest._(logger); + if (yamlDocument != null && !_validate(yamlDocument, logger)) { return null; } @@ -63,6 +66,8 @@ return pubspec; } + final Logger _logger; + /// A map representation of the entire `pubspec.yaml` file. Map<String, dynamic> _descriptor; @@ -91,7 +96,7 @@ version = Version.parse(verStr); } on Exception { if (!_hasShowInvalidVersionMsg) { - globals.printStatus(userMessages.invalidVersionSettingHintMessage(verStr), emphasis: true); + _logger.printStatus(userMessages.invalidVersionSettingHintMessage(verStr), emphasis: true); _hasShowInvalidVersionMsg = true; } } @@ -203,14 +208,14 @@ final List<Uri> results = <Uri>[]; for (final Object asset in assets) { if (asset is! String || asset == null || asset == '') { - globals.printError('Asset manifest contains a null or empty uri.'); + _logger.printError('Asset manifest contains a null or empty uri.'); continue; } final String stringAsset = asset as String; try { results.add(Uri(pathSegments: stringAsset.split('/'))); } on FormatException { - globals.printError('Asset manifest contains invalid uri: $asset.'); + _logger.printError('Asset manifest contains invalid uri: $asset.'); } } return results; @@ -233,11 +238,11 @@ final YamlList fontFiles = fontFamily['fonts'] as YamlList; final String familyName = fontFamily['family'] as String; if (familyName == null) { - globals.printError('Warning: Missing family name for font.', emphasis: true); + _logger.printError('Warning: Missing family name for font.', emphasis: true); continue; } if (fontFiles == null) { - globals.printError('Warning: No fonts specified for font $familyName', emphasis: true); + _logger.printError('Warning: No fonts specified for font $familyName', emphasis: true); continue; } @@ -245,7 +250,7 @@ for (final Map<dynamic, dynamic> fontFile in fontFiles.cast<Map<dynamic, dynamic>>()) { final String asset = fontFile['asset'] as String; if (asset == null) { - globals.printError('Warning: Missing asset in fonts for $familyName', emphasis: true); + _logger.printError('Warning: Missing asset in fonts for $familyName', emphasis: true); continue; } @@ -310,16 +315,16 @@ } @visibleForTesting -String buildSchemaDir(FileSystem fs) { - return globals.fs.path.join( - globals.fs.path.absolute(Cache.flutterRoot), 'packages', 'flutter_tools', 'schema', +String buildSchemaDir(FileSystem fileSystem) { + return fileSystem.path.join( + fileSystem.path.absolute(Cache.flutterRoot), 'packages', 'flutter_tools', 'schema', ); } @visibleForTesting -String buildSchemaPath(FileSystem fs) { - return globals.fs.path.join( - buildSchemaDir(fs), +String buildSchemaPath(FileSystem fileSystem) { + return fileSystem.path.join( + buildSchemaDir(fileSystem), 'pubspec_yaml.json', ); } @@ -327,7 +332,7 @@ /// This method should be kept in sync with the schema in /// `$FLUTTER_ROOT/packages/flutter_tools/schema/pubspec_yaml.json`, /// but avoid introducing dependencies on packages for simple validation. -bool _validate(YamlMap manifest) { +bool _validate(YamlMap manifest, Logger logger) { final List<String> errors = <String>[]; for (final MapEntry<dynamic, dynamic> kvp in manifest.entries) { if (kvp.key is! String) { @@ -357,8 +362,8 @@ } if (errors.isNotEmpty) { - globals.printStatus('Error detected in pubspec.yaml:', emphasis: true); - globals.printError(errors.join('\n')); + logger.printStatus('Error detected in pubspec.yaml:', emphasis: true); + logger.printError(errors.join('\n')); return false; }
diff --git a/packages/flutter_tools/lib/src/globals.dart b/packages/flutter_tools/lib/src/globals.dart index 43a743b..5031e3e 100644 --- a/packages/flutter_tools/lib/src/globals.dart +++ b/packages/flutter_tools/lib/src/globals.dart
@@ -43,7 +43,10 @@ OperatingSystemUtils get os => context.get<OperatingSystemUtils>(); PersistentToolState get persistentToolState => PersistentToolState.instance; Usage get flutterUsage => context.get<Usage>(); -FlutterProjectFactory get projectFactory => context.get<FlutterProjectFactory>() ?? FlutterProjectFactory(); +FlutterProjectFactory get projectFactory => context.get<FlutterProjectFactory>() ?? FlutterProjectFactory( + logger: logger, + fileSystem: fs, +); const FileSystem _kLocalFs = LocalFileSystem();
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 4efd7c5..9928c96 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart
@@ -12,6 +12,7 @@ import 'artifacts.dart'; import 'base/common.dart'; import 'base/file_system.dart'; +import 'base/logger.dart'; import 'build_info.dart'; import 'bundle.dart' as bundle; import 'features.dart'; @@ -24,7 +25,14 @@ import 'template.dart'; class FlutterProjectFactory { - FlutterProjectFactory(); + FlutterProjectFactory({ + @required Logger logger, + @required FileSystem fileSystem, + }) : _logger = logger, + _fileSystem = fileSystem; + + final Logger _logger; + final FileSystem _fileSystem; @visibleForTesting final Map<String, FlutterProject> projects = @@ -34,14 +42,18 @@ /// if `pubspec.yaml` or `example/pubspec.yaml` is invalid. FlutterProject fromDirectory(Directory directory) { assert(directory != null); - return projects.putIfAbsent(directory.path, /* ifAbsent */ () { + return projects.putIfAbsent(directory.path, () { final FlutterManifest manifest = FlutterProject._readManifest( directory.childFile(bundle.defaultManifestPath).path, + logger: _logger, + fileSystem: _fileSystem, ); final FlutterManifest exampleManifest = FlutterProject._readManifest( FlutterProject._exampleDirectory(directory) .childFile(bundle.defaultManifestPath) .path, + logger: _logger, + fileSystem: _fileSystem, ); return FlutterProject(directory, manifest, exampleManifest); }); @@ -167,7 +179,7 @@ FlutterProject get example => FlutterProject( _exampleDirectory(directory), _exampleManifest, - FlutterManifest.empty(), + FlutterManifest.empty(logger: globals.logger), ); /// True if this project is a Flutter module project. @@ -187,13 +199,20 @@ /// /// Completes with an empty [FlutterManifest], if the file does not exist. /// Completes with a ToolExit on validation error. - static FlutterManifest _readManifest(String path) { + static FlutterManifest _readManifest(String path, { + @required Logger logger, + @required FileSystem fileSystem, + }) { FlutterManifest manifest; try { - manifest = FlutterManifest.createFromPath(path); + manifest = FlutterManifest.createFromPath( + path, + logger: logger, + fileSystem: fileSystem, + ); } on YamlException catch (e) { - globals.printStatus('Error detected in pubspec.yaml:', emphasis: true); - globals.printError('$e'); + logger.printStatus('Error detected in pubspec.yaml:', emphasis: true); + logger.printError('$e'); } if (manifest == null) { throwToolExit('Please correct the pubspec.yaml file at $path');
diff --git a/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart b/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart index 81f98300..ace5077 100644 --- a/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart
@@ -2,54 +2,60 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; - import 'package:file/file.dart'; import 'package:file/memory.dart'; -import 'package:flutter_tools/src/base/context.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'; import '../src/context.dart'; -import '../src/pubspec_schema.dart'; void main() { setUpAll(() { Cache.flutterRoot = getFlutterRoot(); }); - group('FlutterManifest', () { - testUsingContext('is empty when the pubspec.yaml file is empty', () async { - final FlutterManifest flutterManifest = FlutterManifest.createFromString(''); - expect(flutterManifest.isEmpty, true); - expect(flutterManifest.appName, ''); - expect(flutterManifest.usesMaterialDesign, false); - expect(flutterManifest.fontsDescriptor, isEmpty); - expect(flutterManifest.fonts, isEmpty); - expect(flutterManifest.assets, isEmpty); - }); + testWithoutContext('FlutterManifest is empty when the pubspec.yaml file is empty', () async { + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + '', + logger: logger, + ); - test('has no fonts or assets when the "flutter" section is empty', () async { - const String manifest = ''' + expect(flutterManifest.isEmpty, true); + expect(flutterManifest.appName, ''); + expect(flutterManifest.usesMaterialDesign, false); + expect(flutterManifest.fontsDescriptor, isEmpty); + expect(flutterManifest.fonts, isEmpty); + expect(flutterManifest.assets, isEmpty); + }); + + 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); - 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); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('knows if material design is used', () async { - const String manifest = ''' + 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: @@ -57,12 +63,17 @@ flutter: uses-material-design: true '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - expect(flutterManifest.usesMaterialDesign, true); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('has two assets', () async { - const String manifest = ''' + expect(flutterManifest.usesMaterialDesign, true); + }); + + testWithoutContext('FlutterManifest has two assets', () async { + const String manifest = ''' name: test dependencies: flutter: @@ -73,14 +84,20 @@ - a/foo - a/bar '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - expect(flutterManifest.assets.length, 2); - expect(flutterManifest.assets[0], Uri.parse('a/foo')); - expect(flutterManifest.assets[1], Uri.parse('a/bar')); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('has one font family with one asset', () async { - const String manifest = ''' + expect(flutterManifest.assets, <Uri>[ + Uri.parse('a/foo'), + Uri.parse('a/bar'), + ]); + }); + + testWithoutContext('FlutterManifest has one font family with one asset', () async { + const String manifest = ''' name: test dependencies: flutter: @@ -92,24 +109,29 @@ fonts: - asset: a/bar '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types - expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor); - final List<Font> fonts = flutterManifest.fonts; - expect(fonts.length, 1); - final Font font = fonts[0]; - final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}]}; // ignore: always_specify_types - expect(font.descriptor, fooFontDescriptor); - expect(font.familyName, 'foo'); - final List<FontAsset> assets = font.fontAssets; - expect(assets.length, 1); - final FontAsset fontAsset = assets[0]; - expect(fontAsset.assetUri.path, 'a/bar'); - expect(fontAsset.weight, isNull); - expect(fontAsset.style, isNull); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('has one font family with a simple asset and one with weight', () async { + 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: @@ -124,29 +146,32 @@ - asset: a/bar weight: 400 '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types - expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor); - final List<Font> fonts = flutterManifest.fonts; - expect(fonts.length, 1); - final Font font = fonts[0]; - final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'asset': 'a/bar'}]}; // ignore: always_specify_types - expect(font.descriptor, fooFontDescriptor); - expect(font.familyName, 'foo'); - final List<FontAsset> assets = font.fontAssets; - expect(assets.length, 2); - final FontAsset fontAsset0 = assets[0]; - expect(fontAsset0.assetUri.path, 'a/bar'); - expect(fontAsset0.weight, isNull); - expect(fontAsset0.style, isNull); - final FontAsset fontAsset1 = assets[1]; - expect(fontAsset1.assetUri.path, 'a/bar'); - expect(fontAsset1.weight, 400); - expect(fontAsset1.style, isNull); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('has one font family with a simple asset and one with weight and style', () async { - const String manifest = ''' + 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: @@ -161,30 +186,32 @@ weight: 400 style: italic '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}, {'style': 'italic', 'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor); - final List<Font> fonts = flutterManifest.fonts; - expect(fonts.length, 1); - final Font font = fonts[0]; - final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'style': 'italic', 'asset': 'a/bar'}]}; // ignore: always_specify_types - expect(font.descriptor, fooFontDescriptor); - expect(font.familyName, 'foo'); - final List<FontAsset> assets = font.fontAssets; - expect(assets.length, 2); - final FontAsset fontAsset0 = assets[0]; - expect(fontAsset0.assetUri.path, 'a/bar'); - expect(fontAsset0.weight, isNull); - expect(fontAsset0.style, isNull); - final FontAsset fontAsset1 = assets[1]; - expect(fontAsset1.assetUri.path, 'a/bar'); - expect(fontAsset1.weight, 400); - expect(fontAsset1.style, 'italic'); - }); + 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'), + ], + )); + }); - test('has two font families, each with one simple asset and one with weight and style', () async { - const String manifest = ''' + testWithoutContext('FlutterManifest has two font families, each with one ' + 'simple asset and one with weight and style', () { + const String manifest = ''' name: test dependencies: flutter: @@ -205,48 +232,95 @@ asset: a/baz style: italic '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - final dynamic expectedFontsDescriptor = <dynamic>[ - {'fonts': [{'asset': 'a/bar'}, {'style': 'italic', 'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}, // ignore: always_specify_types - {'fonts': [{'asset': 'a/baz'}, {'style': 'italic', 'weight': 400, 'asset': 'a/baz'}], 'family': 'bar'}, // ignore: always_specify_types - ]; - expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor); - final List<Font> fonts = flutterManifest.fonts; - expect(fonts.length, 2); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - final Font fooFont = fonts[0]; - final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'style': 'italic', 'asset': 'a/bar'}]}; // ignore: always_specify_types - expect(fooFont.descriptor, fooFontDescriptor); - expect(fooFont.familyName, 'foo'); - final List<FontAsset> fooAassets = fooFont.fontAssets; - expect(fooAassets.length, 2); - final FontAsset fooFontAsset0 = fooAassets[0]; - expect(fooFontAsset0.assetUri.path, 'a/bar'); - expect(fooFontAsset0.weight, isNull); - expect(fooFontAsset0.style, isNull); - final FontAsset fooFontAsset1 = fooAassets[1]; - expect(fooFontAsset1.assetUri.path, 'a/bar'); - expect(fooFontAsset1.weight, 400); - expect(fooFontAsset1.style, 'italic'); + 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'), + ], + ), + ])); + }); - final Font barFont = fonts[1]; - const String fontDescriptor = '{family: bar, fonts: [{asset: a/baz}, {weight: 400, style: italic, asset: a/baz}]}'; // ignore: always_specify_types - expect(barFont.descriptor.toString(), fontDescriptor); - expect(barFont.familyName, 'bar'); - final List<FontAsset> barAssets = barFont.fontAssets; - expect(barAssets.length, 2); - final FontAsset barFontAsset0 = barAssets[0]; - expect(barFontAsset0.assetUri.path, 'a/baz'); - expect(barFontAsset0.weight, isNull); - expect(barFontAsset0.style, isNull); - final FontAsset barFontAsset1 = barAssets[1]; - expect(barFontAsset1.assetUri.path, 'a/baz'); - expect(barFontAsset1.weight, 400); - expect(barFontAsset1.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 BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - testUsingContext('has only one of two font families when one declaration is missing the "family" option', () async { - const String manifest = ''' + 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: @@ -266,30 +340,34 @@ weight: 400 style: italic '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}, {'style': 'italic', 'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types - expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor); - final List<Font> fonts = flutterManifest.fonts; - expect(fonts.length, 1); - final Font fooFont = fonts[0]; - final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'style': 'italic', 'asset': 'a/bar'}]}; // ignore: always_specify_types - expect(fooFont.descriptor, fooFontDescriptor); - expect(fooFont.familyName, 'foo'); - final List<FontAsset> fooAassets = fooFont.fontAssets; - expect(fooAassets.length, 2); - final FontAsset fooFontAsset0 = fooAassets[0]; - expect(fooFontAsset0.assetUri.path, 'a/bar'); - expect(fooFontAsset0.weight, isNull); - expect(fooFontAsset0.style, isNull); - final FontAsset fooFontAsset1 = fooAassets[1]; - expect(fooFontAsset1.assetUri.path, 'a/bar'); - expect(fooFontAsset1.weight, 400); - expect(fooFontAsset1.style, 'italic'); - }); + 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'), + ], + ), + ])); + }); - testUsingContext('has only one of two font families when one declaration is missing the "fonts" option', () async { - const String manifest = ''' + 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: @@ -305,29 +383,34 @@ style: italic - family: bar '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}, {'style': 'italic', 'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types - expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor); - final List<Font> fonts = flutterManifest.fonts; - expect(fonts.length, 1); - final Font fooFont = fonts[0]; - final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'style': 'italic', 'asset': 'a/bar'}]}; // ignore: always_specify_types - expect(fooFont.descriptor, fooFontDescriptor); - expect(fooFont.familyName, 'foo'); - final List<FontAsset> fooAassets = fooFont.fontAssets; - expect(fooAassets.length, 2); - final FontAsset fooFontAsset0 = fooAassets[0]; - expect(fooFontAsset0.assetUri.path, 'a/bar'); - expect(fooFontAsset0.weight, isNull); - expect(fooFontAsset0.style, isNull); - final FontAsset fooFontAsset1 = fooAassets[1]; - expect(fooFontAsset1.assetUri.path, 'a/bar'); - expect(fooFontAsset1.weight, 400); - expect(fooFontAsset1.style, 'italic'); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - testUsingContext('has no font family when declaration is missing the "asset" option', () async { - const String manifest = ''' + 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: @@ -339,57 +422,76 @@ fonts: - weight: 400 '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - expect(flutterManifest.fontsDescriptor, <dynamic>[]); - final List<Font> fonts = flutterManifest.fonts; - expect(fonts.length, 0); - }); + expect(flutterManifest.fontsDescriptor, isEmpty); + expect(flutterManifest.fonts, isEmpty); + }); - test('allows a blank flutter section', () async { - const String manifest = ''' + testWithoutContext('FlutterManifest allows a blank flutter section', () { + const String manifest = ''' name: test dependencies: flutter: sdk: flutter flutter: '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - expect(flutterManifest.isEmpty, false); - expect(flutterManifest.isModule, false); - expect(flutterManifest.isPlugin, false); - expect(flutterManifest.androidPackage, null); - expect(flutterManifest.usesAndroidX, false); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('allows a module declaration', () async { - const String manifest = ''' + 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); - expect(flutterManifest.isModule, true); - expect(flutterManifest.androidPackage, 'com.example'); - expect(flutterManifest.usesAndroidX, true); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('allows a legacy plugin declaration', () async { - const String manifest = ''' + 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); - expect(flutterManifest.isPlugin, true); - expect(flutterManifest.androidPackage, 'com.example'); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('allows a multi-plat plugin declaration with android only', () async { - const String manifest = ''' + 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: @@ -398,13 +500,19 @@ package: com.example pluginClass: TestPlugin '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - expect(flutterManifest.isPlugin, true); - expect(flutterManifest.androidPackage, 'com.example'); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('allows a multi-plat plugin declaration with ios only', () async { - const String manifest = ''' + 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: @@ -412,37 +520,35 @@ ios: pluginClass: HelloPlugin '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - expect(flutterManifest.isPlugin, true); - expect(flutterManifest.androidPackage, isNull); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - testUsingContext('handles an invalid plugin declaration', () async { - const String manifest = ''' + expect(flutterManifest.isPlugin, true); + expect(flutterManifest.androidPackage, isNull); + }); + + testUsingContext('FlutterManifest handles an invalid plugin declaration', () { + const String manifest = ''' name: test flutter: plugin: '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - expect(flutterManifest, null); - expect(testLogger.errorText, contains('Expected "plugin" to be an object, but got null')); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); + expect(flutterManifest, null); + expect(logger.errorText, + contains('Expected "plugin" to be an object, but got null')); + }); - Future<void> checkManifestVersion({ - String manifest, - String expectedAppVersion, - String expectedBuildName, - String expectedBuildNumber, - }) async { - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - expect(flutterManifest.appVersion, expectedAppVersion); - expect(flutterManifest.buildName, expectedBuildName); - expect(flutterManifest.buildNumber, expectedBuildNumber); - } - - test('parses major.minor.patch+build version clause 1', () async { - const String manifest = ''' + testWithoutContext('FlutterManifest parses major.minor.patch+build version clause 1', () { + const String manifest = ''' name: test version: 1.0.0+2 dependencies: @@ -450,16 +556,21 @@ sdk: flutter flutter: '''; - await checkManifestVersion( - manifest: manifest, - expectedAppVersion: '1.0.0+2', - expectedBuildName: '1.0.0', - expectedBuildNumber: '2', - ); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('parses major.minor.patch with no build version', () async { - const String manifest = ''' + 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: @@ -467,16 +578,21 @@ sdk: flutter flutter: '''; - await checkManifestVersion( - manifest: manifest, - expectedAppVersion: '0.0.1', - expectedBuildName: '0.0.1', - expectedBuildNumber: null, - ); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('parses major.minor.patch+build version clause 2', () async { - const String manifest = ''' + expect(flutterManifest, matchesManifest( + appVersion: '0.0.1', + buildName: '0.0.1', + buildNumber: null), + ); + }); + + testWithoutContext('FlutterManifest parses major.minor.patch+build version clause 2', () { + const String manifest = ''' name: test version: 1.0.0-beta+exp.sha.5114f85 dependencies: @@ -484,16 +600,21 @@ sdk: flutter flutter: '''; - await checkManifestVersion( - manifest: manifest, - expectedAppVersion: '1.0.0-beta+exp.sha.5114f85', - expectedBuildName: '1.0.0-beta', - expectedBuildNumber: 'exp.sha.5114f85', - ); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('parses major.minor+build version clause', () async { - const String manifest = ''' + 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+2 dependencies: @@ -501,16 +622,21 @@ sdk: flutter flutter: '''; - await checkManifestVersion( - manifest: manifest, - expectedAppVersion: '1.0+2', - expectedBuildName: '1.0', - expectedBuildNumber: '2', - ); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('parses empty version clause', () async { - const String manifest = ''' + expect(flutterManifest, matchesManifest( + appVersion: '1.0+2', + buildName: '1.0', + buildNumber: '2'), + ); + }); + + testWithoutContext('FlutterManifest parses empty version clause', () { + const String manifest = ''' name: test version: dependencies: @@ -518,33 +644,43 @@ sdk: flutter flutter: '''; - await checkManifestVersion( - manifest: manifest, - expectedAppVersion: null, - expectedBuildName: null, - expectedBuildNumber: null, - ); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - test('parses no version clause', () async { - const String manifest = ''' + expect(flutterManifest, matchesManifest( + appVersion: null, + buildName: null, + buildNumber: null), + ); + }); + + testWithoutContext('FlutterManifest parses no version clause', () { + const String manifest = ''' name: test dependencies: flutter: sdk: flutter flutter: '''; - await checkManifestVersion( - manifest: manifest, - expectedAppVersion: null, - expectedBuildName: null, - expectedBuildNumber: null, - ); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); + + expect(flutterManifest, matchesManifest( + appVersion: null, + buildName: null, + buildNumber: null), + ); + }); // Regression test for https://github.com/flutter/flutter/issues/31764 - testUsingContext('Returns proper error when font detail is malformed', () async { - const String manifest = ''' + testWithoutContext('FlutterManifest returns proper error when font detail is malformed', () { + const String manifest = ''' name: test dependencies: flutter: @@ -555,14 +691,20 @@ fonts: -asset: a/bar '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - expect(flutterManifest, null); - expect(testLogger.errorText, contains('Expected "fonts" to either be null or a list.')); - }); + expect(flutterManifest, null); + expect(logger.errorText, + contains('Expected "fonts" to either be null or a list.')); + }); - testUsingContext('Returns proper error when font detail is not a list of maps', () async { - const String manifest = ''' + testWithoutContext('FlutterManifest returns proper error when font detail is ' + 'not a list of maps', () { + const String manifest = ''' name: test dependencies: flutter: @@ -573,14 +715,20 @@ fonts: - asset '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - expect(flutterManifest, null); - expect(testLogger.errorText, contains('Expected "fonts" to be a list of maps.')); - }); + expect(flutterManifest, null); + expect(logger.errorText, + contains('Expected "fonts" to be a list of maps.')); + }); - testUsingContext('Returns proper error when font is a map instead of a list', () async { - const String manifest = ''' + testWithoutContext('FlutterManifest returns proper error when font is a map ' + 'instead of a list', () { + const String manifest = ''' name: test dependencies: flutter: @@ -591,14 +739,19 @@ fonts: -asset: a/bar '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - expect(flutterManifest, null); - expect(testLogger.errorText, contains('Expected "fonts" to be a list')); - }); + expect(flutterManifest, null); + expect(logger.errorText, contains('Expected "fonts" to be a list')); + }); - testUsingContext('Returns proper error when second font family is invalid', () async { - const String manifest = ''' + testWithoutContext('FlutterManifest returns proper error when second font ' + 'family is invalid', () { + const String manifest = ''' name: test dependencies: flutter: @@ -611,13 +764,18 @@ - asset: a/bar - string '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - expect(flutterManifest, null); - expect(testLogger.errorText, contains('Expected a map.')); - }); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - testUsingContext('Does not crash on empty entry', () async { - const String manifest = ''' + expect(flutterManifest, null); + expect(logger.errorText, contains('Expected a map.')); + }); + + testWithoutContext('FlutterManifest does not crash on empty entry', () { + const String manifest = ''' name: test dependencies: flutter: @@ -628,15 +786,19 @@ - lib/gallery/example_code.dart - '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - final List<Uri> assets = flutterManifest.assets; + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); + final List<Uri> assets = flutterManifest.assets; - expect(testLogger.errorText, contains('Asset manifest contains a null or empty uri.')); - expect(assets.length, 1); - }); + expect(logger.errorText, contains('Asset manifest contains a null or empty uri.')); + expect(assets, hasLength(1)); + }); - testUsingContext('Special characters in asset URIs', () async { - const String manifest = ''' + testWithoutContext('FlutterManifest handles special characters in asset URIs', () { + const String manifest = ''' name: test dependencies: flutter: @@ -648,17 +810,24 @@ - lib/gallery/abc?xyz - lib/gallery/aaa bbb '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - final List<Uri> assets = flutterManifest.assets; + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); + final List<Uri> assets = flutterManifest.assets; - expect(assets.length, 3); - expect(assets[0].path, 'lib/gallery/abc%23xyz'); - expect(assets[1].path, 'lib/gallery/abc%3Fxyz'); - expect(assets[2].path, 'lib/gallery/aaa%20bbb'); - }); + expect(assets, hasLength(3)); + expect(assets, <Uri>[ + Uri.parse('lib/gallery/abc%23xyz'), + Uri.parse('lib/gallery/abc%3Fxyz'), + Uri.parse('lib/gallery/aaa%20bbb'), + ]); + }); - testUsingContext('Returns proper error when flutter is a list instead of a map', () async { - const String manifest = ''' + testWithoutContext('FlutterManifest returns proper error when flutter is a ' + 'list instead of a map', () { + const String manifest = ''' name: test dependencies: flutter: @@ -666,16 +835,43 @@ flutter: - uses-material-design: true '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); - expect(flutterManifest, null); - expect(testLogger.errorText, contains('Expected "flutter" section to be an object or null, but got [{uses-material-design: true}].')); - }); + expect(flutterManifest, null); + expect(logger.errorText, + contains( + 'Expected "flutter" section to be an object or null, but got ' + '[{uses-material-design: true}].', + ), + ); }); - group('FlutterManifest with MemoryFileSystem', () { - Future<void> assertSchemaIsReadable() async { - const String manifest = ''' + 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 BufferLogger logger = BufferLogger.test(); + 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: @@ -683,47 +879,48 @@ flutter: '''; - final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest); - expect(flutterManifest.isEmpty, false); - } - - void testUsingContextAndFs( - String description, - FileSystem filesystem, - dynamic testMethod(), - ) { - testUsingContext( - description, - () async { - writeEmptySchemaFile(filesystem); - testMethod(); - }, - overrides: <Type, Generator>{ - FileSystem: () => filesystem, - ProcessManager: () => FakeProcessManager.any(), - }, - ); - } - - testUsingContext('Validate manifest on original fs', () { - assertSchemaIsReadable(); - }); - - testUsingContextAndFs( - 'Validate manifest on Posix FS', - MemoryFileSystem(style: FileSystemStyle.posix), - () { - assertSchemaIsReadable(); - }, + final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); + fileSystem.file('pubspec.yaml').writeAsStringSync(manifest); + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromPath( + 'pubspec.yaml', + fileSystem: fileSystem, + logger: logger, ); - testUsingContextAndFs( - 'Validate manifest on Windows FS', - MemoryFileSystem(style: FileSystemStyle.windows), - () { - assertSchemaIsReadable(); - }, - ); - + expect(flutterManifest.isEmpty, 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({ + 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({ + Map<String, Object> descriptor, + String familyName, + 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)); +}
diff --git a/packages/flutter_tools/test/general.shard/github_template_test.dart b/packages/flutter_tools/test/general.shard/github_template_test.dart index b5142c1..1082d51 100644 --- a/packages/flutter_tools/test/general.shard/github_template_test.dart +++ b/packages/flutter_tools/test/general.shard/github_template_test.dart
@@ -160,7 +160,10 @@ fileSystem: fs, logger: logger, client: SuccessShortenURLFakeHttpClient(), - flutterProjectFactory: FlutterProjectFactory(), + flutterProjectFactory: FlutterProjectFactory( + fileSystem: fs, + logger: logger, + ), ); expect( await creator.toolCrashIssueTemplateGitHubURL(command, error, stackTrace, doctorText), @@ -176,7 +179,10 @@ fileSystem: fs, logger: logger, client: FakeHttpClient(), - flutterProjectFactory: FlutterProjectFactory(), + flutterProjectFactory: FlutterProjectFactory( + fileSystem: fs, + logger: logger, + ), ); expect( await creator.toolCrashIssueTemplateGitHubURL(command, error, stackTrace, doctorText), @@ -199,7 +205,10 @@ fileSystem: fs, logger: logger, client: FakeHttpClient(), - flutterProjectFactory: FlutterProjectFactory(), + flutterProjectFactory: FlutterProjectFactory( + fileSystem: fs, + logger: logger, + ), ); final Directory projectDirectory = fs.currentDirectory;
diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index 1647480..b212434 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart
@@ -8,6 +8,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/context.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/features.dart'; import 'package:flutter_tools/src/flutter_manifest.dart'; @@ -23,6 +24,10 @@ import '../src/testbed.dart'; void main() { + // TODO(jonahwilliams): remove once FlutterProject is fully refactored. + // this is safe since no tests have expectations on the test logger. + final BufferLogger logger = BufferLogger.test(); + group('Project', () { group('construction', () { testInMemory('fails on null directory', () async { @@ -154,8 +159,8 @@ testInMemory('does nothing, if project is not created', () async { final FlutterProject project = FlutterProject( globals.fs.directory('not_created'), - FlutterManifest.empty(), - FlutterManifest.empty(), + FlutterManifest.empty(logger: logger), + FlutterManifest.empty(logger: logger), ); await project.ensureReadyForPlatformSpecificTooling(); expectNotExists(project.directory); @@ -197,7 +202,10 @@ FileSystem: () => MemoryFileSystem(), ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), - FlutterProjectFactory: () => FlutterProjectFactory(), + FlutterProjectFactory: () => FlutterProjectFactory( + logger: logger, + fileSystem: globals.fs, + ), }); testUsingContext('generates Xcode configuration for macOS', () async { final FlutterProject project = await someProject(); @@ -208,7 +216,10 @@ FileSystem: () => MemoryFileSystem(), ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), - FlutterProjectFactory: () => FlutterProjectFactory(), + FlutterProjectFactory: () => FlutterProjectFactory( + logger: logger, + fileSystem: globals.fs, + ), }); testUsingContext('injects plugins for Linux', () async { final FlutterProject project = await someProject(); @@ -220,7 +231,10 @@ FileSystem: () => MemoryFileSystem(), ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), - FlutterProjectFactory: () => FlutterProjectFactory(), + FlutterProjectFactory: () => FlutterProjectFactory( + logger: logger, + fileSystem: globals.fs, + ), }); testUsingContext('injects plugins for Windows', () async { final FlutterProject project = await someProject(); @@ -246,7 +260,10 @@ FileSystem: () => MemoryFileSystem(), ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), - FlutterProjectFactory: () => FlutterProjectFactory(), + FlutterProjectFactory: () => FlutterProjectFactory( + logger: logger, + fileSystem: globals.fs, + ), }); testInMemory('creates Android library in module', () async { final FlutterProject project = await aModuleProject(); @@ -312,7 +329,10 @@ setUp(() { fs = MemoryFileSystem(); mockXcodeProjectInterpreter = MockXcodeProjectInterpreter(); - flutterProjectFactory = FlutterProjectFactory(); + flutterProjectFactory = FlutterProjectFactory( + logger: logger, + fileSystem: fs, + ); }); testInMemory('default host app language', () async { @@ -348,7 +368,10 @@ fs = MemoryFileSystem(); mockPlistUtils = MockPlistUtils(); mockXcodeProjectInterpreter = MockXcodeProjectInterpreter(); - flutterProjectFactory = FlutterProjectFactory(); + flutterProjectFactory = FlutterProjectFactory( + fileSystem: fs, + logger: logger, + ); }); void testWithMocks(String description, Future<void> testMethod()) { @@ -521,8 +544,12 @@ FlutterProjectFactory flutterProjectFactory; setUp(() { - testbed = Testbed(); - flutterProjectFactory = FlutterProjectFactory(); + testbed = Testbed(setup: () { + flutterProjectFactory = FlutterProjectFactory( + fileSystem: globals.fs, + logger: globals.logger, + ); + }); }); test('Handles asking for builders from an invalid pubspec', () => testbed.run(() { @@ -646,7 +673,10 @@ packagesFile.createSync(recursive: true); packagesFile.writeAsStringSync('flutter_template_images:${dummyTemplateImagesDirectory.uri}'); - final FlutterProjectFactory flutterProjectFactory = FlutterProjectFactory(); + final FlutterProjectFactory flutterProjectFactory = FlutterProjectFactory( + fileSystem: testFileSystem, + logger: globals.logger ?? BufferLogger.test(), + ); testUsingContext( description,
diff --git a/packages/flutter_tools/test/src/android_common.dart b/packages/flutter_tools/test/src/android_common.dart index 01eec17..cba857f 100644 --- a/packages/flutter_tools/test/src/android_common.dart +++ b/packages/flutter_tools/test/src/android_common.dart
@@ -4,6 +4,7 @@ import 'package:meta/meta.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/build_info.dart'; @@ -39,7 +40,11 @@ /// within [directoryOverride]. class FakeFlutterProjectFactory extends FlutterProjectFactory { FakeFlutterProjectFactory(this.directoryOverride) : - assert(directoryOverride != null); + assert(directoryOverride != null), + super( + fileSystem: globals.fs, + logger: globals.logger, + ); final Directory directoryOverride;