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