Skip to content

jowillianto/jowi-test-lib

Repository files navigation

Test Lib

A Simple and Light C++23 modules based C++ testing library.

Example Usage

import jowi.test_lib;

namespace test_lib = jowi::test_lib;
#include <jowi/test_lib.hpp>

JOWI_ADD_TEST(some_name) {
  /*
    Do something over here
  */
}

The above will add the test into the test list. Compiling this file using cmake with jowi_add_test will result in the test being added and run automatically.

Documentation

1. Macros

  • JOWI_ADD_TEST(test_name) This macro creates a function that will add a function declared after it into the test set. An example of adding a test is as follows :
import jowi.test_lib;
#include <jowi/test_lib.hpp>

JOWI_ADD_TEST(your_test_name) {}
  • JOWI_SETUP(argc, argv) This macro setups a function that will setup the test settings for a specific use case. Treat this as if it is a constructor that will construct the tests.

  • JOWI_TEARDOWN() This macro is run at the end of a successful test. Treat this as if it is a destructor that will destruct tests.

2. The Global Context

All variables that modify a test can be modified through its global context which is a structure declaration pertaining to the following :

struct test_context {
  int thread_count = 1;
  test_suite tests = test_suite{};
  test_time_unit time_unit = test_time_unit::MICRO_SECONDS;
}

To obtain the global context, call jowi::test_lib::get_test_context(), this will return a reference to the test context.

test_context& get_test_context();

test_context::set_time_unit(test_time_unit unit)

This sets the time unit used when logging the tests. Valid values are:

enum struct test_time_unit { MICRO_SECONDS, MILLI_SECONDS, SECONDS };

test_context::set_thread_count(int thread_count)

Sets the amount of threads to use when running tests. The default value is 1, and if you desire single threaded execution, there is no need to add a new thread.

2. Assertions [[ Generated by Claude-Sonnet 4]]

This documentation covers all assertion functions in the jowi::test_lib module. All functions throw a fail_assertion exception when the assertion fails, which can be caught by a test framework to mark a test as failed or to ignore an error.

Basic Equality Assertions

void assert_equal(const T &x, const V &y)

Checks that two values are equal using the == operator.

Example:

assert_equal(42, 42);           // Passes
assert_equal("hello", "hello"); // Passes
assert_equal(3.14, 2.71);       // Throws fail_assertion

void assert_not_equal(const T &x, const V &y)

Checks that two values are not equal using the == operator.

Example:

assert_not_equal(42, 24);       // Passes
assert_not_equal("foo", "bar"); // Passes
assert_not_equal(5, 5);         // Throws fail_assertion

Comparison Assertions

void assert_lt(const T &x, const V &y)

Checks that the first value is less than the second value using the < operator.

Example:

assert_lt(5, 10);     // Passes
assert_lt(1.5, 2.0);  // Passes
assert_lt(10, 5);     // Throws fail_assertion
assert_lt(5, 5);      // Throws fail_assertion (equal values)

Boolean Assertions

void assert_true(bool expr, std::string_view err_msg = "expr is not true")

Checks that the given boolean expression evaluates to true.

Example:

assert_true(5 > 3);                           // Passes
assert_true(true);                            // Passes
assert_true(false);                           // Throws fail_assertion
assert_true(x > 0, "x must be positive");     // Custom error message

void assert_false(bool expr, std::string_view err_msg = "expr is true")

Checks that the given boolean expression evaluates to false.

Example:

assert_false(5 < 3);                          // Passes
assert_false(false);                          // Passes
assert_false(true);                           // Throws fail_assertion
assert_false(x < 0, "x should not be negative"); // Custom error message

Floating Point Assertions

void assert_close(double x, double y, double tolerance = 1e-6)

void assert_close(number_type l, number_type r, number_type tol = 1e-6)

Checks that two floating-point numbers are close within a specified tolerance. The second overload works with any floating-point type and uses RMS difference for comparison.

Example:

// First overload (double)
assert_close(3.14159, 3.14160);              // Passes (within default tolerance)
assert_close(1.0, 1.1, 0.2);                 // Passes (within custom tolerance)
assert_close(1.0, 2.0);                      // Throws fail_assertion

// Second overload (generic floating-point)
assert_close(3.14f, 3.141f, 0.01f);          // Passes with float
assert_close(1.0L, 1.00001L, 1e-4L);         // Passes with long double

Container/Range Assertions

void assert_equal(const T &x, const V &y) (Range Overload)

Checks that two ranges contain equal elements by comparing each corresponding pair.

Example:

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {1, 2, 3};
std::array<int, 3> arr = {1, 2, 3};

assert_equal(v1, v2);         // Passes
assert_equal(v1, arr);        // Passes
assert_equal(v1, {1, 2, 4});  // Throws fail_assertion at index 2

void assert_not_equal(const T &x, const V &y) (Range Overload)

Checks that two ranges contain at least one pair of non-equal elements.

Example:

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {1, 2, 4};
std::vector<int> v3 = {1, 2, 3};

assert_not_equal(v1, v2);     // Passes (different at index 2)
assert_not_equal(v1, v3);     // Throws fail_assertion (all elements equal)

void assert_lt(const T &x, const V &y) (Range Overload)

Checks that each element in the first range is less than the corresponding element in the second range.

Example:

std::vector<int> smaller = {1, 3, 5};
std::vector<int> larger = {2, 4, 6};
std::vector<int> mixed = {2, 2, 6};

assert_lt(smaller, larger);   // Passes (1<2, 3<4, 5<6)
assert_lt(smaller, mixed);    // Throws fail_assertion (3 >= 2)

Generic Function Assertion

void assert_func(const T &x, const V &y, F &&comp)

Applies a comparison function to each corresponding pair of elements from two ranges.

Example:

std::vector<int> v1 = {1, 4, 9};
std::vector<int> v2 = {1, 2, 3};

// Custom comparison: check if v1[i] == v2[i]²
assert_func(v1, v2, [](int a, int b) {
    assert_equal(a, b * b);
});  // Passes (1==1², 4==2², 9==3²)

// Using existing assertion function
assert_func(v1, v2, [](int a, int b, auto loc) {
    assert_lt(b, a, loc);
});  // Passes (1<1 fails, so this throws)

Exception Assertions

void assert_throw<exceptions...>(auto &&f)

Checks that calling the given function throws one of the specified exception types. If no exception types are specified, checks that any exception is thrown.

Example:

// Check for any exception
assert_throw([]() { 
    throw std::runtime_error("error"); 
});  // Passes

// Check for specific exception type
assert_throw<std::runtime_error>([]() {
    throw std::runtime_error("error");
});  // Passes

assert_throw([]() { 
    return 42; 
});  // Throws fail_assertion (no exception thrown)

Expected Value Assertions

void assert_expected(const std::expected<T, E> &e)

⚠️ DEPRECATED - Use assert_expected_value instead for new code.

Checks that an std::expected contains a value (not an error).

Example:

std::expected<int, std::string> good_result = 42;
std::expected<int, std::string> bad_result = std::unexpected("error");

assert_expected(good_result);   // Passes
assert_expected(bad_result);    // Throws fail_assertion with error message

T assert_expected_value(std::expected<T, E> &&res)

Checks that an std::expected contains a value and returns that value. If it contains an error, throws a fail_assertion.

Example:

std::expected<int, std::string> good_result = 42;
std::expected<int, std::string> bad_result = std::unexpected("error");

int value = assert_expected_value(std::move(good_result));  // Returns 42
int value2 = assert_expected_value(std::move(bad_result));  // Throws fail_assertion

About

A Simple and Light C++23 modules based C++ testing library.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published