Improve test coverage for gestures.dart (#4773)
This patch adds tests for some code paths we weren't hitting before and removes some dead code that couldn't be tested because it was unreachable.
This commit is contained in:
parent
2898768dde
commit
bb0c41f2a6
@ -2,22 +2,18 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import "dart:math" as math;
|
||||
import "dart:typed_data";
|
||||
import 'dart:math' as math;
|
||||
import 'dart:typed_data';
|
||||
|
||||
// TODO(abarth): Consider using vector_math.
|
||||
class _Vector {
|
||||
_Vector(int size)
|
||||
: _offset = 0, _length = size, _elements = new Float64List(size);
|
||||
|
||||
_Vector.fromValues(List<double> values)
|
||||
: _offset = 0, _length = values.length, _elements = values;
|
||||
_Vector(int size) : _offset = 0, _length = size, _elements = new Float64List(size);
|
||||
|
||||
_Vector.fromVOL(List<double> values, int offset, int length)
|
||||
: _offset = offset, _length = length, _elements = values;
|
||||
|
||||
final int _offset;
|
||||
|
||||
int get length => _length;
|
||||
final int _length;
|
||||
|
||||
final List<double> _elements;
|
||||
@ -35,26 +31,14 @@ class _Vector {
|
||||
}
|
||||
|
||||
double norm() => math.sqrt(this * this);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
String result = "";
|
||||
for (int i = 0; i < _length; i++) {
|
||||
if (i > 0)
|
||||
result += ", ";
|
||||
result += this[i].toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(abarth): Consider using vector_math.
|
||||
class _Matrix {
|
||||
_Matrix(int rows, int cols)
|
||||
: _rows = rows,
|
||||
_columns = cols,
|
||||
: _columns = cols,
|
||||
_elements = new Float64List(rows * cols);
|
||||
|
||||
final int _rows;
|
||||
final int _columns;
|
||||
final List<double> _elements;
|
||||
|
||||
@ -68,21 +52,6 @@ class _Matrix {
|
||||
row * _columns,
|
||||
_columns
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
String result = "";
|
||||
for (int i = 0; i < _rows; i++) {
|
||||
if (i > 0)
|
||||
result += "; ";
|
||||
for (int j = 0; j < _columns; j++) {
|
||||
if (j > 0)
|
||||
result += ", ";
|
||||
result += get(i, j).toString();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// An nth degree polynomial fit to a dataset.
|
||||
|
@ -456,23 +456,18 @@ class DelayedMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_Dela
|
||||
/// defaults to [kLongPressTimeout] to match [LongPressGestureRecognizer] but
|
||||
/// can be changed for specific behaviors.
|
||||
DelayedMultiDragGestureRecognizer({
|
||||
Duration delay: kLongPressTimeout
|
||||
}) : _delay = delay {
|
||||
this.delay: kLongPressTimeout
|
||||
}) {
|
||||
assert(delay != null);
|
||||
}
|
||||
|
||||
/// The amount of time the pointer must remain in the same place for the drag
|
||||
/// to be recognized.
|
||||
Duration get delay => _delay;
|
||||
Duration _delay;
|
||||
set delay(Duration value) {
|
||||
assert(value != null);
|
||||
_delay = value;
|
||||
}
|
||||
final Duration delay;
|
||||
|
||||
@override
|
||||
_DelayedPointerState createNewPointerState(PointerDownEvent event) {
|
||||
return new _DelayedPointerState(event.position, _delay);
|
||||
return new _DelayedPointerState(event.position, delay);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -16,15 +16,6 @@ class _Estimate {
|
||||
final Duration time;
|
||||
final int degree;
|
||||
final double confidence;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Estimate(xCoefficients: $xCoefficients, '
|
||||
'yCoefficients: $yCoefficients, '
|
||||
'time: $time, '
|
||||
'degree: $degree, '
|
||||
'confidence: $confidence)';
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _VelocityTrackerStrategy {
|
||||
@ -33,46 +24,20 @@ abstract class _VelocityTrackerStrategy {
|
||||
void clear();
|
||||
}
|
||||
|
||||
enum _Weighting {
|
||||
weightingNone,
|
||||
weightingDelta,
|
||||
weightingCentral,
|
||||
weightingRecent
|
||||
}
|
||||
|
||||
class _Movement {
|
||||
Duration eventTime = Duration.ZERO;
|
||||
Point position = Point.origin;
|
||||
}
|
||||
|
||||
typedef double _WeightChooser(int index);
|
||||
|
||||
class _LeastSquaresVelocityTrackerStrategy extends _VelocityTrackerStrategy {
|
||||
static const int kHistorySize = 20;
|
||||
static const int kHorizonMilliseconds = 100;
|
||||
|
||||
_LeastSquaresVelocityTrackerStrategy(this.degree, _Weighting weighting)
|
||||
: _index = 0, _movements = new List<_Movement>(kHistorySize) {
|
||||
switch (weighting) {
|
||||
case _Weighting.weightingNone:
|
||||
_chooseWeight = null;
|
||||
break;
|
||||
case _Weighting.weightingDelta:
|
||||
_chooseWeight = _weightDelta;
|
||||
break;
|
||||
case _Weighting.weightingCentral:
|
||||
_chooseWeight = _weightCentral;
|
||||
break;
|
||||
case _Weighting.weightingRecent:
|
||||
_chooseWeight = _weightRecent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_LeastSquaresVelocityTrackerStrategy(this.degree);
|
||||
|
||||
final int degree;
|
||||
final List<_Movement> _movements;
|
||||
_WeightChooser _chooseWeight;
|
||||
int _index;
|
||||
final List<_Movement> _movements = new List<_Movement>(kHistorySize);
|
||||
int _index = 0;
|
||||
|
||||
@override
|
||||
void addMovement(Duration timeStamp, Point position) {
|
||||
@ -104,7 +69,7 @@ class _LeastSquaresVelocityTrackerStrategy extends _VelocityTrackerStrategy {
|
||||
Point position = movement.position;
|
||||
x.add(position.x);
|
||||
y.add(position.y);
|
||||
w.add(_chooseWeight != null ? _chooseWeight(index) : 1.0);
|
||||
w.add(1.0);
|
||||
time.add(-age);
|
||||
index = (index == 0 ? kHistorySize : index) - 1;
|
||||
|
||||
@ -153,54 +118,6 @@ class _LeastSquaresVelocityTrackerStrategy extends _VelocityTrackerStrategy {
|
||||
_index = -1;
|
||||
}
|
||||
|
||||
double _weightDelta(int index) {
|
||||
// Weight points based on how much time elapsed between them and the next
|
||||
// point so that points that "cover" a shorter time span are weighed less.
|
||||
// delta 0ms: 0.5
|
||||
// delta 10ms: 1.0
|
||||
if (index == _index)
|
||||
return 1.0;
|
||||
int nextIndex = (index + 1) % kHistorySize;
|
||||
int deltaMilliseconds = (_movements[nextIndex].eventTime - _movements[index].eventTime).inMilliseconds;
|
||||
if (deltaMilliseconds < 0)
|
||||
return 0.5;
|
||||
if (deltaMilliseconds < 10)
|
||||
return 0.5 + deltaMilliseconds * 0.05;
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
double _weightCentral(int index) {
|
||||
// Weight points based on their age, weighing very recent and very old
|
||||
// points less.
|
||||
// age 0ms: 0.5
|
||||
// age 10ms: 1.0
|
||||
// age 50ms: 1.0
|
||||
// age 60ms: 0.5
|
||||
int ageMilliseconds = (_movements[_index].eventTime - _movements[index].eventTime).inMilliseconds;
|
||||
if (ageMilliseconds < 0)
|
||||
return 0.5;
|
||||
if (ageMilliseconds < 10)
|
||||
return 0.5 + ageMilliseconds * 0.05;
|
||||
if (ageMilliseconds < 50)
|
||||
return 1.0;
|
||||
if (ageMilliseconds < 60)
|
||||
return 0.5 + (60 - ageMilliseconds) * 0.05;
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
double _weightRecent(int index) {
|
||||
// Weight points based on their age, weighing older points less.
|
||||
// age 0ms: 1.0
|
||||
// age 50ms: 1.0
|
||||
// age 100ms: 0.5
|
||||
int ageMilliseconds = (_movements[_index].eventTime - _movements[index].eventTime).inMilliseconds;
|
||||
if (ageMilliseconds < 50)
|
||||
return 1.0;
|
||||
if (ageMilliseconds < 100)
|
||||
return 0.5 + (100 - ageMilliseconds) * 0.01;
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
_Movement _getMovement(int i) {
|
||||
_Movement result = _movements[i];
|
||||
if (result == null) {
|
||||
@ -310,6 +227,6 @@ class VelocityTracker {
|
||||
}
|
||||
|
||||
static _VelocityTrackerStrategy _createStrategy() {
|
||||
return new _LeastSquaresVelocityTrackerStrategy(2, _Weighting.weightingNone);
|
||||
return new _LeastSquaresVelocityTrackerStrategy(2);
|
||||
}
|
||||
}
|
||||
|
@ -128,4 +128,34 @@ void main() {
|
||||
|
||||
drag.dispose();
|
||||
});
|
||||
|
||||
testGesture('Clamp max velocity', (GestureTester tester) {
|
||||
HorizontalDragGestureRecognizer drag = new HorizontalDragGestureRecognizer();
|
||||
|
||||
Velocity velocity;
|
||||
drag.onEnd = (DragEndDetails details) {
|
||||
velocity = details.velocity;
|
||||
};
|
||||
|
||||
TestPointer pointer = new TestPointer(5);
|
||||
PointerDownEvent down = pointer.down(const Point(10.0, 25.0), timeStamp: const Duration(milliseconds: 10));
|
||||
drag.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
tester.route(down);
|
||||
tester.route(pointer.move(const Point(20.0, 25.0), timeStamp: const Duration(milliseconds: 10)));
|
||||
tester.route(pointer.move(const Point(30.0, 25.0), timeStamp: const Duration(milliseconds: 11)));
|
||||
tester.route(pointer.move(const Point(40.0, 25.0), timeStamp: const Duration(milliseconds: 12)));
|
||||
tester.route(pointer.move(const Point(50.0, 25.0), timeStamp: const Duration(milliseconds: 13)));
|
||||
tester.route(pointer.move(const Point(60.0, 25.0), timeStamp: const Duration(milliseconds: 14)));
|
||||
tester.route(pointer.move(const Point(70.0, 25.0), timeStamp: const Duration(milliseconds: 15)));
|
||||
tester.route(pointer.move(const Point(80.0, 25.0), timeStamp: const Duration(milliseconds: 16)));
|
||||
tester.route(pointer.move(const Point(90.0, 25.0), timeStamp: const Duration(milliseconds: 17)));
|
||||
tester.route(pointer.move(const Point(100.0, 25.0), timeStamp: const Duration(milliseconds: 18)));
|
||||
tester.route(pointer.move(const Point(110.0, 25.0), timeStamp: const Duration(milliseconds: 19)));
|
||||
tester.route(pointer.move(const Point(120.0, 25.0), timeStamp: const Duration(milliseconds: 20)));
|
||||
tester.route(pointer.up(timeStamp: const Duration(milliseconds: 20)));
|
||||
expect(velocity.pixelsPerSecond.dx, inInclusiveRange(0.99 * kMaxFlingVelocity, kMaxFlingVelocity));
|
||||
|
||||
drag.dispose();
|
||||
});
|
||||
}
|
22
packages/flutter/test/gestures/events_test.dart
Normal file
22
packages/flutter/test/gestures/events_test.dart
Normal file
@ -0,0 +1,22 @@
|
||||
// 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_test/flutter_test.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
||||
import 'gesture_tester.dart';
|
||||
|
||||
void main() {
|
||||
setUp(ensureGestureBinding);
|
||||
|
||||
testGesture('toString control tests', (GestureTester tester) {
|
||||
expect(new PointerDownEvent(), hasOneLineDescription);
|
||||
expect(new PointerDownEvent().toStringFull(), hasOneLineDescription);
|
||||
});
|
||||
|
||||
testGesture('nthMouseButton control tests', (GestureTester tester) {
|
||||
expect(nthMouseButton(2), kSecondaryMouseButton);
|
||||
expect(nthStylusButton(2), kSecondaryStylusButton);
|
||||
});
|
||||
}
|
@ -77,6 +77,34 @@ void main() {
|
||||
expect(events[2].runtimeType, equals(PointerUpEvent));
|
||||
});
|
||||
|
||||
test('Synthetic move events', () {
|
||||
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder();
|
||||
|
||||
PointerPacket packet = new PointerPacket();
|
||||
packet.pointers = <Pointer>[new Pointer(), new Pointer()];
|
||||
packet.pointers[0]
|
||||
..type = PointerType.down
|
||||
..kind = PointerKind.touch
|
||||
..x = 1.0
|
||||
..y = 3.0;
|
||||
packet.pointers[1]
|
||||
..type = PointerType.up
|
||||
..kind = PointerKind.touch
|
||||
..x = 10.0
|
||||
..y = 15.0;
|
||||
packet.encode(encoder);
|
||||
|
||||
List<PointerEvent> events = <PointerEvent>[];
|
||||
_binding.callback = (PointerEvent event) => events.add(event);
|
||||
|
||||
ui.window.onPointerPacket(encoder.message.buffer);
|
||||
expect(events.length, 3);
|
||||
expect(events[0].runtimeType, equals(PointerDownEvent));
|
||||
expect(events[1].runtimeType, equals(PointerMoveEvent));
|
||||
expect(events[1].delta, equals(const Offset(9.0, 12.0)));
|
||||
expect(events[2].runtimeType, equals(PointerUpEvent));
|
||||
});
|
||||
|
||||
test('Pointer cancel events', () {
|
||||
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder();
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'velocity_tracker_data.dart';
|
||||
|
||||
bool _withinTolerance(double actual, double expected) {
|
||||
@ -47,4 +47,14 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Velocity control test', () {
|
||||
Velocity velocity1 = new Velocity(pixelsPerSecond: const Offset(7.0, 0.0));
|
||||
Velocity velocity2 = new Velocity(pixelsPerSecond: const Offset(12.0, 0.0));
|
||||
expect(velocity1, equals(new Velocity(pixelsPerSecond: new Offset(7.0, 0.0))));
|
||||
expect(velocity1, isNot(equals(velocity2)));
|
||||
expect(velocity2 - velocity1, equals(new Velocity(pixelsPerSecond: new Offset(5.0, 0.0))));
|
||||
expect(velocity1.hashCode, isNot(equals(velocity2.hashCode)));
|
||||
expect(velocity1, hasOneLineDescription);
|
||||
});
|
||||
}
|
||||
|
16
packages/flutter/test/widget/hit_testing_test.dart
Normal file
16
packages/flutter/test/widget/hit_testing_test.dart
Normal file
@ -0,0 +1,16 @@
|
||||
// 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_test/flutter_test.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('toString control test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(new Center(child: new Text('Hello')));
|
||||
HitTestResult result = tester.hitTestOnBinding(Point.origin);
|
||||
expect(result, hasOneLineDescription);
|
||||
expect(result.path.first, hasOneLineDescription);
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user