initial base commit
This commit is contained in:
parent
d1dad7e64e
commit
da6314f6ac
|
@ -0,0 +1,58 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import glob
|
||||||
|
import re
|
||||||
|
|
||||||
|
if sys.version_info < (3,):
|
||||||
|
def isbasestring(s):
|
||||||
|
return isinstance(s,basestring)
|
||||||
|
else:
|
||||||
|
def isbasestring(s):
|
||||||
|
return isinstance(s, (str,bytes))
|
||||||
|
|
||||||
|
def add_kel_source_files(self, sources, filetype, lib_env=None, shared=False, target_post=""):
|
||||||
|
|
||||||
|
if isbasestring(filetype):
|
||||||
|
dir_path = self.Dir('.').abspath
|
||||||
|
filetype = sorted(glob.glob(dir_path+"/"+filetype))
|
||||||
|
|
||||||
|
for path in filetype:
|
||||||
|
target_name = re.sub( r'(.*?)(\.cpp|\.c\+\+)', r'\1' + target_post, path )
|
||||||
|
if shared:
|
||||||
|
target_name+='.os'
|
||||||
|
sources.append( self.SharedObject( target=target_name, source=path ) )
|
||||||
|
else:
|
||||||
|
target_name+='.o'
|
||||||
|
sources.append( self.StaticObject( target=target_name, source=path ) )
|
||||||
|
pass
|
||||||
|
|
||||||
|
env=Environment(CPPPATH=['#source'],
|
||||||
|
CXX='clang++',
|
||||||
|
CPPDEFINES=['GIN_UNIX'],
|
||||||
|
CXXFLAGS=['-std=c++17','-g','-Wall','-Wextra'],
|
||||||
|
LIBS=[])
|
||||||
|
env.__class__.add_source_files = add_kel_source_files
|
||||||
|
|
||||||
|
env.sources = []
|
||||||
|
env.headers = []
|
||||||
|
env.objects = []
|
||||||
|
|
||||||
|
Export('env')
|
||||||
|
SConscript('source/SConscript')
|
||||||
|
SConscript('test/SConscript')
|
||||||
|
|
||||||
|
# Clang format part
|
||||||
|
env.Append(BUILDERS={'ClangFormat' : Builder(action = 'clang-format --style=file -i $SOURCE')})
|
||||||
|
env.format_actions = []
|
||||||
|
def format_iter(env,files):
|
||||||
|
for f in files:
|
||||||
|
env.format_actions.append(env.AlwaysBuild(env.ClangFormat(target=f+"-clang-format",source=f)))
|
||||||
|
pass
|
||||||
|
|
||||||
|
format_iter(env,env.sources + env.headers)
|
||||||
|
|
||||||
|
env.Alias('format', env.format_actions)
|
||||||
|
env.Alias('test', env.test_program)
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/false
|
||||||
|
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import glob
|
||||||
|
|
||||||
|
|
||||||
|
Import('env')
|
||||||
|
|
||||||
|
dir_path = Dir('.').abspath
|
||||||
|
|
||||||
|
env.sources += sorted(glob.glob(dir_path + "/*.cpp"))
|
||||||
|
env.headers += sorted(glob.glob(dir_path + "/*.h"))
|
||||||
|
|
||||||
|
env.add_source_files(env.objects, env.sources)
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import glob
|
||||||
|
|
||||||
|
Import('env')
|
||||||
|
|
||||||
|
dir_path = Dir('.').abspath
|
||||||
|
env.test_sources = sorted(glob.glob(dir_path + "/*.cpp"))
|
||||||
|
|
||||||
|
env_test = env.Clone()
|
||||||
|
env.test_objects = []
|
||||||
|
env.test_sources.append(dir_path+'/suite/suite.cpp')
|
||||||
|
|
||||||
|
env.test_program = env_test.Program('#bin/test', [env.test_sources, env.objects])
|
|
@ -0,0 +1,108 @@
|
||||||
|
#include "suite.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace ent {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
TestCase* testCaseHead = nullptr;
|
||||||
|
TestCase** testCaseTail = &testCaseHead;
|
||||||
|
|
||||||
|
TestCase::TestCase(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCase::~TestCase(){
|
||||||
|
*prev = next;
|
||||||
|
if( next == nullptr ){
|
||||||
|
testCaseTail = prev;
|
||||||
|
}else{
|
||||||
|
next->prev = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestRunner {
|
||||||
|
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(TestCase* testCase = testCaseHead; testCase != nullptr; testCase = testCase->next){
|
||||||
|
testCase->matched_filter = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int run() {
|
||||||
|
size_t passed_count = 0;
|
||||||
|
size_t failed_count = 0;
|
||||||
|
|
||||||
|
for(TestCase* 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() {
|
||||||
|
ent::test::TestRunner runner;
|
||||||
|
runner.allowAll();
|
||||||
|
int rv = runner.run();
|
||||||
|
return rv<0?-1:0;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#define KEL_CONCAT_(x,y) x##y
|
||||||
|
#define KEL_CONCAT(x,y) KEL_CONCAT_(x,y)
|
||||||
|
#define KEL_UNIQUE_NAME(prefix) KEL_CONCAT(prefix, __LINE__)
|
||||||
|
|
||||||
|
namespace ent {
|
||||||
|
namespace test {
|
||||||
|
class TestRunner;
|
||||||
|
class TestCase {
|
||||||
|
private:
|
||||||
|
std::string file;
|
||||||
|
uint line;
|
||||||
|
std::string description;
|
||||||
|
bool matched_filter;
|
||||||
|
TestCase* next;
|
||||||
|
TestCase** prev;
|
||||||
|
|
||||||
|
friend class TestRunner;
|
||||||
|
public:
|
||||||
|
TestCase(const std::string& file_, uint line_, const std::string& description_);
|
||||||
|
~TestCase();
|
||||||
|
|
||||||
|
virtual void run() = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define KEL_TEST(description) \
|
||||||
|
class KEL_UNIQUE_NAME(TestCase) : public ::ent::test::TestCase { \
|
||||||
|
public: \
|
||||||
|
KEL_UNIQUE_NAME(TestCase)(): ::ent::test::TestCase(__FILE__,__LINE__,description) {} \
|
||||||
|
void run() override; \
|
||||||
|
}KEL_UNIQUE_NAME(testCase); \
|
||||||
|
void KEL_UNIQUE_NAME(TestCase)::run()
|
||||||
|
|
||||||
|
#define KEL_EXPECT(expr, msg) \
|
||||||
|
if( ! (expr) ){ \
|
||||||
|
throw std::runtime_error{msg}; \
|
||||||
|
}
|
Loading…
Reference in New Issue