tween_test.dart 7.45 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/widgets.dart';

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

10
void main() {
11 12 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
  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.',
    ]);
  });

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

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

130 131 132 133 134 135 136 137 138 139 140 141
  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);
  });

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

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

  test('RectTween', () {
Dan Field's avatar
Dan Field committed
155 156
    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);
157
    final RectTween tween = RectTween(begin: a, end: b);
158 159 160
    expect(tween.lerp(0.5), equals(Rect.lerp(a, b, 0.5)));
    expect(tween, hasOneLineDescription);
  });
161 162

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

  test('ConstantTween', () {
185
    final ConstantTween<double> tween = ConstantTween<double>(100.0);
186 187 188 189 190 191
    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);
  });
192 193 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

  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);
  });
222
}