Coverage for /Syzygy/msf/msf_writer_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
95.2%79830.C++test

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/msf/msf_writer.h"
  16    :  
  17    :  #include <algorithm>
  18    :  #include <vector>
  19    :  
  20    :  #include "gmock/gmock.h"
  21    :  #include "gtest/gtest.h"
  22    :  #include "syzygy/core/unittest_util.h"
  23    :  #include "syzygy/msf/msf_constants.h"
  24    :  #include "syzygy/msf/msf_data.h"
  25    :  #include "syzygy/msf/msf_reader.h"
  26    :  #include "syzygy/msf/unittest_util.h"
  27    :  
  28    :  namespace msf {
  29    :  
  30    :  namespace {
  31    :  
  32    :  uint32 GetNumPages(uint32 num_bytes) {
  33    :    return (num_bytes + msf::kMsfPageSize - 1) / msf::kMsfPageSize;
  34    :  }
  35    :  
  36    :  class TestMsfWriter : public MsfWriter {
  37    :   public:
  38  E :    TestMsfWriter() {
  39  E :      file_.reset(base::CreateAndOpenTemporaryFile(&path_));
  40  E :      EXPECT_TRUE(file_.get() != NULL);
  41  E :    }
  42    :  
  43  E :    ~TestMsfWriter() {
  44  E :      if (file_.get()) {
  45  i :        fclose(file_.get());
  46  i :        file_.reset();
  47    :      }
  48  E :      base::DeleteFile(path_, false);
  49  E :    }
  50    :  
  51  E :    base::ScopedFILE& file() { return file_; }
  52    :  
  53    :    using MsfWriter::AppendStream;
  54    :    using MsfWriter::WriteHeader;
  55    :  
  56    :    base::FilePath path_;
  57    :  };
  58    :  
  59    :  class TestMsfStream : public MsfStream {
  60    :   public:
  61  E :    TestMsfStream(uint32 length, uint32 mask) : MsfStream(length), data_(length) {
  62  E :      uint32* data = reinterpret_cast<uint32*>(data_.data());
  63    :  
  64    :      // Just to make sure the data is non-repeating (so we can distinguish if it
  65    :      // has been correctly written or not) fill it with integers encoding their
  66    :      // own position in the stream.
  67  E :      for (size_t i = 0; i < data_.size() / sizeof(data[0]); ++i)
  68  E :        data[i] = i | mask;
  69  E :    }
  70    :  
  71  E :    bool ReadBytes(void* dest, size_t count, size_t* bytes_read) {
  72  E :      DCHECK(bytes_read != NULL);
  73    :  
  74  E :      if (pos() == length()) {
  75  i :        *bytes_read = 0;
  76  i :        return true;
  77    :      }
  78    :  
  79  E :      count = std::min(count, length() - pos());
  80  E :      ::memcpy(dest, data_.data() + pos(), count);
  81  E :      Seek(pos() + count);
  82  E :      *bytes_read = count;
  83    :  
  84  E :      return true;
  85  E :    }
  86    :  
  87    :   private:
  88    :    std::vector<uint8> data_;
  89    :  };
  90    :  
  91    :  void EnsureMsfContentsAreIdentical(const MsfFile& msf_file,
  92    :                                     const MsfFile& msf_file_read) {
  93    :    ASSERT_EQ(msf_file.StreamCount(), msf_file_read.StreamCount());
  94    :  
  95    :    for (size_t i = 0; i < msf_file.StreamCount(); ++i) {
  96    :      MsfStream* stream = msf_file.GetStream(i).get();
  97    :      MsfStream* stream_read = msf_file_read.GetStream(i).get();
  98    :  
  99    :      ASSERT_TRUE(stream != NULL);
 100    :      ASSERT_TRUE(stream_read != NULL);
 101    :  
 102    :      ASSERT_EQ(stream->length(), stream_read->length());
 103    :  
 104    :      std::vector<uint8> data;
 105    :      std::vector<uint8> data_read;
 106    :      ASSERT_TRUE(stream->Seek(0));
 107    :      ASSERT_TRUE(stream_read->Seek(0));
 108    :      ASSERT_TRUE(stream->Read(&data, stream->length()));
 109    :      ASSERT_TRUE(stream_read->Read(&data_read, stream_read->length()));
 110    :  
 111    :      // We don't use ContainerEq because upon failure this generates a
 112    :      // ridiculously long and useless error message. We don't use memcmp because
 113    :      // it doesn't given any context as to where the failure occurs.
 114    :      for (size_t j = 0; j < data.size(); ++j)
 115    :        ASSERT_EQ(data[j], data_read[j]);
 116    :    }
 117    :  }
 118    :  
 119    :  }  // namespace
 120    :  
 121    :  using msf::kMsfHeaderMagicString;
 122    :  using msf::kMsfPageSize;
 123    :  using msf::MsfHeader;
 124    :  using msf::MsfReader;
 125    :  
 126  E :  TEST(MsfWriterTest, AppendStream) {
 127  E :    TestMsfWriter writer;
 128    :  
 129  E :    testing::ScopedTempFile temp_file;
 130  E :    writer.file().reset(base::OpenFile(temp_file.path(), "wb"));
 131  E :    ASSERT_TRUE(writer.file().get() != NULL);
 132    :  
 133  E :    scoped_refptr<MsfStream> stream(new TestMsfStream(4 * kMsfPageSize, 0));
 134    :  
 135    :    // Test writing a stream that will force allocation of the free page map
 136    :    // pages.
 137  E :    std::vector<uint32> pages_written;
 138  E :    uint32 page_count = 0;
 139  E :    EXPECT_TRUE(writer.AppendStream(stream.get(), &pages_written, &page_count));
 140  E :    writer.file().reset();
 141    :  
 142    :    // We expect pages_written to contain 4 pages, like the stream. However, we
 143    :    // expect page_count to have 2 more pages for the free page map.
 144  E :    uint32 expected_pages_written[] = {0, 3, 4, 5};
 145    :    EXPECT_THAT(pages_written,
 146  E :                ::testing::ElementsAreArray(expected_pages_written));
 147  E :    EXPECT_EQ(page_count, 6);
 148    :  
 149    :    // Build the expected stream contents. Two blank pages should have been
 150    :    // reserved by the append stream routine.
 151  E :    stream->Seek(0);
 152  E :    std::vector<uint8> expected_contents(6 * kMsfPageSize);
 153  E :    ASSERT_TRUE(stream->Read(expected_contents.data(), kMsfPageSize));
 154    :    ASSERT_TRUE(stream->Read(expected_contents.data() + 3 * kMsfPageSize,
 155  E :                             3 * kMsfPageSize));
 156    :  
 157  E :    std::vector<uint8> contents(6 * kMsfPageSize);
 158    :    ASSERT_EQ(
 159    :        contents.size(),
 160    :        base::ReadFile(temp_file.path(), reinterpret_cast<char*>(contents.data()),
 161  E :                       contents.size()));
 162    :  
 163  E :    EXPECT_THAT(contents, ::testing::ContainerEq(expected_contents));
 164  E :  }
 165    :  
 166  E :  TEST(MsfWriterTest, WriteHeader) {
 167  E :    TestMsfWriter writer;
 168    :  
 169  E :    testing::ScopedTempFile temp_file;
 170  E :    writer.file().reset(base::OpenFile(temp_file.path(), "wb"));
 171  E :    ASSERT_TRUE(writer.file().get() != NULL);
 172    :  
 173  E :    std::vector<uint32> root_directory_pages(kMsfMaxDirPages + 10, 1);
 174    :  
 175    :    // Try to write a root directorty that's too big and expect this to fail.
 176  E :    EXPECT_FALSE(writer.WriteHeader(root_directory_pages, 67 * 4, 438));
 177    :  
 178    :    // Now write a reasonable root directory size.
 179  E :    root_directory_pages.resize(1);
 180  E :    EXPECT_TRUE(writer.WriteHeader(root_directory_pages, 67 * 4, 438));
 181  E :    writer.file().reset();
 182    :  
 183    :    // Build the expected stream contents. Two blank pages should have been
 184    :    // reserved by the append stream routine.
 185  E :    std::vector<uint8> expected_contents(sizeof(MsfHeader));
 186  E :    MsfHeader* header = reinterpret_cast<MsfHeader*>(expected_contents.data());
 187    :    ::memcpy(header->magic_string, kMsfHeaderMagicString,
 188  E :             kMsfHeaderMagicStringSize);
 189  E :    header->page_size = kMsfPageSize;
 190  E :    header->free_page_map = 1;
 191  E :    header->num_pages = 438;
 192  E :    header->directory_size = 67 * 4;
 193  E :    header->root_pages[0] = 1;
 194    :  
 195  E :    std::vector<uint8> contents(sizeof(MsfHeader));
 196    :    ASSERT_EQ(
 197    :        contents.size(),
 198    :        base::ReadFile(temp_file.path(), reinterpret_cast<char*>(contents.data()),
 199  E :                       contents.size()));
 200    :  
 201  E :    EXPECT_THAT(contents, ::testing::ContainerEq(expected_contents));
 202  E :  }
 203    :  
 204  E :  TEST(MsfWriterTest, WriteMsfFile) {
 205  E :    MsfFile msf_file;
 206  E :    for (uint32 i = 0; i < 4; ++i)
 207  E :      msf_file.AppendStream(new TestMsfStream(1 << (8 + i), (i << 24)));
 208    :  
 209    :    // Test that we can create an MSF file and then read it successfully.
 210  E :    testing::ScopedTempFile file;
 211    :    {
 212    :      // Create a scope so that the file gets closed.
 213  E :      TestMsfWriter writer;
 214  E :      EXPECT_TRUE(writer.Write(file.path(), msf_file));
 215  E :    }
 216    :  
 217  E :    MsfFile msf_file_read;
 218  E :    MsfReader reader;
 219  E :    EXPECT_TRUE(reader.Read(file.path(), &msf_file_read));
 220    :  
 221    :    ASSERT_NO_FATAL_FAILURE(
 222  E :        testing::EnsureMsfContentsAreIdentical(msf_file, msf_file_read));
 223  E :  }
 224    :  
 225    :  }  // namespace msf

Coverage information generated Thu Jan 14 17:40:38 2016.