Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/web_ui/test/engine/canvas_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import 'package:ui/src/engine.dart';

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

import '../matchers.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand All @@ -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]));
}
}
}
Expand Down
50 changes: 25 additions & 25 deletions lib/web_ui/test/geometry_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import 'package:test/test.dart';

import 'package:ui/ui.dart';

import 'matchers.dart';

void main() {
internalBootstrapBrowserTest(() => testMain);
}
Expand All @@ -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);
Expand Down
43 changes: 19 additions & 24 deletions lib/web_ui/test/lerp_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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', () {
Expand All @@ -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', () {
Expand All @@ -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', () {
Expand Down
19 changes: 13 additions & 6 deletions lib/web_ui/test/matchers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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>{
Expand All @@ -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;

Expand Down Expand Up @@ -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>?;
Expand All @@ -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) {
Expand All @@ -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} '
Expand Down