3333#include < fstream>
3434#include < string>
3535#include < regex>
36+ #include < type_traits>
3637
37- template <typename T>
38- void ASSERT_EQUAL (T expected,
38+ /* *
39+ * ASSERT_EQUAL is a general utility for comparing two values and throwing
40+ * an Exception with a caller defined message when values are not equivalent.
41+ * Note, ASSERT_EQUAL is typically used to verify that some found value matches
42+ * a given expected or standard value. If the expected value is NaN,
43+ * ASSERT_EQUAL will NOT throw if the found value is also NaN. This is
44+ * particularly helpful for comparing motion capture data where missing data
45+ * are denoted by NaN values. If NaNs are not acceptable for your test, then
46+ * the expected value should not be NaN. In the case of floating point values
47+ * (or containers of floating points) a tolerance of the same value type is
48+ * required.
49+ */
50+ template <typename T,
51+ typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr >
52+ void ASSERT_EQUAL (T expected,
3953 T found,
4054 T tolerance,
4155 std::string file = " " ,
4256 int line = -1 ,
4357 std::string message = " " ) {
58+ // if both values are NaN treat them as being equivalent for the
59+ // sake of comparing experimental data and results where NaNs are
60+ // possible
61+ if (SimTK::isNaN (found) && SimTK::isNaN (expected))
62+ return ;
63+ if (found < expected - tolerance || found > expected + tolerance)
64+ throw OpenSim::Exception (message, file, line);
65+ }
66+
67+ template <typename T,
68+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr >
69+ void ASSERT_EQUAL (T expected,
70+ T found,
71+ std::string file = " " ,
72+ int line = -1 ,
73+ std::string message = " " ) {
74+ if (found != expected)
75+ throw OpenSim::Exception (message, file, line);
76+ }
77+
78+ template <typename T,
79+ typename std::enable_if<!std::is_arithmetic<T>::value>::type* = nullptr >
80+ void ASSERT_EQUAL (T expected,
81+ T found,
82+ T tolerance,
83+ std::string file = " " ,
84+ int line = -1 ,
85+ std::string message = " " ) {
86+ // if both values are NaN treat them as equivalent
87+ if (found.isNaN () && expected.isNaN () )
88+ return ;
4489 if (found < expected - tolerance || found > expected + tolerance)
4590 throw OpenSim::Exception (message, file, line);
4691}
92+
4793template <int M, typename ELT, int STRIDE>
4894void ASSERT_EQUAL (const SimTK::Vec<M, ELT, STRIDE>& vecA,
4995 const SimTK::Vec<M, ELT, STRIDE>& vecB,
5096 const std::string& file = " " ,
5197 int line = -1 ,
5298 const std::string& message = " " ) {
5399 try {
100+ // if both values are NaN treat them as being equivalent
101+ if (vecA.isNaN () && vecB.isNaN ())
102+ return ;
54103 SimTK_TEST_EQ (vecA, vecB);
55104 } catch (const SimTK::Exception::Assert&) {
56105 throw OpenSim::Exception (message, file, line);
@@ -64,12 +113,37 @@ void ASSERT_EQUAL(const SimTK::Vec<M, ELT, STRIDE>& vecA,
64113 int line = -1 ,
65114 const std::string& message = " " ) {
66115 try {
116+ // if both values are NaN treat them as being equivalent
117+ if (vecA.isNaN () && vecB.isNaN ())
118+ return ;
67119 SimTK_TEST_EQ_TOL (vecA, vecB, tolerance);
68120 } catch (const SimTK::Exception::Assert&) {
69121 throw OpenSim::Exception (message, file, line);
70122 }
71123}
72124
125+ template <typename Container, typename T>
126+ void ASSERT_EQUAL ( const Container& vecA,
127+ const Container& vecB,
128+ T tolerance,
129+ std::string file = " " ,
130+ int line = -1 ,
131+ std::string message = " " ) {
132+
133+ if (vecA.size () != vecB.size ()) {
134+ throw OpenSim::Exception (message, file, line);
135+ }
136+ else {
137+ for (auto i = 0 ; i < vecA.size (); ++i) {
138+ // if both values are NaN treat them as being equivalent
139+ if ( SimTK::isNaN (vecA[i]) && SimTK::isNaN (vecB[i]) )
140+ continue ;
141+ if (vecA[i] < vecB[i] - tolerance || vecA[i] > vecB[i] + tolerance) {
142+ throw OpenSim::Exception (message, file, line);
143+ }
144+ }
145+ }
146+ }
73147
74148inline void ASSERT (bool cond,
75149 std::string file=" " ,
0 commit comments