From 16dd5e05906a7c0fe2def1dfca01c0d0ed2d2869 Mon Sep 17 00:00:00 2001 From: Seiji Emery Date: Sun, 21 Jun 2015 09:29:09 -0700 Subject: [PATCH] Added a custom test macro, QFUZZY_COMPARE (compares two values with an explicit error tolerance), and the infrastructure for defining more. Reworked physics test files, but they're a WIP. --- tests/QTestExtensions.hpp | 108 ++++++++ tests/physics/src/BulletUtilTests.cpp | 84 ++----- tests/physics/src/BulletUtilTests.h | 2 +- tests/physics/src/CollisionInfoTests.cpp | 116 +++++---- tests/physics/src/CollisionInfoTests.h | 2 - tests/physics/src/MeshMassPropertiesTests.cpp | 26 +- tests/physics/src/PhysicsTestUtil.h | 31 ++- tests/physics/src/ShapeColliderTests.cpp | 233 ++++-------------- tests/physics/src/ShapeColliderTests.h | 2 - 9 files changed, 274 insertions(+), 330 deletions(-) create mode 100644 tests/QTestExtensions.hpp diff --git a/tests/QTestExtensions.hpp b/tests/QTestExtensions.hpp new file mode 100644 index 0000000000..1bb0dfe111 --- /dev/null +++ b/tests/QTestExtensions.hpp @@ -0,0 +1,108 @@ +// +// QTestExtensions.hpp +// tests/ +// +// Created by Seiji Emery on 6/20/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#ifndef hifi_QTestExtensions_hpp +#define hifi_QTestExtensions_hpp + +#include +#include + +// Adds some additional functionality to QtTest (eg. explicitely defined fuzzy comparison +// of float and custom data types), and some extension mechanisms to provide other new +// functionality as needed. + + +// Generic function that reimplements the debugging output of a QCOMPARE failure via QFAIL. +// Use this to implement your own QCOMPARE-ish macros (see QEXPLICIT_FUZZY_COMPARE for +// more info). +template +void QTest_failWithMessage (const T & actual, const T & expected, const char * actual_expr, const char * expected_expr, int line, const char * file) +{ + +} + +// Generic function that reimplements the debugging output of a QCOMPARE failure via QFAIL. +// Use this to implement your own QCOMPARE-ish macros (see QEXPLICIT_FUZZY_COMPARE for +// more info). +// This version provides a callback to write additional messages. +// If the messages span more than one line, wrap them with '\n\t' to get proper indentation. +template +inline QString QTest_generateCompareFailureMessage (const char * failMessage, const T & actual, const T & expected, const char * actual_expr, const char * expected_expr, std::function writeAdditionalMessages) +{ + QString s1 = actual_expr, s2 = expected_expr; + int pad1_ = qMax(s2.length() - s1.length(), 0); + int pad2_ = qMax(s1.length() - s2.length(), 0); + + QString pad1 = QString(")").rightJustified(pad1_, ' '); + QString pad2 = QString(")").rightJustified(pad2_, ' '); + + QString msg; + QTextStream stream (&msg); + stream << failMessage << "\n\t" + "Actual: (" << actual_expr << pad1 << ": " << actual << "\n\t" + "Expected: (" << expected_expr << pad2 << ": " << expected << "\n\t"; + writeAdditionalMessages(stream); + return msg; +} + +template +inline QString QTest_generateCompareFailureMessage (const char * failMessage, const T & actual, const T & expected, const char * actual_expr, const char * expected_expr) +{ + QString s1 = actual_expr, s2 = expected_expr; + int pad1_ = qMax(s2.length() - s1.length(), 0); + int pad2_ = qMax(s1.length() - s2.length(), 0); + + QString pad1 = QString(")").rightJustified(pad1_, ' '); + QString pad2 = QString(")").rightJustified(pad2_, ' '); + + QString msg; + QTextStream stream (&msg); + stream << failMessage << "\n\t" + "Actual: (" << actual_expr << pad1 << ": " << actual << "\n\t" + "Expected: (" << expected_expr << pad2 << ": " << expected; + return msg; +} + +template +inline bool QTest_fuzzyCompare(const T & actual, const T & expected, const char * actual_expr, const char * expected_expr, int line, const char * file, const V & epsilon) +{ + if (fuzzyCompare(actual, expected) > epsilon) { + QTest::qFail(qPrintable(QTest_generateCompareFailureMessage("Compared values are not the same (fuzzy compare)", actual, expected, actual_expr, expected_expr, + [&] (QTextStream & stream) -> QTextStream & { + return stream << "Err tolerance: " << fuzzyCompare((actual), (expected)) << " > " << epsilon; + })), file, line); + return false; + } + return true; +} + +#define QFUZZY_COMPARE(actual, expected, epsilon) \ +do { \ + if (!QTest_fuzzyCompare(actual, expected, #actual, #expected, __LINE__, __FILE__, epsilon)) \ + return; \ +} while(0) + +// Note: this generates a message that looks something like the following: +// FAIL! : BulletUtilTests::fooTest() Compared values are not the same (fuzzy compare) +// Actual (foo * 3): glm::vec3 { 1, 0, 3 } +// Expected (bar + baz): glm::vec3 { 2, 0, 5 } +// Error Tolerance: 2.23607 > 1 +// Loc: [/Users/semery/hifi/tests/physics/src/BulletUtilTests.cpp(68)] +// +// The last line (and the FAIL! message up to "Compared values...") are generated automatically by +// QFAIL. It is possible to generate these manually via __FILE__ and __LINE__, but QFAIL does this +// already so there's no point in reimplementing it. However, since we are using QFAIL to generate +// our line number for us, it's important that it's actually invoked on the same line as the thing +// that calls it -- hence the elaborate macro(s) above (since the result is *technically* one line) +// + +#endif diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp index 73e092dd41..4d92d6f7b7 100644 --- a/tests/physics/src/BulletUtilTests.cpp +++ b/tests/physics/src/BulletUtilTests.cpp @@ -11,13 +11,13 @@ #include +#include "PhysicsTestUtil.h" #include #include #include "BulletUtilTests.h" - QTEST_MAIN(BulletUtilTests) void BulletUtilTests::fromBulletToGLM() { @@ -25,18 +25,8 @@ void BulletUtilTests::fromBulletToGLM() { glm::vec3 gV = bulletToGLM(bV); QCOMPARE(gV.x, bV.getX()); -// if (gV.x != bV .getX()) { -// std::cout << __FILE__ << ":" << __LINE__ -// << " ERROR: x mismatch bullet.x = " << bV.getX() << " != glm.x = " << gV.x << std::endl; -// } - if (gV.y != bV.getY()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch bullet.y = " << bV.getY() << " != glm.y = " << gV.y << std::endl; - } - if (gV.z != bV.getZ()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch bullet.z = " << bV.getZ() << " != glm.z = " << gV.z << std::endl; - } + QCOMPARE(gV.y, bV.getY()); + QCOMPARE(gV.z, bV.getZ()); float angle = 0.317f * PI; btVector3 axis(1.23f, 2.34f, 3.45f); @@ -44,39 +34,19 @@ void BulletUtilTests::fromBulletToGLM() { btQuaternion bQ(axis, angle); glm::quat gQ = bulletToGLM(bQ); - if (gQ.x != bQ.getX()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch bullet.x = " << bQ.getX() << " != glm.x = " << gQ.x << std::endl; - } - if (gQ.y != bQ.getY()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch bullet.y = " << bQ.getY() << " != glm.y = " << gQ.y << std::endl; - } - if (gQ.z != bQ.getZ()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch bullet.z = " << bQ.getZ() << " != glm.z = " << gQ.z << std::endl; - } - if (gQ.w != bQ.getW()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch bullet.w = " << bQ.getW() << " != glm.w = " << gQ.w << std::endl; - } + QCOMPARE(gQ.x, bQ.getX()); + QCOMPARE(gQ.y, bQ.getY()); + QCOMPARE(gQ.z, bQ.getZ() + 10); + QCOMPARE(gQ.w, bQ.getW()); } void BulletUtilTests::fromGLMToBullet() { glm::vec3 gV(1.23f, 4.56f, 7.89f); btVector3 bV = glmToBullet(gV); - if (gV.x != bV.getX()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch glm.x = " << gV.x << " != bullet.x = " << bV.getX() << std::endl; - } - if (gV.y != bV.getY()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch glm.y = " << gV.y << " != bullet.y = " << bV.getY() << std::endl; - } - if (gV.z != bV.getZ()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch glm.z = " << gV.z << " != bullet.z = " << bV.getZ() << std::endl; - } + + QCOMPARE(gV.x, bV.getX()); + QCOMPARE(gV.y, bV.getY()); + QCOMPARE(gV.z, bV.getZ()); float angle = 0.317f * PI; btVector3 axis(1.23f, 2.34f, 3.45f); @@ -84,25 +54,17 @@ void BulletUtilTests::fromGLMToBullet() { btQuaternion bQ(axis, angle); glm::quat gQ = bulletToGLM(bQ); - if (gQ.x != bQ.getX()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch glm.x = " << gQ.x << " != bullet.x = " << bQ.getX() << std::endl; - } - if (gQ.y != bQ.getY()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch glm.y = " << gQ.y << " != bullet.y = " << bQ.getY() << std::endl; - } - if (gQ.z != bQ.getZ()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch glm.z = " << gQ.z << " != bullet.z = " << bQ.getZ() << std::endl; - } - if (gQ.w != bQ.getW()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: x mismatch glm.w = " << gQ.w << " != bullet.w = " << bQ.getW() << std::endl; - } + QCOMPARE(gQ.x, bQ.getX()); + QCOMPARE(gQ.y, bQ.getY()); + QCOMPARE(gQ.z, bQ.getZ()); + QCOMPARE(gQ.w, bQ.getW()); } -//void BulletUtilTests::runAllTests() { -// fromBulletToGLM(); -// fromGLMToBullet(); -//} +void BulletUtilTests::fooTest () { + + glm::vec3 a { 1, 0, 3 }; + glm::vec3 b { 2, 0, 5 }; + +// QCOMPARE(10, 22); + QFUZZY_COMPARE(a, b, 1.0f); +} diff --git a/tests/physics/src/BulletUtilTests.h b/tests/physics/src/BulletUtilTests.h index 733352905b..df61de8216 100644 --- a/tests/physics/src/BulletUtilTests.h +++ b/tests/physics/src/BulletUtilTests.h @@ -20,7 +20,7 @@ class BulletUtilTests : public QObject { private slots: void fromBulletToGLM(); void fromGLMToBullet(); -// void runAllTests(); + void fooTest (); }; #endif // hifi_BulletUtilTests_h diff --git a/tests/physics/src/CollisionInfoTests.cpp b/tests/physics/src/CollisionInfoTests.cpp index ed9332e894..ca9c54e15a 100644 --- a/tests/physics/src/CollisionInfoTests.cpp +++ b/tests/physics/src/CollisionInfoTests.cpp @@ -24,7 +24,6 @@ QTEST_MAIN(CollisionInfoTests) /* - static glm::vec3 xAxis(1.0f, 0.0f, 0.0f); static glm::vec3 xZxis(0.0f, 1.0f, 0.0f); static glm::vec3 xYxis(0.0f, 0.0f, 1.0f); @@ -32,83 +31,82 @@ static glm::vec3 xYxis(0.0f, 0.0f, 1.0f); void CollisionInfoTests::rotateThenTranslate() { CollisionInfo collision; collision._penetration = xAxis; - collision._contactPoint = yAxis; - collision._addedVelocity = xAxis + yAxis + zAxis; + collision._contactPoint = xYxis; + collision._addedVelocity = xAxis + xYxis + xZxis; glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); float distance = 3.0f; - glm::vec3 translation = distance * yAxis; + glm::vec3 translation = distance * xYxis; collision.rotateThenTranslate(rotation, translation); - - float error = glm::distance(collision._penetration, yAxis); - if (error > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: collision._penetration = " << collision._penetration - << " but we expected " << yAxis - << std::endl; - } + QCOMPARE(collision._penetration, xYxis); +// float error = glm::distance(collision._penetration, xYxis); +// if (error > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: collision._penetration = " << collision._penetration +// << " but we expected " << xYxis +// << std::endl; +// } glm::vec3 expectedContactPoint = -xAxis + translation; - error = glm::distance(collision._contactPoint, expectedContactPoint); - if (error > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: collision._contactPoint = " << collision._contactPoint - << " but we expected " << expectedContactPoint - << std::endl; - } + QCOMPARE(collision._contactPoint, expectedContactPoint); +// error = glm::distance(collision._contactPoint, expectedContactPoint); +// if (error > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: collision._contactPoint = " << collision._contactPoint +// << " but we expected " << expectedContactPoint +// << std::endl; +// } - glm::vec3 expectedAddedVelocity = yAxis - xAxis + zAxis; - error = glm::distance(collision._addedVelocity, expectedAddedVelocity); - if (error > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: collision._addedVelocity = " << collision._contactPoint - << " but we expected " << expectedAddedVelocity - << std::endl; - } + glm::vec3 expectedAddedVelocity = xYxis - xAxis + xZxis; + QCOMPARE(collision._addedVelocity, expectedAddedVelocity); +// error = glm::distance(collision._addedVelocity, expectedAddedVelocity); +// if (error > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: collision._addedVelocity = " << collision._contactPoint +// << " but we expected " << expectedAddedVelocity +// << std::endl; +// } } void CollisionInfoTests::translateThenRotate() { CollisionInfo collision; collision._penetration = xAxis; - collision._contactPoint = yAxis; - collision._addedVelocity = xAxis + yAxis + zAxis; + collision._contactPoint = xYxis; + collision._addedVelocity = xAxis + xYxis + xZxis; glm::quat rotation = glm::angleAxis( -PI_OVER_TWO, zAxis); float distance = 3.0f; - glm::vec3 translation = distance * yAxis; + glm::vec3 translation = distance * xYxis; collision.translateThenRotate(translation, rotation); - - float error = glm::distance(collision._penetration, -yAxis); - if (error > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: collision._penetration = " << collision._penetration - << " but we expected " << -yAxis - << std::endl; - } + QCOMPARE(collision._penetration, -xYxis); +// float error = glm::distance(collision._penetration, -xYxis); +// if (error > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: collision._penetration = " << collision._penetration +// << " but we expected " << -yAxis +// << std::endl; +// } glm::vec3 expectedContactPoint = (1.0f + distance) * xAxis; - error = glm::distance(collision._contactPoint, expectedContactPoint); - if (error > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: collision._contactPoint = " << collision._contactPoint - << " but we expected " << expectedContactPoint - << std::endl; - } + QCOMPARE(collision._contactPoint, expectedContactPoint); +// error = glm::distance(collision._contactPoint, expectedContactPoint); +// if (error > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: collision._contactPoint = " << collision._contactPoint +// << " but we expected " << expectedContactPoint +// << std::endl; +// } - glm::vec3 expectedAddedVelocity = - yAxis + xAxis + zAxis; - error = glm::distance(collision._addedVelocity, expectedAddedVelocity); - if (error > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: collision._addedVelocity = " << collision._contactPoint - << " but we expected " << expectedAddedVelocity - << std::endl; - } -} -*/ + glm::vec3 expectedAddedVelocity = - xYxis + xAxis + xYxis; + QCOMPARE(collision._addedVelocity, expectedAddedVelocity); +// error = glm::distance(collision._addedVelocity, expectedAddedVelocity); +// if (error > EPSILON) { +// std::cout << __FILE__ << ":" << __LINE__ +// << " ERROR: collision._addedVelocity = " << collision._contactPoint +// << " but we expected " << expectedAddedVelocity +// << std::endl; +// } +}*/ -//void CollisionInfoTests::runAllTests() { -// CollisionInfoTests::rotateThenTranslate(); -// CollisionInfoTests::translateThenRotate(); -//} diff --git a/tests/physics/src/CollisionInfoTests.h b/tests/physics/src/CollisionInfoTests.h index 5c2289c26d..10c27fd551 100644 --- a/tests/physics/src/CollisionInfoTests.h +++ b/tests/physics/src/CollisionInfoTests.h @@ -20,8 +20,6 @@ class CollisionInfoTests : public QObject { private slots: // void rotateThenTranslate(); // void translateThenRotate(); - -// void runAllTests(); }; #endif // hifi_CollisionInfoTests_h diff --git a/tests/physics/src/MeshMassPropertiesTests.cpp b/tests/physics/src/MeshMassPropertiesTests.cpp index 376d5b1104..69c7330e09 100644 --- a/tests/physics/src/MeshMassPropertiesTests.cpp +++ b/tests/physics/src/MeshMassPropertiesTests.cpp @@ -9,13 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "PhysicsTestUtil.h" #include #include #include #include "MeshMassPropertiesTests.h" -//#define VERBOSE_UNIT_TESTS +#define VERBOSE_UNIT_TESTS const btScalar acceptableRelativeError(1.0e-5f); const btScalar acceptableAbsoluteError(1.0e-4f); @@ -40,13 +41,13 @@ void pushTriangle(VectorOfIndices& indices, uint32_t a, uint32_t b, uint32_t c) } void MeshMassPropertiesTests::testParallelAxisTheorem() { -#ifdef EXPOSE_HELPER_FUNCTIONS_FOR_UNIT_TEST - // verity we can compute the inertia tensor of a box in two different ways: +//#ifdef EXPOSE_HELPER_FUNCTIONS_FOR_UNIT_TEST + // verity we can compute the inertia tensor of a box in two different ways: // (a) as one box // (b) as a combination of two partial boxes. -#ifdef VERBOSE_UNIT_TESTS - std::cout << "\n" << __FUNCTION__ << std::endl; -#endif // VERBOSE_UNIT_TESTS +//#ifdef VERBOSE_UNIT_TESTS +// std::cout << "\n" << __FUNCTION__ << std::endl; +//#endif // VERBOSE_UNIT_TESTS btScalar bigBoxX = 7.0f; btScalar bigBoxY = 9.0f; @@ -76,11 +77,12 @@ void MeshMassPropertiesTests::testParallelAxisTheorem() { btScalar error; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - error = bitBoxInertia[i][j] - twoSmallBoxesInertia[i][j]; - if (fabsf(error) > acceptableAbsoluteError) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR : box inertia[" << i << "][" << j << "] off by = " - << error << std::endl; - } + QFUZZY_COMPARE(bitBoxInertia[i][j], twoSmallBoxesInertia[i][j], acceptableAbsoluteError); +// error = bitBoxInertia[i][j] - twoSmallBoxesInertia[i][j]; +// if (fabsf(error) > acceptableAbsoluteError) { +// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : box inertia[" << i << "][" << j << "] off by = " +// << error << std::endl; +// } } } @@ -88,7 +90,7 @@ void MeshMassPropertiesTests::testParallelAxisTheorem() { printMatrix("expected inertia", bitBoxInertia); printMatrix("computed inertia", twoSmallBoxesInertia); #endif // VERBOSE_UNIT_TESTS -#endif // EXPOSE_HELPER_FUNCTIONS_FOR_UNIT_TEST +//#endif // EXPOSE_HELPER_FUNCTIONS_FOR_UNIT_TEST } void MeshMassPropertiesTests::testTetrahedron(){ diff --git a/tests/physics/src/PhysicsTestUtil.h b/tests/physics/src/PhysicsTestUtil.h index 25f7e97181..d334203550 100644 --- a/tests/physics/src/PhysicsTestUtil.h +++ b/tests/physics/src/PhysicsTestUtil.h @@ -14,18 +14,39 @@ #include #include +#include + +#include #include +const glm::vec3 origin(0.0f); const glm::vec3 xAxis(1.0f, 0.0f, 0.0f); const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); const glm::vec3 zAxis(0.0f, 0.0f, 1.0f); -inline std::ostream& operator<<(std::ostream& s, const CollisionInfo& c) { - return s << "[penetration=" << c._penetration - << ", contactPoint=" << c._contactPoint - << ", addedVelocity=" << c._addedVelocity - << "]"; +// Implement these functions for whatever data types you need. +// +// fuzzyCompare takes two args of type T (the type you're comparing), and should +// return an error / difference of type V (eg. if T is a vector, V is a scalar). +// For vector types this is just the distance between a and b. +// +// stringify is just a toString() / repr() style function. For PoD types, +// I'd recommend using the c++11 initialization syntax (type { constructor args... }), +// since it's clear and unambiguous. +// +inline float fuzzyCompare (const glm::vec3 & a, const glm::vec3 & b) { + return glm::distance(a, b); +} +inline QTextStream & operator << (QTextStream & stream, const glm::vec3 & v) { + return stream << "glm::vec3 { " << v.x << ", " << v.y << ", " << v.z << " }"; } +inline btScalar fuzzyCompare (btScalar a, btScalar b) { + return a - b; +} + +#include "../QTestExtensions.hpp" + + #endif // hifi_PhysicsTestUtil_h diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index d2b44d344d..37fcef4915 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -10,6 +10,7 @@ // //#include +#include "PhysicsTestUtil.h" #include #include @@ -27,10 +28,11 @@ #include "ShapeColliderTests.h" -const glm::vec3 origin(0.0f); -static const glm::vec3 xAxis(1.0f, 0.0f, 0.0f); -static const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); -static const glm::vec3 zAxis(0.0f, 0.0f, 1.0f); + +//const glm::vec3 origin(0.0f); +//static const glm::vec3 xAxis(1.0f, 0.0f, 0.0f); +//static const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); +//static const glm::vec3 zAxis(0.0f, 0.0f, 1.0f); QTEST_MAIN(ShapeColliderTests) @@ -47,37 +49,12 @@ void ShapeColliderTests::sphereMissesSphere() { SphereShape sphereB(radiusB, offsetDistance * offsetDirection); CollisionList collisions(16); - // collide A to B... - { - bool touching = ShapeCollider::collideShapes(&sphereA, &sphereB, collisions); - if (touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should NOT touch" << std::endl; - } - } - - // collide B to A... - { - bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions); - if (touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should NOT touch" << std::endl; - } - } - - // also test shapeShape - { - bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions); - if (touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should NOT touch" << std::endl; - } - } - - if (collisions.size() > 0) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected empty collision list but size is " << collisions.size() << std::endl; - } + // collide A to B and vice versa + QCOMPARE(ShapeCollider::collideShapes(&sphereA, &sphereB, collisions), false); + QCOMPARE(ShapeCollider::collideShapes(&sphereB, &sphereA, collisions), false); + + // Collision list should be empty + QCOMPARE(collisions.size(), 0); } void ShapeColliderTests::sphereTouchesSphere() { @@ -98,74 +75,38 @@ void ShapeColliderTests::sphereTouchesSphere() { // collide A to B... { - bool touching = ShapeCollider::collideShapes(&sphereA, &sphereB, collisions); - if (!touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should touch" << std::endl; - } else { - ++numCollisions; - } - + QCOMPARE(ShapeCollider::collideShapes(&sphereA, &sphereB, collisions), true); + ++numCollisions; + // verify state of collisions - if (numCollisions != collisions.size()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected collisions size of " << numCollisions << " but actual size is " << collisions.size() - << std::endl; - } + QCOMPARE(collisions.size(), numCollisions); CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: null collision" << std::endl; - return; - } + QVERIFY(collision != nullptr); // penetration points from sphereA into sphereB - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + QCOMPARE(collision->_penetration, expectedPenetration); // contactPoint is on surface of sphereA glm::vec3 AtoB = sphereB.getTranslation() - sphereA.getTranslation(); glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * glm::normalize(AtoB); - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QCOMPARE(collision->_contactPoint, expectedContactPoint); + + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); } // collide B to A... { - bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions); - if (!touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should touch" << std::endl; - } else { - ++numCollisions; - } + QCOMPARE(ShapeCollider::collideShapes(&sphereA, &sphereB, collisions), true); + ++numCollisions; // penetration points from sphereA into sphereB CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - float inaccuracy = glm::length(collision->_penetration + expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); // contactPoint is on surface of sphereA glm::vec3 BtoA = sphereA.getTranslation() - sphereB.getTranslation(); glm::vec3 expectedContactPoint = sphereB.getTranslation() + radiusB * glm::normalize(BtoA); - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); } } @@ -200,25 +141,12 @@ void ShapeColliderTests::sphereMissesCapsule() { glm::vec3 localPosition = localStartPosition + ((float)i * delta) * yAxis; sphereA.setTranslation(rotation * localPosition + translation); - // sphereA agains capsuleB - if (ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphere and capsule should NOT touch" << std::endl; - } - - // capsuleB against sphereA - if (ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphere and capsule should NOT touch" << std::endl; - } - } - - if (collisions.size() > 0) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected empty collision list but size is " << collisions.size() << std::endl; + // sphereA agains capsuleB and vice versa + QCOMPARE(ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions), false); + QCOMPARE(ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions), false); } + + QCOMPARE(collisions.size(), 0); } void ShapeColliderTests::sphereTouchesCapsule() { @@ -239,42 +167,22 @@ void ShapeColliderTests::sphereTouchesCapsule() { { // sphereA collides with capsuleB's cylindrical wall sphereA.setTranslation(radialOffset * xAxis); - - if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphere and capsule should touch" << std::endl; - } else { - ++numCollisions; - } + + QCOMPARE(ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions), true); + ++numCollisions; // penetration points from sphereA into capsuleB CollisionInfo* collision = collisions.getCollision(numCollisions - 1); glm::vec3 expectedPenetration = (radialOffset - totalRadius) * xAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); // contactPoint is on surface of sphereA glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * xAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); // capsuleB collides with sphereA - if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and sphere should touch" << std::endl; - } else { - ++numCollisions; - } + QCOMPARE(ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions), true); + ++numCollisions; // penetration points from sphereA into capsuleB collision = collisions.getCollision(numCollisions - 1); @@ -283,13 +191,8 @@ void ShapeColliderTests::sphereTouchesCapsule() { // the ShapeCollider swapped the order of the shapes expectedPenetration *= -1.0f; } - inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); + // contactPoint is on surface of capsuleB glm::vec3 BtoA = sphereA.getTranslation() - capsuleB.getTranslation(); glm::vec3 closestApproach = capsuleB.getTranslation() + glm::dot(BtoA, yAxis) * yAxis; @@ -299,37 +202,24 @@ void ShapeColliderTests::sphereTouchesCapsule() { closestApproach = sphereA.getTranslation() - glm::dot(BtoA, yAxis) * yAxis; expectedContactPoint = closestApproach - radiusB * glm::normalize(BtoA - closestApproach); } - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } + QFUZZY_COMPARE(collision->_contactPoint, expectedContactPoint, EPSILON); } { // sphereA hits end cap at axis glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; sphereA.setTranslation(axialOffset); - if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphere and capsule should touch" << std::endl; - } else { - ++numCollisions; - } + QCOMPARE(ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions), true); + ++numCollisions; // penetration points from sphereA into capsuleB CollisionInfo* collision = collisions.getCollision(numCollisions - 1); glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabsf(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } + QFUZZY_COMPARE(collision->_penetration, expectedPenetration, EPSILON); // contactPoint is on surface of sphereA glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * yAxis; + + inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); if (fabsf(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ @@ -2509,36 +2399,3 @@ void ShapeColliderTests::measureTimeOfCollisionDispatch() { */ } -//void ShapeColliderTests::runAllTests() { -// ShapeCollider::initDispatchTable(); -// -// //measureTimeOfCollisionDispatch(); -// -// sphereMissesSphere(); -// sphereTouchesSphere(); -// -// sphereMissesCapsule(); -// sphereTouchesCapsule(); -// -// capsuleMissesCapsule(); -// capsuleTouchesCapsule(); -// -// sphereMissesAACube(); -// sphereTouchesAACubeFaces(); -// sphereTouchesAACubeEdges(); -// sphereTouchesAACubeCorners(); -// -// capsuleMissesAACube(); -// capsuleTouchesAACube(); -// -// rayHitsSphere(); -// rayBarelyHitsSphere(); -// rayBarelyMissesSphere(); -// rayHitsCapsule(); -// rayMissesCapsule(); -// rayHitsPlane(); -// rayMissesPlane(); -// -// rayHitsAACube(); -// rayMissesAACube(); -//} diff --git a/tests/physics/src/ShapeColliderTests.h b/tests/physics/src/ShapeColliderTests.h index 8da4c96639..85d907b440 100644 --- a/tests/physics/src/ShapeColliderTests.h +++ b/tests/physics/src/ShapeColliderTests.h @@ -46,8 +46,6 @@ private slots: void rayMissesAACube(); void measureTimeOfCollisionDispatch(); - -// void runAllTests(); }; #endif // hifi_ShapeColliderTests_h