From 0e3aa9b4d71789e307065fc1143ee6dd522a45ad Mon Sep 17 00:00:00 2001 From: Antoni Kiedos <antek_kiedos@outlook.com> Date: Sun, 14 Nov 2021 21:43:59 +0100 Subject: [PATCH] Created v0.1.0. --- CHANGELOG.md | 10 +++ README.md | 3 + bin/lib/.gitkeep | 0 bin/tests/.gitkeep | 0 bin/tests/some_test | Bin 0 -> 99848 bytes dist/.gitkeep | 0 dist/litefprocut.tar.gz | Bin 0 -> 1739 bytes dist/litefprocut/litefprocut.hpp | 110 +++++++++++++++++++++++++++++++ dist/litefprocut/macros.hpp | 46 +++++++++++++ docs/assets/index.md | 14 ++++ include/.gitkeep | 0 include/litefprocut.hpp | 110 +++++++++++++++++++++++++++++++ include/macros.hpp | 46 +++++++++++++ scripts/archive.bash | 8 +++ test.cpp | 14 ++++ tests/.gitkeep | 0 tests/some_test.cpp | 26 ++++++++ 17 files changed, 387 insertions(+) delete mode 100644 bin/lib/.gitkeep delete mode 100644 bin/tests/.gitkeep create mode 100644 bin/tests/some_test delete mode 100644 dist/.gitkeep create mode 100644 dist/litefprocut.tar.gz create mode 100644 dist/litefprocut/litefprocut.hpp create mode 100644 dist/litefprocut/macros.hpp create mode 100644 docs/assets/index.md delete mode 100644 include/.gitkeep create mode 100644 include/litefprocut.hpp create mode 100644 include/macros.hpp create mode 100644 scripts/archive.bash delete mode 100644 tests/.gitkeep create mode 100644 tests/some_test.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29..95fb71f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +## Future releases +- More `ASSERT_*` macros +- Deprecate `END_TEST` and get rid of `add_test` and change `TEST` impl +## 0.1.0 +- `TEST` +- `ASSERT_EQ` +- `ASSERT_TRUE` +- `litefprocut::add_test` +- `litefprocut::init` +- `litefprocut::run_all_tests` \ No newline at end of file diff --git a/README.md b/README.md index e69de29..bb81f86 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,3 @@ +# LiteFProcUT - alightweight & simple file-processing functionality UT framework + +Documentation can be found in `docs/` folder \ No newline at end of file diff --git a/bin/lib/.gitkeep b/bin/lib/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/bin/tests/.gitkeep b/bin/tests/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/bin/tests/some_test b/bin/tests/some_test new file mode 100644 index 0000000000000000000000000000000000000000..453cc91a255fa27e00d9a87a06bccae56620a68c GIT binary patch literal 99848 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 literal 0 HcmV?d00001 diff --git a/dist/.gitkeep b/dist/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/dist/litefprocut.tar.gz b/dist/litefprocut.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..8aa91cb41f85dcd886218b0e762b6c9645d37b41 GIT binary patch literal 1739 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 literal 0 HcmV?d00001 diff --git a/dist/litefprocut/litefprocut.hpp b/dist/litefprocut/litefprocut.hpp new file mode 100644 index 0000000..3ffad80 --- /dev/null +++ b/dist/litefprocut/litefprocut.hpp @@ -0,0 +1,110 @@ +#ifndef LITEFPROCUT_ADD_TEST_HPP +#define LITEFPROCUT_ADD_TEST_HPP + +#include<vector> +#include<functional> +#include<string> +#include<tuple> +#include<fstream> +#include<iostream> +#include<cstring> + +namespace litefprocut +{ + struct test + { + std::size_t passed{}; + std::size_t failed{}; + std::tuple<std::string /*name*/, std::string /*fname*/, std::function<void(const std::string&)>/*test*/> set{}; + explicit test(const std::size_t& p, const std::size_t& f, const decltype(set)& s) : passed{p}, failed{f}, set{s} {} + explicit test(const decltype(set)& s) : set{s} {} + explicit test() = default; + ~test() = default; + }; + struct suite + { + std::vector<test> tests{}; + std::size_t passed{}; + std::size_t failed{}; + std::size_t skipped{}; + std::vector<std::string> skipped_tests{}; + int result{}; + explicit suite() = default; + }; + suite this_suite{}; + decltype(this_suite.tests)::value_type this_test{}; + void add_test(const std::string& fname, const std::string& name, std::function<void(const std::string&)> test_func) + { + this_suite.tests.push_back(test{std::make_tuple(name, fname, test_func)}); + } + void run_all_tests() + { + for(auto& test : this_suite.tests) + { + this_test = test; + std::ifstream ifs{std::get<1>(this_test.set)}; + std::string content{}; + std::string aux{}; + while(std::getline(ifs, aux)) content += aux; + std::cerr << "\e[36mRunning test " << std::get<0>(this_test.set) << " [" << (this_suite.passed + this_suite.failed + this_suite.skipped + 1) << "/" << this_suite.tests.size() << "]\n\e[0m"; + + if(std::find(this_suite.skipped_tests.begin(), this_suite.skipped_tests.end(), std::get<0>(this_test.set)) != this_suite.skipped_tests.end()) + { + ++this_suite.skipped; + std::cerr << "\e[33mTest " << std::get<0>(this_test.set) << " skipped\n\e[0m"; + } + else + { + std::get<2>(this_test.set)(content); + if(this_test.failed == 0) + { + std::cerr << "\e[32mTest " << std::get<0>(this_test.set) << " passed\n\e[0m"; + ++this_suite.passed; + } + else + { + std::cerr << "\e[31mTest " << std::get<0>(this_test.set) << " failed\n\e[0m"; + std::cerr << "\e[31m\t" << this_test.failed << " assertion" << (this_test.failed == 1 ? "" : "s") << " failed, \e[0m\e[32m" << this_test.passed << " passed\n\e[0m"; + ++this_suite.failed; + --this_suite.result; + } + } + } + std::cerr << "\e[3\n2mPassed: " << this_suite.passed + << " (" << ((static_cast<long double>(this_suite.passed) / static_cast<long double>(this_suite.tests.size())) * 100.0) << "%)\n\e[0m"; + std::cerr << "\e[31mFailed: " << this_suite.failed + << " (" << ((static_cast<long double>(this_suite.failed) / static_cast<long double>(this_suite.tests.size())) * 100.0) << "%)\n\e[0m"; + std::cerr << "\e[33mSkipped: " << this_suite.skipped + << " (" << ((static_cast<long double>(this_suite.skipped) / static_cast<long double>(this_suite.tests.size())) * 100.0) << "%)\n\e[0m\n"; + } + void init(const int& argc, char** argv, const std::size_t& n) + { + if(argc < n + 1) + { + std::cerr << "Please provide at least " << n << " arguments!\n"; + std::cerr << "After that " << n << " arguments, you could append:\n"; + std::cerr << "--skip <test name>...\n"; + std::exit(1); + } + else + { + if(std::strcmp(argv[n + 1], "--skip") == 0) + { + for(std::size_t i = n + 2; i < argc; i++) + { + this_suite.skipped_tests.push_back(argv[i]); + // std::cerr << "Adding test " << argv[i] << " to this_suite.skipped_tests...\n"; + } + } + } + } + // FIXME: Does it make sense? + // void next_suite(const std::string& suite_name) + // { + // system(suite_name); + // } +} + +#include "macros.hpp" + +#endif \ No newline at end of file diff --git a/dist/litefprocut/macros.hpp b/dist/litefprocut/macros.hpp new file mode 100644 index 0000000..6336d98 --- /dev/null +++ b/dist/litefprocut/macros.hpp @@ -0,0 +1,46 @@ +#ifndef LITEFPROC_MACROS_HPP +#define LITEFPROC_MACROS_HPP + +#include<iostream> + +#define TEST(name, fname_var)\ +litefprocut::add_test(fname_var, #name, [argv](const std::string& content) +#define END_TEST \ +); +#define ASSERT_EQ(lhs, rhs)\ +if((lhs) != (rhs))\ +{\ + std::cerr << "\e[31mAssertion failed:\n\e[0m";\ + std::cerr << "\e[31m\tExpected: " << rhs << "\n\e[0m";\ + std::cerr << "\e[31m\tActual: " << lhs << "\n\e[0m";\ + ++litefprocut::this_test.failed;\ +}\ +else ++litefprocut::this_test.passed; +#define ASSERT_TRUE(expr)\ +if(!(expr))\ +{\ + std::cerr << "\e[31mExpectation of true failed:\n\e[0m";\ + ++litefprocut::this_test.failed;\ +}\ +else ++litefprocut::this_test.passed; + +// std::ifstream& litefprocut_##name##_ifs{#fname};\ +// std::string litefprocut_##name##_content{};\ +// std::string litefprocut_##name##_aux{}\ +// while(std::getline(litefprocut_##name##_ifs, litefprocut_##name##_aux)) litefprocut_##name##_content += litefprocut_##name##_aux;\ + +// Example: +// int main(int argc, char** argv) +// { +// litefprocut::init(argc, argv, 2); +// TEST(is-version-loaded-correctly, argv[1]) +// { +// std::string fname = argv[1]; +// ASSERT_EQ(load_version(content), fname[fname.find("ver") + 3]) +// } +// litefprocut::run_all_tests(); +// litefprocut::next_suite(argv[2]); +// return litefprocut::this_suite::result; +// } + +#endif \ No newline at end of file diff --git a/docs/assets/index.md b/docs/assets/index.md new file mode 100644 index 0000000..bf58542 --- /dev/null +++ b/docs/assets/index.md @@ -0,0 +1,14 @@ +# TEST(name, fname_var) +`name` - name of the test (literally, not within `"`) +`fname_var` - variable holding processed file name (i.e. `argv[<something>]`) +# ASSERT_EQ(lhs, rhs) +Asserts if `lhs == rhs`. +# ASSERT_TRUE(expr) +Asserts if `expr` is true. + +# `void litefprocut::init(const int& argc, char** argv, const std::size_t& n)` +Checks if `argc < n + 1` and marks given tests as skipped. +# `void litefprocut::run_all_tests()` +Runs all tests in suite +# `void litefprocut::add_test(const std::string& fname, const std::string& name, std::function<void(const std::string&)> test_func)` +Adds test to the `this_suite` object. Can be used directly, but without `TEST` macro in such a case. \ No newline at end of file diff --git a/include/.gitkeep b/include/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/include/litefprocut.hpp b/include/litefprocut.hpp new file mode 100644 index 0000000..3ffad80 --- /dev/null +++ b/include/litefprocut.hpp @@ -0,0 +1,110 @@ +#ifndef LITEFPROCUT_ADD_TEST_HPP +#define LITEFPROCUT_ADD_TEST_HPP + +#include<vector> +#include<functional> +#include<string> +#include<tuple> +#include<fstream> +#include<iostream> +#include<cstring> + +namespace litefprocut +{ + struct test + { + std::size_t passed{}; + std::size_t failed{}; + std::tuple<std::string /*name*/, std::string /*fname*/, std::function<void(const std::string&)>/*test*/> set{}; + explicit test(const std::size_t& p, const std::size_t& f, const decltype(set)& s) : passed{p}, failed{f}, set{s} {} + explicit test(const decltype(set)& s) : set{s} {} + explicit test() = default; + ~test() = default; + }; + struct suite + { + std::vector<test> tests{}; + std::size_t passed{}; + std::size_t failed{}; + std::size_t skipped{}; + std::vector<std::string> skipped_tests{}; + int result{}; + explicit suite() = default; + }; + suite this_suite{}; + decltype(this_suite.tests)::value_type this_test{}; + void add_test(const std::string& fname, const std::string& name, std::function<void(const std::string&)> test_func) + { + this_suite.tests.push_back(test{std::make_tuple(name, fname, test_func)}); + } + void run_all_tests() + { + for(auto& test : this_suite.tests) + { + this_test = test; + std::ifstream ifs{std::get<1>(this_test.set)}; + std::string content{}; + std::string aux{}; + while(std::getline(ifs, aux)) content += aux; + std::cerr << "\e[36mRunning test " << std::get<0>(this_test.set) << " [" << (this_suite.passed + this_suite.failed + this_suite.skipped + 1) << "/" << this_suite.tests.size() << "]\n\e[0m"; + + if(std::find(this_suite.skipped_tests.begin(), this_suite.skipped_tests.end(), std::get<0>(this_test.set)) != this_suite.skipped_tests.end()) + { + ++this_suite.skipped; + std::cerr << "\e[33mTest " << std::get<0>(this_test.set) << " skipped\n\e[0m"; + } + else + { + std::get<2>(this_test.set)(content); + if(this_test.failed == 0) + { + std::cerr << "\e[32mTest " << std::get<0>(this_test.set) << " passed\n\e[0m"; + ++this_suite.passed; + } + else + { + std::cerr << "\e[31mTest " << std::get<0>(this_test.set) << " failed\n\e[0m"; + std::cerr << "\e[31m\t" << this_test.failed << " assertion" << (this_test.failed == 1 ? "" : "s") << " failed, \e[0m\e[32m" << this_test.passed << " passed\n\e[0m"; + ++this_suite.failed; + --this_suite.result; + } + } + } + std::cerr << "\e[3\n2mPassed: " << this_suite.passed + << " (" << ((static_cast<long double>(this_suite.passed) / static_cast<long double>(this_suite.tests.size())) * 100.0) << "%)\n\e[0m"; + std::cerr << "\e[31mFailed: " << this_suite.failed + << " (" << ((static_cast<long double>(this_suite.failed) / static_cast<long double>(this_suite.tests.size())) * 100.0) << "%)\n\e[0m"; + std::cerr << "\e[33mSkipped: " << this_suite.skipped + << " (" << ((static_cast<long double>(this_suite.skipped) / static_cast<long double>(this_suite.tests.size())) * 100.0) << "%)\n\e[0m\n"; + } + void init(const int& argc, char** argv, const std::size_t& n) + { + if(argc < n + 1) + { + std::cerr << "Please provide at least " << n << " arguments!\n"; + std::cerr << "After that " << n << " arguments, you could append:\n"; + std::cerr << "--skip <test name>...\n"; + std::exit(1); + } + else + { + if(std::strcmp(argv[n + 1], "--skip") == 0) + { + for(std::size_t i = n + 2; i < argc; i++) + { + this_suite.skipped_tests.push_back(argv[i]); + // std::cerr << "Adding test " << argv[i] << " to this_suite.skipped_tests...\n"; + } + } + } + } + // FIXME: Does it make sense? + // void next_suite(const std::string& suite_name) + // { + // system(suite_name); + // } +} + +#include "macros.hpp" + +#endif \ No newline at end of file diff --git a/include/macros.hpp b/include/macros.hpp new file mode 100644 index 0000000..6336d98 --- /dev/null +++ b/include/macros.hpp @@ -0,0 +1,46 @@ +#ifndef LITEFPROC_MACROS_HPP +#define LITEFPROC_MACROS_HPP + +#include<iostream> + +#define TEST(name, fname_var)\ +litefprocut::add_test(fname_var, #name, [argv](const std::string& content) +#define END_TEST \ +); +#define ASSERT_EQ(lhs, rhs)\ +if((lhs) != (rhs))\ +{\ + std::cerr << "\e[31mAssertion failed:\n\e[0m";\ + std::cerr << "\e[31m\tExpected: " << rhs << "\n\e[0m";\ + std::cerr << "\e[31m\tActual: " << lhs << "\n\e[0m";\ + ++litefprocut::this_test.failed;\ +}\ +else ++litefprocut::this_test.passed; +#define ASSERT_TRUE(expr)\ +if(!(expr))\ +{\ + std::cerr << "\e[31mExpectation of true failed:\n\e[0m";\ + ++litefprocut::this_test.failed;\ +}\ +else ++litefprocut::this_test.passed; + +// std::ifstream& litefprocut_##name##_ifs{#fname};\ +// std::string litefprocut_##name##_content{};\ +// std::string litefprocut_##name##_aux{}\ +// while(std::getline(litefprocut_##name##_ifs, litefprocut_##name##_aux)) litefprocut_##name##_content += litefprocut_##name##_aux;\ + +// Example: +// int main(int argc, char** argv) +// { +// litefprocut::init(argc, argv, 2); +// TEST(is-version-loaded-correctly, argv[1]) +// { +// std::string fname = argv[1]; +// ASSERT_EQ(load_version(content), fname[fname.find("ver") + 3]) +// } +// litefprocut::run_all_tests(); +// litefprocut::next_suite(argv[2]); +// return litefprocut::this_suite::result; +// } + +#endif \ No newline at end of file diff --git a/scripts/archive.bash b/scripts/archive.bash new file mode 100644 index 0000000..ac20225 --- /dev/null +++ b/scripts/archive.bash @@ -0,0 +1,8 @@ +if [[ ! -d dist/litefprocut ]]; then +mkdir dist/litefprocut +fi +cp include/litefprocut.hpp dist/litefprocut/litefprocut.hpp +cp include/macros.hpp dist/litefprocut/macros.hpp + +tar zcvf litefprocut.tar.gz dist/litefprocut/*.hpp +mv litefprocut.tar.gz dist/litefprocut.tar.gz \ No newline at end of file diff --git a/test.cpp b/test.cpp index e69de29..22a7425 100644 --- a/test.cpp +++ b/test.cpp @@ -0,0 +1,14 @@ +#include<cstdlib> + +#if defined(_WIN32) || defined(_WIN64) +#define PATHSEP "\\" +#define EXEC_EXT ".exe" +#else +#define PATHSEP "/" +#define EXEC_EXT "" +#endif + +int main() +{ + return system("bin" PATHSEP "tests" PATHSEP "some_test" EXEC_EXT); +} \ No newline at end of file diff --git a/tests/.gitkeep b/tests/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/some_test.cpp b/tests/some_test.cpp new file mode 100644 index 0000000..d618888 --- /dev/null +++ b/tests/some_test.cpp @@ -0,0 +1,26 @@ +#include "litefprocut.hpp" +#include "macros.hpp" + +int main(int argc, char** argv) +{ + litefprocut::init(argc, argv, 1); + TEST(is-true, argv[1]) + { + std::string fname = argv[1]; + ASSERT_TRUE(!false) + } + END_TEST + TEST(is-false, argv[1]) + { + ASSERT_EQ(false, false) + } + END_TEST + TEST(does-sum-of-2-and-5-eq-10-or-7?, argv[1]) + { + ASSERT_EQ(2 + 5, 10) + ASSERT_EQ(2 + 5, 7) + } + END_TEST + litefprocut::run_all_tests(); + return litefprocut::this_suite.result; +} \ No newline at end of file -- GitLab