tween_test.dart 7.53 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/animation.dart';
import 'package:flutter/widgets.dart';
8
import 'package:vector_math/vector_math_64.dart';
9

10 11
const String kApiDocsLink = 'See "Types with special considerations" at https://api.flutter.dev/flutter/animation/Tween-class.html for more information.';

12
void main() {
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
  test('throws flutter error when tweening types that do not fully satisfy tween requirements - Object', () {
    final Tween<Object> objectTween = Tween<Object>(
      begin: Object(),
      end: Object(),
    );

    FlutterError? error;
    try {
      objectTween.transform(0.1);
    } on FlutterError catch (err) {
      error = err;
    }

    if (error == null) {
      fail('Expected Tween.transform to throw a FlutterError');
    }

    expect(error.diagnostics.map((DiagnosticsNode node) => node.toString()), <String>[
      'Cannot lerp between "Instance of \'Object\'" and "Instance of \'Object\'".',
      'The type Object might not fully implement `+`, `-`, and/or `*`. $kApiDocsLink',
      'There may be a dedicated "ObjectTween" for this type, or you may need to create one.'
    ]);
  });

  test('throws flutter error when tweening types that do not fully satisfy tween requirements - Color', () {
    final Tween<Color> colorTween = Tween<Color>(
      begin: const Color(0xFF000000),
      end: const Color(0xFFFFFFFF),
    );

    FlutterError? error;
    try {
      colorTween.transform(0.1);
    } on FlutterError catch (err) {
      error = err;
    }

    if (error == null) {
      fail('Expected Tween.transform to throw a FlutterError');
    }

    expect(error.diagnostics.map((DiagnosticsNode node) => node.toString()), <String>[
      'Cannot lerp between "Color(0xff000000)" and "Color(0xffffffff)".',
      'The type Color might not fully implement `+`, `-`, and/or `*`. $kApiDocsLink',
      'To lerp colors, consider ColorTween instead.',
    ]);
  });

  test('throws flutter error when tweening types that do not fully satisfy tween requirements - Rect', () {
    final Tween<Rect> rectTween = Tween<Rect>(
      begin: const Rect.fromLTWH(0, 0, 10, 10),
      end: const Rect.fromLTWH(2, 2, 2, 2)
    );

    FlutterError? error;
    try {
      rectTween.transform(0.1);
    } on FlutterError catch (err) {
      error = err;
    }

    if (error == null) {
      fail('Expected Tween.transform to throw a FlutterError');
    }

    expect(error.diagnostics.map((DiagnosticsNode node) => node.toString()), <String>[
      'Cannot lerp between "Rect.fromLTRB(0.0, 0.0, 10.0, 10.0)" and "Rect.fromLTRB(2.0, 2.0, 4.0, 4.0)".',
      'The type Rect might not fully implement `+`, `-`, and/or `*`. $kApiDocsLink',
      'To lerp rects, consider RectTween instead.',
    ]);
  });

  test('throws flutter error when tweening types that do not fully satisfy tween requirements - int', () {
    final Tween<int> colorTween = Tween<int>(
      begin: 0,
      end: 1,
    );

    FlutterError? error;
    try {
      colorTween.transform(0.1);
    } on FlutterError catch (err) {
      error = err;
    }

    if (error == null) {
      fail('Expected Tween.transform to throw a FlutterError');
    }

    expect(error.diagnostics.map((DiagnosticsNode node) => node.toString()), <String>[
      'Cannot lerp between "0" and "1".',
      'The type int returned a double after multiplication with a double value. $kApiDocsLink',
      'To lerp int values, consider IntTween or StepTween instead.',
    ]);
  });

109
  test('Can chain tweens', () {
110
    final Tween<double> tween = Tween<double>(begin: 0.30, end: 0.50);
111
    expect(tween, hasOneLineDescription);
112 113
    final Animatable<double> chain = tween.chain(Tween<double>(begin: 0.50, end: 1.0));
    final AnimationController controller = AnimationController(
114 115
      vsync: const TestVSync(),
    );
116 117 118 119
    expect(chain.evaluate(controller), 0.40);
    expect(chain, hasOneLineDescription);
  });

120
  test('Can animate tweens', () {
121 122
    final Tween<double> tween = Tween<double>(begin: 0.30, end: 0.50);
    final AnimationController controller = AnimationController(
123 124
      vsync: const TestVSync(),
    );
125
    final Animation<double> animation = tween.animate(controller);
126 127 128 129 130 131
    controller.value = 0.50;
    expect(animation.value, 0.40);
    expect(animation, hasOneLineDescription);
    expect(animation.toStringDetails(), hasOneLineDescription);
  });

132 133 134 135 136 137 138 139 140 141 142 143
  test('Can drive tweens', () {
    final Tween<double> tween = Tween<double>(begin: 0.30, end: 0.50);
    final AnimationController controller = AnimationController(
      vsync: const TestVSync(),
    );
    final Animation<double> animation = controller.drive(tween);
    controller.value = 0.50;
    expect(animation.value, 0.40);
    expect(animation, hasOneLineDescription);
    expect(animation.toStringDetails(), hasOneLineDescription);
  });

144
  test('SizeTween', () {
145
    final SizeTween tween = SizeTween(begin: Size.zero, end: const Size(20.0, 30.0));
146
    expect(tween.lerp(0.5), equals(const Size(10.0, 15.0)));
147 148 149 150
    expect(tween, hasOneLineDescription);
  });

  test('IntTween', () {
151
    final IntTween tween = IntTween(begin: 5, end: 9);
152 153 154
    expect(tween.lerp(0.5), 7);
    expect(tween.lerp(0.7), 8);
  });
155 156

  test('RectTween', () {
Dan Field's avatar
Dan Field committed
157 158
    const Rect a = Rect.fromLTWH(5.0, 3.0, 7.0, 11.0);
    const Rect b = Rect.fromLTWH(8.0, 12.0, 14.0, 18.0);
159
    final RectTween tween = RectTween(begin: a, end: b);
160 161 162
    expect(tween.lerp(0.5), equals(Rect.lerp(a, b, 0.5)));
    expect(tween, hasOneLineDescription);
  });
163 164

  test('Matrix4Tween', () {
165
    final Matrix4 a = Matrix4.identity();
166
    final Matrix4 b = a.clone()..translate(6.0, -8.0, 0.0)..scale(0.5, 1.0, 5.0);
167
    final Matrix4Tween tween = Matrix4Tween(begin: a, end: b);
168 169 170 171
    expect(tween.lerp(0.0), equals(a));
    expect(tween.lerp(1.0), equals(b));
    expect(
      tween.lerp(0.5),
172
      equals(a.clone()..translate(3.0, -4.0, 0.0)..scale(0.75, 1.0, 3.0)),
173 174
    );
    final Matrix4 c = a.clone()..rotateZ(1.0);
175
    final Matrix4Tween rotationTween = Matrix4Tween(begin: a, end: c);
176 177 178 179 180 181
    expect(rotationTween.lerp(0.0), equals(a));
    expect(rotationTween.lerp(1.0), equals(c));
    expect(
      rotationTween.lerp(0.5).absoluteError(
        a.clone()..rotateZ(0.5)
      ),
182
      moreOrLessEquals(0.0),
183
    );
184
  }, skip: isWindows); // floating point math not quite deterministic on Windows?
185 186

  test('ConstantTween', () {
187
    final ConstantTween<double> tween = ConstantTween<double>(100.0);
188 189 190 191 192 193
    expect(tween.begin, 100.0);
    expect(tween.end, 100.0);
    expect(tween.lerp(0.0), 100.0);
    expect(tween.lerp(0.5), 100.0);
    expect(tween.lerp(1.0), 100.0);
  });
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

  test('ReverseTween', () {
    final ReverseTween<int> tween = ReverseTween<int>(IntTween(begin: 5, end: 9));
    expect(tween.lerp(0.5), 7);
    expect(tween.lerp(0.7), 6);
  });

  test('ColorTween', () {
    final ColorTween tween = ColorTween(
      begin: const Color(0xff000000),
      end: const Color(0xffffffff)
    );
    expect(tween.lerp(0.0), const Color(0xff000000));
    expect(tween.lerp(0.5), const Color(0xff7f7f7f));
    expect(tween.lerp(0.7), const Color(0xffb2b2b2));
    expect(tween.lerp(1.0), const Color(0xffffffff));
  });

  test('StepTween', () {
    final StepTween tween = StepTween(begin: 5, end: 9);
    expect(tween.lerp(0.5), 7);
    expect(tween.lerp(0.7), 7);
  });

  test('CurveTween', () {
    final CurveTween tween = CurveTween(curve: Curves.easeIn);
    expect(tween.transform(0.0), 0.0);
    expect(tween.transform(0.5), 0.31640625);
    expect(tween.transform(1.0), 1.0);
  });
224
}