292 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			292 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								**  tap4embedded : http://github.com/fperrad/tap4embedded
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								**  Copyright (C) 2016-2017 Francois Perrad.
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								**  tap4embedded is free software; you can redistribute it and/or modify it
							 | 
						||
| 
								 | 
							
								**  under the terms of the Artistic License 2.0
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef TAP_H
							 | 
						||
| 
								 | 
							
								#define TAP_H
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef TAP_PUTCHAR
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#define TAP_PUTCHAR(c)          fputc((c), stdout)
							 | 
						||
| 
								 | 
							
								#define TAP_FLUSH()             fflush(stdout)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef TAP_FLUSH
							 | 
						||
| 
								 | 
							
								#define TAP_FLUSH()
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(__unix__) || defined(_WIN32) || defined(_WIN64)
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#define TAP_EXIT(n)             exit(n)
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#define TAP_EXIT(n)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(__bool_true_false_are_defined) || defined(__cplusplus)
							 | 
						||
| 
								 | 
							
								#define TAP_BOOL                bool
							 | 
						||
| 
								 | 
							
								#define TAP_TRUE                true
							 | 
						||
| 
								 | 
							
								#define TAP_FALSE               false
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#define TAP_BOOL                char
							 | 
						||
| 
								 | 
							
								#define TAP_TRUE                1
							 | 
						||
| 
								 | 
							
								#define TAP_FALSE               0
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef __cplusplus
							 | 
						||
| 
								 | 
							
								extern "C" {
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern void plan(unsigned int nb);
							 | 
						||
| 
								 | 
							
								extern void no_plan(void);
							 | 
						||
| 
								 | 
							
								extern void skip_all(const char *reason);
							 | 
						||
| 
								 | 
							
								extern void done_testing(unsigned int nb);
							 | 
						||
| 
								 | 
							
								extern void bail_out(const char *reason);
							 | 
						||
| 
								 | 
							
								extern void ok(const char *file, unsigned int line, TAP_BOOL test, const char *name);
							 | 
						||
| 
								 | 
							
								extern void todo(const char *reason, unsigned int count);
							 | 
						||
| 
								 | 
							
								extern void skip(const char *reason, unsigned int count);
							 | 
						||
| 
								 | 
							
								extern void todo_skip(const char *reason);
							 | 
						||
| 
								 | 
							
								extern void skip_rest(const char *reason);
							 | 
						||
| 
								 | 
							
								extern void diag (const char *msg);
							 | 
						||
| 
								 | 
							
								extern int exit_status (void);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define OK(test, name)          ok(__FILE__, __LINE__, (test), (name))
							 | 
						||
| 
								 | 
							
								#define NOK(test, name)         ok(__FILE__, __LINE__, !(test), (name))
							 | 
						||
| 
								 | 
							
								#define PASS(name)              ok(__FILE__, __LINE__, TAP_TRUE, (name))
							 | 
						||
| 
								 | 
							
								#define FAIL(name)              ok(__FILE__, __LINE__, TAP_FALSE, (name))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef TAP_NO_IMPL
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct {
							 | 
						||
| 
								 | 
							
								    unsigned int curr_test;
							 | 
						||
| 
								 | 
							
								    unsigned int expected_tests;
							 | 
						||
| 
								 | 
							
								    unsigned int todo_upto;
							 | 
						||
| 
								 | 
							
								    const char *todo_reason;
							 | 
						||
| 
								 | 
							
								    TAP_BOOL have_plan;
							 | 
						||
| 
								 | 
							
								    TAP_BOOL no_plan;
							 | 
						||
| 
								 | 
							
								    TAP_BOOL have_output_plan;
							 | 
						||
| 
								 | 
							
								    TAP_BOOL done_testing;
							 | 
						||
| 
								 | 
							
								    TAP_BOOL is_passing;
							 | 
						||
| 
								 | 
							
								} tap_t;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								tap_t tap;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void putstr(const char *msg) {
							 | 
						||
| 
								 | 
							
								    TAP_BOOL need_begin = TAP_FALSE;
							 | 
						||
| 
								 | 
							
								    for (; *msg != '\0'; msg++) {
							 | 
						||
| 
								 | 
							
								        if (need_begin) {
							 | 
						||
| 
								 | 
							
								            TAP_PUTCHAR('#');
							 | 
						||
| 
								 | 
							
								            TAP_PUTCHAR(' ');
							 | 
						||
| 
								 | 
							
								            need_begin = TAP_FALSE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        TAP_PUTCHAR(*msg);
							 | 
						||
| 
								 | 
							
								        if (*msg == '\n') {
							 | 
						||
| 
								 | 
							
								            need_begin = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void putuint (unsigned int n) {
							 | 
						||
| 
								 | 
							
								    char buf[8 * sizeof(unsigned int) + 1];
							 | 
						||
| 
								 | 
							
								    char *ptr = &buf[sizeof(buf) - 1];
							 | 
						||
| 
								 | 
							
								    *ptr = '\0';
							 | 
						||
| 
								 | 
							
								    do {
							 | 
						||
| 
								 | 
							
								        char c = '0' + (n % 10u);
							 | 
						||
| 
								 | 
							
								        --ptr;
							 | 
						||
| 
								 | 
							
								        *ptr = c;
							 | 
						||
| 
								 | 
							
								        n /= 10u;
							 | 
						||
| 
								 | 
							
								    } while (n != 0u);
							 | 
						||
| 
								 | 
							
								    putstr(ptr);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void not_yet_plan(void) {
							 | 
						||
| 
								 | 
							
								    if (tap.have_plan) {
							 | 
						||
| 
								 | 
							
								        putstr("You tried to plan twice\n");
							 | 
						||
| 
								 | 
							
								        TAP_FLUSH();
							 | 
						||
| 
								 | 
							
								        TAP_EXIT(-1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void plan(unsigned int nb) {
							 | 
						||
| 
								 | 
							
								    not_yet_plan();
							 | 
						||
| 
								 | 
							
								    putstr("1..");
							 | 
						||
| 
								 | 
							
								    putuint(nb);
							 | 
						||
| 
								 | 
							
								    TAP_PUTCHAR('\n');
							 | 
						||
| 
								 | 
							
								    tap.expected_tests = nb;
							 | 
						||
| 
								 | 
							
								    tap.have_plan = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								    tap.have_output_plan = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								    tap.is_passing = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void no_plan(void) {
							 | 
						||
| 
								 | 
							
								    not_yet_plan();
							 | 
						||
| 
								 | 
							
								    tap.have_plan = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								    tap.no_plan = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								    tap.is_passing = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void skip_all(const char *reason) {
							 | 
						||
| 
								 | 
							
								    not_yet_plan();
							 | 
						||
| 
								 | 
							
								    putstr("1..0 # SKIP ");
							 | 
						||
| 
								 | 
							
								    putstr(reason);
							 | 
						||
| 
								 | 
							
								    TAP_PUTCHAR('\n');
							 | 
						||
| 
								 | 
							
								    tap.curr_test = 1u;
							 | 
						||
| 
								 | 
							
								    tap.expected_tests = 1u;
							 | 
						||
| 
								 | 
							
								    tap.have_plan = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								    tap.have_output_plan = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								    tap.is_passing = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								    TAP_FLUSH();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void done_testing(unsigned int nb) {
							 | 
						||
| 
								 | 
							
								    if (tap.done_testing) {
							 | 
						||
| 
								 | 
							
								        putstr("done_testing() was already called\n");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        tap.done_testing = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								        if ((tap.expected_tests != nb) && (tap.expected_tests != 0u)) {
							 | 
						||
| 
								 | 
							
								            putstr("# Looks like you planned ");
							 | 
						||
| 
								 | 
							
								            putuint(tap.expected_tests);
							 | 
						||
| 
								 | 
							
								            putstr(" tests but ran ");
							 | 
						||
| 
								 | 
							
								            putuint(nb);
							 | 
						||
| 
								 | 
							
								            TAP_PUTCHAR('.');
							 | 
						||
| 
								 | 
							
								            TAP_PUTCHAR('\n');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            tap.expected_tests = nb;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (! tap.have_output_plan) {
							 | 
						||
| 
								 | 
							
								            putstr("1..");
							 | 
						||
| 
								 | 
							
								            putuint(nb);
							 | 
						||
| 
								 | 
							
								            TAP_PUTCHAR('\n');
							 | 
						||
| 
								 | 
							
								            tap.have_output_plan = TAP_TRUE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if ((tap.expected_tests != tap.curr_test) || (tap.curr_test == 0u)) {
							 | 
						||
| 
								 | 
							
								            tap.is_passing = TAP_FALSE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        putstr("# Done with tap4embedded.\n");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    TAP_FLUSH();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void bail_out(const char *reason) {
							 | 
						||
| 
								 | 
							
								    putstr("Bail out!");
							 | 
						||
| 
								 | 
							
								    if (reason != NULL) {
							 | 
						||
| 
								 | 
							
								        TAP_PUTCHAR(' ');
							 | 
						||
| 
								 | 
							
								        TAP_PUTCHAR(' ');
							 | 
						||
| 
								 | 
							
								        putstr(reason);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    TAP_PUTCHAR('\n');
							 | 
						||
| 
								 | 
							
								    TAP_FLUSH();
							 | 
						||
| 
								 | 
							
								    TAP_EXIT(-1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void need_plan(void) {
							 | 
						||
| 
								 | 
							
								    if (! tap.have_plan) {
							 | 
						||
| 
								 | 
							
								        putstr("You tried to run a test without a plan\n");
							 | 
						||
| 
								 | 
							
								        TAP_FLUSH();
							 | 
						||
| 
								 | 
							
								        TAP_EXIT(-1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void ok(const char *file, unsigned int line, TAP_BOOL test, const char *name) {
							 | 
						||
| 
								 | 
							
								    need_plan();
							 | 
						||
| 
								 | 
							
								    ++tap.curr_test;
							 | 
						||
| 
								 | 
							
								    if (! test) {
							 | 
						||
| 
								 | 
							
								        putstr("not ");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    putstr("ok ");
							 | 
						||
| 
								 | 
							
								    putuint(tap.curr_test);
							 | 
						||
| 
								 | 
							
								    if (name != NULL) {
							 | 
						||
| 
								 | 
							
								        putstr(" - ");
							 | 
						||
| 
								 | 
							
								        putstr(name);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if ((tap.todo_reason != NULL) && (tap.todo_upto >= tap.curr_test)) {
							 | 
						||
| 
								 | 
							
								        putstr(" # TODO # ");
							 | 
						||
| 
								 | 
							
								        putstr(tap.todo_reason);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    TAP_PUTCHAR('\n');
							 | 
						||
| 
								 | 
							
								    if (! test) {
							 | 
						||
| 
								 | 
							
								        putstr("#    Failed");
							 | 
						||
| 
								 | 
							
								        if (tap.todo_upto >= tap.curr_test) {
							 | 
						||
| 
								 | 
							
								            putstr(" (TODO)");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            tap.is_passing = TAP_FALSE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        putstr(" test (");
							 | 
						||
| 
								 | 
							
								        putstr(file);
							 | 
						||
| 
								 | 
							
								        putstr(" at line ");
							 | 
						||
| 
								 | 
							
								        putuint(line);
							 | 
						||
| 
								 | 
							
								        putstr(")\n");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void todo(const char *reason, unsigned int count) {
							 | 
						||
| 
								 | 
							
								    tap.todo_upto = tap.curr_test + count;
							 | 
						||
| 
								 | 
							
								    tap.todo_reason = reason;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void skip(const char *reason, unsigned int count) {
							 | 
						||
| 
								 | 
							
								    unsigned int i;
							 | 
						||
| 
								 | 
							
								    need_plan();
							 | 
						||
| 
								 | 
							
								    for (i = 0u; i < count; i++) {
							 | 
						||
| 
								 | 
							
								        ++tap.curr_test;
							 | 
						||
| 
								 | 
							
								        putstr("ok ");
							 | 
						||
| 
								 | 
							
								        putuint(tap.curr_test);
							 | 
						||
| 
								 | 
							
								        putstr(" - # skip");
							 | 
						||
| 
								 | 
							
								        if (reason != NULL) {
							 | 
						||
| 
								 | 
							
								            TAP_PUTCHAR(' ');
							 | 
						||
| 
								 | 
							
								            putstr(reason);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        TAP_PUTCHAR('\n');
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void todo_skip(const char *reason) {
							 | 
						||
| 
								 | 
							
								    need_plan();
							 | 
						||
| 
								 | 
							
								    ++tap.curr_test;
							 | 
						||
| 
								 | 
							
								    putstr("not ok ");
							 | 
						||
| 
								 | 
							
								    putuint(tap.curr_test);
							 | 
						||
| 
								 | 
							
								    putstr(" - # TODO & SKIP");
							 | 
						||
| 
								 | 
							
								    if (reason != NULL) {
							 | 
						||
| 
								 | 
							
								        TAP_PUTCHAR(' ');
							 | 
						||
| 
								 | 
							
								        putstr(reason);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    TAP_PUTCHAR('\n');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void skip_rest(const char *reason) {
							 | 
						||
| 
								 | 
							
								    skip(reason, tap.expected_tests - tap.curr_test);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void diag (const char *msg) {
							 | 
						||
| 
								 | 
							
								    TAP_PUTCHAR('#');
							 | 
						||
| 
								 | 
							
								    TAP_PUTCHAR(' ');
							 | 
						||
| 
								 | 
							
								    putstr(msg);
							 | 
						||
| 
								 | 
							
								    TAP_PUTCHAR('\n');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int exit_status (void) {
							 | 
						||
| 
								 | 
							
								    if (! tap.done_testing) {
							 | 
						||
| 
								 | 
							
								        done_testing(tap.curr_test);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								#if defined(EXIT_SUCCESS) && defined(EXIT_FAILURE)
							 | 
						||
| 
								 | 
							
								    return tap.is_passing ? EXIT_SUCCESS : EXIT_FAILURE;
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								    return tap.is_passing ? 0 : -1;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef __cplusplus
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 |