Skip to content

Commit

Permalink
pull in qassert-meta, update dummy active object same as qpc version …
Browse files Browse the repository at this point in the history
…and other related changes to match QP/C version of this library.
  • Loading branch information
mattheweshleman committed Oct 4, 2024
1 parent d023f83 commit 8a67a7a
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 18 deletions.
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_compile_options(-Wall -Wextra -Werror)

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

if(NOT DEFINED CMS_QPCPP_TOP_DIR)
set(CMS_QPCPP_TOP_DIR ${CMS_EXTERNALS_TOP_DIR}/qpcpp)
Expand All @@ -21,5 +22,16 @@ if(NOT DEFINED CMS_QPCPP_TOP_DIR)
FetchContent_MakeAvailable(qpcpp)
endif(NOT DEFINED CMS_QPCPP_TOP_DIR)

# enable the option to build qassert-meta-lib for QP/C++
option(CMS_ENABLE_QASSERT_META_QPCPP "Setup Internal QAssert Meta Data for QP/C++" ON)

FetchContent_Declare(qassert-meta
GIT_REPOSITORY https://github.com/covemountainsoftware/qassert-meta.git
GIT_TAG ac2e18170208b78c797d8d2fc5374a9b2bf981ce
SOURCE_DIR ${CMS_QASSERT_META_TOP_DIR}
)
message("Fetching qassert-meta git repository")
FetchContent_MakeAvailable(qassert-meta)

include(${CMS_CMAKE_DIR}/qpcppCMakeSupport.cmake)
add_subdirectory(cpputest-for-qpcpp-lib)
2 changes: 1 addition & 1 deletion cpputest-for-qpcpp-lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ add_library(cpputest-for-qpcpp-lib
src/cms_cpputest_qf_onCleanup.cpp
src/cpputestMain.cpp
${CMS_QPCPP_QF_SRCS})

target_link_libraries(cpputest-for-qpcpp-lib qassert-meta-lib)
add_subdirectory(tests)

target_include_directories(cpputest-for-qpcpp-lib PUBLIC
Expand Down
97 changes: 91 additions & 6 deletions cpputest-for-qpcpp-lib/include/cmsDummyActiveObject.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,51 @@
#include <array>
#include <functional>
#include <cstddef>
#include <memory>
#include "cmsVectorBackedQEQueue.hpp"
#include "qevtUniquePtr.hpp"
#include "cms_cpputest_qf_ctrl.hpp"

namespace cms {

namespace test {
/// The Dummy Active Object may be used
/// when an active object (AO) under test is
/// interacting with another AO during a test.
template <size_t InternalEventCount>
class DummyActiveObject : public QP::QActive {
public:

enum class EventBehavior {
CALLBACK, //original behavior, will call the provided callback
RECORDER //will record the event
};

using PostedEventHandler = std::function<void(QP::QEvt const*)>;

explicit DummyActiveObject() :
QP::QActive(Q_STATE_CAST(initial)), m_eventHandler(nullptr),
m_incomingEvents()
DummyActiveObject() :
QP::QActive(Q_STATE_CAST(initial)),
m_eventHandler(nullptr),
m_incomingEvents(),
m_behavior(EventBehavior::CALLBACK),
m_recordedEvents(0)
{
m_incomingEvents.fill(nullptr);
}

explicit DummyActiveObject(EventBehavior behavior) :
QP::QActive(Q_STATE_CAST(initial)),
m_eventHandler(nullptr),
m_incomingEvents(),
m_behavior(behavior),
m_recordedEvents(100)
{
m_incomingEvents.fill(nullptr);

if (m_behavior == EventBehavior::RECORDER) {
m_eventHandler = [=](QP::QEvt const* e) {
this->RecorderEventHandler(e);
};
}
}

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

void SetPostedEventHandler(const PostedEventHandler& handler)
{
m_eventHandler = handler;
if (m_behavior == EventBehavior::CALLBACK) {
m_eventHandler = handler;
}
}

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

bool isRecorderEmpty() { return m_recordedEvents.isEmpty(); }

bool isAnyEventRecorded() { return !m_recordedEvents.isEmpty(); }

bool isSignalRecorded(enum_t sig)
{
if (!isAnyEventRecorded()) {
return false;
}

const auto e = getRecordedEvent<QP::QEvt>();
enum_t recordedSig = e->sig;
return recordedSig == sig;
}

template <class EvtT> cms::QEvtUniquePtr<EvtT> getRecordedEvent()
{
if (!isAnyEventRecorded()) {
return cms::QEvtUniquePtr<EvtT>();
}

return cms::QEvtUniquePtr<EvtT>(
static_cast<QP::QEvt const*>(m_recordedEvents.get(0)));
}

protected:
void RecorderEventHandler(QP::QEvt const * e)
{
if (e->sig >= QP::Q_USER_SIG) {
// record the event
m_recordedEvents.post(e, QP::QF::NO_MARGIN, 0);
}
}

static QP::QState initial(DummyActiveObject* const me,
QP::QEvt const* const)
{
Expand Down Expand Up @@ -99,10 +163,31 @@ class DummyActiveObject : public QP::QActive {
private:
PostedEventHandler m_eventHandler;
std::array<QP::QEvt const*, InternalEventCount> m_incomingEvents;
EventBehavior m_behavior;
cms::VectorBackedQEQueue m_recordedEvents;
};

using DefaultDummyActiveObject = DummyActiveObject<50>;

using DefaultDummyActiveObjectUniquePtr =
std::unique_ptr<DefaultDummyActiveObject>;

/**
* Helper method to create (allocate) and start a dummy active
* object
* @param behavior
* @param priority
* @return ptr as unique_ptr.
*/
inline DefaultDummyActiveObjectUniquePtr CreateAndStartDummyActiveObject(
DefaultDummyActiveObject::EventBehavior behavior = DefaultDummyActiveObject::EventBehavior::CALLBACK,
uint_fast8_t priority = qf_ctrl::DUMMY_AO_A_PRIORITY)
{
auto dummy = std::make_unique<DefaultDummyActiveObject>(behavior);
dummy->dummyStart(priority);
return dummy;
}

} // namespace test
} // namespace cms

#endif // CMS_DUMMY_ACTIVE_OBJECT_HPP
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// @cond
///***************************************************************************
///
/// Copyright (C) 2022 Matthew Eshleman. All rights reserved.
/// Copyright (C) 2022-2024 Matthew Eshleman. All rights reserved.
///
/// This program is open source software: you can redistribute it and/or
/// modify it under the terms of the GNU General Public License as published
Expand Down Expand Up @@ -33,15 +33,26 @@ namespace test {
static constexpr const char* QASSERT_MOCK_NAME = "QASSERT";
static constexpr const char* ONERROR_FUNC_NAME = "Q_onError";

void QAssertMetaOutputEnable();
void QAssertMetaOutputDisable();

inline void MockExpectQAssert()
{
//if we are formally expecting an assert,
//then disable the meta output.
QAssertMetaOutputDisable();

mock(QASSERT_MOCK_NAME)
.expectOneCall(ONERROR_FUNC_NAME)
.ignoreOtherParameters();
}

inline void MockExpectQAssert(const char* module, int id)
{
//if we are formally expecting an assert,
//then disable the meta output.
QAssertMetaOutputDisable();

mock(QASSERT_MOCK_NAME)
.expectOneCall(ONERROR_FUNC_NAME)
.withParameter("module", module)
Expand Down
14 changes: 11 additions & 3 deletions cpputest-for-qpcpp-lib/include/cms_cpputest_qf_ctrl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,17 @@ class PublishedEventRecorder;

namespace qf_ctrl {

static constexpr uint8_t UNIT_UNDER_TEST_PRIORITY = QF_MAX_ACTIVE;
static constexpr uint8_t RECORDER_PRIORITY = 1;

enum : uint8_t {
RECORDER_PRIORITY = 1,
DUMMY_AO_A_PRIORITY,
DUMMY_AO_B_PRIORITY,
DUMMY_AO_C_PRIORITY,
DUMMY_AO_D_PRIORITY,
DUMMY_AO_E_PRIORITY,
UNIT_UNDER_TEST_PRIORITY
};
static_assert(UNIT_UNDER_TEST_PRIORITY < QF_MAX_ACTIVE,
"too many priorities defined");
enum class MemPoolTeardownOption { CHECK_FOR_LEAKS, IGNORE };

struct MemPoolConfig {
Expand Down
28 changes: 26 additions & 2 deletions cpputest-for-qpcpp-lib/src/cms_cpputest_q_onAssert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,35 @@
#include "cms_cpputest.hpp"
#include "qp_port.hpp"
#include "qsafe.h"
#include "qassertMockSupport.hpp"
#include "cmsQAssertMockSupport.hpp"
#include "qassert-meta.h"

static bool m_printAssertMeta = true;

void cms::test::QAssertMetaOutputEnable()
{
m_printAssertMeta = true;
}

void cms::test::QAssertMetaOutputDisable()
{
m_printAssertMeta = false;
}

void Q_onError(char const* const module, int_t const id)
{
//fprintf(stderr, "%s(%s , %d)\n", __FUNCTION__ , module, id);
if (m_printAssertMeta)
{
fprintf(stdout, "\n%s(%s:%d)\n", __FUNCTION__ , module, id);
QAssertMetaDescription meta;
bool found = QAssertMetaGetDescription(module, id, &meta);
if (found)
{
fprintf(stdout, "Additional details on (%s:%d): %s\n", module, id, meta.brief);
fprintf(stdout, "Tips/More:\n%s\n", meta.tips);
fprintf(stdout, "URL: %s\n", meta.url);
}
}

// The TEST_EXIT macro used below is throwing an exception.
// However, many of QP/QF methods are marked as 'noexcept'
Expand Down
1 change: 1 addition & 0 deletions cpputest-for-qpcpp-lib/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set(TEST_SOURCES
cms_cpputest_qf_ctrlTests.cpp
cms_cpputest_qf_ctrlPublishTests.cpp
cms_cpputest_qf_ctrl_post_tests.cpp
cms_dummy_active_object_tests.cpp
publishedEventRecorderTests.cpp
backedQueueTests.cpp
orthogonalComponentTests.cpp
Expand Down
4 changes: 2 additions & 2 deletions cpputest-for-qpcpp-lib/tests/cms_cpputest_qf_ctrlTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ TEST(qf_ctrlTests,

// a 'dummy' active object is needed to verify
// that QF timers are actually firing.
auto dummy = std::unique_ptr<cms::DefaultDummyActiveObject>(
new cms::DefaultDummyActiveObject());
auto dummy = std::unique_ptr<cms::test::DefaultDummyActiveObject>(
new cms::test::DefaultDummyActiveObject());
dummy->dummyStart();
dummy->SetPostedEventHandler([&](QP::QEvt const* e) {
if (e->sig == SIG_1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ using namespace cms::test;

TEST_GROUP(qf_ctrl_post_tests)
{
cms::DefaultDummyActiveObject* mDummy = nullptr;
cms::test::DefaultDummyActiveObject* mDummy = nullptr;

void setup() final
{
qf_ctrl::Setup(QP::Q_USER_SIG, 100);
mDummy = new cms::DefaultDummyActiveObject();
mDummy = new cms::test::DefaultDummyActiveObject();
mDummy->dummyStart();
}

Expand Down
70 changes: 70 additions & 0 deletions cpputest-for-qpcpp-lib/tests/cms_dummy_active_object_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "cmsDummyActiveObject.hpp"
#include "cms_cpputest_qf_ctrl.hpp"
#include "qpcpp.hpp"
#include <memory>

//cpputest header include must always be last
#include "CppUTest/TestHarness.h"

using namespace cms;
using namespace cms::test;

TEST_GROUP(dummy_ao_tests)
{
void setup() final
{
qf_ctrl::Setup(QP::Q_USER_SIG, 100);
}

void teardown() final
{
qf_ctrl::Teardown();
}
};

TEST(dummy_ao_tests, dummy_ao_provides_callback_by_default)
{
auto dummy = CreateAndStartDummyActiveObject();
CHECK_TRUE(dummy->isRecorderEmpty());
CHECK_FALSE(dummy->isAnyEventRecorded());

static constexpr enum_t TEST1_SIG = QP::Q_USER_SIG + 1;
enum_t capturedSig = -1;
dummy->SetPostedEventHandler([&](const QP::QEvt* e){
capturedSig = e->sig;
});
qf_ctrl::PostAndProcess<TEST1_SIG>(dummy.get());
CHECK_EQUAL(TEST1_SIG, capturedSig);
CHECK_FALSE(dummy->isAnyEventRecorded()); //still false, internal recorder not in use here.
CHECK_TRUE(dummy->isRecorderEmpty());
}

TEST(dummy_ao_tests, dummy_ao_provides_recorder_option)
{
auto dummy = CreateAndStartDummyActiveObject(
DefaultDummyActiveObject::EventBehavior::RECORDER);

static constexpr enum_t TEST1_SIG = QP::Q_USER_SIG + 1;
static constexpr enum_t TEST2_SIG = TEST1_SIG + 1;

CHECK_TRUE(dummy->isRecorderEmpty());

enum_t capturedSig = -1;

//this should actually do nothing, since this AO is using its internal
//recorder
dummy->SetPostedEventHandler([&](const QP::QEvt* e){
capturedSig = e->sig;
});
qf_ctrl::PostAndProcess<TEST1_SIG>(dummy.get());
qf_ctrl::PostAndProcess<TEST2_SIG>(dummy.get());
CHECK_EQUAL(-1, capturedSig); //confirm above callback did NOT happen

CHECK_TRUE(dummy->isAnyEventRecorded());
auto recordedEvent1 = dummy->getRecordedEvent<QP::QEvt>();
CHECK_TRUE(recordedEvent1 != nullptr);
CHECK_EQUAL(TEST1_SIG, recordedEvent1->sig);

CHECK_TRUE(dummy->isAnyEventRecorded());
CHECK_TRUE(dummy->isSignalRecorded(TEST2_SIG));
}
2 changes: 1 addition & 1 deletion cpputest-for-qpcpp-lib/tests/qassertTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#include "CppUTest/TestHarness.h"
#include "qp_port.hpp"
#include "qassertMockSupport.hpp"
#include "cmsQAssertMockSupport.hpp"

Q_DEFINE_THIS_MODULE("QAssertTests");

Expand Down

0 comments on commit 8a67a7a

Please sign in to comment.