| // 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:math' as math; | |
| import 'package:flutter/widgets.dart'; | |
| import 'package:flutter_test/flutter_test.dart'; | |
| import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; | |
| class TestCanvas implements Canvas { | |
| final List<Invocation> invocations = <Invocation>[]; | |
| @override | |
| void noSuchMethod(Invocation invocation) { | |
| invocations.add(invocation); | |
| } | |
| } | |
| void main() { | |
| // the textDirection values below are intentionally sometimes different and | |
| // sometimes the same as the layoutDirection, to make sure that they don't | |
| // affect the layout. | |
| test('A Banner with a location of topStart paints in the top left (LTR)', () { | |
| final bannerPainter = BannerPainter( | |
| message: 'foo', | |
| textDirection: TextDirection.rtl, | |
| location: BannerLocation.topStart, | |
| layoutDirection: TextDirection.ltr, | |
| ); | |
| final canvas = TestCanvas(); | |
| bannerPainter.paint(canvas, const Size(1000.0, 1000.0)); | |
| final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #translate; | |
| }); | |
| expect(translateCommand, isNotNull); | |
| expect(translateCommand.positionalArguments[0], lessThan(100.0)); | |
| expect(translateCommand.positionalArguments[1], lessThan(100.0)); | |
| final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #rotate; | |
| }); | |
| expect(rotateCommand, isNotNull); | |
| expect(rotateCommand.positionalArguments[0], equals(-math.pi / 4.0)); | |
| }); | |
| test('A Banner with a location of topStart paints in the top right (RTL)', () { | |
| final bannerPainter = BannerPainter( | |
| message: 'foo', | |
| textDirection: TextDirection.ltr, | |
| location: BannerLocation.topStart, | |
| layoutDirection: TextDirection.rtl, | |
| ); | |
| final canvas = TestCanvas(); | |
| bannerPainter.paint(canvas, const Size(1000.0, 1000.0)); | |
| final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #translate; | |
| }); | |
| expect(translateCommand, isNotNull); | |
| expect(translateCommand.positionalArguments[0], greaterThan(900.0)); | |
| expect(translateCommand.positionalArguments[1], lessThan(100.0)); | |
| final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #rotate; | |
| }); | |
| expect(rotateCommand, isNotNull); | |
| expect(rotateCommand.positionalArguments[0], equals(math.pi / 4.0)); | |
| }); | |
| test('A Banner with a location of topEnd paints in the top right (LTR)', () { | |
| final bannerPainter = BannerPainter( | |
| message: 'foo', | |
| textDirection: TextDirection.ltr, | |
| location: BannerLocation.topEnd, | |
| layoutDirection: TextDirection.ltr, | |
| ); | |
| final canvas = TestCanvas(); | |
| bannerPainter.paint(canvas, const Size(1000.0, 1000.0)); | |
| final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #translate; | |
| }); | |
| expect(translateCommand, isNotNull); | |
| expect(translateCommand.positionalArguments[0], greaterThan(900.0)); | |
| expect(translateCommand.positionalArguments[1], lessThan(100.0)); | |
| final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #rotate; | |
| }); | |
| expect(rotateCommand, isNotNull); | |
| expect(rotateCommand.positionalArguments[0], equals(math.pi / 4.0)); | |
| }); | |
| test('A Banner with a location of topEnd paints in the top left (RTL)', () { | |
| final bannerPainter = BannerPainter( | |
| message: 'foo', | |
| textDirection: TextDirection.rtl, | |
| location: BannerLocation.topEnd, | |
| layoutDirection: TextDirection.rtl, | |
| ); | |
| final canvas = TestCanvas(); | |
| bannerPainter.paint(canvas, const Size(1000.0, 1000.0)); | |
| final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #translate; | |
| }); | |
| expect(translateCommand, isNotNull); | |
| expect(translateCommand.positionalArguments[0], lessThan(100.0)); | |
| expect(translateCommand.positionalArguments[1], lessThan(100.0)); | |
| final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #rotate; | |
| }); | |
| expect(rotateCommand, isNotNull); | |
| expect(rotateCommand.positionalArguments[0], equals(-math.pi / 4.0)); | |
| }); | |
| test('A Banner with a location of bottomStart paints in the bottom left (LTR)', () { | |
| final bannerPainter = BannerPainter( | |
| message: 'foo', | |
| textDirection: TextDirection.ltr, | |
| location: BannerLocation.bottomStart, | |
| layoutDirection: TextDirection.ltr, | |
| ); | |
| final canvas = TestCanvas(); | |
| bannerPainter.paint(canvas, const Size(1000.0, 1000.0)); | |
| final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #translate; | |
| }); | |
| expect(translateCommand, isNotNull); | |
| expect(translateCommand.positionalArguments[0], lessThan(100.0)); | |
| expect(translateCommand.positionalArguments[1], greaterThan(900.0)); | |
| final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #rotate; | |
| }); | |
| expect(rotateCommand, isNotNull); | |
| expect(rotateCommand.positionalArguments[0], equals(math.pi / 4.0)); | |
| }); | |
| test('A Banner with a location of bottomStart paints in the bottom right (RTL)', () { | |
| final bannerPainter = BannerPainter( | |
| message: 'foo', | |
| textDirection: TextDirection.rtl, | |
| location: BannerLocation.bottomStart, | |
| layoutDirection: TextDirection.rtl, | |
| ); | |
| final canvas = TestCanvas(); | |
| bannerPainter.paint(canvas, const Size(1000.0, 1000.0)); | |
| final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #translate; | |
| }); | |
| expect(translateCommand, isNotNull); | |
| expect(translateCommand.positionalArguments[0], greaterThan(900.0)); | |
| expect(translateCommand.positionalArguments[1], greaterThan(900.0)); | |
| final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #rotate; | |
| }); | |
| expect(rotateCommand, isNotNull); | |
| expect(rotateCommand.positionalArguments[0], equals(-math.pi / 4.0)); | |
| }); | |
| test('A Banner with a location of bottomEnd paints in the bottom right (LTR)', () { | |
| final bannerPainter = BannerPainter( | |
| message: 'foo', | |
| textDirection: TextDirection.rtl, | |
| location: BannerLocation.bottomEnd, | |
| layoutDirection: TextDirection.ltr, | |
| ); | |
| final canvas = TestCanvas(); | |
| bannerPainter.paint(canvas, const Size(1000.0, 1000.0)); | |
| final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #translate; | |
| }); | |
| expect(translateCommand, isNotNull); | |
| expect(translateCommand.positionalArguments[0], greaterThan(900.0)); | |
| expect(translateCommand.positionalArguments[1], greaterThan(900.0)); | |
| final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #rotate; | |
| }); | |
| expect(rotateCommand, isNotNull); | |
| expect(rotateCommand.positionalArguments[0], equals(-math.pi / 4.0)); | |
| }); | |
| test('A Banner with a location of bottomEnd paints in the bottom left (RTL)', () { | |
| final bannerPainter = BannerPainter( | |
| message: 'foo', | |
| textDirection: TextDirection.ltr, | |
| location: BannerLocation.bottomEnd, | |
| layoutDirection: TextDirection.rtl, | |
| ); | |
| final canvas = TestCanvas(); | |
| bannerPainter.paint(canvas, const Size(1000.0, 1000.0)); | |
| final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #translate; | |
| }); | |
| expect(translateCommand, isNotNull); | |
| expect(translateCommand.positionalArguments[0], lessThan(100.0)); | |
| expect(translateCommand.positionalArguments[1], greaterThan(900.0)); | |
| final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) { | |
| return invocation.memberName == #rotate; | |
| }); | |
| expect(rotateCommand, isNotNull); | |
| expect(rotateCommand.positionalArguments[0], equals(math.pi / 4.0)); | |
| }); | |
| testWidgets('Banner widget', (WidgetTester tester) async { | |
| debugDisableShadows = false; | |
| await tester.pumpWidget( | |
| const Directionality( | |
| textDirection: TextDirection.ltr, | |
| child: Banner(message: 'Hello', location: BannerLocation.topEnd), | |
| ), | |
| ); | |
| expect( | |
| find.byType(CustomPaint), | |
| paints | |
| ..save() | |
| ..translate(x: 800.0, y: 0.0) | |
| ..rotate(angle: math.pi / 4.0) | |
| ..rect( | |
| rect: const Rect.fromLTRB(-40.0, 28.0, 40.0, 40.0), | |
| color: const Color(0x7f000000), | |
| hasMaskFilter: true, | |
| ) | |
| ..rect( | |
| rect: const Rect.fromLTRB(-40.0, 28.0, 40.0, 40.0), | |
| color: const Color(0xa0b71c1c), | |
| hasMaskFilter: false, | |
| ) | |
| ..paragraph(offset: const Offset(-40.0, 29.0)) | |
| ..restore(), | |
| ); | |
| debugDisableShadows = true; | |
| }); | |
| testWidgets('Banner widget in WidgetsApp', (WidgetTester tester) async { | |
| debugDisableShadows = false; | |
| await tester.pumpWidget(const TestWidgetsApp(home: Placeholder())); | |
| expect( | |
| find.byType(CheckedModeBanner), | |
| paints | |
| ..save() | |
| ..translate(x: 800.0, y: 0.0) | |
| ..rotate(angle: math.pi / 4.0) | |
| ..rect( | |
| rect: const Rect.fromLTRB(-40.0, 28.0, 40.0, 40.0), | |
| color: const Color(0x7f000000), | |
| hasMaskFilter: true, | |
| ) | |
| ..rect( | |
| rect: const Rect.fromLTRB(-40.0, 28.0, 40.0, 40.0), | |
| color: const Color(0xa0b71c1c), | |
| hasMaskFilter: false, | |
| ) | |
| ..paragraph(offset: const Offset(-40.0, 29.0)) | |
| ..restore(), | |
| ); | |
| debugDisableShadows = true; | |
| }); | |
| test('BannerPainter dispatches memory events', () async { | |
| await expectLater( | |
| await memoryEvents( | |
| () => BannerPainter( | |
| message: 'foo', | |
| textDirection: TextDirection.rtl, | |
| location: BannerLocation.topStart, | |
| layoutDirection: TextDirection.ltr, | |
| ).dispose(), | |
| BannerPainter, | |
| ), | |
| areCreateAndDispose, | |
| ); | |
| }); | |
| testWidgets('Can configure shadow for Banner widget', (WidgetTester tester) async { | |
| debugDisableShadows = false; | |
| await tester.pumpWidget( | |
| const Directionality( | |
| textDirection: TextDirection.ltr, | |
| child: Banner( | |
| message: 'Shadow banner', | |
| location: BannerLocation.topEnd, | |
| shadow: BoxShadow(color: Color(0xFF008000), blurRadius: 8.0), | |
| ), | |
| ), | |
| ); | |
| final Finder customPaint = find.byType(CustomPaint); | |
| expect(customPaint, findsOneWidget); | |
| final CustomPaint paintWidget = tester.widget(customPaint); | |
| final painter = paintWidget.foregroundPainter! as BannerPainter; | |
| expect(painter.shadow.color, const Color(0xFF008000)); | |
| expect(painter.shadow.blurRadius, 8.0); | |
| debugDisableShadows = true; | |
| }); | |
| testWidgets('Banner does not crash at zero area', (WidgetTester tester) async { | |
| await tester.pumpWidget( | |
| const Directionality( | |
| textDirection: TextDirection.ltr, | |
| child: Center( | |
| child: SizedBox.shrink( | |
| child: Banner( | |
| message: 'X', | |
| textDirection: TextDirection.ltr, | |
| location: BannerLocation.bottomEnd, | |
| layoutDirection: TextDirection.ltr, | |
| ), | |
| ), | |
| ), | |
| ), | |
| ); | |
| expect(tester.getSize(find.byType(Banner)), Size.zero); | |
| }); | |
| testWidgets('CheckedModeBanner does not crash at zero area', (WidgetTester tester) async { | |
| await tester.pumpWidget( | |
| const Directionality( | |
| textDirection: TextDirection.ltr, | |
| child: Center( | |
| child: SizedBox.shrink(child: CheckedModeBanner(child: Text('X'))), | |
| ), | |
| ), | |
| ); | |
| expect(tester.getSize(find.byType(CheckedModeBanner)), Size.zero); | |
| }); | |
| } |