summaryrefslogtreecommitdiffhomepage
path: root/misc/tests
diff options
context:
space:
mode:
authorTyge Løvset <[email protected]>2023-01-21 17:00:05 +0100
committerTyge Løvset <[email protected]>2023-01-21 17:00:05 +0100
commit798f3a637818147eaf231f438c7b104387de70e5 (patch)
tree36beb7177621d2605a27d048b931fad4a8b62d5d /misc/tests
parente97d06f95a65edd4fdee53555398f7b636a72ab5 (diff)
downloadSTC-modified-798f3a637818147eaf231f438c7b104387de70e5.tar.gz
STC-modified-798f3a637818147eaf231f438c7b104387de70e5.zip
Added modified ctest from https://github.com/bvdberg/ctest, and used on cregex_test.c. Will modify furter to make more like GoogleTest
Diffstat (limited to 'misc/tests')
-rw-r--r--misc/tests/cregex_test.c267
-rw-r--r--misc/tests/ctest.h622
-rw-r--r--misc/tests/main.c31
3 files changed, 774 insertions, 146 deletions
diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c
index cd812aa2..8ac268f1 100644
--- a/misc/tests/cregex_test.c
+++ b/misc/tests/cregex_test.c
@@ -1,260 +1,235 @@
-#if 0
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <stc/csview.h>
-#include <stc/stctest.h>
+#define i_extern
#include <stc/cregex.h>
+#include <stc/csview.h>
+#include "ctest.h"
-#define START_TEST(f) void f(void)
-#define END_TEST
+#define M_START(m) ((m).str - inp)
+#define M_END(m) (M_START(m) + (m).size)
-#define M_START(re, m) ((m).str - (re).input)
-#define M_END(re, m) (M_START(re, m) + (m).size)
-START_TEST(compile_match_char)
+CTEST(cregex, compile_match_char)
{
+ const char* inp;
cregex re = cregex_from("äsdf", 0);
- EXPECT_EQ(re.error, 0);
+ ASSERT_EQ(re.error, 0);
csview match;
- EXPECT_TRUE(cregex_find("äsdf", &re, &match, 0));
- EXPECT_EQ(M_START(re, match), 0);
- EXPECT_EQ(M_END(re, match), 5); // ä is two bytes wide
+ ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_M_FULLMATCH), CREG_OK);
+ ASSERT_EQ(M_START(match), 0);
+ ASSERT_EQ(M_END(match), 5); // ä is two bytes wide
- EXPECT_EQ(cregex_find("zäsdf", &re, &match, 0), 1);
- EXPECT_EQ(M_START(re, match), 1);
- EXPECT_EQ(M_END(re, match), 6);
+ ASSERT_EQ(cregex_find(&re, inp="zäsdf", &match, 0), CREG_OK);
+ ASSERT_EQ(M_START(match), 1);
+ ASSERT_EQ(M_END(match), 6);
cregex_drop(&re);
}
-END_TEST
-START_TEST(compile_match_anchors)
+CTEST(cregex, compile_match_anchors)
{
- cregex re = cregex_from("^äs.f$", 0);
- EXPECT_EQ(re.error, 0);
+ const char* inp;
+ cregex re = cregex_from(inp="^äs.f$", 0);
+ ASSERT_EQ(re.error, 0);
csview match;
- EXPECT_TRUE(cregex_find("äsdf", &re, &match, 0));
- EXPECT_EQ(M_START(re, match), 0);
- EXPECT_EQ(M_END(re, match), 5);
+ ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, 0), CREG_OK);
+ ASSERT_EQ(M_START(match), 0);
+ ASSERT_EQ(M_END(match), 5);
- EXPECT_TRUE(cregex_is_match("äs♥f", &re));
- EXPECT_TRUE(cregex_is_match("äsöf", &re));
+ ASSERT_TRUE(cregex_is_match(&re, "äs♥f"));
+ ASSERT_TRUE(cregex_is_match(&re, "äsöf"));
- cregex_drop(re);
+ cregex_drop(&re);
}
-END_TEST
-START_TEST(compile_match_quantifiers)
+CTEST(cregex, compile_match_quantifiers1)
{
+ const char* inp;
c_AUTO (cregex, re) {
re = cregex_from("ä+", 0);
- EXPECT_EQ(re.error, 0);
+ ASSERT_EQ(re.error, 0);
csview match;
- EXPECT_EQ(cregex_find("ääb", &re, &match, 0), 1);
- EXPECT_EQ(M_START(re, match), 0);
- EXPECT_EQ(M_END(re, match), 4);
+ ASSERT_EQ(cregex_find(&re, inp="ääb", &match, 0), CREG_OK);
+ ASSERT_EQ(M_START(match), 0);
+ ASSERT_EQ(M_END(match), 4);
- EXPECT_EQ(cregex_find("bäbb", &re, &match, 0), 1);
- EXPECT_EQ(M_START(re, match), 1);
- EXPECT_EQ(M_END(re, match), 3);
+ ASSERT_EQ(cregex_find(&re, inp="bäbb", &match, 0), CREG_OK);
+ ASSERT_EQ(M_START(match), 1);
+ ASSERT_EQ(M_END(match), 3);
- EXPECT_FALSE(cregex_find("bbb", &re, &match, 0));
+ ASSERT_EQ(cregex_find(&re, "bbb", &match, 0), CREG_NOMATCH);
}
+}
+
+CTEST(cregex, compile_match_quantifiers2)
+{
+ const char* inp;
c_AUTO (cregex, re) {
re = cregex_from("bä*", 0);
- EXPECT_EQ(re.error, 0);
+ ASSERT_EQ(re.error, 0);
csview match;
- EXPECT_EQ(cregex_find("bääb", &re, &match, 0), 1);
- EXPECT_EQ(M_START(re, match), 0);
- EXPECT_EQ(M_END(re, match), 5);
+ ASSERT_EQ(cregex_find(&re, inp="bääb", &match, 0), CREG_OK);
+ ASSERT_EQ(M_START(match), 0);
+ ASSERT_EQ(M_END(match), 5);
- EXPECT_EQ(cregex_find("bäbb", &re, &match, 0), 1);
- EXPECT_EQ(M_START(re, match), 0);
- EXPECT_EQ(M_END(re, match), 3);
+ ASSERT_EQ(cregex_find(&re, inp="bäbb", &match, 0), CREG_OK);
+ ASSERT_EQ(M_START(match), 0);
+ ASSERT_EQ(M_END(match), 3);
- EXPECT_EQ(cregex_find("bbb", &re, &match, 0), 1);
- EXPECT_EQ(M_START(re, match), 0);
- EXPECT_EQ(M_END(re, match), 1);
+ ASSERT_EQ(cregex_find(&re, inp="bbb", &match, 0), CREG_OK);
+ ASSERT_EQ(M_START(match), 0);
+ ASSERT_EQ(M_END(match), 1);
}
}
-END_TEST
-START_TEST(compile_match_escaped_chars)
+CTEST(cregex, compile_match_escaped_chars)
{
cregex re = cregex_from("\\n\\r\\t\\{", 0);
- EXPECT_EQ(re.error, 0);
+ ASSERT_EQ(re.error, 0);
csview match;
- EXPECT_EQ(cregex_find("\n\r\t{", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("\n\r\t", &re, &match, 0), 0);
+ ASSERT_EQ(cregex_find(&re, "\n\r\t{", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "\n\r\t", &match, 0), CREG_NOMATCH);
cregex_drop(&re);
}
-END_TEST
-START_TEST(compile_match_class_simple)
+CTEST(cregex, compile_match_class_simple)
{
c_AUTO (cregex, re1, re2, re3)
{
re1 = cregex_from("\\s", 0);
- EXPECT_EQ(re1.error, 0);
+ ASSERT_EQ(re1.error, 0);
re2 = cregex_from("\\w", 0);
- EXPECT_EQ(re2.error, 0);
+ ASSERT_EQ(re2.error, 0);
re3 = cregex_from("\\D", 0);
- EXPECT_EQ(re3.error, 0);
+ ASSERT_EQ(re3.error, 0);
csview match;
- EXPECT_EQ(cregex_find(" ", &re1, &match, 0), 1);
- EXPECT_EQ(cregex_find("\r", &re1, &match, 0), 1);
- EXPECT_EQ(cregex_find("\n", &re1, &match, 0), 1);
+ ASSERT_EQ(cregex_find(&re1, " " , &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re1, "\r", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re1, "\n", &match, 0), CREG_OK);
- EXPECT_EQ(cregex_find("a", &re2, &match, 0), 1);
- EXPECT_EQ(cregex_find("0", &re2, &match, 0), 1);
- EXPECT_EQ(cregex_find("_", &re2, &match, 0), 1);
+ ASSERT_EQ(cregex_find(&re2, "a", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re2, "0", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re2, "_", &match, 0), CREG_OK);
- EXPECT_EQ( cregex_find("k", &re3, &match, 0), 1);
- EXPECT_EQ(cregex_find("0", &re3, &match, 0), 0);
+ ASSERT_EQ(cregex_find(&re3, "k", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re3, "0", &match, 0), CREG_NOMATCH);
}
}
-END_TEST
-START_TEST(compile_match_or)
+CTEST(cregex, compile_match_or)
{
c_AUTO (cregex, re, re2)
{
re = cregex_from("as|df", 0);
- EXPECT_EQ(re.error, 0);
+ ASSERT_EQ(re.error, 0);
- csview match;
- EXPECT_EQ(cregex_find("as", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("df", &re, &match, 0), 1);
+ csview match[4];
+ ASSERT_EQ(cregex_find(&re, "as", match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "df", match, 0), CREG_OK);
re2 = cregex_from("(as|df)", 0);
- EXPECT_EQ(re2.error, 0);
+ ASSERT_EQ(re2.error, 0);
- EXPECT_EQ(cregex_find(&re2, "as", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find(&re2, "df", &re, &match, 0), 1);
+ ASSERT_EQ(cregex_find(&re2, "as", match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re2, "df", match, 0), CREG_OK);
}
}
-END_TEST
-START_TEST(compile_match_class_complex_0)
+CTEST(cregex, compile_match_class_complex_0)
{
cregex re = cregex_from("[asdf]", 0);
- EXPECT_EQ(re.error, 0);
+ ASSERT_EQ(re.error, 0);
csview match;
- EXPECT_EQ(cregex_find("a", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("s", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("d", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("f", &re, &match, 0), 1);
+ ASSERT_EQ(cregex_find(&re, "a", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "s", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "d", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "f", &match, 0), CREG_OK);
cregex_drop(&re);
}
-END_TEST
-START_TEST(compile_match_class_complex_1)
+CTEST(cregex, compile_match_class_complex_1)
{
cregex re = cregex_from("[a-zä0-9öA-Z]", 0);
- EXPECT_EQ(re.error, 0);
+ ASSERT_EQ(re.error, 0);
csview match;
- EXPECT_EQ(cregex_find("a", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("5", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("A", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("ä", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("ö", &re, &match, 0), 1);
+ ASSERT_EQ(cregex_find(&re, "a", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "5", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "A", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "ä", &match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "ö", &match, 0), CREG_OK);
cregex_drop(&re);
}
-END_TEST
-START_TEST(compile_match_cap)
+CTEST(cregex, compile_match_cap)
{
cregex re = cregex_from("(abc)d", 0);
- EXPECT_EQ(re.error, 0);
+ ASSERT_EQ(re.error, 0);
- csview match;
- EXPECT_EQ(cregex_find("abcd", &re, &match, 0)), 1;
- EXPECT_EQ(cregex_find("llljabcdkk", &re, &match, 0), 1);
- EXPECT_EQ(cregex_find("abc", &re, &match, 0), 0);
+ csview match[4];
+ ASSERT_EQ(cregex_find(&re, "abcd", match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "llljabcdkk", match, 0), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, "abc", match, 0), CREG_NOMATCH);
cregex_drop(&re);
}
-END_TEST
-START_TEST(search_all)
+CTEST(cregex, search_all)
{
+ const char* inp;
c_AUTO (cregex, re)
{
re = cregex_from("ab", 0);
csview m = {0};
int res;
-
- res = cregex_find("ab,ab,ab", &m, CREG_M_NEXT);
- EXPECT_TRUE(res==1 && M_START(re, m) == 0);
- res = cregex_find("ab,ab,ab", &m, CREG_M_NEXT);
- EXPECT_TRUE(res==1 && M_START(re, m) == 3);
- res = cregex_find("ab,ab,ab", &m, CREG_M_NEXT);
- EXPECT_TRUE(res==1 && M_START(re, m) == 6);
- res = cregex_find("ab,ab,ab", &m, CREG_M_NEXT);
- EXPECT_NE(res, 1);
+ ASSERT_EQ(re.error, CREG_OK);
+ inp="ab,ab,ab";
+ res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ ASSERT_EQ(M_START(m), 0);
+ res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ ASSERT_EQ(res, CREG_OK);
+ ASSERT_EQ(M_START(m), 3);
+ res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ ASSERT_EQ(M_START(m), 6);
+ res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ ASSERT_NE(res, CREG_OK);
}
}
-END_TEST
-START_TEST(captures_len)
+CTEST(cregex, captures_len)
{
c_AUTO (cregex, re) {
cregex re = cregex_from("(ab(cd))(ef)", 0);
- EXPECT_EQ(cregex_captures(&re), 3);
+ ASSERT_EQ(cregex_captures(&re), 4);
}
}
-END_TEST
-START_TEST(captures_cap)
+CTEST(cregex, captures_cap)
{
+ const char* inp;
c_AUTO (cregex, re) {
re = cregex_from("(ab)((cd)+)", 0);
- EXPECT_EQ(cregex_captures(&re), 3);
+ ASSERT_EQ(cregex_captures(&re), 4);
csview cap[5];
- EXPECT_EQ(cregex_find("xxabcdcde", &re, cap, 0), 1);
- EXPECT_TRUE(csview_equals(cap.match[0], c_SV("abcdcd")));
- /*
- EXPECT_EQ(cap0.end, 8);
- EXPECT_EQ(cap1.start, 2);
- EXPECT_EQ(cap1.end, 4);
- EXPECT_EQ(cap2.start, 4);
- EXPECT_EQ(cap2.end, 8);
- */
- EXPECT_FALSE(cregex_is_match("abcdcde", &re));
- EXPECT_TRUE(cregex_is_match("abcdcdcd", &re));
+ ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap, 0), CREG_OK);
+ ASSERT_TRUE(csview_equals(cap[0], "abcdcd"));
+
+ ASSERT_EQ(M_END(cap[0]), 8);
+ ASSERT_EQ(M_START(cap[1]), 2);
+ ASSERT_EQ(M_END(cap[1]), 4);
+ ASSERT_EQ(M_START(cap[2]), 4);
+ ASSERT_EQ(M_END(cap[2]), 8);
+
+ ASSERT_TRUE(cregex_is_match(&re, "abcdcde"));
+ ASSERT_TRUE(cregex_is_match(&re, "abcdcdcd"));
}
}
-END_TEST
-
-
-int main()
-{
- RUN_TEST(compile_match_char);
- RUN_TEST(compile_match_anchors);
- RUN_TEST(compile_match_quantifiers);
- RUN_TEST(compile_match_escaped_chars);
- RUN_TEST(compile_match_class_simple);
- RUN_TEST(compile_match_class_complex_0);
- RUN_TEST(compile_match_class_complex_1);
- RUN_TEST(compile_match_cap);
- RUN_TEST(search_all);
- RUN_TEST(captures_len);
- RUN_TEST(captures_cap);
- RUN_TEST(compile_match_or);
- return REPORT_TESTS();
-}
-#endif
-
diff --git a/misc/tests/ctest.h b/misc/tests/ctest.h
new file mode 100644
index 00000000..13344428
--- /dev/null
+++ b/misc/tests/ctest.h
@@ -0,0 +1,622 @@
+/* Copyright 2011-2023 Bas van den Berg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CTEST_H
+#define CTEST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define CTEST_IMPL_FORMAT_PRINTF(a, b) __attribute__ ((format(printf, a, b)))
+#else
+#define CTEST_IMPL_FORMAT_PRINTF(a, b)
+#endif
+
+#include <inttypes.h> /* intmax_t, uintmax_t, PRI* */
+#include <stdbool.h> /* bool, true, false */
+#include <stddef.h> /* size_t */
+
+typedef void (*ctest_nullary_run_func)(void);
+typedef void (*ctest_unary_run_func)(void*);
+typedef void (*ctest_setup_func)(void*);
+typedef void (*ctest_teardown_func)(void*);
+
+union ctest_run_func_union {
+ ctest_nullary_run_func nullary;
+ ctest_unary_run_func unary;
+};
+
+#define CTEST_IMPL_PRAGMA(x) _Pragma (#x)
+#define CTEST_CONTAINER_OF(p, T, m) \
+ ((T*)((char*)(p) + 0*sizeof((p) == &((T*)0)->m) - offsetof(T, m)))
+
+#if defined(__GNUC__)
+#if defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+/* the GCC argument will work for both gcc and clang */
+#define CTEST_IMPL_DIAG_PUSH_IGNORED(w) \
+ CTEST_IMPL_PRAGMA(GCC diagnostic push) \
+ CTEST_IMPL_PRAGMA(GCC diagnostic ignored "-W" #w)
+#define CTEST_IMPL_DIAG_POP() \
+ CTEST_IMPL_PRAGMA(GCC diagnostic pop)
+#else
+/* the push/pop functionality wasn't in gcc until 4.6, fallback to "ignored" */
+#define CTEST_IMPL_DIAG_PUSH_IGNORED(w) \
+ CTEST_IMPL_PRAGMA(GCC diagnostic ignored "-W" #w)
+#define CTEST_IMPL_DIAG_POP()
+#endif
+#else
+/* leave them out entirely for non-GNUC compilers */
+#define CTEST_IMPL_DIAG_PUSH_IGNORED(w)
+#define CTEST_IMPL_DIAG_POP()
+#endif
+
+struct ctest {
+ uint32_t magic0, padding;
+
+ const char* ssname; // suite name
+ const char* ttname; // test name
+ union ctest_run_func_union run;
+
+ void* data;
+ ctest_setup_func* setup;
+ ctest_teardown_func* teardown;
+
+ int32_t skip;
+ uint32_t magic1;
+};
+
+#define CTEST_IMPL_NAME(name) ctest_##name
+#define CTEST_IMPL_FNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_run)
+#define CTEST_IMPL_TNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname)
+#define CTEST_IMPL_DATA_SNAME(sname) CTEST_IMPL_NAME(sname##_data)
+#define CTEST_IMPL_DATA_TNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_data)
+#define CTEST_IMPL_SETUP_FNAME(sname) CTEST_IMPL_NAME(sname##_setup)
+#define CTEST_IMPL_SETUP_FPNAME(sname) CTEST_IMPL_NAME(sname##_setup_ptr)
+#define CTEST_IMPL_SETUP_TPNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_setup_ptr)
+#define CTEST_IMPL_TEARDOWN_FNAME(sname) CTEST_IMPL_NAME(sname##_teardown)
+#define CTEST_IMPL_TEARDOWN_FPNAME(sname) CTEST_IMPL_NAME(sname##_teardown_ptr)
+#define CTEST_IMPL_TEARDOWN_TPNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_teardown_ptr)
+
+#ifdef __APPLE__
+#define CTEST_IMPL_SECTION __attribute__ ((used, section ("__DATA, .ctest"), aligned(1)))
+#else
+#define CTEST_IMPL_SECTION __attribute__ ((used, section (".ctest"), aligned(1)))
+#endif
+
+#define CTEST_IMPL_STRUCT(sname, tname, tskip, tdata, tsetup, tteardown) \
+ static struct ctest CTEST_IMPL_TNAME(sname, tname) CTEST_IMPL_SECTION = { \
+ 0xBADCAFE0, 0, \
+ #sname, \
+ #tname, \
+ { (ctest_nullary_run_func) CTEST_IMPL_FNAME(sname, tname) }, \
+ tdata, \
+ (ctest_setup_func*) tsetup, \
+ (ctest_teardown_func*) tteardown, \
+ tskip, \
+ 0xBADCAFE1, \
+ }
+
+#ifdef __cplusplus
+
+#define CTEST_SETUP(sname) \
+ template <> void CTEST_IMPL_SETUP_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
+
+#define CTEST_TEARDOWN(sname) \
+ template <> void CTEST_IMPL_TEARDOWN_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
+
+#define CTEST_DATA(sname) \
+ template <typename T> void CTEST_IMPL_SETUP_FNAME(sname)(T* data) { } \
+ template <typename T> void CTEST_IMPL_TEARDOWN_FNAME(sname)(T* data) { } \
+ struct CTEST_IMPL_DATA_SNAME(sname)
+
+#define CTEST_IMPL_CTEST(sname, tname, tskip) \
+ static void CTEST_IMPL_FNAME(sname, tname)(void); \
+ CTEST_IMPL_STRUCT(sname, tname, tskip, NULL, NULL, NULL); \
+ static void CTEST_IMPL_FNAME(sname, tname)(void)
+
+#define CTEST_IMPL_CTEST2(sname, tname, tskip) \
+ static struct CTEST_IMPL_DATA_SNAME(sname) CTEST_IMPL_DATA_TNAME(sname, tname); \
+ static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* data); \
+ static void (*CTEST_IMPL_SETUP_TPNAME(sname, tname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_SETUP_FNAME(sname)<struct CTEST_IMPL_DATA_SNAME(sname)>; \
+ static void (*CTEST_IMPL_TEARDOWN_TPNAME(sname, tname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_TEARDOWN_FNAME(sname)<struct CTEST_IMPL_DATA_SNAME(sname)>; \
+ CTEST_IMPL_STRUCT(sname, tname, tskip, &CTEST_IMPL_DATA_TNAME(sname, tname), &CTEST_IMPL_SETUP_TPNAME(sname, tname), &CTEST_IMPL_TEARDOWN_TPNAME(sname, tname)); \
+ static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
+
+#else
+
+#define CTEST_SETUP(sname) \
+ static void CTEST_IMPL_SETUP_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data); \
+ static void (*CTEST_IMPL_SETUP_FPNAME(sname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_SETUP_FNAME(sname); \
+ static void CTEST_IMPL_SETUP_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
+
+#define CTEST_TEARDOWN(sname) \
+ static void CTEST_IMPL_TEARDOWN_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data); \
+ static void (*CTEST_IMPL_TEARDOWN_FPNAME(sname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_TEARDOWN_FNAME(sname); \
+ static void CTEST_IMPL_TEARDOWN_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
+
+#define CTEST_DATA(sname) \
+ struct CTEST_IMPL_DATA_SNAME(sname); \
+ static void (*CTEST_IMPL_SETUP_FPNAME(sname))(struct CTEST_IMPL_DATA_SNAME(sname)*); \
+ static void (*CTEST_IMPL_TEARDOWN_FPNAME(sname))(struct CTEST_IMPL_DATA_SNAME(sname)*); \
+ struct CTEST_IMPL_DATA_SNAME(sname)
+
+#define CTEST_IMPL_CTEST(sname, tname, tskip) \
+ static void CTEST_IMPL_FNAME(sname, tname)(void); \
+ CTEST_IMPL_STRUCT(sname, tname, tskip, NULL, NULL, NULL); \
+ static void CTEST_IMPL_FNAME(sname, tname)(void)
+
+#define CTEST_IMPL_CTEST2(sname, tname, tskip) \
+ static struct CTEST_IMPL_DATA_SNAME(sname) CTEST_IMPL_DATA_TNAME(sname, tname); \
+ static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* data); \
+ CTEST_IMPL_STRUCT(sname, tname, tskip, &CTEST_IMPL_DATA_TNAME(sname, tname), &CTEST_IMPL_SETUP_FPNAME(sname), &CTEST_IMPL_TEARDOWN_FPNAME(sname)); \
+ static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
+
+#endif
+
+void CTEST_LOG(const char* fmt, ...) CTEST_IMPL_FORMAT_PRINTF(1, 2);
+void CTEST_ERR(const char* fmt, ...) CTEST_IMPL_FORMAT_PRINTF(1, 2); // doesn't return
+
+#define CTEST(sname, tname) CTEST_IMPL_CTEST(sname, tname, 0)
+#define CTEST_SKIP(sname, tname) CTEST_IMPL_CTEST(sname, tname, 1)
+
+#define CTEST2(sname, tname) CTEST_IMPL_CTEST2(sname, tname, 0)
+#define CTEST2_SKIP(sname, tname) CTEST_IMPL_CTEST2(sname, tname, 1)
+
+
+void assert_str(const char* cmp, const char* exp, const char* real, const char* caller, int line);
+#define ASSERT_STR(exp, real) assert_str("==", exp, real, __FILE__, __LINE__)
+#define ASSERT_NOT_STR(exp, real) assert_str("!=", exp, real, __FILE__, __LINE__)
+#define ASSERT_STRSTR(str, substr) assert_str("=~", str, substr, __FILE__, __LINE__)
+#define ASSERT_NOT_STRSTR(str, substr) assert_str("!~", str, substr, __FILE__, __LINE__)
+
+void assert_wstr(const char* cmp, const wchar_t *exp, const wchar_t *real, const char* caller, int line);
+#define ASSERT_WSTR(exp, real) assert_wstr("==", exp, real, __FILE__, __LINE__)
+#define ASSERT_NOT_WSTR(exp, real) assert_wstr("!=", exp, real, __FILE__, __LINE__)
+#define ASSERT_WSTRSTR(str, substr) assert_wstr("=~", str, substr, __FILE__, __LINE__)
+#define ASSERT_NOT_WSTRSTR(str, substr) assert_wstr("!~", str, substr, __FILE__, __LINE__)
+
+void assert_data(const unsigned char* exp, size_t expsize,
+ const unsigned char* real, size_t realsize,
+ const char* caller, int line);
+#define ASSERT_DATA(exp, expsize, real, realsize) \
+ assert_data(exp, expsize, real, realsize, __FILE__, __LINE__)
+
+#define CTEST_FLT_EPSILON 1e-5
+#define CTEST_DBL_EPSILON 1e-12
+
+void assert_compare(const char* cmp, intmax_t exp, intmax_t real, const char* caller, int line);
+#define ASSERT_EQUAL(exp, real) assert_compare("==", exp, real, __FILE__, __LINE__)
+#define ASSERT_NOT_EQUAL(exp, real) assert_compare("!=", exp, real, __FILE__, __LINE__)
+
+#define ASSERT_EQ ASSERT_EQUAL
+#define ASSERT_NE ASSERT_NOT_EQUAL
+#define ASSERT_LT(v1, v2) assert_compare("<", v1, v2, __FILE__, __LINE__)
+#define ASSERT_LE(v1, v2) assert_compare("<=", v1, v2, __FILE__, __LINE__)
+#define ASSERT_GT(v1, v2) assert_compare(">", v1, v2, __FILE__, __LINE__)
+#define ASSERT_GE(v1, v2) assert_compare(">=", v1, v2, __FILE__, __LINE__)
+
+void assert_compare_u(const char* cmp, uintmax_t exp, uintmax_t real, const char* caller, int line);
+#define ASSERT_EQUAL_U(exp, real) assert_compare_u("==", exp, real, __FILE__, __LINE__)
+#define ASSERT_NOT_EQUAL_U(exp, real) assert_compare_u("!=", exp, real, __FILE__, __LINE__)
+
+void assert_interval(intmax_t exp1, intmax_t exp2, intmax_t real, const char* caller, int line);
+#define ASSERT_INTERVAL(exp1, exp2, real) assert_interval(exp1, exp2, real, __FILE__, __LINE__)
+
+void assert_null(void* real, const char* caller, int line);
+#define ASSERT_NULL(real) assert_null((void*)real, __FILE__, __LINE__)
+
+void assert_not_null(const void* real, const char* caller, int line);
+#define ASSERT_NOT_NULL(real) assert_not_null(real, __FILE__, __LINE__)
+
+void assert_true(int real, const char* caller, int line);
+#define ASSERT_TRUE(real) assert_true(real, __FILE__, __LINE__)
+
+void assert_false(int real, const char* caller, int line);
+#define ASSERT_FALSE(real) assert_false(real, __FILE__, __LINE__)
+
+void assert_fail(const char* caller, int line);
+#define ASSERT_FAIL() assert_fail(__FILE__, __LINE__)
+
+void assert_dbl_compare(const char* cmp, double exp, double real, double tol, const char* caller, int line);
+#define ASSERT_DBL_NEAR(exp, real) assert_dbl_compare("==", exp, real, -CTEST_DBL_EPSILON, __FILE__, __LINE__)
+#define ASSERT_DBL_NEAR_TOL(exp, real, tol) assert_dbl_compare("==", exp, real, tol, __FILE__, __LINE__)
+#define ASSERT_DBL_FAR(exp, real) assert_dbl_compare("!=", exp, real, -CTEST_DBL_EPSILON, __FILE__, __LINE__)
+#define ASSERT_DBL_FAR_TOL(exp, real, tol) assert_dbl_compare("!=", exp, real, tol, __FILE__, __LINE__)
+
+#define ASSERT_FLT_NEAR(v1, v2) assert_dbl_compare("==", v1, v2, -CTEST_FLT_EPSILON, __FILE__, __LINE__)
+#define ASSERT_FLT_FAR(v1, v2) assert_dbl_compare("!=", v1, v2, -CTEST_FLT_EPSILON, __FILE__, __LINE__)
+#define ASSERT_DBL_LT(v1, v2) assert_dbl_compare("<", v1, v2, 0.0, __FILE__, __LINE__)
+#define ASSERT_DBL_GT(v1, v2) assert_dbl_compare(">", v1, v2, 0.0, __FILE__, __LINE__)
+
+#ifdef CTEST_MAIN
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#if !defined(_WIN32) || defined(__GNUC__)
+#include <unistd.h>
+#elif defined(_WIN32)
+#include <io.h>
+#endif
+#include <stdint.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+static size_t ctest_errorsize;
+static char* ctest_errormsg;
+#define MSG_SIZE 4096
+static char ctest_errorbuffer[MSG_SIZE];
+static jmp_buf ctest_err;
+static int color_output = 1;
+static const char* suite_name;
+
+typedef int (*ctest_filter_func)(struct ctest*);
+
+#define ANSI_BLACK "\033[0;30m"
+#define ANSI_RED "\033[0;31m"
+#define ANSI_GREEN "\033[0;32m"
+#define ANSI_YELLOW "\033[0;33m"
+#define ANSI_BLUE "\033[0;34m"
+#define ANSI_MAGENTA "\033[0;35m"
+#define ANSI_CYAN "\033[0;36m"
+#define ANSI_GREY "\033[0;37m"
+#define ANSI_DARKGREY "\033[01;30m"
+#define ANSI_BRED "\033[01;31m"
+#define ANSI_BGREEN "\033[01;32m"
+#define ANSI_BYELLOW "\033[01;33m"
+#define ANSI_BBLUE "\033[01;34m"
+#define ANSI_BMAGENTA "\033[01;35m"
+#define ANSI_BCYAN "\033[01;36m"
+#define ANSI_WHITE "\033[01;37m"
+#define ANSI_NORMAL "\033[0m"
+
+CTEST(suite, test) { }
+
+static void vprint_errormsg(const char* const fmt, va_list ap) CTEST_IMPL_FORMAT_PRINTF(1, 0);
+static void print_errormsg(const char* const fmt, ...) CTEST_IMPL_FORMAT_PRINTF(1, 2);
+
+static void vprint_errormsg(const char* const fmt, va_list ap) {
+ // (v)snprintf returns the number that would have been written
+ const int ret = vsnprintf(ctest_errormsg, ctest_errorsize, fmt, ap);
+ if (ret < 0) {
+ ctest_errormsg[0] = 0x00;
+ } else {
+ const size_t size = (size_t) ret;
+ const size_t s = (ctest_errorsize <= size ? size -ctest_errorsize : size);
+ // ctest_errorsize may overflow at this point
+ ctest_errorsize -= s;
+ ctest_errormsg += s;
+ }
+}
+
+static void print_errormsg(const char* const fmt, ...) {
+ va_list argp;
+ va_start(argp, fmt);
+ vprint_errormsg(fmt, argp);
+ va_end(argp);
+}
+
+static void msg_start(const char* color, const char* title) {
+ if (color_output) {
+ print_errormsg("%s", color);
+ }
+ print_errormsg(" %s: ", title);
+}
+
+static void msg_end(void) {
+ if (color_output) {
+ print_errormsg(ANSI_NORMAL);
+ }
+ print_errormsg("\n");
+}
+
+void CTEST_LOG(const char* fmt, ...)
+{
+ va_list argp;
+ msg_start(ANSI_BLUE, "LOG");
+
+ va_start(argp, fmt);
+ vprint_errormsg(fmt, argp);
+ va_end(argp);
+
+ msg_end();
+}
+
+CTEST_IMPL_DIAG_PUSH_IGNORED(missing-noreturn)
+
+void CTEST_ERR(const char* fmt, ...)
+{
+ va_list argp;
+ msg_start(ANSI_YELLOW, "ERR");
+
+ va_start(argp, fmt);
+ vprint_errormsg(fmt, argp);
+ va_end(argp);
+
+ msg_end();
+ longjmp(ctest_err, 1);
+}
+
+CTEST_IMPL_DIAG_POP()
+
+void assert_str(const char* cmp, const char* exp, const char* real, const char* caller, int line) {
+ if ((!exp ^ !real) || (exp && (
+ (cmp[1] == '=' && ((cmp[0] == '=') ^ (strcmp(exp, real) == 0))) ||
+ (cmp[1] == '~' && ((cmp[0] == '=') ^ (strstr(exp, real) != NULL)))
+ ))) {
+ CTEST_ERR("%s:%d assertion failed, '%s' %s '%s'", caller, line, exp, cmp, real);
+ }
+}
+
+void assert_wstr(const char* cmp, const wchar_t *exp, const wchar_t *real, const char* caller, int line) {
+ if ((!exp ^ !real) || (exp && (
+ (cmp[1] == '=' && ((cmp[0] == '=') ^ (wcscmp(exp, real) == 0))) ||
+ (cmp[1] == '~' && ((cmp[0] == '=') ^ (wcsstr(exp, real) != NULL)))
+ ))) {
+ CTEST_ERR("%s:%d assertion failed, '%ls' %s '%ls'", caller, line, exp, cmp, real);
+ }
+}
+
+void assert_data(const unsigned char* exp, size_t expsize,
+ const unsigned char* real, size_t realsize,
+ const char* caller, int line) {
+ size_t i;
+ if (expsize != realsize) {
+ CTEST_ERR("%s:%d expected %" PRIuMAX " bytes, got %" PRIuMAX, caller, line, (uintmax_t) expsize, (uintmax_t) realsize);
+ }
+ for (i=0; i<expsize; i++) {
+ if (exp[i] != real[i]) {
+ CTEST_ERR("%s:%d expected 0x%02x at offset %" PRIuMAX " got 0x%02x",
+ caller, line, exp[i], (uintmax_t) i, real[i]);
+ }
+ }
+}
+
+static bool get_compare_result(const char* cmp, int c3, bool eq) {
+ if (cmp[0] == '<')
+ return c3 < 0 || ((cmp[1] == '=') & eq);
+ if (cmp[0] == '>')
+ return c3 > 0 || ((cmp[1] == '=') & eq);
+ return (cmp[0] == '=') == eq;
+}
+
+void assert_compare(const char* cmp, intmax_t exp, intmax_t real, const char* caller, int line) {
+ int c3 = (real < exp) - (exp < real);
+
+ if (!get_compare_result(cmp, c3, c3 == 0)) {
+ CTEST_ERR("%s:%d assertion failed, %" PRIdMAX " %s %" PRIdMAX "", caller, line, exp, cmp, real);
+ }
+}
+
+void assert_compare_u(const char* cmp, uintmax_t exp, uintmax_t real, const char* caller, int line) {
+ int c3 = (real < exp) - (exp < real);
+
+ if (!get_compare_result(cmp, c3, c3 == 0)) {
+ CTEST_ERR("%s:%d assertion failed, %" PRIuMAX " %s %" PRIuMAX, caller, line, exp, cmp, real);
+ }
+}
+
+void assert_interval(intmax_t exp1, intmax_t exp2, intmax_t real, const char* caller, int line) {
+ if (real < exp1 || real > exp2) {
+ CTEST_ERR("%s:%d expected %" PRIdMAX "-%" PRIdMAX ", got %" PRIdMAX, caller, line, exp1, exp2, real);
+ }
+}
+
+static bool approximately_equal(double a, double b, double epsilon) {
+ double d = a - b;
+ if (d < 0) d = -d;
+ if (a < 0) a = -a;
+ if (b < 0) b = -b;
+ return d <= (a > b ? a : b)*epsilon; /* D.Knuth */
+}
+
+/* tol < 0 means it is an epsilon, else absolute error */
+void assert_dbl_compare(const char* cmp, double exp, double real, double tol, const char* caller, int line) {
+ double diff = exp - real;
+ double absdiff = diff < 0 ? -diff : diff;
+ int c3 = (real < exp) - (exp < real);
+ bool eq = tol < 0 ? approximately_equal(exp, real, -tol) : absdiff <= tol;
+
+ if (!get_compare_result(cmp, c3, eq)) {
+ const char* tolstr = "tol";
+ if (tol < 0) {
+ tolstr = "eps";
+ tol = -tol;
+ }
+ CTEST_ERR("%s:%d assertion failed, %.8g %s %.8g (diff %.4g, %s %.4g)", caller, line, exp, cmp, real, diff, tolstr, tol);
+ }
+}
+
+void assert_null(void* real, const char* caller, int line) {
+ if ((real) != NULL) {
+ CTEST_ERR("%s:%d should be NULL", caller, line);
+ }
+}
+
+void assert_not_null(const void* real, const char* caller, int line) {
+ if (real == NULL) {
+ CTEST_ERR("%s:%d should not be NULL", caller, line);
+ }
+}
+
+void assert_true(int real, const char* caller, int line) {
+ if ((real) == 0) {
+ CTEST_ERR("%s:%d should be true", caller, line);
+ }
+}
+
+void assert_false(int real, const char* caller, int line) {
+ if ((real) != 0) {
+ CTEST_ERR("%s:%d should be false", caller, line);
+ }
+}
+
+void assert_fail(const char* caller, int line) {
+ CTEST_ERR("%s:%d shouldn't come here", caller, line);
+}
+
+
+static int suite_all(struct ctest* t) {
+ (void) t; // fix unused parameter warning
+ return 1;
+}
+
+static int suite_filter(struct ctest* t) {
+ return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0;
+}
+
+static void color_print(const char* color, const char* text) {
+ if (color_output)
+ printf("%s%s" ANSI_NORMAL "\n", color, text);
+ else
+ printf("%s\n", text);
+}
+
+#ifndef CTEST_NO_SEGFAULT
+#include <signal.h>
+static void sighandler(int signum)
+{
+ const char msg_color[] = ANSI_BRED "[SIGSEGV: Segmentation fault]" ANSI_NORMAL "\n";
+ const char msg_nocolor[] = "[SIGSEGV: Segmentation fault]\n";
+
+ const char* msg = color_output ? msg_color : msg_nocolor;
+ write(STDOUT_FILENO, msg, (unsigned int)strlen(msg));
+
+ /* "Unregister" the signal handler and send the signal back to the process
+ * so it can terminate as expected */
+ signal(signum, SIG_DFL);
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ kill(getpid(), signum);
+#endif
+}
+#endif
+
+int ctest_main(int argc, const char *argv[]);
+
+__attribute__((no_sanitize_address)) int ctest_main(int argc, const char *argv[])
+{
+ static int total = 0;
+ static int num_ok = 0;
+ static int num_fail = 0;
+ static int num_skip = 0;
+ static int idx = 1;
+ static ctest_filter_func filter = suite_all;
+
+#ifndef CTEST_NO_SEGFAULT
+ signal(SIGSEGV, sighandler);
+#endif
+
+ if (argc == 2) {
+ suite_name = argv[1];
+ filter = suite_filter;
+ }
+#ifdef CTEST_NO_COLORS
+ color_output = 0;
+#else
+ color_output = isatty(1);
+#endif
+ clock_t t1 = clock();
+
+ uint32_t* magic_begin = &CTEST_IMPL_TNAME(suite, test).magic1;
+ uint32_t* magic_end = &CTEST_IMPL_TNAME(suite, test).magic0, *m;
+ size_t skipints = sizeof(struct ctest)/sizeof *m;
+
+#if (defined __TINYC__ && defined __unix__)
+ #define CTEST_PEEK 10 /* search 4*(1+10) bytes outside ctest entry bounds */
+#else
+ #define CTEST_PEEK 0 /* access only 4 bytes outside outer ctest entry bounds */
+#endif
+ for (m = magic_begin; magic_begin - m <= skipints + CTEST_PEEK; --m) {
+ if (*m == 0xBADCAFE1) {
+ magic_begin = m;
+ m -= skipints - 1;
+ }
+ }
+ for (m = magic_end; m - magic_end <= skipints; ++m) {
+ if (*m == 0xBADCAFE0) {
+ magic_end = m;
+ m += skipints - 1;
+ }
+ }
+ magic_begin = &CTEST_CONTAINER_OF(magic_begin, struct ctest, magic1)->magic0;
+
+ static struct ctest* test;
+ for (m = magic_begin; m <= magic_end; m += skipints) {
+ while (*m != 0xBADCAFE0) ++m;
+ test = CTEST_CONTAINER_OF(m, struct ctest, magic0);
+ if (test == &CTEST_IMPL_TNAME(suite, test)) continue;
+ if (filter(test)) total++;
+ }
+
+ for (m = magic_begin; m <= magic_end; m += skipints) {
+ while (*m != 0xBADCAFE0) ++m;
+ test = CTEST_CONTAINER_OF(m, struct ctest, magic0);
+ if (test == &CTEST_IMPL_TNAME(suite, test)) continue;
+ if (filter(test)) {
+ ctest_errorbuffer[0] = 0;
+ ctest_errorsize = MSG_SIZE-1;
+ ctest_errormsg = ctest_errorbuffer;
+ printf("TEST %d/%d %s:%s ", idx, total, test->ssname, test->ttname);
+ fflush(stdout);
+ if (test->skip) {
+ color_print(ANSI_BYELLOW, "[SKIPPED]");
+ num_skip++;
+ } else {
+ int result = setjmp(ctest_err);
+ if (result == 0) {
+ if (test->setup && *test->setup) (*test->setup)(test->data);
+ if (test->data)
+ test->run.unary(test->data);
+ else
+ test->run.nullary();
+ if (test->teardown && *test->teardown) (*test->teardown)(test->data);
+ // if we got here it's ok
+#ifdef CTEST_NO_COLOR_OK
+ printf("[OK]\n");
+#else
+ color_print(ANSI_BGREEN, "[OK]");
+#endif
+ num_ok++;
+ } else {
+ color_print(ANSI_BRED, "[FAIL]");
+ num_fail++;
+ }
+ if (ctest_errorsize != MSG_SIZE-1) printf("%s", ctest_errorbuffer);
+ }
+ idx++;
+ }
+ }
+ clock_t t2 = clock();
+
+ const char* color = (num_fail) ? ANSI_BRED : ANSI_GREEN;
+ char results[80];
+ snprintf(results, sizeof(results), "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %.1f ms",
+ total, num_ok, num_fail, num_skip, (double)(t2 - t1)*1000.0/CLOCKS_PER_SEC);
+ color_print(color, results);
+ return num_fail;
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/misc/tests/main.c b/misc/tests/main.c
new file mode 100644
index 00000000..2b8931c4
--- /dev/null
+++ b/misc/tests/main.c
@@ -0,0 +1,31 @@
+/* Copyright 2011-2023 Bas van den Berg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#define CTEST_MAIN
+
+// uncomment lines below to enable/disable features. See README.md for details
+//#define CTEST_NO_SEGFAULT
+//#define CTEST_NO_COLORS
+//#define CTEST_NO_COLOR_OK
+
+#include "ctest.h"
+
+int main(int argc, const char *argv[])
+{
+ return ctest_main(argc, argv);
+}
+