зеркало из https://github.com/microsoft/IPC.Bond.git
461 строка
15 KiB
C++
461 строка
15 KiB
C++
#include "stdafx.h"
|
|
#include "IPC/Bond/OutputBuffer.h"
|
|
#include "IPC/detail/RandomString.h"
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
|
|
using namespace IPC::Bond;
|
|
using IPC::detail::GenerateRandomString;
|
|
using IPC::SharedMemory;
|
|
using IPC::create_only;
|
|
|
|
|
|
BOOST_AUTO_TEST_SUITE(OutputBufferTests)
|
|
|
|
static_assert(!std::is_copy_constructible<DefaultOutputBuffer>::value, "OutputBuffer should not be copy constructible.");
|
|
static_assert(!std::is_copy_assignable<DefaultOutputBuffer>::value, "OutputBuffer should not be copy assignable.");
|
|
static_assert(std::is_move_constructible<DefaultOutputBuffer>::value, "OutputBuffer should be move constructible.");
|
|
static_assert(std::is_move_assignable<DefaultOutputBuffer>::value, "OutputBuffer should be move assignable.");
|
|
|
|
template <typename Function, std::size_t... I>
|
|
void ForEach(Function&& func, std::index_sequence<I...>)
|
|
{
|
|
auto dummy = { (func(std::integral_constant<std::size_t, I>{}), 0)... };
|
|
(void)dummy;
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(WriteArithmeticTypesTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
DefaultOutputBuffer output{ pool, 3 };
|
|
|
|
auto values = std::make_tuple(
|
|
static_cast<std::int8_t>(1),
|
|
static_cast<std::int16_t>(2),
|
|
static_cast<std::int32_t>(3),
|
|
static_cast<std::int64_t>(4),
|
|
static_cast<std::uint8_t>(5),
|
|
static_cast<std::uint16_t>(6),
|
|
static_cast<std::uint32_t>(7),
|
|
static_cast<std::uint64_t>(8),
|
|
static_cast<float>(9.10),
|
|
static_cast<double>(11.12));
|
|
|
|
std::size_t size = 0;
|
|
|
|
ForEach(
|
|
[&](auto index)
|
|
{
|
|
const auto& value = std::get<index.value>(values);
|
|
(void)index;
|
|
|
|
output.Write(value);
|
|
size += sizeof(decltype(value));
|
|
},
|
|
std::make_index_sequence<std::tuple_size<decltype(values)>::value>{});
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == size);
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
|
|
|
|
auto ptr = buffer.begin()->data();
|
|
|
|
ForEach(
|
|
[&](auto index)
|
|
{
|
|
const auto& value = std::get<index.value>(values);
|
|
(void)index;
|
|
|
|
BOOST_TEST(std::memcmp(&value, ptr, sizeof(value)) == 0);
|
|
ptr += sizeof(decltype(value));
|
|
},
|
|
std::make_index_sequence<std::tuple_size<decltype(values)>::value>{});
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(WriteRawBytesTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
DefaultOutputBuffer output{ pool, 2 };
|
|
|
|
const char data[] = "Data";
|
|
|
|
output.Write(data, sizeof(data));
|
|
output.Write(data, sizeof(data));
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == 2 * sizeof(data));
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
|
|
|
|
auto ptr = buffer.begin()->data();
|
|
|
|
BOOST_TEST(std::memcmp(ptr, data, sizeof(data)) == 0);
|
|
BOOST_TEST(std::memcmp(ptr + sizeof(data), data, sizeof(data)) == 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(WriteBufferTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
DefaultOutputBuffer output{ pool, 3 };
|
|
|
|
const char data[] = "Data";
|
|
|
|
output.Write(data, sizeof(data));
|
|
|
|
DefaultBufferPool::ConstBlob b1;
|
|
{
|
|
auto blob = pool->TakeBlob();
|
|
blob->resize(10);
|
|
b1 = std::move(blob);
|
|
}
|
|
|
|
DefaultBufferPool::ConstBlob b2;
|
|
{
|
|
auto blob = pool->TakeBlob();
|
|
blob->resize(20);
|
|
b2 = std::move(blob);
|
|
}
|
|
|
|
{
|
|
auto buffer = pool->TakeBuffer();
|
|
buffer->push_back(b1);
|
|
buffer->push_back(DefaultBufferPool::ConstBlob{ pool->TakeBlob() });
|
|
buffer->push_back(b2);
|
|
buffer->push_back(DefaultBufferPool::ConstBlob{});
|
|
|
|
output.Write(DefaultBufferPool::ConstBuffer{ std::move(buffer) });
|
|
}
|
|
|
|
auto otherPool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
{
|
|
auto buffer = otherPool->TakeBuffer();
|
|
auto blob = otherPool->TakeBlob();
|
|
blob->resize(sizeof(data), boost::container::default_init);
|
|
std::strcpy(blob->data(), data);
|
|
buffer->push_back(std::move(blob));
|
|
|
|
output.Write(DefaultBufferPool::ConstBuffer{ std::move(buffer) });
|
|
}
|
|
|
|
output.Write(data, sizeof(data));
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == sizeof(data) + 10 + 20 + 2 * sizeof(data));
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 4);
|
|
|
|
auto blob = buffer.begin();
|
|
BOOST_TEST(blob->size() == sizeof(data));
|
|
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
|
|
|
|
++blob;
|
|
BOOST_TEST(blob->size() == b1.size());
|
|
BOOST_TEST(blob->data() == b1.data());
|
|
|
|
++blob;
|
|
BOOST_TEST(blob->size() == b2.size());
|
|
BOOST_TEST(blob->data() == b2.data());
|
|
|
|
++blob;
|
|
BOOST_TEST(blob->size() == 2 * sizeof(data));
|
|
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
|
|
BOOST_TEST(std::memcmp(blob->data() + sizeof(data), data, sizeof(data)) == 0);
|
|
|
|
BOOST_TEST((++blob == buffer.end()));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(WriteBufferRangeTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
|
|
DefaultBufferPool::ConstBlob constBlob;
|
|
DefaultBufferPool::ConstBuffer constBuffer;
|
|
|
|
const char data[] = "Data!";
|
|
{
|
|
auto blob = pool->TakeBlob();
|
|
blob->resize(sizeof(data), boost::container::default_init);
|
|
std::strcpy(blob->data(), data);
|
|
|
|
constBlob = std::move(blob);
|
|
|
|
auto buffer = pool->TakeBuffer();
|
|
buffer->push_back(constBlob);
|
|
buffer->push_back(constBlob);
|
|
buffer->push_back(constBlob);
|
|
|
|
constBuffer = std::move(buffer);
|
|
}
|
|
|
|
constexpr std::size_t leftOffset = 2, rightOffset = 4;
|
|
|
|
{
|
|
DefaultOutputBuffer output{ pool, 4 };
|
|
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), leftOffset, std::next(constBuffer.begin()), 0 });
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == constBlob.size() - leftOffset);
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
|
|
|
|
auto blob = buffer.begin();
|
|
BOOST_TEST(blob->size() == constBlob.size() - leftOffset);
|
|
BOOST_TEST(blob->data() == constBlob.data() + leftOffset);
|
|
|
|
BOOST_TEST((++blob == buffer.end()));
|
|
}
|
|
{
|
|
DefaultOutputBuffer output{ pool, 3 };
|
|
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), leftOffset, constBuffer.begin(), rightOffset });
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == rightOffset - leftOffset);
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
|
|
|
|
auto blob = buffer.begin();
|
|
BOOST_TEST(blob->size() == rightOffset - leftOffset);
|
|
BOOST_TEST(blob->data() == constBlob.data() + leftOffset);
|
|
|
|
BOOST_TEST((++blob == buffer.end()));
|
|
}
|
|
{
|
|
DefaultOutputBuffer output{ pool, 2 };
|
|
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), leftOffset, std::next(constBuffer.begin()), rightOffset });
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == constBlob.size() - leftOffset + rightOffset);
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 2);
|
|
|
|
auto blob = buffer.begin();
|
|
BOOST_TEST(blob->size() == constBlob.size() - leftOffset);
|
|
BOOST_TEST(blob->data() == constBlob.data() + leftOffset);
|
|
|
|
++blob;
|
|
BOOST_TEST(blob->size() == rightOffset);
|
|
BOOST_TEST(blob->data() == constBlob.data());
|
|
|
|
BOOST_TEST((++blob == buffer.end()));
|
|
}
|
|
{
|
|
DefaultOutputBuffer output{ pool, 2 };
|
|
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), leftOffset, constBuffer.end(), 0 });
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == 3 * constBlob.size() - leftOffset);
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 3);
|
|
|
|
auto blob = buffer.begin();
|
|
BOOST_TEST(blob->size() == constBlob.size() - leftOffset);
|
|
BOOST_TEST(blob->data() == constBlob.data() + leftOffset);
|
|
|
|
++blob;
|
|
BOOST_TEST(blob->size() == constBlob.size());
|
|
BOOST_TEST(blob->data() == constBlob.data());
|
|
|
|
++blob;
|
|
BOOST_TEST(blob->size() == constBlob.size());
|
|
BOOST_TEST(blob->data() == constBlob.data());
|
|
|
|
BOOST_TEST((++blob == buffer.end()));
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(WriteBondBlobWithPrivateMemoryTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
DefaultOutputBuffer output{ pool, 1 };
|
|
|
|
const char data[] = "Data";
|
|
|
|
output.Write(static_cast<short>(1));
|
|
output.Write(bond::blob{ data, sizeof(data) });
|
|
output.Write(static_cast<int>(2));
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == sizeof(data) + sizeof(short) + sizeof(int));
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 1);
|
|
|
|
BOOST_TEST(buffer.size() == buffer.begin()->size());
|
|
|
|
auto ptr = buffer.begin()->data();
|
|
BOOST_TEST(*reinterpret_cast<const short*>(ptr) == 1);
|
|
|
|
ptr += sizeof(short);
|
|
BOOST_TEST(std::memcmp(ptr, data, sizeof(data)) == 0);
|
|
|
|
ptr += sizeof(data);
|
|
BOOST_TEST(*reinterpret_cast<const int*>(ptr) == 2);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(WriteBondBlobWithSharedMemoryTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
DefaultOutputBuffer output{ pool, 2 };
|
|
|
|
output.Write(static_cast<short>(1));
|
|
|
|
const char data[] = "Data";
|
|
{
|
|
auto blob = pool->TakeBlob();
|
|
blob->resize(sizeof(data), boost::container::default_init);
|
|
std::strcpy(blob->data(), data);
|
|
|
|
output.Write(BlobCast(DefaultBufferPool::ConstBlob{ std::move(blob) }, pool->GetMemory()));
|
|
}
|
|
|
|
output.Write(static_cast<int>(2));
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == sizeof(data) + sizeof(short) + sizeof(int));
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 3);
|
|
|
|
auto blob = buffer.begin();
|
|
BOOST_TEST(blob->size() == sizeof(short));
|
|
BOOST_TEST(*reinterpret_cast<const short*>(blob->data()) == 1);
|
|
|
|
++blob;
|
|
BOOST_TEST(blob->size() == sizeof(data));
|
|
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
|
|
|
|
++blob;
|
|
BOOST_TEST(blob->size() == sizeof(int));
|
|
BOOST_TEST(*reinterpret_cast<const int*>(blob->data()) == 2);
|
|
|
|
BOOST_TEST((++blob == buffer.end()));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(WriteEmptyDataTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
|
|
{
|
|
DefaultOutputBuffer output{ pool };
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(!!buffer);
|
|
BOOST_TEST(buffer.size() == 0);
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 0);
|
|
}
|
|
|
|
DefaultOutputBuffer output{ pool };
|
|
|
|
output.Write(bond::blob{});
|
|
output.Write(DefaultBufferPool::ConstBuffer{});
|
|
output.Write(DefaultBufferPool::ConstBuffer::Range{});
|
|
|
|
{
|
|
auto buffer = pool->TakeBuffer();
|
|
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
|
|
|
|
output.Write(constBuffer);
|
|
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.end(), 0 });
|
|
}
|
|
{
|
|
auto buffer = pool->TakeBuffer();
|
|
buffer->push_back(DefaultBufferPool::ConstBlob{});
|
|
DefaultBufferPool::ConstBuffer constBuffer{ std::move(buffer) };
|
|
|
|
output.Write(constBuffer);
|
|
output.Write(DefaultBufferPool::ConstBuffer::Range{ constBuffer, constBuffer.begin(), 0, constBuffer.end(), 0 });
|
|
}
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(!!buffer);
|
|
BOOST_TEST(buffer.size() == 0);
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(FlushTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
DefaultOutputBuffer output{ pool };
|
|
|
|
const char data[] = "Data";
|
|
const auto& buffer = output.GetBuffer();
|
|
|
|
output.Write(data, sizeof(data));
|
|
BOOST_TEST(buffer->empty());
|
|
|
|
output.Flush();
|
|
BOOST_TEST(buffer->size() == 1);
|
|
BOOST_TEST(std::memcmp(buffer->front().data(), data, sizeof(data)) == 0);
|
|
|
|
output.Write(data, sizeof(data));
|
|
BOOST_TEST(buffer->size() == 1);
|
|
|
|
output.Flush();
|
|
BOOST_TEST(buffer->size() == 2);
|
|
BOOST_TEST(std::memcmp(buffer->back().data(), data, sizeof(data)) == 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(GetBufferTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
DefaultOutputBuffer output{ pool };
|
|
const auto& constOutput = output;
|
|
|
|
BOOST_TEST(output.GetBufferPool() == pool);
|
|
|
|
const char data[] = "Data";
|
|
|
|
BOOST_CHECK_NO_THROW(constOutput.GetBuffer());
|
|
BOOST_CHECK_NO_THROW(output.GetBuffer());
|
|
BOOST_TEST(&output.GetBuffer() == &constOutput.GetBuffer());
|
|
BOOST_TEST(output.GetBuffer()->empty());
|
|
|
|
output.Write(data, sizeof(data));
|
|
|
|
BOOST_CHECK_THROW(constOutput.GetBuffer(), std::exception);
|
|
BOOST_CHECK_NO_THROW(output.GetBuffer());
|
|
BOOST_CHECK_NO_THROW(constOutput.GetBuffer());
|
|
|
|
output.Write(data, sizeof(data));
|
|
|
|
BOOST_CHECK_THROW(constOutput.GetBuffer(), std::exception);
|
|
|
|
auto buffer = std::move(output).GetBuffer();
|
|
|
|
BOOST_TEST(buffer.size() == 2 * sizeof(data));
|
|
BOOST_TEST(std::distance(buffer.begin(), buffer.end()) == 2);
|
|
|
|
auto blob = buffer.begin();
|
|
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
|
|
|
|
++blob;
|
|
BOOST_TEST(std::memcmp(blob->data(), data, sizeof(data)) == 0);
|
|
|
|
BOOST_TEST((++blob == buffer.end()));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(CreateOutputBufferTest)
|
|
{
|
|
auto pool = std::make_shared<DefaultBufferPool>(std::make_shared<SharedMemory>(create_only, GenerateRandomString().c_str(), 1024 * 1024));
|
|
DefaultOutputBuffer output{ pool };
|
|
|
|
output.Write(1);
|
|
|
|
{
|
|
const auto& buffer = output.GetBuffer();
|
|
BOOST_TEST(!!buffer);
|
|
BOOST_TEST(buffer->size() == 1);
|
|
}
|
|
|
|
auto output2 = CreateOutputBuffer(output);
|
|
|
|
{
|
|
const auto& buffer = output2.GetBuffer();
|
|
BOOST_TEST(!!buffer);
|
|
BOOST_TEST(buffer->empty());
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|