Browse Source

set up testing for libswan

I haven't actually written any tests yet, but now I can at least
easily write tests when I want to. Also, just having one
.t.cc file for each header means we get to test each header
in isolation, to prevent include order issues.
opengl-renderer-broken
Martin Dørum 4 years ago
parent
commit
93e66ff73f

+ 26
- 0
libswan/CMakeLists.txt View File

@@ -19,3 +19,29 @@ set_target_properties(libswan PROPERTIES OUTPUT_NAME swan)
target_link_libraries(libswan ${libraries})

install(TARGETS libswan DESTINATION swan/libswan)

add_executable(test_libswan
test/lib/test.cc
test/Animation.t.cc
test/Body.t.cc
test/BoundingBox.t.cc
test/common.t.cc
test/Entity.t.cc
test/Game.t.cc
test/Item.t.cc
test/Mod.t.cc
test/OS.t.cc
test/Resource.t.cc
test/SRF.t.cc
test/swan.t.cc
test/Tile.t.cc
test/Timer.t.cc
test/util.t.cc
test/Vector2.t.cc
test/Win.t.cc
test/World.t.cc
test/WorldGen.t.cc
test/WorldPlane.t.cc)
target_link_libraries(test_libswan libswan)
target_include_directories(test_libswan
PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include/swan")

+ 3
- 0
libswan/test/Animation.t.cc View File

@@ -0,0 +1,3 @@
#include "Animation.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Body.t.cc View File

@@ -0,0 +1,3 @@
#include "Body.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/BoundingBox.t.cc View File

@@ -0,0 +1,3 @@
#include "BoundingBox.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Entity.t.cc View File

@@ -0,0 +1,3 @@
#include "Entity.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Game.t.cc View File

@@ -0,0 +1,3 @@
#include "Game.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Item.t.cc View File

@@ -0,0 +1,3 @@
#include "Item.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Mod.t.cc View File

@@ -0,0 +1,3 @@
#include "Mod.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/OS.t.cc View File

@@ -0,0 +1,3 @@
#include "OS.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Resource.t.cc View File

@@ -0,0 +1,3 @@
#include "Resource.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/SRF.t.cc View File

@@ -0,0 +1,3 @@
#include "SRF.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Tile.t.cc View File

@@ -0,0 +1,3 @@
#include "Tile.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Timer.t.cc View File

@@ -0,0 +1,3 @@
#include "Timer.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Vector2.t.cc View File

@@ -0,0 +1,3 @@
#include "Vector2.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/Win.t.cc View File

@@ -0,0 +1,3 @@
#include "Win.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/World.t.cc View File

@@ -0,0 +1,3 @@
#include "World.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/WorldGen.t.cc View File

@@ -0,0 +1,3 @@
#include "WorldGen.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/WorldPlane.t.cc View File

@@ -0,0 +1,3 @@
#include "WorldPlane.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/common.t.cc View File

@@ -0,0 +1,3 @@
#include "common.h"

#include "lib/test.h"

+ 114
- 0
libswan/test/lib/test.cc View File

@@ -0,0 +1,114 @@
#include "test.h"

#include <stdlib.h>
#include <string_view>
#include <vector>
#include <algorithm>
#include <iostream>
#include <sstream>

namespace testlib {

static const std::string color_reset = "\033[0m";
static const std::string color_highlight = "\033[1m";
static const std::string color_testing = color_highlight;
static const std::string color_desc = "\033[33m";
static const std::string color_maybe = "\033[35m";
static const std::string color_success = "\033[32m";
static const std::string color_fail = "\033[31m";
static const std::string color_errormsg = "\033[95m";

std::string color(const std::string &color, std::string_view str) {
return std::string(color) + std::string(str) + std::string(color_reset);
}

struct TestCase {
TestCase(TestSpec *spec):
func(spec->func), description(spec->description),
filename(spec->filename), linenum(spec->linenum), index(spec->index) {}

void (*func)();
std::string_view description;
std::string_view filename;
int linenum;
int index;
};

static std::vector<TestCase> cases;

void addTestCase(TestSpec *testcase) {
cases.emplace_back(testcase);
}

static std::stringstream printFailure(const std::string &msg) {
std::stringstream str;
str
<< "\r" << color(color_highlight + color_fail, "✕ ")
<< color(color_fail, "Failed: ") << "\n"
<< " " << msg << "\n";
return str;
}

static std::stringstream printFailure(const TestFailure &failure) {
std::stringstream str;
str
<< printFailure(failure.message).str()
<< " at " << failure.filename << ":" << failure.linenum << "\n";
return str;
}

}

int main() {
using namespace testlib;

std::sort(begin(cases), end(cases), [](TestCase &a, TestCase &b) {
if (a.filename != b.filename)
return a.filename < b.filename;
return a.index < b.index;
});

std::string_view currfile = "";
bool failed = false;
for (TestCase &testcase: cases) {
if (currfile != testcase.filename) {
currfile = testcase.filename;
size_t lastslash = currfile.find_last_of('/');
std::cout << '\n' << color(color_testing, currfile.substr(lastslash + 1)) << ":\n";
}

std::cout
<< color(color_highlight + color_maybe, "? ")
<< color(color_maybe, "Testing: ")
<< color(color_desc, testcase.description) << " " << std::flush;

try {
testcase.func();
std::cout
<< "\r" << color(color_highlight + color_success, "✓ ")
<< color(color_success, "Success: ") << "\n";
} catch (const TestFailure &failure) {
failed = true;
std::cout << printFailure(failure).str();
} catch (const std::exception &ex) {
failed = true;
std::cout << printFailure(ex.what()).str();
} catch (const std::string &str) {
failed = true;
std::cout << printFailure(str).str();
} catch (const char *str) {
failed = true;
std::cout << printFailure(str).str();
} catch (...) {
failed = true;
std::cout << printFailure("Unknown error.").str();
}
}

std::cout << '\n';

if (failed)
return EXIT_FAILURE;

return EXIT_SUCCESS;
}

+ 61
- 0
libswan/test/lib/test.h View File

@@ -0,0 +1,61 @@
#pragma once

#include <string>

namespace testlib {

struct TestFailure {
TestFailure(const char *msg, const char *file, int line):
message(msg), filename(file), linenum(line) {}

const char *message;
const char *filename;
int linenum;
};

struct TestSpec;
void addTestCase(TestSpec *testcase);

struct TestSpec {
TestSpec(void (*f)(), const char *desc, const char *file, int line, int idx):
func(f), description(desc), filename(file), linenum(line), index(idx) {
addTestCase(this);
}

void (*func)();
const char *description;
const char *filename;
int linenum;
int index;
};

}

#define test3(name, id) name ## id
#define test2(uniqid, desc) \
static void test3(_test_func_, uniqid)(); \
static __attribute__((unused)) testlib::TestSpec test3(_test_register_, uniqid)( \
&test3(_test_func_, uniqid), desc, __FILE__, __LINE__, uniqid); \
static void test3(_test_func_, uniqid)()
#define test(desc) test2(__COUNTER__, desc)

#define expect(expr) do { \
if (!(expr)) { \
throw testlib::TestFailure( \
"Expected '" #expr "' to be true.", __FILE__, __LINE__); \
} \
} while (0)

#define expecteq(a, b) do { \
if ((a) != (b)) { \
throw testlib::TestFailure( \
"Expected '" #a "' to equal '" #b "'.", __FILE__, __LINE__); \
} \
} while (0)

#define expectneq(a, b) do { \
if ((a) == (b)) { \
throw testlib::TestFailure( \
"Expected '" #a "' to not equal '" #b "'.", __FILE__, __LINE__); \
} \
} while (0)

+ 3
- 0
libswan/test/swan.t.cc View File

@@ -0,0 +1,3 @@
#include "swan.h"

#include "lib/test.h"

+ 3
- 0
libswan/test/util.t.cc View File

@@ -0,0 +1,3 @@
#include "util.h"

#include "lib/test.h"

Loading…
Cancel
Save