diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt old mode 100755 new mode 100644 index ba27baba..ff69eb31 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,6 +15,6 @@ file ( ) # Create the tests executable -ADD_EXECUTABLE(tests ${REACTPHYSICS3D_SOURCE_DIR}) +ADD_EXECUTABLE(tests ${TESTS_SOURCE_FILES}) TARGET_LINK_LIBRARIES(tests reactphysics3d) diff --git a/test/Test.cpp b/test/Test.cpp index 073a8242..a1c71b91 100644 --- a/test/Test.cpp +++ b/test/Test.cpp @@ -38,13 +38,47 @@ Test::~Test() { } +// Called to test a boolean condition. +// This method should not be called directly in your test but you should call test() instead (macro) +void Test::applyTest(bool condition, const std::string& testText, + const char* filename, long lineNumber) { + + // If the boolean condition is true + if (condition) { + + // The test passed, call the succeed() method + succeed(); + } + else { // If the boolean condition is false + + // The test failed, call the applyFail() method + applyFail(testText, filename, lineNumber); + } +} + +// Called when a test has failed. +// This method should not be called directly in your test buy you should call fail() instead (macro) +void Test::applyFail(const std::string& testText, const char* filename, long lineNumber) { + + if (mOutputStream) { + + // Display the failure message + *mOutputStream << typeid(*this).name() << "failure : (" << testText << "), " << + filename << "(line " << lineNumber << ")" << std::endl; + } + + // Increase the number of failed tests + mNbFailedTests++; +} + /// Display the report of the unit test and return the number of failed tests -uint Test::report() const { +long Test::report() const { if(mOutputStream) { - *osptr << "Test \"" << + *mOutputStream << "Test \"" << typeid(*this).name() - << "\":\n\tPassed: " << mNbPassedTests << "\tFailed: " << mNbFailedTests << endl; + << "\":\n\tPassed: " << mNbPassedTests << "\tFailed: " << + mNbFailedTests << std::endl; } // Return the number of failed tests diff --git a/test/Test.h b/test/Test.h index 6d06a3be..19861876 100644 --- a/test/Test.h +++ b/test/Test.h @@ -34,8 +34,15 @@ /// Reactphysics3D namespace namespace reactphysics3d { +// Macros +#define test(condition) applyTest(condition, #condition, __FILE__, __LINE__) +#define fail(text) applyFail(text, __FILE__, __LINE__); + +// Class Test /** - * This abstract class represents a unit test + * This abstract class represents a unit test. To create a unit test, you simply + * need to create a class that inherits from the Test class, override the run() method and + * use the test() and fail() macros. */ class Test { @@ -44,10 +51,10 @@ class Test { // ---------- Attributes ---------- // /// Number of tests that passed - uint mNbPassedTests; + long mNbPassedTests; /// Number of tests that failed - uint mNbFailedTests; + long mNbFailedTests; /// Output stream std::ostream* mOutputStream; @@ -62,6 +69,19 @@ class Test { protected : + // ---------- Methods ---------- // + + /// Called to test a boolean condition. + /// This method should not be called directly in your test but you should + /// call test() instead (macro) + void applyTest(bool condition, const std::string& testText, + const char* filename, long lineNumber); + + /// Called when a test has failed. + /// This method should not be called directly in your test buy you should + /// call fail() instead (macro) + void applyFail(const std::string& testText, const char* filename, long lineNumber); + public : // ---------- Methods ---------- // @@ -73,50 +93,58 @@ class Test { ~Test(); /// Return the number of passed tests - uint getNbPassedTests() const; + long getNbPassedTests() const; /// Return the number of failed tests - uint getNbFailedTests() const; + long getNbFailedTests() const; /// Return the output stream const std::ostream* getOutputStream() const; /// Set the output stream - void setOutputStream(const std::ostream* stream); + void setOutputStream(std::ostream *stream); /// Run the unit test virtual void run() = 0; + /// Called when a test passed + void succeed(); + /// Reset the unit test virtual void reset(); /// Display the report of the unit test and return the number of failed tests - uint report() const; + long report() const; }; -/// Reset the unit test +// Called when a test passed +inline void Test::succeed() { + mNbPassedTests++; +} + +// Reset the unit test inline void Test::reset() { mNbPassedTests = 0; mNbFailedTests = 0; } -/// Return the number of passed tests -inline uint Test::getNbPassedTests() const { +// Return the number of passed tests +inline long Test::getNbPassedTests() const { return mNbPassedTests; } -/// Return the number of failed tests -inline uint Test::getNbFailedTests() const { +// Return the number of failed tests +inline long Test::getNbFailedTests() const { return mNbFailedTests; } -/// Return the output stream +// Return the output stream inline const std::ostream* Test::getOutputStream() const { return mOutputStream; } -/// Set the output stream -inline void Test::setOutputStream(const std::ostream* stream) { +// Set the output stream +inline void Test::setOutputStream(std::ostream* stream) { mOutputStream = stream; } diff --git a/test/TestSuite.cpp b/test/TestSuite.cpp index 15a541cc..f8d97363 100644 --- a/test/TestSuite.cpp +++ b/test/TestSuite.cpp @@ -22,3 +22,124 @@ * 3. This notice may not be removed or altered from any source distribution. * * * ********************************************************************************/ + +// Librairies +#include "TestSuite.h" + +using namespace reactphysics3d; + +// Constructor +TestSuite::TestSuite(const std::string& name, std::ostream* outputStream) + : mName(name), mOutputStream(outputStream) { + +} + +// Return the number of passed tests +long TestSuite::getNbPassedTests() const { + + long nbPassedTests = 0; + + for (size_t i=0; igetNbPassedTests(); + } + + return nbPassedTests; +} + +// Return the number of failed tests +long TestSuite::getNbFailedTests() const { + long nbFailedTests = 0; + + for (size_t i=0; igetNbFailedTests(); + } + + return nbFailedTests; +} + +// Add a unit test in the test suite +void TestSuite::addTest(Test* test) { + if (test == NULL) { + throw std::invalid_argument("Error : You cannot add a NULL test in the test suite."); + } + else if (mOutputStream != NULL && test->getOutputStream() == NULL) { + test->setOutputStream(mOutputStream); + } + + // Add the test to the suite + mTests.push_back(test); + + // Reset the added test + test->reset(); +} + +// Add a test suite to the current test suite +void TestSuite::addTestSuite(const TestSuite& testSuite) { + + // Add each test of the test suite to the current one + for (size_t i =0; i < testSuite.mTests.size(); i++) { + assert(testSuite.mTests[i] != NULL); + addTest(testSuite.mTests[i]); + } +} + +// Launch the tests of the test suite +void TestSuite::run() { + + // Reset all the tests + reset(); + + // Run all the tests + for (size_t i=0; i < mTests.size(); i++) { + assert(mTests[i] != NULL); + mTests[i]->run(); + } +} + +// Reset the test suite +void TestSuite::reset() { + for(size_t i=0; i < mTests.size(); ++i) { + assert(mTests[i]); + mTests[i]->reset(); + } +} + +// Display the tests report and return the number of failed tests +long TestSuite::report() const { + if (mOutputStream != NULL) { + long nbFailedTests = 0; + + *mOutputStream << "Test Suite \"" << mName << "\"\n====="; + size_t i; + for (i=0; i < mName.size(); i++) { + *mOutputStream << "="; + } + *mOutputStream << "=" << std::endl; + for (i=0; i < mTests.size(); i++) { + assert(mTests[i] != NULL); + nbFailedTests += mTests[i]->report(); + } + *mOutputStream << "====="; + for (i=0; i < mName.size(); i++) { + *mOutputStream << "="; + } + *mOutputStream << "=" << std::endl; + + // Return the number of failed tests + return nbFailedTests; + } + else { + return getNbFailedTests(); + } +} + +// Delete all the tests +void TestSuite::clear() { + + for (size_t i=0; i +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestSuite +/** + * This class represents a test suite that can + * contains multiple unit tests. You can also add a test suite inside + * another test suite (all the tests of the first test suite will be added + * to the second one). + */ class TestSuite { + private : + + // ---------- Attributes ---------- // + + /// Name of the test suite + std::string mName; + + /// Output stream + std::ostream* mOutputStream; + + /// All the tests of the test suite + std::vector mTests; + + // ---------- Methods ---------- // + + /// Reset the test suite + void reset(); + + /// Private copy-constructor + TestSuite(const TestSuite& testSuite); + + /// Private assigmnent operator + TestSuite& operator=(const TestSuite testSuite); + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestSuite(const std::string& name, std::ostream* outputStream = &std::cout); + + /// Return the name of the test suite + std::string getName() const; + + /// Return the number of passed tests + long getNbPassedTests() const; + + /// Return the number of failed tests + long getNbFailedTests() const; + + /// Return the output stream + const std::ostream* getOutputStream() const; + + /// Set the output stream + void setOutputStream(std::ostream* outputStream); + + /// Add a unit test in the test suite + void addTest(Test* test); + + /// Add a test suite to the current test suite + void addTestSuite(const TestSuite& testSuite); + + /// Launch the tests of the test suite + void run(); + + /// Display the tests report and return the number of failed tests + long report() const; + + // Delete all the tests + void clear(); + }; +// Return the name of the test suite +inline std::string TestSuite::getName() const { + return mName; +} + +// Return the output stream +inline const std::ostream* TestSuite::getOutputStream() const { + return mOutputStream; +} + +// Set the output stream +inline void TestSuite::setOutputStream(std::ostream* outputStream) { + mOutputStream = outputStream; +} + +} + #endif diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 00000000..91a2c47e --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,56 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// Libraries +#include "TestSuite.h" +#include "tests/mathematics/TestVector3.h" +#include "tests/mathematics/TestTransform.h" +#include "tests/mathematics/TestQuaternion.h" + +using namespace reactphysics3d; + +int main() { + + TestSuite testSuite("ReactPhysics3D tests"); + + // ---------- Mathematics tests ---------- // + + testSuite.addTest(new TestVector3); + testSuite.addTest(new TestTransform); + testSuite.addTest(new TestQuaternion); + + // ----------------------------- --------- // + + // Run the tests + testSuite.run(); + + // Display the report + long nbFailedTests = testSuite.report(); + + // Clear the tests from the test suite + testSuite.clear(); + + return nbFailedTests; +} diff --git a/test/tests/mathematics/TestMatrix3x3.h b/test/tests/mathematics/TestMatrix3x3.h new file mode 100644 index 00000000..325f9861 --- /dev/null +++ b/test/tests/mathematics/TestMatrix3x3.h @@ -0,0 +1,72 @@ + +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TEST_MATRIX3X3_H +#define TEST_MATRIX3X3_H + +#endif + +// Libraries +#include "../../Test.h" +#include "../../../src/mathematics/Matrix3x3.h" + +using namespace reactphysics3d; + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestMatrix3x3 +/** + * Unit test for the Matrix3x3 class + */ +class TestMatrix3x3 : public Test { + + private : + + // ---------- Atributes ---------- // + + /// Identity transform + Matrix3x3 mIdentity; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestMatrix3x3() : mIdentity(Matrix3x3::identity()){ + + + } + + /// Run the tests + void run() { + + } + + + }; + +} diff --git a/test/tests/mathematics/TestQuaternion.h b/test/tests/mathematics/TestQuaternion.h new file mode 100644 index 00000000..66ff0266 --- /dev/null +++ b/test/tests/mathematics/TestQuaternion.h @@ -0,0 +1,101 @@ + +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TEST_QUATERNION_H +#define TEST_QUATERNION_H + +#endif + +// Libraries +#include "../../Test.h" +#include "../../../src/mathematics/Quaternion.h" + +using namespace reactphysics3d; + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestQuaternion +/** + * Unit test for the Quaternion class + */ +class TestQuaternion : public Test { + + private : + + // ---------- Atributes ---------- // + + /// Identity Quaternion + Quaternion mIdentity; + + /// First test quaternion + Quaternion mQuaternion1; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestQuaternion() : mIdentity(Quaternion::identity()) { + + decimal sinA = sin(PI/8.0f); + decimal cosA = cos(PI/8.0f); + mQuaternion1 = Quaternion(sinA, sinA, sinA, cosA); + } + + /// Run the tests + void run() { + testConstructors(); + } + + /// Test the constructors + void testConstructors() { + Quaternion quaternion1(mQuaternion1); + test(mQuaternion1== quaternion1); + + Quaternion quaternion2(4, 5, 6, 7); + test(quaternion2 == Quaternion(4, 5, 6, 7)); + + Quaternion quaternion3(8, Vector3(3, 5, 2)); + test(quaternion3 == Quaternion(5, 6, 7, 4)); + + Matrix3x3 matrix(2, 3, 4, 5, 6, 7, 8, 9, 10); + Quaternion quaternion4(matrix); + Matrix3x3 result = quaternion4.getMatrix(); + test(approxEqual(matrix.getValue(0, 0), result.getValue(0, 0), 0.1)); + std::cout << "matrix : " << matrix.getValue(0, 0) << ", " << result.getValue(0, 0) << std::endl; + test(approxEqual(matrix.getValue(0, 1), result.getValue(0, 1), 0.1)); + test(approxEqual(matrix.getValue(0, 2), result.getValue(0, 2), 0.1)); + test(approxEqual(matrix.getValue(1, 0), result.getValue(1, 0), 0.1)); + test(approxEqual(matrix.getValue(1, 1), result.getValue(1, 1), 0.1)); + test(approxEqual(matrix.getValue(1, 2), result.getValue(1, 2), 0.1)); + test(approxEqual(matrix.getValue(2, 0), result.getValue(2, 0), 0.1)); + test(approxEqual(matrix.getValue(2, 1), result.getValue(2, 1), 0.1)); + test(approxEqual(matrix.getValue(2, 2), result.getValue(2, 2), 0.1)); + } + }; + +} diff --git a/test/tests/mathematics/TestTransform.h b/test/tests/mathematics/TestTransform.h new file mode 100644 index 00000000..2de02d79 --- /dev/null +++ b/test/tests/mathematics/TestTransform.h @@ -0,0 +1,205 @@ + +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TEST_TRANSFORM_H +#define TEST_TRANSFORM_H + +#endif + +// Libraries +#include "../../Test.h" +#include "../../../src/mathematics/Transform.h" + +using namespace reactphysics3d; + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestTransform +/** + * Unit test for the Transform class + */ +class TestTransform : public Test { + + private : + + // ---------- Atributes ---------- // + + /// Identity transform + Transform mIdentityTransform; + + /// First example transform + Transform mTransform1; + + /// Second example transform + Transform mTransform2; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestTransform() { + + mIdentityTransform.setToIdentity(); + + decimal sinA = sin(PI/8.0f); + decimal cosA = cos(PI/8.0f); + mTransform1 = Transform(Vector3(4, 5, 6), Quaternion(sinA, sinA, sinA, cosA)); + + decimal sinB = sin(PI/3.0f); + decimal cosB = cos(PI/3.0f); + mTransform2 = Transform(Vector3(8, 45, -6), Quaternion(sinB, sinB, sinB, cosB)); + } + + /// Run the tests + void run() { + testConstructors(); + testGetSet(); + testInverse(); + testGetSetOpenGLMatrix(); + testInterpolateTransform(); + testOperators(); + } + + /// Test the constructors + void testConstructors() { + Transform transform1(Vector3(1, 2, 3), Quaternion(6, 7, 8, 9)); + Transform transform2(Vector3(4, 5, 6), Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1)); + Transform transform3(transform1); + test(transform1.getPosition() == Vector3(1, 2, 3)); + test(transform1.getOrientation() == Quaternion(6, 7, 8, 9)); + test(transform2.getPosition() == Vector3(4, 5, 6)); + test(transform2.getOrientation() == Quaternion::identity()); + test(transform3 == transform1); + } + + /// Test getter and setter + void testGetSet() { + test(mIdentityTransform.getPosition() == Vector3(0, 0, 0)); + test(mIdentityTransform.getOrientation() == Quaternion::identity()); + Transform transform; + transform.setPosition(Vector3(5, 7, 8)); + transform.setOrientation(Quaternion(1, 2, 3, 1)); + test(transform.getPosition() == Vector3(5, 7, 8)); + test(transform.getOrientation() == Quaternion(1, 2, 3, 1)); + transform.setToIdentity(); + test(transform.getPosition() == Vector3(0, 0, 0)); + test(transform.getOrientation() == Quaternion::identity()); + } + + /// Test the inverse + void testInverse() { + Transform inverseTransform = mTransform1.inverse(); + Vector3 vector(2, 3, 4); + Vector3 tempVector = mTransform1 * vector; + Vector3 tempVector2 = inverseTransform * tempVector; + test(approxEqual(tempVector2.x, vector.x, decimal(10e-6))); + test(approxEqual(tempVector2.y, vector.y, decimal(10e-6))); + test(approxEqual(tempVector2.z, vector.z, decimal(10e-6))); + } + + /// Test methods to set and get transform matrix from and to OpenGL + void testGetSetOpenGLMatrix() { + Transform transform; + Vector3 position = mTransform1.getPosition(); + Matrix3x3 orientation = mTransform1.getOrientation().getMatrix(); + decimal openglMatrix[16] = {orientation.getValue(0,0), orientation.getValue(1,0), + orientation.getValue(2,0), 0, + orientation.getValue(0,1), orientation.getValue(1,1), + orientation.getValue(2,1), 0, + orientation.getValue(0,2), orientation.getValue(1,2), + orientation.getValue(2,2), 0, + position.x, position.y, position.z, 1}; + transform.setFromOpenGL(openglMatrix); + decimal openglMatrix2[16]; + transform.getOpenGLMatrix(openglMatrix2); + test(approxEqual(openglMatrix2[0], orientation.getValue(0,0))); + test(approxEqual(openglMatrix2[1], orientation.getValue(1,0))); + test(approxEqual(openglMatrix2[2], orientation.getValue(2,0))); + test(approxEqual(openglMatrix2[3], 0)); + test(approxEqual(openglMatrix2[4], orientation.getValue(0,1))); + test(approxEqual(openglMatrix2[5], orientation.getValue(1,1))); + test(approxEqual(openglMatrix2[6], orientation.getValue(2,1))); + test(approxEqual(openglMatrix2[7], 0)); + test(approxEqual(openglMatrix2[8], orientation.getValue(0,2))); + test(approxEqual(openglMatrix2[9], orientation.getValue(1,2))); + test(approxEqual(openglMatrix2[10], orientation.getValue(2,2))); + test(approxEqual(openglMatrix2[11], 0)); + test(approxEqual(openglMatrix2[12], position.x)); + test(approxEqual(openglMatrix2[13], position.y)); + test(approxEqual(openglMatrix2[14], position.z)); + test(approxEqual(openglMatrix2[15], 1)); + } + + /// Test the method to interpolate transforms + void testInterpolateTransform() { + Transform transformStart = Transform::interpolateTransforms(mTransform1, mTransform2,0); + Transform transformEnd = Transform::interpolateTransforms(mTransform1, mTransform2,1); + test(transformStart == mTransform1); + test(transformEnd == mTransform2); + + decimal sinA = sin(PI/3.0f); + decimal cosA = cos(PI/3.0f); + decimal sinB = sin(PI/6.0f); + decimal cosB = cos(PI/6.0f); + Transform transform1(Vector3(4, 5, 6), Quaternion::identity()); + Transform transform2(Vector3(8, 11, 16), Quaternion(sinA, sinA, sinA, cosA)); + Transform transform = Transform::interpolateTransforms(transform1, transform2, 0.5); + Vector3 position = transform.getPosition(); + Quaternion orientation = transform.getOrientation(); + test(approxEqual(position.x, 6)); + test(approxEqual(position.y, 8)); + test(approxEqual(position.z, 11)); + test(approxEqual(orientation.x, sinB)); + test(approxEqual(orientation.y, sinB)); + test(approxEqual(orientation.z, sinB)); + test(approxEqual(orientation.w, cosB)); + } + + /// Test the overloaded operators + void testOperators() { + + // Equality, inequality operator + test(mTransform1 == mTransform1); + test(mTransform1 != mTransform2); + + // Assignment operator + Transform transform; + transform = mTransform1; + test(transform == mTransform1); + + // Multiplication + Vector3 vector(7, 53, 5); + Vector3 vector2 = mTransform2 * (mTransform1 * vector); + Vector3 vector3 = (mTransform2 * mTransform1) * vector; + test(approxEqual(vector2.x, vector3.x, decimal(10e-6))); + test(approxEqual(vector2.y, vector3.y, decimal(10e-6))); + test(approxEqual(vector2.z, vector3.z, decimal(10e-6))); + } + }; + +} diff --git a/test/tests/mathematics/TestVector3.h b/test/tests/mathematics/TestVector3.h new file mode 100644 index 00000000..4097e730 --- /dev/null +++ b/test/tests/mathematics/TestVector3.h @@ -0,0 +1,225 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TEST_VECTOR3_H +#define TEST_VECTOR3_H + +#endif + +// Libraries +#include "../../Test.h" +#include "../../../src/mathematics/Vector3.h" + +using namespace reactphysics3d; + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestVector3 +/** + * Unit test for the Vector3 class + */ +class TestVector3 : public Test { + + private : + + // ---------- Atributes ---------- // + + /// Zero vector + Vector3 mVectorZero; + + // Vector (3, 4, 5) + Vector3 mVector345; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestVector3() : mVectorZero(0, 0, 0), mVector345(3, 4, 5) {} + + /// Run the tests + void run() { + testConstructors(); + testLengthMethods(); + testDotCrossProducts(); + testOthersMethods(); + testOperators(); + } + + /// Test the constructors, getter and setter + void testConstructors() { + + // Test constructor + test(mVectorZero.x == 0.0); + test(mVectorZero.y == 0.0); + test(mVectorZero.z == 0.0); + test(mVector345.x == 3.0); + test(mVector345.y == 4.0); + test(mVector345.z == 5.0); + + // Test copy-constructor + Vector3 newVector(mVector345); + test(newVector.x == 3.0); + test(newVector.y == 4.0); + test(newVector.z == 5.0); + + // Test method to set values + Vector3 newVector2; + newVector2.setAllValues(decimal(6.1), decimal(7.2), decimal(8.6)); + test(approxEqual(newVector2.x, decimal(6.1))); + test(approxEqual(newVector2.y, decimal(7.2))); + test(approxEqual(newVector2.z, decimal(8.6))); + } + + /// Test the length, unit vector and normalize methods + void testLengthMethods() { + + // Test length methods + test(mVectorZero.length() == 0.0); + test(mVectorZero.lengthSquare() == 0.0); + test(Vector3(1, 0, 0).length() == 1.0); + test(Vector3(0, 1, 0).length() == 1.0); + test(Vector3(0, 0, 1).length() == 1.0); + test(mVector345.lengthSquare() == 50.0); + + // Test unit vector methods + test(Vector3(1, 0, 0).isUnit()); + test(Vector3(0, 1, 0).isUnit()); + test(Vector3(0, 0, 1).isUnit()); + test(!mVector345.isUnit()); + test(Vector3(5, 0, 0).getUnit() == Vector3(1, 0, 0)); + test(Vector3(0, 5, 0).getUnit() == Vector3(0, 1, 0)); + test(Vector3(0, 0, 5).getUnit() == Vector3(0, 0, 1)); + + test(!mVector345.isZero()); + test(mVectorZero.isZero()); + + // Test normalization method + Vector3 mVector100(1, 0, 0); + Vector3 mVector010(0, 1, 0); + Vector3 mVector001(0, 0, 1); + Vector3 mVector500(5, 0, 0); + Vector3 mVector050(0, 5, 0); + Vector3 mVector005(0, 0, 5); + mVector100.normalize(); + mVector010.normalize(); + mVector001.normalize(); + mVector500.normalize(); + mVector050.normalize(); + mVector005.normalize(); + test(mVector100 == Vector3(1, 0, 0)); + test(mVector010 == Vector3(0, 1, 0)); + test(mVector001 == Vector3(0, 0, 1)); + test(mVector500 == Vector3(1, 0, 0)); + test(mVector050 == Vector3(0, 1, 0)); + test(mVector005 == Vector3(0, 0, 1)); + } + + /// Test the dot and cross products + void testDotCrossProducts() { + + // Test the dot product + test(Vector3(5, 0, 0).dot(Vector3(0, 8, 0)) == 0); + test(Vector3(5, 8, 0).dot(Vector3(0, 0, 6)) == 0); + test(Vector3(12, 45, 83).dot(Vector3(0, 0, 0)) == 0); + test(Vector3(5, 7, 8).dot(Vector3(5, 7, 8)) == 138); + test(Vector3(3, 6, 78).dot(Vector3(-3, -6, -78)) == -6129); + test(Vector3(2, 3, 5).dot(Vector3(2, 3, 5)) == 38); + test(Vector3(4, 3, 2).dot(Vector3(8, 9, 10)) == 79); + + // Test the cross product + test(Vector3(0, 0, 0).cross(Vector3(0, 0, 0)) == Vector3(0, 0, 0)); + test(Vector3(6, 7, 2).cross(Vector3(6, 7, 2)) == Vector3(0, 0, 0)); + test(Vector3(1, 0, 0).cross(Vector3(0, 1, 0)) == Vector3(0, 0, 1)); + test(Vector3(0, 1, 0).cross(Vector3(0, 0, 1)) == Vector3(1, 0, 0)); + test(Vector3(0, 0, 1).cross(Vector3(0, 1, 0)) == Vector3(-1, 0, 0)); + test(Vector3(4, 7, 24).cross(Vector3(8, 13, 11)) == Vector3(-235, 148, -4)); + test(Vector3(-4, 42, -2).cross(Vector3(35, 7, -21)) == Vector3(-868, -154, -1498)); + } + + /// Test others methods + void testOthersMethods() { + + // Test the method that returns the absolute vector + test(Vector3(4, 5, 6).getAbsoluteVector() == Vector3(4, 5, 6)); + test(Vector3(-7, -24, -12).getAbsoluteVector() == Vector3(7, 24, 12)); + + // Test the method that returns the minimal element + test(Vector3(6, 35, 82).getMinAxis() == 0); + test(Vector3(564, 45, 532).getMinAxis() == 1); + test(Vector3(98, 23, 3).getMinAxis() == 2); + test(Vector3(-53, -25, -63).getMinAxis() == 2); + + // Test the method that returns the maximal element + test(Vector3(6, 35, 82).getMaxAxis() == 2); + test(Vector3(7, 533, 36).getMaxAxis() == 1); + test(Vector3(98, 23, 3).getMaxAxis() == 0); + test(Vector3(-53, -25, -63).getMaxAxis() == 1); + } + + /// Test the operators + void testOperators() { + + // Test the [] operator + test(mVector345[0] == 3); + test(mVector345[1] == 4); + test(mVector345[2] == 5); + + // Assignment operator + Vector3 newVector(6, 4, 2); + newVector = Vector3(7, 8, 9); + test(newVector == Vector3(7, 8, 9)); + + // Equality, inequality operators + test(Vector3(5, 7, 3) == Vector3(5, 7, 3)); + test(Vector3(63, 64, 24) != Vector3(63, 64, 5)); + test(Vector3(63, 64, 24) != Vector3(12, 64, 24)); + test(Vector3(63, 64, 24) != Vector3(63, 8, 24)); + + // Addition, substraction + Vector3 vector1(6, 33, 62); + Vector3 vector2(7, 68, 35); + test(Vector3(63, 24, 5) + Vector3(3, 4, 2) == Vector3(66, 28, 7)); + test(Vector3(63, 24, 5) - Vector3(3, 4, 2) == Vector3(60, 20, 3)); + vector1 += Vector3(5, 10, 12); + vector2 -= Vector3(10, 21, 5); + test(vector1 == Vector3(11, 43, 74)); + test(vector2 == Vector3(-3, 47, 30)); + + // Multiplication, division + Vector3 vector3(6, 33, 62); + Vector3 vector4(15, 60, 33); + test(Vector3(63, 24, 5) * 3 == Vector3(189, 72, 15)); + test(3 * Vector3(63, 24, 5) == Vector3(189, 72, 15)); + test(Vector3(14, 8, 50) / 2 == Vector3(7, 4, 25)); + vector3 *= 10; + vector4 /= 3; + test(vector3 == Vector3(60, 330, 620)); + test(vector4 == Vector3(5, 20, 11)); + } + }; + +}