Skip to content

Commit

Permalink
Add support for multi object builds
Browse files Browse the repository at this point in the history
  • Loading branch information
mls-m5 committed Aug 24, 2023
1 parent 42d8a08 commit 30262d8
Show file tree
Hide file tree
Showing 9 changed files with 382 additions and 160 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@

example1-basic
example2-mocks

.qtc_clangd/
test_main

17 changes: 10 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
SRC = $(wildcard *.cpp *.h)

all: example1-basic example2-mocks
all: test_main

example1-basic: $(SRC)
g++ example1-basic.cpp -o example1-basic --std=c++14 -g
example1-basic.o: $(SRC)
g++ example1-basic.cpp -c -o example1-basic.o --std=c++17 -g

example2-mocks.o: $(SRC)
g++ example2-mocks.cpp -c -o example2-mocks.o --std=c++17 -g

example2-mocks: $(SRC)
g++ example2-mocks.cpp -o example2-mocks --std=c++14 -g
test_main: example1-basic.o example2-mocks.o test_main.cpp
g++ example1-basic.o example2-mocks.o test_main.cpp -o test_main --std=c++17 -g

clean:
rm -f example1-basic example2-mocks
rm -f example1-basic.o example2-mocks.o test_main
2 changes: 1 addition & 1 deletion example1-basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <limits>
#include <memory>

TEST_SUIT_BEGIN
TEST_SUIT_BEGIN(Example1)

TEST_CASE("Bool assertions") {
struct S {};
Expand Down
2 changes: 1 addition & 1 deletion example2-mocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ struct B {
// Begining of actual test code
// This is what is supposed to be in a test file

TEST_SUIT_BEGIN
TEST_SUIT_BEGIN(Mocks)

SETUP {
// Do setup required by the test, or just ommit this function
Expand Down
137 changes: 137 additions & 0 deletions expect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#pragma once

#define PRINT_INFO std::cout << __FILE__ << ":" << __LINE__ << ": ";
#define ASSERT(test_var_x, error) \
if (!(test_var_x)) { \
PRINT_INFO; \
unittest::testResult++; \
std::cout << #test_var_x << ": " << error << std::endl; \
return; \
} \
unittest::semicolon()

#define EXPECT(test_var_x) ASSERT(test_var_x, "expression is not true")

// Support old syntax
#define ASSERT_EQ EXPECT_EQ
#define ASSERT_NE EXPECT_NE
#define ASSERT_GT EXPECT_GT
#define ASSERT_LT EXPECT_LT
#define ASSERT_NEAR EXPECT_LT

#define EXPECT_EQ(test_var_x, test_var_y) \
if (!((test_var_x) == (test_var_y))) { \
PRINT_INFO; \
unittest::testResult++; \
std::cout << #test_var_x << " = '" << test_var_x \
<< "' is not equal to " << #test_var_y << " = '" \
<< test_var_y << "'" << std::endl; \
unittest::testResult++; \
return; \
} \
unittest::semicolon()

#define EXPECT_NE(test_var_x, test_var_y) \
if ((test_var_x) == (test_var_y)) { \
PRINT_INFO; \
std::cout << #test_var_x << " = " << test_var_x << " is equal to " \
<< #test_var_y << " = " << test_var_y << std::endl; \
unittest::testResult++; \
return; \
} \
unittest::semicolon()

#define EXPECT_GT(test_var_x, test_var_y) \
if (!((test_var_x) > (test_var_y))) { \
PRINT_INFO; \
std::cout << #test_var_x << " = " << test_var_x \
<< " is not greater than " << #test_var_y << " = " \
<< test_var_y << std::endl; \
unittest::testResult++; \
return; \
} \
unittest::semicolon()

#define EXPECT_LT(test_var_x, test_var_y) \
if (!((test_var_x) < (test_var_y))) { \
PRINT_INFO; \
std::cout << #test_var_x << " = " << test_var_x \
<< " is not less than " << #test_var_y << " = " \
<< test_var_y << std::endl; \
unittest::testResult++; \
return; \
} \
unittest::semicolon()

#define EXPECT_NEAR(test_var_x, test_var_y, test_var_e) \
{ \
auto a = (test_var_x); \
auto b = (test_var_y); \
if (a + test_var_e < b || a > b + test_var_e) { \
PRINT_INFO; \
std::cout << #test_var_x << " == " << test_var_x \
<< " is not near " << #test_var_y << std::endl; \
++testResult; \
return; \
} \
} \
unittest::semicolon()

#define EXPECT_TRUE(expression) \
{ \
auto test_var_x = static_cast<bool>(expression); \
if (!test_var_x) { \
PRINT_INFO; \
std::cout << #expression << " == " << test_var_x \
<< " is not true as expected " << std::endl; \
++unittest::testResult; \
return; \
} \
} \
unittest::semicolon()

#define EXPECT_FALSE(expression) \
{ \
auto test_var_x = static_cast<bool>(expression); \
if (test_var_x) { \
PRINT_INFO; \
std::cout << #expression << " == " << test_var_x \
<< " is not false as expected " << std::endl; \
++unittest::testResult; \
return; \
} \
} \
unittest::semicolon()

#define EXPECT_THROW(expression, error) \
{ \
bool threw = false; \
try { \
expression; \
} \
catch (error & e) { \
threw = true; \
} \
if (!threw) { \
std::cout << "Expected exeption " << #error << ": got none" \
<< std::endl; \
unittest::testResult++; \
return; \
} \
} \
unittest::semicolon()

#define ERROR(error) \
PRINT_INFO; \
std::cout << error << std::endl; \
unittest::testResult++; \
return; \
unittest::semicolon()

// The not implemented error is used to flag for wanted features not implemented
#define ERROR_NOT_IMPLEMENTED() \
PRINT_INFO; \
std::cout << "not implemented" << std::endl; \
testResult = -1; \
return; \
unittest::semicolon()
193 changes: 193 additions & 0 deletions registertest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
#pragma once

#include <functional>
#include <iostream>
#include <list>
#include <string>
#include <string_view>

namespace unittest {

struct StaticTestSuit;

struct Tests {

Tests() = default;
Tests(const Tests &) = delete;
Tests(Tests &&) = delete;
Tests &operator=(const Tests &) = delete;
Tests &operator=(Tests &&) = delete;
~Tests();

static Tests &instance() {
static Tests reg{};
return reg;
}

void run();

std::vector<StaticTestSuit *> tests;
};

struct StaticTestSuit {
StaticTestSuit() {
Tests::instance().tests.push_back(this);
}

struct TestEntry {
std::string suit;
std::string name;
std::function<void()> f = {};
std::string result = {};
};

/// List instead of vector to keep position in memory
std::list<TestEntry> entries;

std::string testSuitName;
int testResult = 0;

std::function<void()> &newTest(std::string testName) {
return add(testSuitName, testName);
}

std::function<void()> &add(std::string_view suitName,
std::string_view testName) {
entries.push_back({
.suit = std::string{suitName},
.name = std::string{testName},
});
return entries.back().f;
}

int run() {
using std::cout;
using std::endl;
int numFailed = 0;
int numSucceded = 0;
int numInactive = 0;

// if (!parseArguments(argc, argv)) {
// return 0;
// }

// if (setup) {
// setup();
// }

cout << "==== Starts test suit " << testSuitName << " ====" << endl
<< endl;

for (auto &it : entries) {
if (it.name.rfind("disabled ", 0) == 0) {
it.result = "disabled";
// it.result = "disabled";
++numInactive;
continue;
}

cout << "=== running test: " << it.name << " ===" << endl;
testResult = 0;

#ifdef DO_NOT_CATCH_ERRORS
it.f();
#else
try {
it.f();
}
catch (std::exception &e) {
std::cerr << "error: " << e.what() << endl;
testResult = -2;
}
catch (const char *c) {
std::cerr << "error: " << c << endl;
testResult = -2;
}
catch (const std::string &what) {
std::cerr << "error: " << what << endl;
testResult = -2;
}
catch (...) {
std::cerr << "error" << endl;
testResult = -2;
}
#endif
if (testResult == -1) {
cout << " --> not impl" << endl << endl;
it.result = "not implemented";
}
if (testResult == -2) {
cout << " --> crashed" << endl << endl;
++numFailed;
it.result = "crashed!";
}
else if (testResult) {
cout << " --> failed" << endl << endl << endl << endl;
numFailed++;
it.result = "fail";
}
else {
cout << " --> success " << endl << endl << endl << endl;
it.result = "pass";
numSucceded++;
}
}

cout << endl;
cout << "==== results: ===============================" << endl;
for (auto &it : entries) {
cout << it.result;
for (auto i = it.result.size(); i < 15; ++i) {
cout << " ";
}
if (it.name.rfind("disabled ", 0) == 0) {
cout << " " << it.name.substr(9) << "\n";
}
else {
cout << " " << it.name << "\n";
}
}
cout << endl;
if (numFailed) {
cout << "TEST FAILED...";
}
else {
cout << "SUCCESS...";
}
cout << "\n";
if (numInactive) {
cout << "(Disabled: " << numInactive << ") ";
}
cout << "Failed: " << numFailed << " Passed: " << numSucceded << endl;

return numFailed > 0;
}
};

// struct RegisterTestStatic {
// Tests::TestEntry &entry;

// RegisterTestStatic(const RegisterTestStatic &) = default;
// RegisterTestStatic(RegisterTestStatic &&) = default;
// RegisterTestStatic &operator=(const RegisterTestStatic &) = delete;
// RegisterTestStatic &operator=(RegisterTestStatic &&) = delete;
// ~RegisterTestStatic();

// RegisterTestStatic(std::string_view suitName, std::string_view testName)
// : entry{Tests::instance().add(suitName, testName)} {}

// RegisterTestStatic &operator=(std::function<void()> f) {
// entry.f = f;
// return *this;
// }
//};

inline Tests::~Tests() = default;

inline void Tests::run() {
for (auto &test : tests) {
test->run();
}
}

} // namespace unittest
7 changes: 7 additions & 0 deletions test_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "unittest.h"

int main(int argc, char **argv) {
using namespace unittest;

Tests::instance().run();
}
Loading

0 comments on commit 30262d8

Please sign in to comment.