From 3055ae4e936f30419dbe3064ecdee83cc4db1278 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Thu, 10 Sep 2020 15:50:03 -0700 Subject: [PATCH] Eliminate the need for the mockito package in animated_icons_private_test (#65199) --- .../lib/src/material/animated_icons.dart | 3 +- .../animated_icons/animated_icons.dart | 22 +-- .../material/animated_icons_private_test.dart | 175 +++++++++++++----- 3 files changed, 137 insertions(+), 63 deletions(-) diff --git a/packages/flutter/lib/src/material/animated_icons.dart b/packages/flutter/lib/src/material/animated_icons.dart index c6631b29e61..dd8a86f6c58 100644 --- a/packages/flutter/lib/src/material/animated_icons.dart +++ b/packages/flutter/lib/src/material/animated_icons.dart @@ -18,11 +18,12 @@ import 'package:flutter/widgets.dart'; // Public API. part 'animated_icons/animated_icons.dart'; + // Provides a public interface for referring to the private icon // implementations. part 'animated_icons/animated_icons_data.dart'; -// Animated icons data files. +// Generated animated icon data files. part 'animated_icons/data/add_event.g.dart'; part 'animated_icons/data/arrow_menu.g.dart'; part 'animated_icons/data/close_menu.g.dart'; diff --git a/packages/flutter/lib/src/material/animated_icons/animated_icons.dart b/packages/flutter/lib/src/material/animated_icons/animated_icons.dart index a22598a853e..78b42f13e45 100644 --- a/packages/flutter/lib/src/material/animated_icons/animated_icons.dart +++ b/packages/flutter/lib/src/material/animated_icons/animated_icons.dart @@ -279,17 +279,17 @@ class _PathClose extends _PathCommand { } } -// Interpolates a value given a set of values equally spaced in time. -// -// [interpolator] is the interpolation function used to interpolate between 2 -// points of type T. -// -// This is currently done with linear interpolation between every 2 consecutive -// points. Linear interpolation was smooth enough with the limited set of -// animations we have tested, so we use it for simplicity. If we find this to -// not be smooth enough we can try applying spline instead. -// -// [progress] is expected to be between 0.0 and 1.0. +/// Interpolates a value given a set of values equally spaced in time. +/// +/// [interpolator] is the interpolation function used to interpolate between 2 +/// points of type T. +/// +/// This is currently done with linear interpolation between every 2 consecutive +/// points. Linear interpolation was smooth enough with the limited set of +/// animations we have tested, so we use it for simplicity. If we find this to +/// not be smooth enough we can try applying spline instead. +/// +/// [progress] is expected to be between 0.0 and 1.0. T _interpolate(List values, double progress, _Interpolator interpolator) { assert(progress <= 1.0); assert(progress >= 0.0); diff --git a/packages/flutter/test/material/animated_icons_private_test.dart b/packages/flutter/test/material/animated_icons_private_test.dart index 5abcd68cb79..69de9e34035 100644 --- a/packages/flutter/test/material/animated_icons_private_test.dart +++ b/packages/flutter/test/material/animated_icons_private_test.dart @@ -18,7 +18,6 @@ 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'; @@ -83,16 +82,19 @@ void main () { group('_AnimatedIconPainter', () { const Size size = Size(48.0, 48.0); - final MockCanvas mockCanvas = MockCanvas(); + MockPath mockPath; + MockCanvas mockCanvas; List generatedPaths; - final _UiPathFactory pathFactory = () { - final MockPath path = MockPath(); - generatedPaths.add(path); - return path; - }; + _UiPathFactory pathFactory; setUp(() { - generatedPaths = []; + generatedPaths = []; + mockCanvas = MockCanvas(); + mockPath = MockPath(); + pathFactory = () { + generatedPaths.add(mockPath); + return mockPath; + }; }); test('progress 0', () { @@ -107,13 +109,13 @@ void main () { painter.paint(mockCanvas, size); expect(generatedPaths.length, 1); - verifyInOrder([ - 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(), + generatedPaths[0].verifyCallsInOrder([ + MockCall('moveTo', [0.0, 0.0]), + MockCall('lineTo', [48.0, 0.0]), + MockCall('lineTo', [48.0, 10.0]), + MockCall('lineTo', [0.0, 10.0]), + MockCall('lineTo', [0.0, 0.0]), + MockCall('close'), ]); }); @@ -129,13 +131,13 @@ void main () { painter.paint(mockCanvas, size); expect(generatedPaths.length, 1); - verifyInOrder([ - 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(), + generatedPaths[0].verifyCallsInOrder([ + MockCall('moveTo', [0.0, 38.0]), + MockCall('lineTo', [48.0, 38.0]), + MockCall('lineTo', [48.0, 48.0]), + MockCall('lineTo', [0.0, 48.0]), + MockCall('lineTo', [0.0, 38.0]), + MockCall('close'), ]); }); @@ -151,13 +153,13 @@ void main () { painter.paint(mockCanvas, size); expect(generatedPaths.length, 1); - verifyInOrder([ - 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(), + generatedPaths[0].verifyCallsInOrder([ + MockCall('moveTo', [0.0, 38.0]), + MockCall('lineTo', [48.0, 38.0]), + MockCall('lineTo', [48.0, 48.0]), + MockCall('lineTo', [0.0, 48.0]), + MockCall('lineTo', [0.0, 38.0]), + MockCall('close'), ]); }); @@ -171,7 +173,10 @@ void main () { uiPathFactory: pathFactory, ); painter.paint(mockCanvas, size); - verify(mockCanvas.scale(0.5, 0.5)); + mockCanvas.verifyCallsInOrder([ + MockCall('scale', [0.5, 0.5]), + MockCall.any('drawPath'), + ]); }); test('mirror', () { @@ -184,9 +189,11 @@ void main () { uiPathFactory: pathFactory, ); painter.paint(mockCanvas, size); - verifyInOrder([ - mockCanvas.rotate(math.pi), - mockCanvas.translate(-48.0, -48.0), + mockCanvas.verifyCallsInOrder([ + MockCall('scale', [1.0, 1.0]), + MockCall('rotate', [math.pi]), + MockCall('translate', [-48.0, -48.0]), + MockCall.any('drawPath'), ]); }); @@ -202,13 +209,13 @@ void main () { painter.paint(mockCanvas, size); expect(generatedPaths.length, 1); - verifyInOrder([ - 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(), + generatedPaths[0].verifyCallsInOrder([ + MockCall('moveTo', [0.0, 19.0]), + MockCall('lineTo', [48.0, 19.0]), + MockCall('lineTo', [48.0, 29.0]), + MockCall('lineTo', [0.0, 29.0]), + MockCall('lineTo', [0.0, 19.0]), + MockCall('close'), ]); }); @@ -224,11 +231,11 @@ void main () { painter.paint(mockCanvas, size); expect(generatedPaths.length, 1); - verifyInOrder([ - 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(), + generatedPaths[0].verifyCallsInOrder([ + MockCall('moveTo', [0.0, 24.0]), + MockCall('cubicTo', [16.0, 48.0, 32.0, 48.0, 48.0, 24.0]), + MockCall('lineTo', [0.0, 24.0]), + MockCall('close'), ]); }); @@ -244,11 +251,11 @@ void main () { painter.paint(mockCanvas, size); expect(generatedPaths.length, 1); - verifyInOrder([ - 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(), + generatedPaths[0].verifyCallsInOrder([ + MockCall('moveTo', [0.0, 24.0]), + MockCall('cubicTo', [16.0, 17.0, 32.0, 17.0, 48.0, 24.0]), + MockCall('lineTo', [0.0, 24.0]), + MockCall('close', []), ]); }); @@ -339,10 +346,76 @@ void main () { expect(painter1.shouldRepaint(painter2), true); }); - }); } +// Contains the data from an invocation used for collection of calls and for +// expectations in Mock class. +class MockCall { + // Creates a mock call with optional positional arguments. + MockCall(String memberName, [this.positionalArguments, this.acceptAny = false]) + : memberSymbol = Symbol(memberName); + MockCall.fromSymbol(this.memberSymbol, [this.positionalArguments, this.acceptAny = false]); + // Creates a mock call expectation that doesn't care about what the arguments were. + MockCall.any(String memberName) + : memberSymbol = Symbol(memberName), + acceptAny = true, + positionalArguments = null; + + final Symbol memberSymbol; + String get memberName { + final RegExp symbolMatch = RegExp(r'Symbol\("(?.*)"\)'); + final RegExpMatch match = symbolMatch.firstMatch(memberSymbol.toString()); + assert(match != null); + return match.namedGroup('name'); + } + final List positionalArguments; + final bool acceptAny; + + @override + String toString() { + return '$memberName(${positionalArguments?.join(', ') ?? ''})'; + } +} + +// A very simplified version of a Mock class. +// +// Only verifies positional arguments, and only can verify calls in order. +class Mock { + final List _calls = []; + + // Verify that the given calls happened in the order given. + void verifyCallsInOrder(List expected) { + int count = 0; + expect(expected.length, equals(_calls.length), + reason: 'Incorrect number of calls received. ' + 'Expected ${expected.length} and received ${_calls.length}.\n' + ' Calls Received: $_calls\n' + ' Calls Expected: $expected'); + for (final MockCall call in _calls) { + expect(call.memberSymbol, equals(expected[count].memberSymbol), + reason: 'Unexpected call to ${call.memberName}, expected a call to ' + '${expected[count].memberName} instead.'); + if (call.positionalArguments != null && !expected[count].acceptAny) { + int countArg = 0; + for (final dynamic arg in call.positionalArguments) { + expect(arg, equals(expected[count].positionalArguments[countArg]), + reason: 'Failed at call $count. Positional argument $countArg to ${call.memberName} ' + 'not as expected. Expected ${expected[count].positionalArguments[countArg]} ' + 'and received $arg'); + countArg++; + } + } + count++; + } + } + + @override + void noSuchMethod(Invocation invocation) { + _calls.add(MockCall.fromSymbol(invocation.memberName, invocation.positionalArguments)); + } +} + const _AnimatedIconData movingBar = _AnimatedIconData( Size(48.0, 48.0), <_PathFrames> [