animation_controller_test.dart 10.1 KB
Newer Older
1 2 3 4
// Copyright 2016 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.

5
import 'package:flutter_test/flutter_test.dart';
6 7 8 9
import 'package:flutter/animation.dart';
import 'package:flutter/widgets.dart';

void main() {
10
  setUp(() {
11
    WidgetsFlutterBinding.ensureInitialized();
12 13 14 15
    WidgetsBinding.instance.resetEpoch();
  });

  test('Can set value during status callback', () {
16
    AnimationController controller = new AnimationController(
17 18
      duration: const Duration(milliseconds: 100),
      vsync: const TestVSync(),
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
    );
    bool didComplete = false;
    bool didDismiss = false;
    controller.addStatusListener((AnimationStatus status) {
      if (status == AnimationStatus.completed) {
        didComplete = true;
        controller.value = 0.0;
        controller.forward();
      } else if (status == AnimationStatus.dismissed) {
        didDismiss = true;
        controller.value = 0.0;
        controller.forward();
      }
    });

    controller.forward();
    expect(didComplete, isFalse);
    expect(didDismiss, isFalse);
37
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 1));
38 39
    expect(didComplete, isFalse);
    expect(didDismiss, isFalse);
40
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 2));
41 42
    expect(didComplete, isTrue);
    expect(didDismiss, isTrue);
43 44 45 46

    controller.stop();
  });

47
  test('Receives status callbacks for forward and reverse', () {
48
    AnimationController controller = new AnimationController(
49 50
      duration: const Duration(milliseconds: 100),
      vsync: const TestVSync(),
51 52 53 54 55 56 57 58 59 60 61
    );
    List<double> valueLog = <double>[];
    List<AnimationStatus> log = <AnimationStatus>[];
    controller
      ..addStatusListener((AnimationStatus status) {
        log.add(status);
      })
      ..addListener(() {
        valueLog.add(controller.value);
      });

62 63
    expect(log, equals(<AnimationStatus>[]));
    expect(valueLog, equals(<AnimationStatus>[]));
64 65 66

    controller.forward();

67 68
    expect(log, equals(<AnimationStatus>[AnimationStatus.forward]));
    expect(valueLog, equals(<AnimationStatus>[]));
69 70 71

    controller.reverse();

72 73
    expect(log, equals(<AnimationStatus>[AnimationStatus.forward, AnimationStatus.dismissed]));
    expect(valueLog, equals(<AnimationStatus>[]));
74 75 76

    controller.reverse();

77 78
    expect(log, equals(<AnimationStatus>[AnimationStatus.forward, AnimationStatus.dismissed]));
    expect(valueLog, equals(<AnimationStatus>[]));
79 80 81 82

    log.clear();
    controller.forward();

83 84
    expect(log, equals(<AnimationStatus>[AnimationStatus.forward]));
    expect(valueLog, equals(<AnimationStatus>[]));
85 86 87

    controller.forward();

88 89
    expect(log, equals(<AnimationStatus>[AnimationStatus.forward]));
    expect(valueLog, equals(<AnimationStatus>[]));
90 91 92 93

    controller.reverse();
    log.clear();

94
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 10));
95 96
    expect(log, equals(<AnimationStatus>[]));
    expect(valueLog, equals(<AnimationStatus>[]));
97
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 20));
98 99
    expect(log, equals(<AnimationStatus>[]));
    expect(valueLog, equals(<AnimationStatus>[]));
100
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 30));
101 102
    expect(log, equals(<AnimationStatus>[]));
    expect(valueLog, equals(<AnimationStatus>[]));
103
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 40));
104 105
    expect(log, equals(<AnimationStatus>[]));
    expect(valueLog, equals(<AnimationStatus>[]));
106 107

    controller.stop();
108
  });
109

110
  test('Forward and reverse from values', () {
111
    AnimationController controller = new AnimationController(
112 113
      duration: const Duration(milliseconds: 100),
      vsync: const TestVSync(),
114 115 116 117 118 119 120 121 122 123 124 125
    );
    List<double> valueLog = <double>[];
    List<AnimationStatus> statusLog = <AnimationStatus>[];
    controller
      ..addStatusListener((AnimationStatus status) {
        statusLog.add(status);
      })
      ..addListener(() {
        valueLog.add(controller.value);
      });

    controller.reverse(from: 0.2);
126 127
    expect(statusLog, equals(<AnimationStatus>[ AnimationStatus.reverse ]));
    expect(valueLog, equals(<double>[ 0.2 ]));
128 129 130 131 132
    expect(controller.value, equals(0.2));
    statusLog.clear();
    valueLog.clear();

    controller.forward(from: 0.0);
133 134
    expect(statusLog, equals(<AnimationStatus>[ AnimationStatus.dismissed, AnimationStatus.forward ]));
    expect(valueLog, equals(<double>[ 0.0 ]));
135 136
    expect(controller.value, equals(0.0));
  });
137

138 139
  test('Forward only from value', () {
    AnimationController controller = new AnimationController(
140 141
      duration: const Duration(milliseconds: 100),
      vsync: const TestVSync(),
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
    );
    List<double> valueLog = <double>[];
    List<AnimationStatus> statusLog = <AnimationStatus>[];
    controller
      ..addStatusListener((AnimationStatus status) {
        statusLog.add(status);
      })
      ..addListener(() {
        valueLog.add(controller.value);
      });

    controller.forward(from: 0.2);
    expect(statusLog, equals(<AnimationStatus>[ AnimationStatus.forward ]));
    expect(valueLog, equals(<double>[ 0.2 ]));
    expect(controller.value, equals(0.2));
  });

159 160
  test('Can fling to upper and lower bounds', () {
    AnimationController controller = new AnimationController(
161 162
      duration: const Duration(milliseconds: 100),
      vsync: const TestVSync(),
163 164 165 166 167 168 169 170 171 172 173
    );

    controller.fling();
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 1));
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 2));
    expect(controller.value, 1.0);
    controller.stop();

    AnimationController largeRangeController = new AnimationController(
      duration: const Duration(milliseconds: 100),
      lowerBound: -30.0,
174 175
      upperBound: 45.0,
      vsync: const TestVSync(),
176 177 178 179 180 181 182 183 184 185 186 187
    );

    largeRangeController.fling();
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 3));
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 4));
    expect(largeRangeController.value, 45.0);
    largeRangeController.fling(velocity: -1.0);
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 5));
    WidgetsBinding.instance.handleBeginFrame(const Duration(seconds: 6));
    expect(largeRangeController.value, -30.0);
    largeRangeController.stop();
  });
188 189 190

  test('lastElapsedDuration control test', () {
    AnimationController controller = new AnimationController(
191 192
      duration: const Duration(milliseconds: 100),
      vsync: const TestVSync(),
193 194 195 196 197 198 199 200
    );
    controller.forward();
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 20));
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 30));
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 40));
    expect(controller.lastElapsedDuration, equals(const Duration(milliseconds: 20)));
    controller.stop();
  });
201 202 203

  test('toString control test', () {
    AnimationController controller = new AnimationController(
204 205
      duration: const Duration(milliseconds: 100),
      vsync: const TestVSync(),
206
    );
207
    expect(controller, hasOneLineDescription);
208
    controller.forward();
209
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 10));
210
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 20));
211
    expect(controller, hasOneLineDescription);
212
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 30));
213
    expect(controller, hasOneLineDescription);
214
    controller.reverse();
215 216
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 40));
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 50));
217
    expect(controller, hasOneLineDescription);
218 219
    controller.stop();
  });
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

  test('velocity test - linear', () {
    AnimationController controller = new AnimationController(
      duration: const Duration(milliseconds: 1000),
      vsync: const TestVSync(),
    );

    // mid-flight
    controller.forward();
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 0));
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 500));
    expect(controller.velocity, inInclusiveRange(0.9, 1.1));

    // edges
    controller.forward();
    expect(controller.velocity, inInclusiveRange(0.4, 0.6));
    WidgetsBinding.instance.handleBeginFrame(Duration.ZERO);
    expect(controller.velocity, inInclusiveRange(0.4, 0.6));
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 5));
    expect(controller.velocity, inInclusiveRange(0.9, 1.1));

    controller.forward(from: 0.5);
    expect(controller.velocity, inInclusiveRange(0.4, 0.6));
    WidgetsBinding.instance.handleBeginFrame(Duration.ZERO);
    expect(controller.velocity, inInclusiveRange(0.4, 0.6));
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 5));
    expect(controller.velocity, inInclusiveRange(0.9, 1.1));

    // stopped
    controller.forward(from: 1.0);
    expect(controller.velocity, 0.0);
    WidgetsBinding.instance.handleBeginFrame(Duration.ZERO);
    expect(controller.velocity, 0.0);
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 500));
    expect(controller.velocity, 0.0);

    controller.forward();
    WidgetsBinding.instance.handleBeginFrame(Duration.ZERO);
    WidgetsBinding.instance.handleBeginFrame(const Duration(milliseconds: 1000));
    expect(controller.velocity, 0.0);

    controller.stop();
  });
263 264 265 266 267 268 269 270 271

  test('Disposed AnimationController toString works', () {
    AnimationController controller = new AnimationController(
      duration: const Duration(milliseconds: 100),
      vsync: const TestVSync(),
    );
    controller.dispose();
    expect(controller, hasOneLineDescription);
  });
272 273 274 275 276 277 278 279 280 281 282 283 284 285

  test('AnimationController error handling', () {
    AnimationController controller = new AnimationController(
      vsync: const TestVSync(),
    );

    expect(controller.forward, throwsFlutterError);
    expect(controller.reverse, throwsFlutterError);
    expect(() { controller.animateTo(0.5); }, throwsFlutterError);
    expect(controller.repeat, throwsFlutterError);

    controller.dispose();
    expect(controller.dispose, throwsFlutterError);
  });
286
}