| // Copyright 2015 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdint.h> |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include "chromiumos-wide-profiling/buffer_reader.h" |
| #include "chromiumos-wide-profiling/compat/string.h" |
| #include "chromiumos-wide-profiling/compat/test.h" |
| |
| namespace quipper { |
| |
| // Move the cursor around and make sure the offset is properly set each time. |
| TEST(BufferReaderTest, MoveOffset) { |
| const std::vector<uint8_t> input(1000); |
| BufferReader reader(input.data(), input.size()); |
| |
| // Make sure the reader was properly created. |
| EXPECT_EQ(input.size(), reader.size()); |
| EXPECT_EQ(0, reader.Tell()); |
| |
| // Move the read cursor around. |
| reader.SeekSet(100); |
| EXPECT_EQ(100, reader.Tell()); |
| reader.SeekSet(900); |
| EXPECT_EQ(900, reader.Tell()); |
| reader.SeekSet(500); |
| EXPECT_EQ(500, reader.Tell()); |
| |
| // The cursor can be set to past the end of the buffer, but can't perform any |
| // read operations there. |
| reader.SeekSet(1200); |
| EXPECT_EQ(1200, reader.Tell()); |
| int dummy; |
| EXPECT_FALSE(reader.ReadData(sizeof(dummy), &dummy)); |
| } |
| |
| // Make sure that the reader can handle a read size of zero. |
| TEST(BufferReaderTest, ReadZeroBytes) { |
| const std::vector<uint8_t> input(10); |
| BufferReader reader(input.data(), input.size()); |
| |
| // Move to some location within the buffer. |
| reader.SeekSet(5); |
| EXPECT_TRUE(reader.ReadData(0, NULL)); |
| |
| // Make sure the read pointer hasn't moved. |
| EXPECT_EQ(5, reader.Tell()); |
| } |
| |
| // Read in all data from the input buffer at once. |
| TEST(BufferReaderTest, ReadSingleChunk) { |
| const string kInputData = "abcdefghijklmnopqrstuvwxyz"; |
| BufferReader reader(kInputData.data(), kInputData.size()); |
| |
| std::vector<uint8_t> output(kInputData.size()); |
| EXPECT_TRUE(reader.ReadData(output.size(), output.data())); |
| EXPECT_EQ(output.size(), reader.Tell()); |
| // Compare input and output data, converting the latter to a string for |
| // clarity of error messages. |
| EXPECT_EQ(kInputData, string(output.begin(), output.end())); |
| } |
| |
| // Test the ReadDataValue() function, which is a wrapper around ReadData(). |
| TEST(BufferReaderTest, ReadDataValue) { |
| const string kInputData = "abcdefghijklmnopqrstuvwxyz"; |
| BufferReader reader(kInputData.data(), kInputData.size()); |
| |
| std::vector<uint8_t> output(kInputData.size()); |
| EXPECT_TRUE(reader.ReadDataValue(output.size(), "data", output.data())); |
| EXPECT_EQ(output.size(), reader.Tell()); |
| |
| EXPECT_EQ(kInputData, string(output.begin(), output.end())); |
| } |
| |
| // Read in all data from the input buffer in multiple chunks, in order. |
| TEST(BufferReaderTest, ReadMultipleChunks) { |
| // This string is 26 characters long. |
| const string kInputData = "abcdefghijklmnopqrstuvwxyz"; |
| BufferReader reader(kInputData.data(), kInputData.size()); |
| |
| // Make sure the cursor is updated after each read. |
| std::vector<uint8_t> output(kInputData.size()); |
| EXPECT_TRUE(reader.ReadData(10, output.data() + reader.Tell())); |
| EXPECT_EQ(10, reader.Tell()); |
| EXPECT_TRUE(reader.ReadData(5, output.data() + reader.Tell())); |
| EXPECT_EQ(15, reader.Tell()); |
| EXPECT_TRUE(reader.ReadData(5, output.data() + reader.Tell())); |
| EXPECT_EQ(20, reader.Tell()); |
| EXPECT_TRUE(reader.ReadData(6, output.data() + reader.Tell())); |
| EXPECT_EQ(26, reader.Tell()); |
| |
| EXPECT_EQ(kInputData, string(output.begin(), output.end())); |
| } |
| |
| // Read in all data from the input buffer in multiple chunks, but not in order. |
| TEST(BufferReaderTest, ReadWithJumps) { |
| // This string contains four parts, each 10 characters long. |
| const string kInputData = |
| "0:abcdefg;" |
| "1:hijklmn;" |
| "2:opqrstu;" |
| "3:vwxyzABC"; |
| BufferReader reader(kInputData.data(), kInputData.size()); |
| |
| // Read the data in multiple operations, but not in order. Overwrite the |
| // previously read data in the destination buffer during each read. |
| std::vector<uint8_t> output(10); |
| |
| reader.SeekSet(20); |
| EXPECT_TRUE(reader.ReadData(10, output.data())); |
| EXPECT_EQ(30, reader.Tell()); |
| EXPECT_EQ("2:opqrstu;", string(output.begin(), output.end())); |
| |
| reader.SeekSet(10); |
| EXPECT_TRUE(reader.ReadData(10, output.data())); |
| EXPECT_EQ(20, reader.Tell()); |
| EXPECT_EQ("1:hijklmn;", string(output.begin(), output.end())); |
| |
| reader.SeekSet(30); |
| EXPECT_TRUE(reader.ReadData(10, output.data())); |
| EXPECT_EQ(40, reader.Tell()); |
| EXPECT_EQ("3:vwxyzABC", string(output.begin(), output.end())); |
| |
| reader.SeekSet(0); |
| EXPECT_TRUE(reader.ReadData(10, output.data())); |
| EXPECT_EQ(10, reader.Tell()); |
| EXPECT_EQ("0:abcdefg;", string(output.begin(), output.end())); |
| } |
| |
| // Test reading past the end of the buffer. |
| TEST(BufferReaderTest, ReadPastEndOfData) { |
| // This string is 26 characters long. |
| const string kInputData = "abcdefghijklmnopqrstuvwxyz"; |
| BufferReader reader(kInputData.data(), kInputData.size()); |
| |
| // Must not be able to read past the end of the buffer. |
| std::vector<uint8_t> output(kInputData.size()); |
| reader.SeekSet(0); |
| EXPECT_FALSE(reader.ReadData(30, output.data())); |
| // The read pointer should not have moved. |
| EXPECT_EQ(0, reader.Tell()); |
| |
| // Should still be able to read within the bounds of the buffer, despite the |
| // out-of-bounds read earlier. |
| EXPECT_TRUE(reader.ReadData(13, output.data())); |
| EXPECT_EQ(13, reader.Tell()); |
| |
| // Now attempt another read past the end of the buffer, but starting from the |
| // ending position of the previous read operation. |
| EXPECT_FALSE(reader.ReadData(20, output.data() + reader.Tell())); |
| // The read pointer should be unchanged. |
| EXPECT_EQ(13, reader.Tell()); |
| |
| // Read the rest of the data and make sure it matches the input. |
| EXPECT_TRUE(reader.ReadData(13, output.data() + reader.Tell())); |
| EXPECT_EQ(26, reader.Tell()); |
| |
| EXPECT_EQ(kInputData, string(output.begin(), output.end())); |
| } |
| |
| // Test string reads. |
| TEST(BufferReaderTest, ReadString) { |
| // Construct an input string. |
| string input("The quick brown fox jumps over the lazy dog."); |
| |
| // Read the full string. |
| BufferReader full_reader(input.data(), input.size()); |
| string full_reader_output; |
| EXPECT_TRUE(full_reader.ReadString(input.size(), &full_reader_output)); |
| EXPECT_EQ(input.size(), full_reader.Tell()); |
| EXPECT_EQ(input, full_reader_output); |
| |
| // Read the full string plus the null pointer. |
| BufferReader full_null_reader(input.data(), input.size() + 1); |
| string full_null_reader_output; |
| EXPECT_TRUE(full_null_reader.ReadString(input.size() + 1, |
| &full_null_reader_output)); |
| EXPECT_EQ(input.size() + 1, full_null_reader.Tell()); |
| EXPECT_EQ(input, full_null_reader_output); |
| |
| // Read the first half of the string. |
| BufferReader half_reader(input.data(), input.size() / 2); |
| string half_reader_output; |
| EXPECT_TRUE(half_reader.ReadString(input.size() / 2, &half_reader_output)); |
| EXPECT_EQ(input.size() / 2, half_reader.Tell()); |
| EXPECT_EQ(input.substr(0, input.size() / 2), half_reader_output); |
| |
| // Attempt to read past the end of the string. |
| BufferReader past_end_reader(input.data(), input.size()); |
| string past_end_reader_output; |
| EXPECT_FALSE(past_end_reader.ReadString(input.size() + 2, |
| &past_end_reader_output)); |
| |
| // Create a vector with some extra padding behind it. The padding should be |
| // all zeroes. Read from this vector, with a size that encompasses the |
| // padding. |
| std::vector<char> input_vector(input.begin(), input.end()); |
| input_vector.resize(input.size() + 10, '\0'); |
| |
| BufferReader vector_reader(input_vector.data(), input_vector.size()); |
| string vector_reader_output; |
| EXPECT_TRUE(vector_reader.ReadString(input_vector.size(), |
| &vector_reader_output)); |
| // The reader should have read past the padding too. |
| EXPECT_EQ(input_vector.size(), vector_reader.Tell()); |
| EXPECT_EQ(input, vector_reader_output); |
| } |
| |
| string MakeStringWithNullsForSpaces(string str) { |
| std::replace(str.begin(), str.end(), ' ', '\0'); |
| return str; |
| } |
| |
| TEST(BufferReaderTest, ReadDataString) { |
| // Construct an input string. |
| string input = MakeStringWithNullsForSpaces( |
| "The quick brown fox jumps over the lazy dog."); |
| |
| BufferReader reader(input.data(), input.size()); |
| |
| string expected_out; |
| string out; |
| out.resize(5); |
| EXPECT_TRUE(reader.ReadDataString(10, &out)); |
| expected_out = MakeStringWithNullsForSpaces("The quick "); |
| EXPECT_EQ(10, expected_out.size()) << "Sanity"; |
| EXPECT_EQ(expected_out, out); |
| |
| out.resize(15); |
| EXPECT_TRUE(reader.ReadDataString(10, &out)); |
| expected_out = MakeStringWithNullsForSpaces("brown fox "); |
| EXPECT_EQ(10, expected_out.size()) << "Sanity"; |
| EXPECT_EQ(expected_out, out); |
| |
| reader.SeekSet(reader.size()); |
| |
| // Check destination contents don't get modified on failure. |
| out.resize(5); |
| expected_out = out; |
| EXPECT_FALSE(reader.ReadDataString(10, &out)); |
| EXPECT_EQ(expected_out, out) << "Should be unchanged."; |
| |
| out.resize(15); |
| expected_out = out; |
| EXPECT_FALSE(reader.ReadDataString(10, &out)); |
| EXPECT_EQ(expected_out, out) << "Should be unchanged."; |
| |
| EXPECT_FALSE(out.empty()) << "Sanity"; |
| EXPECT_TRUE(reader.ReadDataString(0, &out)); |
| EXPECT_TRUE(out.empty()) << "Read zero-length should clear output."; |
| } |
| |
| // Reads data to a buffer and verifies that the buffer has not been modified |
| // beyond the writable boundaries. |
| TEST(BufferReaderTest, NoWritingOutOfBounds) { |
| // The input data contains all zeroes. |
| std::vector<uint8_t> input(800, 0); |
| BufferReader reader(input.data(), input.size()); |
| |
| // A sentinel value that fills memory to detect when that section of memory is |
| // overwritten. If the memory shows another value, it means it has been |
| // overwritten. |
| const char kUnwrittenValue = 0xaa; |
| |
| // Create a destination buffer filled with the above sentinel value. |
| std::vector<uint8_t> buffer(1000, kUnwrittenValue); |
| // Only write to the range [100, 900). |
| EXPECT_TRUE(reader.ReadData(800, buffer.data() + 100)); |
| |
| // Check that the data was written to the writable part of the buffer. |
| EXPECT_EQ(input, |
| std::vector<uint8_t>(buffer.begin() + 100, buffer.begin() + 900)); |
| |
| // Now make sure that the other parts of the buffer haven't been overwritten. |
| const std::vector<uint8_t> expected_unwritten_part(100, kUnwrittenValue); |
| EXPECT_EQ(expected_unwritten_part, |
| std::vector<uint8_t>(buffer.begin(), buffer.begin() + 100)); |
| EXPECT_EQ(expected_unwritten_part, |
| std::vector<uint8_t>(buffer.begin() + 900, buffer.begin() + 1000)); |
| } |
| |
| } // namespace quipper |