OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 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 "gtest/gtest.h" |
| 6 #include "gmock/gmock.h" |
| 7 #include "chrome_frame/chrome_frame_automation.h" |
| 8 #include "chrome_frame/chrome_frame_npapi.h" |
| 9 #include "chrome_frame/ff_privilege_check.h" |
| 10 |
| 11 |
| 12 TEST(ChromeFrameNPAPI, DoesNotCrashOnConstruction) { |
| 13 ChromeFrameNPAPI* api = new ChromeFrameNPAPI(); |
| 14 delete api; |
| 15 } |
| 16 |
| 17 |
| 18 // All mocks in the anonymous namespace. |
| 19 namespace { |
| 20 |
| 21 using ::testing::_; |
| 22 using ::testing::Eq; |
| 23 using ::testing::Invoke; |
| 24 using ::testing::Return; |
| 25 using ::testing::StrEq; |
| 26 |
| 27 // Make mocking privilege test easy. |
| 28 class MockPrivilegeTest { |
| 29 public: |
| 30 MockPrivilegeTest() { |
| 31 CHECK(current_ == NULL); |
| 32 current_ = this; |
| 33 } |
| 34 ~MockPrivilegeTest() { |
| 35 CHECK(current_ == this); |
| 36 current_ = NULL; |
| 37 } |
| 38 |
| 39 MOCK_METHOD1(IsFireFoxPrivilegedInvocation, bool(NPP)); |
| 40 |
| 41 static MockPrivilegeTest* current() { return current_; } |
| 42 |
| 43 private: |
| 44 static MockPrivilegeTest* current_; |
| 45 }; |
| 46 |
| 47 MockPrivilegeTest* MockPrivilegeTest::current_ = NULL; |
| 48 |
| 49 const char* kMimeType = "application/chromeframe"; |
| 50 // The default profile name is by default derived from the currently |
| 51 // running executable's name. |
| 52 const wchar_t* kDefaultProfileName = L"chrome_frame_unittests"; |
| 53 |
| 54 |
| 55 class MockNPAPI: public ChromeFrameNPAPI { |
| 56 public: |
| 57 MockNPAPI() : mock_automation_client_(NULL) {} |
| 58 |
| 59 MOCK_METHOD0(CreatePrefService, NpProxyService*()); |
| 60 |
| 61 MOCK_METHOD0(GetLocation, std::string()); |
| 62 MOCK_METHOD0(GetBrowserIncognitoMode, bool()); |
| 63 |
| 64 MOCK_METHOD1(JavascriptToNPObject, virtual NPObject*(const std::string&)); |
| 65 |
| 66 // Make public for test purposes |
| 67 void OnAutomationServerReady() { |
| 68 ChromeFrameNPAPI::OnAutomationServerReady(); |
| 69 } |
| 70 |
| 71 // Neuter this (or it dchecks during testing). |
| 72 void SetReadyState(READYSTATE new_state) {} |
| 73 |
| 74 ChromeFrameAutomationClient* CreateAutomationClient() { |
| 75 return mock_automation_client_; |
| 76 } |
| 77 |
| 78 ChromeFrameAutomationClient* mock_automation_client_; |
| 79 }; |
| 80 |
| 81 class MockAutomationClient: public ChromeFrameAutomationClient { |
| 82 public: |
| 83 MOCK_METHOD6(Initialize, bool(ChromeFrameDelegate*, int, bool, |
| 84 const std::wstring&, const std::wstring&, |
| 85 bool)); |
| 86 MOCK_METHOD1(SetEnableExtensionAutomation, void(bool)); // NOLINT |
| 87 }; |
| 88 |
| 89 class MockProxyService: public NpProxyService { |
| 90 public: |
| 91 MOCK_METHOD2(Initialize, bool(NPP instance, ChromeFrameAutomationClient*)); |
| 92 }; |
| 93 |
| 94 |
| 95 // Test fixture to allow testing the privileged NPAPI APIs |
| 96 class TestNPAPIPrivilegedApi: public ::testing::Test { |
| 97 public: |
| 98 virtual void SetUp() { |
| 99 memset(&instance, 0, sizeof(instance)); |
| 100 |
| 101 // Gets owned & destroyed by mock_api (in the |
| 102 // ChromeFramePlugin<T>::Uninitialize() function). |
| 103 mock_automation = new MockAutomationClient; |
| 104 |
| 105 mock_api.mock_automation_client_ = mock_automation; |
| 106 mock_proxy = new MockProxyService; |
| 107 mock_proxy->AddRef(); |
| 108 mock_proxy_holder.Attach(mock_proxy); |
| 109 } |
| 110 |
| 111 virtual void TearDown() { |
| 112 } |
| 113 |
| 114 void SetupPrivilegeTest(bool is_incognito, |
| 115 bool expect_privilege_check, |
| 116 bool is_privileged, |
| 117 const std::wstring& profile_name, |
| 118 const std::wstring& extra_args) { |
| 119 EXPECT_CALL(mock_api, GetLocation()) |
| 120 .WillOnce(Return(std::string("http://www.google.com"))); |
| 121 EXPECT_CALL(mock_api, CreatePrefService()) |
| 122 .WillOnce(Return(mock_proxy)); |
| 123 EXPECT_CALL(mock_api, GetBrowserIncognitoMode()) |
| 124 .WillOnce(Return(is_incognito)); |
| 125 |
| 126 EXPECT_CALL(*mock_proxy, Initialize(_, _)).WillRepeatedly(Return(false)); |
| 127 |
| 128 EXPECT_CALL(*mock_automation, |
| 129 Initialize(_, _, true, StrEq(profile_name), StrEq(extra_args), false)) |
| 130 .WillOnce(Return(true)); |
| 131 |
| 132 if (expect_privilege_check) { |
| 133 EXPECT_CALL(mock_priv, IsFireFoxPrivilegedInvocation(_)) |
| 134 .WillOnce(Return(is_privileged)); |
| 135 } else { |
| 136 EXPECT_CALL(mock_priv, IsFireFoxPrivilegedInvocation(_)) |
| 137 .Times(0); // Fail if privilege check invoked. |
| 138 } |
| 139 } |
| 140 |
| 141 public: |
| 142 MockNPAPI mock_api; |
| 143 MockAutomationClient* mock_automation; |
| 144 MockProxyService* mock_proxy; |
| 145 ScopedNsPtr<nsISupports> mock_proxy_holder; |
| 146 MockPrivilegeTest mock_priv; |
| 147 NPP_t instance; |
| 148 }; |
| 149 |
| 150 } // namespace |
| 151 |
| 152 // Stub for unittesting. |
| 153 bool IsFireFoxPrivilegedInvocation(NPP npp) { |
| 154 MockPrivilegeTest* mock = MockPrivilegeTest::current(); |
| 155 if (!mock) |
| 156 return false; |
| 157 |
| 158 return mock->IsFireFoxPrivilegedInvocation(npp); |
| 159 } |
| 160 |
| 161 TEST_F(TestNPAPIPrivilegedApi, NoPrivilegeCheckWhenNoArguments) { |
| 162 SetupPrivilegeTest(false, // Not incognito |
| 163 false, // Fail if privilege check is invoked. |
| 164 false, |
| 165 kDefaultProfileName, |
| 166 L""); // No extra args to initialize. |
| 167 |
| 168 // No arguments, no privilege requested. |
| 169 EXPECT_TRUE(mock_api.Initialize(const_cast<NPMIMEType>(kMimeType), |
| 170 &instance, |
| 171 NP_EMBED, |
| 172 0, 0, 0)); |
| 173 } |
| 174 |
| 175 TEST_F(TestNPAPIPrivilegedApi, NoPrivilegeCheckWhenZeroArgument) { |
| 176 SetupPrivilegeTest(false, // Not incognito |
| 177 false, // Fail if privilege check is invoked. |
| 178 false, |
| 179 kDefaultProfileName, |
| 180 L""); // No extra args to initialize. |
| 181 |
| 182 // Privileged mode explicitly zero. |
| 183 char* argn = "is_privileged"; |
| 184 char* argv = "0"; |
| 185 EXPECT_TRUE(mock_api.Initialize(const_cast<NPMIMEType>(kMimeType), |
| 186 &instance, |
| 187 NP_EMBED, |
| 188 1, &argn, &argv)); |
| 189 } |
| 190 |
| 191 TEST_F(TestNPAPIPrivilegedApi, NotPrivilegedDoesNotAllowArgsOrProfile) { |
| 192 SetupPrivilegeTest(false, // Not incognito. |
| 193 true, // Fail unless privilege check is invoked. |
| 194 false, // Not privileged. |
| 195 kDefaultProfileName, |
| 196 L""); // No extra arguments allowed. |
| 197 |
| 198 char* argn[] = { |
| 199 "privileged_mode", |
| 200 "chrome_extra_arguments", |
| 201 "chrome_profile_name", |
| 202 }; |
| 203 char *argv[] = { |
| 204 "1", |
| 205 "foo", |
| 206 "bar", |
| 207 }; |
| 208 EXPECT_TRUE(mock_api.Initialize(const_cast<NPMIMEType>(kMimeType), |
| 209 &instance, |
| 210 NP_EMBED, |
| 211 arraysize(argn), argn, argv)); |
| 212 } |
| 213 |
| 214 TEST_F(TestNPAPIPrivilegedApi, PrivilegedAllowsArgsAndProfile) { |
| 215 SetupPrivilegeTest(false, // Not incognito. |
| 216 true, // Fail unless privilege check is invoked. |
| 217 true, // Privileged mode. |
| 218 L"custom_profile_name", // Custom profile expected. |
| 219 L"-bar=far"); // Extra arguments expected |
| 220 |
| 221 // With privileged mode we expect automation to be enabled. |
| 222 EXPECT_CALL(*mock_automation, SetEnableExtensionAutomation(true)) |
| 223 .Times(1); |
| 224 |
| 225 char* argn[] = { |
| 226 "privileged_mode", |
| 227 "chrome_extra_arguments", |
| 228 "chrome_profile_name", |
| 229 }; |
| 230 char *argv[] = { |
| 231 "1", |
| 232 "-bar=far", |
| 233 "custom_profile_name", |
| 234 }; |
| 235 EXPECT_TRUE(mock_api.Initialize(const_cast<NPMIMEType>(kMimeType), |
| 236 &instance, |
| 237 NP_EMBED, |
| 238 arraysize(argn), argn, argv)); |
| 239 |
| 240 // Since we're mocking out ChromeFrameAutomationClient::Initialize, we need |
| 241 // to tickle this explicitly. |
| 242 mock_api.OnAutomationServerReady(); |
| 243 } |
| 244 |
| 245 |
| 246 namespace { |
| 247 |
| 248 static const NPIdentifier kOnPrivateMessageId = |
| 249 reinterpret_cast<NPIdentifier>(0x100); |
| 250 static const NPIdentifier kPostPrivateMessageId = |
| 251 reinterpret_cast<NPIdentifier>(0x100); |
| 252 |
| 253 |
| 254 class MockNetscapeFuncs { |
| 255 public: |
| 256 MockNetscapeFuncs() { |
| 257 CHECK(NULL == current_); |
| 258 current_ = this; |
| 259 } |
| 260 |
| 261 ~MockNetscapeFuncs() { |
| 262 CHECK(this == current_); |
| 263 current_ = NULL; |
| 264 } |
| 265 |
| 266 MOCK_METHOD3(GetValue, NPError(NPP, NPNVariable, void *)); |
| 267 MOCK_METHOD3(GetStringIdentifiers, void(const NPUTF8 **, |
| 268 int32_t, |
| 269 NPIdentifier *)); // NOLINT |
| 270 MOCK_METHOD1(RetainObject, NPObject*(NPObject*)); // NOLINT |
| 271 MOCK_METHOD1(ReleaseObject, void(NPObject*)); // NOLINT |
| 272 |
| 273 |
| 274 void GetPrivilegedStringIdentifiers(const NPUTF8 **names, |
| 275 int32_t name_count, |
| 276 NPIdentifier *identifiers) { |
| 277 for (int32_t i = 0; i < name_count; ++i) { |
| 278 if (0 == strcmp(names[i], "onprivatemessage")) { |
| 279 identifiers[i] = kOnPrivateMessageId; |
| 280 } else if (0 == strcmp(names[i], "postPrivateMessage")) { |
| 281 identifiers[i] = kPostPrivateMessageId; |
| 282 } else { |
| 283 identifiers[i] = 0; |
| 284 } |
| 285 } |
| 286 } |
| 287 |
| 288 static const NPNetscapeFuncs* netscape_funcs() { |
| 289 return &netscape_funcs_; |
| 290 } |
| 291 |
| 292 private: |
| 293 static NPError MockGetValue(NPP instance, |
| 294 NPNVariable variable, |
| 295 void *ret_value) { |
| 296 DCHECK(current_); |
| 297 return current_->GetValue(instance, variable, ret_value); |
| 298 } |
| 299 |
| 300 static void MockGetStringIdentifiers(const NPUTF8 **names, |
| 301 int32_t name_count, |
| 302 NPIdentifier *identifiers) { |
| 303 DCHECK(current_); |
| 304 return current_->GetStringIdentifiers(names, name_count, identifiers); |
| 305 } |
| 306 |
| 307 static NPObject* MockRetainObject(NPObject* obj) { |
| 308 DCHECK(current_); |
| 309 return current_->RetainObject(obj); |
| 310 } |
| 311 |
| 312 static void MockReleaseObject(NPObject* obj) { |
| 313 DCHECK(current_); |
| 314 current_->ReleaseObject(obj); |
| 315 } |
| 316 |
| 317 static MockNetscapeFuncs* current_; |
| 318 static NPNetscapeFuncs netscape_funcs_; |
| 319 }; |
| 320 |
| 321 MockNetscapeFuncs* MockNetscapeFuncs::current_ = NULL; |
| 322 NPNetscapeFuncs MockNetscapeFuncs::netscape_funcs_ = { |
| 323 0, // size |
| 324 0, // version |
| 325 NULL, // geturl |
| 326 NULL, // posturl |
| 327 NULL, // requestread |
| 328 NULL, // newstream |
| 329 NULL, // write |
| 330 NULL, // destroystream |
| 331 NULL, // status |
| 332 NULL, // uagent |
| 333 NULL, // memalloc |
| 334 NULL, // memfree |
| 335 NULL, // memflush |
| 336 NULL, // reloadplugins |
| 337 NULL, // getJavaEnv |
| 338 NULL, // getJavaPeer |
| 339 NULL, // geturlnotify |
| 340 NULL, // posturlnotify |
| 341 MockGetValue, // getvalue |
| 342 NULL, // setvalue |
| 343 NULL, // invalidaterect |
| 344 NULL, // invalidateregion |
| 345 NULL, // forceredraw |
| 346 NULL, // getstringidentifier |
| 347 MockGetStringIdentifiers, // getstringidentifiers |
| 348 NULL, // getintidentifier |
| 349 NULL, // identifierisstring |
| 350 NULL, // utf8fromidentifier |
| 351 NULL, // intfromidentifier |
| 352 NULL, // createobject |
| 353 MockRetainObject, // retainobject |
| 354 MockReleaseObject, // releaseobject |
| 355 NULL, // invoke |
| 356 NULL, // invokeDefault |
| 357 NULL, // evaluate |
| 358 NULL, // getproperty |
| 359 NULL, // setproperty |
| 360 NULL, // removeproperty |
| 361 NULL, // hasproperty |
| 362 NULL, // hasmethod |
| 363 NULL, // releasevariantvalue |
| 364 NULL, // setexception |
| 365 NULL, // pushpopupsenabledstate |
| 366 NULL, // poppopupsenabledstate |
| 367 NULL, // enumerate |
| 368 NULL, // pluginthreadasynccall |
| 369 NULL, // construct |
| 370 }; |
| 371 |
| 372 NPObject* const kMockNPObject = reinterpret_cast<NPObject*>(0xCafeBabe); |
| 373 |
| 374 class TestNPAPIPrivilegedProperty: public TestNPAPIPrivilegedApi { |
| 375 public: |
| 376 virtual void SetUp() { |
| 377 TestNPAPIPrivilegedApi::SetUp(); |
| 378 npapi::InitializeBrowserFunctions( |
| 379 const_cast<NPNetscapeFuncs*>(mock_funcs.netscape_funcs())); |
| 380 |
| 381 // Expect calls to release and retain objects. |
| 382 EXPECT_CALL(mock_funcs, RetainObject(kMockNPObject)) |
| 383 .WillRepeatedly(Return(kMockNPObject)); |
| 384 EXPECT_CALL(mock_funcs, ReleaseObject(kMockNPObject)) |
| 385 .WillRepeatedly(Return()); |
| 386 |
| 387 // And we should expect SetEnableExtensionAutomation to be called |
| 388 // for privileged tests. |
| 389 EXPECT_CALL(*mock_automation, SetEnableExtensionAutomation(true)) |
| 390 .WillRepeatedly(Return()); |
| 391 |
| 392 // Initializes identifiers. |
| 393 EXPECT_CALL(mock_funcs, GetStringIdentifiers(_, _, _)) |
| 394 .WillRepeatedly( |
| 395 Invoke(&mock_funcs, |
| 396 &MockNetscapeFuncs::GetPrivilegedStringIdentifiers)); |
| 397 MockNPAPI::InitializeIdentifiers(); |
| 398 } |
| 399 |
| 400 virtual void TearDown() { |
| 401 npapi::UninitializeBrowserFunctions(); |
| 402 TestNPAPIPrivilegedApi::TearDown(); |
| 403 } |
| 404 |
| 405 public: |
| 406 MockNetscapeFuncs mock_funcs; |
| 407 }; |
| 408 |
| 409 |
| 410 } // namespace |
| 411 |
| 412 TEST_F(TestNPAPIPrivilegedProperty, |
| 413 NonPrivilegedOnPrivateMessageInitializationFails) { |
| 414 // Attempt setting onprivatemessage when not privileged. |
| 415 SetupPrivilegeTest(false, // not incognito. |
| 416 true, // expect privilege check. |
| 417 false, // not privileged. |
| 418 kDefaultProfileName, |
| 419 L""); |
| 420 |
| 421 char* on_private_message_str = "onprivatemessage()"; |
| 422 EXPECT_CALL(mock_api, JavascriptToNPObject(StrEq(on_private_message_str))) |
| 423 .Times(0); // this should not be called. |
| 424 |
| 425 char* argn[] = { |
| 426 "privileged_mode", |
| 427 "onprivatemessage", |
| 428 }; |
| 429 char* argv[] = { |
| 430 "1", |
| 431 on_private_message_str, |
| 432 }; |
| 433 EXPECT_TRUE(mock_api.Initialize(const_cast<NPMIMEType>(kMimeType), |
| 434 &instance, |
| 435 NP_EMBED, |
| 436 arraysize(argn), argn, argv)); |
| 437 // Shouldn't be able to retrieve it. |
| 438 NPVariant var; |
| 439 VOID_TO_NPVARIANT(var); |
| 440 EXPECT_FALSE(mock_api.GetProperty(kOnPrivateMessageId, &var)); |
| 441 EXPECT_TRUE(NPVARIANT_IS_VOID(var)); |
| 442 |
| 443 mock_api.Uninitialize(); |
| 444 } |
| 445 |
| 446 TEST_F(TestNPAPIPrivilegedProperty, |
| 447 PrivilegedOnPrivateMessageInitializationSucceeds) { |
| 448 // Set onprivatemessage argument when privileged. |
| 449 SetupPrivilegeTest(false, // not incognito. |
| 450 true, // expect privilege check. |
| 451 true, // privileged. |
| 452 kDefaultProfileName, |
| 453 L""); |
| 454 |
| 455 char* on_private_message_str = "onprivatemessage()"; |
| 456 NPObject* on_private_object = kMockNPObject; |
| 457 EXPECT_CALL(mock_api, JavascriptToNPObject(StrEq(on_private_message_str))) |
| 458 .WillOnce(Return(on_private_object)); |
| 459 |
| 460 char* argn[] = { |
| 461 "privileged_mode", |
| 462 "onprivatemessage", |
| 463 }; |
| 464 char* argv[] = { |
| 465 "1", |
| 466 on_private_message_str, |
| 467 }; |
| 468 EXPECT_TRUE(mock_api.Initialize(const_cast<NPMIMEType>(kMimeType), |
| 469 &instance, |
| 470 NP_EMBED, |
| 471 arraysize(argn), argn, argv)); |
| 472 // The property should have been set, verify that |
| 473 // we can retrieve it and test it for correct value. |
| 474 NPVariant var; |
| 475 VOID_TO_NPVARIANT(var); |
| 476 EXPECT_TRUE(mock_api.GetProperty(kOnPrivateMessageId, &var)); |
| 477 EXPECT_TRUE(NPVARIANT_IS_OBJECT(var)); |
| 478 EXPECT_EQ(kMockNPObject, NPVARIANT_TO_OBJECT(var)); |
| 479 |
| 480 mock_api.Uninitialize(); |
| 481 } |
| 482 |
| 483 TEST_F(TestNPAPIPrivilegedProperty, |
| 484 NonPrivilegedOnPrivateMessageAssignmentFails) { |
| 485 // Assigning to onprivatemessage when not privileged should fail. |
| 486 SetupPrivilegeTest(false, // not incognito. |
| 487 true, // expect privilege check. |
| 488 false, // not privileged. |
| 489 kDefaultProfileName, |
| 490 L""); |
| 491 |
| 492 char* argn = "privileged_mode"; |
| 493 char* argv = "1"; |
| 494 EXPECT_TRUE(mock_api.Initialize(const_cast<NPMIMEType>(kMimeType), |
| 495 &instance, |
| 496 NP_EMBED, |
| 497 1, &argn, &argv)); |
| 498 |
| 499 NPVariant var = {}; |
| 500 OBJECT_TO_NPVARIANT(kMockNPObject, var); |
| 501 // Setting should fail. |
| 502 EXPECT_FALSE(mock_api.SetProperty(kOnPrivateMessageId, &var)); |
| 503 |
| 504 // And so should getting. |
| 505 NULL_TO_NPVARIANT(var); |
| 506 EXPECT_FALSE(mock_api.GetProperty(kOnPrivateMessageId, &var)); |
| 507 |
| 508 mock_api.Uninitialize(); |
| 509 } |
| 510 |
| 511 TEST_F(TestNPAPIPrivilegedProperty, |
| 512 PrivilegedOnPrivateMessageAssignmentSucceeds) { |
| 513 // Assigning to onprivatemessage when privileged should succeed. |
| 514 SetupPrivilegeTest(false, // not incognito. |
| 515 true, // expect privilege check. |
| 516 true, // privileged. |
| 517 kDefaultProfileName, |
| 518 L""); |
| 519 |
| 520 char* argn = "privileged_mode"; |
| 521 char* argv = "1"; |
| 522 EXPECT_TRUE(mock_api.Initialize(const_cast<NPMIMEType>(kMimeType), |
| 523 &instance, |
| 524 NP_EMBED, |
| 525 1, &argn, &argv)); |
| 526 |
| 527 NPVariant var = {}; |
| 528 VOID_TO_NPVARIANT(var); |
| 529 // Getting the property when NULL fails under current implementation. |
| 530 // I shouldn't have thought this is correct behavior, e.g. I should |
| 531 // have thought retrieving the NULL should succeed, but this is consistent |
| 532 // with how other properties behave. |
| 533 // TODO(robertshield): investigate and/or fix. |
| 534 EXPECT_FALSE(mock_api.GetProperty(kOnPrivateMessageId, &var)); |
| 535 // EXPECT_TRUE(NPVARIANT_IS_OBJECT(var)); |
| 536 // EXPECT_EQ(NULL, NPVARIANT_TO_OBJECT(var)); |
| 537 |
| 538 // Setting the property should succeed. |
| 539 OBJECT_TO_NPVARIANT(kMockNPObject, var); |
| 540 EXPECT_TRUE(mock_api.SetProperty(kOnPrivateMessageId, &var)); |
| 541 |
| 542 // And fething it should return the value we just set. |
| 543 VOID_TO_NPVARIANT(var); |
| 544 EXPECT_TRUE(mock_api.GetProperty(kOnPrivateMessageId, &var)); |
| 545 EXPECT_TRUE(NPVARIANT_IS_OBJECT(var)); |
| 546 EXPECT_EQ(kMockNPObject, NPVARIANT_TO_OBJECT(var)); |
| 547 |
| 548 mock_api.Uninitialize(); |
| 549 } |
| 550 |
| 551 // TODO(siggi): test invoking postPrivateMessage. |
OLD | NEW |