Giter Site home page Giter Site logo

christophercrouzet / rexo Goto Github PK

View Code? Open in Web Editor NEW
27.0 27.0 6.0 1.52 MB

Neat single-file cross-platform unit testing framework for C/C++.

License: The Unlicense

CMake 0.85% Makefile 0.44% C 85.60% C++ 10.97% Python 2.14%
c framework header-only unit-testing

rexo's Introduction

Hi, I’m Christopher! 👋

Originally from France 🇫🇷, I was a technical artist for over 8 years on VFX and animation movies, but I've since then transitioned to being a full-time software engineer who strives in designing and building tools, workflows, and APIs, with a focus not only on user experience and simplicity, but also on maintainability.

As the time goes by, I'm increasingly being drawn towards lower level territory and have a strong interest in real-time, graphics, simulation, compiler, and also performance programming, for all of which I'm yearning to grow my skills in.

Most of the projects listed in this page were developed as the result of wanting to explore and learn specific topics.

I don't bite so come say hi! 😊

Projects in C/C++ 🚀

rexo
Single-file cross-platform unit testing framework with automatic test registration and an emphasis on providing a clean API.
uuki
Toy project to learn about writing compilers—I haven't really started working on it other than writing a base library with no dynamic allocations, some debugging utilities, a colorful logger, a virtual memory API, a custom linear allocator, and a growable array.
zero
Experiment in writing single-file libraries with no #include statements in the header sections, as described in the article Physical Design of The Machinery.
dekoi
Playground to learn about the Vulkan API by following the Vulkan Tutorial and adapting it to C.
m3ta
Header-only library to experiment with how much code can be evaluated at compile-time using C++'s templates. The answer is: a lot! C++ templates are in fact turing complete! 😄

Projects in Python 🐍

hienoi
Framework to simulate 2D particles. It was a good exercise to learn about OpenGL, NumPy, IPC (Inter-Process Communication), and to figure out how to abstract all this through an easy-to-use API.
wadu
Implementation of recurrence rules for calendar events as defined in the RFC 5545 specification. I expected it to be challenging and it really didn't disappoint! 😅
gorilla
Framework that provides a convenient approach to monkey patching. Mostly done to build experience in designing APIs and delivering a fully finished project, with unit tests and documentation.
bana
Tiny set of extention for the Maya Python API built on top of Gorilla, as a way to validate the design of Gorilla.
revl
Library to generate pseudo-random (deterministic) Maya scenes based on a set of rules, in order to provide something akin to fuzzy testing and also to help profiling performance.

Projects in JavaScript 🌐

eddi
Static site generator that is powering my current website. This was an interesting challenge to learn about Node.js and writing asynchronous code.

rexo's People

Contributors

christophercrouzet avatar default-writer avatar peterleegolang avatar samuelmarks 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

Watchers

 avatar  avatar  avatar  avatar

rexo's Issues

memory leak

#5

using valgrind i was able to find memory leak:

valgrind --leak-check=yes ./build/main

Example project:

https://github.com/funcelot/c

before:

==19423==
==19423== HEAP SUMMARY:
==19423== in use at exit: 392 bytes in 1 blocks
==19423== total heap usage: 35 allocs, 34 frees, 2,616 bytes allocated
==19423==
==19423== 392 bytes in 1 blocks are definitely lost in loss record 1 of 1
==19423== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==19423== by 0x10B7F7: rx__run_test_cases (rexo.h:4846)
==19423== by 0x10BA9C: rx__run_registered_test_cases (rexo.h:4918)
==19423== by 0x10FC53: rx_run (rexo.h:6044)
==19423== by 0x110734: main (main.c:295)
==19423==
==19423== LEAK SUMMARY:
==19423== definitely lost: 392 bytes in 1 blocks
==19423== indirectly lost: 0 bytes in 0 blocks
==19423== possibly lost: 0 bytes in 0 blocks
==19423== still reachable: 0 bytes in 0 blocks
==19423== suppressed: 0 bytes in 0 blocks
==19423==
==19423== For lists of detected and suppressed errors, rerun with: -s
==19423== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

after:

==16591==
==16591== HEAP SUMMARY:
==16591== in use at exit: 0 bytes in 0 blocks
==16591== total heap usage: 35 allocs, 35 frees, 2,616 bytes allocated
==16591==
==16591== All heap blocks were freed -- no leaks are possible
==16591==
==16591== For lists of detected and suppressed errors, rerun with: -s
==16591== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Global buffer overflow on macOS

Hi, when running without any test content, the library seems to do a buffer overflow (no code outside of rexo is involved)

test-board(24232,0x10d806600) malloc: nano zone abandoned due to inability to preallocate reserved vm space.
=================================================================
==24232==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000107974148 at pc 0x000107967a38 bp 0x7ff7b859ed70 sp 0x7ff7b859ed68
READ of size 8 at 0x000107974148 thread T0
    #0 0x107967a37 in rx_enumerate_test_cases rexo.h:6596
    #1 0x10796270f in rx__run_registered_test_cases rexo.h:5349
    #2 0x107961934 in rx_run rexo.h:6682
    #3 0x1079618e3 in rx_main rexo.h:6694
    #4 0x1079618a8 in main test-board.c:28
    #5 0x10d78b52d in start+0x1cd (dyld:x86_64+0x552d)

0x000107974148 is located 24 bytes to the left of global variable 'rx__test_case_desc_ptr_basics_clear' defined in 'tests/test-board.c:21:1' (0x107974160) of size 8
0x000107974148 is located 0 bytes to the right of global variable 'rx__dummy_case' defined in 'extern/librexo/rexo.h:4791:52' (0x107974140) of size 8
SUMMARY: AddressSanitizer: global-buffer-overflow rexo.h:6596 in rx_enumerate_test_cases
Shadow bytes around the buggy address:
  0x100020f2e7d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100020f2e7e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100020f2e7f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100020f2e800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100020f2e810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100020f2e820: 00 00 00 00 00 f9 f9 f9 00[f9]f9 f9 00 f9 f9 f9
  0x100020f2e830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100020f2e840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100020f2e850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100020f2e860: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100020f2e870: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==24232==ABORTING

The content of the test file is:

#include <rexo.h>

RX_TEST_CASE(basics, clear)
{
}

int
main(int argc, char **argv)
{
	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
}

Compiled on macOS using -fsanitize=address,undefined.

Example output

It would be very nice if the Readme would contain either text snippets or screenshots illustrating what the output of this test framework looks like, since that is often an important factor when deciding if it's worth investing time in a given framework.

How does automatic test case registration work?

I'm reading your code to learn how to do this myself.

I've been trying to do it by building a static array at compile time using the preprocessor, ut I'm struggling to get that method to work.

Any tips? thanks

Automatic Test Discovery

Having to write tests and then register them as part of a suite feels a bite redundant, error-prone since it would be easy to forget, and also quite verbose.

While reading CTest's source code, I noticed that data sections defined through compilers attributes could be accessed within the same translation unit, as seen below:

#include <stdio.h>


// Method seen on CTest <https://github.com/bvdberg/ctest>.

// TODO: add alternatives for non-GNU compliant compilers.
#define RXP_SECTION __attribute__ ((used, section (".rexo"), aligned(1)))

#define RX_TEST_CASE(name)                                                     \
    static void name##Func();                                                  \
    static struct RxTestCase name##Struct RXP_SECTION = {                      \
        .pfn = name##Func,                                                     \
    };                                                                         \
    static void name##Func()

typedef void (*RxPfnTestCase)();

static struct RxTestCase rxpRoot RXP_SECTION;


struct RxTestCase {
    const char *pName;
    RxPfnTestCase pfn;
};


RX_TEST_CASE(testFoo) {
    printf("foo\n");
}


RX_TEST_CASE(testBar) {
    printf("bar\n");
}


int
main()
{
    struct RxTestCase *pCase;

    pCase = &rxpRoot;

    ++pCase;
    pCase->pfn();

    ++pCase;
    pCase->pfn();

    return 0;
}

I'm planning to experiment with this approach and will look on how to expend it to the suites. Ideally, we'd end up with this kind of code on the user-side:

#include <rexo/rexo.h>


RX_TEST_CASE(myTestSuite, testFoo) {
    RX_CHECK_INT_EQUAL(1, 1);
}


RX_TEST_CASE(myTestSuite, testBar) {
    RX_CHECK_INT_EQUAL(2, 2);
}


int
main(int argc, const char **ppArgv)
{
    rxRun(argc, ppArgv);
    return 0;
}

Where both test cases would be registered within a same (default initialized) test suite.

In the case where a more specific test suite is required, such as one providing a fixture, then we would be able to explicitely define it as such:

#include <rexo/rexo.h>


enum RxStatus
mySetUp()
{
    // ...
    return RX_SUCCESS;
}

void
myTearDown()
{
    // ...
}


RX_TEST_SUITE(myTestSuite, .setUp = mySetUp, .tearDown = myTearDown);


RX_TEST_CASE(myTestSuite, testFoo) {
    // access some fixture data here.
    RX_CHECK_INT_EQUAL(1, 1);
}


int
main(int argc, const char **ppArgv)
{
    rxRun(argc, ppArgv);
    return 0;
}

Warning passing char ** to const char **

Hi,

There is a warning because rx_main takes a const char ** (which is incompatible with char **) that can be seen with -Wall -Wextra.

Const correctness of double pointers is somewhat often misunderstood, I admit.

test/base64.c:389:32: warning: passing argument 4 of 'rx_main' from incompatible pointer type [-Wincompatible-pointer-types]
  389 |  return rx_main(0, NULL, argc, argv) == RX_SUCCESS ? 0 : 1;
      |                                ^~~~
      |                                |
      |                                char **
In file included from test/base64.c:21:
extern/librexo/rexo.h:6689:22: note: expected 'const char **' but argument is of type 'char **'
 6689 |         const char **argv)

Feature: run selected tests only

Most unit test frameworks have an option to only run tests specified as arguments.

Proposed syntaxes:

  • -t suite: run all tests under suite.
  • -t suite/test: run the explicit test in suite.

The -t option should be combined, that means -t suiteA -t suiteB will run all tests from suiteA and suiteB.

Linking issue on MinGW64 + Clang

Hi,

Using msys2 with the clang64 toolchain I get a few linking issue given a basic template. I'm currently investigating the issue.

lld-link: error: undefined symbol: __start_rxcase
>>> referenced by objects.a(test-vfs-zip.c.obj):(.refptr.__start_rxcase)

lld-link: error: undefined symbol: __start_rxsuite
>>> referenced by objects.a(test-vfs-zip.c.obj):(.refptr.__start_rxsuite)

lld-link: error: undefined symbol: __stop_rxcase
>>> referenced by objects.a(test-vfs-zip.c.obj):(.refptr.__stop_rxcase)

lld-link: error: undefined symbol: __stop_rxsuite
>>> referenced by objects.a(test-vfs-zip.c.obj):(.refptr.__stop_rxsuite)
gcc: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [tests/CMakeFiles/test-vfs-zip.dir/build.make:111: tests/test-vfs-zip.exe] Error 1
make[1]: *** [CMakeFiles/Makefile2:921: tests/CMakeFiles/test-vfs-zip.dir/all] Error 2
make: *** [Makefile:146: all] Error 2

warnings on gcc 9.4

a tremendous number of
warning: too many arguments for format [-Wformat-extra-args]

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.