initial base commit

This commit is contained in:
keldu.magnus 2020-07-27 17:13:05 +02:00
parent d1dad7e64e
commit da6314f6ac
5 changed files with 240 additions and 0 deletions

58
SConstruct Normal file
View File

@ -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)

15
source/SConscript Normal file
View File

@ -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)

16
test/SConscript Normal file
View File

@ -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])

108
test/suite/suite.cpp Normal file
View File

@ -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;
}

43
test/suite/suite.h Normal file
View File

@ -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}; \
}