Coverage for /Syzygy/pe/dia_browser_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
99.5%1992000.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    :  #include "syzygy/pe/dia_browser.h"
  15    :  
  16    :  #include <diacreate.h>
  17    :  
  18    :  #include "base/bind.h"
  19    :  #include "base/path_service.h"
  20    :  #include "base/files/file_path.h"
  21    :  #include "base/memory/scoped_ptr.h"
  22    :  #include "base/win/scoped_comptr.h"
  23    :  #include "gmock/gmock.h"
  24    :  #include "gtest/gtest.h"
  25    :  #include "syzygy/core/unittest_util.h"
  26    :  #include "syzygy/pe/dia_util.h"
  27    :  
  28    :  using base::win::ScopedComPtr;
  29    :  using testing::_;
  30    :  using testing::Return;
  31    :  
  32    :  namespace pe {
  33    :  
  34    :  using builder::Callback;
  35    :  using builder::Not;
  36    :  using builder::Opt;
  37    :  using builder::Or;
  38    :  using builder::Plus;
  39    :  using builder::Seq;
  40    :  using builder::Star;
  41    :  using builder::Tag;
  42    :  using builder::Tags;
  43    :  
  44    :  class PatternTest: public testing::Test {
  45    :   public:
  46  E :    PatternTest() {
  47  E :    }
  48    :  
  49    :    MOCK_METHOD3(OnMatch, DiaBrowser::BrowserDirective(
  50    :        const DiaBrowser&,
  51    :        const DiaBrowser::SymTagVector&,
  52  i :        const DiaBrowser::SymbolPtrVector&));
  53    :  
  54  E :    virtual void SetUp() {
  55  E :      on_match_ = base::Bind(&PatternTest::OnMatch, base::Unretained(this));
  56  E :    }
  57    :  
  58    :   protected:
  59    :    DiaBrowser::MatchCallback on_match_;
  60    :  };
  61    :  
  62    :  const wchar_t kPdbName[] = L"syzygy\\pe\\test_data\\test_dll.pdb";
  63    :  
  64    :  class DiaBrowserTest: public testing::Test {
  65    :   public:
  66    :  
  67  E :    DiaBrowserTest() {
  68  E :    }
  69    :  
  70    :    DiaBrowser::BrowserDirective OnPartialMatchTerminate(
  71    :        const DiaBrowser& dia_browser,
  72    :        const DiaBrowser::SymTagVector& tag_lineage,
  73  E :        const DiaBrowser::SymbolPtrVector& symbol_lineage) {
  74    :      // Call the 'OnPartialMatch' for bookkeeping reasons.
  75  E :      OnPartialMatch(dia_browser, tag_lineage, symbol_lineage);
  76  E :      if (!tag_lineage.empty() && tag_lineage.back() == SymTagUDT)
  77  E :        return DiaBrowser::kBrowserTerminatePath;
  78  E :      return DiaBrowser::kBrowserContinue;
  79  E :    }
  80    :  
  81    :    MOCK_METHOD3(OnPartialMatch, DiaBrowser::BrowserDirective(
  82    :        const DiaBrowser& dia_browser,
  83    :        const DiaBrowser::SymTagVector& tag_lineage,
  84  E :        const DiaBrowser::SymbolPtrVector& symbol_lineage));
  85    :  
  86    :    MOCK_METHOD3(OnFullMatch, DiaBrowser::BrowserDirective(
  87    :        const DiaBrowser& dia_browser,
  88    :        const DiaBrowser::SymTagVector& tag_lineage,
  89  E :        const DiaBrowser::SymbolPtrVector& symbol_lineage));
  90    :  
  91  E :    virtual void SetUp() {
  92    :      on_partial_match_term_ =
  93    :          base::Bind(&DiaBrowserTest::OnPartialMatchTerminate,
  94  E :                     base::Unretained(this));
  95    :      on_partial_match_ = base::Bind(&DiaBrowserTest::OnPartialMatch,
  96  E :                                     base::Unretained(this));
  97    :      on_full_match_ = base::Bind(&DiaBrowserTest::OnFullMatch,
  98  E :                                  base::Unretained(this));
  99    :  
 100  E :      if (!SUCCEEDED(dia_source_.CreateInstance(CLSID_DiaSource)))
 101  E :        ASSERT_HRESULT_SUCCEEDED(NoRegCoCreate(
 102    :            pe::kDiaDllName, CLSID_DiaSource, IID_IDiaDataSource,
 103    :            reinterpret_cast<void**>(&dia_source_)));
 104    :  
 105    :      HRESULT hr = dia_source_->loadDataFromPdb(
 106  E :          testing::GetSrcRelativePath(kPdbName).value().c_str());
 107  E :      ASSERT_HRESULT_SUCCEEDED(hr);
 108    :  
 109  E :      hr = dia_source_->openSession(dia_session_.Receive());
 110  E :      ASSERT_HRESULT_SUCCEEDED(hr);
 111    :  
 112  E :      hr = dia_session_->get_globalScope(global_.Receive());
 113  E :      ASSERT_HRESULT_SUCCEEDED(hr);
 114  E :    }
 115    :  
 116  E :    virtual void TearDown() {
 117  E :      global_.Release();
 118  E :      dia_session_.Release();
 119  E :      dia_source_.Release();
 120  E :    }
 121    :  
 122    :   protected:
 123    :    DiaBrowser::MatchCallback on_partial_match_term_;
 124    :    DiaBrowser::MatchCallback on_partial_match_;
 125    :    DiaBrowser::MatchCallback on_full_match_;
 126    :    ScopedComPtr<IDiaDataSource> dia_source_;
 127    :    ScopedComPtr<IDiaSession> dia_session_;
 128    :    ScopedComPtr<IDiaSymbol> global_;
 129    :  };
 130    :  
 131    :  }  // namespace
 132    :  
 133    :  namespace pe {
 134    :  
 135    :  class TestDiaBrowser : public DiaBrowser {
 136    :   public:
 137    :    using DiaBrowser::TestMatch;
 138    :  };
 139    :  
 140  E :  TEST_F(PatternTest, NullMatchingPatternIsInvalid) {
 141  E :    TestDiaBrowser dia_browser;
 142    :  
 143    :    // The pattern 'Compiland?' would match everything with a null match,
 144    :    // so it should be rejected.
 145  E :    EXPECT_FALSE(dia_browser.AddPattern(Opt(SymTagCompiland), on_match_));
 146  E :  }
 147    :  
 148  E :  TEST_F(PatternTest, Wildcard) {
 149  E :    TestDiaBrowser dia_browser;
 150    :  
 151  E :    ASSERT_TRUE(dia_browser.AddPattern(Tag(SymTagNull), on_match_));
 152    :  
 153    :    // The wild-card pattern should match every sym tag.
 154  E :    for (size_t i = kSymTagBegin; i < kSymTagEnd; ++i) {
 155  E :      SymTag sym_tag = static_cast<SymTag>(i);
 156  E :      std::vector<SymTag> sym_tags(1, sym_tag);
 157  E :      EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 158  E :    }
 159  E :  }
 160    :  
 161  E :  TEST_F(PatternTest, Seq) {
 162  E :    TestDiaBrowser dia_browser;
 163    :  
 164    :    // Set up pattern 'Compiland.Function.Block.Data'.
 165    :    ASSERT_TRUE(dia_browser.AddPattern(
 166    :        Seq(SymTagCompiland, SymTagFunction, SymTagBlock, SymTagData),
 167  E :        on_match_));
 168    :  
 169    :    // This exact pattern should match, but not any prefix of it, nor any
 170    :    // longer pattern containing it as a prefix.
 171  E :    std::vector<SymTag> sym_tags;
 172  E :    sym_tags.push_back(SymTagCompiland);
 173  E :    EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 174  E :    sym_tags.push_back(SymTagFunction);
 175  E :    EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 176  E :    sym_tags.push_back(SymTagBlock);
 177  E :    EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 178  E :    sym_tags.push_back(SymTagData);
 179  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 180  E :    sym_tags.push_back(SymTagData);
 181  E :    EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 182  E :  }
 183    :  
 184  E :  TEST_F(PatternTest, EmptySymTagBitSetRejected) {
 185  E :    TestDiaBrowser dia_browser;
 186    :  
 187    :    // A pattern with an element that can't match anything should be rejected.
 188  E :    EXPECT_FALSE(dia_browser.AddPattern(Not(SymTagNull), on_match_));
 189  E :    EXPECT_FALSE(dia_browser.AddPattern(Tags(SymTagBitSet()), on_match_));
 190  E :  }
 191    :  
 192  E :  TEST_F(PatternTest, Not) {
 193  E :    TestDiaBrowser dia_browser;
 194    :  
 195    :    // Set up pattern '[^Compiland]'
 196  E :    ASSERT_TRUE(dia_browser.AddPattern(Not(SymTagCompiland), on_match_));
 197    :  
 198    :    // This should match every SymTag *except* Compiland.
 199  E :    for (size_t i = kSymTagBegin; i < kSymTagEnd; ++i) {
 200  E :      SymTag sym_tag = static_cast<SymTag>(i);
 201  E :      std::vector<SymTag> sym_tags(1, sym_tag);
 202  E :      if (i == SymTagCompiland)
 203  E :        EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 204  E :      else
 205  E :        EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 206  E :    }
 207  E :  }
 208    :  
 209  E :  TEST_F(PatternTest, MultiArgNot) {
 210  E :    TestDiaBrowser dia_browser;
 211    :  
 212    :    // The multi-arg versions accept up to 8 inputs currently. Test
 213    :    // with a full set of inputs. The sym tags used here are consecutive
 214    :    // from kSymTagBegin.
 215    :    ASSERT_TRUE(dia_browser.AddPattern(Not(SymTagExe,
 216    :                                           SymTagCompiland,
 217    :                                           SymTagCompilandDetails,
 218    :                                           SymTagCompilandEnv,
 219    :                                           SymTagFunction,
 220    :                                           SymTagBlock,
 221    :                                           SymTagData,
 222    :                                           SymTagAnnotation),
 223  E :                                       on_match_));
 224    :  
 225    :    // Ensure the pattern doesn't match the first 8 symtags, but matches all
 226    :    // the rest.
 227  E :    for (size_t i = kSymTagBegin; i < kSymTagEnd; ++i) {
 228  E :      SymTag sym_tag = static_cast<SymTag>(i);
 229  E :      std::vector<SymTag> sym_tags(1, sym_tag);
 230  E :      if (i <= SymTagAnnotation)
 231  E :        EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 232  E :      else
 233  E :        EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 234  E :    }
 235  E :  }
 236    :  
 237  E :  TEST_F(PatternTest, MultiArgTags) {
 238  E :    TestDiaBrowser dia_browser;
 239    :  
 240    :    // The multi-arg versions accept up to 8 inputs currently. Test
 241    :    // with a full set of inputs. The sym tags used here are consecutive
 242    :    // from kSymTagBegin.
 243    :    ASSERT_TRUE(dia_browser.AddPattern(Tags(SymTagExe,
 244    :                                            SymTagCompiland,
 245    :                                            SymTagCompilandDetails,
 246    :                                            SymTagCompilandEnv,
 247    :                                            SymTagFunction,
 248    :                                            SymTagBlock,
 249    :                                            SymTagData,
 250    :                                            SymTagAnnotation),
 251  E :                                       on_match_));
 252    :  
 253    :    // Ensure the pattern matches the first 8 symtags, but does not match all
 254    :    // the rest.
 255  E :    for (size_t i = kSymTagBegin; i < kSymTagEnd; ++i) {
 256  E :      SymTag sym_tag = static_cast<SymTag>(i);
 257  E :      std::vector<SymTag> sym_tags(1, sym_tag);
 258  E :      if (i <= SymTagAnnotation)
 259  E :        EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 260  E :      else
 261  E :        EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 262  E :    }
 263  E :  }
 264    :  
 265  E :  TEST_F(PatternTest, Opt) {
 266  E :    TestDiaBrowser dia_browser;
 267    :  
 268    :    // Set up pattern 'Compiland?.Function'.
 269    :    ASSERT_TRUE(dia_browser.AddPattern(
 270  E :        Seq(Opt(SymTagCompiland), SymTagFunction), on_match_));
 271    :  
 272  E :    std::vector<SymTag> sym_tags;
 273    :  
 274    :    // 'Compiland' should not match.
 275  E :    sym_tags.push_back(SymTagCompiland);
 276  E :    EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 277    :  
 278    :    // 'Compiland.Function' should match.
 279  E :    sym_tags.push_back(SymTagFunction);
 280  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 281    :  
 282    :    // 'Function' should match.
 283  E :    sym_tags.clear();
 284  E :    sym_tags.push_back(SymTagFunction);
 285  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 286  E :  }
 287    :  
 288  E :  TEST_F(PatternTest, Star) {
 289  E :    TestDiaBrowser dia_browser;
 290    :  
 291    :    // Set up pattern 'Compiland.Block*.Data'.
 292    :    ASSERT_TRUE(dia_browser.AddPattern(
 293  E :        Seq(SymTagCompiland, Star(SymTagBlock), SymTagData), on_match_));
 294    :  
 295  E :    std::vector<SymTag> sym_tags;
 296    :  
 297    :    // 'Compiland' should not match.
 298  E :    sym_tags.push_back(SymTagCompiland);
 299  E :    EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 300    :  
 301    :    // 'Compiland.Data' should match.
 302  E :    sym_tags.push_back(SymTagData);
 303  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 304    :  
 305    :    // 'Compiland.Block.Data' should match, with Block repeated
 306    :    // arbitrarily many times. We can only check a finite number, obviously.
 307  E :    for (size_t i = 0; i < 10; ++i) {
 308  E :      sym_tags.pop_back();
 309  E :      sym_tags.push_back(SymTagBlock);
 310  E :      sym_tags.push_back(SymTagData);
 311  E :      EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 312  E :    }
 313  E :  }
 314    :  
 315  E :  TEST_F(PatternTest, Plus) {
 316  E :    TestDiaBrowser dia_browser;
 317    :  
 318    :    // Set up pattern 'Compiland.Block+.Data'.
 319    :    ASSERT_TRUE(dia_browser.AddPattern(
 320  E :        Seq(SymTagCompiland, Plus(SymTagBlock), SymTagData), on_match_));
 321    :  
 322  E :    std::vector<SymTag> sym_tags;
 323    :  
 324    :    // 'Compiland' should not match'.
 325  E :    sym_tags.push_back(SymTagCompiland);
 326  E :    EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 327    :  
 328    :    // 'Compiland.Data' should not match.
 329  E :    sym_tags.push_back(SymTagData);
 330  E :    EXPECT_EQ(0, dia_browser.TestMatch(sym_tags));
 331    :  
 332    :    // 'Compiland.Block.Data' should match, with Block repeated
 333    :    // arbitrarily many times. We can only check a finite number, obviously.
 334  E :    for (size_t i = 0; i < 10; ++i) {
 335  E :      sym_tags.pop_back();
 336  E :      sym_tags.push_back(SymTagBlock);
 337  E :      sym_tags.push_back(SymTagData);
 338  E :      EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 339  E :    }
 340  E :  }
 341    :  
 342  E :  TEST_F(PatternTest, Or) {
 343  E :    TestDiaBrowser dia_browser;
 344    :  
 345    :    // Add an 'or' pattern that uses all 8 arguments.
 346    :    ASSERT_TRUE(dia_browser.AddPattern(
 347    :        Or(SymTagCompiland,
 348    :           Seq(SymTagData, SymTagCompiland, SymTagExe),
 349    :           Seq(SymTagExe, SymTagCompiland),
 350    :           Seq(SymTagExe, SymTagData),
 351    :           Seq(SymTagExe, SymTagExe),
 352    :           Seq(SymTagLabel, SymTagCompiland),
 353    :           Seq(SymTagLabel, SymTagLabel, SymTagLabel),
 354    :           SymTagVTable),
 355  E :        on_match_));
 356    :  
 357  E :    std::vector<SymTag> sym_tags;
 358  E :    sym_tags.push_back(SymTagCompiland);
 359  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 360    :  
 361  E :    sym_tags.clear();
 362  E :    sym_tags.push_back(SymTagData);
 363  E :    sym_tags.push_back(SymTagCompiland);
 364  E :    sym_tags.push_back(SymTagExe);
 365  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 366    :  
 367  E :    sym_tags.clear();
 368  E :    sym_tags.push_back(SymTagExe);
 369  E :    sym_tags.push_back(SymTagCompiland);
 370  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 371    :  
 372  E :    sym_tags.back() = SymTagData;
 373  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 374    :  
 375  E :    sym_tags.back() = SymTagExe;
 376  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 377    :  
 378  E :    sym_tags.clear();
 379  E :    sym_tags.push_back(SymTagLabel);
 380  E :    sym_tags.push_back(SymTagCompiland);
 381  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 382    :  
 383  E :    sym_tags.back() = SymTagLabel;
 384  E :    sym_tags.push_back(SymTagLabel);
 385  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 386    :  
 387  E :    sym_tags.clear();
 388  E :    sym_tags.push_back(SymTagVTable);
 389  E :    EXPECT_EQ(1, dia_browser.TestMatch(sym_tags));
 390  E :  }
 391    :  
 392  E :  TEST_F(DiaBrowserTest, AllCompilandSymbolsExplored) {
 393  E :    TestDiaBrowser dia_browser;
 394    :  
 395  E :    dia_browser.AddPattern(Tag(SymTagCompiland), on_full_match_);
 396    :  
 397    :    EXPECT_CALL(*this, OnFullMatch(_, _, _)).Times(154).
 398  E :        WillRepeatedly(Return(DiaBrowser::kBrowserContinue));
 399  E :    dia_browser.Browse(global_.get());
 400  E :  }
 401    :  
 402  E :  TEST_F(DiaBrowserTest, AllDataSymbolsExplored) {
 403  E :    TestDiaBrowser dia_browser;
 404    :  
 405    :    // Search for (Wildcard)*.Data
 406    :    dia_browser.AddPattern(Seq(Star(SymTagNull), SymTagData),
 407  E :                           on_full_match_);
 408    :  
 409    :    EXPECT_CALL(*this, OnFullMatch(_, _, _)).Times(2883).
 410  E :        WillRepeatedly(Return(DiaBrowser::kBrowserContinue));
 411  E :    dia_browser.Browse(global_.get());
 412  E :  }
 413    :  
 414  E :  TEST_F(DiaBrowserTest, AllDataSymbolsExploredWithPopCallbacks) {
 415  E :    TestDiaBrowser dia_browser;
 416    :  
 417    :    // Search for (Wildcard)*.Data
 418    :    dia_browser.AddPattern(Seq(Star(SymTagNull), SymTagData),
 419  E :                           on_full_match_, on_full_match_);
 420    :  
 421    :    EXPECT_CALL(*this, OnFullMatch(_, _, _)).Times(2 * 2883).
 422  E :        WillRepeatedly(Return(DiaBrowser::kBrowserContinue));
 423  E :    dia_browser.Browse(global_.get());
 424  E :  }
 425    :  
 426  E :  TEST_F(DiaBrowserTest, SomePathsTerminated) {
 427  E :    TestDiaBrowser dia_browser;
 428    :  
 429    :    // Search for UDT.Data and Enum.Data. This will find:
 430    :    //    428 Enum.Data
 431    :    //   1077 UDT.Data
 432    :    // However, we terminate partial matches when they get to
 433    :    // UDT.
 434    :    dia_browser.AddPattern(Seq(Callback(Or(SymTagEnum, SymTagUDT),
 435    :                                        on_partial_match_term_),
 436    :                               SymTagData),
 437  E :                           on_full_match_);
 438    :  
 439    :    // With VC++ 2010, OnPartialMatch hits 174 nodes.
 440    :    static const size_t kNumPartialMatches = 174;
 441    :  
 442    :    // Only the 428 Enum.Data full matches should be hit.
 443    :    static const size_t kNumFullMatches = 428;
 444    :  
 445    :    EXPECT_CALL(*this, OnPartialMatch(_, _, _)).Times(kNumPartialMatches).
 446  E :        WillRepeatedly(Return(DiaBrowser::kBrowserContinue));
 447    :    EXPECT_CALL(*this, OnFullMatch(_, _, _)).Times(kNumFullMatches).
 448  E :        WillRepeatedly(Return(DiaBrowser::kBrowserContinue));
 449  E :    dia_browser.Browse(global_.get());
 450  E :  }
 451    :  
 452    :  }  // namespace pe

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