Skip to content

Commit 8a67a7a

Browse files
pull in qassert-meta, update dummy active object same as qpc version and other related changes to match QP/C version of this library.
1 parent d023f83 commit 8a67a7a

11 files changed

+229
-18
lines changed

CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_compile_options(-Wall -Wextra -Werror)
99

1010
set(CMS_EXTERNALS_TOP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/externals)
1111
set(CMS_CMAKE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cpputest-for-qpcpp-lib/cmake CACHE INTERNAL "")
12+
set(CMS_QASSERT_META_TOP_DIR ${CMS_EXTERNALS_TOP_DIR}/qassert-meta)
1213

1314
if(NOT DEFINED CMS_QPCPP_TOP_DIR)
1415
set(CMS_QPCPP_TOP_DIR ${CMS_EXTERNALS_TOP_DIR}/qpcpp)
@@ -21,5 +22,16 @@ if(NOT DEFINED CMS_QPCPP_TOP_DIR)
2122
FetchContent_MakeAvailable(qpcpp)
2223
endif(NOT DEFINED CMS_QPCPP_TOP_DIR)
2324

25+
# enable the option to build qassert-meta-lib for QP/C++
26+
option(CMS_ENABLE_QASSERT_META_QPCPP "Setup Internal QAssert Meta Data for QP/C++" ON)
27+
28+
FetchContent_Declare(qassert-meta
29+
GIT_REPOSITORY https://github.com/covemountainsoftware/qassert-meta.git
30+
GIT_TAG ac2e18170208b78c797d8d2fc5374a9b2bf981ce
31+
SOURCE_DIR ${CMS_QASSERT_META_TOP_DIR}
32+
)
33+
message("Fetching qassert-meta git repository")
34+
FetchContent_MakeAvailable(qassert-meta)
35+
2436
include(${CMS_CMAKE_DIR}/qpcppCMakeSupport.cmake)
2537
add_subdirectory(cpputest-for-qpcpp-lib)

cpputest-for-qpcpp-lib/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ add_library(cpputest-for-qpcpp-lib
1111
src/cms_cpputest_qf_onCleanup.cpp
1212
src/cpputestMain.cpp
1313
${CMS_QPCPP_QF_SRCS})
14-
14+
target_link_libraries(cpputest-for-qpcpp-lib qassert-meta-lib)
1515
add_subdirectory(tests)
1616

1717
target_include_directories(cpputest-for-qpcpp-lib PUBLIC

cpputest-for-qpcpp-lib/include/cmsDummyActiveObject.hpp

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,51 @@
3030
#include <array>
3131
#include <functional>
3232
#include <cstddef>
33+
#include <memory>
34+
#include "cmsVectorBackedQEQueue.hpp"
35+
#include "qevtUniquePtr.hpp"
36+
#include "cms_cpputest_qf_ctrl.hpp"
3337

3438
namespace cms {
35-
39+
namespace test {
3640
/// The Dummy Active Object may be used
3741
/// when an active object (AO) under test is
3842
/// interacting with another AO during a test.
3943
template <size_t InternalEventCount>
4044
class DummyActiveObject : public QP::QActive {
4145
public:
46+
47+
enum class EventBehavior {
48+
CALLBACK, //original behavior, will call the provided callback
49+
RECORDER //will record the event
50+
};
51+
4252
using PostedEventHandler = std::function<void(QP::QEvt const*)>;
4353

44-
explicit DummyActiveObject() :
45-
QP::QActive(Q_STATE_CAST(initial)), m_eventHandler(nullptr),
46-
m_incomingEvents()
54+
DummyActiveObject() :
55+
QP::QActive(Q_STATE_CAST(initial)),
56+
m_eventHandler(nullptr),
57+
m_incomingEvents(),
58+
m_behavior(EventBehavior::CALLBACK),
59+
m_recordedEvents(0)
60+
{
61+
m_incomingEvents.fill(nullptr);
62+
}
63+
64+
explicit DummyActiveObject(EventBehavior behavior) :
65+
QP::QActive(Q_STATE_CAST(initial)),
66+
m_eventHandler(nullptr),
67+
m_incomingEvents(),
68+
m_behavior(behavior),
69+
m_recordedEvents(100)
4770
{
4871
m_incomingEvents.fill(nullptr);
72+
73+
if (m_behavior == EventBehavior::RECORDER) {
74+
m_eventHandler = [=](QP::QEvt const* e) {
75+
this->RecorderEventHandler(e);
76+
};
77+
}
4978
}
5079

5180
virtual ~DummyActiveObject() = default;
@@ -57,7 +86,9 @@ class DummyActiveObject : public QP::QActive {
5786

5887
void SetPostedEventHandler(const PostedEventHandler& handler)
5988
{
60-
m_eventHandler = handler;
89+
if (m_behavior == EventBehavior::CALLBACK) {
90+
m_eventHandler = handler;
91+
}
6192
}
6293

6394
void dummyStart(uint_fast8_t priority = 1)
@@ -66,7 +97,40 @@ class DummyActiveObject : public QP::QActive {
6697
nullptr, 0);
6798
}
6899

100+
bool isRecorderEmpty() { return m_recordedEvents.isEmpty(); }
101+
102+
bool isAnyEventRecorded() { return !m_recordedEvents.isEmpty(); }
103+
104+
bool isSignalRecorded(enum_t sig)
105+
{
106+
if (!isAnyEventRecorded()) {
107+
return false;
108+
}
109+
110+
const auto e = getRecordedEvent<QP::QEvt>();
111+
enum_t recordedSig = e->sig;
112+
return recordedSig == sig;
113+
}
114+
115+
template <class EvtT> cms::QEvtUniquePtr<EvtT> getRecordedEvent()
116+
{
117+
if (!isAnyEventRecorded()) {
118+
return cms::QEvtUniquePtr<EvtT>();
119+
}
120+
121+
return cms::QEvtUniquePtr<EvtT>(
122+
static_cast<QP::QEvt const*>(m_recordedEvents.get(0)));
123+
}
124+
69125
protected:
126+
void RecorderEventHandler(QP::QEvt const * e)
127+
{
128+
if (e->sig >= QP::Q_USER_SIG) {
129+
// record the event
130+
m_recordedEvents.post(e, QP::QF::NO_MARGIN, 0);
131+
}
132+
}
133+
70134
static QP::QState initial(DummyActiveObject* const me,
71135
QP::QEvt const* const)
72136
{
@@ -99,10 +163,31 @@ class DummyActiveObject : public QP::QActive {
99163
private:
100164
PostedEventHandler m_eventHandler;
101165
std::array<QP::QEvt const*, InternalEventCount> m_incomingEvents;
166+
EventBehavior m_behavior;
167+
cms::VectorBackedQEQueue m_recordedEvents;
102168
};
103169

104170
using DefaultDummyActiveObject = DummyActiveObject<50>;
105-
171+
using DefaultDummyActiveObjectUniquePtr =
172+
std::unique_ptr<DefaultDummyActiveObject>;
173+
174+
/**
175+
* Helper method to create (allocate) and start a dummy active
176+
* object
177+
* @param behavior
178+
* @param priority
179+
* @return ptr as unique_ptr.
180+
*/
181+
inline DefaultDummyActiveObjectUniquePtr CreateAndStartDummyActiveObject(
182+
DefaultDummyActiveObject::EventBehavior behavior = DefaultDummyActiveObject::EventBehavior::CALLBACK,
183+
uint_fast8_t priority = qf_ctrl::DUMMY_AO_A_PRIORITY)
184+
{
185+
auto dummy = std::make_unique<DefaultDummyActiveObject>(behavior);
186+
dummy->dummyStart(priority);
187+
return dummy;
188+
}
189+
190+
} // namespace test
106191
} // namespace cms
107192

108193
#endif // CMS_DUMMY_ACTIVE_OBJECT_HPP

cpputest-for-qpcpp-lib/include/qassertMockSupport.hpp renamed to cpputest-for-qpcpp-lib/include/cmsQAssertMockSupport.hpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/// @cond
44
///***************************************************************************
55
///
6-
/// Copyright (C) 2022 Matthew Eshleman. All rights reserved.
6+
/// Copyright (C) 2022-2024 Matthew Eshleman. All rights reserved.
77
///
88
/// This program is open source software: you can redistribute it and/or
99
/// modify it under the terms of the GNU General Public License as published
@@ -33,15 +33,26 @@ namespace test {
3333
static constexpr const char* QASSERT_MOCK_NAME = "QASSERT";
3434
static constexpr const char* ONERROR_FUNC_NAME = "Q_onError";
3535

36+
void QAssertMetaOutputEnable();
37+
void QAssertMetaOutputDisable();
38+
3639
inline void MockExpectQAssert()
3740
{
41+
//if we are formally expecting an assert,
42+
//then disable the meta output.
43+
QAssertMetaOutputDisable();
44+
3845
mock(QASSERT_MOCK_NAME)
3946
.expectOneCall(ONERROR_FUNC_NAME)
4047
.ignoreOtherParameters();
4148
}
4249

4350
inline void MockExpectQAssert(const char* module, int id)
4451
{
52+
//if we are formally expecting an assert,
53+
//then disable the meta output.
54+
QAssertMetaOutputDisable();
55+
4556
mock(QASSERT_MOCK_NAME)
4657
.expectOneCall(ONERROR_FUNC_NAME)
4758
.withParameter("module", module)

cpputest-for-qpcpp-lib/include/cms_cpputest_qf_ctrl.hpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,17 @@ class PublishedEventRecorder;
3636

3737
namespace qf_ctrl {
3838

39-
static constexpr uint8_t UNIT_UNDER_TEST_PRIORITY = QF_MAX_ACTIVE;
40-
static constexpr uint8_t RECORDER_PRIORITY = 1;
41-
39+
enum : uint8_t {
40+
RECORDER_PRIORITY = 1,
41+
DUMMY_AO_A_PRIORITY,
42+
DUMMY_AO_B_PRIORITY,
43+
DUMMY_AO_C_PRIORITY,
44+
DUMMY_AO_D_PRIORITY,
45+
DUMMY_AO_E_PRIORITY,
46+
UNIT_UNDER_TEST_PRIORITY
47+
};
48+
static_assert(UNIT_UNDER_TEST_PRIORITY < QF_MAX_ACTIVE,
49+
"too many priorities defined");
4250
enum class MemPoolTeardownOption { CHECK_FOR_LEAKS, IGNORE };
4351

4452
struct MemPoolConfig {

cpputest-for-qpcpp-lib/src/cms_cpputest_q_onAssert.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,35 @@
2929
#include "cms_cpputest.hpp"
3030
#include "qp_port.hpp"
3131
#include "qsafe.h"
32-
#include "qassertMockSupport.hpp"
32+
#include "cmsQAssertMockSupport.hpp"
33+
#include "qassert-meta.h"
34+
35+
static bool m_printAssertMeta = true;
36+
37+
void cms::test::QAssertMetaOutputEnable()
38+
{
39+
m_printAssertMeta = true;
40+
}
41+
42+
void cms::test::QAssertMetaOutputDisable()
43+
{
44+
m_printAssertMeta = false;
45+
}
3346

3447
void Q_onError(char const* const module, int_t const id)
3548
{
36-
//fprintf(stderr, "%s(%s , %d)\n", __FUNCTION__ , module, id);
49+
if (m_printAssertMeta)
50+
{
51+
fprintf(stdout, "\n%s(%s:%d)\n", __FUNCTION__ , module, id);
52+
QAssertMetaDescription meta;
53+
bool found = QAssertMetaGetDescription(module, id, &meta);
54+
if (found)
55+
{
56+
fprintf(stdout, "Additional details on (%s:%d): %s\n", module, id, meta.brief);
57+
fprintf(stdout, "Tips/More:\n%s\n", meta.tips);
58+
fprintf(stdout, "URL: %s\n", meta.url);
59+
}
60+
}
3761

3862
// The TEST_EXIT macro used below is throwing an exception.
3963
// However, many of QP/QF methods are marked as 'noexcept'

cpputest-for-qpcpp-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
cms_cpputest_qf_ctrlTests.cpp
77
cms_cpputest_qf_ctrlPublishTests.cpp
88
cms_cpputest_qf_ctrl_post_tests.cpp
9+
cms_dummy_active_object_tests.cpp
910
publishedEventRecorderTests.cpp
1011
backedQueueTests.cpp
1112
orthogonalComponentTests.cpp

cpputest-for-qpcpp-lib/tests/cms_cpputest_qf_ctrlTests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ TEST(qf_ctrlTests,
129129

130130
// a 'dummy' active object is needed to verify
131131
// that QF timers are actually firing.
132-
auto dummy = std::unique_ptr<cms::DefaultDummyActiveObject>(
133-
new cms::DefaultDummyActiveObject());
132+
auto dummy = std::unique_ptr<cms::test::DefaultDummyActiveObject>(
133+
new cms::test::DefaultDummyActiveObject());
134134
dummy->dummyStart();
135135
dummy->SetPostedEventHandler([&](QP::QEvt const* e) {
136136
if (e->sig == SIG_1) {

cpputest-for-qpcpp-lib/tests/cms_cpputest_qf_ctrl_post_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ using namespace cms::test;
3232

3333
TEST_GROUP(qf_ctrl_post_tests)
3434
{
35-
cms::DefaultDummyActiveObject* mDummy = nullptr;
35+
cms::test::DefaultDummyActiveObject* mDummy = nullptr;
3636

3737
void setup() final
3838
{
3939
qf_ctrl::Setup(QP::Q_USER_SIG, 100);
40-
mDummy = new cms::DefaultDummyActiveObject();
40+
mDummy = new cms::test::DefaultDummyActiveObject();
4141
mDummy->dummyStart();
4242
}
4343

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#include "cmsDummyActiveObject.hpp"
2+
#include "cms_cpputest_qf_ctrl.hpp"
3+
#include "qpcpp.hpp"
4+
#include <memory>
5+
6+
//cpputest header include must always be last
7+
#include "CppUTest/TestHarness.h"
8+
9+
using namespace cms;
10+
using namespace cms::test;
11+
12+
TEST_GROUP(dummy_ao_tests)
13+
{
14+
void setup() final
15+
{
16+
qf_ctrl::Setup(QP::Q_USER_SIG, 100);
17+
}
18+
19+
void teardown() final
20+
{
21+
qf_ctrl::Teardown();
22+
}
23+
};
24+
25+
TEST(dummy_ao_tests, dummy_ao_provides_callback_by_default)
26+
{
27+
auto dummy = CreateAndStartDummyActiveObject();
28+
CHECK_TRUE(dummy->isRecorderEmpty());
29+
CHECK_FALSE(dummy->isAnyEventRecorded());
30+
31+
static constexpr enum_t TEST1_SIG = QP::Q_USER_SIG + 1;
32+
enum_t capturedSig = -1;
33+
dummy->SetPostedEventHandler([&](const QP::QEvt* e){
34+
capturedSig = e->sig;
35+
});
36+
qf_ctrl::PostAndProcess<TEST1_SIG>(dummy.get());
37+
CHECK_EQUAL(TEST1_SIG, capturedSig);
38+
CHECK_FALSE(dummy->isAnyEventRecorded()); //still false, internal recorder not in use here.
39+
CHECK_TRUE(dummy->isRecorderEmpty());
40+
}
41+
42+
TEST(dummy_ao_tests, dummy_ao_provides_recorder_option)
43+
{
44+
auto dummy = CreateAndStartDummyActiveObject(
45+
DefaultDummyActiveObject::EventBehavior::RECORDER);
46+
47+
static constexpr enum_t TEST1_SIG = QP::Q_USER_SIG + 1;
48+
static constexpr enum_t TEST2_SIG = TEST1_SIG + 1;
49+
50+
CHECK_TRUE(dummy->isRecorderEmpty());
51+
52+
enum_t capturedSig = -1;
53+
54+
//this should actually do nothing, since this AO is using its internal
55+
//recorder
56+
dummy->SetPostedEventHandler([&](const QP::QEvt* e){
57+
capturedSig = e->sig;
58+
});
59+
qf_ctrl::PostAndProcess<TEST1_SIG>(dummy.get());
60+
qf_ctrl::PostAndProcess<TEST2_SIG>(dummy.get());
61+
CHECK_EQUAL(-1, capturedSig); //confirm above callback did NOT happen
62+
63+
CHECK_TRUE(dummy->isAnyEventRecorded());
64+
auto recordedEvent1 = dummy->getRecordedEvent<QP::QEvt>();
65+
CHECK_TRUE(recordedEvent1 != nullptr);
66+
CHECK_EQUAL(TEST1_SIG, recordedEvent1->sig);
67+
68+
CHECK_TRUE(dummy->isAnyEventRecorded());
69+
CHECK_TRUE(dummy->isSignalRecorded(TEST2_SIG));
70+
}

0 commit comments

Comments
 (0)