tile/tile/base/buffer_test.cc
2024-12-19 14:39:59 +08:00

341 lines
9.7 KiB
C++

#include "tile/base/buffer.h"
#include "tile/base/slice.h"
#include "tile/init/override_flag.h"
#include "gtest/gtest.h"
#include <string>
#define BUFFER_BLOCK_SIZE "4K"
TILE_OVERRIDE_FLAG(tile_buffer_block_size, BUFFER_BLOCK_SIZE);
namespace tile {
namespace {
PolymorphicBuffer
MakeNativeBuffer(Slice s)
{
auto buffer = MakeNativeBufferBlock();
memcpy(buffer->mutable_data(), s.data(), s.size());
return PolymorphicBuffer(buffer, 0, s.size());
}
}// namespace
TEST(CreateBufferSlow, All)
{
static const auto kData = Slice("sadfas234sadf-/+8sdaf sd f~!#");
auto nb = CreateBufferSlow(kData);
ASSERT_EQ(kData, nb.FirstContiguous().data());
ASSERT_EQ(kData, FlattenSlow(nb));
}
TEST(NoncontiguousBuffer, Cut)
{
NoncontiguousBuffer nb;
nb.Append(CreateBufferSlow("asdf"));
auto r = nb.Cut(3);
ASSERT_EQ(1, nb.ByteSize());
ASSERT_EQ("f", FlattenSlow(nb));
ASSERT_EQ(3, r.ByteSize());
ASSERT_EQ("asd", FlattenSlow(r));
}
TEST(NoncontiguousBuffer, Cut1)
{
NoncontiguousBuffer nb;
nb.Append(CreateBufferSlow("asdf"));
auto r = nb.Cut(4);
ASSERT_TRUE(nb.Empty());
ASSERT_EQ(4, r.ByteSize());
}
TEST(NoncontiguousBuffer, Cut2)
{
NoncontiguousBuffer nb;
nb.Append(MakeNativeBuffer("asdf"));
nb.Append(MakeNativeBuffer("asdf"));
auto r = nb.Cut(4);
ASSERT_EQ(4, nb.ByteSize());
ASSERT_EQ(4, r.ByteSize());
}
TEST(NoncontiguousBuffer, Cut3)
{
NoncontiguousBuffer nb;
nb.Append(MakeNativeBuffer("asdf"));
nb.Append(MakeNativeBuffer("asdf"));
auto r = nb.Cut(8);
ASSERT_TRUE(nb.Empty());
ASSERT_EQ(8, r.ByteSize());
}
TEST(NoncontiguousBuffer, Cut4)
{
auto nb = CreateBufferSlow("asdfasf2345sfsdfdf");
auto nb2 = nb;
ASSERT_EQ(FlattenSlow(nb), FlattenSlow(nb2));
NoncontiguousBuffer splited;
splited.Append(nb.Cut(1));
splited.Append(nb.Cut(2));
splited.Append(nb.Cut(3));
splited.Append(nb.Cut(4));
splited.Append(std::move(nb));
ASSERT_EQ(FlattenSlow(nb2), FlattenSlow(splited));
}
TEST(NoncontiguousBuffer, Skip)
{
NoncontiguousBuffer splited;
splited.Append(CreateBufferSlow("asdf"));
splited.Append(CreateBufferSlow("asdf"));
splited.Append(CreateBufferSlow("asdf"));
splited.Append(CreateBufferSlow("asdf"));
splited.Append(CreateBufferSlow("asdf"));
splited.Append(CreateBufferSlow("asdf"));
splited.Append(CreateBufferSlow("asdf"));
splited.Append(CreateBufferSlow("asdf"));
splited.Skip(32);
ASSERT_EQ(0, splited.ByteSize());
}
TEST(NoncontiguousBuffer, Skip2)
{
NoncontiguousBuffer buffer;
EXPECT_TRUE(buffer.Empty());
buffer.Skip(0);// Don't crash.
EXPECT_TRUE(buffer.Empty());
}
TEST(NoncontiguousBuffer, FlattenSlow)
{
NoncontiguousBuffer nb;
nb.Append(MakeNativeBuffer("asd4234"));
nb.Append(MakeNativeBuffer("aXsdfsadfasdf2342"));
ASSERT_EQ("asd4234aXs", FlattenSlow(nb, 10));
}
TEST(NoncontiguousBuffer, FlattenToSlow)
{
struct C {
std::uint64_t ll;
int i;
bool f;
};
NoncontiguousBuffer nb;
nb.Append(MakeNativeBuffer(Slice("\x12\x34\x56\x78\x9a\xbc\xde\xf0", 8)));
nb.Append(MakeNativeBuffer(Slice("\x12\x34\x56\x78", 4)));
nb.Append(MakeNativeBuffer(Slice("\x1", 1)));
nb.Append(MakeNativeBuffer(Slice("\x00\x00\x00", 3)));// Padding
C c;
FlattenToSlow(nb, &c, sizeof(C));
ASSERT_EQ(0xf0debc9a78563412, c.ll);
ASSERT_EQ(0x78563412, c.i);
ASSERT_EQ(true, c.f);
}
TEST(NoncontiguousBuffer, FlattenSlowUntil)
{
NoncontiguousBuffer nb;
nb.Append(MakeNativeBuffer("asd4234"));
nb.Append(MakeNativeBuffer("aXsdfsadfasdf2342"));
ASSERT_EQ("asd4234aX", FlattenSlowUntil(nb, "aX"));
ASSERT_EQ("asd4", FlattenSlowUntil(nb, "4"));
ASSERT_EQ("asd4234aXsdfsadfasdf2342", FlattenSlowUntil(nb, "2342"));
ASSERT_EQ("asd42", FlattenSlowUntil(nb, "z", 5));
ASSERT_EQ("asd42", FlattenSlowUntil(nb, "3", 5));
ASSERT_EQ("asd42", FlattenSlowUntil(nb, "2", 5));
ASSERT_EQ("asd4", FlattenSlowUntil(nb, "4", 5));
}
TEST(NoncontiguousBuffer, FlattenSlowUntil2)
{
auto nb = CreateBufferSlow(
"HTTP/1.1 200 OK\r\nRpc-SeqNo: 14563016719\r\nRpc-Error-Code: "
"0\r\nRpc-Error-Reason: The operation completed "
"successfully.\r\nContent-Type: "
"application/x-protobuf\r\nContent-Length: 0\r\n\r\nHTTP/1.1 200 "
"OK\r\nRpc-Seq");
ASSERT_EQ("HTTP/1.1 200 OK\r\nRpc-SeqNo: 14563016719\r\nRpc-Error-Code: "
"0\r\nRpc-Error-Reason: The operation completed "
"successfully.\r\nContent-Type: "
"application/x-protobuf\r\nContent-Length: 0\r\n\r\n",
FlattenSlowUntil(nb, "\r\n\r\n"));
}
TEST(NoncontiguousBuffer, FlattenSlowUntil3)
{
NoncontiguousBuffer nb;
nb.Append(MakeNativeBuffer("asd4234"));
nb.Append(MakeNativeBuffer("aXsdfsadfasdf2342"));
ASSERT_EQ("asd4234aX", FlattenSlowUntil(nb, "aX"));
ASSERT_EQ("asd4", FlattenSlowUntil(nb, "4"));
ASSERT_EQ("asd4234aX", FlattenSlowUntil(nb, "4aX"));
}
TEST(NoncontiguousBuffer, FlattenSlowUntil4)
{
NoncontiguousBuffer nb;
nb.Append(MakeNativeBuffer("AB"));
nb.Append(MakeNativeBuffer("CDEFGGGGHHHH"));
ASSERT_EQ("ABCDEFGGGG", FlattenSlowUntil(nb, "GGGG"));
}
TEST(NoncontiguousBufferBuilder, Append)
{
NoncontiguousBufferBuilder nbb;
nbb.Append(MakeForeignBuffer(""));
nbb.Append(MakeForeignBuffer("small"));
nbb.Append(MakeForeignBuffer(std::string(8192, 'a')));
nbb.Append(CreateBufferSlow(""));
nbb.Append(CreateBufferSlow("small"));
nbb.Append(CreateBufferSlow(std::string(8192, 'a')));
auto nb = nbb.DestructiveGet();
EXPECT_EQ("small" + std::string(8192, 'a') + "small" + std::string(8192, 'a'), FlattenSlow(nb));
}
TEST(NoncontiguousBufferBuilder, Reserve)
{
auto temp_block = MakeNativeBufferBlock();
auto max_bytes = temp_block->size();
NoncontiguousBufferBuilder nbb;
auto ptr = nbb.data();
auto ptr2 = nbb.Reserve(10);
ASSERT_EQ(ptr, ptr2);
ASSERT_EQ(ptr + 10, nbb.data());
nbb.Append(std::string(max_bytes - 10 - 1, 'a'));
ptr = nbb.data();
ptr2 = nbb.Reserve(1);// Last byte in the block.
ASSERT_EQ(ptr, ptr2);
ASSERT_EQ(max_bytes, nbb.SizeAvailable());
nbb.Append(std::string(max_bytes - 1, 'a'));
ptr = nbb.data();
ptr2 = nbb.Reserve(2);
ASSERT_NE(ptr, ptr2);
ASSERT_EQ(ptr2 + 2, nbb.data());
}
TEST(NoncontiguousBufferBuilder, DestructiveGet1)
{
NoncontiguousBufferBuilder nbb;
nbb.Append("asdf1234", 6);
nbb.Append("1122", 4);
ASSERT_EQ("asdf12"
"1122",
FlattenSlow(nbb.DestructiveGet()));
}
TEST(NoncontiguousBufferBuilder, DestructiveGet2)
{
NoncontiguousBufferBuilder nbb;
nbb.Append("aabbccd");
ASSERT_EQ("aabbccd", FlattenSlow(nbb.DestructiveGet()));
}
TEST(NoncontiguousBufferBuilder, DestructiveGet3)
{
NoncontiguousBufferBuilder nbb;
nbb.Append(std::string(1000000, 'A'));
ASSERT_EQ(std::string(1000000, 'A'), FlattenSlow(nbb.DestructiveGet()));
}
TEST(NoncontiguousBufferBuilder, DestructiveGet4)
{
NoncontiguousBufferBuilder nbb;
nbb.Append('c');
ASSERT_EQ("c", FlattenSlow(nbb.DestructiveGet()));
}
TEST(NoncontiguousBufferBuilder, DestructiveGet5)
{
NoncontiguousBufferBuilder nbb;
nbb.Append(CreateBufferSlow("c"));
ASSERT_EQ("c", FlattenSlow(nbb.DestructiveGet()));
}
TEST(NoncontiguousBufferBuilder, DestructiveGet6)
{
NoncontiguousBufferBuilder nbb;
nbb.Append(Slice("11"), Slice("2"), std::string("3"), std::string("45"), Slice("6"));
nbb.Append("1122", 4);
ASSERT_EQ("11234561122", FlattenSlow(nbb.DestructiveGet()));
}
TEST(MakeReferencingBuffer, Simple)
{
NoncontiguousBufferBuilder nbb;
nbb.Append(MakeReferencingBuffer("abcdefg", 7));
EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet()));
}
TEST(MakeReferencingBuffer, WithCallbackSmallBufferOptimized)
{
int x = 0;
NoncontiguousBufferBuilder nbb;
nbb.Append("aaa", 3);
// Small buffers are copied by `Append` and freed immediately.
nbb.Append(MakeReferencingBuffer("abcdefg", 7, [&] { ++x; }));
// Therefore the callback should have fired on return of `Append`.
EXPECT_EQ(1, x);
auto buffer = nbb.DestructiveGet();
EXPECT_EQ("aaaabcdefg", FlattenSlow(buffer));
}
TEST(MakeReferencingBuffer, WithCallback)
{
static const std::string kBuffer(12345, 'a');
int x = 0;
{
NoncontiguousBufferBuilder nbb;
nbb.Append("aaa", 3);
nbb.Append(MakeReferencingBuffer(kBuffer.data(), 1024, [&] { ++x; }));
EXPECT_EQ(0, x);
auto buffer = nbb.DestructiveGet();
EXPECT_EQ(0, x);
EXPECT_EQ("aaa" + kBuffer.substr(0, 1024), FlattenSlow(buffer));
}
EXPECT_EQ(1, x);
}
TEST(MakeForeignBuffer, String)
{
NoncontiguousBufferBuilder nbb;
nbb.Append(MakeForeignBuffer(std::string("abcdefg")));
EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet()));
}
TEST(MakeForeignBuffer, VectorOfChar)
{
std::vector<char> data{'a', 'b', 'c', 'd', 'e', 'f', 'g'};
NoncontiguousBufferBuilder nbb;
nbb.Append(MakeForeignBuffer(std::move(data)));
EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet()));
}
// TEST(MakeForeignBuffer, VectorOfBytes) {
// std::vector<std::byte> data;
// data.resize(7);
// memcpy(data.data(), "abcdefg", 7);
// NoncontiguousBufferBuilder nbb;
// nbb.Append(MakeForeignBuffer(std::move(data)));
// EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet()));
// }
TEST(MakeForeignBuffer, VectorOfUInt8)
{
std::vector<std::uint8_t> data;
data.resize(7);
memcpy(data.data(), "abcdefg", 7);
NoncontiguousBufferBuilder nbb;
nbb.Append(MakeForeignBuffer(std::move(data)));
EXPECT_EQ("abcdefg", FlattenSlow(nbb.DestructiveGet()));
}
}// namespace tile