mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 01:04:11 +02:00
commit
812b18c74e
67 changed files with 1832 additions and 3050 deletions
CMakeLists.txt
cmake
externals
LibOVR
bullet
glew
glm
gverb
oglplus
openvr
polyvox
qxmpp
sdl2
soxr
tbb
vhacd
macros
examples/libraries
libraries/entities/src
tests
CMakeLists.txtQTestExtensions.h
audio
jitter
networking
octree
physics
CMakeLists.txt
src
BulletTestUtils.hBulletUtilTests.cppBulletUtilTests.hCollisionInfoTests.cppCollisionInfoTests.hGlmTestUtils.hMeshMassPropertiesTests.cppMeshMassPropertiesTests.hPhysicsTestUtil.cppPhysicsTestUtil.hShapeColliderTests.cppShapeColliderTests.hShapeInfoTests.cppShapeInfoTests.hShapeManagerTests.cppShapeManagerTests.hmain.cpp
render-utils
shared
ui
|
@ -133,6 +133,9 @@ if (APPLE)
|
|||
set(CMAKE_OSX_SYSROOT ${_OSX_DESIRED_SDK_PATH}/MacOSX10.9.sdk)
|
||||
endif ()
|
||||
|
||||
# Hide automoc folders (for IDEs)
|
||||
set(AUTOGEN_TARGETS_FOLDER "hidden/generated")
|
||||
|
||||
# Find includes in corresponding build directories
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
# Instruct CMake to run moc automatically when needed.
|
||||
|
|
3
cmake/externals/LibOVR/CMakeLists.txt
vendored
3
cmake/externals/LibOVR/CMakeLists.txt
vendored
|
@ -86,4 +86,7 @@ elseif(NOT ANDROID)
|
|||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARY} ${${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS} CACHE TYPE INTERNAL)
|
||||
endif()
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
|
||||
|
|
3
cmake/externals/bullet/CMakeLists.txt
vendored
3
cmake/externals/bullet/CMakeLists.txt
vendored
|
@ -38,6 +38,9 @@ else ()
|
|||
)
|
||||
endif ()
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
|
3
cmake/externals/glew/CMakeLists.txt
vendored
3
cmake/externals/glew/CMakeLists.txt
vendored
|
@ -12,6 +12,9 @@ if (WIN32)
|
|||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
|
3
cmake/externals/glm/CMakeLists.txt
vendored
3
cmake/externals/glm/CMakeLists.txt
vendored
|
@ -12,6 +12,9 @@ ExternalProject_Add(
|
|||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
|
3
cmake/externals/gverb/CMakeLists.txt
vendored
3
cmake/externals/gverb/CMakeLists.txt
vendored
|
@ -16,6 +16,9 @@ ExternalProject_Add(
|
|||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
|
3
cmake/externals/oglplus/CMakeLists.txt
vendored
3
cmake/externals/oglplus/CMakeLists.txt
vendored
|
@ -12,6 +12,9 @@ ExternalProject_Add(
|
|||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include ${SOURCE_DIR}/implement CACHE TYPE INTERNAL)
|
||||
|
|
3
cmake/externals/openvr/CMakeLists.txt
vendored
3
cmake/externals/openvr/CMakeLists.txt
vendored
|
@ -15,6 +15,9 @@ ExternalProject_Add(
|
|||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/headers CACHE TYPE INTERNAL)
|
||||
|
|
2
cmake/externals/polyvox/CMakeLists.txt
vendored
2
cmake/externals/polyvox/CMakeLists.txt
vendored
|
@ -12,6 +12,8 @@ ExternalProject_Add(
|
|||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
|
|
3
cmake/externals/qxmpp/CMakeLists.txt
vendored
3
cmake/externals/qxmpp/CMakeLists.txt
vendored
|
@ -36,6 +36,9 @@ ExternalProject_Add(
|
|||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL Xcode)
|
||||
|
|
3
cmake/externals/sdl2/CMakeLists.txt
vendored
3
cmake/externals/sdl2/CMakeLists.txt
vendored
|
@ -38,6 +38,9 @@ else ()
|
|||
)
|
||||
endif ()
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (APPLE)
|
||||
|
|
3
cmake/externals/soxr/CMakeLists.txt
vendored
3
cmake/externals/soxr/CMakeLists.txt
vendored
|
@ -16,6 +16,9 @@ ExternalProject_Add(
|
|||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
|
3
cmake/externals/tbb/CMakeLists.txt
vendored
3
cmake/externals/tbb/CMakeLists.txt
vendored
|
@ -53,6 +53,9 @@ else ()
|
|||
)
|
||||
endif ()
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
|
3
cmake/externals/vhacd/CMakeLists.txt
vendored
3
cmake/externals/vhacd/CMakeLists.txt
vendored
|
@ -16,6 +16,9 @@ ExternalProject_Add(
|
|||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
|
139
cmake/macros/SetupHifiTestCase.cmake
Normal file
139
cmake/macros/SetupHifiTestCase.cmake
Normal file
|
@ -0,0 +1,139 @@
|
|||
#
|
||||
# SetupHifiTestCase.cmake
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
# Sets up a hifi testcase using QtTest.
|
||||
# Can be called with arguments; like setup_hifi_project, the arguments correspond to qt modules, so call it
|
||||
# via setup_hifi_testcase(Script Network Qml) to build the testcase with Qt5Script, Qt5Network, and Qt5Qml linked,
|
||||
# for example.
|
||||
|
||||
# One special quirk of this is that because we are creating multiple testcase targets (instead of just one),
|
||||
# any dependencies and other setup that the testcase has must be declared in a macro, and setup_hifi_testcase()
|
||||
# must be called *after* this declaration, not before it.
|
||||
|
||||
# Here's a full example:
|
||||
# tests/my-foo-test/CMakeLists.txt:
|
||||
#
|
||||
# # Declare testcase dependencies
|
||||
# macro (setup_hifi_testcase)
|
||||
# bunch
|
||||
# of
|
||||
# custom
|
||||
# dependencies...
|
||||
#
|
||||
# link_hifi_libraries(shared networking etc)
|
||||
#
|
||||
# copy_dlls_beside_windows_executable()
|
||||
# endmacro()
|
||||
#
|
||||
# setup_hifi_testcase(Network etc)
|
||||
#
|
||||
# Additionally, all .cpp files in the src dir (eg tests/my-foo-test/src) must:
|
||||
# - Contain exactly one test class (any supporting code must be either external or inline in a .hpp file)
|
||||
# - Be built against QtTestLib (test class should be a QObject, with test methods defined as private slots)
|
||||
# - Contain a QTEST_MAIN declaration at the end of the file (or at least be a standalone executable)
|
||||
#
|
||||
# All other testing infrastructure is generated automatically.
|
||||
#
|
||||
|
||||
macro(SETUP_HIFI_TESTCASE)
|
||||
if (NOT DEFINED TEST_PROJ_NAME)
|
||||
message(SEND_ERROR "Missing TEST_PROJ_NAME (setup_hifi_testcase was called incorrectly?)")
|
||||
elseif (NOT COMMAND SETUP_TESTCASE_DEPENDENCIES)
|
||||
message(SEND_ERROR "Missing testcase dependencies declaration (SETUP_TESTCASE_DEPENDENCIES)")
|
||||
elseif (DEFINED ${TEST_PROJ_NAME}_BUILT)
|
||||
message(WARNING "testcase \"" ${TEST_PROJ_NAME} "\" was already built")
|
||||
else ()
|
||||
set(${TEST_PROJ_NAME}_BUILT 1)
|
||||
|
||||
file(GLOB TEST_PROJ_SRC_FILES src/*)
|
||||
file(GLOB TEST_PROJ_SRC_SUBDIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/*)
|
||||
|
||||
foreach (DIR ${TEST_PROJ_SRC_SUBDIRS})
|
||||
if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/${DIR}")
|
||||
file(GLOB DIR_CONTENTS "src/${DIR}/*")
|
||||
set(TEST_PROJ_SRC_FILES ${TEST_PROJ_SRC_FILES} "${DIR_CONTENTS}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Find test classes to build into test executables.
|
||||
# Warn about any .cpp files that are *not* test classes (*Test[s].cpp), since those files will not be used.
|
||||
foreach (SRC_FILE ${TEST_PROJ_SRC_FILES})
|
||||
string(REGEX MATCH ".+Tests?\\.cpp$" TEST_CPP_FILE ${SRC_FILE})
|
||||
string(REGEX MATCH ".+\\.cpp$" NON_TEST_CPP_FILE ${SRC_FILE})
|
||||
if (TEST_CPP_FILE)
|
||||
list(APPEND TEST_CASE_FILES ${TEST_CPP_FILE})
|
||||
elseif (NON_TEST_CPP_FILE)
|
||||
message(WARNING "ignoring .cpp file (not a test class -- this will not be linked or compiled!): " ${NON_TEST_CPP_FILE})
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
if (TEST_CASE_FILES)
|
||||
set(TEST_PROJ_TARGETS "")
|
||||
|
||||
# Add each test class executable (duplicates functionality in SetupHifiProject.cmake)
|
||||
# The resulting targets will be buried inside of hidden/test-executables so that they don't clutter up
|
||||
# the project view in Xcode, Visual Studio, etc.
|
||||
foreach (TEST_FILE ${TEST_CASE_FILES})
|
||||
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
|
||||
set(TARGET_NAME ${TEST_PROJ_NAME}-${TEST_NAME})
|
||||
|
||||
project(${TARGET_NAME})
|
||||
|
||||
# grab the implemenation and header files
|
||||
set(TARGET_SRCS ${TEST_FILE}) # only one source / .cpp file (the test class)
|
||||
|
||||
add_executable(${TARGET_NAME} ${TEST_FILE})
|
||||
add_test(${TARGET_NAME}-test ${TARGET_NAME})
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES
|
||||
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
||||
EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
list (APPEND ${TEST_PROJ_NAME}_TARGETS ${TARGET_NAME})
|
||||
#list (APPEND ALL_TEST_TARGETS ${TARGET_NAME})
|
||||
|
||||
set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN})
|
||||
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core Test)
|
||||
|
||||
# find these Qt modules and link them to our own target
|
||||
find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED)
|
||||
|
||||
foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES})
|
||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||
endforeach()
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "hidden/test-executables")
|
||||
|
||||
# handle testcase-specific dependencies (this a macro that should be defined in the cmakelists.txt file in each tests subdir)
|
||||
|
||||
SETUP_TESTCASE_DEPENDENCIES ()
|
||||
endforeach ()
|
||||
|
||||
set(TEST_TARGET ${TEST_PROJ_NAME}-tests)
|
||||
|
||||
# Add a dummy target so that the project files are visible.
|
||||
# This target will also build + run the other test targets using ctest when built.
|
||||
|
||||
add_custom_target(${TEST_TARGET}
|
||||
COMMAND ctest .
|
||||
SOURCES ${TEST_PROJ_SRC_FILES} # display source files under the testcase target
|
||||
DEPENDS ${${TEST_PROJ_NAME}_TARGETS})
|
||||
set_target_properties(${TEST_TARGET} PROPERTIES
|
||||
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
||||
EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
set_target_properties(${TEST_TARGET} PROPERTIES FOLDER "Tests")
|
||||
|
||||
list (APPEND ALL_TEST_TARGETS ${TEST_TARGET})
|
||||
set(ALL_TEST_TARGETS "${ALL_TEST_TARGETS}" PARENT_SCOPE)
|
||||
else ()
|
||||
message(WARNING "No testcases in " ${TEST_PROJ_NAME})
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro(SETUP_HIFI_TESTCASE)
|
|
@ -11,7 +11,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
test = function(name, func) {
|
||||
var test = function(name, func) {
|
||||
print("Running test: " + name);
|
||||
|
||||
var unitTest = new UnitTest(name, func);
|
||||
|
|
|
@ -249,7 +249,7 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti
|
|||
if (getIsClient()) {
|
||||
// if our Node isn't allowed to create entities in this domain, don't try.
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
if (!nodeList->getThisNodeCanRez()) {
|
||||
if (nodeList && !nodeList->getThisNodeCanRez()) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,37 @@
|
|||
|
||||
# Turn on testing (so that add_test works)
|
||||
enable_testing()
|
||||
|
||||
# add the test directories
|
||||
file(GLOB TEST_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/*")
|
||||
list(REMOVE_ITEM TEST_SUBDIRS "CMakeFiles")
|
||||
foreach(DIR ${TEST_SUBDIRS})
|
||||
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${DIR}")
|
||||
add_subdirectory(${DIR})
|
||||
set_target_properties("${DIR}-tests" PROPERTIES FOLDER "Tests")
|
||||
endif()
|
||||
endforeach()
|
||||
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${DIR}")
|
||||
set(TEST_PROJ_NAME ${DIR})
|
||||
add_subdirectory(${DIR})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
file(GLOB SHARED_TEST_HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp")
|
||||
|
||||
add_custom_target("test-extensions"
|
||||
SOURCES "${SHARED_TEST_HEADER_FILES}")
|
||||
list(APPEND ALL_TEST_TARGETS "test-extensions")
|
||||
set_target_properties("test-extensions" PROPERTIES FOLDER "Tests")
|
||||
|
||||
message(STATUS "ALL_TEST_TARGETS = ${ALL_TEST_TARGETS}")
|
||||
|
||||
# Create the all-tests build target.
|
||||
# The dependency list (ALL_TEST_TARGETS) is generated from setup_hifi_testcase invocations in the CMakeLists.txt
|
||||
# files in the test subdirs. Note: since variables normally do *not* persist into parent scope, we use a hack:
|
||||
#
|
||||
# list(APPEND ALL_TEST_TARGETS ${targets_to_add...}) # appends to a local list var (copied from parent scope)
|
||||
# set (ALL_TEST_TARGETS "${ALL_TEST_TARGETS}" PARENT_SCOPE) # copies this back to parent scope
|
||||
#
|
||||
add_custom_target("all-tests"
|
||||
COMMAND ctest .
|
||||
DEPENDS "${ALL_TEST_TARGETS}")
|
||||
set_target_properties("all-tests" PROPERTIES FOLDER "hidden/test-targets")
|
||||
set_target_properties("all-tests" PROPERTIES
|
||||
EXCLUDE_FROM_DEFAULT_BUILD TRUE
|
||||
EXCLUDE_FROM_ALL TRUE)
|
256
tests/QTestExtensions.h
Normal file
256
tests/QTestExtensions.h
Normal file
|
@ -0,0 +1,256 @@
|
|||
//
|
||||
// QTestExtensions.h
|
||||
// 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 <QtTest/QtTest>
|
||||
#include <functional>
|
||||
|
||||
// Implements several extensions to QtTest.
|
||||
//
|
||||
// Problems with QtTest:
|
||||
// - QCOMPARE can compare float values (using a fuzzy compare), but uses an internal threshold
|
||||
// that cannot be set explicitely (and we need explicit, adjustable error thresholds for our physics
|
||||
// and math test code).
|
||||
// - QFAIL takes a const char * failure message, and writing custom messages to it is complicated.
|
||||
//
|
||||
// To solve this, we have:
|
||||
// - QCOMPARE_WITH_ABS_ERROR (compares floats, or *any other type* using explicitely defined error thresholds.
|
||||
// To use it, you need to have a compareWithAbsError function ((T, T) -> V), and operator << for QTextStream).
|
||||
// - QFAIL_WITH_MESSAGE("some " << streamed << " message"), which builds, writes to, and stringifies
|
||||
// a QTextStream using black magic.
|
||||
// - QCOMPARE_WITH_LAMBDA / QCOMPARE_WITH_FUNCTION, which implements QCOMPARE, but with a user-defined
|
||||
// test function ((T, T) -> bool).
|
||||
// - A simple framework to write additional custom test macros as needed (QCOMPARE is reimplemented
|
||||
// from scratch using QTest::qFail, for example).
|
||||
//
|
||||
|
||||
|
||||
// Generates a QCOMPARE-style failure message that can be passed to QTest::qFail.
|
||||
//
|
||||
// Formatting looks like this:
|
||||
// <qFail message> <failMessage....>
|
||||
// Actual: (<stringified actual expr>) : <actual value>
|
||||
// Expected: (<stringified expected expr>): <expected value>
|
||||
// < additional messages (should be separated by "\n\t" for indent formatting)>
|
||||
// Loc: [<file path....>(<linenum>)]
|
||||
//
|
||||
// Additional messages (after actual/expected) can be written using the std::function callback.
|
||||
// If these messages span more than one line, wrap them with "\n\t" to get proper indentation / formatting)
|
||||
//
|
||||
template <typename T> inline
|
||||
QString QTest_generateCompareFailureMessage (
|
||||
const char* failMessage,
|
||||
const T& actual, const T& expected,
|
||||
const char* actual_expr, const char* expected_expr,
|
||||
std::function<QTextStream& (QTextStream&)> 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;
|
||||
}
|
||||
|
||||
// Generates a QCOMPARE-style failure message that can be passed to QTest::qFail.
|
||||
//
|
||||
// Formatting looks like this:
|
||||
// <qFail message> <failMessage....>
|
||||
// Actual: (<stringified actual expr>) : <actual value>
|
||||
// Expected: (<stringified expected expr>): <expected value>
|
||||
// Loc: [<file path....>(<linenum>)]
|
||||
// (no message callback)
|
||||
//
|
||||
template <typename T> 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;
|
||||
}
|
||||
|
||||
// Hacky function that can assemble a QString from a QTextStream via a callback
|
||||
// (ie. stream operations w/out qDebug())
|
||||
inline
|
||||
QString makeMessageFromStream (std::function<void(QTextStream&)> writeMessage) {
|
||||
QString msg;
|
||||
QTextStream stream(&msg);
|
||||
writeMessage(stream);
|
||||
return msg;
|
||||
}
|
||||
|
||||
inline
|
||||
void QTest_failWithCustomMessage (
|
||||
std::function<void(QTextStream&)> writeMessage, int line, const char* file
|
||||
) {
|
||||
QTest::qFail(qPrintable(makeMessageFromStream(writeMessage)), file, line);
|
||||
}
|
||||
|
||||
// Equivalent to QFAIL, but takes a message that can be formatted using stream operators.
|
||||
// Writes to a QTextStream internally, and calls QTest::qFail (the internal impl of QFAIL,
|
||||
// with the current file and line number)
|
||||
//
|
||||
// example:
|
||||
// inline void foo () {
|
||||
// int thing = 2;
|
||||
// QFAIL_WITH_MESSAGE("Message " << thing << ";");
|
||||
// }
|
||||
//
|
||||
#define QFAIL_WITH_MESSAGE(...) \
|
||||
do { \
|
||||
QTest_failWithCustomMessage([&](QTextStream& stream) { stream << __VA_ARGS__; }, __LINE__, __FILE__); \
|
||||
return; \
|
||||
} while(0)
|
||||
|
||||
// Calls qFail using QTest_generateCompareFailureMessage.
|
||||
// This is (usually) wrapped in macros, but if you call this directly you should return immediately to get QFAIL semantics.
|
||||
template <typename T> inline
|
||||
void QTest_failWithMessage(
|
||||
const char* failMessage,
|
||||
const T& actual, const T& expected,
|
||||
const char* actualExpr, const char* expectedExpr,
|
||||
int line, const char* file
|
||||
) {
|
||||
QTest::qFail(qPrintable(QTest_generateCompareFailureMessage(
|
||||
failMessage, actual, expected, actualExpr, expectedExpr)), file, line);
|
||||
}
|
||||
|
||||
// Calls qFail using QTest_generateCompareFailureMessage.
|
||||
// This is (usually) wrapped in macros, but if you call this directly you should return immediately to get QFAIL semantics.
|
||||
template <typename T> inline
|
||||
void QTest_failWithMessage(
|
||||
const char* failMessage,
|
||||
const T& actual, const T& expected,
|
||||
const char* actualExpr, const char* expectedExpr,
|
||||
int line, const char* file,
|
||||
std::function<QTextStream& (QTextStream&)> writeAdditionalMessageLines
|
||||
) {
|
||||
QTest::qFail(qPrintable(QTest_generateCompareFailureMessage(
|
||||
failMessage, actual, expected, actualExpr, expectedExpr, writeAdditionalMessageLines)), file, line);
|
||||
}
|
||||
|
||||
// Implements QCOMPARE_WITH_ABS_ERROR
|
||||
template <typename T, typename V> inline
|
||||
bool QTest_compareWithAbsError(
|
||||
const T& actual, const T& expected,
|
||||
const char* actual_expr, const char* expected_expr,
|
||||
int line, const char* file,
|
||||
const V& epsilon
|
||||
) {
|
||||
if (abs(getErrorDifference(actual, expected)) > abs(epsilon)) {
|
||||
QTest_failWithMessage(
|
||||
"Compared values are not the same (fuzzy compare)",
|
||||
actual, expected, actual_expr, expected_expr, line, file,
|
||||
[&] (QTextStream& stream) -> QTextStream& {
|
||||
return stream << "Err tolerance: " << getErrorDifference((actual), (expected)) << " > " << epsilon;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Implements a fuzzy QCOMPARE using an explicit epsilon error value.
|
||||
// If you use this, you must have the following functions defined for the types you're using:
|
||||
// <T, V> V compareWithAbsError (const T& a, const T& b) (should return the absolute, max difference between a and b)
|
||||
// <T> QTextStream & operator << (QTextStream& stream, const T& value)
|
||||
//
|
||||
// Here's an implementation for glm::vec3:
|
||||
// inline float compareWithAbsError (const glm::vec3 & a, const glm::vec3 & b) { // returns
|
||||
// return glm::distance(a, b);
|
||||
// }
|
||||
// inline QTextStream & operator << (QTextStream & stream, const T & v) {
|
||||
// return stream << "glm::vec3 { " << v.x << ", " << v.y << ", " << v.z << " }"
|
||||
// }
|
||||
//
|
||||
#define QCOMPARE_WITH_ABS_ERROR(actual, expected, epsilon) \
|
||||
do { \
|
||||
if (!QTest_compareWithAbsError((actual), (expected), #actual, #expected, __LINE__, __FILE__, epsilon)) \
|
||||
return; \
|
||||
} while(0)
|
||||
|
||||
// Implements QCOMPARE using an explicit, externally defined test function.
|
||||
// The advantage of this (over a manual check or what have you) is that the values of actual and
|
||||
// expected are printed in the event that the test fails.
|
||||
//
|
||||
// testFunc(const T & actual, const T & expected) -> bool: true (test succeeds) | false (test fails)
|
||||
//
|
||||
#define QCOMPARE_WITH_FUNCTION(actual, expected, testFunc) \
|
||||
do { \
|
||||
if (!(testFunc((actual), (expected)))) { \
|
||||
QTest_failWithMessage("Compared values are not the same", (actual), (expected), #actual, #expected, __LINE__, __FILE__); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Implements QCOMPARE using an explicit, externally defined test function.
|
||||
// Unlike QCOMPARE_WITH_FUNCTION, this func / closure takes no arguments (which is much more convenient
|
||||
// if you're using a c++11 closure / lambda).
|
||||
//
|
||||
// usage:
|
||||
// QCOMPARE_WITH_LAMBDA(foo, expectedFoo, [&foo, &expectedFoo] () {
|
||||
// return foo->isFooish() && foo->fooishness() >= expectedFoo->fooishness();
|
||||
// });
|
||||
// (fails if foo is not as fooish as expectedFoo)
|
||||
//
|
||||
#define QCOMPARE_WITH_LAMBDA(actual, expected, testClosure) \
|
||||
do { \
|
||||
if (!(testClosure())) { \
|
||||
QTest_failWithMessage("Compared values are not the same", (actual), (expected), #actual, #expected, __LINE__, __FILE__); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Same as QCOMPARE_WITH_FUNCTION, but with a custom fail message
|
||||
#define QCOMPARE_WITH_FUNCTION_AND_MESSAGE(actual, expected, testfunc, failMessage) \
|
||||
do { \
|
||||
if (!(testFunc((actual), (expected)))) { \
|
||||
QTest_failWithMessage((failMessage), (actual), (expected), #actual, #expected, __LINE__, __FILE__); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Same as QCOMPARE_WITH_FUNCTION, but with a custom fail message
|
||||
#define QCOMPARE_WITH_LAMBDA_AND_MESSAGE(actual, expected, testClosure, failMessage) \
|
||||
do { \
|
||||
if (!(testClosure())) { \
|
||||
QTest_failWithMessage((failMessage), (actual), (expected), #actual, #expected, __LINE__, __FILE__); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
set(TARGET_NAME audio-tests)
|
||||
# Declare dependencies
|
||||
macro (SETUP_TESTCASE_DEPENDENCIES)
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared audio networking)
|
||||
|
||||
setup_hifi_project()
|
||||
copy_dlls_beside_windows_executable()
|
||||
endmacro ()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared audio networking)
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
||||
setup_hifi_testcase()
|
|
@ -13,10 +13,17 @@
|
|||
|
||||
#include "SharedUtil.h"
|
||||
|
||||
// Adds an implicit cast to make sure that actual and expected are of the same type.
|
||||
// QCOMPARE(<unsigned int>, <int>) => cryptic linker error.
|
||||
// (since QTest::qCompare is defined for (T, T, ...), but not (T, U, ...))
|
||||
//
|
||||
#define QCOMPARE_WITH_CAST(actual, expected) \
|
||||
QCOMPARE(actual, static_cast<decltype(actual)>(expected))
|
||||
|
||||
QTEST_MAIN(AudioRingBufferTests)
|
||||
|
||||
void AudioRingBufferTests::assertBufferSize(const AudioRingBuffer& buffer, int samples) {
|
||||
if (buffer.samplesAvailable() != samples) {
|
||||
qDebug("Unexpected num samples available! Exptected: %d Actual: %d\n", samples, buffer.samplesAvailable());
|
||||
}
|
||||
QCOMPARE(buffer.samplesAvailable(), samples);
|
||||
}
|
||||
|
||||
void AudioRingBufferTests::runAllTests() {
|
||||
|
@ -54,13 +61,8 @@ void AudioRingBufferTests::runAllTests() {
|
|||
|
||||
// verify 143 samples of read data
|
||||
for (int i = 0; i < 143; i++) {
|
||||
if (readData[i] != i) {
|
||||
qDebug("first readData[%d] incorrect! Expcted: %d Actual: %d", i, i, readData[i]);
|
||||
return;
|
||||
}
|
||||
QCOMPARE(readData[i], (int16_t)i);
|
||||
}
|
||||
|
||||
|
||||
writeIndexAt = 0;
|
||||
readIndexAt = 0;
|
||||
|
||||
|
@ -81,9 +83,6 @@ void AudioRingBufferTests::runAllTests() {
|
|||
readData[i] = writeIndexAt - 100 + i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
writeIndexAt = 0;
|
||||
readIndexAt = 0;
|
||||
|
||||
|
@ -96,50 +95,33 @@ void AudioRingBufferTests::runAllTests() {
|
|||
assertBufferSize(ringBuffer, 100);
|
||||
|
||||
// write 29 silent samples, 100 samples in buffer, make sure non were added
|
||||
int samplesWritten;
|
||||
if ((samplesWritten = ringBuffer.addSilentSamples(29)) != 0) {
|
||||
qDebug("addSilentSamples(29) incorrect! Expected: 0 Actual: %d", samplesWritten);
|
||||
return;
|
||||
}
|
||||
int samplesWritten = ringBuffer.addSilentSamples(29);
|
||||
QCOMPARE(samplesWritten, 0);
|
||||
assertBufferSize(ringBuffer, 100);
|
||||
|
||||
// read 3 samples, 97 samples in buffer (expect to read "1", "2", "3")
|
||||
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 3);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (readData[i] != i + 1) {
|
||||
qDebug("Second readData[%d] incorrect! Expcted: %d Actual: %d", i, i + 1, readData[i]);
|
||||
return;
|
||||
}
|
||||
QCOMPARE(readData[i], static_cast<int16_t>(i + 1));
|
||||
}
|
||||
assertBufferSize(ringBuffer, 97);
|
||||
|
||||
// write 4 silent samples, 100 samples in buffer
|
||||
if ((samplesWritten = ringBuffer.addSilentSamples(4)) != 3) {
|
||||
qDebug("addSilentSamples(4) incorrect! Exptected: 3 Actual: %d", samplesWritten);
|
||||
return;
|
||||
}
|
||||
QCOMPARE(ringBuffer.addSilentSamples(4), 3);
|
||||
assertBufferSize(ringBuffer, 100);
|
||||
|
||||
// read back 97 samples (the non-silent samples), 3 samples in buffer (expect to read "4" thru "100")
|
||||
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 97);
|
||||
for (int i = 3; i < 100; i++) {
|
||||
if (readData[i] != i + 1) {
|
||||
qDebug("third readData[%d] incorrect! Expcted: %d Actual: %d", i, i + 1, readData[i]);
|
||||
return;
|
||||
}
|
||||
QCOMPARE(readData[i], static_cast<int16_t>(i + 1));
|
||||
}
|
||||
assertBufferSize(ringBuffer, 3);
|
||||
|
||||
// read back 3 silent samples, 0 samples in buffer
|
||||
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 3);
|
||||
for (int i = 100; i < 103; i++) {
|
||||
if (readData[i] != 0) {
|
||||
qDebug("Fourth readData[%d] incorrect! Expcted: %d Actual: %d", i, 0, readData[i]);
|
||||
return;
|
||||
}
|
||||
QCOMPARE(readData[i], static_cast<int16_t>(0));
|
||||
}
|
||||
assertBufferSize(ringBuffer, 0);
|
||||
}
|
||||
|
||||
qDebug() << "PASSED";
|
||||
}
|
||||
|
|
|
@ -12,13 +12,16 @@
|
|||
#ifndef hifi_AudioRingBufferTests_h
|
||||
#define hifi_AudioRingBufferTests_h
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include "AudioRingBuffer.h"
|
||||
|
||||
|
||||
namespace AudioRingBufferTests {
|
||||
|
||||
class AudioRingBufferTests : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void runAllTests();
|
||||
|
||||
private:
|
||||
void assertBufferSize(const AudioRingBuffer& buffer, int samples);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tests/audio/src
|
||||
//
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
#include "AudioRingBufferTests.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
AudioRingBufferTests::runAllTests();
|
||||
printf("all tests passed. press enter to exit\n");
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
set(TARGET_NAME jitter-tests)
|
||||
|
||||
setup_hifi_project()
|
||||
# Declare dependencies
|
||||
macro (setup_testcase_dependencies)
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared networking)
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared networking)
|
||||
copy_dlls_beside_windows_executable()
|
||||
endmacro()
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
||||
setup_hifi_testcase()
|
|
@ -23,12 +23,24 @@
|
|||
#include <SimpleMovingAverage.h>
|
||||
#include <StDev.h>
|
||||
|
||||
#include "JitterTests.h"
|
||||
|
||||
// Uncomment this to run manually
|
||||
//#define RUN_MANUALLY
|
||||
|
||||
#ifndef RUN_MANUALLY
|
||||
|
||||
QTEST_MAIN(JitterTests)
|
||||
|
||||
#else // RUN_MANUALLY
|
||||
|
||||
const quint64 MSEC_TO_USEC = 1000;
|
||||
const quint64 LARGE_STATS_TIME = 500; // we don't expect stats calculation to take more than this many usecs
|
||||
|
||||
void runSend(const char* addressOption, int port, int gap, int size, int report);
|
||||
void runReceive(const char* addressOption, int port, int gap, int size, int report);
|
||||
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
if (argc != 7) {
|
||||
printf("usage: jitter-tests <--send|--receive> <address> <port> <gap in usecs> <packet size> <report interval in msecs>\n");
|
||||
|
@ -375,3 +387,5 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo
|
|||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // #ifdef RUN_MANUALLY
|
26
tests/jitter/src/JitterTests.h
Normal file
26
tests/jitter/src/JitterTests.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// QTestExtensions.h
|
||||
// tests/jitter/src
|
||||
//
|
||||
// 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_JitterTests_h
|
||||
#define hifi_JitterTests_h
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
class JitterTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void qTestsNotYetImplemented () {
|
||||
qDebug() << "TODO: Reimplement this using QtTest!\n"
|
||||
"(JitterTests takes commandline arguments (port numbers), and can be run manually by #define-ing RUN_MANUALLY in JitterTests.cpp)";
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,8 +1,10 @@
|
|||
set(TARGET_NAME networking-tests)
|
||||
|
||||
setup_hifi_project()
|
||||
# Declare dependencies
|
||||
macro (setup_testcase_dependencies)
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared networking)
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared networking)
|
||||
copy_dlls_beside_windows_executable()
|
||||
endmacro ()
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
||||
setup_hifi_testcase()
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AudioRingBufferTests.cpp
|
||||
// SequenceNumberStatsTests.cpp
|
||||
// tests/networking/src
|
||||
//
|
||||
// Created by Yixin Wang on 6/24/2014
|
||||
|
@ -9,24 +9,24 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "SequenceNumberStatsTests.h"
|
||||
|
||||
void SequenceNumberStatsTests::runAllTests() {
|
||||
rolloverTest();
|
||||
earlyLateTest();
|
||||
duplicateTest();
|
||||
pruneTest();
|
||||
resyncTest();
|
||||
}
|
||||
QTEST_MAIN(SequenceNumberStatsTests)
|
||||
|
||||
const quint32 UINT16_RANGE = std::numeric_limits<quint16>::max() + 1;
|
||||
|
||||
|
||||
// Adds an implicit cast to make sure that actual and expected are of the same type.
|
||||
// QCOMPARE(<unsigned int>, <int>) => cryptic linker error.
|
||||
// (since QTest::qCompare is defined for (T, T, ...), but not (T, U, ...))
|
||||
//
|
||||
#define QCOMPARE_WITH_CAST(actual, expected) \
|
||||
QCOMPARE(actual, static_cast<decltype(actual)>(expected))
|
||||
|
||||
void SequenceNumberStatsTests::rolloverTest() {
|
||||
|
||||
SequenceNumberStats stats;
|
||||
|
@ -39,11 +39,12 @@ void SequenceNumberStatsTests::rolloverTest() {
|
|||
stats.sequenceNumberReceived(seq);
|
||||
seq = seq + (quint16)1;
|
||||
|
||||
assert(stats.getEarly() == 0);
|
||||
assert(stats.getLate() == 0);
|
||||
assert(stats.getLost() == 0);
|
||||
assert(stats.getReceived() == i + 1);
|
||||
assert(stats.getRecovered() == 0);
|
||||
QCOMPARE_WITH_CAST(stats.getEarly(), 0);
|
||||
QCOMPARE_WITH_CAST(stats.getEarly(), 0);
|
||||
QCOMPARE_WITH_CAST(stats.getLate(), 0);
|
||||
QCOMPARE_WITH_CAST(stats.getLost(), 0);
|
||||
QCOMPARE_WITH_CAST(stats.getReceived(), i + 1);
|
||||
QCOMPARE_WITH_CAST(stats.getRecovered(), 0);
|
||||
}
|
||||
stats.reset();
|
||||
}
|
||||
|
@ -69,11 +70,11 @@ void SequenceNumberStatsTests::earlyLateTest() {
|
|||
seq = seq + (quint16)1;
|
||||
numSent++;
|
||||
|
||||
assert(stats.getEarly() == numEarly);
|
||||
assert(stats.getLate() == numLate);
|
||||
assert(stats.getLost() == numLost);
|
||||
assert(stats.getReceived() == numSent);
|
||||
assert(stats.getRecovered() == numRecovered);
|
||||
QCOMPARE_WITH_CAST(stats.getEarly(), numEarly);
|
||||
QCOMPARE_WITH_CAST(stats.getLate(), numLate);
|
||||
QCOMPARE_WITH_CAST(stats.getLost(), numLost);
|
||||
QCOMPARE_WITH_CAST(stats.getReceived(), numSent);
|
||||
QCOMPARE_WITH_CAST(stats.getRecovered(), numRecovered);
|
||||
}
|
||||
|
||||
// skip 10
|
||||
|
@ -88,11 +89,11 @@ void SequenceNumberStatsTests::earlyLateTest() {
|
|||
seq = seq + (quint16)1;
|
||||
numSent++;
|
||||
|
||||
assert(stats.getEarly() == numEarly);
|
||||
assert(stats.getLate() == numLate);
|
||||
assert(stats.getLost() == numLost);
|
||||
assert(stats.getReceived() == numSent);
|
||||
assert(stats.getRecovered() == numRecovered);
|
||||
QCOMPARE_WITH_CAST(stats.getEarly(), numEarly);
|
||||
QCOMPARE_WITH_CAST(stats.getLate(), numLate);
|
||||
QCOMPARE_WITH_CAST(stats.getLost(), numLost);
|
||||
QCOMPARE_WITH_CAST(stats.getReceived(), numSent);
|
||||
QCOMPARE_WITH_CAST(stats.getRecovered(), numRecovered);
|
||||
}
|
||||
|
||||
// send ones we skipped
|
||||
|
@ -104,11 +105,11 @@ void SequenceNumberStatsTests::earlyLateTest() {
|
|||
numLost--;
|
||||
numRecovered++;
|
||||
|
||||
assert(stats.getEarly() == numEarly);
|
||||
assert(stats.getLate() == numLate);
|
||||
assert(stats.getLost() == numLost);
|
||||
assert(stats.getReceived() == numSent);
|
||||
assert(stats.getRecovered() == numRecovered);
|
||||
QCOMPARE_WITH_CAST(stats.getEarly(), numEarly);
|
||||
QCOMPARE_WITH_CAST(stats.getLate(), numLate);
|
||||
QCOMPARE_WITH_CAST(stats.getLost(), numLost);
|
||||
QCOMPARE_WITH_CAST(stats.getReceived(), numSent);
|
||||
QCOMPARE_WITH_CAST(stats.getRecovered(), numRecovered);
|
||||
}
|
||||
}
|
||||
stats.reset();
|
||||
|
@ -142,12 +143,12 @@ void SequenceNumberStatsTests::duplicateTest() {
|
|||
seq = seq + (quint16)1;
|
||||
numSent++;
|
||||
|
||||
assert(stats.getUnreasonable() == numDuplicate);
|
||||
assert(stats.getEarly() == numEarly);
|
||||
assert(stats.getLate() == numLate);
|
||||
assert(stats.getLost() == numLost);
|
||||
assert(stats.getReceived() == numSent);
|
||||
assert(stats.getRecovered() == 0);
|
||||
QCOMPARE_WITH_CAST(stats.getUnreasonable(), numDuplicate);
|
||||
QCOMPARE_WITH_CAST(stats.getEarly(), numEarly);
|
||||
QCOMPARE_WITH_CAST(stats.getLate(), numLate);
|
||||
QCOMPARE_WITH_CAST(stats.getLost(), numLost);
|
||||
QCOMPARE_WITH_CAST(stats.getReceived(), numSent);
|
||||
QCOMPARE_WITH_CAST(stats.getRecovered(), 0);
|
||||
}
|
||||
|
||||
// skip 10
|
||||
|
@ -164,12 +165,12 @@ void SequenceNumberStatsTests::duplicateTest() {
|
|||
seq = seq + (quint16)1;
|
||||
numSent++;
|
||||
|
||||
assert(stats.getUnreasonable() == numDuplicate);
|
||||
assert(stats.getEarly() == numEarly);
|
||||
assert(stats.getLate() == numLate);
|
||||
assert(stats.getLost() == numLost);
|
||||
assert(stats.getReceived() == numSent);
|
||||
assert(stats.getRecovered() == 0);
|
||||
QCOMPARE_WITH_CAST(stats.getUnreasonable(), numDuplicate);
|
||||
QCOMPARE_WITH_CAST(stats.getEarly(), numEarly);
|
||||
QCOMPARE_WITH_CAST(stats.getLate(), numLate);
|
||||
QCOMPARE_WITH_CAST(stats.getLost(), numLost);
|
||||
QCOMPARE_WITH_CAST(stats.getReceived(), numSent);
|
||||
QCOMPARE_WITH_CAST(stats.getRecovered(), 0);
|
||||
}
|
||||
|
||||
// send 5 duplicates from before skip
|
||||
|
@ -180,12 +181,12 @@ void SequenceNumberStatsTests::duplicateTest() {
|
|||
numDuplicate++;
|
||||
numLate++;
|
||||
|
||||
assert(stats.getUnreasonable() == numDuplicate);
|
||||
assert(stats.getEarly() == numEarly);
|
||||
assert(stats.getLate() == numLate);
|
||||
assert(stats.getLost() == numLost);
|
||||
assert(stats.getReceived() == numSent);
|
||||
assert(stats.getRecovered() == 0);
|
||||
QCOMPARE_WITH_CAST(stats.getUnreasonable(), numDuplicate);
|
||||
QCOMPARE_WITH_CAST(stats.getEarly(), numEarly);
|
||||
QCOMPARE_WITH_CAST(stats.getLate(), numLate);
|
||||
QCOMPARE_WITH_CAST(stats.getLost(), numLost);
|
||||
QCOMPARE_WITH_CAST(stats.getReceived(), numSent);
|
||||
QCOMPARE_WITH_CAST(stats.getRecovered(), 0);
|
||||
}
|
||||
|
||||
// send 5 duplicates from after skip
|
||||
|
@ -196,12 +197,12 @@ void SequenceNumberStatsTests::duplicateTest() {
|
|||
numDuplicate++;
|
||||
numLate++;
|
||||
|
||||
assert(stats.getUnreasonable() == numDuplicate);
|
||||
assert(stats.getEarly() == numEarly);
|
||||
assert(stats.getLate() == numLate);
|
||||
assert(stats.getLost() == numLost);
|
||||
assert(stats.getReceived() == numSent);
|
||||
assert(stats.getRecovered() == 0);
|
||||
QCOMPARE_WITH_CAST(stats.getUnreasonable(), numDuplicate);
|
||||
QCOMPARE_WITH_CAST(stats.getEarly(), numEarly);
|
||||
QCOMPARE_WITH_CAST(stats.getLate(), numLate);
|
||||
QCOMPARE_WITH_CAST(stats.getLost(), numLost);
|
||||
QCOMPARE_WITH_CAST(stats.getReceived(), numSent);
|
||||
QCOMPARE_WITH_CAST(stats.getRecovered(), 0);
|
||||
}
|
||||
}
|
||||
stats.reset();
|
||||
|
@ -253,22 +254,22 @@ void SequenceNumberStatsTests::pruneTest() {
|
|||
numLost += 10;
|
||||
|
||||
const QSet<quint16>& missingSet = stats.getMissingSet();
|
||||
assert(missingSet.size() <= 1000);
|
||||
QCOMPARE_WITH_CAST(missingSet.size() <= 1000, true);
|
||||
if (missingSet.size() > 1000) {
|
||||
qDebug() << "FAIL: missingSet larger than 1000.";
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
assert(missingSet.contains(highestSkipped2));
|
||||
QCOMPARE_WITH_CAST(missingSet.contains(highestSkipped2), true);
|
||||
highestSkipped2 = highestSkipped2 - (quint16)1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 989; i++) {
|
||||
assert(missingSet.contains(highestSkipped));
|
||||
QCOMPARE_WITH_CAST(missingSet.contains(highestSkipped), true);
|
||||
highestSkipped = highestSkipped - (quint16)1;
|
||||
}
|
||||
for (int i = 0; i < 11; i++) {
|
||||
assert(!missingSet.contains(highestSkipped));
|
||||
QCOMPARE_WITH_CAST(!missingSet.contains(highestSkipped), true);
|
||||
highestSkipped = highestSkipped - (quint16)1;
|
||||
}
|
||||
}
|
||||
|
@ -288,7 +289,7 @@ void SequenceNumberStatsTests::resyncTest() {
|
|||
sequence = 89;
|
||||
stats.sequenceNumberReceived(sequence);
|
||||
|
||||
assert(stats.getUnreasonable() == 0);
|
||||
QCOMPARE_WITH_CAST(stats.getUnreasonable(), 0);
|
||||
|
||||
sequence = 2990;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
@ -296,7 +297,7 @@ void SequenceNumberStatsTests::resyncTest() {
|
|||
sequence += (quint16)1;
|
||||
}
|
||||
|
||||
assert(stats.getUnreasonable() == 0);
|
||||
QCOMPARE_WITH_CAST(stats.getUnreasonable(), 0);
|
||||
|
||||
|
||||
sequence = 0;
|
||||
|
@ -305,7 +306,7 @@ void SequenceNumberStatsTests::resyncTest() {
|
|||
sequence += (quint16)1;
|
||||
}
|
||||
|
||||
assert(stats.getUnreasonable() == 7);
|
||||
QCOMPARE_WITH_CAST(stats.getUnreasonable(), 7);
|
||||
|
||||
sequence = 6000;
|
||||
for (int R = 0; R < 7; R++) {
|
||||
|
@ -313,12 +314,12 @@ void SequenceNumberStatsTests::resyncTest() {
|
|||
sequence += (quint16)1;
|
||||
}
|
||||
|
||||
assert(stats.getUnreasonable() == 14);
|
||||
QCOMPARE_WITH_CAST(stats.getUnreasonable(), 14);
|
||||
|
||||
sequence = 9000;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
stats.sequenceNumberReceived(sequence);
|
||||
sequence += (quint16)1;
|
||||
}
|
||||
assert(stats.getUnreasonable() == 0);
|
||||
QCOMPARE_WITH_CAST(stats.getUnreasonable(), 0);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AudioRingBufferTests.h
|
||||
// SequenceNumberStatsTests.h
|
||||
// tests/networking/src
|
||||
//
|
||||
// Created by Yixin Wang on 6/24/2014
|
||||
|
@ -12,13 +12,14 @@
|
|||
#ifndef hifi_SequenceNumberStatsTests_h
|
||||
#define hifi_SequenceNumberStatsTests_h
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include "SequenceNumberStatsTests.h"
|
||||
#include "SequenceNumberStats.h"
|
||||
|
||||
namespace SequenceNumberStatsTests {
|
||||
|
||||
void runAllTests();
|
||||
|
||||
class SequenceNumberStatsTests : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void rolloverTest();
|
||||
void earlyLateTest();
|
||||
void duplicateTest();
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tests/networking/src
|
||||
//
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
#include "SequenceNumberStatsTests.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
SequenceNumberStatsTests::runAllTests();
|
||||
printf("tests passed! press enter to exit");
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
set(TARGET_NAME octree-tests)
|
||||
|
||||
setup_hifi_project(Script Network)
|
||||
# Declare dependencies
|
||||
macro (setup_testcase_dependencies)
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared octree gpu model fbx networking environment entities avatars audio animation script-engine physics)
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared octree gpu model fbx networking environment entities avatars audio animation script-engine physics)
|
||||
copy_dlls_beside_windows_executable()
|
||||
endmacro ()
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
||||
setup_hifi_testcase(Script Network)
|
|
@ -9,92 +9,63 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <AABox.h>
|
||||
#include <AACube.h>
|
||||
|
||||
#include "AABoxCubeTests.h"
|
||||
|
||||
void AABoxCubeTests::AABoxCubeTests(bool verbose) {
|
||||
qDebug() << "******************************************************************************************";
|
||||
qDebug() << "AABoxCubeTests::AABoxCubeTests()";
|
||||
QTEST_MAIN(AABoxCubeTests)
|
||||
|
||||
{
|
||||
qDebug() << "Test 1: AABox.findRayIntersection() inside out MIN_X_FACE";
|
||||
void AABoxCubeTests::raycastOutHitsXMinFace() {
|
||||
// Raycast inside out
|
||||
glm::vec3 corner(0.0f, 0.0f, 0.0f);
|
||||
float size = 1.0f;
|
||||
|
||||
AABox box(corner, size);
|
||||
glm::vec3 origin(0.5f, 0.5f, 0.5f);
|
||||
glm::vec3 direction(-1.0f, 0.0f, 0.0f);
|
||||
float distance;
|
||||
BoxFace face;
|
||||
|
||||
glm::vec3 corner(0.0f, 0.0f, 0.0f);
|
||||
float size = 1.0f;
|
||||
|
||||
AABox box(corner, size);
|
||||
glm::vec3 origin(0.5f, 0.5f, 0.5f);
|
||||
glm::vec3 direction(-1.0f, 0.0f, 0.0f);
|
||||
float distance;
|
||||
BoxFace face;
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face);
|
||||
|
||||
if (intersects && distance == 0.5f && face == MIN_X_FACE) {
|
||||
qDebug() << "Test 1: PASSED";
|
||||
} else {
|
||||
qDebug() << "intersects=" << intersects << "expected=" << true;
|
||||
qDebug() << "distance=" << distance << "expected=" << 0.5f;
|
||||
qDebug() << "face=" << face << "expected=" << MIN_X_FACE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
qDebug() << "Test 2: AABox.findRayIntersection() inside out MAX_X_FACE";
|
||||
|
||||
glm::vec3 corner(0.0f, 0.0f, 0.0f);
|
||||
float size = 1.0f;
|
||||
|
||||
AABox box(corner, size);
|
||||
glm::vec3 origin(0.5f, 0.5f, 0.5f);
|
||||
glm::vec3 direction(1.0f, 0.0f, 0.0f);
|
||||
float distance;
|
||||
BoxFace face;
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face);
|
||||
|
||||
if (intersects && distance == 0.5f && face == MAX_X_FACE) {
|
||||
qDebug() << "Test 2: PASSED";
|
||||
} else {
|
||||
qDebug() << "intersects=" << intersects << "expected=" << true;
|
||||
qDebug() << "distance=" << distance << "expected=" << 0.5f;
|
||||
qDebug() << "face=" << face << "expected=" << MAX_X_FACE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
qDebug() << "Test 3: AABox.findRayIntersection() outside in";
|
||||
|
||||
glm::vec3 corner(0.5f, 0.0f, 0.0f);
|
||||
float size = 0.5f;
|
||||
|
||||
AABox box(corner, size);
|
||||
glm::vec3 origin(0.25f, 0.25f, 0.25f);
|
||||
glm::vec3 direction(1.0f, 0.0f, 0.0f);
|
||||
float distance;
|
||||
BoxFace face;
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face);
|
||||
|
||||
if (intersects && distance == 0.25f && face == MIN_X_FACE) {
|
||||
qDebug() << "Test 3: PASSED";
|
||||
} else {
|
||||
qDebug() << "intersects=" << intersects << "expected=" << true;
|
||||
qDebug() << "distance=" << distance << "expected=" << 0.5f;
|
||||
qDebug() << "face=" << face << "expected=" << MIN_X_FACE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "******************************************************************************************";
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face);
|
||||
|
||||
QCOMPARE(intersects, true);
|
||||
QCOMPARE(distance, 0.5f);
|
||||
QCOMPARE(face, MIN_X_FACE);
|
||||
}
|
||||
|
||||
void AABoxCubeTests::runAllTests(bool verbose) {
|
||||
AABoxCubeTests(verbose);
|
||||
void AABoxCubeTests::raycastOutHitsXMaxFace () {
|
||||
// Raycast inside out
|
||||
glm::vec3 corner(0.0f, 0.0f, 0.0f);
|
||||
float size = 1.0f;
|
||||
|
||||
AABox box(corner, size);
|
||||
glm::vec3 origin(0.5f, 0.5f, 0.5f);
|
||||
glm::vec3 direction(1.0f, 0.0f, 0.0f);
|
||||
float distance;
|
||||
BoxFace face;
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face);
|
||||
|
||||
QCOMPARE(intersects, true);
|
||||
QCOMPARE(distance, 0.5f);
|
||||
QCOMPARE(face, MAX_X_FACE);
|
||||
}
|
||||
void AABoxCubeTests::raycastInHitsXMinFace () {
|
||||
// Raycast outside in
|
||||
glm::vec3 corner(0.5f, 0.0f, 0.0f);
|
||||
float size = 0.5f;
|
||||
|
||||
AABox box(corner, size);
|
||||
glm::vec3 origin(0.25f, 0.25f, 0.25f);
|
||||
glm::vec3 direction(1.0f, 0.0f, 0.0f);
|
||||
float distance;
|
||||
BoxFace face;
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face);
|
||||
|
||||
QCOMPARE(intersects, true);
|
||||
QCOMPARE(distance, 0.25f);
|
||||
QCOMPARE(face, MIN_X_FACE);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,18 @@
|
|||
#ifndef hifi_AABoxCubeTests_h
|
||||
#define hifi_AABoxCubeTests_h
|
||||
|
||||
namespace AABoxCubeTests {
|
||||
void AABoxCubeTests(bool verbose);
|
||||
void runAllTests(bool verbose);
|
||||
}
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
class AABoxCubeTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void raycastOutHitsXMinFace ();
|
||||
void raycastOutHitsXMaxFace ();
|
||||
void raycastInHitsXMinFace ();
|
||||
|
||||
// TODO: Add more unit tests!
|
||||
// (do we need this? Currently no tests for no-intersection or non-orthogonal rays)
|
||||
};
|
||||
|
||||
#endif // hifi_AABoxCubeTests_h
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
//#include "EntityTests.h"
|
||||
#include "ModelTests.h" // needs to be EntityTests.h soon
|
||||
|
||||
QTEST_MAIN(EntityTests)
|
||||
|
||||
/*
|
||||
void EntityTests::entityTreeTests(bool verbose) {
|
||||
|
||||
bool extraVerbose = false;
|
||||
|
@ -508,4 +511,4 @@ void EntityTests::entityTreeTests(bool verbose) {
|
|||
void EntityTests::runAllTests(bool verbose) {
|
||||
entityTreeTests(verbose);
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
|
@ -12,9 +12,21 @@
|
|||
#ifndef hifi_EntityTests_h
|
||||
#define hifi_EntityTests_h
|
||||
|
||||
namespace EntityTests {
|
||||
void entityTreeTests(bool verbose = false);
|
||||
void runAllTests(bool verbose = false);
|
||||
}
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
//
|
||||
// TODO: These are waaay out of date with the current codebase, and should be reimplemented at some point.
|
||||
//
|
||||
|
||||
class EntityTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testsNotImplemented () {
|
||||
qDebug() << "fixme: ModelTests are currently broken and need to be reimplemented";
|
||||
}
|
||||
// void entityTreeTests(bool verbose = false);
|
||||
// void runAllTests(bool verbose = false);
|
||||
};
|
||||
|
||||
#endif // hifi_EntityTests_h
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -12,13 +12,27 @@
|
|||
#ifndef hifi_OctreeTests_h
|
||||
#define hifi_OctreeTests_h
|
||||
|
||||
namespace OctreeTests {
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
void propertyFlagsTests(bool verbose);
|
||||
void byteCountCodingTests(bool verbose);
|
||||
void modelItemTests(bool verbose);
|
||||
class OctreeTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
// FIXME: These two tests are broken and need to be fixed / updated
|
||||
void propertyFlagsTests();
|
||||
void byteCountCodingTests();
|
||||
|
||||
// This test is fine
|
||||
void modelItemTests();
|
||||
|
||||
void runAllTests(bool verbose);
|
||||
// TODO: Break these into separate test functions
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
inline QByteArray makeQByteArray (std::initializer_list<char> bytes) {
|
||||
return QByteArray {
|
||||
bytes.begin(), static_cast<int>(bytes.size() * sizeof(char))
|
||||
};
|
||||
}
|
||||
|
||||
#endif // hifi_OctreeTests_h
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tests/octree/src
|
||||
//
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
#include "AABoxCubeTests.h"
|
||||
#include "ModelTests.h" // needs to be EntityTests.h soon
|
||||
#include "OctreeTests.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
const char* VERBOSE = "--verbose";
|
||||
bool verbose = cmdOptionExists(argc, argv, VERBOSE);
|
||||
qDebug() << "OctreeTests::runAllTests()";
|
||||
//OctreeTests::runAllTests(verbose);
|
||||
//AABoxCubeTests::runAllTests(verbose);
|
||||
EntityTests::runAllTests(verbose);
|
||||
return 0;
|
||||
}
|
|
@ -1,17 +1,18 @@
|
|||
set(TARGET_NAME physics-tests)
|
||||
|
||||
setup_hifi_project()
|
||||
# Declare dependencies
|
||||
macro (SETUP_TESTCASE_DEPENDENCIES)
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(bullet)
|
||||
|
||||
find_package(Bullet REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
link_hifi_libraries(shared physics)
|
||||
copy_dlls_beside_windows_executable()
|
||||
endmacro ()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(bullet)
|
||||
|
||||
find_package(Bullet REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
link_hifi_libraries(shared physics)
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
||||
setup_hifi_testcase(Script)
|
96
tests/physics/src/BulletTestUtils.h
Normal file
96
tests/physics/src/BulletTestUtils.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
//
|
||||
// BulletTestUtils.h
|
||||
// tests/physics/src
|
||||
//
|
||||
// Created by Seiji Emery on 6/22/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_BulletTestUtils_h
|
||||
#define hifi_BulletTestUtils_h
|
||||
|
||||
#include <BulletUtil.h>
|
||||
|
||||
// Implements functionality in QTestExtensions.h for glm types
|
||||
// There are 3 functions in here (which need to be defined for all types that use them):
|
||||
//
|
||||
// - getErrorDifference (const T &, const T &) -> V (used by QCOMPARE_WITH_ABS_ERROR)
|
||||
// - operator << (QTextStream &, const T &) -> QTextStream & (used by all (additional) test macros)
|
||||
// - errorTest (const T &, const T &, V) -> std::function<bool()>
|
||||
// (used by QCOMPARE_WITH_RELATIVE_ERROR via QCOMPARE_WITH_LAMBDA)
|
||||
// (this is only used by btMatrix3x3 in MeshMassPropertiesTests.cpp, so it's only defined for the Mat3 type)
|
||||
|
||||
// Return the error between values a and b; used to implement QCOMPARE_WITH_ABS_ERROR
|
||||
inline btScalar getErrorDifference(const btScalar& a, const btScalar& b) {
|
||||
return fabs(a - b);
|
||||
}
|
||||
// Return the error between values a and b; used to implement QCOMPARE_WITH_ABS_ERROR
|
||||
inline btScalar getErrorDifference(const btVector3& a, const btVector3& b) {
|
||||
return (a - b).length();
|
||||
}
|
||||
// Matrices are compared element-wise -- if the error value for any element > epsilon, then fail
|
||||
inline btScalar getErrorDifference(const btMatrix3x3& a, const btMatrix3x3& b) {
|
||||
btScalar maxDiff = 0;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
btScalar diff = fabs(a[i][j] - b[i][j]);
|
||||
maxDiff = qMax(diff, maxDiff);
|
||||
}
|
||||
}
|
||||
return maxDiff;
|
||||
}
|
||||
|
||||
//
|
||||
// Printing (operator <<)
|
||||
//
|
||||
|
||||
// btMatrix3x3 stream printing (not advised to use this outside of the test macros, due to formatting)
|
||||
inline QTextStream& operator<< (QTextStream& stream, const btMatrix3x3& matrix) {
|
||||
stream << "[\n\t\t";
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
stream << " " << matrix[i][j];
|
||||
}
|
||||
stream << "\n\t\t";
|
||||
}
|
||||
stream << "]\n\t"; // hacky as hell, but this should work...
|
||||
return stream;
|
||||
}
|
||||
inline QTextStream& operator << (QTextStream& stream, const btVector3& v) {
|
||||
return stream << "btVector3 { " << v.x() << ", " << v.y() << ", " << v.z() << " }";
|
||||
}
|
||||
// btScalar operator<< is already implemented (as it's just a typedef-ed float/double)
|
||||
|
||||
//
|
||||
// errorTest (actual, expected, acceptableRelativeError) -> callback closure
|
||||
//
|
||||
|
||||
// Produces a relative error test for btMatrix3x3 usable with QCOMPARE_WITH_LAMBDA.
|
||||
// (used in a *few* physics tests that define QCOMPARE_WITH_RELATIVE_ERROR)
|
||||
inline auto errorTest (const btMatrix3x3& actual, const btMatrix3x3& expected, const btScalar acceptableRelativeError)
|
||||
-> std::function<bool ()>
|
||||
{
|
||||
return [&actual, &expected, acceptableRelativeError] () {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
if (expected[i][j] != btScalar(0.0f)) {
|
||||
auto err = (actual[i][j] - expected[i][j]) / expected[i][j];
|
||||
if (fabsf(err) > acceptableRelativeError)
|
||||
return false;
|
||||
} else {
|
||||
// The zero-case (where expected[i][j] == 0) is covered by the QCOMPARE_WITH_ABS_ERROR impl
|
||||
// (ie. getErrorDifference (const btMatrix3x3& a, const btMatrix3x3& b).
|
||||
// Since the zero-case uses a different error value (abs error) vs the non-zero case (relative err),
|
||||
// it made sense to separate these two cases. To do a full check, call QCOMPARE_WITH_RELATIVE_ERROR
|
||||
// followed by QCOMPARE_WITH_ABS_ERROR (or vice versa).
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -11,26 +11,28 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
//#include "PhysicsTestUtil.h"
|
||||
#include <BulletUtil.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include "BulletUtilTests.h"
|
||||
|
||||
// Constants
|
||||
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);
|
||||
|
||||
|
||||
QTEST_MAIN(BulletUtilTests)
|
||||
|
||||
void BulletUtilTests::fromBulletToGLM() {
|
||||
btVector3 bV(1.23f, 4.56f, 7.89f);
|
||||
glm::vec3 gV = bulletToGLM(bV);
|
||||
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.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);
|
||||
|
@ -38,39 +40,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());
|
||||
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);
|
||||
|
@ -78,25 +60,8 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
void BulletUtilTests::runAllTests() {
|
||||
fromBulletToGLM();
|
||||
fromGLMToBullet();
|
||||
QCOMPARE(gQ.x, bQ.getX());
|
||||
QCOMPARE(gQ.y, bQ.getY());
|
||||
QCOMPARE(gQ.z, bQ.getZ());
|
||||
QCOMPARE(gQ.w, bQ.getW());
|
||||
}
|
||||
|
|
|
@ -12,10 +12,17 @@
|
|||
#ifndef hifi_BulletUtilTests_h
|
||||
#define hifi_BulletUtilTests_h
|
||||
|
||||
namespace BulletUtilTests {
|
||||
#include <QtTest/QtTest>
|
||||
// Add additional qtest functionality (the include order is important!)
|
||||
#include "GlmTestUtils.h"
|
||||
#include "../QTestExtensions.h"
|
||||
|
||||
class BulletUtilTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void fromBulletToGLM();
|
||||
void fromGLMToBullet();
|
||||
void runAllTests();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // hifi_BulletUtilTests_h
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
#include "CollisionInfoTests.h"
|
||||
|
||||
|
||||
/*
|
||||
|
||||
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);
|
||||
|
@ -30,83 +31,40 @@ 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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}*/
|
||||
|
||||
void CollisionInfoTests::runAllTests() {
|
||||
// CollisionInfoTests::rotateThenTranslate();
|
||||
// CollisionInfoTests::translateThenRotate();
|
||||
}
|
||||
|
|
|
@ -12,12 +12,18 @@
|
|||
#ifndef hifi_CollisionInfoTests_h
|
||||
#define hifi_CollisionInfoTests_h
|
||||
|
||||
namespace CollisionInfoTests {
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
// Add additional qtest functionality (the include order is important!)
|
||||
#include "GlmTestUtils.h"
|
||||
#include "../QTestExtensions.h"
|
||||
|
||||
class CollisionInfoTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
// void rotateThenTranslate();
|
||||
// void translateThenRotate();
|
||||
|
||||
void runAllTests();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // hifi_CollisionInfoTests_h
|
||||
|
|
27
tests/physics/src/GlmTestUtils.h
Normal file
27
tests/physics/src/GlmTestUtils.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// GlmTestUtils.h
|
||||
// tests/physics/src
|
||||
//
|
||||
// Created by Seiji Emery on 6/22/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_GlmTestUtils_h
|
||||
#define hifi_GlmTestUtils_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
// Implements functionality in QTestExtensions.h for glm types
|
||||
|
||||
inline float getErrorDifference(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 << " }";
|
||||
}
|
||||
|
||||
#endif
|
|
@ -15,21 +15,10 @@
|
|||
|
||||
#include "MeshMassPropertiesTests.h"
|
||||
|
||||
//#define VERBOSE_UNIT_TESTS
|
||||
|
||||
const btScalar acceptableRelativeError(1.0e-5f);
|
||||
const btScalar acceptableAbsoluteError(1.0e-4f);
|
||||
|
||||
void printMatrix(const std::string& name, const btMatrix3x3& matrix) {
|
||||
std::cout << name << " = [" << std::endl;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
std::cout << " " << matrix[i][j];
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
QTEST_MAIN(MeshMassPropertiesTests)
|
||||
|
||||
void pushTriangle(VectorOfIndices& indices, uint32_t a, uint32_t b, uint32_t c) {
|
||||
indices.push_back(a);
|
||||
|
@ -38,14 +27,10 @@ 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:
|
||||
// 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
|
||||
|
||||
|
||||
btScalar bigBoxX = 7.0f;
|
||||
btScalar bigBoxY = 9.0f;
|
||||
btScalar bigBoxZ = 11.0f;
|
||||
|
@ -70,32 +55,13 @@ void MeshMassPropertiesTests::testParallelAxisTheorem() {
|
|||
|
||||
btMatrix3x3 twoSmallBoxesInertia = smallBoxShiftedRight + smallBoxShiftedLeft;
|
||||
|
||||
// verify bigBox same as twoSmallBoxes
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
printMatrix("expected inertia", bitBoxInertia);
|
||||
printMatrix("computed inertia", twoSmallBoxesInertia);
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
#endif // EXPOSE_HELPER_FUNCTIONS_FOR_UNIT_TEST
|
||||
QCOMPARE_WITH_ABS_ERROR(bitBoxInertia, twoSmallBoxesInertia, acceptableAbsoluteError);
|
||||
}
|
||||
|
||||
void MeshMassPropertiesTests::testTetrahedron(){
|
||||
// given the four vertices of a tetrahedron verify the analytic formula for inertia
|
||||
// agrees with expected results
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
std::cout << "\n" << __FUNCTION__ << std::endl;
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
|
||||
|
||||
// these numbers from the Tonon paper:
|
||||
btVector3 points[4];
|
||||
points[0] = btVector3(8.33220f, -11.86875f, 0.93355f);
|
||||
|
@ -133,37 +99,15 @@ void MeshMassPropertiesTests::testTetrahedron(){
|
|||
}
|
||||
btMatrix3x3 inertia;
|
||||
computeTetrahedronInertia(volume, points, inertia);
|
||||
|
||||
// verify
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
error = (inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j];
|
||||
if (fabsf(error) > acceptableRelativeError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by "
|
||||
<< error << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
std::cout << "expected volume = " << expectedVolume << std::endl;
|
||||
std::cout << "measured volume = " << volume << std::endl;
|
||||
printMatrix("expected inertia", expectedInertia);
|
||||
printMatrix("computed inertia", inertia);
|
||||
|
||||
// when building VERBOSE you might be instrested in the results from the brute force method:
|
||||
btMatrix3x3 bruteInertia;
|
||||
computeTetrahedronInertiaByBruteForce(points, bruteInertia);
|
||||
printMatrix("brute inertia", bruteInertia);
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
|
||||
QCOMPARE_WITH_ABS_ERROR(volume, expectedVolume, acceptableRelativeError * volume);
|
||||
|
||||
QCOMPARE_WITH_RELATIVE_ERROR(inertia, expectedInertia, acceptableRelativeError);
|
||||
}
|
||||
|
||||
void MeshMassPropertiesTests::testOpenTetrahedonMesh() {
|
||||
// given the simplest possible mesh (open, with one triangle)
|
||||
// verify MeshMassProperties computes the right nubers
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
std::cout << "\n" << __FUNCTION__ << std::endl;
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
|
||||
// these numbers from the Tonon paper:
|
||||
VectorOfPoints points;
|
||||
|
@ -199,43 +143,16 @@ void MeshMassPropertiesTests::testOpenTetrahedonMesh() {
|
|||
MeshMassProperties mesh(shiftedPoints, triangles);
|
||||
|
||||
// verify
|
||||
btScalar error = (mesh._volume - expectedVolume) / expectedVolume;
|
||||
if (fabsf(error) > acceptableRelativeError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = "
|
||||
<< error << std::endl;
|
||||
}
|
||||
|
||||
error = (mesh._centerOfMass - expectedCenterOfMass).length();
|
||||
if (fabsf(error) > acceptableAbsoluteError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = "
|
||||
<< error << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j];
|
||||
if (fabsf(error) > acceptableRelativeError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by "
|
||||
<< error << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
std::cout << "expected volume = " << expectedVolume << std::endl;
|
||||
std::cout << "measured volume = " << mesh._volume << std::endl;
|
||||
printMatrix("expected inertia", expectedInertia);
|
||||
printMatrix("computed inertia", mesh._inertia);
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
// (expected - actual) / expected > e ==> expected - actual > e * expected
|
||||
QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume);
|
||||
QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError);
|
||||
QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError);
|
||||
}
|
||||
|
||||
void MeshMassPropertiesTests::testClosedTetrahedronMesh() {
|
||||
// given a tetrahedron as a closed mesh of four tiangles
|
||||
// verify MeshMassProperties computes the right nubers
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
std::cout << "\n" << __FUNCTION__ << std::endl;
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
|
||||
|
||||
// these numbers from the Tonon paper:
|
||||
VectorOfPoints points;
|
||||
points.push_back(btVector3(8.33220f, -11.86875f, 0.93355f));
|
||||
|
@ -266,38 +183,11 @@ void MeshMassPropertiesTests::testClosedTetrahedronMesh() {
|
|||
|
||||
// compute mass properties
|
||||
MeshMassProperties mesh(points, triangles);
|
||||
|
||||
|
||||
// verify
|
||||
btScalar error;
|
||||
error = (mesh._volume - expectedVolume) / expectedVolume;
|
||||
if (fabsf(error) > acceptableRelativeError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = "
|
||||
<< error << std::endl;
|
||||
}
|
||||
|
||||
error = (mesh._centerOfMass - expectedCenterOfMass).length();
|
||||
if (fabsf(error) > acceptableAbsoluteError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = "
|
||||
<< error << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j];
|
||||
if (fabsf(error) > acceptableRelativeError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by "
|
||||
<< error << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
std::cout << "(a) tetrahedron as mesh" << std::endl;
|
||||
std::cout << "expected volume = " << expectedVolume << std::endl;
|
||||
std::cout << "measured volume = " << mesh._volume << std::endl;
|
||||
printMatrix("expected inertia", expectedInertia);
|
||||
printMatrix("computed inertia", mesh._inertia);
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume);
|
||||
QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError);
|
||||
QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError);
|
||||
|
||||
// test again, but this time shift the points so that the origin is definitely OUTSIDE the mesh
|
||||
btVector3 shift = points[0] + expectedCenterOfMass;
|
||||
|
@ -310,44 +200,14 @@ void MeshMassPropertiesTests::testClosedTetrahedronMesh() {
|
|||
mesh.computeMassProperties(points, triangles);
|
||||
|
||||
// verify
|
||||
error = (mesh._volume - expectedVolume) / expectedVolume;
|
||||
if (fabsf(error) > acceptableRelativeError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = "
|
||||
<< error << std::endl;
|
||||
}
|
||||
|
||||
error = (mesh._centerOfMass - expectedCenterOfMass).length();
|
||||
if (fabsf(error) > acceptableAbsoluteError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = "
|
||||
<< error << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j];
|
||||
if (fabsf(error) > acceptableRelativeError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by "
|
||||
<< error << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
std::cout << "(b) shifted tetrahedron as mesh" << std::endl;
|
||||
std::cout << "expected volume = " << expectedVolume << std::endl;
|
||||
std::cout << "measured volume = " << mesh._volume << std::endl;
|
||||
printMatrix("expected inertia", expectedInertia);
|
||||
printMatrix("computed inertia", mesh._inertia);
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
// QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume);
|
||||
// QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError);
|
||||
// QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError);
|
||||
}
|
||||
|
||||
void MeshMassPropertiesTests::testBoxAsMesh() {
|
||||
// verify that a mesh box produces the same mass properties as the analytic box.
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
std::cout << "\n" << __FUNCTION__ << std::endl;
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
|
||||
|
||||
|
||||
// build a box:
|
||||
// /
|
||||
// y
|
||||
|
@ -402,58 +262,30 @@ void MeshMassPropertiesTests::testBoxAsMesh() {
|
|||
MeshMassProperties mesh(points, triangles);
|
||||
|
||||
// verify
|
||||
btScalar error;
|
||||
error = (mesh._volume - expectedVolume) / expectedVolume;
|
||||
if (fabsf(error) > acceptableRelativeError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : volume of tetrahedron off by = "
|
||||
<< error << std::endl;
|
||||
}
|
||||
|
||||
QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume);
|
||||
QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError);
|
||||
|
||||
error = (mesh._centerOfMass - expectedCenterOfMass).length();
|
||||
if (fabsf(error) > acceptableAbsoluteError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : centerOfMass of tetrahedron off by = "
|
||||
<< error << std::endl;
|
||||
}
|
||||
// test this twice: _RELATIVE_ERROR doesn't test zero cases (to avoid divide-by-zero); _ABS_ERROR does.
|
||||
QCOMPARE_WITH_ABS_ERROR(mesh._inertia, expectedInertia, acceptableAbsoluteError);
|
||||
QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
if (expectedInertia [i][j] == btScalar(0.0f)) {
|
||||
error = mesh._inertia[i][j] - expectedInertia[i][j];
|
||||
if (fabsf(error) > acceptableAbsoluteError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by "
|
||||
<< error << " absolute"<< std::endl;
|
||||
}
|
||||
} else {
|
||||
error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j];
|
||||
if (fabsf(error) > acceptableRelativeError) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by "
|
||||
<< error << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_UNIT_TESTS
|
||||
std::cout << "expected volume = " << expectedVolume << std::endl;
|
||||
std::cout << "measured volume = " << mesh._volume << std::endl;
|
||||
std::cout << "expected center of mass = < "
|
||||
<< expectedCenterOfMass[0] << ", "
|
||||
<< expectedCenterOfMass[1] << ", "
|
||||
<< expectedCenterOfMass[2] << "> " << std::endl;
|
||||
std::cout << "computed center of mass = < "
|
||||
<< mesh._centerOfMass[0] << ", "
|
||||
<< mesh._centerOfMass[1] << ", "
|
||||
<< mesh._centerOfMass[2] << "> " << std::endl;
|
||||
printMatrix("expected inertia", expectedInertia);
|
||||
printMatrix("computed inertia", mesh._inertia);
|
||||
#endif // VERBOSE_UNIT_TESTS
|
||||
}
|
||||
|
||||
void MeshMassPropertiesTests::runAllTests() {
|
||||
testParallelAxisTheorem();
|
||||
testTetrahedron();
|
||||
testOpenTetrahedonMesh();
|
||||
testClosedTetrahedronMesh();
|
||||
testBoxAsMesh();
|
||||
//testWithCube();
|
||||
// These two macros impl this:
|
||||
// for (int i = 0; i < 3; ++i) {
|
||||
// for (int j = 0; j < 3; ++j) {
|
||||
// if (expectedInertia [i][j] == btScalar(0.0f)) {
|
||||
// error = mesh._inertia[i][j] - expectedInertia[i][j]; // COMPARE_WITH_ABS_ERROR
|
||||
// if (fabsf(error) > acceptableAbsoluteError) {
|
||||
// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by "
|
||||
// << error << " absolute"<< std::endl;
|
||||
// }
|
||||
// } else {
|
||||
// error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; // COMPARE_WITH_RELATIVE_ERROR
|
||||
// if (fabsf(error) > acceptableRelativeError) {
|
||||
// std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by "
|
||||
// << error << std::endl;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -11,12 +11,30 @@
|
|||
|
||||
#ifndef hifi_MeshMassPropertiesTests_h
|
||||
#define hifi_MeshMassPropertiesTests_h
|
||||
namespace MeshMassPropertiesTests{
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QtGlobal>
|
||||
|
||||
// Add additional qtest functionality (the include order is important!)
|
||||
#include "BulletTestUtils.h"
|
||||
#include "GlmTestUtils.h"
|
||||
#include "../QTestExtensions.h"
|
||||
|
||||
// Relative error macro (see errorTest in BulletTestUtils.h)
|
||||
#define QCOMPARE_WITH_RELATIVE_ERROR(actual, expected, relativeError) \
|
||||
QCOMPARE_WITH_LAMBDA(actual, expected, errorTest(actual, expected, relativeError))
|
||||
|
||||
|
||||
// Testcase class
|
||||
class MeshMassPropertiesTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testParallelAxisTheorem();
|
||||
void testTetrahedron();
|
||||
void testOpenTetrahedonMesh();
|
||||
void testClosedTetrahedronMesh();
|
||||
void testBoxAsMesh();
|
||||
void runAllTests();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // hifi_MeshMassPropertiesTests_h
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
//
|
||||
// PhysicsTestUtil.cpp
|
||||
// tests/physics/src
|
||||
//
|
||||
// Created by Andrew Meadows on 02/21/2014.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "PhysicsTestUtil.h"
|
||||
#include "StreamUtils.h"
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const CollisionInfo& c) {
|
||||
s << "[penetration=" << c._penetration
|
||||
<< ", contactPoint=" << c._contactPoint
|
||||
<< ", addedVelocity=" << c._addedVelocity;
|
||||
return s;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// PhysicsTestUtil.h
|
||||
// tests/physics/src
|
||||
//
|
||||
// Created by Andrew Meadows on 02/21/2014.
|
||||
// Copyright 2014 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_PhysicsTestUtil_h
|
||||
#define hifi_PhysicsTestUtil_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <CollisionInfo.h>
|
||||
|
||||
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);
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const CollisionInfo& c);
|
||||
|
||||
#endif // hifi_PhysicsTestUtil_h
|
File diff suppressed because it is too large
Load diff
|
@ -12,8 +12,21 @@
|
|||
#ifndef hifi_ShapeColliderTests_h
|
||||
#define hifi_ShapeColliderTests_h
|
||||
|
||||
namespace ShapeColliderTests {
|
||||
#include <QtTest/QtTest>
|
||||
#include <QtGlobal>
|
||||
|
||||
// Add additional qtest functionality (the include order is important!)
|
||||
#include "BulletTestUtils.h"
|
||||
#include "GlmTestUtils.h"
|
||||
#include "../QTestExtensions.h"
|
||||
|
||||
|
||||
class ShapeColliderTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
|
||||
void sphereMissesSphere();
|
||||
void sphereTouchesSphere();
|
||||
|
||||
|
@ -42,8 +55,6 @@ namespace ShapeColliderTests {
|
|||
void rayMissesAACube();
|
||||
|
||||
void measureTimeOfCollisionDispatch();
|
||||
|
||||
void runAllTests();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeColliderTests_h
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
|
||||
#include "ShapeInfoTests.h"
|
||||
|
||||
QTEST_MAIN(ShapeInfoTests)
|
||||
|
||||
void ShapeInfoTests::testHashFunctions() {
|
||||
#if MANUAL_TEST
|
||||
int maxTests = 10000000;
|
||||
ShapeInfo info;
|
||||
btHashMap<btHashInt, uint32_t> hashes;
|
||||
|
@ -39,6 +42,7 @@ void ShapeInfoTests::testHashFunctions() {
|
|||
|
||||
int testCount = 0;
|
||||
int numCollisions = 0;
|
||||
|
||||
btClock timer;
|
||||
for (int x = 1; x < numSteps && testCount < maxTests; ++x) {
|
||||
float radiusX = (float)x * deltaLength;
|
||||
|
@ -134,6 +138,8 @@ void ShapeInfoTests::testHashFunctions() {
|
|||
for (int i = 0; i < 32; ++i) {
|
||||
std::cout << "bit 0x" << std::hex << masks[i] << std::dec << " = " << bits[i] << std::endl;
|
||||
}
|
||||
QCOMPARE(numCollisions, 0);
|
||||
#endif // MANUAL_TEST
|
||||
}
|
||||
|
||||
void ShapeInfoTests::testBoxShape() {
|
||||
|
@ -143,21 +149,12 @@ void ShapeInfoTests::testBoxShape() {
|
|||
DoubleHashKey key = info.getHash();
|
||||
|
||||
btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
|
||||
if (!shape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: NULL Box shape" << std::endl;
|
||||
}
|
||||
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Box shape hash = " << key.getHash() << " but found hash = " << otherKey.getHash() << std::endl;
|
||||
}
|
||||
|
||||
if (key.getHash2() != otherKey.getHash2()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Box shape hash2 = " << key.getHash2() << " but found hash2 = " << otherKey.getHash2() << std::endl;
|
||||
}
|
||||
QCOMPARE(key.getHash(), otherKey.getHash());
|
||||
QCOMPARE(key.getHash2(), otherKey.getHash2());
|
||||
|
||||
delete shape;
|
||||
}
|
||||
|
@ -169,17 +166,12 @@ void ShapeInfoTests::testSphereShape() {
|
|||
DoubleHashKey key = info.getHash();
|
||||
|
||||
btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Sphere shape hash = " << key.getHash() << " but found hash = " << otherKey.getHash() << std::endl;
|
||||
}
|
||||
if (key.getHash2() != otherKey.getHash2()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Sphere shape hash2 = " << key.getHash2() << " but found hash2 = " << otherKey.getHash2() << std::endl;
|
||||
}
|
||||
QCOMPARE(key.getHash(), otherKey.getHash());
|
||||
QCOMPARE(key.getHash2(), otherKey.getHash2());
|
||||
|
||||
delete shape;
|
||||
}
|
||||
|
@ -193,17 +185,12 @@ void ShapeInfoTests::testCylinderShape() {
|
|||
DoubleHashKey key = info.getHash();
|
||||
|
||||
btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Cylinder shape hash = " << key.getHash() << " but found hash = " << otherKey.getHash() << std::endl;
|
||||
}
|
||||
if (key.getHash2() != otherKey.getHash2()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Cylinder shape hash2 = " << key.getHash2() << " but found hash2 = " << otherKey.getHash2() << std::endl;
|
||||
}
|
||||
QCOMPARE(key.getHash(), otherKey.getHash());
|
||||
QCOMPARE(key.getHash2(), otherKey.getHash2());
|
||||
|
||||
delete shape;
|
||||
*/
|
||||
|
@ -218,29 +205,14 @@ void ShapeInfoTests::testCapsuleShape() {
|
|||
DoubleHashKey key = info.getHash();
|
||||
|
||||
btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Capsule shape hash = " << key.getHash() << " but found hash = " << otherKey.getHash() << std::endl;
|
||||
}
|
||||
if (key.getHash2() != otherKey.getHash2()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Capsule shape hash2 = " << key.getHash2() << " but found hash2 = " << otherKey.getHash2() << std::endl;
|
||||
}
|
||||
QCOMPARE(key.getHash(), otherKey.getHash());
|
||||
QCOMPARE(key.getHash2(), otherKey.getHash2());
|
||||
|
||||
delete shape;
|
||||
*/
|
||||
}
|
||||
|
||||
void ShapeInfoTests::runAllTests() {
|
||||
//#define MANUAL_TEST
|
||||
#ifdef MANUAL_TEST
|
||||
testHashFunctions();
|
||||
#endif // MANUAL_TEST
|
||||
testBoxShape();
|
||||
testSphereShape();
|
||||
testCylinderShape();
|
||||
testCapsuleShape();
|
||||
}
|
||||
|
|
|
@ -12,13 +12,24 @@
|
|||
#ifndef hifi_ShapeInfoTests_h
|
||||
#define hifi_ShapeInfoTests_h
|
||||
|
||||
namespace ShapeInfoTests {
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
//// Add additional qtest functionality (the include order is important!)
|
||||
//#include "BulletTestUtils.h"
|
||||
//#include "../QTestExtensions.h"
|
||||
|
||||
// Enable this to manually run testHashCollisions
|
||||
// (NOT a regular unit test; takes ~17 secs to run on an i7)
|
||||
#define MANUAL_TEST false
|
||||
|
||||
class ShapeInfoTests : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testHashFunctions();
|
||||
void testBoxShape();
|
||||
void testSphereShape();
|
||||
void testCylinderShape();
|
||||
void testCapsuleShape();
|
||||
void runAllTests();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeInfoTests_h
|
||||
|
|
|
@ -15,43 +15,31 @@
|
|||
|
||||
#include "ShapeManagerTests.h"
|
||||
|
||||
QTEST_MAIN(ShapeManagerTests)
|
||||
|
||||
void ShapeManagerTests::testShapeAccounting() {
|
||||
ShapeManager shapeManager;
|
||||
ShapeInfo info;
|
||||
info.setBox(glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
|
||||
int numReferences = shapeManager.getNumReferences(info);
|
||||
if (numReferences != 0) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected ignorant ShapeManager after initialization" << std::endl;
|
||||
}
|
||||
QCOMPARE(numReferences, 0);
|
||||
|
||||
// create one shape and verify we get a valid pointer
|
||||
btCollisionShape* shape = shapeManager.getShape(info);
|
||||
if (!shape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected shape creation for default parameters" << std::endl;
|
||||
}
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
// verify number of shapes
|
||||
if (shapeManager.getNumShapes() != 1) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected one shape" << std::endl;
|
||||
}
|
||||
QCOMPARE(shapeManager.getNumShapes(), 1);
|
||||
|
||||
// reference the shape again and verify that we get the same pointer
|
||||
btCollisionShape* otherShape = shapeManager.getShape(info);
|
||||
if (otherShape != shape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected shape* " << (void*)(shape)
|
||||
<< " but found shape* " << (void*)(otherShape) << std::endl;
|
||||
}
|
||||
QCOMPARE(otherShape, shape);
|
||||
|
||||
// verify number of references
|
||||
numReferences = shapeManager.getNumReferences(info);
|
||||
int expectedNumReferences = 2;
|
||||
if (numReferences != expectedNumReferences) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected " << expectedNumReferences
|
||||
<< " references but found " << numReferences << std::endl;
|
||||
}
|
||||
QCOMPARE(numReferences, expectedNumReferences);
|
||||
|
||||
// release all references
|
||||
bool released = shapeManager.releaseShape(info);
|
||||
|
@ -60,59 +48,36 @@ void ShapeManagerTests::testShapeAccounting() {
|
|||
released = shapeManager.releaseShape(info) && released;
|
||||
numReferences--;
|
||||
}
|
||||
if (!released) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected shape released" << std::endl;
|
||||
}
|
||||
QCOMPARE(released, true);
|
||||
|
||||
// verify shape still exists (not yet garbage collected)
|
||||
if (shapeManager.getNumShapes() != 1) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected one shape after release but before garbage collection" << std::endl;
|
||||
}
|
||||
QCOMPARE(shapeManager.getNumShapes(), 1);
|
||||
|
||||
// verify shape's refcount is zero
|
||||
numReferences = shapeManager.getNumReferences(info);
|
||||
if (numReferences != 0) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected refcount = 0 for shape but found refcount = " << numReferences << std::endl;
|
||||
}
|
||||
QCOMPARE(numReferences, 0);
|
||||
|
||||
// reference the shape again and verify refcount is updated
|
||||
otherShape = shapeManager.getShape(info);
|
||||
numReferences = shapeManager.getNumReferences(info);
|
||||
if (numReferences != 1) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected refcount = 1 for shape but found refcount = " << numReferences << std::endl;
|
||||
}
|
||||
QCOMPARE(numReferences, 1);
|
||||
|
||||
// verify that shape is not collected as garbage
|
||||
shapeManager.collectGarbage();
|
||||
if (shapeManager.getNumShapes() != 1) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected one shape after release" << std::endl;
|
||||
}
|
||||
QCOMPARE(shapeManager.getNumShapes(), 1);
|
||||
numReferences = shapeManager.getNumReferences(info);
|
||||
if (numReferences != 1) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected refcount = 1 for shape but found refcount = " << numReferences << std::endl;
|
||||
}
|
||||
QCOMPARE(numReferences, 1);
|
||||
|
||||
// release reference and verify that it is collected as garbage
|
||||
released = shapeManager.releaseShape(info);
|
||||
shapeManager.collectGarbage();
|
||||
if (shapeManager.getNumShapes() != 0) {
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected zero shapes after release" << std::endl;
|
||||
}
|
||||
if (shapeManager.hasShape(shape)) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected ignorant ShapeManager after garbage collection" << std::endl;
|
||||
}
|
||||
QCOMPARE(shapeManager.getNumShapes(), 0);
|
||||
QCOMPARE(shapeManager.hasShape(shape), false);
|
||||
|
||||
// add the shape again and verify that it gets added again
|
||||
otherShape = shapeManager.getShape(info);
|
||||
numReferences = shapeManager.getNumReferences(info);
|
||||
if (numReferences != 1) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected refcount = 1 for shape but found refcount = " << numReferences << std::endl;
|
||||
}
|
||||
QCOMPARE(numReferences, 1);
|
||||
}
|
||||
|
||||
void ShapeManagerTests::addManyShapes() {
|
||||
|
@ -132,49 +97,32 @@ void ShapeManagerTests::addManyShapes() {
|
|||
info.setBox(0.5f * scale);
|
||||
btCollisionShape* shape = shapeManager.getShape(info);
|
||||
shapes.push_back(shape);
|
||||
if (!shape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: i = " << i << " null box shape for scale = " << scale << std::endl;
|
||||
}
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
// make a box
|
||||
float radius = 0.5f * s;
|
||||
info.setSphere(radius);
|
||||
shape = shapeManager.getShape(info);
|
||||
shapes.push_back(shape);
|
||||
if (!shape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: i = " << i << " null sphere shape for radius = " << radius << std::endl;
|
||||
}
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
}
|
||||
|
||||
// verify shape count
|
||||
int numShapes = shapeManager.getNumShapes();
|
||||
if (numShapes != 2 * numSizes) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected numShapes = " << numSizes << " but found numShapes = " << numShapes << std::endl;
|
||||
}
|
||||
QCOMPARE(numShapes, 2 * numSizes);
|
||||
|
||||
// release each shape by pointer
|
||||
for (int i = 0; i < numShapes; ++i) {
|
||||
btCollisionShape* shape = shapes[i];
|
||||
bool success = shapeManager.releaseShape(shape);
|
||||
if (!success) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: failed to release shape index " << i << std::endl;
|
||||
break;
|
||||
}
|
||||
QCOMPARE(success, true);
|
||||
}
|
||||
|
||||
// verify zero references
|
||||
for (int i = 0; i < numShapes; ++i) {
|
||||
btCollisionShape* shape = shapes[i];
|
||||
int numReferences = shapeManager.getNumReferences(shape);
|
||||
if (numReferences != 0) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected zero references for shape " << i
|
||||
<< " but refCount = " << numReferences << std::endl;
|
||||
}
|
||||
QCOMPARE(numReferences, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,10 +136,7 @@ void ShapeManagerTests::addBoxShape() {
|
|||
|
||||
ShapeInfo otherInfo = info;
|
||||
btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
|
||||
if (shape != otherShape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: Box ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl;
|
||||
}
|
||||
QCOMPARE(shape, otherShape);
|
||||
}
|
||||
|
||||
void ShapeManagerTests::addSphereShape() {
|
||||
|
@ -204,10 +149,7 @@ void ShapeManagerTests::addSphereShape() {
|
|||
|
||||
ShapeInfo otherInfo = info;
|
||||
btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
|
||||
if (shape != otherShape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: Sphere ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl;
|
||||
}
|
||||
QCOMPARE(shape, otherShape);
|
||||
}
|
||||
|
||||
void ShapeManagerTests::addCylinderShape() {
|
||||
|
@ -222,10 +164,7 @@ void ShapeManagerTests::addCylinderShape() {
|
|||
|
||||
ShapeInfo otherInfo = info;
|
||||
btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
|
||||
if (shape != otherShape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: Cylinder ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl;
|
||||
}
|
||||
QCOMPARE(shape, otherShape);
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -241,18 +180,6 @@ void ShapeManagerTests::addCapsuleShape() {
|
|||
|
||||
ShapeInfo otherInfo = info;
|
||||
btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
|
||||
if (shape != otherShape) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: Capsule ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl;
|
||||
}
|
||||
QCOMPARE(shape, otherShape);
|
||||
*/
|
||||
}
|
||||
|
||||
void ShapeManagerTests::runAllTests() {
|
||||
testShapeAccounting();
|
||||
addManyShapes();
|
||||
addBoxShape();
|
||||
addSphereShape();
|
||||
addCylinderShape();
|
||||
addCapsuleShape();
|
||||
}
|
||||
|
|
|
@ -12,14 +12,18 @@
|
|||
#ifndef hifi_ShapeManagerTests_h
|
||||
#define hifi_ShapeManagerTests_h
|
||||
|
||||
namespace ShapeManagerTests {
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
class ShapeManagerTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testShapeAccounting();
|
||||
void addManyShapes();
|
||||
void addBoxShape();
|
||||
void addSphereShape();
|
||||
void addCylinderShape();
|
||||
void addCapsuleShape();
|
||||
void runAllTests();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeManagerTests_h
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tests/physics/src
|
||||
//
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
#include "ShapeColliderTests.h"
|
||||
#include "ShapeInfoTests.h"
|
||||
#include "ShapeManagerTests.h"
|
||||
#include "BulletUtilTests.h"
|
||||
#include "MeshMassPropertiesTests.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ShapeColliderTests::runAllTests();
|
||||
ShapeInfoTests::runAllTests();
|
||||
ShapeManagerTests::runAllTests();
|
||||
BulletUtilTests::runAllTests();
|
||||
MeshMassPropertiesTests::runAllTests();
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
set(TARGET_NAME render-utils-tests)
|
||||
|
||||
set(TARGET_NAME render-utils-test)
|
||||
|
||||
# This is not a testcase -- just set it up as a regular hifi project
|
||||
setup_hifi_project(Quick Gui OpenGL)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
#include_oglplus()
|
||||
|
||||
|
|
|
@ -10,11 +10,6 @@
|
|||
|
||||
#include "TextRenderer.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdouble-promotion"
|
||||
#endif
|
||||
|
||||
#include <QWindow>
|
||||
#include <QFile>
|
||||
#include <QTime>
|
||||
|
@ -31,10 +26,6 @@
|
|||
#include <QApplication>
|
||||
#include <QOpenGLDebugLogger>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
set(TARGET_NAME shared-tests)
|
||||
|
||||
setup_hifi_project()
|
||||
# Declare dependencies
|
||||
macro (setup_testcase_dependencies)
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared)
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
||||
copy_dlls_beside_windows_executable()
|
||||
endmacro ()
|
||||
|
||||
setup_hifi_testcase()
|
|
@ -17,6 +17,15 @@
|
|||
|
||||
#include "AngularConstraintTests.h"
|
||||
|
||||
// Computes the error value between two quaternions (using glm::dot)
|
||||
float getErrorDifference(const glm::quat& a, const glm::quat& b) {
|
||||
return fabsf(glm::dot(a, b) - 1.0f);
|
||||
}
|
||||
QTextStream& operator<<(QTextStream& stream, const glm::quat& q) {
|
||||
return stream << "glm::quat { " << q.x << ", " << q.y << ", " << q.z << ", " << q.w << " }";
|
||||
}
|
||||
|
||||
QTEST_MAIN(AngularConstraintTests)
|
||||
|
||||
void AngularConstraintTests::testHingeConstraint() {
|
||||
float minAngle = -PI;
|
||||
|
@ -26,25 +35,16 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
glm::vec3 maxAngles(0.0f, 0.0f, 0.0f);
|
||||
|
||||
AngularConstraint* c = AngularConstraint::newAngularConstraint(minAngles, maxAngles);
|
||||
if (!c) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: newAngularConstraint() should make a constraint" << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(c != nullptr, "newAngularConstraint should make a constraint");
|
||||
{ // test in middle of constraint
|
||||
float angle = 0.5f * (minAngle + maxAngle);
|
||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
||||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should not clamp()" << std::endl;
|
||||
}
|
||||
if (rotation != newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should not change rotation" << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained == false, "HingeConstraint should not clamp()");
|
||||
QVERIFY2(rotation == newRotation, "HingeConstraint should not change rotation");
|
||||
}
|
||||
{ // test just inside min edge of constraint
|
||||
float angle = minAngle + 10.0f * EPSILON;
|
||||
|
@ -52,14 +52,9 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should not clamp()" << std::endl;
|
||||
}
|
||||
if (rotation != newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should not change rotation" << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(!constrained, "HingeConstraint should not clamp()");
|
||||
QVERIFY2(newRotation == rotation, "HingeConstraint should not change rotation");
|
||||
}
|
||||
{ // test just inside max edge of constraint
|
||||
float angle = maxAngle - 10.0f * EPSILON;
|
||||
|
@ -67,14 +62,9 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should not clamp()" << std::endl;
|
||||
}
|
||||
if (rotation != newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should not change rotation" << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(!constrained, "HingeConstraint should not clamp()");
|
||||
QVERIFY2(newRotation == rotation, "HingeConstraint should not change rotation");
|
||||
}
|
||||
{ // test just outside min edge of constraint
|
||||
float angle = minAngle - 0.001f;
|
||||
|
@ -82,20 +72,11 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis);
|
||||
float qDot = glm::dot(expectedRotation, newRotation);
|
||||
if (fabsf(qDot - 1.0f) > EPSILON) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
{ // test just outside max edge of constraint
|
||||
float angle = maxAngle + 0.001f;
|
||||
|
@ -103,20 +84,10 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis);
|
||||
float qDot = glm::dot(expectedRotation, newRotation);
|
||||
if (fabsf(qDot - 1.0f) > EPSILON) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, rotation, EPSILON);
|
||||
}
|
||||
{ // test far outside min edge of constraint (wraps around to max)
|
||||
float angle = minAngle - 0.75f * (TWO_PI - (maxAngle - minAngle));
|
||||
|
@ -124,20 +95,11 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should change rotation" << std::endl;
|
||||
}
|
||||
|
||||
glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis);
|
||||
float qDot = glm::dot(expectedRotation, newRotation);
|
||||
if (fabsf(qDot - 1.0f) > EPSILON) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
{ // test far outside max edge of constraint (wraps around to min)
|
||||
float angle = maxAngle + 0.75f * (TWO_PI - (maxAngle - minAngle));
|
||||
|
@ -145,20 +107,11 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis);
|
||||
float qDot = glm::dot(expectedRotation, newRotation);
|
||||
if (fabsf(qDot - 1.0f) > EPSILON) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
|
||||
float ACCEPTABLE_ERROR = 1.0e-4f;
|
||||
|
@ -170,20 +123,11 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(angle, yAxis);
|
||||
float qDot = glm::dot(expectedRotation, newRotation);
|
||||
if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, ACCEPTABLE_ERROR);
|
||||
}
|
||||
{ // test way off rotation > maxAngle
|
||||
float offAngle = 0.5f;
|
||||
|
@ -194,20 +138,11 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis);
|
||||
float qDot = glm::dot(expectedRotation, newRotation);
|
||||
if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
{ // test way off rotation < minAngle
|
||||
float offAngle = 0.5f;
|
||||
|
@ -218,20 +153,11 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis);
|
||||
float qDot = glm::dot(expectedRotation, newRotation);
|
||||
if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
{ // test way off rotation > maxAngle with wrap over to minAngle
|
||||
float offAngle = -0.5f;
|
||||
|
@ -242,20 +168,11 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis);
|
||||
float qDot = glm::dot(expectedRotation, newRotation);
|
||||
if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
{ // test way off rotation < minAngle with wrap over to maxAngle
|
||||
float offAngle = -0.6f;
|
||||
|
@ -266,20 +183,11 @@ void AngularConstraintTests::testHingeConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis);
|
||||
float qDot = glm::dot(expectedRotation, newRotation);
|
||||
if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
delete c;
|
||||
}
|
||||
|
@ -306,24 +214,15 @@ void AngularConstraintTests::testConeRollerConstraint() {
|
|||
glm::vec3 xAxis(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 perpAxis = glm::normalize(xAxis - glm::dot(xAxis, expectedConeAxis) * expectedConeAxis);
|
||||
|
||||
if (!c) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: newAngularConstraint() should make a constraint" << std::endl;
|
||||
}
|
||||
QVERIFY2(c != nullptr, "newAngularConstraint() should make a constraint");
|
||||
{ // test in middle of constraint
|
||||
glm::vec3 angles(PI/20.0f, 0.0f, PI/10.0f);
|
||||
glm::quat rotation(angles);
|
||||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should not clamp()" << std::endl;
|
||||
}
|
||||
if (rotation != newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should not change rotation" << std::endl;
|
||||
}
|
||||
QVERIFY2(!constrained, "ConeRollerConstraint should not clamp()");
|
||||
QVERIFY2(newRotation == rotation, "ConeRollerConstraint should not change rotation");
|
||||
}
|
||||
float deltaAngle = 0.001f;
|
||||
{ // test just inside edge of cone
|
||||
|
@ -331,94 +230,58 @@ void AngularConstraintTests::testConeRollerConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should not clamp()" << std::endl;
|
||||
}
|
||||
if (rotation != newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should not change rotation" << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(!constrained, "ConeRollerConstraint should not clamp()");
|
||||
QVERIFY2(newRotation == rotation, "ConeRollerConstraint should not change rotation");
|
||||
}
|
||||
{ // test just outside edge of cone
|
||||
glm::quat rotation = glm::angleAxis(expectedConeAngle + deltaAngle, perpAxis);
|
||||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should change rotation" << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
||||
}
|
||||
{ // test just inside min edge of roll
|
||||
glm::quat rotation = glm::angleAxis(minAngleZ + deltaAngle, expectedConeAxis);
|
||||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should not clamp()" << std::endl;
|
||||
}
|
||||
if (rotation != newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should not change rotation" << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(!constrained, "ConeRollerConstraint should not clamp()");
|
||||
QVERIFY2(newRotation == rotation, "ConeRollerConstraint should not change rotation");
|
||||
}
|
||||
{ // test just inside max edge of roll
|
||||
glm::quat rotation = glm::angleAxis(maxAngleZ - deltaAngle, expectedConeAxis);
|
||||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should not clamp()" << std::endl;
|
||||
}
|
||||
if (rotation != newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should not change rotation" << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(!constrained, "ConeRollerConstraint should not clamp()");
|
||||
QVERIFY2(newRotation == rotation, "ConeRollerConstraint should not change rotation");
|
||||
}
|
||||
{ // test just outside min edge of roll
|
||||
glm::quat rotation = glm::angleAxis(minAngleZ - deltaAngle, expectedConeAxis);
|
||||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(minAngleZ, expectedConeAxis);
|
||||
if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
{ // test just outside max edge of roll
|
||||
glm::quat rotation = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis);
|
||||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should change rotation" << std::endl;
|
||||
}
|
||||
glm::quat expectedRotation = glm::angleAxis(maxAngleZ, expectedConeAxis);
|
||||
if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
deltaAngle = 0.25f * expectedConeAngle;
|
||||
{ // test far outside cone and min roll
|
||||
|
@ -428,21 +291,14 @@ void AngularConstraintTests::testConeRollerConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should change rotation" << std::endl;
|
||||
}
|
||||
|
||||
glm::quat expectedRoll = glm::angleAxis(minAngleZ, expectedConeAxis);
|
||||
glm::quat expectedPitchYaw = glm::angleAxis(expectedConeAngle, perpAxis);
|
||||
glm::quat expectedRotation = expectedPitchYaw * expectedRoll;
|
||||
if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
{ // test far outside cone and max roll
|
||||
glm::quat roll = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis);
|
||||
|
@ -451,26 +307,15 @@ void AngularConstraintTests::testConeRollerConstraint() {
|
|||
|
||||
glm::quat newRotation = rotation;
|
||||
bool constrained = c->clamp(newRotation);
|
||||
if (!constrained) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should clamp()" << std::endl;
|
||||
}
|
||||
if (rotation == newRotation) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: ConeRollerConstraint should change rotation" << std::endl;
|
||||
}
|
||||
|
||||
glm::quat expectedRoll = glm::angleAxis(maxAngleZ, expectedConeAxis);
|
||||
glm::quat expectedPitchYaw = glm::angleAxis(- expectedConeAngle, perpAxis);
|
||||
glm::quat expectedRotation = expectedPitchYaw * expectedRoll;
|
||||
if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
||||
}
|
||||
delete c;
|
||||
}
|
||||
|
||||
void AngularConstraintTests::runAllTests() {
|
||||
testHingeConstraint();
|
||||
testConeRollerConstraint();
|
||||
}
|
||||
|
|
|
@ -12,10 +12,19 @@
|
|||
#ifndef hifi_AngularConstraintTests_h
|
||||
#define hifi_AngularConstraintTests_h
|
||||
|
||||
namespace AngularConstraintTests {
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
class AngularConstraintTests : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testHingeConstraint();
|
||||
void testConeRollerConstraint();
|
||||
void runAllTests();
|
||||
}
|
||||
};
|
||||
|
||||
// Use QCOMPARE_WITH_ABS_ERROR and define it for glm::quat
|
||||
#include <glm/glm.hpp>
|
||||
float getErrorDifference (const glm::quat& a, const glm::quat& b);
|
||||
QTextStream & operator << (QTextStream& stream, const glm::quat& q);
|
||||
#include "../QTestExtensions.h"
|
||||
|
||||
#endif // hifi_AngularConstraintTests_h
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
QTEST_MAIN(MovingMinMaxAvgTests)
|
||||
|
||||
quint64 MovingMinMaxAvgTests::randQuint64() {
|
||||
quint64 ret = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
|
@ -24,199 +26,193 @@ quint64 MovingMinMaxAvgTests::randQuint64() {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void MovingMinMaxAvgTests::runAllTests() {
|
||||
{
|
||||
// quint64 test
|
||||
void MovingMinMaxAvgTests::testQuint64() {
|
||||
// quint64 test
|
||||
|
||||
const int INTERVAL_LENGTH = 100;
|
||||
const int WINDOW_INTERVALS = 50;
|
||||
const int INTERVAL_LENGTH = 100;
|
||||
const int WINDOW_INTERVALS = 50;
|
||||
|
||||
MovingMinMaxAvg<quint64> stats(INTERVAL_LENGTH, WINDOW_INTERVALS);
|
||||
MovingMinMaxAvg<quint64> stats(INTERVAL_LENGTH, WINDOW_INTERVALS);
|
||||
|
||||
quint64 min = std::numeric_limits<quint64>::max();
|
||||
quint64 max = 0;
|
||||
double average = 0.0;
|
||||
int totalSamples = 0;
|
||||
quint64 min = std::numeric_limits<quint64>::max();
|
||||
quint64 max = 0;
|
||||
double average = 0.0;
|
||||
int totalSamples = 0;
|
||||
|
||||
quint64 windowMin;
|
||||
quint64 windowMax;
|
||||
double windowAverage;
|
||||
quint64 windowMin;
|
||||
quint64 windowMax;
|
||||
double windowAverage;
|
||||
|
||||
QQueue<quint64> windowSamples;
|
||||
// fill window samples
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
QQueue<quint64> windowSamples;
|
||||
// fill window samples
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
|
||||
quint64 sample = randQuint64();
|
||||
quint64 sample = randQuint64();
|
||||
|
||||
windowSamples.enqueue(sample);
|
||||
if (windowSamples.size() > INTERVAL_LENGTH * WINDOW_INTERVALS) {
|
||||
windowSamples.dequeue();
|
||||
windowSamples.enqueue(sample);
|
||||
if (windowSamples.size() > INTERVAL_LENGTH * WINDOW_INTERVALS) {
|
||||
windowSamples.dequeue();
|
||||
}
|
||||
|
||||
stats.update(sample);
|
||||
|
||||
min = std::min(min, sample);
|
||||
max = std::max(max, sample);
|
||||
average = (average * totalSamples + sample) / (totalSamples + 1);
|
||||
totalSamples++;
|
||||
|
||||
QCOMPARE(stats.getMin(), min);
|
||||
QCOMPARE(stats.getMax(), max);
|
||||
|
||||
QCOMPARE_WITH_ABS_ERROR((float) stats.getAverage() / (float) average, 1.0f, EPSILON);
|
||||
QCOMPARE_WITH_ABS_ERROR((float) stats.getAverage(), (float) average, EPSILON);
|
||||
|
||||
if ((i + 1) % INTERVAL_LENGTH == 0) {
|
||||
QVERIFY(stats.getNewStatsAvailableFlag());
|
||||
stats.clearNewStatsAvailableFlag();
|
||||
|
||||
windowMin = std::numeric_limits<quint64>::max();
|
||||
windowMax = 0;
|
||||
windowAverage = 0.0;
|
||||
for (quint64 s : windowSamples) {
|
||||
windowMin = std::min(windowMin, s);
|
||||
windowMax = std::max(windowMax, s);
|
||||
windowAverage += (double)s;
|
||||
}
|
||||
windowAverage /= (double)windowSamples.size();
|
||||
|
||||
stats.update(sample);
|
||||
|
||||
min = std::min(min, sample);
|
||||
max = std::max(max, sample);
|
||||
average = (average * totalSamples + sample) / (totalSamples + 1);
|
||||
totalSamples++;
|
||||
|
||||
assert(stats.getMin() == min);
|
||||
assert(stats.getMax() == max);
|
||||
assert(fabsf((float)stats.getAverage() / (float)average - 1.0f) < EPSILON ||
|
||||
fabsf((float)stats.getAverage() - (float)average) < EPSILON);
|
||||
|
||||
if ((i + 1) % INTERVAL_LENGTH == 0) {
|
||||
|
||||
assert(stats.getNewStatsAvailableFlag());
|
||||
stats.clearNewStatsAvailableFlag();
|
||||
|
||||
windowMin = std::numeric_limits<quint64>::max();
|
||||
windowMax = 0;
|
||||
windowAverage = 0.0;
|
||||
foreach(quint64 s, windowSamples) {
|
||||
windowMin = std::min(windowMin, s);
|
||||
windowMax = std::max(windowMax, s);
|
||||
windowAverage += (double)s;
|
||||
}
|
||||
windowAverage /= (double)windowSamples.size();
|
||||
|
||||
assert(stats.getWindowMin() == windowMin);
|
||||
assert(stats.getWindowMax() == windowMax);
|
||||
assert(fabsf((float)stats.getAverage() / (float)average - 1.0f) < EPSILON ||
|
||||
fabsf((float)stats.getAverage() - (float)average) < EPSILON);
|
||||
|
||||
} else {
|
||||
assert(!stats.getNewStatsAvailableFlag());
|
||||
}
|
||||
QCOMPARE(stats.getWindowMin(), windowMin);
|
||||
QCOMPARE(stats.getWindowMax(), windowMax);
|
||||
QCOMPARE_WITH_ABS_ERROR((float)stats.getAverage(), (float)average, EPSILON);
|
||||
} else {
|
||||
QVERIFY(!stats.getNewStatsAvailableFlag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MovingMinMaxAvgTests::testInt() {
|
||||
// int test
|
||||
|
||||
const int INTERVAL_LENGTH = 1;
|
||||
const int WINDOW_INTERVALS = 75;
|
||||
|
||||
MovingMinMaxAvg<int> stats(INTERVAL_LENGTH, WINDOW_INTERVALS);
|
||||
|
||||
int min = std::numeric_limits<int>::max();
|
||||
int max = 0;
|
||||
double average = 0.0;
|
||||
int totalSamples = 0;
|
||||
|
||||
int windowMin;
|
||||
int windowMax;
|
||||
double windowAverage;
|
||||
|
||||
QQueue<int> windowSamples;
|
||||
// fill window samples
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
|
||||
int sample = rand();
|
||||
|
||||
windowSamples.enqueue(sample);
|
||||
if (windowSamples.size() > INTERVAL_LENGTH * WINDOW_INTERVALS) {
|
||||
windowSamples.dequeue();
|
||||
}
|
||||
|
||||
stats.update(sample);
|
||||
|
||||
min = std::min(min, sample);
|
||||
max = std::max(max, sample);
|
||||
average = (average * totalSamples + sample) / (totalSamples + 1);
|
||||
totalSamples++;
|
||||
|
||||
QCOMPARE(stats.getMin(), min);
|
||||
QCOMPARE(stats.getMax(), max);
|
||||
QCOMPARE_WITH_ABS_ERROR((float)stats.getAverage(), (float)average, EPSILON);
|
||||
|
||||
if ((i + 1) % INTERVAL_LENGTH == 0) {
|
||||
|
||||
QVERIFY(stats.getNewStatsAvailableFlag());
|
||||
stats.clearNewStatsAvailableFlag();
|
||||
|
||||
windowMin = std::numeric_limits<int>::max();
|
||||
windowMax = 0;
|
||||
windowAverage = 0.0;
|
||||
for (int s : windowSamples) {
|
||||
windowMin = std::min(windowMin, s);
|
||||
windowMax = std::max(windowMax, s);
|
||||
windowAverage += (double)s;
|
||||
}
|
||||
windowAverage /= (double)windowSamples.size();
|
||||
|
||||
QCOMPARE(stats.getWindowMin(), windowMin);
|
||||
QCOMPARE(stats.getWindowMax(), windowMax);
|
||||
QCOMPARE_WITH_ABS_ERROR((float)stats.getAverage(), (float)average, EPSILON);
|
||||
} else {
|
||||
QVERIFY(!stats.getNewStatsAvailableFlag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MovingMinMaxAvgTests::testFloat() {
|
||||
// float test
|
||||
|
||||
const int INTERVAL_LENGTH = 57;
|
||||
const int WINDOW_INTERVALS = 1;
|
||||
|
||||
MovingMinMaxAvg<float> stats(INTERVAL_LENGTH, WINDOW_INTERVALS);
|
||||
|
||||
float min = std::numeric_limits<float>::max();
|
||||
float max = 0;
|
||||
double average = 0.0;
|
||||
int totalSamples = 0;
|
||||
|
||||
float windowMin;
|
||||
float windowMax;
|
||||
double windowAverage;
|
||||
|
||||
QQueue<float> windowSamples;
|
||||
// fill window samples
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
|
||||
float sample = randFloat();
|
||||
|
||||
windowSamples.enqueue(sample);
|
||||
if (windowSamples.size() > INTERVAL_LENGTH * WINDOW_INTERVALS) {
|
||||
windowSamples.dequeue();
|
||||
}
|
||||
|
||||
stats.update(sample);
|
||||
|
||||
min = std::min(min, sample);
|
||||
max = std::max(max, sample);
|
||||
average = (average * totalSamples + (double)sample) / (totalSamples + 1);
|
||||
totalSamples++;
|
||||
|
||||
QCOMPARE(stats.getMin(), min);
|
||||
QCOMPARE(stats.getMax(), max);
|
||||
QCOMPARE_WITH_ABS_ERROR((float)stats.getAverage(), (float)average, EPSILON);
|
||||
|
||||
if ((i + 1) % INTERVAL_LENGTH == 0) {
|
||||
|
||||
QVERIFY(stats.getNewStatsAvailableFlag());
|
||||
stats.clearNewStatsAvailableFlag();
|
||||
|
||||
windowMin = std::numeric_limits<float>::max();
|
||||
windowMax = 0;
|
||||
windowAverage = 0.0;
|
||||
for (float s : windowSamples) {
|
||||
windowMin = std::min(windowMin, s);
|
||||
windowMax = std::max(windowMax, s);
|
||||
windowAverage += (double)s;
|
||||
}
|
||||
windowAverage /= (double)windowSamples.size();
|
||||
|
||||
QCOMPARE(stats.getWindowMin(), windowMin);
|
||||
QCOMPARE(stats.getWindowMax(), windowMax);
|
||||
QCOMPARE_WITH_ABS_ERROR((float)stats.getAverage(), (float)average, EPSILON);
|
||||
|
||||
} else {
|
||||
QVERIFY(!stats.getNewStatsAvailableFlag());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// int test
|
||||
|
||||
const int INTERVAL_LENGTH = 1;
|
||||
const int WINDOW_INTERVALS = 75;
|
||||
|
||||
MovingMinMaxAvg<int> stats(INTERVAL_LENGTH, WINDOW_INTERVALS);
|
||||
|
||||
int min = std::numeric_limits<int>::max();
|
||||
int max = 0;
|
||||
double average = 0.0;
|
||||
int totalSamples = 0;
|
||||
|
||||
int windowMin;
|
||||
int windowMax;
|
||||
double windowAverage;
|
||||
|
||||
QQueue<int> windowSamples;
|
||||
// fill window samples
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
|
||||
int sample = rand();
|
||||
|
||||
windowSamples.enqueue(sample);
|
||||
if (windowSamples.size() > INTERVAL_LENGTH * WINDOW_INTERVALS) {
|
||||
windowSamples.dequeue();
|
||||
}
|
||||
|
||||
stats.update(sample);
|
||||
|
||||
min = std::min(min, sample);
|
||||
max = std::max(max, sample);
|
||||
average = (average * totalSamples + sample) / (totalSamples + 1);
|
||||
totalSamples++;
|
||||
|
||||
assert(stats.getMin() == min);
|
||||
assert(stats.getMax() == max);
|
||||
assert(fabsf((float)stats.getAverage() / (float)average - 1.0f) < EPSILON);
|
||||
|
||||
if ((i + 1) % INTERVAL_LENGTH == 0) {
|
||||
|
||||
assert(stats.getNewStatsAvailableFlag());
|
||||
stats.clearNewStatsAvailableFlag();
|
||||
|
||||
windowMin = std::numeric_limits<int>::max();
|
||||
windowMax = 0;
|
||||
windowAverage = 0.0;
|
||||
foreach(int s, windowSamples) {
|
||||
windowMin = std::min(windowMin, s);
|
||||
windowMax = std::max(windowMax, s);
|
||||
windowAverage += (double)s;
|
||||
}
|
||||
windowAverage /= (double)windowSamples.size();
|
||||
|
||||
assert(stats.getWindowMin() == windowMin);
|
||||
assert(stats.getWindowMax() == windowMax);
|
||||
assert(fabsf((float)stats.getAverage() / (float)average - 1.0f) < EPSILON);
|
||||
|
||||
} else {
|
||||
assert(!stats.getNewStatsAvailableFlag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// float test
|
||||
|
||||
const int INTERVAL_LENGTH = 57;
|
||||
const int WINDOW_INTERVALS = 1;
|
||||
|
||||
MovingMinMaxAvg<float> stats(INTERVAL_LENGTH, WINDOW_INTERVALS);
|
||||
|
||||
float min = std::numeric_limits<float>::max();
|
||||
float max = 0;
|
||||
double average = 0.0;
|
||||
int totalSamples = 0;
|
||||
|
||||
float windowMin;
|
||||
float windowMax;
|
||||
double windowAverage;
|
||||
|
||||
QQueue<float> windowSamples;
|
||||
// fill window samples
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
|
||||
float sample = randFloat();
|
||||
|
||||
windowSamples.enqueue(sample);
|
||||
if (windowSamples.size() > INTERVAL_LENGTH * WINDOW_INTERVALS) {
|
||||
windowSamples.dequeue();
|
||||
}
|
||||
|
||||
stats.update(sample);
|
||||
|
||||
min = std::min(min, sample);
|
||||
max = std::max(max, sample);
|
||||
average = (average * totalSamples + (double)sample) / (totalSamples + 1);
|
||||
totalSamples++;
|
||||
|
||||
assert(stats.getMin() == min);
|
||||
assert(stats.getMax() == max);
|
||||
assert(fabsf((float)stats.getAverage() / (float)average - 1.0f) < EPSILON);
|
||||
|
||||
if ((i + 1) % INTERVAL_LENGTH == 0) {
|
||||
|
||||
assert(stats.getNewStatsAvailableFlag());
|
||||
stats.clearNewStatsAvailableFlag();
|
||||
|
||||
windowMin = std::numeric_limits<float>::max();
|
||||
windowMax = 0;
|
||||
windowAverage = 0.0;
|
||||
foreach(float s, windowSamples) {
|
||||
windowMin = std::min(windowMin, s);
|
||||
windowMax = std::max(windowMax, s);
|
||||
windowAverage += (double)s;
|
||||
}
|
||||
windowAverage /= (double)windowSamples.size();
|
||||
|
||||
assert(stats.getWindowMin() == windowMin);
|
||||
assert(stats.getWindowMax() == windowMax);
|
||||
assert(fabsf((float)stats.getAverage() / (float)average - 1.0f) < EPSILON);
|
||||
|
||||
} else {
|
||||
assert(!stats.getNewStatsAvailableFlag());
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("moving min/max/avg test passed!\n");
|
||||
}
|
||||
|
|
|
@ -12,14 +12,26 @@
|
|||
#ifndef hifi_MovingMinMaxAvgTests_h
|
||||
#define hifi_MovingMinMaxAvgTests_h
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
inline float getErrorDifference(float a, float b) {
|
||||
return fabsf(a - b);
|
||||
}
|
||||
|
||||
#include "../QTestExtensions.h"
|
||||
|
||||
#include "MovingMinMaxAvg.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
namespace MovingMinMaxAvgTests {
|
||||
|
||||
class MovingMinMaxAvgTests : public QObject {
|
||||
|
||||
private slots:
|
||||
void testQuint64();
|
||||
void testInt();
|
||||
void testFloat();
|
||||
|
||||
private:
|
||||
quint64 randQuint64();
|
||||
|
||||
void runAllTests();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // hifi_MovingMinMaxAvgTests_h
|
||||
|
|
|
@ -14,156 +14,132 @@
|
|||
#include "SharedUtil.h"
|
||||
#include "MovingPercentile.h"
|
||||
|
||||
#include <limits>
|
||||
#include <qqueue.h>
|
||||
|
||||
QTEST_MAIN(MovingPercentileTests)
|
||||
|
||||
// Defines the test values we use for n:
|
||||
static const QVector<int> testValues { 1, 2, 3, 4, 5, 10, 100 };
|
||||
|
||||
void MovingPercentileTests::testRunningMin() {
|
||||
for (auto n : testValues)
|
||||
testRunningMinForN(n);
|
||||
}
|
||||
|
||||
void MovingPercentileTests::testRunningMax() {
|
||||
for (auto n : testValues)
|
||||
testRunningMaxForN(n);
|
||||
}
|
||||
|
||||
void MovingPercentileTests::testRunningMedian() {
|
||||
for (auto n : testValues)
|
||||
testRunningMedianForN(n);
|
||||
}
|
||||
|
||||
|
||||
float MovingPercentileTests::random() {
|
||||
return rand() / (float)RAND_MAX;
|
||||
}
|
||||
|
||||
void MovingPercentileTests::runAllTests() {
|
||||
|
||||
QVector<int> valuesForN;
|
||||
void MovingPercentileTests::testRunningMinForN (int n) {
|
||||
|
||||
valuesForN.append(1);
|
||||
valuesForN.append(2);
|
||||
valuesForN.append(3);
|
||||
valuesForN.append(4);
|
||||
valuesForN.append(5);
|
||||
valuesForN.append(10);
|
||||
valuesForN.append(100);
|
||||
|
||||
|
||||
QQueue<float> lastNSamples;
|
||||
|
||||
for (int i=0; i<valuesForN.size(); i++) {
|
||||
|
||||
int N = valuesForN.at(i);
|
||||
|
||||
qDebug() << "testing moving percentile with N =" << N << "...";
|
||||
|
||||
{
|
||||
bool fail = false;
|
||||
|
||||
qDebug() << "\t testing running min...";
|
||||
|
||||
lastNSamples.clear();
|
||||
MovingPercentile movingMin(N, 0.0f);
|
||||
|
||||
for (int s = 0; s < 3*N; s++) {
|
||||
|
||||
float sample = random();
|
||||
|
||||
lastNSamples.push_back(sample);
|
||||
if (lastNSamples.size() > N) {
|
||||
lastNSamples.pop_front();
|
||||
}
|
||||
|
||||
movingMin.updatePercentile(sample);
|
||||
|
||||
float experimentMin = movingMin.getValueAtPercentile();
|
||||
|
||||
float actualMin = lastNSamples[0];
|
||||
for (int j = 0; j < lastNSamples.size(); j++) {
|
||||
if (lastNSamples.at(j) < actualMin) {
|
||||
actualMin = lastNSamples.at(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (experimentMin != actualMin) {
|
||||
qDebug() << "\t\t FAIL at sample" << s;
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fail) {
|
||||
qDebug() << "\t\t PASS";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
bool fail = false;
|
||||
|
||||
qDebug() << "\t testing running max...";
|
||||
|
||||
lastNSamples.clear();
|
||||
MovingPercentile movingMax(N, 1.0f);
|
||||
|
||||
for (int s = 0; s < 10000; s++) {
|
||||
|
||||
float sample = random();
|
||||
|
||||
lastNSamples.push_back(sample);
|
||||
if (lastNSamples.size() > N) {
|
||||
lastNSamples.pop_front();
|
||||
}
|
||||
|
||||
movingMax.updatePercentile(sample);
|
||||
|
||||
float experimentMax = movingMax.getValueAtPercentile();
|
||||
|
||||
float actualMax = lastNSamples[0];
|
||||
for (int j = 0; j < lastNSamples.size(); j++) {
|
||||
if (lastNSamples.at(j) > actualMax) {
|
||||
actualMax = lastNSamples.at(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (experimentMax != actualMax) {
|
||||
qDebug() << "\t\t FAIL at sample" << s;
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fail) {
|
||||
qDebug() << "\t\t PASS";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
bool fail = false;
|
||||
|
||||
qDebug() << "\t testing running median...";
|
||||
|
||||
lastNSamples.clear();
|
||||
MovingPercentile movingMedian(N, 0.5f);
|
||||
|
||||
for (int s = 0; s < 10000; s++) {
|
||||
|
||||
float sample = random();
|
||||
|
||||
lastNSamples.push_back(sample);
|
||||
if (lastNSamples.size() > N) {
|
||||
lastNSamples.pop_front();
|
||||
}
|
||||
|
||||
movingMedian.updatePercentile(sample);
|
||||
|
||||
float experimentMedian = movingMedian.getValueAtPercentile();
|
||||
|
||||
int samplesLessThan = 0;
|
||||
int samplesMoreThan = 0;
|
||||
|
||||
for (int j=0; j<lastNSamples.size(); j++) {
|
||||
if (lastNSamples.at(j) < experimentMedian) {
|
||||
samplesLessThan++;
|
||||
} else if (lastNSamples.at(j) > experimentMedian) {
|
||||
samplesMoreThan++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!(samplesLessThan <= N/2 && samplesMoreThan <= N-1/2)) {
|
||||
qDebug() << "\t\t FAIL at sample" << s;
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fail) {
|
||||
qDebug() << "\t\t PASS";
|
||||
}
|
||||
// Stores the last n samples
|
||||
QQueue<float> samples;
|
||||
|
||||
MovingPercentile movingMin (n, 0.0f);
|
||||
|
||||
for (int s = 0; s < 3 * n; ++s) {
|
||||
float sample = random();
|
||||
|
||||
samples.push_back(sample);
|
||||
if (samples.size() > n)
|
||||
samples.pop_front();
|
||||
|
||||
if (samples.size() == 0) {
|
||||
QFAIL_WITH_MESSAGE("\n\n\n\tWTF\n\tsamples.size() = " << samples.size() << ", n = " << n);
|
||||
}
|
||||
|
||||
movingMin.updatePercentile(sample);
|
||||
|
||||
// Calculate the minimum of the moving samples
|
||||
float expectedMin = std::numeric_limits<float>::max();
|
||||
|
||||
int prevSize = samples.size();
|
||||
for (auto val : samples)
|
||||
expectedMin = std::min(val, expectedMin);
|
||||
QCOMPARE(samples.size(), prevSize);
|
||||
|
||||
QCOMPARE(movingMin.getValueAtPercentile(), expectedMin);
|
||||
}
|
||||
}
|
||||
|
||||
void MovingPercentileTests::testRunningMaxForN (int n) {
|
||||
|
||||
// Stores the last n samples
|
||||
QQueue<float> samples;
|
||||
|
||||
MovingPercentile movingMax (n, 1.0f);
|
||||
|
||||
for (int s = 0; s < 10000; ++s) {
|
||||
float sample = random();
|
||||
|
||||
samples.push_back(sample);
|
||||
if (samples.size() > n)
|
||||
samples.pop_front();
|
||||
|
||||
if (samples.size() == 0) {
|
||||
QFAIL_WITH_MESSAGE("\n\n\n\tWTF\n\tsamples.size() = " << samples.size() << ", n = " << n);
|
||||
}
|
||||
|
||||
movingMax.updatePercentile(sample);
|
||||
|
||||
// Calculate the maximum of the moving samples
|
||||
float expectedMax = std::numeric_limits<float>::min();
|
||||
for (auto val : samples)
|
||||
expectedMax = std::max(val, expectedMax);
|
||||
|
||||
QCOMPARE(movingMax.getValueAtPercentile(), expectedMax);
|
||||
}
|
||||
}
|
||||
|
||||
void MovingPercentileTests::testRunningMedianForN (int n) {
|
||||
// Stores the last n samples
|
||||
QQueue<float> samples;
|
||||
|
||||
MovingPercentile movingMedian (n, 0.5f);
|
||||
|
||||
for (int s = 0; s < 10000; ++s) {
|
||||
float sample = random();
|
||||
|
||||
samples.push_back(sample);
|
||||
if (samples.size() > n)
|
||||
samples.pop_front();
|
||||
|
||||
if (samples.size() == 0) {
|
||||
QFAIL_WITH_MESSAGE("\n\n\n\tWTF\n\tsamples.size() = " << samples.size() << ", n = " << n);
|
||||
}
|
||||
|
||||
movingMedian.updatePercentile(sample);
|
||||
auto median = movingMedian.getValueAtPercentile();
|
||||
|
||||
// Check the number of samples that are > or < median
|
||||
int samplesGreaterThan = 0;
|
||||
int samplesLessThan = 0;
|
||||
|
||||
for (auto value : samples) {
|
||||
if (value < median)
|
||||
++samplesGreaterThan;
|
||||
else if (value > median)
|
||||
++samplesLessThan;
|
||||
}
|
||||
|
||||
QCOMPARE_WITH_LAMBDA(samplesLessThan, n / 2, [=]() {
|
||||
return samplesLessThan <= n / 2;
|
||||
});
|
||||
QCOMPARE_WITH_LAMBDA(samplesGreaterThan, (n - 1) / 2, [=]() {
|
||||
return samplesGreaterThan <= n / 2;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,24 @@
|
|||
#ifndef hifi_MovingPercentileTests_h
|
||||
#define hifi_MovingPercentileTests_h
|
||||
|
||||
namespace MovingPercentileTests {
|
||||
#include <QtTest/QtTest>
|
||||
#include <../QTestExtensions.h>
|
||||
|
||||
class MovingPercentileTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
// Tests
|
||||
void testRunningMin ();
|
||||
void testRunningMax ();
|
||||
void testRunningMedian ();
|
||||
|
||||
private:
|
||||
// Utilities and helper functions
|
||||
float random();
|
||||
|
||||
void runAllTests();
|
||||
}
|
||||
void testRunningMinForN (int n);
|
||||
void testRunningMaxForN (int n);
|
||||
void testRunningMedianForN (int n);
|
||||
};
|
||||
|
||||
#endif // hifi_MovingPercentileTests_h
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tests/physics/src
|
||||
//
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
#include "AngularConstraintTests.h"
|
||||
#include "MovingPercentileTests.h"
|
||||
#include "MovingMinMaxAvgTests.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
MovingMinMaxAvgTests::runAllTests();
|
||||
MovingPercentileTests::runAllTests();
|
||||
AngularConstraintTests::runAllTests();
|
||||
printf("tests complete, press enter to exit\n");
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
set(TARGET_NAME ui-tests)
|
||||
|
||||
|
||||
set(TARGET_NAME "ui-test")
|
||||
|
||||
# This is not a testcase -- just set it up as a regular hifi project
|
||||
setup_hifi_project(Widgets OpenGL Network Qml Quick Script)
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
if (WIN32)
|
||||
add_dependency_external_projects(glew)
|
||||
find_package(GLEW REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib)
|
||||
add_dependency_external_projects(glew)
|
||||
find_package(GLEW REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib)
|
||||
endif()
|
||||
|
||||
# link in the shared libraries
|
||||
|
|
Loading…
Reference in a new issue