// 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:ui' as ui; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Future<ui.Image> createTestImage(int width, int height, ui.Color color) async { final ui.Paint paint = ui.Paint() ..style = ui.PaintingStyle.stroke ..strokeWidth = 1.0 ..color = color; final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.Canvas pictureCanvas = ui.Canvas(recorder); pictureCanvas.drawCircle(Offset.zero, 20.0, paint); final ui.Picture picture = recorder.endRecording(); final ui.Image image = await picture.toImage(width, height); picture.dispose(); return image; } void main() { const ui.Color red = ui.Color.fromARGB(255, 255, 0, 0); const ui.Color green = ui.Color.fromARGB(255, 0, 255, 0); const ui.Color transparentRed = ui.Color.fromARGB(128, 255, 0, 0); group('succeeds', () { testWidgetsWithLeakTracking('when images have the same content', (WidgetTester tester) async { final ui.Image image1 = await createTestImage(100, 100, red); addTearDown(image1.dispose); final ui.Image referenceImage1 = await createTestImage(100, 100, red); addTearDown(referenceImage1.dispose); await expectLater(image1, matchesReferenceImage(referenceImage1)); final ui.Image image2 = await createTestImage(100, 100, green); addTearDown(image2.dispose); final ui.Image referenceImage2 = await createTestImage(100, 100, green); addTearDown(referenceImage2.dispose); await expectLater(image2, matchesReferenceImage(referenceImage2)); final ui.Image image3 = await createTestImage(100, 100, transparentRed); addTearDown(image3.dispose); final ui.Image referenceImage3 = await createTestImage(100, 100, transparentRed); addTearDown(referenceImage3.dispose); await expectLater(image3, matchesReferenceImage(referenceImage3)); }); testWidgetsWithLeakTracking('when images are identical', (WidgetTester tester) async { final ui.Image image = await createTestImage(100, 100, red); addTearDown(image.dispose); await expectLater(image, matchesReferenceImage(image)); }); testWidgetsWithLeakTracking('when widget looks the same', (WidgetTester tester) async { addTearDown(tester.view.reset); tester.view ..physicalSize = const Size(10, 10) ..devicePixelRatio = 1; const ValueKey<String> repaintBoundaryKey = ValueKey<String>('boundary'); await tester.pumpWidget( const RepaintBoundary( key: repaintBoundaryKey, child: ColoredBox(color: red), ), ); final ui.Image referenceImage = (tester.renderObject(find.byKey(repaintBoundaryKey)) as RenderRepaintBoundary).toImageSync(); addTearDown(referenceImage.dispose); await expectLater(find.byKey(repaintBoundaryKey), matchesReferenceImage(referenceImage)); }); }); group('fails', () { testWidgetsWithLeakTracking('when image sizes do not match', (WidgetTester tester) async { final ui.Image red50 = await createTestImage(50, 50, red); addTearDown(red50.dispose); final ui.Image red100 = await createTestImage(100, 100, red); addTearDown(red100.dispose); expect( await matchesReferenceImage(red50).matchAsync(red100), equals('does not match as width or height do not match. [100×100] != [50×50]'), ); }); testWidgetsWithLeakTracking('when image pixels do not match', (WidgetTester tester) async { final ui.Image red100 = await createTestImage(100, 100, red); addTearDown(red100.dispose); final ui.Image transparentRed100 = await createTestImage(100, 100, transparentRed); addTearDown(transparentRed100.dispose); expect( await matchesReferenceImage(red100).matchAsync(transparentRed100), equals('does not match on 57 pixels'), ); final ui.Image green100 = await createTestImage(100, 100, green); addTearDown(green100.dispose); expect( await matchesReferenceImage(red100).matchAsync(green100), equals('does not match on 57 pixels'), ); }); testWidgetsWithLeakTracking('when widget does not look the same', (WidgetTester tester) async { addTearDown(tester.view.reset); tester.view ..physicalSize = const Size(10, 10) ..devicePixelRatio = 1; const ValueKey<String> repaintBoundaryKey = ValueKey<String>('boundary'); await tester.pumpWidget( const RepaintBoundary( key: repaintBoundaryKey, child: ColoredBox(color: red), ), ); final ui.Image referenceImage = (tester.renderObject(find.byKey(repaintBoundaryKey)) as RenderRepaintBoundary).toImageSync(); addTearDown(referenceImage.dispose); await tester.pumpWidget( const RepaintBoundary( key: repaintBoundaryKey, child: ColoredBox(color: green), ), ); expect( await matchesReferenceImage(referenceImage).matchAsync( find.byKey(repaintBoundaryKey), ), equals('does not match on 100 pixels'), ); }); }); }