| // 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'; |
| import 'dart:ui' as ui; |
| |
| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/painting.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import '../image_data.dart'; |
| import '../rendering/rendering_tester.dart'; |
| import 'mocks_for_image_cache.dart'; |
| |
| void main() { |
| TestRenderingFlutterBinding(); |
| |
| Future<ui.Codec> _basicDecoder(Uint8List bytes, {int? cacheWidth, int? cacheHeight, bool? allowUpscaling}) { |
| return PaintingBinding.instance!.instantiateImageCodec(bytes, cacheWidth: cacheWidth, cacheHeight: cacheHeight, allowUpscaling: allowUpscaling ?? false); |
| } |
| |
| FlutterExceptionHandler? oldError; |
| setUp(() { |
| oldError = FlutterError.onError; |
| }); |
| |
| tearDown(() { |
| FlutterError.onError = oldError; |
| PaintingBinding.instance!.imageCache!.clear(); |
| PaintingBinding.instance!.imageCache!.clearLiveImages(); |
| }); |
| |
| tearDown(() { |
| imageCache!.clear(); |
| }); |
| |
| 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); |
| expect(imageCache!.statusForKey(provider).untracked, true); |
| expect(imageCache!.pendingImageCount, 0); |
| |
| provider.resolve(ImageConfiguration.empty); |
| |
| expect(imageCache!.statusForKey(key).pending, true); |
| expect(imageCache!.pendingImageCount, 1); |
| |
| await error.future; |
| |
| expect(imageCache!.statusForKey(provider).untracked, true); |
| expect(imageCache!.pendingImageCount, 0); |
| }, 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; |
| |
| expect(imageCache!.currentSize, 1); |
| expect(await MemoryImage(bytes).evict(), true); |
| expect(imageCache!.currentSize, 0); |
| }); |
| |
| 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), |
| )!; |
| 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); |
| expect(imageCache!.currentSize, 1); |
| expect(await imageProvider.evict(cache: otherCache), true); |
| expect(otherCache.currentSize, 0); |
| expect(imageCache!.currentSize, 1); |
| }); |
| |
| 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); |
| }, onError: (dynamic error, StackTrace? stackTrace) { |
| caughtError.complete(true); |
| })); |
| expect(await caughtError.future, true); |
| }); |
| } |