Skip to content

Commit ddbced2

Browse files
add standard mutex support and add tracking capability such that a unit test can detect if a mutex remained in a lock'd state at the end of a unit test.
1 parent aefc35d commit ddbced2

10 files changed

+325
-0
lines changed

cpputest-for-freertos-lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ add_library(cpputest-for-freertos-lib
4242
src/cpputest_for_freertos_timers.cpp
4343
src/cpputest_main.cpp
4444
src/cpputest_for_freertos_semaphore.cpp
45+
src/cpputest_for_freertos_mutex.cpp
4546
include/cpputest_for_freertos_lib.hpp
4647
)
4748

cpputest-for-freertos-lib/include/cpputest_for_freertos_lib.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "cpputest_for_freertos_assert.hpp"
2828
#include "cpputest_for_freertos_task.hpp"
2929
#include "cpputest_for_freertos_timers.hpp"
30+
#include "cpputest_for_freertos_mutex.hpp"
3031

3132
namespace cms {
3233
namespace test {
@@ -38,13 +39,15 @@ namespace cms {
3839
TaskInit();
3940
AssertOutputEnable();
4041
TimersInit();
42+
MutexTrackingInit();
4143
}
4244

4345
/**
4446
* call this in your unit test teardown() method to correctly
4547
* destroy/teardown all available CppUTest for FreeRTOS modules.
4648
*/
4749
void LibTeardownAll() {
50+
MutexTrackingTeardown();
4851
TimersDestroy();
4952
TaskDestroy();
5053
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
#ifndef CPPUTEST_FOR_FREERTOS_LIB_CPPUTEST_FOR_FREERTOS_MUTEX_HPP
3+
#define CPPUTEST_FOR_FREERTOS_LIB_CPPUTEST_FOR_FREERTOS_MUTEX_HPP
4+
5+
namespace cms {
6+
namespace test {
7+
8+
/**
9+
* Initialize the mutex state tracking,
10+
* such that this unit test, when Teardown is called,
11+
* will confirm that all mutexes are unlocked.
12+
*/
13+
void MutexTrackingInit();
14+
15+
/**
16+
* Check the state of any active mutexes.
17+
* If a mutex is found to be locked, then that is considered
18+
* a test failure. i.e. confirm that all mutex usage during
19+
* a unit test locks and then unlocks.
20+
*/
21+
void MutexTrackingTeardown();
22+
23+
/**
24+
* Check if any active mutexes are in a locked
25+
* state.
26+
* @return
27+
*/
28+
bool IsAnyMutexLocked();
29+
30+
} //namespace
31+
}//namespace
32+
33+
#endif //CPPUTEST_FOR_FREERTOS_LIB_CPPUTEST_FOR_FREERTOS_MUTEX_HPP
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/// @brief Provides an implementation of a fake FreeRTOS semaphore
2+
/// which, like FreeRTOS, is under the hood a queue.
3+
/// cpputest-for-freertos-lib assumes that a queue should be
4+
/// functional, i.e. not a mock. No blocking is implemented.
5+
///
6+
/// @ingroup
7+
/// @cond
8+
///***************************************************************************
9+
///
10+
/// Copyright (C) 2024 Matthew Eshleman. All rights reserved.
11+
///
12+
/// This program is open source software: you can redistribute it and/or
13+
/// modify it under the terms of the GNU General Public License as published
14+
/// by the Free Software Foundation, either version 3 of the License, or
15+
/// (at your option) any later version.
16+
///
17+
/// Alternatively, upon written permission from Matthew Eshleman, this program
18+
/// may be distributed and modified under the terms of a Commercial
19+
/// License. For further details, see the Contact Information below.
20+
///
21+
/// Contact Information:
22+
/// Matthew Eshleman
23+
/// https://covemountainsoftware.com
24+
25+
///***************************************************************************
26+
/// @endcond
27+
28+
#include <list>
29+
#include <algorithm>
30+
#include "cpputest_for_freertos_fake_queue.hpp"
31+
#include "cpputest_for_freertos_mutex.hpp"
32+
#include "queue.h"
33+
#include "semphr.h"
34+
35+
//must be last
36+
#include "CppUTest/TestHarness.h"
37+
38+
namespace cms {
39+
namespace test {
40+
41+
static std::list<QueueHandle_t>* s_mutexes = nullptr;
42+
43+
void MutexTrackingInit()
44+
{
45+
configASSERT(s_mutexes == nullptr);
46+
s_mutexes = new std::list<QueueHandle_t>;
47+
}
48+
49+
void MutexTrackingTeardown()
50+
{
51+
if (s_mutexes == nullptr)
52+
return;
53+
54+
bool isAnyLocked = IsAnyMutexLocked();
55+
56+
s_mutexes->clear();
57+
delete s_mutexes;
58+
s_mutexes = nullptr;
59+
60+
if (isAnyLocked)
61+
{
62+
FAIL_TEST("A mutex is still active and locked. Test expects all mutexes to be unlocked.");
63+
}
64+
}
65+
66+
bool IsAnyMutexLocked()
67+
{
68+
if (s_mutexes == nullptr)
69+
return false;
70+
71+
return std::any_of(s_mutexes->begin(), s_mutexes->end(), [](QueueDefinition* mutex)
72+
{
73+
return uxSemaphoreGetCount(mutex) == 0;
74+
});
75+
}
76+
77+
void MutexAboutToDelete(QueueHandle_t mutex)
78+
{
79+
if (s_mutexes == nullptr)
80+
return;
81+
82+
s_mutexes->remove(mutex);
83+
}
84+
} //namespace
85+
}//namespace
86+
87+
extern "C" QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType )
88+
{
89+
(void)ucQueueType;
90+
auto mutex = xQueueGenericCreate(1, 0, ucQueueType);
91+
switch (ucQueueType) {
92+
case queueQUEUE_TYPE_MUTEX:
93+
//wasn't documented, but in experiment, the standard mutex is created unlocked
94+
//(i.e) with one token available
95+
xSemaphoreGive(mutex);
96+
break;
97+
case queueQUEUE_TYPE_RECURSIVE_MUTEX:
98+
//todo
99+
break;
100+
default:
101+
configASSERT(true == false);
102+
break;
103+
}
104+
configASSERT(mutex != nullptr);
105+
if (cms::test::s_mutexes != nullptr)
106+
{
107+
cms::test::s_mutexes->push_back(mutex);
108+
}
109+
return mutex;
110+
}

cpputest-for-freertos-lib/src/cpputest_for_freertos_queue.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,18 @@ extern "C" QueueHandle_t xQueueGenericCreate(const UBaseType_t queueLength,
4040
return queue;
4141
}
4242

43+
namespace cms{
44+
namespace test {
45+
extern void MutexAboutToDelete(QueueHandle_t mutex);
46+
}
47+
}
4348
extern "C" void vQueueDelete(QueueHandle_t queue)
4449
{
4550
configASSERT(queue != nullptr);
51+
if (queue->queueType == queueQUEUE_TYPE_MUTEX)
52+
{
53+
cms::test::MutexAboutToDelete(queue);
54+
}
4655
delete queue;
4756
}
4857

cpputest-for-freertos-lib/src/cpputest_for_freertos_semaphore.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1+
/// @brief Provides an implementation of a fake FreeRTOS semaphore
2+
/// which, like FreeRTOS, is under the hood a queue.
3+
/// cpputest-for-freertos-lib assumes that a queue should be
4+
/// functional, i.e. not a mock. No blocking is implemented.
5+
///
6+
/// @ingroup
7+
/// @cond
8+
///***************************************************************************
9+
///
10+
/// Copyright (C) 2024 Matthew Eshleman. All rights reserved.
11+
///
12+
/// This program is open source software: you can redistribute it and/or
13+
/// modify it under the terms of the GNU General Public License as published
14+
/// by the Free Software Foundation, either version 3 of the License, or
15+
/// (at your option) any later version.
16+
///
17+
/// Alternatively, upon written permission from Matthew Eshleman, this program
18+
/// may be distributed and modified under the terms of a Commercial
19+
/// License. For further details, see the Contact Information below.
20+
///
21+
/// Contact Information:
22+
/// Matthew Eshleman
23+
/// https://covemountainsoftware.com
24+
25+
///***************************************************************************
26+
/// @endcond
27+
128
#include "cpputest_for_freertos_fake_queue.hpp"
229
#include <cstring>
330
#include "queue.h"

cpputest-for-freertos-lib/src/cpputest_for_freertos_timers.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
1+
/// @brief Provides an implementation of fake but functional
2+
/// FreeRTOS software timers.
3+
///
4+
/// @ingroup
5+
/// @cond
6+
///***************************************************************************
7+
///
8+
/// Copyright (C) 2024 Matthew Eshleman. All rights reserved.
9+
///
10+
/// This program is open source software: you can redistribute it and/or
11+
/// modify it under the terms of the GNU General Public License as published
12+
/// by the Free Software Foundation, either version 3 of the License, or
13+
/// (at your option) any later version.
14+
///
15+
/// Alternatively, upon written permission from Matthew Eshleman, this program
16+
/// may be distributed and modified under the terms of a Commercial
17+
/// License. For further details, see the Contact Information below.
18+
///
19+
/// Contact Information:
20+
/// Matthew Eshleman
21+
/// https://covemountainsoftware.com
22+
23+
///***************************************************************************
24+
/// @endcond
25+
126
#include "FreeRTOS.h"
227
#include "timers.h"
328
#include "FakeTimers.hpp"

cpputest-for-freertos-lib/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ set(TEST_SOURCES
66
cpputest_for_freertos_queue_tests.cpp
77
cpputest_for_freertos_task_tests.cpp
88
cpputest_for_freertos_semaphore_tests.cpp
9+
cpputest_for_freertos_mutex_tests.cpp
910
)
1011

1112
# this include expects TEST_SOURCES and TEST_APP_NAME to be
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/// @brief Tests of CppUTest for FreeRTOS mutex implementation
2+
/// @ingroup
3+
/// @cond
4+
///***************************************************************************
5+
///
6+
/// Copyright (C) 2024 Matthew Eshleman. All rights reserved.
7+
///
8+
/// This program is open source software: you can redistribute it and/or
9+
/// modify it under the terms of the GNU General Public License as published
10+
/// by the Free Software Foundation, either version 3 of the License, or
11+
/// (at your option) any later version.
12+
///
13+
/// Alternatively, upon written permission from Matthew Eshleman, this program
14+
/// may be distributed and modified under the terms of a Commercial
15+
/// License. For further details, see the Contact Information below.
16+
///
17+
/// Contact Information:
18+
/// Matthew Eshleman
19+
/// https://covemountainsoftware.com
20+
21+
///***************************************************************************
22+
/// @endcond
23+
24+
#include "FreeRTOS.h"
25+
#include "semphr.h"
26+
#include "cpputest_for_freertos_mutex.hpp"
27+
#include "CppUTest/TestHarness.h"
28+
29+
30+
TEST_GROUP(MutexTests)
31+
{
32+
SemaphoreHandle_t mMutexUnderTest;
33+
34+
void setup() final
35+
{
36+
}
37+
38+
void teardown() final
39+
{
40+
if (mMutexUnderTest != nullptr)
41+
{
42+
vSemaphoreDelete(mMutexUnderTest);
43+
}
44+
}
45+
46+
void CreateMutex()
47+
{
48+
mMutexUnderTest = xSemaphoreCreateMutex();
49+
}
50+
};
51+
52+
TEST(MutexTests, can_create_a_mutex_and_is_not_locked)
53+
{
54+
CreateMutex();
55+
CHECK_EQUAL(1, uxSemaphoreGetCount(mMutexUnderTest));
56+
}
57+
58+
TEST(MutexTests, can_lock_and_unlock_a_mutex)
59+
{
60+
CreateMutex();
61+
xSemaphoreTake(mMutexUnderTest, 1000);
62+
CHECK_EQUAL(0, uxSemaphoreGetCount(mMutexUnderTest));
63+
xSemaphoreGive(mMutexUnderTest);
64+
CHECK_EQUAL(1, uxSemaphoreGetCount(mMutexUnderTest));
65+
}
66+
67+
TEST(MutexTests, library_can_detect_locked_mutexes)
68+
{
69+
CHECK_FALSE(cms::test::IsAnyMutexLocked());
70+
cms::test::MutexTrackingInit();
71+
CreateMutex();
72+
CHECK_FALSE(cms::test::IsAnyMutexLocked());
73+
74+
xSemaphoreTake(mMutexUnderTest, 1000);
75+
CHECK_TRUE(cms::test::IsAnyMutexLocked());
76+
77+
xSemaphoreGive(mMutexUnderTest);
78+
CHECK_FALSE(cms::test::IsAnyMutexLocked());
79+
cms::test::MutexTrackingTeardown();
80+
}
81+
82+
TEST(MutexTests, library_does_not_detect_locked_mutex_that_was_deleted)
83+
{
84+
cms::test::MutexTrackingInit();
85+
CreateMutex();
86+
xSemaphoreTake(mMutexUnderTest, 1000);
87+
CHECK_TRUE(cms::test::IsAnyMutexLocked());
88+
89+
vSemaphoreDelete(mMutexUnderTest);
90+
mMutexUnderTest = nullptr;
91+
CHECK_FALSE(cms::test::IsAnyMutexLocked());
92+
cms::test::MutexTrackingTeardown();
93+
}

cpputest-for-freertos-lib/tests/cpputest_for_freertos_semaphore_tests.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
/// @brief Tests of CppUTest for FreeRTOS semaphore implementation
2+
/// @ingroup
3+
/// @cond
4+
///***************************************************************************
5+
///
6+
/// Copyright (C) 2024 Matthew Eshleman. All rights reserved.
7+
///
8+
/// This program is open source software: you can redistribute it and/or
9+
/// modify it under the terms of the GNU General Public License as published
10+
/// by the Free Software Foundation, either version 3 of the License, or
11+
/// (at your option) any later version.
12+
///
13+
/// Alternatively, upon written permission from Matthew Eshleman, this program
14+
/// may be distributed and modified under the terms of a Commercial
15+
/// License. For further details, see the Contact Information below.
16+
///
17+
/// Contact Information:
18+
/// Matthew Eshleman
19+
/// https://covemountainsoftware.com
20+
21+
///***************************************************************************
22+
/// @endcond
23+
124
#include "FreeRTOS.h"
225
#include "semphr.h"
326
#include "CppUTest/TestHarness.h"

0 commit comments

Comments
 (0)