| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This is the test for the private implementation of animated icons. |
| // To make the private API accessible from the test we do not import the |
| // material material_animated_icons library, but instead, this test file is an |
| // implementation of that library, using some of the parts of the real |
| // material_animated_icons, this give the test access to the private APIs. |
| library material_animated_icons; |
| |
| import 'dart:math' as math show pi; |
| import 'dart:ui' show lerpDouble; |
| import 'dart:ui' as ui show Paint, Path, Canvas; |
| |
| import 'package:flutter/animation.dart'; |
| import 'package:flutter/widgets.dart'; |
| import 'package:meta/meta.dart'; |
| import 'package:mockito/mockito.dart'; |
| |
| import '../flutter_test_alternative.dart'; |
| |
| part 'package:flutter/src/material/animated_icons/animated_icons.dart'; |
| part 'package:flutter/src/material/animated_icons/animated_icons_data.dart'; |
| |
| // We have to import all the generated files in the material library to avoid |
| // analysis errors (as the generated constants are all referenced in the |
| // animated_icons library). |
| part 'package:flutter/src/material/animated_icons/data/add_event.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/arrow_menu.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/close_menu.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/ellipsis_search.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/event_add.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/home_menu.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/list_view.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/menu_arrow.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/menu_close.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/menu_home.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/pause_play.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/play_pause.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/search_ellipsis.g.dart'; |
| part 'package:flutter/src/material/animated_icons/data/view_list.g.dart'; |
| |
| class MockCanvas extends Mock implements ui.Canvas {} |
| class MockPath extends Mock implements ui.Path {} |
| |
| void main () { |
| group('Interpolate points', () { |
| test('- single point', () { |
| const List<Offset> points = <Offset>[ |
| Offset(25.0, 1.0), |
| ]; |
| expect(_interpolate(points, 0.0, Offset.lerp), const Offset(25.0, 1.0)); |
| expect(_interpolate(points, 0.5, Offset.lerp), const Offset(25.0, 1.0)); |
| expect(_interpolate(points, 1.0, Offset.lerp), const Offset(25.0, 1.0)); |
| }); |
| |
| test('- two points', () { |
| const List<Offset> points = <Offset>[ |
| Offset(25.0, 1.0), |
| Offset(12.0, 12.0), |
| ]; |
| expect(_interpolate(points, 0.0, Offset.lerp), const Offset(25.0, 1.0)); |
| expect(_interpolate(points, 0.5, Offset.lerp), const Offset(18.5, 6.5)); |
| expect(_interpolate(points, 1.0, Offset.lerp), const Offset(12.0, 12.0)); |
| }); |
| |
| test('- three points', () { |
| const List<Offset> points = <Offset>[ |
| Offset(25.0, 1.0), |
| Offset(12.0, 12.0), |
| Offset(23.0, 9.0), |
| ]; |
| expect(_interpolate(points, 0.0, Offset.lerp), const Offset(25.0, 1.0)); |
| expect(_interpolate(points, 0.25, Offset.lerp), const Offset(18.5, 6.5)); |
| expect(_interpolate(points, 0.5, Offset.lerp), const Offset(12.0, 12.0)); |
| expect(_interpolate(points, 0.75, Offset.lerp), const Offset(17.5, 10.5)); |
| expect(_interpolate(points, 1.0, Offset.lerp), const Offset(23.0, 9.0)); |
| }); |
| }); |
| |
| group('_AnimatedIconPainter', () { |
| const Size size = Size(48.0, 48.0); |
| final MockCanvas mockCanvas = new MockCanvas(); |
| List<MockPath> generatedPaths; |
| final _UiPathFactory pathFactory = () { |
| final MockPath path = new MockPath(); |
| generatedPaths.add(path); |
| return path; |
| }; |
| |
| setUp(() { |
| generatedPaths = <MockPath> []; |
| }); |
| |
| test('progress 0', () { |
| final _AnimatedIconPainter painter = new _AnimatedIconPainter( |
| paths: movingBar.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| painter.paint(mockCanvas, size); |
| expect(generatedPaths.length, 1); |
| |
| verifyInOrder(<void>[ |
| generatedPaths[0].moveTo(0.0, 0.0), |
| generatedPaths[0].lineTo(48.0, 0.0), |
| generatedPaths[0].lineTo(48.0, 10.0), |
| generatedPaths[0].lineTo(0.0, 10.0), |
| generatedPaths[0].lineTo(0.0, 0.0), |
| generatedPaths[0].close(), |
| ]); |
| }); |
| |
| test('progress 1', () { |
| final _AnimatedIconPainter painter = new _AnimatedIconPainter( |
| paths: movingBar.paths, |
| progress: const AlwaysStoppedAnimation<double>(1.0), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| painter.paint(mockCanvas, size); |
| expect(generatedPaths.length, 1); |
| |
| verifyInOrder(<void>[ |
| generatedPaths[0].moveTo(0.0, 38.0), |
| generatedPaths[0].lineTo(48.0, 38.0), |
| generatedPaths[0].lineTo(48.0, 48.0), |
| generatedPaths[0].lineTo(0.0, 48.0), |
| generatedPaths[0].lineTo(0.0, 38.0), |
| generatedPaths[0].close(), |
| ]); |
| }); |
| |
| test('clamped progress', () { |
| final _AnimatedIconPainter painter = new _AnimatedIconPainter( |
| paths: movingBar.paths, |
| progress: const AlwaysStoppedAnimation<double>(1.5), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| painter.paint(mockCanvas, size); |
| expect(generatedPaths.length, 1); |
| |
| verifyInOrder(<void>[ |
| generatedPaths[0].moveTo(0.0, 38.0), |
| generatedPaths[0].lineTo(48.0, 38.0), |
| generatedPaths[0].lineTo(48.0, 48.0), |
| generatedPaths[0].lineTo(0.0, 48.0), |
| generatedPaths[0].lineTo(0.0, 38.0), |
| generatedPaths[0].close(), |
| ]); |
| }); |
| |
| test('scale', () { |
| final _AnimatedIconPainter painter = new _AnimatedIconPainter( |
| paths: movingBar.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFF00FF00), |
| scale: 0.5, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| painter.paint(mockCanvas, size); |
| verify(mockCanvas.scale(0.5, 0.5)); |
| }); |
| |
| test('mirror', () { |
| final _AnimatedIconPainter painter = new _AnimatedIconPainter( |
| paths: movingBar.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: true, |
| uiPathFactory: pathFactory |
| ); |
| painter.paint(mockCanvas, size); |
| verifyInOrder(<void>[ |
| mockCanvas.rotate(math.pi), |
| mockCanvas.translate(-48.0, -48.0) |
| ]); |
| }); |
| |
| test('interpolated frame', () { |
| final _AnimatedIconPainter painter = new _AnimatedIconPainter( |
| paths: movingBar.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.5), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| painter.paint(mockCanvas, size); |
| expect(generatedPaths.length, 1); |
| |
| verifyInOrder(<void>[ |
| generatedPaths[0].moveTo(0.0, 19.0), |
| generatedPaths[0].lineTo(48.0, 19.0), |
| generatedPaths[0].lineTo(48.0, 29.0), |
| generatedPaths[0].lineTo(0.0, 29.0), |
| generatedPaths[0].lineTo(0.0, 19.0), |
| generatedPaths[0].close(), |
| ]); |
| }); |
| |
| test('curved frame', () { |
| final _AnimatedIconPainter painter = new _AnimatedIconPainter( |
| paths: bow.paths, |
| progress: const AlwaysStoppedAnimation<double>(1.0), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| painter.paint(mockCanvas, size); |
| expect(generatedPaths.length, 1); |
| |
| verifyInOrder(<void>[ |
| generatedPaths[0].moveTo(0.0, 24.0), |
| generatedPaths[0].cubicTo(16.0, 48.0, 32.0, 48.0, 48.0, 24.0), |
| generatedPaths[0].lineTo(0.0, 24.0), |
| generatedPaths[0].close(), |
| ]); |
| }); |
| |
| test('interpolated curved frame', () { |
| final _AnimatedIconPainter painter = new _AnimatedIconPainter( |
| paths: bow.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.25), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| painter.paint(mockCanvas, size); |
| expect(generatedPaths.length, 1); |
| |
| verifyInOrder(<void>[ |
| generatedPaths[0].moveTo(0.0, 24.0), |
| generatedPaths[0].cubicTo(16.0, 17.0, 32.0, 17.0, 48.0, 24.0), |
| generatedPaths[0].lineTo(0.0, 24.0), |
| generatedPaths[0].close(), |
| ]); |
| }); |
| |
| test('should not repaint same values', () { |
| final _AnimatedIconPainter painter1 = new _AnimatedIconPainter( |
| paths: bow.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| |
| final _AnimatedIconPainter painter2 = new _AnimatedIconPainter( |
| paths: bow.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| |
| expect(painter1.shouldRepaint(painter2), false); |
| }); |
| |
| test('should repaint on progress change', () { |
| final _AnimatedIconPainter painter1 = new _AnimatedIconPainter( |
| paths: bow.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| |
| final _AnimatedIconPainter painter2 = new _AnimatedIconPainter( |
| paths: bow.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.1), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| |
| expect(painter1.shouldRepaint(painter2), true); |
| }); |
| |
| test('should repaint on color change', () { |
| final _AnimatedIconPainter painter1 = new _AnimatedIconPainter( |
| paths: bow.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFF00FF00), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| |
| final _AnimatedIconPainter painter2 = new _AnimatedIconPainter( |
| paths: bow.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFFFF0000), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| |
| expect(painter1.shouldRepaint(painter2), true); |
| }); |
| |
| test('should repaint on paths change', () { |
| final _AnimatedIconPainter painter1 = new _AnimatedIconPainter( |
| paths: bow.paths, |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFF0000FF), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| |
| final _AnimatedIconPainter painter2 = new _AnimatedIconPainter( |
| paths: const <_PathFrames> [], |
| progress: const AlwaysStoppedAnimation<double>(0.0), |
| color: const Color(0xFF0000FF), |
| scale: 1.0, |
| shouldMirror: false, |
| uiPathFactory: pathFactory |
| ); |
| |
| expect(painter1.shouldRepaint(painter2), true); |
| }); |
| |
| }); |
| } |
| |
| const _AnimatedIconData movingBar = _AnimatedIconData( |
| Size(48.0, 48.0), |
| <_PathFrames> [ |
| _PathFrames( |
| opacities: <double> [1.0, 0.2], |
| commands: <_PathCommand> [ |
| _PathMoveTo( |
| <Offset> [ |
| Offset(0.0, 0.0), |
| Offset(0.0, 38.0), |
| ], |
| ), |
| _PathLineTo( |
| <Offset> [ |
| Offset(48.0, 0.0), |
| Offset(48.0, 38.0), |
| ], |
| ), |
| _PathLineTo( |
| <Offset> [ |
| Offset(48.0, 10.0), |
| Offset(48.0, 48.0), |
| ], |
| ), |
| _PathLineTo( |
| <Offset> [ |
| Offset(0.0, 10.0), |
| Offset(0.0, 48.0), |
| ], |
| ), |
| _PathLineTo( |
| <Offset> [ |
| Offset(0.0, 0.0), |
| Offset(0.0, 38.0), |
| ], |
| ), |
| _PathClose(), |
| ], |
| ), |
| ], |
| ); |
| |
| const _AnimatedIconData bow = _AnimatedIconData( |
| Size(48.0, 48.0), |
| <_PathFrames> [ |
| _PathFrames( |
| opacities: <double> [1.0, 1.0], |
| commands: <_PathCommand> [ |
| _PathMoveTo( |
| <Offset> [ |
| Offset(0.0, 24.0), |
| Offset(0.0, 24.0), |
| Offset(0.0, 24.0), |
| ], |
| ), |
| _PathCubicTo( |
| <Offset> [ |
| Offset(16.0, 24.0), |
| Offset(16.0, 10.0), |
| Offset(16.0, 48.0), |
| ], |
| <Offset> [ |
| Offset(32.0, 24.0), |
| Offset(32.0, 10.0), |
| Offset(32.0, 48.0), |
| ], |
| <Offset> [ |
| Offset(48.0, 24.0), |
| Offset(48.0, 24.0), |
| Offset(48.0, 24.0), |
| ], |
| ), |
| _PathLineTo( |
| <Offset> [ |
| Offset(0.0, 24.0), |
| Offset(0.0, 24.0), |
| Offset(0.0, 24.0), |
| ], |
| ), |
| _PathClose(), |
| ], |
| ), |
| ], |
| ); |