Unverified Commit 84580b54 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Make Assets more robust across platforms (#14246)

parent 9654659c
...@@ -167,7 +167,7 @@ class AssetBundle { ...@@ -167,7 +167,7 @@ class AssetBundle {
} }
for (_Asset variant in assetVariants[asset]) { for (_Asset variant in assetVariants[asset]) {
assert(variant.assetFileExists); assert(variant.assetFileExists);
entries[variant.assetEntry] = new DevFSFileContent(variant.assetFile); entries[variant.entryUri.path] = new DevFSFileContent(variant.assetFile);
} }
} }
...@@ -177,7 +177,7 @@ class AssetBundle { ...@@ -177,7 +177,7 @@ class AssetBundle {
} }
for (_Asset asset in materialAssets) { for (_Asset asset in materialAssets) {
assert(asset.assetFileExists); assert(asset.assetFileExists);
entries[asset.assetEntry] = new DevFSFileContent(asset.assetFile); entries[asset.entryUri.path] = new DevFSFileContent(asset.assetFile);
} }
entries[_kAssetManifestJson] = _createAssetManifest(assetVariants); entries[_kAssetManifestJson] = _createAssetManifest(assetVariants);
...@@ -199,38 +199,34 @@ class AssetBundle { ...@@ -199,38 +199,34 @@ class AssetBundle {
} }
class _Asset { class _Asset {
_Asset({ this.base, String assetEntry, this.relativePath, this.source }) _Asset({ this.baseDir, this.relativeUri, this.entryUri });
: _assetEntry = assetEntry;
final String _assetEntry; final String baseDir;
final String base; /// A platform-independent Uri where this asset can be found on disk on the
/// host system relative to [baseDir].
final Uri relativeUri;
/// The entry to list in the generated asset manifest. /// A platform-independent Uri representing the entry for the asset manifest.
String get assetEntry => _assetEntry ?? relativePath; final Uri entryUri;
/// Where the resource is on disk relative to [base].
final String relativePath;
final String source;
File get assetFile { File get assetFile {
return fs.file(source != null ? '$base/$source' : '$base/$relativePath'); return fs.file(fs.path.join(baseDir, fs.path.fromUri(relativeUri)));
} }
bool get assetFileExists => assetFile.existsSync(); bool get assetFileExists => assetFile.existsSync();
/// The delta between what the assetEntry is and the relativePath (e.g., /// The delta between what the entryUri is and the relativeUri (e.g.,
/// packages/flutter_gallery). /// packages/flutter_gallery).
String get symbolicPrefix { Uri get symbolicPrefixUri {
if (_assetEntry == null || _assetEntry == relativePath) if (entryUri == relativeUri)
return null; return null;
final int index = _assetEntry.indexOf(relativePath); final int index = entryUri.path.indexOf(relativeUri.path);
return index == -1 ? null : _assetEntry.substring(0, index); return index == -1 ? null : new Uri(path: entryUri.path.substring(0, index));
} }
@override @override
String toString() => 'asset: $assetEntry'; String toString() => 'asset: $entryUri';
@override @override
bool operator ==(dynamic other) { bool operator ==(dynamic other) {
...@@ -239,18 +235,16 @@ class _Asset { ...@@ -239,18 +235,16 @@ class _Asset {
if (other.runtimeType != runtimeType) if (other.runtimeType != runtimeType)
return false; return false;
final _Asset otherAsset = other; final _Asset otherAsset = other;
return otherAsset.base == base return otherAsset.baseDir == baseDir
&& otherAsset.assetEntry == assetEntry && otherAsset.relativeUri == relativeUri
&& otherAsset.relativePath == relativePath && otherAsset.entryUri == entryUri;
&& otherAsset.source == source;
} }
@override @override
int get hashCode { int get hashCode {
return base.hashCode return baseDir.hashCode
^assetEntry.hashCode ^relativeUri.hashCode
^relativePath.hashCode ^ entryUri.hashCode;
^ source.hashCode;
} }
} }
...@@ -272,11 +266,11 @@ List<_Asset> _getMaterialAssets(String fontSet) { ...@@ -272,11 +266,11 @@ List<_Asset> _getMaterialAssets(String fontSet) {
for (Map<String, dynamic> family in _getMaterialFonts(fontSet)) { for (Map<String, dynamic> family in _getMaterialFonts(fontSet)) {
for (Map<String, dynamic> font in family['fonts']) { for (Map<String, dynamic> font in family['fonts']) {
final String assetKey = font['asset']; final Uri entryUri = fs.path.toUri(font['asset']);
result.add(new _Asset( result.add(new _Asset(
base: fs.path.join(Cache.flutterRoot, 'bin', 'cache', 'artifacts', 'material_fonts'), baseDir: fs.path.join(Cache.flutterRoot, 'bin', 'cache', 'artifacts', 'material_fonts'),
source: fs.path.basename(assetKey), relativeUri: new Uri(path: entryUri.pathSegments.last),
relativePath: assetKey entryUri: entryUri
)); ));
} }
} }
...@@ -361,8 +355,8 @@ DevFSContent _createAssetManifest(Map<_Asset, List<_Asset>> assetVariants) { ...@@ -361,8 +355,8 @@ DevFSContent _createAssetManifest(Map<_Asset, List<_Asset>> assetVariants) {
for (_Asset main in assetVariants.keys) { for (_Asset main in assetVariants.keys) {
final List<String> variants = <String>[]; final List<String> variants = <String>[];
for (_Asset variant in assetVariants[main]) for (_Asset variant in assetVariants[main])
variants.add(variant.assetEntry); variants.add(variant.entryUri.path);
json[main.assetEntry] = variants; json[main.entryUri.path] = variants;
} }
return new DevFSStringContent(JSON.encode(json)); return new DevFSStringContent(JSON.encode(json));
} }
...@@ -400,17 +394,17 @@ List<Font> _parsePackageFonts( ...@@ -400,17 +394,17 @@ List<Font> _parsePackageFonts(
for (Font font in manifest.fonts) { for (Font font in manifest.fonts) {
final List<FontAsset> packageFontAssets = <FontAsset>[]; final List<FontAsset> packageFontAssets = <FontAsset>[];
for (FontAsset fontAsset in font.fontAssets) { for (FontAsset fontAsset in font.fontAssets) {
final String assetPath = fontAsset.asset; final Uri assetUri = fontAsset.assetUri;
if (assetPath.startsWith('packages') && if (assetUri.pathSegments.first == 'packages' &&
!fs.isFileSync(packageMap.map[packageName].resolve('../$assetPath').path)) { !fs.isFileSync(fs.path.fromUri(packageMap.map[packageName].resolve('../${assetUri.path}')))) {
packageFontAssets.add(new FontAsset( packageFontAssets.add(new FontAsset(
fontAsset.asset, fontAsset.assetUri,
weight: fontAsset.weight, weight: fontAsset.weight,
style: fontAsset.style, style: fontAsset.style,
)); ));
} else { } else {
packageFontAssets.add(new FontAsset( packageFontAssets.add(new FontAsset(
'packages/$packageName/${fontAsset.asset}', new Uri(pathSegments: <String>['packages', packageName]..addAll(assetUri.pathSegments)),
weight: fontAsset.weight, weight: fontAsset.weight,
style: fontAsset.style, style: fontAsset.style,
)); ));
...@@ -486,20 +480,25 @@ Map<_Asset, List<_Asset>> _parseAssets( ...@@ -486,20 +480,25 @@ Map<_Asset, List<_Asset>> _parseAssets(
final Map<_Asset, List<_Asset>> result = <_Asset, List<_Asset>>{}; final Map<_Asset, List<_Asset>> result = <_Asset, List<_Asset>>{};
final _AssetDirectoryCache cache = new _AssetDirectoryCache(excludeDirs); final _AssetDirectoryCache cache = new _AssetDirectoryCache(excludeDirs);
for (String assetName in flutterManifest.assets) { for (Uri assetUri in flutterManifest.assets) {
final _Asset asset = _resolveAsset( final _Asset asset = _resolveAsset(
packageMap, packageMap,
assetBase, assetBase,
assetName, assetUri,
packageName, packageName,
); );
final List<_Asset> variants = <_Asset>[]; final List<_Asset> variants = <_Asset>[];
for (String path in cache.variantsFor(asset.assetFile.path)) { for (String path in cache.variantsFor(asset.assetFile.path)) {
final String key = fs.path.relative(path, from: asset.base); final String relativePath = fs.path.relative(path, from: asset.baseDir);
String assetEntry; final Uri relativeUri = fs.path.toUri(relativePath);
if (asset.symbolicPrefix != null) final Uri entryUri = asset.symbolicPrefixUri == null
assetEntry = fs.path.join(asset.symbolicPrefix, key); ? relativeUri
variants.add(new _Asset(base: asset.base, assetEntry: assetEntry, relativePath: key)); : asset.symbolicPrefixUri.resolveUri(relativeUri);
variants.add(new _Asset(
baseDir: asset.baseDir,
entryUri: entryUri,
relativeUri: relativeUri,
));
} }
result[asset] = variants; result[asset] = variants;
...@@ -511,11 +510,11 @@ Map<_Asset, List<_Asset>> _parseAssets( ...@@ -511,11 +510,11 @@ Map<_Asset, List<_Asset>> _parseAssets(
final _Asset baseAsset = _resolveAsset( final _Asset baseAsset = _resolveAsset(
packageMap, packageMap,
assetBase, assetBase,
fontAsset.asset, fontAsset.assetUri,
packageName, packageName,
); );
if (!baseAsset.assetFileExists) { if (!baseAsset.assetFileExists) {
printError('Error: unable to locate asset entry in pubspec.yaml: "${fontAsset.asset}".'); printError('Error: unable to locate asset entry in pubspec.yaml: "${fontAsset.assetUri}".');
return null; return null;
} }
...@@ -528,47 +527,42 @@ Map<_Asset, List<_Asset>> _parseAssets( ...@@ -528,47 +527,42 @@ Map<_Asset, List<_Asset>> _parseAssets(
_Asset _resolveAsset( _Asset _resolveAsset(
PackageMap packageMap, PackageMap packageMap,
String assetBase, String assetsBaseDir,
String asset, Uri assetUri,
String packageName, String packageName,
) { ) {
if (asset.startsWith('packages/') && !fs.isFileSync(fs.path.join(assetBase, asset))) { final String assetPath = fs.path.fromUri(assetUri);
if (assetUri.pathSegments.first == 'packages' && !fs.isFileSync(fs.path.join(assetsBaseDir, assetPath))) {
// The asset is referenced in the pubspec.yaml as // The asset is referenced in the pubspec.yaml as
// 'packages/PACKAGE_NAME/PATH/TO/ASSET . // 'packages/PACKAGE_NAME/PATH/TO/ASSET .
final _Asset packageAsset = _resolvePackageAsset(asset, packageMap); final _Asset packageAsset = _resolvePackageAsset(assetUri, packageMap);
if (packageAsset != null) if (packageAsset != null)
return packageAsset; return packageAsset;
} }
final String assetEntry = packageName != null return new _Asset(
? 'packages/$packageName/$asset' // Asset from, and declared in $packageName. baseDir: assetsBaseDir,
: null; // Asset from the current application. entryUri: packageName == null
return new _Asset(base: assetBase, assetEntry: assetEntry, relativePath: asset); ? assetUri // Asset from the current application.
: new Uri(pathSegments: <String>['packages', packageName]..addAll(assetUri.pathSegments)), // Asset from, and declared in $packageName.
relativeUri: assetUri,
);
} }
_Asset _resolvePackageAsset(String asset, PackageMap packageMap) { _Asset _resolvePackageAsset(Uri assetUri, PackageMap packageMap) {
assert(asset.startsWith('packages/')); assert(assetUri.pathSegments.first == 'packages');
String packageKey = asset.substring('packages/'.length); if (assetUri.pathSegments.length > 1) {
String relativeAsset = asset; final String packageName = assetUri.pathSegments[1];
final Uri packageUri = packageMap.map[packageName];
final int index = packageKey.indexOf('/'); if (packageUri != null && packageUri.scheme == 'file') {
if (index != -1) {
relativeAsset = packageKey.substring(index + 1);
packageKey = packageKey.substring(0, index);
final Uri uri = packageMap.map[packageKey];
if (uri != null && uri.scheme == 'file') {
final File file = fs.file(uri);
final String base = file.path.substring(0, file.path.length - 1);
return new _Asset( return new _Asset(
base: base, baseDir: fs.path.fromUri(packageUri),
assetEntry: asset, entryUri: assetUri,
relativePath: relativeAsset, relativeUri: new Uri(pathSegments: assetUri.pathSegments.sublist(2)),
); );
} }
} }
printStatus('Error detected in pubspec.yaml:', emphasis: true); printStatus('Error detected in pubspec.yaml:', emphasis: true);
printError('Could not resolve package $packageKey for asset $asset.\n'); printError('Could not resolve package for asset $assetUri.\n');
return null; return null;
} }
...@@ -52,8 +52,8 @@ class FlutterManifest { ...@@ -52,8 +52,8 @@ class FlutterManifest {
return _flutterDescriptor['fonts'] ?? const <Map<String, dynamic>>[]; return _flutterDescriptor['fonts'] ?? const <Map<String, dynamic>>[];
} }
List<String> get assets { List<Uri> get assets {
return _flutterDescriptor['assets'] ?? const <String>[]; return _flutterDescriptor['assets']?.map(Uri.parse)?.toList() ?? const <Uri>[];
} }
List<Font> _fonts; List<Font> _fonts;
...@@ -89,7 +89,7 @@ class FlutterManifest { ...@@ -89,7 +89,7 @@ class FlutterManifest {
} }
fontAssets.add(new FontAsset( fontAssets.add(new FontAsset(
asset, Uri.parse(asset),
weight: fontFile['weight'], weight: fontFile['weight'],
style: fontFile['style'], style: fontFile['style'],
)); ));
...@@ -122,10 +122,10 @@ class Font { ...@@ -122,10 +122,10 @@ class Font {
} }
class FontAsset { class FontAsset {
FontAsset(this.asset, {this.weight, this.style}) FontAsset(this.assetUri, {this.weight, this.style})
: assert(asset != null); : assert(assetUri != null);
final String asset; final Uri assetUri;
final int weight; final int weight;
final String style; final String style;
...@@ -137,12 +137,12 @@ class FontAsset { ...@@ -137,12 +137,12 @@ class FontAsset {
if (style != null) if (style != null)
descriptor['style'] = style; descriptor['style'] = style;
descriptor['asset'] = asset; descriptor['asset'] = assetUri.path;
return descriptor; return descriptor;
} }
@override @override
String toString() => '$runtimeType(asset: $asset, weight; $weight, style: $style)'; String toString() => '$runtimeType(asset: ${assetUri.path}, weight; $weight, style: $style)';
} }
Future<dynamic> _loadFlutterManifest(String manifestPath) async { Future<dynamic> _loadFlutterManifest(String manifestPath) async {
...@@ -167,4 +167,4 @@ Future<bool> _validate(Object manifest) async { ...@@ -167,4 +167,4 @@ Future<bool> _validate(Object manifest) async {
printError(validator.errors.join('\n')); printError(validator.errors.join('\n'));
return false; return false;
} }
} }
\ No newline at end of file
...@@ -6,7 +6,6 @@ import 'dart:async'; ...@@ -6,7 +6,6 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/asset.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
...@@ -92,6 +91,28 @@ $fontsSection ...@@ -92,6 +91,28 @@ $fontsSection
..writeAsStringSync(font); ..writeAsStringSync(font);
} }
// These tests do not use a memory file system because we want to ensure that
// asset bundles work correctly on Windows and Posix systems.
Directory tempDir;
Directory oldCurrentDir;
setUp(() async {
tempDir = await fs.systemTempDirectory.createTemp('asset_bundle_tests');
oldCurrentDir = fs.currentDirectory;
fs.currentDirectory = tempDir;
});
tearDown(() {
fs.currentDirectory = oldCurrentDir;
try {
tempDir?.deleteSync(recursive: true);
tempDir = null;
} on FileSystemException catch (e) {
// Do nothing, windows sometimes has trouble deleting.
print('Ignored exception during tearDown: $e');
}
});
group('AssetBundle fonts from packages', () { group('AssetBundle fonts from packages', () {
testUsingContext('App includes neither font manifest nor fonts when no defines fonts', () async { testUsingContext('App includes neither font manifest nor fonts when no defines fonts', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -104,7 +125,7 @@ $fontsSection ...@@ -104,7 +125,7 @@ $fontsSection
await bundle.build(manifestPath: 'pubspec.yaml'); await bundle.build(manifestPath: 'pubspec.yaml');
expect(bundle.entries.length, 2); // LICENSE, AssetManifest expect(bundle.entries.length, 2); // LICENSE, AssetManifest
expect(bundle.entries.containsKey('FontManifest.json'), false); expect(bundle.entries.containsKey('FontManifest.json'), false);
}, overrides: contextOverrides); });
testUsingContext('App font uses font file from package', () async { testUsingContext('App font uses font file from package', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -129,7 +150,7 @@ $fontsSection ...@@ -129,7 +150,7 @@ $fontsSection
<String>['test_package'], <String>['test_package'],
expectedFontManifest, expectedFontManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('App font uses local font file and package font file', () async { testUsingContext('App font uses local font file and package font file', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -158,7 +179,7 @@ $fontsSection ...@@ -158,7 +179,7 @@ $fontsSection
<String>['test_package'], <String>['test_package'],
expectedFontManifest, expectedFontManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('App uses package font with own font file', () async { testUsingContext('App uses package font with own font file', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -188,7 +209,7 @@ $fontsSection ...@@ -188,7 +209,7 @@ $fontsSection
<String>['test_package'], <String>['test_package'],
expectedFontManifest, expectedFontManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('App uses package font with font file from another package', () async { testUsingContext('App uses package font with font file from another package', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -219,7 +240,7 @@ $fontsSection ...@@ -219,7 +240,7 @@ $fontsSection
<String>['test_package2'], <String>['test_package2'],
expectedFontManifest, expectedFontManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('App uses package font with properties and own font file', () async { testUsingContext('App uses package font with properties and own font file', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -251,7 +272,7 @@ $fontsSection ...@@ -251,7 +272,7 @@ $fontsSection
<String>['test_package'], <String>['test_package'],
expectedFontManifest, expectedFontManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('App uses local font and package font with own font file.', () async { testUsingContext('App uses local font and package font with own font file.', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -287,10 +308,6 @@ $fontsSection ...@@ -287,10 +308,6 @@ $fontsSection
<String>['test_package'], <String>['test_package'],
expectedFontManifest, expectedFontManifest,
); );
}, overrides: contextOverrides); });
}); });
} }
Map<Type, Generator> get contextOverrides {
return <Type, Generator>{FileSystem: () => new MemoryFileSystem()};
}
...@@ -6,7 +6,6 @@ import 'dart:async'; ...@@ -6,7 +6,6 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/asset.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
...@@ -93,6 +92,28 @@ $assetsSection ...@@ -93,6 +92,28 @@ $assetsSection
} }
} }
// These tests do not use a memory file system because we want to ensure that
// asset bundles work correctly on Windows and Posix systems.
Directory tempDir;
Directory oldCurrentDir;
setUp(() async {
tempDir = await fs.systemTempDirectory.createTemp('asset_bundle_tests');
oldCurrentDir = fs.currentDirectory;
fs.currentDirectory = tempDir;
});
tearDown(() {
fs.currentDirectory = oldCurrentDir;
try {
tempDir?.deleteSync(recursive: true);
tempDir = null;
} on FileSystemException catch (e) {
// Do nothing, windows sometimes has trouble deleting.
print('Ignored exception during tearDown: $e');
}
});
group('AssetBundle assets from packages', () { group('AssetBundle assets from packages', () {
testUsingContext('No assets are bundled when the package has no assets', () async { testUsingContext('No assets are bundled when the package has no assets', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -109,7 +130,7 @@ $assetsSection ...@@ -109,7 +130,7 @@ $assetsSection
UTF8.decode(await bundle.entries['AssetManifest.json'].contentsAsBytes()), UTF8.decode(await bundle.entries['AssetManifest.json'].contentsAsBytes()),
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('No assets are bundled when the package has an asset that is not listed', () async { testUsingContext('No assets are bundled when the package has an asset that is not listed', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -130,7 +151,7 @@ $assetsSection ...@@ -130,7 +151,7 @@ $assetsSection
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('One asset is bundled when the package has and lists one asset its pubspec', () async { testUsingContext('One asset is bundled when the package has and lists one asset its pubspec', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -154,7 +175,7 @@ $assetsSection ...@@ -154,7 +175,7 @@ $assetsSection
<String>['test_package'], <String>['test_package'],
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: contextOverrides); });
testUsingContext("One asset is bundled when the package has one asset, listed in the app's pubspec", () async { testUsingContext("One asset is bundled when the package has one asset, listed in the app's pubspec", () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -178,7 +199,7 @@ $assetsSection ...@@ -178,7 +199,7 @@ $assetsSection
<String>['test_package'], <String>['test_package'],
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('One asset and its variant are bundled when the package has an asset and a variant, and lists the asset in its pubspec', () async { testUsingContext('One asset and its variant are bundled when the package has an asset and a variant, and lists the asset in its pubspec', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -202,7 +223,7 @@ $assetsSection ...@@ -202,7 +223,7 @@ $assetsSection
<String>['test_package'], <String>['test_package'],
expectedManifest, expectedManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('One asset and its variant are bundled when the package has an asset and a variant, and the app lists the asset in its pubspec', () async { testUsingContext('One asset and its variant are bundled when the package has an asset and a variant, and the app lists the asset in its pubspec', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -229,7 +250,7 @@ $assetsSection ...@@ -229,7 +250,7 @@ $assetsSection
<String>['test_package'], <String>['test_package'],
expectedManifest, expectedManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('Two assets are bundled when the package has and lists two assets in its pubspec', () async { testUsingContext('Two assets are bundled when the package has and lists two assets in its pubspec', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -254,7 +275,7 @@ $assetsSection ...@@ -254,7 +275,7 @@ $assetsSection
<String>['test_package'], <String>['test_package'],
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: contextOverrides); });
testUsingContext("Two assets are bundled when the package has two assets, listed in the app's pubspec", () async { testUsingContext("Two assets are bundled when the package has two assets, listed in the app's pubspec", () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -286,7 +307,7 @@ $assetsSection ...@@ -286,7 +307,7 @@ $assetsSection
<String>['test_package'], <String>['test_package'],
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('Two assets are bundled when two packages each have and list an asset their pubspec', () async { testUsingContext('Two assets are bundled when two packages each have and list an asset their pubspec', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -322,7 +343,7 @@ $assetsSection ...@@ -322,7 +343,7 @@ $assetsSection
<String>['test_package', 'test_package2'], <String>['test_package', 'test_package2'],
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: contextOverrides); });
testUsingContext("Two assets are bundled when two packages each have an asset, listed in the app's pubspec", () async { testUsingContext("Two assets are bundled when two packages each have an asset, listed in the app's pubspec", () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -361,7 +382,7 @@ $assetsSection ...@@ -361,7 +382,7 @@ $assetsSection
<String>['test_package', 'test_package2'], <String>['test_package', 'test_package2'],
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: contextOverrides); });
testUsingContext('One asset is bundled when the app depends on a package, listing in its pubspec an asset from another package', () async { testUsingContext('One asset is bundled when the app depends on a package, listing in its pubspec an asset from another package', () async {
establishFlutterRoot(); establishFlutterRoot();
...@@ -392,10 +413,6 @@ $assetsSection ...@@ -392,10 +413,6 @@ $assetsSection
<String>['test_package2'], <String>['test_package2'],
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: contextOverrides); });
}); });
} }
Map<Type, Generator> get contextOverrides {
return <Type, Generator>{FileSystem: () => new MemoryFileSystem()};
}
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/asset.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
...@@ -76,6 +75,28 @@ void main() { ...@@ -76,6 +75,28 @@ void main() {
}); });
group('AssetBundle.build', () { group('AssetBundle.build', () {
// These tests do not use a memory file system because we want to ensure that
// asset bundles work correctly on Windows and Posix systems.
Directory tempDir;
Directory oldCurrentDir;
setUp(() async {
tempDir = await fs.systemTempDirectory.createTemp('asset_bundle_tests');
oldCurrentDir = fs.currentDirectory;
fs.currentDirectory = tempDir;
});
tearDown(() {
fs.currentDirectory = oldCurrentDir;
try {
tempDir?.deleteSync(recursive: true);
tempDir = null;
} on FileSystemException catch (e) {
// Do nothing, windows sometimes has trouble deleting.
print('Ignored exception during tearDown: $e');
}
});
test('nonempty', () async { test('nonempty', () async {
final AssetBundle ab = new AssetBundle(); final AssetBundle ab = new AssetBundle();
expect(await ab.build(), 0); expect(await ab.build(), 0);
...@@ -95,7 +116,7 @@ void main() { ...@@ -95,7 +116,7 @@ void main() {
UTF8.decode(await bundle.entries['AssetManifest.json'].contentsAsBytes()), UTF8.decode(await bundle.entries['AssetManifest.json'].contentsAsBytes()),
expectedAssetManifest, expectedAssetManifest,
); );
}, overrides: <Type, Generator>{FileSystem: () => new MemoryFileSystem(),}); });
}); });
} }
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/asset.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
...@@ -17,6 +16,28 @@ import 'src/common.dart'; ...@@ -17,6 +16,28 @@ import 'src/common.dart';
import 'src/context.dart'; import 'src/context.dart';
void main() { void main() {
// These tests do not use a memory file system because we want to ensure that
// asset bundles work correctly on Windows and Posix systems.
Directory tempDir;
Directory oldCurrentDir;
setUp(() async {
tempDir = await fs.systemTempDirectory.createTemp('asset_bundle_tests');
oldCurrentDir = fs.currentDirectory;
fs.currentDirectory = tempDir;
});
tearDown(() {
fs.currentDirectory = oldCurrentDir;
try {
tempDir?.deleteSync(recursive: true);
tempDir = null;
} on FileSystemException catch (e) {
// Do nothing, windows sometimes has trouble deleting.
print('Ignored exception during tearDown: $e');
}
});
group('AssetBundle asset variants', () { group('AssetBundle asset variants', () {
testUsingContext('main asset and variants', () async { testUsingContext('main asset and variants', () async {
// Setting flutterRoot here so that it picks up the MemoryFileSystem's // Setting flutterRoot here so that it picks up the MemoryFileSystem's
...@@ -59,19 +80,17 @@ flutter: ...@@ -59,19 +80,17 @@ flutter:
expect(UTF8.decode(await bundle.entries[asset].contentsAsBytes()), asset); expect(UTF8.decode(await bundle.entries[asset].contentsAsBytes()), asset);
} }
fs.file('/a/b/c/foo').deleteSync(); fs.file('a/b/c/foo').deleteSync();
bundle = new AssetBundle(); bundle = new AssetBundle();
await bundle.build(manifestPath: 'pubspec.yaml'); await bundle.build(manifestPath: 'pubspec.yaml');
// Now the main asset file, /a/b/c/foo, does not exist. This is OK because // Now the main asset file, /a/b/c/foo, does not exist. This is OK because
// the /a/b/c/*/foo variants do exist. // the /a/b/c/*/foo variants do exist.
expect(bundle.entries.containsKey('/a/b/c/foo'), false); expect(bundle.entries.containsKey('a/b/c/foo'), false);
for (String asset in assets.skip(1)) { for (String asset in assets.skip(1)) {
expect(bundle.entries.containsKey(asset), true); expect(bundle.entries.containsKey(asset), true);
expect(UTF8.decode(await bundle.entries[asset].contentsAsBytes()), asset); expect(UTF8.decode(await bundle.entries[asset].contentsAsBytes()), asset);
} }
}, overrides: <Type, Generator>{
FileSystem: () => new MemoryFileSystem(),
}); });
}); });
......
...@@ -69,7 +69,9 @@ flutter: ...@@ -69,7 +69,9 @@ flutter:
- a/bar - a/bar
'''; ''';
final FlutterManifest flutterManifest = await FlutterManifest.createFromString(manifest); final FlutterManifest flutterManifest = await FlutterManifest.createFromString(manifest);
expect(flutterManifest.assets, <String>['a/foo', 'a/bar']); expect(flutterManifest.assets.length, 2);
expect(flutterManifest.assets[0], Uri.parse('a/foo'));
expect(flutterManifest.assets[1], Uri.parse('a/bar'));
}); });
test('has one font family with one asset', () async { test('has one font family with one asset', () async {
...@@ -97,7 +99,7 @@ flutter: ...@@ -97,7 +99,7 @@ flutter:
final List<FontAsset> assets = font.fontAssets; final List<FontAsset> assets = font.fontAssets;
expect(assets.length, 1); expect(assets.length, 1);
final FontAsset fontAsset = assets[0]; final FontAsset fontAsset = assets[0];
expect(fontAsset.asset, 'a/bar'); expect(fontAsset.assetUri.path, 'a/bar');
expect(fontAsset.weight, isNull); expect(fontAsset.weight, isNull);
expect(fontAsset.style, isNull); expect(fontAsset.style, isNull);
}); });
...@@ -130,11 +132,11 @@ flutter: ...@@ -130,11 +132,11 @@ flutter:
final List<FontAsset> assets = font.fontAssets; final List<FontAsset> assets = font.fontAssets;
expect(assets.length, 2); expect(assets.length, 2);
final FontAsset fontAsset0 = assets[0]; final FontAsset fontAsset0 = assets[0];
expect(fontAsset0.asset, 'a/bar'); expect(fontAsset0.assetUri.path, 'a/bar');
expect(fontAsset0.weight, isNull); expect(fontAsset0.weight, isNull);
expect(fontAsset0.style, isNull); expect(fontAsset0.style, isNull);
final FontAsset fontAsset1 = assets[1]; final FontAsset fontAsset1 = assets[1];
expect(fontAsset1.asset, 'a/bar'); expect(fontAsset1.assetUri.path, 'a/bar');
expect(fontAsset1.weight, 400); expect(fontAsset1.weight, 400);
expect(fontAsset1.style, isNull); expect(fontAsset1.style, isNull);
}); });
...@@ -168,11 +170,11 @@ flutter: ...@@ -168,11 +170,11 @@ flutter:
final List<FontAsset> assets = font.fontAssets; final List<FontAsset> assets = font.fontAssets;
expect(assets.length, 2); expect(assets.length, 2);
final FontAsset fontAsset0 = assets[0]; final FontAsset fontAsset0 = assets[0];
expect(fontAsset0.asset, 'a/bar'); expect(fontAsset0.assetUri.path, 'a/bar');
expect(fontAsset0.weight, isNull); expect(fontAsset0.weight, isNull);
expect(fontAsset0.style, isNull); expect(fontAsset0.style, isNull);
final FontAsset fontAsset1 = assets[1]; final FontAsset fontAsset1 = assets[1];
expect(fontAsset1.asset, 'a/bar'); expect(fontAsset1.assetUri.path, 'a/bar');
expect(fontAsset1.weight, 400); expect(fontAsset1.weight, 400);
expect(fontAsset1.style, 'italic'); expect(fontAsset1.style, 'italic');
}); });
...@@ -214,11 +216,11 @@ flutter: ...@@ -214,11 +216,11 @@ flutter:
final List<FontAsset> fooAassets = fooFont.fontAssets; final List<FontAsset> fooAassets = fooFont.fontAssets;
expect(fooAassets.length, 2); expect(fooAassets.length, 2);
final FontAsset fooFontAsset0 = fooAassets[0]; final FontAsset fooFontAsset0 = fooAassets[0];
expect(fooFontAsset0.asset, 'a/bar'); expect(fooFontAsset0.assetUri.path, 'a/bar');
expect(fooFontAsset0.weight, isNull); expect(fooFontAsset0.weight, isNull);
expect(fooFontAsset0.style, isNull); expect(fooFontAsset0.style, isNull);
final FontAsset fooFontAsset1 = fooAassets[1]; final FontAsset fooFontAsset1 = fooAassets[1];
expect(fooFontAsset1.asset, 'a/bar'); expect(fooFontAsset1.assetUri.path, 'a/bar');
expect(fooFontAsset1.weight, 400); expect(fooFontAsset1.weight, 400);
expect(fooFontAsset1.style, 'italic'); expect(fooFontAsset1.style, 'italic');
...@@ -229,11 +231,11 @@ flutter: ...@@ -229,11 +231,11 @@ flutter:
final List<FontAsset> barAssets = barFont.fontAssets; final List<FontAsset> barAssets = barFont.fontAssets;
expect(barAssets.length, 2); expect(barAssets.length, 2);
final FontAsset barFontAsset0 = barAssets[0]; final FontAsset barFontAsset0 = barAssets[0];
expect(barFontAsset0.asset, 'a/baz'); expect(barFontAsset0.assetUri.path, 'a/baz');
expect(barFontAsset0.weight, isNull); expect(barFontAsset0.weight, isNull);
expect(barFontAsset0.style, isNull); expect(barFontAsset0.style, isNull);
final FontAsset barFontAsset1 = barAssets[1]; final FontAsset barFontAsset1 = barAssets[1];
expect(barFontAsset1.asset, 'a/baz'); expect(barFontAsset1.assetUri.path, 'a/baz');
expect(barFontAsset1.weight, 400); expect(barFontAsset1.weight, 400);
expect(barFontAsset1.style, 'italic'); expect(barFontAsset1.style, 'italic');
}); });
...@@ -274,11 +276,11 @@ flutter: ...@@ -274,11 +276,11 @@ flutter:
final List<FontAsset> fooAassets = fooFont.fontAssets; final List<FontAsset> fooAassets = fooFont.fontAssets;
expect(fooAassets.length, 2); expect(fooAassets.length, 2);
final FontAsset fooFontAsset0 = fooAassets[0]; final FontAsset fooFontAsset0 = fooAassets[0];
expect(fooFontAsset0.asset, 'a/bar'); expect(fooFontAsset0.assetUri.path, 'a/bar');
expect(fooFontAsset0.weight, isNull); expect(fooFontAsset0.weight, isNull);
expect(fooFontAsset0.style, isNull); expect(fooFontAsset0.style, isNull);
final FontAsset fooFontAsset1 = fooAassets[1]; final FontAsset fooFontAsset1 = fooAassets[1];
expect(fooFontAsset1.asset, 'a/bar'); expect(fooFontAsset1.assetUri.path, 'a/bar');
expect(fooFontAsset1.weight, 400); expect(fooFontAsset1.weight, 400);
expect(fooFontAsset1.style, 'italic'); expect(fooFontAsset1.style, 'italic');
}); });
...@@ -314,11 +316,11 @@ flutter: ...@@ -314,11 +316,11 @@ flutter:
final List<FontAsset> fooAassets = fooFont.fontAssets; final List<FontAsset> fooAassets = fooFont.fontAssets;
expect(fooAassets.length, 2); expect(fooAassets.length, 2);
final FontAsset fooFontAsset0 = fooAassets[0]; final FontAsset fooFontAsset0 = fooAassets[0];
expect(fooFontAsset0.asset, 'a/bar'); expect(fooFontAsset0.assetUri.path, 'a/bar');
expect(fooFontAsset0.weight, isNull); expect(fooFontAsset0.weight, isNull);
expect(fooFontAsset0.style, isNull); expect(fooFontAsset0.style, isNull);
final FontAsset fooFontAsset1 = fooAassets[1]; final FontAsset fooFontAsset1 = fooAassets[1];
expect(fooFontAsset1.asset, 'a/bar'); expect(fooFontAsset1.assetUri.path, 'a/bar');
expect(fooFontAsset1.weight, 400); expect(fooFontAsset1.weight, 400);
expect(fooFontAsset1.style, 'italic'); expect(fooFontAsset1.style, 'italic');
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment