Commits

Matt Oswald committed 741a5db

implemented non-fatal errors: Check.<whatever>

Comments (0)

Files changed (34)

Tests/BareTests/BareTest.cpp

 // FilteredTestsRunner has a tendency to not get linked into the test dlls.
 // This is the simplest valid test library possible, and is intended to ensure
 // this error does not happen in the future.
-//
+
 FACT(BareTest)
 {
 }

Tests/UnitTests/Assert.Contains.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertContains)
 {

Tests/UnitTests/Assert.DoesNotContain.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertDoesNotContain)
 {

Tests/UnitTests/Assert.DoesNotThrow.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertDoesNotThrow)
 {

Tests/UnitTests/Assert.Empty.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 namespace
 {

Tests/UnitTests/Assert.Equal.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertEqual)
 {

Tests/UnitTests/Assert.Fail.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertFail)
 {

Tests/UnitTests/Assert.False.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertFalse)
 {

Tests/UnitTests/Assert.InRange.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertInRange)
 {

Tests/UnitTests/Assert.NotEqual.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertNotEqual)
 {

Tests/UnitTests/Assert.NotInRange.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertNotInRange)
 {

Tests/UnitTests/Assert.NotNull.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertNotNull)
 {

Tests/UnitTests/Assert.NotSame.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertNotSame)
 {

Tests/UnitTests/Assert.Null.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertNull)
 {

Tests/UnitTests/Assert.Same.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertSame)
 {

Tests/UnitTests/Assert.Throws.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertThrows)
 {

Tests/UnitTests/Assert.True.cpp

 #include "xUnit++/xUnit++.h"
 
 using xUnitpp::xUnitAssert;
-using xUnitpp::Assert;
 
 SUITE(AssertTrue)
 {

Tests/UnitTests/Attributes.cpp

 #include "xUnit++/xUnitTestRunner.h"
 #include "xUnit++/xUnit++.h"
 
-using xUnitpp::Assert;
 
 SUITE(Attributes)
 {
     attributes.insert(std::make_pair("Skip", "Testing skip."));
 
     xUnitpp::TestCollection collection;
-    xUnitpp::TestCollection::Register reg(collection, []() { SkippedTest().RunTest(); }, "SkippedTest", "Attributes", attributes, -1, __FILE__, __LINE__);
+    xUnitpp::Check check;
+    xUnitpp::TestCollection::Register reg(collection, []() { SkippedTest().RunTest(); },
+        "SkippedTest", "Attributes", attributes, -1, __FILE__, __LINE__, check);
 
     xUnitpp::TestRunner local(emptyReporter);
     local.RunTests([](const xUnitpp::TestDetails &) { return true; },

Tests/UnitTests/LineInfo.cpp

 #include "xUnit++/IOutput.h"
 #include "xUnit++/xUnit++.h"
 
-using xUnitpp::Assert;
 
 SUITE(LineInfo)
 {
 
     xUnitpp::AttributeCollection attributes;
     xUnitpp::TestCollection collection;
-    xUnitpp::TestCollection::Register reg(collection, test, "LineInfoOverridesDefaultTestLineInfo", "LineInfo", attributes, -1, __FILE__, __LINE__);
+    xUnitpp::Check localCheck;
+    xUnitpp::TestCollection::Register reg(collection, test,
+        "LineInfoOverridesDefaultTestLineInfo", "LineInfo", attributes,
+        -1, __FILE__, __LINE__, localCheck);
 
 
 }

Tests/UnitTests/Theory.cpp

 #include "xUnit++/xUnitTime.h"
 #include "xUnit++/xUnit++.h"
 
-using xUnitpp::Assert;
 
 SUITE(Theory)
 {
 
 void TheoryUnderTest(int x)
 {
-    Assert.True(x == 0 || x == 1);
+    xUnitpp::Assert.True(x == 0 || x == 1);
 }
 
 struct TheoryFixture
     template<typename TTheoryData>
     void Register(const std::string &name, TTheoryData &&theoryData)
     {
-        xUnitpp::TestCollection::Register reg(collection, &TheoryUnderTest, theoryData, name, "Theory", attributes, -1, __FILE__, __LINE__);
+        xUnitpp::TestCollection::Register reg(collection, &TheoryUnderTest, theoryData,
+            name, "Theory", attributes, -1, __FILE__, __LINE__, localCheck);
     }
 
     void Run()
     xUnitpp::AttributeCollection attributes;
     xUnitpp::TestCollection collection;
     xUnitpp::TestRunner localRunner;
+    xUnitpp::Check localCheck;
 };
 
 std::vector<std::tuple<int>> RawFunctionProvider()
     dataProvided.reserve(5);
 
     auto doTheory = [&](int x) { dataProvided.push_back(x); };
-    xUnitpp::TestCollection::Register reg(collection, doTheory, RawFunctionProvider, "TheoriesGetAllDataPassedToThem", "Theory", attributes, -1, __FILE__, __LINE__);
+    xUnitpp::TestCollection::Register reg(collection, doTheory, RawFunctionProvider,
+        "TheoriesGetAllDataPassedToThem", "Theory", attributes, -1, __FILE__, __LINE__, localCheck);
 
     Run();
 
 
     auto doTheory = [](int) { Assert.Fail() << "Should not be run."; };
 
-    xUnitpp::TestCollection::Register reg(collection, doTheory, RawFunctionProvider, "TheoriesGetAllDataPassedToThem", "Theory", attributes, -1, __FILE__, __LINE__);
+    xUnitpp::TestCollection::Register reg(collection, doTheory, RawFunctionProvider,
+        "TheoriesGetAllDataPassedToThem", "Theory", attributes, -1, __FILE__, __LINE__, localCheck);
 
     Run();
 }
 
 Stretch
 -----
-non-fatal asserts
-would be nice to have some logging support (Log::Information("msg"))
+would be nice to have some logging support (Log::Information("msg")) (see how Check was implemented)
 msbuild test runner
 GUI runner (windows only, or go QT?)
 custom xUnitAsserts per assert (revisit unit tests at that point)

xUnit++/src/TestCollection.cpp

 }
 
 TestCollection::Register::Register(TestCollection &collection, const std::function<void()> &fn, const std::string &name, const std::string &suite,
-                                   const AttributeCollection &attributes, int milliseconds, const std::string &filename, int line)
+                                   const AttributeCollection &attributes, int milliseconds, const std::string &filename, int line, const Check &check)
 {
-    collection.mTests.emplace_back(xUnitTest(fn, name, suite, attributes, Time::ToDuration(std::chrono::milliseconds(milliseconds)), filename, line));
+    collection.mTests.emplace_back(xUnitTest(fn, name, suite, attributes, Time::ToDuration(std::chrono::milliseconds(milliseconds)), filename, line, check));
 }
 
 const std::vector<xUnitTest> &TestCollection::Tests()

xUnit++/src/xUnitAssert.cpp

     std::string AssembleWhat(const std::string &call, const std::vector<std::string> &userMsg, const std::string &customMsg,
                              const std::string &expected, const std::string &actual)
     {
-        std::string msg = "Assert." + call + "() failure";
+        std::string msg = call + "() failure";
         if (!userMsg.empty())
         {
             msg += ": ";
 
 xUnitAssert::xUnitAssert(const std::string &call, const xUnitpp::LineInfo &lineInfo)
     : lineInfo(lineInfo)
-    , call(call + "() failure")
+    , call(call)
 {
 }
 
 }
 
 xUnitFailure::xUnitFailure()
-    : assert(xUnitAssert::None())
+    : OnFailureComplete([](const xUnitAssert &){})
+    , assert(xUnitAssert::None())
     , refCount(*(new int(0)))
-    , failed(false)
 {
 }
 
-xUnitFailure::xUnitFailure(xUnitAssert assert)
-    : assert(assert)
+xUnitFailure::xUnitFailure(xUnitAssert assert, std::function<void(const xUnitAssert &)> onFailureComplete)
+    : OnFailureComplete(onFailureComplete)
+    , assert(assert)
     , refCount(*(new int(1)))
-    , failed(true)
 {
 }
 
 xUnitFailure::xUnitFailure(const xUnitFailure &other)
-    : assert(other.assert)
+    : OnFailureComplete(other.OnFailureComplete)
+    , assert(other.assert)
     , refCount(other.refCount)
-    , failed(other.failed)
 {
     refCount++;
 }
     {
         delete &refCount;
 
-        if (failed)
-        {
-            throw assert;
-        }
+        // http://cpp-next.com/archive/2012/08/evil-or-just-misunderstood/
+        // http://akrzemi1.wordpress.com/2011/09/21/destructors-that-throw/
+        // throwing destructors aren't Evil, just misunderstood
+        OnFailureComplete(assert);
     } 
 }
 
     return OnSuccess();
 }
 
+Assert::Assert(const std::string &callPrefix, std::function<xUnitFailure(xUnitAssert)> onFailure)
+    : callPrefix(callPrefix)
+    , OnFailure(onFailure)
+{
 }
+
+}

xUnit++/src/xUnitCheck.cpp

+#include "xUnitCheck.h"
+
+namespace xUnitpp
+{
+
+Check::Check()
+    : Assert("Check.",
+        [&](xUnitAssert assert)
+        {
+            return xUnitFailure(assert,
+                [&](const xUnitAssert &assert)
+                {
+                    failedChecks.emplace_back(assert);
+                });
+        })
+{
+}
+
+const std::vector<xUnitAssert> &Check::Failures() const
+{
+    return failedChecks;
+}
+
+}

xUnit++/src/xUnitTest.cpp

 #include "xUnitTest.h"
+#include "xUnitCheck.h"
 
 namespace xUnitpp
 {
 
 xUnitTest::xUnitTest(std::function<void()> test, const std::string &name, const std::string &suite,
                      const AttributeCollection &attributes, Time::Duration timeLimit,
-                     const std::string &filename, int line)
+                     const std::string &filename, int line, const Check &check)
     : mTest(test)
     , mTestDetails(name, suite, attributes, timeLimit, filename, line)
+    , mCheck(std::cref(check))
 {
 }
 
 xUnitTest::xUnitTest(const xUnitTest &other)
     : mTest(other.mTest)
     , mTestDetails(other.mTestDetails)
+    , mCheck(other.mCheck)
 {
 }
 
 xUnitTest::xUnitTest(xUnitTest &&other)
+    : mCheck(other.mCheck)
 {
     swap(*this, other);
 }
 
     swap(a.mTest, b.mTest);
     swap(a.mTestDetails, b.mTestDetails);
+    swap(a.mCheck, b.mCheck);
 }
 
 const TestDetails &xUnitTest::TestDetails() const
     return mTest();
 }
 
+const std::vector<xUnitAssert> &xUnitTest::NonFatalFailures() const
+{
+    return mCheck.get().Failures();
 }
+
+}

xUnit++/src/xUnitTestRunner.cpp

 
                 auto actualTest = [&](bool reportEnd) -> Time::TimeStamp
                     {
+                        bool failed = false;
                         Time::TimeStamp testStart;
+
+                        auto CheckNonFatalErrors = [&]()
+                        {
+                            if (!failed && !test.NonFatalFailures().empty())
+                            {
+                                failed = true;
+                                for (const auto &assert : test.NonFatalFailures())
+                                {
+                                    mImpl->OnTestFailure(test.TestDetails(), assert.what(), assert.LineInfo());
+                                }
+                            }
+                        };
+                        
                         try
                         {
                             mImpl->OnTestStart(test.TestDetails());
                         }
                         catch (const xUnitAssert &e)
                         {
+                            CheckNonFatalErrors();
                             mImpl->OnTestFailure(test.TestDetails(), e.what(), e.LineInfo());
-                            ++failedTests;
+                            failed = true;
                         }
                         catch (const std::exception &e)
                         {
+                            CheckNonFatalErrors();
                             mImpl->OnTestFailure(test.TestDetails(), e.what(), LineInfo::empty());
-                            ++failedTests;
+                            failed = true;
                         }
                         catch (...)
                         {
+                            CheckNonFatalErrors();
                             mImpl->OnTestFailure(test.TestDetails(), "Unknown exception caught: test has crashed", LineInfo::empty());
+                            failed = true;
+                        }
+
+                        CheckNonFatalErrors();
+
+                        if (failed)
+                        {
                             ++failedTests;
                         }
 

xUnit++/xUnit++.vcxproj

     <ClCompile Include="src/xUnitAssert.cpp" />
     <ClCompile Include="src/xUnitTest.cpp" />
     <ClCompile Include="src/xUnitTestRunner.cpp" />
+    <ClCompile Include="src\xUnitCheck.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="xUnit++/Attributes.h" />
     <ClInclude Include="xUnit++/xUnitTest.h" />
     <ClInclude Include="xUnit++/xUnitTestRunner.h" />
     <ClInclude Include="xUnit++/xUnitTime.h" />
+    <ClInclude Include="xUnit++\xUnitCheck.h" />
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VSVersion)' == '' and '$(VisualStudioVersion)' == ''">$(VCTargetsPath11)</VCTargetsPath>

xUnit++/xUnit++.vcxproj.filters

     <ClCompile Include="src/LineInfo.cpp" />
     <ClCompile Include="src/xUnitTest.cpp" />
     <ClCompile Include="src/IOutput.cpp" />
+    <ClCompile Include="src\xUnitCheck.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="xUnit++/xUnitAssert.h" />
     <ClInclude Include="xUnit++/LineInfo.h" />
     <ClInclude Include="xUnit++/xUnitTest.h" />
     <ClInclude Include="xUnit++/xUnitMacros.h" />
+    <ClInclude Include="xUnit++\xUnitCheck.h" />
   </ItemGroup>
 </Project>

xUnit++/xUnit++/TestCollection.h

     return [=]() { return data; };
 }
 
+class Check;
+
 class TestCollection
 {
     friend class Register;
 
     public:
         Register(TestCollection &collection, const std::function<void()> &fn, const std::string &name, const std::string &suite,
-            const AttributeCollection &attributes, int milliseconds, const std::string &filename, int line);
+            const AttributeCollection &attributes, int milliseconds, const std::string &filename, int line, const Check &check);
 
         template<typename TTheory, typename TTheoryData>
         Register(TestCollection &collection, TTheory theory, TTheoryData theoryData, const std::string &name, const std::string &suite,
-            const AttributeCollection &attributes, int milliseconds, const std::string &filename, int line)
+            const AttributeCollection &attributes, int milliseconds, const std::string &filename, int line, const Check &check)
         {
             int id = 1;
             for (auto t : theoryData())
                 auto theoryName = name + "(" + std::to_string(id++) + ")";
 
                 collection.mTests.emplace_back(xUnitTest(TheoryHelper(theory, std::move(t)), theoryName, suite,
-                        attributes, Time::ToDuration(std::chrono::milliseconds(milliseconds)), filename, line));
+                        attributes, Time::ToDuration(std::chrono::milliseconds(milliseconds)), filename, line, check));
             }
         }
     };

xUnit++/xUnit++/TestDetails.h

 #define TESTDETAILS_H_
 
 #include <chrono>
+#include <functional>
 #include <map>
 #include <string>
 #include <tuple>
+#include <vector>
 #include "xUnitTime.h"
 
 namespace xUnitpp
 {
 
+class xUnitAssert;
 typedef std::multimap<std::string, std::string> AttributeCollection;
 
 struct TestDetails

xUnit++/xUnit++/xUnitAssert.h

 #ifndef XUNITASSERT_H_
 #define XUNITASSERT_H_
 
+#if defined(_MSC_VER)
+#define _ALLOW_KEYWORD_MACROS
+#define noexcept(x)
+#endif
+
 #include <algorithm>
 #include <exception>
 #include <functional>
     xUnitFailure();
 
 public:
-    xUnitFailure(xUnitAssert assert);
+    xUnitFailure(xUnitAssert assert, std::function<void(const xUnitAssert &)> onFailureComplete);
     xUnitFailure(const xUnitFailure &other);
-    ~xUnitFailure();
+    ~xUnitFailure() noexcept(false);
 
     static xUnitFailure None();
 
     template<typename T>
     xUnitFailure &operator <<(const T &value)
     {
-        if (failed)
-        {
-            assert.AppendUserMessage(value);
-        }
-
+        assert.AppendUserMessage(value);
         return *this;
     }
 
 private:
     xUnitFailure &operator =(xUnitFailure other);
 
-protected:
+private:
+    std::function<void(const xUnitAssert &)> OnFailureComplete;
+
     xUnitAssert assert;
     int &refCount;
-    bool failed;
 };
 
 class Assert
         return OnSuccess();
     }
 
-    Assert(const std::string &callPrefix = "Assert.")
-        : callPrefix(callPrefix)
-        , OnFailure([](xUnitAssert assert) { return xUnitFailure(assert); })
-    {
-    }
+    Assert(const std::string &callPrefix = "Assert.",
+           std::function<xUnitFailure(xUnitAssert)> onFailure = [](xUnitAssert assert) { return xUnitFailure(assert, [](const xUnitAssert &assert) { throw assert; }); });
 };
 
 const class : public Assert

xUnit++/xUnit++/xUnitCheck.h

+#ifndef XUNITCHECK_H_
+#define XUNITCHECK_H_
+
+#include "xUnitAssert.h"
+
+namespace xUnitpp
+{
+
+class Check : public Assert
+{
+    friend class xUnitTest;
+
+public:
+    Check();
+
+private:
+    const std::vector<xUnitAssert> &Failures() const;
+
+private:
+    std::vector<xUnitAssert> failedChecks;
+};
+
+}
+
+#endif

xUnit++/xUnit++/xUnitMacros.h

 #include "TestCollection.h"
 #include "TestDetails.h"
 #include "Suite.h"
+#include "xUnitCheck.h"
 #include "xUnitMacroHelpers.h"
 
 #define ATTRIBUTES(TestName, ...) \
 
 #define TIMED_FACT_FIXTURE(FactName, FixtureType, timeout) \
     namespace FactName ## _ns { \
+        using xUnitpp::Assert; \
+        xUnitpp::Check Check; \
         class FactName ## _Fixture : public FixtureType \
         { \
         public: \
             void FactName(); \
         }; \
         void FactName ## _runner() { FactName ## _Fixture().FactName(); } \
-        xUnitpp::TestCollection::Register reg(xUnitpp::TestCollection::Instance(), &FactName ## _runner, #FactName, xUnitSuite::Name(), xUnitAttributes::Attributes(), timeout, __FILE__, __LINE__); \
+        xUnitpp::TestCollection::Register reg(xUnitpp::TestCollection::Instance(), \
+            &FactName ## _runner, #FactName, xUnitSuite::Name(), \
+            xUnitAttributes::Attributes(), timeout, __FILE__, __LINE__, Check); \
     } \
     void FactName ## _ns::FactName ## _Fixture::FactName()
 
 
 #define TIMED_DATA_THEORY(TheoryName, params, DataProvider, timeout) \
     namespace TheoryName ## _ns { \
+        using xUnitpp::Assert; \
+        xUnitpp::Check Check; \
         void TheoryName params; \
-        xUnitpp::TestCollection::Register reg(xUnitpp::TestCollection::Instance(), TheoryName, DataProvider, #TheoryName, xUnitSuite::Name(), xUnitAttributes::Attributes(), timeout, __FILE__, __LINE__); \
+        xUnitpp::TestCollection::Register reg(xUnitpp::TestCollection::Instance(), \
+            TheoryName, DataProvider, #TheoryName, xUnitSuite::Name(), \
+            xUnitAttributes::Attributes(), timeout, __FILE__, __LINE__, Check); \
     } \
     void TheoryName ## _ns::TheoryName params
 
 
 #define TIMED_THEORY(TheoryName, params, timeout, ...) \
     namespace TheoryName ## _ns { \
+        using xUnitpp::Assert; \
+        xUnitpp::Check Check; \
         void TheoryName params; \
         decltype(FIRST_ARG(__VA_ARGS__)) args[] = { __VA_ARGS__ }; \
-        xUnitpp::TestCollection::Register reg(xUnitpp::TestCollection::Instance(), TheoryName, xUnitpp::TheoryData(PP_NARGS(__VA_ARGS__), args), #TheoryName, xUnitSuite::Name(), xUnitAttributes::Attributes(), timeout, __FILE__, __LINE__); \
+        xUnitpp::TestCollection::Register reg(xUnitpp::TestCollection::Instance(), \
+            TheoryName, xUnitpp::TheoryData(PP_NARGS(__VA_ARGS__), args), #TheoryName, \
+            xUnitSuite::Name(), xUnitAttributes::Attributes(), timeout, __FILE__, __LINE__, Check); \
     } \
     void TheoryName ## _ns::TheoryName params
 

xUnit++/xUnit++/xUnitTest.h

 #include <functional>
 #include <string>
 #include "TestDetails.h"
+#include "xUnitCheck.h"
 
 namespace xUnitpp
 {
 public:
     xUnitTest(std::function<void()> test, const std::string &name, const std::string &suite,
         const AttributeCollection &attributes, Time::Duration timeLimit,
-        const std::string &filename, int line);
+        const std::string &filename, int line, const Check &check);
     xUnitTest(const xUnitTest &other);
     xUnitTest(xUnitTest &&other);
     xUnitTest &operator =(xUnitTest other);
 
     void Run();
 
+    const std::vector<xUnitAssert> &NonFatalFailures() const;
+
 private:
     std::function<void()> mTest;
     xUnitpp::TestDetails mTestDetails;
+    std::reference_wrapper<const Check> mCheck;
 };
 
 }
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.