235 lines
7.8 KiB
Dart
235 lines
7.8 KiB
Dart
// 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<Map<Object?, Object?>>> _assetBundleMap;
|
|
|
|
Map<String, int> loadCallCount = <String, int>{};
|
|
|
|
@override
|
|
Future<ByteData> load(String key) async {
|
|
if (key == 'AssetManifest.bin') {
|
|
return const StandardMessageCodec().encodeMessage(_assetBundleMap)!;
|
|
}
|
|
|
|
if (key == 'AssetManifest.bin.json') {
|
|
// Encode the manifest data that will be used by the app
|
|
final ByteData data = const StandardMessageCodec().encodeMessage(_assetBundleMap)!;
|
|
// Simulate the behavior of NetworkAssetBundle.load here, for web tests
|
|
return ByteData.sublistView(
|
|
utf8.encode(
|
|
json.encode(
|
|
base64.encode(
|
|
// Encode only the actual bytes of the buffer, and no more...
|
|
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
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 assetBundleMap = <String, List<Map<Object?, Object?>>>{};
|
|
|
|
final 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 mainAssetPath = 'assets/normalFolder/normalFile.png';
|
|
const variantPath = 'assets/normalFolder/3.0x/normalFile.png';
|
|
|
|
final assetBundleMap = <String, List<Map<Object?, Object?>>>{};
|
|
|
|
final mainAssetVariantManifestEntry = <Object?, Object?>{};
|
|
mainAssetVariantManifestEntry['asset'] = variantPath;
|
|
mainAssetVariantManifestEntry['dpr'] = 3.0;
|
|
assetBundleMap[mainAssetPath] = <Map<Object?, Object?>>[mainAssetVariantManifestEntry];
|
|
final testAssetBundle = TestAssetBundle(assetBundleMap);
|
|
|
|
final 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 mainAssetPath = 'assets/normalFolder/normalFile.png';
|
|
|
|
final assetBundleMap = <String, List<Map<Object?, Object?>>>{};
|
|
|
|
assetBundleMap[mainAssetPath] = <Map<Object?, Object?>>[];
|
|
|
|
final testAssetBundle = TestAssetBundle(assetBundleMap);
|
|
|
|
final 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 mainAssetPath = 'assets/normalFolder/normalFile.png';
|
|
const variantPath = 'assets/normalFolder/3.0x/normalFile.png';
|
|
|
|
void buildBundleAndTestVariantLogic(
|
|
double deviceRatio,
|
|
double chosenAssetRatio,
|
|
String expectedAssetPath,
|
|
) {
|
|
const assetManifest = <String, List<Map<Object?, Object?>>>{
|
|
'assets/normalFolder/normalFile.png': <Map<Object?, Object?>>[
|
|
<Object?, Object?>{'asset': 'assets/normalFolder/normalFile.png'},
|
|
<Object?, Object?>{'asset': 'assets/normalFolder/3.0x/normalFile.png', 'dpr': 3.0},
|
|
],
|
|
};
|
|
final testAssetBundle = TestAssetBundle(assetManifest);
|
|
|
|
final 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);
|
|
});
|
|
},
|
|
);
|
|
}
|