diff --git a/include/up-cpp/datamodel/builder/Payload.h b/include/up-cpp/datamodel/builder/Payload.h index d24ffbbf9..1caa021c1 100644 --- a/include/up-cpp/datamodel/builder/Payload.h +++ b/include/up-cpp/datamodel/builder/Payload.h @@ -32,6 +32,9 @@ struct Payload { /// @brief A serialized payload as a pairing of bytes and format. using Serialized = std::tuple; + /// @brief The two types of data that can be stored in a Serialized payload. + enum PayloadType { Data, Format }; + /// @brief Constructs a Payload builder with the payload populated by /// a serialized protobuf. /// @@ -43,7 +46,13 @@ struct Payload { /// @remarks The UPayloadFormat will automatically be set to /// UPAYLOAD_FORMAT_PROTOBUF template - explicit Payload(const ProtobufT&); + explicit Payload(const ProtobufT& message) { + std::string serialized; + message.SerializeToString(&serialized); + payload_ = + std::make_tuple(std::move(serialized), + v1::UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF); + } /// @brief Creates a Payload builder with the payload populated by the /// result of Serializer::serialize(data). @@ -70,7 +79,14 @@ struct Payload { /// will compile out. /// @param data Data to be serialized and stored. template - Payload(Serializer s, const ValueT& data); + Payload(Serializer s, const ValueT& data) { + auto serializedData = Serializer::serialize(data); + if (!UPayloadFormat_IsValid( + std::get(serializedData))) { + throw std::out_of_range("Invalid Serializer payload format"); + } + payload_ = std::move(serializedData); + } /// @brief Creates a Payload builder with a provided pre-serialized data. /// @@ -78,7 +94,8 @@ struct Payload { /// @param format The data format of the payload in value_bytes. /// /// @throws std::out_of_range If format is not valid for v1::UPayloadFormat - Payload(const std::vector& value_bytes, v1::UPayloadFormat format); + Payload(const std::vector& value_bytes, + const v1::UPayloadFormat format); /// @brief Creates a Payload builder with a provided pre-serialized data. /// @@ -89,7 +106,7 @@ struct Payload { /// /// @note This would typically be used for UPAYLOAD_FORMAT_TEXT or /// UPAYLOAD_FORMAT_JSON, but can be used for other payload formats. - Payload(const std::string& value, v1::UPayloadFormat format); + Payload(const std::string& value, const v1::UPayloadFormat format); /// @brief Creates a Payload builder with a provided pre-serialized data. /// @@ -102,7 +119,7 @@ struct Payload { /// /// @note This would typically be used for UPAYLOAD_FORMAT_TEXT or /// UPAYLOAD_FORMAT_JSON, but can be used for other payload formats. - Payload(std::string&& value, v1::UPayloadFormat format); + Payload(std::string&& value, const v1::UPayloadFormat format); /// @brief Creates a Payload builder with a provided pre-serialized data. /// @@ -138,20 +155,24 @@ struct Payload { /// @brief Get a reference to the internal data from this builder. /// - /// @throws PayloadMoved if called after move() has already been called. - [[nodiscard]] constexpr const Serialized& build() const; + /// @throws PayloadMoved if called after buildMove() has already been + /// called. + [[nodiscard]] const Serialized& buildCopy() const; /// @brief Get an xvalue of the internal data that can be moved into a /// UMessage. /// - /// @post This Payload builder will no longer be valid. Calling `build()` + /// @post This Payload builder will no longer be valid. Calling + /// `buildCopy()` /// or `movePayload()` after this will result in an exception. /// - /// @throws PayloadMoved if called after move() has already been called. - [[nodiscard]] constexpr Serialized move() &&; + /// @throws PayloadMoved if called after buildMove() has already been + /// called. + [[nodiscard]] Serialized buildMove() &&; private: Serialized payload_; + bool moved_{false}; }; } // namespace uprotocol::datamodel::builder diff --git a/src/datamodel/builder/Payload.cpp b/src/datamodel/builder/Payload.cpp index b8b83602b..42f43ad19 100644 --- a/src/datamodel/builder/Payload.cpp +++ b/src/datamodel/builder/Payload.cpp @@ -10,3 +10,101 @@ // SPDX-License-Identifier: Apache-2.0 #include "up-cpp/datamodel/builder/Payload.h" +namespace uprotocol::datamodel::builder { + +// Byte vector constructor +Payload::Payload(const std::vector& value_bytes, + const v1::UPayloadFormat format) { + if (!UPayloadFormat_IsValid(format)) { + throw std::out_of_range("Invalid Byte vector payload format"); + } + std::string serialized(value_bytes.begin(), value_bytes.end()); + payload_ = std::make_tuple(std::move(serialized), format); +} + +// String constructor +Payload::Payload(const std::string& value, const v1::UPayloadFormat format) { + if (!UPayloadFormat_IsValid(format)) { + throw std::out_of_range("Invalid String payload format"); + } + payload_ = std::make_tuple(std::move(value), format); +} + +// Move string constructor +Payload::Payload(std::string&& value, const v1::UPayloadFormat format) { + if (!UPayloadFormat_IsValid(format)) { + throw std::out_of_range("Invalid RValue String payload format"); + } + payload_ = std::make_tuple(std::move(value), format); +} + +// Move Serialized constructor +Payload::Payload(Serialized&& serialized) { + if (!UPayloadFormat_IsValid(std::get(serialized))) { + throw std::out_of_range("Invalid RValue Serialized payload format"); + } + payload_ = std::move(serialized); +} + +// Move constructor +Payload::Payload(Payload&& other) noexcept + : payload_(std::move(other.payload_)), moved_(std::move(other.moved_)) {} + +// Copy constructor +Payload::Payload(const Payload& other) + : payload_(other.payload_), moved_(other.moved_) {} + +// Move assignment operator +Payload& Payload::operator=(Payload&& other) noexcept { + payload_ = std::move(other.payload_); + moved_ = std::move(other.moved_); + return *this; +} + +// Copy assignment operator +Payload& Payload::operator=(const Payload& other) { + payload_ = other.payload_; + moved_ = other.moved_; + return *this; +} + +Payload::PayloadMoved::PayloadMoved(PayloadMoved&& other) noexcept + : std::runtime_error(std::move(other)) {} + +// PayloadMoved move assignment operator +Payload::PayloadMoved& Payload::PayloadMoved::operator=( + PayloadMoved&& other) noexcept { + std::runtime_error::operator=(std::move(other)); + return *this; +} + +// PayloadMoved copy constructor +Payload::PayloadMoved::PayloadMoved(const PayloadMoved& other) + : std::runtime_error(other) {} + +// PayloadMoved copy assignment operator +Payload::PayloadMoved& Payload::PayloadMoved::operator=( + const PayloadMoved& other) { + std::runtime_error::operator=(other); + return *this; +} + +// buildCopy method +[[nodiscard]] const Payload::Serialized& Payload::buildCopy() const { + if (moved_) { + throw PayloadMoved("Payload has been already moved"); + } + return payload_; +} + +// buildMove method +[[nodiscard]] Payload::Serialized Payload::buildMove() && { + // Check if payload_ is in the "moved" state + if (moved_) { + throw PayloadMoved("Payload has been already moved"); + } + // Set payload_ to the "moved" state + moved_ = true; + return std::move(payload_); +} +} // namespace uprotocol::datamodel::builder diff --git a/test/coverage/datamodel/PayloadBuilderTest.cpp b/test/coverage/datamodel/PayloadBuilderTest.cpp index 44661c8e4..f624f817b 100644 --- a/test/coverage/datamodel/PayloadBuilderTest.cpp +++ b/test/coverage/datamodel/PayloadBuilderTest.cpp @@ -12,9 +12,27 @@ #include #include +#include + namespace { +using namespace uprotocol::datamodel::builder; + +struct TimeAsPayloadSerializer { + static Payload::Serialized serialize(std::chrono::milliseconds t) { + Payload::PbBytes data; + auto millisec = t.count(); + data.resize(sizeof(millisec)); + *(reinterpret_cast(data.data())) = millisec; + return std::make_tuple(std::move(data), format_); + } + static void setFormat(const uprotocol::v1::UPayloadFormat format) { + format_ = format; + } + static inline uprotocol::v1::UPayloadFormat format_ = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_UNSPECIFIED; +}; -class TestFixture : public testing::Test { +class PayloadTest : public testing::Test { protected: // Run once per TEST_F. // Used to set up clean environments per test. @@ -23,16 +41,523 @@ class TestFixture : public testing::Test { // Run once per execution of the test application. // Used for setup of all tests. Has access to this instance. - TestFixture() = default; - ~TestFixture() = default; + PayloadTest() = default; + ~PayloadTest() = default; // Run once per execution of the test application. // Used only for global setup outside of tests. static void SetUpTestSuite() {} static void TearDownTestSuite() {} + + // Note : Need to make the std::string version longer to avoid SSO (small + // string optimization) as it will interfere with the move tests + const std::string testStringPayload_ = + "Testttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"; + const std::vector testBytesPayload_{'T', 'e', 's', 't', + '0', '1', '2', '3'}; }; -// TODO replace -TEST_F(TestFixture, SomeTestName) {} +/////////////////Serialized Protobuf Tests///////////////////////// + +// Create serialized protobuf payload and verify build payload +TEST_F(PayloadTest, CreateSerializedProtobufPayloadAndBuildTest) { + // Arrange + uprotocol::v1::UUri uriObject; + uriObject.set_authority_name(testStringPayload_); + auto expectedPayloadData = uriObject.SerializeAsString(); + + // Act + Payload payload(uriObject); + + // Assert + auto [payloadData, payloadFormat] = payload.buildCopy(); + EXPECT_EQ(payloadFormat, + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF); + EXPECT_EQ(payloadData, expectedPayloadData); +} + +// Create serialized protobuf payload with empty message +TEST_F(PayloadTest, CreateEmptySerializedProtobufPayloadTest) { + // Arrange + uprotocol::v1::UUri uriObject; + uriObject.set_authority_name(""); + + // Act + Payload payload(uriObject); + + // Assert + auto [payloadData, payloadFormat] = payload.buildCopy(); + EXPECT_EQ(payloadFormat, + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF); + EXPECT_EQ(payloadData, uriObject.SerializeAsString()); +} + +// Create serialized protobuf payload and verify moved payload +TEST_F(PayloadTest, CreateSerializedProtobufPayloadAndMoveTest) { + // Arrange + uprotocol::v1::UUri uriObject; + uriObject.set_authority_name(testStringPayload_); + auto expectedPayloadData = uriObject.SerializeAsString(); + + // Act + Payload payload(uriObject); + auto& [payload_reference, _] = payload.buildCopy(); + const void* original_address = payload_reference.data(); + + // Assert + auto [payloadData, payloadFormat] = std::move(payload).buildMove(); + EXPECT_EQ(payloadFormat, + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF); + EXPECT_EQ(payloadData, expectedPayloadData); + + EXPECT_THROW(auto _ = payload.buildCopy(), Payload::PayloadMoved); + EXPECT_EQ(original_address, payloadData.data()); +} + +// Create serialized protobuf payload. Verify exception for move paylod twice +TEST_F(PayloadTest, CreateSerializedProtobufPayloadAndMoveTwiceExceptionTest) { + // Arrange + uprotocol::v1::UUri uriObject; + uriObject.set_authority_name(testStringPayload_); + + // Act + Payload payload(uriObject); + + // Assert + auto [payloadData, payloadFormat] = std::move(payload).buildMove(); + + EXPECT_EQ(payloadFormat, + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF); + EXPECT_EQ(payloadData, uriObject.SerializeAsString()); + + EXPECT_THROW(std::move(payload).buildMove(), Payload::PayloadMoved); +} + +// Create serialized protobuf payload. Call build after move. +TEST_F(PayloadTest, + CreateSerializedProtobufPayloadAndCallBuildAfterMoveExceptionTest) { + // Arrange + uprotocol::v1::UUri uriObject; + uriObject.set_authority_name(testStringPayload_); + + // Act + Payload payload(uriObject); + // Call move on payload first + auto [payloadData, payloadFormat] = std::move(payload).buildMove(); + + // Assert + + EXPECT_EQ(payloadFormat, + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF); + EXPECT_EQ(payloadData, uriObject.SerializeAsString()); + + // Call build on payload after move + EXPECT_THROW(auto _ = payload.buildCopy(), Payload::PayloadMoved); +} + +/////////////Serializer Payload Protobuf Tests///////////////// + +// Create a serializer payload and verify build payload +TEST_F(PayloadTest, CreateSerializerPayloadAndBuildTest) { + // Arrange + std::chrono::milliseconds t(1234); + TimeAsPayloadSerializer timeSerializer; + timeSerializer.setFormat( + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_RAW); + auto expectedSerializedObject = timeSerializer.serialize( + std::chrono::duration_cast(t)); + + // Act + Payload payload(timeSerializer, t); + + // Assert + auto [payloadData, payloadFormat] = payload.buildCopy(); + EXPECT_EQ(payloadData, + std::get(expectedSerializedObject)); + EXPECT_EQ(payloadFormat, + std::get(expectedSerializedObject)); +} + +// Create a serializer payload with invalid format +TEST_F(PayloadTest, CreateSerializerPayloadWithInvalidFormat) { + // Arrange + std::chrono::milliseconds t(1234); + TimeAsPayloadSerializer timeSerializer; + auto invalidFormat = static_cast(9999); + // Ovreide the format with invalid value + timeSerializer.setFormat(invalidFormat); + + auto expectedSerializedObject = timeSerializer.serialize( + std::chrono::duration_cast(t)); + + // Act + EXPECT_THROW(Payload payload(timeSerializer, t), std::out_of_range); +} + +// Create a serializer payload and verify moved payload +TEST_F(PayloadTest, CreateSerializerPayloadAndMoveTest) { + // Arrange + std::chrono::milliseconds t(12345); + TimeAsPayloadSerializer timeSerializer; + timeSerializer.setFormat( + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_RAW); + auto expectedSerializedObject = timeSerializer.serialize( + std::chrono::duration_cast(t)); + + // Act + Payload payload(timeSerializer, t); + + // Assert + auto [payloadData, payloadFormat] = std::move(payload).buildMove(); + EXPECT_EQ(payloadData, + std::get(expectedSerializedObject)); + EXPECT_EQ(payloadFormat, + std::get(expectedSerializedObject)); + + EXPECT_THROW(auto _ = payload.buildCopy(), Payload::PayloadMoved); +} + +////////////////////////Byte Array Payload Tests//////////////////////// + +// Create payload of Byte array and check if the payload is created correctly +TEST_F(PayloadTest, ByteArrayPayloadTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_RAW; + + // Act + Payload payload(testBytesPayload_, format); + + // Assert + auto [serializedData, payloadFormat] = payload.buildCopy(); + + EXPECT_EQ(serializedData, "Test0123"); + EXPECT_EQ(payloadFormat, format); +} + +// Create payload of Byte array with invalid format and check if it throws +// exception +TEST_F(PayloadTest, ConstructorInvalidFormatForByteArrayPayloadTest) { + // Arrange + uprotocol::v1::UPayloadFormat invalid_format = + static_cast(9999); + + // Act and Assert + EXPECT_THROW(Payload payload(testBytesPayload_, invalid_format), + std::out_of_range); +} + +// Create empty byte array payload +TEST_F(PayloadTest, EmptyByteArrayPayloadTest) { + // Arrange + std::vector value_bytes = {}; + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_RAW; + + // Act + Payload payload(value_bytes, format); + + // Assert + auto [serializedData, payloadFormat] = payload.buildCopy(); + + EXPECT_TRUE(serializedData.empty()); + EXPECT_EQ(payloadFormat, format); +} + +// Create byte array payload and call buildMove() +TEST_F(PayloadTest, MoveByteArrayPayloadTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_RAW; + + // Act + Payload payload(testBytesPayload_, format); + auto [serializedData, payloadFormat] = std::move(payload).buildMove(); + + // Assert + EXPECT_EQ(serializedData, "Test0123"); + EXPECT_EQ(payloadFormat, format); + EXPECT_THROW(auto _ = payload.buildCopy(), Payload::PayloadMoved); +} + +//////////////String Payload Tests////////////// + +// Create payload of std::string and check if the payload is created +TEST_F(PayloadTest, StringPayloadTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_TEXT; + + // Act + Payload payload(testStringPayload_, format); + + // Assert + auto [serializedData, payloadFormat] = payload.buildCopy(); + EXPECT_EQ(serializedData, testStringPayload_); + EXPECT_EQ(payloadFormat, format); +} + +// Create payload of std::string with invalid format +TEST_F(PayloadTest, ConstructorInvalidFormatForStringPayloadTest) { + // Arrange + uprotocol::v1::UPayloadFormat invalid_format = + static_cast(9999); + + // Act and Assert + EXPECT_THROW(Payload payload(testStringPayload_, invalid_format), + std::out_of_range); +} + +// Create empty string payload +TEST_F(PayloadTest, EmptyStringPayloadTest) { + // Arrange + std::string value_string = ""; + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_TEXT; + + // Act + Payload payload(value_string, format); + + // Assert + auto [serializedData, payloadFormat] = payload.buildCopy(); + EXPECT_TRUE(serializedData.empty()); + EXPECT_EQ(payloadFormat, format); +} + +// Create std::string payload and call move on payload object test +TEST_F(PayloadTest, StringMovePayloadTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_TEXT; + + // Act + Payload payload(testStringPayload_, format); + auto [serializedData, payloadFormat] = std::move(payload).buildMove(); + + // Assert + EXPECT_EQ(serializedData, testStringPayload_); + EXPECT_EQ(payloadFormat, format); + EXPECT_THROW(auto _ = payload.buildCopy(), Payload::PayloadMoved); +} + +/////////////////////RValue String Payload Tests///////////////////// + +// Create RValue String Payload +TEST_F(PayloadTest, RValueStringPayloadTest) { + // Arrange + std::string value_string = testStringPayload_; + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_TEXT; + const void* original_address = value_string.data(); + + // Act + Payload payload(std::move(value_string), format); + + // Assert + auto [serializedData, payloadFormat] = std::move(payload).buildMove(); + EXPECT_EQ(serializedData, testStringPayload_); + EXPECT_EQ(payloadFormat, format); + EXPECT_EQ(serializedData.data(), original_address); +} + +// Create payload of RValue String with invalid format +TEST_F(PayloadTest, ConstructorInvalidFormatForRValueStringPayloadTest) { + // Arrange + std::string value_string = testStringPayload_; + uprotocol::v1::UPayloadFormat invalid_format = + static_cast(9999); + + // Act and Assert + EXPECT_THROW(Payload payload(std::move(value_string), invalid_format), + std::out_of_range); +} + +// Create empty RValue String payload +TEST_F(PayloadTest, EmptyRValueStringPayloadTest) { + // Arrange + std::string value_string = ""; + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_TEXT; + + // Act + Payload payload(std::move(value_string), format); + + // Assert + auto [serializedData, payloadFormat] = payload.buildCopy(); + EXPECT_TRUE(serializedData.empty()); + EXPECT_EQ(payloadFormat, format); +} + +// Create RValue String and move payload object test +TEST_F(PayloadTest, RValueStringMovePayloadTest) { + // Arrange + std::string value_string = testStringPayload_; + const void* originalAddress = value_string.data(); + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_TEXT; + + // Act + Payload payload(std::move(value_string), format); + auto [serializedData, payloadFormat] = std::move(payload).buildMove(); + const void* movedAddress = serializedData.data(); + + // Assert + EXPECT_EQ(serializedData, testStringPayload_); + EXPECT_EQ(payloadFormat, format); + + EXPECT_EQ(originalAddress, movedAddress); + EXPECT_THROW(auto _ = payload.buildCopy(), Payload::PayloadMoved); +} + +///////////////////////RValue Serialized Payload Tests////////////////////// + +// Create RValue Serialized payload +TEST_F(PayloadTest, RvalueSerializedConstructorTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_RAW; + Payload::Serialized serialized = + std::make_tuple(testStringPayload_, format); + const void* originalAddress = + std::get(serialized).data(); + + // Act + Payload payload(std::move(serialized)); + + // Assert + auto [payloadData, payloadFormat] = std::move(payload).buildMove(); + EXPECT_EQ(payloadData, testStringPayload_); + EXPECT_EQ(payloadFormat, format); + EXPECT_EQ(payloadData.data(), originalAddress); +} + +// Create payload of RValue Serialized with invalid format +TEST_F(PayloadTest, ConstructorInvalidFormatForRValueSerializedPayloadTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + static_cast(9999); + Payload::Serialized serialized = + std::make_tuple(testStringPayload_, format); + + // Act + EXPECT_THROW(Payload payload(std::move(serialized));, std::out_of_range); +} + +// Create empty RValue Serialized payload and build. +TEST_F(PayloadTest, EmptyRValueSerializedPayloadTest) { + // Arrange + std::string serializedData = ""; + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_RAW; + Payload::Serialized serialized = std::make_tuple(serializedData, format); + + // Act + Payload payload(std::move(serialized)); + + // Assert + auto [payloadData, payloadFormat] = payload.buildCopy(); + EXPECT_TRUE(payloadData.empty()); + EXPECT_EQ(payloadFormat, format); +} + +// Create RValue Serialized and move payload object test +TEST_F(PayloadTest, RValueSerializedMovePayloadTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_RAW; + Payload::Serialized serialized = + std::make_tuple(testStringPayload_, format); + + const void* originalAddress = + std::get(serialized).data(); + + // Act + Payload payload(std::move(serialized)); + auto [payloadData, payloadFormat] = std::move(payload).buildMove(); + const void* movedAddress = payloadData.data(); + + // Assert + EXPECT_EQ(payloadData, testStringPayload_); + EXPECT_EQ(payloadFormat, format); + + EXPECT_EQ(originalAddress, movedAddress); + EXPECT_THROW(auto _ = payload.buildCopy(), Payload::PayloadMoved); +} + +//////////////////////Other Constructor Tests/////////////////////// + +// Move Constructor Test +TEST_F(PayloadTest, MoveConstructorTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_TEXT; + Payload originalPayload(testStringPayload_, format); + + // Act + Payload movedPayload(std::move(originalPayload).buildMove()); + + // Assert + auto [movedData, movedFormat] = movedPayload.buildCopy(); + EXPECT_EQ(movedData, testStringPayload_); + EXPECT_EQ(movedFormat, format); + + EXPECT_THROW(auto _ = originalPayload.buildCopy(), Payload::PayloadMoved); +} + +// Cppy Constructor Test +TEST_F(PayloadTest, CopyConstructorTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_TEXT; + Payload originalPayload(testStringPayload_, format); + + // Act + Payload copiedPayload(originalPayload); + + // Assert + auto [originalData, originalFormat] = originalPayload.buildCopy(); + auto [copiedData, copiedFormat] = copiedPayload.buildCopy(); + EXPECT_EQ(copiedData, originalData); + EXPECT_EQ(copiedFormat, originalFormat); +} + +// Move Assignment Operator Test +TEST_F(PayloadTest, MoveAssignmentOperatorTest) { + // Arrange + uprotocol::v1::UUri uriObject1; + uriObject1.set_authority_name("test1"); + Payload payload1(uriObject1); + + uprotocol::v1::UUri uriObject2; + uriObject2.set_authority_name("test2"); + Payload payload2(uriObject2); + + // Act + payload1 = std::move(payload2); + + // Assert + auto [payloadData, payloadFormat] = payload1.buildCopy(); + EXPECT_EQ(payloadData, uriObject2.SerializeAsString()); + EXPECT_EQ(payloadFormat, + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF); +} + +// Copy Assignment Operator Test +TEST_F(PayloadTest, CopyAssignmentOperatorTest) { + // Arrange + uprotocol::v1::UPayloadFormat format = + uprotocol::v1::UPayloadFormat::UPAYLOAD_FORMAT_TEXT; + Payload originalPayload(testStringPayload_, format); + Payload copiedPayload(testStringPayload_, format); + + // Act + copiedPayload = originalPayload; + + // Assert + auto [originalData, originalFormat] = originalPayload.buildCopy(); + auto [copiedData, copiedFormat] = copiedPayload.buildCopy(); + EXPECT_EQ(copiedData, originalData); + EXPECT_EQ(copiedFormat, originalFormat); +} } // namespace