Commit 2b742289 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Fix several minor bugs and add many tests (#7506)

* MultiTapGestureRecognizer previously would assert if there was no
   competition.
 * GestureArenaTeam would always select the first recongizer as the
   winner even if a later recognizer actually accepted the pointer
   sequence.
 * debugPrintStack would fail a type check if maxFrames was non-null.
 * FractionalOffset.lerp would throw a null-pointer exception if its
   second argument was null.

Also, add a number of tests for previously untested lines of code.
parent ecc49726
...@@ -339,7 +339,7 @@ class FlutterError extends AssertionError { ...@@ -339,7 +339,7 @@ class FlutterError extends AssertionError {
void debugPrintStack({ String label, int maxFrames }) { void debugPrintStack({ String label, int maxFrames }) {
if (label != null) if (label != null)
debugPrint(label); debugPrint(label);
List<String> lines = StackTrace.current.toString().trimRight().split('\n'); Iterable<String> lines = StackTrace.current.toString().trimRight().split('\n');
if (maxFrames != null) if (maxFrames != null)
lines = lines.take(maxFrames); lines = lines.take(maxFrames);
debugPrint(FlutterError.defaultStackFilter(lines).join('\n')); debugPrint(FlutterError.defaultStackFilter(lines).join('\n'));
......
...@@ -49,6 +49,7 @@ class PointerEventConverter { ...@@ -49,6 +49,7 @@ class PointerEventConverter {
final Point position = new Point(datum.physicalX, datum.physicalY) / devicePixelRatio; final Point position = new Point(datum.physicalX, datum.physicalY) / devicePixelRatio;
final Duration timeStamp = datum.timeStamp; final Duration timeStamp = datum.timeStamp;
final PointerDeviceKind kind = datum.kind; final PointerDeviceKind kind = datum.kind;
assert(datum.change != null);
switch (datum.change) { switch (datum.change) {
case ui.PointerChange.add: case ui.PointerChange.add:
assert(!_pointers.containsKey(datum.device)); assert(!_pointers.containsKey(datum.device));
...@@ -325,10 +326,6 @@ class PointerEventConverter { ...@@ -325,10 +326,6 @@ class PointerEventConverter {
radiusMax: datum.radiusMax radiusMax: datum.radiusMax
); );
break; break;
default:
// TODO(ianh): once https://github.com/flutter/flutter/issues/720 is
// done, add real support for PointerAddedEvent and PointerRemovedEvent
assert(false);
} }
} }
} }
......
...@@ -221,12 +221,6 @@ class DoubleTapGestureRecognizer extends GestureRecognizer { ...@@ -221,12 +221,6 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
String toStringShort() => 'double tap'; String toStringShort() => 'double tap';
} }
enum _TapResolution {
tap,
cancel
}
/// TapGesture represents a full gesture resulting from a single tap sequence, /// TapGesture represents a full gesture resulting from a single tap sequence,
/// as part of a [MultiTapGestureRecognizer]. Tap gestures are passive, meaning /// as part of a [MultiTapGestureRecognizer]. Tap gestures are passive, meaning
/// that they will not preempt any other arena member in play. /// that they will not preempt any other arena member in play.
...@@ -246,7 +240,7 @@ class _TapGesture extends _TapTracker { ...@@ -246,7 +240,7 @@ class _TapGesture extends _TapTracker {
if (longTapDelay > Duration.ZERO) { if (longTapDelay > Duration.ZERO) {
_timer = new Timer(longTapDelay, () { _timer = new Timer(longTapDelay, () {
_timer = null; _timer = null;
gestureRecognizer._handleLongTap(event.pointer, _lastPosition); gestureRecognizer._dispatchLongTap(event.pointer, _lastPosition);
}); });
} }
} }
...@@ -289,7 +283,7 @@ class _TapGesture extends _TapTracker { ...@@ -289,7 +283,7 @@ class _TapGesture extends _TapTracker {
void reject() { void reject() {
stopTrackingPointer(handleEvent); stopTrackingPointer(handleEvent);
gestureRecognizer._resolveTap(pointer, _TapResolution.cancel, null); gestureRecognizer._dispatchCancel(pointer);
} }
void cancel() { void cancel() {
...@@ -303,9 +297,8 @@ class _TapGesture extends _TapTracker { ...@@ -303,9 +297,8 @@ class _TapGesture extends _TapTracker {
void _check() { void _check() {
if (_wonArena && _finalPosition != null) if (_wonArena && _finalPosition != null)
gestureRecognizer._resolveTap(pointer, _TapResolution.tap, _finalPosition); gestureRecognizer._dispatchTap(pointer, _finalPosition);
} }
} }
/// Recognizes taps on a per-pointer basis. /// Recognizes taps on a per-pointer basis.
...@@ -365,31 +358,33 @@ class MultiTapGestureRecognizer extends GestureRecognizer { ...@@ -365,31 +358,33 @@ class MultiTapGestureRecognizer extends GestureRecognizer {
@override @override
void acceptGesture(int pointer) { void acceptGesture(int pointer) {
assert(_gestureMap.containsKey(pointer)); assert(_gestureMap.containsKey(pointer));
_gestureMap[pointer]?.accept(); _gestureMap[pointer].accept();
assert(!_gestureMap.containsKey(pointer));
} }
@override @override
void rejectGesture(int pointer) { void rejectGesture(int pointer) {
assert(_gestureMap.containsKey(pointer)); assert(_gestureMap.containsKey(pointer));
_gestureMap[pointer]?.reject(); _gestureMap[pointer].reject();
assert(!_gestureMap.containsKey(pointer)); assert(!_gestureMap.containsKey(pointer));
} }
void _resolveTap(int pointer, _TapResolution resolution, Point globalPosition) { void _dispatchCancel(int pointer) {
assert(_gestureMap.containsKey(pointer));
_gestureMap.remove(pointer); _gestureMap.remove(pointer);
if (resolution == _TapResolution.tap) { if (onTapCancel != null)
if (onTapUp != null) invokeCallback/*<Null>*/('onTapCancel', () => onTapCancel(pointer)); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
invokeCallback/*<Null>*/('onTapUp', () => onTapUp(pointer, new TapUpDetails(globalPosition: globalPosition))); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504 }
if (onTap != null)
invokeCallback/*<Null>*/('onTap', () => onTap(pointer)); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504 void _dispatchTap(int pointer, Point globalPosition) {
} else { assert(_gestureMap.containsKey(pointer));
if (onTapCancel != null) _gestureMap.remove(pointer);
invokeCallback/*<Null>*/('onTapCancel', () => onTapCancel(pointer)); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504 if (onTapUp != null)
} invokeCallback/*<Null>*/('onTapUp', () => onTapUp(pointer, new TapUpDetails(globalPosition: globalPosition))); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
if (onTap != null)
invokeCallback/*<Null>*/('onTap', () => onTap(pointer)); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
} }
void _handleLongTap(int pointer, Point lastPosition) { void _dispatchLongTap(int pointer, Point lastPosition) {
assert(_gestureMap.containsKey(pointer)); assert(_gestureMap.containsKey(pointer));
if (onLongTapDown != null) if (onLongTapDown != null)
invokeCallback/*<Null>*/('onLongTapDown', () => onLongTapDown(pointer, new TapDownDetails(globalPosition: lastPosition))); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504 invokeCallback/*<Null>*/('onLongTapDown', () => onLongTapDown(pointer, new TapDownDetails(globalPosition: lastPosition))); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
...@@ -397,7 +392,7 @@ class MultiTapGestureRecognizer extends GestureRecognizer { ...@@ -397,7 +392,7 @@ class MultiTapGestureRecognizer extends GestureRecognizer {
@override @override
void dispose() { void dispose() {
List<_TapGesture> localGestures = new List<_TapGesture>.from(_gestureMap.values); final List<_TapGesture> localGestures = new List<_TapGesture>.from(_gestureMap.values);
for (_TapGesture gesture in localGestures) for (_TapGesture gesture in localGestures)
gesture.cancel(); gesture.cancel();
// Rejection of each gesture should cause it to be removed from our map // Rejection of each gesture should cause it to be removed from our map
......
...@@ -33,9 +33,11 @@ class _CombiningGestureArenaMember extends GestureArenaMember { ...@@ -33,9 +33,11 @@ class _CombiningGestureArenaMember extends GestureArenaMember {
assert(_pointer == pointer); assert(_pointer == pointer);
assert(_winner != null || _members.isNotEmpty); assert(_winner != null || _members.isNotEmpty);
_close(); _close();
_winner ??= _members.removeAt(0); _winner ??= _members[0];
for (GestureArenaMember member in _members) for (GestureArenaMember member in _members) {
member.rejectGesture(pointer); if (member != _winner)
member.rejectGesture(pointer);
}
_winner.acceptGesture(pointer); _winner.acceptGesture(pointer);
} }
...@@ -72,7 +74,7 @@ class _CombiningGestureArenaMember extends GestureArenaMember { ...@@ -72,7 +74,7 @@ class _CombiningGestureArenaMember extends GestureArenaMember {
_entry.resolve(disposition); _entry.resolve(disposition);
} else { } else {
assert(disposition == GestureDisposition.accepted); assert(disposition == GestureDisposition.accepted);
_winner ?? member; _winner ??= member;
_entry.resolve(disposition); _entry.resolve(disposition);
} }
} }
......
...@@ -141,7 +141,7 @@ class FractionalOffset { ...@@ -141,7 +141,7 @@ class FractionalOffset {
if (a == null) if (a == null)
return new FractionalOffset(b.dx * t, b.dy * t); return new FractionalOffset(b.dx * t, b.dy * t);
if (b == null) if (b == null)
return new FractionalOffset(b.dx * (1.0 - t), b.dy * (1.0 - t)); return new FractionalOffset(a.dx * (1.0 - t), a.dy * (1.0 - t));
return new FractionalOffset(ui.lerpDouble(a.dx, b.dx, t), ui.lerpDouble(a.dy, b.dy, t)); return new FractionalOffset(ui.lerpDouble(a.dx, b.dx, t), ui.lerpDouble(a.dy, b.dy, t));
} }
......
...@@ -112,4 +112,40 @@ void main() { ...@@ -112,4 +112,40 @@ void main() {
expect(animation, hasOneLineDescription); expect(animation, hasOneLineDescription);
expect(animation.toString(), contains('no next')); expect(animation.toString(), contains('no next'));
}); });
test('AnimationMean control test', () {
AnimationController left = new AnimationController(
value: 0.5,
vsync: const TestVSync(),
);
AnimationController right = new AnimationController(
vsync: const TestVSync(),
);
AnimationMean mean = new AnimationMean(left: left, right: right);
expect(mean, hasOneLineDescription);
expect(mean.value, equals(0.25));
List<double> log = <double>[];
void logValue() {
log.add(mean.value);
}
mean.addListener(logValue);
right.value = 1.0;
expect(mean.value, equals(0.75));
expect(log, equals(<double>[0.75]));
log.clear();
mean.removeListener(logValue);
left.value = 0.0;
expect(mean.value, equals(0.50));
expect(log, isEmpty);
});
} }
...@@ -41,4 +41,12 @@ void main() { ...@@ -41,4 +41,12 @@ void main() {
expect(tween.lerp(0.5), 7); expect(tween.lerp(0.5), 7);
expect(tween.lerp(0.7), 8); expect(tween.lerp(0.7), 8);
}); });
test('RectTween', () {
Rect a = new Rect.fromLTWH(5.0, 3.0, 7.0, 11.0);
Rect b = new Rect.fromLTWH(8.0, 12.0, 14.0, 18.0);
RectTween tween = new RectTween(begin: a, end: b);
expect(tween.lerp(0.5), equals(Rect.lerp(a, b, 0.5)));
expect(tween, hasOneLineDescription);
});
} }
// 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.
import 'package:flutter/foundation.dart';
import 'package:test/test.dart';
import 'capture_output.dart';
void main() {
test('debugPrintStack', () {
final List<String> log = captureOutput(() {
debugPrintStack(label: 'Example label', maxFrames: 7);
});
expect(log[0], contains('Example label'));
expect(log[1], contains('debugPrintStack'));
});
test('debugPrintStack', () {
final List<String> log = captureOutput(() {
final FlutterErrorDetails details = new FlutterErrorDetails(
exception: 'Example exception',
stack: StackTrace.current,
library: 'Example library',
context: 'Example context',
informationCollector: (StringBuffer information) {
information.writeln('Example information');
},
);
FlutterError.dumpErrorToConsole(details);
});
expect(log[0], contains('EXAMPLE LIBRARY'));
expect(log[1], contains('Example context'));
expect(log[2], contains('Example exception'));
final String joined = log.join('\n');
expect(joined, contains('captureOutput'));
expect(joined, contains('\nExample information\n'));
});
}
// 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.
import 'package:flutter/foundation.dart';
import 'package:test/test.dart';
enum _TestEnum {
a, b, c, d, e, f, g, h,
}
void main() {
test('BitField control test', () {
BitField<_TestEnum> field = new BitField<_TestEnum>(8);
expect(field[_TestEnum.d], isFalse);
field[_TestEnum.d] = true;
field[_TestEnum.e] = true;
expect(field[_TestEnum.c], isFalse);
expect(field[_TestEnum.d], isTrue);
expect(field[_TestEnum.e], isTrue);
field[_TestEnum.e] = false;
expect(field[_TestEnum.c], isFalse);
expect(field[_TestEnum.d], isTrue);
expect(field[_TestEnum.e], isFalse);
field.reset();
expect(field[_TestEnum.c], isFalse);
expect(field[_TestEnum.d], isFalse);
expect(field[_TestEnum.e], isFalse);
field.reset(true);
expect(field[_TestEnum.c], isTrue);
expect(field[_TestEnum.d], isTrue);
expect(field[_TestEnum.e], isTrue);
});
test('BitField.filed control test', () {
BitField<_TestEnum> field1 = new BitField<_TestEnum>.filled(8, true);
expect(field1[_TestEnum.d], isTrue);
BitField<_TestEnum> field2 = new BitField<_TestEnum>.filled(8, false);
expect(field2[_TestEnum.d], isFalse);
});
}
...@@ -72,4 +72,22 @@ void main() { ...@@ -72,4 +72,22 @@ void main() {
expect(integers, equals(<int>[1, 2, 3, 4, 5])); expect(integers, equals(<int>[1, 2, 3, 4, 5]));
expect(yieldCount, equals(5)); expect(yieldCount, equals(5));
}); });
test('The Caching Iterable: take and skip', () {
Iterable<int> integers = new CachingIterable<int>(range(1, 5).iterator);
expect(yieldCount, equals(0));
Iterable<int> secondTwo = integers.skip(1).take(2);
expect(yieldCount, equals(0));
expect(secondTwo, equals(<int>[2, 3]));
expect(yieldCount, equals(3));
Iterable<int> result = integers.takeWhile((int i) => i < 4).skipWhile((int i) => i < 3);
expect(result, equals(<int>[3]));
expect(yieldCount, equals(4));
expect(integers, equals(<int>[1, 2, 3, 4, 5]));
expect(yieldCount, equals(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.
import 'dart:async';
import 'dart:ui' show VoidCallback;
List<String> captureOutput(VoidCallback fn) {
List<String> log = <String>[];
runZoned(fn, zoneSpecification: new ZoneSpecification(
print: (Zone self,
ZoneDelegate parent,
Zone zone,
String line) {
log.add(line);
},
));
return log;
}
...@@ -84,7 +84,7 @@ void main() { ...@@ -84,7 +84,7 @@ void main() {
log.clear(); log.clear();
}); });
testWidgets('ChangeNotifier with mutating listener', (WidgetTester tester) async { test('ChangeNotifier with mutating listener', () {
final TestNotifier test = new TestNotifier(); final TestNotifier test = new TestNotifier();
final List<String> log = <String>[]; final List<String> log = <String>[];
...@@ -114,7 +114,7 @@ void main() { ...@@ -114,7 +114,7 @@ void main() {
log.clear(); log.clear();
}); });
testWidgets('Merging change notifiers', (WidgetTester tester) async { test('Merging change notifiers', () {
final TestNotifier source1 = new TestNotifier(); final TestNotifier source1 = new TestNotifier();
final TestNotifier source2 = new TestNotifier(); final TestNotifier source2 = new TestNotifier();
final TestNotifier source3 = new TestNotifier(); final TestNotifier source3 = new TestNotifier();
...@@ -147,7 +147,7 @@ void main() { ...@@ -147,7 +147,7 @@ void main() {
log.clear(); log.clear();
}); });
testWidgets('Merging change notifiers ignores null', (WidgetTester tester) async { test('Merging change notifiers ignores null', () {
final TestNotifier source1 = new TestNotifier(); final TestNotifier source1 = new TestNotifier();
final TestNotifier source2 = new TestNotifier(); final TestNotifier source2 = new TestNotifier();
final List<String> log = <String>[]; final List<String> log = <String>[];
...@@ -161,4 +161,24 @@ void main() { ...@@ -161,4 +161,24 @@ void main() {
expect(log, <String>['listener', 'listener']); expect(log, <String>['listener', 'listener']);
log.clear(); log.clear();
}); });
test('Can dispose merged notifier', () {
final TestNotifier source1 = new TestNotifier();
final TestNotifier source2 = new TestNotifier();
final List<String> log = <String>[];
final ChangeNotifier merged = new Listenable.merge(<Listenable>[source1, source2]);
final VoidCallback listener = () { log.add('listener'); };
merged.addListener(listener);
source1.notify();
source2.notify();
expect(log, <String>['listener', 'listener']);
log.clear();
merged.dispose();
source1.notify();
source2.notify();
expect(log, isEmpty);
});
} }
...@@ -2,26 +2,11 @@ ...@@ -2,26 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:quiver/testing/async.dart'; import 'package:quiver/testing/async.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
List<String> captureOutput(VoidCallback fn) { import 'capture_output.dart';
List<String> log = <String>[];
runZoned(fn, zoneSpecification: new ZoneSpecification(
print: (Zone self,
ZoneDelegate parent,
Zone zone,
String line) {
log.add(line);
},
));
return log;
}
void main() { void main() {
test('debugPrint', () { test('debugPrint', () {
......
...@@ -13,7 +13,7 @@ class TestDrag extends Drag { ...@@ -13,7 +13,7 @@ class TestDrag extends Drag {
void main() { void main() {
setUp(ensureGestureBinding); setUp(ensureGestureBinding);
testGesture('Should recognize pan', (GestureTester tester) { testGesture('MultiDrag control test', (GestureTester tester) {
DelayedMultiDragGestureRecognizer drag = new DelayedMultiDragGestureRecognizer(); DelayedMultiDragGestureRecognizer drag = new DelayedMultiDragGestureRecognizer();
bool didStartDrag = false; bool didStartDrag = false;
......
// 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.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart';
import 'gesture_tester.dart';
class TestDrag extends Drag {
}
void main() {
setUp(ensureGestureBinding);
testGesture('Should recognize pan', (GestureTester tester) {
MultiTapGestureRecognizer tap = new MultiTapGestureRecognizer(longTapDelay: kLongPressTimeout);
List<String> log = <String>[];
tap.onTapDown = (int pointer, TapDownDetails details) { log.add('tap-down $pointer'); };
tap.onTapUp = (int pointer, TapUpDetails details) { log.add('tap-up $pointer'); };
tap.onTap = (int pointer) { log.add('tap $pointer'); };
tap.onLongTapDown = (int pointer, TapDownDetails details) { log.add('long-tap-down $pointer'); };
tap.onTapCancel = (int pointer) { log.add('tap-cancel $pointer'); };
TestPointer pointer5 = new TestPointer(5);
PointerDownEvent down5 = pointer5.down(const Point(10.0, 10.0));
tap.addPointer(down5);
tester.closeArena(5);
expect(log, <String>['tap-down 5']);
log.clear();
tester.route(down5);
expect(log, isEmpty);
TestPointer pointer6 = new TestPointer(6);
PointerDownEvent down6 = pointer6.down(const Point(15.0, 15.0));
tap.addPointer(down6);
tester.closeArena(6);
expect(log, <String>['tap-down 6']);
log.clear();
tester.route(down6);
expect(log, isEmpty);
tester.route(pointer5.move(const Point(11.0, 12.0)));
expect(log, isEmpty);
tester.route(pointer6.move(const Point(14.0, 13.0)));
expect(log, isEmpty);
tester.route(pointer5.up());
expect(log, <String>[
'tap-up 5',
'tap 5',
]);
log.clear();
tester.async.elapse(kLongPressTimeout + kPressTimeout);
expect(log, <String>['long-tap-down 6']);
log.clear();
tester.route(pointer6.move(const Point(4.0, 3.0)));
expect(log, <String>['tap-cancel 6']);
log.clear();
tester.route(pointer6.up());
expect(log, isEmpty);
tap.dispose();
});
}
// 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.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart';
import 'gesture_tester.dart';
void main() {
setUp(ensureGestureBinding);
testGesture('GestureArenaTeam rejection test', (GestureTester tester) {
GestureArenaTeam team = new GestureArenaTeam();
HorizontalDragGestureRecognizer horizontalDrag = new HorizontalDragGestureRecognizer()..team = team;
VerticalDragGestureRecognizer verticalDrag = new VerticalDragGestureRecognizer()..team = team;
TapGestureRecognizer tap = new TapGestureRecognizer();
expect(horizontalDrag.team, equals(team));
expect(verticalDrag.team, equals(team));
expect(tap.team, isNull);
List<String> log = <String>[];
horizontalDrag.onStart = (DragStartDetails details) { log.add('hoizontal-drag-start'); };
verticalDrag.onStart = (DragStartDetails details) { log.add('vertical-drag-start'); };
tap.onTap = () { log.add('tap'); };
void test(Offset delta) {
Point origin = const Point(10.0, 10.0);
TestPointer pointer = new TestPointer(5);
PointerDownEvent down = pointer.down(origin);
horizontalDrag.addPointer(down);
verticalDrag.addPointer(down);
tap.addPointer(down);
expect(log, isEmpty);
tester.closeArena(5);
expect(log, isEmpty);
tester.route(down);
expect(log, isEmpty);
tester.route(pointer.move(origin + delta));
tester.route(pointer.up());
}
test(Offset.zero);
expect(log, <String>['tap']);
log.clear();
test(const Offset(0.0, 30.0));
expect(log, <String>['vertical-drag-start']);
log.clear();
horizontalDrag.dispose();
verticalDrag.dispose();
tap.dispose();
});
}
...@@ -20,6 +20,9 @@ void main() { ...@@ -20,6 +20,9 @@ void main() {
expect(insets.collapsedSize, const Size(16.0, 20.0)); expect(insets.collapsedSize, const Size(16.0, 20.0));
expect(insets.flipped, const EdgeInsets.fromLTRB(11.0, 13.0, 5.0, 7.0)); expect(insets.flipped, const EdgeInsets.fromLTRB(11.0, 13.0, 5.0, 7.0));
expect(insets.along(Axis.horizontal), equals(16.0));
expect(insets.along(Axis.vertical), equals(20.0));
expect(insets.inflateRect(new Rect.fromLTRB(23.0, 32.0, 124.0, 143.0)), expect(insets.inflateRect(new Rect.fromLTRB(23.0, 32.0, 124.0, 143.0)),
new Rect.fromLTRB(18.0, 25.0, 135.0, 156.0)); new Rect.fromLTRB(18.0, 25.0, 135.0, 156.0));
...@@ -42,5 +45,9 @@ void main() { ...@@ -42,5 +45,9 @@ void main() {
expect(EdgeInsets.lerp(a, b, 0.25), equals(b * 0.625)); expect(EdgeInsets.lerp(a, b, 0.25), equals(b * 0.625));
expect(EdgeInsets.lerp(a, b, 0.25), equals(a + const EdgeInsets.all(2.5))); expect(EdgeInsets.lerp(a, b, 0.25), equals(a + const EdgeInsets.all(2.5)));
expect(EdgeInsets.lerp(a, b, 0.25), equals(b - const EdgeInsets.all(7.5))); expect(EdgeInsets.lerp(a, b, 0.25), equals(b - const EdgeInsets.all(7.5)));
expect(EdgeInsets.lerp(null, null, 0.25), isNull);
expect(EdgeInsets.lerp(null, b, 0.25), equals(b * 0.25));
expect(EdgeInsets.lerp(a, null, 0.25), equals(a * 0.75));
}); });
} }
// Copyright 2015 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.
import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('FractionalOffset control test', () {
const FractionalOffset offset = const FractionalOffset(0.5, 0.25);
expect(offset, hasOneLineDescription);
expect(offset.hashCode, equals(new FractionalOffset(0.5, 0.25).hashCode));
expect(offset / 2.0, const FractionalOffset(0.25, 0.125));
expect(offset ~/ 2.0, const FractionalOffset(0.0, 0.0));
expect(offset % 5.0, const FractionalOffset(0.5, 0.25));
});
test('FractionalOffset.lerp()', () {
FractionalOffset a = FractionalOffset.topLeft;
FractionalOffset b = FractionalOffset.topCenter;
expect(FractionalOffset.lerp(a, b, 0.25), equals(new FractionalOffset(0.125, 0.0)));
expect(FractionalOffset.lerp(null, null, 0.25), isNull);
expect(FractionalOffset.lerp(null, b, 0.25), equals(b * 0.25));
expect(FractionalOffset.lerp(a, null, 0.25), equals(a * 0.75));
});
}
// 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.
import 'package:flutter/physics.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('Clamped simulation', () {
GravitySimulation gravity = new GravitySimulation(9.81, 10.0, 0.0, 0.0);
ClampedSimulation clamped = new ClampedSimulation(gravity, xMin: 20.0, xMax: 100.0, dxMin: 7.0, dxMax: 11.0);
expect(clamped.x(0.0), equals(20.0));
expect(clamped.dx(0.0), equals(7.0));
expect(clamped.x(100.0), equals(100.0));
expect(clamped.dx(100.0), equals(11.0));
});
}
...@@ -70,6 +70,20 @@ void main() { ...@@ -70,6 +70,20 @@ void main() {
expect(friction.dx(1.0), closeTo(endVelocity, epsilon)); expect(friction.dx(1.0), closeTo(endVelocity, epsilon));
}); });
test('BoundedFrictionSimulation control test', () {
BoundedFrictionSimulation friction = new BoundedFrictionSimulation(0.3, 100.0, 400.0, 50.0, 150.0);
friction.tolerance = const Tolerance(velocity: 1.0);
expect(friction.isDone(0.0), false);
expect(friction.x(0.0), 100);
expect(friction.dx(0.0), 400.0);
expect(friction.x(1.0), equals(150.0));
expect(friction.isDone(1.0), true);
});
test('test_gravity', () { test('test_gravity', () {
GravitySimulation gravity = new GravitySimulation(200.0, 100.0, 600.0, 0.0); GravitySimulation gravity = new GravitySimulation(200.0, 100.0, 600.0, 0.0);
......
// 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.
import 'package:flutter/physics.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('Tolerance control test', () {
expect(Tolerance.defaultTolerance, hasOneLineDescription);
});
}
// Copyright 2015 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.
import 'package:flutter/scheduler.dart';
import 'package:test/test.dart';
void main() {
test('debugAssertAllSchedulerVarsUnset control test', () {
expect(() {
debugAssertAllSchedulerVarsUnset('Example test');
}, isNot(throws));
debugPrintBeginFrameBanner = true;
expect(() {
debugAssertAllSchedulerVarsUnset('Example test');
}, throws);
debugPrintBeginFrameBanner = false;
debugPrintEndFrameBanner = true;
expect(() {
debugAssertAllSchedulerVarsUnset('Example test');
}, throws);
debugPrintEndFrameBanner = false;
expect(() {
debugAssertAllSchedulerVarsUnset('Example test');
}, isNot(throws));
});
}
...@@ -66,4 +66,17 @@ void main() { ...@@ -66,4 +66,17 @@ void main() {
expect(ticker.isTicking, isFalse); expect(ticker.isTicking, isFalse);
expect(ticker.isActive, isFalse); expect(ticker.isActive, isFalse);
}); });
testWidgets('Ticker control test', (WidgetTester tester) async {
Ticker ticker;
void testFunction() {
ticker = new Ticker(null);
}
testFunction();
expect(ticker, hasOneLineDescription);
expect(ticker.toString(debugIncludeStack: true), contains('testFunction'));
});
} }
...@@ -24,10 +24,10 @@ void main() { ...@@ -24,10 +24,10 @@ void main() {
vsync: tester, vsync: tester,
child: const SizedBox( child: const SizedBox(
width: 100.0, width: 100.0,
height: 100.0 height: 100.0,
) ),
) ),
) ),
); );
RenderBox box = tester.renderObject(find.byType(AnimatedSize)); RenderBox box = tester.renderObject(find.byType(AnimatedSize));
...@@ -41,10 +41,10 @@ void main() { ...@@ -41,10 +41,10 @@ void main() {
vsync: tester, vsync: tester,
child: const SizedBox( child: const SizedBox(
width: 200.0, width: 200.0,
height: 200.0 height: 200.0,
) ),
) ),
) ),
); );
await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100));
...@@ -68,10 +68,10 @@ void main() { ...@@ -68,10 +68,10 @@ void main() {
vsync: tester, vsync: tester,
child: const SizedBox( child: const SizedBox(
width: 100.0, width: 100.0,
height: 100.0 height: 100.0,
) ),
) ),
) ),
); );
await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100));
...@@ -100,11 +100,11 @@ void main() { ...@@ -100,11 +100,11 @@ void main() {
vsync: tester, vsync: tester,
child: const SizedBox( child: const SizedBox(
width: 100.0, width: 100.0,
height: 100.0 height: 100.0,
) ),
) ),
) ),
) ),
); );
RenderBox box = tester.renderObject(find.byType(AnimatedSize)); RenderBox box = tester.renderObject(find.byType(AnimatedSize));
...@@ -121,11 +121,11 @@ void main() { ...@@ -121,11 +121,11 @@ void main() {
vsync: tester, vsync: tester,
child: const SizedBox( child: const SizedBox(
width: 200.0, width: 200.0,
height: 200.0 height: 200.0,
) ),
) ),
) ),
) ),
); );
await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100));
...@@ -143,10 +143,10 @@ void main() { ...@@ -143,10 +143,10 @@ void main() {
child: new AnimatedContainer( child: new AnimatedContainer(
duration: const Duration(milliseconds: 100), duration: const Duration(milliseconds: 100),
width: 100.0, width: 100.0,
height: 100.0 height: 100.0,
) ),
) ),
) ),
); );
RenderBox box = tester.renderObject(find.byType(AnimatedSize)); RenderBox box = tester.renderObject(find.byType(AnimatedSize));
...@@ -161,10 +161,10 @@ void main() { ...@@ -161,10 +161,10 @@ void main() {
child: new AnimatedContainer( child: new AnimatedContainer(
duration: const Duration(milliseconds: 100), duration: const Duration(milliseconds: 100),
width: 200.0, width: 200.0,
height: 200.0 height: 200.0,
) ),
) ),
) ),
); );
await tester.pump(const Duration(milliseconds: 1)); // register change await tester.pump(const Duration(milliseconds: 1)); // register change
...@@ -176,4 +176,37 @@ void main() { ...@@ -176,4 +176,37 @@ void main() {
expect(box.size.width, equals(200.0)); expect(box.size.width, equals(200.0));
expect(box.size.height, equals(200.0)); expect(box.size.height, equals(200.0));
}); });
testWidgets('AnimatedSize resync', (WidgetTester tester) async {
await tester.pumpWidget(
new Center(
child: new AnimatedSize(
duration: const Duration(milliseconds: 200),
vsync: const TestVSync(),
child: new SizedBox(
width: 100.0,
height: 100.0,
),
),
),
);
await tester.pumpWidget(
new Center(
child: new AnimatedSize(
duration: const Duration(milliseconds: 200),
vsync: tester,
child: new SizedBox(
width: 200.0,
height: 100.0,
),
),
),
);
await tester.pump(const Duration(milliseconds: 100));
RenderBox box = tester.renderObject(find.byType(AnimatedSize));
expect(box.size.width, equals(150.0));
});
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment