You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
347 lines
8.5 KiB
347 lines
8.5 KiB
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <nvram/messages/io.h>
|
|
|
|
namespace nvram {
|
|
|
|
namespace {
|
|
|
|
// A simple |InputStreamBuffer| implementation that sets up a sequence of
|
|
// windows of |sizes| specified by the template parameters. Each byte read from
|
|
// the buffer has a value corresponding to its position in the stream.
|
|
template<size_t... sizes>
|
|
class TestInputStreamBuffer : public InputStreamBuffer {
|
|
public:
|
|
TestInputStreamBuffer() {
|
|
Advance();
|
|
}
|
|
|
|
private:
|
|
bool Advance() override {
|
|
if (index_ >= (sizeof(kSizes) / sizeof(kSizes[0]))) {
|
|
return false;
|
|
}
|
|
|
|
memset(buffer, 0xff, kMaxSize);
|
|
const size_t size = kSizes[index_] < kMaxSize ? kSizes[index_] : kMaxSize;
|
|
pos_ = buffer;
|
|
end_ = buffer + size;
|
|
for (uint8_t* p = buffer; p < end_; ++p) {
|
|
*p = static_cast<uint8_t>(count_++ % 256);
|
|
}
|
|
++index_;
|
|
return true;
|
|
}
|
|
|
|
static constexpr size_t kMaxSize = 256;
|
|
static constexpr size_t kSizes[] = { sizes... };
|
|
|
|
uint8_t buffer[kMaxSize];
|
|
size_t index_ = 0;
|
|
size_t count_ = 0;
|
|
};
|
|
|
|
template<size_t... sizes>
|
|
constexpr size_t TestInputStreamBuffer<sizes...>::kSizes[];
|
|
|
|
// Tests whether a read of the given size returns the correct data, i.e. bytes
|
|
// with consecutive values starting at |pos|.
|
|
void CheckRead(InputStreamBuffer* buffer, size_t size, size_t pos) {
|
|
uint8_t data[256];
|
|
ASSERT_LE(size, sizeof(data));
|
|
EXPECT_TRUE(buffer->Read(data, size));
|
|
for (uint8_t* p = data; p < data + size; ++p) {
|
|
EXPECT_EQ(pos++ % 256, *p);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(InputStreamBufferTest, Basic) {
|
|
TestInputStreamBuffer<10> buf;
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
uint8_t byte = 0;
|
|
EXPECT_TRUE(buf.ReadByte(&byte));
|
|
EXPECT_EQ(0, byte);
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
CheckRead(&buf, 6, 1);
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
EXPECT_TRUE(buf.Skip(3));
|
|
EXPECT_TRUE(buf.Done());
|
|
}
|
|
|
|
TEST(InputStreamBufferTest, Empty) {
|
|
InputStreamBuffer buf(nullptr, nullptr);
|
|
EXPECT_TRUE(buf.Done());
|
|
uint8_t byte = 0;
|
|
EXPECT_FALSE(buf.ReadByte(&byte));
|
|
}
|
|
|
|
TEST(InputStreamBufferTest, LargeRead) {
|
|
TestInputStreamBuffer<10> buf;
|
|
uint8_t read_buf[10];
|
|
EXPECT_FALSE(buf.Read(read_buf, SIZE_MAX));
|
|
}
|
|
|
|
TEST(InputStreamBufferTest, LargeSkip) {
|
|
TestInputStreamBuffer<10> buf;
|
|
EXPECT_FALSE(buf.Skip(SIZE_MAX));
|
|
}
|
|
|
|
TEST(InputStreamBufferTest, OverlappingReadByte) {
|
|
TestInputStreamBuffer<1, 1> buf;
|
|
|
|
uint8_t byte = 0;
|
|
EXPECT_TRUE(buf.ReadByte(&byte));
|
|
EXPECT_EQ(0, byte);
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
EXPECT_TRUE(buf.ReadByte(&byte));
|
|
EXPECT_EQ(1, byte);
|
|
EXPECT_TRUE(buf.Done());
|
|
}
|
|
|
|
TEST(InputStreamBufferTest, OverlappingRead) {
|
|
TestInputStreamBuffer<10, 10, 10> buf;
|
|
CheckRead(&buf, 15, 0);
|
|
CheckRead(&buf, 10, 15);
|
|
CheckRead(&buf, 5, 25);
|
|
EXPECT_TRUE(buf.Done());
|
|
}
|
|
|
|
TEST(InputStreamBufferTest, OverlappingSkip) {
|
|
TestInputStreamBuffer<10, 10, 10> buf;
|
|
EXPECT_TRUE(buf.Skip(15));
|
|
EXPECT_TRUE(buf.Skip(10));
|
|
EXPECT_TRUE(buf.Skip(5));
|
|
EXPECT_TRUE(buf.Done());
|
|
}
|
|
|
|
TEST(NestedInputStreamBufferTest, Large) {
|
|
TestInputStreamBuffer<10> buf;
|
|
NestedInputStreamBuffer nested(&buf, SIZE_MAX);
|
|
EXPECT_FALSE(nested.Skip(SIZE_MAX));
|
|
}
|
|
|
|
TEST(NestedInputStreamBufferTest, Short) {
|
|
TestInputStreamBuffer<10> buf;
|
|
NestedInputStreamBuffer nested(&buf, 5);
|
|
CheckRead(&nested, 5, 0);
|
|
EXPECT_TRUE(nested.Done());
|
|
EXPECT_FALSE(nested.Skip(1));
|
|
}
|
|
|
|
TEST(NestedInputStreamBufferTest, Matching) {
|
|
TestInputStreamBuffer<10, 5> buf;
|
|
NestedInputStreamBuffer nested(&buf, 10);
|
|
CheckRead(&nested, 10, 0);
|
|
EXPECT_TRUE(nested.Done());
|
|
EXPECT_FALSE(nested.Skip(1));
|
|
}
|
|
|
|
TEST(NestedInputStreamBufferTest, Overlapping) {
|
|
TestInputStreamBuffer<2, 3, 5, 8> buf;
|
|
NestedInputStreamBuffer nested(&buf, 16);
|
|
CheckRead(&nested, 8, 0);
|
|
EXPECT_FALSE(nested.Done());
|
|
CheckRead(&nested, 8, 8);
|
|
EXPECT_TRUE(nested.Done());
|
|
EXPECT_FALSE(nested.Skip(1));
|
|
}
|
|
|
|
namespace {
|
|
|
|
// An |OutputStreamBuffer| implementation backed by a sequence of buffer windows
|
|
// of |sizes| specified as template parameters. The output is expected to be
|
|
// sequential byte values starting at 0.
|
|
template<size_t... sizes>
|
|
class TestOutputStreamBuffer : public OutputStreamBuffer {
|
|
public:
|
|
TestOutputStreamBuffer() {
|
|
Advance();
|
|
}
|
|
|
|
~TestOutputStreamBuffer() {
|
|
EXPECT_TRUE(Verify());
|
|
}
|
|
|
|
bool Verify() {
|
|
for (; check_pos_ < pos_; check_pos_++, count_++) {
|
|
data_matches_ &= *check_pos_ == (count_ % 256);
|
|
}
|
|
|
|
return data_matches_;
|
|
}
|
|
|
|
private:
|
|
bool Advance() override {
|
|
if (index_ >= (sizeof(kSizes) / sizeof(kSizes[0]))) {
|
|
return false;
|
|
}
|
|
|
|
pos_ = end_;
|
|
Verify();
|
|
|
|
memset(buffer, 0xff, kMaxSize);
|
|
const size_t size = kSizes[index_] < kMaxSize ? kSizes[index_] : kMaxSize;
|
|
pos_ = buffer;
|
|
check_pos_ = buffer;
|
|
end_ = buffer + size;
|
|
++index_;
|
|
return true;
|
|
}
|
|
|
|
static constexpr size_t kMaxSize = 256;
|
|
static constexpr size_t kSizes[] = { sizes... };
|
|
|
|
uint8_t buffer[kMaxSize];
|
|
size_t index_ = 0;
|
|
|
|
// The pointer in buffer until which the data has been checked to match the
|
|
// expectations.
|
|
uint8_t* check_pos_ = nullptr;
|
|
|
|
// The counter that determines the expected value for the buffer bytes.
|
|
size_t count_ = 0;
|
|
|
|
// Whether all bytes that have been checked so far had the expected value.
|
|
bool data_matches_ = true;
|
|
};
|
|
|
|
template<size_t... sizes>
|
|
constexpr size_t TestOutputStreamBuffer<sizes...>::kSizes[];
|
|
|
|
// Writes a buffer of |size| to |buf|. The buffer contains consecutive byte
|
|
// value starting at pos.
|
|
void WriteBuf(OutputStreamBuffer* buffer, size_t size, size_t pos) {
|
|
uint8_t data[1024];
|
|
ASSERT_LE(size, sizeof(data));
|
|
for (uint8_t* p = data; p < data + size; ++p) {
|
|
*p = pos++ % 256;
|
|
}
|
|
EXPECT_TRUE(buffer->Write(data, size));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(OutputStreamBufferTest, Basic) {
|
|
TestOutputStreamBuffer<10> buf;
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
EXPECT_TRUE(buf.WriteByte(0));
|
|
EXPECT_TRUE(buf.WriteByte(1));
|
|
EXPECT_FALSE(buf.Done());
|
|
EXPECT_TRUE(buf.Verify());
|
|
|
|
WriteBuf(&buf, 6, 2);
|
|
EXPECT_FALSE(buf.Done());
|
|
EXPECT_TRUE(buf.Verify());
|
|
|
|
WriteBuf(&buf, 2, 8);
|
|
EXPECT_TRUE(buf.Done());
|
|
}
|
|
|
|
TEST(OutputStreamBufferTest, Empty) {
|
|
OutputStreamBuffer buf(nullptr, nullptr);
|
|
EXPECT_TRUE(buf.Done());
|
|
EXPECT_FALSE(buf.WriteByte(0));
|
|
}
|
|
|
|
TEST(OutputStreamBufferTest, ShortWrite) {
|
|
TestOutputStreamBuffer<10> buf;
|
|
WriteBuf(&buf, 5, 0);
|
|
}
|
|
|
|
TEST(OutputStreamBufferTest, LargeWrite) {
|
|
TestOutputStreamBuffer<5> buf;
|
|
uint8_t data[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
|
EXPECT_FALSE(buf.Write(data, sizeof(data)));
|
|
}
|
|
|
|
TEST(OutputStreamBufferTest, OverlappingWriteByte) {
|
|
TestOutputStreamBuffer<1, 1> buf;
|
|
EXPECT_TRUE(buf.WriteByte(0));
|
|
EXPECT_FALSE(buf.Done());
|
|
EXPECT_TRUE(buf.WriteByte(1));
|
|
EXPECT_TRUE(buf.Done());
|
|
}
|
|
|
|
TEST(OutputStreamBufferTest, OverlappingWrite) {
|
|
TestOutputStreamBuffer<10, 10, 10> buf;
|
|
WriteBuf(&buf, 15, 0);
|
|
EXPECT_FALSE(buf.Done());
|
|
WriteBuf(&buf, 10, 15);
|
|
EXPECT_FALSE(buf.Done());
|
|
WriteBuf(&buf, 5, 25);
|
|
EXPECT_TRUE(buf.Done());
|
|
}
|
|
|
|
TEST(CountingOutputStreamBuffer, Basic) {
|
|
CountingOutputStreamBuffer buf;
|
|
EXPECT_EQ(0U, buf.bytes_written());
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
WriteBuf(&buf, 15, 0);
|
|
EXPECT_EQ(15U, buf.bytes_written());
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
EXPECT_TRUE(buf.WriteByte(0));
|
|
EXPECT_EQ(16U, buf.bytes_written());
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
WriteBuf(&buf, 1024, 0);
|
|
EXPECT_EQ(1040U, buf.bytes_written());
|
|
EXPECT_FALSE(buf.Done());
|
|
}
|
|
|
|
TEST(BlobOutputStreamBuffer, Basic) {
|
|
Blob blob;
|
|
ASSERT_TRUE(blob.Resize(1024 * 1024));
|
|
BlobOutputStreamBuffer buf(&blob);
|
|
|
|
WriteBuf(&buf, 15, 0);
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
EXPECT_TRUE(buf.WriteByte(15));
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
EXPECT_TRUE(buf.Truncate());
|
|
EXPECT_EQ(16U, blob.size());
|
|
for (size_t i = 0; i < blob.size(); ++i) {
|
|
EXPECT_EQ(i % 256, blob.data()[i]);
|
|
}
|
|
|
|
WriteBuf(&buf, 1024, 16);
|
|
EXPECT_FALSE(buf.Done());
|
|
|
|
EXPECT_TRUE(buf.Truncate());
|
|
EXPECT_EQ(1040U, blob.size());
|
|
for (size_t i = 0; i < blob.size(); ++i) {
|
|
EXPECT_EQ(i % 256, blob.data()[i]);
|
|
}
|
|
}
|
|
|
|
} // namespace nvram
|