From 4b379f8efc5bce52c80c93fb6300002c6739df4b Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 10 Oct 2024 17:45:52 -0700 Subject: [PATCH] Fix issues with DpContainer and ExternalSerializeBuffer (#2941) * Revise Fw/Types * Revise DpContainer to reset data size when setting the buffer * Revise ExternalSerializeBuffer to clear the serialization state when setting the buffer * Add tests for ExternalSerializeBuffer * Revise ExternalSerializeBuffer and tests * Revise tests for ExternalSerializeBuffer * Revise DpTest * Add comment; remove blank line * Fix spelling --- FppTest/dp/DpTest.cpp | 18 ++++ FppTest/dp/DpTest.hpp | 5 +- FppTest/dp/test/ut/TestMain.cpp | 63 ++++++++--- FppTest/dp/test/ut/Tester.cpp | 22 ++++ Fw/Dp/DpContainer.cpp | 4 + Fw/Dp/DpContainer.hpp | 2 + Fw/Dp/test/ut/TestMain.cpp | 2 + Fw/Types/CMakeLists.txt | 1 + Fw/Types/Serializable.cpp | 11 +- Fw/Types/Serializable.hpp | 14 +-- .../test/ut/ExternalSerializeBufferTest.cpp | 100 ++++++++++++++++++ 11 files changed, 215 insertions(+), 27 deletions(-) create mode 100644 Fw/Types/test/ut/ExternalSerializeBufferTest.cpp diff --git a/FppTest/dp/DpTest.cpp b/FppTest/dp/DpTest.cpp index 56d0e7baa5..b1a74e0dd4 100644 --- a/FppTest/dp/DpTest.cpp +++ b/FppTest/dp/DpTest.cpp @@ -102,6 +102,7 @@ void DpTest::schedIn_handler(const NATIVE_INT_TYPE portNum, U32 context) { void DpTest ::dpRecv_Container1_handler(DpContainer& container, Fw::Success::T status) { // Test container assignment this->m_container = container; + this->checkContainerEmpty(this->m_container); if (status == Fw::Success::SUCCESS) { auto serializeStatus = Fw::FW_SERIALIZE_OK; for (FwSizeType i = 0; i < CONTAINER_1_DATA_SIZE; ++i) { @@ -121,6 +122,7 @@ void DpTest ::dpRecv_Container1_handler(DpContainer& container, Fw::Success::T s void DpTest ::dpRecv_Container2_handler(DpContainer& container, Fw::Success::T status) { // Test container assignment this->m_container = container; + this->checkContainerEmpty(this->m_container); if (status == Fw::Success::SUCCESS) { const DpTest_Data dataRecord(this->dataRecordData); auto serializeStatus = Fw::FW_SERIALIZE_OK; @@ -141,6 +143,7 @@ void DpTest ::dpRecv_Container2_handler(DpContainer& container, Fw::Success::T s void DpTest ::dpRecv_Container3_handler(DpContainer& container, Fw::Success::T status) { // Test container assignment this->m_container = container; + this->checkContainerEmpty(this->m_container); if (status == Fw::Success::SUCCESS) { auto serializeStatus = Fw::FW_SERIALIZE_OK; for (FwSizeType i = 0; i < CONTAINER_3_DATA_SIZE; ++i) { @@ -161,6 +164,7 @@ void DpTest ::dpRecv_Container3_handler(DpContainer& container, Fw::Success::T s void DpTest ::dpRecv_Container4_handler(DpContainer& container, Fw::Success::T status) { // Test container assignment this->m_container = container; + this->checkContainerEmpty(this->m_container); if (status == Fw::Success::SUCCESS) { auto serializeStatus = Fw::FW_SERIALIZE_OK; for (FwSizeType i = 0; i < CONTAINER_4_DATA_SIZE; ++i) { @@ -181,6 +185,7 @@ void DpTest ::dpRecv_Container4_handler(DpContainer& container, Fw::Success::T s void DpTest ::dpRecv_Container5_handler(DpContainer& container, Fw::Success::T status) { // Test container assignment this->m_container = container; + this->checkContainerEmpty(this->m_container); if (status == Fw::Success::SUCCESS) { auto serializeStatus = Fw::FW_SERIALIZE_OK; for (FwSizeType i = 0; i < CONTAINER_5_DATA_SIZE; ++i) { @@ -201,6 +206,7 @@ void DpTest ::dpRecv_Container5_handler(DpContainer& container, Fw::Success::T s void DpTest ::dpRecv_Container6_handler(DpContainer& container, Fw::Success::T status) { // Test container assignment this->m_container = container; + this->checkContainerEmpty(this->m_container); if (status == Fw::Success::SUCCESS) { auto serializeStatus = Fw::FW_SERIALIZE_OK; for (FwSizeType i = 0; i < CONTAINER_6_DATA_SIZE; ++i) { @@ -220,6 +226,7 @@ void DpTest ::dpRecv_Container6_handler(DpContainer& container, Fw::Success::T s void DpTest ::dpRecv_Container7_handler(DpContainer& container, Fw::Success::T status) { // Test container assignment this->m_container = container; + this->checkContainerEmpty(this->m_container); if (status == Fw::Success::SUCCESS) { auto serializeStatus = Fw::FW_SERIALIZE_OK; for (FwSizeType i = 0; i < CONTAINER_7_DATA_SIZE; ++i) { @@ -241,10 +248,21 @@ void DpTest ::dpRecv_Container7_handler(DpContainer& container, Fw::Success::T s // Private helper functions // ---------------------------------------------------------------------- +void DpTest::checkContainerEmpty(const DpContainer& container) const { + const FwSizeType dataSize = container.getDataSize(); + FW_ASSERT(dataSize == 0, static_cast(dataSize)); + const Fw::SerializeBufferBase& buffer = container.m_dataBuffer; + const FwSizeType buffLength = buffer.getBuffLength(); + FW_ASSERT(buffLength == 0, static_cast(buffLength)); + const FwSizeType buffLeft = buffer.getBuffLeft(); + FW_ASSERT(buffLeft == 0, static_cast(buffLeft)); +} + void DpTest::checkContainer(const DpContainer& container, FwDpIdType localId, FwSizeType size, FwDpPriorityType priority) const { + this->checkContainerEmpty(container); FW_ASSERT(container.getBaseId() == this->getIdBase(), container.getBaseId(), this->getIdBase()); FW_ASSERT(container.getId() == container.getBaseId() + localId, container.getId(), container.getBaseId(), ContainerId::Container1); diff --git a/FppTest/dp/DpTest.hpp b/FppTest/dp/DpTest.hpp index 1adab4e75b..05c6b83c22 100644 --- a/FppTest/dp/DpTest.hpp +++ b/FppTest/dp/DpTest.hpp @@ -15,7 +15,6 @@ namespace FppTest { class DpTest : public DpTestComponentBase { - // Friend class for testing friend class Tester; @@ -139,6 +138,10 @@ class DpTest : public DpTestComponentBase { // Private helper functions // ---------------------------------------------------------------------- + //! Check that a container is empty + void checkContainerEmpty(const DpContainer& container //!< The container + ) const; + //! Check a container for validity void checkContainer(const DpContainer& container, //!< The container FwDpIdType localId, //!< The expected local id diff --git a/FppTest/dp/test/ut/TestMain.cpp b/FppTest/dp/test/ut/TestMain.cpp index 63f0dc9b46..2ab5ab49b1 100644 --- a/FppTest/dp/test/ut/TestMain.cpp +++ b/FppTest/dp/test/ut/TestMain.cpp @@ -8,94 +8,127 @@ using namespace FppTest; +// Iterate the tests to ensure that everything works after the first time +static constexpr FwIndexType NUM_ITERS = 2; + TEST(schedIn, OK) { COMMENT("schedIn OK"); Tester tester; - tester.schedIn_OK(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.schedIn_OK(); + } } TEST(productRecvIn, Container1_SUCCESS) { COMMENT("Receive Container1 SUCCESS"); Tester tester; - tester.productRecvIn_Container1_SUCCESS(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container1_SUCCESS(); + } } TEST(productRecvIn, Container1_FAILURE) { COMMENT("Receive Container1 FAILURE"); Tester tester; - tester.productRecvIn_Container1_FAILURE(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container1_FAILURE(); + } } TEST(productRecvIn, Container2_SUCCESS) { COMMENT("Receive Container2 SUCCESS"); Tester tester; - tester.productRecvIn_Container2_SUCCESS(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container2_SUCCESS(); + } } TEST(productRecvIn, Container2_FAILURE) { COMMENT("Receive Container2 FAILURE"); Tester tester; - tester.productRecvIn_Container2_FAILURE(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container2_FAILURE(); + } } TEST(productRecvIn, Container3_SUCCESS) { COMMENT("Receive Container3 SUCCESS"); Tester tester; - tester.productRecvIn_Container3_SUCCESS(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container3_SUCCESS(); + } } TEST(productRecvIn, Container3_FAILURE) { COMMENT("Receive Container3 FAILURE"); Tester tester; - tester.productRecvIn_Container3_FAILURE(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container3_FAILURE(); + } } TEST(productRecvIn, Container4_SUCCESS) { COMMENT("Receive Container4 SUCCESS"); Tester tester; - tester.productRecvIn_Container4_SUCCESS(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container4_SUCCESS(); + } } TEST(productRecvIn, Container4_FAILURE) { COMMENT("Receive Container4 FAILURE"); Tester tester; - tester.productRecvIn_Container4_FAILURE(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container4_FAILURE(); + } } TEST(productRecvIn, Container5_SUCCESS) { COMMENT("Receive Container5 SUCCESS"); Tester tester; - tester.productRecvIn_Container5_SUCCESS(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container5_SUCCESS(); + } } TEST(productRecvIn, Container5_FAILURE) { COMMENT("Receive Container5 FAILURE"); Tester tester; - tester.productRecvIn_Container5_FAILURE(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container5_FAILURE(); + } } TEST(productRecvIn, Container6_SUCCESS) { COMMENT("Receive Container6 SUCCESS"); Tester tester; - tester.productRecvIn_Container6_SUCCESS(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container6_SUCCESS(); + } } TEST(productRecvIn, Container6_FAILURE) { COMMENT("Receive Container6 FAILURE"); Tester tester; - tester.productRecvIn_Container6_FAILURE(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container6_FAILURE(); + } } TEST(productRecvIn, Container7_SUCCESS) { COMMENT("Receive Container7 SUCCESS"); Tester tester; - tester.productRecvIn_Container7_SUCCESS(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container7_SUCCESS(); + } } TEST(productRecvIn, Container7_FAILURE) { COMMENT("Receive Container7 FAILURE"); Tester tester; - tester.productRecvIn_Container7_FAILURE(); + for (FwIndexType i = 0; i < NUM_ITERS; i++) { + tester.productRecvIn_Container7_FAILURE(); + } } int main(int argc, char** argv) { diff --git a/FppTest/dp/test/ut/Tester.cpp b/FppTest/dp/test/ut/Tester.cpp index e12d70bb99..08d8f067de 100644 --- a/FppTest/dp/test/ut/Tester.cpp +++ b/FppTest/dp/test/ut/Tester.cpp @@ -63,6 +63,7 @@ Tester::~Tester() {} // ---------------------------------------------------------------------- void Tester::schedIn_OK() { + this->clearHistory(); this->invoke_to_schedIn(0, 0); this->component.doDispatch(); ASSERT_PRODUCT_REQUEST_SIZE(6); @@ -83,6 +84,8 @@ void Tester::schedIn_OK() { void Tester::productRecvIn_Container1_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; + // Clear the history + this->clearHistory(); // Check the record size constexpr FwSizeType recordSize = DpTestComponentBase::SIZE_OF_U32Record_RECORD; ASSERT_EQ(recordSize, sizeof(FwDpIdType) + sizeof(U32)); @@ -107,12 +110,15 @@ void Tester::productRecvIn_Container1_SUCCESS() { } void Tester::productRecvIn_Container1_FAILURE() { + this->clearHistory(); productRecvIn_CheckFailure(DpTest::ContainerId::Container1, this->container1Buffer); } void Tester::productRecvIn_Container2_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; + // Clear the history + this->clearHistory(); // Check the record size constexpr FwSizeType recordSize = DpTestComponentBase::SIZE_OF_DataRecord_RECORD; ASSERT_EQ(recordSize, sizeof(FwDpIdType) + DpTest_Data::SERIALIZED_SIZE); @@ -137,12 +143,15 @@ void Tester::productRecvIn_Container2_SUCCESS() { } void Tester::productRecvIn_Container2_FAILURE() { + this->clearHistory(); productRecvIn_CheckFailure(DpTest::ContainerId::Container2, this->container2Buffer); } void Tester::productRecvIn_Container3_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; + // Clear the history + this->clearHistory(); // Compute the data element size const FwSizeType arraySize = this->u8ArrayRecordData.size(); const FwSizeType dataEltSize = sizeof(FwSizeStoreType) + arraySize; @@ -178,12 +187,15 @@ void Tester::productRecvIn_Container3_SUCCESS() { } void Tester::productRecvIn_Container3_FAILURE() { + this->clearHistory(); productRecvIn_CheckFailure(DpTest::ContainerId::Container3, this->container3Buffer); } void Tester::productRecvIn_Container4_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; + // Clear the history + this->clearHistory(); // Compute the data element size const FwSizeType arraySize = this->u32ArrayRecordData.size(); const FwSizeType dataEltSize = sizeof(FwSizeStoreType) + arraySize * sizeof(U32); @@ -220,11 +232,14 @@ void Tester::productRecvIn_Container4_SUCCESS() { void Tester::productRecvIn_Container4_FAILURE() { productRecvIn_CheckFailure(DpTest::ContainerId::Container4, this->container4Buffer); + this->clearHistory(); } void Tester::productRecvIn_Container5_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; + // Clear the history + this->clearHistory(); // Compute the data element size const FwSizeType arraySize = this->dataArrayRecordData.size(); const FwSizeType dataEltSize = sizeof(FwSizeStoreType) + arraySize * DpTest_Data::SERIALIZED_SIZE; @@ -260,12 +275,15 @@ void Tester::productRecvIn_Container5_SUCCESS() { } void Tester::productRecvIn_Container5_FAILURE() { + this->clearHistory(); productRecvIn_CheckFailure(DpTest::ContainerId::Container5, this->container5Buffer); } void Tester::productRecvIn_Container6_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; + // Clear the history + this->clearHistory(); // Check the record size constexpr FwSizeType recordSize = DpTestComponentBase::SIZE_OF_StringRecord_RECORD; ASSERT_EQ(recordSize, sizeof(FwDpIdType) + Fw::StringBase::STATIC_SERIALIZED_SIZE(DpTest_stringSize)); @@ -293,12 +311,15 @@ void Tester::productRecvIn_Container6_SUCCESS() { } void Tester::productRecvIn_Container6_FAILURE() { + this->clearHistory(); productRecvIn_CheckFailure(DpTest::ContainerId::Container6, this->container6Buffer); } void Tester::productRecvIn_Container7_SUCCESS() { Fw::Buffer buffer; FwSizeType expectedNumElts; + // Clear the history + this->clearHistory(); // Check the record size const FwSizeType arraySize = DpTest::STRING_ARRAY_RECORD_ARRAY_SIZE; const FwSizeType recordSize = DpTestComponentBase::SIZE_OF_StringArrayRecord_RECORD(arraySize); @@ -337,6 +358,7 @@ void Tester::productRecvIn_Container7_SUCCESS() { } void Tester::productRecvIn_Container7_FAILURE() { + this->clearHistory(); productRecvIn_CheckFailure(DpTest::ContainerId::Container7, this->container7Buffer); } diff --git a/Fw/Dp/DpContainer.cpp b/Fw/Dp/DpContainer.cpp index 9eac97f16b..be3a6c6f77 100644 --- a/Fw/Dp/DpContainer.cpp +++ b/Fw/Dp/DpContainer.cpp @@ -139,7 +139,11 @@ void DpContainer::setBuffer(const Buffer& buffer) { FW_ASSERT(bufferSize >= minBufferSize, static_cast(bufferSize), static_cast(minBufferSize)); U8* const dataAddr = &buffAddr[DATA_OFFSET]; + // Set the buffer + // This action also clears the serialization state in the buffer this->m_dataBuffer.setExtBuffer(dataAddr, static_cast(dataCapacity)); + // Reset the data size + this->m_dataSize = 0; } Utils::HashBuffer DpContainer::getHeaderHash() const { diff --git a/Fw/Dp/DpContainer.hpp b/Fw/Dp/DpContainer.hpp index a9d9e3030c..b0363dbfe6 100644 --- a/Fw/Dp/DpContainer.hpp +++ b/Fw/Dp/DpContainer.hpp @@ -173,6 +173,8 @@ class DpContainer { //! Invalidate the packet buffer void invalidateBuffer() { this->m_buffer = Fw::Buffer(); + this->m_dataBuffer.clear(); + this->m_dataSize = 0; } //! Get the stored header hash diff --git a/Fw/Dp/test/ut/TestMain.cpp b/Fw/Dp/test/ut/TestMain.cpp index 90a7d8b058..5c04d2d356 100644 --- a/Fw/Dp/test/ut/TestMain.cpp +++ b/Fw/Dp/test/ut/TestMain.cpp @@ -155,6 +155,8 @@ TEST(Header, BufferSet) { container.invalidateBuffer(); // Check that the buffer is invalid ASSERT_EQ(container.getBuffer(), Fw::Buffer()); + // Check that the data size is zero + ASSERT_EQ(container.getDataSize(), 0); } TEST(Header, BadPacketDescriptor) { diff --git a/Fw/Types/CMakeLists.txt b/Fw/Types/CMakeLists.txt index 0d1fc3c273..6c3c54334f 100644 --- a/Fw/Types/CMakeLists.txt +++ b/Fw/Types/CMakeLists.txt @@ -25,6 +25,7 @@ set(MOD_DEPS register_fprime_module() ### UTs ### set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/test/ut/ExternalSerializeBufferTest.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/TypesTest.cpp" ) set(UT_MOD_DEPS diff --git a/Fw/Types/Serializable.cpp b/Fw/Types/Serializable.cpp index dfba70881f..afe43934ed 100644 --- a/Fw/Types/Serializable.cpp +++ b/Fw/Types/Serializable.cpp @@ -46,10 +46,8 @@ void SerializeBufferBase::copyFrom(const SerializeBufferBase& src) { FW_ASSERT(src.getBuffAddr()); FW_ASSERT(this->getBuffAddr()); // destination has to be same or bigger - FW_ASSERT( - src.getBuffLength() <= this->getBuffCapacity(), - static_cast(src.getBuffLength()), - static_cast(this->getBuffLength())); + FW_ASSERT(src.getBuffLength() <= this->getBuffCapacity(), static_cast(src.getBuffLength()), + static_cast(this->getBuffLength())); (void)memcpy(this->getBuffAddr(), src.getBuffAddr(), this->m_serLoc); } @@ -676,6 +674,8 @@ SerializeStatus SerializeBufferBase::setBuffLen(Serializable::SizeType length) { } Serializable::SizeType SerializeBufferBase::getBuffLeft() const { + FW_ASSERT(this->m_serLoc >= this->m_deserLoc, static_cast(this->m_serLoc), + static_cast(this->m_deserLoc)); return this->m_serLoc - this->m_deserLoc; } @@ -765,11 +765,14 @@ ExternalSerializeBuffer::ExternalSerializeBuffer() { void ExternalSerializeBuffer::setExtBuffer(U8* buffPtr, Serializable::SizeType size) { FW_ASSERT(buffPtr != nullptr); + this->clear(); this->m_buff = buffPtr; this->m_buffSize = size; } void ExternalSerializeBuffer::clear() { + this->resetSer(); + this->resetDeser(); this->m_buff = nullptr; this->m_buffSize = 0; } diff --git a/Fw/Types/Serializable.hpp b/Fw/Types/Serializable.hpp index f9ee4cd8f0..61513d5531 100644 --- a/Fw/Types/Serializable.hpp +++ b/Fw/Types/Serializable.hpp @@ -197,7 +197,6 @@ class SerializeBufferBase { // Copy constructor can be used only by the implementation SerializeBufferBase(const SerializeBufferBase& src); //!< constructor with buffer as source - void copyFrom(const SerializeBufferBase& src); //!< copy data from source buffer Serializable::SizeType m_serLoc; //!< current offset in buffer of serialized data Serializable::SizeType m_deserLoc; //!< current offset for deserialization @@ -208,10 +207,12 @@ class SerializeBufferBase { //! External serialize buffer with no copy semantics class ExternalSerializeBuffer : public SerializeBufferBase { public: - ExternalSerializeBuffer(U8* buffPtr, Serializable::SizeType size); //!< construct with external buffer - ExternalSerializeBuffer(); //!< default constructor - ~ExternalSerializeBuffer() {} //!< destructor - void setExtBuffer(U8* buffPtr, Serializable::SizeType size); //!< Set the external buffer + ExternalSerializeBuffer(U8* buffPtr, Serializable::SizeType size); //!< construct with external buffer + ExternalSerializeBuffer(); //!< default constructor + ~ExternalSerializeBuffer() {} //!< destructor + //! Set the external buffer + //! This action also resets the serialization and deserialization pointers + void setExtBuffer(U8* buffPtr, Serializable::SizeType size); void clear(); //!< clear external buffer ExternalSerializeBuffer(const ExternalSerializeBuffer& src) = delete; //!< deleted copy constructor @@ -262,8 +263,7 @@ class ExternalSerializeBufferWithMemberCopy final : public ExternalSerializeBuff ExternalSerializeBufferWithMemberCopy& operator=(const ExternalSerializeBufferWithMemberCopy& src) { // Ward against self-assignment if (this != &src) { - this->m_buff = src.m_buff; - this->m_buffSize = src.m_buffSize; + this->setExtBuffer(src.m_buff, src.m_buffSize); } return *this; } diff --git a/Fw/Types/test/ut/ExternalSerializeBufferTest.cpp b/Fw/Types/test/ut/ExternalSerializeBufferTest.cpp new file mode 100644 index 0000000000..01d472cd17 --- /dev/null +++ b/Fw/Types/test/ut/ExternalSerializeBufferTest.cpp @@ -0,0 +1,100 @@ +#include +#include + +#include "Fw/Types/Serializable.hpp" + +namespace ExternalSerializeBufferTest { + + using SizeType = Fw::Serializable::SizeType; + + constexpr SizeType BUFFER_SIZE = 10; + + U8 buffer[BUFFER_SIZE]; + + void serializeOK(Fw::ExternalSerializeBuffer& esb) { + const SizeType buffCapacity = esb.getBuffCapacity(); + ASSERT_EQ(esb.getBuffLength(), 0); + for (SizeType i = 0; i < buffCapacity; i++) { + const U8 value = static_cast(i); + const Fw::SerializeStatus status = esb.serialize(value); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + } + ASSERT_EQ(esb.getBuffLength(), buffCapacity); + } + + void serializeFail(Fw::ExternalSerializeBuffer& esb) { + ASSERT_EQ(esb.getBuffLength(), esb.getBuffCapacity()); + const Fw::SerializeStatus status = esb.serialize(static_cast(0)); + ASSERT_EQ(status, Fw::FW_SERIALIZE_NO_ROOM_LEFT); + } + + void deserializeOK(Fw::ExternalSerializeBuffer& esb) { + const SizeType buffCapacity = esb.getBuffCapacity(); + ASSERT_EQ(esb.getBuffLeft(), buffCapacity); + for (SizeType i = 0; i < buffCapacity; i++) { + U8 value = 0; + const Fw::SerializeStatus status = esb.deserialize(value); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(value, static_cast(i)); + } + ASSERT_EQ(esb.getBuffLeft(), 0); + } + + void deserializeFail(Fw::ExternalSerializeBuffer& esb) { + U8 value = 0; + ASSERT_EQ(esb.getBuffLeft(), 0); + const Fw::SerializeStatus status = esb.deserialize(value); + ASSERT_EQ(status, Fw::FW_DESERIALIZE_BUFFER_EMPTY); + } + + TEST(ExternalSerializeBuffer, Basic) { + Fw::ExternalSerializeBuffer esb(buffer, BUFFER_SIZE); + // Serialization should succeed + serializeOK(esb); + // Serialization should fail + serializeFail(esb); + // Deserialization should succeed + deserializeOK(esb); + // Deserialization should fail + deserializeFail(esb); + } + + TEST(ExternalSerializeBuffer, Clear) { + Fw::ExternalSerializeBuffer esb(buffer, BUFFER_SIZE); + // Serialization should succeed + serializeOK(esb); + // Clear the buffer + esb.clear(); + // Serialization should fail + serializeFail(esb); + // Deserialization should fail + deserializeFail(esb); + } + + TEST(ExternalSerializeBuffer, SetExtBuffer) { + Fw::ExternalSerializeBuffer esb(buffer, BUFFER_SIZE); + // Serialization should succeed + serializeOK(esb); + // Set the buffer + // This should also clear the serialization state + esb.setExtBuffer(buffer, BUFFER_SIZE); + // Serialization should succeed + serializeOK(esb); + // Deserialization should succeed + deserializeOK(esb); + } + + TEST(ExternalSerializeBufferWithMemberCopy, Assign) { + Fw::ExternalSerializeBufferWithMemberCopy esb1(buffer, BUFFER_SIZE); + Fw::ExternalSerializeBufferWithMemberCopy esb2(buffer, BUFFER_SIZE); + // Serialization should succeed + serializeOK(esb1); + // Assign esb2 to esb1 + esb1 = esb2; + // Deserialization should fail + deserializeFail(esb1); + // Serialization should succeed + serializeOK(esb1); + } + +}