Write tests in C

Related tags

Debug libtap
Overview

NAME

libtap - Write tests in C

SYNOPSIS

#include <tap.h>

int main () {
    plan(5);
    int bronze = 1, silver = 2, gold = 3;
    ok(bronze < silver, "bronze is less than silver");
    ok(bronze > silver, "not quite");
    is("gold", "gold", "gold is gold");
    cmp_ok(silver, "<", gold, "%d <= %d", silver, gold);
    like("platinum", ".*inum", "platinum matches .*inum");
    done_testing();
}

results in:

1..5
ok 1 - bronze is less than silver
not ok 2 - not quite
#   Failed test 'not quite'
#   at t/synopsis.c line 7.
ok 3 - gold is gold
ok 4 - 2 <= 3
ok 5 - platinum matches .*inum
# Looks like you failed 1 test of 5 run.

DESCRIPTION

tap is an easy to read and easy to write way of creating tests for your software. This library creates functions that can be used to generate it for your C programs. It is implemented using macros that include file and line info automatically, and makes it so that the format message of each test is optional. It is mostly based on the Test::More Perl module.

INSTALL

On Unix systems:

$ make
$ make install

For more detailed installation instructions (eg, for Windows), see INSTALL.

FUNCTIONS

  • plan(tests)

  • plan(NO_PLAN)

  • plan(SKIP_ALL);

  • plan(SKIP_ALL, fmt, ...)

    Use this to start a series of tests. When you know how many tests there will be, you can put a number as a number of tests you expect to run. If you do not know how many tests there will be, you can use plan(NO_PLAN) or not call this function. When you pass it a number of tests to run, a message similar to the following will appear in the output:

    1..5
    

    If you pass it SKIP_ALL, the whole test will be skipped.

  • ok(test)

  • ok(test, fmt, ...)

    Specify a test. the test can be any statement returning a true or false value. You may optionally pass a format string describing the test.

    ok(r = reader_new("Of Mice and Men"), "create a new reader");
    ok(reader_go_to_page(r, 55), "can turn the page");
    ok(r->page == 55, "page turned to the right one");
    

    Should print out:

    ok 1 - create a new reader
    ok 2 - can turn the page
    ok 3 - page turned to the right one
    

    On failure, a diagnostic message will be printed out.

    not ok 3 - page turned to the right one
    #   Failed test 'page turned to the right one'
    #   at reader.c line 13.
    
  • is(got, expected)

  • is(got, expected, fmt, ...)

  • isnt(got, unexpected)

  • isnt(got, unexpected, fmt, ...)

    Tests that the string you got is what you expected. with isnt, it is the reverse.

    is("this", "that", "this is that");
    

    prints:

    not ok 1 - this is that
    #   Failed test 'this is that'
    #   at is.c line 6.
    #          got: 'this'
    #     expected: 'that'
    
  • cmp_ok(a, op, b)

  • cmp_ok(a, op, b, fmt, ...)

    Compares two ints with any binary operator that doesn't require an lvalue. This is nice to use since it provides a better error message than an equivalent ok.

    cmp_ok(420, ">", 666);
    

    prints:

    not ok 1
    #   Failed test at cmpok.c line 5.
    #     420
    #         >
    #     666
    
  • cmp_mem(got, expected, n)

  • cmp_mem(got, expected, n, fmt, ...)

    Tests that the first n bytes of the memory you got is what you expected. NULL pointers for got and expected are handled (if either is NULL, the test fails), but you need to ensure n is not too large.

    char *a = "foo";
    char *b = "bar";
    cmp_mem(a, b, 3)
    

    prints

    not ok 1
    #   Failed test at t/cmp_mem.c line 9.
    #     Difference starts at offset 0
    #          got: 0x66
    #     expected: 0x62
    
  • like(got, expected)

  • like(got, expected, fmt, ...)

  • unlike(got, unexpected)

  • unlike(got, unexpected, fmt, ...)

    Tests that the string you got matches the expected extended POSIX regex. unlike is the reverse. These macros are the equivalent of a skip on Windows.

    like("stranger", "^s.(r).*\\1$", "matches the regex");
    

    prints:

    ok 1 - matches the regex
    
  • pass()

  • pass(fmt, ...)

  • fail()

  • fail(fmt, ...)

    Speciy that a test succeeded or failed. Use these when the statement is longer than you can fit into the argument given to an ok() test.

  • dies_ok(code)

  • dies_ok(code, fmt, ...)

  • lives_ok(code)

  • lives_ok(code, fmt, ...)

    Tests whether the given code causes your program to exit. The code gets passed to a macro that will test it in a forked process. If the code succeeds it will be executed in the parent process. You can test things like passing a function a null pointer and make sure it doesnt dereference it and crash.

    dies_ok({abort();}, "abort does close your program");
    dies_ok({int x = 0/0;}, "divide by zero crash");
    lives_ok({pow(3.0, 5.0);}, "nothing wrong with taking 3**5");
    

    On Windows, these macros are the equivalent of a skip.

  • done_testing()

    Summarizes the tests that occurred and exits the main function. If there was no plan, it will print out the number of tests as.

    1..5
    

    It will also print a diagnostic message about how many failures there were.

    # Looks like you failed 2 tests of 3 run.
    

    If all planned tests were successful, it will return 0. If any test fails, it will return 1. If they all passed, but there were missing tests, it will return 2.

  • diag(fmt, ...)

    print out a message to the tap output on stdout. Each line is preceeded by a "# " so that you know its a diagnostic message.

    diag("This is\na diag\nto describe\nsomething.");
    

    prints:

    # This is
    # a diag
    # to describe
    # something
    

    ok() and this function return an int so you can use it like:

    ok(0) || diag("doh!");
    
  • skip(test, n)

  • skip(test, n, fmt, ...)

  • end_skip

    Skip a series of n tests if test is true. You may give a reason why you are skipping them or not. The (possibly) skipped tests must occur between the skip and end_skip macros.

    skip(TRUE, 2);
    ok(1);
    ok(0);
    end_skip;
    

    prints:

    ok 1 # skip
    ok 2 # skip
    
  • todo()

  • todo(fmt, ...)

  • end_todo

    Specifies a series of tests that you expect to fail because they are not yet implemented.

    todo()
    ok(0);
    end_todo;
    

    prints:

    not ok 1 # TODO
    #   Failed (TODO) test at todo.c line 7
    
  • BAIL_OUT()

  • BAIL_OUT(fmt, ...)

    Immediately stops all testing.

    BAIL_OUT("Can't go no further");
    

    prints

    Bail out!  Can't go no further
    

    and exits with 255.

Comments
  • Enhancement: add

    Enhancement: add "All tests passed!" output from exit_status()

    I would like to suggest adding the following code just after line 752 in tap.c

    if (retval == 0) {
    printf("All tests passed!\n");
    }
    

    The effect of this would be to let the user know that no tests failed. This is helpful for console programs that produce a lot of output, so that the user doesn't have to scroll back through all of it to see what happened. In other cases, exit_status() prints informative information, so it would be good to have information printed about tests passing as well.

    opened by leavens 4
  • Add AUTO_PLAN to determine number of tests in file

    Add AUTO_PLAN to determine number of tests in file

    Motivation

    A lot of my test files take the form of:

    
    void test_literals(void) {
        cmp_ok(3, "==", 3, "should find that 3 equals 3");
    }
    
    void test_arithmetic(void) {
        cmp_ok(1+1, "==", 2, "should find that 1+1 equals 2");
        cmp_ok(2*2, "==", 4, "should find that 2*2 equals 4");
    }
    
    int main(int argc, char **argv) {
        plan(NO_PLAN);
        test_literals();
        test_arithmetic();
        done_testing();
    }
    

    However, the problem with this is that it doesn't know the number of tests in advance. The easy workaround is to run it once, determine the number of tests, and then modify the plan(NO_PLAN) like to use that number, but this is a little awkward, especially when the compiler could do the counting for us.

    Implementation

    AUTO_PLAN is an implementation of this idea of making the compiler count for us. It uses the special preprocessor variable __COUNTER__ to count all of the lines that could produce an output line. The way to use this feature is:

    
    void test_literals(void) {
        cmp_ok(3, "==", 3, "should find that 3 equals 3");
    }
    
    void test_arithmetic(void) {
        cmp_ok(1+1, "==", 2, "should find that 1+1 equals 2");
        cmp_ok(2*2, "==", 4, "should find that 2*2 equals 4");
    }
    
    int main(int argc, char **argv) {
        plan(AUTO_PLAN);
        test_literals();
        test_arithmetic();
        done_testing();
    }
    

    The compiler will automatically determine that it should plan for 3 test cases (the 3 cmp_ok lines) and rewrite the plan(AUTO_PLAN) as plan(3). I decided to hide this feature behind an #ifdef USE_AUTO_PLAN because there is a possibility that someone's code already uses the __COUNTER__ variable.

    One of the major limitations of this feature is that you can't split your tests up into multiple files and expect it to work, because the __COUNTER__ variable gets reset for each file. We could work around this problem by using Boost, but that's too large of a dependency for a simple library like this one.

    Another limitation is that it will get the wrong count if you use pass() and fail() separately. This is because they each use ok() internally, but each ok() increases the number of tests, so if you had a construct like:

    void test_pass_fail(void) {
        if (some_complicated_function()) {
            pass("Hooray");
        } else {
            fail("Boo");
        }
    }
    

    then this will be incorrectly counted as 2 tests instead of 1 (the pass() gets transformed into ok(1, "", "Hooray") and similarly for fail()). A workaround would be:

    void test_pass_fail(void) {
        int rv;
    
        rv = some_complicated_function();
        cmp_ok(rv, "==", 0, "should do something correctly");
    }
    

    which will be correctly counted as 1 test.


    Let me know if you have any questions or concerns with this feature.

    opened by player1537 4
  • Version?

    Version?

    I submitted libtap to the AUR, but I didn't know what the version of this library was so I made one up. It would help a lot if you would tag releases so they show up under "Releases" on github: git tag 0.1.0 or git tag v0.1.0. If you do that, I can make another PKGBUILD that targets released versions instead of development versions.

    If my pull request (#17) is acceptable, I'll switch my PKGBUILD to point to this repository instead of my fork.

    opened by beatgammit 3
  • cmp_mem() improvements

    cmp_mem() improvements

    I've implemented the improvements you proposed in your comments for #10

    • NULL for got and expected is handled
    • reworked logic so memcmp() is not needed
    • cosmetic fix in diagnostics
    opened by sputtene 3
  • Add cmp_mem test

    Add cmp_mem test

    Hi Zorgnax,

    I've added a cmp_mem test to easily compare arrays, memory regions, ... When I have time, I might add a version that takes an array literal instead of a variable as the "expected" parameter.

    Thanks for libtap!

    opened by sputtene 3
  • Request to pull - Winblows / C++ compatibility

    Request to pull - Winblows / C++ compatibility

    Hi,

    even though I'm not a fan of the target platform in particular, I'd like to ask you to integrate this set of changes which makes libtap integrate well with VS C++ projects (tested with 2010) and provide a way of running prove against the actual generated tests by default.

    Thank you for maintaining libtap! Alex

    opened by outergod 3
  • Only define define MAP_ANONYMOUS when necessary

    Only define define MAP_ANONYMOUS when necessary

    On NetBSD MAP_ANONYMOUS is already defined and libtap fails to build with:

    $ uname -v
    NetBSD 7.1.2 (GENERIC.201803151611Z)
    
    $ gmake
    cc -Wall -I. -fPIC   -c tap.c  -o tap.o
    tap.c:302:0: warning: "MAP_ANONYMOUS" redefined [enabled by default]
     #define MAP_ANONYMOUS MAP_ANON
     ^
    In file included from tap.c:297:0:
    /usr/include/sys/mman.h:97:0: note: this is the location of the previous definition
     #define MAP_ANONYMOUS 0x1000 /* allocated from memory, swap space */
     ^
    tap.c: In function 'tap_test_died':
    tap.c:302:23: error: 'MAP_ANONYMOUS' undeclared (first use in this function)
     #define MAP_ANONYMOUS MAP_ANON
                           ^
    tap.c:313:39: note: in expansion of macro 'MAP_ANONYMOUS'
                              MAP_SHARED | MAP_ANONYMOUS, -1, 0);
                                           ^
    tap.c:302:23: note: each undeclared identifier is reported only once for each function it appears in
     #define MAP_ANONYMOUS MAP_ANON
                           ^
    tap.c:313:39: note: in expansion of macro 'MAP_ANONYMOUS'
                              MAP_SHARED | MAP_ANONYMOUS, -1, 0);
                                           ^
    Makefile:16: recipe for target 'tap.o' failed
    gmake: *** [tap.o] Error 1
    

    I started out with this approach:

    #ifndef MAP_ANONYMOUS && defined MAP_ANON
    #define MAP_ANONYMOUS MAP_ANON
    #endif
    

    but instead decided to heavily borrow an approach from libressl-portable.

    opened by travispaul 2
  • use of plan() causes bool functions that don't return anything to work both as true and false

    use of plan() causes bool functions that don't return anything to work both as true and false

    I have been using libtap in my Introduction to Programming with C class at UCF this semester. Overall we are very happy with it. Thanks!

    However, students complained that for one of my test suites all the tests passed, even though they had no code in a predicate function (i.e., one that should return a _Bool). Of course, that is an incorrect implementation, but often students are omitting the return statement in a function, and so not detecting that is a serious problem when not detected. I was eventually able to find that the tests improperly passed in this manner only if the testing code called plan(). If the call to plan() is omitted, then the tests work properly, checking the return value. I have boiled this down to the attached files, which I thiink clearly show the problem. This happens under Windows 10 using gcc (GCC) 5.4.0 running under cygwin and also under MingW gcc.

    The attached zip file has 3 files. bfun.c has a Boolean-valued function named bfun in it that doesn't return a value. bfun.h is a header file for that. test_bfun.c has a main() function, which shows the problem. If you comment out the call to plan() in test_bfun.c, you get the expected detection of incorrect behavior in bfun().

    bfun-example.zip

    opened by leavens 2
  • Create shared objects by default

    Create shared objects by default

    • create directories as necessary
    • use -fPIC so shared objects work
    • updated .gitignore

    I'm building a PKGBUILD for ArchLinux and it works with these changes.

    opened by beatgammit 2
  • Forcibly disable optimization on tests

    Forcibly disable optimization on tests

    I ran into the issue of GCC optimization causing a test failure in t/diesok.c at the division-by-zero test, even after rebasing our internal package's source against 56e3123 (internal case CPANEL-41315). At first, I resorted to inline assembly, and I also considered using a pragma or function attributes to limit the disabling of optimization to just the code or file of that test, but this seemed like the most generic well-supported solution.

    opened by sloanebernstein 1
  • Fix bug which prevents builds for Windows targets

    Fix bug which prevents builds for Windows targets

    unlike is replaced with a skip macro on Windows. The macro definition is missing needed parenthesis and that results in Windows builds failing. This PR corrects the macro.

    opened by jeffsw 1
Releases(0.1.0)
Owner
Jacob Gelbman
Jacob Gelbman
A modern, C++-native, header-only, test framework for unit-tests, TDD and BDD - using C++11, C++14, C++17 and later (or C++03 on the Catch1.x branch)

Catch2 v3 is being developed! You are on the devel branch, where the next major version, v3, of Catch2 is being developed. As it is a significant rewo

Catch Org 16k Jan 8, 2023
Execute Input/Output tests on a software

IO-Tester The goal of this software is to take files as parameter that contains lists of inputs and expected ouputs and to tell the user if the tests

Martin 31 Dec 11, 2022
Palanteer is a set of high performance visual profiler, debugger, tests enabler for C++ and Python

Palanteer is a set of lean and efficient tools to improve the general software quality, for C++ and Python programs.

Damien Feneyrou 1.9k Dec 29, 2022
DotX64Dbg aims to provide a seamless way to write and test plugins for X64Dbg using .Net 5.0 and C#.

DotX64Dbg (EARLY ALPHA) Plugins and Scripting with C# for x64Dbg. Create Plugins for X64Dbg with ease DotX64Dbg aims to provide a seamless way to writ

ζeh Matt 7 Oct 16, 2022
Write tests in C

NAME libtap - Write tests in C SYNOPSIS #include <tap.h> int main () { plan(5); int bronze = 1, silver = 2, gold = 3; ok(bronze < silver,

Jacob Gelbman 231 Jan 2, 2023
RemixDB: A read- and write-optimized concurrent KV store. Fast point and range queries. Extremely low write-amplification.

REMIX and RemixDB The REMIX data structure was introduced in paper "REMIX: Efficient Range Query for LSM-trees", FAST'21. This repository maintains a

Xingbo Wu 81 Dec 3, 2022
A modern, C++-native, header-only, test framework for unit-tests, TDD and BDD - using C++11, C++14, C++17 and later (or C++03 on the Catch1.x branch)

Catch2 v3 is being developed! You are on the devel branch, where the next major version, v3, of Catch2 is being developed. As it is a significant rewo

Catch Org 16k Jan 8, 2023
A modern, C++-native, header-only, test framework for unit-tests, TDD and BDD - using C++11, C++14, C++17 and later (or C++03 on the Catch1.x branch)

Catch2 v3 is being developed! You are on the devel branch, where the next major version, v3, of Catch2 is being developed. As it is a significant rewo

Catch Org 16k Jan 8, 2023
Execute Input/Output tests on a software

IO-Tester The goal of this software is to take files as parameter that contains lists of inputs and expected ouputs and to tell the user if the tests

Martin 31 Dec 11, 2022
A modern, C++-native, header-only, test framework for unit-tests, TDD and BDD - using C++11, C++14, C++17 and later (or C++03 on the Catch1.x branch)

Catch2 v3 is being developed! You are on the devel branch, where the next major version, v3, of Catch2 is being developed. As it is a significant rewo

Catch Org 16k Jan 9, 2023
Simple useful interoperability tests for WebRTC libraries. If you are a WebRTC library developer we'd love to include you!

Overview This project aims to be a convenient location for WebRTC library developers to perform interoperability tests. Who can Participate The projec

Aaron Clauson 106 Dec 18, 2022
Palanteer is a set of high performance visual profiler, debugger, tests enabler for C++ and Python

Palanteer is a set of lean and efficient tools to improve the general software quality, for C++ and Python programs.

Damien Feneyrou 1.9k Dec 29, 2022
Driver layer GPU libraries and tests for PSP2

PVR_PSP2 Driver layer GPU libraries and tests for PSP2 Currently this project include: Common and PSP2-specific GPU driver headers. Extension library

null 69 Dec 1, 2022
A modern, C++11-native, single-file header-only, tiny framework for unit-tests, TDD and BDD (includes C++98 variant)

lest – lest errors escape testing This tiny C++11 test framework is based on ideas and examples by Kevlin Henney [1,2] and on ideas found in the CATCH

Martin Moene 355 Dec 28, 2022
This repository aims to contain solutions and explanations to various competitive programming problems, which may be important for interviews and online tests of different companies.

Competitive Programming Solutions Compilation Hello everyone ?? This repository contains solutions and explanations to various competitive programming

Abhinav Agrawal 33 Dec 14, 2022
Harbour DB speed tests comparison

hbDBSpeedTests Harbour DB speed tests comparison - Registers Count: 821051 MySql configuration( 1 or 2 ) /data/mysql/dbstru.zip - Import structure of

DIEGO H FAZIO 3 Nov 18, 2021
Community-gathered tests for C++ course read in YSDA

YSDA-CPP-collective-tests Коллективно собранные тесты для задач с закрытыми тестами из курса C++. Структура Структура этого репозитория соответствует

Martynov Pavel 5 Nov 1, 2021
Tests to check the determinism of the basic floating point arithmetic operations on different devices, using Unity and Rust.

This repo contains tests to check the determinism (consistency) of the basic floating point arithmetic operations (add, subtract, multiply, divide) on

Erik Roystan 9 Dec 20, 2022
Tests and validation for the Hive Helsinki GET_Next_Line project.

gnl-eval Tests and validation for the Hive Helsinki GET_Next_Line project. This is not meant to completely replace careful evaluation, but to give som

null 1 May 12, 2022