summaryrefslogtreecommitdiff
path: root/c++/test/suite.cpp
blob: 0fca8f9036a6c4f7b3ca7a25893247e88b7d24f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "suite.h"

#include <map>
#include <string>
#include <chrono>
#include <iostream>

namespace saw {
namespace test {
	test_case* testCaseHead = nullptr;
	test_case** testCaseTail = &testCaseHead;

	test_case::test_case(const std::string& file_, uint line_, const std::string& description_):
		file{file_},
		line{line_},
		description{description_},
		matched_filter{false},
		next{nullptr},
		prev{testCaseTail}
	{
		*prev = this;
		testCaseTail = &next;
	}

	test_case::~test_case(){
		*prev = next;
		if( next == nullptr ){
			testCaseTail = prev;
		}else{
			next->prev = prev;
		}
	}

	class test_runner {
	private:
		enum Colour {
			RED,
			GREEN,
			BLUE,
			WHITE
		};

		void write(Colour colour, const std::string& front, const std::string& message){
			std::string start_col, end_col;
			switch(colour){
				case RED: start_col = "\033[0;1;31m"; break;
				case GREEN: start_col = "\033[0;1;32m"; break;
				case BLUE: start_col = "\033[0;1;34m"; break;
				case WHITE: start_col = "\033[0m"; break;
			}
			end_col = "\033[0m";
			std::cout<<start_col<<front<<end_col<<message<<'\n';
		}	
	public:
		void allowAll(){
			for(test_case* testCase = testCaseHead; testCase != nullptr; testCase = testCase->next){
				testCase->matched_filter = true;
			}
		}

		int run() {
			size_t passed_count = 0;
			size_t failed_count = 0;
			
			for(test_case* testCase = testCaseHead; testCase != nullptr; testCase =testCase->next){
				if(testCase->matched_filter){
					std::string name = testCase->file + std::string(":") + std::to_string(testCase->line) + std::string(": ") + testCase->description;
					write(BLUE, "[ TEST ] ", name);
					bool failed = true;
					std::string fail_message;
					auto start_clock = std::chrono::steady_clock::now();
					try {
						testCase->run();
						failed = false;
					}catch(std::exception& e){
						fail_message = e.what();
						failed = true;
					}
					auto stop_clock = std::chrono::steady_clock::now();

					auto runtime_duration_intern = stop_clock - start_clock;
					auto runtime_duration = std::chrono::duration_cast<std::chrono::microseconds>(runtime_duration_intern);
					std::string message = name + std::string(" (") + std::to_string(runtime_duration.count()) + std::string(" µs)");
					if(failed){
						write(RED, "[ FAIL ] ", message + " " + fail_message);
						++failed_count;
					}else{
						write(GREEN, "[ PASS ] ", message);
						++passed_count;
					}
				}
			}

			if(passed_count>0) write(GREEN, std::to_string(passed_count) + std::string(" test(s) passed"), "");
			if(failed_count>0) write(RED, std::to_string(failed_count) + std::string(" test(s) failed"), "");
			return -failed_count;
		}
	};
}
}

int main() {
	saw::test::test_runner runner;
	runner.allowAll();
	int rv = runner.run();
	return rv<0?-1:0;
}