image_provider_and_image_cache_test.dart 4.26 KB
Newer Older
1 2 3 4 5 6
// 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:async';
import 'dart:typed_data';
7
import 'dart:ui' as ui;
8 9 10 11 12

import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';

13
import '../image_data.dart';
14 15 16 17
import '../rendering/rendering_tester.dart';
import 'mocks_for_image_cache.dart';

void main() {
18
  TestRenderingFlutterBinding.ensureInitialized();
19

20
  Future<ui.Codec> _basicDecoder(Uint8List bytes, {int? cacheWidth, int? cacheHeight, bool? allowUpscaling}) {
21
    return PaintingBinding.instance.instantiateImageCodec(bytes, cacheWidth: cacheWidth, cacheHeight: cacheHeight, allowUpscaling: allowUpscaling ?? false);
22
  }
23

24
  FlutterExceptionHandler? oldError;
25 26 27 28 29 30
  setUp(() {
    oldError = FlutterError.onError;
  });

  tearDown(() {
    FlutterError.onError = oldError;
31 32
    PaintingBinding.instance.imageCache.clear();
    PaintingBinding.instance.imageCache.clearLiveImages();
33 34 35
  });

  tearDown(() {
36
    imageCache.clear();
37 38 39 40 41 42 43 44 45 46
  });

  test('AssetImageProvider - evicts on failure to load', () async {
    final Completer<FlutterError> error = Completer<FlutterError>();
    FlutterError.onError = (FlutterErrorDetails details) {
      error.complete(details.exception as FlutterError);
    };

    const ImageProvider provider = ExactAssetImage('does-not-exist');
    final Object key = await provider.obtainKey(ImageConfiguration.empty);
47 48
    expect(imageCache.statusForKey(provider).untracked, true);
    expect(imageCache.pendingImageCount, 0);
49 50 51

    provider.resolve(ImageConfiguration.empty);

52 53
    expect(imageCache.statusForKey(key).pending, true);
    expect(imageCache.pendingImageCount, 1);
54 55 56

    await error.future;

57 58
    expect(imageCache.statusForKey(provider).untracked, true);
    expect(imageCache.pendingImageCount, 0);
59 60 61 62 63 64 65 66 67 68
  }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56314

  test('ImageProvider can evict images', () async {
    final Uint8List bytes = Uint8List.fromList(kTransparentImage);
    final MemoryImage imageProvider = MemoryImage(bytes);
    final ImageStream stream = imageProvider.resolve(ImageConfiguration.empty);
    final Completer<void> completer = Completer<void>();
    stream.addListener(ImageStreamListener((ImageInfo info, bool syncCall) => completer.complete()));
    await completer.future;

69
    expect(imageCache.currentSize, 1);
70
    expect(await MemoryImage(bytes).evict(), true);
71
    expect(imageCache.currentSize, 0);
72 73 74 75 76 77 78 79
  });

  test('ImageProvider.evict respects the provided ImageCache', () async {
    final ImageCache otherCache = ImageCache();
    final Uint8List bytes = Uint8List.fromList(kTransparentImage);
    final MemoryImage imageProvider = MemoryImage(bytes);
    final ImageStreamCompleter cacheStream = otherCache.putIfAbsent(
      imageProvider, () => imageProvider.load(imageProvider, _basicDecoder),
80
    )!;
81 82 83 84 85 86 87 88 89 90 91 92
    final ImageStream stream = imageProvider.resolve(ImageConfiguration.empty);
    final Completer<void> completer = Completer<void>();
    final Completer<void> cacheCompleter = Completer<void>();
    stream.addListener(ImageStreamListener((ImageInfo info, bool syncCall) {
      completer.complete();
    }));
    cacheStream.addListener(ImageStreamListener((ImageInfo info, bool syncCall) {
      cacheCompleter.complete();
    }));
    await Future.wait(<Future<void>>[completer.future, cacheCompleter.future]);

    expect(otherCache.currentSize, 1);
93
    expect(imageCache.currentSize, 1);
94 95
    expect(await imageProvider.evict(cache: otherCache), true);
    expect(otherCache.currentSize, 0);
96
    expect(imageCache.currentSize, 1);
97 98 99 100 101 102 103 104 105 106 107
  });

  test('ImageProvider errors can always be caught', () async {
    final ErrorImageProvider imageProvider = ErrorImageProvider();
    final Completer<bool> caughtError = Completer<bool>();
    FlutterError.onError = (FlutterErrorDetails details) {
      caughtError.complete(false);
    };
    final ImageStream stream = imageProvider.resolve(ImageConfiguration.empty);
    stream.addListener(ImageStreamListener((ImageInfo info, bool syncCall) {
      caughtError.complete(false);
108
    }, onError: (dynamic error, StackTrace? stackTrace) {
109 110 111 112 113
      caughtError.complete(true);
    }));
    expect(await caughtError.future, true);
  });
}