| // 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() { |
| setUpAll(() { |
| Cache.flutterRoot = getFlutterRoot(); |
| }); |
| |
| testWithoutContext('FlutterManifest is empty when the pubspec.yaml file is empty', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| 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 { |
| final BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| )!; |
| |
| expect(flutterManifest.generateSyntheticPackage, false); |
| }); |
| |
| testWithoutContext('FlutterManifest has two assets', () async { |
| const String manifest = ''' |
| name: test |
| dependencies: |
| flutter: |
| sdk: flutter |
| flutter: |
| uses-material-design: true |
| assets: |
| - a/foo |
| - a/bar |
| '''; |
| final BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| )!; |
| |
| 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: |
| sdk: flutter |
| flutter: |
| uses-material-design: true |
| fonts: |
| - family: foo |
| fonts: |
| - asset: a/bar |
| '''; |
| final BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 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')); |
| }); |
| |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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+2 |
| dependencies: |
| flutter: |
| sdk: flutter |
| flutter: |
| '''; |
| final BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| 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: |
| flutter: |
| sdk: flutter |
| flutter: |
| '''; |
| final BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| expect(flutterManifest, isNotNull); |
| expect(flutterManifest!.fonts.length, 0); |
| }); |
| |
| testWithoutContext('FlutterManifest ignores empty list of assets', () { |
| const String manifest = ''' |
| name: test |
| dependencies: |
| flutter: |
| sdk: flutter |
| flutter: |
| assets: [] |
| '''; |
| final BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| expect(flutterManifest, isNotNull); |
| expect(flutterManifest!.assets.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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| 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: |
| sdk: flutter |
| flutter: |
| uses-material-design: true |
| assets: |
| - lib/gallery/example_code.dart |
| - |
| '''; |
| final BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| )!; |
| final List<Uri> assets = flutterManifest.assets; |
| |
| expect(logger.errorText, contains('Asset manifest contains a null or empty uri.')); |
| expect(assets, hasLength(1)); |
| }); |
| |
| testWithoutContext('FlutterManifest handles special characters in asset URIs', () { |
| const String manifest = ''' |
| name: test |
| dependencies: |
| flutter: |
| sdk: flutter |
| flutter: |
| uses-material-design: true |
| assets: |
| - lib/gallery/abc#xyz |
| - lib/gallery/abc?xyz |
| - lib/gallery/aaa bbb |
| '''; |
| final BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| )!; |
| final List<Uri> assets = flutterManifest.assets; |
| |
| 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'), |
| ]); |
| }); |
| |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 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: |
| sdk: flutter |
| flutter: |
| '''; |
| |
| 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, |
| )!; |
| |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| expect(flutterManifest, null); |
| expect(logger.errorText, 'Expected "licenses" to be a list of files, but element 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 BufferLogger logger = BufferLogger.test(); |
| 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].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 BufferLogger logger = BufferLogger.test(); |
| 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].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].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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| 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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| expect(flutterManifest, null); |
| expect(logger.errorText, 'Expected "libraries" key in the 0 element of "deferred-components" to be a list, 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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| expect(flutterManifest, null); |
| expect(logger.errorText, 'Expected "libraries" key in the 0 element of "deferred-components" to be a list of dart library Strings, but element 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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| expect(flutterManifest, null); |
| expect(logger.errorText, 'Expected "assets" key in the 0 element of "deferred-components" to be a list of file paths, but element 0 was a YamlMap\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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| expect(flutterManifest, null); |
| expect(logger.errorText, 'Expected "assets" key in the 0 element of "deferred-components" to be a list of file paths, but element 1 was a YamlMap\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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| expect(flutterManifest, null); |
| expect(logger.errorText, 'Expected "assets" key in the 1 element of "deferred-components" to be a list of file paths, but element 1 was a YamlMap\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 BufferLogger logger = BufferLogger.test(); |
| final FlutterManifest? flutterManifest = FlutterManifest.createFromString( |
| manifest, |
| logger: logger, |
| ); |
| |
| expect(flutterManifest, null); |
| expect(logger.errorText, 'Expected "assets" key in the 0 element of "deferred-components" 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 BufferLogger logger = BufferLogger.test(); |
| 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].path, 'path/to/asset1.jpg'); |
| expect(deferredComponents[0].assets[1].path, 'path/to/asset2.jpg'); |
| expect(deferredComponents[0].assets[2].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); |
| }); |
| } |
| |
| 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)); |
| } |