diff --git a/CMakeLists.txt b/CMakeLists.txt
index 958a62d..37e02d3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -98,6 +98,7 @@ set(SOURCE_FILES
src/ordered-set.c
src/posix-compat.c
src/theories.c
+ src/asprintf.c
src/main.c
src/entry.c
)
@@ -123,6 +124,7 @@ set(INTERFACE_FILES
include/criterion/ordered-set.h
include/criterion/stats.h
include/criterion/theories.h
+ include/criterion/asprintf-compat.h
)
# Generate the configure file
diff --git a/doc/assert.rst b/doc/assert.rst
new file mode 100644
index 0000000..720bcaf
--- /dev/null
+++ b/doc/assert.rst
@@ -0,0 +1,96 @@
+.. _assertions-ref:
+
+Assertion reference
+===================
+
+This is an exhaustive list of all assertion macros that Criterion provides.
+
+As each ``assert`` macros have an ``expect`` counterpart with the exact same
+number of parameters and name suffix, there is no benefit in adding ``expect``
+macros to this list. Hence only ``assert`` macros are represented here.
+
+Common Assertions
+-----------------
+
+======================================================================= =========================================================================== ===========================================
+Macro Passes if and only if Notes
+======================================================================= =========================================================================== ===========================================
+cr_assert(Condition, [Message, [Args...]]) ``Condition`` is true.
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_not(Condition, [Message, [Args...]]) ``Condition`` is false.
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_null(Value, [Message, [Args...]]) ``Value`` is ``NULL``.
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_not_null(Value, [Message, [Args...]]) ``Value`` is not ``NULL``.
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_eq(Actual, Expected, [Message, [Args...]]) ``Actual`` is equal to ``Expected``. Compatible with C++ operator overloading
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_neq(Actual, Unexpected, [Message, [Args...]]) ``Actual`` is not equal to ``Unexpected``. Compatible with C++ operator overloading
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_lt(Actual, Reference, [Message, [Args...]]) ``Actual`` is less than ``Reference``. Compatible with C++ operator overloading
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_leq(Actual, Reference, [Message, [Args...]]) ``Actual`` is less or equal to ``Reference``. Compatible with C++ operator overloading
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_gt(Actual, Reference, [Message, [Args...]]) ``Actual`` is greater than ``Reference``. Compatible with C++ operator overloading
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_geq(Actual, Reference, [Message, [Args...]]) ``Actual`` is greater or equal to ``Reference``. Compatible with C++ operator overloading
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_float_eq(Actual, Expected, Epsilon, [Message, [Args...]]) ``Actual`` is equal to ``Expected`` with a tolerance of ``Epsilon``. Use this to test equality between floats
+----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_float_neq(Actual, Unexpected, Epsilon, [Message, [Args...]]) ``Actual`` is not equal to ``Unexpected`` with a tolerance of ``Epsilon``. Use this to test inequality between floats
+======================================================================= =========================================================================== ===========================================
+
+String Assertions
+-----------------
+
+Note: these macros are meant to deal with *native* strings, i.e. char arrays.
+Most of them won't work on ``std::string`` in C++, with some exceptions -- for
+``std::string``, you should use regular comparison assersions, as listed above.
+
+=========================================================== =================================================================== ===========================================
+Macro Passes if and only if Notes
+=========================================================== =================================================================== ===========================================
+cr_assert_str_empty(Value, [Message, [Args...]]) ``Value`` is an empty string. Also works on std::string
+----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
+cr_assert_str_not_empty(Value, [Message, [Args...]]) ``Value`` is not an empty string. Also works on std::string
+----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
+cr_assert_str_eq(Actual, Expected, [Message, [Args...]]) ``Actual`` is lexicographically equal to ``Expected``.
+----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
+cr_assert_str_neq(Actual, Unexpected, [Message, [Args...]]) ``Actual`` is not lexicographically equal to ``Unexpected``.
+----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
+cr_assert_str_lt(Actual, Reference, [Message, [Args...]]) ``Actual`` is lexicographically less than ``Reference``.
+----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
+cr_assert_str_leq(Actual, Reference, [Message, [Args...]]) ``Actual`` is lexicographically less or equal to ``Reference``.
+----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
+cr_assert_str_gt(Actual, Reference, [Message, [Args...]]) ``Actual`` is lexicographically greater than ``Reference``.
+----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
+cr_assert_str_geq(Actual, Reference, [Message, [Args...]]) ``Actual`` is lexicographically greater or equal to ``Reference``.
+=========================================================== =================================================================== ===========================================
+
+Array Assertions
+-----------------
+
+=========================================================================== =========================================================================== ===========================================
+Macro Passes if and only if Notes
+=========================================================================== =========================================================================== ===========================================
+cr_assert_arr_eq(Actual, Expected, [Message, [Args...]]) ``Actual`` is byte-to-byte equal to ``Expected``. This should not be used on struct arrays,
+ consider using ``cr_assert_arr_eq_cmp``
+ instead.
+--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_arr_neq(Actual, Unexpected, [Message, [Args...]]) ``Actual`` is not byte-to-byte equal to ``Unexpected``. This should not be used on struct arrays,
+ consider using ``cr_assert_arr_neq_cmp``
+ instead.
+--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_arr_eq_cmp(Actual, Expected, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively equal to ``Expected`` Only available in C++ and GNU C99
+--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_arr_neq_cmp(Actual, Unexpected, Size, Cmp, [Message, [Args...]]) ``Actual`` is not comparatively equal to ``Expected`` Only available in C++ and GNU C99
+--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_arr_lt_cmp(Actual, Reference, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively less than ``Reference`` Only available in C++ and GNU C99
+--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_arr_leq_cmp(Actual, Reference, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively less or equal to ``Reference`` Only available in C++ and GNU C99
+--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_arr_gt_cmp(Actual, Reference, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively greater than ``Reference`` Only available in C++ and GNU C99
+--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
+cr_assert_arr_geq_cmp(Actual, Reference, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively greater or equal to ``Reference`` Only available in C++ and GNU C99
+=========================================================================== =========================================================================== ===========================================
+
diff --git a/doc/index.rst b/doc/index.rst
index e9d55c5..56fbdf4 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -7,6 +7,7 @@ Criterion
intro
setup
starter
+ assert
hooks
env
theories
diff --git a/doc/starter.rst b/doc/starter.rst
index 6a9408e..4e32912 100644
--- a/doc/starter.rst
+++ b/doc/starter.rst
@@ -48,45 +48,8 @@ parameter, and an optional failure message:
cr_assert(strlen("") == 0);
}
-On top of those, more assertions are available for common operations:
-
-* ``cr_assert_null(Ptr, [Message])``: passes if Ptr is NULL.
-* ``cr_assert_eq(Actual, Expected, [Message])``: passes if Actual == Expected.
-* ``cr_assert_lt(Actual, Expected, [Message])``: passes if Actual < Expected.
-* ``cr_assert_leq(Actual, Expected, [Message])``: passes if Actual <= Expected.
-* ``cr_assert_gt(Actual, Expected, [Message])``: passes if Actual > Expected.
-* ``cr_assert_geq(Actual, Expected, [Message])``: passes if Actual >= Expected.
-* ``cr_assert_float_eq(Actual, Expected, Epsilon, [Message])``:
- passes if Actual == Expected with an error of Epsilon.
-* ``cr_assert_arrays_eq(Actual, Expected, Size, [Message])``:
- passes if all elements of Actual (from 0 to Size - 1) are equals to those
- of Expected.
-* ``cr_assert_arrays_eq_cmp(Actual, Expected, Size, Cmp, [Message])``:
- Same as ``arrays_eq`` but equality is defined by the result of the binary
- Cmp function.
-
-Equality and lexical comparison assertions are also available for strings:
-
-* ``cr_assert_strings_eq(Actual, Expected, [Message])``
-* ``cr_assert_strings_lt(Actual, Expected, [Message])``
-* ``cr_assert_strings_leq(Actual, Expected, [Message])``
-* ``cr_assert_strings_gt(Actual, Expected, [Message])``
-* ``cr_assert_strings_geq(Actual, Expected, [Message])``
-
-And some assertions have a logical negative counterpart:
-
-* ``cr_assert_not(Condition, [Message])``
-* ``cr_assert_not_null(Ptr, [Message])``
-* ``cr_assert_neq(Actual, Unexpected, [Message])``
-* ``cr_assert_float_neq(Actual, Unexpected, Epsilon, [Message])``
-* ``cr_assert_strings_neq(Actual, Unexpected, [Message])``
-* ``cr_assert_arrays_neq(Actual, Unexpected, Size, [Message])``
-* ``cr_assert_arrays_neq_cmp(Actual, Unexpected, Size, Cmp, [Message])``
-
-Of course, every ``assert`` has an ``expect`` counterpart.
-
-Please note that ``arrays_(n)eq`` assertions should not be used on padded
-structures -- please use ``arrays_(n)eq_cmp`` instead.
+On top of those, more assertions are available for common operations. See
+:ref:`assertions-ref` for a complete list.
Configuring tests
-----------------
diff --git a/include/criterion/abort.h b/include/criterion/abort.h
index 598b27e..026289f 100644
--- a/include/criterion/abort.h
+++ b/include/criterion/abort.h
@@ -29,6 +29,7 @@
CR_BEGIN_C_API
CR_API NORETURN void criterion_abort_test(void);
+CR_INLINE static void criterion_continue_test(void) {}
CR_END_C_API
diff --git a/include/criterion/asprintf-compat.h b/include/criterion/asprintf-compat.h
new file mode 100644
index 0000000..6f78efd
--- /dev/null
+++ b/include/criterion/asprintf-compat.h
@@ -0,0 +1,43 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef CRITERION_ASPRINTF_COMPAT_H_
+# define CRITERION_ASPRINTF_COMPAT_H_
+
+# ifdef __cplusplus
+# include
+# else
+# include
+# endif
+
+# include "common.h"
+
+CR_BEGIN_C_API
+
+FORMAT(printf, 2, 3)
+CR_API int cr_asprintf(char **strp, const char *fmt, ...);
+CR_API int cr_vasprintf(char **strp, const char *fmt, va_list ap);
+
+CR_END_C_API
+
+#endif /* !CRITERION_ASPRINTF_COMPAT_H_ */
diff --git a/include/criterion/assert.h b/include/criterion/assert.h
index 1d67a00..9a42e55 100644
--- a/include/criterion/assert.h
+++ b/include/criterion/assert.h
@@ -24,11 +24,13 @@
#ifndef CRITERION_ASSERT_H_
# define CRITERION_ASSERT_H_
+# include "preprocess.h"
+# include "asprintf-compat.h"
+
# ifdef __cplusplus
# include
# include
-using std::strcmp;
-using std::memcmp;
+# include
# else
# include
# include
@@ -41,11 +43,6 @@ using std::memcmp;
# include "event.h"
# include "abort.h"
-enum criterion_assert_kind {
- NORMAL,
- FATAL
-};
-
struct criterion_assert_args {
const char *msg;
int sentinel_;
@@ -60,274 +57,457 @@ struct criterion_assert_args {
# define CR_GET_CONDITION_STR(Condition, ...) #Condition
# define CR_VA_SKIP(_, ...) __VA_ARGS__
-# ifndef __cplusplus
-# define CR_ZERO_FILL(Arg) memset(&(Arg), 0, sizeof (Arg))
-# else
-# define CR_ZERO_FILL(Arg) std::memset(&(Arg), 0, sizeof (Arg))
-# endif
-
-# define cr_assert_impl(Kind, ...) \
- do { \
- struct criterion_assert_args args = { \
- CR_EXPAND(CR_VA_SKIP(__VA_ARGS__)) \
- }; \
- bool passed = !!(CR_EXPAND(CR_GET_CONDITION(__VA_ARGS__))); \
- struct criterion_assert_stats stat; \
- CR_ZERO_FILL(stat); \
- stat.kind = (Kind); \
- stat.condition = CR_EXPAND(CR_GET_CONDITION_STR(__VA_ARGS__)); \
- stat.message = args.msg ? args.msg : ""; \
- stat.passed = passed; \
- stat.file = __FILE__; \
- stat.line = __LINE__; \
- send_event(ASSERT, &stat, sizeof (stat)); \
- if (!passed && (Kind) == FATAL) \
- criterion_abort_test(); \
- } while (0)
-
-// Common asserts
-
-# define cr_abort_test(Message) \
- do { \
- const char *msg = (Message); \
- cr_assert(0, msg ? msg : "The conditions for this test were not met.");\
- } while (0)
-
# ifdef __cplusplus
-# define CR_SENTINEL 0
+# define CR_STDN std::
# else
-# define CR_SENTINEL .sentinel_ = 0
+# define CR_STDN
# endif
-# define cr_assert(...) CR_EXPAND(cr_assert_(__VA_ARGS__, CR_SENTINEL))
+# define CR_INIT_STATS_(BufSize, MsgVar, ...) CR_EXPAND( \
+ do { \
+ const char *default_msg = "" CR_VA_HEAD(__VA_ARGS__); \
+ char *formatted_msg = NULL; \
+ int msglen = cr_asprintf(&formatted_msg, "" CR_VA_TAIL(__VA_ARGS__)); \
+ MsgVar = formatted_msg && *formatted_msg ? \
+ formatted_msg : default_msg; \
+ \
+ if (!formatted_msg || !*formatted_msg) \
+ msglen = strlen(default_msg); \
+ \
+ BufSize = sizeof(struct criterion_assert_stats) \
+ + sizeof (size_t) + msglen + 1; \
+ \
+ char *buf = (char*) CR_STDN malloc(BufSize); \
+ stat = (struct criterion_assert_stats*) buf; \
+ CR_STDN memset(buf, 0, sizeof (struct criterion_assert_stats)); \
+ buf += sizeof (struct criterion_assert_stats); \
+ *((size_t*) buf) = msglen + 1; \
+ buf += sizeof (size_t); \
+ CR_STDN strcpy(buf, MsgVar); \
+ CR_STDN free(formatted_msg); \
+ } while (0))
-# define cr_expect(...) CR_EXPAND(cr_expect_(__VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_(Condition, ...) CR_EXPAND(cr_assert_impl(FATAL, Condition, __VA_ARGS__))
-# define cr_expect_(Condition, ...) CR_EXPAND(cr_assert_impl(NORMAL, Condition, __VA_ARGS__))
-
-# define cr_assert_not(...) CR_EXPAND(cr_assert_not_(__VA_ARGS__, CR_SENTINEL))
-# define cr_expect_not(...) CR_EXPAND(cr_expect_not_(__VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_not_(Condition, ...) \
- CR_EXPAND(cr_assert_impl(FATAL, !(Condition), __VA_ARGS__))
-# define cr_expect_not_(Condition, ...) \
- CR_EXPAND(cr_expect_impl(NORMAL, !(Condition), __VA_ARGS__))
-
-// Native asserts
-
-# define cr_assert_op_(Op, Actual, Expected, ...) \
- CR_EXPAND(cr_assert_impl(FATAL, (Actual) Op (Expected), __VA_ARGS__))
-# define cr_expect_op_(Op, Actual, Expected, ...) \
- CR_EXPAND(cr_assert_impl(NORMAL, (Actual) Op (Expected), __VA_ARGS__))
-
-# define cr_assert_eq(...) CR_EXPAND(cr_assert_op_(==, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_eq(...) CR_EXPAND(cr_expect_op_(==, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_neq(...) CR_EXPAND(cr_assert_op_(!=, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_neq(...) CR_EXPAND(cr_expect_op_(!=, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_lt(...) CR_EXPAND(cr_assert_op_(<, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_lt(...) CR_EXPAND(cr_expect_op_(<, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_gt(...) CR_EXPAND(cr_assert_op_(>, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_gt(...) CR_EXPAND(cr_expect_op_(>, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_leq(...) CR_EXPAND(cr_assert_op_(<=, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_leq(...) CR_EXPAND(cr_expect_op_(<=, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_geq(...) CR_EXPAND(cr_assert_op_(>=, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_geq(...) CR_EXPAND(cr_expect_op_(>=, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_null_(Value, ...) \
- CR_EXPAND(cr_assert_impl(FATAL, (Value) == NULL, __VA_ARGS__))
-# define cr_expect_null_(Value, ...) \
- CR_EXPAND(cr_assert_impl(NORMAL, (Value) == NULL, __VA_ARGS__))
-
-# define cr_assert_null(...) CR_EXPAND(cr_assert_null_(__VA_ARGS__, CR_SENTINEL))
-# define cr_expect_null(...) CR_EXPAND(cr_expect_null_(__VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_not_null_(Value, ...) \
- CR_EXPAND(cr_assert_impl(FATAL, (Value) != NULL, __VA_ARGS__))
-# define cr_expect_not_null_(Value, ...) \
- CR_EXPAND(cr_assert_impl(NORMAL, (Value) != NULL, __VA_ARGS__))
-
-# define cr_assert_not_null(...) CR_EXPAND(cr_assert_not_null_(__VA_ARGS__, CR_SENTINEL))
-# define cr_expect_not_null(...) CR_EXPAND(cr_expect_not_null_(__VA_ARGS__, CR_SENTINEL))
-
-// Floating-point asserts
-
-# define cr_assert_float_eq(...) \
- CR_EXPAND(cr_assert_float_eq_(__VA_ARGS__, CR_SENTINEL))
-# define cr_expect_float_eq(...) \
- CR_EXPAND(cr_expect_float_eq_(__VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_float_eq_(Actual, Expected, Epsilon, ...) \
- CR_EXPAND(cr_assert_impl(FATAL, (Expected) - (Actual) <= (Epsilon) \
- && (Actual) - (Expected) <= (Epsilon), \
- __VA_ARGS__))
-# define cr_expect_float_eq_(Actual, Expected, Epsilon, ...) \
- CR_EXPAND(cr_assert_impl(NORMAL, (Expected) - (Actual) <= (Epsilon) \
- && (Actual) - (Expected) <= (Epsilon), \
- __VA_ARGS__))
-
-# define cr_assert_float_neq(...) \
- CR_EXPAND(cr_assert_float_neq_(__VA_ARGS__, CR_SENTINEL))
-# define cr_expect_float_neq(...) \
- CR_EXPAND(cr_expect_float_neq_(__VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_float_neq_(Actual, Expected, Epsilon, ...) \
- CR_EXPAND(cr_assert_impl(FATAL, (Expected) - (Actual) > (Epsilon) \
- || (Actual) - (Expected) > (Epsilon), \
- __VA_ARGS__))
-# define cr_expect_float_neq_(Actual, Expected, Epsilon, ...) \
- CR_EXPAND(cr_assert_impl(NORMAL, (Expected) - (Actual) > (Epsilon) \
- || (Actual) - (Expected) > (Epsilon), \
- __VA_ARGS__))
-
-// String asserts
-
-# define cr_assert_strings_(Op, Actual, Expected, ...) \
- CR_EXPAND(cr_assert_impl(FATAL, strcmp((Actual), (Expected)) Op 0, __VA_ARGS__))
-# define cr_expect_strings_(Op, Actual, Expected, ...) \
- CR_EXPAND(cr_assert_impl(NORMAL, strcmp((Actual), (Expected)) Op 0, __VA_ARGS__))
-
-# define cr_assert_strings_eq(...) \
- CR_EXPAND(cr_assert_strings_(==, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_strings_eq(...) \
- CR_EXPAND(cr_expect_strings_(==, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_strings_neq(...) \
- CR_EXPAND(cr_assert_strings_(!=, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_strings_neq(...) \
- CR_EXPAND(cr_expect_strings_(!=, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_strings_gt(...) CR_EXPAND(cr_assert_strings_(>, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_strings_gt(...) CR_EXPAND(cr_expect_strings_(>, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_strings_lt(...) CR_EXPAND(cr_assert_strings_(<, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_strings_lt(...) CR_EXPAND(cr_expect_strings_(<, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_strings_leq(...) CR_EXPAND(cr_assert_strings_(<=, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_strings_leq(...) CR_EXPAND(cr_expect_strings_(<=, __VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_strings_geq(...) CR_EXPAND(cr_assert_strings_(>=, __VA_ARGS__, CR_SENTINEL))
-# define cr_expect_strings_geq(...) CR_EXPAND(cr_expect_strings_(>=, __VA_ARGS__, CR_SENTINEL))
-
-// Array asserts
-
-# define cr_assert_arrays_eq(...) \
- CR_EXPAND(cr_assert_arrays_eq_(__VA_ARGS__, CR_SENTINEL))
-# define cr_expect_arrays_eq(...) \
- CR_EXPAND(cr_expect_arrays_eq_(__VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_arrays_neq(...) \
- CR_EXPAND(cr_assert_arrays_neq_(__VA_ARGS__, CR_SENTINEL))
-# define cr_expect_arrays_neq(...) \
- CR_EXPAND(cr_expect_arrays_neq_(__VA_ARGS__, CR_SENTINEL))
-
-# define cr_assert_arrays_eq_(A, B, Size, ...) \
- CR_EXPAND(cr_assert_impl(FATAL, !memcmp((A), (B), (Size)), \
- __VA_ARGS__))
-# define cr_expect_arrays_eq_(A, B, Size, ...) \
- CR_EXPAND(cr_assert_impl(NORMAL, !memcmp((A), (B), (Size)), \
- __VA_ARGS__))
-
-# define cr_assert_arrays_neq_(A, B, Size, ...) \
- CR_EXPAND(cr_assert_impl(FATAL, memcmp((A), (B), (Size)), \
- __VA_ARGS__))
-# define cr_expect_arrays_neq_(A, B, Size, ...) \
- CR_EXPAND(cr_assert_impl(NORMAL, memcmp((A), (B), (Size)), \
- __VA_ARGS__))
+# define CR_FAIL_ABORT_ criterion_abort_test
+# define CR_FAIL_CONTINUES_ criterion_continue_test
# ifdef __GNUC__
-# define CRIT_ARR_COMPARE_(A, B, Size, Cmp, Result) \
- __typeof__(&(A)[0]) first = (A); \
- __typeof__(&(B)[0]) second = (B); \
- int equals = 1; \
- size_t i, size; \
- for (i = 0, size = (Size); equals && i < size; ++i) \
- equals = equals && !Cmp(first + i, second + i)
+// We disable the format-zero-length warning because we use the validity of
+// asprintf(out, "") for empty assertion messages
+# pragma GCC diagnostic ignored "-Wformat-zero-length"
+# endif
-# define cr_assert_arrays_eq_cmp_(A, B, Size, Cmp, ...) \
- do { \
- CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
- cr_assert_impl(FATAL, equals, \
- __VA_ARGS__); \
+# define cr_assert_impl(Fail, Condition, ...) \
+ do { \
+ bool passed = !!(Condition); \
+ \
+ const char *msg = NULL; \
+ size_t bufsize; \
+ \
+ struct criterion_assert_stats *stat; \
+ CR_EXPAND(CR_INIT_STATS_(bufsize, msg, CR_VA_TAIL(__VA_ARGS__))); \
+ stat->passed = passed; \
+ stat->file = __FILE__; \
+ stat->line = __LINE__; \
+ \
+ send_event(ASSERT, stat, bufsize); \
+ CR_STDN free(stat); \
+ \
+ if (!passed) \
+ Fail(); \
} while (0)
-# define cr_expect_arrays_eq_cmp_(A, B, Size, Cmp, ...) \
- do { \
- CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
- cr_assert_impl(NORMAL, equals, \
- __VA_ARGS__); \
+// Base assertions
+
+# define cr_fail(Fail, ...) \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ 0, \
+ dummy, \
+ "The conditions for this assertion were not met.", \
+ __VA_ARGS__ \
+ ))
+
+# define cr_assert_fail(...) CR_EXPAND(cr_fail(CR_FAIL_ABORT_, __VA_ARGS__))
+# define cr_expect_fail(...) CR_EXPAND(cr_fail(CR_FAIL_CONTINUES_, __VA_ARGS__))
+
+# define cr_assert(...) \
+ CR_EXPAND(cr_assert_impl( \
+ CR_FAIL_ABORT_, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ dummy, \
+ "The expression " CR_STR(CR_VA_HEAD(__VA_ARGS__)) " is false.", \
+ CR_VA_TAIL(__VA_ARGS__) \
+ ))
+
+# define cr_expect(...) \
+ CR_EXPAND(cr_assert_impl( \
+ CR_FAIL_CONTINUES_, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ dummy, \
+ "The expression " CR_STR(CR_VA_HEAD(__VA_ARGS__)) " is false.", \
+ CR_VA_TAIL(__VA_ARGS__) \
+ ))
+
+# define cr_assert_not(...) \
+ CR_EXPAND(cr_assert_impl( \
+ CR_FAIL_ABORT_, \
+ !(CR_VA_HEAD(__VA_ARGS__)), \
+ dummy, \
+ "The expression " CR_STR(!(CR_VA_HEAD(__VA_ARGS__))) " is false.", \
+ CR_VA_TAIL(__VA_ARGS__) \
+ ))
+
+# define cr_expect_not(...) \
+ CR_EXPAND(cr_assert_impl( \
+ CR_FAIL_CONTINUES_, \
+ !(CR_VA_HEAD(__VA_ARGS__)), \
+ dummy, \
+ "The expression " CR_STR(!(CR_VA_HEAD(__VA_ARGS__))) " is false.", \
+ CR_VA_TAIL(__VA_ARGS__) \
+ ))
+
+// Common binary assertions
+
+# define cr_assert_op_(Fail, Op, Actual, Expected, ...) \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ (Actual) Op (Expected), \
+ dummy, \
+ "The expression " CR_STR((Actual) Op (Expected)) " is false.", \
+ __VA_ARGS__ \
+ ))
+
+# define cr_assert_op_va_(Fail, Op, ...) \
+ CR_EXPAND(cr_assert_op_( \
+ Fail, \
+ Op, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
+ CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
+ ))
+
+# define cr_assert_eq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
+# define cr_expect_eq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, ==, __VA_ARGS__))
+
+# define cr_assert_neq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, !=, __VA_ARGS__))
+# define cr_expect_neq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, !=, __VA_ARGS__))
+
+# define cr_assert_lt(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, <, __VA_ARGS__))
+# define cr_expect_lt(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, <, __VA_ARGS__))
+
+# define cr_assert_leq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, <=, __VA_ARGS__))
+# define cr_expect_leq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, <=, __VA_ARGS__))
+
+# define cr_assert_gt(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, >, __VA_ARGS__))
+# define cr_expect_gt(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, >, __VA_ARGS__))
+
+# define cr_assert_geq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, >=, __VA_ARGS__))
+# define cr_expect_geq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, >=, __VA_ARGS__))
+
+// Common unary assertions
+
+# define cr_assert_null_op_(Fail, Op, Not, Value, ...) \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ (Value) Op NULL, \
+ dummy, \
+ CR_STR(Value) " is" Not " null.", \
+ __VA_ARGS__ \
+ ))
+
+# define cr_assert_null_op_va_(Fail, Op, Not, ...) \
+ CR_EXPAND(cr_assert_null_op_( \
+ Fail, \
+ Op, \
+ Not, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ CR_VA_TAIL(__VA_ARGS__) \
+ ))
+
+# define cr_assert_null(...) CR_EXPAND(cr_assert_null_op_va_(CR_FAIL_ABORT_, ==, " not", __VA_ARGS__))
+# define cr_expect_null(...) CR_EXPAND(cr_assert_null_op_va_(CR_FAIL_CONTINUES_, ==, " not", __VA_ARGS__))
+
+# define cr_assert_not_null(...) CR_EXPAND(cr_assert_null_op_va_(CR_FAIL_ABORT_, !=, "", __VA_ARGS__))
+# define cr_expect_not_null(...) CR_EXPAND(cr_assert_null_op_va_(CR_FAIL_CONTINUES_, !=, "", __VA_ARGS__))
+
+// Floating-point assertions
+
+# define cr_assert_float_eq_op_(Actual, Expected, Epsilon) \
+ (Expected) - (Actual) <= (Epsilon) && (Actual) - (Expected) <= (Epsilon)
+
+# define cr_assert_float_neq_op_(Actual, Expected, Epsilon) \
+ (Expected) - (Actual) > (Epsilon) || (Actual) - (Expected) > (Epsilon)
+
+# define cr_assert_float_op_(Fail, Op, Actual, Expected, Epsilon, ...) \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ Op(Actual, Expected, Epsilon), \
+ dummy, \
+ "The expression " CR_STR(Op(Actual, Expected, Epsilon)) " is false.", \
+ __VA_ARGS__ \
+ ))
+
+# define cr_assert_float_op_va_(Fail, Op, ...) \
+ CR_EXPAND(cr_assert_float_op_( \
+ Fail, \
+ Op, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
+ CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
+ CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))) \
+ ))
+
+# define cr_assert_float_eq(...) CR_EXPAND(cr_assert_float_op_va_(CR_FAIL_ABORT_, cr_assert_float_eq_op_, __VA_ARGS__))
+# define cr_expect_float_eq(...) CR_EXPAND(cr_assert_float_op_va_(CR_FAIL_CONTINUES_, cr_assert_float_eq_op_, __VA_ARGS__))
+
+# define cr_assert_float_neq(...) CR_EXPAND(cr_assert_float_op_va_(CR_FAIL_ABORT_, cr_assert_float_neq_op_, __VA_ARGS__))
+# define cr_expect_float_neq(...) CR_EXPAND(cr_assert_float_op_va_(CR_FAIL_CONTINUES_, cr_assert_float_neq_op_, __VA_ARGS__))
+
+// String assertions
+
+# define cr_assert_str_op_empty_(Fail, Op, Not, Value, ...) \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ (Value)[0] Op '\0', \
+ dummy, \
+ CR_STR(Value) " is" Not " empty.", \
+ __VA_ARGS__ \
+ ))
+
+# define cr_assert_str_op_empty_va_(Fail, Op, Not, ...) \
+ CR_EXPAND(cr_assert_str_op_empty_( \
+ Fail, \
+ Op, \
+ Not, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ CR_VA_TAIL(__VA_ARGS__) \
+ ))
+
+# define cr_assert_str_empty(...) CR_EXPAND(cr_assert_str_op_empty_va_(CR_FAIL_ABORT_, ==, " not", __VA_ARGS__))
+# define cr_expect_str_empty(...) CR_EXPAND(cr_assert_str_op_empty_va_(CR_FAIL_CONTINUES_, ==, " not", __VA_ARGS__))
+
+# define cr_assert_str_not_empty(...) CR_EXPAND(cr_assert_str_op_empty_va_(CR_FAIL_ABORT_, !=, "", __VA_ARGS__))
+# define cr_expect_str_not_empty(...) CR_EXPAND(cr_assert_str_op_empty_va_(CR_FAIL_CONTINUES_, !=, "", __VA_ARGS__))
+
+# define cr_assert_str_op_(Fail, Op, Actual, Expected, ...) \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ CR_STDN strcmp((Actual), (Expected)) Op 0, \
+ dummy, \
+ "The expression (as strings) " \
+ CR_STR((Actual) Op (Expected)) " is false", \
+ __VA_ARGS__ \
+ ))
+
+# define cr_assert_str_op_va_(Fail, Op, ...) \
+ CR_EXPAND(cr_assert_str_op_( \
+ Fail, \
+ Op, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
+ CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
+ ))
+
+# define cr_assert_str_eq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
+# define cr_expect_str_eq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, ==, __VA_ARGS__))
+
+# define cr_assert_str_neq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, !=, __VA_ARGS__))
+# define cr_expect_str_neq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, !=, __VA_ARGS__))
+
+# define cr_assert_str_lt(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, <, __VA_ARGS__))
+# define cr_expect_str_lt(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, <, __VA_ARGS__))
+
+# define cr_assert_str_leq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, <=, __VA_ARGS__))
+# define cr_expect_str_leq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, <=, __VA_ARGS__))
+
+# define cr_assert_str_gt(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, >, __VA_ARGS__))
+# define cr_expect_str_gt(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, >, __VA_ARGS__))
+
+# define cr_assert_str_geq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, >=, __VA_ARGS__))
+# define cr_expect_str_geq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, >=, __VA_ARGS__))
+
+// Array assertions
+
+# define cr_assert_mem_op_(Fail, Op, Actual, Expected, Size, ...) \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ CR_STDN memcmp((Actual), (Expected), (Size)) Op 0, \
+ dummy, \
+ "The expression " \
+ CR_STR((Actual)[0 .. Size] Op (Expected)[0 .. Size]) \
+ "is false.", \
+ __VA_ARGS__ \
+ ))
+
+# define cr_assert_mem_op_va_(Fail, Op, ...) \
+ CR_EXPAND(cr_assert_mem_op_( \
+ Fail, \
+ Op, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
+ CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
+ CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))) \
+ ))
+
+# define cr_assert_arr_eq(...) CR_EXPAND(cr_assert_mem_op_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
+# define cr_expect_arr_eq(...) CR_EXPAND(cr_assert_mem_op_va_(CR_FAIL_CONTINUES_, ==, __VA_ARGS__))
+
+# define cr_assert_arr_neq(...) CR_EXPAND(cr_assert_mem_op_va_(CR_FAIL_ABORT_, !=, __VA_ARGS__))
+# define cr_expect_arr_neq(...) CR_EXPAND(cr_assert_mem_op_va_(CR_FAIL_CONTINUES_, !=, __VA_ARGS__))
+
+// Safe array comparison assertions
+
+# if defined(__GNUC__) || defined(__cplusplus)
+
+# ifdef __cplusplus
+# define CR_ARR_COMPARE_(A, B, Size, Cmp, Result) \
+ int Result = std::lexicographical_compare((A), (A) + Size, (B), (B) + Size, Cmp)
+# else
+# define CR_ARR_COMPARE_(A, B, Size, Cmp, Result) \
+ __typeof__(&(A)[0]) first = (A); \
+ __typeof__(&(B)[0]) second = (B); \
+ int Result = 0; \
+ size_t i, size; \
+ for (i = 0, size = (Size); !Result && i < size; ++i) \
+ Result = Cmp(first + i, second + i)
+# endif
+
+# define cr_assert_arr_op_cmp_(Fail, Op, Actual, Expected, Size, Cmp, ...) \
+ do { \
+ CR_ARR_COMPARE_(Actual, Expected, Size, Cmp, order); \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ order Op 0, \
+ dummy, \
+ "The expression " \
+ CR_STR((Actual)[0 .. Size] Op (Expected)[0 .. Size]) \
+ " is false.", \
+ __VA_ARGS__ \
+ )); \
} while (0)
-# define cr_assert_arrays_eq_cmp(...) \
- cr_assert_arrays_eq_cmp_(__VA_ARGS__, CR_SENTINEL)
-# define cr_expect_arrays_eq_cmp(...) \
- cr_expect_arrays_eq_cmp_(__VA_ARGS__, CR_SENTINEL)
+# define cr_assert_arr_op_cmp_va_(Fail, Op, ...) \
+ CR_EXPAND(cr_assert_arr_op_cmp_( \
+ Fail, \
+ Op, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
+ CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
+ CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)))), \
+ CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)))) \
+ ))
-# define cr_assert_arrays_neq_cmp_(A, B, Size, Cmp, ...) \
- do { \
- CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
- cr_assert_impl(FATAL, !equals, \
- __VA_ARGS__); \
- } while (0)
+# define cr_assert_arr_eq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
+# define cr_expect_arr_eq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, ==, __VA_ARGS__))
-# define cr_expect_arrays_neq_cmp_(A, B, Size, Cmp, ...) \
- do { \
- CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
- cr_assert_impl(NORMAL, equals, \
- __VA_ARGS__); \
- } while (0)
+# define cr_assert_arr_neq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, !=, __VA_ARGS__))
+# define cr_expect_arr_neq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, !=, __VA_ARGS__))
-# define cr_assert_arrays_neq_cmp(...) \
- cr_assert_arrays_eq_cmp_(__VA_ARGS__, CR_SENTINEL)
-# define cr_expect_arrays_neq_cmp(...) \
- cr_expect_arrays_eq_cmp_(__VA_ARGS__, CR_SENTINEL)
-# endif /* !__GNUC__ */
+# define cr_assert_arr_lt_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, <, __VA_ARGS__))
+# define cr_expect_arr_lt_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, <, __VA_ARGS__))
+
+# define cr_assert_arr_leq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, <=, __VA_ARGS__))
+# define cr_expect_arr_leq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, <=, __VA_ARGS__))
+
+# define cr_assert_arr_gt_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, >, __VA_ARGS__))
+# define cr_expect_arr_gt_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, >, __VA_ARGS__))
+
+# define cr_assert_arr_geq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, >=, __VA_ARGS__))
+# define cr_expect_arr_geq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, >=, __VA_ARGS__))
+
+# else
+
+# define CRITERION_GNUC_WARN__(Msg) \
+ _Pragma(#Msg)
+
+# define CRITERION_GNUC_WARN_(Name) CRITERION_GNUC_WARN__( \
+ message \
+ "The `" #Name "` macro is only available on GNU C compilers." \
+ )
+
+# define cr_assert_arr_eq_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_eq_cmp) CR_NOOP
+# define cr_expect_arr_eq_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_eq_cmp) CR_NOOP
+
+# define cr_assert_arr_neq_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_neq_cmp) CR_NOOP
+# define cr_expect_arr_neq_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_neq_cmp) CR_NOOP
+
+# define cr_assert_arr_lt_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_lt_cmp) CR_NOOP
+# define cr_expect_arr_lt_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_lt_cmp) CR_NOOP
+
+# define cr_assert_arr_leq_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_leq_cmp) CR_NOOP
+# define cr_expect_arr_leq_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_leq_cmp) CR_NOOP
+
+# define cr_assert_arr_gt_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_gt_cmp) CR_NOOP
+# define cr_expect_arr_gt_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_gt_cmp) CR_NOOP
+
+# define cr_assert_arr_geq_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_geq_cmp) CR_NOOP
+# define cr_expect_arr_geq_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_geq_cmp) CR_NOOP
+
+# endif
# ifdef __cplusplus
-# define cr_assert_throw(...) CR_EXPAND(cr_assert_throw_(__VA_ARGS__, CR_SENTINEL))
-# define cr_assert_throw_(Statement, Exception, ...) \
- try { \
- Statement; \
- } catch (Exception &ex) { \
- } catch (...) { CR_EXPAND(cr_assert_impl(FATAL, 0, __VA_ARGS__)); }
-# define cr_assert_no_throw(...) CR_EXPAND(cr_assert_not_throw_(__VA_ARGS__, CR_SENTINEL))
-# define cr_assert_no_throw_(Statement, Exception, ...) \
- try { \
- Statement; \
- } catch (Exception &ex) { CR_EXPAND(cr_assert_impl(FATAL, 0, __VA_ARGS__)); }
+# define cr_assert_throw_(Fail, Statement, Exception, ...) \
+ try { \
+ Statement; \
+ } catch (Exception const &) { \
+ } catch (...) { CR_EXPAND(cr_fail(Fail, CR_VA_TAIL(__VA_ARGS__))); }
-# define cr_expect_throw(...) CR_EXPAND(cr_expect_throw_(__VA_ARGS__, CR_SENTINEL))
-# define cr_expect_throw_(Statement, Exception, ...) \
- try { \
- Statement; \
- } catch (Exception &ex) { \
- } catch (...) { CR_EXPAND(cr_assert_impl(NORMAL, 0, __VA_ARGS__)); }
+# define cr_assert_throw_va_(...) \
+ CR_EXPAND(cr_assert_throw_( \
+ CR_VA_HEAD(__VA_ARGS__), \
+ CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
+ CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
+ dummy, \
+ CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))) \
+ ))
+
+# define cr_assert_throw(...) CR_EXPAND(cr_assert_throw_va_(CR_FAIL_ABORT_, __VA_ARGS__))
+# define cr_expect_throw(...) CR_EXPAND(cr_assert_throw_va_(CR_FAIL_CONTINUES_, __VA_ARGS__))
+
+# define cr_assert_no_throw_(Fail, Statement, Exception, ...) \
+ try { \
+ Statement; \
+ } catch (Exception const &) { CR_EXPAND(cr_fail(Fail, CR_VA_TAIL(__VA_ARGS__))); }
+
+# define cr_assert_no_throw_va_(...) \
+ CR_EXPAND(cr_assert_no_throw_( \
+ CR_VA_HEAD(__VA_ARGS__), \
+ CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
+ CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
+ dummy, \
+ CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))) \
+ ))
+
+# define cr_assert_no_throw(...) CR_EXPAND(cr_assert_no_throw_va_(CR_FAIL_ABORT_, __VA_ARGS__))
+# define cr_expect_no_throw(...) CR_EXPAND(cr_assert_no_throw_va_(CR_FAIL_CONTINUES_, __VA_ARGS__))
-# define cr_expect_no_throw(...) CR_EXPAND(cr_expect_not_throw_(__VA_ARGS__, CR_SENTINEL))
-# define cr_expect_no_throw_(Statement, Exception, ...) \
- try { \
- Statement; \
- } catch (Exception &ex) { CR_EXPAND(cr_assert_impl(NORMAL, 0, __VA_ARGS__)); }
# endif
// The section below is here for backward compatibility purposes.
-// It shall be removed in the text major version of Criterion
+// It shall be removed in the next major version of Criterion
# ifndef CRITERION_NO_COMPAT
-# define CRITERION_ASSERT_DEPRECATED_(Name) CRITERION_ASSERT_DEPRECATED__( \
- message \
- "The `" #Name "` macro is deprecated, " \
- "please use `cr_" #Name "` instead." \
+# define CRITERION_ASSERT_DEPRECATED_(Name) CRITERION_ASSERT_DEPRECATED__( \
+ message \
+ ("The `" #Name "` macro is deprecated, " \
+ "please use `cr_" #Name "` instead.") \
)
+# define CRITERION_ASSERT_DEPRECATED_B(Name, Newname) \
+ CRITERION_ASSERT_DEPRECATED__( \
+ message \
+ ("The `" #Name "` macro is deprecated, " \
+ "please use `" #Newname "` instead.") \
+ )
+
+# ifdef _MSC_VER
+# define CRITERION_ASSERT_DEPRECATED__(Msg) \
+ __pragma(Msg)
+# else
# define CRITERION_ASSERT_DEPRECATED__(Msg) \
_Pragma(#Msg)
+# endif
# ifndef assert
# define assert(...) CRITERION_ASSERT_DEPRECATED_(assert) cr_assert(__VA_ARGS__)
@@ -339,6 +519,22 @@ struct criterion_assert_args {
# endif /* !_ASSERT_H */
# endif /* !assert */
+// scheduled for removal after 2.0
+# define cr_abort_test(Message) CRITERION_ASSERT_DEPRECATED_B(cr_abort_test, cr_assert_fail) cr_assert_fail(Message)
+# define cr_assert_strings_eq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_eq, cr_assert_str_eq) cr_assert_str_eq(__VA_ARGS__)
+# define cr_assert_strings_neq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_neq, cr_assert_str_neq) cr_assert_str_neq(__VA_ARGS__)
+# define cr_assert_strings_lt(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_lt, cr_assert_str_lt) cr_assert_str_lt(__VA_ARGS__)
+# define cr_assert_strings_leq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_leq, cr_assert_str_leq) cr_assert_str_leq(__VA_ARGS__)
+# define cr_assert_strings_gt(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_gt, cr_assert_str_gt) cr_assert_str_gt(__VA_ARGS__)
+# define cr_assert_strings_geq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_geq, cr_assert_str_geq) cr_assert_str_geq(__VA_ARGS__)
+
+# define cr_assert_arrays_eq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_arrays_eq, cr_assert_arr_eq) cr_assert_arr_eq(__VA_ARGS__)
+# define cr_assert_arrays_neq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_arrays_neq, cr_assert_arr_neq) cr_assert_arr_neq(__VA_ARGS__)
+
+# define cr_assert_arrays_eq_cmp(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_arrays_eq_cmp, cr_assert_arr_eq_cmp) cr_assert_arr_eq_cmp(__VA_ARGS__)
+# define cr_assert_arrays_neq_cmp(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_arrays_neq_cmp, cr_assert_arr_neq_cmp) cr_assert_arr_neq_cmp(__VA_ARGS__)
+
+// scheduled for removal at 2.0
# define abort_test(Message) CRITERION_ASSERT_DEPRECATED_(abort_test) cr_abort_test(Message)
# define expect(...) CRITERION_ASSERT_DEPRECATED_(expect) cr_expect(__VA_ARGS__)
# define assert_not(...) CRITERION_ASSERT_DEPRECATED_(assert_not) cr_assert_not(__VA_ARGS__)
diff --git a/include/criterion/common.h b/include/criterion/common.h
index 6d0910a..ae962eb 100644
--- a/include/criterion/common.h
+++ b/include/criterion/common.h
@@ -24,8 +24,6 @@
#ifndef CRITERION_COMMON_H_
# define CRITERION_COMMON_H_
-# define CR_EXPAND(x) x
-
# if defined(_MSC_VER)
# if _MSC_VER < 1900
# error \
@@ -101,12 +99,15 @@
# ifdef __GNUC__
# define UNUSED CR_ATTRIBUTE(unused)
# define NORETURN CR_ATTRIBUTE(noreturn)
+# define CR_INLINE CR_ATTRIBUTE(always_inline) inline
# elif CR_IS_MSVC
# define UNUSED
# define NORETURN __declspec(noreturn)
+# define CR_INLINE __forceinline
# else
# define UNUSED
# define NORETURN
+# define CR_INLINE inline
# endif
# ifdef _WIN32
diff --git a/include/criterion/event.h b/include/criterion/event.h
index 37881db..5138901 100644
--- a/include/criterion/event.h
+++ b/include/criterion/event.h
@@ -26,17 +26,13 @@
# ifdef __cplusplus
# include
-# include
# else
# include
-# include
# endif
# include "common.h"
CR_BEGIN_C_API
-extern FILE *g_event_pipe;
-
CR_API void send_event(int kind, void *data, size_t size);
CR_END_C_API
diff --git a/include/criterion/preprocess.h b/include/criterion/preprocess.h
new file mode 100644
index 0000000..822e0e3
--- /dev/null
+++ b/include/criterion/preprocess.h
@@ -0,0 +1,72 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef CRITERION_PREPROCESS_H_
+# define CRITERION_PREPROCESS_H_
+
+# define CR_NOOP do {} while(0)
+
+# ifdef __cplusplus
+# define CR_NOTHROW throw()
+# else
+# define CR_NOTHROW
+# endif
+
+# define CR_EXPAND(x) x
+
+# define CR_STR(x) CR_EXPAND(CR_STR_(x))
+# define CR_STR_(x) #x
+
+# define CR_VA_TAIL(...) CR_EXPAND(CR_VA_TAIL_HELPER(CR_VA_TAIL_SELECT(__VA_ARGS__), __VA_ARGS__))
+
+# define CR_VA_TAIL_HELPER(N, ...) CR_EXPAND(CR_VA_TAIL_HELPER_(N, __VA_ARGS__))
+# define CR_VA_TAIL_HELPER_(N, ...) CR_EXPAND(CR_VA_TAIL_HELPER_##N(__VA_ARGS__))
+# define CR_VA_TAIL_HELPER_1(Head)
+# define CR_VA_TAIL_HELPER_2(Head, ...) __VA_ARGS__
+
+# define CR_VA_HEAD(...) CR_EXPAND(CR_VA_HEAD_HELPER(CR_VA_TAIL_SELECT(__VA_ARGS__), __VA_ARGS__))
+
+# define CR_VA_HEAD_HELPER(N, ...) CR_EXPAND(CR_VA_HEAD_HELPER_(N, __VA_ARGS__))
+# define CR_VA_HEAD_HELPER_(N, ...) CR_EXPAND(CR_VA_HEAD_HELPER_##N(__VA_ARGS__))
+# define CR_VA_HEAD_HELPER_1(Head) Head
+# define CR_VA_HEAD_HELPER_2(Head, ...) Head
+
+# define CR_VA_TAIL_SELECT(...) CR_EXPAND(CR_VA_TAIL_SELECT64(__VA_ARGS__, \
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+ 2, 2, 1, _))
+
+# define CR_VA_TAIL_SELECT64( \
+ _01, _02, _03, _04, _05, _06, _07, _08, _09, _10, \
+ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
+ _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
+ _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
+ _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
+ _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
+ _61, _62, _63, X, ...) X
+
+#endif /* !CRITERION_PREPROCESS_H_ */
diff --git a/include/criterion/stats.h b/include/criterion/stats.h
index a1d62ed..8d6d4ca 100644
--- a/include/criterion/stats.h
+++ b/include/criterion/stats.h
@@ -27,8 +27,6 @@
# include "types.h"
struct criterion_assert_stats {
- int kind;
- const char *condition;
const char *message;
bool passed;
unsigned line;
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt
index f95f255..a3a05ee 100644
--- a/samples/CMakeLists.txt
+++ b/samples/CMakeLists.txt
@@ -46,23 +46,27 @@ if (HAVE_PCRE)
set(SCRIPTS ${SCRIPTS} pattern)
endif ()
-foreach(sample ${SAMPLES})
- add_executable(${sample}.bin ${sample})
- target_link_libraries(${sample}.bin criterion)
- add_test(${sample} ${sample}.bin)
- set_property(TEST ${sample} PROPERTY
- ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
- )
-
- if (NOT MSVC) # we disable the scripted tests when building with MSVC
- add_test(${sample}_compare sh ${CMAKE_CURRENT_LIST_DIR}/tests/run_test.sh "${CMAKE_CURRENT_LIST_DIR}" . . ${sample}.bin)
- set_property(TEST ${sample}_compare PROPERTY
- ENVIRONMENT "LC_ALL=en_US.utf8"
+macro(add_samples DIR_ SAMPLES_)
+ foreach(sample ${SAMPLES_})
+ add_executable(${sample}.bin ${sample})
+ target_link_libraries(${sample}.bin criterion)
+ add_test(${sample} ${sample}.bin)
+ set_property(TEST ${sample} PROPERTY
ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
- ENVIRONMENT "CRITERION_SHORT_FILENAME=1"
)
- endif ()
-endforeach()
+
+ if (NOT MSVC) # we disable the scripted tests when building with MSVC
+ add_test(${sample}_compare sh ${DIR_}/run_test.sh "${CMAKE_CURRENT_LIST_DIR}" . . ${sample}.bin)
+ set_property(TEST ${sample}_compare PROPERTY
+ ENVIRONMENT "LC_ALL=en_US.utf8"
+ ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
+ ENVIRONMENT "CRITERION_SHORT_FILENAME=1"
+ )
+ endif ()
+ endforeach()
+endmacro()
+
+add_samples("${CMAKE_CURRENT_LIST_DIR}/tests" "${SAMPLES}")
if (NOT MSVC) # we disable the scripted tests when building with MSVC
@@ -81,3 +85,5 @@ foreach(script ${SCRIPTS})
endforeach()
endif()
+
+add_subdirectory(tests)
diff --git a/samples/asserts.c b/samples/asserts.c
index 0d9daab..1d5d83e 100644
--- a/samples/asserts.c
+++ b/samples/asserts.c
@@ -6,29 +6,32 @@ Test(asserts, base) {
cr_assert(true, "Assertions may take failure messages");
+ cr_assert(true, "Or even %d format string %s", 1, "with parameters");
+
cr_expect(false, "assert is fatal, expect isn't");
cr_assert(false, "This assert runs");
cr_assert(false, "This does not");
}
Test(asserts, old_school) {
- if (false)
- cr_abort_test("You can abort the test with a message from anywhere");
-
- cr_abort_test(NULL); // or without a message
+ cr_expect_fail("You can fail an assertion with a message from anywhere");
+ cr_assert_fail(); // or without a message
}
Test(asserts, string) {
- cr_assert_strings_eq("hello", "hello");
- cr_assert_strings_neq("hello", "olleh");
+ cr_assert_str_empty("");
+ cr_assert_str_not_empty("foo");
- cr_assert_strings_gt("hello", "hell");
- cr_assert_strings_geq("hello", "hell");
- cr_assert_strings_geq("hello", "hello");
+ cr_assert_str_eq("hello", "hello");
+ cr_assert_str_neq("hello", "olleh");
- cr_assert_strings_lt("hell", "hello");
- cr_assert_strings_leq("hell", "hello");
- cr_assert_strings_leq("hello", "hello");
+ cr_assert_str_gt("hello", "hell");
+ cr_assert_str_geq("hello", "hell");
+ cr_assert_str_geq("hello", "hello");
+
+ cr_assert_str_lt("hell", "hello");
+ cr_assert_str_leq("hell", "hello");
+ cr_assert_str_leq("hello", "hello");
}
Test(asserts, native) {
@@ -62,8 +65,8 @@ Test(asserts, array) {
int arr1[] = {1, 2, 3, 4};
int arr2[] = {4, 3, 2, 1};
- cr_assert_arrays_eq(arr1, arr1, 4);
- cr_assert_arrays_neq(arr1, arr2, 4);
+ cr_assert_arr_eq(arr1, arr1, 4);
+ cr_assert_arr_neq(arr1, arr2, 4);
#ifdef __GNUC__
struct dummy_struct s1[] = {{4, 2}, {2, 4}};
@@ -74,7 +77,7 @@ Test(asserts, array) {
s2[1].a = 2;
s2[1].b = 4;
- // cr_assert_arrays_eq(s1, s2, 2); not guaranteed to work on structs.
- cr_assert_arrays_eq_cmp(s1, s2, 2, eq_dummy);
+ // cr_assert_arr_eq(s1, s2, 2); not guaranteed to work on structs.
+ cr_assert_arr_eq_cmp(s1, s2, 2, eq_dummy);
#endif
}
diff --git a/samples/asserts.c.bin.err.expected b/samples/asserts.c.bin.err.expected
index 0f81d72..95d9a94 100644
--- a/samples/asserts.c.bin.err.expected
+++ b/samples/asserts.c.bin.err.expected
@@ -1,6 +1,7 @@
-[[0;34m----[0m] [0;1masserts.c[0m:[0;31m9[0m: Assertion failed: assert is fatal, expect isn't
-[[0;34m----[0m] [0;1masserts.c[0m:[0;31m10[0m: Assertion failed: This assert runs
+[[0;34m----[0m] [0;1masserts.c[0m:[0;31m11[0m: Assertion failed: assert is fatal, expect isn't
+[[0;34m----[0m] [0;1masserts.c[0m:[0;31m12[0m: Assertion failed: This assert runs
[[0;31mFAIL[0m] asserts::base: (0.00s)
-[[0;34m----[0m] [0;1masserts.c[0m:[0;31m18[0m: Assertion failed: The conditions for this test were not met.
+[[0;34m----[0m] [0;1masserts.c[0m:[0;31m17[0m: Assertion failed: You can fail an assertion with a message from anywhere
+[[0;34m----[0m] [0;1masserts.c[0m:[0;31m18[0m: Assertion failed: The conditions for this assertion were not met.
[[0;31mFAIL[0m] asserts::old_school: (0.00s)
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m6[0;1m | Passing: [0;32m4[0;1m | Failing: [0;31m2[0;1m | Crashing: [0;31m0[0;1m [0m
diff --git a/samples/asserts.cc b/samples/asserts.cc
index c7f5c8f..46c22af 100644
--- a/samples/asserts.cc
+++ b/samples/asserts.cc
@@ -8,29 +8,32 @@ Test(asserts, base) {
cr_assert(true, "Assertions may take failure messages");
+ cr_assert(true, "Or even %d format string %s", 1, "with parameters");
+
cr_expect(false, "assert is fatal, expect isn't");
cr_assert(false, "This assert runs");
cr_assert(false, "This does not");
}
Test(asserts, old_school) {
- if (false)
- cr_abort_test("You can abort the test with a message from anywhere");
-
- cr_abort_test(NULL); // or without a message
+ cr_expect_fail("You can fail an assertion with a message from anywhere");
+ cr_assert_fail(); // or without a message
}
Test(asserts, string) {
- cr_assert_strings_eq("hello", "hello");
- cr_assert_strings_neq("hello", "olleh");
+ cr_assert_str_empty("");
+ cr_assert_str_not_empty("foo");
- cr_assert_strings_gt("hello", "hell");
- cr_assert_strings_geq("hello", "hell");
- cr_assert_strings_geq("hello", "hello");
+ cr_assert_str_eq("hello", "hello");
+ cr_assert_str_neq("hello", "olleh");
- cr_assert_strings_lt("hell", "hello");
- cr_assert_strings_leq("hell", "hello");
- cr_assert_strings_leq("hello", "hello");
+ cr_assert_str_gt("hello", "hell");
+ cr_assert_str_geq("hello", "hell");
+ cr_assert_str_geq("hello", "hello");
+
+ cr_assert_str_lt("hell", "hello");
+ cr_assert_str_leq("hell", "hello");
+ cr_assert_str_leq("hello", "hello");
}
Test(asserts, native) {
@@ -64,8 +67,8 @@ Test(asserts, array) {
int arr1[] = {1, 2, 3, 4};
int arr2[] = {4, 3, 2, 1};
- cr_assert_arrays_eq(arr1, arr1, 4);
- cr_assert_arrays_neq(arr1, arr2, 4);
+ cr_assert_arr_eq(arr1, arr1, 4);
+ cr_assert_arr_neq(arr1, arr2, 4);
#ifdef __GNUC__
struct dummy_struct s1[] = {{4, 2}, {2, 4}};
@@ -76,8 +79,8 @@ Test(asserts, array) {
s2[1].a = 2;
s2[1].b = 4;
- // cr_assert_arrays_eq(s1, s2, 2); not guaranteed to work on structs.
- cr_assert_arrays_eq_cmp(s1, s2, 2, eq_dummy);
+ // cr_assert_arrays_eq(&s1, &s2, 2); not guaranteed to work on structs.
+ cr_assert_arr_eq_cmp(&s1, &s2, 2, eq_dummy);
#endif
}
diff --git a/samples/asserts.cc.bin.err.expected b/samples/asserts.cc.bin.err.expected
index 8b27ddd..ac5d522 100644
--- a/samples/asserts.cc.bin.err.expected
+++ b/samples/asserts.cc.bin.err.expected
@@ -1,8 +1,11 @@
-[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m11[0m: Assertion failed: assert is fatal, expect isn't
-[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m12[0m: Assertion failed: This assert runs
+[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m83[0m: Assertion failed: The expression (&s1)[0 .. 2] == (&s2)[0 .. 2] is false.
+[[0;31mFAIL[0m] asserts::array: (0.00s)
+[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m13[0m: Assertion failed: assert is fatal, expect isn't
+[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m14[0m: Assertion failed: This assert runs
[[0;31mFAIL[0m] asserts::base: (0.00s)
-[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m86[0m: Assertion failed: 0
+[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m89[0m: Assertion failed: The conditions for this assertion were not met.
[[0;31mFAIL[0m] asserts::exception: (0.00s)
-[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m20[0m: Assertion failed: The conditions for this test were not met.
+[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m19[0m: Assertion failed: You can fail an assertion with a message from anywhere
+[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m20[0m: Assertion failed: The conditions for this assertion were not met.
[[0;31mFAIL[0m] asserts::old_school: (0.00s)
-[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m7[0;1m | Passing: [0;32m4[0;1m | Failing: [0;31m3[0;1m | Crashing: [0;31m0[0;1m [0m
+[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m7[0;1m | Passing: [0;32m3[0;1m | Failing: [0;31m4[0;1m | Crashing: [0;31m0[0;1m [0m
diff --git a/samples/description.c.bin.err.expected b/samples/description.c.bin.err.expected
index 64ffe21..2cc0d10 100644
--- a/samples/description.c.bin.err.expected
+++ b/samples/description.c.bin.err.expected
@@ -1,3 +1,3 @@
-[[0;34m----[0m] [0;1mdescription.c[0m:[0;31m4[0m: Assertion failed: 0
+[[0;34m----[0m] [0;1mdescription.c[0m:[0;31m4[0m: Assertion failed: The expression 0 is false.
[[0;31mFAIL[0m] misc::failing: (0.00s)
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m1[0;1m | Passing: [0;32m0[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
diff --git a/samples/description.cc.bin.err.expected b/samples/description.cc.bin.err.expected
index 730b527..b9cebe4 100644
--- a/samples/description.cc.bin.err.expected
+++ b/samples/description.cc.bin.err.expected
@@ -1,3 +1,3 @@
-[[0;34m----[0m] [0;1mdescription.cc[0m:[0;31m4[0m: Assertion failed: 0
+[[0;34m----[0m] [0;1mdescription.cc[0m:[0;31m4[0m: Assertion failed: The expression 0 is false.
[[0;31mFAIL[0m] misc::failing: (0.00s)
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m1[0;1m | Passing: [0;32m0[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
diff --git a/samples/report.c.bin.err.expected b/samples/report.c.bin.err.expected
index 5b8f140..f08bf9a 100644
--- a/samples/report.c.bin.err.expected
+++ b/samples/report.c.bin.err.expected
@@ -1,3 +1,3 @@
-[[0;34m----[0m] [0;1mreport.c[0m:[0;31m5[0m: Assertion failed: 0
+[[0;34m----[0m] [0;1mreport.c[0m:[0;31m5[0m: Assertion failed: The expression 0 is false.
[[0;31mFAIL[0m] sample::test: (0.00s)
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m1[0;1m | Passing: [0;32m0[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
diff --git a/samples/report.cc.bin.err.expected b/samples/report.cc.bin.err.expected
index d81ba26..72c59aa 100644
--- a/samples/report.cc.bin.err.expected
+++ b/samples/report.cc.bin.err.expected
@@ -1,3 +1,3 @@
-[[0;34m----[0m] [0;1mreport.cc[0m:[0;31m5[0m: Assertion failed: 0
+[[0;34m----[0m] [0;1mreport.cc[0m:[0;31m5[0m: Assertion failed: The expression 0 is false.
[[0;31mFAIL[0m] sample::test: (0.00s)
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m1[0;1m | Passing: [0;32m0[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
diff --git a/samples/simple.c.bin.err.expected b/samples/simple.c.bin.err.expected
index ef375ca..a687898 100644
--- a/samples/simple.c.bin.err.expected
+++ b/samples/simple.c.bin.err.expected
@@ -1,3 +1,3 @@
-[[0;34m----[0m] [0;1msimple.c[0m:[0;31m4[0m: Assertion failed: 0
+[[0;34m----[0m] [0;1msimple.c[0m:[0;31m4[0m: Assertion failed: The expression 0 is false.
[[0;31mFAIL[0m] misc::failing: (0.00s)
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m1[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
diff --git a/samples/simple.cc.bin.err.expected b/samples/simple.cc.bin.err.expected
index c52de64..816d6cd 100644
--- a/samples/simple.cc.bin.err.expected
+++ b/samples/simple.cc.bin.err.expected
@@ -1,3 +1,3 @@
-[[0;34m----[0m] [0;1msimple.cc[0m:[0;31m4[0m: Assertion failed: 0
+[[0;34m----[0m] [0;1msimple.cc[0m:[0;31m4[0m: Assertion failed: The expression 0 is false.
[[0;31mFAIL[0m] misc::failing: (0.00s)
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m1[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
diff --git a/samples/tests/CMakeLists.txt b/samples/tests/CMakeLists.txt
new file mode 100644
index 0000000..6399df5
--- /dev/null
+++ b/samples/tests/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(SAMPLES
+ failmessages.c
+)
+
+add_samples("${CMAKE_CURRENT_LIST_DIR}" "${SAMPLES}")
diff --git a/samples/tests/failmessages.c b/samples/tests/failmessages.c
new file mode 100644
index 0000000..e2bc221
--- /dev/null
+++ b/samples/tests/failmessages.c
@@ -0,0 +1,49 @@
+#include
+
+Test(messages, default) {
+ cr_expect(0);
+ cr_expect_eq(0, 1);
+ cr_expect_neq(1, 1);
+ cr_expect_lt(2, 1);
+ cr_expect_leq(2, 1);
+ cr_expect_gt(1, 2);
+ cr_expect_geq(1, 2);
+ cr_expect_null("");
+ cr_expect_not_null(NULL);
+
+ cr_expect_float_eq(1, 2, 0.1);
+ cr_expect_float_neq(2, 2, 0.1);
+
+ cr_expect_str_empty("foo");
+ cr_expect_str_not_empty("");
+ cr_expect_str_eq("abc", "abd");
+ cr_expect_str_neq("abc", "abc");
+ cr_expect_str_lt("abc", "aba");
+ cr_expect_str_leq("abc", "aba");
+ cr_expect_str_gt("abc", "abd");
+ cr_expect_str_geq("abc", "abd");
+}
+
+Test(messages, user) {
+ cr_expect(0, "foo %s", "bar");
+ cr_expect_eq(0, 1, "foo %s", "bar");
+ cr_expect_neq(1, 1, "foo %s", "bar");
+ cr_expect_lt(2, 1, "foo %s", "bar");
+ cr_expect_leq(2, 1, "foo %s", "bar");
+ cr_expect_gt(1, 2, "foo %s", "bar");
+ cr_expect_geq(1, 2, "foo %s", "bar");
+ cr_expect_null("", "foo %s", "bar");
+ cr_expect_not_null(NULL, "foo %s", "bar");
+
+ cr_expect_float_eq(1, 2, 0.1, "foo %s", "bar");
+ cr_expect_float_neq(2, 2, 0.1, "foo %s", "bar");
+
+ cr_expect_str_empty("foo", "foo %s", "bar");
+ cr_expect_str_not_empty("", "foo %s", "bar");
+ cr_expect_str_eq("abc", "abd", "foo %s", "bar");
+ cr_expect_str_neq("abc", "abc", "foo %s", "bar");
+ cr_expect_str_lt("abc", "aba", "foo %s", "bar");
+ cr_expect_str_leq("abc", "aba", "foo %s", "bar");
+ cr_expect_str_gt("abc", "abd", "foo %s", "bar");
+ cr_expect_str_geq("abc", "abd", "foo %s", "bar");
+}
diff --git a/samples/tests/failmessages.c.bin.err.expected b/samples/tests/failmessages.c.bin.err.expected
new file mode 100644
index 0000000..b6af5a9
--- /dev/null
+++ b/samples/tests/failmessages.c.bin.err.expected
@@ -0,0 +1,41 @@
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m4[0m: Assertion failed: The expression 0 is false.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m5[0m: Assertion failed: The expression (0) == (1) is false.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m6[0m: Assertion failed: The expression (1) != (1) is false.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m7[0m: Assertion failed: The expression (2) < (1) is false.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m8[0m: Assertion failed: The expression (2) <= (1) is false.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m9[0m: Assertion failed: The expression (1) > (2) is false.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m10[0m: Assertion failed: The expression (1) >= (2) is false.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m11[0m: Assertion failed: "" is not null.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m12[0m: Assertion failed: ((void *)0) is null.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m14[0m: Assertion failed: The expression (2) - (1) <= (0.1) && (1) - (2) <= (0.1) is false.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m15[0m: Assertion failed: The expression (2) - (2) > (0.1) || (2) - (2) > (0.1) is false.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m17[0m: Assertion failed: "foo" is not empty.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m18[0m: Assertion failed: "" is empty.
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m19[0m: Assertion failed: The expression (as strings) ("abc") == ("abd") is false
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m20[0m: Assertion failed: The expression (as strings) ("abc") != ("abc") is false
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m21[0m: Assertion failed: The expression (as strings) ("abc") < ("aba") is false
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m22[0m: Assertion failed: The expression (as strings) ("abc") <= ("aba") is false
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m23[0m: Assertion failed: The expression (as strings) ("abc") > ("abd") is false
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m24[0m: Assertion failed: The expression (as strings) ("abc") >= ("abd") is false
+[[0;31mFAIL[0m] messages::default: (0.00s)
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m28[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m29[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m30[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m31[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m32[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m33[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m34[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m35[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m36[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m38[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m39[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m41[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m42[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m43[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m44[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m45[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m46[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m47[0m: Assertion failed: foo bar
+[[0;34m----[0m] [0;1mfailmessages.c[0m:[0;31m48[0m: Assertion failed: foo bar
+[[0;31mFAIL[0m] messages::user: (0.00s)
+[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m0[0;1m | Failing: [0;31m2[0;1m | Crashing: [0;31m0[0;1m [0m
diff --git a/samples/tests/failmessages.c.bin.out.expected b/samples/tests/failmessages.c.bin.out.expected
new file mode 100644
index 0000000..e69de29
diff --git a/samples/theories.c b/samples/theories.c
index 6e96a6d..0bbe7cc 100644
--- a/samples/theories.c
+++ b/samples/theories.c
@@ -95,12 +95,12 @@ Theory((char c, bool b, short s, int i, long l, long long ll, float f, double d,
cr_assert_eq(ll, 1);
cr_assert_eq(f, 3.14f);
cr_assert_eq(d, 3.14);
- cr_assert_strings_eq(str, "test");
- cr_assert_strings_eq(cstr, "other test");
+ cr_assert_str_eq(str, "test");
+ cr_assert_str_eq(cstr, "other test");
cr_assert_eq(obj->foo, 42);
// abort to see the formatted string of all parameters
- cr_abort_test(NULL);
+ cr_assert_fail();
}
// Manually generate datapoints
@@ -117,5 +117,5 @@ static void generate_datapoints(void) {
Theory((int i), theory, gen, .init = generate_datapoints) {
(void) i;
- cr_abort_test(NULL); // we fail to display the parameter
+ cr_assert_fail(); // we fail to display the parameter
}
diff --git a/samples/theories.cc b/samples/theories.cc
index d0e3dd3..5602754 100644
--- a/samples/theories.cc
+++ b/samples/theories.cc
@@ -103,12 +103,12 @@ Theory((char c, bool b, short s, int i, long l, long long ll, float f, double d,
cr_assert_eq(ll, 1);
cr_assert_eq(f, 3.14f);
cr_assert_eq(d, 3.14);
- cr_assert_strings_eq(str, "test");
- cr_assert_strings_eq(cstr, "other test");
+ cr_assert_str_eq(str, "test");
+ cr_assert_str_eq(cstr, "other test");
cr_assert_eq(obj->foo, 42);
// abort to see the formatted string of all parameters
- cr_abort_test(NULL);
+ cr_assert_fail();
}
// Manually generate datapoints
@@ -125,5 +125,5 @@ static void generate_datapoints(void) {
Theory((int i), theory, gen, .init = generate_datapoints) {
(void) i;
- cr_abort_test(NULL); // we fail to display the parameter
+ cr_assert_fail(); // we fail to display the parameter
}
diff --git a/src/asprintf.c b/src/asprintf.c
new file mode 100644
index 0000000..c2a4a12
--- /dev/null
+++ b/src/asprintf.c
@@ -0,0 +1,63 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2015 Franklin "Snaipe" Mathieu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+#include
+#include "criterion/asprintf-compat.h"
+
+int cr_asprintf(char **strp, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int res = cr_vasprintf(strp, fmt, ap);
+ va_end(ap);
+ return res;
+}
+
+int cr_vasprintf(char **strp, const char *fmt, va_list ap) {
+ va_list vl;
+ va_copy(vl, ap);
+
+ int size = vsnprintf(0, 0, fmt, vl);
+ int res = -1;
+
+ if (size < 0 || size >= INT_MAX) {
+ goto cleanup;
+ }
+
+ char *str = malloc(size + 1);
+ if (str) {
+ int res2 = vsnprintf(str, size + 1, fmt, ap);
+ if (res2 < 0 || res2 > size) {
+ free(str);
+ goto cleanup;
+ }
+ *strp = str;
+ res = res2;
+ }
+
+cleanup:
+ va_end(vl);
+ return res;
+}
diff --git a/src/event.c b/src/event.c
index 83a92e0..abb85a6 100644
--- a/src/event.c
+++ b/src/event.c
@@ -37,6 +37,12 @@ void destroy_event(void *ptr, UNUSED void *meta) {
free(ev->data);
}
+void destroy_assert_event(void *ptr, UNUSED void *meta) {
+ struct event *ev = ptr;
+ free((void*) ((struct criterion_assert_stats *) ev->data)->message);
+ free(ev->data);
+}
+
struct event *read_event(FILE *f) {
unsigned kind;
if (fread(&kind, sizeof (unsigned), 1, f) == 0)
@@ -45,33 +51,45 @@ struct event *read_event(FILE *f) {
switch (kind) {
case ASSERT: {
const size_t assert_size = sizeof (struct criterion_assert_stats);
- unsigned char *buf = malloc(assert_size);
- if (fread(buf, assert_size, 1, f) == 0) {
- free(buf);
- return NULL;
- }
+ struct criterion_assert_stats *buf = NULL;
+ char *msg = NULL;
+
+ buf = malloc(assert_size);
+ if (fread(buf, assert_size, 1, f) == 0)
+ goto fail_assert;
+
+ size_t len = 0;
+ if (fread(&len, sizeof (size_t), 1, f) == 0)
+ goto fail_assert;
+
+ msg = malloc(len);
+ if (fread(msg, len, 1, f) == 0)
+ goto fail_assert;
+
+ buf->message = msg;
struct event *ev = smalloc(
.size = sizeof (struct event),
- .dtor = destroy_event
+ .dtor = destroy_assert_event
);
*ev = (struct event) { .kind = kind, .data = buf };
return ev;
+
+fail_assert:
+ free(buf);
+ free(msg);
+ return NULL;
}
case THEORY_FAIL: {
- size_t *len = malloc(sizeof (size_t));
- if (fread(len, sizeof (size_t), 1, f) == 0) {
- free(len);
+ size_t len = 0;
+ if (fread(&len, sizeof (size_t), 1, f) == 0)
return NULL;
- }
- char *buf = malloc(*len);
- if (fread(buf, *len, 1, f) == 0) {
- free(len);
+ char *buf = malloc(len);
+ if (fread(buf, len, 1, f) == 0) {
free(buf);
return NULL;
}
- free(len);
struct event *ev = smalloc(
.size = sizeof (struct event),
diff --git a/src/event.h b/src/event.h
index fc8ce4f..21d9b21 100644
--- a/src/event.h
+++ b/src/event.h
@@ -25,6 +25,9 @@
# define EVENT_H_
# include "criterion/event.h"
+# include
+
+extern FILE *g_event_pipe;
struct event {
int kind;
diff --git a/src/log/normal.c b/src/log/normal.c
index 9f278cf..dedcd5e 100644
--- a/src/log/normal.c
+++ b/src/log/normal.c
@@ -160,8 +160,7 @@ void normal_log_post_all(struct criterion_global_stats *stats) {
void normal_log_assert(struct criterion_assert_stats *stats) {
if (!stats->passed) {
- char *dup = strdup(*stats->message ? stats->message
- : stats->condition);
+ char *dup = strdup(*stats->message ? stats->message : "");
#ifdef VANILLA_WIN32
char *line = strtok(dup, "\n");
diff --git a/src/log/tap.c b/src/log/tap.c
index c58d0fd..76937a0 100644
--- a/src/log/tap.c
+++ b/src/log/tap.c
@@ -86,7 +86,7 @@ void tap_log_post_test(struct criterion_test_stats *stats) {
stats->elapsed_time);
for (struct criterion_assert_stats *asrt = stats->asserts; asrt; asrt = asrt->next) {
if (!asrt->passed) {
- char *dup = strdup(*asrt->message ? asrt->message : asrt->condition);
+ char *dup = strdup(*asrt->message ? asrt->message : "");
#ifdef VANILLA_WIN32
char *line = strtok(dup, "\n");
#else
diff --git a/src/theories.c b/src/theories.c
index 3bf0f5b..9e440ff 100644
--- a/src/theories.c
+++ b/src/theories.c
@@ -23,6 +23,7 @@
*/
#include
#include
+#include
#include
#include
#include