Index: base/win/pe_image_unittest.cc |
diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc |
index af4209be18a89c9d845031f56e810a0d2a2fea40..fe490d959fffc222a71b268d06c4493107822362 100644 |
--- a/base/win/pe_image_unittest.cc |
+++ b/base/win/pe_image_unittest.cc |
@@ -3,6 +3,8 @@ |
// found in the LICENSE file. |
// This file contains unit tests for PEImage. |
+#include <algorithm> |
+#include <vector> |
#include "testing/gtest/include/gtest/gtest.h" |
#include "base/win/pe_image.h" |
@@ -11,6 +13,139 @@ |
namespace base { |
namespace win { |
+namespace { |
+ |
+class Expectations { |
rvargas (doing something else)
2015/02/24 01:52:20
Please move this outside of the namespaces...
Will Harris
2015/02/24 19:00:28
Done.
rvargas (doing something else)
2015/02/24 20:03:22
Sorry, what I meant was to move the anonymous name
|
+ public: |
+ enum Value { |
+ sections = 0, |
rvargas (doing something else)
2015/02/24 01:52:21
Shout for enums
Will Harris
2015/02/24 19:00:29
Done.
|
+ imports_dlls, |
+ delay_dlls, |
+ exports, |
+ imports, |
+ delay_imports, |
+ relocs |
+ }; |
+ |
+ enum Arch { |
+ ARCH_X86 = 0, |
+ ARCH_X64, |
+ ARCH_X86_ON_X64, |
+ ARCH_X64_ON_X64, |
+ ARCH_X86_ON_X86, |
+ ARCH_ALL |
+ }; |
+ |
+ int GetExpectation(Value value); |
+ void SetOverride(Value value, Version version, Arch arch, int count); |
rvargas (doing something else)
2015/02/24 01:52:20
... so that it becomes obvious what Version is
Will Harris
2015/02/24 19:00:28
Done.
|
+ void SetOverride(Value value, Version version, int count); |
+ void SetOverride(Value value, Arch arch, int count); |
+ |
+ void SetDefault(Value value, int count) { |
+ SetOverride(value, VERSION_WIN_LAST, ARCH_ALL, count); |
+ } |
+ |
+ Expectations() { |
rvargas (doing something else)
2015/02/24 01:52:20
nit: The constructor goes before all other methods
Will Harris
2015/02/24 19:00:29
Done.
|
+ my_version_ = GetVersion(); |
+#if defined(ARCH_CPU_64_BITS) |
+ my_arch_ = ARCH_X64_ON_X64; |
rvargas (doing something else)
2015/02/24 01:52:20
X64?
Will Harris
2015/02/24 19:00:28
Done.
|
+#else |
+ OSInfo* os_info = OSInfo::GetInstance(); |
+ if (os_info->wow64_status() == OSInfo::WOW64_DISABLED) |
+ my_arch_ = ARCH_X86_ON_X86; |
rvargas (doing something else)
2015/02/24 01:52:21
X86?... Arch seems to have too many values :)
Will Harris
2015/02/24 19:00:28
Acknowledged.
|
+ else |
+ my_arch_ = ARCH_X86_ON_X64; |
+#endif |
+ } |
+ |
+ private: |
+ class Override { |
+ public: |
+ enum MatchType { MATCH_VERSION, MATCH_ARCH, MATCH_BOTH, MATCH_NONE }; |
+ explicit Override(Value value, Version version, Arch arch, int count) |
rvargas (doing something else)
2015/02/24 01:52:20
no need for explicit.
rvargas (doing something else)
2015/02/24 01:52:21
nit: add empty line before this one.
Will Harris
2015/02/24 19:00:28
Done.
Will Harris
2015/02/24 19:00:28
Done.
|
+ : value_(value), version_(version), arch_(arch), count_(count){}; |
rvargas (doing something else)
2015/02/24 01:52:21
nit: space before {}... and this is not a single l
Will Harris
2015/02/24 19:00:28
Done.
|
+ |
+ bool Matches(Value value, Version version, Arch arch, MatchType type) { |
+ if (value_ != value) |
+ return false; |
+ switch (type) { |
rvargas (doing something else)
2015/02/24 01:52:21
nit: empty line before this
Will Harris
2015/02/24 19:00:28
Done.
|
+ case MATCH_BOTH: |
+ return MatchesVersion(version) && MatchesArch(arch); |
+ break; |
rvargas (doing something else)
2015/02/24 01:52:21
nit: no break after return
Will Harris
2015/02/24 19:00:28
Done.
|
+ case MATCH_ARCH: |
+ return MatchesArch(arch) && version_ == VERSION_WIN_LAST; |
+ break; |
+ case MATCH_VERSION: |
+ return MatchesVersion(version) && arch_ == ARCH_ALL; |
+ break; |
+ case MATCH_NONE: |
+ return (arch_ == ARCH_ALL && version_ == VERSION_WIN_LAST); |
+ break; |
+ } |
+ return false; |
+ } |
+ |
+ int GetCount() { return count_; } |
+ |
+ private: |
+ bool MatchesArch(Arch arch) { |
+ switch (arch) { |
+ case ARCH_X64_ON_X64: |
+ return (arch_ == ARCH_X64_ON_X64 || arch_ == ARCH_X64); |
+ break; |
+ case ARCH_X86_ON_X86: |
+ return (arch_ == ARCH_X86_ON_X86 || arch_ == ARCH_X86); |
+ break; |
+ case ARCH_X86_ON_X64: |
+ return (arch_ == ARCH_X86_ON_X64 || arch_ == ARCH_X86); |
+ break; |
+ default: |
+ return false; |
+ } |
+ } |
+ |
+ bool MatchesVersion(Version version) { return (version == version_); } |
+ |
+ Value value_; |
+ Version version_; |
+ Arch arch_; |
+ int count_; |
+ }; |
+ |
+ bool MatchesMyArch(Arch arch); |
+ |
+ std::vector<Override> overrides_; |
+ Arch my_arch_; |
+ Version my_version_; |
+}; |
+ |
+int Expectations::GetExpectation(Value value) { |
+ // Prefer OS version specificity over Arch specificity. |
+ for (auto type : {Expectations::Override::MATCH_BOTH, |
rvargas (doing something else)
2015/02/24 01:52:20
nit: space after {
Will Harris
2015/02/24 19:00:28
Done. Strange, all these are being done by clang
|
+ Expectations::Override::MATCH_VERSION, |
+ Expectations::Override::MATCH_ARCH, |
+ Expectations::Override::MATCH_NONE}) |
rvargas (doing something else)
2015/02/24 01:52:21
nit: needs {}
Will Harris
2015/02/24 19:00:28
Done.
|
+ for (auto or : overrides_) |
rvargas (doing something else)
2015/02/24 01:52:20
nit: needs {}
rvargas (doing something else)
2015/02/24 01:52:21
nit: use a name longer than "or" (in general, name
Will Harris
2015/02/24 19:00:28
Done.
Will Harris
2015/02/24 19:00:29
Done.
|
+ if (or.Matches(value, my_version_, my_arch_, type)) |
+ return or.GetCount(); |
+ return 0; |
rvargas (doing something else)
2015/02/24 01:52:21
Shouldn't this be a failure instead?
Will Harris
2015/02/24 19:00:29
returns -1 which makes it never possible in the te
|
+} |
+ |
+void Expectations::SetOverride(Value value, |
+ Version version, |
+ Arch arch, |
+ int count) { |
+ overrides_.push_back(Override(value, version, arch, count)); |
+} |
+ |
+void Expectations::SetOverride(Value value, Version version, int count) { |
+ SetOverride(value, version, ARCH_ALL, count); |
+} |
+ |
+void Expectations::SetOverride(Value value, Arch arch, int count) { |
+ SetOverride(value, VERSION_WIN_LAST, arch, count); |
+} |
+ |
// Just counts the number of invocations. |
bool ExportsCallback(const PEImage &image, |
DWORD ordinal, |
@@ -83,167 +218,60 @@ bool DelayImportChunksCallback(const PEImage &image, |
return true; |
} |
-// Identifiers for the set of supported expectations. |
-enum ExpectationSet { |
- WIN_2K_SET, |
- WIN_XP_SET, |
- WIN_VISTA_SET, |
- WIN_7_SET, |
- WIN_8_SET, |
- UNSUPPORTED_SET, |
-}; |
- |
-// We'll be using some known values for the tests. |
-enum Value { |
- sections = 0, |
- imports_dlls, |
- delay_dlls, |
- exports, |
- imports, |
- delay_imports, |
- relocs |
-}; |
- |
-ExpectationSet GetExpectationSet(DWORD os) { |
- if (os == 50) |
- return WIN_2K_SET; |
- if (os == 51) |
- return WIN_XP_SET; |
- if (os == 60) |
- return WIN_VISTA_SET; |
- if (os == 61) |
- return WIN_7_SET; |
- if (os >= 62) |
- return WIN_8_SET; |
- return UNSUPPORTED_SET; |
-} |
- |
-// Retrieves the expected value from advapi32.dll based on the OS. |
-int GetExpectedValue(Value value, DWORD os) { |
- const int xp_delay_dlls = 2; |
- const int xp_exports = 675; |
- const int xp_imports = 422; |
- const int xp_delay_imports = 8; |
- const int xp_relocs = 9180; |
- const int vista_delay_dlls = 4; |
- const int vista_exports = 799; |
- const int vista_imports = 476; |
- const int vista_delay_imports = 24; |
- const int vista_relocs = 10188; |
- const int w2k_delay_dlls = 0; |
- const int w2k_exports = 566; |
- const int w2k_imports = 357; |
- const int w2k_delay_imports = 0; |
- const int w2k_relocs = 7388; |
- const int win7_delay_dlls = 7; |
- const int win7_exports = 806; |
- const int win7_imports = 568; |
- const int win7_delay_imports = 71; |
- int win7_relocs = 7812; |
- int win7_sections = 4; |
- const int win8_delay_dlls = 9; |
- const int win8_exports = 806; |
- const int win8_imports = 568; |
- const int win8_delay_imports = 113; |
- const int win8_relocs = 9478; |
- int win8_sections = 4; |
- int win8_import_dlls = 17; |
- |
- base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); |
- // 32-bit process on a 32-bit system. |
- if (os_info->architecture() == base::win::OSInfo::X86_ARCHITECTURE) { |
- win8_sections = 5; |
- win8_import_dlls = 19; |
- |
- // 64-bit process on a 64-bit system. |
- } else if (os_info->wow64_status() == base::win::OSInfo::WOW64_DISABLED) { |
- win7_sections = 6; |
- win7_relocs = 2712; |
- } |
- |
- // Contains the expected value, for each enumerated property (Value), and the |
- // OS version: [Value][os_version] |
- const int expected[][5] = { |
- {4, 4, 4, win7_sections, win8_sections}, |
- {3, 3, 3, 13, win8_import_dlls}, |
- {w2k_delay_dlls, xp_delay_dlls, vista_delay_dlls, win7_delay_dlls, |
- win8_delay_dlls}, |
- {w2k_exports, xp_exports, vista_exports, win7_exports, win8_exports}, |
- {w2k_imports, xp_imports, vista_imports, win7_imports, win8_imports}, |
- {w2k_delay_imports, xp_delay_imports, |
- vista_delay_imports, win7_delay_imports, win8_delay_imports}, |
- {w2k_relocs, xp_relocs, vista_relocs, win7_relocs, win8_relocs} |
- }; |
- COMPILE_ASSERT(arraysize(expected[0]) == UNSUPPORTED_SET, |
- expected_value_set_mismatch); |
- |
- if (value > relocs) |
- return 0; |
- ExpectationSet expected_set = GetExpectationSet(os); |
- if (expected_set >= arraysize(expected)) { |
- // This should never happen. Log a failure if it does. |
- EXPECT_NE(UNSUPPORTED_SET, expected_set); |
- expected_set = WIN_2K_SET; |
- } |
- |
- return expected[value][expected_set]; |
-} |
- |
- |
-// TODO(jschuh): crbug.com/167707 Need to fix test on Win64 bots |
-#if defined(OS_WIN) && defined(ARCH_CPU_X86_64) |
-#define MAYBE_EnumeratesPE DISABLED_EnumeratesPE |
-#else |
-#define MAYBE_EnumeratesPE EnumeratesPE |
-#endif |
+} // namespace |
// Tests that we are able to enumerate stuff from a PE file, and that |
// the actual number of items found is within the expected range. |
-TEST(PEImageTest, MAYBE_EnumeratesPE) { |
- HMODULE module = LoadLibrary(L"advapi32.dll"); |
+TEST(PEImageTest, EnumeratesPE) { |
+ Expectations expectations; |
+ |
+ // Default expectations. |
+ expectations.SetDefault(Expectations::sections, 5); |
+ expectations.SetDefault(Expectations::imports_dlls, 1); |
+ expectations.SetDefault(Expectations::delay_dlls, 1); |
+ expectations.SetDefault(Expectations::exports, 1); |
+ expectations.SetDefault(Expectations::imports, 63); |
+ expectations.SetDefault(Expectations::delay_imports, 2); |
+ expectations.SetDefault(Expectations::relocs, 1584); |
+ |
+ // 64-bit expectations (taken from win_chromium_x64_rel_ng). |
rvargas (doing something else)
2015/02/24 01:52:20
nit: Don't add comments that are prone to be stale
Will Harris
2015/02/24 19:00:28
Done.
|
+ expectations.SetOverride(Expectations::sections, Expectations::ARCH_X64, 6); |
+ expectations.SetOverride(Expectations::imports, Expectations::ARCH_X64, 66); |
+ expectations.SetOverride(Expectations::relocs, Expectations::ARCH_X64, 630); |
+ |
+ HMODULE module = LoadLibrary(L"pe_image_test.dll"); |
rvargas (doing something else)
2015/02/24 01:52:21
If we want to at least keep the same coverage leve
Will Harris
2015/02/24 19:00:28
Done.
|
ASSERT_TRUE(NULL != module); |
PEImage pe(module); |
int count = 0; |
EXPECT_TRUE(pe.VerifyMagic()); |
- DWORD os = pe.GetNTHeaders()->OptionalHeader.MajorOperatingSystemVersion; |
- os = os * 10 + pe.GetNTHeaders()->OptionalHeader.MinorOperatingSystemVersion; |
- |
- // Skip this test for unsupported OS versions. |
- if (GetExpectationSet(os) == UNSUPPORTED_SET) |
- return; |
- |
pe.EnumSections(SectionsCallback, &count); |
- EXPECT_EQ(GetExpectedValue(sections, os), count); |
+ EXPECT_EQ(expectations.GetExpectation(Expectations::sections), count); |
count = 0; |
pe.EnumImportChunks(ImportChunksCallback, &count); |
- EXPECT_EQ(GetExpectedValue(imports_dlls, os), count); |
+ EXPECT_EQ(expectations.GetExpectation(Expectations::imports_dlls), count); |
count = 0; |
pe.EnumDelayImportChunks(DelayImportChunksCallback, &count); |
- EXPECT_EQ(GetExpectedValue(delay_dlls, os), count); |
+ EXPECT_EQ(expectations.GetExpectation(Expectations::delay_dlls), count); |
count = 0; |
pe.EnumExports(ExportsCallback, &count); |
- EXPECT_GT(count, GetExpectedValue(exports, os) - 20); |
- EXPECT_LT(count, GetExpectedValue(exports, os) + 100); |
+ EXPECT_EQ(expectations.GetExpectation(Expectations::exports), count); |
count = 0; |
pe.EnumAllImports(ImportsCallback, &count); |
- EXPECT_GT(count, GetExpectedValue(imports, os) - 20); |
- EXPECT_LT(count, GetExpectedValue(imports, os) + 100); |
+ EXPECT_EQ(expectations.GetExpectation(Expectations::imports), count); |
count = 0; |
pe.EnumAllDelayImports(ImportsCallback, &count); |
- EXPECT_GT(count, GetExpectedValue(delay_imports, os) - 2); |
- EXPECT_LT(count, GetExpectedValue(delay_imports, os) + 8); |
+ EXPECT_EQ(expectations.GetExpectation(Expectations::delay_imports), count); |
count = 0; |
pe.EnumRelocs(RelocsCallback, &count); |
- EXPECT_GT(count, GetExpectedValue(relocs, os) - 150); |
- EXPECT_LT(count, GetExpectedValue(relocs, os) + 1500); |
+ EXPECT_EQ(expectations.GetExpectation(Expectations::relocs), count); |
FreeLibrary(module); |
} |