From 17c76a851e3c3550f6398aad11e7c71e1a122576 Mon Sep 17 00:00:00 2001 From: shmibs Date: Fri, 1 Aug 2014 09:05:48 -0700 Subject: all around cleanup --- README.pdf | Bin 144894 -> 138351 bytes README.tex | 76 ++++++++++++++++++-------- a_simple_example.c | 52 ++++++++++++++++++ simple-test.h | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++ simple_test.c | 52 ------------------ test.h | 150 --------------------------------------------------- 6 files changed, 262 insertions(+), 224 deletions(-) create mode 100644 a_simple_example.c create mode 100644 simple-test.h delete mode 100644 simple_test.c delete mode 100644 test.h diff --git a/README.pdf b/README.pdf index de7fbc8..fb6f9c7 100644 Binary files a/README.pdf and b/README.pdf differ diff --git a/README.tex b/README.tex index 9a66a4b..6494ee5 100644 --- a/README.tex +++ b/README.tex @@ -58,10 +58,15 @@ } } -\newcommand{\myrow}[2]{ +\newcommand{\mymacrow}[2]{ \footnotesize\textcolor{DarkOrchid3}{\textbf{#1}}: & \small #2 \\[8pt] } +\newcommand{\mytermrow}[2]{ + \tt\bf\small #1 & \tt\small #2 \\ +} + + \begin{document} @@ -93,7 +98,7 @@ \hrule \lstset{style=customc} - \lstinputlisting{simple_test.c} + \lstinputlisting{a_simple_example.c} \hrule \pagebreak @@ -102,10 +107,12 @@ \hrule \vspace{8pt} + % successful output \begin{tabular*}{\textwidth}{r@{\ \tt\bf :: }l} - \tt\bf\small 1 & \tt\small\color{Brown3}description of the first test \\ - \tt\bf\small 2 & \tt\small\color{Brown3}this is the second test \\ - & \tt\small\color{SteelBlue3}grabbing heap string... \\ + \mytermrow{1}{\color{Yellow4}description of the first test} + \mytermrow{2}{\color{Yellow4}this is the second test} + \mytermrow{ }{\color{DodgerBlue2}grabbing heap string...} + \mytermrow{ }{\color{SpringGreen4}success!} \end{tabular*} \vspace{8pt} @@ -116,17 +123,14 @@ \hrule \vspace{8pt} + % failed output \begin{tabular*}{\textwidth}{r@{\ \tt\bf :: }l} - \tt\bf\small 1 & \tt\small \color{Brown3}description of the first test \\ + \mytermrow{1}{\color{Yellow4}description of the first test} + \mytermrow{ }{\color{Red1}FAIL: error message shown on failing} + \mytermrow{ }{\textcolor{SpringGreen4}{\textbf{\ \ expected:}}6} + \mytermrow{ }{\textcolor{Red1}{\textbf{\ \ \ \ actual:}}0} \end{tabular*} - \myhl{\tt\small\textbf{FAIL: error message shown on failing}} - - \begin{tabular*}{\textwidth}{r@{\ }l} - \tt\bf\small\color{Green3} expected: & \tt\small 6 \\ - \tt\bf\small\color{Red1} actual: & \tt\small 0 \\ - \end{tabular*} - \vspace{8pt} \hrule @@ -134,38 +138,66 @@ \myheading{defined macros} \begin{tabularx}{\textwidth}{r@{\ }X} - \myrow{EXPECT\_ZERO(summary, arg)}{ + \mymacrow{BEGIN\_TEST}{ + must appear before all tests and + after all global variable declarations + } + \mymacrow{END\_TEST}{ + must appear at the end of your test + program + } + \mymacrow{CLEANUP(statements)}{ + this defines a list of statements to run + when the test exits, either successfully or + on a failure. it isn't necessary for a test + to run, but, if it does appear, it must be + after the declaration of all variables to + which it makes reference. + } + \mymacrow{RETURN()}{ + place at the end of a test which uses + CLEANUP to ensure it is called before the + test exits. i couldn't find any way around + this without using more than just one + header file, so i hope it isn't too annoying. + } + \mymacrow{STATE(description)}{ + show a prettily-formatted description of the + program's state during a test. takes printf-style + arguments. + } + \mymacrow{EXPECT\_ZERO(summary, arg)}{ fail if \texttt{arg} does not resolve to 0 } - \myrow{EXPECT\_ONE(summary, arg)}{ + \mymacrow{EXPECT\_ONE(summary, arg)}{ fail if \texttt{arg} does not resolve to 1 } - \myrow{EXPECT\_GREATER\_THAN\_ZERO(summary, arg)}{ + \mymacrow{EXPECT\_GREATER\_THAN\_ZERO(summary, arg)}{ fail if \texttt{arg} does not resolve to a value greater than 0. this will be replaced with more generic integer comparisons soon. } - \myrow{EXPECT\_INT(summary, arg1, arg2)}{ + \mymacrow{EXPECT\_INT(summary, arg1, arg2)}{ fail if \texttt{arg2} does not match the expected integer value \texttt{arg1} } - \myrow{EXPECT\_EQUAL\_INT(summary, arg1, arg2)}{ + \mymacrow{EXPECT\_EQUAL\_INT(summary, arg1, arg2)}{ fail if \texttt{arg1} and \texttt{arg2} are not equal } - \myrow{EXPECT\_UNEQUAL\_INT(summary, arg1, arg2)}{ + \mymacrow{EXPECT\_UNEQUAL\_INT(summary, arg1, arg2)}{ fail if \texttt{arg1} and \texttt{arg2} are equal } - \myrow{EXPECT\_STR(summary, arg1, arg2)}{ + \mymacrow{EXPECT\_STR(summary, arg1, arg2)}{ fail if string \texttt{arg2} does not match the expected string value \texttt{arg1} } - \myrow{EXPECT\_EQUAL\_STR(summary, arg1, arg2)}{ + \mymacrow{EXPECT\_EQUAL\_STR(summary, arg1, arg2)}{ fail if \texttt{arg1} and \texttt{arg2} are not equivalent strings } - \myrow{EXPECT\_UNEQUAL\_STR(summary, arg1, arg2)}{ + \mymacrow{EXPECT\_UNEQUAL\_STR(summary, arg1, arg2)}{ fail if \texttt{arg1} and \texttt{arg2} are equivalent strings } diff --git a/a_simple_example.c b/a_simple_example.c new file mode 100644 index 0000000..fb7d774 --- /dev/null +++ b/a_simple_example.c @@ -0,0 +1,52 @@ +#include "simple-test.h" +#include "header_with_stuff_to_be_tested.h" + +BEGIN_TEST + +/* a simple test using only stack mem */ +TEST("description of the first test") +{ + int var1=2; + int var2=4; + + /* add is a function included from our hypothetical + * header_with_stuff_to_be_tested */ + EXPECT_INT("error message shown on failing", + var1+var2, add(var1, var2)); +} + +/* this test uses heap memory, so things get a bit + * more complicated */ +TEST("this is the second test") +{ + /* first, ensure all your pointers which will + * point to heap mem are declared */ + char *heap_string=NULL; + + /* next, declare a list of statements to be + * called to clean up memory once the test + * is completed */ + CLEANUP( + if(heap_string != NULL) + free(heap_string); + ); + + /* then, define the body of the test */ + + /* STATE can be used to report (with pretty + * formatting) the current state within the + * test, which may be useful in the case of + * a segfault */ + STATE("grabbing heap string"); + + heap_string=get_heap_string_value(); + + EXPECT_STR("i suck at grabbing pointers!", + "expected value", heap_string); + + /* finally, call RETURN(); to run the + * cleanup code and continue */ + RETURN(); +} + +END_TEST diff --git a/simple-test.h b/simple-test.h new file mode 100644 index 0000000..b5e4678 --- /dev/null +++ b/simple-test.h @@ -0,0 +1,156 @@ +#ifndef _TEST_H_ +#define _TEST_H_ + +#include +#include +#include + +/************* + * REGIONS * + *************/ + +/* extra levels of abstraction are necessary + * to get __COUNTER__ to evaluate before + * being concatenated */ +#define _TEST_PASTE(x, y) \ +x ## y + +/* the whole thing is inside one + * big function. yay! */ +#define BEGIN_TEST \ +typedef void (*_test_cleanup_t)(void); \ +_test_cleanup_t _test_cleanup_current=NULL; \ +int _test_count_current=1; \ +int main(int argc, char *argv[]) \ +{ + +/* yaaaay! */ +#define END_TEST \ + printf("\e[1m :: \e[m\e[32msuccess!\e[m\n"); \ + return 0; \ +} + +/* print a fancy description and + * reset the cleanup function + * pointer to NULL so, if it isn't + * defined again, no cleanup will + * be called */ +#define TEST(description) \ +_test_cleanup_current=NULL; \ +printf("\e[1m%3i :: \e[m\e[33m%s\e[m\n", _test_count_current++, description); + +/* pass in statements to be called on test + * exit. goes after varible declarations and + * before test body. */ +#define CLEANUP(statements) \ +_TEST_CLEANUP_UNIQ(statements, __COUNTER__) + +/* insert a unique cleanup function */ +#define _TEST_CLEANUP_UNIQ(statements, unique_count) \ +void _TEST_PASTE(_test_cleanup_, unique_count)(void) \ +{ \ + statements \ +} \ +_test_cleanup_current=_TEST_PASTE(_test_cleanup_, unique_count); + +/* pretty printing for the current state within + * a test */ +#define STATE(...) \ + do { \ + printf("\e[1m :: \e[m\e[34m"); \ + printf(...); \ + printf("...\e[m\n"); \ + } while(0) + +/* one of these goes at the end of every test + * with CLEANUP (unless you want memory leaks). + * if you want, stick it in those without CLEANUP + * too. */ +#define RETURN() _TEST_RETURN(false) + +/* checks if there is a cleanup function to + * call and then either continues or terminates + * the test */ +#define _TEST_RETURN(fail) \ +do { \ + if(_test_cleanup_current != NULL) \ + (*_test_cleanup_current)(); \ + if(fail) \ + exit(1); \ +} while(0) + +/*********** + * TESTS * + ***********/ + +#define EXPECT_ZERO(summary, arg) \ +do { \ + if(arg) \ + _TEST_FAIL_VAL(summary, "%i", "%i", 0, arg); \ +} while(0); + +#define EXPECT_ONE(summary, arg) \ +do { \ + if(arg != 1) \ + _TEST_FAIL_VAL(summary, "%i", "%i", 1, arg); \ +} while(0); + +#define EXPECT_GREATER_THAN_ZERO(summary, arg) \ +do { \ + if(arg <= 0) \ + _TEST_FAIL_VAL(summary, "%s", "%i", ">0", arg); \ +} while(0); + +#define EXPECT_INT(summary, arg1, arg2) \ +do { \ + if(arg1 != arg2) \ + _TEST_FAIL_VAL(summary, "%i", "%i", arg1, arg2); \ +} while(0); + +#define EXPECT_EQUAL_INT(summary, arg1, arg2) \ +do { \ + if(arg1 != arg2) \ + _TEST_FAIL_EQUAL(summary, "%i", "%i", arg1, arg2); \ +} while(0); + +#define EXPECT_UNEQUAL_INT(summary, arg1, arg2) \ +do { \ + if(arg1 == arg2) \ + _TEST_FAIL_EQUAL(summary, "%i", "%i", arg1, arg2); \ +} while(0); + +#define EXPECT_STR(summary, arg1, arg2) \ +do { \ + if( strcmp(arg1, arg2) ) \ + _TEST_FAIL_VAL(summary, "‘%s’", "‘%s’", arg1, arg2); \ +} while(0); + +#define EXPECT_EQUAL_STR(summary, arg1, arg2) \ +do { \ + if( strcmp(arg1, arg2) ) \ + _TEST_FAIL_EQUAL(summary, "‘%s’", "‘%s’", arg1, arg2); \ +} while(0); + +#define EXPECT_UNEQUAL_STR(summary, arg1, arg2) \ +do { \ + if( !strcmp(arg1, arg2) ) \ + _TEST_FAIL_EQUAL(summary, "‘%s’", "‘%s’", arg1, arg2); \ +} while(0); + +#define _TEST_FAIL_VAL(summary, format1, format2, expected, actual) \ +do { \ + printf("\e[1m :: \e[m\e[31mFAIL: " summary "\e[m\n"); \ + printf("\e[1m :: \e[m\e[1;32m expected:\e[m " format1 "\n", expected);\ + printf("\e[1m :: \e[m\e[1;31m actual:\e[m " format1 "\n", actual); \ + _TEST_RETURN(true); \ +} while(0) + +#define _TEST_FAIL_EQUAL(summary, format1, format2, arg1, arg2) \ +do { \ + printf("\e[1m :: \e[m\e[31mFAIL: " summary "\e[m\n"); \ + printf("\e[1m :: \e[m arg1 == \e[1;31m" format1 "\e[m\n", arg1); \ + printf("\e[1m :: \e[m arg2 == \e[1;31m" format2 "\e[m\n", arg2); \ + _TEST_RETURN(true); \ +} while(0) + +#endif diff --git a/simple_test.c b/simple_test.c deleted file mode 100644 index e57db38..0000000 --- a/simple_test.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "test.h" -#include "header_with_stuff_to_be_tested.h" - -BEGIN_TEST - -/* a simple test using only stack mem */ -TEST("description of the first test") -{ - int var1=2; - int var2=4; - - /* add is a function included from our hypothetical - * header_with_stuff_to_be_tested */ - EXPECT_INT("error message shown on failing", - var1+var2, add(var1, var2)); -} - -/* this test uses heap memory, so things get a bit - * more complicated */ -TEST("this is the second test") -{ - /* first, ensure all your pointers which will - * point to heap mem are declared */ - char *heap_string=NULL; - - /* next, declare a list of statements to be - * called to clean up memory once the test - * is completed */ - CLEANUP( - if(heap_string != NULL) - free(heap_string); - ) - - /* then, define the body of the test */ - - /* STATE can be used to report (with pretty - * formatting) the current state within the - * test, which may be useful in the case of - * a segfault */ - STATE("grabbing heap string"); - - heap_string=get_heap_string_value(); - - EXPECT_STR("i suck at grabbing pointers!", - "expected value", heap_string); - - /* finally, call RETURN(); to run the - * cleanup code and continue */ - RETURN(); -} - -END_TEST diff --git a/test.h b/test.h deleted file mode 100644 index 0ac1e77..0000000 --- a/test.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef _TEST_H_ -#define _TEST_H_ - -#include -#include -#include - -/************* - * REGIONS * - *************/ - -/* extra levels of abstraction are necessary - * to get __COUNTER__ to evaluate before - * being concatenated */ -#define _TEST_PASTE(x, y) \ -x ## y - -/* the whole thing is inside one - * big function. yay! */ -#define BEGIN_TEST \ -typedef void (*_test_cleanup_t)(void); \ -_test_cleanup_t _test_cleanup_current=NULL; \ -int _test_count_current=1; \ -int main(int argc, char *argv[]) \ -{ - -/* yaaaay! */ -#define END_TEST \ - return 0; \ -} - -/* print a fancy description and - * reset the cleanup function - * pointer to NULL so, if it isn't - * defined again, no cleanup will - * be called */ -#define TEST(description) \ -_test_cleanup_current=NULL; \ -printf("\e[1m%3i :: \e[m\e[33m%s\e[m\n", _test_count_current++, description); - -/* pass in statements to be called on test - * exit. goes after varible declarations and - * before test body. */ -#define CLEANUP(statements) \ -_TEST_CLEANUP_UNIQ(statements, __COUNTER__) - -/* insert a unique cleanup function */ -#define _TEST_CLEANUP_UNIQ(statements, unique_count) \ -void _TEST_PASTE(_test_cleanup_, unique_count)(void) \ -{ \ - statements \ -} \ -_test_cleanup_current=_TEST_PASTE(_test_cleanup_, unique_count); - -/* pretty printing for the current state within - * a test */ -#define STATE(str) printf("\e[1m :: \e[m\e[34m%s...\e[m\n", str) - -/* one of these goes at the end of every test - * with CLEANUP (unless you want memory leaks). - * if you want, stick it in those without CLEANUP - * too. */ -#define RETURN() _TEST_RETURN(false) - -/* checks if there is a cleanup function to - * call and then either continues or terminates - * the test */ -#define _TEST_RETURN(fail) \ -do { \ - if(_test_cleanup_current != NULL) \ - (*_test_cleanup_current)(); \ - if(fail) \ - exit(1); \ -} while(0) - -/*********** - * TESTS * - ***********/ - -#define EXPECT_ZERO(summary, arg) \ -do { \ - if(arg) \ - FAIL_VAL(summary, "%i", "%i", 0, arg); \ -} while(0); - -#define EXPECT_ONE(summary, arg) \ -do { \ - if(arg != 1) \ - FAIL_VAL(summary, "%i", "%i", 1, arg); \ -} while(0); - -#define EXPECT_GREATER_THAN_ZERO(summary, arg) \ -do { \ - if(arg <= 0) \ - FAIL_VAL(summary, "%s", "%i", ">0", arg); \ -} while(0); - -#define EXPECT_INT(summary, arg1, arg2) \ -do { \ - if(arg1 != arg2) \ - FAIL_VAL(summary, "%i", "%i", arg1, arg2); \ -} while(0); - -#define EXPECT_EQUAL_INT(summary, arg1, arg2) \ -do { \ - if(arg1 != arg2) \ - FAIL_EQUAL(summary, "%i", "%i", arg1, arg2); \ -} while(0); - -#define EXPECT_UNEQUAL_INT(summary, arg1, arg2) \ -do { \ - if(arg1 == arg2) \ - FAIL_EQUAL(summary, "%i", "%i", arg1, arg2); \ -} while(0); - -#define EXPECT_STR(summary, arg1, arg2) \ -do { \ - if( strcmp(arg1, arg2) ) \ - FAIL_VAL(summary, "%s", "%s", arg1, arg2); \ -} while(0); - -#define EXPECT_EQUAL_STR(summary, arg1, arg2) \ -do { \ - if( strcmp(arg1, arg2) ) \ - FAIL_EQUAL(summary, "%s", "%s", arg1, arg2); \ -} while(0); - -#define EXPECT_UNEQUAL_STR(summary, arg1, arg2) \ -do { \ - if( !strcmp(arg1, arg2) ) \ - FAIL_EQUAL(summary, "%s", "%s", arg1, arg2); \ -} while(0); - -#define FAIL_VAL(summary, format1, format2, expected, actual) \ -do { \ - puts("\e[1;41mFAIL: " summary "\e[m"); \ - printf(" \e[1;32mexpected:\e[m " format1 \ - "\n \e[1;31mactual:\e[m " format2 "\n", expected, actual); \ - _TEST_RETURN(true); \ -} while(0) - -#define FAIL_EQUAL(summary, format1, format2, arg1, arg2) \ -do { \ - puts("\e[1;41mFAIL: " summary "\e[m"); \ - printf(" arg1 == \e[1;31m" format1 "\e[m\n", arg1); \ - printf(" arg2 == \e[1;31m" format2 "\e[m\n", arg2); \ - _TEST_RETURN(true); \ -} while(0) - -#endif -- cgit v1.2.3