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 #include <atlbase.h> |
| 6 #include <atlapp.h> |
| 7 #include <atlmisc.h> |
| 8 #include <atlwin.h> |
| 9 |
| 10 #include "testing/gtest/include/gtest/gtest.h" |
| 11 #include "testing/gmock/include/gmock/gmock.h" |
| 12 |
| 13 #include "base/logging.h" |
| 14 #include "base/scoped_ptr.h" |
| 15 #include "base/win/registry.h" |
| 16 #include "chrome_frame/infobars/infobar_content.h" |
| 17 #include "chrome_frame/ready_mode/internal/installation_state.h" |
| 18 #include "chrome_frame/ready_mode/internal/ready_mode_state.h" |
| 19 #include "chrome_frame/ready_mode/internal/ready_prompt_content.h" |
| 20 #include "chrome_frame/ready_mode/internal/ready_prompt_window.h" |
| 21 #include "chrome_frame/ready_mode/internal/registry_ready_mode_state.h" |
| 22 #include "chrome_frame/ready_mode/ready_mode_manager.h" |
| 23 #include "chrome_frame/simple_resource_loader.h" |
| 24 #include "chrome_frame/test/chrome_frame_test_utils.h" |
| 25 |
| 26 namespace { |
| 27 |
| 28 class SetResourceInstance { |
| 29 public: |
| 30 SetResourceInstance() { |
| 31 SimpleResourceLoader* loader_instance = SimpleResourceLoader::instance(); |
| 32 DCHECK(loader_instance != NULL); |
| 33 res_dll_ = loader_instance->GetResourceModuleHandle(); |
| 34 old_res_dll_ = ATL::_AtlBaseModule.SetResourceInstance(res_dll_); |
| 35 } |
| 36 |
| 37 ~SetResourceInstance() { |
| 38 DCHECK_EQ(res_dll_, ATL::_AtlBaseModule.SetResourceInstance(old_res_dll_)); |
| 39 } |
| 40 |
| 41 private: |
| 42 HMODULE res_dll_; |
| 43 HMODULE old_res_dll_; |
| 44 }; |
| 45 |
| 46 class SimpleWindow : public CWindowImpl<SimpleWindow, |
| 47 CWindow, |
| 48 CFrameWinTraits> { |
| 49 public: |
| 50 virtual ~SimpleWindow() { |
| 51 if (IsWindow()) |
| 52 DestroyWindow(); |
| 53 } |
| 54 |
| 55 static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM l_param) { |
| 56 HWND* out = reinterpret_cast<HWND*>(l_param); |
| 57 EXPECT_TRUE(out != NULL); |
| 58 |
| 59 if (out == NULL) |
| 60 return FALSE; |
| 61 |
| 62 EXPECT_TRUE(*out == NULL || ::IsChild(*out, hwnd)); |
| 63 |
| 64 if (*out == NULL) |
| 65 *out = hwnd; |
| 66 |
| 67 return TRUE; |
| 68 } |
| 69 |
| 70 HWND GetZeroOrOneChildWindows() { |
| 71 HWND child = NULL; |
| 72 EnumChildWindows(m_hWnd, EnumChildProc, reinterpret_cast<LPARAM>(&child)); |
| 73 return child; |
| 74 } |
| 75 |
| 76 BEGIN_MSG_MAP(SimpleWindow) |
| 77 END_MSG_MAP() |
| 78 }; |
| 79 |
| 80 class MockInfobarContentFrame : public InfobarContent::Frame { |
| 81 public: |
| 82 // InfobarContent::Frame implementation |
| 83 MOCK_METHOD0(GetFrameWindow, HWND(void)); |
| 84 MOCK_METHOD0(CloseInfobar, void(void)); |
| 85 }; // class Frame |
| 86 |
| 87 class MockReadyModeState : public ReadyModeState { |
| 88 public: |
| 89 // ReadyModeState implementation |
| 90 MOCK_METHOD0(TemporarilyDeclineChromeFrame, void(void)); |
| 91 MOCK_METHOD0(PermanentlyDeclineChromeFrame, void(void)); |
| 92 MOCK_METHOD0(AcceptChromeFrame, void(void)); |
| 93 }; |
| 94 |
| 95 ACTION_P(ReturnPointee, pointer) { |
| 96 return *pointer; |
| 97 } |
| 98 |
| 99 ACTION_P2(SetPointeeTo, pointer, value) { |
| 100 *pointer = value; |
| 101 } |
| 102 |
| 103 class MockInstallationState : public InstallationState { |
| 104 public: |
| 105 // InstallationState implementation |
| 106 MOCK_METHOD0(IsProductInstalled, bool(void)); |
| 107 MOCK_METHOD0(IsProductRegistered, bool(void)); |
| 108 MOCK_METHOD0(InstallProduct, bool(void)); |
| 109 MOCK_METHOD0(UnregisterProduct, bool(void)); |
| 110 }; // MockInstallationState |
| 111 |
| 112 class MockRegistryReadyModeStateObserver |
| 113 : public RegistryReadyModeState::Observer { |
| 114 public: |
| 115 // RegistryReadyModeState::Observer implementation |
| 116 MOCK_METHOD0(OnStateChange, void(void)); |
| 117 }; // class MockRegistryReadyModeStateObserver |
| 118 |
| 119 } // namespace |
| 120 |
| 121 class ReadyPromptTest : public testing::Test { |
| 122 public: |
| 123 ReadyPromptTest() { |
| 124 hwnd_ = window_.Create(NULL); |
| 125 DCHECK(hwnd_ != NULL); |
| 126 window_.ShowWindow(SW_SHOW); |
| 127 DCHECK(window_.IsWindowVisible()); |
| 128 EXPECT_CALL(frame_, GetFrameWindow()).Times(testing::AnyNumber()) |
| 129 .WillRepeatedly(testing::Return(hwnd_)); |
| 130 } |
| 131 |
| 132 protected: |
| 133 SimpleWindow window_; |
| 134 HWND hwnd_; |
| 135 MockInfobarContentFrame frame_; |
| 136 SetResourceInstance set_resource_instance_; |
| 137 }; |
| 138 |
| 139 class ReadyPromptWindowTest : public ReadyPromptTest { |
| 140 public: |
| 141 ReadyPromptWindowTest() { |
| 142 // owned by ReadyPromptWindow |
| 143 state_ = new MockReadyModeState(); |
| 144 ready_prompt_window_ = (new ReadyPromptWindow())->Initialize(&frame_, |
| 145 state_); |
| 146 } |
| 147 |
| 148 void SetUp() { |
| 149 ReadyPromptTest::SetUp(); |
| 150 |
| 151 ASSERT_TRUE(ready_prompt_window_ != NULL); |
| 152 RECT position = {0, 0, 800, 39}; |
| 153 ASSERT_TRUE(ready_prompt_window_->SetWindowPos(HWND_TOP, &position, |
| 154 SWP_SHOWWINDOW)); |
| 155 } |
| 156 |
| 157 protected: |
| 158 MockReadyModeState* state_; |
| 159 base::WeakPtr<ReadyPromptWindow> ready_prompt_window_; |
| 160 }; // class ReadyPromptWindowTest |
| 161 |
| 162 class ReadyPromptWindowButtonTest : public ReadyPromptWindowTest { |
| 163 public: |
| 164 void TearDown() { |
| 165 ASSERT_TRUE(ready_prompt_window_ != NULL); |
| 166 ASSERT_TRUE(ready_prompt_window_->DestroyWindow()); |
| 167 ASSERT_TRUE(ready_prompt_window_ == NULL); |
| 168 ASSERT_FALSE(message_loop_.WasTimedOut()); |
| 169 |
| 170 ReadyPromptWindowTest::TearDown(); |
| 171 } |
| 172 |
| 173 protected: |
| 174 struct ClickOnCaptionData { |
| 175 const wchar_t* target_caption; |
| 176 bool found; |
| 177 }; // struct ClickOnCaptionData |
| 178 |
| 179 static BOOL CALLBACK ClickOnCaptionProc(HWND hwnd, LPARAM l_param) { |
| 180 wchar_t window_caption[256] = {0}; |
| 181 size_t buffer_length = arraysize(window_caption); |
| 182 |
| 183 ClickOnCaptionData* data = reinterpret_cast<ClickOnCaptionData*>(l_param); |
| 184 EXPECT_TRUE(data->target_caption != NULL); |
| 185 |
| 186 if (data->target_caption == NULL) |
| 187 return FALSE; |
| 188 |
| 189 if (wcsnlen(data->target_caption, buffer_length + 1) == buffer_length + 1) |
| 190 return FALSE; |
| 191 |
| 192 if (::GetWindowText(hwnd, window_caption, buffer_length) == |
| 193 static_cast<int>(buffer_length)) { |
| 194 return TRUE; |
| 195 } |
| 196 |
| 197 if (wcscmp(data->target_caption, window_caption) == 0) { |
| 198 EXPECT_FALSE(data->found); |
| 199 |
| 200 CRect client_rect; |
| 201 EXPECT_TRUE(::GetClientRect(hwnd, client_rect)); |
| 202 |
| 203 CPoint center_point(client_rect.CenterPoint()); |
| 204 LPARAM coordinates = (center_point.y << 16) | center_point.x; |
| 205 |
| 206 ::PostMessage(hwnd, WM_LBUTTONDOWN, 0, coordinates); |
| 207 ::PostMessage(hwnd, WM_LBUTTONUP, 0, coordinates); |
| 208 |
| 209 data->found = true; |
| 210 } |
| 211 |
| 212 return TRUE; |
| 213 } |
| 214 |
| 215 bool ClickOnCaption(const std::wstring& caption) { |
| 216 ClickOnCaptionData data = {caption.c_str(), false}; |
| 217 |
| 218 ::EnumChildWindows(hwnd_, ClickOnCaptionProc, |
| 219 reinterpret_cast<LPARAM>(&data)); |
| 220 return data.found; |
| 221 } |
| 222 |
| 223 void RunUntilCloseInfobar() { |
| 224 EXPECT_CALL(frame_, CloseInfobar()).WillOnce(QUIT_LOOP(message_loop_)); |
| 225 ASSERT_NO_FATAL_FAILURE(message_loop_.RunFor(5)); // seconds |
| 226 } |
| 227 |
| 228 chrome_frame_test::TimedMsgLoop message_loop_; |
| 229 }; |
| 230 |
| 231 TEST_F(ReadyPromptTest, ReadyPromptContentTest) { |
| 232 // owned by ReadyPromptContent |
| 233 MockReadyModeState* state = new MockReadyModeState(); |
| 234 scoped_ptr<ReadyPromptContent> content_(new ReadyPromptContent(state)); |
| 235 |
| 236 content_->InstallInFrame(&frame_); |
| 237 |
| 238 // Ensure that, if a child is created, it is not visible yet. |
| 239 HWND child_hwnd = window_.GetZeroOrOneChildWindows(); |
| 240 if (child_hwnd != NULL) { |
| 241 CWindow child(child_hwnd); |
| 242 RECT child_dimensions; |
| 243 EXPECT_TRUE(child.GetClientRect(&child_dimensions)); |
| 244 EXPECT_FALSE(child.IsWindowVisible() && !::IsRectEmpty(&child_dimensions)); |
| 245 } |
| 246 |
| 247 int desired_height = content_->GetDesiredSize(400, 0); |
| 248 EXPECT_GT(desired_height, 0); |
| 249 RECT dimensions = {10, 15, 410, 20}; |
| 250 content_->SetDimensions(dimensions); |
| 251 |
| 252 child_hwnd = window_.GetZeroOrOneChildWindows(); |
| 253 EXPECT_TRUE(child_hwnd != NULL); |
| 254 |
| 255 if (child_hwnd != NULL) { |
| 256 CWindow child(child_hwnd); |
| 257 EXPECT_TRUE(child.IsWindowVisible()); |
| 258 RECT child_dimensions; |
| 259 EXPECT_TRUE(child.GetWindowRect(&child_dimensions)); |
| 260 EXPECT_TRUE(window_.ScreenToClient(&child_dimensions)); |
| 261 EXPECT_TRUE(::EqualRect(&child_dimensions, &dimensions)); |
| 262 } |
| 263 |
| 264 // Being visible doesn't change the desired height |
| 265 EXPECT_EQ(desired_height, content_->GetDesiredSize(400, 0)); |
| 266 |
| 267 content_.reset(); |
| 268 |
| 269 EXPECT_TRUE(window_.GetZeroOrOneChildWindows() == NULL); |
| 270 } |
| 271 |
| 272 TEST_F(ReadyPromptWindowTest, Destroy) { |
| 273 // Should delete associated mocks, not invoke on ReadyModeState |
| 274 ready_prompt_window_->DestroyWindow(); |
| 275 } |
| 276 |
| 277 TEST_F(ReadyPromptWindowButtonTest, ClickYes) { |
| 278 EXPECT_CALL(*state_, AcceptChromeFrame()); |
| 279 ASSERT_TRUE(ClickOnCaption(L"&Yes")); |
| 280 RunUntilCloseInfobar(); |
| 281 } |
| 282 |
| 283 TEST_F(ReadyPromptWindowButtonTest, ClickRemindMeLater) { |
| 284 EXPECT_CALL(*state_, TemporarilyDeclineChromeFrame()); |
| 285 ASSERT_TRUE(ClickOnCaption(L"Remind me &Later")); |
| 286 RunUntilCloseInfobar(); |
| 287 } |
| 288 |
| 289 TEST_F(ReadyPromptWindowButtonTest, ClickNo) { |
| 290 EXPECT_CALL(*state_, PermanentlyDeclineChromeFrame()); |
| 291 ASSERT_TRUE(ClickOnCaption(L"&No")); |
| 292 RunUntilCloseInfobar(); |
| 293 } |
| 294 |
| 295 class ReadyModeRegistryTest : public testing::Test { |
| 296 public: |
| 297 class TimeControlledRegistryReadyModeState : public RegistryReadyModeState { |
| 298 public: |
| 299 TimeControlledRegistryReadyModeState( |
| 300 const std::wstring& key_name, |
| 301 base::TimeDelta temporary_decline_duration, |
| 302 InstallationState* installation_state, |
| 303 Observer* observer) |
| 304 : RegistryReadyModeState(key_name, temporary_decline_duration, |
| 305 installation_state, observer), |
| 306 now_(base::Time::Now()) { |
| 307 } |
| 308 |
| 309 base::Time now_; |
| 310 |
| 311 protected: |
| 312 virtual base::Time GetNow() { |
| 313 return now_; |
| 314 } |
| 315 }; // class TimeControlledRegistryReadyModeState |
| 316 |
| 317 ReadyModeRegistryTest() |
| 318 : is_product_registered_(true), |
| 319 is_product_installed_(false), |
| 320 observer_(NULL), |
| 321 installation_state_(NULL) { |
| 322 } |
| 323 |
| 324 virtual void SetUp() { |
| 325 base::win::RegKey key; |
| 326 ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, kRootKey, KEY_ALL_ACCESS)); |
| 327 observer_ = new MockRegistryReadyModeStateObserver(); |
| 328 installation_state_ = new MockInstallationState(); |
| 329 |
| 330 EXPECT_CALL(*installation_state_, IsProductRegistered()) |
| 331 .Times(testing::AnyNumber()) |
| 332 .WillRepeatedly(ReturnPointee(&is_product_registered_)); |
| 333 EXPECT_CALL(*installation_state_, IsProductInstalled()) |
| 334 .Times(testing::AnyNumber()) |
| 335 .WillRepeatedly(ReturnPointee(&is_product_installed_)); |
| 336 |
| 337 ready_mode_state_.reset(new TimeControlledRegistryReadyModeState( |
| 338 kRootKey, |
| 339 base::TimeDelta::FromSeconds(kTemporaryDeclineDurationInSeconds), |
| 340 installation_state_, |
| 341 observer_)); |
| 342 } |
| 343 |
| 344 virtual void TearDown() { |
| 345 base::win::RegKey key; |
| 346 EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS)); |
| 347 EXPECT_TRUE(key.DeleteKey(kRootKey)); |
| 348 } |
| 349 |
| 350 protected: |
| 351 void AdjustClockBySeconds(int seconds) { |
| 352 ready_mode_state_->now_ += base::TimeDelta::FromSeconds(seconds); |
| 353 } |
| 354 |
| 355 void ExpectUnregisterProductAndReturn(bool success) { |
| 356 EXPECT_CALL(*installation_state_, UnregisterProduct()) |
| 357 .WillOnce(testing::DoAll( |
| 358 SetPointeeTo(&is_product_registered_, !success), |
| 359 testing::Return(success))); |
| 360 } |
| 361 |
| 362 void ExpectInstallProductAndReturn(bool success) { |
| 363 EXPECT_CALL(*installation_state_, InstallProduct()) |
| 364 .WillOnce(testing::DoAll(SetPointeeTo(&is_product_installed_, success), |
| 365 testing::Return(success))); |
| 366 } |
| 367 |
| 368 bool is_product_registered_; |
| 369 bool is_product_installed_; |
| 370 MockInstallationState* installation_state_; |
| 371 MockRegistryReadyModeStateObserver* observer_; |
| 372 |
| 373 scoped_ptr<TimeControlledRegistryReadyModeState> ready_mode_state_; |
| 374 base::win::RegKey config_key; |
| 375 static const wchar_t kRootKey[]; |
| 376 static const int kTemporaryDeclineDurationInSeconds; |
| 377 }; |
| 378 |
| 379 const int ReadyModeRegistryTest::kTemporaryDeclineDurationInSeconds = 2; |
| 380 const wchar_t ReadyModeRegistryTest::kRootKey[] = L"chrome_frame_unittests"; |
| 381 |
| 382 TEST_F(ReadyModeRegistryTest, CallNothing) { |
| 383 // expect it to delete the two mocks... Google Mock fails if they are leaked. |
| 384 } |
| 385 |
| 386 TEST_F(ReadyModeRegistryTest, NotInstalledStatus) { |
| 387 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 388 } |
| 389 |
| 390 TEST_F(ReadyModeRegistryTest, NotRegisteredStatus) { |
| 391 is_product_registered_ = false; |
| 392 ASSERT_EQ(READY_MODE_PERMANENTLY_DECLINED, ready_mode_state_->GetStatus()); |
| 393 } |
| 394 |
| 395 TEST_F(ReadyModeRegistryTest, InstalledStatus) { |
| 396 is_product_installed_ = true; |
| 397 ASSERT_EQ(READY_MODE_ACCEPTED, ready_mode_state_->GetStatus()); |
| 398 } |
| 399 |
| 400 TEST_F(ReadyModeRegistryTest, TemporarilyDeclineChromeFrame) { |
| 401 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 402 |
| 403 EXPECT_CALL(*observer_, OnStateChange()); |
| 404 ready_mode_state_->TemporarilyDeclineChromeFrame(); |
| 405 |
| 406 ASSERT_EQ(READY_MODE_TEMPORARILY_DECLINED, ready_mode_state_->GetStatus()); |
| 407 |
| 408 AdjustClockBySeconds(kTemporaryDeclineDurationInSeconds + 1); |
| 409 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 410 } |
| 411 |
| 412 TEST_F(ReadyModeRegistryTest, TemporarilyDeclineChromeFrameSetClockBack) { |
| 413 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 414 |
| 415 EXPECT_CALL(*observer_, OnStateChange()); |
| 416 ready_mode_state_->TemporarilyDeclineChromeFrame(); |
| 417 |
| 418 ASSERT_EQ(READY_MODE_TEMPORARILY_DECLINED, ready_mode_state_->GetStatus()); |
| 419 |
| 420 AdjustClockBySeconds(kTemporaryDeclineDurationInSeconds + 1); |
| 421 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 422 } |
| 423 |
| 424 TEST_F(ReadyModeRegistryTest, PermanentlyDeclineChromeFrame) { |
| 425 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 426 |
| 427 EXPECT_CALL(*observer_, OnStateChange()); |
| 428 ExpectUnregisterProductAndReturn(true); |
| 429 ready_mode_state_->PermanentlyDeclineChromeFrame(); |
| 430 |
| 431 ASSERT_EQ(READY_MODE_PERMANENTLY_DECLINED, ready_mode_state_->GetStatus()); |
| 432 } |
| 433 |
| 434 TEST_F(ReadyModeRegistryTest, PermanentlyDeclineChromeFrameFailUnregister) { |
| 435 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 436 |
| 437 EXPECT_CALL(*observer_, OnStateChange()); |
| 438 ExpectUnregisterProductAndReturn(false); |
| 439 ready_mode_state_->PermanentlyDeclineChromeFrame(); |
| 440 |
| 441 ASSERT_EQ(READY_MODE_PERMANENTLY_DECLINED, ready_mode_state_->GetStatus()); |
| 442 } |
| 443 |
| 444 TEST_F(ReadyModeRegistryTest, AcceptChromeFrame) { |
| 445 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 446 |
| 447 EXPECT_CALL(*observer_, OnStateChange()); |
| 448 ExpectInstallProductAndReturn(true); |
| 449 ready_mode_state_->AcceptChromeFrame(); |
| 450 |
| 451 ASSERT_EQ(READY_MODE_ACCEPTED, ready_mode_state_->GetStatus()); |
| 452 } |
| 453 |
| 454 // TODO(erikwright): What do we actually want to happen if the install fails? |
| 455 // Stay in Ready Mode? Attempt to unregister (deactivate ready mode)? |
| 456 // |
| 457 // Which component is responsible for messaging the user? The installer? The |
| 458 // InstallationState implementation? The ReadyModeState implementation? |
| 459 TEST_F(ReadyModeRegistryTest, AcceptChromeFrameInstallFails) { |
| 460 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 461 |
| 462 ExpectInstallProductAndReturn(false); |
| 463 ready_mode_state_->AcceptChromeFrame(); |
| 464 |
| 465 ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); |
| 466 } |
OLD | NEW |