| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // This test requires loading a set of DLLs from the chrome_frame\test\data | |
| 6 // directory into the process and then inspecting them. As such, it is | |
| 7 // part of chrome_frame_tests.exe and not chrome_frame_unittests.exe which | |
| 8 // needs to run as a standalone test. No test is an island except for | |
| 9 // chrome_frame_unittests.exe. | |
| 10 | |
| 11 #include "chrome_frame/module_utils.h" | |
| 12 #include "testing/gtest/include/gtest/gtest.h" | |
| 13 | |
| 14 #include "base/logging.h" | |
| 15 #include "base/file_path.h" | |
| 16 #include "base/path_service.h" | |
| 17 #include "chrome_frame/test_utils.h" | |
| 18 | |
| 19 #include "chrome_tab.h" // NOLINT | |
| 20 | |
| 21 class ModuleUtilsTest : public testing::Test { | |
| 22 protected: | |
| 23 // Constructor | |
| 24 ModuleUtilsTest() {} | |
| 25 | |
| 26 // Returns the full path to the test DLL given a name. | |
| 27 virtual bool GetDllPath(const std::wstring& dll_name, std::wstring* path) { | |
| 28 if (!path) { | |
| 29 return false; | |
| 30 } | |
| 31 | |
| 32 FilePath test_path; | |
| 33 if (!PathService::Get(base::DIR_SOURCE_ROOT, &test_path)) { | |
| 34 return false; | |
| 35 } | |
| 36 | |
| 37 test_path = test_path.Append(L"chrome_frame") | |
| 38 .Append(L"test") | |
| 39 .Append(L"data") | |
| 40 .Append(L"test_dlls") | |
| 41 .Append(FilePath(dll_name)); | |
| 42 | |
| 43 *path = test_path.value(); | |
| 44 return true; | |
| 45 } | |
| 46 | |
| 47 // Loads the CF Dll and returns its path in |cf_dll_path|. | |
| 48 virtual bool LoadChromeFrameDll(std::wstring* cf_dll_path) { | |
| 49 DCHECK(cf_dll_path); | |
| 50 // Look for the CF dll in both the current directory and in servers. | |
| 51 FilePath dll_path = ScopedChromeFrameRegistrar::GetChromeFrameBuildPath(); | |
| 52 | |
| 53 bool success = false; | |
| 54 if (!dll_path.empty()) { | |
| 55 cf_dll_path_ = dll_path.value(); | |
| 56 HMODULE handle = LoadLibrary(cf_dll_path_.c_str()); | |
| 57 if (handle) { | |
| 58 hmodule_map_[cf_dll_path_] = handle; | |
| 59 *cf_dll_path = cf_dll_path_; | |
| 60 success = true; | |
| 61 } else { | |
| 62 LOG(ERROR) << "Failed to load test dll: " << dll_path.value(); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 return success; | |
| 67 } | |
| 68 | |
| 69 virtual bool LoadTestDll(const std::wstring& dll_name) { | |
| 70 bool success = false; | |
| 71 std::wstring dll_path; | |
| 72 if (GetDllPath(dll_name, &dll_path)) { | |
| 73 HMODULE handle = LoadLibrary(dll_path.c_str()); | |
| 74 if (handle) { | |
| 75 hmodule_map_[dll_name] = handle; | |
| 76 success = true; | |
| 77 } else { | |
| 78 LOG(ERROR) << "Failed to load test dll: " << dll_name; | |
| 79 } | |
| 80 } else { | |
| 81 LOG(ERROR) << "Failed to get dll path for " << dll_name; | |
| 82 } | |
| 83 return success; | |
| 84 } | |
| 85 | |
| 86 // Unload any DLLs we have loaded and make sure they stay unloaded. | |
| 87 virtual void TearDown() { | |
| 88 DllRedirector::PathToHModuleMap::const_iterator iter(hmodule_map_.begin()); | |
| 89 for (; iter != hmodule_map_.end(); ++iter) { | |
| 90 FreeLibrary(iter->second); | |
| 91 } | |
| 92 | |
| 93 // Check that the modules were actually unloaded (i.e. we had no dangling | |
| 94 // references). Do this after freeing all modules since they can have | |
| 95 // references to each other. | |
| 96 for (iter = hmodule_map_.begin(); iter != hmodule_map_.end(); ++iter) { | |
| 97 // The CF module gets pinned, so don't check that that is unloaded. | |
| 98 if (iter->first != cf_dll_path_) { | |
| 99 HMODULE temp_handle; | |
| 100 ASSERT_FALSE(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, | |
| 101 reinterpret_cast<LPCTSTR>(iter->second), | |
| 102 &temp_handle)); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 hmodule_map_.clear(); | |
| 107 } | |
| 108 | |
| 109 DllRedirector::PathToHModuleMap hmodule_map_; | |
| 110 std::wstring cf_dll_path_; | |
| 111 }; | |
| 112 | |
| 113 // Tests that if we load a few versions of the same module that all export | |
| 114 // DllGetClassObject, that we correctly a) find a DllGetClassObject function | |
| 115 // pointer and b) find it in the right module. | |
| 116 TEST_F(ModuleUtilsTest, BasicTest) { | |
| 117 ASSERT_TRUE(LoadTestDll(L"3\\TestDll.dll")); | |
| 118 ASSERT_TRUE(LoadTestDll(L"2\\TestDll.dll")); | |
| 119 ASSERT_TRUE(LoadTestDll(L"1\\TestDll.dll")); | |
| 120 | |
| 121 DllRedirector redir; | |
| 122 redir.EnsureInitialized(L"TestDll.dll", CLSID_ChromeActiveDocument); | |
| 123 | |
| 124 LPFNGETCLASSOBJECT found_ptr = redir.get_dll_get_class_object_ptr(); | |
| 125 EXPECT_TRUE(found_ptr != NULL); | |
| 126 | |
| 127 LPFNGETCLASSOBJECT direct_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>( | |
| 128 GetProcAddress(hmodule_map_[L"1\\TestDll.dll"], | |
| 129 "DllGetClassObject")); | |
| 130 EXPECT_TRUE(direct_ptr != NULL); | |
| 131 | |
| 132 EXPECT_EQ(found_ptr, direct_ptr); | |
| 133 } | |
| 134 | |
| 135 // Tests that a DLL that does not return a class factory for a Chrome Frame | |
| 136 // guid even though it has a lower version string. | |
| 137 TEST_F(ModuleUtilsTest, NoCFDllTest) { | |
| 138 ASSERT_TRUE(LoadTestDll(L"1\\TestDll.dll")); | |
| 139 ASSERT_TRUE(LoadTestDll(L"TestDllNoCF\\TestDll.dll")); | |
| 140 | |
| 141 DllRedirector redir; | |
| 142 redir.EnsureInitialized(L"TestDll.dll", CLSID_ChromeActiveDocument); | |
| 143 | |
| 144 LPFNGETCLASSOBJECT found_ptr = redir.get_dll_get_class_object_ptr(); | |
| 145 EXPECT_TRUE(found_ptr != NULL); | |
| 146 | |
| 147 LPFNGETCLASSOBJECT direct_ptr = | |
| 148 reinterpret_cast<LPFNGETCLASSOBJECT>( | |
| 149 GetProcAddress(hmodule_map_[L"1\\TestDll.dll"], | |
| 150 "DllGetClassObject")); | |
| 151 EXPECT_TRUE(direct_ptr != NULL); | |
| 152 | |
| 153 EXPECT_EQ(found_ptr, direct_ptr); | |
| 154 } | |
| 155 | |
| 156 // Tests that this works with the actual CF dll. | |
| 157 TEST_F(ModuleUtilsTest, ChromeFrameDllTest) { | |
| 158 ASSERT_TRUE(LoadTestDll(L"DummyCF\\npchrome_frame.dll")); | |
| 159 std::wstring cf_dll_path; | |
| 160 ASSERT_TRUE(LoadChromeFrameDll(&cf_dll_path)); | |
| 161 ASSERT_TRUE(!cf_dll_path.empty()); | |
| 162 | |
| 163 DllRedirector redir; | |
| 164 redir.EnsureInitialized(L"npchrome_frame.dll", CLSID_ChromeActiveDocument); | |
| 165 | |
| 166 LPFNGETCLASSOBJECT found_ptr = redir.get_dll_get_class_object_ptr(); | |
| 167 EXPECT_TRUE(found_ptr != NULL); | |
| 168 | |
| 169 LPFNGETCLASSOBJECT direct_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>( | |
| 170 GetProcAddress(hmodule_map_[L"DummyCF\\npchrome_frame.dll"], | |
| 171 "DllGetClassObject")); | |
| 172 EXPECT_TRUE(direct_ptr != NULL); | |
| 173 | |
| 174 EXPECT_EQ(found_ptr, direct_ptr); | |
| 175 | |
| 176 // Now try asking for a ChromeActiveDocument using the non-dummy CF DLL | |
| 177 // handle and make sure that the delegation to the dummy module happens | |
| 178 // correctly. Use the bare guid to keep dependencies simple | |
| 179 const wchar_t kClsidChromeActiveDocument[] = | |
| 180 L"{3e1d0e7f-f5e3-44cc-aa6a-c0a637619ab8}"; | |
| 181 | |
| 182 LPFNGETCLASSOBJECT cf_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>( | |
| 183 GetProcAddress(hmodule_map_[cf_dll_path], | |
| 184 "DllGetClassObject")); | |
| 185 EXPECT_TRUE(cf_ptr != NULL); | |
| 186 | |
| 187 CLSID cf_clsid; | |
| 188 HRESULT hr = CLSIDFromString(kClsidChromeActiveDocument, &cf_clsid); | |
| 189 EXPECT_HRESULT_SUCCEEDED(hr); | |
| 190 | |
| 191 CComPtr<IClassFactory> class_factory; | |
| 192 DWORD result = cf_ptr(cf_clsid, IID_IClassFactory, | |
| 193 reinterpret_cast<void**>(&class_factory)); | |
| 194 | |
| 195 EXPECT_EQ(S_OK, result); | |
| 196 } | |
| OLD | NEW |