animation_sheet_test.dart 5.8 KB
Newer Older
1 2 3 4
// 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.

5 6 7
// This file is run as part of a reduced test set in CI on Mac and Windows
// machines.
@Tags(<String>['reduced-test-set'])
8
library;
9

10 11
import 'dart:ui' as ui;

12 13
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
14
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
15

16

17 18 19 20 21 22
void main() {
  /*
   * Here lies tests for packages/flutter_test/lib/src/animation_sheet.dart
   * because [matchesGoldenFile] does not use Skia Gold in its native package.
   */

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
  testWidgetsWithLeakTracking('recording disposes images',
  (WidgetTester tester) async {
    final AnimationSheetBuilder builder = AnimationSheetBuilder(frameSize: _DecuplePixels.size);

    await tester.pumpFrames(
      builder.record(
        const _DecuplePixels(Duration(seconds: 1)),
      ),
      const Duration(milliseconds: 200),
      const Duration(milliseconds: 100),
    );
  },
    skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001
    // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071
    leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true),
  );

  testWidgetsWithLeakTracking('correctly records frames using collate',
  (WidgetTester tester) async {
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
    final AnimationSheetBuilder builder = AnimationSheetBuilder(frameSize: _DecuplePixels.size);

    await tester.pumpFrames(
      builder.record(
        const _DecuplePixels(Duration(seconds: 1)),
      ),
      const Duration(milliseconds: 200),
      const Duration(milliseconds: 100),
    );

    await tester.pumpFrames(
      builder.record(
        const _DecuplePixels(Duration(seconds: 1)),
        recording: false,
      ),
      const Duration(milliseconds: 200),
      const Duration(milliseconds: 100),
    );

    await tester.pumpFrames(
      builder.record(
        const _DecuplePixels(Duration(seconds: 1)),
      ),
      const Duration(milliseconds: 400),
      const Duration(milliseconds: 100),
    );

69 70
    final ui.Image image = await builder.collate(5);

71
    await expectLater(
72
      image,
73 74
      matchesGoldenFile('test.animation_sheet_builder.collate.png'),
    );
75

76
    image.dispose();
77 78 79 80 81
  },
    skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001
    // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071
    leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true),
  ); // https://github.com/flutter/flutter/issues/56001
82

83
  testWidgetsWithLeakTracking('use allLayers to record out-of-subtree contents', (WidgetTester tester) async {
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
    final AnimationSheetBuilder builder = AnimationSheetBuilder(
      frameSize: const Size(8, 2),
      allLayers: true,
    );

    // The `record` (sized 8, 2) is placed on top of `_DecuplePixels`
    // (sized 12, 3), aligned at its top left.
    await tester.pumpFrames(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Stack(
          children: <Widget>[
            const _DecuplePixels(Duration(seconds: 1)),
            Align(
              alignment: Alignment.topLeft,
              child: builder.record(Container()),
            ),
          ],
        ),
      ),
      const Duration(milliseconds: 600),
      const Duration(milliseconds: 100),
    );

108 109
    final ui.Image image = await builder.collate(5);

110
    await expectLater(
111
      image,
112 113
      matchesGoldenFile('test.animation_sheet_builder.out_of_tree.png'),
    );
114
    image.dispose();
115 116 117 118 119
  },
    skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001
    // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071
    leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true),
  );
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
}

// An animation of a yellow pixel moving from left to right, in a container of
// (10, 1) with a 1-pixel-wide black border.
class _DecuplePixels extends StatefulWidget {
  const _DecuplePixels(this.duration);

  static const Size size = Size(12, 3);

  final Duration duration;

  @override
  State<StatefulWidget> createState() => _DecuplePixelsState();
}

135 136
class _DecuplePixelsState extends State<_DecuplePixels> with SingleTickerProviderStateMixin<_DecuplePixels> {
  late AnimationController _controller;
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: widget.duration,
      vsync: this,
    );
    _controller.repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller.view,
158
      builder: (BuildContext context, Widget? child) {
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
        return CustomPaint(
          painter: _PaintDecuplePixels(_controller.value),
        );
      },
    );
  }
}

class _PaintDecuplePixels extends CustomPainter {
  _PaintDecuplePixels(this.value);

  final double value;

  @override
  bool shouldRepaint(_PaintDecuplePixels oldDelegate) {
    return oldDelegate.value != value;
  }

  @override
  void paint(Canvas canvas, Size size) {
    canvas.save();
    final Rect rect = RectTween(
      begin: const Rect.fromLTWH(1, 1, 1, 1),
      end: const Rect.fromLTWH(11, 1, 1, 1),
183
    ).transform(value)!;
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
    canvas.drawRect(rect, Paint()..color = Colors.yellow);
    final Paint black = Paint()..color = Colors.black;
    canvas
      // Top border
      ..drawRect(const Rect.fromLTRB(0, 0, 12, 1), black)
      // Bottom border
      ..drawRect(const Rect.fromLTRB(0, 2, 12, 3), black)
      // Left border
      ..drawRect(const Rect.fromLTRB(0, 0, 1, 3), black)
      // Right border
      ..drawRect(const Rect.fromLTRB(11, 0, 12, 3), black);

    canvas.restore();
  }
}