summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cmocka.h35
-rw-r--r--src/cmocka.c6
-rw-r--r--test_ordering_fail.c95
-rw-r--r--tests/CMakeLists.txt14
-rw-r--r--tests/test_returns.c69
-rw-r--r--tests/test_returns_fail.c77
6 files changed, 289 insertions, 7 deletions
diff --git a/include/cmocka.h b/include/cmocka.h
index 6242ff2..fecd873 100644
--- a/include/cmocka.h
+++ b/include/cmocka.h
@@ -304,9 +304,11 @@ void will_return(#function, LargestIntegralType value);
*
* @param[in] value The value to be returned by mock().
*
- * @param[in] count The parameter returns the number of times the value should
- * be returned by mock(). If count is set to -1 the value will
- * always be returned.
+ * @param[in] count The parameter indicates the number of times the value should
+ * be returned by mock(). If count is set to -1, the value
+ * will always be returned but must be returned at least once.
+ * If count is set to -2, the value will always be returned
+ * by mock(), but is not required to be returned.
*
* @see mock()
*/
@@ -339,6 +341,33 @@ void will_return_always(#function, LargestIntegralType value);
will_return_count(function, (value), -1)
#endif
+#ifdef DOXYGEN
+/**
+ * @brief Store a value that may be always returned by mock().
+ *
+ * This stores a value which will always be returned by mock() but is not
+ * required to be returned by at least one call to mock(). Therefore,
+ * in contrast to will_return_always() which causes a test failure if it
+ * is not returned at least once, will_return_maybe() will never cause a test
+ * to fail if its value is not returned.
+ *
+ * @param[in] #function The function which should return the given value.
+ *
+ * @param[in] #value The value to be returned by mock().
+ *
+ * This is equivalent to:
+ * @code
+ * will_return_count(function, value, -2);
+ * @endcode
+ *
+ * @see will_return_count()
+ * @see mock()
+ */
+void will_return_maybe(#function, LargestIntegralType value);
+#else
+#define will_return_maybe(function, value) \
+ will_return_count(function, (value), -2)
+#endif
/** @} */
/**
diff --git a/src/cmocka.c b/src/cmocka.c
index 4f13f21..376acba 100644
--- a/src/cmocka.c
+++ b/src/cmocka.c
@@ -689,8 +689,10 @@ static int get_symbol_value(
assert_true(return_value);
*output = (void*) value_node->value;
return_value = value_node->refcount;
- if (--value_node->refcount == 0) {
+ if (value_node->refcount - 1 == 0) {
list_remove_free(value_node, NULL, NULL);
+ } else if (value_node->refcount > -2) {
+ --value_node->refcount;
}
} else {
return_value = get_symbol_value(
@@ -943,7 +945,7 @@ void _will_return(const char * const function_name, const char * const file,
const int count) {
SymbolValue * const return_value =
(SymbolValue*)malloc(sizeof(*return_value));
- assert_true(count > 0 || count == -1);
+ assert_true(count != 0);
return_value->value = value;
set_source_location(&return_value->location, file, line);
add_symbol_value(&global_function_result_map_head, &function_name, 1,
diff --git a/test_ordering_fail.c b/test_ordering_fail.c
new file mode 100644
index 0000000..652f5ad
--- /dev/null
+++ b/test_ordering_fail.c
@@ -0,0 +1,95 @@
+#include "config.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <cmocka_private.h>
+
+static void mock_test_a_called(void)
+{
+ function_called();
+}
+
+static void mock_test_b_called(void)
+{
+ function_called();
+}
+
+static void mock_test_c_called(void)
+{
+ function_called();
+}
+
+static void test_does_fail_for_unexpected_call(void **state)
+{
+ (void)state;
+ expect_function_call(mock_test_a_called);
+ expect_function_call(mock_test_a_called);
+
+ mock_test_a_called();
+ mock_test_a_called();
+ mock_test_a_called();
+}
+
+static void test_does_fail_for_unmade_expected_call(void **state)
+{
+ (void)state;
+ expect_function_call(mock_test_a_called);
+ expect_function_call(mock_test_a_called);
+
+ mock_test_a_called();
+}
+
+static void test_ordering_fails_out_of_order(void **state)
+{
+ (void)state;
+ expect_function_call(mock_test_a_called);
+ expect_function_call(mock_test_b_called);
+ expect_function_call(mock_test_a_called);
+
+ mock_test_b_called();
+}
+
+static void test_ordering_fails_out_of_order_for_at_least_once_calls(void **state)
+{
+ (void)state;
+ expect_function_call_any(mock_test_a_called);
+ ignore_function_calls(mock_test_b_called);
+
+ mock_test_b_called();
+ mock_test_c_called();
+}
+
+/* Primarily used to test error message */
+static void test_fails_out_of_order_if_no_calls_found_on_any(void **state)
+{
+ (void)state;
+ expect_function_call_any(mock_test_a_called);
+ ignore_function_calls(mock_test_b_called);
+
+ mock_test_a_called();
+ mock_test_c_called();
+}
+
+static void test_fails_if_zero_count_used(void **state)
+{
+ (void)state;
+ expect_function_calls(mock_test_a_called, 0);
+
+ mock_test_a_called();
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_does_fail_for_unexpected_call)
+ ,cmocka_unit_test(test_does_fail_for_unmade_expected_call)
+ ,cmocka_unit_test(test_does_fail_for_unmade_expected_call)
+ ,cmocka_unit_test(test_ordering_fails_out_of_order)
+ ,cmocka_unit_test(test_ordering_fails_out_of_order_for_at_least_once_calls)
+ ,cmocka_unit_test(test_fails_out_of_order_if_no_calls_found_on_any)
+ ,cmocka_unit_test(test_fails_if_zero_count_used)
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 4b015ba..0422487 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -19,7 +19,9 @@ set(CMOCKA_TESTS
test_skip
test_setup_fail
test_ordering
- test_ordering_fail)
+ test_ordering_fail
+ test_returns
+ test_returns_fail)
foreach(_CMOCKA_TEST ${CMOCKA_TESTS})
add_cmocka_test(${_CMOCKA_TEST} ${_CMOCKA_TEST}.c ${CMOCKA_STATIC_LIBRARY})
@@ -33,7 +35,7 @@ add_cmocka_test(test_cmockery test_cmockery.c ${CMOCKA_STATIC_LIBRARY})
### Exceptions
-# test_assert_macros_fail
+# test_skip
set_tests_properties(
test_skip
PROPERTIES
@@ -57,6 +59,14 @@ set_tests_properties(
"\\[ FAILED \\] 7 test"
)
+# test_returns_fail ensure proper failures
+set_tests_properties(
+ test_returns_fail
+ PROPERTIES
+ PASS_REGULAR_EXPRESSION
+ "\\[ FAILED \\] 3 test"
+)
+
# test_exception_handler
if (WIN32)
set_tests_properties(
diff --git a/tests/test_returns.c b/tests/test_returns.c
new file mode 100644
index 0000000..b9370c9
--- /dev/null
+++ b/tests/test_returns.c
@@ -0,0 +1,69 @@
+#include "config.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <cmocka_private.h>
+
+#include <stdlib.h>
+
+int mock_function(void);
+void mock_function_call_times(size_t times, int expectedValue);
+
+int mock_function(void)
+{
+ return (int) mock();
+}
+
+void mock_function_call_times(size_t times, int expectedValue)
+{
+ size_t i;
+ for (i = 0u; i < times; ++i)
+ {
+ assert_int_equal(expectedValue, mock_function());
+ }
+}
+
+static void test_will_return_maybe_for_no_calls(void **state)
+{
+ (void) state;
+
+ will_return_maybe(mock_function, 32);
+}
+
+static void test_will_return_maybe_for_one_mock_call(void **state)
+{
+ int value;
+
+ (void) state;
+
+ value = rand();
+ will_return_maybe(mock_function, value);
+ mock_function_call_times(1u, value);
+}
+
+static void test_will_return_maybe_for_more_than_one_call(void **state)
+{
+ int value;
+ size_t numberOfCalls;
+ (void)state;
+
+ value = rand();
+ numberOfCalls = (size_t) ((rand()) % 20 + 2);
+ will_return_maybe(mock_function, value);
+ mock_function_call_times(numberOfCalls, value);
+}
+
+int main(int argc, char **argv) {
+ const struct CMUnitTest alloc_tests[] = {
+ cmocka_unit_test(test_will_return_maybe_for_no_calls)
+ ,cmocka_unit_test(test_will_return_maybe_for_one_mock_call)
+ ,cmocka_unit_test(test_will_return_maybe_for_more_than_one_call)
+ };
+
+ (void)argc;
+ (void)argv;
+
+ return cmocka_run_group_tests(alloc_tests, NULL, NULL);
+}
diff --git a/tests/test_returns_fail.c b/tests/test_returns_fail.c
new file mode 100644
index 0000000..81197d3
--- /dev/null
+++ b/tests/test_returns_fail.c
@@ -0,0 +1,77 @@
+#include "config.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <cmocka_private.h>
+
+#include <stdlib.h>
+
+int mock_function(void);
+void mock_function_call_times(size_t times, int expectedValue);
+
+int mock_function(void)
+{
+ return (int) mock();
+}
+
+void mock_function_call_times(size_t times, int expectedValue)
+{
+ size_t i;
+ for (i = 0u; i < times; ++i)
+ {
+ assert_int_equal(expectedValue, mock_function());
+ }
+}
+
+static void test_will_return_fails_for_no_calls(void **state)
+{
+ (void) state;
+
+ will_return(mock_function, 32);
+}
+
+static void test_will_return_count_fails_for_unreturned_items(void **state)
+{
+ int value;
+ size_t numberOfCalls;
+
+ (void) state;
+
+ value = rand();
+ numberOfCalls = (size_t) ((rand()) % 20 + 2);
+
+ will_return_count(mock_function, value, numberOfCalls);
+ mock_function_call_times(numberOfCalls - 1u, value);
+}
+
+static void test_will_return_always_fails_for_no_calls(void **state)
+{
+ int value;
+
+ (void) state;
+
+ value = rand();
+
+ will_return_always(mock_function, value);
+}
+
+static int teardown(void **state) {
+ free(*state);
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ const struct CMUnitTest alloc_tests[] = {
+ cmocka_unit_test_teardown(test_will_return_fails_for_no_calls, teardown)
+ ,cmocka_unit_test_teardown(test_will_return_count_fails_for_unreturned_items, teardown)
+ ,cmocka_unit_test_teardown(test_will_return_always_fails_for_no_calls, teardown)
+ };
+
+ (void)argc;
+ (void)argv;
+
+ return cmocka_run_group_tests(alloc_tests, NULL, NULL);
+}