I've just finished the relative error patch, I of course added all the tests
as well. This is a new feature and doesn't touch and of the existing
functions, so it should be an easy addition. It does however, require cmath
for the fabs function, if this is a problem and someone can offer a non
library dependent absolute value function I'd be happy to replace fabs. VC++
has a fabs funcion but I'm not sure about the includes nessecary for it,
etc. It also treats comparisons with zero as a special case, to avoid
division by zero it calls AreClose for (expected==0.0).

The interface is as follows:

For all instances of the *CLOSE macro or *Close function the word RELATIVELY
or Relatively have been appended.

Example

CHECK_RELATIVELY_CLOSE(1.0f,1.01f,0.01f)

On Thu, Feb 4, 2010 at 4:36 PM, Sean Farrell <sean.farr...@rioki.org> wrote:

> Hi looks interesting.
>
> Since it is very small and portable, care to make a patch?
>
> Sean
>
> On Thu, Feb 4, 2010 at 9:18 PM, Charles Mark Maynard <cmayn...@gmail.com>
> wrote:
> > Hello all, I have been using UnitTest++ and am currently working on a
> > project and researching 3 numerical libraries(TET,GSL,BOOST MATH). While
> > testing I've ran into a problem using CHECK_ARRAY_CLOSE. It is not a bug,
> > but rather that in some cases the numbers are so large that is would be
> > better to check relative error then absolute. I would like to propose a
> new
> > comparison test CHECK_ARRAY_RELATIVE, which would use relative error
> instead
> > for values larger than the tolerance value.
> >
> > Currently I have resorted to using the following conditional to check
> > absolute or relatvie based on the size of the values I'm comparing:
> >
> > bool pass=true;
> > //choose between checking relative or absolute error
> > if(fabs(pnm.TET_pnm_r()[j])<accuracy ||
> fabs(pnm.GSL_pnm_r()[j])<accuracy)
> > {
> >   //absolute error
> >   if(fabs(pnm.TET_pnm_r()[j]-pnm.GSL_pnm_r()[j])<accuracy)
> >     std::cout<<"Absolute N: "<<n<<" M: "<<m<<" TET:
> "<<pnm.TET_pnm_r()[j]<<"
> > GSL: " << pnm.GSL_pnm_r()[j]<<" RIGHT\n";
> >   else
> >   {
> >     std::cout<<"***** Absolute N: "<<n<<" M: "<<m<<" TET:
> > "<<pnm.TET_pnm_r()[j]<<" GSL: " << pnm.GSL_pnm_r()[j]<<" WRONG\n";
> >     pass=false;
> >   }
> > }
> > else
> > {
> >   //relative error
> >
> >
> if((fabs(pnm.TET_pnm_r()[j]-pnm.GSL_pnm_r()[j])/pnm.TET_pnm_r()[j])<accuracy)
> >     std::cout<<"Relative N: "<<n<<" M: "<<m<<" TET:
> "<<pnm.TET_pnm_r()[j]<<"
> > GSL: " << pnm.GSL_pnm_r()[j]<<" RIGHT\n";
> >   else
> >   {
> >     std::cout<<"***** Relative N: "<<n<<" M: "<<m<<" TET:
> > "<<pnm.TET_pnm_r()[j]<<" GSL: " << pnm.GSL_pnm_r()[j]<<" WRONG\n";
> >     pass=false;
> >   }
> > }
> >
> > Let me know if this is of interest, I would be willing to help with
> > development. I've looked at through the repository, and this shouldn't
> take
> > too much effort to add, mostly a new AreRelativelyClose method and a less
> > than comparison of the expected term with the tolerance to decide which
> one
> > to call.
> >
> > Cheers,
> > Mark
> >
> >
> ------------------------------------------------------------------------------
> > The Planet: dedicated and managed hosting, cloud storage, colocation
> > Stay online with enterprise data centers and the best network in the
> > business
> > Choose flexible plans and management services without long-term contracts
> > Personal 24x7 support from experience hosting pros just a phone call
> away.
> > http://p.sf.net/sfu/theplanet-com
> > _______________________________________________
> > unittest-cpp-devel mailing list
> > unittest-cpp-devel@lists.sourceforge.net
> > https://lists.sourceforge.net/lists/listinfo/unittest-cpp-devel
> >
> >
>
>
> ------------------------------------------------------------------------------
> The Planet: dedicated and managed hosting, cloud storage, colocation
> Stay online with enterprise data centers and the best network in the
> business
> Choose flexible plans and management services without long-term contracts
> Personal 24x7 support from experience hosting pros just a phone call away.
> http://p.sf.net/sfu/theplanet-com
> _______________________________________________
> unittest-cpp-devel mailing list
> unittest-cpp-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/unittest-cpp-devel
>
Index: src/Checks.h
===================================================================
--- src/Checks.h	(revision 207)
+++ src/Checks.h	(working copy)
@@ -1,6 +1,7 @@
 #ifndef UNITTEST_CHECKS_H
 #define UNITTEST_CHECKS_H
 
+#include <cmath>
 #include "Config.h"
 #include "TestResults.h"
 #include "MemoryOutStream.h"
@@ -42,6 +43,15 @@
 }
 
 template< typename Expected, typename Actual, typename Tolerance >
+bool AreRelativelyClose(Expected const& expected, Actual const& actual, Tolerance const& tolerance)
+{
+    if(actual!=0.0)
+        return ((fabs(actual - expected) / actual) <= tolerance);
+    else
+        return AreClose(expected, actual, tolerance);
+}
+
+template< typename Expected, typename Actual, typename Tolerance >
 void CheckClose(TestResults& results, Expected const& expected, Actual const& actual, Tolerance const& tolerance,
                 TestDetails const& details)
 {
@@ -54,7 +64,19 @@
     }
 }
 
+template< typename Expected, typename Actual, typename Tolerance >
+void CheckRelativelyClose(TestResults& results, Expected const& expected, Actual const& actual, Tolerance const& tolerance,
+                TestDetails const& details)
+{
+    if (!AreRelativelyClose(expected, actual, tolerance))
+    { 
+        UnitTest::MemoryOutStream stream;
+        stream << "Expected " << expected << " +/- " << tolerance << " but was " << actual;
 
+        results.OnTestFailure(details, stream.GetText());
+    }
+}
+
 template< typename Expected, typename Actual >
 void CheckArrayEqual(TestResults& results, Expected const& expected, Actual const& actual,
                 int const count, TestDetails const& details)
@@ -93,6 +115,15 @@
 }
 
 template< typename Expected, typename Actual, typename Tolerance >
+bool ArrayAreRelativelyClose(Expected const& expected, Actual const& actual, int const count, Tolerance const& tolerance)
+{
+    bool equal = true;
+    for (int i = 0; i < count; ++i)
+        equal &= AreRelativelyClose(expected[i], actual[i], tolerance);
+    return equal;
+}
+
+template< typename Expected, typename Actual, typename Tolerance >
 void CheckArrayClose(TestResults& results, Expected const& expected, Actual const& actual,
                    int const count, Tolerance const& tolerance, TestDetails const& details)
 {
@@ -116,6 +147,29 @@
 }
 
 template< typename Expected, typename Actual, typename Tolerance >
+void CheckArrayRelativelyClose(TestResults& results, Expected const& expected, Actual const& actual,
+                   int const count, Tolerance const& tolerance, TestDetails const& details)
+{
+    bool equal = ArrayAreRelativelyClose(expected, actual, count, tolerance);
+
+    if (!equal)
+    {
+        UnitTest::MemoryOutStream stream;
+
+        stream << "Expected [ ";
+        for (int expectedIndex = 0; expectedIndex < count; ++expectedIndex)
+            stream << expected[expectedIndex] << " ";
+        stream << "] +/- " << tolerance << " but was [ ";
+
+		for (int actualIndex = 0; actualIndex < count; ++actualIndex)
+            stream << actual[actualIndex] << " ";
+        stream << "]";
+
+        results.OnTestFailure(details, stream.GetText());
+    }
+}
+
+template< typename Expected, typename Actual, typename Tolerance >
 void CheckArray2DClose(TestResults& results, Expected const& expected, Actual const& actual,
                    int const rows, int const columns, Tolerance const& tolerance, TestDetails const& details)
 {
@@ -153,6 +207,44 @@
     }
 }
 
+template< typename Expected, typename Actual, typename Tolerance >
+void CheckArray2DRelativelyClose(TestResults& results, Expected const& expected, Actual const& actual,
+                   int const rows, int const columns, Tolerance const& tolerance, TestDetails const& details)
+{
+    bool equal = true;
+    for (int i = 0; i < rows; ++i)
+        equal &= ArrayAreRelativelyClose(expected[i], actual[i], columns, tolerance);
+
+    if (!equal)
+    {
+        UnitTest::MemoryOutStream stream;
+
+        stream << "Expected [ ";    
+
+		for (int expectedRow = 0; expectedRow < rows; ++expectedRow)
+        {
+            stream << "[ ";
+            for (int expectedColumn = 0; expectedColumn < columns; ++expectedColumn)
+                stream << expected[expectedRow][expectedColumn] << " ";
+            stream << "] ";
+        }
+
+		stream << "] +/- " << tolerance << " but was [ ";
+
+		for (int actualRow = 0; actualRow < rows; ++actualRow)
+        {
+            stream << "[ ";
+            for (int actualColumn = 0; actualColumn < columns; ++actualColumn)
+                stream << actual[actualRow][actualColumn] << " ";
+            stream << "] ";
+        }
+
+		stream << "]";
+
+        results.OnTestFailure(details, stream.GetText());
+    }
 }
 
+}
+
 #endif
Index: src/tests/TestChecks.cpp
===================================================================
--- src/tests/TestChecks.cpp	(revision 207)
+++ src/tests/TestChecks.cpp	(working copy)
@@ -180,7 +180,90 @@
     CHECK_EQUAL(10, reporter.lastFailedLine);
 }
 
+TEST(CheckRelativelyCloseTrue)
+{
+    TestResults results;
+    CheckRelativelyClose(results, 3.001f, 3.0f, 0.1f, TestDetails("", "", "", 0));
+    CHECK_EQUAL(0, results.GetFailureCount());
+}
 
+TEST(CheckRelativelyCloseFalse)
+{
+    TestResults results;
+    CheckRelativelyClose(results, 3.5f, 3.0f, 0.1f, TestDetails("", "", "", 0));
+    CHECK_EQUAL(1, results.GetFailureCount());
+}
+
+TEST(CheckRelativelyCloseWithZeroEpsilonWorksForSameNumber)
+{
+    TestResults results;
+    CheckRelativelyClose(results, 0.1f, 0.1f, 0, TestDetails("", "", "", 0));
+    CHECK_EQUAL(0, results.GetFailureCount());
+}
+
+TEST(CheckRelativelyCloseWithNaNFails)
+{
+    union
+    {
+        unsigned int bitpattern;
+        float nan;
+    };
+    bitpattern = 0xFFFFFFFF;
+    TestResults results;
+    CheckRelativelyClose(results, 3.0f, nan, 0.1f, TestDetails("", "", "", 0));
+    CHECK_EQUAL(1, results.GetFailureCount());
+}
+
+TEST(CheckRelativelyCloseWithNaNAgainstItselfFails)
+{
+    union
+    {
+        unsigned int bitpattern;
+        float nan;
+    };
+    bitpattern = 0xFFFFFFFF;
+    TestResults results;
+    CheckRelativelyClose(results, nan, nan, 0.1f, TestDetails("", "", "", 0));
+    CHECK_EQUAL(1, results.GetFailureCount());
+}
+
+TEST(CheckRelativelyCloseFailureIncludesCheckExpectedAndActual)
+{
+    RecordingReporter reporter;
+    TestResults results(&reporter);
+    const float expected = 0.9f;
+    const float actual = 1.1f;
+    CheckRelativelyClose(results, expected, actual, 0.01f, TestDetails("", "", "", 0));
+
+	using namespace std;
+    CHECK(strstr(reporter.lastFailedMessage, "xpected 0.9"));
+    CHECK(strstr(reporter.lastFailedMessage, "was 1.1"));
+}
+
+TEST(CheckRelativelyCloseFailureIncludesTolerance)
+{
+    RecordingReporter reporter;
+    TestResults results(&reporter);
+    CheckRelativelyClose(results, 2, 3, 0.01f, TestDetails("", "", "", 0));
+
+	using namespace std;
+    CHECK(strstr(reporter.lastFailedMessage, "0.01"));
+}
+
+TEST(CheckRelativelyCloseFailureIncludesDetails)
+{
+    RecordingReporter reporter;
+    TestResults results(&reporter);
+    TestDetails const details("mytest", "mysuite", "header.h", 10);
+
+    CheckRelativelyClose(results, 2, 3, 0.01f, details);
+
+    CHECK_EQUAL("mytest", reporter.lastFailedTest);
+    CHECK_EQUAL("mysuite", reporter.lastFailedSuite);
+    CHECK_EQUAL("header.h", reporter.lastFailedFile);
+    CHECK_EQUAL(10, reporter.lastFailedLine);
+}
+
 TEST(CheckArrayEqualTrue)
 {
     TestResults results;
@@ -236,7 +319,42 @@
     CHECK_EQUAL(1337, reporter.lastFailedLine);
 }
 
+TEST(CheckArrayRelativelyCloseTrue)
+{
+    TestResults results;
 
+    float const array1[3] = { 1.0f, 1.5f, 2.0f };
+    float const array2[3] = { 1.01f, 1.51f, 2.01f };
+    CheckArrayRelativelyClose(results, array1, array2, 3, 0.02f, TestDetails("", "", "", 0));
+    CHECK_EQUAL(0, results.GetFailureCount());
+}
+
+TEST(CheckArrayRelativelyCloseFalse)
+{
+    TestResults results;
+
+    float const array1[3] = { 1.0f, 1.5f, 2.0f };
+    float const array2[3] = { 1.01f, 1.51f, 2.01f };
+    CheckArrayRelativelyClose(results, array1, array2, 3, 0.001f, TestDetails("", "", "", 0));
+    CHECK_EQUAL(1, results.GetFailureCount());
+}
+
+TEST(CheckArrayRelativelyCloseFailureIncludesDetails)
+{
+    RecordingReporter reporter;
+    TestResults results(&reporter);
+    TestDetails const details("arrayRelativelyCloseTest", "arrayRelativelyCloseSuite", "file", 1337);
+
+    float const array1[3] = { 1.0f, 1.5f, 2.0f };
+    float const array2[3] = { 1.01f, 1.51f, 2.01f };
+    CheckArrayClose(results, array1, array2, 3, 0.001f, details);
+
+    CHECK_EQUAL("arrayRelativelyCloseTest", reporter.lastFailedTest);
+    CHECK_EQUAL("arrayRelativelyCloseSuite", reporter.lastFailedSuite);
+    CHECK_EQUAL("file", reporter.lastFailedFile);
+    CHECK_EQUAL(1337, reporter.lastFailedLine);
+}
+
 TEST(CheckArray2DCloseTrue)
 {
     TestResults results;
@@ -265,11 +383,44 @@
     CHECK_EQUAL(1, results.GetFailureCount());
 }
 
+TEST(CheckArray2DRelativelyCloseTrue)
+{
+    TestResults results;
+
+    float const array1[3][3] = { { 1.0f, 1.5f, 2.0f },
+                                 { 2.0f, 2.5f, 3.0f },
+                                 { 3.0f, 3.5f, 4.0f } };
+    float const array2[3][3] = { { 1.01f, 1.51f, 2.01f },
+                                 { 2.01f, 2.51f, 3.01f },
+                                 { 3.01f, 3.51f, 4.01f } };
+    CheckArray2DRelativelyClose(results, array1, array2, 3, 3, 0.02f, TestDetails("", "", "", 0));
+    CHECK_EQUAL(0, results.GetFailureCount());
+}
+
+TEST(CheckArray2DRelativelyCloseFalse)
+{
+    TestResults results;
+
+    float const array1[3][3] = { { 1.0f, 1.5f, 2.0f },
+                                 { 2.0f, 2.5f, 3.0f },
+                                 { 3.0f, 3.5f, 4.0f } };
+    float const array2[3][3] = { { 1.01f, 1.51f, 2.01f },
+                                 { 2.01f, 2.51f, 3.01f },
+                                 { 3.01f, 3.51f, 4.01f } };
+    CheckArray2DRelativelyClose(results, array1, array2, 3, 3, 0.001f, TestDetails("", "", "", 0));
+    CHECK_EQUAL(1, results.GetFailureCount());
+}
+
 TEST(CheckCloseWithDoublesSucceeds)
 {
     CHECK_CLOSE(0.5, 0.5, 0.0001);
 }
 
+TEST(CheckRelativelyCloseWithDoublesSucceeds)
+{
+    CHECK_RELATIVELY_CLOSE(0.5, 0.5, 0.0001);
+}
+
 TEST(CheckArray2DCloseFailureIncludesDetails)
 {
     RecordingReporter reporter;
@@ -290,4 +441,24 @@
     CHECK_EQUAL(1234, reporter.lastFailedLine);
 }
 
+TEST(CheckArray2DRelativelyCloseFailureIncludesDetails)
+{
+    RecordingReporter reporter;
+    TestResults results(&reporter);
+    TestDetails const details("array2DRelativelyCloseTest", "array2DRelativelyCloseSuite", "file", 1234);
+
+    float const array1[3][3] = { { 1.0f, 1.5f, 2.0f },
+                                 { 2.0f, 2.5f, 3.0f },
+                                 { 3.0f, 3.5f, 4.0f } };
+    float const array2[3][3] = { { 1.01f, 1.51f, 2.01f },
+                                 { 2.01f, 2.51f, 3.01f },
+                                 { 3.01f, 3.51f, 4.01f } };
+    CheckArray2DRelativelyClose(results, array1, array2, 3, 3, 0.001f, details);
+
+    CHECK_EQUAL("array2DRelativelyCloseTest", reporter.lastFailedTest);
+    CHECK_EQUAL("array2DRelativelyCloseSuite", reporter.lastFailedSuite);
+    CHECK_EQUAL("file", reporter.lastFailedFile);
+    CHECK_EQUAL(1234, reporter.lastFailedLine);
 }
+
+}
Index: src/tests/TestCheckMacros.cpp
===================================================================
--- src/tests/TestCheckMacros.cpp	(revision 207)
+++ src/tests/TestCheckMacros.cpp	(working copy)
@@ -326,7 +326,118 @@
     CHECK_EQUAL(1, g_sideEffect);
 }
 
+TEST(CheckRelativelyCloseSucceedsOnEqual)
+{
+    bool failure = true;
+    {
+        RecordingReporter reporter;
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+        CHECK_RELATIVELY_CLOSE (1.0f, 1.001f, 0.01f);
+        failure = (testResults.GetFailureCount() > 0);
+    }
 
+    CHECK(!failure);
+}
+
+TEST(CheckRelativelyCloseFailsOnNotEqual)
+{
+    bool failure = false;
+    {
+        RecordingReporter reporter;
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+        CHECK_RELATIVELY_CLOSE (1.0f, 1.1f, 0.01f);
+        failure = (testResults.GetFailureCount() > 0);
+    }
+
+    CHECK(failure);
+}
+
+TEST(CheckRelativelyCloseFailsOnException)
+{
+    bool failure = false;
+    {
+        RecordingReporter reporter;
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+        CHECK_RELATIVELY_CLOSE ((float)ThrowingFunction(), 1.0001f, 0.1f);
+        failure = (testResults.GetFailureCount() > 0);
+    }
+
+    CHECK(failure);
+}
+
+TEST(CheckRelativelyCloseFailureContainsCorrectDetails)
+{
+    int line = 0;
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		UnitTest::TestDetails testDetails("test", "suite", "filename", -1);
+		ScopedCurrentTest scopedResults(testResults, &testDetails);
+
+		CHECK_RELATIVELY_CLOSE (1.0f, 1.1f, 0.01f);    line = __LINE__;
+    }
+
+    CHECK_EQUAL("test", reporter.lastFailedTest);
+    CHECK_EQUAL("suite", reporter.lastFailedSuite);
+    CHECK_EQUAL("filename", reporter.lastFailedFile);
+    CHECK_EQUAL(line, reporter.lastFailedLine);
+}
+
+TEST(CheckRelativelyCloseFailureBecauseOfExceptionContainsCorrectDetails)
+{
+    int line = 0;
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		UnitTest::TestDetails testDetails("closeTest", "closeSuite", "filename", -1);
+		ScopedCurrentTest scopedResults(testResults, &testDetails);
+        CHECK_RELATIVELY_CLOSE ((float)ThrowingFunction(), 1.0001f, 0.1f);    line = __LINE__;
+    }
+
+    CHECK_EQUAL("closeTest", reporter.lastFailedTest);
+    CHECK_EQUAL("closeSuite", reporter.lastFailedSuite);
+    CHECK_EQUAL("filename", reporter.lastFailedFile);
+    CHECK_EQUAL(line, reporter.lastFailedLine);
+}
+
+TEST(CheckRelativelyCloseFailureBecauseOfExceptionIncludesCheckContents)
+{
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+        CHECK_RELATIVELY_CLOSE ((float)ThrowingFunction(), 1.0001f, 0.1f);
+    }
+
+    CHECK(strstr(reporter.lastFailedMessage, "(float)ThrowingFunction()"));
+    CHECK(strstr(reporter.lastFailedMessage, "1.0001f"));
+}
+
+TEST(CheckRelativelyCloseDoesNotHaveSideEffectsWhenPassing)
+{
+    g_sideEffect = 0;
+    {
+        UnitTest::TestResults testResults;
+		ScopedCurrentTest scopedResults(testResults);
+        CHECK_RELATIVELY_CLOSE (1, FunctionWithSideEffects(), 0.1f);
+    }
+    CHECK_EQUAL(1, g_sideEffect);
+}
+
+TEST(CheckRelativelyCloseDoesNotHaveSideEffectsWhenFailing)
+{
+    g_sideEffect = 0;
+    {
+        UnitTest::TestResults testResults;
+		ScopedCurrentTest scopedResults(testResults);
+        CHECK_RELATIVELY_CLOSE (2, FunctionWithSideEffects(), 0.1f);
+    }
+    CHECK_EQUAL(1, g_sideEffect);
+}
+
 class ThrowingObject
 {
 public:
@@ -336,7 +447,6 @@
     }
 };
 
-
 TEST(CheckArrayCloseSucceedsOnEqual)
 {
     bool failure = true;
@@ -475,7 +585,144 @@
     CHECK(strstr(reporter.lastFailedMessage, "obj"));
 }
 
+TEST(CheckArrayRelativelyCloseSucceedsOnEqual)
+{
+    bool failure = true;
+    {
+        RecordingReporter reporter;
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+        const float data[4] = { 0, 1, 2, 3 };
+        CHECK_ARRAY_RELATIVELY_CLOSE (data, data, 4, 0.01f);
+        failure = (testResults.GetFailureCount() > 0);
+    }
 
+    CHECK(!failure);
+}
+
+TEST(CheckArrayRelativelyCloseFailsOnNotEqual)
+{
+    bool failure = false;
+    {
+        RecordingReporter reporter;
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		int const data1[4] = { 0, 1, 2, 3 };
+        int const data2[4] = { 0, 1, 3, 3 };
+		CHECK_ARRAY_RELATIVELY_CLOSE (data1, data2, 4, 0.01f);
+
+		failure = (testResults.GetFailureCount() > 0);
+    }
+
+    CHECK(failure);
+}
+
+TEST(CheckArrayRelativelyCloseFailureIncludesCheckExpectedAndActual)
+{
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		int const data1[4] = { 0, 1, 2, 3 };
+        int const data2[4] = { 0, 1, 3, 3 };
+        CHECK_ARRAY_RELATIVELY_CLOSE (data1, data2, 4, 0.01f);
+    }
+
+    CHECK(strstr(reporter.lastFailedMessage, "xpected [ 0 1 2 3 ]"));
+    CHECK(strstr(reporter.lastFailedMessage, "was [ 0 1 3 3 ]"));
+}
+
+TEST(CheckArrayRelativelyCloseFailureContainsCorrectDetails)
+{
+    int line = 0;
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		UnitTest::TestDetails testDetails("arrayRelativelyCloseTest", "arrayRelativelyCloseSuite", "filename", -1);
+		ScopedCurrentTest scopedResults(testResults, &testDetails);
+
+		int const data1[4] = { 0, 1, 2, 3 };
+        int const data2[4] = { 0, 1, 3, 3 };
+        CHECK_ARRAY_RELATIVELY_CLOSE (data1, data2, 4, 0.01f);     line = __LINE__;
+    }
+
+    CHECK_EQUAL("arrayRelativelyCloseTest", reporter.lastFailedTest);
+    CHECK_EQUAL("arrayRelativelyCloseSuite", reporter.lastFailedSuite);
+    CHECK_EQUAL("filename", reporter.lastFailedFile);
+    CHECK_EQUAL(line, reporter.lastFailedLine);
+}
+
+TEST(CheckArrayRelativelyCloseFailureBecauseOfExceptionContainsCorrectDetails)
+{
+    int line = 0;
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		UnitTest::TestDetails testDetails("arrayRelativelyCloseTest", "arrayRelativelyCloseSuite", "filename", -1);
+		ScopedCurrentTest scopedResults(testResults, &testDetails);
+
+		int const data[4] = { 0, 1, 2, 3 };
+        CHECK_ARRAY_RELATIVELY_CLOSE (data, ThrowingObject(), 4, 0.01f);     line = __LINE__;
+    }
+
+    CHECK_EQUAL("arrayRelativelyCloseTest", reporter.lastFailedTest);
+    CHECK_EQUAL("arrayRelativelyCloseSuite", reporter.lastFailedSuite);
+    CHECK_EQUAL("filename", reporter.lastFailedFile);
+    CHECK_EQUAL(line, reporter.lastFailedLine);
+}
+
+TEST(CheckArrayRelativelyCloseFailureIncludesTolerance)
+{
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		float const data1[4] = { 0, 1, 2, 3 };
+        float const data2[4] = { 0, 1, 3, 3 };
+        CHECK_ARRAY_RELATIVELY_CLOSE (data1, data2, 4, 0.01f);
+    }
+
+    CHECK(strstr(reporter.lastFailedMessage, "0.01"));
+}
+
+
+TEST(CheckArrayRelativelyCloseFailsOnException)
+{
+    bool failure = false;
+    {
+        RecordingReporter reporter;
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		const float data[4] = { 0, 1, 2, 3 };
+        ThrowingObject obj;
+        CHECK_ARRAY_RELATIVELY_CLOSE (data, obj, 3, 0.01f);
+
+		failure = (testResults.GetFailureCount() > 0);
+    }
+
+    CHECK(failure);
+}
+
+TEST(CheckArrayRelativelyCloseFailureOnExceptionIncludesCheckContents)
+{
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		const float data[4] = { 0, 1, 2, 3 };
+        ThrowingObject obj;
+        CHECK_ARRAY_RELATIVELY_CLOSE (data, obj, 3, 0.01f);
+    }
+
+    CHECK(strstr(reporter.lastFailedMessage, "data"));
+    CHECK(strstr(reporter.lastFailedMessage, "obj"));
+}
+
 TEST(CheckArrayEqualSuceedsOnEqual)
 {
     bool failure = true;
@@ -613,6 +860,33 @@
 	CHECK_EQUAL(1, g_sideEffect);
 }
 
+TEST(CheckArrayRelativelyCloseDoesNotHaveSideEffectsWhenPassing)
+{
+    g_sideEffect = 0;
+    {
+        UnitTest::TestResults testResults;
+		ScopedCurrentTest scopedResults(testResults);
+
+		const float data[] = { 0, 1, 2, 3 };
+        CHECK_ARRAY_RELATIVELY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f);
+    }
+    CHECK_EQUAL(1, g_sideEffect);
+}
+
+TEST(CheckArrayRelativelyCloseDoesNotHaveSideEffectsWhenFailing)
+{
+    g_sideEffect = 0;
+    {
+        UnitTest::TestResults testResults;
+		ScopedCurrentTest scopedResults(testResults);
+
+		const float data[] = { 0, 1, 3, 3 };
+        CHECK_ARRAY_RELATIVELY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f);
+    }
+
+	CHECK_EQUAL(1, g_sideEffect);
+}
+
 class ThrowingObject2D
 {
 public:
@@ -622,7 +896,6 @@
     }
 };
 
-
 TEST(CheckArray2DCloseSucceedsOnEqual)
 {
     bool failure = true;
@@ -763,6 +1036,146 @@
     CHECK(strstr(reporter.lastFailedMessage, "obj"));
 }
 
+TEST(CheckArray2DRelativelyCloseSucceedsOnEqual)
+{
+    bool failure = true;
+    {
+        RecordingReporter reporter;
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		const float data[2][2] = { {0, 1}, {2, 3} };
+        CHECK_ARRAY2D_RELATIVELY_CLOSE (data, data, 2, 2, 0.01f);
+
+		failure = (testResults.GetFailureCount() > 0);
+    }
+
+    CHECK(!failure);
+}
+
+TEST(CheckArray2DRelativelyCloseFailsOnNotEqual)
+{
+    bool failure = false;
+    {
+        RecordingReporter reporter;
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		int const data1[2][2] = { {0, 1}, {2, 3} };
+        int const data2[2][2] = { {0, 1}, {3, 3} };
+        CHECK_ARRAY2D_RELATIVELY_CLOSE (data1, data2, 2, 2, 0.01f);
+
+		failure = (testResults.GetFailureCount() > 0);
+    }
+
+    CHECK(failure);
+}
+
+TEST(CheckArray2DRelativelyCloseFailureIncludesCheckExpectedAndActual)
+{
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		int const data1[2][2] = { {0, 1}, {2, 3} };
+        int const data2[2][2] = { {0, 1}, {3, 3} };
+
+		CHECK_ARRAY2D_RELATIVELY_CLOSE (data1, data2, 2, 2, 0.01f);
+    }
+
+    CHECK(strstr(reporter.lastFailedMessage, "xpected [ [ 0 1 ] [ 2 3 ] ]"));
+    CHECK(strstr(reporter.lastFailedMessage, "was [ [ 0 1 ] [ 3 3 ] ]"));
+}
+
+TEST(CheckArray2DRelativelyCloseFailureContainsCorrectDetails)
+{
+    int line = 0;
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		UnitTest::TestDetails testDetails("array2DRelativelyCloseTest", "array2DRelativelyCloseSuite", "filename", -1);
+		ScopedCurrentTest scopedResults(testResults, &testDetails);
+
+		int const data1[2][2] = { {0, 1}, {2, 3} };
+        int const data2[2][2] = { {0, 1}, {3, 3} };
+		CHECK_ARRAY2D_RELATIVELY_CLOSE (data1, data2, 2, 2, 0.01f);     line = __LINE__;
+    }
+
+    CHECK_EQUAL("array2DRelativelyCloseTest", reporter.lastFailedTest);
+    CHECK_EQUAL("array2DRelativelyCloseSuite", reporter.lastFailedSuite);
+    CHECK_EQUAL("filename", reporter.lastFailedFile);
+    CHECK_EQUAL(line, reporter.lastFailedLine);
+}
+
+TEST(CheckArray2DRelativelyCloseFailureBecauseOfExceptionContainsCorrectDetails)
+{
+    int line = 0;
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		UnitTest::TestDetails testDetails("array2DRelativelyCloseTest", "array2DRelativelyCloseSuite", "filename", -1);
+		ScopedCurrentTest scopedResults(testResults, &testDetails);
+
+		const float data[2][2] = { {0, 1}, {2, 3} };
+        CHECK_ARRAY2D_RELATIVELY_CLOSE (data, ThrowingObject2D(), 2, 2, 0.01f);   line = __LINE__;
+    }
+
+    CHECK_EQUAL("array2DRelativelyCloseTest", reporter.lastFailedTest);
+    CHECK_EQUAL("array2DRelativelyCloseSuite", reporter.lastFailedSuite);
+    CHECK_EQUAL("filename", reporter.lastFailedFile);
+    CHECK_EQUAL(line, reporter.lastFailedLine);
+}
+
+TEST(CheckArray2DRelativelyCloseFailureIncludesTolerance)
+{
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		float const data1[2][2] = { {0, 1}, {2, 3} };
+        float const data2[2][2] = { {0, 1}, {3, 3} };
+        CHECK_ARRAY2D_RELATIVELY_CLOSE (data1, data2, 2, 2, 0.01f);
+    }
+
+    CHECK(strstr(reporter.lastFailedMessage, "0.01"));
+}
+
+TEST(CheckArray2DRelativelyCloseFailsOnException)
+{
+    bool failure = false;
+    {
+        RecordingReporter reporter;
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		const float data[2][2] = { {0, 1}, {2, 3} };
+        ThrowingObject2D obj;
+        CHECK_ARRAY2D_RELATIVELY_CLOSE (data, obj, 2, 2, 0.01f);
+
+		failure = (testResults.GetFailureCount() > 0);
+    }
+
+    CHECK(failure);
+}
+
+TEST(CheckArray2DRelativelyCloseFailureOnExceptionIncludesCheckContents)
+{
+    RecordingReporter reporter;
+    {
+        UnitTest::TestResults testResults(&reporter);
+		ScopedCurrentTest scopedResults(testResults);
+
+		const float data[2][2] = { {0, 1}, {2, 3} };
+        ThrowingObject2D obj;
+        CHECK_ARRAY2D_RELATIVELY_CLOSE (data, obj, 2, 2, 0.01f);
+    }
+
+    CHECK(strstr(reporter.lastFailedMessage, "data"));
+    CHECK(strstr(reporter.lastFailedMessage, "obj"));
+}
+
 float const* const* FunctionWithSideEffects3()
 {
     ++g_sideEffect;
@@ -798,4 +1211,30 @@
     CHECK_EQUAL(1, g_sideEffect);
 }
 
+TEST(CheckArrayRelatively2DCloseDoesNotHaveSideEffectsWhenPassing)
+{
+    g_sideEffect = 0;
+    {
+        UnitTest::TestResults testResults;
+		ScopedCurrentTest scopedResults(testResults);
+
+		const float data[2][2] = { {0, 1}, {2, 3} };
+        CHECK_ARRAY2D_RELATIVELY_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f);
+    }
+    CHECK_EQUAL(1, g_sideEffect);
 }
+
+TEST(CheckArray2DRelativelyCloseDoesNotHaveSideEffectsWhenFailing)
+{
+    g_sideEffect = 0;
+    {
+        UnitTest::TestResults testResults;
+		ScopedCurrentTest scopedResults(testResults);
+
+		const float data[2][2] = { {0, 1}, {3, 3} };
+        CHECK_ARRAY2D_RELATIVELY_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f);
+    }
+    CHECK_EQUAL(1, g_sideEffect);
+}
+
+}
Index: src/CheckMacros.h
===================================================================
--- src/CheckMacros.h	(revision 207)
+++ src/CheckMacros.h	(working copy)
@@ -19,6 +19,10 @@
 	#error UnitTest++ redefines CHECK_CLOSE
 #endif
 
+#ifdef CHECK_RELATIVELY_CLOSE
+	#error UnitTest++ redefines CHECK_CLOSE
+#endif
+
 #ifdef CHECK_ARRAY_EQUAL
 	#error UnitTest++ redefines CHECK_ARRAY_EQUAL
 #endif
@@ -27,10 +31,18 @@
 	#error UnitTest++ redefines CHECK_ARRAY_CLOSE
 #endif
 
+#ifdef CHECK_ARRAY_RELATIVELY_CLOSE
+	#error UnitTest++ redefines CHECK_ARRAY_CLOSE
+#endif
+
 #ifdef CHECK_ARRAY2D_CLOSE
 	#error UnitTest++ redefines CHECK_ARRAY2D_CLOSE
 #endif
 
+#ifdef CHECK_ARRAY2D_RELATIVELY_CLOSE
+	#error UnitTest++ redefines CHECK_ARRAY2D_CLOSE
+#endif
+
 #define CHECK(value) \
     do \
     { \
@@ -68,6 +80,18 @@
         } \
     } while (0)
 
+#define CHECK_RELATIVELY_CLOSE(expected, actual, tolerance) \
+    do \
+    { \
+        try { \
+            UnitTest::CheckRelativelyClose(*UnitTest::CurrentTest::Results(), expected, actual, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
+        } \
+        catch (...) { \
+            UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
+                    "Unhandled exception in CHECK_CLOSE(" #expected ", " #actual ")"); \
+        } \
+    } while (0)
+
 #define CHECK_ARRAY_EQUAL(expected, actual, count) \
     do \
     { \
@@ -92,6 +116,18 @@
         } \
     } while (0)
 
+#define CHECK_ARRAY_RELATIVELY_CLOSE(expected, actual, count, tolerance) \
+    do \
+    { \
+        try { \
+            UnitTest::CheckArrayRelativelyClose(*UnitTest::CurrentTest::Results(), expected, actual, count, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
+        } \
+        catch (...) { \
+            UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
+                    "Unhandled exception in CHECK_ARRAY_CLOSE(" #expected ", " #actual ")"); \
+        } \
+    } while (0)
+
 #define CHECK_ARRAY2D_CLOSE(expected, actual, rows, columns, tolerance) \
     do \
     { \
@@ -104,6 +140,17 @@
         } \
     } while (0)
 
+#define CHECK_ARRAY2D_RELATIVELY_CLOSE(expected, actual, rows, columns, tolerance) \
+    do \
+    { \
+        try { \
+            UnitTest::CheckArray2DRelativelyClose(*UnitTest::CurrentTest::Results(), expected, actual, rows, columns, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
+        } \
+        catch (...) { \
+            UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
+                    "Unhandled exception in CHECK_ARRAY_CLOSE(" #expected ", " #actual ")"); \
+        } \
+    } while (0)
 
 #define CHECK_THROW(expression, ExpectedExceptionType) \
     do \
------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
unittest-cpp-devel mailing list
unittest-cpp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/unittest-cpp-devel

Reply via email to