diff options
author | Claudius Holeksa <mail@keldu.de> | 2023-06-10 17:21:29 +0200 |
---|---|---|
committer | Claudius Holeksa <mail@keldu.de> | 2023-06-10 17:21:29 +0200 |
commit | 6c8e3d1786a5de4ae562c03693b8dad9dd0ab26e (patch) | |
tree | 18275240cfb8ff30e1d383ea351a277e894e988f | |
parent | b670001ca80dbc0e1a51b4a08776eb41dabc2a9e (diff) |
tests,c++: Intermediate commit preparing testing and json
-rw-r--r-- | default.nix | 14 | ||||
-rw-r--r-- | src/codec-json/json.h | 10 | ||||
-rw-r--r-- | src/codec-json/json.tmpl.h | 26 | ||||
-rw-r--r-- | src/test/.nix/derivation.nix | 30 | ||||
-rw-r--r-- | src/test/SConscript | 33 | ||||
-rw-r--r-- | src/test/SConstruct | 66 | ||||
-rw-r--r-- | src/test/suite.cpp | 107 | ||||
-rw-r--r-- | src/test/suite.h | 43 | ||||
-rw-r--r-- | tests/.nix/derivation.nix | 27 | ||||
-rw-r--r-- | tests/SConscript | 32 | ||||
-rw-r--r-- | tests/SConstruct | 66 | ||||
-rw-r--r-- | tests/core.cpp | 7 |
12 files changed, 457 insertions, 4 deletions
diff --git a/default.nix b/default.nix index 3d8adb3..e27153a 100644 --- a/default.nix +++ b/default.nix @@ -13,6 +13,13 @@ in rec { inherit clang-tools; }; + test = pkgs.callPackage src/test/.nix/derivation.nix { + inherit version; + inherit forstio; + inherit clang; + inherit clang-tools; + }; + async = pkgs.callPackage src/async/.nix/derivation.nix { inherit version; inherit forstio; @@ -55,4 +62,11 @@ in rec { inherit clang-tools; }; }; + + forstio-test-cases = pkgs.callPackage tests/.nix/derivation.nix { + inherit version; + inherit forstio; + inherit clang; + inherit clang-tools; + }; } diff --git a/src/codec-json/json.h b/src/codec-json/json.h index 2a0bea9..f23aff9 100644 --- a/src/codec-json/json.h +++ b/src/codec-json/json.h @@ -18,7 +18,15 @@ class data<Schema, encode::Json> { private: own<buffer> buffer_; public: - data() = default; + + data(): + buffer_{heap<ring_buffer>()} + {} + + buffer& get_buffer(){ + assert(buffer_); + return *buffer_; + } std::size_t get_size() const { return buffer_.size(); diff --git a/src/codec-json/json.tmpl.h b/src/codec-json/json.tmpl.h index d29f29c..3699e10 100644 --- a/src/codec-json/json.tmpl.h +++ b/src/codec-json/json.tmpl.h @@ -9,11 +9,31 @@ class json_encode_impl { static_assert(always_false<Schema, RootSchema, FromEncode>, "This schema type is not being handle by the json encoding."); }; -template<size_t N, typename RootSchema, typename FromEncode> -class json_encode_impl<saw::schema::Primitive<schema::FloatingPoint,N>, RootSchema, FromEncode> { +template<typename T, size_t N, typename RootSchema, typename FromEncode> +class json_encode_impl<saw::schema::Primitive<T,N>, RootSchema, FromEncode> { static ErrorOr<void> encode(const data<Schema, FromEncode>& from, data<Schema, encode::Json>& to, size_t ptr) { auto val = from.get(); - auto tc_result = std::to_chars(); + std::array<uint8_t, 256> data; + auto tc_result = std::to_chars(reinterpret_cast<int8_t>(data.data()), reinrepret_cast<int8_t>(data.data())+data.size(), val); + + if(tc_result.ec != std::errc{}){ + return make_error<err::critical>(); + } + + size_t bytes_written = 0; + for(auto ptr = data.data(); ptr != tc_result.ptr; ++ptr){ + ++bytes_written; + } + + auto& buff = to.get_buffer(); + error err = buff.write_require_length(bytes_written); + if(!err.template is_type<err::no_error>()){ + return std::move(err); + } + + for(auto ptr = data.data(); ptr != tc_result.ptr; ++ptr){ + buff.push(ptr[0]); + } return Void{}; } diff --git a/src/test/.nix/derivation.nix b/src/test/.nix/derivation.nix new file mode 100644 index 0000000..750d8ed --- /dev/null +++ b/src/test/.nix/derivation.nix @@ -0,0 +1,30 @@ +{ lib +, stdenvNoCC +, scons +, clang +, clang-tools +, version +, forstio +}: + +let + +in stdenvNoCC.mkDerivation { + pname = "forstio-test"; + inherit version; + src = ./..; + + enableParallelBuilding = true; + + nativeBuildInputs = [ + scons + clang + clang-tools + ]; + + buildInputs = [ + forstio.core + ]; + + outputs = ["out" "dev"]; +} diff --git a/src/test/SConscript b/src/test/SConscript new file mode 100644 index 0000000..6379b24 --- /dev/null +++ b/src/test/SConscript @@ -0,0 +1,33 @@ +#!/bin/false + +import os +import os.path +import glob + + +Import('env') + +dir_path = Dir('.').abspath + +# Environment for base library +test_env = env.Clone(); + +test_env.sources = sorted(glob.glob(dir_path + "/*.cpp")) +test_env.headers = sorted(glob.glob(dir_path + "/*.h")) + +env.sources += test_env.sources; +env.headers += test_env.headers; + +## Shared lib +objects = [] +test_env.add_source_files(objects, test_env.sources, shared=False); +test_env.library = test_env.StaticLibrary('#build/forstio-test', [objects]); + +# Set Alias +env.Alias('library_test', [test_env.library]); + +env.targets += ['library_test']; + +# Install +env.Install('$prefix/lib/', [test_env.library]); +env.Install('$prefix/include/forstio/test/', [test_env.headers]); diff --git a/src/test/SConstruct b/src/test/SConstruct new file mode 100644 index 0000000..0d7b7c6 --- /dev/null +++ b/src/test/SConstruct @@ -0,0 +1,66 @@ +#!/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 + +def isAbsolutePath(key, dirname, env): + assert os.path.isabs(dirname), "%r must have absolute path syntax" % (key,) + +env_vars = Variables( + args=ARGUMENTS +) + +env_vars.Add('prefix', + help='Installation target location of build results and headers', + default='/usr/local/', + validator=isAbsolutePath +) + +env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=[], + CPPDEFINES=['SAW_UNIX'], + CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'], + LIBS=['forstio-core']) +env.__class__.add_source_files = add_kel_source_files +env.Tool('compilation_db'); +env.cdb = env.CompilationDatabase('compile_commands.json'); + +env.objects = []; +env.sources = []; +env.headers = []; +env.targets = []; + +Export('env') +SConscript('SConscript') + +env.Alias('cdb', env.cdb); +env.Alias('all', [env.targets]); +env.Default('all'); + +env.Alias('install', '$prefix') diff --git a/src/test/suite.cpp b/src/test/suite.cpp new file mode 100644 index 0000000..0fca8f9 --- /dev/null +++ b/src/test/suite.cpp @@ -0,0 +1,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; +} diff --git a/src/test/suite.h b/src/test/suite.h new file mode 100644 index 0000000..34f29bf --- /dev/null +++ b/src/test/suite.h @@ -0,0 +1,43 @@ +#pragma once + +#include <string> +#include <memory> +#include <stdexcept> +#include <type_traits> + +#include <forstio/core/common.h> + +namespace saw { +namespace test { +class test_runner; +class test_case { +private: + std::string file; + uint line; + std::string description; + bool matched_filter; + test_case* next; + test_case** prev; + + friend class test_runner; +public: + test_case(const std::string& file_, uint line_, const std::string& description_); + ~test_case(); + + virtual void run() = 0; +}; +} +} +#define SAW_TEST(description) \ + class SAW_UNIQUE_NAME(test_case) : public ::saw::test::test_case { \ + public: \ + SAW_UNIQUE_NAME(test_case)(): ::saw::test::test_case(__FILE__,__LINE__,description) {} \ + void run() override; \ + }SAW_UNIQUE_NAME(test_case_); \ + void SAW_UNIQUE_NAME(test_case)::run() + +#define SAW_EXPECT(expr, msg_split) \ + if( ! (expr) ){ \ + auto msg = msg_split; \ + throw std::runtime_error{std::string{msg}};\ + } diff --git a/tests/.nix/derivation.nix b/tests/.nix/derivation.nix new file mode 100644 index 0000000..d5a698c --- /dev/null +++ b/tests/.nix/derivation.nix @@ -0,0 +1,27 @@ +{ lib +, stdenvNoCC +, scons +, clang +, clang-tools +, version +, forstio +}: + +stdenvNoCC.mkDerivation { + pname = "forstio-test-cases"; + inherit version; + src = ./..; + + enableParallelBuilding = true; + + nativeBuildInputs = [ + scons + clang + clang-tools + forstio.core + forstio.async + forstio.test + ]; + + outputs = ["out" "dev"]; +} diff --git a/tests/SConscript b/tests/SConscript new file mode 100644 index 0000000..3659c0b --- /dev/null +++ b/tests/SConscript @@ -0,0 +1,32 @@ +#!/bin/false + +import os +import os.path +import glob + + +Import('env') + +dir_path = Dir('.').abspath + +# Environment for base library +test_cases_env = env.Clone(); + +test_cases_env.sources = sorted(glob.glob(dir_path + "/*.cpp")) +test_cases_env.headers = sorted(glob.glob(dir_path + "/*.h")) + +env.sources += test_cases_env.sources; +env.headers += test_cases_env.headers; + +objects_static = [] +test_cases_env.add_source_files(objects_static, test_cases_env.sources, shared=False); +test_cases_env.program = test_cases_env.Program('#bin/tests', objects_static); + +# Set Alias +env.Alias('test', test_cases_env.program); +env.Alias('check', test_cases_env.program); + +env.targets += ['test']; + +# Install +env.Install('$prefix/bin/', [test_cases_env.program]); diff --git a/tests/SConstruct b/tests/SConstruct new file mode 100644 index 0000000..98eccdb --- /dev/null +++ b/tests/SConstruct @@ -0,0 +1,66 @@ +#!/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 + +def isAbsolutePath(key, dirname, env): + assert os.path.isabs(dirname), "%r must have absolute path syntax" % (key,) + +env_vars = Variables( + args=ARGUMENTS +) + +env_vars.Add('prefix', + help='Installation target location of build results and headers', + default='/usr/local/', + validator=isAbsolutePath +) + +env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=[], + CPPDEFINES=['SAW_UNIX'], + CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'], + LIBS=['forstio-core', 'forstio-async']) +env.__class__.add_source_files = add_kel_source_files +env.Tool('compilation_db'); +env.cdb = env.CompilationDatabase('compile_commands.json'); + +env.objects = []; +env.sources = []; +env.headers = []; +env.targets = []; + +Export('env') +SConscript('SConscript') + +env.Alias('cdb', env.cdb); +env.Alias('all', [env.targets]); +env.Default('all'); + +env.Alias('install', '$prefix') diff --git a/tests/core.cpp b/tests/core.cpp new file mode 100644 index 0000000..af19b42 --- /dev/null +++ b/tests/core.cpp @@ -0,0 +1,7 @@ +#include <forstio/test/suite.h> + +namespace { +SAW_TEST { + +} +} |