mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[web] Update the within() matcher to be more useful (flutter/engine#39288)
* [web] Add the moreOrLessEquals matcher * address review comments * use within() instead * fix wasm tests
This commit is contained in:
parent
0f117282e4
commit
1df3bf7ab1
@ -11,6 +11,8 @@ import 'package:ui/src/engine.dart';
|
||||
|
||||
import 'package:ui/ui.dart' as ui;
|
||||
|
||||
import '../matchers.dart';
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
}
|
||||
@ -31,7 +33,7 @@ void runCanvasTests({required bool deviceClipRoundsOut}) {
|
||||
expect(value.length, equals(16));
|
||||
for (int r = 0; r < 4; r++) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
expect(value[r*4 + c], closeTo(expected[r*4 + c], 1e-10));
|
||||
expect(value[r*4 + c], within(from: expected[r*4 + c]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,8 @@ import 'package:test/test.dart';
|
||||
|
||||
import 'package:ui/ui.dart';
|
||||
|
||||
import 'matchers.dart';
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
}
|
||||
@ -31,34 +33,32 @@ void testMain() {
|
||||
});
|
||||
test('Offset.fromDirection', () {
|
||||
expect(Offset.fromDirection(0.0, 0.0), const Offset(0.0, 0.0));
|
||||
expect(Offset.fromDirection(pi / 2.0).dx,
|
||||
closeTo(0.0, 1e-12)); // aah, floating point math. i love you so.
|
||||
expect(Offset.fromDirection(pi / 2.0).dy, 1.0);
|
||||
expect(Offset.fromDirection(-pi / 2.0).dx, closeTo(0.0, 1e-12));
|
||||
expect(Offset.fromDirection(-pi / 2.0).dy, -1.0);
|
||||
// aah, floating point math. i love you so.
|
||||
expect(Offset.fromDirection(pi / 2.0), within(from: const Offset(0.0, 1.0)));
|
||||
expect(Offset.fromDirection(-pi / 2.0), within(from: const Offset(0.0, -1.0)));
|
||||
expect(Offset.fromDirection(0.0), const Offset(1.0, 0.0));
|
||||
expect(Offset.fromDirection(pi / 4.0).dx,
|
||||
closeTo(1.0 / math.sqrt(2.0), 1e-12));
|
||||
expect(Offset.fromDirection(pi / 4.0).dy,
|
||||
closeTo(1.0 / math.sqrt(2.0), 1e-12));
|
||||
expect(Offset.fromDirection(-pi / 4.0).dx,
|
||||
closeTo(1.0 / math.sqrt(2.0), 1e-12));
|
||||
expect(Offset.fromDirection(-pi / 4.0).dy,
|
||||
closeTo(-1.0 / math.sqrt(2.0), 1e-12));
|
||||
expect(Offset.fromDirection(pi).dx, -1.0);
|
||||
expect(Offset.fromDirection(pi).dy, closeTo(0.0, 1e-12));
|
||||
expect(Offset.fromDirection(pi * 3.0 / 4.0).dx,
|
||||
closeTo(-1.0 / math.sqrt(2.0), 1e-12));
|
||||
expect(Offset.fromDirection(pi * 3.0 / 4.0).dy,
|
||||
closeTo(1.0 / math.sqrt(2.0), 1e-12));
|
||||
expect(Offset.fromDirection(-pi * 3.0 / 4.0).dx,
|
||||
closeTo(-1.0 / math.sqrt(2.0), 1e-12));
|
||||
expect(Offset.fromDirection(-pi * 3.0 / 4.0).dy,
|
||||
closeTo(-1.0 / math.sqrt(2.0), 1e-12));
|
||||
expect(
|
||||
Offset.fromDirection(pi / 4.0),
|
||||
within(from: Offset(1.0 / math.sqrt(2.0), 1.0 / math.sqrt(2.0))),
|
||||
);
|
||||
expect(
|
||||
Offset.fromDirection(-pi / 4.0),
|
||||
within(from: Offset(1.0 / math.sqrt(2.0), -1.0 / math.sqrt(2.0))),
|
||||
);
|
||||
expect(Offset.fromDirection(pi), within(from: const Offset(-1.0, 0.0)));
|
||||
expect(
|
||||
Offset.fromDirection(pi * 3.0 / 4.0),
|
||||
within(from: Offset(-1.0 / math.sqrt(2.0), 1.0 / math.sqrt(2.0))),
|
||||
);
|
||||
expect(
|
||||
Offset.fromDirection(-pi * 3.0 / 4.0),
|
||||
within(from: Offset(-1.0 / math.sqrt(2.0), -1.0 / math.sqrt(2.0))),
|
||||
);
|
||||
expect(Offset.fromDirection(0.0, 2.0), const Offset(2.0, 0.0));
|
||||
expect(
|
||||
Offset.fromDirection(pi / 6, 2.0).dx, closeTo(math.sqrt(3.0), 1e-12));
|
||||
expect(Offset.fromDirection(pi / 6, 2.0).dy, closeTo(1.0, 1e-12));
|
||||
Offset.fromDirection(pi / 6, 2.0),
|
||||
within(from: Offset(math.sqrt(3.0), 1.0)),
|
||||
);
|
||||
});
|
||||
test('Size.aspectRatio', () {
|
||||
expect(const Size(0.0, 0.0).aspectRatio, 0.0);
|
||||
|
||||
@ -7,12 +7,7 @@ import 'package:test/test.dart';
|
||||
|
||||
import 'package:ui/ui.dart';
|
||||
|
||||
/// The epsilon of tolerable double precision error.
|
||||
///
|
||||
/// This is used in various places in the framework to allow for floating point
|
||||
/// precision loss in calculations. Differences below this threshold are safe
|
||||
/// to disregard.
|
||||
const double precisionErrorTolerance = 1e-10;
|
||||
import 'matchers.dart';
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
@ -31,19 +26,19 @@ void testMain() {
|
||||
});
|
||||
|
||||
test('lerpDouble should treat a null input as 0 if the other input is non-null', () {
|
||||
expect(lerpDouble(null, 10.0, 0.25), closeTo(2.5, precisionErrorTolerance));
|
||||
expect(lerpDouble(10.0, null, 0.25), closeTo(7.5, precisionErrorTolerance));
|
||||
expect(lerpDouble(null, 10.0, 0.25), within(from: 2.5));
|
||||
expect(lerpDouble(10.0, null, 0.25), within(from: 7.5));
|
||||
|
||||
expect(lerpDouble(null, 10, 0.25), closeTo(2.5, precisionErrorTolerance));
|
||||
expect(lerpDouble(10, null, 0.25), closeTo(7.5, precisionErrorTolerance));
|
||||
expect(lerpDouble(null, 10, 0.25), within(from: 2.5));
|
||||
expect(lerpDouble(10, null, 0.25), within(from: 7.5));
|
||||
});
|
||||
|
||||
test('lerpDouble should handle interpolation values < 0.0', () {
|
||||
expect(lerpDouble(0.0, 10.0, -5.0), closeTo(-50.0, precisionErrorTolerance));
|
||||
expect(lerpDouble(10.0, 0.0, -5.0), closeTo(60.0, precisionErrorTolerance));
|
||||
expect(lerpDouble(0.0, 10.0, -5.0), within(from: -50.0));
|
||||
expect(lerpDouble(10.0, 0.0, -5.0), within(from: 60.0));
|
||||
|
||||
expect(lerpDouble(0, 10, -5), closeTo(-50, precisionErrorTolerance));
|
||||
expect(lerpDouble(10, 0, -5), closeTo(60, precisionErrorTolerance));
|
||||
expect(lerpDouble(0, 10, -5), within(from: -50.0));
|
||||
expect(lerpDouble(10, 0, -5), within(from: 60.0));
|
||||
});
|
||||
|
||||
test('lerpDouble should return the start value at 0.0', () {
|
||||
@ -55,17 +50,17 @@ void testMain() {
|
||||
});
|
||||
|
||||
test('lerpDouble should interpolate between two values', () {
|
||||
expect(lerpDouble(0.0, 10.0, 0.25), closeTo(2.5, precisionErrorTolerance));
|
||||
expect(lerpDouble(10.0, 0.0, 0.25), closeTo(7.5, precisionErrorTolerance));
|
||||
expect(lerpDouble(0.0, 10.0, 0.25), within(from: 2.5));
|
||||
expect(lerpDouble(10.0, 0.0, 0.25), within(from: 7.5));
|
||||
|
||||
expect(lerpDouble(0, 10, 0.25), closeTo(2.5, precisionErrorTolerance));
|
||||
expect(lerpDouble(10, 0, 0.25), closeTo(7.5, precisionErrorTolerance));
|
||||
expect(lerpDouble(0, 10, 0.25), within(from: 2.5));
|
||||
expect(lerpDouble(10, 0, 0.25), within(from: 7.5));
|
||||
|
||||
// Exact answer: 20.0 - 1.0e-29
|
||||
expect(lerpDouble(10.0, 1.0e30, 1.0e-29), closeTo(20.0, precisionErrorTolerance));
|
||||
expect(lerpDouble(10.0, 1.0e30, 1.0e-29), within(from: 20.0));
|
||||
|
||||
// Exact answer: 5.0 + 5.0e29
|
||||
expect(lerpDouble(10.0, 1.0e30, 0.5), closeTo(5.0e29, precisionErrorTolerance));
|
||||
expect(lerpDouble(10.0, 1.0e30, 0.5), within(from: 5.0e29));
|
||||
});
|
||||
|
||||
test('lerpDouble should return the end value at 1.0', () {
|
||||
@ -80,11 +75,11 @@ void testMain() {
|
||||
});
|
||||
|
||||
test('lerpDouble should handle interpolation values > 1.0', () {
|
||||
expect(lerpDouble(0.0, 10.0, 5.0), closeTo(50.0, precisionErrorTolerance));
|
||||
expect(lerpDouble(10.0, 0.0, 5.0), closeTo(-40.0, precisionErrorTolerance));
|
||||
expect(lerpDouble(0.0, 10.0, 5.0), within(from: 50.0));
|
||||
expect(lerpDouble(10.0, 0.0, 5.0), within(from: -40.0));
|
||||
|
||||
expect(lerpDouble(0, 10, 5), closeTo(50, precisionErrorTolerance));
|
||||
expect(lerpDouble(10, 0, 5), closeTo(-40, precisionErrorTolerance));
|
||||
expect(lerpDouble(0, 10, 5), within(from: 50.0));
|
||||
expect(lerpDouble(10, 0, 5), within(from: -40.0));
|
||||
});
|
||||
|
||||
test('lerpDouble should return input value in all cases if begin/end are equal', () {
|
||||
|
||||
@ -15,6 +15,13 @@ import 'package:test/test.dart';
|
||||
import 'package:ui/src/engine.dart';
|
||||
import 'package:ui/ui.dart';
|
||||
|
||||
/// The epsilon of tolerable double precision error.
|
||||
///
|
||||
/// This is used in various places in the framework to allow for floating point
|
||||
/// precision loss in calculations. Differences below this threshold are safe
|
||||
/// to disregard.
|
||||
const double precisionErrorTolerance = 1e-10;
|
||||
|
||||
/// Enumerates all persisted surfaces in the tree rooted at [root].
|
||||
///
|
||||
/// If [root] is `null` returns all surfaces from the last rendered scene.
|
||||
@ -60,7 +67,7 @@ Iterable<PersistedOffset> enumerateOffsets([PersistedSurface? root]) {
|
||||
///
|
||||
/// This makes it useful for comparing numbers, [Color]s, [Offset]s and other
|
||||
/// sets of value for which a metric space is defined.
|
||||
typedef DistanceFunction<T> = num Function(T a, T b);
|
||||
typedef DistanceFunction<T> = double Function(T a, T b);
|
||||
|
||||
/// The type of a union of instances of [DistanceFunction<T>] for various types
|
||||
/// T.
|
||||
@ -73,7 +80,7 @@ typedef DistanceFunction<T> = num Function(T a, T b);
|
||||
///
|
||||
/// Calling an instance of this type must either be done dynamically, or by
|
||||
/// first casting it to a [DistanceFunction<T>] for some concrete T.
|
||||
typedef AnyDistanceFunction = num Function(Never a, Never b);
|
||||
typedef AnyDistanceFunction = double Function(Never a, Never b);
|
||||
|
||||
const Map<Type, AnyDistanceFunction> _kStandardDistanceFunctions =
|
||||
<Type, AnyDistanceFunction>{
|
||||
@ -85,7 +92,7 @@ const Map<Type, AnyDistanceFunction> _kStandardDistanceFunctions =
|
||||
Size: _sizeDistance,
|
||||
};
|
||||
|
||||
int _intDistance(int a, int b) => (b - a).abs();
|
||||
double _intDistance(int a, int b) => (b - a).abs().toDouble();
|
||||
double _doubleDistance(double a, double b) => (b - a).abs();
|
||||
double _offsetDistance(Offset a, Offset b) => (b - a).distance;
|
||||
|
||||
@ -131,8 +138,8 @@ double _sizeDistance(Size a, Size b) {
|
||||
/// [double]s and has an optional `epsilon` parameter.
|
||||
/// * [closeTo], which specializes in numbers only.
|
||||
Matcher within<T>({
|
||||
required num distance,
|
||||
required T from,
|
||||
double distance = precisionErrorTolerance,
|
||||
DistanceFunction<T>? distanceFunction,
|
||||
}) {
|
||||
distanceFunction ??= _kStandardDistanceFunctions[T] as DistanceFunction<T>?;
|
||||
@ -152,7 +159,7 @@ class _IsWithinDistance<T> extends Matcher {
|
||||
|
||||
final DistanceFunction<T> distanceFunction;
|
||||
final T value;
|
||||
final num epsilon;
|
||||
final double epsilon;
|
||||
|
||||
@override
|
||||
bool matches(Object? object, Map<dynamic, dynamic> matchState) {
|
||||
@ -163,7 +170,7 @@ class _IsWithinDistance<T> extends Matcher {
|
||||
return true;
|
||||
}
|
||||
final T test = object;
|
||||
final num distance = distanceFunction(test, value);
|
||||
final double distance = distanceFunction(test, value);
|
||||
if (distance < 0) {
|
||||
throw ArgumentError(
|
||||
'Invalid distance function was used to compare a ${value.runtimeType} '
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user