summaryrefslogtreecommitdiffstats
path: root/src/lib-test/test-common.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-test/test-common.h')
-rw-r--r--src/lib-test/test-common.h165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/lib-test/test-common.h b/src/lib-test/test-common.h
new file mode 100644
index 0000000..f845c0d
--- /dev/null
+++ b/src/lib-test/test-common.h
@@ -0,0 +1,165 @@
+#ifndef TEST_COMMON_H
+#define TEST_COMMON_H
+
+struct istream *test_istream_create(const char *data);
+struct istream *test_istream_create_data(const void *data, size_t size);
+void test_istream_set_size(struct istream *input, uoff_t size);
+void test_istream_set_allow_eof(struct istream *input, bool allow);
+void test_istream_set_max_buffer_size(struct istream *input, size_t size);
+
+struct ostream *test_ostream_create(buffer_t *output);
+struct ostream *test_ostream_create_nonblocking(buffer_t *output,
+ size_t max_internal_buffer_size);
+/* When output->used reaches max_size, start buffering output internally.
+ When internal buffer reaches max_internal_buffer_size, start returning 0 for
+ o_stream_send*(). */
+void test_ostream_set_max_output_size(struct ostream *output, size_t max_size);
+
+void test_begin(const char *name);
+#define test_assert(code) STMT_START { \
+ if (!(code)) test_assert_failed(#code, __FILE__, __LINE__); \
+ } STMT_END
+/* Additional parameter may be int or unsigned int, to indicate which of
+ * a barrage of tests have failed (such as in a loop).
+ */
+#define test_assert_idx(code, i) STMT_START { \
+ if (!(code)) test_assert_failed_idx(#code, __FILE__, __LINE__, i); \
+ } STMT_END
+/* Additional parameters are s1 (source) and s2 (destination) string
+ * in strcmp().
+ */
+#define test_assert_strcmp(s1, s2) STMT_START { \
+ test_assert_strcmp_idx(s1, s2, LLONG_MIN); \
+ } STMT_END
+
+/* Same as test_assert_strcmp expect that it takes an additional i as input.
+ * When i is greater than or equals 0 it is used to identify the barrage of
+ * tests failed like in test_assert_idx.
+*/
+#define test_assert_strcmp_idx(_s1, _s2, i) STMT_START { \
+ const char *_temp_s1 = (_s1); \
+ const char *_temp_s2 = (_s2); \
+ if ((null_strcmp(_temp_s1,_temp_s2) != 0)) \
+ test_assert_failed_strcmp_idx("strcmp(" #_s1 "," #_s2 ")", \
+ __FILE__, __LINE__, _temp_s1, _temp_s2, i); \
+ } STMT_END
+
+#define test_assert_cmp(_value1, _op, _value2) \
+ test_assert_cmp_idx(_value1, _op, _value2, LLONG_MIN)
+#define test_assert_cmp_idx(_value1, _op, _value2, _idx) STMT_START { \
+ intmax_t _temp_value1 = (_value1); \
+ intmax_t _temp_value2 = (_value2); \
+ if (!(_value1 _op _value2)) \
+ test_assert_failed_cmp_intmax_idx( \
+ #_value1 " " #_op " " #_value2, \
+ __FILE__, __LINE__, _temp_value1, _temp_value2, \
+ #_op, _idx); \
+ } STMT_END
+
+#define test_assert_ucmp(_value1, _op, _value2) \
+ test_assert_ucmp_idx(_value1, _op, _value2, LLONG_MIN)
+#define test_assert_ucmp_idx(_value1, _op, _value2, _idx) STMT_START { \
+ uintmax_t _temp_value1 = (_value1); \
+ uintmax_t _temp_value2 = (_value2); \
+ if (!(_value1 _op _value2)) \
+ test_assert_failed_ucmp_intmax_idx( \
+ #_value1 " " #_op " " #_value2, \
+ __FILE__, __LINE__, _temp_value1, _temp_value2, \
+ #_op, _idx); \
+ } STMT_END
+
+#ifdef STATIC_CHECKER
+# define ATTR_STATIC_CHECKER_NORETURN ATTR_NORETURN
+#else
+# define ATTR_STATIC_CHECKER_NORETURN
+#endif
+
+void test_assert_failed(const char *code, const char *file, unsigned int line)
+ ATTR_STATIC_CHECKER_NORETURN;
+void test_assert_failed_idx(const char *code, const char *file, unsigned int line, long long i)
+ ATTR_STATIC_CHECKER_NORETURN;
+void test_assert_failed_strcmp_idx(const char *code, const char *file, unsigned int line,
+ const char * src, const char * dst, long long i)
+ ATTR_STATIC_CHECKER_NORETURN;
+void test_assert_failed_cmp_intmax_idx(const char *code, const char *file,
+ unsigned int line,
+ intmax_t src, intmax_t dst,
+ const char *op, long long i)
+ ATTR_STATIC_CHECKER_NORETURN;
+void test_assert_failed_ucmp_intmax_idx(const char *code, const char *file,
+ unsigned int line,
+ uintmax_t src, uintmax_t dst,
+ const char *op, long long i)
+ ATTR_STATIC_CHECKER_NORETURN;
+bool test_has_failed(void);
+/* If you're testing nasty cases which you want to warn, surround the noisy op with these */
+void test_expect_errors(unsigned int expected);
+void test_expect_error_string(const char *substr); /* expect just 1 message matching the printf format */
+void test_expect_error_string_n_times(const char *substr, unsigned int times); /* expect just n messages matching the printf format */
+void test_expect_no_more_errors(void);
+/* Note that test_expect_error{s,_string}() effectively begin with a check equivalent
+ to test_expect_no_more_errors(), so you don't need the latter explicitly if following
+ it with either of the former.*/
+
+void test_end(void);
+
+void test_out(const char *name, bool success);
+void test_out_quiet(const char *name, bool success); /* only prints failures */
+void test_out_reason(const char *name, bool success, const char *reason)
+ ATTR_NULL(3);
+
+int test_run(void (*const test_functions[])(void)) ATTR_WARN_UNUSED_RESULT;
+struct named_test {
+ const char *name;
+ void (*func)(void);
+};
+int test_run_named(const struct named_test tests[], const char *match) ATTR_WARN_UNUSED_RESULT;
+
+#define TEST_DECL(x) void x(void);
+#define TEST_NAMELESS(x) x, /* Were you to want to use the X trick but not name the tests */
+#define TEST_NAMED(x) { .name = #x , .func = x },
+
+enum fatal_test_state {
+ FATAL_TEST_FINISHED, /* no more test stages, don't call again */
+ FATAL_TEST_FAILURE, /* single stage has failed, continue */
+ FATAL_TEST_ABORT, /* something's gone horrifically wrong */
+};
+/* The fatal function is called first with stage=0. After each call the stage
+ is increased by 1. The idea is that each stage would be running an
+ individual test that is supposed to crash. The function is called until
+ FATAL_TEST_FINISHED or FATAL_TEST_ABORT is returned. */
+typedef enum fatal_test_state test_fatal_func_t(unsigned int stage);
+
+typedef void test_fatal_callback_t(void *context);
+
+struct named_fatal {
+ const char *name;
+ test_fatal_func_t *func;
+};
+int test_run_with_fatals(void (*const test_functions[])(void),
+ test_fatal_func_t *const fatal_functions[]);
+int test_run_named_with_fatals(const char *match, const struct named_test tests[],
+ const struct named_fatal fatals[]);
+
+/* Require the Fatal/Panic string to match this or the fatal test fails. */
+void test_expect_fatal_string(const char *substr);
+/* Call the specified callback when a fatal is being triggered. This is mainly
+ intended to allow freeing memory so valgrind won't complain about memory
+ leaks. */
+void test_fatal_set_callback(test_fatal_callback_t *callback, void *context);
+#define test_fatal_set_callback(callback, context) \
+ test_fatal_set_callback(1 ? (test_fatal_callback_t *)callback : \
+ CALLBACK_TYPECHECK(callback, void (*)(typeof(context))), \
+ context)
+
+#define FATAL_DECL(x) enum fatal_test_state x(unsigned int);
+#define FATAL_NAMELESS(x) x, /* Were you to want to use the X trick but not name the tests */
+#define FATAL_NAMED(x) { .name = #x , .func = x },
+
+/* If a child is forked within test context, but wants to operate outside it,
+ then this will avoid valgrind leak errors */
+void test_forked_end(void);
+/* If a fork() wants to exit(), then this will avoid valgrind leak errors */
+void test_exit(int status) ATTR_NORETURN;
+
+#endif