diff --git a/CMakeLists.txt b/CMakeLists.txt
index 958a62d..2038e17 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -110,6 +110,12 @@ if (PCRE_FOUND)
set(HAVE_PCRE 1)
endif ()
+if ("${CMAKE_SYSTEM_NAME}" EQUAL "Linux")
+ set (SOURCE_FILES ${SOURCE_FILES}
+ src/asprintf.c
+ )
+endif ()
+
set(INTERFACE_FILES
include/criterion/assert.h
include/criterion/abort.h
@@ -123,6 +129,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/include/criterion/abort.h b/include/criterion/abort.h
index 598b27e..ca981b5 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_API CR_INLINE 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..2fc5c1b
--- /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 asprintf(char **strp, const char *fmt, ...) CR_NOTHROW;
+CR_API int vasprintf(char **strp, const char *fmt, va_list ap) CR_NOTHROW;
+
+CR_END_C_API
+
+#endif /* !CRITERION_ASPRINTF_COMPAT_H_ */
diff --git a/include/criterion/assert.h b/include/criterion/assert.h
index 1d67a00..4aeaa9b 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,264 +57,372 @@ 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))
+# ifdef __cplusplus
+# define CR_STDN std::
# else
-# define CR_ZERO_FILL(Arg) std::memset(&(Arg), 0, sizeof (Arg))
+# define CR_STDN
# endif
-# define cr_assert_impl(Kind, ...) \
+# define CR_INIT_STATS_(BufSize, MsgVar, ...) CR_EXPAND( \
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(); \
+ const char *default_msg = "" CR_VA_HEAD(__VA_ARGS__); \
+ char *formatted_msg = NULL; \
+ int msglen = asprintf(&formatted_msg, "" CR_VA_TAIL(__VA_ARGS__)); \
+ MsgVar = formatted_msg ? formatted_msg : default_msg; \
+ \
+ if (!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; \
+ buf += sizeof (size_t); \
+ CR_STDN strcpy(buf, MsgVar); \
+ CR_STDN free(formatted_msg); \
+ } while (0))
+
+# define CR_FAIL_ABORT_ criterion_abort_test
+# define CR_FAIL_CONTINUES_ criterion_continue_test
+
+# define cr_assert_impl(Fail, Condition, ...) \
+ do { \
+ bool passed = !!(Condition); \
+ \
+ const char *msg = NULL; \
+ size_t bufsize; \
+ \
+ _Pragma("GCC diagnostic ignored \"-Wformat-zero-length\"") \
+ 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)
-// Common asserts
+// Base assertions
-# define cr_abort_test(Message) \
- do { \
- const char *msg = (Message); \
- cr_assert(0, msg ? msg : "The conditions for this test were not met.");\
+# define cr_fail(Fail, ...) \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ 0, \
+ dummy, \
+ "The condition 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, \
+ CR_STR(CR_VA_HEAD(__VA_ARGS__)), \
+ CR_VA_TAIL(__VA_ARGS__)))
+
+# define cr_expect(...) CR_EXPAND(cr_assert_impl( \
+ CR_FAIL_CONTINUES_, \
+ CR_VA_HEAD(__VA_ARGS__), \
+ dummy, \
+ CR_STR(CR_VA_HEAD(__VA_ARGS__)), \
+ CR_VA_TAIL(__VA_ARGS__)))
+
+# define cr_assert_not(...) CR_EXPAND(cr_assert_impl( \
+ CR_FAIL_ABORT_, \
+ !(CR_VA_HEAD(__VA_ARGS__)), \
+ dummy, \
+ CR_STR(!(CR_VA_HEAD(__VA_ARGS__))), \
+ CR_VA_TAIL(__VA_ARGS__)))
+
+# define cr_expect_not(...) CR_EXPAND(cr_assert_impl( \
+ CR_FAIL_CONTINUES_, \
+ !(CR_VA_HEAD(__VA_ARGS__)), \
+ dummy, \
+ CR_STR(!(CR_VA_HEAD(__VA_ARGS__))), \
+ 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, \
+ CR_STR((Actual) Op (Expected)), \
+ __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(...) CR_EXPAND(cr_assert_eq(CR_VA_HEAD(__VA_ARGS__), NULL, CR_VA_TAIL(__VA_ARGS__)))
+# define cr_expect_null(...) CR_EXPAND(cr_expect_eq(CR_VA_HEAD(__VA_ARGS__), NULL, CR_VA_TAIL(__VA_ARGS__)))
+
+# define cr_assert_not_null(...) CR_EXPAND(cr_assert_neq(CR_VA_HEAD(__VA_ARGS__), NULL, CR_VA_TAIL(__VA_ARGS__)))
+# define cr_expect_not_null(...) CR_EXPAND(cr_expect_neq(CR_VA_HEAD(__VA_ARGS__), NULL, CR_VA_TAIL(__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, \
+ CR_STR(Op(Actual, Expected, Epsilon)), \
+ __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_(Fail, Op, Actual, Expected, ...) \
+ CR_EXPAND(cr_assert_impl( \
+ Fail, \
+ CR_STDN strcmp((Actual), (Expected)) Op 0, \
+ dummy, \
+ CR_STR((as strings) (Actual) Op (Expected)), \
+ __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, \
+ CR_STR((Actual)[0 .. Size] Op (Expected)[0 .. Size]), \
+ __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, \
+ CR_STR((Actual)[0 .. Size] Op (Expected)[0 .. Size]), \
+ __VA_ARGS__ \
+ )); \
} while (0)
-# ifdef __cplusplus
-# define CR_SENTINEL 0
+# 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_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_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_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 CR_SENTINEL .sentinel_ = 0
+
+# 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
-# define cr_assert(...) CR_EXPAND(cr_assert_(__VA_ARGS__, CR_SENTINEL))
-
-# 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__))
-
-# 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)
-
-# 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__); \
- } 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__); \
- } 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_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_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_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__ */
-
# 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 &ex) { \
+ } 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 &ex) { 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__( \
@@ -326,6 +431,13 @@ struct criterion_assert_args {
"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." \
+ )
+
# define CRITERION_ASSERT_DEPRECATED__(Msg) \
_Pragma(#Msg)
@@ -339,6 +451,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/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/asserts.c b/samples/asserts.c
index 0d9daab..2318944 100644
--- a/samples/asserts.c
+++ b/samples/asserts.c
@@ -12,23 +12,21 @@ Test(asserts, base) {
}
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_eq("hello", "hello");
+ cr_assert_str_neq("hello", "olleh");
- cr_assert_strings_gt("hello", "hell");
- cr_assert_strings_geq("hello", "hell");
- cr_assert_strings_geq("hello", "hello");
+ cr_assert_str_gt("hello", "hell");
+ cr_assert_str_geq("hello", "hell");
+ cr_assert_str_geq("hello", "hello");
- cr_assert_strings_lt("hell", "hello");
- cr_assert_strings_leq("hell", "hello");
- cr_assert_strings_leq("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 +60,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 +72,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.cc b/samples/asserts.cc
index c7f5c8f..98cd394 100644
--- a/samples/asserts.cc
+++ b/samples/asserts.cc
@@ -14,23 +14,21 @@ Test(asserts, base) {
}
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_eq("hello", "hello");
+ cr_assert_str_neq("hello", "olleh");
- cr_assert_strings_gt("hello", "hell");
- cr_assert_strings_geq("hello", "hell");
- cr_assert_strings_geq("hello", "hello");
+ cr_assert_str_gt("hello", "hell");
+ cr_assert_str_geq("hello", "hell");
+ cr_assert_str_geq("hello", "hello");
- cr_assert_strings_lt("hell", "hello");
- cr_assert_strings_leq("hell", "hello");
- cr_assert_strings_leq("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 +62,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 +74,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/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..2eada51
--- /dev/null
+++ b/src/asprintf.c
@@ -0,0 +1,62 @@
+/*
+ * 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 "criterion/asprintf-compat.h"
+
+int asprintf(char **strp, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int res = vasprintf(strp, fmt, ap);
+ va_end(ap);
+ return res;
+}
+
+int 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..ba91d73 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)->message);
+ free(ev->data);
+}
+
struct event *read_event(FILE *f) {
unsigned kind;
if (fread(&kind, sizeof (unsigned), 1, f) == 0)
@@ -45,18 +51,36 @@ 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;
+ size_t *len = NULL;
+ char *msg = NULL;
+
+ buf = malloc(assert_size);
+ if (fread(buf, assert_size, 1, f) == 0)
+ goto fail_assert;
+
+ len = malloc(sizeof (size_t));
+ if (fread(len, sizeof (size_t), 1, f) == 0)
+ goto fail_assert;
+
+ msg = malloc(*len);
+ if (fread(buf, *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(len);
+ free(buf);
+ free(msg);
+ return NULL;
}
case THEORY_FAIL: {
size_t *len = malloc(sizeof (size_t));
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