serialization: Accept multiple parameters in ParamsStream constructor

Before this change it was possible but awkward to create ParamStream streams
with multiple parameter objects. After this change it is straightforward.

The change to support multiple parameters is implemented by letting
ParamsStream contain substream instances, instead of just references to
external substreams. So a side-effect of this change is that ParamStream can
now accept rvalue stream arguments and be easier to use in some other cases. A
test for rvalues is added in this commit, and some simplifications to non-test
code are made in the next commit.
This commit is contained in:
Ryan Ofsky
2023-11-22 17:56:04 -05:00
parent cb28849a88
commit e6794e475c
2 changed files with 109 additions and 2 deletions

View File

@@ -15,6 +15,18 @@
BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup)
// For testing move-semantics, declare a version of datastream that can be moved
// but is not copyable.
class UncopyableStream : public DataStream
{
public:
using DataStream::DataStream;
UncopyableStream(const UncopyableStream&) = delete;
UncopyableStream& operator=(const UncopyableStream&) = delete;
UncopyableStream(UncopyableStream&&) noexcept = default;
UncopyableStream& operator=(UncopyableStream&&) noexcept = default;
};
class CSerializeMethodsTestSingle
{
protected:
@@ -344,6 +356,73 @@ public:
}
};
struct OtherParam {
uint8_t param;
SER_PARAMS_OPFUNC
};
//! Checker for value of OtherParam. When being serialized, serializes the
//! param to the stream. When being unserialized, verifies the value in the
//! stream matches the param.
class OtherParamChecker
{
public:
template <typename Stream>
void Serialize(Stream& s) const
{
const uint8_t param = s.template GetParams<OtherParam>().param;
s << param;
}
template <typename Stream>
void Unserialize(Stream& s) const
{
const uint8_t param = s.template GetParams<OtherParam>().param;
uint8_t value;
s >> value;
BOOST_CHECK_EQUAL(value, param);
}
};
//! Test creating a stream with multiple parameters and making sure
//! serialization code requiring different parameters can retrieve them. Also
//! test that earlier parameters take precedence if the same parameter type is
//! specified twice. (Choice of whether earlier or later values take precedence
//! or multiple values of the same type are allowed was arbitrary, and just
//! decided based on what would require smallest amount of ugly C++ template
//! code. Intent of the test is to just ensure there is no unexpected behavior.)
BOOST_AUTO_TEST_CASE(with_params_multi)
{
const OtherParam other_param_used{.param = 0x10};
const OtherParam other_param_ignored{.param = 0x11};
const OtherParam other_param_override{.param = 0x12};
const OtherParamChecker check;
DataStream stream;
ParamsStream pstream{stream, RAW, other_param_used, other_param_ignored};
Base base1{0x20};
pstream << base1 << check << other_param_override(check);
BOOST_CHECK_EQUAL(stream.str(), "\x20\x10\x12");
Base base2;
pstream >> base2 >> check >> other_param_override(check);
BOOST_CHECK_EQUAL(base2.m_base_data, 0x20);
}
//! Test creating a ParamsStream that moves from a stream argument.
BOOST_AUTO_TEST_CASE(with_params_move)
{
UncopyableStream stream{};
ParamsStream pstream{std::move(stream), RAW, HEX, RAW};
Base base1{0x20};
pstream << base1;
Base base2;
pstream >> base2;
BOOST_CHECK_EQUAL(base2.m_base_data, 0x20);
}
BOOST_AUTO_TEST_CASE(with_params_base)
{
Base b{0x0F};