203 lines
5.2 KiB
C++
203 lines
5.2 KiB
C++
|
|
// Copyright 2019 The Chromium Authors
|
||
|
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
|
// found in the LICENSE file.
|
||
|
|
|
||
|
|
#include "base/containers/buffer_iterator.h"
|
||
|
|
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#include <limits>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
||
|
|
|
||
|
|
namespace base {
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
struct TestStruct {
|
||
|
|
uint32_t one;
|
||
|
|
uint8_t two;
|
||
|
|
};
|
||
|
|
|
||
|
|
bool operator==(const TestStruct& lhs, const TestStruct& rhs) {
|
||
|
|
return lhs.one == rhs.one && lhs.two == rhs.two;
|
||
|
|
}
|
||
|
|
|
||
|
|
TestStruct CreateTestStruct() {
|
||
|
|
TestStruct expected;
|
||
|
|
expected.one = 0xabcdef12;
|
||
|
|
expected.two = 0x34;
|
||
|
|
return expected;
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(BufferIteratorTest, Object) {
|
||
|
|
TestStruct expected = CreateTestStruct();
|
||
|
|
|
||
|
|
char buffer[sizeof(TestStruct)];
|
||
|
|
memcpy(buffer, &expected, sizeof(buffer));
|
||
|
|
|
||
|
|
{
|
||
|
|
// Read the object.
|
||
|
|
BufferIterator<char> iterator(buffer, sizeof(buffer));
|
||
|
|
const TestStruct* actual = iterator.Object<TestStruct>();
|
||
|
|
EXPECT_EQ(expected, *actual);
|
||
|
|
}
|
||
|
|
{
|
||
|
|
// Iterator's view of the data is not large enough to read the object.
|
||
|
|
BufferIterator<char> iterator(buffer, sizeof(buffer) - 1);
|
||
|
|
const TestStruct* actual = iterator.Object<TestStruct>();
|
||
|
|
EXPECT_FALSE(actual);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(BufferIteratorTest, MutableObject) {
|
||
|
|
TestStruct expected = CreateTestStruct();
|
||
|
|
|
||
|
|
char buffer[sizeof(TestStruct)];
|
||
|
|
|
||
|
|
BufferIterator<char> iterator(buffer, sizeof(buffer));
|
||
|
|
|
||
|
|
{
|
||
|
|
// Write the object.
|
||
|
|
TestStruct* actual = iterator.MutableObject<TestStruct>();
|
||
|
|
actual->one = expected.one;
|
||
|
|
actual->two = expected.two;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Rewind the iterator.
|
||
|
|
iterator.Seek(0);
|
||
|
|
|
||
|
|
{
|
||
|
|
// Read the object back.
|
||
|
|
const TestStruct* actual = iterator.Object<TestStruct>();
|
||
|
|
EXPECT_EQ(expected, *actual);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(BufferIteratorTest, ObjectSizeOverflow) {
|
||
|
|
char buffer[64];
|
||
|
|
BufferIterator<char> iterator(buffer, std::numeric_limits<size_t>::max());
|
||
|
|
|
||
|
|
auto* pointer = iterator.Object<uint64_t>();
|
||
|
|
EXPECT_TRUE(pointer);
|
||
|
|
|
||
|
|
iterator.Seek(iterator.total_size() - 1);
|
||
|
|
|
||
|
|
auto* invalid_pointer = iterator.Object<uint64_t>();
|
||
|
|
EXPECT_FALSE(invalid_pointer);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(BufferIteratorTest, Span) {
|
||
|
|
TestStruct expected = CreateTestStruct();
|
||
|
|
|
||
|
|
std::vector<char> buffer(sizeof(TestStruct) * 3);
|
||
|
|
|
||
|
|
{
|
||
|
|
// Load the span with data.
|
||
|
|
BufferIterator<char> iterator(buffer);
|
||
|
|
span<TestStruct> span = iterator.MutableSpan<TestStruct>(3);
|
||
|
|
for (auto& ts : span) {
|
||
|
|
memcpy(&ts, &expected, sizeof(expected));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
{
|
||
|
|
// Read the data back out.
|
||
|
|
BufferIterator<char> iterator(buffer);
|
||
|
|
|
||
|
|
const TestStruct* actual = iterator.Object<TestStruct>();
|
||
|
|
EXPECT_EQ(expected, *actual);
|
||
|
|
|
||
|
|
actual = iterator.Object<TestStruct>();
|
||
|
|
EXPECT_EQ(expected, *actual);
|
||
|
|
|
||
|
|
actual = iterator.Object<TestStruct>();
|
||
|
|
EXPECT_EQ(expected, *actual);
|
||
|
|
|
||
|
|
EXPECT_EQ(iterator.total_size(), iterator.position());
|
||
|
|
}
|
||
|
|
{
|
||
|
|
// Cannot create spans larger than there are data for.
|
||
|
|
BufferIterator<char> iterator(buffer);
|
||
|
|
span<const TestStruct> span = iterator.Span<TestStruct>(4);
|
||
|
|
EXPECT_TRUE(span.empty());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(BufferIteratorTest, SpanOverflow) {
|
||
|
|
char buffer[64];
|
||
|
|
|
||
|
|
BufferIterator<char> iterator(buffer, std::numeric_limits<size_t>::max());
|
||
|
|
{
|
||
|
|
span<const uint64_t> empty_span = iterator.Span<uint64_t>(
|
||
|
|
(std::numeric_limits<size_t>::max() / sizeof(uint64_t)) + 1);
|
||
|
|
EXPECT_TRUE(empty_span.empty());
|
||
|
|
}
|
||
|
|
{
|
||
|
|
span<const uint64_t> empty_span =
|
||
|
|
iterator.Span<uint64_t>(std::numeric_limits<size_t>::max());
|
||
|
|
EXPECT_TRUE(empty_span.empty());
|
||
|
|
}
|
||
|
|
{
|
||
|
|
iterator.Seek(iterator.total_size() - 7);
|
||
|
|
span<const uint64_t> empty_span = iterator.Span<uint64_t>(1);
|
||
|
|
EXPECT_TRUE(empty_span.empty());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(BufferIteratorTest, Position) {
|
||
|
|
char buffer[64];
|
||
|
|
BufferIterator<char> iterator(buffer, sizeof(buffer));
|
||
|
|
EXPECT_EQ(sizeof(buffer), iterator.total_size());
|
||
|
|
|
||
|
|
size_t position = iterator.position();
|
||
|
|
EXPECT_EQ(0u, position);
|
||
|
|
|
||
|
|
iterator.Object<uint8_t>();
|
||
|
|
EXPECT_EQ(sizeof(uint8_t), iterator.position() - position);
|
||
|
|
position = iterator.position();
|
||
|
|
|
||
|
|
iterator.Object<uint32_t>();
|
||
|
|
EXPECT_EQ(sizeof(uint32_t), iterator.position() - position);
|
||
|
|
position = iterator.position();
|
||
|
|
|
||
|
|
iterator.Seek(32);
|
||
|
|
EXPECT_EQ(32u, iterator.position());
|
||
|
|
|
||
|
|
EXPECT_EQ(sizeof(buffer), iterator.total_size());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(BufferIteratorTest, CopyObject) {
|
||
|
|
TestStruct expected = CreateTestStruct();
|
||
|
|
|
||
|
|
constexpr int kNumCopies = 3;
|
||
|
|
char buffer[sizeof(TestStruct) * kNumCopies];
|
||
|
|
for (int i = 0; i < kNumCopies; i++)
|
||
|
|
memcpy(buffer + i * sizeof(TestStruct), &expected, sizeof(TestStruct));
|
||
|
|
|
||
|
|
BufferIterator<char> iterator(buffer);
|
||
|
|
absl::optional<TestStruct> actual;
|
||
|
|
for (int i = 0; i < kNumCopies; i++) {
|
||
|
|
actual = iterator.CopyObject<TestStruct>();
|
||
|
|
ASSERT_TRUE(actual.has_value());
|
||
|
|
EXPECT_EQ(expected, *actual);
|
||
|
|
}
|
||
|
|
actual = iterator.CopyObject<TestStruct>();
|
||
|
|
EXPECT_FALSE(actual.has_value());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(BufferIteratorTest, SeekWithSizeConfines) {
|
||
|
|
const char buffer[] = "vindicate";
|
||
|
|
BufferIterator<const char> iterator(buffer);
|
||
|
|
iterator.Seek(5);
|
||
|
|
iterator.TruncateTo(3);
|
||
|
|
EXPECT_TRUE(iterator.Span<char>(4).empty());
|
||
|
|
|
||
|
|
std::string result;
|
||
|
|
while (const char* c = iterator.Object<char>())
|
||
|
|
result += *c;
|
||
|
|
EXPECT_EQ(result, "cat");
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
} // namespace base
|