From da9c6660099c70b8a9e8c4f799f1bc913bcdf660 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 9 Jul 2014 17:57:38 +0200 Subject: [PATCH 01/13] add tests to memmgr_mock Signed-off-by: Wilfried Chauveau --- boards/x86/main.c | 1 + core/core.mk | 1 + core/memmgr/memmgr_mock_test.c | 77 ++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 core/memmgr/memmgr_mock_test.c diff --git a/boards/x86/main.c b/boards/x86/main.c index dd8116b..026ae82 100644 --- a/boards/x86/main.c +++ b/boards/x86/main.c @@ -31,6 +31,7 @@ static void runAllTests() RUN_TEST_GROUP(object); RUN_TEST_GROUP(mutex); RUN_TEST_GROUP(spinlock); + RUN_TEST_GROUP(memmgr_mock); } void die(const char *reason) diff --git a/core/core.mk b/core/core.mk index fd55f55..85efe66 100644 --- a/core/core.mk +++ b/core/core.mk @@ -20,6 +20,7 @@ CORE_SRCS = \ $(CORE_DIR)/common/object_test.c \ $(CORE_DIR)/memmgr/memmgr.c \ $(CORE_DIR)/memmgr/memmgr_mock.c \ + $(CORE_DIR)/memmgr/memmgr_mock_test.c \ $(CORE_DIR)/memmgr/memmgr_unity.c \ $(CORE_DIR)/memmgr/memmgr_test.c \ $(CORE_DIR)/memmgr/memmgr_test_alloc.c \ diff --git a/core/memmgr/memmgr_mock_test.c b/core/memmgr/memmgr_mock_test.c new file mode 100644 index 0000000..5fd6e59 --- /dev/null +++ b/core/memmgr/memmgr_mock_test.c @@ -0,0 +1,77 @@ +/* + Copyright 2014 Chauveau Wilfried + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* Includes ------------------------------------------------------------------*/ +#include +#include "tests/common_mock.h" +#include "tests/memmgr_mock.h" +#include "unity_fixture.h" + +/* Macro definitions ---------------------------------------------------------*/ + +/* Type definitions ----------------------------------------------------------*/ + +/* Prototypes ----------------------------------------------------------------*/ + +/* Variables -----------------------------------------------------------------*/ + +/* Private Functions definitions ---------------------------------------------*/ +/* Functions definitions -----------------------------------------------------*/ +TEST_GROUP(memmgr_mock); + +TEST_GROUP_RUNNER(memmgr_mock) +{ + RUN_TEST_CASE(memmgr_mock, free_expect_alloc_failure); + RUN_TEST_CASE(memmgr_mock, alloc_expect_alloc_failure); +} + +TEST_SETUP(memmgr_mock) +{ + +} + +TEST_TEAR_DOWN(memmgr_mock) +{ + +} + +TEST(memmgr_mock, free_expect_alloc_failure) +{ + UnityMalloc_MakeMallocFailAfterCount(0); + + die_Expect("expect init failure"); + VERIFY_DIE_START + mock_mm_free_Expect(NULL); + VERIFY_DIE_END + die_Verify(); +} + +TEST(memmgr_mock, alloc_expect_alloc_failure) +{ + UnityMalloc_MakeMallocFailAfterCount(0); + + die_Expect("expect init failure"); + VERIFY_DIE_START + mock_mm_alloc_Expect(0); + VERIFY_DIE_END + die_Verify(); + + die_Expect("expect init failure"); + VERIFY_DIE_START + mock_mm_alloc_ExpectAndReturn(0, NULL); + VERIFY_DIE_END + die_Verify(); +} From 0e446c2679e9a9edf6f999945af5a533cc6a6c0a Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Thu, 10 Jul 2014 15:51:15 +0200 Subject: [PATCH 02/13] add tests to memmgr_mock Signed-off-by: Wilfried Chauveau --- core/memmgr/memmgr_mock.c | 3 +- core/memmgr/memmgr_mock_test.c | 71 ++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/core/memmgr/memmgr_mock.c b/core/memmgr/memmgr_mock.c index 31030ac..50e263f 100644 --- a/core/memmgr/memmgr_mock.c +++ b/core/memmgr/memmgr_mock.c @@ -153,8 +153,6 @@ static void mock_clean(void) /* Functions definitions -----------------------------------------------------*/ void mock_memmgr_setup(void) { - mock_clean(); - gs_mm_alloc = mm_alloc; gs_mm_free = mm_free; UT_PTR_SET(mm_alloc, mock_mm_alloc); @@ -186,6 +184,7 @@ void mock_mm_free_Expect(void *ptr) void mock_memmgr_verify(void) { + mock_clean(); TEST_ASSERT_NULL_MESSAGE(gs_mock_expect, "Calls were still expected"); } diff --git a/core/memmgr/memmgr_mock_test.c b/core/memmgr/memmgr_mock_test.c index 5fd6e59..485124a 100644 --- a/core/memmgr/memmgr_mock_test.c +++ b/core/memmgr/memmgr_mock_test.c @@ -16,36 +16,53 @@ /* Includes ------------------------------------------------------------------*/ #include +#include "os/memmgr.h" #include "tests/common_mock.h" #include "tests/memmgr_mock.h" #include "unity_fixture.h" -/* Macro definitions ---------------------------------------------------------*/ +static bool gs_this_test_should_fail = false; +static uint32_t gs_mm_alloc_expect_size = 0; +static bool gs_mm_alloc_called = false; -/* Type definitions ----------------------------------------------------------*/ - -/* Prototypes ----------------------------------------------------------------*/ +static void *test_mock_mm_alloc(uint32_t size) +{ + TEST_ASSERT_EQUAL_UINT32(gs_mm_alloc_expect_size, size); + gs_mm_alloc_called = true; -/* Variables -----------------------------------------------------------------*/ + return &gs_mm_alloc_expect_size; +} -/* Private Functions definitions ---------------------------------------------*/ -/* Functions definitions -----------------------------------------------------*/ TEST_GROUP(memmgr_mock); TEST_GROUP_RUNNER(memmgr_mock) { RUN_TEST_CASE(memmgr_mock, free_expect_alloc_failure); RUN_TEST_CASE(memmgr_mock, alloc_expect_alloc_failure); + RUN_TEST_CASE(memmgr_mock, verify_clean_remaining_expectations); + RUN_TEST_CASE(memmgr_mock, fail_on_unexpected_call_to_alloc); + RUN_TEST_CASE(memmgr_mock, fail_on_unexpected_call_to_free); + + RUN_TEST_CASE(memmgr_mock, mock_mm_alloc_should_call_saved_cbk_if_return_not_set); } TEST_SETUP(memmgr_mock) { - + gs_mm_alloc_expect_size = 0; + gs_mm_alloc_called = false; + gs_this_test_should_fail = false; + mock_memmgr_setup(); } TEST_TEAR_DOWN(memmgr_mock) { + mock_memmgr_verify(); + if (gs_this_test_should_fail) { + TEST_ASSERT_MESSAGE((Unity.CurrentTestFailed == 1), + "This test should have failed but did not."); + Unity.CurrentTestFailed = 0; + } } TEST(memmgr_mock, free_expect_alloc_failure) @@ -75,3 +92,41 @@ TEST(memmgr_mock, alloc_expect_alloc_failure) VERIFY_DIE_END die_Verify(); } + +TEST(memmgr_mock, verify_clean_remaining_expectations) +{ + mock_mm_alloc_Expect(0); + if (TEST_PROTECT()) { + mock_memmgr_verify(); + } +} + +TEST(memmgr_mock, fail_on_unexpected_call_to_alloc) +{ + gs_this_test_should_fail = true; + if (TEST_PROTECT()) + { + mm_alloc(0); + } +} + +TEST(memmgr_mock, fail_on_unexpected_call_to_free) +{ + gs_this_test_should_fail = true; + if (TEST_PROTECT()) + { + mm_free(0); + } +} + +TEST(memmgr_mock, mock_mm_alloc_should_call_saved_cbk_if_return_not_set) +{ + UT_PTR_SET(mm_alloc, test_mock_mm_alloc); + mock_memmgr_setup(); + gs_mm_alloc_expect_size = 32; + mock_mm_alloc_Expect(32); + + TEST_ASSERT_EQUAL_PTR(&gs_mm_alloc_expect_size, mm_alloc(32)); + + TEST_ASSERT_TRUE_MESSAGE(gs_mm_alloc_called, "saved cbk was not called"); +} From baf48297cef15b21563cda338a3e76b6d37fca06 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Fri, 11 Jul 2014 16:55:32 +0200 Subject: [PATCH 03/13] mocks & mocks' tests have to be reworked from scratch as real TDD. Signed-off-by: Wilfried Chauveau --- boards/x86/main.c | 3 +- core/core.mk | 1 + core/memmgr/chunk_mock.c | 7 +- core/memmgr/chunk_mock_test.c | 159 ++++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 core/memmgr/chunk_mock_test.c diff --git a/boards/x86/main.c b/boards/x86/main.c index 026ae82..fbe2521 100644 --- a/boards/x86/main.c +++ b/boards/x86/main.c @@ -25,13 +25,14 @@ static char *gs_expected_cause = NULL; static void runAllTests() { + RUN_TEST_GROUP(chunk_mock); + RUN_TEST_GROUP(memmgr_mock); RUN_TEST_GROUP(mm_chunk); RUN_TEST_GROUP(memmgr); RUN_TEST_GROUP(cexcept); RUN_TEST_GROUP(object); RUN_TEST_GROUP(mutex); RUN_TEST_GROUP(spinlock); - RUN_TEST_GROUP(memmgr_mock); } void die(const char *reason) diff --git a/core/core.mk b/core/core.mk index 85efe66..1c4b515 100644 --- a/core/core.mk +++ b/core/core.mk @@ -28,6 +28,7 @@ CORE_SRCS = \ $(CORE_DIR)/memmgr/memmgr_test_realloc.c \ $(CORE_DIR)/memmgr/chunk.c \ $(CORE_DIR)/memmgr/chunk_mock.c \ + $(CORE_DIR)/memmgr/chunk_mock_test.c \ $(CORE_DIR)/memmgr/chunk_test.c \ $(CORE_DIR)/memmgr/chunk_test_tools.c \ $(CORE_DIR)/memmgr/chunk_test_validate.c \ diff --git a/core/memmgr/chunk_mock.c b/core/memmgr/chunk_mock.c index 13292e4..c473c86 100644 --- a/core/memmgr/chunk_mock.c +++ b/core/memmgr/chunk_mock.c @@ -174,8 +174,6 @@ static void mock_clean(void) /* Definitions ---------------------------------------------------------------*/ void mock_chunk_setup(void) { - mock_clean(); - gs_chunk_split = mm_chunk_split; gs_chunk_merge = mm_chunk_merge; UT_PTR_SET(mm_find_first_free, mock_mm_find_first_free); @@ -186,8 +184,9 @@ void mock_chunk_setup(void) void mock_chunk_verify(void) { - TEST_ASSERT_NULL_MESSAGE(gs_mock_expect, - "Calls were still expected"); + bool success = gs_mock_expect == NULL; + mock_clean(); + TEST_ASSERT_MESSAGE(success, "Calls were still expected"); } void mock_mm_find_first_free_ExpectAndReturn(uint16_t wanted_csize, mm_chunk_t *ret) diff --git a/core/memmgr/chunk_mock_test.c b/core/memmgr/chunk_mock_test.c new file mode 100644 index 0000000..18c5af3 --- /dev/null +++ b/core/memmgr/chunk_mock_test.c @@ -0,0 +1,159 @@ +/* + Copyright 2014 Chauveau Wilfried + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* Includes ------------------------------------------------------------------*/ +#include +#include "os/memmgr.h" +#include "tests/common_mock.h" +#include "tests/chunk_mock.h" +#include "unity_fixture.h" + +static bool gs_this_test_should_fail = false; +static uint32_t gs_mm_alloc_expect_size = 0; +static bool gs_mm_alloc_called = false; + +static void expected_failure(void) +{ + UnityPrint("[[This message was expected]]"); + Unity.CurrentTestFailed = 0; + gs_this_test_should_fail = false; +} + +TEST_GROUP(chunk_mock); + +TEST_GROUP_RUNNER(chunk_mock) +{ + RUN_TEST_CASE(chunk_mock, alloc_failure_on_expect_find_first_free); + RUN_TEST_CASE(chunk_mock, alloc_failure_on_expect_validate_csize); + RUN_TEST_CASE(chunk_mock, alloc_failure_on_expect_split); + RUN_TEST_CASE(chunk_mock, alloc_failure_on_expect_merge); + RUN_TEST_CASE(chunk_mock, verify_clean_remaining_expectations); + RUN_TEST_CASE(chunk_mock, fail_on_unexpected_call_to_split); + RUN_TEST_CASE(chunk_mock, fail_on_unexpected_call_to_merge); + RUN_TEST_CASE(chunk_mock, fail_on_unexpected_call_to_validate_csize); + RUN_TEST_CASE(chunk_mock, fail_on_unexpected_call_to_find_first_free); +} + +TEST_SETUP(chunk_mock) +{ + gs_mm_alloc_expect_size = 0; + gs_mm_alloc_called = false; + gs_this_test_should_fail = false; + mock_chunk_setup(); +} + +TEST_TEAR_DOWN(chunk_mock) +{ + mock_chunk_verify(); +} + +TEST(chunk_mock, alloc_failure_on_expect_find_first_free) +{ + UnityMalloc_MakeMallocFailAfterCount(0); + die_Expect("expect init failure"); + VERIFY_DIE_START + mock_mm_find_first_free_ExpectAndReturn(0, NULL); + VERIFY_DIE_END + die_Verify(); +} + +TEST(chunk_mock, alloc_failure_on_expect_validate_csize) +{ + UnityMalloc_MakeMallocFailAfterCount(0); + + die_Expect("expect init failure"); + VERIFY_DIE_START + mock_mm_validate_csize_ExpectAndReturn(0, 0, false); + VERIFY_DIE_END + die_Verify(); +} + +TEST(chunk_mock, alloc_failure_on_expect_split) +{ + UnityMalloc_MakeMallocFailAfterCount(0); + + die_Expect("expect init failure"); + VERIFY_DIE_START + mock_mm_chunk_split_ExpectAndReturn(NULL, 0, true); + VERIFY_DIE_END + die_Verify(); +} + +TEST(chunk_mock, alloc_failure_on_expect_merge) +{ + UnityMalloc_MakeMallocFailAfterCount(0); + + die_Expect("expect init failure"); + VERIFY_DIE_START + mock_mm_chunk_merge_Expect(NULL); + VERIFY_DIE_END + die_Verify(); +} + +TEST(chunk_mock, verify_clean_remaining_expectations) +{ + gs_this_test_should_fail = true; + mock_mm_chunk_merge_Expect(NULL); + if (TEST_PROTECT()) { + mock_chunk_verify(); + } else { + expected_failure(); + } +} + +TEST(chunk_mock, fail_on_unexpected_call_to_split) +{ + gs_this_test_should_fail = true; + if (TEST_PROTECT()) + { + mm_chunk_split(NULL, 0); + } else { + expected_failure(); + } +} + +TEST(chunk_mock, fail_on_unexpected_call_to_merge) +{ + gs_this_test_should_fail = true; + if (TEST_PROTECT()) + { + mm_chunk_merge(NULL); + } else { + expected_failure(); + } +} + +TEST(chunk_mock, fail_on_unexpected_call_to_validate_csize) +{ + gs_this_test_should_fail = true; + if (TEST_PROTECT()) + { + mm_validate_csize(0, 0); + } else { + expected_failure(); + } +} + +TEST(chunk_mock, fail_on_unexpected_call_to_find_first_free) +{ + gs_this_test_should_fail = true; + if (TEST_PROTECT()) + { + mm_find_first_free(0); + } else { + expected_failure(); + } +} From 2e6ec445871dcd2d59cd73fb9b06741459a0fd72 Mon Sep 17 00:00:00 2001 From: ithinuel Date: Tue, 16 Sep 2014 20:39:31 +0200 Subject: [PATCH 04/13] update some interfaces. Signed-off-by: ithinuel --- .gitignore | 3 + .gitmodules | 2 +- API/common/common.h | 4 +- API/tests/common_mock.h | 4 - API/tests/memmgr_mock.h | 1 + API/tests/memmgr_unity.h | 4 +- boards/unity/main.c | 25 +----- core/common/cexcept_test.c | 130 +++++++++++++----------------- core/memmgr/chunk_mock.c | 2 +- core/memmgr/chunk_mock_test.c | 83 ++++++------------- core/memmgr/chunk_test.c | 6 +- core/memmgr/chunk_test_validate.c | 38 +++------ core/memmgr/memmgr_mock.c | 41 +++++++--- core/memmgr/memmgr_mock_test.c | 70 ++++++++-------- core/memmgr/memmgr_test_free.c | 6 +- core/os/task_mock.c | 14 ++-- core/os/task_mock_test.c | 42 +++------- os/Unix/system.c | 2 +- os/Unix/task.c | 10 +++ os/Unix/task_test.c | 7 +- projects/tests/mcp/mcp.c | 6 +- third_party/unity | 2 +- 22 files changed, 212 insertions(+), 290 deletions(-) diff --git a/.gitignore b/.gitignore index 89e71aa..b21d35e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ .project .cproject .settings + +# autosave +*~ diff --git a/.gitmodules b/.gitmodules index 9a42e21..b14ed53 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "third_party/unity"] path = third_party/unity - url = git://github.com/ThrowTheSwitch/Unity.git + url = git://github.com/ithinuel/Unity.git [submodule "third_party/lwip"] path = third_party/lwip url = git://git.savannah.nongnu.org/lwip.git diff --git a/API/common/common.h b/API/common/common.h index e659a06..6704f47 100644 --- a/API/common/common.h +++ b/API/common/common.h @@ -22,8 +22,10 @@ #include /* Macros --------------------------------------------------------------------*/ +#define container_of(ptr, type, member) \ + (type *)((uintptr_t)ptr - __builtin_offsetof(type, member)) #define base_of(ptr, type) \ - (type *)((uintptr_t)ptr - __builtin_offsetof(type, base)) + container_of(ptr, type, base) /* Public functions ----------------------------------------------------------*/ /** diff --git a/API/tests/common_mock.h b/API/tests/common_mock.h index 8527d88..66e35c8 100644 --- a/API/tests/common_mock.h +++ b/API/tests/common_mock.h @@ -21,10 +21,6 @@ #include #include -#define VERIFY_DIE_START \ - if (setjmp(g_on_die)==0) { -#define VERIFY_DIE_END \ - } /* Public functions ----------------------------------------------------------*/ void die_Expect (char *expected_cause); diff --git a/API/tests/memmgr_mock.h b/API/tests/memmgr_mock.h index 1ef71b3..075451b 100644 --- a/API/tests/memmgr_mock.h +++ b/API/tests/memmgr_mock.h @@ -25,6 +25,7 @@ void mock_memmgr_setup (void); void mock_mm_alloc_Expect (uint32_t size); void mock_mm_alloc_ExpectAndReturn (uint32_t size, void *ret); +void mock_mm_alloc_IgnoreAndReturn (void *ret); void mock_mm_free_Expect (void *ptr); void mock_memmgr_verify (void); diff --git a/API/tests/memmgr_unity.h b/API/tests/memmgr_unity.h index f1c6b47..690259e 100644 --- a/API/tests/memmgr_unity.h +++ b/API/tests/memmgr_unity.h @@ -14,8 +14,8 @@ limitations under the License. */ -#ifndef __TESTS_MEMMGR_MOCK_H__ -#define __TESTS_MEMMGR_MOCK_H__ +#ifndef __TESTS_MEMMGR_UNITY_H__ +#define __TESTS_MEMMGR_UNITY_H__ /* Includes ------------------------------------------------------------------*/ #include diff --git a/boards/unity/main.c b/boards/unity/main.c index 6d1ab9b..8f7855a 100644 --- a/boards/unity/main.c +++ b/boards/unity/main.c @@ -21,32 +21,9 @@ #include "os/system.h" #include "mcp/mcp.h" -jmp_buf g_on_die; -static char *gs_expected_cause = NULL; - void die(const char *reason) { - if (gs_expected_cause != NULL) { - TEST_ASSERT_EQUAL_STRING(gs_expected_cause, reason); - gs_expected_cause= NULL; - longjmp(g_on_die, 1); - } else { - TEST_FAIL_MESSAGE(reason); - /* test fail may return on teardown */ - exit(1); - } -} - -void die_Expect(char *expected_cause) -{ - gs_expected_cause = expected_cause; -} - -void die_Verify(void) -{ - if (gs_expected_cause != NULL) { - TEST_FAIL_MESSAGE("This test should have died"); - } + TEST_FAIL_MESSAGE(reason); } int main(int argc, char **argv, char **arge) diff --git a/core/common/cexcept_test.c b/core/common/cexcept_test.c index 035be91..a275977 100644 --- a/core/common/cexcept_test.c +++ b/core/common/cexcept_test.c @@ -88,22 +88,45 @@ TEST_TEAR_DOWN(cexcept) { /* Tests ---------------------------------------------------------------------*/ TEST(cexcept, Throw_alone) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN do_something(true); - VERIFY_DIE_END - - die_Verify(); + VERIFY_FAILS_END("Throw without context"); } TEST(cexcept, Try_Fail_to_alloc) { -// mm_Expect(false); + bool first_try = false; + bool first_catch = false; + UnityMalloc_MakeMallocFailAfterCount(0); + EXPECT_ABORT_BEGIN + Try { + TEST_FAIL_MESSAGE("Should not be reached."); + } while(0); + break; + }/* close case */ + }/* close switch */ + }/* close block */ + + VERIFY_FAILS_END("Throw without context"); + + UnityMalloc_MakeMallocFailAfterCount(1); + Try { + first_try = true; + Try { + TEST_FAIL_MESSAGE("Should not be reached."); + } Catch { + + } + EndTry + } Catch { + first_catch = true; + } + EndTry + TEST_ASSERT_TRUE_MESSAGE(first_try && first_catch, "First try should have passed"); } + TEST(cexcept, Catch_without_ctx) { - die_Expect("Catch without context"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN switch(1) { case 0: @@ -116,16 +139,13 @@ TEST(cexcept, Catch_without_ctx) break; } } - VERIFY_DIE_END - - die_Verify(); + VERIFY_FAILS_END("Catch without context"); } TEST(cexcept, Finally_without_ctx) { jmp_buf __buf; - die_Expect("Finally without context"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN switch(1) { case 0: @@ -138,14 +158,12 @@ TEST(cexcept, Finally_without_ctx) break; } } - VERIFY_DIE_END - - die_Verify(); + VERIFY_FAILS_END("Finally without context"); } + TEST(cexcept, EndTry_without_ctx) { - die_Expect("Exit without context"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN { switch(1) { @@ -153,9 +171,7 @@ TEST(cexcept, EndTry_without_ctx) { do {} EndTry - VERIFY_DIE_END - - die_Verify(); + VERIFY_FAILS_END("Exit without context"); } TEST(cexcept, Try_EndTry) @@ -171,20 +187,17 @@ TEST(cexcept, Try_EndTry) } TEST(cexcept, Try_Throw_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(true); did_try_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_FALSE(did_try_end); - die_Verify(); } TEST(cexcept, Try_Catch_EndTry) @@ -249,9 +262,7 @@ TEST(cexcept, Try_Catch_Throw_EndTry) } TEST(cexcept, Try_Throw_Catch_Throw_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(true); @@ -265,13 +276,12 @@ TEST(cexcept, Try_Throw_Catch_Throw_EndTry) did_catch_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_FALSE(did_try_end); TEST_ASSERT_TRUE(did_catch_start); TEST_ASSERT_FALSE(did_catch_end); - die_Verify(); } TEST(cexcept, Try_Catch_Finally_EndTry) @@ -359,9 +369,7 @@ TEST(cexcept, Try_Catch_Throw_Finally_EndTry) } TEST(cexcept, Try_Catch_Finally_Throw_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(false); @@ -378,7 +386,7 @@ TEST(cexcept, Try_Catch_Finally_Throw_EndTry) did_finally_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_TRUE(did_try_end); @@ -386,13 +394,10 @@ TEST(cexcept, Try_Catch_Finally_Throw_EndTry) TEST_ASSERT_FALSE(did_catch_end); TEST_ASSERT_TRUE(did_finally_start); TEST_ASSERT_FALSE(did_finally_end); - die_Verify(); } TEST(cexcept, Try_Throw_Catch_Throw_Finally_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(true); @@ -410,7 +415,7 @@ TEST(cexcept, Try_Throw_Catch_Throw_Finally_EndTry) did_finally_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_FALSE(did_try_end); @@ -418,13 +423,10 @@ TEST(cexcept, Try_Throw_Catch_Throw_Finally_EndTry) TEST_ASSERT_FALSE(did_catch_end); TEST_ASSERT_TRUE(did_finally_start); TEST_ASSERT_TRUE(did_finally_end); - die_Verify(); } TEST(cexcept, Try_Throw_Catch_Finally_Throw_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(true); @@ -442,7 +444,7 @@ TEST(cexcept, Try_Throw_Catch_Finally_Throw_EndTry) did_finally_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_FALSE(did_try_end); @@ -450,13 +452,10 @@ TEST(cexcept, Try_Throw_Catch_Finally_Throw_EndTry) TEST_ASSERT_TRUE(did_catch_end); TEST_ASSERT_TRUE(did_finally_start); TEST_ASSERT_FALSE(did_finally_end); - die_Verify(); } TEST(cexcept, Try_Catch_Throw_Finally_Throw_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(false); @@ -475,7 +474,7 @@ TEST(cexcept, Try_Catch_Throw_Finally_Throw_EndTry) did_finally_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_TRUE(did_try_end); @@ -483,13 +482,10 @@ TEST(cexcept, Try_Catch_Throw_Finally_Throw_EndTry) TEST_ASSERT_FALSE(did_catch_end); TEST_ASSERT_TRUE(did_finally_start); TEST_ASSERT_FALSE(did_finally_end); - die_Verify(); } TEST(cexcept, Try_Throw_Catch_Throw_Finally_Throw_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(true); @@ -508,7 +504,7 @@ TEST(cexcept, Try_Throw_Catch_Throw_Finally_Throw_EndTry) did_finally_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_FALSE(did_try_end); @@ -516,7 +512,6 @@ TEST(cexcept, Try_Throw_Catch_Throw_Finally_Throw_EndTry) TEST_ASSERT_FALSE(did_catch_end); TEST_ASSERT_TRUE(did_finally_start); TEST_ASSERT_FALSE(did_finally_end); - die_Verify(); } TEST(cexcept, Try_Finally_EndTry) @@ -540,9 +535,7 @@ TEST(cexcept, Try_Finally_EndTry) } TEST(cexcept, Try_Throw_Finally_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(true); @@ -554,18 +547,15 @@ TEST(cexcept, Try_Throw_Finally_EndTry) did_finally_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_FALSE(did_try_end); TEST_ASSERT_TRUE(did_finally_start); TEST_ASSERT_TRUE(did_finally_end); - die_Verify(); } TEST(cexcept, Try_Finally_Throw_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(false); @@ -577,18 +567,15 @@ TEST(cexcept, Try_Finally_Throw_EndTry) { did_finally_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_TRUE(did_try_end); TEST_ASSERT_TRUE(did_finally_start); TEST_ASSERT_FALSE(did_finally_end); - die_Verify(); } TEST(cexcept, Try_Throw_Finally_Throw_EndTry) { - die_Expect("Throw without context"); - - VERIFY_DIE_START + EXPECT_ABORT_BEGIN Try { did_try_start = true; do_something(true); @@ -600,13 +587,12 @@ TEST(cexcept, Try_Throw_Finally_Throw_EndTry) { did_finally_end = true; } EndTry - VERIFY_DIE_END + VERIFY_FAILS_END("Throw without context"); TEST_ASSERT_TRUE(did_try_start); TEST_ASSERT_FALSE(did_try_end); TEST_ASSERT_TRUE(did_finally_start); TEST_ASSERT_FALSE(did_finally_end); - die_Verify(); } diff --git a/core/memmgr/chunk_mock.c b/core/memmgr/chunk_mock.c index c473c86..782019d 100644 --- a/core/memmgr/chunk_mock.c +++ b/core/memmgr/chunk_mock.c @@ -126,7 +126,7 @@ static void mock_mm_chunk_merge(mm_chunk_t *this) static bool mock_mm_validate_csize(uint16_t min_csize, uint32_t csize) { TEST_ASSERT_MESSAGE(mock_expect() == mock_call_type_validate_csize, - "Unexpected call to mm_validate_csize"); + "Unexpected call to mm_validate_csize."); TEST_ASSERT_EQUAL_UINT16(gs_mock_expect->call.validate_csize.expect_min_csize, min_csize); TEST_ASSERT_EQUAL_UINT32(gs_mock_expect->call.validate_csize.expect_csize, csize); bool ret = gs_mock_expect->call.validate_csize.then_return; diff --git a/core/memmgr/chunk_mock_test.c b/core/memmgr/chunk_mock_test.c index 18c5af3..629d2ab 100644 --- a/core/memmgr/chunk_mock_test.c +++ b/core/memmgr/chunk_mock_test.c @@ -21,17 +21,9 @@ #include "tests/chunk_mock.h" #include "unity_fixture.h" -static bool gs_this_test_should_fail = false; static uint32_t gs_mm_alloc_expect_size = 0; static bool gs_mm_alloc_called = false; -static void expected_failure(void) -{ - UnityPrint("[[This message was expected]]"); - Unity.CurrentTestFailed = 0; - gs_this_test_should_fail = false; -} - TEST_GROUP(chunk_mock); TEST_GROUP_RUNNER(chunk_mock) @@ -51,7 +43,6 @@ TEST_SETUP(chunk_mock) { gs_mm_alloc_expect_size = 0; gs_mm_alloc_called = false; - gs_this_test_should_fail = false; mock_chunk_setup(); } @@ -63,97 +54,69 @@ TEST_TEAR_DOWN(chunk_mock) TEST(chunk_mock, alloc_failure_on_expect_find_first_free) { UnityMalloc_MakeMallocFailAfterCount(0); - die_Expect("expect init failure"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mock_mm_find_first_free_ExpectAndReturn(0, NULL); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("expect init failure"); } TEST(chunk_mock, alloc_failure_on_expect_validate_csize) { UnityMalloc_MakeMallocFailAfterCount(0); - - die_Expect("expect init failure"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mock_mm_validate_csize_ExpectAndReturn(0, 0, false); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("expect init failure"); } TEST(chunk_mock, alloc_failure_on_expect_split) { UnityMalloc_MakeMallocFailAfterCount(0); - die_Expect("expect init failure"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mock_mm_chunk_split_ExpectAndReturn(NULL, 0, true); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("expect init failure"); } TEST(chunk_mock, alloc_failure_on_expect_merge) { UnityMalloc_MakeMallocFailAfterCount(0); - die_Expect("expect init failure"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mock_mm_chunk_merge_Expect(NULL); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("expect init failure"); } TEST(chunk_mock, verify_clean_remaining_expectations) { - gs_this_test_should_fail = true; mock_mm_chunk_merge_Expect(NULL); - if (TEST_PROTECT()) { - mock_chunk_verify(); - } else { - expected_failure(); - } + EXPECT_ABORT_BEGIN + mock_chunk_verify(); + VERIFY_FAILS_END("Calls were still expected"); } TEST(chunk_mock, fail_on_unexpected_call_to_split) { - gs_this_test_should_fail = true; - if (TEST_PROTECT()) - { - mm_chunk_split(NULL, 0); - } else { - expected_failure(); - } + EXPECT_ABORT_BEGIN + mm_chunk_split(NULL, 0); + VERIFY_FAILS_END("Unexpected call to mm_chunk_split."); } TEST(chunk_mock, fail_on_unexpected_call_to_merge) { - gs_this_test_should_fail = true; - if (TEST_PROTECT()) - { - mm_chunk_merge(NULL); - } else { - expected_failure(); - } + EXPECT_ABORT_BEGIN + mm_chunk_merge(NULL); + VERIFY_FAILS_END("Unexpected call to mm_chunk_merge."); } TEST(chunk_mock, fail_on_unexpected_call_to_validate_csize) { - gs_this_test_should_fail = true; - if (TEST_PROTECT()) - { - mm_validate_csize(0, 0); - } else { - expected_failure(); - } + EXPECT_ABORT_BEGIN + mm_validate_csize(0, 0); + VERIFY_FAILS_END("Unexpected call to mm_validate_csize."); } TEST(chunk_mock, fail_on_unexpected_call_to_find_first_free) { - gs_this_test_should_fail = true; - if (TEST_PROTECT()) - { - mm_find_first_free(0); - } else { - expected_failure(); - } + EXPECT_ABORT_BEGIN + mm_find_first_free(0); + VERIFY_FAILS_END("Unexpected call to mm_find_first_free."); } diff --git a/core/memmgr/chunk_test.c b/core/memmgr/chunk_test.c index f2ae3fa..f52e346 100644 --- a/core/memmgr/chunk_test.c +++ b/core/memmgr/chunk_test.c @@ -159,11 +159,9 @@ TEST(mm_chunk, merge_alloc_alloc) mm_chunk_t *second = mm_chunk_next_get(g_first); uint32_t payload_b = chunk_test_fill_with_prepare(second, 'B'); - die_Expect("MM: cant merge"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mm_chunk_merge(g_first); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("MM: cant merge"); chunk_test_verify(a_state, 3); chunk_test_fill_with_verify(mm_toptr(g_first), 'A', payload_a); diff --git a/core/memmgr/chunk_test_validate.c b/core/memmgr/chunk_test_validate.c index 048dd7e..fa66663 100644 --- a/core/memmgr/chunk_test_validate.c +++ b/core/memmgr/chunk_test_validate.c @@ -37,13 +37,9 @@ static mm_chunk_t *gs_chnk = (mm_chunk_t *)gs_raw; /* functions's definitions */ static void eval_validate_xorsum(void) { - die_Expect("MM: xorsum"); - VERIFY_DIE_START - + EXPECT_ABORT_BEGIN mm_chunk_validate(gs_chnk); - - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("MM: xorsum"); } /* Test group definitions ----------------------------------------------------*/ @@ -79,42 +75,28 @@ TEST(mm_chunk_validate, validate) TEST(mm_chunk_validate, validate_alignment) { - die_Expect("MM: alignment"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mm_chunk_validate((mm_chunk_t *)((uintptr_t)gs_chnk + 1)); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("MM: alignment"); } TEST(mm_chunk_validate, validate_out_of_bound) { - die_Expect("MM: out of bound"); - VERIFY_DIE_START - + EXPECT_ABORT_BEGIN mm_chunk_validate((mm_chunk_t *)(gs_raw-MM_CFG_ALIGNMENT)); + VERIFY_FAILS_END("MM: out of bound"); - VERIFY_DIE_END - die_Verify(); - - die_Expect("MM: out of bound"); - VERIFY_DIE_START - + EXPECT_ABORT_BEGIN mm_chunk_validate((mm_chunk_t *)(gs_raw+MM_CFG_ALIGNMENT)); - - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("MM: out of bound"); } TEST(mm_chunk_validate, validate_overflow) { - die_Expect("MM: overflowed"); - VERIFY_DIE_START - + EXPECT_ABORT_BEGIN memset(mm_toptr(gs_chnk), 0, 1); mm_chunk_validate(gs_chnk); - - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("MM: overflowed"); } TEST(mm_chunk_validate, validate_corruption_prev_size) diff --git a/core/memmgr/memmgr_mock.c b/core/memmgr/memmgr_mock.c index 50e263f..8ff0e4a 100644 --- a/core/memmgr/memmgr_mock.c +++ b/core/memmgr/memmgr_mock.c @@ -41,6 +41,7 @@ struct _mock_call { struct { + bool do_expect; uint32_t expect_size; bool then_return_set; void *then_return; @@ -57,7 +58,8 @@ void * unity_malloc (size_t size); void unity_free (void *ptr); static void * mock_mm_alloc (uint32_t size); -static void mock_mm_alloc_expect_internal (uint32_t expect_size, +static void mock_mm_alloc_expect_internal (bool do_expect, + uint32_t expect_size, bool then_return_set, void *then_return); static void mock_mm_free (void *ptr); @@ -74,13 +76,17 @@ static mm_free_f gs_mm_free = NULL; static mock_call_t *gs_mock_expect = NULL; static mock_call_t *gs_mock_last = NULL; +static uint32_t gs_setup_counter = 0; + /* Private Functions definitions ---------------------------------------------*/ static void *mock_mm_alloc(uint32_t size) { TEST_ASSERT_MESSAGE(mock_expect() == mock_call_type_alloc, "Unexpected call to mm_alloc."); - TEST_ASSERT_EQUAL_UINT32(gs_mock_expect->call.alloc.expect_size, size); + if (gs_mock_expect->call.alloc.do_expect) { + TEST_ASSERT_EQUAL_UINT32(gs_mock_expect->call.alloc.expect_size, size); + } void *ptr = gs_mock_expect->call.alloc.then_return; if (!gs_mock_expect->call.alloc.then_return_set) { ptr = gs_mm_alloc(size); @@ -90,13 +96,15 @@ static void *mock_mm_alloc(uint32_t size) return ptr; } -static void mock_mm_alloc_expect_internal(uint32_t expect_size, bool then_return_set, void *then_return) +static void mock_mm_alloc_expect_internal(bool do_expect, uint32_t expect_size, + bool then_return_set, void *then_return) { mock_call_t *new = unity_malloc(sizeof(mock_call_t)); if (new == NULL) { die("expect init failure"); } new->type = mock_call_type_alloc; + new->call.alloc.do_expect = do_expect; new->call.alloc.expect_size = expect_size; new->call.alloc.then_return_set = then_return_set; new->call.alloc.then_return = then_return; @@ -153,20 +161,29 @@ static void mock_clean(void) /* Functions definitions -----------------------------------------------------*/ void mock_memmgr_setup(void) { + TEST_ASSERT_EQUAL_UINT32_MESSAGE(0, gs_setup_counter, + "API is not clean, missing a call to mock_memmgr_verify"), + gs_setup_counter++; + gs_mm_alloc = mm_alloc; gs_mm_free = mm_free; - UT_PTR_SET(mm_alloc, mock_mm_alloc); - UT_PTR_SET(mm_free, mock_mm_free); + mm_alloc = mock_mm_alloc; + mm_free = mock_mm_free; } void mock_mm_alloc_Expect(uint32_t size) { - mock_mm_alloc_expect_internal(size, false, NULL); + mock_mm_alloc_expect_internal(true, size, false, NULL); } void mock_mm_alloc_ExpectAndReturn(uint32_t size, void *ptr) { - mock_mm_alloc_expect_internal(size, true, ptr); + mock_mm_alloc_expect_internal(true, size, true, ptr); +} + +void mock_mm_alloc_IgnoreAndReturn(void *ret) +{ + mock_mm_alloc_expect_internal(false, 0, true, ret); } void mock_mm_free_Expect(void *ptr) @@ -184,7 +201,13 @@ void mock_mm_free_Expect(void *ptr) void mock_memmgr_verify(void) { + TEST_ASSERT_EQUAL_UINT32_MESSAGE(1, gs_setup_counter, + "Unexpected call to mock_memmgr_verify"), + gs_setup_counter--; + + bool success = gs_mock_expect == NULL; mock_clean(); - TEST_ASSERT_NULL_MESSAGE(gs_mock_expect, - "Calls were still expected"); + mm_alloc = gs_mm_alloc; + mm_free = gs_mm_free; + TEST_ASSERT_MESSAGE(success, "Calls were still expected."); } diff --git a/core/memmgr/memmgr_mock_test.c b/core/memmgr/memmgr_mock_test.c index 485124a..726b0a8 100644 --- a/core/memmgr/memmgr_mock_test.c +++ b/core/memmgr/memmgr_mock_test.c @@ -21,7 +21,6 @@ #include "tests/memmgr_mock.h" #include "unity_fixture.h" -static bool gs_this_test_should_fail = false; static uint32_t gs_mm_alloc_expect_size = 0; static bool gs_mm_alloc_called = false; @@ -44,83 +43,69 @@ TEST_GROUP_RUNNER(memmgr_mock) RUN_TEST_CASE(memmgr_mock, fail_on_unexpected_call_to_free); RUN_TEST_CASE(memmgr_mock, mock_mm_alloc_should_call_saved_cbk_if_return_not_set); + RUN_TEST_CASE(memmgr_mock, dont_fail_when_ignore_size_and_return); } TEST_SETUP(memmgr_mock) { gs_mm_alloc_expect_size = 0; gs_mm_alloc_called = false; - gs_this_test_should_fail = false; mock_memmgr_setup(); } TEST_TEAR_DOWN(memmgr_mock) { mock_memmgr_verify(); - - if (gs_this_test_should_fail) { - TEST_ASSERT_MESSAGE((Unity.CurrentTestFailed == 1), - "This test should have failed but did not."); - Unity.CurrentTestFailed = 0; - } } TEST(memmgr_mock, free_expect_alloc_failure) { UnityMalloc_MakeMallocFailAfterCount(0); - - die_Expect("expect init failure"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mock_mm_free_Expect(NULL); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("expect init failure"); } TEST(memmgr_mock, alloc_expect_alloc_failure) { UnityMalloc_MakeMallocFailAfterCount(0); - die_Expect("expect init failure"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mock_mm_alloc_Expect(0); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("expect init failure"); - die_Expect("expect init failure"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mock_mm_alloc_ExpectAndReturn(0, NULL); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("expect init failure"); } TEST(memmgr_mock, verify_clean_remaining_expectations) { mock_mm_alloc_Expect(0); - if (TEST_PROTECT()) { - mock_memmgr_verify(); - } + EXPECT_ABORT_BEGIN + mock_memmgr_verify(); + VERIFY_FAILS_END("Calls were still expected."); + mock_memmgr_setup(); /* re-open mock_memmgr session. */ } TEST(memmgr_mock, fail_on_unexpected_call_to_alloc) { - gs_this_test_should_fail = true; - if (TEST_PROTECT()) - { - mm_alloc(0); - } + EXPECT_ABORT_BEGIN + mm_alloc(0); + VERIFY_FAILS_END("Unexpected call to mm_alloc."); } TEST(memmgr_mock, fail_on_unexpected_call_to_free) { - gs_this_test_should_fail = true; - if (TEST_PROTECT()) - { - mm_free(0); - } + EXPECT_ABORT_BEGIN + mm_free(0); + VERIFY_FAILS_END("Unexpected call to mm_free."); } TEST(memmgr_mock, mock_mm_alloc_should_call_saved_cbk_if_return_not_set) { + mock_memmgr_verify(); /* close pre-opened mock_memmgr session. */ + UT_PTR_SET(mm_alloc, test_mock_mm_alloc); mock_memmgr_setup(); gs_mm_alloc_expect_size = 32; @@ -130,3 +115,20 @@ TEST(memmgr_mock, mock_mm_alloc_should_call_saved_cbk_if_return_not_set) TEST_ASSERT_TRUE_MESSAGE(gs_mm_alloc_called, "saved cbk was not called"); } + +TEST(memmgr_mock, dont_fail_when_ignore_size_and_return) +{ + uint32_t expect_s0 = 32; + uint32_t expect_s1 = 23; + void *expect_p0 = (void *)0x1234; + void *expect_p1 = (void *)0x5678; + void *expect_p2 = (void *)0x9012; + + mock_mm_alloc_ExpectAndReturn(expect_s0, expect_p0); + mock_mm_alloc_IgnoreAndReturn(expect_p1); + mock_mm_alloc_ExpectAndReturn(expect_s1, expect_p2); + + TEST_ASSERT_EQUAL_PTR(expect_p0, mm_alloc(expect_s0)); + TEST_ASSERT_EQUAL_PTR(expect_p1, mm_alloc(234)); + TEST_ASSERT_EQUAL_PTR(expect_p2, mm_alloc(expect_s1)); +} diff --git a/core/memmgr/memmgr_test_free.c b/core/memmgr/memmgr_test_free.c index fb6af23..c88e3f3 100644 --- a/core/memmgr/memmgr_test_free.c +++ b/core/memmgr/memmgr_test_free.c @@ -130,9 +130,7 @@ TEST(memmgr_free, double_free_leads_to_death) mm_chunk_validate(g_first); TEST_ASSERT_FALSE(g_first->allocated); - die_Expect("MM: double free"); - VERIFY_DIE_START + EXPECT_ABORT_BEGIN mm_free(ptr); - VERIFY_DIE_END - die_Verify(); + VERIFY_FAILS_END("MM: double free"); } diff --git a/core/os/task_mock.c b/core/os/task_mock.c index 83f7767..350c92b 100644 --- a/core/os/task_mock.c +++ b/core/os/task_mock.c @@ -23,9 +23,9 @@ typedef struct _task_delay_call_t task_delay_call_t; struct _task_delay_call_t { - int32_t expect_ms; - task_delay_ms_delegate_f then_cbk; - task_delay_call_t *next; + int32_t expect_ms; + task_delay_ms_delegate_f then_cbk; + task_delay_call_t *next; }; void *unity_malloc(size_t size); @@ -38,9 +38,10 @@ static task_delay_call_t *gs_last = NULL; static void mock_task_delay_ms(int32_t ms) { + int32_t expected = 0; TEST_ASSERT_NOT_NULL_MESSAGE(gs_first, "Unexpected call to task_delay_ms"); - TEST_ASSERT_EQUAL_INT32(gs_first->expect_ms, ms); - if (gs_first->then_cbk != NULL) { + expected = gs_first->expect_ms; + if ((expected == ms) && (gs_first->then_cbk != NULL)) { gs_first->then_cbk(); } @@ -50,6 +51,8 @@ static void mock_task_delay_ms(int32_t ms) if (gs_first == NULL) { gs_last = NULL; } + + TEST_ASSERT_EQUAL_INT32(expected, ms); } static void task_delay_ms_ExpectthenCbk(uint32_t ms, task_delay_ms_delegate_f cbk) @@ -93,5 +96,6 @@ void task_mock_delay_ms_verify(void) unity_free(gs_last); gs_last = c; } + gs_first = NULL; TEST_ASSERT_MESSAGE(success, "missing call to task_delay_ms"); } diff --git a/core/os/task_mock_test.c b/core/os/task_mock_test.c index 268fa18..e316c24 100644 --- a/core/os/task_mock_test.c +++ b/core/os/task_mock_test.c @@ -54,33 +54,17 @@ TEST_TEAR_DOWN(task_mock) TEST(task_mock, fail_on_unexpected_delay) { - if (TEST_PROTECT()) { - task_delay_ms(10); - } - - TEST_ASSERT_EQUAL_MESSAGE(1, Unity.CurrentTestFailed, - "This test should have failed"); - if (Unity.CurrentTestFailed == 1) { - Unity.CurrentTestFailed = 0; - UnityPrint("===== this is an expected failure ====="); - } + EXPECT_ABORT_BEGIN + task_delay_ms(10); + VERIFY_FAILS_END("Unexpected call to task_delay_ms"); } TEST(task_mock, fail_on_wrong_delay_argument) { task_delay_ms_ExpectNthenCbk(10, 1, NULL); - if (TEST_PROTECT()) { - task_delay_ms(5); - } - - TEST_ASSERT_EQUAL_MESSAGE(1, Unity.CurrentTestFailed, - "This test should have failed"); - - if (Unity.CurrentTestFailed == 1) { - Unity.CurrentTestFailed = 0; - UnityPrint("===== this is an expected failure ====="); - task_delay_ms(10); - } + EXPECT_ABORT_BEGIN + task_delay_ms(5); + VERIFY_FAILS_END("Expected 10 Was 5"); } TEST(task_mock, expect_1_delay) @@ -113,15 +97,7 @@ TEST(task_mock, thencbk_called_once_at_the_end) TEST(task_mock, verify_clean_expectation_stack) { task_delay_ms_ExpectNthenCbk(10, 1, NULL); - if (TEST_PROTECT()) { - task_mock_delay_ms_verify(); - } - - TEST_ASSERT_EQUAL_MESSAGE(1, Unity.CurrentTestFailed, - "This test should have failed"); - - if (Unity.CurrentTestFailed == 1) { - Unity.CurrentTestFailed = 0; - UnityPrint("===== this is an expected failure ====="); - } + EXPECT_ABORT_BEGIN + task_mock_delay_ms_verify(); + VERIFY_FAILS_END("missing call to task_delay_ms"); } diff --git a/os/Unix/system.c b/os/Unix/system.c index 65a59f4..8be4106 100644 --- a/os/Unix/system.c +++ b/os/Unix/system.c @@ -37,6 +37,6 @@ void system_boot(system_entry_t *entry) task_start(t); } while (task_running_count()) { - sleep(1); + task_delay_ms(10); } } diff --git a/os/Unix/task.c b/os/Unix/task.c index d5bdca0..2649ca8 100644 --- a/os/Unix/task.c +++ b/os/Unix/task.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "common/common.h" #include "os/task.h" @@ -38,6 +39,7 @@ typedef struct static void * task_wrapper (void *arg); static void task_delete (object_t *base); static char * task_to_string (object_t *base); +static void task_delay_ms_internal (int32_t ms); /* Variables -----------------------------------------------------------------*/ static cexcept_ctx_t *gs_ctx = NULL; @@ -47,6 +49,8 @@ static object_ops_t gs_obj_ops = { }; static volatile uint32_t gs_task_running_count = 0; +task_delay_ms_f task_delay_ms = task_delay_ms_internal; + /* Private functions ---------------------------------------------------------*/ static void *task_wrapper(void *arg) { @@ -78,6 +82,11 @@ static char *task_to_string(object_t *base) return string; } +static void task_delay_ms_internal(int32_t ms) +{ + usleep(ms * 1000); +} + /* Functions definitions -----------------------------------------------------*/ cexcept_ctx_t *task_cexcept_get_ctx(void) { @@ -125,6 +134,7 @@ void task_stop(task_t *this) task_internal_t *self = base_of(this, task_internal_t); if (self->thread != 0) { pthread_cancel(self->thread); + pthread_join(self->thread, NULL); self->thread = 0; gs_task_running_count--; } diff --git a/os/Unix/task_test.c b/os/Unix/task_test.c index 8f021c3..bec8ee7 100644 --- a/os/Unix/task_test.c +++ b/os/Unix/task_test.c @@ -16,7 +16,6 @@ /* Includes ------------------------------------------------------------------*/ #include -#include #include "unity_fixture.h" #include "os/task.h" @@ -28,7 +27,7 @@ static void task_test_routine(void *arg) while(true) { gs_counter++; - usleep(1000); + task_delay_ms(1); } } @@ -69,13 +68,13 @@ TEST(task, delete_cancel_thread) { task_start(gs_tsk); uint32_t val1 = gs_counter; - usleep(10000); + task_delay_ms(10); uint32_t val2 = gs_counter; TEST_ASSERT_MESSAGE((val1 != val2), "Task is not running"); task_stop(gs_tsk); val1 = gs_counter; - usleep(10000); + task_delay_ms(10); val2 = gs_counter; TEST_ASSERT_MESSAGE((val1 == val2), "Task is still running"); diff --git a/projects/tests/mcp/mcp.c b/projects/tests/mcp/mcp.c index 0ea677e..3d6fee3 100644 --- a/projects/tests/mcp/mcp.c +++ b/projects/tests/mcp/mcp.c @@ -33,6 +33,8 @@ static void runAllTests() { RUN_TEST_GROUP(chunk_mock); RUN_TEST_GROUP(memmgr_mock); + RUN_TEST_GROUP(task_mock); + RUN_TEST_GROUP(mm_chunk); RUN_TEST_GROUP(memmgr); RUN_TEST_GROUP(cexcept); @@ -41,10 +43,10 @@ static void runAllTests() RUN_TEST_GROUP(spinlock); RUN_TEST_GROUP(stream); RUN_TEST_GROUP(task); - RUN_TEST_GROUP(task_mock); } static void mcp_entry(void) { - UnityMain(0, NULL, runAllTests); + char *argv[2] = { "unit test", NULL }; + UnityMain(1, argv, runAllTests); } diff --git a/third_party/unity b/third_party/unity index fe2c691..8ccf127 160000 --- a/third_party/unity +++ b/third_party/unity @@ -1 +1 @@ -Subproject commit fe2c691e9dcc69668e9043ed7a0b61dc7021662e +Subproject commit 8ccf127e24a8d4aff0c29ad1e6279bed652abded From 434d921f6493a2a61b50fdbbe9777ef0c5f43311 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 16 Sep 2014 20:42:09 +0200 Subject: [PATCH 05/13] start list implementation. Signed-off-by: Wilfried Chauveau --- API/collections/list.h | 43 +++++++++ core/collections/list.c | 103 ++++++++++++++++++++ core/collections/list_test.c | 182 +++++++++++++++++++++++++++++++++++ core/core.mk | 2 + projects/tests/mcp/mcp.c | 1 + 5 files changed, 331 insertions(+) create mode 100644 API/collections/list.h create mode 100644 core/collections/list.c create mode 100644 core/collections/list_test.c diff --git a/API/collections/list.h b/API/collections/list.h new file mode 100644 index 0000000..7f9f8ee --- /dev/null +++ b/API/collections/list.h @@ -0,0 +1,43 @@ +/* + Copyright 2014 Chauveau Wilfried + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef __COLLECTIONS_LIST_H__ +#define __COLLECTIONS_LIST_H__ +/* Includes ------------------------------------------------------------------*/ +#include +#include "common/object.h" + +/* Types ---------------------------------------------------------------------*/ +typedef struct +{ + object_t base; +} list_t; + +typedef struct _list_node_t list_node_t; + +struct _list_node_t +{ + list_t *owner; + list_node_t *prev; + list_node_t *next; +}; + +list_t * list_create (void); +bool list_push_back (list_t *this, + list_node_t *item); +list_node_t * list_pop_front (list_t *this); + +#endif diff --git a/core/collections/list.c b/core/collections/list.c new file mode 100644 index 0000000..7481fe9 --- /dev/null +++ b/core/collections/list.c @@ -0,0 +1,103 @@ +/* + Copyright 2014 Chauveau Wilfried + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* Includes ------------------------------------------------------------------*/ +#include +#include "common/common.h" +#include "collections/list.h" +#include "os/memmgr.h" + +/* Types ---------------------------------------------------------------------*/ +typedef struct +{ + list_t base; + list_node_t *first; + list_node_t *last; +} list_internal_t; + +/* Prototypes ----------------------------------------------------------------*/ +static char * list_to_string (object_t *this); +static void list_delete (object_t *this); + +/* Variables -----------------------------------------------------------------*/ +static const object_ops_t stack_obj_ops = { + .to_string = list_to_string, + .delete = list_delete +}; + + +/* Functions definitions -----------------------------------------------------*/ +static char *list_to_string(object_t *this) +{ + return NULL; +} +static void list_delete(object_t *this) +{ + mm_free(this); +} + +/* Functions definitions -----------------------------------------------------*/ +list_t *list_create(void) +{ + list_internal_t *si = mm_zalloc(sizeof(list_internal_t)); + if (si != NULL) { + si->base.base.ops = &stack_obj_ops; + return &si->base; + } + return NULL; +} + + +bool list_push_back(list_t *this, list_node_t *item) +{ + bool ret = false; + if ((item != NULL) && (item->owner == NULL) && (this != NULL)) { + list_internal_t *self = base_of(this, list_internal_t); + item->owner = this; + + if (self->first == NULL) { + self->first = item; + } + if (self->last != NULL) { + item->prev = self->last; + self->last->next = item; + } + self->last = item; + + ret = true; + } + return ret; +} + +list_node_t *list_pop_front(list_t *this) +{ + list_node_t *node = NULL; + if (this != NULL) { + list_internal_t *self = base_of(this, list_internal_t); + + node = self->first; + if (node != NULL) { + list_node_t *first = node->next; + if (first != NULL) { + first->prev = NULL; + } + self->first = first; + node->next = NULL; + node->owner = NULL; + } + } + return node; +} diff --git a/core/collections/list_test.c b/core/collections/list_test.c new file mode 100644 index 0000000..52f73a7 --- /dev/null +++ b/core/collections/list_test.c @@ -0,0 +1,182 @@ +/* + Copyright 2014 Chauveau Wilfried + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* Includes ------------------------------------------------------------------*/ +#include +#include "collections/list.h" +#include "common/common.h" +#include "tests/memmgr_mock.h" +#include "unity_fixture.h" + +/* Helpers -------------------------------------------------------------------*/ +typedef struct +{ + list_node_t node; + uint32_t value; +} test_list_items_t; + +static list_t *gs_list = NULL; +static const test_list_items_t gsc_item_1 = { .value = 1 }; +static const test_list_items_t gsc_item_2 = { .value = 2 }; +static const test_list_items_t gsc_item_3 = { .value = 3 }; +static test_list_items_t gs_item_1; +static test_list_items_t gs_item_2; +static test_list_items_t gs_item_3; + +/* Helper --------------------------------------------------------------------*/ +#define TEST_ASSERT_CHAIN(list, prev, cur, next) \ + eval_chain(list, prev, cur, next, __LINE__) +void eval_chain(list_t *list, test_list_items_t *prev, test_list_items_t *cur, test_list_items_t *next, UNITY_LINE_TYPE line) +{ + if (list == NULL) { + UNITY_TEST_ASSERT_NULL(cur->node.owner, line, "Owner Expected NULL"); + } else { + UNITY_TEST_ASSERT_EQUAL_PTR(list, cur->node.owner, line, "Owner Expected Non-NULL"); + } + if (prev == NULL) { + UNITY_TEST_ASSERT_NULL(cur->node.prev, line, "Expected NULL"); + } else { + UNITY_TEST_ASSERT_EQUAL_PTR(&prev->node, cur->node.prev, line, NULL); + } + if (next == NULL) { + UNITY_TEST_ASSERT_NULL(cur->node.next, line, "Expected NULL"); + } else { + UNITY_TEST_ASSERT_EQUAL_PTR(&next->node, cur->node.next, line, NULL); + } +} + +/* Group ---------------------------------------------------------------------*/ +TEST_GROUP(list); + +TEST_GROUP_RUNNER(list) +{ + RUN_TEST_CASE(list, null_on_alloc_failure); + RUN_TEST_CASE(list, push_back_null_does_no_harm); + RUN_TEST_CASE(list, push_back_0_item); + RUN_TEST_CASE(list, push_back_1_item); + RUN_TEST_CASE(list, push_back_many_item); + RUN_TEST_CASE(list, push_back_already_listed); + RUN_TEST_CASE(list, pop_front_null_does_no_harm); + RUN_TEST_CASE(list, pop_front_0_item); + RUN_TEST_CASE(list, pop_front_1_item); + RUN_TEST_CASE(list, pop_front_n_item); +} + +TEST_SETUP(list) +{ + gs_item_1 = gsc_item_1; + gs_item_2 = gsc_item_2; + gs_item_3 = gsc_item_3; + + gs_list = list_create(); + TEST_ASSERT_NOT_NULL(gs_list); +} + +TEST_TEAR_DOWN(list) +{ + object_delete(&gs_list->base); + gs_list = NULL; +} + +TEST(list, null_on_alloc_failure) +{ + mock_memmgr_setup(); + mock_mm_alloc_IgnoreAndReturn(NULL); + TEST_ASSERT_NULL(list_create()); + mock_memmgr_verify(); +} + +TEST(list, push_back_null_does_no_harm) +{ + TEST_ASSERT_FALSE(list_push_back(NULL, NULL)); +} + +TEST(list, push_back_0_item) +{ + TEST_ASSERT_FALSE(list_push_back(gs_list, NULL)); +} + +TEST(list, push_back_1_item) +{ + TEST_ASSERT_TRUE(list_push_back(gs_list, &gs_item_1.node)); +} + +TEST(list, push_back_many_item) +{ + TEST_ASSERT_TRUE(list_push_back(gs_list, &gs_item_1.node)); + TEST_ASSERT_CHAIN(gs_list, NULL, &gs_item_1, NULL); + + TEST_ASSERT_TRUE(list_push_back(gs_list, &gs_item_2.node)); + TEST_ASSERT_CHAIN(gs_list, NULL, &gs_item_1, &gs_item_2); + TEST_ASSERT_CHAIN(gs_list, &gs_item_1, &gs_item_2, NULL); + + TEST_ASSERT_TRUE(list_push_back(gs_list, &gs_item_3.node)); + TEST_ASSERT_CHAIN(gs_list, NULL, &gs_item_1, &gs_item_2); + TEST_ASSERT_CHAIN(gs_list, &gs_item_1, &gs_item_2, &gs_item_3); + TEST_ASSERT_CHAIN(gs_list, &gs_item_2, &gs_item_3, NULL); +} + +TEST(list, push_back_already_listed) +{ + TEST_ASSERT_TRUE(list_push_back(gs_list, &gs_item_1.node)); + TEST_ASSERT_CHAIN(gs_list, NULL, &gs_item_1, NULL); + + list_t *list = list_create(); + TEST_ASSERT_FALSE(list_push_back(list, &gs_item_1.node)); + TEST_ASSERT_CHAIN(gs_list, NULL, &gs_item_1, NULL); + object_delete(&list->base); +} + +TEST(list, pop_front_null_does_no_harm) +{ + TEST_ASSERT_NULL(list_pop_front(NULL)); +} + +TEST(list, pop_front_0_item) +{ + TEST_ASSERT_NULL(list_pop_front(gs_list)); +} + +TEST(list, pop_front_1_item) +{ + list_push_back(gs_list, &gs_item_1.node); + list_push_back(gs_list, &gs_item_2.node); + list_push_back(gs_list, &gs_item_3.node); + + TEST_ASSERT_EQUAL_PTR(&gs_item_1.node, list_pop_front(gs_list)); + TEST_ASSERT_CHAIN(NULL, NULL, &gs_item_1, NULL); + TEST_ASSERT_CHAIN(gs_list, NULL, &gs_item_2, &gs_item_3); + TEST_ASSERT_CHAIN(gs_list, &gs_item_2, &gs_item_3, NULL); +} + +TEST(list, pop_front_n_item) +{ + list_push_back(gs_list, &gs_item_1.node); + list_push_back(gs_list, &gs_item_2.node); + list_push_back(gs_list, &gs_item_3.node); + + TEST_ASSERT_EQUAL_PTR(&gs_item_1.node, list_pop_front(gs_list)); + TEST_ASSERT_CHAIN(NULL, NULL, &gs_item_1, NULL); + TEST_ASSERT_CHAIN(gs_list, NULL, &gs_item_2, &gs_item_3); + TEST_ASSERT_CHAIN(gs_list, &gs_item_2, &gs_item_3, NULL); + + TEST_ASSERT_EQUAL_PTR(&gs_item_2.node, list_pop_front(gs_list)); + TEST_ASSERT_CHAIN(NULL, NULL, &gs_item_2, NULL); + TEST_ASSERT_CHAIN(gs_list, NULL, &gs_item_3, NULL); + + TEST_ASSERT_EQUAL_PTR(&gs_item_3.node, list_pop_front(gs_list)); + TEST_ASSERT_CHAIN(NULL, NULL, &gs_item_3, NULL); +} diff --git a/core/core.mk b/core/core.mk index 3df5fee..29c7161 100644 --- a/core/core.mk +++ b/core/core.mk @@ -15,6 +15,8 @@ CORE_DIR = core CORE_SRCS = \ + $(CORE_DIR)/collections/list_test.c \ + $(CORE_DIR)/collections/list.c \ $(CORE_DIR)/common/common.c \ $(CORE_DIR)/common/object.c \ $(CORE_DIR)/common/object_test.c \ diff --git a/projects/tests/mcp/mcp.c b/projects/tests/mcp/mcp.c index 3d6fee3..c703cbd 100644 --- a/projects/tests/mcp/mcp.c +++ b/projects/tests/mcp/mcp.c @@ -43,6 +43,7 @@ static void runAllTests() RUN_TEST_GROUP(spinlock); RUN_TEST_GROUP(stream); RUN_TEST_GROUP(task); + RUN_TEST_GROUP(list); } static void mcp_entry(void) From 0917dea4b0f3ad99bad432fae4aa1d682c4eb4ee Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 16 Sep 2014 21:13:06 +0200 Subject: [PATCH 06/13] list: implement to_string & delete Signed-off-by: Wilfried Chauveau --- core/collections/list.c | 23 +++++++++++++++++++++-- core/collections/list_test.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/core/collections/list.c b/core/collections/list.c index 7481fe9..d81a4ea 100644 --- a/core/collections/list.c +++ b/core/collections/list.c @@ -16,6 +16,8 @@ /* Includes ------------------------------------------------------------------*/ #include +#include + #include "common/common.h" #include "collections/list.h" #include "os/memmgr.h" @@ -26,6 +28,8 @@ typedef struct list_t base; list_node_t *first; list_node_t *last; + + uint32_t cnt; } list_internal_t; /* Prototypes ----------------------------------------------------------------*/ @@ -42,10 +46,24 @@ static const object_ops_t stack_obj_ops = { /* Functions definitions -----------------------------------------------------*/ static char *list_to_string(object_t *this) { - return NULL; + list_t *self = base_of(this, list_t); + list_internal_t *self2 = base_of(self, list_internal_t); + + char *string = mm_zalloc(11); + if (string != NULL) { + snprintf(string, 11, "list: %d", self2->cnt % 1000); + } + + return string; } static void list_delete(object_t *this) { + list_t *self = base_of(this, list_t); + list_internal_t *self2 = base_of(self, list_internal_t); + while (self2->cnt > 0) { + list_pop_front(self); + } + mm_free(this); } @@ -76,7 +94,7 @@ bool list_push_back(list_t *this, list_node_t *item) self->last->next = item; } self->last = item; - + self->cnt++; ret = true; } return ret; @@ -97,6 +115,7 @@ list_node_t *list_pop_front(list_t *this) self->first = first; node->next = NULL; node->owner = NULL; + self->cnt--; } } return node; diff --git a/core/collections/list_test.c b/core/collections/list_test.c index 52f73a7..99bf44a 100644 --- a/core/collections/list_test.c +++ b/core/collections/list_test.c @@ -18,6 +18,7 @@ #include #include "collections/list.h" #include "common/common.h" +#include "os/memmgr.h" #include "tests/memmgr_mock.h" #include "unity_fixture.h" @@ -69,10 +70,12 @@ TEST_GROUP_RUNNER(list) RUN_TEST_CASE(list, push_back_1_item); RUN_TEST_CASE(list, push_back_many_item); RUN_TEST_CASE(list, push_back_already_listed); + RUN_TEST_CASE(list, to_string_show_item_count); RUN_TEST_CASE(list, pop_front_null_does_no_harm); RUN_TEST_CASE(list, pop_front_0_item); RUN_TEST_CASE(list, pop_front_1_item); RUN_TEST_CASE(list, pop_front_n_item); + RUN_TEST_CASE(list, delete_unlist_items); } TEST_SETUP(list) @@ -140,6 +143,17 @@ TEST(list, push_back_already_listed) object_delete(&list->base); } +TEST(list, to_string_show_item_count) +{ + list_push_back(gs_list, &gs_item_1.node); + list_push_back(gs_list, &gs_item_2.node); + list_push_back(gs_list, &gs_item_3.node); + + char *s = object_to_string(&gs_list->base); + TEST_ASSERT_EQUAL_STRING("list: 3", s); + mm_free(s); +} + TEST(list, pop_front_null_does_no_harm) { TEST_ASSERT_NULL(list_pop_front(NULL)); @@ -180,3 +194,17 @@ TEST(list, pop_front_n_item) TEST_ASSERT_EQUAL_PTR(&gs_item_3.node, list_pop_front(gs_list)); TEST_ASSERT_CHAIN(NULL, NULL, &gs_item_3, NULL); } + +TEST(list, delete_unlist_items) +{ + list_t *list = list_create(); + + list_push_back(list, &gs_item_1.node); + list_push_back(list, &gs_item_2.node); + list_push_back(list, &gs_item_3.node); + + object_delete(&list->base); + TEST_ASSERT_CHAIN(NULL, NULL, &gs_item_1, NULL); + TEST_ASSERT_CHAIN(NULL, NULL, &gs_item_2, NULL); + TEST_ASSERT_CHAIN(NULL, NULL, &gs_item_3, NULL); +} From c62930154bccaec54e4379122cc745bc5df89832 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 16 Sep 2014 23:59:39 +0200 Subject: [PATCH 07/13] add cstring dup, rename test_mutex as mutex_test & fix mutex to_string Signed-off-by: Wilfried Chauveau --- API/utils/cstring.h | 27 +++++++++++++ core/core.mk | 4 +- core/utils/cstring.c | 40 +++++++++++++++++++ core/utils/cstring_test.c | 54 ++++++++++++++++++++++++++ os/Unix/mutex.c | 3 +- os/Unix/{test_mutex.c => mutex_test.c} | 4 +- os/Unix/os.mk | 2 +- os/Unix/task.c | 15 ++++--- projects/tests/mcp/mcp.c | 1 + 9 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 API/utils/cstring.h create mode 100644 core/utils/cstring.c create mode 100644 core/utils/cstring_test.c rename os/Unix/{test_mutex.c => mutex_test.c} (91%) diff --git a/API/utils/cstring.h b/API/utils/cstring.h new file mode 100644 index 0000000..0e0e748 --- /dev/null +++ b/API/utils/cstring.h @@ -0,0 +1,27 @@ +/* + Copyright 2014 Chauveau Wilfried + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef __UTILS_STRING_H__ +#define __UTILS_STRING_H__ + +/** + * Duplicate the string. + * @param str String to duplicate. + * @return new string or NULL. + */ +char * cstring_dup (const char *str); + +#endif diff --git a/core/core.mk b/core/core.mk index 29c7161..af290ee 100644 --- a/core/core.mk +++ b/core/core.mk @@ -41,7 +41,9 @@ CORE_SRCS = \ $(CORE_DIR)/os/spinlock.c \ $(CORE_DIR)/os/spinlock_test.c \ $(CORE_DIR)/os/task_mock.c \ - $(CORE_DIR)/os/task_mock_test.c + $(CORE_DIR)/os/task_mock_test.c \ + $(CORE_DIR)/utils/cstring.c \ + $(CORE_DIR)/utils/cstring_test.c CORE_CFLAGS += diff --git a/core/utils/cstring.c b/core/utils/cstring.c new file mode 100644 index 0000000..27f9ce0 --- /dev/null +++ b/core/utils/cstring.c @@ -0,0 +1,40 @@ +/* + Copyright 2014 Chauveau Wilfried + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* Includes ------------------------------------------------------------------*/ +#include +#include +#include + +#include "os/memmgr.h" +#include "utils/cstring.h" + +/* Functions -----------------------------------------------------------------*/ +char *cstring_dup(const char *str) +{ + char *res = NULL; + if (str == NULL) { + return NULL; + } + uint32_t len = strlen(str); + res = mm_alloc(len + 1); + + if (res != NULL) { + strncpy(res, str, len); + res[len] = '\0'; + } + return res; +} diff --git a/core/utils/cstring_test.c b/core/utils/cstring_test.c new file mode 100644 index 0000000..102e15f --- /dev/null +++ b/core/utils/cstring_test.c @@ -0,0 +1,54 @@ +/* + Copyright 2014 Chauveau Wilfried + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* Includes ------------------------------------------------------------------*/ +#include "unity_fixture.h" +#include "tests/memmgr_unity.h" +#include "os/memmgr.h" +#include "utils/cstring.h" + + +/* Test group definitions ----------------------------------------------------*/ +TEST_GROUP(cstring); + +TEST_GROUP_RUNNER(cstring) +{ + RUN_TEST_CASE(cstring, dup_null_is_ok); + RUN_TEST_CASE(cstring, dup_can_be_freed); +} + +TEST_SETUP(cstring) +{ + unity_mock_setup(); +} + +TEST_TEAR_DOWN(cstring) +{ + +} + +/* Tests ---------------------------------------------------------------------*/ +TEST(cstring, dup_null_is_ok) +{ + TEST_ASSERT_NULL(cstring_dup(NULL)); +} + +TEST(cstring, dup_can_be_freed) +{ + char *s = cstring_dup("Bonjour"); + TEST_ASSERT_EQUAL_STRING("Bonjour", s); + mm_free(s); +} diff --git a/os/Unix/mutex.c b/os/Unix/mutex.c index e778e0d..6fb6426 100644 --- a/os/Unix/mutex.c +++ b/os/Unix/mutex.c @@ -22,6 +22,7 @@ #include "common/common.h" #include "os/memmgr.h" #include "os/mutex.h" +#include "utils/cstring.h" /* Types ---------------------------------------------------------------------*/ typedef struct @@ -50,7 +51,7 @@ static void mutex_obj_delete(object_t *self) static char *mutex_obj_to_string(object_t *self) { unix_mutex_t *this = base_of(base_of(self, mutex_t), unix_mutex_t); - return (char *)this->name; + return cstring_dup(this->name); } mutex_t *mutex_new(bool locked, const char *name) diff --git a/os/Unix/test_mutex.c b/os/Unix/mutex_test.c similarity index 91% rename from os/Unix/test_mutex.c rename to os/Unix/mutex_test.c index bd3a65f..e8bf403 100644 --- a/os/Unix/test_mutex.c +++ b/os/Unix/mutex_test.c @@ -47,5 +47,7 @@ TEST_TEAR_DOWN(mutex) /* Tests ---------------------------------------------------------------------*/ TEST(mutex, to_string) { - TEST_ASSERT_EQUAL_STRING("unit_tests", object_to_string(&gs_mtx->base)); + char *string = object_to_string(&gs_mtx->base); + TEST_ASSERT_EQUAL_STRING("unit_tests", string); + mm_free(string); } diff --git a/os/Unix/os.mk b/os/Unix/os.mk index 5b5524a..ebccf68 100644 --- a/os/Unix/os.mk +++ b/os/Unix/os.mk @@ -18,7 +18,7 @@ OS_SRCS = \ $(OS_DIR)/task.c \ $(OS_DIR)/task_test.c \ $(OS_DIR)/mutex.c \ - $(OS_DIR)/test_mutex.c \ + $(OS_DIR)/mutex_test.c \ $(OS_DIR)/system.c OS_CFLAGS += -include "unity_fixture.h" diff --git a/os/Unix/task.c b/os/Unix/task.c index 2649ca8..306ef3a 100644 --- a/os/Unix/task.c +++ b/os/Unix/task.c @@ -70,14 +70,19 @@ static void task_delete(object_t *base) static char *task_to_string(object_t *base) { - const char *prefix = "task: "; task_t *this = base_of(base, task_t); task_internal_t *self = base_of(this, task_internal_t); - char * string = malloc(strlen(prefix) + strlen(self->name) + 1); + + const char *prefix = "task: "; + uint32_t prefix_len = strlen(prefix); + uint32_t name_len = strlen(self->name); + uint32_t total = prefix_len + name_len; + + char * string = malloc(total + 1); if (string != NULL) { - strcpy(string, prefix); - strcpy(string + strlen(prefix), self->name); - string[strlen(prefix) + strlen(self->name)] = '\0'; + strncpy(string, prefix, prefix_len); + strncpy(string + prefix_len, self->name, name_len); + string[total] = '\0'; } return string; } diff --git a/projects/tests/mcp/mcp.c b/projects/tests/mcp/mcp.c index c703cbd..c89dcad 100644 --- a/projects/tests/mcp/mcp.c +++ b/projects/tests/mcp/mcp.c @@ -37,6 +37,7 @@ static void runAllTests() RUN_TEST_GROUP(mm_chunk); RUN_TEST_GROUP(memmgr); + RUN_TEST_GROUP(cstring); RUN_TEST_GROUP(cexcept); RUN_TEST_GROUP(object); RUN_TEST_GROUP(mutex); From b62300501c4a21ca5d157604885d715ff7752f41 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 17 Sep 2014 00:04:20 +0200 Subject: [PATCH 08/13] check that locking/unlocking null mutex will die. Signed-off-by: Wilfried Chauveau --- os/Unix/mutex_test.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/os/Unix/mutex_test.c b/os/Unix/mutex_test.c index e8bf403..e4f87c5 100644 --- a/os/Unix/mutex_test.c +++ b/os/Unix/mutex_test.c @@ -29,6 +29,8 @@ TEST_GROUP(mutex); TEST_GROUP_RUNNER(mutex) { RUN_TEST_CASE(mutex, to_string); + RUN_TEST_CASE(mutex, lock_null_should_die); + RUN_TEST_CASE(mutex, unlock_null_should_die); } TEST_SETUP(mutex) @@ -51,3 +53,17 @@ TEST(mutex, to_string) TEST_ASSERT_EQUAL_STRING("unit_tests", string); mm_free(string); } + +TEST(mutex, lock_null_should_die) +{ + EXPECT_ABORT_BEGIN + mutex_lock(NULL, -1); + VERIFY_FAILS_END("null mutex"); +} + +TEST(mutex, unlock_null_should_die) +{ + EXPECT_ABORT_BEGIN + mutex_unlock(NULL); + VERIFY_FAILS_END("null mutex"); +} From 3ef44eacb4dcbb1047a9067bd3075d72e786af71 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 17 Sep 2014 01:04:06 +0200 Subject: [PATCH 09/13] test dynamically allocated exception message. Signed-off-by: Wilfried Chauveau --- API/cexcept/cexcept.h | 2 +- API/common/cexcept.h | 2 +- boards/unity/cexcept.c | 42 ++++++++++++++++++++------------------ core/common/cexcept_test.c | 25 +++++++++++++++++++++-- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/API/cexcept/cexcept.h b/API/cexcept/cexcept.h index eff809c..71a63de 100644 --- a/API/cexcept/cexcept.h +++ b/API/cexcept/cexcept.h @@ -24,7 +24,7 @@ struct cexcept { const char * type; - const char * message; + char * message; bool is_dynamic; }; diff --git a/API/common/cexcept.h b/API/common/cexcept.h index 57de24f..e3b5597 100644 --- a/API/common/cexcept.h +++ b/API/common/cexcept.h @@ -91,7 +91,7 @@ typedef struct cexcept_ctx cexcept_ctx_t; * @param is_dynamic true if message should be clean. */ void cexcept_throw (const char *type, - const char *message, + char *message, bool is_dynamic); /** diff --git a/boards/unity/cexcept.c b/boards/unity/cexcept.c index 7f70e4a..492e79a 100644 --- a/boards/unity/cexcept.c +++ b/boards/unity/cexcept.c @@ -33,11 +33,12 @@ struct cexcept_ctx uint8_t state; cexcept_t excpt; - bool excpt_is_set; + bool is_set; + bool is_caught; }; /* Public functions ----------------------------------------------------------*/ -void cexcept_throw(const char *type, const char *message, bool is_dynamic) +void cexcept_throw(const char *type, char *message, bool is_dynamic) { cexcept_ctx_t *cur = task_cexcept_get_ctx(); @@ -45,13 +46,15 @@ void cexcept_throw(const char *type, const char *message, bool is_dynamic) die("Throw without context"); } - if (cur->excpt_is_set && cur->excpt.is_dynamic) { - mm_free((void *)cur->excpt.message); + if (cur->is_set && cur->excpt.is_dynamic) { + mm_free(cur->excpt.message); } + cur->excpt.type = type; cur->excpt.message = message; - cur->excpt.is_dynamic = false; - cur->excpt_is_set = true; + cur->excpt.is_dynamic = is_dynamic; + cur->is_set = true; + cur->is_caught = false; longjmp(cur->jmpbuf, cur->state); } @@ -62,7 +65,8 @@ void *cexcept_enter_ctx(void) cexcept_throw("NOMEM", "no memory available to enter cexcept ctx.", false); } new->prev = task_cexcept_get_ctx(); - new->excpt_is_set = false; + new->is_set = false; + new->is_caught = false; new->state = 1; task_cexcept_set_ctx(new); @@ -76,7 +80,7 @@ cexcept_t *cexcept_catch(void) die("Catch without context"); } ctx->state = 2; - ctx->excpt_is_set = false; + ctx->is_caught = true; return &ctx->excpt; } @@ -91,21 +95,19 @@ void cexcept_finally(void) void cexcept_exit_ctx(void) { - bool excpt_is_set = false; - cexcept_t ex = {0}; - cexcept_ctx_t *cur = task_cexcept_get_ctx(), - *prev = NULL; + cexcept_ctx_t ctx = {0}; + cexcept_ctx_t *cur = task_cexcept_get_ctx(); if (cur == NULL) { - die("Exit without context"); + die("EndTry without context"); } - excpt_is_set = cur->excpt_is_set; - ex = cur->excpt; - prev = cur->prev; - task_cexcept_set_ctx(prev); - + ctx = *cur; mm_free(cur); - if (excpt_is_set) { - cexcept_throw(ex.type, ex.message, ex.is_dynamic); + task_cexcept_set_ctx(ctx.prev); + + if (ctx.is_set && !ctx.is_caught) { + cexcept_throw(ctx.excpt.type, ctx.excpt.message, ctx.excpt.is_dynamic); + } else if (ctx.excpt.is_dynamic && (ctx.excpt.message != NULL)) { + mm_free(ctx.excpt.message); } } diff --git a/core/common/cexcept_test.c b/core/common/cexcept_test.c index a275977..d3eba6a 100644 --- a/core/common/cexcept_test.c +++ b/core/common/cexcept_test.c @@ -18,7 +18,7 @@ #include #include "unity_fixture.h" #include "common/cexcept.h" - +#include "utils/cstring.h" #include "tests/common_mock.h" #include "tests/memmgr_unity.h" @@ -68,6 +68,7 @@ TEST_GROUP_RUNNER(cexcept) { RUN_TEST_CASE(cexcept, Try_Finally_Throw_EndTry); RUN_TEST_CASE(cexcept, Try_Throw_Finally_Throw_EndTry); + RUN_TEST_CASE(cexcept, ReThrow_from_dynamicaly_allocated_Thrown_message_dont_leak); } TEST_SETUP(cexcept) @@ -171,7 +172,7 @@ TEST(cexcept, EndTry_without_ctx) { do {} EndTry - VERIFY_FAILS_END("Exit without context"); + VERIFY_FAILS_END("EndTry without context"); } TEST(cexcept, Try_EndTry) @@ -595,4 +596,24 @@ TEST(cexcept, Try_Throw_Finally_Throw_EndTry) { TEST_ASSERT_FALSE(did_finally_end); } +TEST(cexcept, ReThrow_from_dynamicaly_allocated_Thrown_message_dont_leak) +{ + const char *hello = "Hello"; + Try { + Try { + Try { + char *msg = cstring_dup(hello); + Throw("woops", msg, true); + } + EndTry + } + Catch { + Throw("arg", "real bad luck", false); + } + EndTry + } + Catch { + } + EndTry +} From c2729f0427335c7c7b382e2116e4207feab3294c Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 17 Sep 2014 01:11:29 +0200 Subject: [PATCH 10/13] fix dynamically allocated cexcept message test & typo. Signed-off-by: Wilfried Chauveau --- core/common/cexcept_test.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/common/cexcept_test.c b/core/common/cexcept_test.c index d3eba6a..e8925a3 100644 --- a/core/common/cexcept_test.c +++ b/core/common/cexcept_test.c @@ -68,7 +68,7 @@ TEST_GROUP_RUNNER(cexcept) { RUN_TEST_CASE(cexcept, Try_Finally_Throw_EndTry); RUN_TEST_CASE(cexcept, Try_Throw_Finally_Throw_EndTry); - RUN_TEST_CASE(cexcept, ReThrow_from_dynamicaly_allocated_Thrown_message_dont_leak); + RUN_TEST_CASE(cexcept, ReThrow_from_dynamically_allocated_Thrown_message_dont_leak); } TEST_SETUP(cexcept) @@ -596,9 +596,10 @@ TEST(cexcept, Try_Throw_Finally_Throw_EndTry) { TEST_ASSERT_FALSE(did_finally_end); } -TEST(cexcept, ReThrow_from_dynamicaly_allocated_Thrown_message_dont_leak) +TEST(cexcept, ReThrow_from_dynamically_allocated_Thrown_message_dont_leak) { const char *hello = "Hello"; + const char *real_bad_luck = "real bad luck"; Try { Try { Try { @@ -608,12 +609,14 @@ TEST(cexcept, ReThrow_from_dynamicaly_allocated_Thrown_message_dont_leak) EndTry } Catch { - Throw("arg", "real bad luck", false); + TEST_ASSERT_EQUAL_STRING(hello, cexcept_message(e)); + char *badluck = cstring_dup(real_bad_luck); + Throw("arg", badluck, true); } EndTry } Catch { - + TEST_ASSERT_EQUAL_STRING(real_bad_luck, cexcept_message(e)); } EndTry } From cba631b0afa96e1e0ab90edc215e9c0ea8abe27e Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Thu, 18 Sep 2014 00:02:54 +0200 Subject: [PATCH 11/13] change task_stop to use "task_must_stop" as a nice stop, instead of killing the task. Signed-off-by: Wilfried Chauveau --- API/os/task.h | 5 +++-- os/Unix/task.c | 18 ++++++++++++++---- os/Unix/task_test.c | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/API/os/task.h b/API/os/task.h index 40833d8..a58d1a0 100644 --- a/API/os/task.h +++ b/API/os/task.h @@ -25,7 +25,7 @@ /* Public types --------------------------------------------------------------*/ typedef void (*task_delay_ms_f) (int32_t ms); -typedef void (*task_start_f) (void *arg); +typedef void (*task_method_f) (void *arg); typedef struct { object_t base; @@ -51,13 +51,14 @@ void task_cexcept_set_ctx (cexcept_ctx_t *); * @param priority Task priority. * @return Create task or NULL. */ -task_t * task_create (task_start_f routine, +task_t * task_create (task_method_f routine, void *arg, uint32_t stack_size, uint32_t priority, char *name); bool task_start (task_t *this); void task_stop (task_t *this); +bool task_must_stop (task_t *this); uint32_t task_running_count (void); #endif diff --git a/os/Unix/task.c b/os/Unix/task.c index 306ef3a..f2003cf 100644 --- a/os/Unix/task.c +++ b/os/Unix/task.c @@ -28,11 +28,12 @@ typedef struct { task_t base; pthread_t thread; - task_start_f routine; + task_method_f routine; void * arg; uint32_t stack_size; uint32_t priority; char * name; + bool must_stop; } task_internal_t; /* Prototypes ----------------------------------------------------------------*/ @@ -104,7 +105,7 @@ void task_cexcept_set_ctx(cexcept_ctx_t *ctx) } -task_t *task_create(task_start_f routine, void *arg, uint32_t stack_size, +task_t *task_create(task_method_f routine, void *arg, uint32_t stack_size, uint32_t priority, char *name) { @@ -127,6 +128,7 @@ task_t *task_create(task_start_f routine, void *arg, uint32_t stack_size, bool task_start(task_t *this) { task_internal_t *self = base_of(this, task_internal_t); + self->must_stop = false; bool running = (pthread_create(&self->thread, NULL, task_wrapper, self) == 0); if (running) { gs_task_running_count++; @@ -138,13 +140,21 @@ void task_stop(task_t *this) { task_internal_t *self = base_of(this, task_internal_t); if (self->thread != 0) { - pthread_cancel(self->thread); + self->must_stop = true; pthread_join(self->thread, NULL); self->thread = 0; - gs_task_running_count--; } } +bool task_must_stop(task_t *this) +{ + if (this == NULL) { + return true; + } + task_internal_t *self = base_of(this, task_internal_t); + return self->must_stop; +} + uint32_t task_running_count(void) { return gs_task_running_count; diff --git a/os/Unix/task_test.c b/os/Unix/task_test.c index bec8ee7..b97b42c 100644 --- a/os/Unix/task_test.c +++ b/os/Unix/task_test.c @@ -24,7 +24,7 @@ static volatile uint32_t gs_counter = 0; static void task_test_routine(void *arg) { - while(true) + while(!task_must_stop(gs_tsk)) { gs_counter++; task_delay_ms(1); From 903be0db8370e90ebf33a565322c50d678ca3e5b Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Thu, 18 Sep 2014 00:03:38 +0200 Subject: [PATCH 12/13] implement real mutex for Unix Signed-off-by: Wilfried Chauveau --- core/memmgr/memmgr_test.c | 8 ++--- os/Unix/mutex.c | 20 ++++++++++-- os/Unix/mutex_test.c | 65 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 8 deletions(-) diff --git a/core/memmgr/memmgr_test.c b/core/memmgr/memmgr_test.c index 81ac2c3..3fce4a7 100644 --- a/core/memmgr/memmgr_test.c +++ b/core/memmgr/memmgr_test.c @@ -184,7 +184,7 @@ TEST(memmgr, calloc_zalloc_failed) TEST(memmgr, init) { chunk_test_state_t a_expect[] = { - {9, true}, {CSIZE_MAX-9, false}, + {19, true}, {CSIZE_MAX-19, false}, {CSIZE_MAX, false}, {CSIZE_MAX, false}, {CSIZE_MAX, false}, {CSIZE_MAX, false}, {CSIZE_MAX, false}, {CSIZE_MAX, false}, @@ -209,8 +209,8 @@ TEST(memmgr, info) chunk_test_fill_with_prepare(g_first, 'A'); mm_info_t a_expect[] = { { - .size = 16, - .csize = 9, + .size = 56, + .csize = 19, .allocated = true, .allocator = NULL }, @@ -222,7 +222,7 @@ TEST(memmgr, info) }, { .size = 0, - .csize = 32705, + .csize = 32695, .allocated = false, .allocator = NULL }, diff --git a/os/Unix/mutex.c b/os/Unix/mutex.c index 6fb6426..987eef9 100644 --- a/os/Unix/mutex.c +++ b/os/Unix/mutex.c @@ -27,8 +27,9 @@ /* Types ---------------------------------------------------------------------*/ typedef struct { - mutex_t base; - const char *name; + mutex_t base; + const char *name; + pthread_mutex_t mtx; } unix_mutex_t; /* Prototypes ----------------------------------------------------------------*/ @@ -62,6 +63,11 @@ mutex_t *mutex_new(bool locked, const char *name) this->base.base.ops = &gs_mutex_object_ops; this->name = name; base = &(this->base); + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&this->mtx, &attr); } return base; } @@ -71,7 +77,13 @@ bool mutex_lock(mutex_t *self, int32_t ms) if (self == NULL) { die("null mutex"); } - return true; + unix_mutex_t *this = base_of(self, unix_mutex_t); + + struct timespec t = {0}; + t.tv_sec = ms/1000; + t.tv_nsec = (ms - 1000*t.tv_sec) * 1000000; + + return (pthread_mutex_timedlock(&this->mtx, &t) == 0); } void mutex_unlock(mutex_t *self) @@ -79,4 +91,6 @@ void mutex_unlock(mutex_t *self) if (self == NULL) { die("null mutex"); } + unix_mutex_t *this = base_of(self, unix_mutex_t); + pthread_mutex_unlock(&this->mtx); } diff --git a/os/Unix/mutex_test.c b/os/Unix/mutex_test.c index e4f87c5..fcce464 100644 --- a/os/Unix/mutex_test.c +++ b/os/Unix/mutex_test.c @@ -19,9 +19,20 @@ #include "tests/memmgr_unity.h" #include "os/memmgr.h" #include "os/mutex.h" +#include "os/task.h" /*----------------------------------------------------------------------------*/ static mutex_t *gs_mtx = NULL; +static bool gs_test_mtx = false; + +void test_mutex(void *arg) +{ + if (mutex_lock(gs_mtx, 50)) { + gs_test_mtx = true; + task_delay_ms(250); + mutex_unlock(gs_mtx); + } +} /* Test group definitions ----------------------------------------------------*/ TEST_GROUP(mutex); @@ -31,13 +42,20 @@ TEST_GROUP_RUNNER(mutex) RUN_TEST_CASE(mutex, to_string); RUN_TEST_CASE(mutex, lock_null_should_die); RUN_TEST_CASE(mutex, unlock_null_should_die); + + RUN_TEST_CASE(mutex, lock_once); + RUN_TEST_CASE(mutex, lock_recursive); + RUN_TEST_CASE(mutex, unlock_once); + RUN_TEST_CASE(mutex, unlock_recursive); + + RUN_TEST_CASE(mutex, lock_fail_on_multithread); } TEST_SETUP(mutex) { unity_mock_setup(); gs_mtx = mutex_new(false, "unit_tests"); - + gs_test_mtx = false; } TEST_TEAR_DOWN(mutex) @@ -67,3 +85,48 @@ TEST(mutex, unlock_null_should_die) mutex_unlock(NULL); VERIFY_FAILS_END("null mutex"); } + +TEST(mutex, lock_once) +{ + TEST_ASSERT_TRUE(mutex_lock(gs_mtx, -1)); +} + +TEST(mutex, lock_recursive) +{ + TEST_ASSERT_TRUE(mutex_lock(gs_mtx, -1)); + TEST_ASSERT_TRUE(mutex_lock(gs_mtx, -1)); +} + +TEST(mutex, unlock_once) +{ + mutex_unlock(gs_mtx); +} + +TEST(mutex, unlock_recursive) +{ + mutex_unlock(gs_mtx); + mutex_unlock(gs_mtx); +} + +TEST(mutex, lock_fail_on_multithread) +{ + task_t *tsk = task_create(test_mutex, NULL, 0, 0, "test_mutex"); + + TEST_ASSERT_TRUE(mutex_lock(gs_mtx, -1)); + task_start(tsk); + task_delay_ms(250); + TEST_ASSERT_FALSE(gs_test_mtx); + task_stop(tsk); + mutex_unlock(gs_mtx); + + task_start(tsk); + task_delay_ms(10); + TEST_ASSERT_FALSE(mutex_lock(gs_mtx, 10)); + task_delay_ms(250); + TEST_ASSERT_TRUE(gs_test_mtx); + TEST_ASSERT_TRUE(mutex_lock(gs_mtx, -1)); + + object_delete(&tsk->base); +} + + From 926e9ccef2b531ee16d0e922d341ef421a31b633 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Thu, 18 Sep 2014 00:06:52 +0200 Subject: [PATCH 13/13] missing a test case for task_must_stop Signed-off-by: Wilfried Chauveau --- os/Unix/task_test.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/os/Unix/task_test.c b/os/Unix/task_test.c index b97b42c..588a5b8 100644 --- a/os/Unix/task_test.c +++ b/os/Unix/task_test.c @@ -38,6 +38,8 @@ TEST_GROUP_RUNNER(task) RUN_TEST_CASE(task, alloc_failure_returns_null); RUN_TEST_CASE(task, delete_cancel_thread); RUN_TEST_CASE(task, count_running_tasks); + + RUN_TEST_CASE(task, null_task_should_always_stop); } TEST_SETUP(task) @@ -88,3 +90,8 @@ TEST(task, count_running_tasks) task_stop(gs_tsk); TEST_ASSERT_EQUAL_UINT32(1, task_running_count()); } + +TEST(task, null_task_should_always_stop) +{ + TEST_ASSERT_TRUE(task_must_stop(NULL)); +}