| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/scoped_ptr.h" | 5 #include "base/scoped_ptr.h" |
| 6 #include "base/utf_string_conversions.h" |
| 6 #include "base/values.h" | 7 #include "base/values.h" |
| 8 #include "chrome/browser/configuration_policy_pref_store.h" |
| 7 #include "chrome/browser/dummy_pref_store.h" | 9 #include "chrome/browser/dummy_pref_store.h" |
| 8 #include "chrome/browser/pref_value_store.h" | 10 #include "chrome/browser/pref_value_store.h" |
| 9 | |
| 10 #include "testing/gmock/include/gmock/gmock.h" | 11 #include "testing/gmock/include/gmock/gmock.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
| 12 | 13 |
| 13 using testing::_; | 14 using testing::_; |
| 14 using testing::Mock; | 15 using testing::Mock; |
| 15 | 16 |
| 16 // Names of the preferences used in this test program. | 17 // Names of the preferences used in this test program. |
| 17 namespace prefs { | 18 namespace prefs { |
| 18 const wchar_t kCurrentThemeID[] = L"extensions.theme.id"; | 19 const wchar_t kCurrentThemeID[] = L"extensions.theme.id"; |
| 19 const wchar_t kDeleteCache[] = L"browser.clear_data.cache"; | 20 const wchar_t kDeleteCache[] = L"browser.clear_data.cache"; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 const std::wstring kHomepageValue = L"http://www.ferretcentral.org"; | 56 const std::wstring kHomepageValue = L"http://www.ferretcentral.org"; |
| 56 } | 57 } |
| 57 | 58 |
| 58 namespace recommended_pref { | 59 namespace recommended_pref { |
| 59 const int kMaxTabsValue = 10; | 60 const int kMaxTabsValue = 10; |
| 60 const bool kRecommendedPrefValue = true; | 61 const bool kRecommendedPrefValue = true; |
| 61 } | 62 } |
| 62 | 63 |
| 63 class PrefValueStoreTest : public testing::Test { | 64 class PrefValueStoreTest : public testing::Test { |
| 64 protected: | 65 protected: |
| 65 scoped_ptr<PrefValueStore> pref_value_store_; | |
| 66 | |
| 67 // |PrefStore|s are owned by the |PrefValueStore|. | |
| 68 DummyPrefStore* enforced_pref_store_; | |
| 69 DummyPrefStore* extension_pref_store_; | |
| 70 DummyPrefStore* command_line_pref_store_; | |
| 71 DummyPrefStore* recommended_pref_store_; | |
| 72 DummyPrefStore* user_pref_store_; | |
| 73 | |
| 74 // Preferences are owned by the individual |DummyPrefStores|. | |
| 75 DictionaryValue* enforced_prefs_; | |
| 76 DictionaryValue* extension_prefs_; | |
| 77 DictionaryValue* command_line_prefs_; | |
| 78 DictionaryValue* user_prefs_; | |
| 79 DictionaryValue* recommended_prefs_; | |
| 80 | |
| 81 virtual void SetUp() { | 66 virtual void SetUp() { |
| 82 // Create dummy user preferences. | 67 // Create dummy user preferences. |
| 83 enforced_prefs_= CreateEnforcedPrefs(); | 68 enforced_prefs_= CreateEnforcedPrefs(); |
| 84 extension_prefs_ = CreateExtensionPrefs(); | 69 extension_prefs_ = CreateExtensionPrefs(); |
| 85 command_line_prefs_ = CreateCommandLinePrefs(); | 70 command_line_prefs_ = CreateCommandLinePrefs(); |
| 86 user_prefs_ = CreateUserPrefs(); | 71 user_prefs_ = CreateUserPrefs(); |
| 87 recommended_prefs_ = CreateRecommendedPrefs(); | 72 recommended_prefs_ = CreateRecommendedPrefs(); |
| 88 | 73 |
| 89 // Create |DummyPrefStore|s. | 74 // Create |DummyPrefStore|s. |
| 90 enforced_pref_store_ = new DummyPrefStore(); | 75 enforced_pref_store_ = new DummyPrefStore(); |
| 91 enforced_pref_store_->set_prefs(enforced_prefs_); | 76 enforced_pref_store_->set_prefs(enforced_prefs_); |
| 92 extension_pref_store_ = new DummyPrefStore(); | 77 extension_pref_store_ = new DummyPrefStore(); |
| 93 extension_pref_store_->set_prefs(extension_prefs_); | 78 extension_pref_store_->set_prefs(extension_prefs_); |
| 94 command_line_pref_store_ = new DummyPrefStore(); | 79 command_line_pref_store_ = new DummyPrefStore(); |
| 95 command_line_pref_store_->set_prefs(command_line_prefs_); | 80 command_line_pref_store_->set_prefs(command_line_prefs_); |
| 96 user_pref_store_ = new DummyPrefStore(); | 81 user_pref_store_ = new DummyPrefStore(); |
| 97 user_pref_store_->set_read_only(false); | 82 user_pref_store_->set_read_only(false); |
| 98 user_pref_store_->set_prefs(user_prefs_); | 83 user_pref_store_->set_prefs(user_prefs_); |
| 99 recommended_pref_store_ = new DummyPrefStore(); | 84 recommended_pref_store_ = new DummyPrefStore(); |
| 100 recommended_pref_store_->set_prefs(recommended_prefs_); | 85 recommended_pref_store_->set_prefs(recommended_prefs_); |
| 101 | 86 |
| 102 // Create a new pref-value-store. | 87 // Create a new pref-value-store. |
| 103 pref_value_store_.reset(new PrefValueStore(enforced_pref_store_, | 88 pref_value_store_ = new PrefValueStore(enforced_pref_store_, |
| 104 extension_pref_store_, | 89 extension_pref_store_, |
| 105 command_line_pref_store_, | 90 command_line_pref_store_, |
| 106 user_pref_store_, | 91 user_pref_store_, |
| 107 recommended_pref_store_)); | 92 recommended_pref_store_); |
| 93 |
| 94 ui_thread_.reset(new ChromeThread(ChromeThread::UI, &loop_)); |
| 95 file_thread_.reset(new ChromeThread(ChromeThread::FILE, &loop_)); |
| 108 } | 96 } |
| 109 | 97 |
| 110 // Creates a new dictionary and stores some sample user preferences | 98 // Creates a new dictionary and stores some sample user preferences |
| 111 // in it. | 99 // in it. |
| 112 DictionaryValue* CreateUserPrefs() { | 100 DictionaryValue* CreateUserPrefs() { |
| 113 DictionaryValue* user_prefs = new DictionaryValue(); | 101 DictionaryValue* user_prefs = new DictionaryValue(); |
| 114 user_prefs->SetBoolean(prefs::kDeleteCache, user_pref::kDeleteCacheValue); | 102 user_prefs->SetBoolean(prefs::kDeleteCache, user_pref::kDeleteCacheValue); |
| 115 user_prefs->SetInteger(prefs::kMaxTabs, user_pref::kMaxTabsValue); | 103 user_prefs->SetInteger(prefs::kMaxTabs, user_pref::kMaxTabsValue); |
| 116 user_prefs->SetString(prefs::kCurrentThemeID, | 104 user_prefs->SetString(prefs::kCurrentThemeID, |
| 117 user_pref::kCurrentThemeIDValue); | 105 user_pref::kCurrentThemeIDValue); |
| 118 user_prefs->SetString(prefs::kApplicationLocale, | 106 user_prefs->SetString(prefs::kApplicationLocale, |
| 119 user_pref::kApplicationLocaleValue); | 107 user_pref::kApplicationLocaleValue); |
| 120 user_prefs->SetString(prefs::kHomepage, user_pref::kHomepageValue); | 108 user_prefs->SetString(prefs::kHomepage, user_pref::kHomepageValue); |
| 121 return user_prefs; | 109 return user_prefs; |
| 122 } | 110 } |
| 123 | 111 |
| 124 DictionaryValue* CreateEnforcedPrefs() { | 112 DictionaryValue* CreateEnforcedPrefs() { |
| 125 DictionaryValue* enforced_prefs = new DictionaryValue(); | 113 DictionaryValue* enforced_prefs = new DictionaryValue(); |
| 126 enforced_prefs->SetString(prefs::kHomepage, enforced_pref::kHomepageValue); | 114 enforced_prefs->SetString(prefs::kHomepage, enforced_pref::kHomepageValue); |
| 115 expected_differing_paths_.push_back(WideToUTF8(prefs::kHomepage)); |
| 127 return enforced_prefs; | 116 return enforced_prefs; |
| 128 } | 117 } |
| 129 | 118 |
| 130 DictionaryValue* CreateExtensionPrefs() { | 119 DictionaryValue* CreateExtensionPrefs() { |
| 131 DictionaryValue* extension_prefs = new DictionaryValue(); | 120 DictionaryValue* extension_prefs = new DictionaryValue(); |
| 132 extension_prefs->SetString(prefs::kCurrentThemeID, | 121 extension_prefs->SetString(prefs::kCurrentThemeID, |
| 133 extension_pref::kCurrentThemeIDValue); | 122 extension_pref::kCurrentThemeIDValue); |
| 134 extension_prefs->SetString(prefs::kHomepage, | 123 extension_prefs->SetString(prefs::kHomepage, |
| 135 extension_pref::kHomepageValue); | 124 extension_pref::kHomepageValue); |
| 136 return extension_prefs; | 125 return extension_prefs; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 147 return command_line_prefs; | 136 return command_line_prefs; |
| 148 } | 137 } |
| 149 | 138 |
| 150 DictionaryValue* CreateRecommendedPrefs() { | 139 DictionaryValue* CreateRecommendedPrefs() { |
| 151 DictionaryValue* recommended_prefs = new DictionaryValue(); | 140 DictionaryValue* recommended_prefs = new DictionaryValue(); |
| 152 recommended_prefs->SetInteger(prefs::kMaxTabs, | 141 recommended_prefs->SetInteger(prefs::kMaxTabs, |
| 153 recommended_pref::kMaxTabsValue); | 142 recommended_pref::kMaxTabsValue); |
| 154 recommended_prefs->SetBoolean( | 143 recommended_prefs->SetBoolean( |
| 155 prefs::kRecommendedPref, | 144 prefs::kRecommendedPref, |
| 156 recommended_pref::kRecommendedPrefValue); | 145 recommended_pref::kRecommendedPrefValue); |
| 146 |
| 147 // Expected differing paths must be added in lexicographic order |
| 148 // to work properly |
| 149 expected_differing_paths_.push_back("tabs"); |
| 150 expected_differing_paths_.push_back(WideToUTF8(prefs::kMaxTabs)); |
| 151 expected_differing_paths_.push_back("this"); |
| 152 expected_differing_paths_.push_back("this.pref"); |
| 153 expected_differing_paths_.push_back(WideToUTF8(prefs::kRecommendedPref)); |
| 157 return recommended_prefs; } | 154 return recommended_prefs; } |
| 158 | 155 |
| 159 DictionaryValue* CreateSampleDictValue() { | 156 DictionaryValue* CreateSampleDictValue() { |
| 160 DictionaryValue* sample_dict = new DictionaryValue(); | 157 DictionaryValue* sample_dict = new DictionaryValue(); |
| 161 sample_dict->SetBoolean(L"issample", true); | 158 sample_dict->SetBoolean(L"issample", true); |
| 162 sample_dict->SetInteger(L"value", 4); | 159 sample_dict->SetInteger(L"value", 4); |
| 163 sample_dict->SetString(L"descr", L"Sample Test Dictionary"); | 160 sample_dict->SetString(L"descr", L"Sample Test Dictionary"); |
| 164 return sample_dict; | 161 return sample_dict; |
| 165 } | 162 } |
| 166 | 163 |
| 167 ListValue* CreateSampleListValue() { | 164 ListValue* CreateSampleListValue() { |
| 168 ListValue* sample_list = new ListValue(); | 165 ListValue* sample_list = new ListValue(); |
| 169 sample_list->Set(0, Value::CreateIntegerValue(0)); | 166 sample_list->Set(0, Value::CreateIntegerValue(0)); |
| 170 sample_list->Set(1, Value::CreateIntegerValue(1)); | 167 sample_list->Set(1, Value::CreateIntegerValue(1)); |
| 171 sample_list->Set(2, Value::CreateIntegerValue(2)); | 168 sample_list->Set(2, Value::CreateIntegerValue(2)); |
| 172 sample_list->Set(3, Value::CreateIntegerValue(3)); | 169 sample_list->Set(3, Value::CreateIntegerValue(3)); |
| 173 return sample_list; | 170 return sample_list; |
| 174 } | 171 } |
| 175 | 172 |
| 176 virtual void TearDown() {} | 173 virtual void TearDown() { |
| 174 loop_.RunAllPending(); |
| 175 } |
| 176 |
| 177 MessageLoop loop_; |
| 178 |
| 179 scoped_refptr<PrefValueStore> pref_value_store_; |
| 180 |
| 181 // |PrefStore|s are owned by the |PrefValueStore|. |
| 182 DummyPrefStore* enforced_pref_store_; |
| 183 DummyPrefStore* extension_pref_store_; |
| 184 DummyPrefStore* command_line_pref_store_; |
| 185 DummyPrefStore* recommended_pref_store_; |
| 186 DummyPrefStore* user_pref_store_; |
| 187 |
| 188 // A vector of the preferences paths in the managed and recommended |
| 189 // PrefStores that are set at the beginning of a test. Can be modified |
| 190 // by the test to track changes that it makes to the preferences |
| 191 // stored in the managed and recommended PrefStores. |
| 192 std::vector<std::string> expected_differing_paths_; |
| 193 |
| 194 // Preferences are owned by the individual |DummyPrefStores|. |
| 195 DictionaryValue* enforced_prefs_; |
| 196 DictionaryValue* extension_prefs_; |
| 197 DictionaryValue* command_line_prefs_; |
| 198 DictionaryValue* user_prefs_; |
| 199 DictionaryValue* recommended_prefs_; |
| 200 |
| 201 private: |
| 202 scoped_ptr<ChromeThread> ui_thread_; |
| 203 scoped_ptr<ChromeThread> file_thread_; |
| 177 }; | 204 }; |
| 178 | 205 |
| 179 | |
| 180 TEST_F(PrefValueStoreTest, IsReadOnly) { | 206 TEST_F(PrefValueStoreTest, IsReadOnly) { |
| 181 enforced_pref_store_->set_read_only(true); | 207 enforced_pref_store_->set_read_only(true); |
| 182 extension_pref_store_->set_read_only(true); | 208 extension_pref_store_->set_read_only(true); |
| 183 command_line_pref_store_->set_read_only(true); | 209 command_line_pref_store_->set_read_only(true); |
| 184 user_pref_store_->set_read_only(true); | 210 user_pref_store_->set_read_only(true); |
| 185 recommended_pref_store_->set_read_only(true); | 211 recommended_pref_store_->set_read_only(true); |
| 186 EXPECT_TRUE(pref_value_store_->ReadOnly()); | 212 EXPECT_TRUE(pref_value_store_->ReadOnly()); |
| 187 | 213 |
| 188 user_pref_store_->set_read_only(false); | 214 user_pref_store_->set_read_only(false); |
| 189 EXPECT_FALSE(pref_value_store_->ReadOnly()); | 215 EXPECT_FALSE(pref_value_store_->ReadOnly()); |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 EXPECT_FALSE(pref_value_store_->PrefValueInUserStore( | 446 EXPECT_FALSE(pref_value_store_->PrefValueInUserStore( |
| 421 prefs::kRecommendedPref)); | 447 prefs::kRecommendedPref)); |
| 422 EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore( | 448 EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore( |
| 423 prefs::kRecommendedPref)); | 449 prefs::kRecommendedPref)); |
| 424 | 450 |
| 425 // Test a preference for which the PrefValueStore does not contain a value. | 451 // Test a preference for which the PrefValueStore does not contain a value. |
| 426 ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref)); | 452 ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref)); |
| 427 EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(prefs::kMissingPref)); | 453 EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(prefs::kMissingPref)); |
| 428 EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(prefs::kMissingPref)); | 454 EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(prefs::kMissingPref)); |
| 429 } | 455 } |
| 456 |
| 457 class MockPolicyRefreshCallback { |
| 458 public: |
| 459 MockPolicyRefreshCallback() {} |
| 460 MOCK_METHOD1(DoCallback, void(const std::vector<std::string>)); |
| 461 }; |
| 462 |
| 463 TEST_F(PrefValueStoreTest, TestPolicyRefresh) { |
| 464 // pref_value_store_ is initialized by PrefValueStoreTest to have values |
| 465 // in both it's managed and recommended store. By replacing them with |
| 466 // dummy stores, all of the paths of the prefs originally managed and |
| 467 // recommended stores should change. |
| 468 MockPolicyRefreshCallback callback; |
| 469 EXPECT_CALL(callback, DoCallback(_)).Times(0); |
| 470 ChromeThread::PostTask( |
| 471 ChromeThread::UI, FROM_HERE, |
| 472 NewRunnableMethod( |
| 473 pref_value_store_.get(), |
| 474 &PrefValueStore::RefreshPolicyPrefs, |
| 475 new DummyPrefStore(), |
| 476 new DummyPrefStore(), |
| 477 NewCallback(&callback, |
| 478 &MockPolicyRefreshCallback::DoCallback))); |
| 479 Mock::VerifyAndClearExpectations(&callback); |
| 480 EXPECT_CALL(callback, DoCallback(expected_differing_paths_)).Times(1); |
| 481 loop_.RunAllPending(); |
| 482 } |
| 483 |
| 484 TEST_F(PrefValueStoreTest, TestRefreshPolicyPrefsCompletion) { |
| 485 // Test changed preferences in managed store and removed |
| 486 // preferences in the recommended store. In addition |
| 487 // to "homepage", the other prefs that are set by default in |
| 488 // the test class are removed by the DummyStore |
| 489 scoped_ptr<DummyPrefStore> new_managed_store(new DummyPrefStore()); |
| 490 DictionaryValue* dict = new DictionaryValue(); |
| 491 dict->SetString(L"homepage", L"some other changed homepage"); |
| 492 new_managed_store->set_prefs(dict); |
| 493 MockPolicyRefreshCallback callback; |
| 494 EXPECT_CALL(callback, DoCallback(expected_differing_paths_)).Times(1); |
| 495 pref_value_store_->RefreshPolicyPrefsCompletion( |
| 496 new_managed_store.release(), |
| 497 new DummyPrefStore(), |
| 498 NewCallback(&callback, |
| 499 &MockPolicyRefreshCallback::DoCallback)); |
| 500 |
| 501 // Test properties that have been removed from the managed store. |
| 502 // Homepage is still set in managed prefs. |
| 503 expected_differing_paths_.clear(); |
| 504 expected_differing_paths_.push_back(std::string("homepage")); |
| 505 MockPolicyRefreshCallback callback2; |
| 506 EXPECT_CALL(callback2, DoCallback(expected_differing_paths_)).Times(1); |
| 507 pref_value_store_->RefreshPolicyPrefsCompletion( |
| 508 new DummyPrefStore(), |
| 509 new DummyPrefStore(), |
| 510 NewCallback(&callback2, |
| 511 &MockPolicyRefreshCallback::DoCallback)); |
| 512 |
| 513 // Test properties that are added to the recommended store. |
| 514 scoped_ptr<DummyPrefStore> new_recommended_store(new DummyPrefStore()); |
| 515 dict = new DictionaryValue(); |
| 516 dict->SetString(L"homepage", L"some other changed homepage 2"); |
| 517 new_recommended_store->set_prefs(dict); |
| 518 expected_differing_paths_.clear(); |
| 519 expected_differing_paths_.push_back(std::string("homepage")); |
| 520 MockPolicyRefreshCallback callback3; |
| 521 EXPECT_CALL(callback3, DoCallback(expected_differing_paths_)).Times(1); |
| 522 pref_value_store_->RefreshPolicyPrefsCompletion( |
| 523 new DummyPrefStore(), |
| 524 new_recommended_store.release(), |
| 525 NewCallback(&callback3, |
| 526 &MockPolicyRefreshCallback::DoCallback)); |
| 527 |
| 528 // Test adding a multi-key path. |
| 529 new_managed_store.reset(new DummyPrefStore()); |
| 530 dict = new DictionaryValue(); |
| 531 dict->SetString("segment1.segment2", "value"); |
| 532 new_managed_store->set_prefs(dict); |
| 533 expected_differing_paths_.clear(); |
| 534 expected_differing_paths_.push_back(std::string("homepage")); |
| 535 expected_differing_paths_.push_back(std::string("segment1")); |
| 536 expected_differing_paths_.push_back(std::string("segment1.segment2")); |
| 537 MockPolicyRefreshCallback callback4; |
| 538 EXPECT_CALL(callback4, DoCallback(expected_differing_paths_)).Times(1); |
| 539 pref_value_store_->RefreshPolicyPrefsCompletion( |
| 540 new_managed_store.release(), |
| 541 new DummyPrefStore(), |
| 542 NewCallback(&callback4, |
| 543 &MockPolicyRefreshCallback::DoCallback)); |
| 544 } |
| 545 |
| 546 TEST_F(PrefValueStoreTest, TestConcurrentPolicyRefresh) { |
| 547 MockPolicyRefreshCallback callback1; |
| 548 ChromeThread::PostTask( |
| 549 ChromeThread::UI, FROM_HERE, |
| 550 NewRunnableMethod( |
| 551 pref_value_store_.get(), |
| 552 &PrefValueStore::RefreshPolicyPrefs, |
| 553 new DummyPrefStore(), |
| 554 new DummyPrefStore(), |
| 555 NewCallback(&callback1, |
| 556 &MockPolicyRefreshCallback::DoCallback))); |
| 557 EXPECT_CALL(callback1, DoCallback(_)).Times(0); |
| 558 |
| 559 MockPolicyRefreshCallback callback2; |
| 560 ChromeThread::PostTask( |
| 561 ChromeThread::UI, FROM_HERE, |
| 562 NewRunnableMethod( |
| 563 pref_value_store_.get(), |
| 564 &PrefValueStore::RefreshPolicyPrefs, |
| 565 new DummyPrefStore(), |
| 566 new DummyPrefStore(), |
| 567 NewCallback(&callback2, |
| 568 &MockPolicyRefreshCallback::DoCallback))); |
| 569 EXPECT_CALL(callback2, DoCallback(_)).Times(0); |
| 570 |
| 571 MockPolicyRefreshCallback callback3; |
| 572 ChromeThread::PostTask( |
| 573 ChromeThread::UI, FROM_HERE, |
| 574 NewRunnableMethod( |
| 575 pref_value_store_.get(), |
| 576 &PrefValueStore::RefreshPolicyPrefs, |
| 577 new DummyPrefStore(), |
| 578 new DummyPrefStore(), |
| 579 NewCallback(&callback3, |
| 580 &MockPolicyRefreshCallback::DoCallback))); |
| 581 EXPECT_CALL(callback3, DoCallback(_)).Times(0); |
| 582 Mock::VerifyAndClearExpectations(&callback1); |
| 583 Mock::VerifyAndClearExpectations(&callback2); |
| 584 Mock::VerifyAndClearExpectations(&callback3); |
| 585 |
| 586 EXPECT_CALL(callback1, DoCallback(expected_differing_paths_)).Times(1); |
| 587 std::vector<std::string> no_differing_paths; |
| 588 EXPECT_CALL(callback2, DoCallback(no_differing_paths)).Times(1); |
| 589 EXPECT_CALL(callback3, DoCallback(no_differing_paths)).Times(1); |
| 590 loop_.RunAllPending(); |
| 591 } |
| OLD | NEW |