multiple breaking change improvements

This commit is contained in:
Mindaugas Vinkelis
2019-06-25 11:08:26 +03:00
committed by Mindaugas Vinkelis
parent 57dd028b7a
commit 1822796f2e
65 changed files with 1993 additions and 2242 deletions

512
tests/adapter.cpp Normal file
View File

@@ -0,0 +1,512 @@
//MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#include <bitsery/adapter/buffer.h>
#include <bitsery/adapter_writer.h>
#include <bitsery/adapter_reader.h>
#include <bitsery/traits/vector.h>
#include <bitsery/traits/array.h>
#include <bitsery/traits/string.h>
#include <gmock/gmock.h>
#include <bitsery/adapter/stream.h>
//some helper types
using Buffer = std::vector<char>;
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
using Writer = bitsery::AdapterWriter<OutputAdapter, bitsery::DefaultConfig>;
using Reader = bitsery::AdapterReader<InputAdapter, bitsery::DefaultConfig>;
using bitsery::ReaderError;
using testing::Eq;
using testing::Ge;
TEST(OutputBuffer, WhenInitialBufferIsEmptyThenResizeInAdapterConstructor) {
//setup data
Buffer buf{};
EXPECT_THAT(buf.size(), Eq(0));
OutputAdapter adapter{buf};
EXPECT_THAT(buf.size(), Ge(1));
}
TEST(OutputBuffer, WhenSetWritePositionThenResizeUnderlyingBufferIfRequired) {
//setup data
Buffer buf{};
Writer w{buf};
const auto initialSize = buf.size();
EXPECT_THAT(buf.size(), Eq(initialSize));
EXPECT_THAT(w.currentWritePos(), Eq(0));
w.currentWritePos(initialSize + 10);
EXPECT_THAT(w.currentWritePos(), Eq(initialSize + 10));
EXPECT_THAT(buf.size(), Ge(initialSize + 10));
}
TEST(OutputBuffer, WhenSettingCurrentPositionBeforeBufferEndThenWrittenBytesCountIsNotAffected) {
//setup data
Buffer buf{};
Writer w{buf};
const auto initialSize = buf.size();
EXPECT_THAT(buf.size(), Eq(initialSize));
EXPECT_THAT(w.writtenBytesCount(), Eq(0));
w.currentWritePos(initialSize + 10);
w.writeBytes<8>(static_cast<uint64_t>(1));
EXPECT_THAT(w.writtenBytesCount(), Eq(initialSize + 10 + 8));
w.currentWritePos(0);
EXPECT_THAT(w.writtenBytesCount(), Eq(initialSize + 10 + 8));
}
TEST(InputBuffer, CorrectlySetsAndGetsCurrentReadPosition) {
Buffer buf{};
buf.resize(100);
Reader r{{buf.begin(), 10}};
r.currentReadPos(5);
EXPECT_THAT(r.currentReadPos(), Eq(5));
r.currentReadPos(0);
EXPECT_THAT(r.currentReadPos(), Eq(0));
uint8_t tmp;
r.readBytes<1>(tmp);
EXPECT_THAT(r.currentReadPos(), Eq(1));
}
TEST(InputBuffer, WhenSetReadPositionOutOfRangeThenDataOverflow) {
Buffer buf{};
buf.resize(100);
Reader r{{buf.begin(), 10}};
r.currentReadPos(10);
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
r.currentReadPos(11);
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
}
TEST(InputBuffer, WhenSetReadEndPositionOutOfRangeThenDataOverflow) {
Buffer buf{};
buf.resize(100);
Reader r{{buf.begin(), 10}};
r.currentReadEndPos(11);
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
}
TEST(InputBuffer, WhenReadEndPositionIsNotSetThenReturnZeroAsBufferEndPosition) {
Buffer buf{};
buf.resize(100);
Reader r{{buf.begin(), 10}};
EXPECT_THAT(r.currentReadEndPos(), Eq(0));
r.currentReadEndPos(5);
EXPECT_THAT(r.currentReadEndPos(), Eq(5));
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
}
TEST(InputBuffer, WhenReadEndPositionIsNotZeroThenDataOverflowErrorWillBeIgnored) {
Buffer buf{};
buf.resize(100);
Reader r{{buf.begin(), 1}};
r.currentReadEndPos(1);
uint32_t tmp{};
r.readBytes<4>(tmp);
EXPECT_THAT(tmp, Eq(0));
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
r.currentReadEndPos(0);
r.readBytes<4>(tmp);
EXPECT_THAT(tmp, Eq(0));
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
}
TEST(InputBuffer, WhenReadingPastReadEndPositionOrBufferEndThenReadPositionDoesntChange) {
Buffer buf{};
buf.resize(10);
Reader r{{buf.begin(), 3}};
uint32_t tmp{};
r.currentReadEndPos(2);
r.readBytes<4>(tmp);
EXPECT_THAT(r.currentReadPos(), Eq(0));
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
EXPECT_THAT(tmp, Eq(0));
r.currentReadEndPos(0);
r.readBytes<4>(tmp);
EXPECT_THAT(r.currentReadPos(), Eq(0));
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
EXPECT_THAT(tmp, Eq(0));
}
TEST(InputBuffer, WhenReaderHasErrorsThenSettingReadPosAndReadEndPosIsIgnoredAndGettingAlwaysReturnsZero) {
Buffer buf{};
buf.resize(10);
Reader r{{buf.begin(), 10}};
uint32_t tmp{};
r.readBytes<4>(tmp);
r.currentReadEndPos(5);
EXPECT_THAT(r.currentReadPos(), Eq(4));
EXPECT_THAT(r.currentReadEndPos(), Eq(5));
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
r.currentReadEndPos(11);
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
EXPECT_THAT(r.currentReadPos(), Eq(0));
EXPECT_THAT(r.currentReadEndPos(), Eq(0));
r.currentReadPos(1);
r.currentReadEndPos(1);
EXPECT_THAT(r.currentReadPos(), Eq(0));
EXPECT_THAT(r.currentReadEndPos(), Eq(0));
}
TEST(InputBuffer, ConstDataForBufferAllAdapters) {
//create and write to buffer
uint16_t data = 7549;
Buffer bufWrite{};
Writer bw{bufWrite};
bw.writeBytes<2>(data);
bw.flush();
const Buffer buf{bufWrite};
//read from buffer
using Adapter1 = bitsery::InputBufferAdapter<const Buffer>;
using Adapter2 = bitsery::UnsafeInputBufferAdapter<const Buffer>;
bitsery::AdapterReader<Adapter1, bitsery::DefaultConfig> r1{Adapter1{buf.begin(), buf.end()}};
bitsery::AdapterReader<Adapter2, bitsery::DefaultConfig> r2{Adapter2{buf.begin(), buf.end()}};
uint16_t res1{};
r1.readBytes<2>(res1);
uint16_t res2{};
r2.readBytes<2>(res2);
EXPECT_THAT(res1, Eq(data));
EXPECT_THAT(res2, Eq(data));
}
template <template<typename...> class TAdapter>
struct BufferConfig {
using Data = std::vector<char>;
using Adapter = TAdapter<Data>;
using Reader = bitsery::AdapterReader<Adapter, bitsery::DefaultConfig>;
Data data{};
Reader createReader(const std::vector<char>& buffer) {
data = buffer;
return Reader{Adapter{data.begin(), data.size()}};
}
};
template <typename TAdapter>
struct StreamConfig {
using Data = std::stringstream;
using Adapter = TAdapter;
using Reader = bitsery::AdapterReader<Adapter, bitsery::DefaultConfig>;
Data data{};
Reader createReader(const std::vector<char>& buffer) {
std::string str(buffer.begin(), buffer.end());
data = std::stringstream{str};
return Reader{Adapter{data}};
}
};
template<typename TAdapterWithData>
class AdapterConfig : public testing::Test {
public:
TAdapterWithData config{};
};
using AdapterInputTypes = ::testing::Types<
BufferConfig<bitsery::InputBufferAdapter>,
BufferConfig<bitsery::UnsafeInputBufferAdapter>,
StreamConfig<bitsery::InputStreamAdapter>
>;
template <typename TConfig>
class InputAll: public AdapterConfig<TConfig> {
};
TYPED_TEST_CASE(InputAll, AdapterInputTypes);
using AdapterInputSafeOnlyTypes = ::testing::Types<
BufferConfig<bitsery::InputBufferAdapter>,
StreamConfig<bitsery::InputStreamAdapter>
>;
template <typename TConfig>
class InputSafeOnly: public AdapterConfig<TConfig> {
};
TYPED_TEST_CASE(InputSafeOnly, AdapterInputSafeOnlyTypes);
TYPED_TEST(InputAll, SettingMultipleErrorsAlwaysReturnsFirstError) {
auto r = this->config.createReader({0,0,0,0});
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
r.error(ReaderError::InvalidPointer);
EXPECT_THAT(r.error(), Eq(ReaderError::InvalidPointer));
r.error(ReaderError::DataOverflow);
EXPECT_THAT(r.error(), Eq(ReaderError::InvalidPointer));
r.error(ReaderError::NoError);
EXPECT_THAT(r.error(), Eq(ReaderError::InvalidPointer));
}
TYPED_TEST(InputAll, WhenAlignHasNonZerosThenInvalidDataError) {
auto r = this->config.createReader({0x7F});
bitsery::AdapterReaderBitPackingWrapper<decltype(r)> bpr{r};
uint8_t tmp{0xFF};
bpr.readBits(tmp,3);
bpr.align();
EXPECT_THAT(bpr.error(), Eq(ReaderError::InvalidData));
}
TYPED_TEST(InputAll, WhenAllBytesAreReadWithoutErrorsThenIsCompletedSuccessfully) {
//setup data
uint32_t tb = 94545646;
int16_t tc = -8778;
uint8_t td = 200;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<4>(tb);
bw.writeBytes<2>(tc);
bw.writeBytes<1>(td);
bw.flush();
buf.resize(bw.writtenBytesCount());
auto br = this->config.createReader(buf);
uint32_t rb = 94545646;
int16_t rc = -8778;
uint8_t rd = 200;
br.template readBytes<4>(rb);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
br.template readBytes<2>(rc);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(br.isCompletedSuccessfully(), Eq(false));
br.template readBytes<1>(rd);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(br.isCompletedSuccessfully(), Eq(true));
EXPECT_THAT(rb, Eq(tb));
EXPECT_THAT(rc, Eq(tc));
EXPECT_THAT(rd, Eq(td));
}
TYPED_TEST(InputSafeOnly, WhenAllBytesAreReadWithoutErrorsThenIsCompletedSuccessfully) {
//setup data
uint32_t tb = 94545646;
int16_t tc = -8778;
uint8_t td = 200;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<4>(tb);
bw.writeBytes<2>(tc);
bw.writeBytes<1>(td);
bw.flush();
buf.resize(bw.writtenBytesCount());
auto br = this->config.createReader(buf);
uint32_t rb = 94545646;
int16_t rc = -8778;
uint8_t rd = 200;
br.template readBytes<4>(rb);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
br.template readBytes<2>(rc);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(br.isCompletedSuccessfully(), Eq(false));
br.template readBytes<1>(rd);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(br.isCompletedSuccessfully(), Eq(true));
br.template readBytes<1>(rd);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::DataOverflow));
EXPECT_THAT(br.isCompletedSuccessfully(), Eq(false));
Reader br1{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
br1.template readBytes<4>(rb);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
br1.template readBytes<2>(rc);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(br1.isCompletedSuccessfully(), Eq(false));
br1.template readBytes<2>(rc);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::DataOverflow));
EXPECT_THAT(br1.isCompletedSuccessfully(), Eq(false));
br1.template readBytes<1>(rd);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::DataOverflow));
EXPECT_THAT(br1.isCompletedSuccessfully(), Eq(false));
}
TYPED_TEST(InputSafeOnly, WhenReadingMoreThanAvailableThenDataOverflow) {
//setup data
uint8_t t1 = 111;
Buffer buf{};
Writer w{buf};
w.writeBytes<1>(t1);
w.flush();
buf.resize(w.writtenBytesCount());
auto r = this->config.createReader(buf);
uint8_t r1{};
EXPECT_THAT(r.isCompletedSuccessfully(), Eq(false));
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
r.template readBytes<1>(r1);
EXPECT_THAT(r.isCompletedSuccessfully(), Eq(true));
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
EXPECT_THAT(r1, Eq(t1));
r.template readBytes<1>(r1);
r.template readBytes<1>(r1);
EXPECT_THAT(r1, Eq(0));
EXPECT_THAT(r.isCompletedSuccessfully(), Eq(false));
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
}
TYPED_TEST(InputSafeOnly, WhenReaderHasErrorsAllThenReadsReturnZero) {
//setup data
uint8_t t1 = 111;
Buffer buf{};
Writer w{buf};
w.writeBytes<1>(t1);
w.writeBytes<1>(t1);
w.flush();
buf.resize(w.writtenBytesCount());
auto r = this->config.createReader(buf);
uint8_t r1{};
r.template readBytes<1>(r1);
EXPECT_THAT(r1, Eq(t1));
r.error(ReaderError::InvalidPointer);
r.template readBytes<1>(r1);
EXPECT_THAT(r1, Eq(0));
}
template<typename T>
class OutputStreamBuffered : public testing::Test {
public:
using Buffer = T;
using Adapter = bitsery::BasicBufferedOutputStreamAdapter<char, std::char_traits<char>, Buffer>;
using Writer = bitsery::AdapterWriter<Adapter, bitsery::DefaultConfig>;
static constexpr size_t InternalBufferSize = 128;
std::stringstream stream{};
Writer writer{{stream, 128}};
};
using BufferedAdapterInternalBufferTypes = ::testing::Types<
std::vector<char>,
std::array<char, 128>,
std::string
>;
TYPED_TEST_CASE(OutputStreamBuffered, BufferedAdapterInternalBufferTypes);
TYPED_TEST(OutputStreamBuffered, WhenBufferOverflowThenWriteBufferAndRemainingDataToStream) {
uint8_t x{};
for (auto i = 0u; i < TestFixture::InternalBufferSize; ++i)
this->writer.template writeBytes<1>(x);
EXPECT_TRUE(this->stream.str().empty());
this->writer.template writeBytes<1>(x);
EXPECT_THAT(this->stream.str().size(), Eq(TestFixture::InternalBufferSize + 1));
}
TYPED_TEST(OutputStreamBuffered, WhenFlushThenWriteImmediately) {
uint8_t x{};
this->writer.template writeBytes<1>(x);
EXPECT_THAT(this->stream.str().size(), Eq(0));
this->writer.flush();
EXPECT_THAT(this->stream.str().size(), Eq(1));
this->writer.flush();
EXPECT_THAT(this->stream.str().size(), Eq(1));
}
TYPED_TEST(OutputStreamBuffered, WhenBufferIsStackAllocatedThenBufferSizeViaCtorHasNoEffect) {
//create writer with half the internal buffer size
//for std::vector it should overflow, and for std::array it should have no effect
typename TestFixture::Writer w{{this->stream, TestFixture::InternalBufferSize / 2}};
uint8_t x{};
for (auto i = 0u; i < TestFixture::InternalBufferSize; ++i)
w.template writeBytes<1>(x);
static constexpr bool ShouldWriteToStream = bitsery::traits::ContainerTraits<typename TestFixture::Buffer>::isResizable;
EXPECT_THAT(this->stream.str().empty(), ::testing::Ne(ShouldWriteToStream));
}
TEST(AdapterWriterMeasureSize, CorrectlyMeasuresWrittenBytesCountForSerialization) {
bitsery::MeasureSize w{};
EXPECT_THAT(w.writtenBytesCount(), Eq(0));
w.writeBytes<8>(uint64_t{0});
EXPECT_THAT(w.writtenBytesCount(), Eq(8));
w.writeBuffer<8, uint64_t>(nullptr, 9);
EXPECT_THAT(w.writtenBytesCount(), Eq(80));
w.currentWritePos(10);
w.writeBytes<4>(uint32_t{0});
EXPECT_THAT(w.writtenBytesCount(), Eq(80));
EXPECT_THAT(w.currentWritePos(), Eq(14));
w.currentWritePos(80);
EXPECT_THAT(w.writtenBytesCount(), Eq(80));
w.writeBits(uint32_t{0}, 7u);
EXPECT_THAT(w.writtenBytesCount(), Eq(80));
w.align();
EXPECT_THAT(w.writtenBytesCount(), Eq(81));
w.writeBits(uint32_t{0}, 7u);
w.flush();
EXPECT_THAT(w.writtenBytesCount(), Eq(82));
// doesn't compile on older compilers if I write bitsery::MeasureSize::BitPackingEnabled directly in EXPECT_THAT macro.
constexpr bool bpEnabled = bitsery::MeasureSize::BitPackingEnabled;
EXPECT_THAT(bpEnabled, Eq(true));
}
struct CustomInternalContextConfig: bitsery::DefaultConfig {
using InternalContext = std::tuple<int, float>;
};
TEST(AdapterWriterMeasureSize, SupportsInternalAndExternalContexts) {
char extCtx{'A'};
bitsery::BasicMeasureSize<CustomInternalContextConfig, char> w{extCtx};
EXPECT_THAT(w.externalContext(), Eq('A'));
std::tuple<int, float>& tmp = w.internalContext();
}

View File

@@ -1,162 +0,0 @@
//MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#include <bitsery/adapter/stream.h>
#include <bitsery/adapter_writer.h>
#include <bitsery/adapter_reader.h>
#include <bitsery/traits/vector.h>
#include <bitsery/traits/array.h>
#include <bitsery/traits/string.h>
#include <gmock/gmock.h>
#include <sstream>
//some helper types
using Stream = std::stringstream;
using OutputAdapter = bitsery::OutputStreamAdapter;
using InputAdapter = bitsery::InputStreamAdapter ;
using Writer = bitsery::AdapterWriter<bitsery::OutputStreamAdapter, bitsery::DefaultConfig>;
using Reader = bitsery::AdapterReader<bitsery::InputStreamAdapter, bitsery::DefaultConfig>;
static constexpr size_t InternalBufferSize = 128;
using BufferedAdapterInternalBuffer = std::array<char, InternalBufferSize>;
using OutputBufferedAdapter = bitsery::BasicBufferedOutputStreamAdapter<char, std::char_traits<char>, BufferedAdapterInternalBuffer>;
using BufferedWriter = bitsery::AdapterWriter<OutputBufferedAdapter, bitsery::DefaultConfig>;
using testing::Eq;
TEST(AdapterIOStream, CorrectlyReturnsIsCompletedSuccessfully) {
//setup data
uint8_t t1 = 111;
Stream buf{};
Writer w{{buf}};
w.writeBytes<1>(t1);
w.flush();
Reader r{{buf}};
uint8_t r1{};
EXPECT_THAT(r.isCompletedSuccessfully(), Eq(false));
r.readBytes<1>(r1);
EXPECT_THAT(r.isCompletedSuccessfully(), Eq(true));
EXPECT_THAT(r1, Eq(t1));
}
TEST(AdapterIOStream, ReadingMoreThanAvailableReturnsZero) {
//setup data
uint8_t t1 = 111;
Stream buf{};
Writer w{{buf}};
w.writeBytes<1>(t1);
w.flush();
Reader r{{buf}};
uint8_t r1{};
r.readBytes<1>(r1);
r.readBytes<1>(r1);
EXPECT_THAT(r1, Eq(0));
}
//this is strange, but probably stringstream doesnt use any of the base methods that sets io_base::iostate flags
TEST(AdapterIOStream, WhenReadingMoreThanAvailableThenDataOverflow) {
//setup data
uint8_t t1 = 111;
Stream buf{};
Writer w{{buf}};
w.writeBytes<1>(t1);
w.flush();
Reader r{{buf}};
uint8_t r1{};
EXPECT_THAT(r.isCompletedSuccessfully(), Eq(false));
EXPECT_THAT(r.error(), Eq(bitsery::ReaderError::NoError));
r.readBytes<1>(r1);
EXPECT_THAT(r.isCompletedSuccessfully(), Eq(true));
EXPECT_THAT(r.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(r1, Eq(t1));
r.readBytes<1>(r1);
r.readBytes<1>(r1);
EXPECT_THAT(r1, Eq(0));
EXPECT_THAT(r.isCompletedSuccessfully(), Eq(false));
EXPECT_THAT(r.error(), Eq(bitsery::ReaderError::DataOverflow));
}
template<typename T>
class AdapterBufferedOutputStream : public testing::Test {
public:
using Buffer = T;
using Adapter = bitsery::BasicBufferedOutputStreamAdapter<char, std::char_traits<char>, Buffer>;
using Writer = bitsery::AdapterWriter<Adapter, bitsery::DefaultConfig>;
static constexpr size_t InternalBufferSize = 128;
Stream stream{};
Writer writer{{stream, 128}};
};
using BufferedAdapterInternalBufferTypes = ::testing::Types<
std::vector<char>,
std::array<char, 128>,
std::string
>;
TYPED_TEST_CASE(AdapterBufferedOutputStream, BufferedAdapterInternalBufferTypes);
TYPED_TEST(AdapterBufferedOutputStream, WhenBufferOverflowThenWriteBufferAndRemainingDataToStream) {
uint8_t x{};
for (auto i = 0u; i < TestFixture::InternalBufferSize; ++i)
this->writer.template writeBytes<1>(x);
EXPECT_TRUE(this->stream.str().empty());
this->writer.template writeBytes<1>(x);
EXPECT_THAT(this->stream.str().size(), Eq(TestFixture::InternalBufferSize + 1));
}
TYPED_TEST(AdapterBufferedOutputStream, WhenFlushThenWriteImmediately) {
uint8_t x{};
this->writer.template writeBytes<1>(x);
EXPECT_THAT(this->stream.str().size(), Eq(0));
this->writer.flush();
EXPECT_THAT(this->stream.str().size(), Eq(1));
this->writer.flush();
EXPECT_THAT(this->stream.str().size(), Eq(1));
}
TYPED_TEST(AdapterBufferedOutputStream, WhenBufferIsStackAllocatedThenBufferSizeViaCtorHasNoEffect) {
//create writer with half the internal buffer size
//for std::vector it should overflow, and for std::array it should have no effect
typename TestFixture::Writer w{{this->stream, TestFixture::InternalBufferSize / 2}};
uint8_t x{};
for (auto i = 0u; i < TestFixture::InternalBufferSize; ++i)
w.template writeBytes<1>(x);
static constexpr bool ShouldWriteToStream = bitsery::traits::ContainerTraits<typename TestFixture::Buffer>::isResizable;
EXPECT_THAT(this->stream.str().empty(), ::testing::Ne(ShouldWriteToStream));
}

View File

@@ -1,180 +0,0 @@
//MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <list>
#include <bitset>
using testing::Eq;
struct IntegralTypes {
int64_t a;
uint32_t b;
int16_t c;
uint8_t d;
int8_t e;
int8_t f[2];
};
TEST(DataReading, WhenReadingMoreThanAvailableThenEmptyBufferError) {
//setup data
uint8_t a = 111;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<1>(a);
bw.writeBytes<1>(a);
bw.writeBytes<1>(a);
bw.flush();
//read from buffer
Reader br{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
int32_t c;
br.readBytes<4>(c);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::DataOverflow));
}
TEST(DataReading, WhenErrorOccursThenAllOtherOperationsFailsForSameError) {
//setup data
uint8_t a = 111;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<1>(a);
bw.writeBytes<1>(a);
bw.writeBytes<1>(a);
bw.flush();
//read from buffer
Reader br{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
int32_t c;
br.readBytes<4>(c);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::DataOverflow));
br.readBytes<1>(a);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::DataOverflow));
}
TEST(DataReading, ReadIsCompletedSuccessfullyWhenAllBytesAreReadWithoutErrors) {
//setup data
IntegralTypes data;
data.b = 94545646;
data.c = -8778;
data.d = 200;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<4>(data.b);
bw.writeBytes<2>(data.c);
bw.writeBytes<1>(data.d);
bw.flush();
//read from buffer
Reader br{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
IntegralTypes res;
br.readBytes<4>(res.b);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
br.readBytes<2>(res.c);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(br.isCompletedSuccessfully(), Eq(false));
br.readBytes<1>(res.d);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(br.isCompletedSuccessfully(), Eq(true));
br.readBytes<1>(res.d);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::DataOverflow));
EXPECT_THAT(br.isCompletedSuccessfully(), Eq(false));
Reader br1{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
br1.readBytes<4>(res.b);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
br1.readBytes<2>(res.c);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(br1.isCompletedSuccessfully(), Eq(false));
br1.readBytes<2>(res.c);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::DataOverflow));
EXPECT_THAT(br1.isCompletedSuccessfully(), Eq(false));
br1.readBytes<1>(res.d);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::DataOverflow));
EXPECT_THAT(br1.isCompletedSuccessfully(), Eq(false));
}
TEST(DataReading, WhenReaderHasErrorsAllOperationsReadsReturnZero) {
//setup data
uint8_t a = 111;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<1>(a);
bw.writeBytes<1>(a);
bw.writeBytes<1>(a);
bw.flush();
//read from buffer
Reader br{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
bitsery::AdapterReaderBitPackingWrapper<Reader> bpr{br};
int32_t c;
bpr.readBytes<4>(c);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::DataOverflow));
int16_t r1= {-645};
uint32_t r2[2] = {54898,87854};
uint8_t r3 = 0xFF;
bpr.readBytes<2>(r1);
bpr.readBuffer<4>(r2, 2);
bpr.readBits(r3, 7);
EXPECT_THAT(r1, Eq(0));
EXPECT_THAT(r2[0], Eq(0u));
EXPECT_THAT(r2[1], Eq(0u));
EXPECT_THAT(r3, Eq(0u));
}
TEST(DataReading, ConstBufferAllAdapters) {
//create and write to buffer
uint16_t data = 7549;
Buffer bufWrite{};
Writer bw{bufWrite};
bw.writeBytes<2>(data);
bw.flush();
const Buffer buf{bufWrite};
//read from buffer
using Adapter1 = bitsery::InputBufferAdapter<const Buffer>;
using Adapter2 = bitsery::UnsafeInputBufferAdapter<const Buffer>;
bitsery::AdapterReader<Adapter1, bitsery::DefaultConfig> r1{Adapter1{buf.begin(), buf.end()}};
bitsery::AdapterReader<Adapter2, bitsery::DefaultConfig> r2{Adapter2{buf.begin(), buf.end()}};
uint16_t res1{};
r1.readBytes<2>(res1);
uint16_t res2{};
r2.readBytes<2>(res2);
EXPECT_THAT(res1, Eq(data));
EXPECT_THAT(res2, Eq(data));
}

View File

@@ -1,137 +0,0 @@
//MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#include <bitsery/traits/string.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
using testing::Eq;
using SessionsEnabledWriter = bitsery::AdapterWriter<OutputAdapter, SessionsEnabledConfig>;
using SessionsEnabledReader = bitsery::AdapterReader<InputAdapter, SessionsEnabledConfig>;
TEST(DataReadingErrors, WhenContainerOrTextSizeIsMoreThanMaxThenInvalidDataError) {
SerializationContext ctx;
std::string tmp = "larger text then allowed";
ctx.createSerializer().text1b(tmp,100);
ctx.createDeserializer().text1b(tmp, 10);
EXPECT_THAT(ctx.br->error(), Eq(bitsery::ReaderError::InvalidData));
}
TEST(DataReadingErrors, WhenReadingBoolByteReadsMoreThanOneThenInvalidBufferDataErrorAndResultIsFalse) {
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.value1b(uint8_t{1});
ser.value1b(uint8_t{2});
bool res{};
auto& des = ctx.createDeserializer();
des.boolValue(res);
EXPECT_THAT(res, Eq(true));
des.boolValue(res);
EXPECT_THAT(res, Eq(false));
EXPECT_THAT(ctx.br->error(), Eq(bitsery::ReaderError::InvalidData));
}
TEST(DataReadingErrors, WhenReadingAlignHasNonZerosThenInvalidDataError) {
Buffer buf{};
Writer bw{buf};
uint8_t tmp{0xFF};
bw.writeBytes<1>(tmp);
bw.flush();
Reader br{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
bitsery::AdapterReaderBitPackingWrapper<Reader> bpr{br};
bpr.readBits(tmp,3);
bpr.align();
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::InvalidData));
}
TEST(DataReadingErrors, WhenReadingNewSessionInMiddleOfOldDataThenInvalidDataError) {
uint8_t tmp{0xFF};
Buffer buf{};
SessionsEnabledWriter bw{buf};
for (auto i = 0; i < 2; ++i) {
bw.beginSession();
bw.writeBytes<1>(tmp);
bw.writeBytes<1>(tmp);
bw.endSession();
}
bw.flush();
SessionsEnabledReader br{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
for (auto i = 0; i < 2; ++i) {
br.beginSession();
br.readBytes<1>(tmp);
br.beginSession();
br.readBytes<1>(tmp);
br.endSession();
br.endSession();
}
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::InvalidData));
}
TEST(DataReadingErrors, WhenInitializingSessionsWhenNotEnoughDataThenInvalidData) {
uint8_t tmp1{0xFF};
Buffer buf1{};
SessionsEnabledWriter bw1{buf1};
bw1.writeBytes<1>(tmp1);
bw1.flush();
SessionsEnabledReader br1{InputAdapter{buf1.begin(), bw1.writtenBytesCount()}};
br1.beginSession();
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::InvalidData));
Buffer buf2{};
SessionsEnabledWriter bw2{buf2};
uint16_t tmp2{0x8000};
bw2.writeBytes<2>(tmp2);
bw2.flush();
SessionsEnabledReader br2{InputAdapter{buf2.begin(), bw2.writtenBytesCount()}};
br2.beginSession();
EXPECT_THAT(br2.error(), Eq(bitsery::ReaderError::InvalidData));
}
TEST(DataReadingErrors, WhenInitializingSessionsWhereSessionsDataOffsetIsCorruptedThenInvalidData) {
Buffer buf{};
SessionsEnabledWriter bw{buf};
bw.writeBytes<1>(uint8_t{1});
bw.writeBytes<1>(uint8_t{1});
bw.writeBytes<4>(uint32_t{10});
SessionsEnabledReader br{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
br.beginSession();
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::InvalidData));
}
TEST(DataReadingErrors, WhenReadingNewSessionOutsideSessionThenInvalidData) {
Buffer buf{};
SessionsEnabledWriter bw{buf};
bw.beginSession();
bw.writeBytes<1>(uint8_t{1});
bw.endSession();
bw.flush();
SessionsEnabledReader br{InputAdapter{buf.begin(), bw.writtenBytesCount()}};
br.beginSession();
br.endSession();
br.beginSession();
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::InvalidData));
}

View File

@@ -84,7 +84,7 @@ TEST(FlexibleSyntax, UseObjectFncInsteadOfValueN) {
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto &ser = ctx.createSerializer();
auto ser = ctx.createSerializer();
ser.object(ti);
ser.object(te);
ser.object(tf);
@@ -97,7 +97,7 @@ TEST(FlexibleSyntax, UseObjectFncInsteadOfValueN) {
float rf{};
double rd{};
bool rb{};
auto &des = ctx.createDeserializer();
auto des = ctx.createDeserializer();
des.object(ri);
des.object(re);
des.object(rf);
@@ -119,7 +119,7 @@ TEST(FlexibleSyntax, MixDifferentSyntax) {
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto &ser = ctx.createSerializer();
auto ser = ctx.createSerializer();
ser.value<sizeof(ti)>(ti);
ser.archive(te, tf, td);
ser.object(tb);
@@ -130,7 +130,7 @@ TEST(FlexibleSyntax, MixDifferentSyntax) {
float rf{};
double rd{};
bool rb{};
auto &des = ctx.createDeserializer();
auto des = ctx.createDeserializer();
des.archive(ri, re, rf);
des.value8b(rd);
des.object(rb);
@@ -384,12 +384,12 @@ TEST(FlexibleSyntax, StdSmartPtr) {
bitsery::ext::PointerLinkingContext plctx1{};
BasicSerializationContext<bitsery::DefaultConfig, bitsery::ext::PointerLinkingContext> ctx;
ctx.createSerializer(&plctx1).archive(dataShared1, dataWeak1, dataUnique1);
ctx.createSerializer(plctx1).archive(dataShared1, dataWeak1, dataUnique1);
std::shared_ptr<int> resShared1{};
std::weak_ptr<int> resWeak1{};
std::unique_ptr<std::string> resUnique1{};
ctx.createDeserializer(&plctx1).archive(resShared1, resWeak1, resUnique1);
ctx.createDeserializer(plctx1).archive(resShared1, resWeak1, resUnique1);
//clear shared state from pointer linking context
plctx1.clearSharedState();

View File

@@ -182,13 +182,13 @@ TEST(DeserializeNonDefaultConstructible, StdMap) {
data.emplace(NonDefaultConstructible{2}, NonDefaultConstructible{3});
data.emplace(NonDefaultConstructible{4}, NonDefaultConstructible{4});
auto& ser = ctx.createSerializer();
ser.ext(data, bitsery::ext::StdMap{10},[&ser](NonDefaultConstructible& key, NonDefaultConstructible& value) {
auto ser = ctx.createSerializer();
ser.ext(data, bitsery::ext::StdMap{10},[](decltype(ser)& ser, NonDefaultConstructible& key, NonDefaultConstructible& value) {
ser.object(key);
ser.object(value);
});
auto& des = ctx.createDeserializer();
des.ext(res, bitsery::ext::StdMap{10},[&des](NonDefaultConstructible& key, NonDefaultConstructible& value) {
auto des = ctx.createDeserializer();
des.ext(res, bitsery::ext::StdMap{10},[](decltype(des)& des, NonDefaultConstructible& key, NonDefaultConstructible& value) {
des.object(key);
des.object(value);
});
@@ -223,8 +223,8 @@ TEST(DeserializeNonDefaultConstructible, NonPolymorphicPointerAndSmartPointer) {
NonPolymorphicPointers res{};
bitsery::ext::PointerLinkingContext plctx1{};
ctx.createSerializer(&plctx1).object(data);
ctx.createDeserializer(&plctx1).object(res);
ctx.createSerializer(plctx1).object(data);
ctx.createDeserializer(plctx1).object(res);
EXPECT_THAT(*res.pp, Eq(*data.pp));
delete res.pp;
@@ -322,8 +322,8 @@ TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer) {
std::get<1>(serCtx).registerBasesList<typename SerContext::TSerializer>(bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
std::get<1>(desCtx).registerBasesList<typename SerContext::TDeserializer>(bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
ctx.createSerializer(&serCtx).object(data);
ctx.createDeserializer(&desCtx).object(res);
ctx.createSerializer(serCtx).object(data);
ctx.createDeserializer(desCtx).object(res);
auto respp = dynamic_cast<PolymorphicNDC1*>(res.pp);
auto resup = dynamic_cast<PolymorphicNDC2*>(res.up.get());
auto ressp = dynamic_cast<PolymorphicNDC1*>(res.sp.get());

View File

@@ -38,12 +38,12 @@ TEST(SerializeBooleans, BoolAsBit) {
bool t2{false};
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
auto ser = ctx.createSerializer();
ser.enableBitPacking([&t1, &t2](Serializer& sbp) {
sbp.boolValue(t1);
sbp.boolValue(t2);
});
auto& des = ctx.createDeserializer();
auto des = ctx.createDeserializer();
des.enableBitPacking([&res1, &res2](Deserializer& sbp) {
sbp.boolValue(res1);
sbp.boolValue(res2);
@@ -60,10 +60,10 @@ TEST(SerializeBooleans, BoolAsByte) {
bool t2{false};
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
auto ser = ctx.createSerializer();
ser.boolValue(t1);
ser.boolValue(t2);
auto& des = ctx.createDeserializer();
auto des = ctx.createDeserializer();
des.boolValue(res1);
des.boolValue(res2);
@@ -71,3 +71,17 @@ TEST(SerializeBooleans, BoolAsByte) {
EXPECT_THAT(res2, Eq(t2));
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
}
TEST(SerializeBooleans, WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorAndResultIsFalse) {
SerializationContext ctx;
auto ser = ctx.createSerializer();
ser.value1b(uint8_t{1});
ser.value1b(uint8_t{2});
bool res{};
auto des = ctx.createDeserializer();
des.boolValue(res);
EXPECT_THAT(res, Eq(true));
des.boolValue(res);
EXPECT_THAT(res, Eq(false));
EXPECT_THAT(ctx.br->error(), Eq(bitsery::ReaderError::InvalidData));
}

View File

@@ -64,6 +64,13 @@ std::list<MyStruct2> getFilledContainer<std::list<MyStruct2>>() {
};
}
struct EmptyFtor {
template <typename S, typename T>
void operator() (S& , T& ) {
}
};
/*
* start testing session
*/
@@ -106,12 +113,12 @@ TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, CustomFunctionIncrements
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
auto& ser = ctx.createSerializer();
ser.container(this->src, 1000, [&ser](TValue& v) {
auto ser = ctx.createSerializer();
ser.container(this->src, 1000, [](decltype(ser)& ser, TValue& v) {
ser.template value<sizeof(v)>(v);
});
auto& des = ctx.createDeserializer();
des.container(this->res, 1000, [&des](TValue &v) {
auto des = ctx.createDeserializer();
des.container(this->res, 1000, [](decltype(des)& des, TValue &v) {
des.template value<sizeof(v)>(v);
//increment by 1 after reading
v++;
@@ -161,9 +168,8 @@ TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, CustomFunctionThatDoNoth
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
auto emptyFnc = [](TValue &) {};
ctx.createSerializer().container(this->src, 1000, emptyFnc);
ctx.createDeserializer().container(this->res, 1000, emptyFnc);
ctx.createSerializer().container(this->src, 1000, EmptyFtor{});
ctx.createDeserializer().container(this->res, 1000, EmptyFtor{});
EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(this->src.size())));
}
@@ -231,14 +237,14 @@ TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, CustomFunctionThatSerializ
using TValue = decltype(*std::begin(res));
SerializationContext ctx{};
auto& ser = ctx.createSerializer();
ser.container(src, [&ser](TValue &v) {
auto ser = ctx.createSerializer();
ser.container(src, [](decltype(ser)& ser, TValue &v) {
char tmp{};
ser.object(v);
ser.value1b(tmp);
});
auto& des = ctx.createDeserializer();
des.container(res, [&des](TValue &v) {
auto des = ctx.createDeserializer();
des.container(res, [](decltype(des)& des, TValue &v) {
char tmp{};
des.object(v);
des.value1b(tmp);
@@ -253,12 +259,11 @@ class SerializeContainer : public ::testing::TestWithParam<size_t> {
TEST_P(SerializeContainer, SizeHasVariableLength) {
SerializationContext ctx{};
auto emptyFnc = [](uint8_t &) {};
std::vector<uint8_t > src(GetParam());
std::vector<uint8_t > res{};
ctx.createSerializer().container(src, std::numeric_limits<size_t>::max(), emptyFnc);
ctx.createDeserializer().container(res, std::numeric_limits<size_t>::max(), emptyFnc);
ctx.createSerializer().container(src, std::numeric_limits<size_t>::max(), EmptyFtor{});
ctx.createDeserializer().container(res, std::numeric_limits<size_t>::max(), EmptyFtor{});
EXPECT_THAT(res.size(), Eq(src.size()));
EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(src.size())));

View File

@@ -26,136 +26,83 @@
using testing::Eq;
template <typename ... Args>
struct ConfigWithContext: bitsery::DefaultConfig {
using InternalContext = std::tuple<Args...>;
};
template <typename Context, typename ... Args>
using SerializerConfigWithContext = bitsery::BasicSerializer<
bitsery::AdapterWriter<bitsery::OutputBufferAdapter<Buffer>, ConfigWithContext<Args...>>, Context>;
template <typename Context, typename ... Args>
using DeserializerConfigWithContext = bitsery::BasicDeserializer<
bitsery::AdapterReader<bitsery::InputBufferAdapter<Buffer>, ConfigWithContext<Args...>>, Context>;
template <typename Context>
using MySerializer = bitsery::BasicSerializer<Writer, Context>;
template <typename Context>
using MyDeserializer = bitsery::BasicDeserializer<Reader, Context>;
using bitsery::DefaultConfig;
using SingleTypeContext = int;
using MultipleTypesContext = std::tuple<int, float, char>;
TEST(SerializationContext, WhenUsingContextThenReturnsUnderlyingPointerOrNull) {
Buffer buf{};
MySerializer<SingleTypeContext> ser1{buf, nullptr};
EXPECT_THAT(ser1.context(), ::testing::IsNull());
MySerializer<MultipleTypesContext> ser2{buf, nullptr};
EXPECT_THAT(ser2.context(), ::testing::IsNull());
SingleTypeContext sctx{};
MyDeserializer<SingleTypeContext> des1{InputAdapter{buf.begin(), 1}, &sctx};
EXPECT_THAT(des1.context(), Eq(&sctx));
MultipleTypesContext mctx{};
MyDeserializer<MultipleTypesContext> des2{InputAdapter{buf.begin(), 1}, &mctx};
EXPECT_THAT(des2.context(), Eq(&mctx));
TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext) {
SingleTypeContext ctx{54};
BasicSerializationContext<DefaultConfig, SingleTypeContext> c1;
auto ser1 = c1.createSerializer(ctx);
EXPECT_THAT(ser1.context<SingleTypeContext>(), Eq(ctx));
}
TEST(SerializationContext, WhenContextIsTupleThenContextCastOverloadCastsToIndividualTupleTypes) {
Buffer buf{};
MySerializer<MultipleTypesContext> ser1{buf, nullptr};
EXPECT_THAT(ser1.context<int>(), ::testing::IsNull());
EXPECT_THAT(ser1.context<float>(), ::testing::IsNull());
EXPECT_THAT(ser1.context<char>(), ::testing::IsNull());
TEST(SerializationContext, WhenContextIsTupleThenReturnsTupleElements) {
MultipleTypesContext ctx{5, 798.654, 'F'};
BasicSerializationContext<DefaultConfig, MultipleTypesContext> c1;
auto ser1 = c1.createSerializer(ctx);
EXPECT_THAT(ser1.context<int>(), std::get<0>(ctx));
EXPECT_THAT(ser1.context<float>(), std::get<1>(ctx));
EXPECT_THAT(ser1.context<char>(), std::get<2>(ctx));
}
TEST(SerializationContext, WhenContextIsNotTupleThenContextCastOverloadReturnSameType) {
Buffer buf{};
SingleTypeContext ctx{};
MySerializer<SingleTypeContext> ser1{buf, &ctx};
EXPECT_THAT(ser1.context<SingleTypeContext>(), Eq(&ctx));
}
TEST(SerializationContext, SerializerDeserializerCanHaveInternalContextViaConfig) {
Buffer buf{};
SerializerConfigWithContext<void, float, int> ser{buf};
EXPECT_THAT(ser.context<int>(), ::testing::NotNull());
EXPECT_THAT(*ser.context<int>(), Eq(0));
*ser.context<int>() = 10;
EXPECT_THAT(*ser.context<int>(), Eq(10));
DeserializerConfigWithContext<void, char> des{InputAdapter{buf.begin(), 1}};
EXPECT_THAT(des.context<char>(), ::testing::NotNull());
EXPECT_THAT(*des.context<char>(), Eq(0));
*des.context<char>() = 10;
EXPECT_THAT(*des.context<char>(), Eq(10));
//new instance has new context
SerializerConfigWithContext<void, float, int> ser2{buf};
EXPECT_THAT(ser2.context<int>(), ::testing::NotNull());
EXPECT_THAT(*ser2.context<int>(), Eq(0));
}
TEST(SerializationContext, WhenInternalAndExternalContextIsTheSamePriorityGoesToInternalContext) {
Buffer buf{};
int externalCtx = 5;
SerializerConfigWithContext<int, float, int> ser{buf, &externalCtx};
EXPECT_THAT(ser.context<int>(), ::testing::NotNull());
EXPECT_THAT(*ser.context<int>(), Eq(0));
*ser.context<int>() = 2;
DeserializerConfigWithContext<int, int, char> des{InputAdapter{buf.begin(), 1}, &externalCtx};
EXPECT_THAT(des.context<char>(), ::testing::NotNull());
EXPECT_THAT(*des.context<char>(), Eq(0));
*des.context<int>() = 3;
EXPECT_THAT(externalCtx, Eq(5));
}
TEST(SerializationContext, ContextIfExistsReturnsNullWhenTypeDoesntExists) {
Buffer buf{};
std::tuple<double, short> extCtx1{};
SerializerConfigWithContext<std::tuple<double, short>, float, int> ser{buf, &extCtx1};
EXPECT_THAT(ser.contextOrNull<int>(), ::testing::NotNull());
TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull) {
SingleTypeContext ctx1= 32;
BasicSerializationContext<DefaultConfig, SingleTypeContext> c1;
auto ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<char>(), ::testing::IsNull());
EXPECT_THAT(ser.contextOrNull<int>(), ::testing::NotNull());
*ser.contextOrNull<int>() = 2;
EXPECT_THAT(ctx1, Eq(2));
double extCtx2{};
DeserializerConfigWithContext<double, int, char> des{InputAdapter{buf.begin(), 1}, &extCtx2};
EXPECT_THAT(des.contextOrNull<double>(), ::testing::NotNull());
EXPECT_THAT(des.contextOrNull<float>(), ::testing::IsNull());
MultipleTypesContext ctx2{5, 798.654, 'F'};
BasicSerializationContext<DefaultConfig, MultipleTypesContext> c2;
auto des = c2.createDeserializer(ctx2);
EXPECT_THAT(des.contextOrNull<double>(), ::testing::IsNull());
EXPECT_THAT(des.contextOrNull<int>(), ::testing::NotNull());
EXPECT_THAT(*des.contextOrNull<char>(), Eq('F'));
EXPECT_THAT(*des.contextOrNull<int>(), Eq(5));
}
TEST(SerializationContext, WhenBitPackingIsEnabledThenInternalContextIsMovedToNewInstanceAndMovedBackAfterwards) {
Buffer buf{};
using Ser = SerializerConfigWithContext<void, int>;
using BPSer = typename Ser::BPEnabledType;
using Des = DeserializerConfigWithContext<void, int>;
using BPDes = typename Des::BPEnabledType;
Ser ser{buf, nullptr};
*ser.context<int>() = 1;
EXPECT_THAT(*ser.context<int>(), Eq(1));
ser.enableBitPacking([](BPSer& s) {
EXPECT_THAT(*s.context<int>(), Eq(1));
*s.context<int>() = 2;
});
EXPECT_THAT(*ser.context<int>(), Eq(2));
Des des{InputAdapter{buf.begin(), 1}, nullptr};
*des.context<int>() = 3;
EXPECT_THAT(*des.context<int>(), Eq(3));
des.enableBitPacking([](BPDes& d) {
EXPECT_THAT(*d.context<int>(), Eq(3));
*d.context<int>() = 4;
});
EXPECT_THAT(*des.context<int>(), Eq(4));
struct Base { int value{}; };
struct Derived: Base{};
TEST(SerializationContext, ContextWillTryToConvertIfTypeIsConvertible) {
Derived ctx1{};
BasicSerializationContext<DefaultConfig, Derived> c1;
auto ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<Derived>(), ::testing::NotNull());
EXPECT_THAT(ser.contextOrNull<Base>(), ::testing::NotNull());
ser.context<Derived>();
ser.context<Base>();
}
TEST(SerializationContext, WhenMultipleConvertibleTypesExistsThenFirstMatchIsTaken) {
{
using CTX1 = std::tuple<Base, int, Derived>;
CTX1 ctx1{};
std::get<0>(ctx1).value = 1;
std::get<2>(ctx1).value = 2;
BasicSerializationContext<DefaultConfig, CTX1> c1;
auto ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.context<Derived>().value, Eq(std::get<2>(ctx1).value));
EXPECT_THAT(ser.context<Base>().value, Eq(std::get<0>(ctx1).value));
}
{
using CTX2 = std::tuple<float, Derived, Base>;
CTX2 ctx2{};
std::get<1>(ctx2).value = 1;
std::get<2>(ctx2).value = 2;
BasicSerializationContext<DefaultConfig, CTX2> c2;
auto des = c2.createSerializer(ctx2);
EXPECT_THAT(des.context<Derived>().value, Eq(std::get<1>(ctx2).value));
//Base will not be accessable in this case, because Derived is first valid match
EXPECT_THAT(des.context<Base>().value, Eq(std::get<1>(ctx2).value));
}
}

View File

@@ -228,13 +228,10 @@ TEST(SerializeExtensionCompactValueAsObjectDeserializeOverflow, TestEnums) {
SerializationContext ctx;
auto data = getValue<uint32_t >(true, 17);
uint16_t res{};
auto& ser = ctx.createSerializer();
ser.ext(data, CompactValueAsObject{});
auto& des = ctx.createDeserializer();
des.ext(res, CompactValueAsObject{});
auto& rd = bitsery::AdapterAccess::getReader(des);
ctx.createSerializer().ext(data, CompactValueAsObject{});
ctx.createDeserializer().ext(res, CompactValueAsObject{});
EXPECT_THAT(data, ::testing::Ne(res));
EXPECT_THAT(rd.error(), Eq(bitsery::ReaderError::DataOverflow));
EXPECT_THAT(ctx.br->error(), Eq(bitsery::ReaderError::InvalidData));
}

View File

@@ -128,7 +128,7 @@ TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithNoAlignBefore
SerializationContext ctx;
ctx.createSerializer().enableBitPacking([&v, &values, &rangeForValue](BPSer& ser){
//lambdas differ only in capture clauses, it would make sense to use std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [&ser, &rangeForValue](MyStruct1& data) {
auto serLambda = [&rangeForValue](BPSer& ser, MyStruct1& data) {
ser.ext(data.i1, rangeForValue);
ser.ext(data.i2, rangeForValue);
};
@@ -136,7 +136,7 @@ TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithNoAlignBefore
});
ctx.createDeserializer().enableBitPacking([&res, &values, &rangeForValue](BPDes& des) {
auto desLambda = [&des, &rangeForValue](MyStruct1& data) {
auto desLambda = [&rangeForValue](BPDes& des, MyStruct1& data) {
des.ext(data.i1, rangeForValue);
des.ext(data.i2, rangeForValue);
};
@@ -161,14 +161,14 @@ TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithAlignBeforeDa
SerializationContext ctx;
ctx.createSerializer().enableBitPacking([&v, &values, &rangeForValue](BPSer& ser){
//lambdas differ only in capture clauses, it would make sense to use std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [&ser, &rangeForValue](MyStruct1& data) {
auto serLambda = [&rangeForValue](BPSer& ser, MyStruct1& data) {
ser.ext(data.i1, rangeForValue);
ser.ext(data.i2, rangeForValue);
};
ser.ext(v, Entropy<std::vector<MyStruct1>>(values, true), serLambda);
});
ctx.createDeserializer().enableBitPacking([&res, &values, &rangeForValue](BPDes& des) {
auto desLambda = [&des, &rangeForValue](MyStruct1& data) {
auto desLambda = [&rangeForValue](BPDes& des, MyStruct1& data) {
des.ext(data.i1, rangeForValue);
des.ext(data.i2, rangeForValue);
};
@@ -189,10 +189,10 @@ TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenCustomFunctionNotInvoked)
SerializationContext ctx;
ctx.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext(v, Entropy<std::list<MyStruct1>>{values}, [](MyStruct1& ) {});
ser.ext(v, Entropy<std::list<MyStruct1>>{values}, [](BPSer& ,MyStruct1& ) {});
});
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext(res, Entropy<std::list<MyStruct1>>{values}, []( MyStruct1& ) {});
des.ext(res, Entropy<std::list<MyStruct1>>{values}, [](BPDes& , MyStruct1& ) {});
});
EXPECT_THAT(res, Eq(v));

View File

@@ -32,114 +32,73 @@ struct DataV1 {
int32_t v1;
};
template <typename S>
void serialize(S& s, DataV1& o) {
s.value4b(o.v1);
}
struct DataV2 {
int32_t v1;
int32_t v2;
};
template <typename S>
void serialize(S& s, DataV2& o) {
s.value4b(o.v1);
s.value4b(o.v2);
}
struct DataV3 {
int32_t v1;
int32_t v2;
int32_t v3;
template <typename S>
void serialize(S& s) {
s.value4b(v1);
s.value4b(v2);
s.value4b(v3);
}
};
TEST(SerializeExtensionGrowable, WriteSessionsDataAtBufferEndAfterFlush) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
auto& ser = ctx.createSerializer();
TEST(SerializeExtensionGrowable, SessionsLengthIsStoredWith4BytesBeforeSessionDataStarts) {
SerializationContext ctx;
auto ser = ctx.createSerializer();
//session cannot be empty
ser.ext(int8_t{}, Growable{}, [&ser] (int8_t& v) {
ser.value2b(int16_t{1});
ser.ext(int8_t{2}, Growable{}, [] (decltype(ser)& ser, int8_t& v) {
ser.value1b(v);
});
ser.value1b(int8_t{3});
EXPECT_THAT(ctx.getBufferSize(), Eq(1u));
ctx.bw->flush();
EXPECT_THAT(ctx.getBufferSize(), Gt(1u));
}
TEST(SerializeExtensionGrowable, SessionDataConsistOfSessionsEndPosAnd4BytesSessionsDataOffset) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
constexpr size_t DATA_SIZE = 4;
int32_t data{};
auto& ser = ctx.createSerializer();
ser.ext(data, Growable{}, [&ser](int32_t & v) { ser.value4b(v);});
ctx.createDeserializer();//to flush data and create buffer reader
EXPECT_THAT(ctx.getBufferSize(), Eq(1+4 + DATA_SIZE));
//read value back
auto& br = *(ctx.br);
br.readBytes<DATA_SIZE>(data);
size_t sessionEnd{};
//there should start session data with first size of session
bitsery::details::readSize(br, sessionEnd, 1000000u);
EXPECT_THAT(sessionEnd, Eq(DATA_SIZE));
//this is the the offset from the end of buffer where actual data ends
uint32_t sessionsOffset{};//bufferEnd - sessionsOffset = dataEnd
br.readBytes<4>(sessionsOffset);
EXPECT_THAT(sessionsOffset, Eq(1+4));//1byte for session info, 4 bytes for session offset variable
auto writtenSize = ctx.bw->writtenBytesCount();
auto dSize = writtenSize - sessionsOffset;
EXPECT_THAT(dSize, Eq(DATA_SIZE));
}
TEST(SerializeExtensionGrowable, WhenNestedSessionsThenStoreEachDepthAndSize) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
DataV3 data{19457,846, 498418};
ctx.createSerializer();
ctx.bw->beginSession();
ctx.bw->writeBytes<4>(data.v1);
ctx.bw->beginSession();
ctx.bw->writeBytes<4>(data.v2);
ctx.bw->endSession();
ctx.bw->beginSession();
ctx.bw->writeBytes<4>(data.v3);
ctx.bw->endSession();
ctx.bw->endSession();
DataV3 res{};
ctx.createDeserializer();//to flush data and create buffer reader
ctx.br->readBytes<4>(res.v1);
ctx.br->readBytes<4>(res.v2);
ctx.br->readBytes<4>(res.v3);
//read data correctly
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
EXPECT_THAT(res.v3, Eq(data.v3));
size_t sessionEnd[3];
//read sessions sizes
bitsery::details::readSize(*(ctx.br), sessionEnd[0],10000000u);
bitsery::details::readSize(*(ctx.br), sessionEnd[1],10000000u);
bitsery::details::readSize(*(ctx.br), sessionEnd[2],10000000u);
EXPECT_THAT(sessionEnd[0], Eq(12));
EXPECT_THAT(sessionEnd[1], Eq(8));
EXPECT_THAT(sessionEnd[2], Eq(12));
auto des = ctx.createDeserializer();
uint8_t res1b{};
uint16_t res2b{};
uint32_t res4b{};
des.value2b(res2b);
EXPECT_THAT(res2b, Eq(1));
des.value4b(res4b);
EXPECT_THAT(res4b, Eq(1+4));//size + 4bytes
des.value1b(res1b);
EXPECT_THAT(res1b, Eq(2));
des.value1b(res1b);
EXPECT_THAT(res1b, Eq(3));
EXPECT_THAT(ctx.bw->writtenBytesCount(), Eq(8));
}
TEST(SerializeExtensionGrowable, MultipleSessionsReadSameVersionData) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
SerializationContext ctx;
DataV2 data{8454,987451};
ctx.createSerializer();
auto& bw = (*ctx.bw);
auto ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
bw.beginSession();
bw.writeBytes<4>(data.v1);
bw.writeBytes<4>(data.v2);
bw.endSession();
bitsery::FtorExtObject<Growable>{}(ser, data);
}
//create more sessions that can fit in 2 bytes
ctx.createDeserializer();//to flush data and create buffer reader
ctx.createDeserializer();
DataV2 res{};
auto& br = (*ctx.br);
auto des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
br.beginSession();
br.readBytes<4>(res.v1);
br.readBytes<4>(res.v2);
br.endSession();
bitsery::FtorExtObject<Growable>{}(des, res);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
}
@@ -147,53 +106,37 @@ TEST(SerializeExtensionGrowable, MultipleSessionsReadSameVersionData) {
}
TEST(SerializeExtensionGrowable, MultipleSessionsReadNewerVersionData) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
DataV3 data{8454,987451,54};
ctx.createSerializer();
auto& bw = (*ctx.bw);
SerializationContext ctx;
DataV3 data{8454,987451, 45612};
auto ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
bw.beginSession();
bw.writeBytes<4>(data.v1);
bw.writeBytes<4>(data.v2);
bw.writeBytes<4>(data.v3);
bw.endSession();
bitsery::FtorExtObject<Growable>{}(ser, data);
}
//create more sessions that can fit in 2 bytes
ctx.createDeserializer();//to flush data and create buffer reader
ctx.createDeserializer();
DataV2 res{};
auto& br = (*ctx.br);
auto des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
br.beginSession();
br.readBytes<4>(res.v1);
br.readBytes<4>(res.v2);
br.endSession();
bitsery::FtorExtObject<Growable>{}(des, res);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
}
EXPECT_THAT(br.isCompletedSuccessfully(), Eq(true));
EXPECT_THAT(ctx.br->isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleSessionsReadOlderVersionData) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
SerializationContext ctx;
DataV2 data{8454,987451};
ctx.createSerializer();
auto& bw = (*ctx.bw);
auto ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
bw.beginSession();
bw.writeBytes<4>(data.v1);
bw.writeBytes<4>(data.v2);
bw.endSession();
bitsery::FtorExtObject<Growable>{}(ser, data);
}
//create more sessions that can fit in 2 bytes
ctx.createDeserializer();//to flush data and create buffer reader
DataV3 res{4798,657891,985};
auto& br = (*ctx.br);
ctx.createDeserializer();
DataV3 res{};
auto des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
br.beginSession();
br.readBytes<4>(res.v1);
br.readBytes<4>(res.v2);
br.readBytes<4>(res.v3);
br.endSession();
bitsery::FtorExtObject<Growable>{}(des, res);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
EXPECT_THAT(res.v3, Eq(0));
@@ -202,225 +145,94 @@ TEST(SerializeExtensionGrowable, MultipleSessionsReadOlderVersionData) {
}
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadSameVersionData) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
SerializationContext ctx;
DataV2 data{8454,987451};
ctx.createSerializer();
auto& bw = (*ctx.bw);
for (auto i = 0; i < 2; ++i) {
bw.beginSession();
bw.writeBytes<4>(data.v1);
bw.writeBytes<4>(data.v2);
bw.beginSession();
bw.writeBytes<4>(data.v1);
bw.writeBytes<4>(data.v2);
bw.endSession();
bw.endSession();
auto ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{}, [](decltype(ser)& ser, DataV2& o) {
ser.value4b(o.v1);
ser.value4b(o.v2);
bitsery::FtorExtObject<Growable>{}(ser, o);
});
}
//create more sessions that can fit in 2 bytes
ctx.createDeserializer();//to flush data and create buffer reader
ctx.createDeserializer();
DataV2 res{};
auto& br = (*ctx.br);
for (auto i = 0; i < 2; ++i) {
br.beginSession();
br.readBytes<4>(res.v1);
br.readBytes<4>(res.v2);
auto des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{}, [&res, &data](decltype(des)& des, DataV2& o) {
des.value4b(o.v1);
des.value4b(o.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
br.beginSession();
br.readBytes<4>(res.v1);
br.readBytes<4>(res.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
br.endSession();
br.endSession();
bitsery::FtorExtObject<Growable>{}(des, o);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
});
}
EXPECT_THAT(ctx.br->isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadNewerVersionData) {
SerializationContext ctx;
DataV3 data{8454,987451, 54124};
auto ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{}, [](decltype(ser)& ser, DataV3& o) {
ser.value4b(o.v1);
ser.value4b(o.v2);
bitsery::FtorExtObject<Growable>{}(ser, o);
//new fields can only be added at the end
ser.value4b(o.v3);
});
}
ctx.createDeserializer();
DataV2 res{};
auto des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{}, [&res, &data](decltype(des)& des, DataV2& o) {
des.value4b(o.v1);
des.value4b(o.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
bitsery::FtorExtObject<Growable>{}(des, o);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
});
}
EXPECT_THAT(ctx.br->isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadOlderVersionData) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
SerializationContext ctx;
DataV2 data{8454,987451};
ctx.createSerializer();
auto& bw = (*ctx.bw);
for (auto i = 0; i < 5; ++i) {
bw.beginSession();
bw.writeBytes<4>(data.v1);
bw.endSession();
bw.writeBytes<4>(data.v2);
}
auto ser = ctx.createSerializer();
//create more sessions that can fit in 2 bytes
ctx.createDeserializer();//to flush data and create buffer reader
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{}, [](decltype(ser)& ser, DataV2& o) {
ser.value4b(o.v1);
ser.value4b(o.v2);
bitsery::FtorExtObject<Growable>{}(ser, o);
});
}
ctx.createDeserializer();
DataV3 res{};
auto& br = (*ctx.br);
for (auto i = 0; i < 5; ++i) {
br.beginSession();
br.readBytes<4>(res.v1);
EXPECT_THAT(res.v1, Eq(data.v1));
//new flow
br.beginSession();
br.readBytes<4>(res.v3);
EXPECT_THAT(res.v3, Eq(0));
br.beginSession();
br.readBytes<4>(res.v3);
EXPECT_THAT(res.v3, Eq(0));
br.endSession();
br.endSession();
br.beginSession();
br.readBytes<4>(res.v3);
EXPECT_THAT(res.v3, Eq(0));
br.endSession();
br.endSession();
br.readBytes<4>(res.v2);
EXPECT_THAT(res.v2, Eq(data.v2));
}
EXPECT_THAT(ctx.br->isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadNewerVersionData1) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
DataV3 data{8454,987451,54};
ctx.createSerializer();
auto& bw = (*ctx.bw);
for (auto i = 0; i < 2; ++i) {
bw.beginSession();
{
bw.writeBytes<4>(data.v1);
bw.writeBytes<4>(data.v2);
//new flow
bw.beginSession();
{
bw.writeBytes<4>(data.v3);
}
bw.endSession();
bw.beginSession();
{
bw.writeBytes<4>(data.v3);
bw.beginSession();
{
bw.beginSession();
{
bw.writeBytes<4>(data.v3);
bw.writeBytes<4>(data.v3);
}
bw.endSession();
bw.writeBytes<4>(data.v3);
}
bw.endSession();
}
bw.endSession();
bw.writeBytes<4>(data.v3);
}
bw.endSession();
bw.writeBytes<4>(data.v2);
}
//create more sessions that can fit in 2 bytes
ctx.createDeserializer();//to flush data and create buffer reader
DataV2 res{};
auto& br = (*ctx.br);
for (auto i = 0; i < 2; ++i) {
br.beginSession();
{
br.readBytes<4>(res.v1);
br.readBytes<4>(res.v2);
auto des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{}, [&res, &data](decltype(des)& des, DataV3& o) {
des.value4b(o.v1);
des.value4b(o.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
}
br.endSession();
br.readBytes<4>(res.v2);
EXPECT_THAT(res.v2, Eq(data.v2));
}
EXPECT_THAT(ctx.br->isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadNewerVersionData2) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
DataV3 data{8454,987451,54};
ctx.createSerializer();
auto& bw = (*ctx.bw);
for (auto i = 0; i < 2; ++i) {
bw.beginSession();
bw.writeBytes<4>(data.v1);
bw.writeBytes<4>(data.v2);
bw.beginSession();
bw.writeBytes<4>(data.v1);
bw.writeBytes<4>(data.v2);
//new flow
bw.beginSession();
bw.writeBytes<4>(data.v3);
bw.endSession();
bw.beginSession();
bw.writeBytes<4>(data.v3);
bw.beginSession();
bw.beginSession();
bw.writeBytes<4>(data.v3);
bw.writeBytes<4>(data.v3);
bw.endSession();
bw.writeBytes<4>(data.v3);
bw.endSession();
bw.endSession();
bw.writeBytes<4>(data.v3);
bw.endSession();
bw.writeBytes<4>(data.v2);
//new flow
bw.writeBytes<4>(data.v3);
bw.beginSession();
bw.writeBytes<4>(data.v3);
bw.endSession();
bw.writeBytes<4>(data.v3);
bw.endSession();
}
//create more sessions that can fit in 2 bytes
ctx.createDeserializer();//to flush data and create buffer reader
DataV2 res{};
auto& br = (*ctx.br);
for (auto i = 0; i < 2; ++i) {
br.beginSession();
br.readBytes<4>(res.v1);
br.readBytes<4>(res.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
br.beginSession();
br.readBytes<4>(res.v1);
br.readBytes<4>(res.v2);
bitsery::FtorExtObject<Growable>{}(des, o);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
br.endSession();
br.readBytes<4>(res.v2);
EXPECT_THAT(res.v2, Eq(data.v2));
br.endSession();
}
EXPECT_THAT(ctx.br->isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, SessionsStartsAtEndOfSerialization) {
BasicSerializationContext<SessionsEnabledConfig, void> ctx;
DataV2 data{8454,987451};
ctx.createSerializer();
auto& bw = (*ctx.bw);
for (auto i = 0; i < 100; ++i)
bw.writeBytes<4>(data.v1);
for (auto i = 0; i < 10; ++i) {
bw.beginSession();
bw.writeBytes<4>(data.v1);
bw.writeBytes<4>(data.v2);
bw.endSession();
}
//create more sessions that can fit in 2 bytes
ctx.createDeserializer();//to flush data and create buffer reader
DataV2 res{};
auto& br = (*ctx.br);
for (auto i = 0; i < 100; ++i)
br.readBytes<4>(res.v1);
for (auto i = 0; i < 10; ++i) {
br.beginSession();
br.readBytes<4>(res.v1);
br.readBytes<4>(res.v2);
br.endSession();
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
EXPECT_THAT(res.v3, Eq(0));
//new fields can only be added at the end
des.value4b(o.v3);
EXPECT_THAT(res.v3, Eq(0));
});
}
EXPECT_THAT(ctx.br->isCompletedSuccessfully(), Eq(true));
}

View File

@@ -27,11 +27,7 @@
using bitsery::ext::BaseClass;
using bitsery::ext::VirtualBaseClass;
struct ConfigWithInheritanceCtx:bitsery::DefaultConfig {
using InternalContext = std::tuple<bitsery::ext::InheritanceContext>;
};
using SerContext = BasicSerializationContext<ConfigWithInheritanceCtx, void>;
using SerContext = BasicSerializationContext<bitsery::DefaultConfig, bitsery::ext::InheritanceContext>;
using testing::Eq;
@@ -68,7 +64,7 @@ struct Derive2NonVirtually:Base {
template <typename S>
void serialize(S& s, Derive2NonVirtually& o) {
//use lambda to serialize base
s.ext(o, BaseClass<Base>{}, [&s](Base& b) {
s.ext(o, BaseClass<Base>{}, [](S& s, Base& b) {
s.object(b);
});
s.value1b(o.y2);
@@ -140,8 +136,10 @@ TEST(SerializeExtensionInheritance, BaseClass) {
Derive1NonVirtually rd1{};
SerContext ctx{};
ctx.createSerializer().object(d1);
ctx.createDeserializer().object(rd1);
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(d1);
ctx.createDeserializer(inherCtxDes).object(rd1);
EXPECT_THAT(rd1.x, Eq(d1.x));
EXPECT_THAT(rd1.y1, Eq(d1.y1));
@@ -155,8 +153,10 @@ TEST(SerializeExtensionInheritance, VirtualBaseClass) {
Derive1Virtually rd1{};
SerContext ctx{};
ctx.createSerializer().object(d1);
ctx.createDeserializer().object(rd1);
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(d1);
ctx.createDeserializer(inherCtxDes).object(rd1);
EXPECT_THAT(rd1.x, Eq(d1.x));
EXPECT_THAT(rd1.y1, Eq(d1.y1));
@@ -174,8 +174,10 @@ TEST(SerializeExtensionInheritance, MultipleBasesWithoutVirtualInheritance) {
MultipleInheritanceNonVirtualBase res{};
SerContext ctx{};
ctx.createSerializer().object(md);
ctx.createDeserializer().object(res);
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(md);
ctx.createDeserializer(inherCtxDes).object(res);
EXPECT_THAT(static_cast<Derive1NonVirtually&>(res).x, Eq(static_cast<Derive1NonVirtually&>(md).x));
EXPECT_THAT(static_cast<Derive2NonVirtually&>(res).x, Eq(static_cast<Derive2NonVirtually&>(md).x));
@@ -217,8 +219,10 @@ TEST(SerializeExtensionInheritance, MultipleBasesWithVirtualInheritance) {
MultipleInheritanceVirtualBase res{};
SerContext ctx{};
ctx.createSerializer().object(md);
ctx.createDeserializer().object(res);
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(md);
ctx.createDeserializer(inherCtxDes).object(res);
EXPECT_THAT(res, Eq(md));
EXPECT_THAT(ctx.getBufferSize(), Eq(4)); //4 because virtual base
}
@@ -233,8 +237,10 @@ TEST(SerializeExtensionInheritance, MultipleBasesWithVirtualInheritanceMultipleO
std::vector<MultipleInheritanceVirtualBase> res{};
SerContext ctx{};
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).container(data, 10);
ctx.createDeserializer(inherCtxDes).container(res, 10);
EXPECT_THAT(res, ::testing::ContainerEq(data));
EXPECT_THAT(ctx.getBufferSize(), Eq(1 + 4 * data.size())); //1 container size + 4 because virtual base * elements
}
@@ -264,7 +270,7 @@ public:
template <typename S>
void serialize(S& s, DerivedPrivateBase& o) {
//use lambda for base serialization
s.ext(o, BaseClass<BasePrivateSerialize>{}, [&s](BasePrivateSerialize& b) {
s.ext(o, BaseClass<BasePrivateSerialize>{}, [](S& s, BasePrivateSerialize& b) {
s.object(b);
});
s.value1b(o.z);
@@ -309,10 +315,12 @@ TEST(SerializeExtensionInheritance, WhenDerivedClassHasAmbiguousSerializeFunctio
DerivedMemberSerialize res2{};
SerContext ctx{};
ctx.createSerializer().object(data1);
ctx.createSerializer().object(data2);
ctx.createDeserializer().object(res1);
ctx.createDeserializer().object(res2);
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(data1);
ctx.createSerializer(inherCtxSer).object(data2);
ctx.createDeserializer(inherCtxDes).object(res1);
ctx.createDeserializer(inherCtxDes).object(res2);
EXPECT_THAT(res1.getX(), Eq(data1.getX()));
EXPECT_THAT(res1.z, Eq(data1.z));
EXPECT_THAT(res2.x, Eq(data2.x));
@@ -348,8 +356,10 @@ TEST(SerializeExtensionInheritance, CanSerializeAbstractClass) {
data.exec();
ImplementedBase res{};
SerContext ctx{};
ctx.createSerializer().object(data);
ctx.createDeserializer().object(res);
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(data);
ctx.createDeserializer(inherCtxDes).object(res);
EXPECT_THAT(res.x, Eq(data.x));
EXPECT_THAT(res.y, Eq(data.y));
}

View File

@@ -60,13 +60,19 @@ public:
PointerLinkingContext plctx1{};
SerContext sctx1{};
typename SerContext::TSerializer &createSerializer() {
return sctx1.createSerializer(&plctx1);
typename SerContext::TSerializer createSerializer() {
return sctx1.createSerializer(plctx1);
}
typename SerContext::TDeserializer createDeserializer() {
return sctx1.createDeserializer(plctx1);
}
bool isPointerContextValid() {
return plctx1.isValid();
}
};
TEST(SerializeExtensionPointer, RequiresPointerLinkingContext) {
@@ -74,15 +80,15 @@ TEST(SerializeExtensionPointer, RequiresPointerLinkingContext) {
//linking context
PointerLinkingContext plctx1{};
SerContext sctx1;
sctx1.createSerializer(&plctx1).ext(data, PointerOwner{});
sctx1.createDeserializer(&plctx1).ext(data, PointerOwner{});
sctx1.createSerializer(plctx1).ext(data, PointerOwner{});
sctx1.createDeserializer(plctx1).ext(data, PointerOwner{});
//linking context in tuple
using ContextInTuple = std::tuple<int, PointerLinkingContext, float, char>;
ContextInTuple plctx2(0, PointerLinkingContext{}, 0.0f, 'a');
BasicSerializationContext<SessionsEnabledConfig, ContextInTuple> sctx2;
sctx2.createSerializer(&plctx2).ext(data, PointerObserver{});
sctx2.createDeserializer(&plctx2).ext(data, PointerObserver{});
BasicSerializationContext<bitsery::DefaultConfig, ContextInTuple> sctx2;
sctx2.createSerializer(plctx2).ext(data, PointerObserver{});
sctx2.createDeserializer(plctx2).ext(data, PointerObserver{});
}
TEST(SerializeExtensionPointer, PointerLinkingContextAcceptsMultipleSharedOwnersAndReturnSameId) {
@@ -115,12 +121,12 @@ TEST(SerializeExtensionPointer, WhenOnlySharedObserverThenPointerLinkingContextI
TEST_F(SerializeExtensionPointerSerialization, WhenPointersAreNullThenIsValid) {
auto &ser = createSerializer();
auto ser = createSerializer();
ser.ext2b(p1null, PointerOwner{});
ser.ext2b(p1null, PointerObserver{});
ser.ext(p3null, PointerOwner{});
ser.ext(p3null, PointerObserver{});
sctx1.createDeserializer();
createDeserializer();
EXPECT_THAT(sctx1.bw->writtenBytesCount(), Eq(4));
EXPECT_THAT(plctx1.isValid(), Eq(true));
@@ -128,18 +134,9 @@ TEST_F(SerializeExtensionPointerSerialization, WhenPointersAreNullThenIsValid) {
#ifndef NDEBUG
TEST(SerializeExtensionPointer, WhenPointerLinkingContextIsNullAndPointerIsNotNullThenAssert) {
MyStruct1 tmp;
MyStruct1 *data = &tmp;
//linking context
PointerLinkingContext plctx1{};
SerContext sctx1;
EXPECT_DEATH(sctx1.createSerializer(nullptr).ext(data, PointerOwner{}), "");
}
TEST_F(SerializeExtensionPointerSerialization, WhenPointerOwnerIsNotUniqueThenAssert) {
auto &ser = createSerializer();
auto ser = createSerializer();
ser.ext2b(p1null, PointerOwner{});
ser.ext2b(pd1, PointerOwner{});
ser.ext4b(pd2, PointerOwner{});
@@ -149,7 +146,7 @@ TEST_F(SerializeExtensionPointerSerialization, WhenPointerOwnerIsNotUniqueThenAs
}
TEST_F(SerializeExtensionPointerSerialization, WhenRererencedByPointerIsSameAsPointerOwnerThenAssert1) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
ser1.ext4b(pd2, PointerOwner{});
ser1.ext(d3, ReferencedByPointer{});
@@ -157,14 +154,14 @@ TEST_F(SerializeExtensionPointerSerialization, WhenRererencedByPointerIsSameAsPo
}
TEST_F(SerializeExtensionPointerSerialization, WhenRererencedByPointerIsSameAsPointerOwnerThenAssert2) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
ser1.ext2b(pd1, PointerOwner{});
ser1.ext4b(d2, ReferencedByPointer{});
EXPECT_DEATH(ser1.ext2b(d1, ReferencedByPointer{}), "");
}
TEST_F(SerializeExtensionPointerSerialization, WhenNonNullPointerIsNullThenAssert) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
EXPECT_DEATH(ser1.ext2b(p1null, PointerOwner{PointerType::NotNull}), "");
EXPECT_DEATH(ser1.ext2b(p1null, PointerObserver{PointerType::NotNull}), "");
}
@@ -172,7 +169,7 @@ TEST_F(SerializeExtensionPointerSerialization, WhenNonNullPointerIsNullThenAsser
#endif
TEST_F(SerializeExtensionPointerSerialization, WhenPointerObserverPointsToOwnerThenIsValid) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
ser1.ext2b(pd1, PointerOwner{});
ser1.ext2b(p1null, PointerObserver{});
EXPECT_THAT(plctx1.isValid(), Eq(true));
@@ -185,7 +182,7 @@ TEST_F(SerializeExtensionPointerSerialization, WhenPointerObserverPointsToOwnerT
}
TEST_F(SerializeExtensionPointerSerialization, ReferenceTypeCanAlsoBeReferencedByPointerObservers) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
ser1.ext2b(p1null, PointerObserver{});
EXPECT_THAT(plctx1.isValid(), Eq(true));
ser1.ext4b(pd2, PointerObserver{});//points to d2, and d2 is not still marked as owner
@@ -197,10 +194,10 @@ TEST_F(SerializeExtensionPointerSerialization, ReferenceTypeCanAlsoBeReferencedB
}
TEST_F(SerializeExtensionPointerSerialization, WhenPointerIsNullThenPointerIdIsZero) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
ser1.ext(p3null, PointerOwner{});
ser1.ext2b(p1null, PointerObserver{});
sctx1.createDeserializer();
createDeserializer();
EXPECT_THAT(sctx1.bw->writtenBytesCount(), Eq(2));
size_t res;
bitsery::details::readSize(*sctx1.br, res, 10000u);
@@ -210,12 +207,12 @@ TEST_F(SerializeExtensionPointerSerialization, WhenPointerIsNullThenPointerIdIsZ
}
TEST_F(SerializeExtensionPointerSerialization, PointerIdsStartsFromOne) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
ser1.ext2b(pd1, PointerObserver{});
ser1.ext4b(pd2, PointerObserver{});
ser1.ext4b(pd2, PointerObserver{});
ser1.ext2b(p1null, PointerObserver{});
sctx1.createDeserializer();
createDeserializer();
EXPECT_THAT(sctx1.bw->writtenBytesCount(), Eq(4));
size_t res;
bitsery::details::readSize(*sctx1.br, res, 10000u);
@@ -229,20 +226,20 @@ TEST_F(SerializeExtensionPointerSerialization, PointerIdsStartsFromOne) {
}
TEST_F(SerializeExtensionPointerSerialization, PointerObserversDoesntSerializeObject) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
ser1.ext2b(pd1, PointerObserver{});
ser1.ext4b(pd2, PointerObserver{});
ser1.ext4b(pd2, PointerObserver{});
sctx1.createDeserializer();
createDeserializer();
EXPECT_THAT(sctx1.bw->writtenBytesCount(), Eq(3));
}
TEST_F(SerializeExtensionPointerSerialization, ReferencedByPointerSerializesIdAndObject) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
ser1.ext2b(d1, ReferencedByPointer{});
ser1.ext4b(d2, ReferencedByPointer{});
ser1.ext4b(pd2, PointerObserver{});
auto &des = sctx1.createDeserializer();
auto des = createDeserializer();
EXPECT_THAT(sctx1.bw->writtenBytesCount(), Eq(3 + 6));
size_t id{};
bitsery::details::readSize(*sctx1.br, id, 10000u);
@@ -258,10 +255,10 @@ TEST_F(SerializeExtensionPointerSerialization, ReferencedByPointerSerializesIdAn
}
TEST_F(SerializeExtensionPointerSerialization, PointerOwnerSerializesIdAndObject) {
auto &ser1 = createSerializer();
auto ser1 = createSerializer();
ser1.ext4b(pd2, PointerOwner{});
ser1.ext(pd3, PointerOwner{});
auto &des1 = sctx1.createDeserializer();
auto des1 = createDeserializer();
//2x ids + int32_t + MyStruct1
EXPECT_THAT(sctx1.bw->writtenBytesCount(), Eq(2 + 4 + MyStruct1::SIZE));
size_t id;
@@ -276,22 +273,14 @@ TEST_F(SerializeExtensionPointerSerialization, PointerOwnerSerializesIdAndObject
class SerializeExtensionPointerDeserialization : public SerializeExtensionPointerSerialization {
public:
typename SerContext::TSerializer &createSerializer() {
return sctx1.createSerializer(&plctx1);
}
typename SerContext::TDeserializer &createDeserializer() {
return sctx1.createDeserializer(&plctx1);
}
};
TEST_F(SerializeExtensionPointerDeserialization, ReferencedByPointer) {
auto &ser = createSerializer();
auto ser = createSerializer();
ser.ext2b(d1, ReferencedByPointer{});
ser.ext4b(d2, ReferencedByPointer{});
ser.ext(d3, ReferencedByPointer{});
auto &des = createDeserializer();
auto des = createDeserializer();
des.ext2b(r1, ReferencedByPointer{});
des.ext4b(r2, ReferencedByPointer{});
des.ext(r3, ReferencedByPointer{});
@@ -302,10 +291,10 @@ TEST_F(SerializeExtensionPointerDeserialization, ReferencedByPointer) {
}
TEST_F(SerializeExtensionPointerDeserialization, WhenReferencedByPointerReadsNullPointerThenInvalidPointerError) {
auto &ser = createSerializer();
auto ser = createSerializer();
bitsery::details::writeSize(*sctx1.bw, 0u);
ser.ext2b(d1, ReferencedByPointer{});
auto &des = createDeserializer();
auto des = createDeserializer();
des.ext2b(r1, ReferencedByPointer{});
EXPECT_THAT(sctx1.br->error(), Eq(bitsery::ReaderError::InvalidPointer));
}
@@ -313,21 +302,21 @@ TEST_F(SerializeExtensionPointerDeserialization, WhenReferencedByPointerReadsNul
TEST_F(SerializeExtensionPointerDeserialization, WhenNonNullPointerIsNullThenInvalidPointerError) {
createSerializer();
bitsery::details::writeSize(*sctx1.bw, 0u);
auto &des1 = createDeserializer();
auto des1 = createDeserializer();
des1.ext2b(p1null, PointerOwner{PointerType::NotNull});
EXPECT_THAT(sctx1.br->error(), Eq(bitsery::ReaderError::InvalidPointer));
auto &des2 = createDeserializer();
auto des2 = createDeserializer();
des2.ext2b(p1null, PointerObserver{PointerType::NotNull});
EXPECT_THAT(sctx1.br->error(), Eq(bitsery::ReaderError::InvalidPointer));
}
TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerCreatesObjects) {
auto &ser = createSerializer();
auto ser = createSerializer();
ser.ext2b(pd1, PointerOwner{});
ser.ext4b(pd2, PointerOwner{});
ser.ext(pd3, PointerOwner{});
auto &des = createDeserializer();
auto des = createDeserializer();
des.ext2b(p1null, PointerOwner{});
des.ext4b(p2null, PointerOwner{});
des.ext(p3null, PointerOwner{});
@@ -342,11 +331,11 @@ TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerCreatesObjects) {
}
TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerDestroysObjects) {
auto &ser = createSerializer();
auto ser = createSerializer();
ser.ext2b(p1null, PointerOwner{});
ser.ext4b(p2null, PointerOwner{});
ser.ext(p3null, PointerOwner{});
auto &des = createDeserializer();
auto des = createDeserializer();
//pr cannot link to local variables, need to allocate them separately
pr1 = new int16_t{};
pr2 = new MyEnumClass{};
@@ -362,7 +351,7 @@ TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerDestroysObjects) {
}
TEST_F(SerializeExtensionPointerDeserialization, PointerObserver) {
auto &ser = createSerializer();
auto ser = createSerializer();
//first owner, than observer
ser.ext4b(d2, ReferencedByPointer{});
ser.ext2b(p1null, PointerObserver{});
@@ -370,7 +359,7 @@ TEST_F(SerializeExtensionPointerDeserialization, PointerObserver) {
//first observer, than owner
ser.ext(pd3, PointerObserver{});
ser.ext(pd3, PointerOwner{});
auto &des = createDeserializer();
auto des = createDeserializer();
des.ext4b(r2, ReferencedByPointer{});
des.ext2b(pr1, PointerObserver{});
des.ext4b(p2null, PointerObserver{});
@@ -399,7 +388,7 @@ struct Test1Data {
template<typename S>
void serialize(S &s) {
//set container elements to be candidates for non-owning pointers
s.container(vdata, 100, [&s](MyStruct1 &d) {
s.container(vdata, 100, [](S& s, MyStruct1 &d) {
s.ext(d, ReferencedByPointer{});
});
//contains non owning pointers
@@ -407,7 +396,7 @@ struct Test1Data {
//IMPORTANT !!!
// ALWAYS ACCEPT BY REFERENCE like this: T* (&obj)
//
s.container(vptr, 100, [&s](MyStruct1 *(&d)) {
s.container(vptr, 100, [](S& s, MyStruct1 *(&d)) {
s.ext(d, PointerObserver{});
});
//just a regular fields
@@ -443,8 +432,8 @@ TEST(SerializeExtensionPointer, IntegrationTest) {
PointerLinkingContext plctx1{};
SerContext sctx1;
sctx1.createSerializer(&plctx1).object(data);
sctx1.createDeserializer(&plctx1).object(res);
sctx1.createSerializer(plctx1).object(data);
sctx1.createDeserializer(plctx1).object(res);
EXPECT_THAT(plctx1.isValid(), Eq(true));
//check regular fields
@@ -474,13 +463,13 @@ TEST(SerializeExtensionPointer, PointerOwnerWithNonPolymorphicTypeCanUseLambdaOv
//linking context
PointerLinkingContext plctx1{};
SerContext sctx1;
auto &ser = sctx1.createSerializer(&plctx1);
ser.ext(data, PointerOwner{}, [&ser](MyStruct1 &o) {
auto ser = sctx1.createSerializer(plctx1);
ser.ext(data, PointerOwner{}, [](decltype(ser)& ser, MyStruct1 &o) {
//serialize only one field
ser.value4b(o.i1);
});
auto &des = sctx1.createDeserializer(&plctx1);
des.ext(res, PointerOwner{}, [&des](MyStruct1 &o) {
auto des = sctx1.createDeserializer(plctx1);
des.ext(res, PointerOwner{}, [](decltype(des)& des,MyStruct1 &o) {
//deserialize only one field
des.value4b(o.i1);
});
@@ -500,13 +489,13 @@ TEST(SerializeExtensionPointer, ReferencedByPointerCanUseLambdaOverload) {
//linking context
PointerLinkingContext plctx1{};
SerContext sctx1;
auto &ser = sctx1.createSerializer(&plctx1);
ser.ext(data, ReferencedByPointer{}, [&ser](MyStruct1 &o) {
auto ser = sctx1.createSerializer(plctx1);
ser.ext(data, ReferencedByPointer{}, [](decltype(ser)& ser,MyStruct1 &o) {
//serialize only one field
ser.value4b(o.i1);
});
auto &des = sctx1.createDeserializer(&plctx1);
des.ext(res, ReferencedByPointer{}, [&des](MyStruct1 &o) {
auto des = sctx1.createDeserializer(plctx1);
des.ext(res, ReferencedByPointer{}, [](decltype(des)& des,MyStruct1 &o) {
//deserialize only one field
des.value4b(o.i1);
});
@@ -521,8 +510,8 @@ TEST(SerializeExtensionPointer, PointerOwnerCanUseValueOverload) {
PointerLinkingContext plctx1{};
SerContext sctx1;
sctx1.createSerializer(&plctx1).ext8b(data, PointerOwner{});
sctx1.createDeserializer(&plctx1).ext8b(res, PointerOwner{});
sctx1.createSerializer(plctx1).ext8b(data, PointerOwner{});
sctx1.createDeserializer(plctx1).ext8b(res, PointerOwner{});
EXPECT_THAT(*res, Eq(*data));
@@ -536,8 +525,8 @@ TEST(SerializeExtensionPointer, ReferencedByPointerCanUseValueOverload) {
PointerLinkingContext plctx1{};
SerContext sctx1;
sctx1.createSerializer(&plctx1).ext8b(data, ReferencedByPointer{});
sctx1.createDeserializer(&plctx1).ext8b(res, ReferencedByPointer{});
sctx1.createSerializer(plctx1).ext8b(data, ReferencedByPointer{});
sctx1.createDeserializer(plctx1).ext8b(res, ReferencedByPointer{});
EXPECT_THAT(res, Eq(data));
}

View File

@@ -148,16 +148,16 @@ public:
TContext plctx{};
SerContext sctx{};
typename SerContext::TSerializer &createSerializer() {
auto &res = sctx.createSerializer(&plctx);
typename SerContext::TSerializer createSerializer() {
auto res = sctx.createSerializer(plctx);
std::get<2>(plctx).clear();
//bind serializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TSerializer>(bitsery::ext::PolymorphicClassesList<Base>{});
return res;
}
typename SerContext::TDeserializer &createDeserializer() {
auto &res = sctx.createDeserializer(&plctx);
typename SerContext::TDeserializer createDeserializer() {
auto res = sctx.createDeserializer(plctx);
std::get<2>(plctx).clear();
//bind deserializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TDeserializer>(bitsery::ext::PolymorphicClassesList<Base>{});
@@ -319,7 +319,7 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes,
createSerializer().ext(baseData, PointerOwner{});
BaseClone *baseRes = nullptr; //this class will be registered, but it doesn't have relationships specified via PolymorphicBaseClass
auto &des = sctx.createDeserializer(&plctx);
auto des = sctx.createDeserializer(plctx);
auto &pc = std::get<2>(plctx);
pc.clear();
pc.registerBasesList<SerContext::TDeserializer>(bitsery::ext::PolymorphicClassesList<BaseClone>{});

View File

@@ -157,7 +157,7 @@ struct MemResourceForTest : public bitsery::ext::MemResourceBase {
return res;
}
void deallocate(void* ptr, size_t bytes, size_t alignment, size_t typeId) override {
void deallocate(void* ptr, size_t bytes, size_t alignment, size_t typeId) noexcept override {
deallocs.push_back({ptr, bytes, alignment, typeId});
bitsery::ext::MemResourceNewDelete{}.deallocate(ptr, bytes, alignment, typeId);
}
@@ -172,8 +172,8 @@ public:
TContext plctx{};
SerContext sctx{};
typename SerContext::TSerializer& createSerializer() {
auto& res = sctx.createSerializer(&plctx);
typename SerContext::TSerializer createSerializer() {
auto res = sctx.createSerializer(plctx);
std::get<2>(plctx).clear();
//bind serializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TSerializer>(
@@ -181,8 +181,8 @@ public:
return res;
}
typename SerContext::TDeserializer& createDeserializer() {
auto& res = sctx.createDeserializer(&plctx);
typename SerContext::TDeserializer createDeserializer() {
auto res = sctx.createDeserializer(plctx);
std::get<2>(plctx).clear();
//bind deserializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TDeserializer>(
@@ -202,7 +202,7 @@ public:
TEST_F(SerializeExtensionPointerWithAllocator, CanSetDefaultMemoryResourceInPointerLinkingContext) {
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
std::get<0>(plctx).getAllocator().setMemResource(&memRes);
Base* baseData = new Derived1{2, 1};
createSerializer().ext(baseData, PointerOwner{});
@@ -225,7 +225,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, CanSetDefaultMemoryResourceInPoin
TEST_F(SerializeExtensionPointerWithAllocator, CorrectlyDeallocatesPreviousInstance) {
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
std::get<0>(plctx).getAllocator().setMemResource(&memRes);
Base* baseData = new Derived1{2, 1};
createSerializer().ext(baseData, PointerOwner{});
@@ -252,7 +252,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, CorrectlyDeallocatesPreviousInsta
TEST_F(SerializeExtensionPointerWithAllocator, DefaultDeleterIsNotUsedForStdUniquePtr) {
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
std::get<0>(plctx).getAllocator().setMemResource(&memRes);
std::unique_ptr<Base> baseData{};
createSerializer().ext(baseData, StdSmartPtr{});
@@ -274,7 +274,7 @@ struct CustomBaseDeleter {
TEST_F(SerializeExtensionPointerWithAllocator, CustomDeleterIsUsedForStdUniquePtr) {
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
std::get<0>(plctx).getAllocator().setMemResource(&memRes);
std::unique_ptr<Base, CustomBaseDeleter> baseData{};
createSerializer().ext(baseData, StdSmartPtr{});
@@ -289,7 +289,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, CustomDeleterIsUsedForStdUniquePt
TEST_F(SerializeExtensionPointerWithAllocator, CanSetMemResourcePerPointer) {
MemResourceForTest memRes1{};
MemResourceForTest memRes2{};
std::get<0>(plctx).setMemResource(&memRes1);
std::get<0>(plctx).getAllocator().setMemResource(&memRes1);
Base* baseData = new Derived1{2, 1};
createSerializer().ext(baseData, PointerOwner{bitsery::ext::PointerType::Nullable, &memRes2});
@@ -320,7 +320,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, CanSetMemResourcePerPointer) {
TEST_F(SerializeExtensionPointerWithAllocator, MemResourceSetPerPointerByDefaultDoNotPropagate) {
MemResourceForTest memRes1{};
MemResourceForTest memRes2{};
std::get<0>(plctx).setMemResource(&memRes1);
std::get<0>(plctx).getAllocator().setMemResource(&memRes1);
auto data = std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
data->ptr = std::unique_ptr<Base>(new Derived1{5, 6});
@@ -343,7 +343,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, MemResourceSetPerPointerByDefault
TEST_F(SerializeExtensionPointerWithAllocator, MemResourceSetPerPointerCanPropagate) {
MemResourceForTest memRes1{};
MemResourceForTest memRes2{};
std::get<0>(plctx).setMemResource(&memRes1);
std::get<0>(plctx).getAllocator().setMemResource(&memRes1);
auto data = std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
data->ptr = std::unique_ptr<Base>(new Derived1{5, 6});

View File

@@ -95,7 +95,7 @@ namespace bitsery {
template <typename S>
void serialize(S& s, std::unordered_map<std::string, MyStruct1>& o) {
s.ext(o, StdMap{10}, [&s](std::string& key, MyStruct1& value) {
s.ext(o, StdMap{10}, [](S& s, std::string& key, MyStruct1& value) {
s.text1b(key, 100);
s.object(value);
});
@@ -103,7 +103,7 @@ namespace bitsery {
template <typename S>
void serialize(S& s, std::unordered_multimap<int32_t, float>& o) {
s.ext(o, StdMap{10}, [&s](int32_t& key, float& value) {
s.ext(o, StdMap{10}, [](S& s, int32_t& key, float& value) {
s.value4b(key);
s.value4b(value);
});
@@ -111,7 +111,7 @@ namespace bitsery {
template <typename S>
void serialize(S& s, std::map<MyEnumClass , MyStruct1>& o) {
s.ext(o, StdMap{10}, [&s](MyEnumClass& key, MyStruct1& value) {
s.ext(o, StdMap{10}, [](S& s, MyEnumClass& key, MyStruct1& value) {
s.value4b(key);
s.object(value);
});
@@ -119,7 +119,7 @@ namespace bitsery {
template <typename S>
void serialize(S& s, std::multimap<int32_t ,int64_t>& o) {
s.ext(o, StdMap{10}, [&s](int32_t& key, int64_t& value) {
s.ext(o, StdMap{10}, [](S& s, int32_t& key, int64_t& value) {
s.enableBitPacking([&key, &value](typename S::BPEnabledType& sbp) {
int64_t values[3]{1ll, 2ll, 3ll};
sbp.ext(key, bitsery::ext::ValueRange<int32_t>{-100,100});

View File

@@ -84,12 +84,12 @@ TEST(SerializeExtensionStdOptional, AlignAfterStateWriteRead) {
SerializationContext ctx;
ctx.createSerializer().enableBitPacking([&t1, &range](BPSer& ser) {
ser.ext(t1, StdOptional(true), [&ser, &range](int32_t& v) {
ser.ext(t1, StdOptional(true), [&range](BPSer& ser, int32_t& v) {
ser.ext(v, range);
});
});
ctx.createDeserializer().enableBitPacking([&r1, &range](BPDes& des) {
des.ext(r1, StdOptional(true), [&des, &range](int32_t& v) {
des.ext(r1, StdOptional(true), [&range](BPDes& des, int32_t& v) {
des.ext(v, range);
});
});
@@ -105,12 +105,12 @@ TEST(SerializeExtensionStdOptional, NoAlignAfterStateWriteRead) {
SerializationContext ctx;
ctx.createSerializer().enableBitPacking([&t1, &range](BPSer& ser) {
ser.ext(t1, StdOptional(false), [&ser, &range](int32_t& v) {
ser.ext(t1, StdOptional(false), [&range](BPSer& ser, int32_t& v) {
ser.ext(v, range);
});
});
ctx.createDeserializer().enableBitPacking([&r1, &range](BPDes& des) {
des.ext(r1, StdOptional(false), [&des, &range](int32_t& v) {
des.ext(r1, StdOptional(false), [&range](BPDes& des, int32_t& v) {
des.ext(v, range);
});
});

View File

@@ -66,12 +66,12 @@ TEST(SerializeExtensionStdSet, FunctionSyntax) {
SerializationContext ctx1;
std::unordered_multiset<int32_t> t1{54,-484,841,79};
std::unordered_multiset<int32_t> r1{74,878,15,16,-7,5,-4,8,7};
auto& ser = ctx1.createSerializer();
ser.ext(t1, StdSet{10}, [&ser](int32_t& v) {
auto ser = ctx1.createSerializer();
ser.ext(t1, StdSet{10}, [](decltype(ser)& ser, int32_t& v) {
ser.value4b(v);
});
auto& des = ctx1.createDeserializer();
des.ext(r1, StdSet{10}, [&des](int32_t& v) {
auto des = ctx1.createDeserializer();
des.ext(r1, StdSet{10}, [](decltype(des)& des, int32_t& v) {
des.value4b(v);
});
EXPECT_THAT(r1, Eq(t1));

View File

@@ -120,14 +120,12 @@ public:
TContext plctx{};
SerContext sctx{};
typename SerContext::TSerializer& createSerializer() {
auto& res = sctx.createSerializer(&plctx);
return res;
typename SerContext::TSerializer createSerializer() {
return sctx.createSerializer(plctx);
}
typename SerContext::TDeserializer& createDeserializer() {
auto& res = sctx.createDeserializer(&plctx);
return res;
typename SerContext::TDeserializer createDeserializer() {
return sctx.createDeserializer(plctx);
}
bool isPointerContextValid() {
@@ -156,8 +154,8 @@ public:
TContext plctx{};
SerContext sctx{};
typename SerContext::TSerializer& createSerializer() {
auto& res = sctx.createSerializer(&plctx);
typename SerContext::TSerializer createSerializer() {
auto res = sctx.createSerializer(plctx);
std::get<2>(plctx).clear();
//bind serializer with classes
std::get<2>(plctx).template registerBasesList<SerContext::TSerializer>(
@@ -165,8 +163,8 @@ public:
return res;
}
typename SerContext::TDeserializer& createDeserializer() {
auto& res = sctx.createDeserializer(&plctx);
typename SerContext::TDeserializer createDeserializer() {
auto res = sctx.createDeserializer(plctx);
std::get<2>(plctx).clear();
//bind deserializer with classes
std::get<2>(plctx).template registerBasesList<SerContext::TDeserializer>(
@@ -268,14 +266,14 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, CanUseLambdaOverload
using Ext = typename TestFixture::TExt;
Ptr data{new MyStruct1{3, 78}};
auto& ser = this->createSerializer();
ser.ext(data, Ext{}, [&ser](MyStruct1& o) {
auto ser = this->createSerializer();
ser.ext(data, Ext{}, [](decltype(ser)& ser, MyStruct1& o) {
//serialize only one field
ser.value4b(o.i1);
});
Ptr res{new MyStruct1{97, 12}};
auto& des = this->createDeserializer();
des.ext(res, Ext{}, [&des](MyStruct1& o) {
auto des = this->createDeserializer();
des.ext(res, Ext{}, [](decltype(des)& des, MyStruct1& o) {
des.value4b(o.i1);
});
@@ -300,12 +298,12 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, FirstPtrThenPointerO
Ptr data{new uint16_t{3}};
uint16_t* dataObs = data.get();
auto& ser = this->createSerializer();
auto ser = this->createSerializer();
ser.ext2b(data, Ext{});
ser.ext2b(dataObs, PointerObserver{});
Ptr res{};
uint16_t* resObs = nullptr;
auto& des = this->createDeserializer();
auto des = this->createDeserializer();
des.ext2b(res, Ext{});
des.ext2b(resObs, PointerObserver{});
@@ -318,12 +316,12 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, FirstPointerObserver
Ptr data{new uint16_t{3}};
uint16_t* dataObs = data.get();
auto& ser = this->createSerializer();
auto ser = this->createSerializer();
ser.ext2b(dataObs, PointerObserver{});
ser.ext2b(data, Ext{});
Ptr res{};
uint16_t* resObs = nullptr;
auto& des = this->createDeserializer();
auto des = this->createDeserializer();
des.ext2b(resObs, PointerObserver{});
des.ext2b(res, Ext{});
EXPECT_THAT(resObs, Eq(res.get()));
@@ -405,16 +403,16 @@ public:
TContext plctx{};
SerContext sctx{};
typename SerContext::TSerializer& createSerializer() {
auto& res = sctx.createSerializer(&plctx);
typename SerContext::TSerializer createSerializer() {
auto res = sctx.createSerializer(plctx);
std::get<2>(plctx).clear();
//bind serializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TSerializer>(bitsery::ext::PolymorphicClassesList<Base>{});
return res;
}
typename SerContext::TDeserializer& createDeserializer() {
auto& res = sctx.createDeserializer(&plctx);
typename SerContext::TDeserializer createDeserializer() {
auto res = sctx.createDeserializer(plctx);
std::get<2>(plctx).clear();
//bind deserializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TDeserializer>(bitsery::ext::PolymorphicClassesList<Base>{});
@@ -438,10 +436,10 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, SameSharedObjectIsSerializedOnce) {
std::shared_ptr<Base> baseData1{new Derived{3, 78}};
std::shared_ptr<Base> baseData2{baseData1};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData1, StdSmartPtr{});
ser.ext(baseData1, StdSmartPtr{});
auto& des = createDeserializer();
createDeserializer();
//1b linking context (for 1st time)
//1b dynamic type info
@@ -455,10 +453,10 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, PointerLinkingContextCorrectlyClearS
std::shared_ptr<Base> baseData1{new Derived{3, 78}};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData1, StdSmartPtr{});
std::shared_ptr<Base> baseRes1{};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes1, StdSmartPtr{});
EXPECT_THAT(baseRes1.use_count(), Eq(2));
clearSharedState();
@@ -471,7 +469,7 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, CorrectlyManagesSameSharedObject) {
std::shared_ptr<Base> baseData1{new Derived{3, 78}};
std::shared_ptr<Base> baseData2{new Derived{55, 11}};
std::shared_ptr<Base> baseData21{baseData2};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData1, StdSmartPtr{});
ser.ext(baseData2, StdSmartPtr{});
ser.ext(baseData21, StdSmartPtr{});
@@ -479,7 +477,7 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, CorrectlyManagesSameSharedObject) {
std::shared_ptr<Base> baseRes1{};
std::shared_ptr<Base> baseRes2{};
std::shared_ptr<Base> baseRes21{};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes1, StdSmartPtr{});
des.ext(baseRes2, StdSmartPtr{});
des.ext(baseRes21, StdSmartPtr{});
@@ -502,7 +500,7 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FirstSharedThenWeakPtr) {
std::shared_ptr<Base> baseData1{new Derived{3, 78}};
std::weak_ptr<Base> baseData11{baseData1};
std::weak_ptr<Base> baseData12{baseData11};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData1, StdSmartPtr{});
ser.ext(baseData11, StdSmartPtr{});
ser.ext(baseData12, StdSmartPtr{});
@@ -510,7 +508,7 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FirstSharedThenWeakPtr) {
std::shared_ptr<Base> baseRes1{};
std::weak_ptr<Base> baseRes11{};
std::weak_ptr<Base> baseRes12{};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes1, StdSmartPtr{});
des.ext(baseRes11, StdSmartPtr{});
des.ext(baseRes12, StdSmartPtr{});
@@ -533,7 +531,7 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FirstWeakThenSharedPtr) {
std::shared_ptr<MyStruct1> baseData1{new MyStruct1{3, 78}};
std::weak_ptr<MyStruct1> baseData11{baseData1};
std::weak_ptr<MyStruct1> baseData2{};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData2, StdSmartPtr{});
ser.ext(baseData11, StdSmartPtr{});
ser.ext(baseData1, StdSmartPtr{});
@@ -541,7 +539,7 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FirstWeakThenSharedPtr) {
std::shared_ptr<MyStruct1> baseRes1{};
std::weak_ptr<MyStruct1> baseRes11{};
std::weak_ptr<MyStruct1> baseRes2{};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes2, StdSmartPtr{});
des.ext(baseRes11, StdSmartPtr{});
des.ext(baseRes1, StdSmartPtr{});
@@ -562,13 +560,13 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstPolymorphicData0Result1)
std::shared_ptr<Base> baseData1{};
std::weak_ptr<Base> baseData2{};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData2, StdSmartPtr{});
ser.ext(baseData1, StdSmartPtr{});
std::shared_ptr<Base> baseRes1{new Base{}};
std::weak_ptr<Base> baseRes2{baseRes1};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes2, StdSmartPtr{});
des.ext(baseRes1, StdSmartPtr{});
@@ -585,13 +583,13 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstNonPolymorphicData0Resul
std::shared_ptr<MyStruct2> baseData1{};
std::weak_ptr<MyStruct2> baseData2{};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData2, StdSmartPtr{});
ser.ext(baseData1, StdSmartPtr{});
std::shared_ptr<MyStruct2> baseRes1{new MyStruct2{MyStruct2::MyEnum::V4, {1, 87}}};
std::weak_ptr<MyStruct2> baseRes2{baseRes1};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes2, StdSmartPtr{});
des.ext(baseRes1, StdSmartPtr{});
@@ -610,7 +608,7 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FewPtrsAreEmpty) {
std::shared_ptr<Base> baseData2{};
std::weak_ptr<Base> baseData3{};
std::weak_ptr<Base> baseData11{baseData1};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData1, StdSmartPtr{});
ser.ext(baseData2, StdSmartPtr{});
ser.ext(baseData3, StdSmartPtr{});
@@ -620,7 +618,7 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FewPtrsAreEmpty) {
std::shared_ptr<Base> baseRes2{new Derived{3, 78}};
std::weak_ptr<Base> baseRes3{baseRes2};
std::weak_ptr<Base> baseRes11{};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes1, StdSmartPtr{});
des.ext(baseRes2, StdSmartPtr{});
des.ext(baseRes3, StdSmartPtr{});
@@ -641,11 +639,11 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FewPtrsAreEmpty) {
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsSameType) {
std::shared_ptr<Base> baseData1{new Derived{3, 78}};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData1, StdSmartPtr{});
std::shared_ptr<Base> baseRes1{new Derived{0, 0}};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes1, StdSmartPtr{});
clearSharedState();
@@ -658,11 +656,11 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsSameType) {
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsDifferentType) {
std::shared_ptr<Base> baseData1{new Derived{3, 78}};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData1, StdSmartPtr{});
std::shared_ptr<Base> baseRes1{new Base{}};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes1, StdSmartPtr{});
clearSharedState();
@@ -676,7 +674,7 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsDifferentType)
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenOnlyWeakPtrIsSerializedThenPointerCointextIsInvalid) {
std::shared_ptr<Base> tmp{new Derived{3, 78}};
std::weak_ptr<Base> baseData1{tmp};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData1, StdSmartPtr{});
EXPECT_FALSE(isPointerContextValid());
@@ -684,11 +682,11 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WhenOnlyWeakPtrIsSerializedThenPoint
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenOnlyWeakPtrIsDeserializedThenPointerCointextIsInvalid) {
std::shared_ptr<Base> baseData1{new Derived{3, 78}};
auto& ser = createSerializer();
auto ser = createSerializer();
ser.ext(baseData1, StdSmartPtr{});
std::weak_ptr<Base> baseRes1{};
auto& des = createDeserializer();
auto des = createDeserializer();
des.ext(baseRes1, StdSmartPtr{});
EXPECT_FALSE(isPointerContextValid());

View File

@@ -46,7 +46,6 @@ TEST(SerializeExtensionStdTuple, ValueTypesCanBeSerializedWithLambdaAndOrCallabl
std::tuple<float, int32_t> r1{};
SerializationContext ctx;
auto exec = [](auto& s, auto& o) {
using S = decltype(s);
s.ext(o, bitsery::ext::StdTuple{
[](auto& s1, float& o1) {
s1.value4b(o1);
@@ -54,8 +53,8 @@ TEST(SerializeExtensionStdTuple, ValueTypesCanBeSerializedWithLambdaAndOrCallabl
OverloadValue<int32_t, 4>{}
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
ctx.createSerializer().object(t1, exec);
ctx.createDeserializer().object(r1, exec);
EXPECT_THAT(t1, Eq(r1));
}
@@ -64,7 +63,6 @@ TEST(SerializeExtensionStdTuple, CanOverloadDefaultSerializeFunction) {
std::tuple<MyStruct1, MyStruct2> r1{};
SerializationContext ctx;
auto exec = [](auto& s, auto& o) {
using S = decltype(s);
s.ext(o, bitsery::ext::StdTuple{
[](auto& s1, MyStruct1& o1) {
s1.value4b(o1.i1);
@@ -72,8 +70,8 @@ TEST(SerializeExtensionStdTuple, CanOverloadDefaultSerializeFunction) {
},
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
ctx.createSerializer().object(t1, exec);
ctx.createDeserializer().object(r1, exec);
EXPECT_THAT(std::get<1>(t1), Eq(std::get<1>(r1)));
EXPECT_THAT(std::get<0>(t1).i1, Eq(std::get<0>(r1).i1));
EXPECT_THAT(std::get<0>(t1).i2, ::testing::Ne(std::get<0>(r1).i2));

View File

@@ -77,10 +77,8 @@ TEST(SerializeExtensionStdVariant, ValueTypesCanBeSerializedWithLambdaAndOrCalla
s.value4b(v);
};
auto& ser = ctx.createSerializer();
ser.ext(t1, bitsery::ext::StdVariant{fncFloat, OverloadValue<char, 1>{}});
auto& des = ctx.createDeserializer();
des.ext(r1, bitsery::ext::StdVariant{fncFloat, OverloadValue<char, 1>{}});
ctx.createSerializer().ext(t1, bitsery::ext::StdVariant{fncFloat, OverloadValue<char, 1>{}});
ctx.createDeserializer().ext(r1, bitsery::ext::StdVariant{fncFloat, OverloadValue<char, 1>{}});
EXPECT_THAT(t1, Eq(r1));
}
@@ -99,8 +97,8 @@ TEST(SerializeExtensionStdVariant, CanOverloadDefaultSerializationFunction) {
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
ctx.createSerializer().object(t1, exec);
ctx.createDeserializer().object(r1, exec);
EXPECT_THAT(std::get<1>(r1).i2, Eq(0));
}
@@ -135,8 +133,8 @@ TEST(SerializeExtensionStdVariant, CanUseNonDefaultConstructableTypes) {
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
ctx.createSerializer().object(t1, exec);
ctx.createDeserializer().object(r1, exec);
EXPECT_THAT(t1, Eq(r1));
}
@@ -156,8 +154,8 @@ TEST(SerializeExtensionStdVariant, CorrectlyHandleMonoState) {
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
ctx.createSerializer().object(t1, exec);
ctx.createDeserializer().object(r1, exec);
EXPECT_THAT(t1, Eq(r1));
std::variant<std::monostate> t2{};

View File

@@ -206,4 +206,5 @@ TEST(SerializeExtensionValueRange, WhenDataIsInvalidThenReturnMinimumRangeValue)
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res1, Eq(4));
EXPECT_THAT(ctx.br->error(), Eq(bitsery::ReaderError::InvalidData));
}

View File

@@ -69,12 +69,12 @@ void serialize(S& s, X& o)
template <typename S>
void serialize(S& s, Y& o)
{
auto writeInt = [&s]( int& v) { s.template value<sizeof(v)>(v); };
auto writeInt = [](S& s, int& v) { s.template value<sizeof(v)>(v); };
s.template text<1>(o.s, 10000);
s.template value<sizeof(o.y)>(o.y);
s.container(o.arr, writeInt);
s.container(o.carr, writeInt);
s.container(o.vx, 10000, [&s](X& v) { s.object(v); });
s.container(o.vx, 10000, [](S& s, X& v) { s.object(v); });
}
@@ -99,7 +99,7 @@ TEST(SerializeObject, GeneralConceptTest) {
z.x = X{ 234 };
auto& ser = ctx.createSerializer();
auto ser = ctx.createSerializer();
ser.object(y);
ser.object(z);
@@ -107,7 +107,7 @@ TEST(SerializeObject, GeneralConceptTest) {
Y yres{};
Z zres{};
auto& des = ctx.createDeserializer();
auto des = ctx.createDeserializer();
des.object(yres);
des.object(zres);

View File

@@ -28,9 +28,11 @@ using testing::Eq;
bool SerializeDeserializeContainerSize(SerializationContext& ctx, const size_t size) {
std::vector<char> t1(size);
ctx.createSerializer().container(t1, size+1, []( char& ){});
auto ser = ctx.createSerializer();
ser.container(t1, size+1, [](decltype(ser)& , char& ){});
t1.clear();
ctx.createDeserializer().container(t1, size+1, []( char& ){});
auto des = ctx.createDeserializer();
des.container(t1, size+1, [](decltype(des)&, char& ){});
return t1.size() == size;
}

View File

@@ -86,10 +86,6 @@ void serialize(S&s, MyStruct2& o) {
s.object(o.s1);
}
struct SessionsEnabledConfig: public bitsery::DefaultConfig {
static constexpr bool BufferSessionsEnabled = true;
};
using Buffer = std::vector<char>;
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
@@ -100,34 +96,59 @@ using Reader = bitsery::AdapterReader<InputAdapter, bitsery::DefaultConfig>;
template <typename Config, typename Context>
class BasicSerializationContext {
public:
using TWriter = bitsery::AdapterWriter<OutputAdapter, Config>;
using TReader = bitsery::AdapterReader<InputAdapter, Config>;
using TSerializer = bitsery::BasicSerializer<TWriter, Context>;
using TDeserializer = bitsery::BasicDeserializer<TReader, Context>;
using TWriter = bitsery::AdapterWriter<OutputAdapter, Config, Context>;
using TReader = bitsery::AdapterReader<InputAdapter, Config, Context>;
using TSerializer = bitsery::BasicSerializer<TWriter>;
using TDeserializer = bitsery::BasicDeserializer<TReader>;
using TSerializerBPEnabled = typename TSerializer::BPEnabledType;
using TDeserializerBPEnabled = typename TDeserializer::BPEnabledType;
Buffer buf{};
std::unique_ptr<TSerializer> ser{};
std::unique_ptr<bitsery::BasicDeserializer<TReader, Context>> des{};
TWriter* bw{};
TReader* br{};
std::unique_ptr<TWriter> bw{};
std::unique_ptr<TReader> br{};
TSerializer& createSerializer(Context* ctx = nullptr) {
if (!ser) {
ser = std::unique_ptr<TSerializer>(new TSerializer(OutputAdapter{buf}, ctx));
bw = &bitsery::AdapterAccess::getWriter(*ser);
template <typename T=Context, typename std::enable_if<std::is_void<T>::value>::type* = nullptr>
TSerializer createSerializer() {
if (!bw) {
bw = std::unique_ptr<TWriter>(new TWriter{OutputAdapter{buf}});
}
return *ser;
};
return TSerializer{*bw};
}
TDeserializer & createDeserializer(Context* ctx = nullptr) {
bw->flush();
if (!des) {
des = std::unique_ptr<TDeserializer>(
new TDeserializer(InputAdapter{buf.begin(), bw->writtenBytesCount()}, ctx));
br = &bitsery::AdapterAccess::getReader(*des);
template <typename T=Context>
TSerializer createSerializer(typename std::enable_if<!std::is_void<T>::value, T>::type& ctx) {
if (!bw) {
bw = std::unique_ptr<TWriter>(new TWriter{OutputAdapter{buf}, ctx});
}
return *des;
};
return TSerializer{*bw};
}
template <typename T=Context, typename std::enable_if<std::is_void<T>::value>::type* = nullptr>
TDeserializer createDeserializer() {
size_t writtenBytes = 0;
if (bw) {
bw->flush();
writtenBytes = bw->writtenBytesCount();
}
if (!br) {
br = std::unique_ptr<TReader>(new TReader{InputAdapter{buf.begin(), writtenBytes}});
}
return TDeserializer{*br};
}
template <typename T=Context>
TDeserializer createDeserializer(typename std::enable_if<!std::is_void<T>::value, T>::type& ctx) {
size_t writtenBytes = 0;
if (bw) {
bw->flush();
writtenBytes = bw->writtenBytesCount();
}
if (!br) {
br = std::unique_ptr<TReader>(new TReader{InputAdapter{buf.begin(), writtenBytes}, ctx});
}
return TDeserializer{*br};
}
size_t getBufferSize() const {
return bw->writtenBytesCount();

View File

@@ -118,4 +118,12 @@ TEST(SerializeText, WhenCArrayNotNullterminatedThenAssert) {
t1[CARR_LENGTH-1] = 'x';
EXPECT_DEATH(ctx.createSerializer().text<2>(t1), "");
}
#endif
#endif
TEST(SerializeText, WhenContainerOrTextSizeIsMoreThanMaxThenInvalidDataError) {
SerializationContext ctx;
std::string tmp = "larger text then allowed";
ctx.createSerializer().text1b(tmp,100);
ctx.createDeserializer().text1b(tmp, 10);
EXPECT_THAT(ctx.br->error(), Eq(bitsery::ReaderError::InvalidData));
}