Git Product home page Git Product logo

libcester's Introduction

libcester

A robust header only unit testing framework for C programming language. Support function mocking, memory leak detection, crash report.

cester is a header only automated testing framework for the C programming language, it requires no dependency and can be downloaded and used in a project immediately. Works on various platorms including embedded systems and compatible with various compilers. Allows shared instance TestInstance object in which each test cases can use to share data and access the command line arguments.

#include <exotic/cester.h>

CESTER_TEST(test_one, inst,
    cester_assert_equal(NULL, ((void*)0));    
)

The test results can be outputed as various format JunitXML, Test Anything Protocol, Test Anything Protocol Version 13 and text. Visit https://exoticlibraries.github.io/libcester/docs/ for documentation and tutorials.


Table of content

Features

  • Single header only, just download cester.h and you are good to go.
  • Automatic test detection, registration and execution, just write your test and run.
  • Isolated unit testing, each test case is executed in it own process so a crashed test can be properly reported.
  • Very portable, compatiple with ANSI C and C++98 without any trade off in functionalities.
  • A test instance object to share data between multiple test case to avoid the global scope pollution.
  • Provides simple API for mocking functions with gcc compiler options.
  • Generate report in various output formats, junitxml, text, tap, tapV13.
  • Does not produce any warnings even with strict warning options turned on.
  • Test for failures such as segfault, memory leak, premature termination e.t.c.
  • Rich collection of assertions for various type with proper reporting.
  • Modular, excluded un-used features from your test, selective_compilation.
  • No extra dependencies needed, once you have the C or C++ standard library available.
  • Support test fixture to setup and tear down resources used by the test cases.
  • Detail docuentation with examples and API references.

Standards Compliance and Portability

The project is compliant with the original C language specification ISO/IEC 9899:1990 and the first POSIX specification IEEE Std 1003.1-1988 which ensures the project compatibility in various environments. It also makes use of features in the newer revisions ISO/IEC 9899:1999 and IEEE Std 1003.1-2001 whenever possible.

Even though the project is designed for C, but also works with C++ as it is compatible with C++98 Standard (ISO/IEC 14882:1998), C++03 Standard (ISO/IEC 14882:2003) and C++11 Standard (ISO/IEC 14882:2011).

The project can be used with any C or C++ compiler. There are optional macros and options that can be used to attain the desired output in the case of undesired results.

Installation

If you install the library file cester.h using any of the commands below, it can be included in your test like <exotic/cester.h>.

Windows

Install the library using powershell. It auto detect your insalled C and C++ compilers include directory and install libcester into the include folder. Execute the command in powershell as admin.

& $([scriptblock]::Create((New-Object Net.WebClient).DownloadString("https://exoticlibraries.github.io/magic/install.ps1"))) libcester

Unix, Linux, Mac

Use the remote installation script to install libcester with bash. If the command is executes with super user priviledge (sudo) it will be installed in the folder /usr/include else it will be installed in the folder /usr/local/include. Or you can specify where to install it using the option --installfolder=./

bash <(curl -s https://exoticlibraries.github.io/magic/install.sh) libcester

Other platforms

You can simply download the header file cester.h from the repo into your project source folder and include it in your project. Download the file from here. The you can include it in your test relatively like #include "cester.h".

Documentation

The documentation provides several examples, tutorials, and detailed guides for using the library. While reference provides a low-level overview of all the implemented APIs in the library.

Some of the documentation pages are listed below:

For some know unfixed issues see the page known_issues.

Usage

Writing and Running test

The macro CESTER_TEST is used to create a test case, the first parameter is the test case name the second parameter is the test instance object which is used to share data between the test cases and also has the command line arguments object and count, the last parameter is the body of the test case. The following example defines a test case that chack if NULL is the same as ((void*)0)

//test.c
#include <exotic/cester.h>

CESTER_TEST(test_one, inst,
    cester_assert_equal(NULL, ((void*)0));    
)

CESTER_TEST(test_two, inst,
    cester_assert_ptr_equal(inst, NULL);    
)

cester will automatically detect and register the test cases if the macro __BASE_FILE__ is predefined by the compiler. If no test is detected see the FAQ below on ways to make cester aware of the test case.

The test above can be compiled and run like below. Do not forget to add the option -I. for gcc so it can find the __BASE_FILE__.

gcc test.c -I.-o test
./test

  + (0.00s) test one
  - (0.00s) test two

AssertionError crash_test.c:10: in 'test_two' => expected '0761C50', received '0000000'

Ran 2 test(s) in 0.01 Seconds
Synthesis: FAILURE Tests: 2 | Passing: 1 | Failing: 1

Macros

Many predefined helper macros are present in cester, all cester macros begins with CESTER_ and cester_. The detail documentation of the macros is at Helper Macros.

Mocking

cester supports mocking function. The mock feature currently works on GCC compiler because of the use of the --wrap option which is not supported on MAC OSX and might not be available in other compilers. The two macros CESTER_MOCK_SIMPLE_FUNCTION and CESTER_MOCK_FUNCTION are used for function mocking.

The following test mocks a funtion that accept no parameter and return a value:

originals.c

#ifndef ORIGINALS
#define ORIGINALS

int multiply_by() {
    return 2;
}

int multiply_a_number(int a) {
    return a * multiply_by() ;
}
#endif

test_mock.c

#include <exotic/cester.h>
#include "originals.c"

CESTER_MOCK_FUNCTION(multiply_by(), int, {
    return 5;
})

CESTER_TEST(check_mocked_function, test_instance,
    cester_assert_equal(multiply_a_number(2), 10);
)

Compile the test file test_mock.c with the --wrap option e.g. in the example above the function multiply_by was mocked so the option -Wl,--wrap=multiply_by is supplied during compilation.

gcc test_mock.c -I. -Wl,--wrap=multiply_by -o test_mock
./test_mock

+ (0.00s) check mocked function

Ran 1 test(s) in 0.00 Seconds
Synthesis: SUCCESS Tests: 1 | Passing: 1 | Failing: 0

More detailed explanation on mocking function can be seen at https://exoticlibraries.github.io/libcester/docs/mocking.html.

Cester options

cester accepts various options to tune it functionalities. Any command line parameter that starts with --cester- is treated as cester option otherwise it is ignored. All the available options can be viewed here.

The following options performs important task:

  • --cester-noisolation: instruct cester to run all the test in one single process. With this option signal will be used for crash reporting but if the test is compiled with the macro CESTER_NO_SIGNAL defined, cester will not be able to recover from critical crash therefore if a test case segfault the tests will terminate immediately.

  • --cester-output=?: Change the format in which the outpout is generated. Various format is supported, all the supported format can be viewed here. E.g. to print the output in JunitXML format you supply the option --cester-output=junitxml.

  • --cester-nomemtest: instruct cester to skip memory leak detection and test. Alternatively the test can be compiled with the macro CESTER_NO_MEM_TEST defined at the beginning of the source file.

  • --cester-nostreamcapture: instruct cester to skip stream capture, assertion and test. Alternatively the test can be compiled with the macro CESTER_NO_STREAM_CAPTURE defined at the beginning of the source file.

  • --cester-verbose: printf as much output as possible including passed test expression, output to the stdout from within the test case. This option combined with --cester-minimal prints out the output in a very sane format.

  • --cester-test=?: Select whiich test case to execute, this flag accept CSV of the test case, all other testcase will be ignred. E.g. To execute the two test test_string and test_int supply the flag --cester-test=test_string,test_int.

  • --cester-info=?: Prints the tests information printing feature. This feature can be disable at compile time by deining the macro CESTER_NO_PRINT_DETAIL before including cester.h. All possible value can be viewed here. E.g. to print all trhe test executable information supply the flag --cester-info=all.

  • --cester-help: to view all the options accepted by cester.

FAQ

No test detected

If no test was ran or your test cases were not detected, in most cases it because your compiler did not define the __BASE_FILE__ macro. If you are using the Visual studio IDE you should define the macro in Properties -> C/C++ -> Preprocessor -> Preprocessor Definition as __BASE_FILE__="%(Filename)%(Extension)". Or you can add the macro at compile time as option to your compiler using the macro option. e.g. in gcc

gcc -D__BASE_FILE__=\"/the/path/to/your/testfile.c\" testfile.c -I.

Setting for Visual C compiler

cl /D__BASE_FILE__=\"/the/path/to/your/testfile.c\" testfile.c

You can also define the __BASE_FILE__ at the beginning of your test file with the absolute path to the test file. E.g for the test file test.c:

#define __BASE_FILE__ "/path/to/test.c"
#include <exotic/cester.h>

CESTER_TEST(test1, test_instance,
    cester_assert_equal(NULL, NULL);
)

Alternatively the test cases should be manually registered in the main method, you will have to disable cester main function by defining the macro CESTER_NO_MAIN.

#define CESTER_NO_MAIN
#include <exotic/cester.h>

CESTER_TEST(test1, test_instance,
    cester_assert_equal(NULL, NULL);
)

CESTER_BODY(
int main(int argc, char** argv) {
    CESTER_REGISTER_TEST(test1);
    return CESTER_RUN_ALL_TESTS(argc, argv);
}
)

Visit this link for more detail on manual test registration.

How it works

The base file which is the file that contains the tests is included more than twice during the macro expansion process to define and register the test cases. The working principle is best explained by a thought experiment.

Imagine a source file including a header file. Then imagine the header file including the source file that included it. Now imagine doing that three times in a row within the same header file. Proceed to imagine redefining all of the identifiers each time. Finally imagine doing all of that with preprocessor directives. What you ended up with is CHEAT - Sampsa Kiiskinen

The project uses the same approach used by the cheat project. It makes a very tricky use of the C preprocessor directive to achieve test cases registration so the developer can concentrate on writing the test only while cester manages the test registration, execution and analysis.

See the pages at how it works for more explanation.

Contributing

If you have any issue or you want to request a feature you can open a request here anytime and if you made some changes that should be added to the main project send in a pull request.

References

License

MIT License Copyright (c) 2020, Adewale Azeez

libcester's People

Contributors

inkrementator avatar kajtek avatar litikagithub avatar marcelinto avatar nicolasnoble avatar thecarisma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

libcester's Issues

Malformed output JUnit xml file

From master branch.

Command ./tests --cester-verbose --cester-minimal --cester-output=junitxml > out.xml produces

�[0m<?xml version="1.0" encoding="UTF-8" ?>
�[0m�[0m<testsuite tests="�[0m�[0m1�[0m�[0m" failures="�[0m�[0m0�[0m�[0m" name="�[0m�[0mtests�[0m�[0m" errors="0" skipped="�[0m�[0m0�[0m�[0m" time="�[0m�[0m0.00�[0m�[0m">
�[0m�[0m    <testcase classname="�[0m�[0mtests�[0m�[0m" name="�[0m�[0mtest_add_should_sum�[0m�[0m" time="�[0m�[0m0.00�[0m�[0m"�[0m�[0m/>
�[0m�[0m</testsuite>
�[0m

Output on terminal looks good.

Add functionality to time how long a test case should run

If the test case executes beyond the expected time it should fail with ExecutionBeyoundTimeError or something.
There is no need to introduce a thread it should work in multiprocess so the main process can time how long it starts running and if it beyond the time it kills the test case process and reports it,

There should also be an option to allow it to execute complete and report the time the execution completes and the time it expected to complete so it fails on the differences.

Add functionality to test whether a test case compiles or not, and to execute an external app

Test compilation

Add magic and an awesome feature where you can test whether a test case compiles or not if it does not output the error message. The compiled source can be any language,
This can be achieved by setting the compilation executable, options for that test case then cester try to execute that with exec or similar function, then capture the output. This should be optional and can be disabled with #define CESTER_IGNORE_COMPILATION_TEST

Sample format

CESTER_COMPILE_TEST(does_this_so_code_compiles, inst, "gcc", "-ansi --pedantic-errors", {
    #include <stdio>
    int main() {
        printf("yahoo\n");
    }
})
CESTER_COMPILE_TEST(does_this_python_code_runs, inst, "python", "", {
    import io
    print("hello python")
})

The first argument is the test case, the second is the test instance, the third is the compiler executable, the fourth is the code to compile (this is converted to string so there should be a way to remove the enclosing { and };

Test execution

cester should be able to test whether a program runs and validates the output is what is expected similar to CESTER_COMPILE_TEST

CESTER_EXECUTE_TEST(execute_program, inst, "program.exe", "--op", {
    cester_assert_program_output_eq(execute_program, "Unknow option --op");
})

the first argument is the test case name, the second is the test instance, the third is the program or full path to the program o execute, the fourth is the argument to send to the program, the last is the test case body

Enable interactive text execution.

Allow the ability to execute the test interactively.

  • Can execute the previous test
  • Execute a particular test by name or index
  • Change text cases parameters
  • Can see the time, memory took e.t.c to execute a test case
  • E.t.c.

skip all other test cases if a test case crash

On linux with C++ compiler if a test case crash and was recovered by signal, the second time another test case crash signal is not able to recover and intercept the segfault, this bug is only present on Linux with C++ compiler, clang, and gcc.

The solution is to simply skip other test cases if one crash occur, but that would not be the default behavior because compiling the test as C or C++ on other platforms the issue is not present, instead accept a cli flag --cester-skiponfirstcrash and CESTER_SKIP_ON_FIRST_CRASH() this way the option can be supplied to faulty binaries only

A new test case macro that have platform and compiler selection

Add a new test case macro that allows selectively execution features, can accept options for the compiler, platform, and architecture.
Should execute test if it matched the + selection and ignore if matches the - selection. Using bitflag for a more seamless selection. Should be optional for compilation.

Proposed format

CESTER_TEST_SELECTIVE(test_name, arg, {
    // test body
    cester_assert_nothing();
}, 
// fourth argument is flags of selected platforms, compilers, and architectures 
CESTER_SELECTIVE_PLATFORM_ALL | CESTER_SELECTIVE_COMPILER_ALL | CESTER_SELECTIVE_ARCH_ALL
,
// fifth argument is flags of platforms, compilers, and architectures to ignore
CESTER_SELECTIVE_RASPBERRY_PI
)

Possible CESTER_SELECTIVE_* bit flags

  • CESTER_SELECTIVE_PLATFORM_ALL
  • CESTER_SELECTIVE_COMPILER_ALL
  • CESTER_SELECTIVE_ARCH_ALL
  • CESTER_SELECTIVE_NONE
  • CESTER_SELECTIVE_PLATFORM_WINDOWS
  • CESTER_SELECTIVE_PLATFORM_LINUX
  • CESTER_SELECTIVE_PLATFORM_MACOS
  • CESTER_SELECTIVE_PLATFORM_UNIX
  • CESTER_SELECTIVE_PLATFORM_RASPBERRY_PI
  • CESTER_SELECTIVE_PLATFORM_ANDRUINO
  • CESTER_SELECTIVE_PLATFORM_HAIKU
  • CESTER_SELECTIVE_COMPILER_CLANG
  • CESTER_SELECTIVE_COMPILER_GCC
  • CESTER_SELECTIVE_COMPILER_TCC
  • CESTER_SELECTIVE_COMPILER_MSVC
  • CESTER_SELECTIVE_ARCH_ARM
  • CESTER_SELECTIVE_ARCH_X86
  • CESTER_SELECTIVE_ARCH_X64
  • CESTER_SELECTIVE_ARCH_X86_64

Add support for multiple C/C++ files containing tests

Discussed in #54

Originally posted by stefano-p July 21, 2021

I was evaluating this framework and found that is seems not possible to build multiple c test files. So do I have to put all tests in one single module?

This file alone ( test_all.c) compiles and run correctly.

test_all.c

#define CESTER_NO_MAIN
#include <exotic/cester.h>

CESTER_TEST(test1, test_instance,
            cester_assert_equal(NULL, NULL);
)

CESTER_TEST(test_two, test_instance,
    cester_assert_ptr_equal(test_instance, NULL);    
)

CESTER_TEST(test_three, test_instance,
    cester_assert_short_eq(1, 1);    
)

CESTER_BODY(
int main(int argc, char** argv) {
        return CESTER_RUN_ALL_TESTS(argc, argv);
}
)

But as I add a new one (test_my_module1.c) I get some strange linker errors saying that there are:

  • multiple definition of `superTestInstance';
  • multiple definition of `default_color';
  • multiple definition of `hConsole';

I also had to define CESTER_NO_MAIN and CESTER_NO_SIGNAL in order to lower the number of "multiple definition" errors.

test_my_module1.c

#define CESTER_NO_MAIN
#define CESTER_NO_SIGNAL
#include <exotic/cester.h>

CESTER_TEST(test4, test_instance,
            cester_assert_equal(NULL, NULL);
)

Is it possible to spread tests across multiple c files? How?

Please add support for for multiple C/C++ files containing assertions/tests. Ideally it should be possible to build the tests with a single command, and then run the tests with a single command.

CESTER_COMMENT doen't print out the message

The doc says that everything in the macro is printed out at the beginning of the test. However, in my environment of mingw64 in msys2 on windows, the following snippet doesn't print the message.

#include <exotic/cester.h>

CESTER_COMMENT(
    This is a multiline comment in \n
    the source code this text is printed out \n
    before any test cases is executed.
)

CESTER_TEST(foo_bar, test_instance,
	cester_assert_cmp_msg(10,>,2,"is 10 greater than 2");
)
	
CESTER_TEST(foo_zoo, test_instance,
	cester_assert_int_gt(1, 2);
)

After compiling it with gcc test.c -I. -o test, the exe only prints the test results without the comment at the beginning. Am I missing anything?

Currently won't properly compile for "embedded"

If neither _WIN32 nor unix are defined, the following compilation error occurs:

libcester/include/exotic/cester.h:3199:13: error: label 'end_sub_process' used but not defined
 3199 |             goto end_sub_process;
      |             ^~~~

The label end_sub_process is only defined for the _WIN32 or unix case, but not in the 3rd case fallback.

I guess this block of code needs to be disabled in this situation.

Issue with capturing stderr stream

I have an issue with this code

CESTER_CAPTURE_STDERR();
__wrap_infrsprin_(&n,rp,ip,c,&torq1);
cester_assert_stderr_stream_content_contain("constraint");
CESTER_RELEASE_STDERR();

that seems to not capture stderr stream content

Support for multiple CESTER_OPTIONS, and like block

Support for multiple functions for a single macro function below:

CESTER_OPTIONS
CESTER_BEFORE_ALL
CESTER_BEFORE_EACH
CESTER_AFTER_ALL
CESTER_AFTER_ALL

# and in future

CESTER_SETUP
CESTER_TEARDOWN

The method is to concatenate the line number with the name of the function like:

#define CESTER_OPTIONS(x) void cester_options_before_main_##__LINE__();

File globals

In the file that contains my tests, I would like to define a structure that holds all of my test configurations and is then used to initialize the arg pointer in CESTER_BEFORE_ALL. So, something like this:

struct MyTestSetup
{
   ...
};

CESTER_BEFORE_ALL(inst,
    class MyTestSetup setup;
    inst->arg = &setup;
)

However, because the mechanism include the file multiple times, I can't do this because it will fail compilation. I also cannot put the structure definition into the CESTER_BEFORE_ALL definition because then the individual tests won't see it.

So, I can make it work by doing

#ifndef DO_ONCE
#define DO_ONCE
struct MyTestSetup
{
   ...
};
#endif

Not horrible, but not pretty.

Is there a macro that I did not see that allows me to do this more cleanly?

If not, its not a high priority but I would suggest that there be a CESTER_FILE_GLOBAL() section, or something that does the equivalent of the DO_ONCE hack and allows you to put file global type definitions and variables.

Request, more information displayed for assertion with the verbosity set to on

Make the assertion macro print more information in the output, such as the expression that gave a particular output.

For the test case

CESTER_TEST(test_xarray_init, inst, 
    XArray* array;
    enum xtypes_stat status = xarray_new(&array);
    cester_assert_uint_eq(status, X_OK);
)

Compile and run test with the verbose option on :

Currently

Passed test_xarray.c:18: in 'test_xarray_init' expr => 'expected 0, received 0'

Proposed

Passed test_xarray.c:18: in 'test_xarray_init' expr => 'expected status=0, received L_OK=0'

The proposed should be the output with verbose on and the currently is when no verbose is on

TODOs

  • Make failing line print red instead of just grey and red marker
  • add s or m as in seconds or minute to the time displayed before the test name
  • can register for a test to segfault
  • can register for a test to fail
  • can register for a test to be prematurely terminated
  • expected timeout for a test case. can extend the timeout for a test case
  • test whether a test case output to console, stderr and stdout
  • make the library compatible with C 89 and ANSI
  • add assertion macros to test for types range

see https://www.decodejava.com/data-types-in-c.htm https://en.wikipedia.org/wiki/C_data_types

configure libcester repo to properly handle newlines

cester.h appears to have \r\n at the end of each line.

Normally, source code in git has just \n at the end, and git automatically transforms these to \r\n pairs if a checkout is done on Windows and transforms them back to \r\n when the commit is done.

 % curl -s https://raw.githubusercontent.com/exoticlibraries/libcester/master/include/exotic/cester.h | cat -v |head
^M
/**^M
    \copyright MIT License Copyright (c) 2020, Adewale Azeez ^M
    \author Adewale Azeez <[email protected]>^M
    \date 10 April 2020^M
    \file cester.h^M
^M
    Cester is a header only unit testing framework for C. The header ^M
    file can be downloaded and placed in a project folder or can be ^M
    used as part of libopen library by including it in the projects ^M
%

This is generally considered incorrect.

For example, when I updated my cester.h to the new version, I got this warning:

 % git commit -m 'now follows CESTER specs' -a
warning: CRLF will be replaced by LF in src/tests/cester.h.
The file will have its original line endings in your working directory
[slg-dev fbfbd8a] now follows CESTER specs
 3 files changed, 69 insertions(+), 79 deletions(-)
 create mode 100644 src/tests/Makefile
%

You may wish to review these articles and update it accordingly:

use a proper test reporter

OK, the current test reporter is garbage and not easy to manage at all. I am looking at portion the library to systems with very small memory and interfaces hence there might be a need to remote failures or errors in a non-textual way, e.g. on andruino failure can be reported with red light and success can be reported with a green light.

e.g.
To report the test execution on andruino using a red and green led

CESTER_REPORTER_FINAL(_, exit_code, {
     if (exit_code == EXIT_SUCCESS) {
         digitalWrite(GREEN_LED_BUILTIN, HIGH);
         return;
    }
    digitalWrite(RED_LED_BUILTIN, HIGH);
});

In the current implementation it possible but that will be a crazy task to achieve, with a proper reporter interface that will be easily achievable and more test report format like subunit, key-value can be easily integrated.

Also, the new report should provide an interface to intercept or/and allow the creation of custom reports.

CESTER_REPORTER_EXPECT_ACTUAL(cr1, pass, test_case, expect, actual, {
     if (pass == 1) {
         printf("The test in test case %s passes --- expected %s received %s\n", test_case->name, expect, actual);
    }
});

Add key-value output format with segment and group

Text

  + (0.00s) test assert equal
  + (0.00s) test assert not equal

Passed test_assert_test_verbose_levels.c:6: in 'test_assert_equal' => expected 'NULL=0000000000000000', received '((void*)0)=0000000000000000'
Passed test_assert_test_verbose_levels.c:10: in 'test_assert_not_equal' => not expecting 'NULL', received '"NotEqual"'
Passed test_assert_test_verbose_levels.c:11: in 'test_assert_not_equal' expr => '(1)'

Ran 2 test(s) in 0.00 Seconds
Synthesis: SUCCESS Tests: 2 | Passing: 2 | Failing: 0

key-value

total_test = 2
passing = 2
failing = 0
file_name = test_assert_test_verbose_levels

[test_assert_equal]
total_test = 1
passing = 1
failing = 0
time_taken = 0.00s
output = Passed test_assert_test_verbose_levels.c:6: in 'test_assert_equal' => expected 'NULL=0000000000000000', received '((void*)0)=0000000000000000'

[test_assert_not_equal]
total_test = 2
passing = 2
failing = 0
time_taken = 0.00s
output = Passed test_assert_test_verbose_levels.c:10: in 'test_assert_not_equal' => not expecting 'NULL', received '"NotEqual"' \
                           Passed test_assert_test_verbose_levels.c:11: in 'test_assert_not_equal' expr => '(1)'


Tests using c++ templates

It would be useful to be able to define a test that uses C++ templates to test template functions. For example, if I have a function like this:

template <typename T>
inline bool isSubnormal(const T & v)
{
    return std::isfinite(v) && !std::isnormal(v) && v != T(0.0);
}

Currently, my tests look like this:

CESTER_TEST(isSubnormalFloatWithSubnormalInput, inst,
    float p1 = std::numeric_limits<float>::min() / float(2.0);
    cester_assert_true(isSubnormal(p1));
)
CESTER_TEST(isSubnormalDoubleWithSubnormalInput, inst,
    double p1 = std::numeric_limits<double>::min() / double(2.0);
    cester_assert_true(isSubnormal(p1));
)

It would be great to do something like:

CESTER_TEMPLATE_TEST(isSubnormalWithSubnormalInput, inst, T, (float, double, long double),
    T p1 = std::numeric_limits<T>::min() / T(2.0);
    cester_assert_true(isSubnormal(p1));
)

Basically - add parameters specifying the template variable and the list of types to instantiate.

It would have to generate names for each of the tests that include an indication what T was for that test.

I have not really thought through the ideal syntax, because if you have more than one template variable, my suggested syntax is not very practical, but you get the idea.....

Add macro to run the before_ and after funtion

Create macros to invoke the before and after function

CESTER_BEFORE_ALL()
CESTER_BEFORE_EACH()
CESTER_AFTER_ALL()
CESTER_AFTER_EACH()

Attache to superTestInstance.registered_test_cases

Fail to compile the example on termux

Firstly, thanks for the awesome testing framework.

I've used libcester on termux, but failed to compile the given example. The errors are as follows:

In file included from ./test.c:2:
/data/data/com.termux/files/usr/local/include/exotic/cester.h:283:10: error: field has incomplete type 'FILE' (aka 'struct __sFILE')
    FILE original_stream;                   /**< The actual address of the captured stream. For internal use only.*/
         ^
/data/data/com.termux/files/usr/include/stdio.h:61:8: note: forward declaration of 'struct __sFILE'
struct __sFILE;
       ^
In file included from ./test.c:2:
/data/data/com.termux/files/usr/local/include/exotic/cester.h:407:10: error: field has incomplete type 'FILE' (aka 'struct __sFILE')
    FILE output_stream_address;                         /**< Output stream address. incase the output stream was captured in test it state can be reset. For internal use only. */
         ^
/data/data/com.termux/files/usr/include/stdio.h:61:8: note: forward declaration of 'struct __sFILE'
struct __sFILE;
       ^
In file included from ./././test.c:2:
/data/data/com.termux/files/usr/local/include/exotic/cester.h:3880:13: error: incomplete type 'FILE' (aka 'struct __sFILE') is not assignable
    *stream = *(captured_stream->replaced_stream_handle);
    ~~~~~~~ ^
/data/data/com.termux/files/usr/include/stdio.h:61:8: note: forward declaration of 'struct __sFILE'
struct __sFILE;
       ^
In file included from ./././test.c:2:
/data/data/com.termux/files/usr/local/include/exotic/cester.h:3959:33: error: incomplete type 'FILE' (aka 'struct __sFILE') is not assignable
                        *stream = *(captured_stream->replaced_stream_handle);
                        ~~~~~~~ ^
/data/data/com.termux/files/usr/local/include/exotic/cester.h:367:43: note: expanded from macro 'CESTER_ARRAY_FOREACH'
                                          z\
                                          ^
/data/data/com.termux/files/usr/include/stdio.h:61:8: note: forward declaration of 'struct __sFILE'
struct __sFILE;
       ^
4 errors generated.

My compiler is clang of version 15 on termux. Then I check it on windows with clang of the same version, and no error happens.

Maybe this error is related to the termux platform, but I'm not sure. If you are free, please check it. Thanks!

Cannot use automatic variables in CESTER_BEFORE_ALL

I used something like this:

CESTER_BEFORE_ALL(inst,  
    std::vector setup;
    inst->arg = & setup;
)

This did not work because the destructor for 'setup' was called before any of the tests were actually called.

This should be a big Warning in the documentation for CESTER_BEFORE_ALL. I know the example uses dynamic allocation which gets around the problem, but it does not explain why. I think it needs a clear statement that you must use data that is not automatically deallocated.

In hindsight I understand why this is, but it took me a while to figure out why I was crashing and I think others will make the same mistake.

explain "Isolated tests not supported in this environment. The tests will be run on the main process"

I've added cester to a system and I'm getting this warning, which is perplexing:

./cester.h:3277:17: warning: Isolated tests not supported in this environment. The tests will be run on the main process [-W#pragma-messages]
        #pragma message("Isolated tests not supported in this environment. The tests will be run on the main process")
                ^
1 warning generated.

It still works, but I'd like to know what the warning means. It's not in the documentation.

remove the usage of jmp_buf for crash recovery

Use the iterator for a more clean recovery method instead of jmp_buf.
The way this will work is a super instance index will increase per the test case index so when a test case crashes the run_test_iterator will be invoked with the next test index instead of starting over again, or as of today using jmp_buf to jump to the point of recovery.

[-Wint-conversion] warning always occurs.

I am new beginner for this framework.
I found some annoying warning message during my tutorial.

How to reproduce

// test.c
#include <exotic/cester.h>
 
CESTER_TEST(test_one, inst,
    cester_assert_nothing();    
)
$ gcc -I./ test.c -o test.out
In file included from test.c:1:
./exotic/cester.h:481:5: warning: initialization of ‘int’ from ‘void *’ makes integer from pointer without a cast [-Wint-conversion]
  481 |     CESTER_NULL,                                     /* output_stream_address */
      |     ^~~~~~~~~~~
./exotic/cester.h:481:5: note: (near initialization for ‘superTestInstance.output_stream_address._flags’)

my environment

$ uname -a
Linux foo 6.5.0-27-generic #28~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 15 10:51:06 UTC 2 x86_64 x86_64 x86_64 GNU/Linux

temporary solution

I managed to prevent the warning message from appearing by using -Wno-int-conversion option.

Please help newbie. Thanks :)

Add generators and parametarized test

Add generator to generate values between ranges,
To generate assertions for ranges of options

CESTER_TEST(generators, inst, {
    CESTER_GENERATE_INT_RANGE(x,1, 30, {
        cester_assert_int_eq(x, y);
    })
})

or better format

New future features

  • add logic to send a kill signal to a test case or running program case or compilation case after some time or at a specific time, so the user termination can be tested
  • fix libcester tap format printing multiple #
  • check whether malloc is actually called for a malloc with a different name
  • add libcester to madeinnigeria repo
  • add JSON output format
  • add key-value output format

Compilation error on older Linux kernel 3.10.0-957

In file included from /path/tests/tests.c:1:0:
/path/_deps/libcester-src/include/./exotic/cester.h: In function ‘cester_run_test’:
/path/build/_deps/libcester-src/include/./exotic/cester.h:3259:9: error: unknown type name ‘pid_t’
         pid_t pid;

I think the problem occurs because older POSIX (so older Linux API) defines pid_t only in <sys/types.h>. POSIX.1-2001 defines it also in <unistd.h> and cester.h includes only the last one.
I would recommend to add additional <sys/types.h> maybe in some #ifdef statement checking available POSIX implementation.

I found this issue on CentOS 7.4 with 3.10.0-957 kernel.

A bug that execute an expression in assertion macro twice instead of once

Bug Reproduction

#include <stdio.h>
#include <exotic/cester.h>

CESTER_BODY(
int global_size = 1;
int size() {
    printf("Getting size %d\n", global_size);
    global_size++;
    return global_size;
}
)

CESTER_TEST(test_init_set, _, {
    cester_assert_int_eq(size(), 1);
})

CESTER_OPTIONS(
    CESTER_VERBOSE_LEVEL(2);
)

Notice it prints out "Getting size X" more than once

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.