diff --git a/CHANGELOG.md b/CHANGELOG.md
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..95fb71feefa7ce306c15a7ae1a444ca39daa6ba2 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bb81f863af5b07d4c5d50bc3e2ef133beb4fc05d 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/bin/tests/.gitkeep b/bin/tests/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/bin/tests/some_test b/bin/tests/some_test
new file mode 100644
index 0000000000000000000000000000000000000000..453cc91a255fa27e00d9a87a06bccae56620a68c
Binary files /dev/null and b/bin/tests/some_test differ
diff --git a/dist/.gitkeep b/dist/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/dist/litefprocut.tar.gz b/dist/litefprocut.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..8aa91cb41f85dcd886218b0e762b6c9645d37b41
Binary files /dev/null and b/dist/litefprocut.tar.gz differ
diff --git a/dist/litefprocut/litefprocut.hpp b/dist/litefprocut/litefprocut.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ffad80820a50bbf3fb497a7f05f868fb6c9779a
--- /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 0000000000000000000000000000000000000000..6336d985e14bdc3587a56a636588c26c5b903660
--- /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 0000000000000000000000000000000000000000..bf58542ab73247900347c5407374208f1db28a6c
--- /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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/include/litefprocut.hpp b/include/litefprocut.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ffad80820a50bbf3fb497a7f05f868fb6c9779a
--- /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 0000000000000000000000000000000000000000..6336d985e14bdc3587a56a636588c26c5b903660
--- /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 0000000000000000000000000000000000000000..ac202251c8839fa9779f11d7282990b45c0ce0a9
--- /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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..22a7425e19c7e1f99ea079f6e3481128515c84e6 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/tests/some_test.cpp b/tests/some_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d61888882c504b14b63d20a0d2b65829a9d81de1
--- /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