diff options
-rw-r--r-- | doc/01-introduction.html | 24 | ||||
-rw-r--r-- | doc/02-writing-tests.html | 119 | ||||
-rw-r--r-- | doc/03-assertions.html | 89 | ||||
-rw-r--r-- | doc/style.css | 48 | ||||
-rw-r--r-- | doc/table-of-contents.html | 17 | ||||
-rw-r--r-- | doc/template.html | 22 | ||||
-rw-r--r-- | example/sum.c | 2 | ||||
-rw-r--r-- | lily-test.h | 21 |
8 files changed, 342 insertions, 0 deletions
diff --git a/doc/01-introduction.html b/doc/01-introduction.html new file mode 100644 index 0000000..156994b --- /dev/null +++ b/doc/01-introduction.html @@ -0,0 +1,24 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="style.css"> + <title>Introduction | lily-test</title> +</head> +<body> + <div id="flex-root"> + <iframe id="toc" src="table-of-contents.html"></iframe> + <div id="content"> + + <h1>Introduction</h1> + + <p>lily-test is a single-header midsize unit testing framework written in C89. + + </div> + </div> + <div id="footer"> + <a id="next" href="02-writing-tests.html">Next ⇒</a> + </div> +</body> +</html> diff --git a/doc/02-writing-tests.html b/doc/02-writing-tests.html new file mode 100644 index 0000000..152ccac --- /dev/null +++ b/doc/02-writing-tests.html @@ -0,0 +1,119 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="style.css"> + <title>Writing Tests | lily-test</title> +</head> +<body> + <div id="flex-root"> + <iframe id="toc" src="table-of-contents.html"></iframe> + <div id="content"> + + <h1>Writing Tests</h1> + + <p>A basic unit test file looks like this:</p> + + <pre><code> +#include "lily-test.h" + +LILY_FILE_BEGIN(example_file) + + +LILY_TEST("example test 1") +{ + CHECK_EQ(1+1, 2, "%d"); +} +#include LILY_PUSH_TEST() + + +LILY_TEST("example test 2") +{ + CHECK_LT(3.0, 4.0, "%0.2f"); +} +#include LILY_PUSH_TEST() + + +#define LILY_FILE_END +#include LILY_REGISTER_TESTS() + </code></pre> + + <p>This will define a function pointer <code>example_file</code> with signature <code>void ()</code> that, when called, will execute the two tests and display to stderr any errors that they generate. While there is more boilerplate than in comparable C++ libraries, this means that lily-test supports test auto-registration. To add a new test, just use the <code>LILY_TEST</code> macro as shown, and then follow the function body with <code>#include LILY_PUSH_TEST()</code> to register it. These macros will only work correctly when used between a <code>LILY_FILE_BEGIN</code> and <code>LILY_FILE_END</code> block, and only when used <em>together</em>; using <code>LILY_TEST</code> without a <code>LILY_PUSH_TEST</code> is probably going to throw up a ton of compile errors.</p> + + <h2>Using a single file</h2> + + <p>For very small projects, you may be able to get away with using only a single unit test file. In this case, you should set it up along the following lines:</p> + + <pre><code> +#define LILY_IMPLEMENTATION +#include "lily-test.h" + +/* any includes or code to get your tests working */ + +LILY_FILE_BEGIN(tests) + +/* test definitions... */ + +#define LILY_FILE_END +#include LILY_REGISTER_TESTS() + +int main() +{ + lily_begin(); + tests(); + lily_finish(); + return 0; +} + </code></pre> + + However, in most cases you will want to have multiple test files. + + + <h2>Multiple test files</h2> + + <p>You will need, in addition to your unit test files, a header file that contains extern declarations of the function pointers defined by your files and a main C source file that contains a <code>main</code> function to run all of the function pointers. A nice way to set this up is to use X-macros, like this:</p> + + <pre><code> +/* tests.h */ + +#define TESTS \ + X(suite_1) \ + X(suite_2) \ + X(suite_3) \ + + +#define X(suite) extern void (*suite)(); +TESTS +#undef X + </code></pre> + + <pre><code> +/* tests_main.c */ + +#define LILY_IMPLEMENTATION +#include "lily-test.h" + +int main() +{ + lily_begin(); + #define X(suite) suite(); + TESTS + #undef X + lily_finish(); + return 0; +} + </code></pre> + + <p>This is convenient, because it means that when you add a new test file you need only add a single line to the definition of the <code>TESTS</code> macro in <code>tests.h</code> and all of the other relevant code is added for you automatically.<p> + + <p>Note that exactly ONE file should define <code>LILY_IMPLEMENTATION</code>. I find it reasonable to make this the same file with the implementation of <code>main</code> but YMMV.</p> + + </div> + </div> + <div id="footer"> + <a id="prev" href="01-introduction.html">⇐ Previous</a> + <a id="next" href="03-assertions.html">Next ⇒</a> + </div> +</body> +</html> diff --git a/doc/03-assertions.html b/doc/03-assertions.html new file mode 100644 index 0000000..92126a8 --- /dev/null +++ b/doc/03-assertions.html @@ -0,0 +1,89 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="style.css"> + <title>Assertions | lily-test</title> +</head> +<body> + <div id="flex-root"> + <iframe id="toc" src="table-of-contents.html"></iframe> + <div id="content"> + + + <h1>Assertions</h1> + + <p>There are two different basic types of assertions: checks and requirements. Both checks and requires will mark the overall test as failed if they are false, but a require will also immediately stop executing the test in addition.<p> + + <h2>Check Macros</h2> + + <h3>CHECK(x)</h3> + + <p>Marks the test as failed if <code>x</code> is false and prints stringified <code>x</code>.</p> + + <h3>CHECK_EQ(x, y, fmt)</h3> + + <p>Marks the test as failed if <code>x == y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>CHECK_NEQ(x, y, fmt)</h3> + + <p>Marks the test as failed if <code>x != y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>CHECK_LT(x, y, fmt)</h3> + + <p>Marks the test as failed if <code>x < y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>CHECK_LE(x, y, fmt)</h3> + + <p>Marks the test as failed if <code>x <= y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>CHECK_GT(x, y, fmt)</h3> + + <p>Marks the test as failed if <code>x > y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>CHECK_GE(x, y, fmt)</h3> + + <p>Marks the test as failed if <code>x >= y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <br> + + <h2>Require Macros</h2> + + <h3>REQUIRE(x)</h3> + + <p>Marks the test as failed and immediately ends test execution if <code>x</code> is false and prints stringified <code>x</code>.</p> + + <h3>REQUIRE_EQ(x, y, fmt)</h3> + + <p>Marks the test as failed and immediately ends test execution if <code>x == y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>REQUIRE_NEQ(x, y, fmt)</h3> + + <p>Marks the test as failed and immediately ends test execution if <code>x != y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>REQUIRE_LT(x, y, fmt)</h3> + + <p>Marks the test as failed and immediately ends test execution if <code>x < y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>REQUIRE_LE(x, y, fmt)</h3> + + <p>Marks the test as failed and immediately ends test execution if <code>x <= y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>REQUIRE_GT(x, y, fmt)</h3> + + <p>Marks the test as failed and immediately ends test execution if <code>x > y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + <h3>REQUIRE_GE(x, y, fmt)</h3> + + <p>Marks the test as failed and immediately ends test execution if <code>x >= y</code> is false. Prints both the stringified names of <code>x</code> and <code>y</code> as well as their values, using the printf format code provided in <code>fmt</code>. + + + </div> + </div> + <div id="footer"> + <a id="prev" href="02-writing-tests.html">⇐ Previous</a> + <a id="next" href="#">Next ⇒</a> + </div> +</body> +</html> diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 0000000..d6ff59a --- /dev/null +++ b/doc/style.css @@ -0,0 +1,48 @@ +body { + color: #f6f5f4; + background: #181a1b; +} + +#flex-root { + display: flex; + flex-direction: row; + flex-wrap: wrap; + width: 100%; +} + +a { + color: #f57c85; +} + +a:visited { + color: #fa6571; +} + +#toc { + border-style: none solid none none; + border-width: 1px; + border-color: #f57c85; + flex: 1 15 0; + max-width: 15em; + min-height: 15em; +} + +#content { + margin: 0 1em; + flex: 1 1 0; +} + +#footer { + border-style: solid none none none; + border-width: 1px; + border-color: #f57c85; + padding: 1em; +} + +#footer #prev { + float: left; +} + +#footer #next { + float: right; +} diff --git a/doc/table-of-contents.html b/doc/table-of-contents.html new file mode 100644 index 0000000..c450da8 --- /dev/null +++ b/doc/table-of-contents.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="style.css"> + <title>Table of Contents</title> +</head> +<body> + <h1>Contents</h1> + <ol> + <li><a href="01-introduction.html" target="_parent">Introduction</a></li> + <li><a href="02-writing-tests.html" target="_parent">Writing Tests</a></li> + <li><a href="03-assertions.html" target="_parent">Assertions</a></li> + </ol> +</body> +</html> diff --git a/doc/template.html b/doc/template.html new file mode 100644 index 0000000..6d4337b --- /dev/null +++ b/doc/template.html @@ -0,0 +1,22 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="style.css"> + <title>TEMPLATE</title> +</head> +<body> + <div id="flex-root"> + <iframe id="toc" src="table-of-contents.html"></iframe> + <div id="content"> + + + </div> + </div> + <div id="footer"> + <a id="prev" href="#">⇐ Previous</a> + <a id="next" href="#">Next ⇒</a> + </div> +</body> +</html> diff --git a/example/sum.c b/example/sum.c index d9d1221..645ed8e 100644 --- a/example/sum.c +++ b/example/sum.c @@ -24,6 +24,8 @@ LILY_TEST("sums are correct") int main() { + lily_begin(); sum_suite(); + lily_finish(); return 0; } diff --git a/lily-test.h b/lily-test.h index ac956aa..e6925aa 100644 --- a/lily-test.h +++ b/lily-test.h @@ -170,6 +170,8 @@ void lily_require(int x, const char *location, const char *fmt, ...); #define REQUIRE_GE(x, y, fmt) LILY_REQUIRE_CMP(x, >=, y, fmt) +void lily_begin(); +void lily_finish(); void lily_run_test(void (*test)()); @@ -183,6 +185,7 @@ struct lily_global_t { int n_assertions_failed; int n_tests; int n_tests_failed; + double epsilon; } extern lily_g; #ifdef LILY_IMPLEMENTATION @@ -242,6 +245,7 @@ void lily_run_test(void (*test)()) } if (lily_g.failed) { + lily_g.n_tests_failed += 1; printf("================================================================================\n"); printf("test \"%s\" failed!\n", lily_g.test_name); lily_test_msg_t *n = lily_g.HEAD.next; @@ -304,6 +308,23 @@ void lily_require(int x, const char *location, const char *fmt, ...) longjmp(lily_g.env, 1); } } + + +void lily_begin() +{ + printf("================================================================================\n"); + printf("lily-test version %d.%d.%d\n", LILY_VERSION_MAJOR, LILY_VERSION_MINOR, LILY_VERSION_PATCH); +} + + +void lily_finish() +{ + printf("================================================================================\n"); + printf("ran %d tests (%d failed)\n", + lily_g.n_tests, lily_g.n_tests_failed); + printf("checked %d asserts (%d failed)\n", + lily_g.n_assertions, lily_g.n_assertions_failed); +} #endif /* ifdef LILY_TEST_H */ |