Skip to content
Snippets Groups Projects
Commit 0e3aa9b4 authored by Antoni Kiedos's avatar Antoni Kiedos
Browse files

Created v0.1.0.

parent a1546979
No related branches found
No related tags found
No related merge requests found
## 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
# LiteFProcUT - alightweight & simple file-processing functionality UT framework
Documentation can be found in `docs/` folder
\ No newline at end of file
File added
File added
#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
#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
# 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
#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
#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
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
#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
#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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment