Coverage for /Syzygy/block_graph/transform_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
98.6%73740.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    :  // Unittests for BlockGraph transform wrapper.
  16    :  
  17    :  #include "syzygy/block_graph/transform.h"
  18    :  
  19    :  #include "gmock/gmock.h"
  20    :  #include "gtest/gtest.h"
  21    :  
  22    :  namespace block_graph {
  23    :  namespace {
  24    :  
  25    :  using testing::_;
  26    :  using testing::Invoke;
  27    :  using testing::Return;
  28    :  
  29    :  // A constant data structure/buffer from which to initialize a data block.
  30    :  // The structure contains a core reference (function pointer) and an integer
  31    :  // data element.
  32    :  struct MyData {
  33    :    void (*code)(int);
  34    :    int data;
  35    :  };
  36    :  const BlockGraph::Offset kOffsetOfReferenceToCode = offsetof(MyData, code);
  37    :  const BlockGraph::Offset kOffsetOfData = offsetof(MyData, data);
  38    :  const MyData kDataBytes = { reinterpret_cast<void(*)(int)>(0xCAFEBABE),
  39    :                              0xDEADBEEF };
  40    :  
  41    :  // A byte buffer from which to initialize a code block. The original C source
  42    :  // code for this function is:
  43    :  //
  44    :  //     static int y = 1;
  45    :  //     void add(int x) {
  46    :  //       y += x;
  47    :  //     }
  48    :  //
  49    :  // Note the reference to
  50    :  // y starts 5 bytes from the end.
  51    :  const uint8 kCodeBytes[] = {
  52    :    0x8B, 0x44, 0x24, 0x04,               // mov eax,dword ptr [esp+4]
  53    :    0x01, 0x05, 0x00, 0x00, 0x00, 0x00,  // add dword ptr [_y],eax
  54    :    0xC3                                 // ret
  55    :  };
  56    :  const BlockGraph::Offset kOffsetOfCode = 0;
  57    :  const BlockGraph::Offset kOffsetOfReferenceToData = sizeof(kCodeBytes) - 5;
  58    :  
  59    :  class ApplyBlockGraphTransformTest : public testing::Test {
  60    :   public:
  61  E :    virtual void SetUp() {
  62  E :      header_block_ = block_graph_.AddBlock(BlockGraph::DATA_BLOCK, 10, "Header");
  63  E :    }
  64    :  
  65    :   protected:
  66    :    BlockGraph block_graph_;
  67    :    BlockGraph::Block* header_block_;
  68    :  };
  69    :  
  70    :  class MockBlockGraphTransform : public BlockGraphTransformInterface {
  71    :   public:
  72  E :    virtual ~MockBlockGraphTransform() { }
  73    :  
  74  E :    virtual const char* name() const { return "MockBlockGraphTransform"; }
  75    :  
  76  E :    MOCK_METHOD2(TransformBlockGraph, bool(BlockGraph*, BlockGraph::Block*));
  77    :  
  78    :    bool DeleteHeader(BlockGraph* block_graph,
  79  E :                      BlockGraph::Block* header_block) {
  80  E :      CHECK(block_graph->RemoveBlock(header_block));
  81  E :      return true;
  82  E :    }
  83    :  };
  84    :  
  85    :  class ApplyBasicBlockSubGraphTransformTest : public testing::Test {
  86    :   public:
  87  E :    ApplyBasicBlockSubGraphTransformTest()
  88    :        : data_block_(NULL), code_block_(NULL) {
  89  E :    }
  90    :  
  91  E :    virtual void SetUp() {
  92    :      // Create some blocks to test with.
  93    :      data_block_ = block_graph_.AddBlock(
  94  E :          BlockGraph::DATA_BLOCK, sizeof(kDataBytes), "Data");
  95  E :      ASSERT_TRUE(data_block_ != NULL);
  96    :      code_block_ = block_graph_.AddBlock(
  97  E :          BlockGraph::CODE_BLOCK, sizeof(kCodeBytes), "Code");
  98  E :      ASSERT_TRUE(code_block_ != NULL);
  99    :  
 100    :      // Set up the data block.
 101    :      data_block_->SetData(reinterpret_cast<const uint8*>(&kDataBytes),
 102  E :                           sizeof(kDataBytes));
 103    :  
 104    :      // Set up the code block.
 105  E :      ASSERT_TRUE(code_block_->SetLabel(
 106    :          kOffsetOfCode,
 107    :          BlockGraph::Label("Code", BlockGraph::CODE_LABEL)));
 108  E :      code_block_->SetData(kCodeBytes, sizeof(kCodeBytes));
 109    :  
 110    :      // Set up the references
 111  E :      ASSERT_TRUE(
 112    :          data_block_->SetReference(kOffsetOfReferenceToCode,
 113    :                                    MakeReference(code_block_, kOffsetOfCode)));
 114  E :      ASSERT_TRUE(
 115    :          code_block_->SetReference(kOffsetOfReferenceToData,
 116    :                                    MakeReference(data_block_, kOffsetOfData)));
 117  E :    }
 118    :  
 119    :    static BlockGraph::Reference MakeReference(BlockGraph::Block* target,
 120  E :                                               BlockGraph::Offset offset) {
 121  E :      EXPECT_TRUE(target != NULL);
 122    :      return BlockGraph::Reference(BlockGraph::RELATIVE_REF,
 123    :                                   BlockGraph::Reference::kMaximumSize,
 124  E :                                   target, offset, offset);
 125  E :    }
 126    :  
 127    :   protected:
 128    :    BlockGraph block_graph_;
 129    :    BlockGraph::Block* data_block_;
 130    :    BlockGraph::Block* code_block_;
 131    :  };
 132    :  
 133    :  class MockBasicBlockSubGraphTransform :
 134    :      public BasicBlockSubGraphTransformInterface {
 135    :   public:
 136  E :    virtual ~MockBasicBlockSubGraphTransform() { }
 137    :  
 138  i :    virtual const char* name() const { return "MockBasicBlockSubGraphTransform"; }
 139    :  
 140    :    MOCK_METHOD2(TransformBasicBlockSubGraph,
 141  E :                 bool(BlockGraph*, BasicBlockSubGraph*));
 142    :  };
 143    :  
 144    :  }  // namespace
 145    :  
 146  E :  TEST_F(ApplyBlockGraphTransformTest, NormalTransformSucceeds) {
 147  E :    MockBlockGraphTransform transform;
 148    :    EXPECT_CALL(transform, TransformBlockGraph(_, _)).Times(1).
 149  E :        WillOnce(Return(true));
 150    :    EXPECT_TRUE(ApplyBlockGraphTransform(&transform,
 151    :                                         &block_graph_,
 152  E :                                         header_block_));
 153  E :  }
 154    :  
 155  E :  TEST_F(ApplyBlockGraphTransformTest, DeletingHeaderFails) {
 156  E :    MockBlockGraphTransform transform;
 157    :    EXPECT_CALL(transform, TransformBlockGraph(_, _)).Times(1).WillOnce(
 158  E :        Invoke(&transform, &MockBlockGraphTransform::DeleteHeader));
 159    :    EXPECT_FALSE(ApplyBlockGraphTransform(&transform,
 160    :                                          &block_graph_,
 161  E :                                          header_block_));
 162  E :  }
 163    :  
 164  E :  TEST_F(ApplyBasicBlockSubGraphTransformTest, TransformFails) {
 165    :    // Remember the block ids of the original blocks.
 166  E :    BlockGraph::BlockId data_block_id = data_block_->id();
 167  E :    BlockGraph::BlockId code_block_id = code_block_->id();
 168    :  
 169    :    // Apply an empty transform that reports failure.
 170  E :    MockBasicBlockSubGraphTransform transform;
 171    :    EXPECT_CALL(transform, TransformBasicBlockSubGraph(_, _)).Times(1).
 172  E :        WillOnce(Return(false));
 173    :    EXPECT_FALSE(ApplyBasicBlockSubGraphTransform(&transform,
 174    :                                                  &block_graph_,
 175    :                                                  code_block_,
 176  E :                                                  NULL));
 177    :  
 178    :    // The original block graph should be unchanged.
 179  E :    EXPECT_EQ(2U, block_graph_.blocks().size());
 180  E :    EXPECT_EQ(data_block_, block_graph_.GetBlockById(data_block_id));
 181  E :    EXPECT_EQ(code_block_, block_graph_.GetBlockById(code_block_id));
 182  E :  }
 183    :  
 184  E :  TEST_F(ApplyBasicBlockSubGraphTransformTest, EmptyTransformSucceeds) {
 185    :    // Remember the block ids of the original blocks.
 186  E :    BlockGraph::BlockId data_block_id = data_block_->id();
 187  E :    BlockGraph::BlockId code_block_id = code_block_->id();
 188    :  
 189    :    // Apply an empty transform that reports success.
 190  E :    MockBasicBlockSubGraphTransform transform;
 191  E :    BlockVector new_blocks;
 192    :    EXPECT_CALL(transform, TransformBasicBlockSubGraph(_, _)).Times(1).
 193  E :        WillOnce(Return(true));
 194    :    EXPECT_TRUE(ApplyBasicBlockSubGraphTransform(&transform,
 195    :                                                 &block_graph_,
 196    :                                                 code_block_,
 197  E :                                                 &new_blocks));
 198    :  
 199    :    // The code block should have been replaced with an equivalent one. We'll
 200    :    // have the same number of blocks, but the code block should no longer
 201    :    // be in the graph.
 202  E :    EXPECT_EQ(2U, block_graph_.blocks().size());
 203  E :    EXPECT_EQ(data_block_, block_graph_.GetBlockById(data_block_id));
 204  E :    EXPECT_EQ(NULL, block_graph_.GetBlockById(code_block_id));
 205    :  
 206    :    // Clean up our dangling pointer.
 207  E :    code_block_ = NULL;
 208    :  
 209    :    // Find the new block.
 210  E :    ASSERT_EQ(1U, new_blocks.size());
 211  E :    const BlockGraph::Block* new_block = new_blocks[0];
 212    :  
 213    :    // Validate the references.
 214  E :    EXPECT_EQ(1U, new_block->references().size());
 215  E :    BlockGraph::Reference ref;
 216  E :    EXPECT_TRUE(new_block->GetReference(kOffsetOfReferenceToData, &ref));
 217  E :    EXPECT_EQ(kOffsetOfData, ref.offset());
 218  E :    EXPECT_EQ(data_block_, ref.referenced());
 219    :  
 220    :    // Validate the referrers.
 221  E :    EXPECT_EQ(1U, new_block->referrers().size());
 222  E :    EXPECT_EQ(data_block_, new_block->referrers().begin()->first);
 223  E :    EXPECT_EQ(kOffsetOfReferenceToCode, new_block->referrers().begin()->second);
 224    :    EXPECT_TRUE(new_block->referrers().begin()->first->GetReference(
 225  E :        kOffsetOfReferenceToCode, &ref));
 226  E :    EXPECT_EQ(new_block, ref.referenced());
 227  E :  }
 228    :  
 229    :  }  // namespace block_graph

Coverage information generated Thu Jul 04 09:34:53 2013.