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

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