From 44f4292c944f031ecd1b654e7cf9a6fcefb1b8fe Mon Sep 17 00:00:00 2001 From: thomas-bc <49786685+thomas-bc@users.noreply.github.com> Date: Thu, 30 Jan 2025 19:10:10 -0800 Subject: [PATCH] Add first pass at UTs --- Svc/Deframer/CMakeLists.txt | 14 +++ Svc/Deframer/Deframer.cpp | 7 +- Svc/Deframer/test/ut/DeframerTestMain.cpp | 29 +++++ Svc/Deframer/test/ut/DeframerTester.cpp | 67 ++++++++++++ Svc/Deframer/test/ut/DeframerTester.hpp | 77 +++++++++++++ Svc/FrameAccumulator/CMakeLists.txt | 19 ++-- Svc/FrameAccumulator/FrameAccumulator.hpp | 3 +- Svc/FrameAccumulator/FrameDetector.hpp | 2 +- .../test/ut/FrameAccumulatorTestMain.cpp | 29 +++++ .../test/ut/FrameAccumulatorTester.cpp | 101 ++++++++++++++++++ .../test/ut/FrameAccumulatorTester.hpp | 96 +++++++++++++++++ Svc/Router/test/ut/RouterTestMain.cpp | 8 +- Svc/Router/test/ut/RouterTester.cpp | 3 +- 13 files changed, 441 insertions(+), 14 deletions(-) create mode 100644 Svc/Deframer/test/ut/DeframerTestMain.cpp create mode 100644 Svc/Deframer/test/ut/DeframerTester.cpp create mode 100644 Svc/Deframer/test/ut/DeframerTester.hpp create mode 100644 Svc/FrameAccumulator/test/ut/FrameAccumulatorTestMain.cpp create mode 100644 Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.cpp create mode 100644 Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.hpp diff --git a/Svc/Deframer/CMakeLists.txt b/Svc/Deframer/CMakeLists.txt index 771be8b995..43b667f25e 100644 --- a/Svc/Deframer/CMakeLists.txt +++ b/Svc/Deframer/CMakeLists.txt @@ -17,3 +17,17 @@ set(MOD_DEPS ) register_fprime_module() + + +#### UTs #### +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/Deframer.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/DeframerTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/DeframerTestMain.cpp" +) +set(UT_MOD_DEPS + STest +) +set(UT_AUTO_HELPERS ON) + +register_fprime_ut() diff --git a/Svc/Deframer/Deframer.cpp b/Svc/Deframer/Deframer.cpp index bce452194a..af2e30a616 100644 --- a/Svc/Deframer/Deframer.cpp +++ b/Svc/Deframer/Deframer.cpp @@ -6,6 +6,7 @@ #include "Svc/Deframer/Deframer.hpp" #include "FpConfig.hpp" +#include "Fw/Types/Assert.hpp" namespace Svc { @@ -23,7 +24,11 @@ Deframer ::~Deframer() {} void Deframer ::framedIn_handler(FwIndexType portNum, Fw::Buffer& data, Fw::Buffer& context) { - // TODO: add asserts? + // Add checks to ensure that the data is a valid F' frame ?? + // Seems like this component should be able to do that on its own without relying + // on an upstream component (the F´ accumulator) + FW_ASSERT(data.getSize() >= FrameConfig::HEADER_SIZE + FrameConfig::CHECKSUM_SIZE); + data.setData(data.getData() + FrameConfig::HEADER_SIZE); data.setSize(data.getSize() - FrameConfig::HEADER_SIZE - FrameConfig::CHECKSUM_SIZE); diff --git a/Svc/Deframer/test/ut/DeframerTestMain.cpp b/Svc/Deframer/test/ut/DeframerTestMain.cpp new file mode 100644 index 0000000000..3f7a451b2b --- /dev/null +++ b/Svc/Deframer/test/ut/DeframerTestMain.cpp @@ -0,0 +1,29 @@ +// ====================================================================== +// \title DeframerTestMain.cpp +// \author chammard +// \brief cpp file for Deframer component test main function +// ====================================================================== + +#include "DeframerTester.hpp" +#include "STest/Random/Random.hpp" + +TEST(Deframer, NominalFrame) { + Svc::DeframerTester tester; + tester.testNominalFrame(); +} + +TEST(Deframer, TruncatedFrame) { + Svc::DeframerTester tester; + tester.testTruncatedFrame(); +} + +TEST(Deframer, ZeroSizeFrame) { + Svc::DeframerTester tester; + tester.testZeroSizeFrame(); +} + +int main(int argc, char** argv) { + STest::Random::seed(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Svc/Deframer/test/ut/DeframerTester.cpp b/Svc/Deframer/test/ut/DeframerTester.cpp new file mode 100644 index 0000000000..e3d0aa5284 --- /dev/null +++ b/Svc/Deframer/test/ut/DeframerTester.cpp @@ -0,0 +1,67 @@ +// ====================================================================== +// \title DeframerTester.cpp +// \author chammard +// \brief cpp file for Deframer component test harness implementation class +// ====================================================================== + +#include "DeframerTester.hpp" +#include "STest/Random/Random.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +DeframerTester ::DeframerTester() + : DeframerGTestBase("DeframerTester", DeframerTester::MAX_HISTORY_SIZE), component("Deframer") { + this->initComponents(); + this->connectPorts(); +} + +DeframerTester ::~DeframerTester() {} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void DeframerTester ::testNominalFrame() { + // Get random byte of data + U8 randomByte = STest::Random::lowerUpper(0, 255); + // | F´ start word | Length (= 1) | Data | Checksum (4 bytes) | + U8 data[13] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00, 0x01, randomByte, 0x00, 0x00, 0x00, 0x00}; + this->mockReceiveData(data, sizeof(data)); + + // Assert that something was emitted on the deframedOut port + ASSERT_from_deframedOut_SIZE(1); + // Assert that the data that was emitted on deframedOut is equal to Data field above (randomByte) + ASSERT_EQ(this->fromPortHistory_deframedOut->at(0).data.getData()[0], randomByte); +} + +void DeframerTester::testTruncatedFrame() { + // Send a truncated frame, too short to be valid + U8 data[11] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + ASSERT_DEATH(this->mockReceiveData(data, sizeof(data)), "Deframer.cpp"); + ASSERT_from_deframedOut_SIZE(0); +} + +void DeframerTester::testZeroSizeFrame() { + // Send a null frame, too short to be valid + U8 data[0] = {}; + ASSERT_DEATH(this->mockReceiveData(data, sizeof(data)), "Deframer.cpp"); + ASSERT_from_deframedOut_SIZE(0); +} + +// ---------------------------------------------------------------------- +// Test Helpers +// ---------------------------------------------------------------------- + +void DeframerTester::mockReceiveData(U8* data, FwSizeType size) { + Fw::Buffer nullContext; + Fw::Buffer buffer; + buffer.setData(data); + buffer.setSize(size); + this->invoke_to_framedIn(0, buffer, nullContext); +} + +} // namespace Svc diff --git a/Svc/Deframer/test/ut/DeframerTester.hpp b/Svc/Deframer/test/ut/DeframerTester.hpp new file mode 100644 index 0000000000..c350223dd4 --- /dev/null +++ b/Svc/Deframer/test/ut/DeframerTester.hpp @@ -0,0 +1,77 @@ +// ====================================================================== +// \title DeframerTester.hpp +// \author chammard +// \brief hpp file for Deframer component test harness implementation class +// ====================================================================== + +#ifndef Svc_DeframerTester_HPP +#define Svc_DeframerTester_HPP + +#include "Svc/Deframer/Deframer.hpp" +#include "Svc/Deframer/DeframerGTestBase.hpp" + +namespace Svc { + +class DeframerTester : public DeframerGTestBase { + public: + // ---------------------------------------------------------------------- + // Constants + // ---------------------------------------------------------------------- + + // Maximum size of histories storing events, telemetry, and port outputs + static const FwSizeType MAX_HISTORY_SIZE = 10; + + // Instance ID supplied to the component instance under test + static const FwEnumStoreType TEST_INSTANCE_ID = 0; + + public: + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + //! Construct object DeframerTester + DeframerTester(); + + //! Destroy object DeframerTester + ~DeframerTester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! Test receiving a nominal frame + void testNominalFrame(); + + //! Test receiving a truncated frame + void testTruncatedFrame(); + + //! Test receiving a zero size frame + void testZeroSizeFrame(); + + private: + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + //! Connect ports + void connectPorts(); + + //! Initialize components + void initComponents(); + + void mockReceiveData(U8* data, FwSizeType size); + + + private: + // ---------------------------------------------------------------------- + // Member variables + // ---------------------------------------------------------------------- + + //! The component under test + Deframer component; +}; + +} // namespace Svc + +#endif diff --git a/Svc/FrameAccumulator/CMakeLists.txt b/Svc/FrameAccumulator/CMakeLists.txt index 1fad436a2a..7ad0ef2fdf 100644 --- a/Svc/FrameAccumulator/CMakeLists.txt +++ b/Svc/FrameAccumulator/CMakeLists.txt @@ -12,11 +12,18 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/FrameAccumulator.cpp" ) -# Uncomment and add any modules that this component depends on, else -# they might not be available when cmake tries to build this component. +register_fprime_module() -# set(MOD_DEPS -# Add your dependencies here -# ) +#### UTS #### +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/FrameAccumulator.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/FrameAccumulatorTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/FrameAccumulatorTestMain.cpp" +) +set(UT_MOD_DEPS + Utils/Types + STest +) +set(UT_AUTO_HELPERS ON) -register_fprime_module() +register_fprime_ut() diff --git a/Svc/FrameAccumulator/FrameAccumulator.hpp b/Svc/FrameAccumulator/FrameAccumulator.hpp index 842eb13350..135a99e56e 100644 --- a/Svc/FrameAccumulator/FrameAccumulator.hpp +++ b/Svc/FrameAccumulator/FrameAccumulator.hpp @@ -8,6 +8,7 @@ #define Svc_FrameAccumulator_HPP #include "Fw/Types/MemAllocator.hpp" +#include "Utils/Types/CircularBuffer.hpp" #include "Svc/FrameAccumulator/FrameAccumulatorComponentAc.hpp" #include "Svc/FrameAccumulator/FrameDetector.hpp" @@ -46,7 +47,7 @@ class FrameAccumulator : public FrameAccumulatorComponentBase { void dataIn_handler(FwIndexType portNum, //!< The port number Fw::Buffer& recvBuffer, const Drv::RecvStatus& recvStatus) override; - private: + PRIVATE: //! \brief process raw buffer //! \return raw data buffer void processBuffer(Fw::Buffer& buffer); diff --git a/Svc/FrameAccumulator/FrameDetector.hpp b/Svc/FrameAccumulator/FrameDetector.hpp index 040996db37..69a4914e30 100644 --- a/Svc/FrameAccumulator/FrameDetector.hpp +++ b/Svc/FrameAccumulator/FrameDetector.hpp @@ -41,7 +41,7 @@ namespace Svc { //! //! \param data: circular buffer with read-only access //! \param size_out: set as output to caller indicating size when appropriate - //! \return status of the detection to be pared with size_out + //! \return status of the detection to be paired with size_out virtual Status detect(const Types::CircularBuffer& data, FwSizeType& size_out) const = 0; }; diff --git a/Svc/FrameAccumulator/test/ut/FrameAccumulatorTestMain.cpp b/Svc/FrameAccumulator/test/ut/FrameAccumulatorTestMain.cpp new file mode 100644 index 0000000000..4a7b8906a7 --- /dev/null +++ b/Svc/FrameAccumulator/test/ut/FrameAccumulatorTestMain.cpp @@ -0,0 +1,29 @@ +// ====================================================================== +// \title FrameAccumulatorTestMain.cpp +// \author chammard +// \brief cpp file for FrameAccumulator component test main function +// ====================================================================== + +#include "FrameAccumulatorTester.hpp" +#include "STest/Random/Random.hpp" + +TEST(FrameAccumulator, TestFrameDetected) { + Svc::FrameAccumulatorTester tester; + tester.testFrameDetected(); +} + +TEST(FrameAccumulator, TestMoreDataNeeded) { + Svc::FrameAccumulatorTester tester; + tester.testMoreDataNeeded(); +} + +TEST(FrameAccumulator, TestNoFrameDetected) { + Svc::FrameAccumulatorTester tester; + tester.testNoFrameDetected(); +} + +int main(int argc, char** argv) { + STest::Random::seed(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.cpp b/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.cpp new file mode 100644 index 0000000000..89176e3a3f --- /dev/null +++ b/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.cpp @@ -0,0 +1,101 @@ +// ====================================================================== +// \title FrameAccumulatorTester.cpp +// \author chammard +// \brief cpp file for FrameAccumulator component test harness implementation class +// ====================================================================== + +#include "FrameAccumulatorTester.hpp" +#include "STest/Random/Random.hpp" + + + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +FrameAccumulatorTester ::FrameAccumulatorTester() + : FrameAccumulatorGTestBase("FrameAccumulatorTester", FrameAccumulatorTester::MAX_HISTORY_SIZE), + component("FrameAccumulator") { + this->initComponents(); + this->connectPorts(); + component.configure(this->mockDetector, 1, this->mallocator, 2048); +} + +FrameAccumulatorTester ::~FrameAccumulatorTester() {} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void FrameAccumulatorTester ::testFrameDetected() { + // Prepare a random size buffer + U32 buffer_size = STest::Random::lowerUpper(1, 1024); + U8 data[buffer_size]; + Fw::Buffer buffer(data, buffer_size); + // Set the mock detector to report success of size_out = buffer_size + this->mockDetector.next_status = FrameDetector::Status::FRAME_DETECTED; + this->mockDetector.next_size_out = buffer_size; + // Receive the buffer on dataIn + this->invoke_to_dataIn(0, buffer, Drv::RecvStatus::RECV_OK); + // Checks + ASSERT_from_dataDeallocate_SIZE(1); // input buffer was deallocated + ASSERT_from_frameOut_SIZE(1); // frame was sent + ASSERT_EQ(this->component.m_inRing.get_allocated_size(), 0); // no data left in ring buffer + ASSERT_EQ(this->fromPortHistory_frameOut->at(0).data.getSize(), buffer_size); // all data was sent out +} + +void FrameAccumulatorTester ::testMoreDataNeeded() { + // Prepare a random size buffer + U32 buffer_size = STest::Random::lowerUpper(1, 1024); + U8 data[buffer_size]; + Fw::Buffer buffer(data, buffer_size); + // Set the mock detector to report more data needed + this->mockDetector.next_status = FrameDetector::Status::MORE_DATA_NEEDED; + this->mockDetector.next_size_out = buffer_size + 1; + // Receive the buffer on dataIn + this->invoke_to_dataIn(0, buffer, Drv::RecvStatus::RECV_OK); + // Checks + ASSERT_from_dataDeallocate_SIZE(1); // input buffer was deallocated + ASSERT_from_frameOut_SIZE(0); // frame was not sent (waiting on more data) + ASSERT_EQ(this->component.m_inRing.get_allocated_size(), buffer_size); // data left in ring buffer +} + +void FrameAccumulatorTester ::testNoFrameDetected() { + // Prepare a random size buffer + U32 buffer_size = STest::Random::lowerUpper(1, 1024); + U8 data[buffer_size]; + Fw::Buffer buffer(data, buffer_size); + // Set the mock detector + this->mockDetector.next_status = FrameDetector::Status::NO_FRAME_DETECTED; + this->mockDetector.next_size_out = 0; + // Receive the buffer on dataIn + this->invoke_to_dataIn(0, buffer, Drv::RecvStatus::RECV_OK); + // Checks + ASSERT_from_dataDeallocate_SIZE(1); // input buffer was deallocated + ASSERT_from_frameOut_SIZE(0); // No frame was sent out + ASSERT_EQ(this->component.m_inRing.get_allocated_size(), 0); // all data was consumed and discarded +} + +// ---------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------- + + +// ---------------------------------------------------------------------- +// Port handler overrides +// ---------------------------------------------------------------------- +Fw::Buffer FrameAccumulatorTester ::from_frameAllocate_handler( + FwIndexType portNum, + U32 size + ) + { + this->pushFromPortEntry_frameAllocate(size); + this->m_buffer.setData(this->m_buffer_slot); + this->m_buffer.setSize(size); + ::memset(this->m_buffer.getData(), 0, size); + return this->m_buffer; + } + +} // namespace Svc diff --git a/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.hpp b/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.hpp new file mode 100644 index 0000000000..4d70184057 --- /dev/null +++ b/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.hpp @@ -0,0 +1,96 @@ +// ====================================================================== +// \title FrameAccumulatorTester.hpp +// \author chammard +// \brief hpp file for FrameAccumulator component test harness implementation class +// ====================================================================== + +#ifndef Svc_FrameAccumulatorTester_HPP +#define Svc_FrameAccumulatorTester_HPP + +#include "Svc/FrameAccumulator/FrameAccumulator.hpp" +#include "Svc/FrameAccumulator/FrameAccumulatorGTestBase.hpp" +#include "Svc/FrameAccumulator/FrameDetector/FprimeFrameDetector.hpp" +#include "Fw/Types/MallocAllocator.hpp" + +namespace Svc { + +class FrameAccumulatorTester : public FrameAccumulatorGTestBase { + public: + // ---------------------------------------------------------------------- + // Constants + // ---------------------------------------------------------------------- + + // Maximum size of histories storing events, telemetry, and port outputs + static const FwSizeType MAX_HISTORY_SIZE = 10; + + // Instance ID supplied to the component instance under test + static const FwEnumStoreType TEST_INSTANCE_ID = 0; + + public: + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + //! Construct object FrameAccumulatorTester + FrameAccumulatorTester(); + + //! Destroy object FrameAccumulatorTester + ~FrameAccumulatorTester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! + void testFrameDetected(); + void testMoreDataNeeded(); + void testNoFrameDetected(); + + private: + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + //! Connect ports + void connectPorts(); + + //! Initialize components + void initComponents(); + + private: + // ---------------------------------------------------------------------- + // Port handler overrides + // ---------------------------------------------------------------------- + Fw::Buffer from_frameAllocate_handler(FwIndexType portNum, U32 size) override; + + private: + // ---------------------------------------------------------------------- + // Member variables + // ---------------------------------------------------------------------- + + //! The component under test + FrameAccumulator component; + + class MockDetector : public FrameDetector { + public: + Status detect(const Types::CircularBuffer& data, FwSizeType& size_out) const override { + size_out = next_size_out; + return next_status; + } + + Status next_status = Status::FRAME_DETECTED; + U32 next_size_out = 0; + }; + + //! Instances required by the component under test + MockDetector mockDetector; + Fw::MallocAllocator mallocator; + + Fw::Buffer m_buffer; // buffer to be returned by mocked frameAllocate call + U8 m_buffer_slot[2048]; +}; + +} // namespace Svc + +#endif diff --git a/Svc/Router/test/ut/RouterTestMain.cpp b/Svc/Router/test/ut/RouterTestMain.cpp index 786208c3e9..39c10d8985 100644 --- a/Svc/Router/test/ut/RouterTestMain.cpp +++ b/Svc/Router/test/ut/RouterTestMain.cpp @@ -8,22 +8,22 @@ #include -TEST(Route, TestComInterface) { +TEST(Router, TestComInterface) { COMMENT("Route a com packet"); Svc::RouterTester tester; tester.testRouteComInterface(); } -TEST(Route, TestFileInterface) { +TEST(Router, TestFileInterface) { COMMENT("Route a file packet"); Svc::RouterTester tester; tester.testRouteFileInterface(); } -TEST(Route, TestUnknownInterface) { +TEST(Router, TestUnknownInterface) { COMMENT("Attempt to route a packet of unknown type"); Svc::RouterTester tester; tester.testRouteUnknownPacket(); } -TEST(Route, TestCommandResponse) { +TEST(Router, TestCommandResponse) { COMMENT("Handle a command response (no-op)"); Svc::RouterTester tester; tester.testCommandResponse(); diff --git a/Svc/Router/test/ut/RouterTester.cpp b/Svc/Router/test/ut/RouterTester.cpp index 11807b174f..dce7913230 100644 --- a/Svc/Router/test/ut/RouterTester.cpp +++ b/Svc/Router/test/ut/RouterTester.cpp @@ -61,7 +61,8 @@ void RouterTester::mockReceivePacketType(Fw::ComPacket::ComPacketType packetType U8 data[sizeof descriptorType]; Fw::Buffer buffer(data, sizeof(data)); buffer.getSerializeRepr().serialize(descriptorType); - this->invoke_to_bufferIn(0, buffer); + Fw::Buffer nullContext; + this->invoke_to_dataIn(0, buffer, nullContext); } } // namespace Svc