Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit a77e7bc

Browse files
authored
[web] Update the within() matcher to be more useful (#39288)
* [web] Add the moreOrLessEquals matcher * address review comments * use within() instead * fix wasm tests
1 parent 616ecd8 commit a77e7bc

File tree

4 files changed

+60
-56
lines changed

4 files changed

+60
-56
lines changed

lib/web_ui/test/engine/canvas_test.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import 'package:ui/src/engine.dart';
1111

1212
import 'package:ui/ui.dart' as ui;
1313

14+
import '../matchers.dart';
15+
1416
void main() {
1517
internalBootstrapBrowserTest(() => testMain);
1618
}
@@ -31,7 +33,7 @@ void runCanvasTests({required bool deviceClipRoundsOut}) {
3133
expect(value.length, equals(16));
3234
for (int r = 0; r < 4; r++) {
3335
for (int c = 0; c < 4; c++) {
34-
expect(value[r*4 + c], closeTo(expected[r*4 + c], 1e-10));
36+
expect(value[r*4 + c], within(from: expected[r*4 + c]));
3537
}
3638
}
3739
}

lib/web_ui/test/geometry_test.dart

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import 'package:test/test.dart';
1313

1414
import 'package:ui/ui.dart';
1515

16+
import 'matchers.dart';
17+
1618
void main() {
1719
internalBootstrapBrowserTest(() => testMain);
1820
}
@@ -31,34 +33,32 @@ void testMain() {
3133
});
3234
test('Offset.fromDirection', () {
3335
expect(Offset.fromDirection(0.0, 0.0), const Offset(0.0, 0.0));
34-
expect(Offset.fromDirection(pi / 2.0).dx,
35-
closeTo(0.0, 1e-12)); // aah, floating point math. i love you so.
36-
expect(Offset.fromDirection(pi / 2.0).dy, 1.0);
37-
expect(Offset.fromDirection(-pi / 2.0).dx, closeTo(0.0, 1e-12));
38-
expect(Offset.fromDirection(-pi / 2.0).dy, -1.0);
36+
// aah, floating point math. i love you so.
37+
expect(Offset.fromDirection(pi / 2.0), within(from: const Offset(0.0, 1.0)));
38+
expect(Offset.fromDirection(-pi / 2.0), within(from: const Offset(0.0, -1.0)));
3939
expect(Offset.fromDirection(0.0), const Offset(1.0, 0.0));
40-
expect(Offset.fromDirection(pi / 4.0).dx,
41-
closeTo(1.0 / math.sqrt(2.0), 1e-12));
42-
expect(Offset.fromDirection(pi / 4.0).dy,
43-
closeTo(1.0 / math.sqrt(2.0), 1e-12));
44-
expect(Offset.fromDirection(-pi / 4.0).dx,
45-
closeTo(1.0 / math.sqrt(2.0), 1e-12));
46-
expect(Offset.fromDirection(-pi / 4.0).dy,
47-
closeTo(-1.0 / math.sqrt(2.0), 1e-12));
48-
expect(Offset.fromDirection(pi).dx, -1.0);
49-
expect(Offset.fromDirection(pi).dy, closeTo(0.0, 1e-12));
50-
expect(Offset.fromDirection(pi * 3.0 / 4.0).dx,
51-
closeTo(-1.0 / math.sqrt(2.0), 1e-12));
52-
expect(Offset.fromDirection(pi * 3.0 / 4.0).dy,
53-
closeTo(1.0 / math.sqrt(2.0), 1e-12));
54-
expect(Offset.fromDirection(-pi * 3.0 / 4.0).dx,
55-
closeTo(-1.0 / math.sqrt(2.0), 1e-12));
56-
expect(Offset.fromDirection(-pi * 3.0 / 4.0).dy,
57-
closeTo(-1.0 / math.sqrt(2.0), 1e-12));
40+
expect(
41+
Offset.fromDirection(pi / 4.0),
42+
within(from: Offset(1.0 / math.sqrt(2.0), 1.0 / math.sqrt(2.0))),
43+
);
44+
expect(
45+
Offset.fromDirection(-pi / 4.0),
46+
within(from: Offset(1.0 / math.sqrt(2.0), -1.0 / math.sqrt(2.0))),
47+
);
48+
expect(Offset.fromDirection(pi), within(from: const Offset(-1.0, 0.0)));
49+
expect(
50+
Offset.fromDirection(pi * 3.0 / 4.0),
51+
within(from: Offset(-1.0 / math.sqrt(2.0), 1.0 / math.sqrt(2.0))),
52+
);
53+
expect(
54+
Offset.fromDirection(-pi * 3.0 / 4.0),
55+
within(from: Offset(-1.0 / math.sqrt(2.0), -1.0 / math.sqrt(2.0))),
56+
);
5857
expect(Offset.fromDirection(0.0, 2.0), const Offset(2.0, 0.0));
5958
expect(
60-
Offset.fromDirection(pi / 6, 2.0).dx, closeTo(math.sqrt(3.0), 1e-12));
61-
expect(Offset.fromDirection(pi / 6, 2.0).dy, closeTo(1.0, 1e-12));
59+
Offset.fromDirection(pi / 6, 2.0),
60+
within(from: Offset(math.sqrt(3.0), 1.0)),
61+
);
6262
});
6363
test('Size.aspectRatio', () {
6464
expect(const Size(0.0, 0.0).aspectRatio, 0.0);

lib/web_ui/test/lerp_test.dart

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@ import 'package:test/test.dart';
77

88
import 'package:ui/ui.dart';
99

10-
/// The epsilon of tolerable double precision error.
11-
///
12-
/// This is used in various places in the framework to allow for floating point
13-
/// precision loss in calculations. Differences below this threshold are safe
14-
/// to disregard.
15-
const double precisionErrorTolerance = 1e-10;
10+
import 'matchers.dart';
1611

1712
void main() {
1813
internalBootstrapBrowserTest(() => testMain);
@@ -31,19 +26,19 @@ void testMain() {
3126
});
3227

3328
test('lerpDouble should treat a null input as 0 if the other input is non-null', () {
34-
expect(lerpDouble(null, 10.0, 0.25), closeTo(2.5, precisionErrorTolerance));
35-
expect(lerpDouble(10.0, null, 0.25), closeTo(7.5, precisionErrorTolerance));
29+
expect(lerpDouble(null, 10.0, 0.25), within(from: 2.5));
30+
expect(lerpDouble(10.0, null, 0.25), within(from: 7.5));
3631

37-
expect(lerpDouble(null, 10, 0.25), closeTo(2.5, precisionErrorTolerance));
38-
expect(lerpDouble(10, null, 0.25), closeTo(7.5, precisionErrorTolerance));
32+
expect(lerpDouble(null, 10, 0.25), within(from: 2.5));
33+
expect(lerpDouble(10, null, 0.25), within(from: 7.5));
3934
});
4035

4136
test('lerpDouble should handle interpolation values < 0.0', () {
42-
expect(lerpDouble(0.0, 10.0, -5.0), closeTo(-50.0, precisionErrorTolerance));
43-
expect(lerpDouble(10.0, 0.0, -5.0), closeTo(60.0, precisionErrorTolerance));
37+
expect(lerpDouble(0.0, 10.0, -5.0), within(from: -50.0));
38+
expect(lerpDouble(10.0, 0.0, -5.0), within(from: 60.0));
4439

45-
expect(lerpDouble(0, 10, -5), closeTo(-50, precisionErrorTolerance));
46-
expect(lerpDouble(10, 0, -5), closeTo(60, precisionErrorTolerance));
40+
expect(lerpDouble(0, 10, -5), within(from: -50.0));
41+
expect(lerpDouble(10, 0, -5), within(from: 60.0));
4742
});
4843

4944
test('lerpDouble should return the start value at 0.0', () {
@@ -55,17 +50,17 @@ void testMain() {
5550
});
5651

5752
test('lerpDouble should interpolate between two values', () {
58-
expect(lerpDouble(0.0, 10.0, 0.25), closeTo(2.5, precisionErrorTolerance));
59-
expect(lerpDouble(10.0, 0.0, 0.25), closeTo(7.5, precisionErrorTolerance));
53+
expect(lerpDouble(0.0, 10.0, 0.25), within(from: 2.5));
54+
expect(lerpDouble(10.0, 0.0, 0.25), within(from: 7.5));
6055

61-
expect(lerpDouble(0, 10, 0.25), closeTo(2.5, precisionErrorTolerance));
62-
expect(lerpDouble(10, 0, 0.25), closeTo(7.5, precisionErrorTolerance));
56+
expect(lerpDouble(0, 10, 0.25), within(from: 2.5));
57+
expect(lerpDouble(10, 0, 0.25), within(from: 7.5));
6358

6459
// Exact answer: 20.0 - 1.0e-29
65-
expect(lerpDouble(10.0, 1.0e30, 1.0e-29), closeTo(20.0, precisionErrorTolerance));
60+
expect(lerpDouble(10.0, 1.0e30, 1.0e-29), within(from: 20.0));
6661

6762
// Exact answer: 5.0 + 5.0e29
68-
expect(lerpDouble(10.0, 1.0e30, 0.5), closeTo(5.0e29, precisionErrorTolerance));
63+
expect(lerpDouble(10.0, 1.0e30, 0.5), within(from: 5.0e29));
6964
});
7065

7166
test('lerpDouble should return the end value at 1.0', () {
@@ -80,11 +75,11 @@ void testMain() {
8075
});
8176

8277
test('lerpDouble should handle interpolation values > 1.0', () {
83-
expect(lerpDouble(0.0, 10.0, 5.0), closeTo(50.0, precisionErrorTolerance));
84-
expect(lerpDouble(10.0, 0.0, 5.0), closeTo(-40.0, precisionErrorTolerance));
78+
expect(lerpDouble(0.0, 10.0, 5.0), within(from: 50.0));
79+
expect(lerpDouble(10.0, 0.0, 5.0), within(from: -40.0));
8580

86-
expect(lerpDouble(0, 10, 5), closeTo(50, precisionErrorTolerance));
87-
expect(lerpDouble(10, 0, 5), closeTo(-40, precisionErrorTolerance));
81+
expect(lerpDouble(0, 10, 5), within(from: 50.0));
82+
expect(lerpDouble(10, 0, 5), within(from: -40.0));
8883
});
8984

9085
test('lerpDouble should return input value in all cases if begin/end are equal', () {

lib/web_ui/test/matchers.dart

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ import 'package:test/test.dart';
1515
import 'package:ui/src/engine.dart';
1616
import 'package:ui/ui.dart';
1717

18+
/// The epsilon of tolerable double precision error.
19+
///
20+
/// This is used in various places in the framework to allow for floating point
21+
/// precision loss in calculations. Differences below this threshold are safe
22+
/// to disregard.
23+
const double precisionErrorTolerance = 1e-10;
24+
1825
/// Enumerates all persisted surfaces in the tree rooted at [root].
1926
///
2027
/// If [root] is `null` returns all surfaces from the last rendered scene.
@@ -60,7 +67,7 @@ Iterable<PersistedOffset> enumerateOffsets([PersistedSurface? root]) {
6067
///
6168
/// This makes it useful for comparing numbers, [Color]s, [Offset]s and other
6269
/// sets of value for which a metric space is defined.
63-
typedef DistanceFunction<T> = num Function(T a, T b);
70+
typedef DistanceFunction<T> = double Function(T a, T b);
6471

6572
/// The type of a union of instances of [DistanceFunction<T>] for various types
6673
/// T.
@@ -73,7 +80,7 @@ typedef DistanceFunction<T> = num Function(T a, T b);
7380
///
7481
/// Calling an instance of this type must either be done dynamically, or by
7582
/// first casting it to a [DistanceFunction<T>] for some concrete T.
76-
typedef AnyDistanceFunction = num Function(Never a, Never b);
83+
typedef AnyDistanceFunction = double Function(Never a, Never b);
7784

7885
const Map<Type, AnyDistanceFunction> _kStandardDistanceFunctions =
7986
<Type, AnyDistanceFunction>{
@@ -85,7 +92,7 @@ const Map<Type, AnyDistanceFunction> _kStandardDistanceFunctions =
8592
Size: _sizeDistance,
8693
};
8794

88-
int _intDistance(int a, int b) => (b - a).abs();
95+
double _intDistance(int a, int b) => (b - a).abs().toDouble();
8996
double _doubleDistance(double a, double b) => (b - a).abs();
9097
double _offsetDistance(Offset a, Offset b) => (b - a).distance;
9198

@@ -131,8 +138,8 @@ double _sizeDistance(Size a, Size b) {
131138
/// [double]s and has an optional `epsilon` parameter.
132139
/// * [closeTo], which specializes in numbers only.
133140
Matcher within<T>({
134-
required num distance,
135141
required T from,
142+
double distance = precisionErrorTolerance,
136143
DistanceFunction<T>? distanceFunction,
137144
}) {
138145
distanceFunction ??= _kStandardDistanceFunctions[T] as DistanceFunction<T>?;
@@ -152,7 +159,7 @@ class _IsWithinDistance<T> extends Matcher {
152159

153160
final DistanceFunction<T> distanceFunction;
154161
final T value;
155-
final num epsilon;
162+
final double epsilon;
156163

157164
@override
158165
bool matches(Object? object, Map<dynamic, dynamic> matchState) {
@@ -163,7 +170,7 @@ class _IsWithinDistance<T> extends Matcher {
163170
return true;
164171
}
165172
final T test = object;
166-
final num distance = distanceFunction(test, value);
173+
final double distance = distanceFunction(test, value);
167174
if (distance < 0) {
168175
throw ArgumentError(
169176
'Invalid distance function was used to compare a ${value.runtimeType} '

0 commit comments

Comments
 (0)