animated_icons_private_test.dart 13.4 KB
Newer Older
1 2 3 4 5
// 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.
6
// To make the private API accessible from the test we do not import the
7 8 9 10 11 12 13 14 15 16
// 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';
17
import 'package:flutter/widgets.dart';
18
import 'package:meta/meta.dart';
19
import 'package:mockito/mockito.dart';
20 21

import '../flutter_test_alternative.dart';
22

23 24
part 'package:flutter/src/material/animated_icons/animated_icons.dart';
part 'package:flutter/src/material/animated_icons/animated_icons_data.dart';
25 26 27 28 29

// 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';
30
part 'package:flutter/src/material/animated_icons/data/arrow_menu.g.dart';
31 32 33 34 35
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';
36
part 'package:flutter/src/material/animated_icons/data/menu_arrow.g.dart';
37 38 39 40 41 42
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';
43 44 45 46 47 48 49

class MockCanvas extends Mock implements ui.Canvas {}
class MockPath extends Mock implements ui.Path {}

void main () {
  group('Interpolate points', () {
    test('- single point', () {
50 51
      const List<Offset> points = <Offset>[
        Offset(25.0, 1.0),
52 53 54 55 56 57 58
      ];
      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', () {
59 60 61
      const List<Offset> points = <Offset>[
        Offset(25.0, 1.0),
        Offset(12.0, 12.0),
62 63 64 65 66 67 68
      ];
      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', () {
69 70 71 72
      const List<Offset> points = <Offset>[
        Offset(25.0, 1.0),
        Offset(12.0, 12.0),
        Offset(23.0, 9.0),
73 74 75 76 77 78 79 80 81 82
      ];
      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', () {
83
    const Size size = Size(48.0, 48.0);
84
    final MockCanvas mockCanvas = MockCanvas();
85 86
    List<MockPath> generatedPaths;
    final _UiPathFactory pathFactory = () {
87
      final MockPath path = MockPath();
88 89 90 91 92 93 94 95 96
      generatedPaths.add(path);
      return path;
    };

    setUp(() {
      generatedPaths = <MockPath> [];
    });

    test('progress 0', () {
97
      final _AnimatedIconPainter painter = _AnimatedIconPainter(
98 99 100 101 102 103 104
        paths: movingBar.paths,
        progress: const AlwaysStoppedAnimation<double>(0.0),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );
105
      painter.paint(mockCanvas, size);
106 107
      expect(generatedPaths.length, 1);

108
      verifyInOrder(<void>[
109 110 111 112 113 114 115 116 117 118
        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', () {
119
      final _AnimatedIconPainter painter = _AnimatedIconPainter(
120 121 122 123 124 125 126
        paths: movingBar.paths,
        progress: const AlwaysStoppedAnimation<double>(1.0),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );
127
      painter.paint(mockCanvas, size);
128 129
      expect(generatedPaths.length, 1);

130
      verifyInOrder(<void>[
131 132 133 134 135 136 137 138 139 140
        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', () {
141
      final _AnimatedIconPainter painter = _AnimatedIconPainter(
142 143 144 145 146 147 148
        paths: movingBar.paths,
        progress: const AlwaysStoppedAnimation<double>(1.5),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );
149
      painter.paint(mockCanvas, size);
150 151
      expect(generatedPaths.length, 1);

152
      verifyInOrder(<void>[
153 154 155 156 157 158 159 160 161 162
        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', () {
163
      final _AnimatedIconPainter painter = _AnimatedIconPainter(
164 165 166 167 168 169 170
        paths: movingBar.paths,
        progress: const AlwaysStoppedAnimation<double>(0.0),
        color: const Color(0xFF00FF00),
        scale: 0.5,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );
171
      painter.paint(mockCanvas, size);
172 173 174 175
      verify(mockCanvas.scale(0.5, 0.5));
    });

    test('mirror', () {
176
      final _AnimatedIconPainter painter = _AnimatedIconPainter(
177 178 179 180 181 182 183
        paths: movingBar.paths,
        progress: const AlwaysStoppedAnimation<double>(0.0),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: true,
        uiPathFactory: pathFactory
      );
184
      painter.paint(mockCanvas, size);
185
      verifyInOrder(<void>[
186 187 188 189 190 191
        mockCanvas.rotate(math.pi),
        mockCanvas.translate(-48.0, -48.0)
      ]);
    });

    test('interpolated frame', () {
192
      final _AnimatedIconPainter painter = _AnimatedIconPainter(
193 194 195 196 197 198 199
        paths: movingBar.paths,
        progress: const AlwaysStoppedAnimation<double>(0.5),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );
200
      painter.paint(mockCanvas, size);
201 202
      expect(generatedPaths.length, 1);

203
      verifyInOrder(<void>[
204 205 206 207 208 209 210 211 212 213
        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', () {
214
      final _AnimatedIconPainter painter = _AnimatedIconPainter(
215 216 217 218 219 220 221
        paths: bow.paths,
        progress: const AlwaysStoppedAnimation<double>(1.0),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );
222
      painter.paint(mockCanvas, size);
223 224
      expect(generatedPaths.length, 1);

225
      verifyInOrder(<void>[
226 227 228 229 230 231 232 233
        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', () {
234
      final _AnimatedIconPainter painter = _AnimatedIconPainter(
235 236 237 238 239 240 241
        paths: bow.paths,
        progress: const AlwaysStoppedAnimation<double>(0.25),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );
242
      painter.paint(mockCanvas, size);
243 244
      expect(generatedPaths.length, 1);

245
      verifyInOrder(<void>[
246 247 248 249 250 251 252 253
        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', () {
254
      final _AnimatedIconPainter painter1 = _AnimatedIconPainter(
255 256 257 258 259 260 261 262
        paths: bow.paths,
        progress: const AlwaysStoppedAnimation<double>(0.0),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );

263
      final _AnimatedIconPainter painter2 = _AnimatedIconPainter(
264 265 266 267 268 269 270 271 272 273 274 275
        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', () {
276
      final _AnimatedIconPainter painter1 = _AnimatedIconPainter(
277 278 279 280 281 282 283 284
        paths: bow.paths,
        progress: const AlwaysStoppedAnimation<double>(0.0),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );

285
      final _AnimatedIconPainter painter2 = _AnimatedIconPainter(
286 287 288 289 290 291 292 293 294 295 296 297
        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', () {
298
      final _AnimatedIconPainter painter1 = _AnimatedIconPainter(
299 300 301 302 303 304 305 306
        paths: bow.paths,
        progress: const AlwaysStoppedAnimation<double>(0.0),
        color: const Color(0xFF00FF00),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );

307
      final _AnimatedIconPainter painter2 = _AnimatedIconPainter(
308 309 310 311 312 313 314 315 316 317 318 319
        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', () {
320
      final _AnimatedIconPainter painter1 = _AnimatedIconPainter(
321 322 323 324 325 326 327 328
        paths: bow.paths,
        progress: const AlwaysStoppedAnimation<double>(0.0),
        color: const Color(0xFF0000FF),
        scale: 1.0,
        shouldMirror: false,
        uiPathFactory: pathFactory
      );

329
      final _AnimatedIconPainter painter2 = _AnimatedIconPainter(
330 331 332 333 334 335 336 337 338 339 340 341 342 343
        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);
    });

  });
}

344 345 346 347 348 349 350 351 352 353
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),
354 355
          ],
        ),
356 357 358 359
        _PathLineTo(
          <Offset> [
            Offset(48.0, 0.0),
            Offset(48.0, 38.0),
360 361
          ],
        ),
362 363 364 365
        _PathLineTo(
          <Offset> [
            Offset(48.0, 10.0),
            Offset(48.0, 48.0),
366 367
          ],
        ),
368 369 370 371
        _PathLineTo(
          <Offset> [
            Offset(0.0, 10.0),
            Offset(0.0, 48.0),
372 373
          ],
        ),
374 375 376 377
        _PathLineTo(
          <Offset> [
            Offset(0.0, 0.0),
            Offset(0.0, 38.0),
378 379
          ],
        ),
380
        _PathClose(),
381 382 383 384 385
      ],
    ),
  ],
);

386 387 388 389 390 391 392 393 394 395 396
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),
397 398
          ],
        ),
399 400 401 402 403
        _PathCubicTo(
          <Offset> [
            Offset(16.0, 24.0),
            Offset(16.0, 10.0),
            Offset(16.0, 48.0),
404
          ],
405 406 407 408
          <Offset> [
            Offset(32.0, 24.0),
            Offset(32.0, 10.0),
            Offset(32.0, 48.0),
409
          ],
410 411 412 413
          <Offset> [
            Offset(48.0, 24.0),
            Offset(48.0, 24.0),
            Offset(48.0, 24.0),
414 415
          ],
        ),
416 417 418 419 420
        _PathLineTo(
          <Offset> [
            Offset(0.0, 24.0),
            Offset(0.0, 24.0),
            Offset(0.0, 24.0),
421 422
          ],
        ),
423
        _PathClose(),
424 425 426 427
      ],
    ),
  ],
);