summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-12-30 21:22:50 -0600
committersanine <sanine.not@pm.me>2022-12-30 21:22:50 -0600
commitbf71f069d4861ba2285c96dd98bdf1bbe0322fc2 (patch)
tree454cdcd335a408b8a4c1c1b038b152363335dcc2
parentb8c647c9250b514a5daa11ea731691b19944aa4e (diff)
begin documentation and add lily_begin() and lily_finish()
-rw-r--r--doc/01-introduction.html24
-rw-r--r--doc/02-writing-tests.html119
-rw-r--r--doc/03-assertions.html89
-rw-r--r--doc/style.css48
-rw-r--r--doc/table-of-contents.html17
-rw-r--r--doc/template.html22
-rw-r--r--example/sum.c2
-rw-r--r--lily-test.h21
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 */