Renames tinytest files again.
This commit is contained in:
7
BUILD
7
BUILD
@@ -2,6 +2,9 @@ load("@rules_cc//cc:defs.bzl", "cc_library")
|
|||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "tinytest",
|
name = "tinytest",
|
||||||
srcs = ["test.cpp"],
|
srcs = ["tinytest.cpp"],
|
||||||
hdrs = ["test.h"],
|
hdrs = ["tinytest.h"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#define _XOPEN_SOURCE_EXTENDED
|
#define _XOPEN_SOURCE_EXTENDED
|
||||||
#include "test.h"
|
#include "tinytest.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -7,12 +7,12 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Test {
|
namespace TinyTest {
|
||||||
namespace {
|
namespace {
|
||||||
using std::endl;
|
using std::endl;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
} // End namespace
|
} // End namespace
|
||||||
|
|
||||||
// Test lifecycle
|
// Test lifecycle
|
||||||
// suiteSetupFn(); - This is called to allocate any suite level resources. This
|
// suiteSetupFn(); - This is called to allocate any suite level resources. This
|
||||||
@@ -143,146 +143,164 @@ using std::vector;
|
|||||||
// Default to (string, _FnToTest, vector<tuple<"", _T1, [](a,b){return a==b;},
|
// Default to (string, _FnToTest, vector<tuple<"", _T1, [](a,b){return a==b;},
|
||||||
// make_tuple()) Also allow make_tuple(T2) if the last param is not a tuple.
|
// make_tuple()) Also allow make_tuple(T2) if the last param is not a tuple.
|
||||||
|
|
||||||
TestResults::TestResults()
|
TestResults::TestResults() : errors_(0), failed_(0), passed_(0), skipped_(0), total_(0) {}
|
||||||
: errors_(0), failed_(0), passed_(0), skipped_(0), total_(0) {}
|
|
||||||
|
|
||||||
TestResults::TestResults(const TestResults &other)
|
TestResults::TestResults(const TestResults& other)
|
||||||
: error_messages_(other.error_messages_), errors_(other.errors_),
|
: error_messages_(other.error_messages_),
|
||||||
failed_(other.failed_), failure_messages_(other.failure_messages_),
|
errors_(other.errors_),
|
||||||
passed_(other.passed_), skip_messages_(other.skip_messages_),
|
failed_(other.failed_),
|
||||||
skipped_(other.skipped_), total_(other.total_) {}
|
failure_messages_(other.failure_messages_),
|
||||||
|
passed_(other.passed_),
|
||||||
|
skip_messages_(other.skip_messages_),
|
||||||
|
skipped_(other.skipped_),
|
||||||
|
total_(other.total_) {}
|
||||||
|
|
||||||
TestResults::TestResults(uint32_t errors, uint32_t failed, uint32_t passed,
|
TestResults::TestResults(uint32_t errors,
|
||||||
uint32_t skipped, uint32_t total,
|
uint32_t failed,
|
||||||
|
uint32_t passed,
|
||||||
|
uint32_t skipped,
|
||||||
|
uint32_t total,
|
||||||
vector<string> error_messages,
|
vector<string> error_messages,
|
||||||
vector<string> failure_messages,
|
vector<string> failure_messages,
|
||||||
vector<string> skip_messages)
|
vector<string> skip_messages)
|
||||||
: error_messages_(error_messages), errors_(errors), failed_(failed),
|
: error_messages_(error_messages),
|
||||||
failure_messages_(failure_messages), passed_(passed),
|
errors_(errors),
|
||||||
skip_messages_(skip_messages), skipped_(skipped), total_(total) {}
|
failed_(failed),
|
||||||
|
failure_messages_(failure_messages),
|
||||||
|
passed_(passed),
|
||||||
|
skip_messages_(skip_messages),
|
||||||
|
skipped_(skipped),
|
||||||
|
total_(total) {}
|
||||||
|
|
||||||
TestResults &TestResults::error() {
|
TestResults& TestResults::error() {
|
||||||
errors_++;
|
errors_++;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResults &TestResults::error(string message) {
|
TestResults& TestResults::error(string message) {
|
||||||
errors_++;
|
errors_++;
|
||||||
error_messages_.push_back(message);
|
error_messages_.push_back(message);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResults &TestResults::fail() {
|
TestResults& TestResults::fail() {
|
||||||
total_++;
|
total_++;
|
||||||
failed_++;
|
failed_++;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResults &TestResults::fail(const string &message) {
|
TestResults& TestResults::fail(const string& message) {
|
||||||
total_++;
|
total_++;
|
||||||
failed_++;
|
failed_++;
|
||||||
failure_messages_.push_back(message);
|
failure_messages_.push_back(message);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<string> TestResults::failure_messages() { return failure_messages_; }
|
vector<string> TestResults::failure_messages() {
|
||||||
|
return failure_messages_;
|
||||||
|
}
|
||||||
|
|
||||||
TestResults &TestResults::pass() {
|
TestResults& TestResults::pass() {
|
||||||
total_++;
|
total_++;
|
||||||
passed_++;
|
passed_++;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResults &TestResults::skip() {
|
TestResults& TestResults::skip() {
|
||||||
total_++;
|
total_++;
|
||||||
skipped_++;
|
skipped_++;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResults &TestResults::skip(const string &message) {
|
TestResults& TestResults::skip(const string& message) {
|
||||||
total_++;
|
total_++;
|
||||||
skipped_++;
|
skipped_++;
|
||||||
skip_messages_.push_back(message);
|
skip_messages_.push_back(message);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<string> TestResults::skip_messages() { return skip_messages_; }
|
vector<string> TestResults::skip_messages() {
|
||||||
|
return skip_messages_;
|
||||||
|
}
|
||||||
|
|
||||||
vector<string> TestResults::error_messages() { return error_messages_; }
|
vector<string> TestResults::error_messages() {
|
||||||
|
return error_messages_;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t TestResults::errors() { return errors_; }
|
uint32_t TestResults::errors() {
|
||||||
|
return errors_;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t TestResults::failed() { return failed_; }
|
uint32_t TestResults::failed() {
|
||||||
|
return failed_;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t TestResults::passed() { return passed_; }
|
uint32_t TestResults::passed() {
|
||||||
|
return passed_;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t TestResults::skipped() { return skipped_; }
|
uint32_t TestResults::skipped() {
|
||||||
|
return skipped_;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t TestResults::total() { return total_; }
|
uint32_t TestResults::total() {
|
||||||
|
return total_;
|
||||||
|
}
|
||||||
|
|
||||||
TestResults TestResults::operator+(const TestResults &other) const {
|
TestResults TestResults::operator+(const TestResults& other) const {
|
||||||
vector<string> error_messages;
|
vector<string> error_messages;
|
||||||
error_messages.insert(error_messages.end(), error_messages_.begin(),
|
error_messages.insert(error_messages.end(), error_messages_.begin(), error_messages_.end());
|
||||||
error_messages_.end());
|
error_messages.insert(error_messages.end(), other.error_messages_.begin(), other.error_messages_.end());
|
||||||
error_messages.insert(error_messages.end(), other.error_messages_.begin(),
|
|
||||||
other.error_messages_.end());
|
|
||||||
vector<string> failure_messages;
|
vector<string> failure_messages;
|
||||||
failure_messages.insert(failure_messages.end(), failure_messages_.begin(),
|
failure_messages.insert(failure_messages.end(), failure_messages_.begin(), failure_messages_.end());
|
||||||
failure_messages_.end());
|
failure_messages.insert(failure_messages.end(), other.failure_messages_.begin(), other.failure_messages_.end());
|
||||||
failure_messages.insert(failure_messages.end(),
|
|
||||||
other.failure_messages_.begin(),
|
|
||||||
other.failure_messages_.end());
|
|
||||||
vector<string> skip_messages;
|
vector<string> skip_messages;
|
||||||
skip_messages.insert(skip_messages.end(), skip_messages_.begin(),
|
skip_messages.insert(skip_messages.end(), skip_messages_.begin(), skip_messages_.end());
|
||||||
skip_messages_.end());
|
skip_messages.insert(skip_messages.end(), other.skip_messages_.begin(), other.skip_messages_.end());
|
||||||
skip_messages.insert(skip_messages.end(), other.skip_messages_.begin(),
|
|
||||||
other.skip_messages_.end());
|
|
||||||
|
|
||||||
return TestResults(errors_ + other.errors_, failed_ + other.failed_,
|
return TestResults(errors_ + other.errors_,
|
||||||
passed_ + other.passed_, skipped_ + other.skipped_,
|
failed_ + other.failed_,
|
||||||
total_ + other.total_, error_messages, failure_messages,
|
passed_ + other.passed_,
|
||||||
|
skipped_ + other.skipped_,
|
||||||
|
total_ + other.total_,
|
||||||
|
error_messages,
|
||||||
|
failure_messages,
|
||||||
skip_messages);
|
skip_messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResults &TestResults::operator+=(const TestResults &other) {
|
TestResults& TestResults::operator+=(const TestResults& other) {
|
||||||
error_messages_.insert(error_messages_.end(), other.error_messages_.begin(),
|
error_messages_.insert(error_messages_.end(), other.error_messages_.begin(), other.error_messages_.end());
|
||||||
other.error_messages_.end());
|
|
||||||
errors_ += other.errors_;
|
errors_ += other.errors_;
|
||||||
failed_ += other.failed_;
|
failed_ += other.failed_;
|
||||||
failure_messages_.insert(failure_messages_.end(),
|
failure_messages_.insert(failure_messages_.end(), other.failure_messages_.begin(), other.failure_messages_.end());
|
||||||
other.failure_messages_.begin(),
|
|
||||||
other.failure_messages_.end());
|
|
||||||
passed_ += other.passed_;
|
passed_ += other.passed_;
|
||||||
skip_messages_.insert(skip_messages_.end(), other.skip_messages_.begin(),
|
skip_messages_.insert(skip_messages_.end(), other.skip_messages_.begin(), other.skip_messages_.end());
|
||||||
other.skip_messages_.end());
|
|
||||||
skipped_ += other.skipped_;
|
skipped_ += other.skipped_;
|
||||||
total_ += other.total_;
|
total_ += other.total_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintResults(std::ostream &os, TestResults results) {
|
void PrintResults(std::ostream& os, TestResults results) {
|
||||||
auto skip_messages = results.skip_messages();
|
auto skip_messages = results.skip_messages();
|
||||||
if (skip_messages.size() > 0) {
|
if (skip_messages.size() > 0) {
|
||||||
os << "Skipped:" << endl;
|
os << "Skipped:" << endl;
|
||||||
for_each(skip_messages.begin(), skip_messages.end(),
|
for_each(skip_messages.begin(), skip_messages.end(), [&os](const string& message) {
|
||||||
[&os](const string &message) {
|
os << "🚧Skipped: " << message << endl;
|
||||||
os << "🚧Skipped: " << message << endl;
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
auto failure_messages = results.failure_messages();
|
auto failure_messages = results.failure_messages();
|
||||||
if (failure_messages.size() > 0) {
|
if (failure_messages.size() > 0) {
|
||||||
os << "Failures:" << endl;
|
os << "Failures:" << endl;
|
||||||
for_each(failure_messages.begin(), failure_messages.end(),
|
for_each(failure_messages.begin(), failure_messages.end(), [&os](const string& message) {
|
||||||
[&os](const string &message) {
|
os << "❌FAILED: " << message << endl;
|
||||||
os << "❌FAILED: " << message << endl;
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
auto error_messages = results.error_messages();
|
auto error_messages = results.error_messages();
|
||||||
if (error_messages.size() > 0) {
|
if (error_messages.size() > 0) {
|
||||||
os << "Errors:" << endl;
|
os << "Errors:" << endl;
|
||||||
for_each(
|
for_each(error_messages.begin(), error_messages.end(), [&os](const string& message) {
|
||||||
error_messages.begin(), error_messages.end(),
|
os << "🔥ERROR: " << message << endl;
|
||||||
[&os](const string &message) { os << "🔥ERROR: " << message << endl; });
|
});
|
||||||
}
|
}
|
||||||
os << "Total tests: " << results.total() << endl;
|
os << "Total tests: " << results.total() << endl;
|
||||||
os << "Passed: " << results.passed() << " ✅" << endl;
|
os << "Passed: " << results.passed() << " ✅" << endl;
|
||||||
@@ -294,4 +312,4 @@ void PrintResults(std::ostream &os, TestResults results) {
|
|||||||
MaybeTestConfigureFunction DefaultTestConfigureFunction() {
|
MaybeTestConfigureFunction DefaultTestConfigureFunction() {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
} // End namespace Test
|
} // namespace TinyTest
|
||||||
@@ -52,14 +52,13 @@
|
|||||||
// Tuple printer from:
|
// Tuple printer from:
|
||||||
// https://stackoverflow.com/questions/6245735/pretty-print-stdtuple/31116392#58417285
|
// https://stackoverflow.com/questions/6245735/pretty-print-stdtuple/31116392#58417285
|
||||||
template <typename TChar, typename TTraits, typename... TArgs>
|
template <typename TChar, typename TTraits, typename... TArgs>
|
||||||
auto &operator<<(std::basic_ostream<TChar, TTraits> &os,
|
auto& operator<<(std::basic_ostream<TChar, TTraits>& os, std::tuple<TArgs...> const& t) {
|
||||||
std::tuple<TArgs...> const &t) {
|
std::apply([&os](auto&&... args) { ((os << args << " "), ...); }, t);
|
||||||
std::apply([&os](auto &&...args) { ((os << args << " "), ...); }, t);
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TChar, typename TTraits, typename TItem>
|
template <typename TChar, typename TTraits, typename TItem>
|
||||||
auto &operator<<(std::basic_ostream<TChar, TTraits> &os, std::vector<TItem> v) {
|
auto& operator<<(std::basic_ostream<TChar, TTraits>& os, std::vector<TItem> v) {
|
||||||
os << "[ ";
|
os << "[ ";
|
||||||
for (auto it = v.begin(); it != v.end(); it++) {
|
for (auto it = v.begin(); it != v.end(); it++) {
|
||||||
if (it != v.begin()) {
|
if (it != v.begin()) {
|
||||||
@@ -72,40 +71,38 @@ auto &operator<<(std::basic_ostream<TChar, TTraits> &os, std::vector<TItem> v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TChar, typename TTraits, typename TItem>
|
template <typename TChar, typename TTraits, typename TItem>
|
||||||
auto &compare(std::basic_ostream<TChar, TTraits> &error_message,
|
auto& compare(std::basic_ostream<TChar, TTraits>& error_message,
|
||||||
std::vector<TItem> expected, std::vector<TItem> actual) {
|
std::vector<TItem> expected,
|
||||||
|
std::vector<TItem> actual) {
|
||||||
if (expected.size() != actual.size()) {
|
if (expected.size() != actual.size()) {
|
||||||
error_message << "size mismatch expected: " << expected.size()
|
error_message << "size mismatch expected: " << expected.size() << ", actual: " << actual.size();
|
||||||
<< ", actual: " << actual.size();
|
|
||||||
return error_message;
|
return error_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t index = 0; index < expected.size(); index++) {
|
for (size_t index = 0; index < expected.size(); index++) {
|
||||||
if (expected[index] != actual[index]) {
|
if (expected[index] != actual[index]) {
|
||||||
error_message << "vectors differ at index " << index << ", \""
|
error_message << "vectors differ at index " << index << ", \"" << expected[index] << "\" != \"" << actual[index]
|
||||||
<< expected[index] << "\" != \"" << actual[index]
|
<< "\", expected: \"" << expected << "\", actual: \"" << actual << "\"";
|
||||||
<< "\", expected: \"" << expected << "\", actual: \""
|
|
||||||
<< actual << "\"";
|
|
||||||
return error_message;
|
return error_message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error_message;
|
return error_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Test {
|
namespace TinyTest {
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::tuple;
|
using std::tuple;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
/// @brief
|
/// @brief
|
||||||
class TestResults {
|
class TestResults {
|
||||||
public:
|
public:
|
||||||
/// @brief Creates an empty TestResults instance representing no tests run.
|
/// @brief Creates an empty TestResults instance representing no tests run.
|
||||||
TestResults();
|
TestResults();
|
||||||
|
|
||||||
/// @brief Creates a new TestResults instance that is a copy of other.
|
/// @brief Creates a new TestResults instance that is a copy of other.
|
||||||
/// @param other
|
/// @param other
|
||||||
TestResults(const TestResults &other);
|
TestResults(const TestResults& other);
|
||||||
|
|
||||||
/// @brief Creates a new TestResults instance with specific counts.
|
/// @brief Creates a new TestResults instance with specific counts.
|
||||||
/// @param errors The number of errors while running the tests.
|
/// @param errors The number of errors while running the tests.
|
||||||
@@ -117,45 +114,48 @@ public:
|
|||||||
/// @param error_messages The list of error messages.
|
/// @param error_messages The list of error messages.
|
||||||
/// @param failure_messages The list of failure messages.
|
/// @param failure_messages The list of failure messages.
|
||||||
/// @param skip_messages The list of skip messages.
|
/// @param skip_messages The list of skip messages.
|
||||||
TestResults(uint32_t errors, uint32_t failed, uint32_t passed,
|
TestResults(uint32_t errors,
|
||||||
uint32_t skipped, uint32_t total,
|
uint32_t failed,
|
||||||
|
uint32_t passed,
|
||||||
|
uint32_t skipped,
|
||||||
|
uint32_t total,
|
||||||
std::vector<std::string> error_messages,
|
std::vector<std::string> error_messages,
|
||||||
std::vector<std::string> failure_messages,
|
std::vector<std::string> failure_messages,
|
||||||
std::vector<std::string> skip_messages);
|
std::vector<std::string> skip_messages);
|
||||||
|
|
||||||
/// @brief Adds an error. This increments errors.
|
/// @brief Adds an error. This increments errors.
|
||||||
/// @return A reference to this instance. Used for chaining.
|
/// @return A reference to this instance. Used for chaining.
|
||||||
TestResults &error();
|
TestResults& error();
|
||||||
|
|
||||||
/// @brief Adds an error with a message. This increments errors as well as
|
/// @brief Adds an error with a message. This increments errors as well as
|
||||||
/// saving the error message.
|
/// saving the error message.
|
||||||
/// @param message The error message.
|
/// @param message The error message.
|
||||||
/// @return A reference to this instance. Used for chaining.
|
/// @return A reference to this instance. Used for chaining.
|
||||||
TestResults &error(std::string message);
|
TestResults& error(std::string message);
|
||||||
|
|
||||||
/// @brief Adds a failed test. This increments total and failed.
|
/// @brief Adds a failed test. This increments total and failed.
|
||||||
/// @return A reference to this instance. Used for chaining.
|
/// @return A reference to this instance. Used for chaining.
|
||||||
TestResults &fail();
|
TestResults& fail();
|
||||||
|
|
||||||
/// @brief Adds a failed test with a message. This increments total and failed
|
/// @brief Adds a failed test with a message. This increments total and failed
|
||||||
/// as well as saving the failure message.
|
/// as well as saving the failure message.
|
||||||
/// @param message The reason the test failed.
|
/// @param message The reason the test failed.
|
||||||
/// @return A reference to this instance. Used for chaining.
|
/// @return A reference to this instance. Used for chaining.
|
||||||
TestResults &fail(const std::string &message);
|
TestResults& fail(const std::string& message);
|
||||||
|
|
||||||
/// @brief Adds a passed test. This increments total and passed.
|
/// @brief Adds a passed test. This increments total and passed.
|
||||||
/// @return A reference to this instance. Used for chaining.
|
/// @return A reference to this instance. Used for chaining.
|
||||||
TestResults &pass();
|
TestResults& pass();
|
||||||
|
|
||||||
/// @brief Adds a skipped test. This increments total and skipped.
|
/// @brief Adds a skipped test. This increments total and skipped.
|
||||||
/// @return A reference to this instance. Used for chaining.
|
/// @return A reference to this instance. Used for chaining.
|
||||||
TestResults &skip();
|
TestResults& skip();
|
||||||
|
|
||||||
/// @brief Adds a skipped test with a message. This increments total and
|
/// @brief Adds a skipped test with a message. This increments total and
|
||||||
/// skipped as well as saving the skip message.
|
/// skipped as well as saving the skip message.
|
||||||
/// @param message The reason the test was skipped.
|
/// @param message The reason the test was skipped.
|
||||||
/// @return A reference to this instance. Used for chaining.
|
/// @return A reference to this instance. Used for chaining.
|
||||||
TestResults &skip(const std::string &message);
|
TestResults& skip(const std::string& message);
|
||||||
|
|
||||||
/// @brief Getter for the list of error messages.
|
/// @brief Getter for the list of error messages.
|
||||||
/// @return
|
/// @return
|
||||||
@@ -192,15 +192,15 @@ public:
|
|||||||
/// @brief Returns the combination of this and another TestResults instance.
|
/// @brief Returns the combination of this and another TestResults instance.
|
||||||
/// @param other The other TestResults instance to add to this one.
|
/// @param other The other TestResults instance to add to this one.
|
||||||
/// @return The combination of the two TestResults instances.
|
/// @return The combination of the two TestResults instances.
|
||||||
TestResults operator+(const TestResults &other) const;
|
TestResults operator+(const TestResults& other) const;
|
||||||
|
|
||||||
/// @brief Adds another TestResults to this one and returns a reference to
|
/// @brief Adds another TestResults to this one and returns a reference to
|
||||||
/// this instance.
|
/// this instance.
|
||||||
/// @param other The other TestResults instance to add to this one.
|
/// @param other The other TestResults instance to add to this one.
|
||||||
/// @return A reference to this instance.
|
/// @return A reference to this instance.
|
||||||
TestResults &operator+=(const TestResults &other);
|
TestResults& operator+=(const TestResults& other);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> error_messages_;
|
std::vector<std::string> error_messages_;
|
||||||
uint32_t errors_;
|
uint32_t errors_;
|
||||||
uint32_t failed_;
|
uint32_t failed_;
|
||||||
@@ -214,8 +214,7 @@ private:
|
|||||||
/// @brief
|
/// @brief
|
||||||
/// @tparam TResult
|
/// @tparam TResult
|
||||||
template <typename TResult>
|
template <typename TResult>
|
||||||
using TestCompareFunction =
|
using TestCompareFunction = std::function<bool(const TResult& expected, const TResult& actual)>;
|
||||||
std::function<bool(const TResult &expected, const TResult &actual)>;
|
|
||||||
|
|
||||||
/// @brief
|
/// @brief
|
||||||
/// @tparam TResult
|
/// @tparam TResult
|
||||||
@@ -263,11 +262,13 @@ using TestTuple =
|
|||||||
/// @tparam TFunctionToTest
|
/// @tparam TFunctionToTest
|
||||||
/// @tparam ...TInputParams
|
/// @tparam ...TInputParams
|
||||||
template <typename TResult, typename... TInputParams>
|
template <typename TResult, typename... TInputParams>
|
||||||
using TestSuite =
|
using TestSuite = std::tuple<std::string,
|
||||||
std::tuple<std::string, std::function<TResult(TInputParams...)>,
|
std::function<TResult(TInputParams...)>,
|
||||||
std::vector<TestTuple<TResult, TInputParams...>>,
|
std::vector<TestTuple<TResult, TInputParams...>>,
|
||||||
MaybeTestCompareFunction<TResult>, MaybeTestConfigureFunction,
|
MaybeTestCompareFunction<TResult>,
|
||||||
MaybeTestConfigureFunction, bool>;
|
MaybeTestConfigureFunction,
|
||||||
|
MaybeTestConfigureFunction,
|
||||||
|
bool>;
|
||||||
|
|
||||||
// This function is called to execute a test suite. You provide it with some
|
// This function is called to execute a test suite. You provide it with some
|
||||||
// configuration info, optional utility callback functions, and test data (input
|
// configuration info, optional utility callback functions, and test data (input
|
||||||
@@ -366,14 +367,13 @@ using TestSuite =
|
|||||||
/// @param is_enabled If false none of these tests are run and they are all
|
/// @param is_enabled If false none of these tests are run and they are all
|
||||||
/// reported as skipped.
|
/// reported as skipped.
|
||||||
template <typename TResult, typename... TInputParams>
|
template <typename TResult, typename... TInputParams>
|
||||||
TestResults
|
TestResults execute_suite(std::string suite_label,
|
||||||
execute_suite(std::string suite_label,
|
std::function<TResult(TInputParams...)> function_to_test,
|
||||||
std::function<TResult(TInputParams...)> function_to_test,
|
vector<TestTuple<TResult, TInputParams...>> tests,
|
||||||
vector<TestTuple<TResult, TInputParams...>> tests,
|
MaybeTestCompareFunction<TResult> suite_compare = std::nullopt,
|
||||||
MaybeTestCompareFunction<TResult> suite_compare = std::nullopt,
|
MaybeTestConfigureFunction before_all = std::nullopt,
|
||||||
MaybeTestConfigureFunction before_all = std::nullopt,
|
MaybeTestConfigureFunction after_all = std::nullopt,
|
||||||
MaybeTestConfigureFunction after_all = std::nullopt,
|
bool is_enabled = true) {
|
||||||
bool is_enabled = true) {
|
|
||||||
TestResults results;
|
TestResults results;
|
||||||
std::cout << "🚀Beginning Suite: " << suite_label << std::endl;
|
std::cout << "🚀Beginning Suite: " << suite_label << std::endl;
|
||||||
|
|
||||||
@@ -384,77 +384,74 @@ execute_suite(std::string suite_label,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Execute Tests
|
// Step 2: Execute Tests
|
||||||
for_each(
|
for_each(tests.begin(),
|
||||||
tests.begin(), tests.end(),
|
tests.end(),
|
||||||
[&suite_label, &function_to_test, &results,
|
[&suite_label, &function_to_test, &results, &suite_compare](TestTuple<TResult, TInputParams...> test_data) {
|
||||||
&suite_compare](TestTuple<TResult, TInputParams...> test_data) {
|
// Step 2a: Extract our variables from the TestTuple.
|
||||||
// Step 2a: Extract our variables from the TestTuple.
|
const std::string& test_name = std::get<0>(test_data);
|
||||||
const std::string &test_name = std::get<0>(test_data);
|
const std::string qualified_test_name = suite_label + "::" + test_name;
|
||||||
const std::string qualified_test_name = suite_label + "::" + test_name;
|
const TResult& expected_output = std::get<1>(test_data);
|
||||||
const TResult &expected_output = std::get<1>(test_data);
|
std::tuple<TInputParams...> input_params = std::get<2>(test_data);
|
||||||
std::tuple<TInputParams...> input_params = std::get<2>(test_data);
|
MaybeTestCompareFunction<TResult> maybe_compare_function = std::get<3>(test_data);
|
||||||
MaybeTestCompareFunction<TResult> maybe_compare_function =
|
TestCompareFunction<TResult> compare_function =
|
||||||
std::get<3>(test_data);
|
maybe_compare_function.has_value() ? *maybe_compare_function
|
||||||
TestCompareFunction<TResult> compare_function =
|
: suite_compare.has_value() ? *suite_compare
|
||||||
maybe_compare_function.has_value() ? *maybe_compare_function
|
: [](const TResult& l, const TResult& r) { return l == r; };
|
||||||
: suite_compare.has_value()
|
MaybeTestConfigureFunction before_each = std::get<4>(test_data);
|
||||||
? *suite_compare
|
MaybeTestConfigureFunction after_each = std::get<5>(test_data);
|
||||||
: [](const TResult &l, const TResult &r) { return l == r; };
|
bool is_enabled = std::get<6>(test_data);
|
||||||
MaybeTestConfigureFunction before_each = std::get<4>(test_data);
|
|
||||||
MaybeTestConfigureFunction after_each = std::get<5>(test_data);
|
|
||||||
bool is_enabled = std::get<6>(test_data);
|
|
||||||
|
|
||||||
if (!is_enabled) {
|
if (!is_enabled) {
|
||||||
std::cout << " 🚧Skipping Test: " << test_name << std::endl;
|
std::cout << " 🚧Skipping Test: " << test_name << std::endl;
|
||||||
results.skip(qualified_test_name);
|
results.skip(qualified_test_name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2b: Test Setup
|
// Step 2b: Test Setup
|
||||||
std::cout << " Beginning Test: " << test_name << std::endl;
|
std::cout << " Beginning Test: " << test_name << std::endl;
|
||||||
if (before_each.has_value()) {
|
if (before_each.has_value()) {
|
||||||
(*before_each)();
|
(*before_each)();
|
||||||
}
|
}
|
||||||
|
|
||||||
TResult actual;
|
TResult actual;
|
||||||
try {
|
try {
|
||||||
// Step 2c: Execute the test method.
|
// Step 2c: Execute the test method.
|
||||||
actual = std::apply(function_to_test, input_params);
|
actual = std::apply(function_to_test, input_params);
|
||||||
} catch (const std::exception &ex) {
|
} catch (const std::exception& ex) {
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "Caught exception \"" << ex.what() << "\"";
|
os << "Caught exception \"" << ex.what() << "\"";
|
||||||
results.error(qualified_test_name + " " + os.str());
|
results.error(qualified_test_name + " " + os.str());
|
||||||
std::cout << " 🔥ERROR: " << os.str() << std::endl;
|
std::cout << " 🔥ERROR: " << os.str() << std::endl;
|
||||||
} catch (const std::string &message) {
|
} catch (const std::string& message) {
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "Caught string \"" << message << "\"";
|
os << "Caught string \"" << message << "\"";
|
||||||
results.error(qualified_test_name + " " + os.str());
|
results.error(qualified_test_name + " " + os.str());
|
||||||
std::cout << " 🔥ERROR: " << os.str() << std::endl;
|
std::cout << " 🔥ERROR: " << os.str() << std::endl;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
string message = "Caught something that is neither an std::exception "
|
string message =
|
||||||
"nor an std::string.";
|
"Caught something that is neither an std::exception "
|
||||||
results.error(qualified_test_name + " " + message);
|
"nor an std::string.";
|
||||||
std::cout << " 🔥ERROR: " << message << std::endl;
|
results.error(qualified_test_name + " " + message);
|
||||||
}
|
std::cout << " 🔥ERROR: " << message << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
// Step 2d: Pass or fail.
|
// Step 2d: Pass or fail.
|
||||||
if (compare_function(expected_output, actual)) {
|
if (compare_function(expected_output, actual)) {
|
||||||
results.pass();
|
results.pass();
|
||||||
std::cout << " ✅PASSED" << std::endl;
|
std::cout << " ✅PASSED" << std::endl;
|
||||||
} else {
|
} else {
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "expected: \"" << expected_output << "\", actual: \"" << actual
|
os << "expected: \"" << expected_output << "\", actual: \"" << actual << "\"";
|
||||||
<< "\"";
|
results.fail(qualified_test_name + " " + os.str());
|
||||||
results.fail(qualified_test_name + " " + os.str());
|
std::cout << " ❌FAILED: " << os.str() << std::endl;
|
||||||
std::cout << " ❌FAILED: " << os.str() << std::endl;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2e: Test Teardown
|
// Step 2e: Test Teardown
|
||||||
if (after_each.has_value()) {
|
if (after_each.has_value()) {
|
||||||
(*after_each)();
|
(*after_each)();
|
||||||
}
|
}
|
||||||
std::cout << " Ending Test: " << test_name << std::endl;
|
std::cout << " Ending Test: " << test_name << std::endl;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Step 3: Suite Teardown
|
// Step 3: Suite Teardown
|
||||||
if (after_all.has_value()) {
|
if (after_all.has_value()) {
|
||||||
@@ -482,17 +479,15 @@ execute_suite(std::string suite_label,
|
|||||||
/// @param is_enabled If false the test is reported as skipped. If true the test
|
/// @param is_enabled If false the test is reported as skipped. If true the test
|
||||||
/// is run as normal.
|
/// is run as normal.
|
||||||
template <typename TResult, typename... TInputParams>
|
template <typename TResult, typename... TInputParams>
|
||||||
TestResults
|
TestResults execute_suite(std::string suite_label,
|
||||||
execute_suite(std::string suite_label,
|
std::function<TResult(TInputParams...)> function_to_test,
|
||||||
std::function<TResult(TInputParams...)> function_to_test,
|
std::initializer_list<TestTuple<TResult, TInputParams...>> tests,
|
||||||
std::initializer_list<TestTuple<TResult, TInputParams...>> tests,
|
MaybeTestCompareFunction<TResult> suite_compare = std::nullopt,
|
||||||
MaybeTestCompareFunction<TResult> suite_compare = std::nullopt,
|
MaybeTestConfigureFunction before_all = std::nullopt,
|
||||||
MaybeTestConfigureFunction before_all = std::nullopt,
|
MaybeTestConfigureFunction after_all = std::nullopt,
|
||||||
MaybeTestConfigureFunction after_all = std::nullopt,
|
bool is_enabled = true) {
|
||||||
bool is_enabled = true) {
|
|
||||||
std::vector test_data = std::vector(tests);
|
std::vector test_data = std::vector(tests);
|
||||||
return execute_suite(suite_label, function_to_test, tests, suite_compare,
|
return execute_suite(suite_label, function_to_test, tests, suite_compare, before_all, after_all, is_enabled);
|
||||||
before_all, after_all, is_enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief
|
/// @brief
|
||||||
@@ -516,15 +511,14 @@ execute_suite(std::string suite_label,
|
|||||||
/// skipped for reporting purposes.
|
/// skipped for reporting purposes.
|
||||||
/// @return A TestTuple suitable for use as a test run when calling test_fn.
|
/// @return A TestTuple suitable for use as a test run when calling test_fn.
|
||||||
template <typename TResult, typename... TInputParams>
|
template <typename TResult, typename... TInputParams>
|
||||||
TestTuple<TResult, TInputParams...>
|
TestTuple<TResult, TInputParams...> make_test(const string& test_name,
|
||||||
make_test(const string &test_name, const TResult &expected,
|
const TResult& expected,
|
||||||
tuple<TInputParams...> input_params,
|
tuple<TInputParams...> input_params,
|
||||||
MaybeTestCompareFunction<TResult> test_compare_fn = std::nullopt,
|
MaybeTestCompareFunction<TResult> test_compare_fn = std::nullopt,
|
||||||
MaybeTestConfigureFunction before_each = std::nullopt,
|
MaybeTestConfigureFunction before_each = std::nullopt,
|
||||||
MaybeTestConfigureFunction after_each = std::nullopt,
|
MaybeTestConfigureFunction after_each = std::nullopt,
|
||||||
bool is_enabled = true) {
|
bool is_enabled = true) {
|
||||||
return make_tuple(test_name, expected, input_params, test_compare_fn,
|
return make_tuple(test_name, expected, input_params, test_compare_fn, before_each, after_each, is_enabled);
|
||||||
before_each, after_each, is_enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief
|
/// @brief
|
||||||
@@ -540,27 +534,26 @@ make_test(const string &test_name, const TResult &expected,
|
|||||||
/// @param is_enabled
|
/// @param is_enabled
|
||||||
/// @return
|
/// @return
|
||||||
template <typename TResult, typename TFunctionToTest, typename... TInputParams>
|
template <typename TResult, typename TFunctionToTest, typename... TInputParams>
|
||||||
TestSuite<TResult, TInputParams...>
|
TestSuite<TResult, TInputParams...> make_test_suite(const string& suite_name,
|
||||||
make_test_suite(const string &suite_name, TFunctionToTest function_to_test,
|
TFunctionToTest function_to_test,
|
||||||
vector<TestTuple<TResult, TInputParams...>> test_data,
|
vector<TestTuple<TResult, TInputParams...>> test_data,
|
||||||
MaybeTestCompareFunction<TResult> compare = std::nullopt,
|
MaybeTestCompareFunction<TResult> compare = std::nullopt,
|
||||||
MaybeTestConfigureFunction before_each = std::nullopt,
|
MaybeTestConfigureFunction before_each = std::nullopt,
|
||||||
MaybeTestConfigureFunction after_each = std::nullopt,
|
MaybeTestConfigureFunction after_each = std::nullopt,
|
||||||
bool is_enabled = true) {
|
bool is_enabled = true) {
|
||||||
return make_tuple(suite_name, function_to_test, test_data, compare,
|
return make_tuple(suite_name, function_to_test, test_data, compare, before_each, after_each, is_enabled);
|
||||||
before_each, after_each, is_enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TResult, typename TFunctionToTest, typename... TInputParams>
|
template <typename TResult, typename TFunctionToTest, typename... TInputParams>
|
||||||
TestSuite<TResult, TInputParams...> make_test_suite(
|
TestSuite<TResult, TInputParams...> make_test_suite(
|
||||||
const string &suite_name, TFunctionToTest function_to_test,
|
const string& suite_name,
|
||||||
|
TFunctionToTest function_to_test,
|
||||||
std::initializer_list<TestTuple<TResult, TInputParams...>> test_data,
|
std::initializer_list<TestTuple<TResult, TInputParams...>> test_data,
|
||||||
MaybeTestCompareFunction<TResult> compare = std::nullopt,
|
MaybeTestCompareFunction<TResult> compare = std::nullopt,
|
||||||
MaybeTestConfigureFunction before_each = std::nullopt,
|
MaybeTestConfigureFunction before_each = std::nullopt,
|
||||||
MaybeTestConfigureFunction after_each = std::nullopt,
|
MaybeTestConfigureFunction after_each = std::nullopt,
|
||||||
bool is_enabled = true) {
|
bool is_enabled = true) {
|
||||||
return make_tuple(suite_name, function_to_test, test_data, compare,
|
return make_tuple(suite_name, function_to_test, test_data, compare, before_each, after_each, is_enabled);
|
||||||
before_each, after_each, is_enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief
|
/// @brief
|
||||||
@@ -568,8 +561,7 @@ TestSuite<TResult, TInputParams...> make_test_suite(
|
|||||||
/// @tparam TInputParams... The types of parameters sent to the test function.
|
/// @tparam TInputParams... The types of parameters sent to the test function.
|
||||||
/// @param test_suite A tuple representing the test suite configuration.
|
/// @param test_suite A tuple representing the test suite configuration.
|
||||||
template <typename TResult, typename... TInputParams>
|
template <typename TResult, typename... TInputParams>
|
||||||
TestResults
|
TestResults execute_suite(const TestSuite<TResult, TInputParams...>& test_suite) {
|
||||||
execute_suite(const TestSuite<TResult, TInputParams...> &test_suite) {
|
|
||||||
return execute_suite<TResult, TInputParams...>(
|
return execute_suite<TResult, TInputParams...>(
|
||||||
std::get<0>(test_suite), std::get<1>(test_suite), std::get<2>(test_suite)
|
std::get<0>(test_suite), std::get<1>(test_suite), std::get<2>(test_suite)
|
||||||
// TODO: make this work for the optional parts of the tuple too.
|
// TODO: make this work for the optional parts of the tuple too.
|
||||||
@@ -582,8 +574,7 @@ execute_suite(const TestSuite<TResult, TInputParams...> &test_suite) {
|
|||||||
/// @param second
|
/// @param second
|
||||||
/// @return
|
/// @return
|
||||||
template <typename... TInputParams>
|
template <typename... TInputParams>
|
||||||
MaybeTestConfigureFunction coalesce(MaybeTestConfigureFunction first,
|
MaybeTestConfigureFunction coalesce(MaybeTestConfigureFunction first, MaybeTestConfigureFunction second) {
|
||||||
MaybeTestConfigureFunction second) {
|
|
||||||
if (first.has_value()) {
|
if (first.has_value()) {
|
||||||
if (second.has_value()) {
|
if (second.has_value()) {
|
||||||
// This is the only place we actually need to combine them.
|
// This is the only place we actually need to combine them.
|
||||||
@@ -602,8 +593,8 @@ MaybeTestConfigureFunction coalesce(MaybeTestConfigureFunction first,
|
|||||||
/// @brief Writes a friendly version of results to the provided stream.
|
/// @brief Writes a friendly version of results to the provided stream.
|
||||||
/// @param os The stream to write to.
|
/// @param os The stream to write to.
|
||||||
/// @param results The TestResults to write.
|
/// @param results The TestResults to write.
|
||||||
void PrintResults(std::ostream &os, TestResults results);
|
void PrintResults(std::ostream& os, TestResults results);
|
||||||
} // End namespace Test
|
} // End namespace TinyTest
|
||||||
|
|
||||||
// TODO: Add TShared(*)(string /*test_name*/, UUID /*test_run_id*/)
|
// TODO: Add TShared(*)(string /*test_name*/, UUID /*test_run_id*/)
|
||||||
// allocate_shared_data to the test tuple to make some shared data that can be
|
// allocate_shared_data to the test tuple to make some shared data that can be
|
||||||
@@ -616,4 +607,4 @@ void PrintResults(std::ostream &os, TestResults results);
|
|||||||
// then the allocated resources they should be freed by test teardown
|
// then the allocated resources they should be freed by test teardown
|
||||||
// function. Suite and/or test compare functions may consume this shared data,
|
// function. Suite and/or test compare functions may consume this shared data,
|
||||||
// but it will not be shared with the execution of function_to_test.
|
// but it will not be shared with the execution of function_to_test.
|
||||||
#endif // End !defined TEST_H__
|
#endif // End !defined TEST_H__
|
||||||
Reference in New Issue
Block a user