// 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 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'mock_canvas.dart'; class MyPainter extends CustomPainter { const MyPainter({ required this.color, }); final Color color; @override void paint(Canvas canvas, Size size) { canvas.drawColor(color, BlendMode.color); } @override bool shouldRepaint(MyPainter oldDelegate) { return true; } } @immutable class MethodAndArguments { const MethodAndArguments(this.method, this.arguments); final Symbol method; final List<dynamic> arguments; @override bool operator ==(Object other) { if (!(other is MethodAndArguments && other.method == method)) { return false; } for (int i = 0; i < arguments.length; i++) { if (arguments[i] != other.arguments[i]) { return false; } } return true; } @override int get hashCode => method.hashCode; @override String toString() => '$method, $arguments'; } void main() { group('something', () { testWidgets('matches when the predicate returns true', (WidgetTester tester) async { await tester.pumpWidget( const CustomPaint( painter: MyPainter(color: Colors.transparent), child: SizedBox(width: 50, height: 50), ), ); final List<MethodAndArguments> methodsAndArguments = <MethodAndArguments>[]; expect( tester.renderObject(find.byType(CustomPaint)), paints..something((Symbol method, List<dynamic> arguments) { methodsAndArguments.add(MethodAndArguments(method, arguments)); return method == #drawColor; }), ); expect( methodsAndArguments, <MethodAndArguments>[ const MethodAndArguments(#save, <dynamic>[]), const MethodAndArguments(#drawColor, <dynamic>[Colors.transparent, BlendMode.color]), // The #restore call is never evaluated ], ); }); testWidgets('fails when the predicate always returns false', (WidgetTester tester) async { await tester.pumpWidget( const CustomPaint( painter: MyPainter(color: Colors.transparent), child: SizedBox(width: 50, height: 50), ), ); final List<MethodAndArguments> methodsAndArguments = <MethodAndArguments>[]; expect( tester.renderObject(find.byType(CustomPaint)), isNot( paints..something((Symbol method, List<dynamic> arguments) { methodsAndArguments.add(MethodAndArguments(method, arguments)); return false; }), ), ); expect( methodsAndArguments, <MethodAndArguments>[ const MethodAndArguments(#save, <dynamic>[]), const MethodAndArguments(#drawColor, <dynamic>[Colors.transparent, BlendMode.color]), const MethodAndArguments(#restore, <dynamic>[]), ], ); }); testWidgets('fails when the predicate throws', (WidgetTester tester) async { await tester.pumpWidget( const CustomPaint( painter: MyPainter(color: Colors.transparent), child: SizedBox(width: 50, height: 50), ), ); final List<MethodAndArguments> methodsAndArguments = <MethodAndArguments>[]; expect( tester.renderObject(find.byType(CustomPaint)), isNot( paints..something((Symbol method, List<dynamic> arguments) { methodsAndArguments.add(MethodAndArguments(method, arguments)); if (method == #save) { return false; } if (method == #drawColor) { throw 'fail'; } return true; }), ), ); expect( methodsAndArguments, <MethodAndArguments>[ const MethodAndArguments(#save, <dynamic>[]), const MethodAndArguments(#drawColor, <dynamic>[Colors.transparent, BlendMode.color]), // The #restore call is never evaluated ], ); }); }); group('everything', () { testWidgets('matches when the predicate always returns true', (WidgetTester tester) async { await tester.pumpWidget( const CustomPaint( painter: MyPainter(color: Colors.transparent), child: SizedBox(width: 50, height: 50), ), ); final List<MethodAndArguments> methodsAndArguments = <MethodAndArguments>[]; expect( tester.renderObject(find.byType(CustomPaint)), paints..everything((Symbol method, List<dynamic> arguments) { methodsAndArguments.add(MethodAndArguments(method, arguments)); return true; }), ); expect( methodsAndArguments, <MethodAndArguments>[ const MethodAndArguments(#save, <dynamic>[]), const MethodAndArguments(#drawColor, <dynamic>[Colors.transparent, BlendMode.color]), const MethodAndArguments(#restore, <dynamic>[]), ], ); }); testWidgets('fails when the predicate returns false', (WidgetTester tester) async { await tester.pumpWidget( const CustomPaint( painter: MyPainter(color: Colors.transparent), child: SizedBox(width: 50, height: 50), ), ); final List<MethodAndArguments> methodsAndArguments = <MethodAndArguments>[]; expect( tester.renderObject(find.byType(CustomPaint)), isNot( paints..everything((Symbol method, List<dynamic> arguments) { methodsAndArguments.add(MethodAndArguments(method, arguments)); // returns false on #drawColor return method == #restore || method == #save; }), ), ); expect( methodsAndArguments, <MethodAndArguments>[ const MethodAndArguments(#save, <dynamic>[]), const MethodAndArguments(#drawColor, <dynamic>[Colors.transparent, BlendMode.color]), // The #restore call is never evaluated ], ); }); testWidgets('fails if the predicate ever throws', (WidgetTester tester) async { await tester.pumpWidget( const CustomPaint( painter: MyPainter(color: Colors.transparent), child: SizedBox(width: 50, height: 50), ), ); final List<MethodAndArguments> methodsAndArguments = <MethodAndArguments>[]; expect( tester.renderObject(find.byType(CustomPaint)), isNot( paints..everything((Symbol method, List<dynamic> arguments) { methodsAndArguments.add(MethodAndArguments(method, arguments)); if (method == #drawColor) { throw 'failed '; } return true; }), ), ); expect( methodsAndArguments, <MethodAndArguments>[ const MethodAndArguments(#save, <dynamic>[]), const MethodAndArguments(#drawColor, <dynamic>[Colors.transparent, BlendMode.color]), // The #restore call is never evaluated ], ); }); }); }