Matt Oswald avatar Matt Oswald committed ded393f

adding unit tests - Assert.Equal tests added
minor fixes for Assert.Equal overloads to make them easier to use
renamed TestRunner.h/cpp to xUnitTestRunner.h/cpp

Comments (0)

Files changed (13)

 see VS2012's implementation of method attributes
 support wstring
 consider doing LINEINFO the way VS2012 does
-unit test the lib
+unit test the lib - started
+custom xUnitAsserts per assert (revisit unit tests at that point)
 xml output

xUnit++/TestRunner.cpp

-#include "TestRunner.h"
-#include <atomic>
-#include <future>
-#include <limits>
-#include <mutex>
-#include <random>
-#include <vector>
-#include "DefaultReporter.h"
-#include "Fact.h"
-#include "TestCollection.h"
-#include "TestDetails.h"
-#include "xUnitAssert.h"
-
-namespace
-{
-
-class ActiveTests
-{
-public:
-    struct TestInstance
-    {
-        TestInstance(const xUnitpp::TestDetails &testDetails, int id, int groupId, int groupSize, std::function<void()> test)
-            : testDetails(testDetails)
-            , id(id)
-            , dataIndex(-1)
-            , groupId(groupId)
-            , groupSize(groupSize)
-            , test(test)
-        {
-        }
-
-        TestInstance(const xUnitpp::TestDetails &testDetails, int id, int dataIndex, int groupId, int groupSize, std::function<void()> test)
-            : testDetails(testDetails)
-            , id(id)
-            , dataIndex(dataIndex)
-            , groupId(groupId)
-            , groupSize(groupSize)
-            , test(test)
-        {
-        }
-
-        TestInstance(const TestInstance &other)
-            : testDetails(other.testDetails)
-            , id(other.id)
-            , dataIndex(other.dataIndex)
-            , groupId(other.groupId)
-            , groupSize(other.groupSize)
-            , test(other.test)
-        {
-        }
-
-        TestInstance(TestInstance &&other)
-        {
-            swap(*this, other);
-        }
-
-        TestInstance &operator =(TestInstance other)
-        {
-            swap(*this, other);
-            return *this;
-        }
-
-        friend void swap(TestInstance &ti0, TestInstance &ti1)
-        {
-            using std::swap;
-
-            swap(ti0.testDetails, ti1.testDetails);
-            swap(ti0.id, ti1.id);
-            swap(ti0.dataIndex, ti1.dataIndex);
-            swap(ti0.groupId, ti1.groupId);
-            swap(ti0.groupSize, ti1.groupSize);
-            swap(ti0.test, ti1.test);
-        }
-
-        xUnitpp::TestDetails testDetails;
-
-        size_t id;
-        size_t dataIndex;
-        size_t groupId;
-        size_t groupSize;
-
-        std::function<void()> test;
-    };
-
-    ActiveTests(const std::vector<xUnitpp::Fact> &facts, const std::vector<xUnitpp::Theory> &theories, const std::string &suite)
-    {
-        size_t id = 0;
-        size_t groupId = 0;
-
-        for (auto &fact : facts)
-        {
-            if (suite == "" || fact.TestDetails().Suite == suite)
-            {
-                mTests.emplace_back(TestInstance(fact.TestDetails(), ++id, ++groupId, 1, fact.Test()));
-            }
-        }
-
-        for (auto &theorySet : theories)
-        {
-            if (suite == "" || theorySet.TestDetails().Suite == suite)
-            {
-                ++groupId;
-                size_t dataIndex = 0;
-                for (auto &theory : theorySet.Theories())
-                {
-                    mTests.emplace_back(TestInstance(theorySet.TestDetails(), ++id, dataIndex++, groupId, theorySet.Theories().size(), theory));
-                }
-            }
-        }
-
-        std::shuffle(mTests.begin(), mTests.end(), std::default_random_engine(std::random_device()()));
-    }
-
-    std::vector<TestInstance>::iterator begin()
-    {
-        return mTests.begin();
-    }
-
-    std::vector<TestInstance>::iterator end()
-    {
-        return mTests.end();
-    }
-
-private:
-    std::vector<TestInstance> mTests;
-};
-
-}
-
-namespace xUnitpp
-{
-
-class TestRunner::Impl
-{
-public:
-    Impl(std::function<void(const TestDetails &, int)> onTestStart,
-         std::function<void(const TestDetails &, int, const std::string &)> onTestFailure,
-         std::function<void(const TestDetails &, int, std::chrono::milliseconds)> onTestFinish,
-         std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete)
-        : mOnTestStart(onTestStart)
-        , mOnTestFailure(onTestFailure)
-        , mOnTestFinish(onTestFinish)
-        , mOnAllTestsComplete(onAllTestsComplete)
-    {
-    }
-
-    void OnTestStart(const TestDetails &details, int dataIndex)
-    {
-        std::lock_guard<std::mutex> guard(mStartMtx);
-        mOnTestStart(details, dataIndex);
-    }
-
-    void OnTestFailure(const TestDetails &details, int dataIndex, const std::string &message)
-    {
-        std::lock_guard<std::mutex> guard(mFailureMtx);
-        mOnTestFailure(details, dataIndex, message);
-    }
-
-    void OnTestFinish(const TestDetails &details, int dataIndex, std::chrono::milliseconds time)
-    {
-        std::lock_guard<std::mutex> guard(mFinishMtx);
-        mOnTestFinish(details, dataIndex, time);
-    }
-
-
-    void OnAllTestsComplete(int total, int skipped, int failed, std::chrono::milliseconds totalTime)
-    {
-        mOnAllTestsComplete(total, skipped, failed, totalTime);
-    }
-
-private:
-    std::function<void(const TestDetails &, int)> mOnTestStart;
-    std::function<void(const TestDetails &, int, const std::string &)> mOnTestFailure;
-    std::function<void(const TestDetails &, int, std::chrono::milliseconds)> mOnTestFinish;
-    std::function<void(int, int, int, std::chrono::milliseconds)> mOnAllTestsComplete;
-
-    std::mutex mStartMtx;
-    std::mutex mFailureMtx;
-    std::mutex mFinishMtx;
-};
-
-size_t RunAllTests(const std::string &suite)
-{
-    return RunAllTests(suite, std::chrono::milliseconds::zero());
-}
-
-size_t RunAllTests(std::chrono::milliseconds maxTestRunTime)
-{
-    return RunAllTests("", maxTestRunTime);
-}
-
-size_t RunAllTests(const std::string &suite, std::chrono::milliseconds maxTestRunTime, size_t maxConcurrent)
-{
-    return
-        TestRunner(&DefaultReporter::ReportStart,
-                   &DefaultReporter::ReportFailure,
-                   &DefaultReporter::ReportFinish,
-                   &DefaultReporter::ReportAllTestsComplete)
-            .RunTests(TestCollection::Facts(), TestCollection::Theories(), suite, maxTestRunTime, maxConcurrent);
-}
-
-TestRunner::TestRunner(std::function<void(const TestDetails &, int)> onTestStart,
-                       std::function<void(const TestDetails &, int, const std::string &)> onTestFailure,
-                       std::function<void(const TestDetails &, int, std::chrono::milliseconds)> onTestFinish,
-                       std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete)
-    : mImpl(new Impl(onTestStart, onTestFailure, onTestFinish, onAllTestsComplete))
-{
-}
-
-size_t TestRunner::RunTests(const std::vector<Fact> &facts, const std::vector<Theory> &theories, const std::string &suite, std::chrono::milliseconds maxTestRunTime, size_t maxConcurrent)
-{
-    auto timeStart = std::chrono::system_clock::now();
-
-    ActiveTests activeTests(facts, theories, suite);
-
-    if (maxConcurrent == 0)
-    {
-        maxConcurrent = std::numeric_limits<decltype(maxConcurrent)>::max();
-    }
-
-    class ThreadCounter
-    {
-    public:
-        ThreadCounter(size_t maxThreads)
-            : maxThreads(maxThreads)
-            , activeThreads(0)
-        {
-        }
-
-        void operator++()
-        {
-            std::unique_lock<std::mutex> lock(mtx);
-            condition.wait(lock, [&]() { return activeThreads < maxThreads; });
-
-            ++activeThreads;
-        }
-
-        void operator--()
-        {
-            std::lock_guard<std::mutex> guard(mtx);
-            --activeThreads;
-        }
-
-    private:
-        size_t maxThreads;
-        size_t activeThreads;
-        std::mutex mtx;
-        std::condition_variable condition;
-    } threadCounter(maxConcurrent);
-
-    std::atomic<int> failedTests = 0;
-
-    std::vector<std::future<void>> futures;
-    for (auto &test : activeTests)
-    {
-        futures.push_back(std::async([&]()
-            {
-                struct CounterGuard
-                {
-                    CounterGuard(ThreadCounter &tc)
-                        : tc(tc)
-                    {
-                        ++tc;
-                    }
-
-                    ~CounterGuard()
-                    {
-                        --tc;
-                    }
-
-                private:
-                    ThreadCounter &tc;
-                } counterGuard(threadCounter);
-
-                auto actualTest = [&](bool reportEnd) -> TimeStamp
-                    {
-                        TimeStamp testStart;
-                        try
-                        {
-                            mImpl->OnTestStart(test.testDetails, test.dataIndex);
-
-                            testStart = Clock::now();
-                            test.test();
-                        }
-                        catch (std::exception &e)
-                        {
-                            mImpl->OnTestFailure(test.testDetails, test.dataIndex, e.what());
-                            ++failedTests;
-                        }
-                        catch (...)
-                        {
-                            mImpl->OnTestFailure(test.testDetails, test.dataIndex, "Unknown exception caught: test has crashed");
-                            ++failedTests;
-                        }
-
-                        if (reportEnd)
-                        {
-                            mImpl->OnTestFinish(test.testDetails, test.dataIndex, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - testStart));
-                        }
-
-                        return testStart;
-                    };
-
-                auto testTimeLimit = test.testDetails.TimeLimit;
-                if (testTimeLimit < std::chrono::milliseconds::zero())
-                {
-                    testTimeLimit = maxTestRunTime;
-                }
-
-                if (testTimeLimit > std::chrono::milliseconds::zero())
-                {
-                    //
-                    // note that forcing a test to run in under a certain amount of time is inherently fragile
-                    // there's no guarantee that a thread, once started, actually gets `maxTestRunTime` milliseconds of CPU
-
-                    TimeStamp testStart;
-
-                    std::mutex m;
-                    std::unique_lock<std::mutex> gate(m);
-
-                    auto threadStarted = std::make_shared<std::condition_variable>();
-                    std::thread timedRunner([&, threadStarted]()
-                        {
-                            m.lock();
-                            m.unlock();
-
-                            testStart = actualTest(false);
-                            threadStarted->notify_all();
-                        });
-                    timedRunner.detach();
-
-                    if (threadStarted->wait_for(gate, testTimeLimit) == std::cv_status::timeout)
-                    {
-                        mImpl->OnTestFailure(test.testDetails, test.dataIndex, "Test failed to complete within " + std::to_string(testTimeLimit.count()) + " milliseconds.");
-                        mImpl->OnTestFinish(test.testDetails, test.dataIndex, testTimeLimit);
-                        ++failedTests;
-                    }
-                    else
-                    {
-                        mImpl->OnTestFinish(test.testDetails, test.dataIndex, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - testStart));
-                    }
-                }
-                else
-                {
-                    actualTest(true);
-                }
-            }));
-    }
-
-    for (auto &test : futures)
-    {
-        test.get();
-    }
-    
-    mImpl->OnAllTestsComplete(futures.size(), failedTests, 0, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - timeStart));
-
-    return -failedTests;
-}
-
-}

xUnit++/TestRunner.h

-#ifndef TESTRUNNER_H_
-#define TESTRUNNER_H_
-
-#include <chrono>
-#include <functional>
-#include <memory>
-#include <string>
-#include <vector>
-#include "xUnitTime.h"
-
-namespace xUnitpp
-{
-
-class Fact;
-class Theory;
-struct TestDetails;
-
-size_t RunAllTests(const std::string &suite);
-size_t RunAllTests(std::chrono::milliseconds maxTestRunTime);
-size_t RunAllTests(const std::string &suite = "", std::chrono::milliseconds maxTestRunTime = std::chrono::milliseconds::zero(), size_t maxConcurrent = 0);
-
-class TestRunner
-{
-public:
-    TestRunner(std::function<void(const TestDetails &, int)> onTestStart,
-               std::function<void(const TestDetails &, int, const std::string &)> onTestFailure,
-               std::function<void(const TestDetails &, int, std::chrono::milliseconds)> onTestFinish,
-               std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete);
-    size_t RunTests(const std::vector<Fact> &facts, const std::vector<Theory> &theories, const std::string &suite,
-                    std::chrono::milliseconds maxTestRunTime = std::chrono::milliseconds::zero(), size_t maxConcurrent = 0);
-
-private:
-    class Impl;
-    std::unique_ptr<Impl> mImpl;
-};
-
-}
-
-#endif

xUnit++/Tests/Assert.Equal.cpp

+#include "../xUnit++.h"
+
+using xUnitpp::xUnitAssert;
+using xUnitpp::Assert;
+
+FACT(AssertEqualWithDefaultComparerWithSuccess)
+{
+	Assert.Equal(0, 0);
+}
+
+FACT(AssertEqualWithDefaultComparerAssertsOnFailure)
+{
+    Assert.Throws<xUnitAssert>([]() { Assert.Equal(0, 1); });
+}
+
+FACT(AssertEqualWithCustomComparerWithSuccess)
+{
+    Assert.Equal(0, 1, [](int a, int b) { return true; });
+}
+
+FACT(AssertEqualWithCustomComparerAssertsOnFailure)
+{
+    Assert.Throws<xUnitAssert>([]() { Assert.Equal(0, 0, [](int a, int b) { return false; }); });
+}
+
+FACT(AssertEqualAppendsUserMessage)
+{
+    static const std::string msg = "custom message";
+
+    auto assert = Assert.Throws<xUnitAssert>([]() { Assert.Equal(0, 1, msg); });
+
+    Assert.Contains(assert.what(), msg.c_str());
+}
+
+FACT(AssertEqualForFloatsWithinPrecision)
+{
+    auto f0 = 1.2345678f;
+    auto f1 = 1.2349999f;
+
+    Assert.Equal(f0, f1, 3);
+}
+
+FACT(AssertEqualForFloatsAssertsOnFailure)
+{
+    auto f0 = 1.2345678f;
+    auto f1 = 1.2349999f;
+
+    Assert.Throws<xUnitAssert>([=]() { Assert.Equal(f0, f1, 4); });
+}
+
+FACT(AssertSequenceEqualDefaultComparerWithSuccess)
+{
+    std::vector<int> v0;
+    v0.push_back(0);
+    v0.push_back(1);
+    v0.push_back(2);
+    v0.push_back(3);
+
+    std::vector<long long> v1;
+    v1.push_back(0);
+    v1.push_back(1);
+    v1.push_back(2);
+    v1.push_back(3);
+
+    Assert.Equal(v0.begin(), v0.end(), v1.begin(), v1.end());
+}
+
+FACT(AssertSequenceEqualDefaultComparerAssertsOnFailureDueToLength)
+{
+    std::vector<int> v0;
+    v0.push_back(0);
+    v0.push_back(1);
+
+    std::vector<long long> v1;
+    v1.push_back(0);
+    v1.push_back(1);
+    v1.push_back(2);
+    v1.push_back(3);
+
+    auto assert = Assert.Throws<xUnitAssert>([&]() { Assert.Equal(v0.begin(), v0.end(), v1.begin(), v1.end()); });
+
+    Assert.Contains(assert.what(), "at location 2");
+}
+
+FACT(AssertSequenceEqualDefaultComparerAssertsOnFailureDueToMismatch)
+{
+    std::vector<int> v0;
+    v0.push_back(0);
+    v0.push_back(0);
+
+    std::vector<long long> v1;
+    v1.push_back(0);
+    v1.push_back(1);
+    v1.push_back(2);
+    v1.push_back(3);
+
+    auto assert = Assert.Throws<xUnitAssert>([&]() { Assert.Equal(v0.begin(), v0.end(), v1.begin(), v1.end()); });
+
+    Assert.Contains(assert.what(), "at location 1");
+}
+
+FACT(AssertSequenceEqualCustomComparerWithSuccess)
+{
+    std::vector<int> v0;
+    v0.push_back(0);
+    v0.push_back(1);
+    v0.push_back(2);
+    v0.push_back(3);
+
+    std::vector<long long> v1;
+    v1.push_back(10);
+    v1.push_back(11);
+    v1.push_back(12);
+    v1.push_back(13);
+
+    Assert.Equal(v0.begin(), v0.end(), v1.begin(), v1.end(), [](int a, long long b) { return true; });
+}
+
+FACT(AssertSequenceEqualCustomComparerAssertsOnFailureDueToLength)
+{
+    std::vector<int> v0;
+    v0.push_back(0);
+    v0.push_back(1);
+
+    std::vector<long long> v1;
+    v1.push_back(0);
+    v1.push_back(1);
+    v1.push_back(2);
+    v1.push_back(3);
+
+    auto assert = Assert.Throws<xUnitAssert>([&]() { Assert.Equal(v0.begin(), v0.end(), v1.begin(), v1.end(), [](int a, long long b) { return true; }); });
+
+    Assert.Contains(assert.what(), "at location 2");
+}
+
+FACT(AssertSequenceEqualDefaultAssertsOnFailureDueToMismatch)
+{
+    std::vector<int> v0;
+    v0.push_back(0);
+    v0.push_back(1);
+
+    std::vector<long long> v1;
+    v1.push_back(0);
+    v1.push_back(1);
+    v1.push_back(2);
+    v1.push_back(3);
+
+    auto assert = Assert.Throws<xUnitAssert>([&]() { Assert.Equal(v0.begin(), v0.end(), v1.begin(), v1.end(), [](int a, long long b) { return false; }); });
+
+    Assert.Contains(assert.what(), "at location 0");
+}
-#include <exception>
-#include <functional>
-#include <iostream>
-#include <cmath>
-#include <string>
-#include <thread>
-#include <tuple>
-#include <vector>
-#include "TestRunner.h"
-#include "xUnitAssert.h"
-#include "xUnitMacros.h"
-
-using namespace xUnitpp;
-
-FACT(SuccessfulFact)
-{
-    Assert.Equal(1, 1);
-}
-
-FACT(FailingFact)
-{
-    Assert.Equal(0, 1);
-}
-
-struct
-{
-    std::vector<std::tuple<int, char, bool>> operator()() const
-    {
-        auto result = std::vector<std::tuple<int, char, bool>>();
-        result.push_back(std::make_tuple(1, (char)1, true));
-        result.push_back(std::make_tuple(0, (char)1, false));
-        result.push_back(std::make_tuple(0, (char)1, true));
-        return result;
-    }
-} TestingTheoryDataProvider;
-
-THEORY(TestingNewTheory, (int x, char y, bool equal), TestingTheoryDataProvider)
-{
-    if (equal)
-    {
-        Assert.Equal(x, y);
-    }
-    else
-    {
-        Assert.NotEqual(x, y);
-    }
-}
-
-struct MyFixture
-{
-    MyFixture()
-        : x(0)
-        , y(1)
-        , match(false)
-    {
-    }
-
-    int x;
-    int y;
-    bool match;
-};
-
-FACT_FIXTURE(TestFactFixture, MyFixture)
-{
-    Assert.NotEqual(x, y);
-}
-
-SUITE(Special)
-{
-    FACT(SuiteFact)
-    {
-        Assert.Equal(0, 1);
-    }
-
-    std::vector<std::tuple<int, char>> SuiteTheoryDataProvider()
-    {
-        auto result = std::vector<std::tuple<int, char>>();
-        result.push_back(std::make_tuple(1, (char)1));
-        return result;
-    }
-
-    THEORY(SuiteTheory, (int x, char y), SuiteTheoryDataProvider)
-    {
-        Assert.Equal(x, y);
-    }
-
-    FACT_FIXTURE(SuiteFactFixture, MyFixture)
-    {
-        Assert.Equal(x, y - 1);
-    }
-}
-
-FACT(LongRunning)
-{
-    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
-}
-
-TIMED_FACT(LongRunningOk, 0)
-{
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-}
-
-TIMED_FACT(CustomLongRunning, 25)
-{
-    std::this_thread::sleep_for(std::chrono::milliseconds(35));
-}
+#include "xUnitTestRunner.h"
 
 int main()
 {

xUnit++/xUnit++.h

+#ifndef XUNITPP_H_
+#define XUNITPP_H_
+
+#include "xUnitAssert.h"
+#include "xUnitMacros.h"
+
+#endif

xUnit++/xUnit++.vcxproj

     <ClCompile Include="main.cpp" />
     <ClCompile Include="TestCollection.cpp" />
     <ClCompile Include="TestDetails.cpp" />
-    <ClCompile Include="TestRunner.cpp" />
+    <ClCompile Include="Tests\Assert.Equal.cpp" />
     <ClCompile Include="Theory.cpp" />
     <ClCompile Include="xUnitAssert.cpp" />
+    <ClCompile Include="xUnitTestRunner.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="DefaultReporter.h" />
     <ClInclude Include="TestCollection.h" />
     <ClInclude Include=".\xUnitMacros.h" />
     <ClInclude Include="TestDetails.h" />
-    <ClInclude Include="TestRunner.h" />
     <ClInclude Include="Theory.h" />
+    <ClInclude Include="xUnit++.h" />
     <ClInclude Include="xUnitAssert.h" />
+    <ClInclude Include="xUnitTestRunner.h" />
     <ClInclude Include="xUnitTime.h" />
   </ItemGroup>
   <PropertyGroup Label="Globals">

xUnit++/xUnit++.vcxproj.filters

     <ClCompile Include="xUnitAssert.cpp" />
     <ClCompile Include="TestCollection.cpp" />
     <ClCompile Include="Theory.cpp" />
-    <ClCompile Include="TestRunner.cpp" />
     <ClCompile Include="TestDetails.cpp" />
     <ClCompile Include="DefaultReporter.cpp" />
+    <ClCompile Include="Tests\Assert.Equal.cpp">
+      <Filter>Tests</Filter>
+    </ClCompile>
+    <ClCompile Include="xUnitTestRunner.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Fact.h" />
     <ClInclude Include="Suite.h" />
     <ClInclude Include=".\xUnitMacros.h" />
     <ClInclude Include="Theory.h" />
-    <ClInclude Include="TestRunner.h" />
     <ClInclude Include="TestDetails.h" />
     <ClInclude Include="xUnitTime.h" />
     <ClInclude Include="DefaultReporter.h" />
+    <ClInclude Include="xUnit++.h" />
+    <ClInclude Include="xUnitTestRunner.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <Filter Include="Tests">
+      <UniqueIdentifier>{f2938ea3-789e-45dd-95bf-6dd64ff5780e}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
 </Project>

xUnit++/xUnitAssert.cpp

             }
         }
 
-        
-
         if (!expected.empty())
         {
             msg += "\n     Expected: " + expected;
     }
 }
 
-void Assert::Equal(double expected, double actual, size_t precision, const std::string &msg) const
+void Assert::Equal(float expected, float actual, int precision, const std::string &msg) const
+{
+    Equal((double)expected, (double)actual, precision, msg);
+}
+
+void Assert::Equal(double expected, double actual, int precision, const std::string &msg) const
 {
     auto er = round(expected, precision);
     auto ar = round(actual, precision);
     }
 }
 
+void Assert::DoesNotContain(const char *actualString, const char *value, const std::string &msg) const
+{
+    DoesNotContain(std::string(actualString), std::string(value), msg);
+}
+
 void Assert::DoesNotContain(const std::string &actualString, const std::string &value, const std::string &msg) const
 {
     auto found = actualString.find(value);
     }
 }
 
+void Assert::Contains(const char *actualString, const char *value, const std::string &msg) const
+{
+    Contains(std::string(actualString), std::string(value), msg);
+}
+
 void Assert::Contains(const std::string &actualString, const std::string &value, const std::string &msg) const
 {
     if (actualString.find(value) == std::string::npos)

xUnit++/xUnitAssert.h

         Equal(t0, t1, [](T0 t0, T1 t1) { return t0 == t1; }, msg);
     }
 
-    void Equal(double expected, double actual, size_t precision, const std::string &msg = "") const;
+    void Equal(float expected, float actual, int precision, const std::string &msg = "") const;
+    void Equal(double expected, double actual, int precision, const std::string &msg = "") const;
 
     template<typename TSeq0, typename TSeq1, typename TComparer>
     void Equal(const TSeq0 &begin0, const TSeq0 &end0, const TSeq1 &begin1, const TSeq1 &end1, TComparer comparer, const std::string &msg = "") const
         }
     }
 
+    void DoesNotContain(const char *actualString, const char *value, const std::string &msg = "") const;
+
     void DoesNotContain(const std::string &actualString, const std::string &value, const std::string &msg = "") const;
 
     template<typename TSequence, typename T>
         }
     }
 
+    void Contains(const char *actualString, const char *value, const std::string &msg = "") const;
+
     void Contains(const std::string &actualString, const std::string &value, const std::string &msg = "") const;
 
     template<typename TActual, typename TRange>

xUnit++/xUnitMacros.h

 
 #define THEORY(TheoryName, params, DataProvider) TIMED_THEORY(TheoryName, params, DataProvider, -1)
 
-#define ASSERT_EQUAL(expected, actual, comparer_or_precision)
+//#define ASSERT_EQUAL(expected, actual, comparer_or_precision)
 //#define ASSERT_EQUAL(expected, actual)
-#define ASSERT_NOT_EQUAL(expected, actual, comparer)
+//#define ASSERT_NOT_EQUAL(expected, actual, comparer)
 //#define ASSERT_NOT_EQUAL(expected, actual)
-#define ASSERT_NO_THROW(expression)
-#define ASSERT_THROWS(expression)
-#define ASSERT_FAIL(message)
-#define ASSERT_FALSE(check, ...)
-#define ASSERT_TRUE(check, ...)
-#define ASSERT_EMPTY(container)
-#define ASSERT_NOT_EMPTY(container)
-#define ASSERT_DOES_NOT_CONTAIN(container, item)
-#define ASSERT_CONTAINS(container, item)
-#define ASSERT_IN_RANGE(value, min, max)
-#define ASSERT_NOT_IN_RANGE(value, min, max)
-#define ASSERT_NOT_NULL(value)
-#define ASSERT_NULL(value)
-#define ASSERT_NOT_SAME(value0, value1)
-#define ASSERT_SAME(value0, value1)
+//#define ASSERT_NO_THROW(expression)
+//#define ASSERT_THROWS(expression)
+//#define ASSERT_FAIL(message)
+//#define ASSERT_FALSE(check, ...)
+//#define ASSERT_TRUE(check, ...)
+//#define ASSERT_EMPTY(container)
+//#define ASSERT_NOT_EMPTY(container)
+//#define ASSERT_DOES_NOT_CONTAIN(container, item)
+//#define ASSERT_CONTAINS(container, item)
+//#define ASSERT_IN_RANGE(value, min, max)
+//#define ASSERT_NOT_IN_RANGE(value, min, max)
+//#define ASSERT_NOT_NULL(value)
+//#define ASSERT_NULL(value)
+//#define ASSERT_NOT_SAME(value0, value1)
+//#define ASSERT_SAME(value0, value1)
 
 #endif

xUnit++/xUnitTestRunner.cpp

+#include "xUnitTestRunner.h"
+#include <atomic>
+#include <future>
+#include <limits>
+#include <mutex>
+#include <random>
+#include <vector>
+#include "DefaultReporter.h"
+#include "Fact.h"
+#include "TestCollection.h"
+#include "TestDetails.h"
+#include "xUnitAssert.h"
+
+namespace
+{
+
+class ActiveTests
+{
+public:
+    struct TestInstance
+    {
+        TestInstance(const xUnitpp::TestDetails &testDetails, int id, int groupId, int groupSize, std::function<void()> test)
+            : testDetails(testDetails)
+            , id(id)
+            , dataIndex(-1)
+            , groupId(groupId)
+            , groupSize(groupSize)
+            , test(test)
+        {
+        }
+
+        TestInstance(const xUnitpp::TestDetails &testDetails, int id, int dataIndex, int groupId, int groupSize, std::function<void()> test)
+            : testDetails(testDetails)
+            , id(id)
+            , dataIndex(dataIndex)
+            , groupId(groupId)
+            , groupSize(groupSize)
+            , test(test)
+        {
+        }
+
+        TestInstance(const TestInstance &other)
+            : testDetails(other.testDetails)
+            , id(other.id)
+            , dataIndex(other.dataIndex)
+            , groupId(other.groupId)
+            , groupSize(other.groupSize)
+            , test(other.test)
+        {
+        }
+
+        TestInstance(TestInstance &&other)
+        {
+            swap(*this, other);
+        }
+
+        TestInstance &operator =(TestInstance other)
+        {
+            swap(*this, other);
+            return *this;
+        }
+
+        friend void swap(TestInstance &ti0, TestInstance &ti1)
+        {
+            using std::swap;
+
+            swap(ti0.testDetails, ti1.testDetails);
+            swap(ti0.id, ti1.id);
+            swap(ti0.dataIndex, ti1.dataIndex);
+            swap(ti0.groupId, ti1.groupId);
+            swap(ti0.groupSize, ti1.groupSize);
+            swap(ti0.test, ti1.test);
+        }
+
+        xUnitpp::TestDetails testDetails;
+
+        size_t id;
+        size_t dataIndex;
+        size_t groupId;
+        size_t groupSize;
+
+        std::function<void()> test;
+    };
+
+    ActiveTests(const std::vector<xUnitpp::Fact> &facts, const std::vector<xUnitpp::Theory> &theories, const std::string &suite)
+    {
+        size_t id = 0;
+        size_t groupId = 0;
+
+        for (auto &fact : facts)
+        {
+            if (suite == "" || fact.TestDetails().Suite == suite)
+            {
+                mTests.emplace_back(TestInstance(fact.TestDetails(), ++id, ++groupId, 1, fact.Test()));
+            }
+        }
+
+        for (auto &theorySet : theories)
+        {
+            if (suite == "" || theorySet.TestDetails().Suite == suite)
+            {
+                ++groupId;
+                size_t dataIndex = 0;
+                for (auto &theory : theorySet.Theories())
+                {
+                    mTests.emplace_back(TestInstance(theorySet.TestDetails(), ++id, dataIndex++, groupId, theorySet.Theories().size(), theory));
+                }
+            }
+        }
+
+        std::shuffle(mTests.begin(), mTests.end(), std::default_random_engine(std::random_device()()));
+    }
+
+    std::vector<TestInstance>::iterator begin()
+    {
+        return mTests.begin();
+    }
+
+    std::vector<TestInstance>::iterator end()
+    {
+        return mTests.end();
+    }
+
+private:
+    std::vector<TestInstance> mTests;
+};
+
+}
+
+namespace xUnitpp
+{
+
+class TestRunner::Impl
+{
+public:
+    Impl(std::function<void(const TestDetails &, int)> onTestStart,
+         std::function<void(const TestDetails &, int, const std::string &)> onTestFailure,
+         std::function<void(const TestDetails &, int, std::chrono::milliseconds)> onTestFinish,
+         std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete)
+        : mOnTestStart(onTestStart)
+        , mOnTestFailure(onTestFailure)
+        , mOnTestFinish(onTestFinish)
+        , mOnAllTestsComplete(onAllTestsComplete)
+    {
+    }
+
+    void OnTestStart(const TestDetails &details, int dataIndex)
+    {
+        std::lock_guard<std::mutex> guard(mStartMtx);
+        mOnTestStart(details, dataIndex);
+    }
+
+    void OnTestFailure(const TestDetails &details, int dataIndex, const std::string &message)
+    {
+        std::lock_guard<std::mutex> guard(mFailureMtx);
+        mOnTestFailure(details, dataIndex, message);
+    }
+
+    void OnTestFinish(const TestDetails &details, int dataIndex, std::chrono::milliseconds time)
+    {
+        std::lock_guard<std::mutex> guard(mFinishMtx);
+        mOnTestFinish(details, dataIndex, time);
+    }
+
+
+    void OnAllTestsComplete(int total, int skipped, int failed, std::chrono::milliseconds totalTime)
+    {
+        mOnAllTestsComplete(total, skipped, failed, totalTime);
+    }
+
+private:
+    std::function<void(const TestDetails &, int)> mOnTestStart;
+    std::function<void(const TestDetails &, int, const std::string &)> mOnTestFailure;
+    std::function<void(const TestDetails &, int, std::chrono::milliseconds)> mOnTestFinish;
+    std::function<void(int, int, int, std::chrono::milliseconds)> mOnAllTestsComplete;
+
+    std::mutex mStartMtx;
+    std::mutex mFailureMtx;
+    std::mutex mFinishMtx;
+};
+
+size_t RunAllTests(const std::string &suite)
+{
+    return RunAllTests(suite, std::chrono::milliseconds::zero());
+}
+
+size_t RunAllTests(std::chrono::milliseconds maxTestRunTime)
+{
+    return RunAllTests("", maxTestRunTime);
+}
+
+size_t RunAllTests(const std::string &suite, std::chrono::milliseconds maxTestRunTime, size_t maxConcurrent)
+{
+    return
+        TestRunner(&DefaultReporter::ReportStart,
+                   &DefaultReporter::ReportFailure,
+                   &DefaultReporter::ReportFinish,
+                   &DefaultReporter::ReportAllTestsComplete)
+            .RunTests(TestCollection::Facts(), TestCollection::Theories(), suite, maxTestRunTime, maxConcurrent);
+}
+
+TestRunner::TestRunner(std::function<void(const TestDetails &, int)> onTestStart,
+                       std::function<void(const TestDetails &, int, const std::string &)> onTestFailure,
+                       std::function<void(const TestDetails &, int, std::chrono::milliseconds)> onTestFinish,
+                       std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete)
+    : mImpl(new Impl(onTestStart, onTestFailure, onTestFinish, onAllTestsComplete))
+{
+}
+
+size_t TestRunner::RunTests(const std::vector<Fact> &facts, const std::vector<Theory> &theories, const std::string &suite, std::chrono::milliseconds maxTestRunTime, size_t maxConcurrent)
+{
+    auto timeStart = std::chrono::system_clock::now();
+
+    ActiveTests activeTests(facts, theories, suite);
+
+    if (maxConcurrent == 0)
+    {
+        maxConcurrent = std::numeric_limits<decltype(maxConcurrent)>::max();
+    }
+
+    class ThreadCounter
+    {
+    public:
+        ThreadCounter(size_t maxThreads)
+            : maxThreads(maxThreads)
+            , activeThreads(0)
+        {
+        }
+
+        void operator++()
+        {
+            std::unique_lock<std::mutex> lock(mtx);
+            condition.wait(lock, [&]() { return activeThreads < maxThreads; });
+
+            ++activeThreads;
+        }
+
+        void operator--()
+        {
+            std::lock_guard<std::mutex> guard(mtx);
+            --activeThreads;
+        }
+
+    private:
+        size_t maxThreads;
+        size_t activeThreads;
+        std::mutex mtx;
+        std::condition_variable condition;
+    } threadCounter(maxConcurrent);
+
+    std::atomic<int> failedTests = 0;
+
+    std::vector<std::future<void>> futures;
+    for (auto &test : activeTests)
+    {
+        futures.push_back(std::async([&]()
+            {
+                struct CounterGuard
+                {
+                    CounterGuard(ThreadCounter &tc)
+                        : tc(tc)
+                    {
+                        ++tc;
+                    }
+
+                    ~CounterGuard()
+                    {
+                        --tc;
+                    }
+
+                private:
+                    ThreadCounter &tc;
+                } counterGuard(threadCounter);
+
+                auto actualTest = [&](bool reportEnd) -> TimeStamp
+                    {
+                        TimeStamp testStart;
+                        try
+                        {
+                            mImpl->OnTestStart(test.testDetails, test.dataIndex);
+
+                            testStart = Clock::now();
+                            test.test();
+                        }
+                        catch (std::exception &e)
+                        {
+                            mImpl->OnTestFailure(test.testDetails, test.dataIndex, e.what());
+                            ++failedTests;
+                        }
+                        catch (...)
+                        {
+                            mImpl->OnTestFailure(test.testDetails, test.dataIndex, "Unknown exception caught: test has crashed");
+                            ++failedTests;
+                        }
+
+                        if (reportEnd)
+                        {
+                            mImpl->OnTestFinish(test.testDetails, test.dataIndex, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - testStart));
+                        }
+
+                        return testStart;
+                    };
+
+                auto testTimeLimit = test.testDetails.TimeLimit;
+                if (testTimeLimit < std::chrono::milliseconds::zero())
+                {
+                    testTimeLimit = maxTestRunTime;
+                }
+
+                if (testTimeLimit > std::chrono::milliseconds::zero())
+                {
+                    //
+                    // note that forcing a test to run in under a certain amount of time is inherently fragile
+                    // there's no guarantee that a thread, once started, actually gets `maxTestRunTime` milliseconds of CPU
+
+                    TimeStamp testStart;
+
+                    std::mutex m;
+                    std::unique_lock<std::mutex> gate(m);
+
+                    auto threadStarted = std::make_shared<std::condition_variable>();
+                    std::thread timedRunner([&, threadStarted]()
+                        {
+                            m.lock();
+                            m.unlock();
+
+                            testStart = actualTest(false);
+                            threadStarted->notify_all();
+                        });
+                    timedRunner.detach();
+
+                    if (threadStarted->wait_for(gate, testTimeLimit) == std::cv_status::timeout)
+                    {
+                        mImpl->OnTestFailure(test.testDetails, test.dataIndex, "Test failed to complete within " + std::to_string(testTimeLimit.count()) + " milliseconds.");
+                        mImpl->OnTestFinish(test.testDetails, test.dataIndex, testTimeLimit);
+                        ++failedTests;
+                    }
+                    else
+                    {
+                        mImpl->OnTestFinish(test.testDetails, test.dataIndex, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - testStart));
+                    }
+                }
+                else
+                {
+                    actualTest(true);
+                }
+            }));
+    }
+
+    for (auto &test : futures)
+    {
+        test.get();
+    }
+    
+    mImpl->OnAllTestsComplete(futures.size(), failedTests, 0, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - timeStart));
+
+    return -failedTests;
+}
+
+}

xUnit++/xUnitTestRunner.h

+#ifndef XUNITTESTRUNNER_H_
+#define XUNITTESTRUNNER_H_
+
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+#include "xUnitTime.h"
+
+namespace xUnitpp
+{
+
+class Fact;
+class Theory;
+struct TestDetails;
+
+size_t RunAllTests(const std::string &suite);
+size_t RunAllTests(std::chrono::milliseconds maxTestRunTime);
+size_t RunAllTests(const std::string &suite = "", std::chrono::milliseconds maxTestRunTime = std::chrono::milliseconds::zero(), size_t maxConcurrent = 0);
+
+class TestRunner
+{
+public:
+    TestRunner(std::function<void(const TestDetails &, int)> onTestStart,
+               std::function<void(const TestDetails &, int, const std::string &)> onTestFailure,
+               std::function<void(const TestDetails &, int, std::chrono::milliseconds)> onTestFinish,
+               std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete);
+    size_t RunTests(const std::vector<Fact> &facts, const std::vector<Theory> &theories, const std::string &suite,
+                    std::chrono::milliseconds maxTestRunTime = std::chrono::milliseconds::zero(), size_t maxConcurrent = 0);
+
+private:
+    class Impl;
+    std::unique_ptr<Impl> mImpl;
+};
+
+}
+
+#endif
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.