blob: 6a90fbe66aea2e0ff6b69b374bc2d9f5ddb20877 [file] [log] [blame]
#include "quiche/http2/adapter/chunked_buffer.h"
#include <algorithm>
#include <initializer_list>
#include <memory>
#include <string>
#include <utility>
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "quiche/common/platform/api/quiche_test.h"
namespace http2 {
namespace adapter {
namespace {
constexpr absl::string_view kLoremIpsum =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua.";
struct DataAndSize {
std::unique_ptr<char[]> data;
size_t size;
};
DataAndSize MakeDataAndSize(absl::string_view source) {
auto data = std::unique_ptr<char[]>(new char[source.size()]);
std::copy(source.begin(), source.end(), data.get());
return {std::move(data), source.size()};
}
TEST(ChunkedBufferTest, Empty) {
ChunkedBuffer buffer;
EXPECT_TRUE(buffer.Empty());
buffer.Append("some data");
EXPECT_FALSE(buffer.Empty());
buffer.RemovePrefix(9);
EXPECT_TRUE(buffer.Empty());
}
TEST(ChunkedBufferTest, ReusedAfterEmptied) {
ChunkedBuffer buffer;
buffer.Append("some data");
buffer.RemovePrefix(9);
buffer.Append("different data");
EXPECT_EQ("different data", buffer.GetPrefix());
}
TEST(ChunkedBufferTest, LargeAppendAfterEmptied) {
ChunkedBuffer buffer;
buffer.Append("some data");
EXPECT_THAT(buffer.GetPrefix(), testing::StartsWith("some data"));
buffer.RemovePrefix(9);
auto more_data =
MakeDataAndSize(absl::StrCat("different data", std::string(2048, 'x')));
buffer.Append(std::move(more_data.data), more_data.size);
EXPECT_THAT(buffer.GetPrefix(), testing::StartsWith("different data"));
}
TEST(ChunkedBufferTest, LargeAppends) {
ChunkedBuffer buffer;
buffer.Append(std::string(500, 'a'));
buffer.Append(std::string(2000, 'b'));
buffer.Append(std::string(10, 'c'));
auto more_data = MakeDataAndSize(std::string(4490, 'd'));
buffer.Append(std::move(more_data.data), more_data.size);
EXPECT_EQ(500 + 2000 + 10 + 4490, absl::StrJoin(buffer.Read(), "").size());
}
TEST(ChunkedBufferTest, RemovePartialPrefix) {
ChunkedBuffer buffer;
auto data_and_size = MakeDataAndSize(kLoremIpsum);
buffer.Append(std::move(data_and_size.data), data_and_size.size);
EXPECT_EQ(kLoremIpsum.size(), buffer.TotalSize());
buffer.RemovePrefix(6);
EXPECT_THAT(buffer.GetPrefix(), testing::StartsWith("ipsum"));
EXPECT_EQ(kLoremIpsum.size() - 6, buffer.TotalSize());
buffer.RemovePrefix(20);
EXPECT_THAT(buffer.GetPrefix(), testing::StartsWith(", consectetur"));
EXPECT_EQ(kLoremIpsum.size() - 26, buffer.TotalSize());
buffer.Append(" Anday igpay atinlay!");
EXPECT_EQ(kLoremIpsum.size() - 26 + 21, buffer.TotalSize());
const std::initializer_list<absl::string_view> parts = {
kLoremIpsum.substr(26), " Anday igpay atinlay!"};
EXPECT_EQ(absl::StrJoin(parts, ""), absl::StrJoin(buffer.Read(), ""));
}
TEST(ChunkedBufferTest, DifferentAppends) {
ChunkedBuffer buffer;
buffer.Append("Lorem ipsum");
auto more_data = MakeDataAndSize(" dolor sit amet, ");
buffer.Append(std::move(more_data.data), more_data.size);
buffer.Append("consectetur adipiscing elit, ");
more_data = MakeDataAndSize("sed do eiusmod tempor incididunt ut ");
buffer.Append(std::move(more_data.data), more_data.size);
buffer.Append("labore et dolore magna aliqua.");
EXPECT_EQ(kLoremIpsum, absl::StrJoin(buffer.Read(), ""));
buffer.RemovePrefix(kLoremIpsum.size());
EXPECT_TRUE(buffer.Empty());
}
TEST(ChunkedBufferTest, GetAppendRegion) {
ChunkedBuffer buffer;
constexpr absl::string_view kFirstAppendText = "Lorem ipsum";
{
auto region = buffer.GetAppendRegion();
ASSERT_GE(region.size, kFirstAppendText.size());
memcpy(region.data, kFirstAppendText.data(), kFirstAppendText.size());
region.written = kFirstAppendText.size();
}
EXPECT_EQ(kFirstAppendText, buffer.GetPrefix());
EXPECT_EQ(kFirstAppendText.size(), buffer.TotalSize());
constexpr absl::string_view kSecondAppendText = " dolor sit amet, ";
{
auto region = buffer.GetAppendRegion();
ASSERT_GE(region.size, kSecondAppendText.size());
memcpy(region.data, kSecondAppendText.data(), kSecondAppendText.size());
region.written = kSecondAppendText.size();
}
EXPECT_EQ(kFirstAppendText.size() + kSecondAppendText.size(),
buffer.TotalSize());
EXPECT_EQ(absl::StrCat(kFirstAppendText, kSecondAppendText),
buffer.GetPrefix());
}
TEST(ChunkedBufferTest, GetAppendRegionAcrossChunks) {
ChunkedBuffer buffer;
{
auto region = buffer.GetAppendRegion();
ASSERT_GE(region.size, 1024);
const std::string first_part(1024, 'a');
memcpy(region.data, first_part.data(), 1024);
region.written = 1024;
}
EXPECT_EQ(1024, buffer.TotalSize());
{
auto region = buffer.GetAppendRegion();
ASSERT_GE(region.size, 1024);
const std::string second_part(10, 'b');
memcpy(region.data, second_part.data(), 10);
region.written = 10;
}
EXPECT_EQ(1034, buffer.TotalSize());
const std::string expected =
absl::StrCat(std::string(1024, 'a'), std::string(10, 'b'));
EXPECT_EQ(expected, absl::StrJoin(buffer.Read(), ""));
}
TEST(ChunkedBufferTest, GetAppendRegionThenAppend) {
ChunkedBuffer buffer;
constexpr absl::string_view kFirstAppendText = "Lorem ipsum";
{
auto region = buffer.GetAppendRegion();
ASSERT_GE(region.size, kFirstAppendText.size());
memcpy(region.data, kFirstAppendText.data(), kFirstAppendText.size());
region.written = kFirstAppendText.size();
}
constexpr absl::string_view kSecondAppendText = " dolor sit amet, ";
buffer.Append(kSecondAppendText);
EXPECT_EQ(kFirstAppendText.size() + kSecondAppendText.size(),
buffer.TotalSize());
EXPECT_EQ(absl::StrCat(kFirstAppendText, kSecondAppendText),
buffer.GetPrefix());
}
} // namespace
} // namespace adapter
} // namespace http2