1 /* 2 * Copyright 2010 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/base/gunit.h" 12 #include "webrtc/base/pathutils.h" 13 #include "webrtc/base/scoped_ptr.h" 14 #include "webrtc/base/win32toolhelp.h" 15 16 namespace rtc { 17 18 typedef struct { 19 // Required to match the toolhelp api struct 'design'. 20 DWORD dwSize; 21 int a; 22 uint32 b; 23 } TestData; 24 25 class Win32ToolhelpTest : public testing::Test { 26 public: 27 Win32ToolhelpTest() { 28 } 29 30 HANDLE AsHandle() { 31 return reinterpret_cast<HANDLE>(this); 32 } 33 34 static Win32ToolhelpTest* AsFixture(HANDLE handle) { 35 return reinterpret_cast<Win32ToolhelpTest*>(handle); 36 } 37 38 static bool First(HANDLE handle, TestData* d) { 39 Win32ToolhelpTest* tst = Win32ToolhelpTest::AsFixture(handle); 40 // This method should be called only once for every test. 41 // If it is called more than once it return false which 42 // should break the test. 43 EXPECT_EQ(0, tst->first_called_); // Just to be safe. 44 if (tst->first_called_ > 0) { 45 return false; 46 } 47 48 *d = kTestData[0]; 49 tst->index_ = 1; 50 ++(tst->first_called_); 51 return true; 52 } 53 54 static bool Next(HANDLE handle, TestData* d) { 55 Win32ToolhelpTest* tst = Win32ToolhelpTest::AsFixture(handle); 56 ++(tst->next_called_); 57 58 if (tst->index_ >= kTestDataSize) { 59 return FALSE; 60 } 61 62 *d = kTestData[tst->index_]; 63 ++(tst->index_); 64 return true; 65 } 66 67 static bool Fail(HANDLE handle, TestData* d) { 68 Win32ToolhelpTest* tst = Win32ToolhelpTest::AsFixture(handle); 69 ++(tst->fail_called_); 70 return false; 71 } 72 73 static bool CloseHandle(HANDLE handle) { 74 Win32ToolhelpTest* tst = Win32ToolhelpTest::AsFixture(handle); 75 ++(tst->close_handle_called_); 76 return true; 77 } 78 79 protected: 80 virtual void SetUp() { 81 fail_called_ = 0; 82 first_called_ = 0; 83 next_called_ = 0; 84 close_handle_called_ = 0; 85 index_ = 0; 86 } 87 88 static bool AllZero(const TestData& data) { 89 return data.dwSize == 0 && data.a == 0 && data.b == 0; 90 } 91 92 static bool Equals(const TestData& expected, const TestData& actual) { 93 return expected.dwSize == actual.dwSize 94 && expected.a == actual.a 95 && expected.b == actual.b; 96 } 97 98 bool CheckCallCounters(int first, int next, int fail, int close) { 99 bool match = first_called_ == first && next_called_ == next 100 && fail_called_ == fail && close_handle_called_ == close; 101 102 if (!match) { 103 LOG(LS_ERROR) << "Expected: (" 104 << first << ", " 105 << next << ", " 106 << fail << ", " 107 << close << ")"; 108 109 LOG(LS_ERROR) << "Actual: (" 110 << first_called_ << ", " 111 << next_called_ << ", " 112 << fail_called_ << ", " 113 << close_handle_called_ << ")"; 114 } 115 return match; 116 } 117 118 static const int kTestDataSize = 3; 119 static const TestData kTestData[]; 120 int index_; 121 int first_called_; 122 int fail_called_; 123 int next_called_; 124 int close_handle_called_; 125 }; 126 127 const TestData Win32ToolhelpTest::kTestData[] = { 128 {1, 1, 1}, {2, 2, 2}, {3, 3, 3} 129 }; 130 131 132 class TestTraits { 133 public: 134 typedef TestData Type; 135 136 static bool First(HANDLE handle, Type* t) { 137 return Win32ToolhelpTest::First(handle, t); 138 } 139 140 static bool Next(HANDLE handle, Type* t) { 141 return Win32ToolhelpTest::Next(handle, t); 142 } 143 144 static bool CloseHandle(HANDLE handle) { 145 return Win32ToolhelpTest::CloseHandle(handle); 146 } 147 }; 148 149 class BadFirstTraits { 150 public: 151 typedef TestData Type; 152 153 static bool First(HANDLE handle, Type* t) { 154 return Win32ToolhelpTest::Fail(handle, t); 155 } 156 157 static bool Next(HANDLE handle, Type* t) { 158 // This should never be called. 159 ADD_FAILURE(); 160 return false; 161 } 162 163 static bool CloseHandle(HANDLE handle) { 164 return Win32ToolhelpTest::CloseHandle(handle); 165 } 166 }; 167 168 class BadNextTraits { 169 public: 170 typedef TestData Type; 171 172 static bool First(HANDLE handle, Type* t) { 173 return Win32ToolhelpTest::First(handle, t); 174 } 175 176 static bool Next(HANDLE handle, Type* t) { 177 return Win32ToolhelpTest::Fail(handle, t); 178 } 179 180 static bool CloseHandle(HANDLE handle) { 181 return Win32ToolhelpTest::CloseHandle(handle); 182 } 183 }; 184 185 // The toolhelp in normally inherited but most of 186 // these tests only excercise the methods from the 187 // traits therefore I use a typedef to make the 188 // test code easier to read. 189 typedef rtc::ToolhelpEnumeratorBase<TestTraits> EnumeratorForTest; 190 191 TEST_F(Win32ToolhelpTest, TestNextWithInvalidCtorHandle) { 192 EnumeratorForTest t(INVALID_HANDLE_VALUE); 193 194 EXPECT_FALSE(t.Next()); 195 EXPECT_TRUE(CheckCallCounters(0, 0, 0, 0)); 196 } 197 198 // Tests that Next() returns false if the first-pointer 199 // function fails. 200 TEST_F(Win32ToolhelpTest, TestNextFirstFails) { 201 typedef rtc::ToolhelpEnumeratorBase<BadFirstTraits> BadEnumerator; 202 rtc::scoped_ptr<BadEnumerator> t(new BadEnumerator(AsHandle())); 203 204 // If next ever fails it shall always fail. 205 EXPECT_FALSE(t->Next()); 206 EXPECT_FALSE(t->Next()); 207 EXPECT_FALSE(t->Next()); 208 t.reset(); 209 EXPECT_TRUE(CheckCallCounters(0, 0, 1, 1)); 210 } 211 212 // Tests that Next() returns false if the next-pointer 213 // function fails. 214 TEST_F(Win32ToolhelpTest, TestNextNextFails) { 215 typedef rtc::ToolhelpEnumeratorBase<BadNextTraits> BadEnumerator; 216 rtc::scoped_ptr<BadEnumerator> t(new BadEnumerator(AsHandle())); 217 218 // If next ever fails it shall always fail. No more calls 219 // shall be dispatched to Next(...). 220 EXPECT_TRUE(t->Next()); 221 EXPECT_FALSE(t->Next()); 222 EXPECT_FALSE(t->Next()); 223 t.reset(); 224 EXPECT_TRUE(CheckCallCounters(1, 0, 1, 1)); 225 } 226 227 228 // Tests that current returns an object is all zero's 229 // if Next() hasn't been called. 230 TEST_F(Win32ToolhelpTest, TestCurrentNextNotCalled) { 231 rtc::scoped_ptr<EnumeratorForTest> t(new EnumeratorForTest(AsHandle())); 232 EXPECT_TRUE(AllZero(t->current())); 233 t.reset(); 234 EXPECT_TRUE(CheckCallCounters(0, 0, 0, 1)); 235 } 236 237 // Tests the simple everything works path through the code. 238 TEST_F(Win32ToolhelpTest, TestCurrentNextCalled) { 239 rtc::scoped_ptr<EnumeratorForTest> t(new EnumeratorForTest(AsHandle())); 240 241 EXPECT_TRUE(t->Next()); 242 EXPECT_TRUE(Equals(t->current(), kTestData[0])); 243 EXPECT_TRUE(t->Next()); 244 EXPECT_TRUE(Equals(t->current(), kTestData[1])); 245 EXPECT_TRUE(t->Next()); 246 EXPECT_TRUE(Equals(t->current(), kTestData[2])); 247 EXPECT_FALSE(t->Next()); 248 t.reset(); 249 EXPECT_TRUE(CheckCallCounters(1, 3, 0, 1)); 250 } 251 252 TEST_F(Win32ToolhelpTest, TestCurrentProcess) { 253 WCHAR buf[MAX_PATH]; 254 GetModuleFileName(NULL, buf, ARRAY_SIZE(buf)); 255 std::wstring name = ToUtf16(Pathname(ToUtf8(buf)).filename()); 256 257 rtc::ProcessEnumerator processes; 258 bool found = false; 259 while (processes.Next()) { 260 if (!name.compare(processes.current().szExeFile)) { 261 found = true; 262 break; 263 } 264 } 265 EXPECT_TRUE(found); 266 267 rtc::ModuleEnumerator modules(processes.current().th32ProcessID); 268 found = false; 269 while (modules.Next()) { 270 if (!name.compare(modules.current().szModule)) { 271 found = true; 272 break; 273 } 274 } 275 EXPECT_TRUE(found); 276 } 277 278 } // namespace rtc 279