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 @@ -[----] asserts.c:9: Assertion failed: assert is fatal, expect isn't -[----] asserts.c:10: Assertion failed: This assert runs +[----] asserts.c:11: Assertion failed: assert is fatal, expect isn't +[----] asserts.c:12: Assertion failed: This assert runs [FAIL] asserts::base: (0.00s) -[----] asserts.c:18: Assertion failed: The conditions for this test were not met. +[----] asserts.c:17: Assertion failed: You can fail an assertion with a message from anywhere +[----] asserts.c:18: Assertion failed: The conditions for this assertion were not met. [FAIL] asserts::old_school: (0.00s) [====] Synthesis: Tested: 6 | Passing: 4 | Failing: 2 | Crashing: 0  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 @@ -[----] asserts.cc:11: Assertion failed: assert is fatal, expect isn't -[----] asserts.cc:12: Assertion failed: This assert runs +[----] asserts.cc:83: Assertion failed: The expression (&s1)[0 .. 2] == (&s2)[0 .. 2] is false. +[FAIL] asserts::array: (0.00s) +[----] asserts.cc:13: Assertion failed: assert is fatal, expect isn't +[----] asserts.cc:14: Assertion failed: This assert runs [FAIL] asserts::base: (0.00s) -[----] asserts.cc:86: Assertion failed: 0 +[----] asserts.cc:89: Assertion failed: The conditions for this assertion were not met. [FAIL] asserts::exception: (0.00s) -[----] asserts.cc:20: Assertion failed: The conditions for this test were not met. +[----] asserts.cc:19: Assertion failed: You can fail an assertion with a message from anywhere +[----] asserts.cc:20: Assertion failed: The conditions for this assertion were not met. [FAIL] asserts::old_school: (0.00s) -[====] Synthesis: Tested: 7 | Passing: 4 | Failing: 3 | Crashing: 0  +[====] Synthesis: Tested: 7 | Passing: 3 | Failing: 4 | Crashing: 0  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 @@ -[----] description.c:4: Assertion failed: 0 +[----] description.c:4: Assertion failed: The expression 0 is false. [FAIL] misc::failing: (0.00s) [====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0  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 @@ -[----] description.cc:4: Assertion failed: 0 +[----] description.cc:4: Assertion failed: The expression 0 is false. [FAIL] misc::failing: (0.00s) [====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0  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 @@ -[----] report.c:5: Assertion failed: 0 +[----] report.c:5: Assertion failed: The expression 0 is false. [FAIL] sample::test: (0.00s) [====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0  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 @@ -[----] report.cc:5: Assertion failed: 0 +[----] report.cc:5: Assertion failed: The expression 0 is false. [FAIL] sample::test: (0.00s) [====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0  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 @@ -[----] simple.c:4: Assertion failed: 0 +[----] simple.c:4: Assertion failed: The expression 0 is false. [FAIL] misc::failing: (0.00s) [====] Synthesis: Tested: 2 | Passing: 1 | Failing: 1 | Crashing: 0  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 @@ -[----] simple.cc:4: Assertion failed: 0 +[----] simple.cc:4: Assertion failed: The expression 0 is false. [FAIL] misc::failing: (0.00s) [====] Synthesis: Tested: 2 | Passing: 1 | Failing: 1 | Crashing: 0  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 @@ +[----] failmessages.c:4: Assertion failed: The expression 0 is false. +[----] failmessages.c:5: Assertion failed: The expression (0) == (1) is false. +[----] failmessages.c:6: Assertion failed: The expression (1) != (1) is false. +[----] failmessages.c:7: Assertion failed: The expression (2) < (1) is false. +[----] failmessages.c:8: Assertion failed: The expression (2) <= (1) is false. +[----] failmessages.c:9: Assertion failed: The expression (1) > (2) is false. +[----] failmessages.c:10: Assertion failed: The expression (1) >= (2) is false. +[----] failmessages.c:11: Assertion failed: "" is not null. +[----] failmessages.c:12: Assertion failed: ((void *)0) is null. +[----] failmessages.c:14: Assertion failed: The expression (2) - (1) <= (0.1) && (1) - (2) <= (0.1) is false. +[----] failmessages.c:15: Assertion failed: The expression (2) - (2) > (0.1) || (2) - (2) > (0.1) is false. +[----] failmessages.c:17: Assertion failed: "foo" is not empty. +[----] failmessages.c:18: Assertion failed: "" is empty. +[----] failmessages.c:19: Assertion failed: The expression (as strings) ("abc") == ("abd") is false +[----] failmessages.c:20: Assertion failed: The expression (as strings) ("abc") != ("abc") is false +[----] failmessages.c:21: Assertion failed: The expression (as strings) ("abc") < ("aba") is false +[----] failmessages.c:22: Assertion failed: The expression (as strings) ("abc") <= ("aba") is false +[----] failmessages.c:23: Assertion failed: The expression (as strings) ("abc") > ("abd") is false +[----] failmessages.c:24: Assertion failed: The expression (as strings) ("abc") >= ("abd") is false +[FAIL] messages::default: (0.00s) +[----] failmessages.c:28: Assertion failed: foo bar +[----] failmessages.c:29: Assertion failed: foo bar +[----] failmessages.c:30: Assertion failed: foo bar +[----] failmessages.c:31: Assertion failed: foo bar +[----] failmessages.c:32: Assertion failed: foo bar +[----] failmessages.c:33: Assertion failed: foo bar +[----] failmessages.c:34: Assertion failed: foo bar +[----] failmessages.c:35: Assertion failed: foo bar +[----] failmessages.c:36: Assertion failed: foo bar +[----] failmessages.c:38: Assertion failed: foo bar +[----] failmessages.c:39: Assertion failed: foo bar +[----] failmessages.c:41: Assertion failed: foo bar +[----] failmessages.c:42: Assertion failed: foo bar +[----] failmessages.c:43: Assertion failed: foo bar +[----] failmessages.c:44: Assertion failed: foo bar +[----] failmessages.c:45: Assertion failed: foo bar +[----] failmessages.c:46: Assertion failed: foo bar +[----] failmessages.c:47: Assertion failed: foo bar +[----] failmessages.c:48: Assertion failed: foo bar +[FAIL] messages::user: (0.00s) +[====] Synthesis: Tested: 2 | Passing: 0 | Failing: 2 | Crashing: 0  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