diff --git a/dev/manual_tests/test/mock_image_http.dart b/dev/manual_tests/test/mock_image_http.dart index d2f68d3651..1a15b7a5f9 100644 --- a/dev/manual_tests/test/mock_image_http.dart +++ b/dev/manual_tests/test/mock_image_http.dart @@ -6,7 +6,7 @@ import 'dart:io'; import 'package:mockito/mockito.dart'; -import '../../../packages/flutter/test/painting/image_data.dart'; +import '../../../packages/flutter/test/image_data.dart'; // Returns a mock HTTP client that responds with an image to all requests. MockHttpClient createMockImageHttpClient(SecurityContext _) { diff --git a/dev/tracing_tests/test/image_cache_tracing_test.dart b/dev/tracing_tests/test/image_cache_tracing_test.dart index 3d8a9b3b18..bae94ab696 100644 --- a/dev/tracing_tests/test/image_cache_tracing_test.dart +++ b/dev/tracing_tests/test/image_cache_tracing_test.dart @@ -5,8 +5,6 @@ import 'dart:convert'; import 'dart:developer' as developer; import 'dart:isolate' as isolate; -import 'dart:typed_data'; -import 'dart:ui' as ui; import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -40,8 +38,7 @@ void main() { ); PaintingBinding.instance.imageCache.clear(); - // ignore: invalid_use_of_protected_member - completer2.setImage(const ImageInfo(image: TestImage())); + completer2.testSetImage(ImageInfo(image: await createTestImage())); PaintingBinding.instance.imageCache.putIfAbsent( 'Test2', () => completer2, @@ -76,7 +73,7 @@ void main() { }, { 'name': 'ImageCache.evict', - 'args': {'sizeInBytes': 0, 'isolateId': isolateId} + 'args': {'sizeInBytes': 4, 'isolateId': isolateId} }, ], ); @@ -110,20 +107,8 @@ bool _mapsEqual(Map expectedArgs, Map args) { return true; } -class TestImageStreamCompleter extends ImageStreamCompleter {} - -class TestImage implements ui.Image { - const TestImage({this.height = 0, this.width = 0}); - @override - final int height; - @override - final int width; - - @override - void dispose() { } - - @override - Future toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) { - throw UnimplementedError(); +class TestImageStreamCompleter extends ImageStreamCompleter { + void testSetImage(ImageInfo image) { + setImage(image); } } diff --git a/dev/tracing_tests/test/image_painting_event_test.dart b/dev/tracing_tests/test/image_painting_event_test.dart index a786cce741..c07321e135 100644 --- a/dev/tracing_tests/test/image_painting_event_test.dart +++ b/dev/tracing_tests/test/image_painting_event_test.dart @@ -5,7 +5,6 @@ import 'dart:async'; import 'dart:convert' show jsonEncode; import 'dart:developer' as developer; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/painting.dart'; @@ -46,7 +45,7 @@ void main() { final Completer completer = Completer(); vmService.onExtensionEvent.first.then(completer.complete); - const TestImage image = TestImage(width: 300, height: 300); + final ui.Image image = await createTestImage(width: 300, height: 300); final TestCanvas canvas = TestCanvas(); paintImage( canvas: canvas, @@ -79,7 +78,7 @@ void main() { final Completer completer = Completer(); vmService.onExtensionEvent.first.then(completer.complete); - const TestImage image = TestImage(width: 300, height: 300); + final ui.Image image = await createTestImage(width: 300, height: 300); final TestCanvas canvas = TestCanvas(); paintImage( canvas: canvas, @@ -105,23 +104,6 @@ void main() { }, skip: isBrowser); // uses dart:isolate and io } -class TestImage implements ui.Image { - const TestImage({this.height = 0, this.width = 0}); - @override - final int height; - @override - final int width; - - @override - void dispose() {} - - @override - Future toByteData( - {ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba}) { - throw UnimplementedError(); - } -} - class TestCanvas implements Canvas { @override void noSuchMethod(Invocation invocation) {} diff --git a/packages/flutter/test/cupertino/bottom_tab_bar_test.dart b/packages/flutter/test/cupertino/bottom_tab_bar_test.dart index 9747dc0c12..9f17634937 100644 --- a/packages/flutter/test/cupertino/bottom_tab_bar_test.dart +++ b/packages/flutter/test/cupertino/bottom_tab_bar_test.dart @@ -10,7 +10,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../painting/image_data.dart'; +import '../image_data.dart'; import '../widgets/semantics_tester.dart'; Future pumpWidgetWithBoilerplate(WidgetTester tester, Widget widget) async { @@ -257,7 +257,7 @@ Future main() async { }); testWidgets('Use active icon', (WidgetTester tester) async { - final MemoryImage activeIcon = MemoryImage(Uint8List.fromList(kBlueSquare)); + final MemoryImage activeIcon = MemoryImage(Uint8List.fromList(kBlueSquarePng)); final MemoryImage inactiveIcon = MemoryImage(Uint8List.fromList(kTransparentImage)); await pumpWidgetWithBoilerplate(tester, MediaQuery( diff --git a/packages/flutter/test/cupertino/material/tab_scaffold_test.dart b/packages/flutter/test/cupertino/material/tab_scaffold_test.dart index 04122e4759..827b97943d 100644 --- a/packages/flutter/test/cupertino/material/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/material/tab_scaffold_test.dart @@ -10,7 +10,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../../painting/image_data.dart'; +import '../../image_data.dart'; List selectedTabs; diff --git a/packages/flutter/test/cupertino/scaffold_test.dart b/packages/flutter/test/cupertino/scaffold_test.dart index 6ab1b127a4..b100332fc4 100644 --- a/packages/flutter/test/cupertino/scaffold_test.dart +++ b/packages/flutter/test/cupertino/scaffold_test.dart @@ -9,7 +9,7 @@ import 'dart:typed_data'; import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../painting/image_data.dart'; +import '../image_data.dart'; import '../rendering/mock_canvas.dart'; /// Integration tests testing both [CupertinoPageScaffold] and [CupertinoTabScaffold]. diff --git a/packages/flutter/test/cupertino/tab_scaffold_test.dart b/packages/flutter/test/cupertino/tab_scaffold_test.dart index 65281a75f8..7e717be5be 100644 --- a/packages/flutter/test/cupertino/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/tab_scaffold_test.dart @@ -9,7 +9,7 @@ import 'dart:typed_data'; import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../painting/image_data.dart'; +import '../image_data.dart'; import '../rendering/rendering_tester.dart'; List selectedTabs; diff --git a/packages/flutter/test/flutter_test_alternative.dart b/packages/flutter/test/flutter_test_alternative.dart index 9110617c38..5eef49a04b 100644 --- a/packages/flutter/test/flutter_test_alternative.dart +++ b/packages/flutter/test/flutter_test_alternative.dart @@ -12,6 +12,7 @@ import 'package:test_api/test_api.dart' as test_package show TypeMatcher; // ign export 'package:test_api/test_api.dart' hide TypeMatcher, isInstanceOf; // ignore: deprecated_member_use export 'package:test_api/fake.dart'; // ignore: deprecated_member_use +export 'package:flutter_test/flutter_test.dart' show createTestImage; /// A matcher that compares the type of the actual value to the type argument T. test_package.TypeMatcher isInstanceOf() => isA(); diff --git a/packages/flutter/test/painting/image_data.dart b/packages/flutter/test/image_data.dart similarity index 98% rename from packages/flutter/test/painting/image_data.dart rename to packages/flutter/test/image_data.dart index 37359438dc..4af22490cf 100644 --- a/packages/flutter/test/painting/image_data.dart +++ b/packages/flutter/test/image_data.dart @@ -4,9 +4,8 @@ // @dart = 2.8 - /// A 50x50 blue square png. -const List kBlueSquare = [ +const List kBlueSquarePng = [ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1e, 0x3f, 0x88, 0xb1, 0x00, 0x00, 0x00, 0x48, 0x49, 0x44, @@ -41,7 +40,7 @@ const List kAnimatedGif = [ 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b, ]; -// A PNG with 100x100 blue pixels. +/// A PNG with 100x100 blue pixels. // // Constructed by the following code: // ```dart diff --git a/packages/flutter/test/material/circle_avatar_test.dart b/packages/flutter/test/material/circle_avatar_test.dart index aec85d2a99..13830c911d 100644 --- a/packages/flutter/test/material/circle_avatar_test.dart +++ b/packages/flutter/test/material/circle_avatar_test.dart @@ -10,7 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../painting/image_data.dart'; +import '../image_data.dart'; void main() { testWidgets('CircleAvatar with dark background color', (WidgetTester tester) async { diff --git a/packages/flutter/test/painting/binding_test.dart b/packages/flutter/test/painting/binding_test.dart index bf9da5b897..bea214f278 100644 --- a/packages/flutter/test/painting/binding_test.dart +++ b/packages/flutter/test/painting/binding_test.dart @@ -9,16 +9,18 @@ import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter/painting.dart'; +import 'package:flutter_test/flutter_test.dart'; + +Future main() async { + final ui.Image image = await createTestImage(); -void main() { testWidgets('didHaveMemoryPressure clears imageCache', (WidgetTester tester) async { imageCache.putIfAbsent(1, () => OneFrameImageStreamCompleter( Future.value(ImageInfo( - image: FakeImage(), + image: image, scale: 1.0, ), ))); @@ -115,19 +117,3 @@ class FakeImageCache extends ImageCache { super.clearLiveImages(); } } - -class FakeImage implements ui.Image { - @override - void dispose() {} - - @override - int get height => 10; - - @override - Future toByteData({ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba}) { - throw UnimplementedError(); - } - - @override - int get width => 10; -} diff --git a/packages/flutter/test/painting/decoration_test.dart b/packages/flutter/test/painting/decoration_test.dart index b3093629f2..a4161f0ba1 100644 --- a/packages/flutter/test/painting/decoration_test.dart +++ b/packages/flutter/test/painting/decoration_test.dart @@ -6,8 +6,7 @@ @TestOn('!chrome') import 'dart:async'; -import 'dart:typed_data'; -import 'dart:ui' as ui show Image, ImageByteFormat, ColorFilter; +import 'dart:ui' as ui show Image, ColorFilter; import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; @@ -29,6 +28,10 @@ class TestCanvas implements Canvas { } class SynchronousTestImageProvider extends ImageProvider { + const SynchronousTestImageProvider(this.image); + + final ui.Image image; + @override Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(1); @@ -37,7 +40,7 @@ class SynchronousTestImageProvider extends ImageProvider { @override ImageStreamCompleter load(int key, DecoderCallback decode) { return OneFrameImageStreamCompleter( - SynchronousFuture(TestImageInfo(key, image: TestImage(), scale: 1.0)) + SynchronousFuture(TestImageInfo(key, image: image, scale: 1.0)) ); } } @@ -73,6 +76,10 @@ class AsyncTestImageProvider extends ImageProvider { } class DelayedImageProvider extends ImageProvider { + DelayedImageProvider(this.image); + + final ui.Image image; + final Completer _completer = Completer(); @override @@ -85,30 +92,14 @@ class DelayedImageProvider extends ImageProvider { return OneFrameImageStreamCompleter(_completer.future); } - void complete() { - _completer.complete(ImageInfo(image: TestImage())); + Future complete() async { + _completer.complete(ImageInfo(image: image)); } @override String toString() => '${describeIdentity(this)}()'; } -class TestImage implements ui.Image { - @override - int get width => 100; - - @override - int get height => 100; - - @override - void dispose() { } - - @override - Future toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) async { - throw UnsupportedError('Cannot encode test image'); - } -} - void main() { TestRenderingFlutterBinding(); // initializes the imageCache @@ -141,8 +132,9 @@ void main() { expect(a, equals(b)); }); - test('BoxDecorationImageListenerSync', () { - final ImageProvider imageProvider = SynchronousTestImageProvider(); + test('BoxDecorationImageListenerSync', () async { + final ui.Image image = await createTestImage(width: 100, height: 100); + final ImageProvider imageProvider = SynchronousTestImageProvider(image); final DecorationImage backgroundImage = DecorationImage(image: imageProvider); final BoxDecoration boxDecoration = BoxDecoration(image: backgroundImage); @@ -183,11 +175,12 @@ void main() { // Regression test for https://github.com/flutter/flutter/issues/7289. // A reference test would be better. - test('BoxDecoration backgroundImage clip', () { + test('BoxDecoration backgroundImage clip', () async { + final ui.Image image = await createTestImage(width: 100, height: 100); void testDecoration({ BoxShape shape = BoxShape.rectangle, BorderRadius borderRadius, bool expectClip }) { assert(shape != null); - FakeAsync().run((FakeAsync async) { - final DelayedImageProvider imageProvider = DelayedImageProvider(); + FakeAsync().run((FakeAsync async) async { + final DelayedImageProvider imageProvider = DelayedImageProvider(image); final DecorationImage backgroundImage = DecorationImage(image: imageProvider); final BoxDecoration boxDecoration = BoxDecoration( @@ -209,7 +202,7 @@ void main() { // _BoxDecorationPainter._paintDecorationImage() resolves the background // image and adds a listener to the resolved image stream. boxPainter.paint(canvas, Offset.zero, imageConfiguration); - imageProvider.complete(); + await imageProvider.complete(); // Run the listener which calls onChanged() which saves an internal // reference to the TestImage. @@ -237,10 +230,11 @@ void main() { testDecoration(expectClip: false); }); - test('DecorationImage test', () { + test('DecorationImage test', () async { const ColorFilter colorFilter = ui.ColorFilter.mode(Color(0xFF00FF00), BlendMode.src); + final ui.Image image = await createTestImage(width: 100, height: 100); final DecorationImage backgroundImage = DecorationImage( - image: SynchronousTestImageProvider(), + image: SynchronousTestImageProvider(image), colorFilter: colorFilter, fit: BoxFit.contain, alignment: Alignment.bottomLeft, @@ -256,7 +250,7 @@ void main() { final Invocation call = canvas.invocations.singleWhere((Invocation call) => call.memberName == #drawImageNine); expect(call.isMethod, isTrue); expect(call.positionalArguments, hasLength(4)); - expect(call.positionalArguments[0], isA()); + expect(call.positionalArguments[0], isA()); expect(call.positionalArguments[1], const Rect.fromLTRB(10.0, 20.0, 40.0, 60.0)); expect(call.positionalArguments[2], const Rect.fromLTRB(0.0, 0.0, 100.0, 100.0)); expect(call.positionalArguments[3], isA()); @@ -265,10 +259,10 @@ void main() { expect(call.positionalArguments[3].filterQuality, FilterQuality.low); }); - test( - 'DecorationImage with null textDirection configuration should throw Error', () { + test('DecorationImage with null textDirection configuration should throw Error', () async { + final ui.Image image = await createTestImage(width: 100, height: 100); final DecorationImage backgroundImage = DecorationImage( - image: SynchronousTestImageProvider(), + image: SynchronousTestImageProvider(image), matchTextDirection: true, ); final BoxDecoration boxDecoration = BoxDecoration( @@ -434,12 +428,12 @@ void main() { expect(Decoration.lerp(const FlutterLogoDecoration(), const BoxDecoration(), 1.0), isA()); }); - test('paintImage BoxFit.none scale test', () { + test('paintImage BoxFit.none scale test', () async { for (double scale = 1.0; scale <= 4.0; scale += 1.0) { final TestCanvas canvas = TestCanvas([]); const Rect outputRect = Rect.fromLTWH(30.0, 30.0, 250.0, 250.0); - final ui.Image image = TestImage(); + final ui.Image image = await createTestImage(width: 100, height: 100); paintImage( canvas: canvas, @@ -459,7 +453,7 @@ void main() { expect(call.isMethod, isTrue); expect(call.positionalArguments, hasLength(4)); - expect(call.positionalArguments[0], isA()); + expect(call.positionalArguments[0], isA()); // sourceRect should contain all pixels of the source image expect(call.positionalArguments[1], Offset.zero & imageSize); @@ -477,13 +471,13 @@ void main() { } }); - test('paintImage BoxFit.scaleDown scale test', () { + test('paintImage BoxFit.scaleDown scale test', () async { for (double scale = 1.0; scale <= 4.0; scale += 1.0) { final TestCanvas canvas = TestCanvas([]); // container size > scaled image size const Rect outputRect = Rect.fromLTWH(30.0, 30.0, 250.0, 250.0); - final ui.Image image = TestImage(); + final ui.Image image = await createTestImage(width: 100, height: 100); paintImage( canvas: canvas, @@ -503,7 +497,7 @@ void main() { expect(call.isMethod, isTrue); expect(call.positionalArguments, hasLength(4)); - expect(call.positionalArguments[0], isA()); + expect(call.positionalArguments[0], isA()); // sourceRect should contain all pixels of the source image expect(call.positionalArguments[1], Offset.zero & imageSize); @@ -521,12 +515,12 @@ void main() { } }); - test('paintImage BoxFit.scaleDown test', () { + test('paintImage BoxFit.scaleDown test', () async { final TestCanvas canvas = TestCanvas([]); // container height (20 px) < scaled image height (50 px) const Rect outputRect = Rect.fromLTWH(30.0, 30.0, 250.0, 20.0); - final ui.Image image = TestImage(); + final ui.Image image = await createTestImage(width: 100, height: 100); paintImage( canvas: canvas, @@ -546,7 +540,7 @@ void main() { expect(call.isMethod, isTrue); expect(call.positionalArguments, hasLength(4)); - expect(call.positionalArguments[0], isA()); + expect(call.positionalArguments[0], isA()); // sourceRect should contain all pixels of the source image expect(call.positionalArguments[1], Offset.zero & imageSize); @@ -563,7 +557,7 @@ void main() { expect(call.positionalArguments[3], isA()); }); - test('paintImage boxFit, scale and alignment test', () { + test('paintImage boxFit, scale and alignment test', () async { const List boxFits = [ BoxFit.contain, BoxFit.cover, @@ -578,7 +572,7 @@ void main() { final TestCanvas canvas = TestCanvas([]); const Rect outputRect = Rect.fromLTWH(30.0, 30.0, 250.0, 250.0); - final ui.Image image = TestImage(); + final ui.Image image = await createTestImage(width: 100, height: 100); paintImage( canvas: canvas, @@ -601,9 +595,10 @@ void main() { } }); - test('scale cannot be null in DecorationImage', () { + test('scale cannot be null in DecorationImage', () async { + final ui.Image image = await createTestImage(width: 100, height: 100); try { - DecorationImage(scale: null, image: SynchronousTestImageProvider()); + DecorationImage(scale: null, image: SynchronousTestImageProvider(image)); } on AssertionError catch (error) { expect(error.toString(), contains('scale != null')); expect(error.toString(), contains('is not true')); @@ -612,9 +607,10 @@ void main() { fail('DecorationImage did not throw AssertionError when scale was null'); }); - test('DecorationImage scale test', () { + test('DecorationImage scale test', () async { + final ui.Image image = await createTestImage(width: 100, height: 100); final DecorationImage backgroundImage = DecorationImage( - image: SynchronousTestImageProvider(), + image: SynchronousTestImageProvider(image), scale: 4, alignment: Alignment.topLeft ); diff --git a/packages/flutter/test/painting/image_cache_clearing_test.dart b/packages/flutter/test/painting/image_cache_clearing_test.dart index 6d0c5422cb..94acdf34fb 100644 --- a/packages/flutter/test/painting/image_cache_clearing_test.dart +++ b/packages/flutter/test/painting/image_cache_clearing_test.dart @@ -10,8 +10,8 @@ import 'dart:typed_data'; import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../image_data.dart'; import '../rendering/rendering_tester.dart'; -import 'image_data.dart'; void main() { TestRenderingFlutterBinding(); diff --git a/packages/flutter/test/painting/image_cache_resize_test.dart b/packages/flutter/test/painting/image_cache_resize_test.dart index 9c647d3362..81b60dd72d 100644 --- a/packages/flutter/test/painting/image_cache_resize_test.dart +++ b/packages/flutter/test/painting/image_cache_resize_test.dart @@ -4,6 +4,8 @@ // @dart = 2.8 +import 'dart:ui' as ui; + import 'package:flutter/painting.dart'; import '../flutter_test_alternative.dart'; @@ -22,10 +24,10 @@ void main() { test('Image cache resizing based on count', () async { imageCache.maximumSize = 2; - final TestImageInfo a = await extractOneFrame(const TestImageProvider(1, 1).resolve(ImageConfiguration.empty)) as TestImageInfo; - final TestImageInfo b = await extractOneFrame(const TestImageProvider(2, 2).resolve(ImageConfiguration.empty)) as TestImageInfo; - final TestImageInfo c = await extractOneFrame(const TestImageProvider(3, 3).resolve(ImageConfiguration.empty)) as TestImageInfo; - final TestImageInfo d = await extractOneFrame(const TestImageProvider(1, 4).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo a = await extractOneFrame(TestImageProvider(1, 1, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo b = await extractOneFrame(TestImageProvider(2, 2, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo c = await extractOneFrame(TestImageProvider(3, 3, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo d = await extractOneFrame(TestImageProvider(1, 4, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(a.value, equals(1)); expect(b.value, equals(2)); expect(c.value, equals(3)); @@ -33,29 +35,29 @@ void main() { imageCache.maximumSize = 0; - final TestImageInfo e = await extractOneFrame(const TestImageProvider(1, 5).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo e = await extractOneFrame(TestImageProvider(1, 5, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(e.value, equals(5)); - final TestImageInfo f = await extractOneFrame(const TestImageProvider(1, 6).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo f = await extractOneFrame(TestImageProvider(1, 6, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(f.value, equals(6)); imageCache.maximumSize = 3; - final TestImageInfo g = await extractOneFrame(const TestImageProvider(1, 7).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo g = await extractOneFrame(TestImageProvider(1, 7, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(g.value, equals(7)); - final TestImageInfo h = await extractOneFrame(const TestImageProvider(1, 8).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo h = await extractOneFrame(TestImageProvider(1, 8, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(h.value, equals(7)); }); test('Image cache resizing based on size', () async { - const TestImage testImage = TestImage(width: 8, height: 8); // 256 B. + final ui.Image testImage = await createTestImage(width: 8, height: 8); // 256 B. imageCache.maximumSizeBytes = 256 * 2; - final TestImageInfo a = await extractOneFrame(const TestImageProvider(1, 1, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; - final TestImageInfo b = await extractOneFrame(const TestImageProvider(2, 2, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; - final TestImageInfo c = await extractOneFrame(const TestImageProvider(3, 3, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; - final TestImageInfo d = await extractOneFrame(const TestImageProvider(1, 4, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo a = await extractOneFrame(TestImageProvider(1, 1, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo b = await extractOneFrame(TestImageProvider(2, 2, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo c = await extractOneFrame(TestImageProvider(3, 3, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo d = await extractOneFrame(TestImageProvider(1, 4, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(a.value, equals(1)); expect(b.value, equals(2)); expect(c.value, equals(3)); @@ -63,18 +65,18 @@ void main() { imageCache.maximumSizeBytes = 0; - final TestImageInfo e = await extractOneFrame(const TestImageProvider(1, 5, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo e = await extractOneFrame(TestImageProvider(1, 5, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(e.value, equals(5)); - final TestImageInfo f = await extractOneFrame(const TestImageProvider(1, 6, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo f = await extractOneFrame(TestImageProvider(1, 6, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(f.value, equals(6)); imageCache.maximumSizeBytes = 256 * 3; - final TestImageInfo g = await extractOneFrame(const TestImageProvider(1, 7, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo g = await extractOneFrame(TestImageProvider(1, 7, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(g.value, equals(7)); - final TestImageInfo h = await extractOneFrame(const TestImageProvider(1, 8, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo h = await extractOneFrame(TestImageProvider(1, 8, image: testImage).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(h.value, equals(7)); }); } diff --git a/packages/flutter/test/painting/image_cache_test.dart b/packages/flutter/test/painting/image_cache_test.dart index fe8ef5af44..d5af602726 100644 --- a/packages/flutter/test/painting/image_cache_test.dart +++ b/packages/flutter/test/painting/image_cache_test.dart @@ -4,6 +4,8 @@ // @dart = 2.8 +import 'dart:ui' as ui; + import 'package:flutter/painting.dart'; import '../flutter_test_alternative.dart'; @@ -23,82 +25,82 @@ void main() { test('maintains cache size', () async { imageCache.maximumSize = 3; - final TestImageInfo a = await extractOneFrame(const TestImageProvider(1, 1).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo a = await extractOneFrame(TestImageProvider(1, 1, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(a.value, equals(1)); - final TestImageInfo b = await extractOneFrame(const TestImageProvider(1, 2).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo b = await extractOneFrame(TestImageProvider(1, 2, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(b.value, equals(1)); - final TestImageInfo c = await extractOneFrame(const TestImageProvider(1, 3).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo c = await extractOneFrame(TestImageProvider(1, 3, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(c.value, equals(1)); - final TestImageInfo d = await extractOneFrame(const TestImageProvider(1, 4).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo d = await extractOneFrame(TestImageProvider(1, 4, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(d.value, equals(1)); - final TestImageInfo e = await extractOneFrame(const TestImageProvider(1, 5).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo e = await extractOneFrame(TestImageProvider(1, 5, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(e.value, equals(1)); - final TestImageInfo f = await extractOneFrame(const TestImageProvider(1, 6).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo f = await extractOneFrame(TestImageProvider(1, 6, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(f.value, equals(1)); expect(f, equals(a)); // cache still only has one entry in it: 1(1) - final TestImageInfo g = await extractOneFrame(const TestImageProvider(2, 7).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo g = await extractOneFrame(TestImageProvider(2, 7, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(g.value, equals(7)); // cache has two entries in it: 1(1), 2(7) - final TestImageInfo h = await extractOneFrame(const TestImageProvider(1, 8).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo h = await extractOneFrame(TestImageProvider(1, 8, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(h.value, equals(1)); // cache still has two entries in it: 2(7), 1(1) - final TestImageInfo i = await extractOneFrame(const TestImageProvider(3, 9).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo i = await extractOneFrame(TestImageProvider(3, 9, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(i.value, equals(9)); // cache has three entries in it: 2(7), 1(1), 3(9) - final TestImageInfo j = await extractOneFrame(const TestImageProvider(1, 10).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo j = await extractOneFrame(TestImageProvider(1, 10, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(j.value, equals(1)); // cache still has three entries in it: 2(7), 3(9), 1(1) - final TestImageInfo k = await extractOneFrame(const TestImageProvider(4, 11).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo k = await extractOneFrame(TestImageProvider(4, 11, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(k.value, equals(11)); // cache has three entries: 3(9), 1(1), 4(11) - final TestImageInfo l = await extractOneFrame(const TestImageProvider(1, 12).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo l = await extractOneFrame(TestImageProvider(1, 12, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(l.value, equals(1)); // cache has three entries: 3(9), 4(11), 1(1) - final TestImageInfo m = await extractOneFrame(const TestImageProvider(2, 13).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo m = await extractOneFrame(TestImageProvider(2, 13, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(m.value, equals(13)); // cache has three entries: 4(11), 1(1), 2(13) - final TestImageInfo n = await extractOneFrame(const TestImageProvider(3, 14).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo n = await extractOneFrame(TestImageProvider(3, 14, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(n.value, equals(14)); // cache has three entries: 1(1), 2(13), 3(14) - final TestImageInfo o = await extractOneFrame(const TestImageProvider(4, 15).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo o = await extractOneFrame(TestImageProvider(4, 15, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(o.value, equals(15)); // cache has three entries: 2(13), 3(14), 4(15) - final TestImageInfo p = await extractOneFrame(const TestImageProvider(1, 16).resolve(ImageConfiguration.empty)) as TestImageInfo; + final TestImageInfo p = await extractOneFrame(TestImageProvider(1, 16, image: await createTestImage()).resolve(ImageConfiguration.empty)) as TestImageInfo; expect(p.value, equals(16)); // cache has three entries: 3(14), 4(15), 1(16) }); test('clear removes all images and resets cache size', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); expect(imageCache.currentSize, 0); expect(imageCache.currentSizeBytes, 0); - await extractOneFrame(const TestImageProvider(1, 1, image: testImage).resolve(ImageConfiguration.empty)); - await extractOneFrame(const TestImageProvider(2, 2, image: testImage).resolve(ImageConfiguration.empty)); + await extractOneFrame(TestImageProvider(1, 1, image: testImage).resolve(ImageConfiguration.empty)); + await extractOneFrame(TestImageProvider(2, 2, image: testImage).resolve(ImageConfiguration.empty)); expect(imageCache.currentSize, 2); expect(imageCache.currentSizeBytes, 256 * 2); @@ -110,9 +112,9 @@ void main() { }); test('evicts individual images', () async { - const TestImage testImage = TestImage(width: 8, height: 8); - await extractOneFrame(const TestImageProvider(1, 1, image: testImage).resolve(ImageConfiguration.empty)); - await extractOneFrame(const TestImageProvider(2, 2, image: testImage).resolve(ImageConfiguration.empty)); + final ui.Image testImage = await createTestImage(width: 8, height: 8); + await extractOneFrame(TestImageProvider(1, 1, image: testImage).resolve(ImageConfiguration.empty)); + await extractOneFrame(TestImageProvider(2, 2, image: testImage).resolve(ImageConfiguration.empty)); expect(imageCache.currentSize, 2); expect(imageCache.currentSizeBytes, 256 * 2); @@ -122,10 +124,10 @@ void main() { }); test('Do not cache large images', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); imageCache.maximumSizeBytes = 1; - await extractOneFrame(const TestImageProvider(1, 1, image: testImage).resolve(ImageConfiguration.empty)); + await extractOneFrame(TestImageProvider(1, 1, image: testImage).resolve(ImageConfiguration.empty)); expect(imageCache.currentSize, 0); expect(imageCache.currentSizeBytes, 0); expect(imageCache.maximumSizeBytes, 1); @@ -143,7 +145,7 @@ void main() { }); test('already pending image is returned when it is put into the cache again', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); final TestImageStreamCompleter completer2 = TestImageStreamCompleter(); @@ -160,7 +162,7 @@ void main() { }); test('pending image is removed when cache is cleared', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); final TestImageStreamCompleter completer2 = TestImageStreamCompleter(); @@ -187,7 +189,7 @@ void main() { }); test('pending image is removed when image is evicted', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); final TestImageStreamCompleter completer2 = TestImageStreamCompleter(); @@ -207,21 +209,25 @@ void main() { }); test("failed image can successfully be removed from the cache's pending images", () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); - const FailingTestImageProvider(1, 1, image: testImage) + FailingTestImageProvider(1, 1, image: testImage) .resolve(ImageConfiguration.empty) .addListener(ImageStreamListener( - (ImageInfo image, bool synchronousCall) { }, + (ImageInfo image, bool synchronousCall) { + fail('Image should not complete successfully'); + }, onError: (dynamic exception, StackTrace stackTrace) { final bool evictionResult = imageCache.evict(1); expect(evictionResult, isTrue); }, )); + // yield an event turn so that async work can complete. + await null; }); test('containsKey - pending', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); @@ -234,7 +240,7 @@ void main() { }); test('containsKey - completed', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); @@ -251,8 +257,8 @@ void main() { test('putIfAbsent updates LRU properties of a live image', () async { imageCache.maximumSize = 1; - const TestImage testImage = TestImage(width: 8, height: 8); - const TestImage testImage2 = TestImage(width: 10, height: 10); + final ui.Image testImage = await createTestImage(width: 8, height: 8); + final ui.Image testImage2 = await createTestImage(width: 10, height: 10); final TestImageStreamCompleter completer1 = TestImageStreamCompleter()..testSetImage(testImage); final TestImageStreamCompleter completer2 = TestImageStreamCompleter()..testSetImage(testImage2); @@ -286,12 +292,12 @@ void main() { test('Live image cache avoids leaks of unlistened streams', () async { imageCache.maximumSize = 3; - const TestImageProvider(1, 1).resolve(ImageConfiguration.empty); - const TestImageProvider(2, 2).resolve(ImageConfiguration.empty); - const TestImageProvider(3, 3).resolve(ImageConfiguration.empty); - const TestImageProvider(4, 4).resolve(ImageConfiguration.empty); - const TestImageProvider(5, 5).resolve(ImageConfiguration.empty); - const TestImageProvider(6, 6).resolve(ImageConfiguration.empty); + TestImageProvider(1, 1, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(2, 2, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(3, 3, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(4, 4, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(5, 5, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(6, 6, image: await createTestImage()).resolve(ImageConfiguration.empty); // wait an event loop to let image resolution process. await null; @@ -303,12 +309,12 @@ void main() { test('Disabled image cache does not leak live images', () async { imageCache.maximumSize = 0; - const TestImageProvider(1, 1).resolve(ImageConfiguration.empty); - const TestImageProvider(2, 2).resolve(ImageConfiguration.empty); - const TestImageProvider(3, 3).resolve(ImageConfiguration.empty); - const TestImageProvider(4, 4).resolve(ImageConfiguration.empty); - const TestImageProvider(5, 5).resolve(ImageConfiguration.empty); - const TestImageProvider(6, 6).resolve(ImageConfiguration.empty); + TestImageProvider(1, 1, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(2, 2, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(3, 3, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(4, 4, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(5, 5, image: await createTestImage()).resolve(ImageConfiguration.empty); + TestImageProvider(6, 6, image: await createTestImage()).resolve(ImageConfiguration.empty); // wait an event loop to let image resolution process. await null; @@ -318,7 +324,7 @@ void main() { }); test('Evicting a pending image clears the live image by default', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); @@ -332,7 +338,7 @@ void main() { }); test('Evicting a pending image does clear the live image when includeLive is false and only cache listening', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); @@ -348,7 +354,7 @@ void main() { }); test('Evicting a pending image does clear the live image when includeLive is false and some other listener', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); @@ -365,7 +371,7 @@ void main() { }); test('Evicting a completed image does clear the live image by default', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter() ..testSetImage(testImage) @@ -381,7 +387,7 @@ void main() { }); test('Evicting a completed image does not clear the live image when includeLive is set to false', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final TestImageStreamCompleter completer1 = TestImageStreamCompleter() ..testSetImage(testImage) @@ -399,7 +405,7 @@ void main() { }); test('Clearing liveImages removes callbacks', () async { - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); final ImageStreamListener listener = ImageStreamListener((ImageInfo info, bool syncCall) {}); @@ -442,7 +448,7 @@ void main() { // If the live image did not track the size properly, the last line of // this test will fail. - const TestImage testImage = TestImage(width: 8, height: 8); + final ui.Image testImage = await createTestImage(width: 8, height: 8); const int testImageSize = 8 * 8 * 4; final ImageStreamListener listener = ImageStreamListener((ImageInfo info, bool syncCall) {}); diff --git a/packages/flutter/test/painting/image_decoder_test.dart b/packages/flutter/test/painting/image_decoder_test.dart index 36ce220884..aea7103403 100644 --- a/packages/flutter/test/painting/image_decoder_test.dart +++ b/packages/flutter/test/painting/image_decoder_test.dart @@ -10,7 +10,7 @@ import 'dart:ui' as ui; import 'package:flutter/painting.dart'; import '../flutter_test_alternative.dart'; -import 'image_data.dart'; +import '../image_data.dart'; import 'painting_utils.dart'; void main() { diff --git a/packages/flutter/test/painting/image_provider_and_image_cache_test.dart b/packages/flutter/test/painting/image_provider_and_image_cache_test.dart index 6195f99a46..7e9a3e1896 100644 --- a/packages/flutter/test/painting/image_provider_and_image_cache_test.dart +++ b/packages/flutter/test/painting/image_provider_and_image_cache_test.dart @@ -12,8 +12,8 @@ import 'package:flutter/painting.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../image_data.dart'; import '../rendering/rendering_tester.dart'; -import 'image_data.dart'; import 'mocks_for_image_cache.dart'; void main() { diff --git a/packages/flutter/test/painting/image_provider_network_image_test.dart b/packages/flutter/test/painting/image_provider_network_image_test.dart index 7b02899ca1..ee9fb00d58 100644 --- a/packages/flutter/test/painting/image_provider_network_image_test.dart +++ b/packages/flutter/test/painting/image_provider_network_image_test.dart @@ -15,8 +15,8 @@ import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; import '../flutter_test_alternative.dart' show Fake; +import '../image_data.dart'; import '../rendering/rendering_tester.dart'; -import 'image_data.dart'; void main() { TestRenderingFlutterBinding(); diff --git a/packages/flutter/test/painting/image_provider_resize_image_test.dart b/packages/flutter/test/painting/image_provider_resize_image_test.dart index 29afff69ed..21948fb32c 100644 --- a/packages/flutter/test/painting/image_provider_resize_image_test.dart +++ b/packages/flutter/test/painting/image_provider_resize_image_test.dart @@ -10,8 +10,8 @@ import 'dart:typed_data'; import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../image_data.dart'; import '../rendering/rendering_tester.dart'; -import 'image_data.dart'; void main() { TestRenderingFlutterBinding(); @@ -36,7 +36,7 @@ void main() { test('ResizeImage resizes to the correct dimensions (down)', () async { - final Uint8List bytes = Uint8List.fromList(kBlueSquare); + final Uint8List bytes = Uint8List.fromList(kBlueSquarePng); final MemoryImage imageProvider = MemoryImage(bytes); final Size rawImageSize = await _resolveAndGetSize(imageProvider); expect(rawImageSize, const Size(50, 50)); diff --git a/packages/flutter/test/painting/image_provider_test.dart b/packages/flutter/test/painting/image_provider_test.dart index ec81db82ff..3b2895f58a 100644 --- a/packages/flutter/test/painting/image_provider_test.dart +++ b/packages/flutter/test/painting/image_provider_test.dart @@ -15,8 +15,8 @@ import 'package:flutter/painting.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../image_data.dart'; import '../rendering/rendering_tester.dart'; -import 'image_data.dart'; import 'mocks_for_image_cache.dart'; void main() { @@ -149,7 +149,7 @@ void main() { test('File image sets tag', () async { final MemoryFileSystem fs = MemoryFileSystem(); - final File file = fs.file('/blue.png')..createSync(recursive: true)..writeAsBytesSync(kBlueRectPng); + final File file = fs.file('/blue.png')..createSync(recursive: true)..writeAsBytesSync(kBlueSquarePng); final FileImage provider = FileImage(file); final MultiFrameImageStreamCompleter completer = provider.load(provider, _decoder) as MultiFrameImageStreamCompleter; @@ -158,7 +158,7 @@ void main() { }); test('Memory image sets tag', () async { - final Uint8List bytes = Uint8List.fromList(kBlueRectPng); + final Uint8List bytes = Uint8List.fromList(kBlueSquarePng); final MemoryImage provider = MemoryImage(bytes); final MultiFrameImageStreamCompleter completer = provider.load(provider, _decoder) as MultiFrameImageStreamCompleter; @@ -176,7 +176,7 @@ void main() { }); test('Resize image sets tag', () async { - final Uint8List bytes = Uint8List.fromList(kBlueRectPng); + final Uint8List bytes = Uint8List.fromList(kBlueSquarePng); final ResizeImage provider = ResizeImage(MemoryImage(bytes), width: 40, height: 40); final MultiFrameImageStreamCompleter completer = provider.load( await provider.obtainKey(ImageConfiguration.empty), @@ -206,6 +206,6 @@ class FakeCodec implements Codec { class _TestAssetBundle extends CachingAssetBundle { @override Future load(String key) async { - return Uint8List.fromList(kBlueRectPng).buffer.asByteData(); + return Uint8List.fromList(kBlueSquarePng).buffer.asByteData(); } } diff --git a/packages/flutter/test/painting/image_test_utils.dart b/packages/flutter/test/painting/image_test_utils.dart index e08a6db590..082e8ebbb8 100644 --- a/packages/flutter/test/painting/image_test_utils.dart +++ b/packages/flutter/test/painting/image_test_utils.dart @@ -5,13 +5,13 @@ // @dart = 2.8 import 'dart:async'; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; -import 'image_data.dart'; +import 'package:flutter_test/flutter_test.dart'; + class TestImageProvider extends ImageProvider { TestImageProvider(this.testImage); @@ -49,12 +49,6 @@ class TestImageProvider extends ImageProvider { String toString() => '${describeIdentity(this)}()'; } -Future createTestImage() { - final Completer uiImage = Completer(); - ui.decodeImageFromList(Uint8List.fromList(kTransparentImage), uiImage.complete); - return uiImage.future; -} - class FakeImageConfiguration implements ImageConfiguration { @override dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); diff --git a/packages/flutter/test/painting/mocks_for_image_cache.dart b/packages/flutter/test/painting/mocks_for_image_cache.dart index e6baec849d..899254cf58 100644 --- a/packages/flutter/test/painting/mocks_for_image_cache.dart +++ b/packages/flutter/test/painting/mocks_for_image_cache.dart @@ -5,9 +5,7 @@ // @dart = 2.8 import 'dart:async'; -import 'dart:typed_data'; import 'dart:ui' as ui show Image; -import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; @@ -31,7 +29,7 @@ class TestImageInfo implements ImageInfo { } class TestImageProvider extends ImageProvider { - const TestImageProvider(this.key, this.imageValue, { this.image = const TestImage() }) + const TestImageProvider(this.key, this.imageValue, { @required this.image }) : assert(image != null); final int key; @@ -74,22 +72,6 @@ Future extractOneFrame(ImageStream stream) { return completer.future; } -class TestImage implements ui.Image { - const TestImage({this.height = 0, this.width = 0}); - @override - final int height; - @override - final int width; - - @override - void dispose() { } - - @override - Future toByteData({ ImageByteFormat format = ImageByteFormat.rawRgba }) { - throw UnimplementedError(); - } -} - class ErrorImageProvider extends ImageProvider { @override ImageStreamCompleter load(ErrorImageProvider key, DecoderCallback decode) { @@ -141,7 +123,7 @@ class LoadErrorCompleterImageProvider extends ImageProvider toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) async { - throw UnsupportedError('Cannot encode test image'); - } -} - class TestCanvas implements Canvas { final List invocations = []; @@ -39,17 +20,23 @@ class TestCanvas implements Canvas { } void main() { + ui.Image image300x300; + ui.Image image300x200; + setUpAll(() async { + image300x300 = await createTestImage(width: 300, height: 300, cache: false); + image300x200 = await createTestImage(width: 300, height: 200, cache: false); + }); + setUp(() { debugFlushLastFrameImageSizeInfo(); }); - test('Cover and align', () { - final TestImage image = TestImage(width: 300, height: 300); + test('Cover and align', () async { final TestCanvas canvas = TestCanvas(); paintImage( canvas: canvas, rect: const Rect.fromLTWH(50.0, 75.0, 200.0, 100.0), - image: image, + image: image300x300, fit: BoxFit.cover, alignment: const Alignment(-1.0, 0.0), ); @@ -59,12 +46,12 @@ void main() { }); expect(command, isNotNull); - expect(command.positionalArguments[0], equals(image)); + expect(command.positionalArguments[0], equals(image300x300)); expect(command.positionalArguments[1], equals(const Rect.fromLTWH(0.0, 75.0, 300.0, 150.0))); expect(command.positionalArguments[2], equals(const Rect.fromLTWH(50.0, 75.0, 200.0, 100.0))); }); - test('debugInvertOversizedImages', () { + test('debugInvertOversizedImages', () async { debugInvertOversizedImages = true; final FlutterExceptionHandler oldFlutterError = FlutterError.onError; @@ -73,14 +60,13 @@ void main() { messages.add(details.exceptionAsString()); }; - final TestImage image = TestImage(width: 300, height: 300); final TestCanvas canvas = TestCanvas(); const Rect rect = Rect.fromLTWH(50.0, 50.0, 200.0, 100.0); paintImage( canvas: canvas, rect: rect, - image: image, + image: image300x300, debugImageLabel: 'TestImage', fit: BoxFit.fill, ); @@ -132,12 +118,11 @@ void main() { imageSizeInfo = info; }; - final TestImage image = TestImage(width: 300, height: 300); final TestCanvas canvas = TestCanvas(); paintImage( canvas: canvas, rect: const Rect.fromLTWH(50.0, 75.0, 200.0, 100.0), - image: image, + image: image300x300, debugImageLabel: 'test.png', ); @@ -155,7 +140,7 @@ void main() { paintImage( canvas: canvas, rect: const Rect.fromLTWH(50.0, 75.0, 200.0, 100.0), - image: image, + image: image300x300, debugImageLabel: 'test.png', ); @@ -172,12 +157,11 @@ void main() { imageSizeInfo = info; }; - final TestImage image = TestImage(width: 300, height: 300); final TestCanvas canvas = TestCanvas(); paintImage( canvas: canvas, rect: const Rect.fromLTWH(50.0, 75.0, 200.0, 100.0), - image: image, + image: image300x300, debugImageLabel: 'test.png', ); @@ -195,7 +179,7 @@ void main() { paintImage( canvas: canvas, rect: const Rect.fromLTWH(50.0, 75.0, 200.0, 150.0), - image: image, + image: image300x300, debugImageLabel: 'test.png', ); @@ -216,12 +200,11 @@ void main() { imageSizeInfo = info; }; - final TestImage image = TestImage(width: 300, height: 200); final TestCanvas canvas = TestCanvas(); paintImage( canvas: canvas, rect: const Rect.fromLTWH(50.0, 75.0, 200.0, 100.0), - image: image, + image: image300x200, ); expect(count, 1); diff --git a/packages/flutter/test/painting/shape_decoration_test.dart b/packages/flutter/test/painting/shape_decoration_test.dart index 6222e5b44e..d472b9e63f 100644 --- a/packages/flutter/test/painting/shape_decoration_test.dart +++ b/packages/flutter/test/painting/shape_decoration_test.dart @@ -4,7 +4,6 @@ // @dart = 2.8 -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; @@ -59,12 +58,13 @@ void main() { expect(b.hitTest(size, const Offset(20.0, 50.0)), isTrue); }); - test('ShapeDecoration.image RTL test', () { + test('ShapeDecoration.image RTL test', () async { + final ui.Image image = await createTestImage(width: 100, height: 200); final List log = []; final ShapeDecoration decoration = ShapeDecoration( shape: const CircleBorder(), image: DecorationImage( - image: TestImageProvider(), + image: TestImageProvider(image), alignment: AlignmentDirectional.bottomEnd, ), ); @@ -113,6 +113,10 @@ void main() { } class TestImageProvider extends ImageProvider { + TestImageProvider(this.image); + + final ui.Image image; + @override Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); @@ -121,23 +125,7 @@ class TestImageProvider extends ImageProvider { @override ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { return OneFrameImageStreamCompleter( - SynchronousFuture(ImageInfo(image: TestImage(), scale: 1.0)), + SynchronousFuture(ImageInfo(image: image, scale: 1.0)), ); } } - -class TestImage implements ui.Image { - @override - int get width => 100; - - @override - int get height => 200; - - @override - void dispose() { } - - @override - Future toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) async { - throw UnsupportedError('Cannot encode test image'); - } -} diff --git a/packages/flutter/test/rendering/image_test.dart b/packages/flutter/test/rendering/image_test.dart index dce4dd9ec9..504d44b468 100644 --- a/packages/flutter/test/rendering/image_test.dart +++ b/packages/flutter/test/rendering/image_test.dart @@ -4,76 +4,22 @@ // @dart = 2.8 -import 'dart:typed_data'; -import 'dart:ui' as ui show Image, ImageByteFormat; +import 'dart:ui' as ui show Image; +import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'rendering_tester.dart'; -class SquareImage implements ui.Image { - @override - int get width => 10; - - @override - int get height => 10; - - @override - Future toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) async { - throw UnsupportedError('Cannot encode test image'); - } - - @override - String toString() => '[$width\u00D7$height]'; - - @override - void dispose() { } -} - -class WideImage implements ui.Image { - @override - int get width => 20; - - @override - int get height => 10; - - @override - Future toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) async { - throw UnsupportedError('Cannot encode test image'); - } - - @override - String toString() => '[$width\u00D7$height]'; - - @override - void dispose() { } -} - -class TallImage implements ui.Image { - @override - int get width => 10; - - @override - int get height => 20; - - @override - Future toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) async { - throw UnsupportedError('Cannot encode test image'); - } - - @override - String toString() => '[$width\u00D7$height]'; - - @override - void dispose() { } -} - -void main() { +Future main() async { + final ui.Image squareImage = await createTestImage(width: 10, height: 10); + final ui.Image wideImage = await createTestImage(width: 20, height: 10); + final ui.Image tallImage = await createTestImage(width: 10, height: 20); test('Image sizing', () { RenderImage image; - image = RenderImage(image: SquareImage()); + image = RenderImage(image: squareImage); layout(image, constraints: const BoxConstraints( minWidth: 25.0, @@ -83,7 +29,8 @@ void main() { expect(image.size.width, equals(25.0)); expect(image.size.height, equals(25.0)); - expect(image, hasAGoodToStringDeep); + // TODO(dnfield): https://github.com/flutter/flutter/issues/66289 + expect(image, hasAGoodToStringDeep, skip: kIsWeb); expect( image.toStringDeep(minLevel: DiagnosticLevel.info), equalsIgnoringHashCodes( @@ -91,14 +38,14 @@ void main() { ' parentData: (can use size)\n' ' constraints: BoxConstraints(25.0<=w<=100.0, 25.0<=h<=100.0)\n' ' size: Size(25.0, 25.0)\n' - ' image: [10×10]\n' + ' image: $squareImage\n' ' alignment: center\n' ' invertColors: false\n' ' filterQuality: low\n' ), ); - image = RenderImage(image: WideImage()); + image = RenderImage(image: wideImage); layout(image, constraints: const BoxConstraints( minWidth: 5.0, @@ -108,7 +55,7 @@ void main() { expect(image.size.width, equals(60.0)); expect(image.size.height, equals(30.0)); - image = RenderImage(image: TallImage()); + image = RenderImage(image: tallImage); layout(image, constraints: const BoxConstraints( minWidth: 50.0, @@ -118,7 +65,7 @@ void main() { expect(image.size.width, equals(50.0)); expect(image.size.height, equals(75.0)); - image = RenderImage(image: WideImage()); + image = RenderImage(image: wideImage); layout(image, constraints: const BoxConstraints( minWidth: 5.0, @@ -128,7 +75,7 @@ void main() { expect(image.size.width, equals(20.0)); expect(image.size.height, equals(10.0)); - image = RenderImage(image: WideImage()); + image = RenderImage(image: wideImage); layout(image, constraints: const BoxConstraints( minWidth: 5.0, @@ -138,7 +85,7 @@ void main() { expect(image.size.width, equals(16.0)); expect(image.size.height, equals(8.0)); - image = RenderImage(image: TallImage()); + image = RenderImage(image: tallImage); layout(image, constraints: const BoxConstraints( minWidth: 5.0, @@ -148,7 +95,7 @@ void main() { expect(image.size.width, equals(8.0)); expect(image.size.height, equals(16.0)); - image = RenderImage(image: SquareImage()); + image = RenderImage(image: squareImage); layout(image, constraints: const BoxConstraints( minWidth: 4.0, @@ -158,7 +105,7 @@ void main() { expect(image.size.width, equals(8.0)); expect(image.size.height, equals(8.0)); - image = RenderImage(image: WideImage()); + image = RenderImage(image: wideImage); layout(image, constraints: const BoxConstraints( minWidth: 20.0, @@ -168,7 +115,7 @@ void main() { expect(image.size.width, equals(30.0)); expect(image.size.height, equals(20.0)); - image = RenderImage(image: TallImage()); + image = RenderImage(image: tallImage); layout(image, constraints: const BoxConstraints( minWidth: 20.0, diff --git a/packages/flutter/test/widgets/box_decoration_test.dart b/packages/flutter/test/widgets/box_decoration_test.dart index 3cfacf2641..fdd9da6a94 100644 --- a/packages/flutter/test/widgets/box_decoration_test.dart +++ b/packages/flutter/test/widgets/box_decoration_test.dart @@ -15,7 +15,7 @@ import 'package:flutter/painting.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../painting/image_data.dart'; +import '../image_data.dart'; import '../rendering/mock_canvas.dart'; class TestImageProvider extends ImageProvider { diff --git a/packages/flutter/test/widgets/fade_in_image_test.dart b/packages/flutter/test/widgets/fade_in_image_test.dart index dc0505ce5f..427793857a 100644 --- a/packages/flutter/test/widgets/fade_in_image_test.dart +++ b/packages/flutter/test/widgets/fade_in_image_test.dart @@ -10,7 +10,8 @@ import 'dart:ui' as ui; import 'package:flutter/widgets.dart'; import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../painting/image_data.dart'; + +import '../image_data.dart'; import '../painting/image_test_utils.dart'; const Duration animationDuration = Duration(milliseconds: 50); diff --git a/packages/flutter/test/widgets/image_data.dart b/packages/flutter/test/widgets/image_data.dart deleted file mode 100644 index 46a898b7e4..0000000000 --- a/packages/flutter/test/widgets/image_data.dart +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -// @dart = 2.8 - -const List kTransparentImage = [ - 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, - 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, - 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, - 0x41, 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0D, - 0x0A, 0x2D, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, -]; - -/// An animated GIF image with 3 1x1 pixel frames (a red, green, and blue -/// frames). The GIF animates forever, and each frame has a 100ms delay. -const List kAnimatedGif = [ - 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0xa1, 0x03, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x21, - 0xff, 0x0b, 0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e, 0x30, - 0x03, 0x01, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x4c, - 0x01, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x2c, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x54, 0x01, 0x00, 0x21, - 0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b, -]; diff --git a/packages/flutter/test/widgets/image_headers_test.dart b/packages/flutter/test/widgets/image_headers_test.dart index b6a630ae4c..ad4dba2bf5 100644 --- a/packages/flutter/test/widgets/image_headers_test.dart +++ b/packages/flutter/test/widgets/image_headers_test.dart @@ -11,7 +11,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import '../flutter_test_alternative.dart' show Fake; -import '../painting/image_data.dart'; +import '../image_data.dart'; void main() { final MockHttpClient client = MockHttpClient(); diff --git a/packages/flutter/test/widgets/image_icon_test.dart b/packages/flutter/test/widgets/image_icon_test.dart index 2a8f8d5ae4..68c4c453d3 100644 --- a/packages/flutter/test/widgets/image_icon_test.dart +++ b/packages/flutter/test/widgets/image_icon_test.dart @@ -10,13 +10,22 @@ import 'package:flutter_test/flutter_test.dart'; import '../painting/mocks_for_image_cache.dart'; -const ImageProvider _kImage = TestImageProvider(21, 42); void main() { + ImageProvider _image; + + setUpAll(() async { + _image = TestImageProvider( + 21, + 42, + image: await createTestImage(width: 10, height: 10), + ); + }); + testWidgets('ImageIcon sizing - no theme, default size', (WidgetTester tester) async { await tester.pumpWidget( - const Center( - child: ImageIcon(_kImage), + Center( + child: ImageIcon(_image), ), ); @@ -27,10 +36,10 @@ void main() { testWidgets('Icon opacity', (WidgetTester tester) async { await tester.pumpWidget( - const Center( + Center( child: IconTheme( - data: IconThemeData(opacity: 0.5), - child: ImageIcon(_kImage), + data: const IconThemeData(opacity: 0.5), + child: ImageIcon(_image), ), ), ); diff --git a/packages/flutter/test/widgets/image_resolution_test.dart b/packages/flutter/test/widgets/image_resolution_test.dart index 02ff2b97e5..d6b461135b 100644 --- a/packages/flutter/test/widgets/image_resolution_test.dart +++ b/packages/flutter/test/widgets/image_resolution_test.dart @@ -6,7 +6,7 @@ @TestOn('!chrome') // asset bundle behaves differently. import 'dart:typed_data'; -import 'dart:ui' as ui show Image, ImageByteFormat; +import 'dart:ui' as ui show Image; import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; @@ -14,26 +14,7 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'image_data.dart'; - -class TestImage implements ui.Image { - TestImage(this.scale); - final double scale; - - @override - int get width => (48*scale).floor(); - - @override - int get height => (48*scale).floor(); - - @override - void dispose() { } - - @override - Future toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) async { - throw UnsupportedError('Cannot encode test image'); - } -} +import '../image_data.dart'; class TestByteData implements ByteData { TestByteData(this.scale); @@ -104,14 +85,17 @@ class FakeImageStreamCompleter extends ImageStreamCompleter { } class TestAssetImage extends AssetImage { - const TestAssetImage(String name) : super(name); + const TestAssetImage(String name, this.images) : super(name); + + final Map images; @override ImageStreamCompleter load(AssetBundleImageKey key, DecoderCallback decode) { ImageInfo imageInfo; key.bundle.load(key.name).then((ByteData data) { final TestByteData testData = data as TestByteData; - final ui.Image image = TestImage(testData.scale); + final ui.Image image = images[testData.scale]; + assert(image != null, 'Expected ${testData.scale} to have a key in $images'); imageInfo = ImageInfo(image: image, scale: key.scale); }); assert(imageInfo != null); @@ -121,7 +105,7 @@ class TestAssetImage extends AssetImage { } } -Widget buildImageAtRatio(String image, Key key, double ratio, bool inferSize, [ AssetBundle bundle ]) { +Widget buildImageAtRatio(String imageName, Key key, double ratio, bool inferSize, Map images, [ AssetBundle bundle ]) { const double windowSize = 500.0; // 500 logical pixels const double imageSize = 200.0; // 200 logical pixels @@ -138,12 +122,12 @@ Widget buildImageAtRatio(String image, Key key, double ratio, bool inferSize, [ Image( key: key, excludeFromSemantics: true, - image: TestAssetImage(image), + image: TestAssetImage(imageName, images), ) : Image( key: key, excludeFromSemantics: true, - image: TestAssetImage(image), + image: TestAssetImage(imageName, images), height: imageSize, width: imageSize, fit: BoxFit.fill, @@ -180,9 +164,6 @@ Widget buildImageCacheResized(String name, Key key, int width, int height, int c RenderImage getRenderImage(WidgetTester tester, Key key) { return tester.renderObject(find.byKey(key)); } -TestImage getTestImage(WidgetTester tester, Key key) { - return tester.renderObject(find.byKey(key)).image as TestImage; -} Future pumpTreeToLayout(WidgetTester tester, Widget widget) { const Duration pumpDuration = Duration(milliseconds: 0); @@ -193,88 +174,96 @@ Future pumpTreeToLayout(WidgetTester tester, Widget widget) { void main() { const String image = 'assets/image.png'; + final Map images = {}; + setUpAll(() async { + for (final double scale in const [0.5, 1.0, 1.5, 2.0, 4.0, 10.0]) { + final int dimension = (48 * scale).floor(); + images[scale] = await createTestImage(width: dimension, height: dimension); + } + }); + testWidgets('Image for device pixel ratio 1.0', (WidgetTester tester) async { const double ratio = 1.0; Key key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); - expect(getTestImage(tester, key).scale, 1.0); + expect(getRenderImage(tester, key).scale, 1.0); key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); - expect(getTestImage(tester, key).scale, 1.0); + expect(getRenderImage(tester, key).scale, 1.0); }); testWidgets('Image for device pixel ratio 0.5', (WidgetTester tester) async { const double ratio = 0.5; Key key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); - expect(getTestImage(tester, key).scale, 1.0); + expect(getRenderImage(tester, key).scale, 1.0); key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); - expect(getTestImage(tester, key).scale, 1.0); + expect(getRenderImage(tester, key).scale, 1.0); }); testWidgets('Image for device pixel ratio 1.5', (WidgetTester tester) async { const double ratio = 1.5; Key key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); - expect(getTestImage(tester, key).scale, 1.5); + expect(getRenderImage(tester, key).scale, 1.5); key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); - expect(getTestImage(tester, key).scale, 1.5); + expect(getRenderImage(tester, key).scale, 1.5); }); testWidgets('Image for device pixel ratio 1.75', (WidgetTester tester) async { const double ratio = 1.75; Key key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); - expect(getTestImage(tester, key).scale, 1.5); + expect(getRenderImage(tester, key).scale, 1.5); key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); - expect(getTestImage(tester, key).scale, 1.5); + expect(getRenderImage(tester, key).scale, 1.5); }); testWidgets('Image for device pixel ratio 2.3', (WidgetTester tester) async { const double ratio = 2.3; Key key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); - expect(getTestImage(tester, key).scale, 2.0); + expect(getRenderImage(tester, key).scale, 2.0); key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); - expect(getTestImage(tester, key).scale, 2.0); + expect(getRenderImage(tester, key).scale, 2.0); }); testWidgets('Image for device pixel ratio 3.7', (WidgetTester tester) async { const double ratio = 3.7; Key key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); - expect(getTestImage(tester, key).scale, 4.0); + expect(getRenderImage(tester, key).scale, 4.0); key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); - expect(getTestImage(tester, key).scale, 4.0); + expect(getRenderImage(tester, key).scale, 4.0); }); testWidgets('Image for device pixel ratio 5.1', (WidgetTester tester) async { const double ratio = 5.1; Key key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); - expect(getTestImage(tester, key).scale, 4.0); + expect(getRenderImage(tester, key).scale, 4.0); key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); - expect(getTestImage(tester, key).scale, 4.0); + expect(getRenderImage(tester, key).scale, 4.0); }); testWidgets('Image for device pixel ratio 1.0, with no main asset', (WidgetTester tester) async { @@ -292,13 +281,13 @@ void main() { const double ratio = 1.0; Key key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, bundle)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images, bundle)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); - expect(getTestImage(tester, key).scale, 1.5); + expect(getRenderImage(tester, key).scale, 1.5); key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, bundle)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images, bundle)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); - expect(getTestImage(tester, key).scale, 1.5); + expect(getRenderImage(tester, key).scale, 1.5); }); testWidgets('Image for device pixel ratio 1.0, with a main asset and a 1.0x asset', (WidgetTester tester) async { @@ -321,13 +310,15 @@ void main() { const double ratio = 1.0; Key key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, bundle)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images, bundle)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); - expect(getTestImage(tester, key).scale, 10.0); + // Verify we got the 10x scaled image, since the TestByteData said it should be 10x. + expect(getRenderImage(tester, key).image.height, 480); key = GlobalKey(); - await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, bundle)); + await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images, bundle)); expect(getRenderImage(tester, key).size, const Size(480.0, 480.0)); - expect(getTestImage(tester, key).scale, 10.0); + // Verify we got the 10x scaled image, since the TestByteData said it should be 10x. + expect(getRenderImage(tester, key).image.height, 480); }); testWidgets('Image cache resize upscale display 5', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/image_rtl_test.dart b/packages/flutter/test/widgets/image_rtl_test.dart index 584cb03cc3..f96593be3c 100644 --- a/packages/flutter/test/widgets/image_rtl_test.dart +++ b/packages/flutter/test/widgets/image_rtl_test.dart @@ -4,8 +4,7 @@ // @dart = 2.8 -import 'dart:typed_data'; -import 'dart:ui' as ui show Image, ImageByteFormat; +import 'dart:ui' as ui show Image; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; @@ -14,6 +13,10 @@ import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; class TestImageProvider extends ImageProvider { + const TestImageProvider(this.image); + + final ui.Image image; + @override Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); @@ -22,28 +25,16 @@ class TestImageProvider extends ImageProvider { @override ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { return OneFrameImageStreamCompleter( - SynchronousFuture(ImageInfo(image: TestImage())) + SynchronousFuture(ImageInfo(image: image)), ); } } -class TestImage implements ui.Image { - @override - int get width => 16; - - @override - int get height => 9; - - @override - void dispose() { } - - @override - Future toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) async { - throw UnsupportedError('Cannot encode test image'); - } -} - void main() { + ui.Image testImage; + setUpAll(() async { + testImage = await createTestImage(width: 16, height: 9); + }); testWidgets('DecorationImage RTL with alignment topEnd and match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( @@ -54,7 +45,7 @@ void main() { height: 50.0, decoration: BoxDecoration( image: DecorationImage( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: AlignmentDirectional.topEnd, repeat: ImageRepeat.repeatX, matchTextDirection: true, @@ -93,7 +84,7 @@ void main() { height: 50.0, decoration: BoxDecoration( image: DecorationImage( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: AlignmentDirectional.topEnd, repeat: ImageRepeat.repeatX, matchTextDirection: true, @@ -129,7 +120,7 @@ void main() { height: 50.0, decoration: BoxDecoration( image: DecorationImage( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: AlignmentDirectional.topEnd, repeat: ImageRepeat.repeatX, ), @@ -164,7 +155,7 @@ void main() { height: 50.0, decoration: BoxDecoration( image: DecorationImage( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: AlignmentDirectional.topEnd, repeat: ImageRepeat.repeatX, ), @@ -199,7 +190,7 @@ void main() { height: 50.0, decoration: BoxDecoration( image: DecorationImage( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, matchTextDirection: true, ), @@ -231,7 +222,7 @@ void main() { height: 50.0, decoration: BoxDecoration( image: DecorationImage( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, ), ), @@ -258,7 +249,7 @@ void main() { height: 50.0, decoration: BoxDecoration( image: DecorationImage( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, matchTextDirection: true, ), @@ -286,7 +277,7 @@ void main() { height: 50.0, decoration: BoxDecoration( image: DecorationImage( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, matchTextDirection: true, ), @@ -313,7 +304,7 @@ void main() { width: 100.0, height: 50.0, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: AlignmentDirectional.topEnd, repeat: ImageRepeat.repeatX, matchTextDirection: true, @@ -350,7 +341,7 @@ void main() { width: 100.0, height: 50.0, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: AlignmentDirectional.topEnd, repeat: ImageRepeat.repeatX, matchTextDirection: true, @@ -384,7 +375,7 @@ void main() { width: 100.0, height: 50.0, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: AlignmentDirectional.topEnd, repeat: ImageRepeat.repeatX, ), @@ -417,7 +408,7 @@ void main() { width: 100.0, height: 50.0, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: AlignmentDirectional.topEnd, repeat: ImageRepeat.repeatX, ), @@ -450,15 +441,13 @@ void main() { width: 100.0, height: 50.0, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, matchTextDirection: true, ), ), ), ), - Duration.zero, - EnginePhase.layout, // so that we don't try to paint the fake images ); expect(find.byType(Container), paints ..translate(x: 50.0, y: 0.0) @@ -480,7 +469,7 @@ void main() { width: 100.0, height: 50.0, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, ), ), @@ -505,7 +494,7 @@ void main() { width: 100.0, height: 50.0, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, matchTextDirection: true, ), @@ -531,7 +520,7 @@ void main() { width: 100.0, height: 50.0, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, matchTextDirection: true, ), @@ -553,7 +542,7 @@ void main() { Directionality( textDirection: TextDirection.ltr, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, matchTextDirection: false, ), @@ -565,7 +554,7 @@ void main() { Directionality( textDirection: TextDirection.ltr, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: AlignmentDirectional.centerEnd, matchTextDirection: true, ), @@ -577,7 +566,7 @@ void main() { Directionality( textDirection: TextDirection.ltr, child: Image( - image: TestImageProvider(), + image: TestImageProvider(testImage), alignment: Alignment.centerRight, matchTextDirection: false, ), diff --git a/packages/flutter/test/widgets/image_test.dart b/packages/flutter/test/widgets/image_test.dart index 67595a45dd..6922b67a6a 100644 --- a/packages/flutter/test/widgets/image_test.dart +++ b/packages/flutter/test/widgets/image_test.dart @@ -15,24 +15,18 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../painting/image_data.dart'; +import '../image_data.dart'; import 'semantics_tester.dart'; -// This must be run with [WidgetTester.runAsync] since it performs real async -// work. -Future createTestImage([List bytes = kTransparentImage]) async { - final ui.Codec codec = await ui.instantiateImageCodec(Uint8List.fromList(bytes)); - final ui.FrameInfo frameInfo = await codec.getNextFrame(); - return frameInfo.image; -} - void main() { int originalCacheSize; + ui.Image image10x10; - setUp(() { + setUp(() async { originalCacheSize = imageCache.maximumSize; imageCache.clear(); imageCache.clearLiveImages(); + image10x10 = await createTestImage(width: 10, height: 10); }); tearDown(() { @@ -56,7 +50,7 @@ void main() { RenderImage renderImage = key.currentContext.findRenderObject() as RenderImage; expect(renderImage.image, isNull); - imageProvider1.complete(); + imageProvider1.complete(image10x10); await tester.idle(); // resolve the future from the image provider await tester.pump(null, EnginePhase.layout); @@ -98,7 +92,7 @@ void main() { RenderImage renderImage = key.currentContext.findRenderObject() as RenderImage; expect(renderImage.image, isNull); - imageProvider1.complete(); + imageProvider1.complete(image10x10); await tester.idle(); // resolve the future from the image provider await tester.pump(null, EnginePhase.layout); @@ -138,7 +132,7 @@ void main() { RenderImage renderImage = key.currentContext.findRenderObject() as RenderImage; expect(renderImage.image, isNull); - imageProvider1.complete(); + imageProvider1.complete(image10x10); await tester.idle(); // resolve the future from the image provider await tester.pump(null, EnginePhase.layout); @@ -176,7 +170,7 @@ void main() { RenderImage renderImage = key.currentContext.findRenderObject() as RenderImage; expect(renderImage.image, isNull); - imageProvider1.complete(); + imageProvider1.complete(image10x10); await tester.idle(); // resolve the future from the image provider await tester.pump(null, EnginePhase.layout); @@ -466,15 +460,19 @@ void main() { }); testWidgets('Verify Image stops listening to ImageStream', (WidgetTester tester) async { + final ui.Image image100x100 = await tester.runAsync(() async => createTestImage(width: 100, height: 100)); + // Web does not override the toString, whereas VM does + final String imageString = image100x100.toString(); + final TestImageProvider imageProvider = TestImageProvider(); await tester.pumpWidget(Image(image: imageProvider, excludeFromSemantics: true)); final State image = tester.state/*State*/(find.byType(Image)); expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, unresolved, 2 listeners), pixels: null, loadingProgress: null, frameNumber: null, wasSynchronouslyLoaded: false)')); - imageProvider.complete(); + imageProvider.complete(image100x100); await tester.pump(); - expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, [100×100] @ 1.0x, 1 listener), pixels: [100×100] @ 1.0x, loadingProgress: null, frameNumber: 0, wasSynchronouslyLoaded: false)')); + expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, $imageString @ 1.0x, 1 listener), pixels: $imageString @ 1.0x, loadingProgress: null, frameNumber: 0, wasSynchronouslyLoaded: false)')); await tester.pumpWidget(Container()); - expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(lifecycle state: defunct, not mounted, stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, [100×100] @ 1.0x, 0 listeners), pixels: [100×100] @ 1.0x, loadingProgress: null, frameNumber: 0, wasSynchronouslyLoaded: false)')); + expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(lifecycle state: defunct, not mounted, stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, $imageString @ 1.0x, 0 listeners), pixels: $imageString @ 1.0x, loadingProgress: null, frameNumber: 0, wasSynchronouslyLoaded: false)')); }); testWidgets('Stream completer errors can be listened to by attaching before resolving', (WidgetTester tester) async { @@ -768,7 +766,7 @@ void main() { } ) ); - provider.complete(); + provider.complete(image10x10); await precache; expect(provider._lastResolvedConfiguration, isNotNull); @@ -862,6 +860,7 @@ void main() { final TestImageProvider imageProvider1 = TestImageProvider(); final TestImageProvider imageProvider2 = TestImageProvider(); + final ui.Image image100x100 = await tester.runAsync(() async => createTestImage(width: 100, height: 100)); await tester.pumpWidget( Container( @@ -877,8 +876,8 @@ void main() { RenderImage renderImage = key.currentContext.findRenderObject() as RenderImage; expect(renderImage.image, isNull); - imageProvider1.complete(); - imageProvider2.complete(); + imageProvider1.complete(image10x10); + imageProvider2.complete(image100x100); await tester.idle(); // resolve the future from the image provider await tester.pump(null, EnginePhase.layout); @@ -905,8 +904,8 @@ void main() { }); testWidgets('Image State can be reconfigured to use another image', (WidgetTester tester) async { - final Image image1 = Image(image: TestImageProvider()..complete(), width: 10.0, excludeFromSemantics: true); - final Image image2 = Image(image: TestImageProvider()..complete(), width: 20.0, excludeFromSemantics: true); + final Image image1 = Image(image: TestImageProvider()..complete(image10x10), width: 10.0, excludeFromSemantics: true); + final Image image2 = Image(image: TestImageProvider()..complete(image10x10), width: 20.0, excludeFromSemantics: true); final Column column = Column(children: [image1, image2]); await tester.pumpWidget(column, null, EnginePhase.layout); @@ -1014,7 +1013,6 @@ void main() { }); testWidgets('Image invokes frameBuilder with correct wasSynchronouslyLoaded=false', (WidgetTester tester) async { - final ui.Image image = await tester.runAsync(createTestImage); final TestImageStreamCompleter streamCompleter = TestImageStreamCompleter(); final TestImageProvider imageProvider = TestImageProvider(streamCompleter: streamCompleter); int lastFrame; @@ -1034,15 +1032,14 @@ void main() { expect(lastFrame, isNull); expect(lastFrameWasSync, isFalse); expect(find.byType(RawImage), findsOneWidget); - streamCompleter.setData(imageInfo: ImageInfo(image: image)); + streamCompleter.setData(imageInfo: ImageInfo(image: image10x10)); await tester.pump(); expect(lastFrame, 0); expect(lastFrameWasSync, isFalse); }); testWidgets('Image invokes frameBuilder with correct wasSynchronouslyLoaded=true', (WidgetTester tester) async { - final ui.Image image = await tester.runAsync(createTestImage); - final TestImageStreamCompleter streamCompleter = TestImageStreamCompleter(ImageInfo(image: image)); + final TestImageStreamCompleter streamCompleter = TestImageStreamCompleter(ImageInfo(image: image10x10)); final TestImageProvider imageProvider = TestImageProvider(streamCompleter: streamCompleter); int lastFrame; bool lastFrameWasSync; @@ -1061,7 +1058,7 @@ void main() { expect(lastFrame, 0); expect(lastFrameWasSync, isTrue); expect(find.byType(RawImage), findsOneWidget); - streamCompleter.setData(imageInfo: ImageInfo(image: image)); + streamCompleter.setData(imageInfo: ImageInfo(image: image10x10)); await tester.pump(); expect(lastFrame, 1); expect(lastFrameWasSync, isTrue); @@ -1173,7 +1170,6 @@ void main() { }); testWidgets('Image invokes loadingBuilder on chunk event notification', (WidgetTester tester) async { - final ui.Image image = await tester.runAsync(createTestImage); final TestImageStreamCompleter streamCompleter = TestImageStreamCompleter(); final TestImageProvider imageProvider = TestImageProvider(streamCompleter: streamCompleter); final List chunkEvents = []; @@ -1208,7 +1204,7 @@ void main() { expect(chunkEvents.length, 3); expect(find.text('loading 30 / 100'), findsOneWidget); expect(find.byType(RawImage), findsNothing); - streamCompleter.setData(imageInfo: ImageInfo(image: image)); + streamCompleter.setData(imageInfo: ImageInfo(image: image10x10)); await tester.pump(); expect(chunkEvents.length, 4); expect(find.byType(Text), findsNothing); @@ -1216,7 +1212,6 @@ void main() { }); testWidgets("Image doesn't rebuild on chunk events if loadingBuilder is null", (WidgetTester tester) async { - final ui.Image image = await tester.runAsync(createTestImage); final TestImageStreamCompleter streamCompleter = TestImageStreamCompleter(); final TestImageProvider imageProvider = TestImageProvider(streamCompleter: streamCompleter); @@ -1230,7 +1225,7 @@ void main() { expect(tester.binding.hasScheduledFrame, isFalse); streamCompleter.setData(chunkEvent: const ImageChunkEvent(cumulativeBytesLoaded: 10, expectedTotalBytes: 100)); expect(tester.binding.hasScheduledFrame, isFalse); - streamCompleter.setData(imageInfo: ImageInfo(image: image)); + streamCompleter.setData(imageInfo: ImageInfo(image: image10x10)); expect(tester.binding.hasScheduledFrame, isTrue); await tester.pump(); streamCompleter.setData(chunkEvent: const ImageChunkEvent(cumulativeBytesLoaded: 10, expectedTotalBytes: 100)); @@ -1451,7 +1446,6 @@ void main() { testWidgets('Same image provider in multiple parts of the tree, no cache room left', (WidgetTester tester) async { imageCache.maximumSize = 0; - final ui.Image image = await tester.runAsync(createTestImage); final TestImageProvider provider1 = TestImageProvider(); final TestImageProvider provider2 = TestImageProvider(); @@ -1480,10 +1474,10 @@ void main() { expect(provider1.loadCallCount, 1); expect(provider2.loadCallCount, 1); - provider1.complete(image); + provider1.complete(image10x10); await tester.idle(); - provider2.complete(image); + provider2.complete(image10x10); await tester.idle(); expect(imageCache.liveImageCount, 2); @@ -1516,7 +1510,7 @@ void main() { } ) ); - provider.complete(); + provider.complete(image10x10); await precache; // Should have ended up with only a weak ref, not in cache because cache size is 0 @@ -1566,7 +1560,7 @@ void main() { } ) ); - provider.complete(); + provider.complete(image10x10); await precache; // Should have ended up in the cache and have a weak reference. @@ -1644,7 +1638,7 @@ void main() { Object caughtException; await tester.pumpWidget( Image( - image: const FailingImageProvider(failOnObtainKey: true, throws: 'threw'), + image: FailingImageProvider(failOnObtainKey: true, throws: 'threw', image: image10x10), errorBuilder: (BuildContext context, Object error, StackTrace stackTrace) { caughtException = error; return SizedBox.expand(key: errorKey); @@ -1664,7 +1658,7 @@ void main() { Object caughtException; await tester.pumpWidget( Image( - image: const FailingImageProvider(failOnLoad: true, throws: 'threw'), + image: FailingImageProvider(failOnLoad: true, throws: 'threw', image: image10x10), errorBuilder: (BuildContext context, Object error, StackTrace stackTrace) { caughtException = error; return SizedBox.expand(key: errorKey); @@ -1681,8 +1675,8 @@ void main() { testWidgets('no errorBuilder - failure reported to FlutterError', (WidgetTester tester) async { await tester.pumpWidget( - const Image( - image: FailingImageProvider(failOnLoad: true, throws: 'threw'), + Image( + image: FailingImageProvider(failOnLoad: true, throws: 'threw', image: image10x10), ), ); @@ -1736,7 +1730,7 @@ void main() { imageSizeInfo = info; }; - final ui.Image image = await tester.runAsync(() => createTestImage(kBlueRectPng)); + final ui.Image image = await tester.runAsync(() => createTestImage(width: 100, height: 100)); final TestImageStreamCompleter streamCompleter = TestImageStreamCompleter( ImageInfo( image: image, @@ -1847,8 +1841,7 @@ class TestImageProvider extends ImageProvider { return _streamCompleter; } - void complete([ui.Image image]) { - image ??= TestImage(); + void complete(ui.Image image) { _completer.complete(ImageInfo(image: image)); } @@ -1898,25 +1891,6 @@ class TestImageStreamCompleter extends ImageStreamCompleter { } } -class TestImage implements ui.Image { - @override - int get width => 100; - - @override - int get height => 100; - - @override - void dispose() { } - - @override - Future toByteData({ ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba }) async { - throw UnsupportedError('Cannot encode test image'); - } - - @override - String toString() => '[$width\u00D7$height]'; -} - class DebouncingImageProvider extends ImageProvider { DebouncingImageProvider(this.imageProvider, this.seenKeys); @@ -1949,14 +1923,17 @@ class FailingImageProvider extends ImageProvider { this.failOnObtainKey = false, this.failOnLoad = false, @required this.throws, + @required this.image, }) : assert(failOnLoad != null), assert(failOnObtainKey != null), assert(failOnLoad == true || failOnObtainKey == true), - assert(throws != null); + assert(throws != null), + assert(image != null); final bool failOnObtainKey; final bool failOnLoad; final Object throws; + final ui.Image image; @override Future obtainKey(ImageConfiguration configuration) { @@ -1974,7 +1951,7 @@ class FailingImageProvider extends ImageProvider { return OneFrameImageStreamCompleter( Future.value( ImageInfo( - image: TestImage(), + image: image, scale: 0, ), ), diff --git a/packages/flutter/test/widgets/obscured_animated_image_test.dart b/packages/flutter/test/widgets/obscured_animated_image_test.dart index 1a50c9921b..92629bec3a 100644 --- a/packages/flutter/test/widgets/obscured_animated_image_test.dart +++ b/packages/flutter/test/widgets/obscured_animated_image_test.dart @@ -11,9 +11,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../image_data.dart'; import '../painting/fake_codec.dart'; import '../painting/fake_image_provider.dart'; -import '../painting/image_data.dart'; Future main() async { final FakeCodec fakeCodec = await FakeCodec.fromData(Uint8List.fromList(kAnimatedGif)); diff --git a/packages/flutter/test/widgets/scroll_aware_image_provider_test.dart b/packages/flutter/test/widgets/scroll_aware_image_provider_test.dart index a68e50c4cc..47aedaf905 100644 --- a/packages/flutter/test/widgets/scroll_aware_image_provider_test.dart +++ b/packages/flutter/test/widgets/scroll_aware_image_provider_test.dart @@ -4,13 +4,21 @@ // @dart = 2.8 +import 'dart:ui' as ui show Image; + import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/widgets.dart'; import '../painting/image_test_utils.dart'; -import '../painting/mocks_for_image_cache.dart' show TestImage; void main() { + + ui.Image testImage; + + setUpAll(() async { + testImage = await createTestImage(width: 10, height: 10); + }); + tearDown(() { imageCache.clear(); }); @@ -28,7 +36,6 @@ void main() { await tester.pumpWidget(TestWidget(key)); final DisposableBuildContext context = DisposableBuildContext(key.currentState); - const TestImage testImage = TestImage(width: 10, height: 10); final TestImageProvider testImageProvider = TestImageProvider(testImage); final ScrollAwareImageProvider imageProvider = ScrollAwareImageProvider( context: context, @@ -64,7 +71,6 @@ void main() { )); final DisposableBuildContext context = DisposableBuildContext(key.currentState); - const TestImage testImage = TestImage(width: 10, height: 10); final TestImageProvider testImageProvider = TestImageProvider(testImage); final ScrollAwareImageProvider imageProvider = ScrollAwareImageProvider( context: context, @@ -105,7 +111,6 @@ void main() { )); final DisposableBuildContext context = DisposableBuildContext(keys.last.currentState); - const TestImage testImage = TestImage(width: 10, height: 10); final TestImageProvider testImageProvider = TestImageProvider(testImage); final ScrollAwareImageProvider imageProvider = ScrollAwareImageProvider( context: context, @@ -163,7 +168,6 @@ void main() { )); final DisposableBuildContext context = DisposableBuildContext(keys.last.currentState); - const TestImage testImage = TestImage(width: 10, height: 10); final TestImageProvider testImageProvider = TestImageProvider(testImage); final ScrollAwareImageProvider imageProvider = ScrollAwareImageProvider( context: context, @@ -231,7 +235,6 @@ void main() { )); final DisposableBuildContext context = DisposableBuildContext(keys.last.currentState); - const TestImage testImage = TestImage(width: 10, height: 10); final TestImageProvider testImageProvider = TestImageProvider(testImage); final ScrollAwareImageProvider imageProvider = ScrollAwareImageProvider( context: context, @@ -297,7 +300,6 @@ void main() { )); final DisposableBuildContext context = DisposableBuildContext(key.currentState); - const TestImage testImage = TestImage(width: 10, height: 10); final TestImageProvider testImageProvider = TestImageProvider(testImage); final ScrollAwareImageProvider imageProvider = ScrollAwareImageProvider( context: context, @@ -349,7 +351,6 @@ void main() { )); final DisposableBuildContext context = DisposableBuildContext(key.currentState); - const TestImage testImage = TestImage(width: 10, height: 10); final TestImageProvider testImageProvider = TestImageProvider(testImage); final ScrollAwareImageProvider imageProvider = ScrollAwareImageProvider( context: context, @@ -369,7 +370,7 @@ void main() { expect(imageCache.currentSize, 0); // Occupy the only slot in the cache with another image. - final TestImageProvider testImageProvider2 = TestImageProvider(const TestImage()); + final TestImageProvider testImageProvider2 = TestImageProvider(testImage); testImageProvider2.complete(); await precacheImage(testImageProvider2, context.context); expect(imageCache.containsKey(testImageProvider), false); diff --git a/packages/flutter/test/widgets/shape_decoration_test.dart b/packages/flutter/test/widgets/shape_decoration_test.dart index de5662d420..525259080b 100644 --- a/packages/flutter/test/widgets/shape_decoration_test.dart +++ b/packages/flutter/test/widgets/shape_decoration_test.dart @@ -10,7 +10,7 @@ import 'dart:ui' as ui show Image; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../painting/image_data.dart'; +import '../image_data.dart'; import '../painting/mocks_for_image_cache.dart'; import '../rendering/mock_canvas.dart'; import 'test_border.dart' show TestBorder; diff --git a/packages/flutter_test/lib/flutter_test.dart b/packages/flutter_test/lib/flutter_test.dart index c6b05e7b1c..ad6076bb23 100644 --- a/packages/flutter_test/lib/flutter_test.dart +++ b/packages/flutter_test/lib/flutter_test.dart @@ -56,6 +56,7 @@ export 'src/event_simulation.dart'; export 'src/finders.dart'; export 'src/frame_timing_summarizer.dart'; export 'src/goldens.dart'; +export 'src/image.dart'; export 'src/matchers.dart'; export 'src/nonconst.dart'; export 'src/platform.dart'; diff --git a/packages/flutter_test/lib/src/image.dart b/packages/flutter_test/lib/src/image.dart new file mode 100644 index 0000000000..04f73064d0 --- /dev/null +++ b/packages/flutter_test/lib/src/image.dart @@ -0,0 +1,119 @@ +// 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 'test_async_utils.dart'; + +final Map _cache = {}; + +/// Creates an arbitrarily sized image for testing. +/// +/// If the [cache] parameter is set to true, the image will be cached for the +/// rest of this suite. This is normally desirable, assuming a test suite uses +/// images with the same dimensions in most tests, as it will save on memory +/// usage and CPU time over the course of the suite. However, it should be +/// avoided for images that are used only once in a test suite, especially if +/// the image is large, as it will require holding on to the memory for that +/// image for the duration of the suite. +/// +/// This method requires real async work, and will not work properly in the +/// [FakeAsync] zones set up by [testWidgets]. Typically, it should be invoked +/// as a setup step before [testWidgets] are run, such as [setUp] or [setUpAll]. +/// If needed, it can be invoked using [WidgetTester.runAsync]. +Future createTestImage({ + int width = 1, + int height = 1, + bool cache = true, +}) => TestAsyncUtils.guard(() async { + assert(width != null && width > 0); + assert(height != null && height > 0); + assert(cache != null); + + final int cacheKey = hashValues(width, height); + if (cache && _cache.containsKey(cacheKey)) { + return _cache[cacheKey]; + } + + final ui.Image image = await _createImage(width, height); + if (cache) { + _cache[cacheKey] = image; + } + return image; +}); + +Future _createImage(int width, int height) async { + if (kIsWeb) { + return await _webCreateTestImage( + width: width, + height: height, + ); + } + + final Completer completer = Completer(); + ui.decodeImageFromPixels( + Uint8List.fromList(List.filled(width * height * 4, 0, growable: false)), + width, + height, + ui.PixelFormat.rgba8888, + (ui.Image image) { + completer.complete(image); + }, + ); + return await completer.future; +} + +/// Web doesn't support [decodeImageFromPixels]. Instead, generate a 1bpp BMP +/// and just use [instantiateImageCodec]. +// TODO(dnfield): Remove this when https://github.com/flutter/flutter/issues/49244 +// is resolved. +Future _webCreateTestImage({ + int width, + int height, +}) async { + // See https://en.wikipedia.org/wiki/BMP_file_format for format examples. + final int bufferSize = 0x36 + (width * height); + final ByteData bmpData = ByteData(bufferSize); + // 'BM' header + bmpData.setUint8(0x00, 0x42); + bmpData.setUint8(0x01, 0x4D); + // Size of data + bmpData.setUint32(0x02, bufferSize, Endian.little); + // Offset where pixel array begins + bmpData.setUint32(0x0A, 0x36, Endian.little); + // Bytes in DIB header + bmpData.setUint32(0x0E, 0x28, Endian.little); + // width + bmpData.setUint32(0x12, width, Endian.little); + // height + bmpData.setUint32(0x16, height, Endian.little); + // Color panes + bmpData.setUint16(0x1A, 0x01, Endian.little); + // bpp + bmpData.setUint16(0x1C, 0x01, Endian.little); + // no compression + bmpData.setUint32(0x1E, 0x00, Endian.little); + // raw bitmap data size + bmpData.setUint32(0x22, width * height, Endian.little); + // print DPI width + bmpData.setUint32(0x26, width, Endian.little); + // print DPI height + bmpData.setUint32(0x2A, height, Endian.little); + // colors in the palette + bmpData.setUint32(0x2E, 0x00, Endian.little); + // important colors + bmpData.setUint32(0x32, 0x00, Endian.little); + // rest of data is zeroed as black pixels. + + final ui.Codec codec = await ui.instantiateImageCodec( + bmpData.buffer.asUint8List(), + ); + final ui.FrameInfo frameInfo = await codec.getNextFrame(); + return frameInfo.image; +}