Coverage for /Syzygy/block_graph/transform_unittest.cc

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

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