summaryrefslogtreecommitdiff
path: root/include/gst/check
diff options
context:
space:
mode:
Diffstat (limited to 'include/gst/check')
-rw-r--r--include/gst/check/check-prelude.h43
-rw-r--r--include/gst/check/check.h33
-rw-r--r--include/gst/check/gstbufferstraw.h40
-rw-r--r--include/gst/check/gstcheck.h756
-rw-r--r--include/gst/check/gstconsistencychecker.h52
-rw-r--r--include/gst/check/gstharness.h474
-rw-r--r--include/gst/check/gsttestclock.h148
-rw-r--r--include/gst/check/internal-check.h1328
8 files changed, 2874 insertions, 0 deletions
diff --git a/include/gst/check/check-prelude.h b/include/gst/check/check-prelude.h
new file mode 100644
index 0000000000..0fc272598b
--- /dev/null
+++ b/include/gst/check/check-prelude.h
@@ -0,0 +1,43 @@
+/* GStreamer Check Library
+ * Copyright (C) 2018 GStreamer developers
+ *
+ * check-prelude.h: prelude include header for gst-check library
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CHECK_PRELUDE_H__
+#define __GST_CHECK_PRELUDE_H__
+
+#include <gst/gst.h>
+
+#ifndef GST_CHECK_API
+#ifdef BUILDING_GST_CHECK
+#define GST_CHECK_API GST_API_EXPORT /* from config.h */
+#else
+#define GST_CHECK_API GST_API_IMPORT
+#endif
+#endif
+
+#ifndef GST_DISABLE_DEPRECATED
+#define GST_CHECK_DEPRECATED GST_CHECK_API
+#define GST_CHECK_DEPRECATED_FOR(f) GST_CHECK_API
+#else
+#define GST_CHECK_DEPRECATED G_DEPRECATED GST_CHECK_API
+#define GST_CHECK_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) GST_CHECK_API
+#endif
+
+#endif /* __GST_CHECK_PRELUDE_H__ */
diff --git a/include/gst/check/check.h b/include/gst/check/check.h
new file mode 100644
index 0000000000..512f06ca54
--- /dev/null
+++ b/include/gst/check/check.h
@@ -0,0 +1,33 @@
+/* GStreamer
+ * Copyright (C) 2012 GStreamer developers
+ *
+ * check.h: single include header for gst-check library
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CHECK__H__
+#define __GST_CHECK__H__
+
+#include <gst/check/check-prelude.h>
+
+#include <gst/check/gstbufferstraw.h>
+#include <gst/check/gstcheck.h>
+#include <gst/check/gstconsistencychecker.h>
+#include <gst/check/gstharness.h>
+#include <gst/check/gsttestclock.h>
+
+#endif /* __GST_CHECK__H__ */
diff --git a/include/gst/check/gstbufferstraw.h b/include/gst/check/gstbufferstraw.h
new file mode 100644
index 0000000000..9eec1f9bd4
--- /dev/null
+++ b/include/gst/check/gstbufferstraw.h
@@ -0,0 +1,40 @@
+/* GStreamer
+ *
+ * Copyright (C) 2006 Andy Wingo <wingo at pobox.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_BUFFER_STRAW_H__
+#define __GST_BUFFER_STRAW_H__
+
+
+#include <gst/check/gstcheck.h>
+
+G_BEGIN_DECLS
+
+GST_CHECK_API
+void gst_buffer_straw_start_pipeline (GstElement * bin, GstPad * pad);
+
+GST_CHECK_API
+GstBuffer * gst_buffer_straw_get_buffer (GstElement * bin, GstPad * pad);
+
+GST_CHECK_API
+void gst_buffer_straw_stop_pipeline (GstElement * bin, GstPad * pad);
+
+G_END_DECLS
+
+#endif /* __GST_BUFFER_STRAW_H__ */
diff --git a/include/gst/check/gstcheck.h b/include/gst/check/gstcheck.h
new file mode 100644
index 0000000000..b7ec2c4ab3
--- /dev/null
+++ b/include/gst/check/gstcheck.h
@@ -0,0 +1,756 @@
+/* GStreamer
+ *
+ * Common code for GStreamer unittests
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ * Copyright (C) <2008> Thijs Vermeir <thijsvermeir@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CHECK_H__
+#define __GST_CHECK_H__
+
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <gst/gst.h>
+#include <gst/check/check-prelude.h>
+
+#define CK_DLL_EXP GST_CHECK_API
+#include <gst/check/internal-check.h>
+
+G_BEGIN_DECLS
+
+GST_CHECK_API GstDebugCategory *check_debug;
+#define GST_CAT_DEFAULT check_debug
+
+/* logging function for tests
+ * a test uses g_message() to log a debug line
+ * a gst unit test can be run with GST_TEST_DEBUG env var set to see the
+ * messages
+ */
+GST_CHECK_API gboolean _gst_check_threads_running;
+GST_CHECK_API gboolean _gst_check_raised_critical;
+GST_CHECK_API gboolean _gst_check_raised_warning;
+GST_CHECK_API gboolean _gst_check_expecting_log;
+GST_CHECK_API gboolean _gst_check_list_tests;
+
+/* global variables used in test methods */
+GST_CHECK_API GList * buffers;
+
+GST_CHECK_API GMutex check_mutex;
+GST_CHECK_API GCond check_cond;
+
+/**
+ * GstCheckABIStruct:
+ * @name: The name of the structure
+ * @size: The current size of a structure
+ * @abi_size: The reference size of the structure
+ */
+typedef struct
+{
+ const char *name;
+ int size;
+ int abi_size;
+}
+GstCheckABIStruct;
+
+/**
+ * GstCheckLogFilter:
+ *
+ * Opaque structure containing data about a log filter
+ * function.
+ */
+typedef struct _GstCheckLogFilter GstCheckLogFilter;
+
+/**
+ * GstCheckLogFilterFunc:
+ * @log_domain: the log domain of the message
+ * @log_level: the log level of the message
+ * @message: the message that has occurred
+ * @user_data: user data
+ *
+ * A function that is called for messages matching the filter added by
+ * @gst_check_add_log_filter.
+ *
+ * Returns: %TRUE if message should be discarded by GstCheck.
+ *
+ * Since: 1.12
+ */
+typedef gboolean (*GstCheckLogFilterFunc) (const gchar * log_domain,
+ GLogLevelFlags log_level, const gchar * message, gpointer user_data);
+
+GST_CHECK_API
+void gst_check_init (int *argc, char **argv[]);
+
+GST_CHECK_API
+GstCheckLogFilter * gst_check_add_log_filter (const gchar * log_domain,
+ GLogLevelFlags log_level, GRegex * regex, GstCheckLogFilterFunc func,
+ gpointer user_data, GDestroyNotify destroy_data);
+
+GST_CHECK_API
+void gst_check_remove_log_filter (GstCheckLogFilter * filter);
+
+GST_CHECK_API
+void gst_check_clear_log_filter (void);
+
+GST_CHECK_API
+GstFlowReturn gst_check_chain_func (GstPad * pad, GstObject * parent, GstBuffer * buffer);
+
+GST_CHECK_API
+void gst_check_message_error (GstMessage * message, GstMessageType type,
+ GQuark domain, gint code);
+
+GST_CHECK_API
+GstElement *gst_check_setup_element (const gchar * factory);
+
+GST_CHECK_API
+void gst_check_teardown_element (GstElement * element);
+
+GST_CHECK_API
+GstPad *gst_check_setup_src_pad (GstElement * element,
+ GstStaticPadTemplate * tmpl);
+
+GST_CHECK_API
+GstPad *gst_check_setup_src_pad_from_template (GstElement * element,
+ GstPadTemplate * tmpl);
+
+GST_CHECK_API
+GstPad * gst_check_setup_src_pad_by_name (GstElement * element,
+ GstStaticPadTemplate * tmpl, const gchar *name);
+
+GST_CHECK_API
+GstPad * gst_check_setup_src_pad_by_name_from_template (GstElement * element,
+ GstPadTemplate * tmpl, const gchar *name);
+
+GST_CHECK_API
+GstPad *gst_check_setup_sink_pad (GstElement * element,
+ GstStaticPadTemplate * tmpl);
+
+GST_CHECK_API
+GstPad *gst_check_setup_sink_pad_from_template (GstElement * element,
+ GstPadTemplate * tmpl);
+
+GST_CHECK_API
+GstPad * gst_check_setup_sink_pad_by_name (GstElement * element,
+ GstStaticPadTemplate * tmpl, const gchar *name);
+
+GST_CHECK_API
+GstPad * gst_check_setup_sink_pad_by_name_from_template (GstElement * element,
+ GstPadTemplate * tmpl, const gchar *name);
+
+GST_CHECK_API
+void gst_check_teardown_pad_by_name (GstElement * element, const gchar *name);
+
+GST_CHECK_API
+void gst_check_teardown_src_pad (GstElement * element);
+
+GST_CHECK_API
+void gst_check_drop_buffers (void);
+
+GST_CHECK_API
+void gst_check_caps_equal (GstCaps * caps1, GstCaps * caps2);
+
+GST_CHECK_API
+void gst_check_buffer_data (GstBuffer * buffer, gconstpointer data, gsize size);
+
+GST_CHECK_API
+void gst_check_element_push_buffer_list (const gchar * element_name,
+ GList * buffer_in, GstCaps * caps_in, GList * buffer_out,
+ GstCaps * caps_out, GstFlowReturn last_flow_return);
+
+GST_CHECK_API
+void gst_check_element_push_buffer (const gchar * element_name,
+ GstBuffer * buffer_in, GstCaps * caps_in, GstBuffer * buffer_out,
+ GstCaps *caps_out);
+
+GST_CHECK_API
+void gst_check_teardown_sink_pad (GstElement * element);
+
+GST_CHECK_API
+void gst_check_abi_list (GstCheckABIStruct list[], gboolean have_abi_sizes);
+
+GST_CHECK_API
+gint gst_check_run_suite (Suite * suite, const gchar * name,
+ const gchar * fname);
+
+GST_CHECK_API
+void gst_check_setup_events (GstPad * srcpad, GstElement * element,
+ GstCaps * caps, GstFormat format);
+
+GST_CHECK_API
+void gst_check_setup_events_with_stream_id (GstPad * srcpad,
+ GstElement * element, GstCaps * caps, GstFormat format,
+ const gchar * stream_id);
+
+GST_CHECK_API
+void gst_check_objects_destroyed_on_unref (gpointer object_to_unref, gpointer first_object, ...)
+ G_GNUC_NULL_TERMINATED;
+
+GST_CHECK_API
+void gst_check_object_destroyed_on_unref (gpointer object_to_unref);
+
+#ifndef __GI_SCANNER__
+
+#define fail_unless_message_error(msg, domain, code) \
+gst_check_message_error (msg, GST_MESSAGE_ERROR, \
+ GST_ ## domain ## _ERROR, GST_ ## domain ## _ERROR_ ## code)
+#define assert_message_error(m, d, c) fail_unless_message_error(m, d, c)
+
+#ifdef GST_CHECK_TEST_ENVIRONMENT_BEACON
+#define GST_DO_CHECK_TEST_ENVIRONMENT \
+G_STMT_START { \
+ if (g_getenv (GST_CHECK_TEST_ENVIRONMENT_BEACON) == NULL) \
+ fail ("Test environment not set up correctly! Expected environment " \
+ "variable '%s' to be set.", GST_CHECK_TEST_ENVIRONMENT_BEACON); \
+} G_STMT_END
+
+#else
+#define GST_DO_CHECK_TEST_ENVIRONMENT /* nothing to check */
+#endif
+
+/**
+ * GST_START_TEST:
+ * @__testname: test function name
+ *
+ * wrapper for checks START_TEST
+ */
+/**
+ * GST_END_TEST:
+ *
+ * wrapper for checks END_TEST
+ */
+#define GST_START_TEST(__testname) \
+static void __testname (int G_GNUC_UNUSED __i__) \
+{\
+ GST_DEBUG ("test start"); \
+ GST_DO_CHECK_TEST_ENVIRONMENT; \
+ tcase_fn_start (""# __testname, __FILE__, __LINE__);
+
+#define GST_END_TEST GST_LOG ("cleaning up tasks"); \
+ gst_task_cleanup_all (); \
+ END_TEST
+
+/* additional fail macros */
+/**
+ * fail_unless_equals_int:
+ * @a: a #gint value or expression
+ * @b: a #gint value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to. This
+ * macro is for use in unit tests.
+ */
+#define fail_unless_equals_int(a, b) \
+G_STMT_START { \
+ int first = a; \
+ int second = b; \
+ fail_unless(first == second, \
+ "'" #a "' (%d) is not equal to '" #b"' (%d)", first, second); \
+} G_STMT_END;
+/**
+ * assert_equals_int:
+ * @a: a #gint value or expression
+ * @b: a #gint value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to. This
+ * macro is for use in unit tests.
+ */
+#define assert_equals_int(a, b) fail_unless_equals_int(a, b)
+
+/**
+ * fail_unless_equals_int_hex:
+ * @a: a #gint value or expression
+ * @b: a #gint value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to in
+ * hexadecimal format. This macro is for use in unit tests.
+ *
+ * Since: 1.2
+ */
+#define fail_unless_equals_int_hex(a, b) \
+G_STMT_START { \
+ int first = a; \
+ int second = b; \
+ fail_unless(first == second, \
+ "'" #a "' (0x%08x) is not equal to '" #b"' (0x%08x)", first, second);\
+} G_STMT_END;
+
+/**
+ * assert_equals_int_hex:
+ * @a: a #gint value or expression
+ * @b: a #gint value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to in
+ * hexadecimal format. This macro is for use in unit tests.
+ *
+ * Since: 1.2
+ */
+#define assert_equals_int_hex(a, b) fail_unless_equals_int_hex(a, b)
+
+/**
+ * fail_unless_equals_int64:
+ * @a: a #gint64 value or expression
+ * @b: a #gint64 value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to. This
+ * macro is for use in unit tests.
+ */
+#define fail_unless_equals_int64(a, b) \
+G_STMT_START { \
+ gint64 first = a; \
+ gint64 second = b; \
+ fail_unless(first == second, \
+ "'" #a "' (%" G_GINT64_FORMAT") is not equal to '" #b"' (%" \
+ G_GINT64_FORMAT")", first, second); \
+} G_STMT_END;
+/**
+ * assert_equals_int64:
+ * @a: a #gint64 value or expression
+ * @b: a #gint64 value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to. This
+ * macro is for use in unit tests.
+ */
+#define assert_equals_int64(a, b) fail_unless_equals_int64(a, b)
+
+/**
+ * fail_unless_equals_int64_hex:
+ * @a: a #gint64 value or expression
+ * @b: a #gint64 value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to in
+ * hexadecimal format. This macro is for use in unit tests.
+ *
+ * Since: 1.2
+ */
+#define fail_unless_equals_int64_hex(a, b) \
+G_STMT_START { \
+ gint64 first = a; \
+ gint64 second = b; \
+ fail_unless(first == second, \
+ "'" #a "' (0x%016x) is not equal to '" #b"' (0x%016x)", first, second);\
+} G_STMT_END;
+/**
+ * assert_equals_int64_hex:
+ * @a: a #gint64 value or expression
+ * @b: a #gint64 value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to in
+ * hexadecimal format. This macro is for use in unit tests.
+ *
+ * Since: 1.2
+ */
+#define assert_equals_int64_hex(a,b) fail_unless_equals_int64_hex(a,b)
+
+/**
+ * fail_unless_equals_uint64:
+ * @a: a #guint64 value or expression
+ * @b: a #guint64 value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to. This
+ * macro is for use in unit tests.
+ */
+#define fail_unless_equals_uint64(a, b) \
+G_STMT_START { \
+ guint64 first = a; \
+ guint64 second = b; \
+ fail_unless(first == second, \
+ "'" #a "' (%" G_GUINT64_FORMAT ") is not equal to '" #b"' (%" \
+ G_GUINT64_FORMAT ")", first, second); \
+} G_STMT_END;
+/**
+ * assert_equals_uint64:
+ * @a: a #guint64 value or expression
+ * @b: a #guint64 value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to. This
+ * macro is for use in unit tests.
+ */
+#define assert_equals_uint64(a, b) fail_unless_equals_uint64(a, b)
+
+/**
+ * fail_unless_equals_uint64_hex:
+ * @a: a #gint64 value or expression
+ * @b: a #gint64 value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to in
+ * hexadecimal format. This macro is for use in unit tests.
+ *
+ * Since: 1.2
+ */
+#define fail_unless_equals_uint64_hex(a, b) \
+G_STMT_START { \
+ guint64 first = a; \
+ guint64 second = b; \
+ fail_unless(first == second, \
+ "'" #a "' (0x%016x) is not equal to '" #b"' (0x%016x)", first, second);\
+} G_STMT_END;
+/**
+ * assert_equals_uint64_hex:
+ * @a: a #guint64 value or expression
+ * @b: a #guint64 value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to in
+ * hexadecimal format. This macro is for use in unit tests.
+ *
+ * Since: 1.2
+ */
+#define assert_equals_uint64_hex(a,b) fail_unless_equals_uint64_hex(a,b)
+
+/**
+ * fail_unless_equals_string:
+ * @a: a string literal or expression
+ * @b: a string literal or expression
+ *
+ * This macro checks that @a and @b are equal (as per g_strcmp0()) and aborts if
+ * this is not the case, printing both expressions and the values they
+ * evaluated to. This macro is for use in unit tests.
+ */
+#define fail_unless_equals_string(a, b) \
+G_STMT_START { \
+ const gchar * first = a; \
+ const gchar * second = b; \
+ fail_unless(g_strcmp0 (first, second) == 0, \
+ "'" #a "' (%s) is not equal to '" #b"' (%s)", first, second); \
+} G_STMT_END;
+/**
+ * assert_equals_string:
+ * @a: a string literal or expression
+ * @b: a string literal or expression
+ *
+ * This macro checks that @a and @b are equal (as per g_strcmp0()) and aborts if
+ * this is not the case, printing both expressions and the values they
+ * evaluated to. This macro is for use in unit tests.
+ */
+#define assert_equals_string(a, b) fail_unless_equals_string(a, b)
+
+/**
+ * fail_unless_equals_float:
+ * @a: a #gdouble or #gfloat value or expression
+ * @b: a #gdouble or #gfloat value or expression
+ *
+ * This macro checks that @a and @b are (almost) equal and aborts if this
+ * is not the case, printing both expressions and the values they evaluated
+ * to. This macro is for use in unit tests.
+ */
+#define fail_unless_equals_float(a, b) \
+G_STMT_START { \
+ double first = a; \
+ double second = b; \
+ /* This will only work for 'normal' values and values around 0, \
+ * which should be good enough for our purposes here */ \
+ fail_unless(fabs (first - second) < 0.0000001, \
+ "'" #a "' (%g) is not equal to '" #b "' (%g)", first, second);\
+} G_STMT_END;
+
+/**
+ * assert_equals_float:
+ * @a: a #gdouble or #gfloat value or expression
+ * @b: a #gdouble or #gfloat value or expression
+ *
+ * This macro checks that @a and @b are (almost) equal and aborts if this
+ * is not the case, printing both expressions and the values they evaluated
+ * to. This macro is for use in unit tests.
+ */
+#define assert_equals_float(a, b) fail_unless_equals_float(a, b)
+
+/**
+ * fail_unless_equals_pointer:
+ * @a: a pointer value or expression
+ * @b: a pointer value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this
+ * is not the case, printing both expressions and the values they
+ * evaluated to. This macro is for use in unit tests.
+ *
+ * Since: 1.2
+ */
+#define fail_unless_equals_pointer(a, b) \
+G_STMT_START { \
+ gpointer first = a; \
+ gpointer second = b; \
+ fail_unless(first == second, \
+ "'" #a "' (%p) is not equal to '" #b "' (%p)", first, second);\
+} G_STMT_END;
+
+/**
+ * assert_equals_pointer:
+ * @a: a pointer value or expression
+ * @b: a pointer value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this
+ * is not the case, printing both expressions and the values they
+ * evaluated to. This macro is for use in unit tests.
+ *
+ * Since: 1.2
+ */
+#define assert_equals_pointer(a, b) fail_unless_equals_pointer(a, b)
+
+/**
+ * fail_unless_equals_clocktime:
+ * @a: a #GstClockTime value or expression
+ * @b: a #GstClockTime value or expression
+ *
+ * This macro checks that @a and @b are equal and aborts if this is not the
+ * case, printing both expressions and the values they evaluated to. This
+ * macro is for use in unit tests.
+ */
+#define fail_unless_equals_clocktime(a, b) \
+G_STMT_START { \
+ GstClockTime first = a; \
+ GstClockTime second = b; \
+ fail_unless(first == second, \
+ "'" #a "' (%" GST_TIME_FORMAT") is not equal to '" #b"' (%" GST_TIME_FORMAT")", \
+ GST_TIME_ARGS (first), GST_TIME_ARGS (second)); \
+} G_STMT_END;
+
+/***
+ * thread test macros and variables
+ */
+GST_CHECK_API GList *thread_list;
+GST_CHECK_API GMutex mutex;
+GST_CHECK_API GCond start_cond; /* used to notify main thread of thread startups */
+GST_CHECK_API GCond sync_cond; /* used to synchronize all threads and main thread */
+
+#define MAIN_START_THREADS(count, function, data) \
+MAIN_INIT(); \
+MAIN_START_THREAD_FUNCTIONS(count, function, data); \
+MAIN_SYNCHRONIZE();
+
+#define MAIN_INIT() \
+G_STMT_START { \
+ g_mutex_init (&mutex); \
+ g_cond_init (&start_cond); \
+ g_cond_init (&sync_cond); \
+ _gst_check_threads_running = TRUE; \
+} G_STMT_END;
+
+#define MAIN_START_THREAD_FUNCTIONS(count, function, data) \
+G_STMT_START { \
+ int i; \
+ for (i = 0; i < count; ++i) { \
+ MAIN_START_THREAD_FUNCTION (i, function, data); \
+ } \
+} G_STMT_END;
+
+#define MAIN_START_THREAD_FUNCTION(i, function, data) \
+G_STMT_START { \
+ GThread *thread = NULL; \
+ GST_DEBUG ("MAIN: creating thread %d", i); \
+ g_mutex_lock (&mutex); \
+ thread = g_thread_try_new ("gst-check", \
+ (GThreadFunc) function, data, NULL); \
+ /* wait for thread to signal us that it's ready */ \
+ GST_DEBUG ("MAIN: waiting for thread %d", i); \
+ g_cond_wait (&start_cond, &mutex); \
+ g_mutex_unlock (&mutex); \
+ \
+ thread_list = g_list_append (thread_list, thread); \
+} G_STMT_END;
+
+
+#define MAIN_SYNCHRONIZE() \
+G_STMT_START { \
+ GST_DEBUG ("MAIN: synchronizing"); \
+ g_cond_broadcast (&sync_cond); \
+ GST_DEBUG ("MAIN: synchronized"); \
+} G_STMT_END;
+
+#define MAIN_STOP_THREADS() \
+G_STMT_START { \
+ _gst_check_threads_running = FALSE; \
+ \
+ /* join all threads */ \
+ GST_DEBUG ("MAIN: joining"); \
+ g_list_foreach (thread_list, (GFunc) g_thread_join, NULL); \
+ g_list_free (thread_list); \
+ thread_list = NULL; \
+ g_mutex_clear (&mutex); \
+ g_cond_clear (&start_cond); \
+ g_cond_clear (&sync_cond); \
+ GST_DEBUG ("MAIN: joined"); \
+} G_STMT_END;
+
+#define THREAD_START() \
+THREAD_STARTED(); \
+THREAD_SYNCHRONIZE();
+
+#define THREAD_STARTED() \
+G_STMT_START { \
+ /* signal main thread that we started */ \
+ GST_DEBUG ("THREAD %p: started", g_thread_self ()); \
+ g_mutex_lock (&mutex); \
+ g_cond_signal (&start_cond); \
+} G_STMT_END;
+
+#define THREAD_SYNCHRONIZE() \
+G_STMT_START { \
+ /* synchronize everyone */ \
+ GST_DEBUG ("THREAD %p: syncing", g_thread_self ()); \
+ fail_if (g_mutex_trylock (&mutex), \
+ "bug in unit test, mutex should be locked at this point");\
+ g_cond_wait (&sync_cond, &mutex); \
+ GST_DEBUG ("THREAD %p: synced", g_thread_self ()); \
+ g_mutex_unlock (&mutex); \
+} G_STMT_END;
+
+#define THREAD_SWITCH() \
+G_STMT_START { \
+ g_thread_yield (); \
+} G_STMT_END;
+
+#define THREAD_TEST_RUNNING() (!!_gst_check_threads_running)
+
+/* additional assertions */
+
+#if GST_DISABLE_GLIB_CHECKS
+#define ASSERT_CRITICAL(code)
+#else
+#define ASSERT_CRITICAL(code) \
+G_STMT_START { \
+ _gst_check_expecting_log = TRUE; \
+ _gst_check_raised_critical = FALSE; \
+ code; \
+ if (!_gst_check_raised_critical) \
+ _ck_assert_failed (__FILE__, __LINE__, \
+ "Expected g_critical, got nothing", NULL); \
+ _gst_check_expecting_log = FALSE; \
+} G_STMT_END
+#endif /* GST_DISABLE_GLIB_CHECKS */
+
+#define ASSERT_WARNING(code) \
+G_STMT_START { \
+ _gst_check_expecting_log = TRUE; \
+ _gst_check_raised_warning = FALSE; \
+ code; \
+ if (!_gst_check_raised_warning) \
+ _ck_assert_failed (__FILE__, __LINE__, \
+ "Expected g_warning, got nothing", NULL); \
+ _gst_check_expecting_log = FALSE; \
+} G_STMT_END
+
+
+#define ASSERT_OBJECT_REFCOUNT(object, name, value) \
+G_STMT_START { \
+ int rc; \
+ rc = GST_OBJECT_REFCOUNT_VALUE (object); \
+ fail_unless (rc == value, \
+ "%s (%p) refcount is %d instead of %d", \
+ name, object, rc, value); \
+} G_STMT_END
+
+#define ASSERT_OBJECT_REFCOUNT_BETWEEN(object, name, lower, upper) \
+G_STMT_START { \
+ int rc = GST_OBJECT_REFCOUNT_VALUE (object); \
+ int lo = lower; \
+ int hi = upper; \
+ \
+ fail_unless (rc >= lo, \
+ "%s (%p) refcount %d is smaller than %d", \
+ name, object, rc, lo); \
+ fail_unless (rc <= hi, \
+ "%s (%p) refcount %d is bigger than %d", \
+ name, object, rc, hi); \
+} G_STMT_END
+
+
+#define ASSERT_CAPS_REFCOUNT(caps, name, value) \
+ ASSERT_MINI_OBJECT_REFCOUNT(caps, name, value)
+
+#define ASSERT_BUFFER_REFCOUNT(buffer, name, value) \
+ ASSERT_MINI_OBJECT_REFCOUNT(buffer, name, value)
+
+#define ASSERT_MINI_OBJECT_REFCOUNT(miniobj, name, value) \
+G_STMT_START { \
+ int rc; \
+ rc = GST_MINI_OBJECT_REFCOUNT_VALUE (miniobj); \
+ fail_unless (rc == value, \
+ name " (%p) refcount is %d instead of %d", miniobj, rc, value); \
+} G_STMT_END
+
+#define ASSERT_SET_STATE(element, state, ret) \
+fail_unless (gst_element_set_state (GST_ELEMENT(element), \
+ state) == ret, \
+ "could not change state to " #state);
+
+#define GST_CHECK_MAIN(name) \
+int main (int argc, char **argv) \
+{ \
+ Suite *s; \
+ gst_check_init (&argc, &argv); \
+ s = name ## _suite (); \
+ return gst_check_run_suite (s, # name, __FILE__); \
+}
+
+/* Hack to allow run-time selection of unit tests to run via the
+ * GST_CHECKS environment variable (test function names globs, comma
+ * separated), or GST_CHECKS_IGNORE with the same semantics */
+
+GST_CHECK_API
+gboolean _gst_check_run_test_func (const gchar * func_name);
+
+static inline void
+__gst_tcase_add_test (TCase * tc, TFun tf, const char * fname, int signal,
+ int allowed_exit_value, int start, int end)
+{
+ if (_gst_check_list_tests) {
+ g_print ("Test: %s\n", fname);
+ return;
+ }
+
+ if (_gst_check_run_test_func (fname)) {
+ _tcase_add_test (tc, tf, fname, signal, allowed_exit_value, start, end);
+ }
+}
+
+#define _tcase_add_test __gst_tcase_add_test
+
+/* A special variant to add broken tests. These are normally skipped, but can be
+ * forced to run via GST_CHECKS */
+#define tcase_skip_broken_test(chain,test_func) \
+G_STMT_START { \
+ const char *env = g_getenv ("GST_CHECKS"); \
+ \
+ if (env != NULL && g_pattern_match_simple (env, G_STRINGIFY (test_func))) { \
+ tcase_add_test(chain,test_func); \
+ } else { \
+ g_printerr ("FIXME: skipping test %s because it's broken\n", G_STRINGIFY (test_func)); \
+ } \
+} G_STMT_END
+
+#define tcase_skip_broken_loop_test(chain,test_func,a,b) \
+ tcase_skip_broken_test (chain, test_func)
+
+#endif /* !__GI_SCANNER__ */
+
+G_END_DECLS
+
+#endif /* __GST_CHECK_H__ */
diff --git a/include/gst/check/gstconsistencychecker.h b/include/gst/check/gstconsistencychecker.h
new file mode 100644
index 0000000000..03ce583a8f
--- /dev/null
+++ b/include/gst/check/gstconsistencychecker.h
@@ -0,0 +1,52 @@
+/* GStreamer
+ *
+ * unit testing helper lib
+ *
+ * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CONSISTENCY_CHECKER_H__
+#define __GST_CONSISTENCY_CHECKER_H__
+
+#include <gst/check/gstcheck.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstStreamConsistency:
+ *
+ * Opaque consistency checker handle.
+ */
+typedef struct _GstStreamConsistency GstStreamConsistency;
+
+GST_CHECK_API
+GstStreamConsistency * gst_consistency_checker_new (GstPad * pad);
+
+GST_CHECK_API
+gboolean gst_consistency_checker_add_pad (GstStreamConsistency * consist,
+ GstPad * pad);
+
+GST_CHECK_API
+void gst_consistency_checker_reset (GstStreamConsistency * consist);
+
+GST_CHECK_API
+void gst_consistency_checker_free (GstStreamConsistency * consist);
+
+G_END_DECLS
+
+#endif /* __GST_CONSISTENCY_CHECKER_H__ */
diff --git a/include/gst/check/gstharness.h b/include/gst/check/gstharness.h
new file mode 100644
index 0000000000..160fdb01d8
--- /dev/null
+++ b/include/gst/check/gstharness.h
@@ -0,0 +1,474 @@
+/* GstHarness - A test-harness for GStreamer testing
+ *
+ * Copyright (C) 2012-2015 Pexip <pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_HARNESS_H__
+#define __GST_HARNESS_H__
+
+#include <gst/gst.h>
+#include <gst/check/gsttestclock.h>
+#include <gst/check/check-prelude.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstHarnessThread:
+ *
+ * Opaque handle representing a GstHarness stress testing thread.
+ *
+ * Since: 1.6
+ */
+typedef struct _GstHarnessThread GstHarnessThread;
+
+typedef struct _GstHarness GstHarness;
+typedef struct _GstHarnessPrivate GstHarnessPrivate;
+
+/**
+ * GstHarness:
+ * @element: the element inside the harness
+ * @srcpad: the internal harness source pad
+ * @sinkpad: the internal harness sink pad
+ * @src_harness: the source (input) harness (if any)
+ * @sink_harness: the sink (output) harness (if any)
+ *
+ * Since: 1.6
+ */
+struct _GstHarness {
+ GstElement * element;
+
+ GstPad * srcpad;
+ GstPad * sinkpad;
+
+ GstHarness * src_harness;
+ GstHarness * sink_harness;
+
+ /*< private >*/
+ GstHarnessPrivate * priv;
+};
+
+/* Harness creation */
+
+GST_CHECK_API
+GstHarness * gst_harness_new_empty (void);
+
+GST_CHECK_API
+void gst_harness_add_element_full (GstHarness * h,
+ GstElement * element,
+ GstStaticPadTemplate * hsrc,
+ const gchar * element_sinkpad_name,
+ GstStaticPadTemplate * hsink,
+ const gchar * element_srcpad_name);
+
+GST_CHECK_API
+GstHarness * gst_harness_new_full (GstElement * element,
+ GstStaticPadTemplate * hsrc,
+ const gchar * element_sinkpad_name,
+ GstStaticPadTemplate * hsink,
+ const gchar * element_srcpad_name);
+
+GST_CHECK_API
+GstHarness * gst_harness_new_with_element (GstElement * element,
+ const gchar * element_sinkpad_name,
+ const gchar * element_srcpad_name);
+
+GST_CHECK_API
+GstHarness * gst_harness_new_with_padnames (const gchar * element_name,
+ const gchar * element_sinkpad_name,
+ const gchar * element_srcpad_name);
+
+GST_CHECK_API
+GstHarness * gst_harness_new_with_templates (const gchar * element_name,
+ GstStaticPadTemplate * hsrc,
+ GstStaticPadTemplate * hsink);
+
+GST_CHECK_API
+GstHarness * gst_harness_new (const gchar * element_name);
+
+GST_CHECK_API
+GstHarness * gst_harness_new_parse (const gchar * launchline);
+
+GST_CHECK_API
+void gst_harness_add_parse (GstHarness * h, const gchar * launchline);
+
+GST_CHECK_API
+void gst_harness_teardown (GstHarness * h);
+
+GST_CHECK_API
+void gst_harness_add_element_src_pad (GstHarness * h, GstPad * srcpad);
+
+GST_CHECK_API
+void gst_harness_add_element_sink_pad (GstHarness * h, GstPad * sinkpad);
+
+/* Caps Functions */
+
+GST_CHECK_API
+void gst_harness_set_src_caps (GstHarness * h, GstCaps * caps);
+
+GST_CHECK_API
+void gst_harness_set_sink_caps (GstHarness * h, GstCaps * caps);
+
+GST_CHECK_API
+void gst_harness_set_caps (GstHarness * h, GstCaps * in, GstCaps * out);
+
+GST_CHECK_API
+void gst_harness_set_src_caps_str (GstHarness * h, const gchar * str);
+
+GST_CHECK_API
+void gst_harness_set_sink_caps_str (GstHarness * h, const gchar * str);
+
+GST_CHECK_API
+void gst_harness_set_caps_str (GstHarness * h,
+ const gchar * in,
+ const gchar * out);
+
+/* Clock Functions */
+
+GST_CHECK_API
+void gst_harness_use_systemclock (GstHarness * h);
+
+GST_CHECK_API
+void gst_harness_use_testclock (GstHarness * h);
+
+GST_CHECK_API
+GstTestClock * gst_harness_get_testclock (GstHarness * h);
+
+GST_CHECK_API
+gboolean gst_harness_set_time (GstHarness * h, GstClockTime time);
+
+GST_CHECK_API
+gboolean gst_harness_wait_for_clock_id_waits (GstHarness * h,
+ guint waits,
+ guint timeout);
+
+GST_CHECK_API
+gboolean gst_harness_crank_single_clock_wait (GstHarness * h);
+
+GST_CHECK_API
+gboolean gst_harness_crank_multiple_clock_waits (GstHarness * h,
+ guint waits);
+
+/* misc */
+
+GST_CHECK_API
+void gst_harness_play (GstHarness * h);
+
+GST_CHECK_API
+void gst_harness_set_blocking_push_mode (GstHarness * h);
+
+GST_CHECK_API
+void gst_harness_set_forwarding (GstHarness * h, gboolean forwarding);
+
+/* buffers */
+
+GST_CHECK_API
+GstBuffer * gst_harness_create_buffer (GstHarness * h, gsize size);
+
+GST_CHECK_API
+GstFlowReturn gst_harness_push (GstHarness * h, GstBuffer * buffer);
+
+GST_CHECK_API
+GstBuffer * gst_harness_pull (GstHarness * h);
+
+GST_CHECK_API
+GstBuffer * gst_harness_try_pull (GstHarness * h);
+
+GST_CHECK_API
+gboolean gst_harness_pull_until_eos (GstHarness * h, GstBuffer ** buf);
+
+GST_CHECK_API
+GstBuffer * gst_harness_push_and_pull (GstHarness * h, GstBuffer * buffer);
+
+GST_CHECK_API
+guint gst_harness_buffers_received (GstHarness * h);
+
+GST_CHECK_API
+guint gst_harness_buffers_in_queue (GstHarness * h);
+
+GST_CHECK_API
+void gst_harness_set_drop_buffers (GstHarness * h, gboolean drop_buffers);
+
+GST_CHECK_API
+void gst_harness_dump_to_file (GstHarness * h, const gchar * filename);
+
+GST_CHECK_API
+guint8 * gst_harness_take_all_data (GstHarness * h, gsize * size);
+
+GST_CHECK_API
+GstBuffer * gst_harness_take_all_data_as_buffer (GstHarness * h);
+
+GST_CHECK_API
+GBytes * gst_harness_take_all_data_as_bytes (GstHarness * h);
+
+GST_CHECK_API
+GstClockTime gst_harness_get_last_pushed_timestamp (GstHarness * h);
+
+/* downstream events */
+
+GST_CHECK_API
+gboolean gst_harness_push_event (GstHarness * h, GstEvent * event);
+
+GST_CHECK_API
+GstEvent * gst_harness_pull_event (GstHarness * h);
+
+GST_CHECK_API
+GstEvent * gst_harness_try_pull_event (GstHarness * h);
+
+GST_CHECK_API
+guint gst_harness_events_received (GstHarness * h);
+
+GST_CHECK_API
+guint gst_harness_events_in_queue (GstHarness * h);
+
+/* upstream events */
+
+GST_CHECK_API
+gboolean gst_harness_push_upstream_event (GstHarness * h, GstEvent * event);
+
+GST_CHECK_API
+GstEvent * gst_harness_pull_upstream_event (GstHarness * h);
+
+GST_CHECK_API
+GstEvent * gst_harness_try_pull_upstream_event (GstHarness * h);
+
+GST_CHECK_API
+guint gst_harness_upstream_events_received (GstHarness * h);
+
+GST_CHECK_API
+guint gst_harness_upstream_events_in_queue (GstHarness * h);
+
+/* latency */
+
+GST_CHECK_API
+GstClockTime gst_harness_query_latency (GstHarness * h);
+
+GST_CHECK_API
+void gst_harness_set_upstream_latency (GstHarness * h, GstClockTime latency);
+
+GST_CHECK_API
+void gst_harness_set_live (GstHarness * h, gboolean is_live);
+
+/* allocation query parameters */
+
+GST_CHECK_API
+void gst_harness_set_propose_allocator (GstHarness * h,
+ GstAllocator * allocator,
+ const GstAllocationParams * params);
+
+GST_CHECK_API
+void gst_harness_get_allocator (GstHarness * h,
+ GstAllocator ** allocator,
+ GstAllocationParams * params);
+
+GST_CHECK_API
+void gst_harness_add_propose_allocation_meta (GstHarness * h,
+ GType api,
+ const GstStructure * params);
+
+/* src-harness */
+
+GST_CHECK_API
+void gst_harness_add_src_harness (GstHarness * h,
+ GstHarness * src_harness,
+ gboolean has_clock_wait);
+
+GST_CHECK_API
+void gst_harness_add_src (GstHarness * h,
+ const gchar * src_element_name,
+ gboolean has_clock_wait);
+
+GST_CHECK_API
+void gst_harness_add_src_parse (GstHarness * h,
+ const gchar * launchline,
+ gboolean has_clock_wait);
+
+GST_CHECK_API
+GstFlowReturn gst_harness_push_from_src (GstHarness * h);
+
+GST_CHECK_API
+GstFlowReturn gst_harness_src_crank_and_push_many (GstHarness * h,
+ gint cranks,
+ gint pushes);
+
+GST_CHECK_API
+gboolean gst_harness_src_push_event (GstHarness * h);
+
+/* sink-harness */
+
+GST_CHECK_API
+void gst_harness_add_sink_harness (GstHarness * h,
+ GstHarness * sink_harness);
+
+GST_CHECK_API
+void gst_harness_add_sink (GstHarness * h,
+ const gchar * sink_element_name);
+
+GST_CHECK_API
+void gst_harness_add_sink_parse (GstHarness * h,
+ const gchar * launchline);
+
+GST_CHECK_API
+GstFlowReturn gst_harness_push_to_sink (GstHarness * h);
+
+GST_CHECK_API
+GstFlowReturn gst_harness_sink_push_many (GstHarness * h, gint pushes);
+
+/* convenience functions */
+
+GST_CHECK_API
+GstElement * gst_harness_find_element (GstHarness * h,
+ const gchar * element_name);
+
+GST_CHECK_API
+void gst_harness_set (GstHarness * h,
+ const gchar * element_name,
+ const gchar * first_property_name, ...) G_GNUC_NULL_TERMINATED;
+
+GST_CHECK_API
+void gst_harness_get (GstHarness * h,
+ const gchar * element_name,
+ const gchar * first_property_name, ...) G_GNUC_NULL_TERMINATED;
+
+GST_CHECK_API
+void gst_harness_add_probe (GstHarness * h,
+ const gchar * element_name,
+ const gchar * pad_name,
+ GstPadProbeType mask,
+ GstPadProbeCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy_data);
+
+/* Stress */
+
+GST_CHECK_API
+guint gst_harness_stress_thread_stop (GstHarnessThread * t);
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_custom_start (GstHarness * h,
+ GFunc init,
+ GFunc callback,
+ gpointer data,
+ gulong sleep);
+
+#define gst_harness_stress_statechange_start(h) \
+ gst_harness_stress_statechange_start_full (h, G_USEC_PER_SEC / 100)
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_statechange_start_full (GstHarness * h,
+ gulong sleep);
+
+#define gst_harness_stress_push_buffer_start(h, c, s, b) \
+ gst_harness_stress_push_buffer_start_full (h, c, s, b, 0)
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_push_buffer_start_full (GstHarness * h,
+ GstCaps * caps,
+ const GstSegment * segment,
+ GstBuffer * buf,
+ gulong sleep);
+
+/**
+ * GstHarnessPrepareBufferFunc:
+ * @h: a #GstHarness
+ * @data: user data
+ *
+ * Since: 1.6
+ */
+typedef GstBuffer * (*GstHarnessPrepareBufferFunc) (GstHarness * h, gpointer data);
+
+#define gst_harness_stress_push_buffer_with_cb_start(h, c, s, f, d, n) \
+ gst_harness_stress_push_buffer_with_cb_start_full (h, c, s, f, d, n, 0)
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_push_buffer_with_cb_start_full (GstHarness * h,
+ GstCaps * caps,
+ const GstSegment * segment,
+ GstHarnessPrepareBufferFunc func,
+ gpointer data,
+ GDestroyNotify notify,
+ gulong sleep);
+
+#define gst_harness_stress_push_event_start(h, e) \
+ gst_harness_stress_push_event_start_full (h, e, 0)
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_push_event_start_full (GstHarness * h,
+ GstEvent * event,
+ gulong sleep);
+
+/**
+ * GstHarnessPrepareEventFunc:
+ * @h: a #GstHarness
+ * @data: user data
+ *
+ * Since: 1.8
+ */
+typedef GstEvent * (*GstHarnessPrepareEventFunc) (GstHarness * h, gpointer data);
+
+#define gst_harness_stress_push_event_with_cb_start(h, f, d, n) \
+ gst_harness_stress_push_event_with_cb_start_full (h, f, d, n, 0)
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_push_event_with_cb_start_full (GstHarness * h,
+ GstHarnessPrepareEventFunc func,
+ gpointer data,
+ GDestroyNotify notify,
+ gulong sleep);
+
+#define gst_harness_stress_send_upstream_event_start(h, e) \
+ gst_harness_stress_push_upstream_event_start_full (h, e, 0)
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_push_upstream_event_start_full (GstHarness * h,
+ GstEvent * event,
+ gulong sleep);
+
+#define gst_harness_stress_send_upstream_event_with_cb_start(h, f, d, n) \
+ gst_harness_stress_push_upstream_event_with_cb_start_full (h, f, d, n, 0)
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_push_upstream_event_with_cb_start_full (GstHarness * h,
+ GstHarnessPrepareEventFunc func,
+ gpointer data,
+ GDestroyNotify notify,
+ gulong sleep);
+
+
+#define gst_harness_stress_property_start(h, n, v) \
+ gst_harness_stress_property_start_full (h, n, v, G_USEC_PER_SEC / 1000)
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_property_start_full (GstHarness * h,
+ const gchar * name,
+ const GValue * value,
+ gulong sleep);
+
+#define gst_harness_stress_requestpad_start(h, t, n, c, r) \
+ gst_harness_stress_requestpad_start_full (h, t, n, c, r, G_USEC_PER_SEC / 100)
+
+GST_CHECK_API
+GstHarnessThread * gst_harness_stress_requestpad_start_full (GstHarness * h,
+ GstPadTemplate * templ,
+ const gchar * name,
+ GstCaps * caps,
+ gboolean release,
+ gulong sleep);
+
+G_END_DECLS
+
+#endif /* __GST_HARNESS_H__ */
diff --git a/include/gst/check/gsttestclock.h b/include/gst/check/gsttestclock.h
new file mode 100644
index 0000000000..a1c1f5a88b
--- /dev/null
+++ b/include/gst/check/gsttestclock.h
@@ -0,0 +1,148 @@
+/* GstTestClock - A deterministic clock for GStreamer unit tests
+ *
+ * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+ * Copyright (C) 2012 Sebastian Rasmussen <sebastian.rasmussen@axis.com>
+ * Copyright (C) 2012 Havard Graff <havard@pexip.com>
+ * Copyright (C) 2013 Haakon Sporsheim <haakon@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_TEST_CLOCK_H__
+#define __GST_TEST_CLOCK_H__
+
+#include <gst/gst.h>
+#include <gst/check/check-prelude.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_TEST_CLOCK (gst_test_clock_get_type ())
+#define GST_TEST_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ GST_TYPE_TEST_CLOCK, GstTestClock))
+#define GST_IS_TEST_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ GST_TYPE_TEST_CLOCK))
+#define GST_TEST_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ GST_TYPE_TEST_CLOCK, GstTestClockClass))
+#define GST_IS_TEST_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE (\
+ (klass), GST_TYPE_TEST_CLOCK))
+#define GST_TEST_CLOCK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS (\
+ (obj), GST_TYPE_TEST_CLOCK, GstTestClockClass))
+#define GST_TEST_CLOCK_CAST(obj) ((GstTestClock*)(obj))
+
+typedef struct _GstTestClock GstTestClock;
+typedef struct _GstTestClockClass GstTestClockClass;
+typedef struct _GstTestClockPrivate GstTestClockPrivate;
+
+/**
+ * GstTestClock:
+ *
+ * A #GstTestClock structure which is based on a #GstClock along with some
+ * private data.
+ *
+ * Since: 1.2
+ */
+struct _GstTestClock
+{
+ GstClock parent;
+
+ /*< private >*/
+ GstTestClockPrivate *priv;
+};
+
+/**
+ * GstTestClockClass:
+ * @parent_class: the parent class structure
+ *
+ * The class of a #GstTestClock, which has no virtual methods to override.
+ *
+ * Since: 1.2
+ */
+struct _GstTestClockClass
+{
+ GstClockClass parent_class;
+};
+
+GST_CHECK_API
+GType gst_test_clock_get_type (void);
+
+GST_CHECK_API
+GstClock * gst_test_clock_new (void);
+
+GST_CHECK_API
+GstClock * gst_test_clock_new_with_start_time (GstClockTime start_time);
+
+GST_CHECK_API
+void gst_test_clock_set_time (GstTestClock * test_clock,
+ GstClockTime new_time);
+
+GST_CHECK_API
+void gst_test_clock_advance_time (GstTestClock * test_clock,
+ GstClockTimeDiff delta);
+
+GST_CHECK_API
+guint gst_test_clock_peek_id_count (GstTestClock * test_clock);
+
+GST_CHECK_API
+gboolean gst_test_clock_has_id (GstTestClock * test_clock, GstClockID id);
+
+GST_CHECK_API
+gboolean gst_test_clock_peek_next_pending_id (GstTestClock * test_clock,
+ GstClockID * pending_id);
+
+GST_CHECK_API
+void gst_test_clock_wait_for_next_pending_id (GstTestClock * test_clock,
+ GstClockID * pending_id);
+
+GST_CHECK_DEPRECATED_FOR(gst_test_clock_wait_for_multiple_pending_ids)
+void gst_test_clock_wait_for_pending_id_count (GstTestClock * test_clock,
+ guint count);
+
+GST_CHECK_API
+GstClockID gst_test_clock_process_next_clock_id (GstTestClock * test_clock);
+
+GST_CHECK_API
+GstClockTime gst_test_clock_get_next_entry_time (GstTestClock * test_clock);
+
+GST_CHECK_API
+void gst_test_clock_wait_for_multiple_pending_ids (GstTestClock * test_clock,
+ guint count,
+ GList ** pending_list);
+
+GST_CHECK_API
+gboolean gst_test_clock_timed_wait_for_multiple_pending_ids (GstTestClock * test_clock,
+ guint count,
+ guint timeout_ms,
+ GList ** pending_list);
+
+GST_CHECK_API
+gboolean gst_test_clock_process_id (GstTestClock * test_clock,
+ GstClockID pending_id);
+
+GST_CHECK_API
+guint gst_test_clock_process_id_list (GstTestClock * test_clock,
+ const GList * pending_list);
+
+GST_CHECK_API
+GstClockTime gst_test_clock_id_list_get_latest_time (const GList * pending_list);
+
+GST_CHECK_API
+gboolean gst_test_clock_crank (GstTestClock * test_clock);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstTestClock, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* __GST_TEST_CLOCK_H__ */
diff --git a/include/gst/check/internal-check.h b/include/gst/check/internal-check.h
new file mode 100644
index 0000000000..52c8b766e2
--- /dev/null
+++ b/include/gst/check/internal-check.h
@@ -0,0 +1,1328 @@
+/*-*- mode:C; -*- */
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef CHECK_H
+#define CHECK_H
+
+#include <stddef.h>
+#include <string.h>
+
+/*
+ Macros and functions starting with _ (underscore) are internal and
+ may change without notice. You have been warned!.
+*/
+
+
+#ifdef __cplusplus
+#define CK_CPPSTART extern "C" {
+#define CK_CPPEND }
+CK_CPPSTART
+#endif
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define GCC_VERSION_AT_LEAST(major, minor) \
+((__GNUC__ > (major)) || \
+ (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+#else
+#define GCC_VERSION_AT_LEAST(major, minor) 0
+#endif
+#if GCC_VERSION_AT_LEAST(2,95)
+#define CK_ATTRIBUTE_UNUSED __attribute__ ((unused))
+#else
+#define CK_ATTRIBUTE_UNUSED
+#endif /* GCC 2.95 */
+#if GCC_VERSION_AT_LEAST(2,5)
+#define CK_ATTRIBUTE_NORETURN __attribute__ ((noreturn))
+#else
+#define CK_ATTRIBUTE_NORETURN
+#endif /* GCC 2.5 */
+#include <sys/types.h>
+
+/*
+ * Used to create the linker script for hiding lib-local symbols. Shall
+ * be put directly in front of the exported symbol.
+ */
+#define CK_EXPORT
+
+/*
+ * Used for MSVC to create the export attribute
+ * CK_DLL_EXP is defined during the compilation of the library
+ * on the command line.
+ */
+#ifndef CK_DLL_EXP
+# if defined(_MSC_VER)
+# define CK_DLL_EXP __declspec(dllimport)
+# else
+# define CK_DLL_EXP extern
+# endif
+#endif
+
+/* check version numbers */
+#define CHECK_MAJOR_VERSION (0)
+#define CHECK_MINOR_VERSION (9)
+#define CHECK_MICRO_VERSION (14)
+CK_DLL_EXP /*extern*/ int CK_EXPORT check_major_version;
+CK_DLL_EXP /*extern*/ int CK_EXPORT check_minor_version;
+CK_DLL_EXP /*extern*/ int CK_EXPORT check_micro_version;
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+#if defined(_MSC_VER)
+#define pid_t int
+#endif
+
+/**
+ * Type for a test case
+ *
+ * A TCase represents a test case. Create with tcase_create, free
+ * with tcase_free. For the moment, test cases can only be run
+ * through a suite
+*/
+typedef struct TCase TCase;
+
+/**
+ * Type for a test function
+ */
+typedef void (*TFun) (int);
+
+/**
+ * Type for a setup/teardown function
+ */
+typedef void (*SFun) (void);
+
+/**
+ * Type for a test suite
+ */
+typedef struct Suite Suite;
+
+/**
+ * Creates a test suite with the given name.
+ *
+ * Create a suite, which will contain test cases. Once
+ * created, use suite_add_tcase() to add test cases.
+ * When finished, create a suite runner from the
+ * suite using srunner_create()
+ *
+ * @param name name of the suite
+ *
+ * @return suite
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP Suite *CK_EXPORT suite_create (const char *name);
+
+/**
+ * Determines whether a given test suite contains a case named after a
+ * given string.
+ *
+ * @param s suite to check
+ * @param tcname test case to look for
+ *
+ * @return 1 iff the given test case is within the given suite;
+ * 0 otherwise
+ *
+ * @since 0.9.9
+ */
+CK_DLL_EXP int CK_EXPORT suite_tcase (Suite * s, const char *tcname);
+
+/**
+ * Add a test case to a suite.
+ *
+ * Note that if the TCase has already been added attempting
+ * to add it again will be ignored.
+ *
+ * @param s suite to add test case to
+ * @param tc test case to add to suite
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP void CK_EXPORT suite_add_tcase (Suite * s, TCase * tc);
+
+/**
+ * Create a test case.
+ *
+ * Once created, tests can be added with the tcase_add_test()
+ * function, and the test case assigned to a suite with the
+ * suite_add_tcase() function.
+ *
+ * @param name name of the test case
+ *
+ * @return test case containing no tests
+ *
+ * @since 0.6.0
+ * */
+CK_DLL_EXP TCase *CK_EXPORT tcase_create (const char *name);
+
+/**
+ * Associate a test case with certain tags.
+ * Replaces any existing tags with the new set.
+ *
+ * @param tc the test case
+ *
+ * @param tags string containing arbitrary tags separated by spaces.
+ * This will be copied. Passing NULL clears all tags.
+ *
+ * @since 0.11.0
+ * */
+CK_DLL_EXP void CK_EXPORT tcase_set_tags (TCase * tc, const char *tags);
+/**
+ * Add a test function to a test case
+ *
+ * @param tc test case to add test to
+ * @param tf test function to add to test case
+ *
+ * @since 0.6.0
+ * */
+#define tcase_add_test(tc,tf) tcase_add_test_raise_signal(tc,tf,0)
+
+/**
+ * Add a test function with signal handling to a test case
+ *
+ * The added test is expected to terminate by throwing the given signal
+ *
+ * @param tc test case to add test to
+ * @param tf test function to add to test case
+ * @param signal expected signal for test function to throw in order for
+ * the test to be considered passing
+ *
+ * @since 0.9.2
+ * */
+#define tcase_add_test_raise_signal(tc,tf,signal) \
+ _tcase_add_test((tc),(tf),"" # tf "",(signal), 0, 0, 1)
+
+/**
+ * Add a test function with an expected exit value to a test case
+ *
+ * The added test is expected to terminate by exiting with the given value
+ *
+ * @param tc test case to add test to
+ * @param tf test function to add to test case
+ * @param expected_exit_value exit value for test function to return in
+ * order for the test to be considered passing
+ *
+ * @since 0.9.7
+ */
+#define tcase_add_exit_test(tc, tf, expected_exit_value) \
+ _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),0,1)
+
+/**
+ * Add a looping test function to a test case
+ *
+ * The test will be called in a for(i = s; i < e; i++) loop with each
+ * iteration being executed in a new context. The loop variable 'i' is
+ * available in the test.
+ *
+ * @param tc test case to add test to
+ * @param tf function to add to test case
+ * @param s starting index for value "i" in test
+ * @param e ending index for value "i" in test
+ *
+ * @since 0.9.4
+ */
+#define tcase_add_loop_test(tc,tf,s,e) \
+ _tcase_add_test((tc),(tf),"" # tf "",0,0,(s),(e))
+
+/**
+ * Add a looping test function with signal handling to a test case
+ *
+ * The test will be called in a for(i = s; i < e; i++) loop with each
+ * iteration being executed in a new context. The loop variable 'i' is
+ * available in the test.
+ *
+ * The added test is expected to terminate by throwing the given signal
+ *
+ * @param tc test case to add test to
+ * @param tf function to add to test case
+ * @param signal expected signal for test function to throw in order for
+ * the test to be considered passing
+ * @param s starting index for value "i" in test
+ * @param e ending index for value "i" in test
+ *
+ * @since 0.9.5
+ */
+#define tcase_add_loop_test_raise_signal(tc,tf,signal,s,e) \
+ _tcase_add_test((tc),(tf),"" # tf "",(signal),0,(s),(e))
+
+/**
+ * Add a looping test function with an expected exit value to a test case
+ *
+ * The test will be called in a for(i = s; i < e; i++) loop with each
+ * iteration being executed in a new context. The loop variable 'i' is
+ * available in the test.
+ *
+ * The added test is expected to terminate by exiting with the given value
+ *
+ * @param tc test case to add test to
+ * @param tf function to add to test case
+ * @param expected_exit_value exit value for test function to return in
+ * order for the test to be considered passing
+ * @param s starting index for value "i" in test
+ * @param e ending index for value "i" in test
+ *
+ * @since 0.9.7
+ */
+#define tcase_add_loop_exit_test(tc,tf,expected_exit_value,s,e) \
+ _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),(s),(e))
+
+/* Add a test function to a test case
+ (function version -- use this when the macro won't work
+*/
+CK_DLL_EXP void CK_EXPORT _tcase_add_test (TCase * tc, TFun tf,
+ const char *fname, int _signal, int allowed_exit_value, int start, int end);
+
+/**
+ * Add unchecked fixture setup/teardown functions to a test case
+ *
+ * Unchecked fixture functions are run at the start and end of the
+ * test case, and not before and after unit tests. Further,
+ * unchecked fixture functions are not run in a separate address space,
+ * like test functions, and so must not exit or signal (e.g.,
+ * segfault).
+ *
+ * Also, when run in CK_NOFORK mode, unchecked fixture functions may
+ * lead to different unit test behavior if unit tests change data
+ * setup by the fixture functions.
+ *
+ * Note that if a setup function fails, the remaining setup functions
+ * will be omitted, as will the test case and the teardown functions.
+ * If a teardown function fails the remaining teardown functions will be
+ * omitted.
+ *
+ * @param tc test case to add unchecked fixture setup/teardown to
+ * @param setup function to add to be executed before the test case;
+ * if NULL no setup function is added
+ * @param teardown function to add to be executed after the test case;
+ * if NULL no teardown function is added
+ * @since 0.8.0
+ */
+CK_DLL_EXP void CK_EXPORT tcase_add_unchecked_fixture (TCase * tc, SFun setup,
+ SFun teardown);
+
+/**
+ * Add checked fixture setup/teardown functions to a test case
+ *
+ * Checked fixture functions are run before and after each unit test inside
+ * of the address space of the test. Thus, if using CK_FORK
+ * mode the separate process running the unit test will survive signals
+ * or unexpected exits in the fixture function. Also, if the setup
+ * function is idempotent, unit test behavior will be the same in
+ * CK_FORK and CK_NOFORK modes.
+ *
+ * However, since fixture functions are run before and after each unit
+ * test, they should not be expensive code.
+ *
+ * Note that if a setup function fails, the remaining setup functions
+ * will be omitted, as will the test and the teardown functions. If a
+ * teardown function fails the remaining teardown functions will be
+ * omitted.
+ *
+ * @param tc test case to add checked fixture setup/teardown to
+ * @param setup function to add to be executed before each unit test in
+ * the test case; if NULL no setup function is added
+ * @param teardown function to add to be executed after each unit test in
+ * the test case; if NULL no teardown function is added
+ *
+ * @since 0.8.0
+*/
+CK_DLL_EXP void CK_EXPORT tcase_add_checked_fixture (TCase * tc, SFun setup,
+ SFun teardown);
+
+/**
+ * Set the timeout for all tests in a test case.
+ *
+ * A test that lasts longer than the timeout (in seconds) will be killed
+ * and thus fail with an error.
+ *
+ * If not set, the default timeout is one assigned at compile time. If
+ * the environment variable CK_DEFAULT_TIMEOUT is defined and no timeout
+ * is set, the value in the environment variable is used.
+ *
+ * If Check is compile without fork() support this call is ignored,
+ * as timeouts are not possible.
+ *
+ * @param tc test case to assign timeout to
+ * @param timeout to use, in seconds. If the value contains a decimal
+ * portion, but no high resolution timer is available,
+ * the value is rounded up to the nearest second.
+ *
+ * @since 0.9.2
+ */
+CK_DLL_EXP void CK_EXPORT tcase_set_timeout (TCase * tc, double timeout);
+
+/* Internal function to mark the start of a test function */
+CK_DLL_EXP void CK_EXPORT tcase_fn_start (const char *fname, const char *file,
+ int line);
+
+/**
+ * Start a unit test with START_TEST(unit_name), end with END_TEST.
+ *
+ * One must use braces within a START_/END_ pair to declare new variables
+ *
+ * @since 0.6.0
+ */
+#define START_TEST(__testname)\
+static void __testname (int _i CK_ATTRIBUTE_UNUSED)\
+{\
+ tcase_fn_start (""# __testname, __FILE__, __LINE__);
+
+/**
+ * End a unit test
+ *
+ * @since 0.6.0
+ */
+#define END_TEST }
+
+/*
+ * Fail the test case unless expr is false
+ *
+ * This call is deprecated.
+ */
+#define fail_unless ck_assert_msg
+
+/*
+ * Fail the test case if expr is false
+ *
+ * This call is deprecated.
+ *
+ * NOTE: The space before the comma sign before ## is essential to be compatible
+ * with gcc 2.95.3 and earlier.
+ * FIXME: these macros may conflict with C89 if expr is
+ * FIXME: strcmp (str1, str2) due to excessive string length.
+ */
+#define fail_if(expr, ...)\
+ (expr) ? \
+ _ck_assert_failed(__FILE__, __LINE__, "Failure '"#expr"' occurred" , ## __VA_ARGS__, NULL) \
+ : _mark_point(__FILE__, __LINE__)
+
+/*
+ * Fail the test
+ *
+ * This call is deprecated.
+ */
+#define fail ck_abort_msg
+
+/*
+ * This is called whenever an assertion fails.
+ */
+CK_DLL_EXP void CK_EXPORT
+_ck_assert_failed (const char *file, int line, const char *expr, ...)
+ CK_ATTRIBUTE_NORETURN;
+
+/**
+ * Fail the test if expression is false
+ *
+ * @param expr expression to evaluate
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert(expr) ck_assert_msg(expr, NULL)
+
+/* The space before the comma sign before ## is essential to be compatible
+ with gcc 2.95.3 and earlier.
+*/
+/**
+ * Fail the test if the expression is false; print message on failure
+ *
+ * @param expr expression to evaluate
+ * @param ... message to print (in printf format) if expression is false
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_msg(expr, ...) \
+ (expr) ? \
+ _mark_point(__FILE__, __LINE__) : \
+ _ck_assert_failed(__FILE__, __LINE__, "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL)
+
+/**
+ * Unconditionally fail the test
+ *
+ * @note Once called, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_abort() ck_abort_msg(NULL)
+/**
+ * Unconditionally fail the test; print a message
+ *
+ * @param ... message to print (in printf format)
+ *
+ * @note Once called, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_abort_msg(...) _ck_assert_failed(__FILE__, __LINE__, "Failed" , ## __VA_ARGS__, NULL)
+
+/* Signed and unsigned integer comparison macros with improved output compared to ck_assert(). */
+/* OP may be any comparison operator. */
+#define _ck_assert_int(X, OP, Y) do { \
+ gint64 _ck_x = (X); \
+ gint64 _ck_y = (Y); \
+ ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: " \
+ "%s==%" G_GINT64_FORMAT ", %s==%" G_GINT64_FORMAT, #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
+} while (0)
+
+/**
+ * Check two signed integers to determine if X==Y
+ *
+ * If not X==Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
+/**
+ * Check two signed integers to determine if X!=Y
+ *
+ * If not X!=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_int_ne(X, Y) _ck_assert_int(X, !=, Y)
+/**
+ * Check two signed integers to determine if X<Y
+ *
+ * If not X<Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_int_lt(X, Y) _ck_assert_int(X, <, Y)
+/**
+ * Check two signed integers to determine if X<=Y
+ *
+ * If not X<=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_int_le(X, Y) _ck_assert_int(X, <=, Y)
+/**
+ * Check two signed integers to determine if X>Y
+ *
+ * If not X>Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_int_gt(X, Y) _ck_assert_int(X, >, Y)
+/**
+ * Check two signed integers to determine if X>=Y
+ *
+ * If not X>=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_int_ge(X, Y) _ck_assert_int(X, >=, Y)
+
+#define _ck_assert_uint(X, OP, Y) do { \
+ guint64 _ck_x = (X); \
+ guint64 _ck_y = (Y); \
+ ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: " \
+ "%s==%" G_GUINT64_FORMAT ", %s==%" G_GUINT64_FORMAT, #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
+} while (0)
+/**
+ * Check two unsigned integers to determine if X==Y
+ *
+ * If not X==Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_eq(X, Y) _ck_assert_uint(X, ==, Y)
+/**
+ * Check two unsigned integers to determine if X!=Y
+ *
+ * If not X!=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_ne(X, Y) _ck_assert_uint(X, !=, Y)
+/**
+ * Check two unsigned integers to determine if X<Y
+ *
+ * If not X<Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_lt(X, Y) _ck_assert_uint(X, <, Y)
+/**
+ * Check two unsigned integers to determine if X<=Y
+ *
+ * If not X<=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_le(X, Y) _ck_assert_uint(X, <=, Y)
+/**
+ * Check two unsigned integers to determine if X>Y
+ *
+ * If not X>Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_gt(X, Y) _ck_assert_uint(X, >, Y)
+/**
+ * Check two unsigned integers to determine if X>=Y
+ *
+ * If not X>=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_ge(X, Y) _ck_assert_uint(X, >=, Y)
+
+/* String comparison macros with improved output compared to ck_assert() */
+/* OP might be any operator that can be used in '0 OP strcmp(X,Y)' comparison */
+/* The x and y parameter swap in strcmp() is needed to handle >, >=, <, <= operators */
+#define _ck_assert_str(X, OP, Y) do { \
+ const char* _ck_x = (X); \
+ const char* _ck_y = (Y); \
+ ck_assert_msg(0 OP strcmp(_ck_y, _ck_x), \
+ "Assertion '%s' failed: %s==\"%s\", %s==\"%s\"", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
+} while (0)
+/**
+ * Check two strings to determine if 0==strcmp(X,Y)
+ *
+ * If not 0==strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_str_eq(X, Y) _ck_assert_str(X, ==, Y)
+/**
+ * Check two strings to determine if 0!=strcmp(X,Y)
+ *
+ * If not 0!=strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_str_ne(X, Y) _ck_assert_str(X, !=, Y)
+/**
+ * Check two strings to determine if 0<strcmp(X,Y), (e.g. strcmp(X,Y)>0)
+ *
+ * If not 0<strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_str_lt(X, Y) _ck_assert_str(X, <, Y)
+/**
+ * Check two strings to determine if 0<=strcmp(X,Y) (e.g. strcmp(X,Y)>=0)
+ *
+ * If not 0<=strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_str_le(X, Y) _ck_assert_str(X, <=, Y)
+/**
+ * Check two strings to determine if 0<strcmp(X,Y) (e.g. strcmp(X,Y)>0)
+ *
+ * If not 0<strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_str_gt(X, Y) _ck_assert_str(X, >, Y)
+/**
+ * Check two strings to determine if 0>=strcmp(X,Y) (e.g. strcmp(X,Y)<=0)
+ *
+ * If not 0>=strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_str_ge(X, Y) _ck_assert_str(X, >=, Y)
+
+/* Pointer comparison macros with improved output compared to ck_assert(). */
+/* OP may only be == or != */
+#define _ck_assert_ptr(X, OP, Y) do { \
+ const void* _ck_x = (X); \
+ const void* _ck_y = (Y); \
+ ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s==%#x, %s==%#x", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
+} while (0)
+
+/**
+ * Check if two pointers are equal.
+ *
+ * If the two passed pointers are not equal, the test
+ * fails.
+ *
+ * @param X pointer
+ * @param Y pointer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_ptr_eq(X, Y) _ck_assert_ptr(X, ==, Y)
+
+/**
+ * Check if two pointers are not.
+ *
+ * If the two passed pointers are equal, the test fails.
+ *
+ * @param X pointer
+ * @param Y pointer to compare against X
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_ptr_ne(X, Y) _ck_assert_ptr(X, !=, Y)
+
+/**
+ * Mark the last point reached in a unit test.
+ *
+ * If the test throws a signal or exits, the location noted with the
+ * failure is the last location of a ck_assert*() or ck_abort() call.
+ * Use mark_point() to record intermediate locations (useful for tracking down
+ * crashes or exits).
+ *
+ * @since 0.6.0
+*/
+#define mark_point() _mark_point(__FILE__,__LINE__)
+
+/* Non macro version of #mark_point */
+CK_DLL_EXP void CK_EXPORT _mark_point (const char *file, int line);
+
+/**
+ * Enum describing the possible results of a test
+ */
+enum test_result
+{
+ CK_TEST_RESULT_INVALID, /**< Default value; should not encounter this */
+ CK_PASS, /**< Test passed */
+ CK_FAILURE, /**< Test completed but failed */
+ CK_ERROR /**< Test failed to complete
+ (unexpected signal or non-zero early exit) */
+};
+
+/**
+ * Enum specifying the verbosity of output a SRunner should produce
+ */
+enum print_output
+{
+ CK_SILENT, /**< No output */
+ CK_MINIMAL, /**< Only summary output */
+ CK_NORMAL, /**< All failed tests */
+ CK_VERBOSE, /**< All tests */
+ CK_ENV, /**< Look at environment var CK_VERBOSITY
+ for what verbosity to use, which can be
+ either "silent", "minimal", "normal",
+ or "verbose". If the environment variable
+ is not set, then CK_NORMAL will be used.*/
+#if 0
+ CK_SUBUNIT, /**< Run as a subunit child process */
+#endif
+ CK_LAST /**< Not a valid option */
+};
+
+/**
+ * Holds state for a running of a test suite
+ */
+typedef struct SRunner SRunner;
+
+/**
+ * Opaque type for a test failure
+ */
+typedef struct TestResult TestResult;
+
+/**
+ * Enum representing the types of contexts for a test
+ */
+enum ck_result_ctx
+{
+ CK_CTX_INVALID, /**< Default value; should not encounter this */
+ CK_CTX_SETUP, /**< Setup before a test */
+ CK_CTX_TEST, /**< Body of test itself */
+ CK_CTX_TEARDOWN /**< Teardown after a test */
+};
+
+/**
+ * Retrieve type of result that the given test result represents.
+ *
+ * This is a member of test_result, and can represent a
+ * pass, failure, or error.
+ *
+ * @param tr test result to retrieve result from
+ *
+ * @return result of given test
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP int CK_EXPORT tr_rtype (TestResult * tr);
+
+/**
+ * Retrieve context in which the result occurred for the given test result.
+ *
+ * The types of contents include the test setup, teardown, or the
+ * body of the test itself.
+ *
+ * @param tr test result to retrieve context from
+ *
+ * @return context to which the given test result applies
+ *
+ * @since 0.8.0
+ */
+CK_DLL_EXP enum ck_result_ctx CK_EXPORT tr_ctx (TestResult * tr);
+
+/**
+ * Retrieve failure message from test result, if applicable.
+ *
+ * @return pointer to a message, if one exists. NULL otherwise.
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP const char *CK_EXPORT tr_msg (TestResult * tr);
+
+/**
+ * Retrieve line number at which a failure occurred, if applicable.
+ *
+ * @return If the test resulted in a failure, returns the line number
+ * that the failure occurred on; otherwise returns -1.
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP int CK_EXPORT tr_lno (TestResult * tr);
+
+/**
+ * Retrieve file name at which a failure occurred, if applicable.
+ *
+ * @return If the test resulted in a failure, returns a string
+ * containing the name of the file where the failure
+ * occurred; otherwise returns NULL.
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP const char *CK_EXPORT tr_lfile (TestResult * tr);
+
+/**
+ * Retrieve test case name in which a failure occurred, if applicable.
+ *
+ * @return If the test resulted in a failure, returns a string
+ * containing the name of the test suite where the failure
+ * occurred; otherwise returns NULL.
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP const char *CK_EXPORT tr_tcname (TestResult * tr);
+
+/**
+ * Creates a suite runner for the given suite.
+ *
+ * Once created, additional suites can be added to the
+ * suite runner using srunner_add_suite(), and the suite runner can be
+ * run with srunner_run_all(). Once finished, the suite runner
+ * must be freed with srunner_free().
+ *
+ * @param s suite to generate a suite runner for
+ *
+ * @return suite runner for the given suite
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP SRunner *CK_EXPORT srunner_create (Suite * s);
+
+/**
+ * Add an additional suite to a suite runner.
+ *
+ * The first suite in a suite runner is always added in srunner_create().
+ * This call adds additional suites to a suite runner.
+ *
+ * @param sr suite runner to add the given suite
+ * @param s suite to add to the given suite runner
+ *
+ * @since 0.7.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_add_suite (SRunner * sr, Suite * s);
+
+/**
+ * Frees a suite runner, including all contained suite and test cases.
+ *
+ * This call is responsible for freeing all resources related to a
+ * suite runner and all contained suites and test cases. Suite and
+ * test cases need not be freed individually, as this call handles that.
+ *
+ * @param sr suite runner to free
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_free (SRunner * sr);
+
+/**
+ * Runs a suite runner and all contained suite, printing results to
+ * stdout as specified by the print_mode.
+ *
+ * In addition to running all suites, if the suite runner has been
+ * configured to output to a log, that is also performed.
+ *
+ * Note that if the CK_RUN_CASE, CK_RUN_SUITE, CK_INCLUDE_TAGS and/or
+ * CK_EXCLUDE_TAGS environment variables are defined, then only the
+ * named suites or test cases will run.
+ *
+ * @param sr suite runner to run all suites from
+ * @param print_mode the verbosity in which to report results to stdout
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_run_all (SRunner * sr,
+ enum print_output print_mode);
+
+/**
+ * Run a specific suite or test case from a suite runner, printing results
+ * to stdout as specified by the print_mode.
+ *
+ * In addition to running any applicable suites or test cases, if the
+ * suite runner has been configured to output to a log, that is also
+ * performed.
+ *
+ * Note that if the sname and tcname parameters are passed as null
+ * then the function will fallback to using the environment variables
+ * CK_RUN_SUITE and CK_RUN_CASE respectively in order to select the
+ * suite/cases.
+ *
+ * Similarly if the CK_INCLUDE_TAGS and/or CK_EXCLUDE_TAGS environment
+ * variables are defined then these will further filter the test cases
+ * (see srunner_run_tagged, below).
+ *
+ * @param sr suite runner where the given suite or test case must be
+ * @param sname suite name to run. A NULL means use the value of the
+ * environment variable CK_RUN_SUITE if set, otherwise run "any/every
+ * suite".
+ * @param tcname test case name to run. A NULL means use the value of
+ * the environment variable CK_RUN_CASE if set, otherwise run
+ * "any/every case".
+ * @param print_mode the verbosity in which to report results to stdout
+ *
+ * @since 0.9.9
+ */
+CK_DLL_EXP void CK_EXPORT srunner_run (SRunner * sr, const char *sname,
+ const char *tcname, enum print_output print_mode);
+
+
+/**
+ * Run a specific suite or test case or testcases with specific tags
+ * from a suite runner, printing results to stdout as specified by the
+ * print_mode.
+ *
+ * In addition to running any applicable suites or test cases, if the
+ * suite runner has been configured to output to a log, that is also
+ * performed.
+ *
+ * Note that if sname, tcname, include_tags, exclude_tags parameters
+ * are passed as NULL then if the environment variables CK_RUN_SUITE,
+ * CK_RUN_CASE, CK_INCLUDE_TAGS, CK_EXCLUDE_TAGS are defined then these
+ * values will be used instead.
+ *
+ * @param sr suite runner where the given suite or test case must be
+ * @param sname suite name to run. A NULL means use the value of the
+ * environment variable CK_RUN_SUITE if set, otherwise run "any/every
+ * suite".
+ * @param tcname test case name to run. A NULL means use the value of
+ * the environment variable CK_RUN_CASE if set, otherwise run
+ * "any/every case".
+ * @param include_tags space separate list of tags. Only run test
+ * cases that share one of these tags. A NULL means use the value of
+ * the environment variable CK_INCLUDE_TAGS if set, otherwise run
+ * "any/every test case".
+ * @param exclude_tags space separate list of tags. Only run test
+ * cases that do not share one of these tags even if they are selected
+ * by an included tag. A NULL means use the value of the environment
+ * variable CK_EXCLUDE_TAGS if set, otherwise run "any/every test
+ * case".
+ * @param print_mode the verbosity in which to report results to stdout
+ *
+ * @since 0.11.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_run_tagged (SRunner * sr, const char *sname,
+ const char *tcname,
+ const char *include_tags,
+ const char *exclude_tags, enum print_output print_mode);
+
+/**
+ * Retrieve the number of failed tests executed by a suite runner.
+ *
+ * This value represents both test failures and errors.
+ *
+ * @param sr suite runner to query for all failed tests
+ *
+ * @return number of test failures and errors found by the suite runner
+ *
+ * @since 0.6.1
+ */
+CK_DLL_EXP int CK_EXPORT srunner_ntests_failed (SRunner * sr);
+
+/**
+ * Retrieve the total number of tests run by a suite runner.
+ *
+ * @param sr suite runner to query for all tests run
+ *
+ * @return number of all tests run by the suite runner
+ *
+ * @since 0.6.1
+ */
+CK_DLL_EXP int CK_EXPORT srunner_ntests_run (SRunner * sr);
+
+/**
+ * Return an array of results for all failures found by a suite runner.
+ *
+ * Number of results is equal to srunner_nfailed_tests().
+ *
+ * Information about individual results can be queried using:
+ * tr_rtype(), tr_ctx(), tr_msg(), tr_lno(), tr_lfile(), and tr_tcname().
+ *
+ * Memory is malloc'ed and must be freed; however free the entire structure
+ * instead of individual test cases.
+ *
+ * @param sr suite runner to retrieve results from
+ *
+ * @return array of TestResult objects
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP TestResult **CK_EXPORT srunner_failures (SRunner * sr);
+
+/**
+ * Return an array of results for all tests run by a suite runner.
+ *
+ * Number of results is equal to srunner_ntests_run(), and excludes
+ * failures due to setup function failure.
+ *
+ * Information about individual results can be queried using:
+ * tr_rtype(), tr_ctx(), tr_msg(), tr_lno(), tr_lfile(), and tr_tcname().
+ *
+ * Memory is malloc'ed and must be freed; however free the entire structure
+ * instead of individual test cases.
+ *
+ * @param sr suite runner to retrieve results from
+ *
+ * @return array of TestResult objects
+ *
+ * @since 0.6.1
+*/
+CK_DLL_EXP TestResult **CK_EXPORT srunner_results (SRunner * sr);
+
+/**
+ * Print the results contained in an SRunner to stdout.
+ *
+ * @param sr suite runner to print results for to stdout
+ * @param print_mode the print_output (verbosity) to use to report
+ * the result
+ *
+ * @since 0.7.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_print (SRunner * sr,
+ enum print_output print_mode);
+
+/**
+ * Set the suite runner to output the result in log format to the
+ * given file.
+ *
+ * Note: log file setting is an initialize only operation -- it should
+ * be done immediately after SRunner creation, and the log file can't be
+ * changed after being set.
+ *
+ * This setting does not conflict with the other log output types;
+ * all logging types can occur concurrently if configured.
+ *
+ * @param sr suite runner to log results of in log format
+ * @param fname file name to output log results to
+ *
+ * @since 0.7.1
+*/
+CK_DLL_EXP void CK_EXPORT srunner_set_log (SRunner * sr, const char *fname);
+
+/**
+ * Checks if the suite runner is assigned a file for log output.
+ *
+ * @param sr suite runner to check
+ *
+ * @return 1 iff the suite runner currently is configured to output
+ * in log format; 0 otherwise
+ *
+ * @since 0.7.1
+ */
+CK_DLL_EXP int CK_EXPORT srunner_has_log (SRunner * sr);
+
+/**
+ * Retrieves the name of the currently assigned file
+ * for log output, if any exists.
+ *
+ * @return the name of the log file, or NULL if none is configured
+ *
+ * @since 0.7.1
+ */
+CK_DLL_EXP const char *CK_EXPORT srunner_log_fname (SRunner * sr);
+
+/**
+ * Set the suite runner to output the result in XML format to the
+ * given file.
+ *
+ * Note: XML file setting is an initialize only operation -- it should
+ * be done immediately after SRunner creation, and the XML file can't be
+ * changed after being set.
+ *
+ * This setting does not conflict with the other log output types;
+ * all logging types can occur concurrently if configured.
+ *
+ * @param sr suite runner to log results of in XML format
+ * @param fname file name to output XML results to
+ *
+ * @since 0.9.1
+*/
+CK_DLL_EXP void CK_EXPORT srunner_set_xml (SRunner * sr, const char *fname);
+
+/**
+ * Checks if the suite runner is assigned a file for XML output.
+ *
+ * @param sr suite runner to check
+ *
+ * @return 1 iff the suite runner currently is configured to output
+ * in XML format; 0 otherwise
+ *
+ * @since 0.9.1
+ */
+CK_DLL_EXP int CK_EXPORT srunner_has_xml (SRunner * sr);
+
+/**
+ * Retrieves the name of the currently assigned file
+ * for XML output, if any exists.
+ *
+ * @return the name of the XML file, or NULL if none is configured
+ *
+ * @since 0.9.1
+ */
+CK_DLL_EXP const char *CK_EXPORT srunner_xml_fname (SRunner * sr);
+
+/**
+ * Set the suite runner to output the result in TAP format to the
+ * given file.
+ *
+ * Note: TAP file setting is an initialize only operation -- it should
+ * be done immediately after SRunner creation, and the TAP file can't be
+ * changed after being set.
+ *
+ * This setting does not conflict with the other log output types;
+ * all logging types can occur concurrently if configured.
+ *
+ * @param sr suite runner to log results of in TAP format
+ * @param fname file name to output TAP results to
+ *
+ * @since 0.9.12
+*/
+CK_DLL_EXP void CK_EXPORT srunner_set_tap (SRunner * sr, const char *fname);
+
+/**
+ * Checks if the suite runner is assigned a file for TAP output.
+ *
+ * @param sr suite runner to check
+ *
+ * @return 1 iff the suite runner currently is configured to output
+ * in TAP format; 0 otherwise
+ *
+ * @since 0.9.12
+ */
+CK_DLL_EXP int CK_EXPORT srunner_has_tap (SRunner * sr);
+
+/**
+ * Retrieves the name of the currently assigned file
+ * for TAP output, if any exists.
+ *
+ * @return the name of the TAP file, or NULL if none is configured
+ *
+ * @since 0.9.12
+ */
+CK_DLL_EXP const char *CK_EXPORT srunner_tap_fname (SRunner * sr);
+
+/**
+ * Enum describing the current fork usage.
+ */
+enum fork_status
+{
+ CK_FORK_GETENV, /**< look in the environment for CK_FORK */
+ CK_FORK, /**< call fork to run tests */
+ CK_NOFORK /**< don't call fork */
+};
+
+/**
+ * Retrieve the current fork status for the given suite runner
+ *
+ * @param sr suite runner to check fork status of
+ *
+ * @since 0.8.0
+ */
+CK_DLL_EXP enum fork_status CK_EXPORT srunner_fork_status (SRunner * sr);
+
+/**
+ * Set the fork status for a given suite runner.
+ *
+ * The default fork status is CK_FORK_GETENV, which will look
+ * for the CK_FORK environment variable, which can be set to
+ * "yes" or "no". If the environment variable is not present,
+ * CK_FORK will be used if fork() is available on the system,
+ * otherwise CK_NOFORK is used.
+ *
+ * If set to CK_FORK or CK_NOFORK, the environment variable
+ * if defined is ignored.
+ *
+ * If Check is compiled without support for fork(), attempting
+ * to set the status to CK_FORK is ignored.
+ *
+ * @param sr suite runner to assign the fork status to
+ * @param fstat fork status to assign
+ *
+ * @since 0.8.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_set_fork_status (SRunner * sr,
+ enum fork_status fstat);
+
+/**
+ * Invoke fork() during a test and assign the child to the same
+ * process group that the rest of the test case uses.
+ *
+ * One can invoke fork() directly during a test; however doing so
+ * may not guarantee that any children processes are destroyed once
+ * the test finishes. Once a test has completed, all processes in
+ * the process group will be killed; using this wrapper will prevent
+ * orphan processes.
+ *
+ * If Check is compiled without fork() support this call simply
+ * return -1 and does nothing.
+ *
+ * @return On success, the PID of the child process is returned in
+ * the parent, and 0 is returned in the child. On failure,
+ * a value of -1 is returned to the parent process and no
+ * child process is created.
+ *
+ * @since 0.9.3
+ */
+#if !defined(_MSC_VER)
+CK_DLL_EXP pid_t CK_EXPORT check_fork (void);
+#endif
+
+/**
+ * Wait for the pid and exit.
+ *
+ * This is to be used in conjunction with check_fork(). When called,
+ * will wait for the given process to terminate. If the process
+ * exited without error, exit(EXIT_SUCCESS) is invoked; otherwise
+ * exit(EXIT_FAILURE) is invoked.
+ *
+ * If Check is compiled without support for fork(), this invokes
+ * exit(EXIT_FAILURE).
+ *
+ * @param pid process to wait for, created by check_fork()
+ *
+ * @since 0.9.3
+ */
+#if !defined(_MSC_VER)
+CK_DLL_EXP void CK_EXPORT
+check_waitpid_and_exit (pid_t pid)
+ CK_ATTRIBUTE_NORETURN;
+#endif
+
+#ifdef __cplusplus
+CK_CPPEND
+#endif
+#endif /* CHECK_H */