asserts: Add assertions for wide strings

This commit creates _wcs_ variants of the _str_ assertions for operating
on wchar_t * instead of char *.  The assertions are useful for programs
using wchar_t strings, particularly on Windows where use of the wide
character version of the Windows API is encouraged by Microsoft.

Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
This commit is contained in:
Kevin Locke 2016-09-09 16:39:16 -06:00 committed by Snaipe
parent 59ed78c4a2
commit 07c380d6b7
9 changed files with 418 additions and 9 deletions

View File

@ -29,6 +29,11 @@ String Assertions
.. doxygengroup:: StringAsserts
Wide String Assertions
----------------------
.. doxygengroup:: WideStringAsserts
Array Assertions
-----------------

View File

@ -800,6 +800,288 @@
/**@}*/
/**
* @defgroup WideStringAsserts Wide String Assertions
*
* @note
* These macros are meant to deal with *native* wide character strings, i.e.
* wchar_t arrays. Most of them won't work on ``std::wstring`` in C++, with
* some exceptions -- for ``std::wstring``, you should use regular comparison
* assertions.
*
* @{
*/
/**
* Passes if Value is an empty wide string
*
* Passes if Value is an empty wide string.
* Otherwise the test is marked as failure and the execution of the function
* is aborted.
*
* The optional (non-wide) string is printed on failure.
*
* @note Also works on std::wstring.
*
* @param[in] Value Wide string to test
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_assert_wcs_empty(Value, FormatString, ...) internal
/**
* Passes if Value is an empty wide string
*
* Passes if Value is an empty wide string.
* Otherwise the test is marked as failure but the execution will continue.
*
* The optional (non-wide) string is printed on failure.
*
* @note Also works on std::wstring.
*
* @param[in] Value Wide string to test
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_expect_wcs_empty(Value, FormatString, ...) internal
/**
* Passes if Value is not an empty wide string
*
* Passes if Value is not an empty wide string.
* Otherwise the test is marked as failure and the execution of the function
* is aborted.
*
* The optional (non-wide) string is printed on failure.
*
* @note Also works on std::string.
*
* @param[in] Value Wide string to test
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_assert_wcs_not_empty(Value, FormatString, ...) internal
/**
* Passes if Value is not an empty wide string
*
* Passes if Value is not an empty wide string.
* Otherwise the test is marked as failure but the execution will continue.
*
* The optional (non-wide) string is printed on failure.
*
* @note Also works on std::string.
*
* @param[in] Value Wide string to test
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_expect_wcs_not_empty(Value, FormatString, ...) internal
/**
* Passes if Actual is lexicographically equal to Expected
*
* Passes if Actual is lexicographically equal to Expected.
* Otherwise the test is marked as failure and the execution of the function
* is aborted.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Expected Expected wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_assert_wcs_eq(Actual, Expected, FormatString, ...) internal
/**
* Passes if Actual is lexicographically equal to Expected
*
* Passes if Actual is lexicographically equal to Expected.
* Otherwise the test is marked as failure but the execution will continue.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Expected Expected wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_expect_wcs_eq(Actual, Expected, FormatString, ...) internal
/**
* Passes if Actual is not lexicographically equal to Unexpected
*
* Passes if Actual is not lexicographically equal to Unexpected.
* Otherwise the test is marked as failure and the execution of the function
* is aborted.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Unexpected Unexpected wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_assert_wcs_neq(Actual, Unexpected, FormatString, ...) internal
/**
* Passes if Actual is not lexicographically equal to Unexpected
*
* Passes if Actual is not lexicographically equal to Unexpected.
* Otherwise the test is marked as failure but the execution will continue.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Unexpected Unexpected wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_expect_wcs_neq(Actual, Unexpected, FormatString, ...) internal
/**
* Passes if Actual is lexicographically less than Reference
*
* Passes if Actual is lexicographically less than Reference.
* Otherwise the test is marked as failure and the execution of the function
* is aborted.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Reference Reference wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_assert_wcs_lt(Actual, Reference, FormatString, ...) internal
/**
* Passes if Actual is lexicographically less than Reference
*
* Passes if Actual is lexicographically less than Reference.
* Otherwise the test is marked as failure but the execution will continue.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Reference Reference wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_expect_wcs_lt(Actual, Reference, FormatString, ...) internal
/**
* Passes if Actual is lexicographically less or equal to Reference
*
* Passes if Actual is lexicographically less or equal to Reference.
* Otherwise the test is marked as failure and the execution of the function
* is aborted.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Reference Reference wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_assert_wcs_leq(Actual, Reference, FormatString, ...) internal
/**
* Passes if Actual is lexicographically less or equal to Reference
*
* Passes if Actual is lexicographically less or equal to Reference.
* Otherwise the test is marked as failure but the execution will continue.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Reference Reference wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_expect_wcs_leq(Actual, Reference, FormatString, ...) internal
/**
* Passes if Actual is lexicographically greater than Reference
*
* Passes if Actual is lexicographically greater than Reference.
* Otherwise the test is marked as failure and the execution of the function
* is aborted.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Reference Reference wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_assert_wcs_gt(Actual, Reference, FormatString, ...) internal
/**
* Passes if Actual is lexicographically greater than Reference
*
* Passes if Actual is lexicographically greater than Reference.
* Otherwise the test is marked as failure but the execution will continue.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Reference Reference wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_expect_wcs_gt(Actual, Reference, FormatString, ...) internal
/**
* Passes if Actual is lexicographically greater or equal to Reference
*
* Passes if Actual is lexicographically greater or equal to Reference.
* Otherwise the test is marked as failure and the execution of the function
* is aborted.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Reference Reference wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_assert_wcs_geq(Actual, Reference, FormatString, ...) internal
/**
* Passes if Actual is lexicographically greater or equal to Reference
*
* Passes if Actual is lexicographically greater or equal to Reference.
* Otherwise the test is marked as failure but the execution will continue.
*
* The optional (non-wide) string is printed on failure.
*
* @param[in] Actual Wide string to test
* @param[in] Reference Reference wide string
* @param[in] FormatString (optional) printf-like format string
* @param[in] ... (optional) format string parameters
*
*****************************************************************************/
#define cr_expect_wcs_geq(Actual, Reference, FormatString, ...) internal
/**@}*/
/**
* @defgroup ArrayAsserts Array assertions
* @{

View File

@ -32,10 +32,12 @@
#ifdef __cplusplus
# include <cstring>
# include <cstdlib>
# include <cwchar>
#else
# include <string.h>
# include <stdlib.h>
# include <stdbool.h>
# include <wchar.h>
#endif
#include "../types.h"
#include "../stats.h"
@ -300,6 +302,54 @@ CR_END_C_API
CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
))
/* Wide String */
#define cr_assert_wcs_op_empty_(Fail, Op, Msg, Value, ...) \
do { \
const wchar_t *cr_wcs_value__ = (Value); \
CR_EXPAND(cr_assert_impl( \
Fail, \
((cr_wcs_value__) != NULL) && (cr_wcs_value__)[0] Op L'\0', \
dummy, \
((cr_wcs_value__) != NULL) ? Msg : CRITERION_ASSERT_MSG_IS_NULL, \
(CR_STR(Value), cr_wcs_value__), \
__VA_ARGS__ \
)); \
} while (0)
#define cr_assert_wcs_op_empty_va_(Fail, Op, Msg, ...) \
CR_EXPAND(cr_assert_wcs_op_empty_( \
Fail, \
Op, \
Msg, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_TAIL(__VA_ARGS__) \
))
#define cr_assert_wcs_op_(Fail, Op, Actual, Expected, ...) \
do { \
const wchar_t *cr_wcs_actual__ = (Actual); \
const wchar_t *cr_wcs_expected__ = (Expected); \
CR_EXPAND(cr_assert_impl( \
Fail, \
((cr_wcs_actual__) != NULL) && ((cr_wcs_expected__) != NULL) \
&& CR_STDN wcscmp((cr_wcs_actual__), (cr_wcs_expected__)) Op 0, \
dummy, \
CRITERION_ASSERT_MSG_EXPR_FALSE, \
(CR_STR((Actual) Op (Expected))), \
__VA_ARGS__ \
)); \
} while (0)
#define cr_assert_wcs_op_va_(Fail, Op, ...) \
CR_EXPAND(cr_assert_wcs_op_( \
Fail, \
Op, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
))
/* Array */
#define cr_assert_mem_op_(Fail, Op, Actual, Expected, Size, ...) \
@ -550,6 +600,38 @@ CR_END_C_API
#define cr_assert_str_geq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, >=, __VA_ARGS__))
#undef cr_expect_str_geq
#define cr_expect_str_geq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, >=, __VA_ARGS__))
#undef cr_assert_wcs_empty
#define cr_assert_wcs_empty(...) CR_EXPAND(cr_assert_wcs_op_empty_va_(CR_FAIL_ABORT_, ==, CRITERION_ASSERT_MSG_IS_NOT_EMPTY, __VA_ARGS__))
#undef cr_expect_wcs_empty
#define cr_expect_wcs_empty(...) CR_EXPAND(cr_assert_wcs_op_empty_va_(CR_FAIL_CONTINUES_, ==, CRITERION_ASSERT_MSG_IS_NOT_EMPTY, __VA_ARGS__))
#undef cr_assert_wcs_not_empty
#define cr_assert_wcs_not_empty(...) CR_EXPAND(cr_assert_wcs_op_empty_va_(CR_FAIL_ABORT_, !=, CRITERION_ASSERT_MSG_IS_EMPTY, __VA_ARGS__))
#undef cr_expect_wcs_not_empty
#define cr_expect_wcs_not_empty(...) CR_EXPAND(cr_assert_wcs_op_empty_va_(CR_FAIL_CONTINUES_, !=, CRITERION_ASSERT_MSG_IS_EMPTY, __VA_ARGS__))
#undef cr_assert_wcs_eq
#define cr_assert_wcs_eq(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
#undef cr_expect_wcs_eq
#define cr_expect_wcs_eq(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_CONTINUES_, ==, __VA_ARGS__))
#undef cr_assert_wcs_neq
#define cr_assert_wcs_neq(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_ABORT_, !=, __VA_ARGS__))
#undef cr_expect_wcs_neq
#define cr_expect_wcs_neq(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_CONTINUES_, !=, __VA_ARGS__))
#undef cr_assert_wcs_lt
#define cr_assert_wcs_lt(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_ABORT_, <, __VA_ARGS__))
#undef cr_expect_wcs_lt
#define cr_expect_wcs_lt(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_CONTINUES_, <, __VA_ARGS__))
#undef cr_assert_wcs_leq
#define cr_assert_wcs_leq(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_ABORT_, <=, __VA_ARGS__))
#undef cr_expect_wcs_leq
#define cr_expect_wcs_leq(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_CONTINUES_, <=, __VA_ARGS__))
#undef cr_assert_wcs_gt
#define cr_assert_wcs_gt(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_ABORT_, >, __VA_ARGS__))
#undef cr_expect_wcs_gt
#define cr_expect_wcs_gt(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_CONTINUES_, >, __VA_ARGS__))
#undef cr_assert_wcs_geq
#define cr_assert_wcs_geq(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_ABORT_, >=, __VA_ARGS__))
#undef cr_expect_wcs_geq
#define cr_expect_wcs_geq(...) CR_EXPAND(cr_assert_wcs_op_va_(CR_FAIL_CONTINUES_, >=, __VA_ARGS__))
#undef cr_assert_arr_eq
#define cr_assert_arr_eq(...) CR_EXPAND(cr_assert_mem_op_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
#undef cr_expect_arr_eq

View File

@ -34,6 +34,22 @@ Test(asserts, string) {
cr_assert_str_leq("hello", "hello");
}
Test(asserts, wstring) {
cr_assert_wcs_empty(L"");
cr_assert_wcs_not_empty(L"foo");
cr_assert_wcs_eq(L"hello", L"hello");
cr_assert_wcs_neq(L"hello", L"olleh");
cr_assert_wcs_gt(L"hello", L"hell");
cr_assert_wcs_geq(L"hello", L"hell");
cr_assert_wcs_geq(L"hello", L"hello");
cr_assert_wcs_lt(L"hell", L"hello");
cr_assert_wcs_leq(L"hell", L"hello");
cr_assert_wcs_leq(L"hello", L"hello");
}
Test(asserts, native) {
cr_assert_eq(1, 1);
cr_assert_neq(1, 2);

View File

@ -37,6 +37,22 @@ Test(asserts, string) {
cr_assert_str_leq("hello", "hello");
}
Test(asserts, wstring) {
cr_assert_wcs_empty(L"");
cr_assert_wcs_not_empty(L"foo");
cr_assert_wcs_eq(L"hello", L"hello");
cr_assert_wcs_neq(L"hello", L"olleh");
cr_assert_wcs_gt(L"hello", L"hell");
cr_assert_wcs_geq(L"hello", L"hell");
cr_assert_wcs_geq(L"hello", L"hello");
cr_assert_wcs_lt(L"hell", L"hello");
cr_assert_wcs_leq(L"hell", L"hello");
cr_assert_wcs_leq(L"hello", L"hello");
}
Test(asserts, native) {
cr_assert_eq(1, 1);
cr_assert_neq(1, 2);

View File

@ -7,7 +7,7 @@ Test C assertions:
[\x1b[0;34m----\x1b[0m] \x1b[0;1masserts.c\x1b[0m:\x1b[0;31m17\x1b[0m: Assertion failed: You can fail an assertion with a message from anywhere (esc)
[\x1b[0;34m----\x1b[0m] \x1b[0;1masserts.c\x1b[0m:\x1b[0;31m18\x1b[0m: Assertion failed: The conditions for this assertion were not met. (esc)
\[\\x1b\[0;31mFAIL\\x1b\[0m\] asserts::old_school: \(\d\.\d\ds\) \(esc\) (re)
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m6\x1b[0;1m | Passing: \x1b[0;32m4\x1b[0;1m | Failing: \x1b[0;31m2\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m7\x1b[0;1m | Passing: \x1b[0;32m5\x1b[0;1m | Failing: \x1b[0;31m2\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
Test C++ assertions:
@ -15,12 +15,12 @@ Test C++ assertions:
[\x1b[0;34m----\x1b[0m] \x1b[0;1masserts.cc\x1b[0m:\x1b[0;31m14\x1b[0m: Assertion failed: assert is fatal, expect isn't (esc)
[\x1b[0;34m----\x1b[0m] \x1b[0;1masserts.cc\x1b[0m:\x1b[0;31m15\x1b[0m: Assertion failed: This assert runs (esc)
\[\\x1b\[0;31mFAIL\\x1b\[0m\] asserts::base: \(\d\.\d\ds\) \(esc\) (re)
[\x1b[0;34m----\x1b[0m] \x1b[0;1masserts.cc\x1b[0m:\x1b[0;31m113\x1b[0m: Assertion failed: The statement `throw std::exception()` did not throw an instance of the `std::bad_alloc` exception. (esc)
[\x1b[0;34m----\x1b[0m] \x1b[0;1masserts.cc\x1b[0m:\x1b[0;31m129\x1b[0m: Assertion failed: The statement `throw std::exception()` did not throw an instance of the `std::bad_alloc` exception. (esc)
\[\\x1b\[0;31mFAIL\\x1b\[0m\] asserts::exception: \(\d\.\d\ds\) \(esc\) (re)
[\x1b[0;34m----\x1b[0m] \x1b[0;1masserts.cc\x1b[0m:\x1b[0;31m20\x1b[0m: Assertion failed: You can fail an assertion with a message from anywhere (esc)
[\x1b[0;34m----\x1b[0m] \x1b[0;1masserts.cc\x1b[0m:\x1b[0;31m21\x1b[0m: Assertion failed: The conditions for this assertion were not met. (esc)
\[\\x1b\[0;31mFAIL\\x1b\[0m\] asserts::old_school: \(\d\.\d\ds\) \(esc\) (re)
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m7\x1b[0;1m | Passing: \x1b[0;32m4\x1b[0;1m | Failing: \x1b[0;31m3\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m8\x1b[0;1m | Passing: \x1b[0;32m5\x1b[0;1m | Failing: \x1b[0;31m3\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
Using redirections

View File

@ -75,18 +75,23 @@ Testing multiple samples with --json
$ asserts.c.bin --json
{
"id": "Criterion v2.3.0-dev",
"passed": 4,
"passed": 5,
"failed": 2,
"errored": 0,
"skipped": 0,
"test_suites": [
{
"name": "asserts",
"passed": 4,
"passed": 5,
"failed": 2,
"errored": 0,
"skipped": 0,
"tests": [
{
"name": "wstring",
"assertions": 10,
"status": "PASSED"
},
{
"name": "string",
"assertions": 10,

View File

@ -22,10 +22,11 @@ Testing multiple samples with --tap
$ asserts.c.bin --tap
TAP version 13
1..6
1..7
# Criterion v2.3.0-dev
# Running 6 tests from asserts
# Running 7 tests from asserts
ok - asserts::wstring \(\d\.\d\ds\) (re)
ok - asserts::string \(\d\.\d\ds\) (re)
not ok - asserts::old_school \(\d\.\d\ds\) (re)
asserts.c:18: Assertion failed: The conditions for this assertion were not met.

View File

@ -31,8 +31,10 @@ Testing multiple samples with --xml
$ asserts.c.bin --xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Tests compiled with Criterion v2.3.0-dev -->
<testsuites name="Criterion Tests" tests="6" failures="2" errors="0" disabled="0">
<testsuite name="asserts" tests="6" failures="2" errors="0" disabled="0" skipped="0" time="0.000">
<testsuites name="Criterion Tests" tests="7" failures="2" errors="0" disabled="0">
<testsuite name="asserts" tests="7" failures="2" errors="0" disabled="0" skipped="0" time="0.000">
<testcase name="wstring" assertions="10" status="PASSED" time="0.000">
</testcase>
<testcase name="string" assertions="10" status="PASSED" time="0.000">
</testcase>
<testcase name="old_school" assertions="2" status="FAILED" time="0.000">