| // 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 'dart:convert'; |
| import 'dart:ui' as ui; |
| |
| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/painting.dart'; |
| import 'package:flutter/services.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| class TestAssetBundle extends CachingAssetBundle { |
| TestAssetBundle(this._assetBundleMap); |
| |
| final Map<String, List<String>> _assetBundleMap; |
| |
| Map<String, int> loadCallCount = <String, int>{}; |
| |
| String get _assetBundleContents { |
| return json.encode(_assetBundleMap); |
| } |
| |
| @override |
| Future<ByteData> load(String key) async { |
| if (key == 'AssetManifest.json') { |
| return ByteData.view(Uint8List.fromList(const Utf8Encoder().convert(_assetBundleContents)).buffer); |
| } |
| |
| loadCallCount[key] = loadCallCount[key] ?? 0 + 1; |
| if (key == 'one') { |
| return ByteData(1) |
| ..setInt8(0, 49); |
| } |
| throw FlutterError('key not found'); |
| } |
| |
| @override |
| Future<ui.ImmutableBuffer> loadBuffer(String key) async { |
| final ByteData data = await load(key); |
| return ui.ImmutableBuffer.fromUint8List(data.buffer.asUint8List()); |
| } |
| } |
| |
| void main() { |
| group('1.0 scale device tests', () { |
| void buildAndTestWithOneAsset(String mainAssetPath) { |
| final Map<String, List<String>> assetBundleMap = <String, List<String>>{}; |
| |
| assetBundleMap[mainAssetPath] = <String>[]; |
| |
| final AssetImage assetImage = AssetImage( |
| mainAssetPath, |
| bundle: TestAssetBundle(assetBundleMap), |
| ); |
| const ImageConfiguration configuration = ImageConfiguration.empty; |
| |
| assetImage.obtainKey(configuration) |
| .then(expectAsync1((AssetBundleImageKey bundleKey) { |
| expect(bundleKey.name, mainAssetPath); |
| expect(bundleKey.scale, 1.0); |
| })); |
| } |
| |
| test('When asset is main variant check scale is 1.0', () { |
| buildAndTestWithOneAsset('assets/normalFolder/normalFile.png'); |
| }); |
| |
| test('When asset path and key are the same string even though it could be took as a 3.0x variant', () async { |
| buildAndTestWithOneAsset('assets/parentFolder/3.0x/normalFile.png'); |
| }); |
| |
| test('When asset path contains variant identifier as part of parent folder name scale is 1.0', () { |
| buildAndTestWithOneAsset('assets/parentFolder/__3.0x__/leafFolder/normalFile.png'); |
| }); |
| |
| test('When asset path contains variant identifier as part of leaf folder name scale is 1.0', () { |
| buildAndTestWithOneAsset('assets/parentFolder/__3.0x_leaf_folder_/normalFile.png'); |
| }); |
| |
| test('When asset path contains variant identifier as part of parent folder name scale is 1.0', () { |
| buildAndTestWithOneAsset('assets/parentFolder/__3.0x__/leafFolder/normalFile.png'); |
| }); |
| |
| test('When asset path contains variant identifier in parent folder scale is 1.0', () { |
| buildAndTestWithOneAsset('assets/parentFolder/3.0x/leafFolder/normalFile.png'); |
| }); |
| }); |
| |
| |
| group('High-res device behavior tests', () { |
| test('When asset is not main variant check scale is not 1.0', () { |
| const String mainAssetPath = 'assets/normalFolder/normalFile.png'; |
| const String variantPath = 'assets/normalFolder/3.0x/normalFile.png'; |
| |
| final Map<String, List<String>> assetBundleMap = |
| <String, List<String>>{}; |
| |
| assetBundleMap[mainAssetPath] = <String>[mainAssetPath, variantPath]; |
| |
| final TestAssetBundle testAssetBundle = TestAssetBundle(assetBundleMap); |
| |
| final AssetImage assetImage = AssetImage( |
| mainAssetPath, |
| bundle: testAssetBundle, |
| ); |
| |
| assetImage.obtainKey(ImageConfiguration.empty) |
| .then(expectAsync1((AssetBundleImageKey bundleKey) { |
| expect(bundleKey.name, mainAssetPath); |
| expect(bundleKey.scale, 1.0); |
| })); |
| |
| assetImage.obtainKey(ImageConfiguration( |
| bundle: testAssetBundle, |
| devicePixelRatio: 3.0, |
| )).then(expectAsync1((AssetBundleImageKey bundleKey) { |
| expect(bundleKey.name, variantPath); |
| expect(bundleKey.scale, 3.0); |
| })); |
| }); |
| |
| test('When high-res device and high-res asset not present in bundle then return main variant', () { |
| const String mainAssetPath = 'assets/normalFolder/normalFile.png'; |
| |
| final Map<String, List<String>> assetBundleMap = |
| <String, List<String>>{}; |
| |
| assetBundleMap[mainAssetPath] = <String>[mainAssetPath]; |
| |
| final TestAssetBundle testAssetBundle = TestAssetBundle(assetBundleMap); |
| |
| final AssetImage assetImage = AssetImage( |
| mainAssetPath, |
| bundle: TestAssetBundle(assetBundleMap), |
| ); |
| |
| |
| assetImage.obtainKey(ImageConfiguration.empty) |
| .then(expectAsync1((AssetBundleImageKey bundleKey) { |
| expect(bundleKey.name, mainAssetPath); |
| expect(bundleKey.scale, 1.0); |
| })); |
| |
| assetImage.obtainKey(ImageConfiguration( |
| bundle: testAssetBundle, |
| devicePixelRatio: 3.0, |
| )).then(expectAsync1((AssetBundleImageKey bundleKey) { |
| expect(bundleKey.name, mainAssetPath); |
| expect(bundleKey.scale, 1.0); |
| })); |
| }); |
| }); |
| |
| group('Regression - When assets available are 1.0 and 3.0 check devices with a range of scales', () { |
| const String mainAssetPath = 'assets/normalFolder/normalFile.png'; |
| const String variantPath = 'assets/normalFolder/3.0x/normalFile.png'; |
| |
| |
| void buildBundleAndTestVariantLogic( |
| double deviceRatio, |
| double chosenAssetRatio, |
| String expectedAssetPath, |
| ) { |
| final Map<String, List<String>> assetBundleMap = |
| <String, List<String>>{}; |
| |
| assetBundleMap[mainAssetPath] = <String>[mainAssetPath, variantPath]; |
| |
| final TestAssetBundle testAssetBundle = TestAssetBundle(assetBundleMap); |
| |
| final AssetImage assetImage = AssetImage( |
| mainAssetPath, |
| bundle: testAssetBundle, |
| ); |
| |
| // we have 1.0 and 3.0, asking for 1.5 should give |
| assetImage.obtainKey(ImageConfiguration( |
| bundle: testAssetBundle, |
| devicePixelRatio: deviceRatio, |
| )).then(expectAsync1((AssetBundleImageKey bundleKey) { |
| expect(bundleKey.name, expectedAssetPath); |
| expect(bundleKey.scale, chosenAssetRatio); |
| })); |
| } |
| |
| test('Obvious case 1.0 - we have exact asset', () { |
| buildBundleAndTestVariantLogic(1.0, 1.0, mainAssetPath); |
| }); |
| |
| test('Obvious case 3.0 - we have exact asset', () { |
| buildBundleAndTestVariantLogic(3.0, 3.0, variantPath); |
| }); |
| |
| test('Typical case 2.0', () { |
| buildBundleAndTestVariantLogic(2.0, 1.0, mainAssetPath); |
| }); |
| |
| test('Borderline case 2.01', () { |
| buildBundleAndTestVariantLogic(2.01, 3.0, variantPath); |
| }); |
| test('Borderline case 2.9', () { |
| buildBundleAndTestVariantLogic(2.9, 3.0, variantPath); |
| }); |
| |
| test('Typical case 4.0', () { |
| buildBundleAndTestVariantLogic(4.0, 3.0, variantPath); |
| }); |
| }); |
| |
| } |