From f265eb24142ade6cbc9c4fe4c1eb78fdb604577a Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 25 Apr 2024 16:27:12 -0700 Subject: [PATCH] Fix string records for data products (#2697) * Revise Linux platform types * Fix regression in test autocoder TimeBaseStoreType is not the same as TimeBase * Revise test autocoder Cast to the TimeBaseStore type with a known size * Revise test autocoder Remove unnecessary const casting * Fix integer type mismatch in ComQueue * Update fpp version * Update fpp version * Revise DpWriter unit tests Remove manually written functions Use new autocode in tester base * Update fpp version * Update fpp version * Revise DpTest Add check for priority set by dpGet * Reivse StringType; add ExternalString * Revise dp test * Revise dp test; update fpp version * Revise dp test * Revise dp test * Revise dp test * Revise dp test * Revise dp test * Revise dp test * Revise dp test * Revise dp test * Revise dp test * Revise fpp version * Update fpp version * Revise ExternalString * Reformat Fw/Serializable.{hpp,cpp} * Reformat StringType.{hpp,cpp} * Revise StringBase * Update fpp version * Remove trailing space * Reformat code * Revise dp test * Reformat cpp and hpp files in Fw/Types * Revise string types * Revise string types * Revise string types * Remove EightyCharString * Revise CmdString * Revise LogString * Revise PrmString * Revise TextLogString * Revise Test/String * Revise TlmString * Revise InternalInterfaceString * Revise Os/QueueString * Revise Os/TaskString * Add missing type qualifier * Fix warning in String.hpp * Revise string types * Remove stray character * Revise StringBase * Revise string types * Revise String type * Revise FileNameString * Revise string types * Add missing file * Revise InternalInterfaceString * Revise comment * Revise TlmString * Revise string types * Revise log strings * Revise PrmString * Revise Os string classes * Revise string types * Revise string types * Revise os strings * Add test for ExternalString to TypesTest * Revise ExternalString * Revise ExternalString * Update fpp version * Format Fw/Types * Update fpp version * Revise code formatting * Remove helper scripts * Update fpp version * Fix spelling * Update requirements * Update actions@version * Fix pip-check CI by restricting versions * Remove debugging instructions --------- Co-authored-by: thomas-bc Co-authored-by: M Starch --- .github/workflows/pip-check.yml | 14 +++- FppTest/dp/DpTest.cpp | 53 ++++++++++++-- FppTest/dp/DpTest.fpp | 18 +++++ FppTest/dp/DpTest.hpp | 126 +++++++++++++++++++------------- FppTest/dp/test/ut/TestMain.cpp | 24 ++++++ FppTest/dp/test/ut/Tester.cpp | 110 ++++++++++++++++++++++++++-- FppTest/dp/test/ut/Tester.hpp | 39 +++++++++- Fw/Types/StringBase.cpp | 8 ++ Fw/Types/StringBase.hpp | 3 + requirements.txt | 24 +++--- 10 files changed, 340 insertions(+), 79 deletions(-) diff --git a/.github/workflows/pip-check.yml b/.github/workflows/pip-check.yml index 82c5c8e928..7c67c4d37c 100644 --- a/.github/workflows/pip-check.yml +++ b/.github/workflows/pip-check.yml @@ -17,11 +17,19 @@ jobs: strategy: matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] - runner: [macos-latest, ubuntu-latest] + runner: [macos-13, macos-latest, ubuntu-latest] + # macos-14 (ARM) currently breaks actions/setup-python with 3.8 and 3.9 + # so we exclude them from the matrix and also test with macos-13 (x86) + # More info at https://github.com/actions/setup-python/issues/850 + exclude: + - runner: macos-latest + python-version: '3.8' + - runner: macos-latest + python-version: '3.9' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/FppTest/dp/DpTest.cpp b/FppTest/dp/DpTest.cpp index da812182d3..f8f10e22ff 100644 --- a/FppTest/dp/DpTest.cpp +++ b/FppTest/dp/DpTest.cpp @@ -15,19 +15,25 @@ namespace FppTest { // Construction, initialization, and destruction // ---------------------------------------------------------------------- -DpTest ::DpTest(const char* const compName, - U32 u32RecordData, - U16 dataRecordData, - const U8ArrayRecordData& u8ArrayRecordData, - const U32ArrayRecordData& u32ArrayRecordData, - const DataArrayRecordData& dataArrayRecordData) +DpTest::DpTest(const char* const compName, + U32 u32RecordData, + U16 dataRecordData, + const U8ArrayRecordData& u8ArrayRecordData, + const U32ArrayRecordData& u32ArrayRecordData, + const DataArrayRecordData& dataArrayRecordData, + const Fw::StringBase& a_stringRecordData) : DpTestComponentBase(compName), u32RecordData(u32RecordData), dataRecordData(dataRecordData), u8ArrayRecordData(u8ArrayRecordData), u32ArrayRecordData(u32ArrayRecordData), dataArrayRecordData(dataArrayRecordData), - sendTime(Fw::ZERO_TIME) {} + stringRecordData(a_stringRecordData), + sendTime(Fw::ZERO_TIME) { + for (auto& elt : this->stringArrayRecordData) { + elt = &a_stringRecordData; + } +} void DpTest ::init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance) { DpTestComponentBase::init(queueDepth, instance); @@ -50,6 +56,8 @@ void DpTest::schedIn_handler(const NATIVE_INT_TYPE portNum, U32 context) { this->dpRequest_Container4(CONTAINER_4_DATA_SIZE); // Request a buffer for Container 5 this->dpRequest_Container5(CONTAINER_5_DATA_SIZE); + // Request a buffer for Container 6 + this->dpRequest_Container6(CONTAINER_6_DATA_SIZE); // Get a buffer for Container 1 { DpContainer container; @@ -178,6 +186,37 @@ void DpTest ::dpRecv_Container5_handler(DpContainer& container, Fw::Success::T s } } +void DpTest ::dpRecv_Container6_handler(DpContainer& container, Fw::Success::T status) { + if (status == Fw::Success::SUCCESS) { + auto serializeStatus = Fw::FW_SERIALIZE_OK; + for (FwSizeType i = 0; i < CONTAINER_6_DATA_SIZE; ++i) { + serializeStatus = container.serializeRecord_StringRecord(this->stringRecordData); + if (serializeStatus == Fw::FW_SERIALIZE_NO_ROOM_LEFT) { + break; + } + FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, status); + } + // Use the time stamp from the time get port + this->dpSend(container); + } +} + +void DpTest ::dpRecv_Container7_handler(DpContainer& container, Fw::Success::T status) { + if (status == Fw::Success::SUCCESS) { + auto serializeStatus = Fw::FW_SERIALIZE_OK; + for (FwSizeType i = 0; i < CONTAINER_7_DATA_SIZE; ++i) { + serializeStatus = container.serializeRecord_StringArrayRecord( + this->stringArrayRecordData, FW_NUM_ARRAY_ELEMENTS(this->stringArrayRecordData)); + if (serializeStatus == Fw::FW_SERIALIZE_NO_ROOM_LEFT) { + break; + } + FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, status); + } + // Use the time stamp from the time get port + this->dpSend(container); + } +} + // ---------------------------------------------------------------------- // Private helper functions // ---------------------------------------------------------------------- diff --git a/FppTest/dp/DpTest.fpp b/FppTest/dp/DpTest.fpp index 77398715ea..98c733e0d3 100644 --- a/FppTest/dp/DpTest.fpp +++ b/FppTest/dp/DpTest.fpp @@ -3,6 +3,12 @@ module FppTest { @ A component for testing data product code gen active component DpTest { + # ---------------------------------------------------------------------- + # Constants + # ---------------------------------------------------------------------- + + constant stringSize = 80 + # ---------------------------------------------------------------------- # Types # ---------------------------------------------------------------------- @@ -58,6 +64,12 @@ module FppTest { @ Record 5 product record DataArrayRecord: Data array id 500 + @ Record 6 + product record StringRecord: string size stringSize id 600 + + @ Record 7 + product record StringArrayRecord: string size stringSize array id 700 + # ---------------------------------------------------------------------- # Containers # ---------------------------------------------------------------------- @@ -77,6 +89,12 @@ module FppTest { @ Container 5 product container Container5 id 500 default priority 50 + @ Container 6 + product container Container6 id 600 default priority 60 + + @ Container 7 + product container Container7 id 700 default priority 70 + } } diff --git a/FppTest/dp/DpTest.hpp b/FppTest/dp/DpTest.hpp index 47959a0a7f..29a3e4bc56 100644 --- a/FppTest/dp/DpTest.hpp +++ b/FppTest/dp/DpTest.hpp @@ -10,10 +10,15 @@ #include #include "FppTest/dp/DpTestComponentAc.hpp" +#include "Fw/Types/String.hpp" namespace FppTest { class DpTest : public DpTestComponentBase { + + // Friend class for testing + friend class Tester; + public: // ---------------------------------------------------------------------- // Constants @@ -29,6 +34,12 @@ class DpTest : public DpTestComponentBase { static constexpr FwSizeType CONTAINER_4_PACKET_SIZE = DpContainer::getPacketSizeForDataSize(CONTAINER_4_DATA_SIZE); static constexpr FwSizeType CONTAINER_5_DATA_SIZE = 1000; static constexpr FwSizeType CONTAINER_5_PACKET_SIZE = DpContainer::getPacketSizeForDataSize(CONTAINER_5_DATA_SIZE); + static constexpr FwSizeType CONTAINER_6_DATA_SIZE = 1000; + static constexpr FwSizeType CONTAINER_6_PACKET_SIZE = DpContainer::getPacketSizeForDataSize(CONTAINER_6_DATA_SIZE); + static constexpr FwSizeType CONTAINER_7_DATA_SIZE = 1000; + static constexpr FwSizeType CONTAINER_7_PACKET_SIZE = DpContainer::getPacketSizeForDataSize(CONTAINER_7_DATA_SIZE); + + static constexpr FwSizeType STRING_ARRAY_RECORD_ARRAY_SIZE = 100; public: // ---------------------------------------------------------------------- @@ -38,6 +49,7 @@ class DpTest : public DpTestComponentBase { using U8ArrayRecordData = std::array; using U32ArrayRecordData = std::array; using DataArrayRecordData = std::array; + using PtrToConstStringBase = const Fw::StringBase*; public: // ---------------------------------------------------------------------- @@ -45,12 +57,13 @@ class DpTest : public DpTestComponentBase { // ---------------------------------------------------------------------- //! Construct object DpTest - DpTest(const char* const compName, //!< The component name - U32 u32RecordData, //!< The U32Record data - U16 dataRecordData, //!< The DataRecord data - const U8ArrayRecordData& u8ArrayRecordData, //!< The U8ArrayRecord data - const U32ArrayRecordData& u32ArrayRecordData, //!< The U32ArrayRecord data - const DataArrayRecordData& dataArrayRecordData //!< The DataArrayRecord data + DpTest(const char* const compName, //!< The component name + U32 u32RecordData, //!< The U32Record data + U16 dataRecordData, //!< The DataRecord data + const U8ArrayRecordData& u8ArrayRecordData, //!< The U8ArrayRecord data + const U32ArrayRecordData& u32ArrayRecordData, //!< The U32ArrayRecord data + const DataArrayRecordData& dataArrayRecordData, //!< The DataArrayRecord data + const Fw::StringBase& stringRecordData //!< The StringRecord data ); //! Initialize object DpTest @@ -69,73 +82,82 @@ class DpTest : public DpTestComponentBase { //! Set the send time void setSendTime(Fw::Time time) { this->sendTime = time; } - PRIVATE : - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for schedIn - void - schedIn_handler(const NATIVE_INT_TYPE portNum, //!< The port number - U32 context //!< The call order - ) override; - - PRIVATE : - // ---------------------------------------------------------------------- - // Data product handler implementations - // ---------------------------------------------------------------------- - - //! Receive a data product container of type Container1 - //! \return Serialize status - void - dpRecv_Container1_handler(DpContainer& container, //!< The container - Fw::Success::T //!< The container status - ) override; + private: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for schedIn + void schedIn_handler(const NATIVE_INT_TYPE portNum, //!< The port number + U32 context //!< The call order + ) final; + + private: + // ---------------------------------------------------------------------- + // Data product handler implementations + // ---------------------------------------------------------------------- + + //! Receive a data product container of type Container1 + //! \return Serialize status + void dpRecv_Container1_handler(DpContainer& container, //!< The container + Fw::Success::T //!< The container status + ) final; //! Receive a data product container of type Container2 //! \return Serialize status void dpRecv_Container2_handler(DpContainer& container, //!< The container Fw::Success::T //!< The container status - ) override; + ) final; //! Receive a data product container of type Container3 //! \return Serialize status void dpRecv_Container3_handler(DpContainer& container, //!< The container Fw::Success::T //!< The container status - ) override; + ) final; //! Receive a data product container of type Container4 //! \return Serialize status void dpRecv_Container4_handler(DpContainer& container, //!< The container Fw::Success::T //!< The container status - ) override; + ) final; //! Receive a data product container of type Container5 //! \return Serialize status void dpRecv_Container5_handler(DpContainer& container, //!< The container Fw::Success::T //!< The container status - ) override; + ) final; - PRIVATE : - // ---------------------------------------------------------------------- - // Private helper functions - // ---------------------------------------------------------------------- + //! Receive a data product container of type Container6 + //! \return Serialize status + void dpRecv_Container6_handler(DpContainer& container, //!< The container + Fw::Success::T //!< The container status + ) final; + + //! Receive a data product container of type Container7 + //! \return Serialize status + void dpRecv_Container7_handler(DpContainer& container, //!< The container + Fw::Success::T //!< The container status + ) final; + + private: + // ---------------------------------------------------------------------- + // Private helper functions + // ---------------------------------------------------------------------- - //! Check a container for validity - void - checkContainer(const DpContainer& container, //!< The container - FwDpIdType localId, //!< The expected local id - FwSizeType size, //!< The expected size - FwDpPriorityType priority //!< The expected priority - ) const; + //! Check a container for validity + void checkContainer(const DpContainer& container, //!< The container + FwDpIdType localId, //!< The expected local id + FwSizeType size, //!< The expected size + FwDpPriorityType priority //!< The expected priority + ) const; - PRIVATE : - // ---------------------------------------------------------------------- - // Private member variables - // ---------------------------------------------------------------------- + private: + // ---------------------------------------------------------------------- + // Private member variables + // ---------------------------------------------------------------------- - //! U32Record data - const U32 u32RecordData; + //! U32Record data + const U32 u32RecordData; //! DataRecord data const U16 dataRecordData; @@ -149,6 +171,12 @@ class DpTest : public DpTestComponentBase { //! DataArrayRecord data const DataArrayRecordData& dataArrayRecordData; + //! StringRecord data + const Fw::StringBase& stringRecordData; + + //! StringArrayRecord data + PtrToConstStringBase stringArrayRecordData[STRING_ARRAY_RECORD_ARRAY_SIZE]; + //! Send time for testing Fw::Time sendTime; }; diff --git a/FppTest/dp/test/ut/TestMain.cpp b/FppTest/dp/test/ut/TestMain.cpp index d1034cb308..63f0dc9b46 100644 --- a/FppTest/dp/test/ut/TestMain.cpp +++ b/FppTest/dp/test/ut/TestMain.cpp @@ -74,6 +74,30 @@ TEST(productRecvIn, Container5_FAILURE) { tester.productRecvIn_Container5_FAILURE(); } +TEST(productRecvIn, Container6_SUCCESS) { + COMMENT("Receive Container6 SUCCESS"); + Tester tester; + tester.productRecvIn_Container6_SUCCESS(); +} + +TEST(productRecvIn, Container6_FAILURE) { + COMMENT("Receive Container6 FAILURE"); + Tester tester; + tester.productRecvIn_Container6_FAILURE(); +} + +TEST(productRecvIn, Container7_SUCCESS) { + COMMENT("Receive Container7 SUCCESS"); + Tester tester; + tester.productRecvIn_Container7_SUCCESS(); +} + +TEST(productRecvIn, Container7_FAILURE) { + COMMENT("Receive Container7 FAILURE"); + Tester tester; + tester.productRecvIn_Container7_FAILURE(); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); STest::Random::seed(); diff --git a/FppTest/dp/test/ut/Tester.cpp b/FppTest/dp/test/ut/Tester.cpp index 9973b8ff02..a37f75a568 100644 --- a/FppTest/dp/test/ut/Tester.cpp +++ b/FppTest/dp/test/ut/Tester.cpp @@ -4,10 +4,11 @@ // \brief cpp file for DpTest test harness implementation class // ====================================================================== -#include #include +#include "FppTest/dp/FppConstantsAc.hpp" #include "FppTest/dp/test/ut/Tester.hpp" +#include "Fw/Types/ExternalString.hpp" #include "STest/Pick/Pick.hpp" namespace FppTest { @@ -28,16 +29,21 @@ Tester::Tester() container4Buffer(this->container4Data, sizeof this->container4Data), container5Data{}, container5Buffer(this->container5Data, sizeof this->container5Data), + container6Data{}, + container6Buffer(this->container6Data, sizeof this->container6Data), + container7Data{}, + container7Buffer(this->container7Data, sizeof this->container7Data), component("DpTest", STest::Pick::any(), STest::Pick::any(), this->u8ArrayRecordData, this->u32ArrayRecordData, - this->dataArrayRecordData) { + this->dataArrayRecordData, + this->stringRecordData) { this->initComponents(); this->connectPorts(); this->component.setIdBase(ID_BASE); - // Fill in arrays with random data + // Fill in arrays and strings with random data for (U8& elt : this->u8ArrayRecordData) { elt = static_cast(STest::Pick::any()); } @@ -47,6 +53,7 @@ Tester::Tester() for (DpTest_Data& elt : this->dataArrayRecordData) { elt.set(static_cast(STest::Pick::any())); } + generateRandomString(this->stringRecordData); } Tester::~Tester() {} @@ -58,12 +65,13 @@ Tester::~Tester() {} void Tester::schedIn_OK() { this->invoke_to_schedIn(0, 0); this->component.doDispatch(); - ASSERT_PRODUCT_REQUEST_SIZE(5); + ASSERT_PRODUCT_REQUEST_SIZE(6); ASSERT_PRODUCT_REQUEST(0, ID_BASE + DpTest::ContainerId::Container1, FwSizeType(DpTest::CONTAINER_1_PACKET_SIZE)); ASSERT_PRODUCT_REQUEST(1, ID_BASE + DpTest::ContainerId::Container2, FwSizeType(DpTest::CONTAINER_2_PACKET_SIZE)); ASSERT_PRODUCT_REQUEST(2, ID_BASE + DpTest::ContainerId::Container3, FwSizeType(DpTest::CONTAINER_3_PACKET_SIZE)); ASSERT_PRODUCT_REQUEST(3, ID_BASE + DpTest::ContainerId::Container4, FwSizeType(DpTest::CONTAINER_4_PACKET_SIZE)); ASSERT_PRODUCT_REQUEST(4, ID_BASE + DpTest::ContainerId::Container5, FwSizeType(DpTest::CONTAINER_5_PACKET_SIZE)); + ASSERT_PRODUCT_REQUEST(5, ID_BASE + DpTest::ContainerId::Container6, FwSizeType(DpTest::CONTAINER_6_PACKET_SIZE)); ASSERT_PRODUCT_GET_SIZE(5); ASSERT_PRODUCT_GET(0, ID_BASE + DpTest::ContainerId::Container1, FwSizeType(DpTest::CONTAINER_1_PACKET_SIZE)); ASSERT_PRODUCT_GET(1, ID_BASE + DpTest::ContainerId::Container2, FwSizeType(DpTest::CONTAINER_2_PACKET_SIZE)); @@ -129,6 +137,7 @@ void Tester::productRecvIn_Container2_FAILURE() { void Tester::productRecvIn_Container3_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; + // Compute the data element size const FwSizeType dataEltSize = sizeof(FwSizeStoreType) + this->u8ArrayRecordData.size(); // Invoke the port and check the header this->productRecvIn_InvokeAndCheckHeader(DpTest::ContainerId::Container3, dataEltSize, @@ -165,6 +174,7 @@ void Tester::productRecvIn_Container3_FAILURE() { void Tester::productRecvIn_Container4_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; + // Compute the data element size const FwSizeType dataEltSize = sizeof(FwSizeStoreType) + this->u32ArrayRecordData.size() * sizeof(U32); // Invoke the port and check the header this->productRecvIn_InvokeAndCheckHeader(DpTest::ContainerId::Container4, dataEltSize, @@ -201,7 +211,9 @@ void Tester::productRecvIn_Container4_FAILURE() { void Tester::productRecvIn_Container5_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; - const FwSizeType dataEltSize = sizeof(FwSizeStoreType) + this->dataArrayRecordData.size() * DpTest_Data::SERIALIZED_SIZE; + // Compute the data element size + const FwSizeType dataEltSize = + sizeof(FwSizeStoreType) + this->dataArrayRecordData.size() * DpTest_Data::SERIALIZED_SIZE; // Invoke the port and check the header this->productRecvIn_InvokeAndCheckHeader(DpTest::ContainerId::Container5, dataEltSize, DpTest::ContainerPriority::Container5, this->container5Buffer, buffer, @@ -234,6 +246,77 @@ void Tester::productRecvIn_Container5_FAILURE() { productRecvIn_CheckFailure(DpTest::ContainerId::Container5, this->container5Buffer); } +void Tester::productRecvIn_Container6_SUCCESS() { + Fw::Buffer buffer; + FwSizeType expectedNumElts; + // Construct the possibly truncated string + // Add one to the string size to account for the null terminator + char esData[DpTest_stringSize+1]; + Fw::ExternalString es(esData, sizeof esData, this->stringRecordData); + // Invoke the port and check the header + this->productRecvIn_InvokeAndCheckHeader(DpTest::ContainerId::Container6, es.serializedSize(), + DpTest::ContainerPriority::Container6, this->container6Buffer, buffer, + expectedNumElts); + // Check the data + Fw::SerializeBufferBase& serialRepr = buffer.getSerializeRepr(); + Fw::TestUtil::DpContainerHeader::checkDeserialAtOffset(serialRepr, Fw::DpContainer::DATA_OFFSET); + for (FwSizeType i = 0; i < expectedNumElts; ++i) { + FwDpIdType id; + Fw::String elt; + auto status = serialRepr.deserialize(id); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + const FwDpIdType expectedId = this->component.getIdBase() + DpTest::RecordId::StringRecord; + ASSERT_EQ(id, expectedId); + status = serialRepr.deserialize(elt); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(elt, es); + } +} + +void Tester::productRecvIn_Container6_FAILURE() { + productRecvIn_CheckFailure(DpTest::ContainerId::Container6, this->container6Buffer); +} + +void Tester::productRecvIn_Container7_SUCCESS() { + Fw::Buffer buffer; + FwSizeType expectedNumElts; + // Construct the possibly truncated string + // Add one to the string size to account for the null terminator + char esData[DpTest_stringSize+1]; + Fw::ExternalString es(esData, sizeof esData, this->stringRecordData); + const FwSizeType arraySize = DpTest::STRING_ARRAY_RECORD_ARRAY_SIZE; + const FwSizeType dataEltSize = sizeof(FwSizeStoreType) + arraySize * es.serializedSize(); + // Invoke the port and check the header + this->productRecvIn_InvokeAndCheckHeader(DpTest::ContainerId::Container7, dataEltSize, + DpTest::ContainerPriority::Container7, this->container7Buffer, buffer, + expectedNumElts); + // Check the data + Fw::SerializeBufferBase& serialRepr = buffer.getSerializeRepr(); + Fw::TestUtil::DpContainerHeader::checkDeserialAtOffset(serialRepr, Fw::DpContainer::DATA_OFFSET); + for (FwSizeType i = 0; i < expectedNumElts; ++i) { + FwDpIdType id; + auto status = serialRepr.deserialize(id); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + const FwDpIdType expectedId = this->component.getIdBase() + DpTest::RecordId::StringArrayRecord; + ASSERT_EQ(id, expectedId); + FwSizeType size; + status = serialRepr.deserializeSize(size); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(size, arraySize); + const U8* const buffAddr = serialRepr.getBuffAddr(); + for (FwSizeType j = 0; j < size; ++j) { + Fw::String elt; + status = serialRepr.deserialize(elt); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(elt, es); + } + } +} + +void Tester::productRecvIn_Container7_FAILURE() { + productRecvIn_CheckFailure(DpTest::ContainerId::Container7, this->container7Buffer); +} + // ---------------------------------------------------------------------- // Helper methods // ---------------------------------------------------------------------- @@ -247,6 +330,23 @@ Fw::Time Tester::randomizeTestTime() { return time; } +void Tester::generateRandomString(Fw::StringBase& str) { + // Reserve enough space for max length plus null terminator + char buffer[MAX_STRING_LENGTH + 1]; + // Pick a random string length + const FwSizeType length = STest::Pick::lowerUpper(0, MAX_STRING_LENGTH); + // Fill buffer with a random null-terminated string with that length + FwSizeType i = 0; + for (; i < length; i++) { + U32 u32 = STest::Pick::lowerUpper(1, std::numeric_limits::max()); + buffer[i] = static_cast(u32); + } + FW_ASSERT(i <= sizeof buffer, static_cast(i), static_cast(MAX_STRING_LENGTH)); + buffer[i] = 0; + // Copy the contents of buffer into str + str.format("%s", buffer); +} + void Tester::productRecvIn_InvokeAndCheckHeader(FwDpIdType id, FwSizeType dataEltSize, FwDpPriorityType priority, diff --git a/FppTest/dp/test/ut/Tester.hpp b/FppTest/dp/test/ut/Tester.hpp index d941707881..b7021af1da 100644 --- a/FppTest/dp/test/ut/Tester.hpp +++ b/FppTest/dp/test/ut/Tester.hpp @@ -28,6 +28,8 @@ class Tester : public DpTestGTestBase { static constexpr FwSizeType TEST_INSTANCE_QUEUE_DEPTH = 10; // The component id base static constexpr FwDpIdType ID_BASE = 100; + // The max string length for string data + static constexpr FwSizeType MAX_STRING_LENGTH = 100; //! Construct object Tester //! @@ -75,7 +77,19 @@ class Tester : public DpTestGTestBase { //! productRecvIn with Container 5 (FAILURE) void productRecvIn_Container5_FAILURE(); - PRIVATE: + //! productRecvIn with Container 6 (SUCCESS) + void productRecvIn_Container6_SUCCESS(); + + //! productRecvIn with Container 6 (FAILURE) + void productRecvIn_Container6_FAILURE(); + + //! productRecvIn with Container 7 (SUCCESS) + void productRecvIn_Container7_SUCCESS(); + + //! productRecvIn with Container 7 (FAILURE) + void productRecvIn_Container7_FAILURE(); + + private: // ---------------------------------------------------------------------- // Handlers for data product ports // ---------------------------------------------------------------------- @@ -85,7 +99,7 @@ class Tester : public DpTestGTestBase { Fw::Buffer& buffer //!< The buffer ) override; - PRIVATE: + private: // ---------------------------------------------------------------------- // Helper methods // ---------------------------------------------------------------------- @@ -102,6 +116,10 @@ class Tester : public DpTestGTestBase { //! \return The time Fw::Time randomizeTestTime(); + //! Generate a random string + static void generateRandomString(Fw::StringBase& str //!< The string (output) + ); + //! Invoke productRecvIn and check header //! This sets the output buffer to the received buffer and sets the //! deserialization pointer to the start of the data payload @@ -118,7 +136,7 @@ class Tester : public DpTestGTestBase { Fw::Buffer buffer //!< The buffer ); - PRIVATE: + private: // ---------------------------------------------------------------------- // Variables // ---------------------------------------------------------------------- @@ -153,6 +171,18 @@ class Tester : public DpTestGTestBase { //! Buffer for Container 5 const Fw::Buffer container5Buffer; + //! Buffer data for Container 6 + U8 container6Data[DpTest::CONTAINER_6_PACKET_SIZE]; + + //! Buffer for Container 6 + const Fw::Buffer container6Buffer; + + //! Buffer data for Container 7 + U8 container7Data[DpTest::CONTAINER_7_PACKET_SIZE]; + + //! Buffer for Container 7 + const Fw::Buffer container7Buffer; + //! Data for U8 array record DpTest::U8ArrayRecordData u8ArrayRecordData; @@ -162,6 +192,9 @@ class Tester : public DpTestGTestBase { //! Data for Data array record DpTest::DataArrayRecordData dataArrayRecordData; + //! Data for String record + Fw::String stringRecordData; + //! The component under test DpTest component; }; diff --git a/Fw/Types/StringBase.cpp b/Fw/Types/StringBase.cpp index 2a7cef41f8..f3cc9d1e0e 100644 --- a/Fw/Types/StringBase.cpp +++ b/Fw/Types/StringBase.cpp @@ -117,6 +117,14 @@ StringBase::SizeType StringBase::length() const { return static_cast(StringUtils::string_length(this->toChar(), this->getCapacity())); } +StringBase::SizeType StringBase::serializedSize() const { + return static_cast(sizeof(FwSizeStoreType)) + this->length(); +} + +StringBase::SizeType StringBase::serializedTruncatedSize(FwSizeType maxLength) const { + return static_cast(sizeof(FwSizeStoreType)) + FW_MIN(this->length(), maxLength); +} + SerializeStatus StringBase::serialize(SerializeBufferBase& buffer) const { return buffer.serialize(reinterpret_cast(this->toChar()), this->length()); } diff --git a/Fw/Types/StringBase.hpp b/Fw/Types/StringBase.hpp index 37ea190e48..4e07bc33e8 100644 --- a/Fw/Types/StringBase.hpp +++ b/Fw/Types/StringBase.hpp @@ -26,6 +26,9 @@ class StringBase : public Serializable { virtual const CHAR* toChar() const = 0; //