Commits

Matt Oswald  committed cc174c7

moved Assert class into correct header and implemented the full failure message for all assertions

  • Participants
  • Parent commits 95b98f5

Comments (0)

Files changed (3)

File xUnit++/main.cpp

 
 using namespace xUnitpp;
 
-const class
-{
-private:
-    static double round(double value, size_t precision)
-    {
-        if (value < 0)
-        {
-            return std::ceil((value - 0.5) * std::pow(10, precision)) / std::pow(10, precision);
-        }
-        else
-        {
-            return std::floor((value + 0.5) * std::pow(10, precision)) / std::pow(10, precision);
-        }
-    }
-
-public:
-    template<typename T0, typename T1, typename TComparer>
-    void Equal(T0 t0, T1 t1, TComparer comparer) const
-    {
-        if (!comparer(t0, t1))
-        {
-            throw xUnitAssert("Not equal.");
-        }
-    }
-
-    template<typename T0, typename T1>
-    void Equal(T0 t0, T1 t1) const
-    {
-        Equal(t0, t1, [](T0 t0, T1 t1) { return t0 == t1; });
-    }
-
-    void Equal(double expected, double actual, size_t precision) const
-    {
-        auto er = round(expected, precision);
-        auto ar = round(actual, precision);
-
-        Equal(er, ar, [](double er, double ar) { return er == ar; });
-    }
-
-    // !!! enable_if has std::begin, std::end
-    // then template on template of type T
-    template<typename T, typename TComparer>
-    void Equal(const std::vector<T> &expected, const std::vector<T> &actual, TComparer comparer) const
-    {
-        if (expected.size() != actual.size())
-        {
-            throw xUnitAssert("Lengths differ.");
-        }
-
-        for (auto e = expected.begin(), a = actual.begin(); e != expected.end(); ++e, ++a)
-        {
-            Equal(*e, *a, comparer);
-        }
-    }
-
-    // !!! enable_if has std::begin, std::end
-    // then template on template of type T
-    template<typename T>
-    void Equal(const std::vector<T> &expected, const std::vector<T> &actual) const
-    {
-        Equal(expected, actual, [](const T &t0, const T &t1) { return t0 == t1; });
-    }
-
-    template<typename T0, typename T1, typename TComparer>
-    void NotEqual(T0 t0, T1 t1, TComparer comparer) const
-    {
-        if (comparer(t0, t1))
-        {
-            throw xUnitAssert("Equal.");
-        }
-    }
-
-    template<typename T0, typename T1>
-    void NotEqual(T0 t0, T1 t1) const
-    {
-        NotEqual(t0, t1, [](T0 t0, T1 t1) { return t0 == t1; });
-    }
-
-    template<typename T, typename TComparer>
-    void NotEqual(const std::vector<T> &expected, const std::vector<T> &actual, TComparer comparer)
-    {
-        if (expected.size() == actual.size())
-        {
-            for (auto e = expected.begin(), a = actual.begin(); e != expected.end(); ++e, ++a)
-            {
-                NotEqual(*e, *a, comparer);
-            }
-        }
-    }
-
-    template<typename T>
-    void NotEqual(const std::vector<T> &expected, const std::vector<T> &actual)
-    {
-        NotEqual(expected, actual, [](const T &t0, const T &t1) { return t0 == t1; });
-    }
-
-    template<typename TFunc>
-    void DoesNotThrow(TFunc &&fn) const
-    {
-        try
-        {
-            fn();
-        }
-        catch (std::exception &e)
-        {
-            throw xUnitAssert(std::string("Caught std::exception with message: ") + e.what());
-        }
-        catch (...)
-        {
-            throw xUnitAssert(std::string("Caught unknown exception (crash) with message: ") + e.what());
-        }
-    }
-
-    template<typename TException, typename TFunc>
-    TException Throws(TFunc &&fn) const
-    {
-        try
-        {
-            fn();
-        }
-        catch (TException e)
-        {
-            return e;
-        }
-        catch (std::exception &e)
-        {
-            throw xUnitAssert(std::string("Caught std::exception with message: ") + e.what());
-        }
-        catch (...)
-        {
-            throw xUnitAssert(std::string("Caught unknown exception (crash) with message: ") + e.what());
-        }
-
-        throw xUnitAssert(std::string("Did not catch any exceptions."));
-    }
-
-    void Fail(const std::string &msg) const
-    {
-        throw xUnitAssert(msg);
-    }
-
-    void False(bool b, const std::string &msg) const
-    {
-        if (b)
-        {
-            throw xUnitAssert(msg);
-        }
-    }
-
-    void False(bool b) const
-    {
-        False(b, "Expected false.");
-    }
-
-    void True(bool b, const std::string &msg) const
-    {
-        if (!b)
-        {
-            throw xUnitAssert(msg);
-        }
-    }
-
-    void True(bool b) const
-    {
-        True(b, "Expected true.");
-    }
-
-    template<typename TContainer>
-    void Empty(TContainer container) const
-    {
-        if (!container.empty())
-        {
-            throw xUnitAssert("Container is not empty.");
-        }
-    }
-
-    template<typename TContainer>
-    void NotEmpty(TContainer container) const
-    {
-        if (container.empty())
-        {
-            throw xUnitAssert("Container is empty.");
-        }
-    }
-
-    template<typename TContainer, typename TItem>
-    void DoesNotContain(TContainer container, TItem item) const
-    {
-        if (std::find(container.begin(), container.end(), item))
-        {
-            throw xUnitAssert("Container contains item.");
-        }
-    }
-
-    void DoesNotContain(const std::string &actualString, const std::string &expectedSubstring) const
-    {
-        if (actualString.find(expectedSubstring) != std::string::npos)
-        {
-            throw xUnitAssert("Actual string contains substring.");
-        }
-    }
-
-    template<typename TContainer, typename TItem>
-    void Contains(TContainer container, TItem item) const
-    {
-        if (!std::find(container.begin(), container.end(), item))
-        {
-            throw xUnitAssert("Container does not contain item.");
-        }
-    }
-
-    void Contains(const std::string &actualString, const std::string &expectedSubstring) const
-    {
-        if (actualString.find(expectedSubstring) == std::string::npos)
-        {
-            throw xUnitAssert("Actual string does not contain substring.");
-        }
-    }
-
-    template<typename TActual, typename TRange>
-    void InRange(TActual actual, TRange min, TRange max) const
-    {
-        if (actual < min || actual >= max)
-        {
-            throw xUnitAssert("Value does not exist in range.");
-        }
-    }
-
-    template<typename TActual, typename TRange>
-    void NotInRange(TActual actual, TRange min, TRange max) const
-    {
-        if (actual >= min && actual < max)
-        {
-            throw xUnitAssert("Value does not exist in range.");
-        }
-    }
-
-    template<typename T>
-    void NotNull(T value) const
-    {
-        if (value == nullptr)
-        {
-            throw xUnitAssert("Value is null.");
-        }
-    }
-
-    template<typename T>
-    void Null(T value) const
-    {
-        if (value != nullptr)
-        {
-            throw xUnitAssert("Value is not null.");
-        }
-    }
-
-    template<typename T>
-    void NotSame(const T &t0, const T &t1) const
-    {
-        if (&t0 == &t1)
-        {
-            throw xUnitAssert("Values are the same instance.");
-        }
-    }
-
-    template<typename T>
-    void Same(const T &t0, const T &t1) const
-    {
-        if (&t0 != &t1)
-        {
-            throw xUnitAssert("Values are not the same instance.");
-        }
-    }
-} Assert;
-
 FACT(SuccessfulFact)
 {
     Assert.Equal(1, 1);

File xUnit++/xUnitAssert.cpp

 #include "xUnitAssert.h"
 
+namespace
+{
+    std::string AssembleWhat(const std::string &call, const std::string &userMsg, const std::string &customMsg,
+                             const std::string &expected, const std::string &actual)
+    {
+        std::string msg = "Assert." + call + "() failure";
+        if (!userMsg.empty())
+        {
+            msg += ": " + userMsg;
+
+            if (!customMsg.empty())
+            {
+                msg += "\n     " + customMsg;
+            }
+        }
+        else
+        {
+            if (!customMsg.empty())
+            {
+                msg += ": " + customMsg;
+            }
+        }
+
+        
+
+        if (!expected.empty())
+        {
+            msg += "\n     Expected: " + expected;
+            msg += "\n       Actual: " + actual;
+        }
+
+        msg += "\n";
+
+        return msg;
+    }
+}
+
 namespace xUnitpp
 {
 
-xUnitAssert::xUnitAssert()
+xUnitAssert::xUnitAssert(const std::string &call, const std::string &userMsg, const std::string &customMsg,
+                         const std::string &expected, const std::string &actual)
+    : base(AssembleWhat(call, userMsg, customMsg, expected, actual).c_str())
 {
 }
 
-xUnitAssert::xUnitAssert(const std::string &msg)
-    : base(msg.c_str())
+double Assert::round(double value, size_t precision)
 {
+    if (value < 0)
+    {
+        return std::ceil((value - 0.5) * std::pow(10, precision)) / std::pow(10, precision);
+    }
+    else
+    {
+        return std::floor((value + 0.5) * std::pow(10, precision)) / std::pow(10, precision);
+    }
+}
+
+void Assert::Equal(double expected, double actual, size_t precision, const std::string &msg) const
+{
+    auto er = round(expected, precision);
+    auto ar = round(actual, precision);
+
+    Equal(er, ar, [](double er, double ar) { return er == ar; }, msg);
+}
+
+void Assert::Fail(const std::string &msg) const
+{
+    throw xUnitAssert("Fail", msg, "", "", "");
+}
+
+void Assert::False(bool b, const std::string &msg) const
+{
+    if (b)
+    {
+        throw xUnitAssert("False", msg, "", "false", "true");
+    }
+}
+
+void Assert::True(bool b, const std::string &msg) const
+{
+    if (!b)
+    {
+        throw xUnitAssert("True", msg, "", "true", "false");
+    }
+}
+
+void Assert::DoesNotContain(const std::string &actualString, const std::string &value, const std::string &msg) const
+{
+    auto found = actualString.find(value);
+    if (found != std::string::npos)
+    {
+        throw xUnitAssert("DoesNotContain", msg, "Found: \"" + value + "\" at position " + std::to_string(found) + ".", "", "");
+    }
+}
+
+void Assert::Contains(const std::string &actualString, const std::string &value, const std::string &msg) const
+{
+    if (actualString.find(value) == std::string::npos)
+    {
+        throw xUnitAssert("Contains", msg, "", "", "");
+    }
 }
 
 }

File xUnit++/xUnitAssert.h

 #ifndef XUNITASSERT_H_
 #define XUNITASSERT_H_
 
+#include <algorithm>
 #include <exception>
 #include <string>
+#include <type_traits>
 
 namespace xUnitpp
 {
     typedef std::exception base;
 
 public:
-    xUnitAssert();
-    explicit xUnitAssert(const std::string &msg);
+    explicit xUnitAssert(const std::string &call, const std::string &userMsg, const std::string &customMsg,
+                         const std::string &expected, const std::string &actual);
 };
 
+const class Assert
+{
+private:
+    static double round(double value, size_t precision);
+
+    template<typename T0>
+    static std::string RangeToString(const T0 &begin, const T0 &end)
+    {
+        std::string result = "[ ";
+
+        std::for_each(begin, end, [&result](decltype(*begin) val) { result += std::to_string(val) + ", "; });
+
+        result[result.size() - 2] = ' ';
+        result[result.size() - 1] = ']';
+
+        return result;
+    }
+
+    template<typename T>
+    struct has_empty
+    {
+    private:
+        template<typename U, U>
+        class check {};
+
+        template<typename C>
+        static char f(check<void (C::*)(), &C::empty> *);
+
+        template<typename C>
+        static long f(...);
+
+    public:
+        static const bool value = (sizeof(f<T>(nullptr)) == sizeof(char));
+    };
+
+public:
+    template<typename T0, typename T1, typename TComparer>
+    void Equal(T0 t0, T1 t1, TComparer comparer, const std::string &msg = "") const
+    {
+        using namespace std;
+
+        if (!comparer(t0, t1))
+        {
+            throw xUnitAssert("Equal", msg, "", to_string(t0), to_string(t1));
+        }
+    }
+
+    template<typename T0, typename T1>
+    void Equal(T0 t0, T1 t1, const std::string &msg = "") const
+    {
+        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;
+
+    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
+    {
+        auto cur0 = begin0;
+        auto cur1 = begin1;
+
+        size_t index = 0;
+        while (cur0 != end0 && cur1 != end1)
+        {
+            if (!comparer(*cur0, *cur1))
+            {
+                break;
+            }
+
+            ++cur0;
+            ++cur1;
+            ++index;
+        }
+
+        if (cur0 != end0 || cur1 != end1)
+        {
+            throw xUnitAssert("Equal", msg,
+                "Sequence unequal at location " + std::to_string(index) + ".",
+                RangeToString(begin0, end0),
+                RangeToString(begin1, end1));
+        }
+    }
+
+    template<typename TSeq0, typename TSeq1>
+    void Equal(const TSeq0 &begin0, const TSeq0 &end0, const TSeq1 &begin1, const TSeq1 &end1, const std::string &msg = "") const
+    {
+        Equal(begin0, end0, begin1, end1, [](decltype(*begin0) a, decltype(*begin1) b) { return a == b; }, msg);
+    }
+
+    template<typename T0, typename T1, typename TComparer>
+    void NotEqual(T0 t0, T1 t1, TComparer comparer, const std::string &msg = "") const
+    {
+        if (comparer(t0, t1))
+        {
+            throw xUnitAssert("NotEqual", msg, "", "", "");
+        }
+    }
+
+    template<typename T0, typename T1>
+    void NotEqual(T0 t0, T1 t1, const std::string &msg = "") const
+    {
+        NotEqual(t0, t1, [](T0 t0, T1 t1) { return t0 == t1; }, msg);
+    }
+
+    template<typename TSeq0, typename TSeq1, typename TComparer>
+    void NotEqual(const TSeq0 &begin0, const TSeq0 &end0, const TSeq1 &begin1, const TSeq1 &end1, TComparer comparer, const std::string &msg = "") const
+    {
+        auto cur0 = begin0;
+        auto cur1 = begin1;
+
+        while (cur0 != end0 && cur1 != end1)
+        {
+            if (!comparer(*cur0, *cur1))
+            {
+                return;
+            }
+
+            ++cur0;
+            ++cur1;
+        }
+
+        throw xUnitAssert("NotEqual", msg, "", "", "");
+    }
+
+    template<typename TSeq0, typename TSeq1, typename TComparer>
+    void NotEqual(const TSeq0 &begin0, const TSeq0 &end0, const TSeq1 &begin1, const TSeq1 &end1, const std::string &msg = "") const
+    {
+        NotEqual(begin0, end0, begin1, end1, [](decltype(*begin0) a, decltype(*begin1) b) { return a == b; }, msg);
+    }
+
+    template<typename TFunc>
+    void DoesNotThrow(TFunc &&fn, const std::string &msg = "") const
+    {
+        try
+        {
+            fn();
+        }
+        catch (std::exception &e)
+        {
+            throw xUnitAssert("DoesNotThrow", msg, "", "(no exception)", e.what());
+        }
+        catch (...)
+        {
+            throw xUnitAssert("DoesNotThrow", msg, "", "(no exception)", "Crash: unknown exception.");
+        }
+    }
+
+    template<typename TException, typename TFunc>
+    TException Throws(TFunc &&fn, const std::string &msg = "") const
+    {
+        try
+        {
+            fn();
+        }
+        catch (TException e)
+        {
+            return e;
+        }
+        catch (const std::exception &e)
+        {
+            throw xUnitAssert("Throws", msg, "", typeid(TException).name(), e.what());
+        }
+        catch (...)
+        {
+            throw xUnitAssert("Throws", msg, "", typeid(TException).name(), "Crash: unknown exception.");
+        }
+
+        throw xUnitAssert("Throws", msg, "", typeid(TException).name(), "No exception.");
+    }
+
+    void Fail(const std::string &msg = "") const;
+
+    void False(bool b, const std::string &msg = "") const;
+
+    void True(bool b, const std::string &msg = "") const;
+
+    template<typename TSequence>
+    typename std::enable_if<has_empty<TSequence>::value>::type Empty(const TSequence &sequence, const std::string &msg = "") const
+    {
+        if (!sequence.empty())
+        {
+            throw xUnitAssert("Empty", msg, "", "", "");
+        }
+    }
+
+    template<typename TSequence>
+    typename std::enable_if<!has_empty<TSequence>::value>::type Empty(const TSequence &sequence, const std::string &msg = "") const
+    {
+        using namespace std;
+
+        if (begin(sequence) != end(sequence))
+        {
+            throw xUnitAssert("Empty", msg, "", "", "");
+        }
+    }
+
+    template<typename TSequence, typename T>
+    void DoesNotContain(const TSequence &sequence, T value, const std::string &msg = "") const
+    {
+        using namespace std;
+
+        auto found = find(begin(sequence), end(sequence), value);
+        if (found != end(sequence))
+        {
+            throw xUnitAssert("DoesNotContain", msg, "Found: " + to_string(value) + " at position " + to_string(distance(begin(sequence), found)) + ".", "", "");
+        }
+    }
+
+    void DoesNotContain(const std::string &actualString, const std::string &value, const std::string &msg = "") const;
+
+    template<typename TSequence, typename T>
+    void Contains(const TSequence &sequence, T value, const std::string &msg = "") const
+    {
+        using namespace std;
+
+        if (find(begin(sequence), end(sequence), value) == end(sequence))
+        {
+            throw xUnitAssert("Contains", msg, "", "", "");
+        }
+    }
+
+    void Contains(const std::string &actualString, const std::string &value, const std::string &msg = "") const;
+
+    template<typename TActual, typename TRange>
+    void InRange(TActual actual, TRange min, TRange max, const std::string &msg = "") const
+    {
+        if (actual < min || actual >= max)
+        {
+            throw xUnitAssert("InRange", msg, "", "[" + std::to_string(min) + " - " + std::to_string(max) + ")", std::to_string(actual));
+        }
+    }
+
+    template<typename TActual, typename TRange>
+    void NotInRange(TActual actual, TRange min, TRange max, const std::string &msg = "") const
+    {
+        if (actual >= min && actual < max)
+        {
+            throw xUnitAssert("NotInRange", msg, "", "[" + std::to_string(min) + " - " + std::to_string(max) + ")", std::to_string(actual));
+        }
+    }
+
+    template<typename T>
+    void NotNull(T value, const std::string &msg = "") const
+    {
+        if (value == nullptr)
+        {
+            throw xUnitAssert("NotNull", msg, "", "", "");
+        }
+    }
+
+    template<typename T>
+    void Null(T value, const std::string &msg = "") const
+    {
+        if (value != nullptr)
+        {
+            throw xUnitAssert("Null", msg, "", "", "");
+        }
+    }
+
+    template<typename T>
+    void NotSame(const T &t0, const T &t1, const std::string &msg = "") const
+    {
+        if (&t0 == &t1)
+        {
+            throw xUnitAssert("NotSame", msg, "", "", "");
+        }
+    }
+
+    template<typename T>
+    void Same(const T &t0, const T &t1, const std::string &msg = "") const
+    {
+        if (&t0 != &t1)
+        {
+            throw xUnitAssert("Same", msg, "", "", "");
+        }
+    }
+} Assert;
+
 }
 
 #endif