普通文本  |  269行  |  9.53 KB

// 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 <vector>

#include "compat/test.h"
#include "file_reader.h"
#include "file_utils.h"
#include "scoped_temp_path.h"
#include "test_utils.h"

namespace quipper {

// Move the cursor around and make sure the offset is properly set each time.
TEST(FileReaderTest, MoveOffset) {
  std::vector<uint8_t> input_data(1000);

  ScopedTempFile input_file;
  ASSERT_TRUE(BufferToFile(input_file.path(), input_data));

  // Create a reader for reading.
  FileReader reader(input_file.path());
  EXPECT_EQ(input_data.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 file, 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(FileReaderTest, ReadZeroBytes) {
  std::vector<uint8_t> input_data(10);

  ScopedTempFile input_file;
  ASSERT_TRUE(BufferToFile(input_file.path(), input_data));

  FileReader reader(input_file.path());
  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 file at once.
TEST(FileReaderTest, ReadSingleChunk) {
  const string kInputData = "abcdefghijklmnopqrstuvwxyz";

  ScopedTempFile input_file;
  ASSERT_TRUE(BufferToFile(input_file.path(), kInputData));
  FileReader reader(input_file.path());

  // Read all the data from the file in one go.
  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(FileReaderTest, ReadDataValue) {
  const string kInputData = "abcdefghijklmnopqrstuvwxyz";

  ScopedTempFile input_file;
  ASSERT_TRUE(BufferToFile(input_file.path(), kInputData));
  FileReader reader(input_file.path());

  // Read all the data from the file in one go.
  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 file in multiple chunks, in order.
TEST(FileReaderTest, ReadMultipleChunks) {
  // This string is 26 characters long.
  const string kInputData = "abcdefghijklmnopqrstuvwxyz";

  ScopedTempFile input_file;
  ASSERT_TRUE(BufferToFile(input_file.path(), kInputData));
  FileReader reader(input_file.path());

  // Read the data in multiple operations. Make sure the cursor is updated.
  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 file in multiple chunks, but not in order.
TEST(FileReaderTest, ReadWithJumps) {
  // This string contains four parts, each 10 characters long.
  const string kInputData =
      "0:abcdefg;"
      "1:hijklmn;"
      "2:opqrstu;"
      "3:vwxyzABC";

  ScopedTempFile input_file;
  ASSERT_TRUE(BufferToFile(input_file.path(), kInputData));
  FileReader reader(input_file.path());

  // Read the data in multiple operations, but not in order. The destination
  // offset must still match the source offset.
  std::vector<uint8_t> output(10);

  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 file.
TEST(FileReaderTest, ReadPastEndOfData) {
  // This string is 26 characters long.
  const string kInputData = "abcdefghijklmnopqrstuvwxyz";

  ScopedTempFile input_file;
  ASSERT_TRUE(BufferToFile(input_file.path(), kInputData));
  FileReader reader(input_file.path());

  // Must not be able to read past the end of the file.
  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 file, 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 file, 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(FileReaderTest, ReadString) {
  // Construct an input string.
  string input_string("The quick brown fox jumps over the lazy dog.");

  ScopedTempFile input_file;
  ASSERT_TRUE(BufferToFile(input_file.path(), input_string));

  // Read the full string.
  FileReader full_reader(input_file.path());
  string full_reader_output;
  EXPECT_TRUE(full_reader.ReadString(input_string.size(), &full_reader_output));
  EXPECT_EQ(input_string.size(), full_reader.Tell());
  EXPECT_EQ(input_string, full_reader_output);

  // Read the first half of the string.
  FileReader half_reader(input_file.path());
  string half_reader_output;
  EXPECT_TRUE(
      half_reader.ReadString(input_string.size() / 2, &half_reader_output));
  EXPECT_EQ(input_string.size() / 2, half_reader.Tell());
  EXPECT_EQ(input_string.substr(0, input_string.size() / 2),
            half_reader_output);

  // Attempt to read past the end of the string.
  FileReader past_end_reader(input_file.path());
  string past_end_reader_output = "previous string value";
  EXPECT_FALSE(past_end_reader.ReadString(input_string.size() + 1,
                                          &past_end_reader_output));
  EXPECT_EQ("previous string value", past_end_reader_output);

  // Create a string with some extra padding behind it. The padding should be
  // all zeroes. Read from this string, with a size that encompasses the
  // padding.
  string input_string_with_padding(input_string.begin(), input_string.end());
  input_string_with_padding.resize(input_string.size() + 10, '\0');

  ScopedTempFile input_file_padded;
  ASSERT_TRUE(
      BufferToFile(input_file_padded.path(), input_string_with_padding));

  // Read everything including the padding.
  FileReader padding_reader(input_file_padded.path());
  string padding_reader_output;
  EXPECT_TRUE(padding_reader.ReadString(input_string_with_padding.size(),
                                        &padding_reader_output));
  // The reader should have read past the padding too.
  EXPECT_EQ(input_string_with_padding.size(), padding_reader.Tell());
  // However, the output string itself should not have padding.
  EXPECT_EQ(input_string, padding_reader_output);
}

// Reads data to a buffer and verifies that the buffer has not been modified
// beyond the writable boundaries.
TEST(FileReaderTest, NoWritingOutOfBounds) {
  // The input data contains all zeroes.
  std::vector<uint8_t> input_data(800, 0);

  // Write it to file.
  ScopedTempFile input_file;
  ASSERT_TRUE(BufferToFile(input_file.path(), input_data));
  FileReader reader(input_file.path());

  // 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_data,
            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