-
-
Notifications
You must be signed in to change notification settings - Fork 947
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement closeToVector4 and closeToQuaternion by extracing a g…
…eneric CloseToVector base (#3480) This creates a generic `CloseToVector` class to be used to power the existing `closeToVector2` and `closeToVector3` and brand-new `closeToVector4` and `closeToQuaternion` matchers. This base class is not exposed (for now; but we could reconsider if demand arises).
- Loading branch information
1 parent
8db2476
commit 57e5851
Showing
10 changed files
with
303 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import 'package:flame_test/src/is_close_to_vector.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:vector_math/vector_math.dart'; | ||
|
||
/// Returns a matcher which checks if the argument is a Quaternion within | ||
/// distance [epsilon] of [quaternion]. For example: | ||
/// | ||
/// ```dart | ||
/// expect( | ||
/// rotation, | ||
/// closeToQuaternion(Quaternion.axisAngle(Vector3(1, 0, 0), pi / 2)), | ||
/// ); | ||
/// ``` | ||
Matcher closeToQuaternion(Quaternion quaternion, [double epsilon = 1e-15]) { | ||
return _IsCloseToQuaternion(quaternion, epsilon); | ||
} | ||
|
||
class _IsCloseToQuaternion extends IsCloseToVector<Quaternion> { | ||
const _IsCloseToQuaternion(super.value, super.epsilon); | ||
|
||
@override | ||
double dist(Quaternion a, Quaternion b) => (a - b).length; | ||
|
||
@override | ||
List<double> storage(Quaternion value) => value.storage; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import 'package:flame_test/src/is_close_to_vector.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:vector_math/vector_math.dart'; | ||
|
||
/// Returns a matcher which checks if the argument is a 4d vector within | ||
/// distance [epsilon] of [vector]. For example: | ||
/// | ||
/// ```dart | ||
/// expect(matrix4.row1, closeToVector4(Vector4(1, 0, 0, 1))); | ||
/// expect(matrix4.row2, closeToVector4(Vector4(0, 1, 0, -1), 1e-10)); | ||
/// ``` | ||
Matcher closeToVector4(Vector4 vector, [double epsilon = 1e-15]) { | ||
return _IsCloseToVector4(vector, epsilon); | ||
} | ||
|
||
class _IsCloseToVector4 extends IsCloseToVector<Vector4> { | ||
const _IsCloseToVector4(super.value, super.epsilon); | ||
|
||
@override | ||
double dist(Vector4 a, Vector4 b) => (a - b).length; | ||
|
||
@override | ||
List<double> storage(Vector4 value) => value.storage; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
abstract class IsCloseToVector<V> extends Matcher { | ||
const IsCloseToVector(this._value, this._epsilon); | ||
|
||
final V _value; | ||
final double _epsilon; | ||
|
||
double dist(V a, V b); | ||
List<double> storage(V value); | ||
|
||
@override | ||
bool matches(dynamic item, Map matchState) { | ||
return (item is V) && dist(item, _value) <= _epsilon; | ||
} | ||
|
||
@override | ||
Description describe(Description description) { | ||
final coords = storage(_value).join(', '); | ||
return description.add('a $V object within $_epsilon of ($coords)'); | ||
} | ||
|
||
@override | ||
Description describeMismatch( | ||
dynamic item, | ||
Description mismatchDescription, | ||
Map matchState, | ||
bool verbose, | ||
) { | ||
if (item is! V) { | ||
return mismatchDescription.add('is not an instance of $V'); | ||
} | ||
final distance = dist(item, _value); | ||
return mismatchDescription.add('is at distance $distance'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import 'package:flame_test/flame_test.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:vector_math/vector_math.dart'; | ||
|
||
void main() { | ||
group('closeToQuaternion', () { | ||
test('matches normally', () { | ||
expect( | ||
Quaternion.fromRotation(Matrix3.identity()), | ||
closeToQuaternion(Quaternion(0, 0, 0, 1)), | ||
); | ||
expect( | ||
Quaternion(-14, 99, -99, 14), | ||
closeToQuaternion(Quaternion(-14, 99, -99, 14)), | ||
); | ||
expect( | ||
Quaternion(1e-20, -1e-16, 0, -0), | ||
closeToQuaternion(Quaternion(0, 0, 0, 0)), | ||
); | ||
|
||
expect( | ||
Quaternion(1.0001, 2.0, -1.0001, -0), | ||
closeToQuaternion(Quaternion(1, 2, -1, 0), 0.01), | ||
); | ||
expect( | ||
Quaternion(5, 9, 11, 15), | ||
closeToQuaternion(Quaternion(10, 10, 10, 10), 10), | ||
); | ||
}); | ||
|
||
test('fails on type mismatch', () { | ||
try { | ||
expect(4.14, closeToQuaternion(Quaternion(0, 0, 0, 0))); | ||
} on TestFailure catch (e) { | ||
expect( | ||
e.message, | ||
contains( | ||
'Expected: a Quaternion object within 1e-15 of ' | ||
'(0.0, 0.0, 0.0, 0.0)', | ||
), | ||
); | ||
expect(e.message, contains('Actual: <4.14>')); | ||
expect(e.message, contains('Which: is not an instance of Quaternion')); | ||
} | ||
}); | ||
|
||
test('fails on value mismatch', () { | ||
try { | ||
expect( | ||
Quaternion(101, 217, 100, 0), | ||
closeToQuaternion(Quaternion(100, 220, 101, 0)), | ||
); | ||
} on TestFailure catch (e) { | ||
expect( | ||
e.message, | ||
contains( | ||
'Expected: a Quaternion object within 1e-15 of ' | ||
'(100.0, 220.0, 101.0, 0.0)', | ||
), | ||
); | ||
expect( | ||
e.message, | ||
contains('Actual: Quaternion:<101.0, 217.0, 100.0 @ 0.0>'), | ||
); | ||
expect(e.message, contains('Which: is at distance 3.3166247903554')); | ||
} | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import 'package:flame_test/src/close_to_vector4.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:vector_math/vector_math.dart'; | ||
|
||
void main() { | ||
group('closeToVector4', () { | ||
test('matches normally', () { | ||
expect(Vector4.zero(), closeToVector4(Vector4(0, 0, 0, 0))); | ||
expect( | ||
Vector4(-14, 99, -99, 14), | ||
closeToVector4(Vector4(-14, 99, -99, 14)), | ||
); | ||
expect( | ||
Vector4(1e-20, -1e-16, 0, -0), | ||
closeToVector4(Vector4(0, 0, 0, 0)), | ||
); | ||
|
||
expect( | ||
Vector4(1.0001, 2.0, -1.0001, -0), | ||
closeToVector4(Vector4(1, 2, -1, 0), 0.01), | ||
); | ||
expect(Vector4(5, 9, 11, 15), closeToVector4(Vector4.all(10), 10)); | ||
}); | ||
|
||
test('fails on type mismatch - double', () { | ||
try { | ||
expect(4.14, closeToVector4(Vector4.zero())); | ||
} on TestFailure catch (e) { | ||
expect( | ||
e.message, | ||
contains( | ||
'Expected: a Vector4 object within 1e-15 of (0.0, 0.0, 0.0, 0.0)', | ||
), | ||
); | ||
expect(e.message, contains('Actual: <4.14>')); | ||
expect(e.message, contains('Which: is not an instance of Vector4')); | ||
} | ||
}); | ||
|
||
test('fails on type mismatch - vector2', () { | ||
try { | ||
expect(Vector2(1, 2), closeToVector4(Vector4.zero())); | ||
} on TestFailure catch (e) { | ||
expect( | ||
e.message, | ||
contains( | ||
'Expected: a Vector4 object within 1e-15 of (0.0, 0.0, 0.0, 0.0)', | ||
), | ||
); | ||
expect(e.message, contains('Actual: Vector2:<[1.0,2.0]>')); | ||
expect(e.message, contains('Which: is not an instance of Vector4')); | ||
} | ||
}); | ||
|
||
test('fails on type mismatch - vector3', () { | ||
try { | ||
expect(Vector3(1, 2, 3), closeToVector4(Vector4.zero())); | ||
} on TestFailure catch (e) { | ||
expect( | ||
e.message, | ||
contains( | ||
'Expected: a Vector4 object within 1e-15 of (0.0, 0.0, 0.0, 0.0)', | ||
), | ||
); | ||
expect(e.message, contains('Actual: Vector3:<[1.0,2.0,3.0]>')); | ||
expect(e.message, contains('Which: is not an instance of Vector4')); | ||
} | ||
}); | ||
|
||
test('fails on value mismatch', () { | ||
try { | ||
expect( | ||
Vector4(101, 217, 100, 0), | ||
closeToVector4(Vector4(100, 220, 101, 0)), | ||
); | ||
} on TestFailure catch (e) { | ||
expect( | ||
e.message, | ||
contains( | ||
'Expected: a Vector4 object within 1e-15 of ' | ||
'(100.0, 220.0, 101.0, 0.0)', | ||
), | ||
); | ||
expect( | ||
e.message, | ||
contains('Actual: Vector4:<101.0,217.0,100.0,0.0>'), | ||
); | ||
expect(e.message, contains('Which: is at distance 3.3166247903554')); | ||
} | ||
}); | ||
}); | ||
} |
Oops, something went wrong.