image_resolution_test.dart 6.96 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:convert';
6
import 'dart:ui' as ui;
7 8 9 10 11 12 13

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 {
14
  TestAssetBundle(this._assetBundleMap);
15

16
  final Map<String, List<String>> _assetBundleMap;
17 18 19 20 21 22 23 24 25

  Map<String, int> loadCallCount = <String, int>{};

  String get _assetBundleContents {
    return json.encode(_assetBundleMap);
  }

  @override
  Future<ByteData> load(String key) async {
26
    if (key == 'AssetManifest.json') {
27
      return ByteData.view(Uint8List.fromList(const Utf8Encoder().convert(_assetBundleContents)).buffer);
28
    }
29 30

    loadCallCount[key] = loadCallCount[key] ?? 0 + 1;
31
    if (key == 'one') {
32
      return ByteData(1)
33
        ..setInt8(0, 49);
34
    }
35
    throw FlutterError('key not found');
36
  }
37 38 39 40 41 42

  @override
  Future<ui.ImmutableBuffer> loadBuffer(String key) async {
    final ByteData data = await load(key);
    return ui.ImmutableBuffer.fromUint8List(data.buffer.asUint8List());
  }
43 44 45 46
}

void main() {
  group('1.0 scale device tests', () {
47
    void buildAndTestWithOneAsset(String mainAssetPath) {
48 49 50 51
      final Map<String, List<String>> assetBundleMap = <String, List<String>>{};

      assetBundleMap[mainAssetPath] = <String>[];

52
      final AssetImage assetImage = AssetImage(
53 54 55
        mainAssetPath,
        bundle: TestAssetBundle(assetBundleMap),
      );
56
      const ImageConfiguration configuration = ImageConfiguration.empty;
57 58

      assetImage.obtainKey(configuration)
59 60 61 62
        .then(expectAsync1((AssetBundleImageKey bundleKey) {
          expect(bundleKey.name, mainAssetPath);
          expect(bundleKey.scale, 1.0);
        }));
63 64 65
    }

    test('When asset is main variant check scale is 1.0', () {
66
      buildAndTestWithOneAsset('assets/normalFolder/normalFile.png');
67 68
    });

69
    test('When asset path and key are the same string even though it could be took as a 3.0x variant', () async {
70
      buildAndTestWithOneAsset('assets/parentFolder/3.0x/normalFile.png');
71
    });
72

73
    test('When asset path contains variant identifier as part of parent folder name scale is 1.0', () {
74
      buildAndTestWithOneAsset('assets/parentFolder/__3.0x__/leafFolder/normalFile.png');
75
    });
76

77
    test('When asset path contains variant identifier as part of leaf folder name scale is 1.0', () {
78
      buildAndTestWithOneAsset('assets/parentFolder/__3.0x_leaf_folder_/normalFile.png');
79
    });
80

81
    test('When asset path contains variant identifier as part of parent folder name scale is 1.0', () {
82
      buildAndTestWithOneAsset('assets/parentFolder/__3.0x__/leafFolder/normalFile.png');
83
    });
84

85
    test('When asset path contains variant identifier in parent folder scale is 1.0', () {
86
      buildAndTestWithOneAsset('assets/parentFolder/3.0x/leafFolder/normalFile.png');
87
    });
88 89 90 91 92 93 94 95 96 97 98 99 100
  });


  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];

101
      final TestAssetBundle testAssetBundle = TestAssetBundle(assetBundleMap);
102

103
      final AssetImage assetImage = AssetImage(
104 105 106
        mainAssetPath,
        bundle: testAssetBundle,
      );
107 108

      // we have the exact match for this scale, let's use it
109
      assetImage.obtainKey(ImageConfiguration.empty)
110 111 112 113
        .then(expectAsync1((AssetBundleImageKey bundleKey) {
          expect(bundleKey.name, mainAssetPath);
          expect(bundleKey.scale, 1.0);
        }));
114 115

      // we also have the exact match for this scale, let's use it
116
      assetImage.obtainKey(ImageConfiguration(
117 118 119
        bundle: testAssetBundle,
        devicePixelRatio: 3.0,
      )).then(expectAsync1((AssetBundleImageKey bundleKey) {
120 121 122 123 124
        expect(bundleKey.name, variantPath);
        expect(bundleKey.scale, 3.0);
      }));
    });

125
    test('When high-res device and high-res asset not present in bundle then  return main variant', () {
126 127 128 129 130 131 132
      const String mainAssetPath = 'assets/normalFolder/normalFile.png';

      final Map<String, List<String>> assetBundleMap =
      <String, List<String>>{};

      assetBundleMap[mainAssetPath] = <String>[mainAssetPath];

133
      final TestAssetBundle testAssetBundle = TestAssetBundle(assetBundleMap);
134

135
      final AssetImage assetImage = AssetImage(
136 137 138
        mainAssetPath,
        bundle: TestAssetBundle(assetBundleMap),
      );
139 140


141
      assetImage.obtainKey(ImageConfiguration.empty)
142 143 144 145
        .then(expectAsync1((AssetBundleImageKey bundleKey) {
          expect(bundleKey.name, mainAssetPath);
          expect(bundleKey.scale, 1.0);
        }));
146

147
      assetImage.obtainKey(ImageConfiguration(
148
        bundle: testAssetBundle,
149 150
        devicePixelRatio: 3.0,
      )).then(expectAsync1((AssetBundleImageKey bundleKey) {
151 152 153 154
        expect(bundleKey.name, mainAssetPath);
        expect(bundleKey.scale, 1.0);
      }));
    });
155
  });
156

157
  group('Regression - When assets available are 1.0 and 3.0 check devices with a range of scales', () {
158 159 160 161
    const String mainAssetPath = 'assets/normalFolder/normalFile.png';
    const String variantPath = 'assets/normalFolder/3.0x/normalFile.png';


162
    void buildBundleAndTestVariantLogic(
163 164 165 166
      double deviceRatio,
      double chosenAssetRatio,
      String expectedAssetPath,
    ) {
167 168 169 170 171
      final Map<String, List<String>> assetBundleMap =
      <String, List<String>>{};

      assetBundleMap[mainAssetPath] = <String>[mainAssetPath, variantPath];

172
      final TestAssetBundle testAssetBundle = TestAssetBundle(assetBundleMap);
173

174
      final AssetImage assetImage = AssetImage(
175 176 177
        mainAssetPath,
        bundle: testAssetBundle,
      );
178 179

      // we have 1.0 and 3.0, asking for 1.5 should give
180
      assetImage.obtainKey(ImageConfiguration(
181
        bundle: testAssetBundle,
182 183
        devicePixelRatio: deviceRatio,
      )).then(expectAsync1((AssetBundleImageKey bundleKey) {
184 185 186 187 188 189
        expect(bundleKey.name, expectedAssetPath);
        expect(bundleKey.scale, chosenAssetRatio);
      }));
    }

    test('Obvious case 1.0 - we have exact asset', () {
190
      buildBundleAndTestVariantLogic(1.0, 1.0, mainAssetPath);
191 192 193
    });

    test('Obvious case 3.0 - we have exact asset', () {
194
      buildBundleAndTestVariantLogic(3.0, 3.0, variantPath);
195 196 197
    });

    test('Typical case 2.0', () {
198
      buildBundleAndTestVariantLogic(2.0, 1.0, mainAssetPath);
199 200 201
    });

    test('Borderline case 2.01', () {
202
      buildBundleAndTestVariantLogic(2.01, 3.0, variantPath);
203 204
    });
    test('Borderline case 2.9', () {
205
      buildBundleAndTestVariantLogic(2.9, 3.0, variantPath);
206 207 208
    });

    test('Typical case 4.0', () {
209
      buildBundleAndTestVariantLogic(4.0, 3.0, variantPath);
210
    });
211
  });
212 213

}