// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "include/base/cef_bind.h" #include "include/cef_request_context_handler.h" #include "include/cef_waitable_event.h" #include "include/wrapper/cef_closure_task.h" #include "tests/ceftests/test_handler.h" #include "tests/ceftests/test_util.h" #include "tests/gtest/include/gtest/gtest.h" #include "tests/shared/browser/client_app_browser.h" namespace { // Fully qualified preference names. const char kPrefTest[] = "test"; const char kPrefTestBool[] = "test.bool"; const char kPrefTestInt[] = "test.int"; const char kPrefTestDouble[] = "test.double"; const char kPrefTestString[] = "test.string"; const char kPrefTestList[] = "test.list"; const char kPrefTestDict[] = "test.dict"; const char kPrefTestNoExist[] = "test.noexist"; // Unqualified preference names. const char kPrefBool[] = "bool"; const char kPrefInt[] = "int"; const char kPrefDouble[] = "double"; const char kPrefString[] = "string"; const char kPrefList[] = "list"; const char kPrefDict[] = "dict"; std::string* PendingAction() { static std::string str; return &str; } // Browser-side app delegate. class PreferenceBrowserTest : public client::ClientAppBrowser::Delegate { public: PreferenceBrowserTest() {} void OnBeforeCommandLineProcessing( CefRefPtr app, CefRefPtr command_line) override { // Enables testing of preferences. // See CefBrowserPrefStore::CreateService. command_line->AppendSwitch("enable-preference-testing"); } private: IMPLEMENT_REFCOUNTING(PreferenceBrowserTest); }; void ValidateReset(CefRefPtr context, const char* name) { EXPECT_TRUE(context->HasPreference(name)); EXPECT_TRUE(context->CanSetPreference(name)); CefString error; EXPECT_TRUE(context->SetPreference(name, nullptr, error)); EXPECT_TRUE(error.empty()); } void ValidateBool(CefRefPtr context, bool set, bool expected, const char* name = kPrefTestBool) { EXPECT_TRUE(context->HasPreference(name)); EXPECT_TRUE(context->CanSetPreference(name)); CefRefPtr value; if (set) { value = CefValue::Create(); value->SetBool(expected); CefString error; EXPECT_TRUE(context->SetPreference(name, value, error)); EXPECT_TRUE(error.empty()); } value = context->GetPreference(name); EXPECT_TRUE(value.get()); EXPECT_EQ(VTYPE_BOOL, value->GetType()); EXPECT_EQ(expected, value->GetBool()) << *PendingAction(); } void ValidateInt(CefRefPtr context, bool set, int expected, const char* name = kPrefTestInt) { EXPECT_TRUE(context->HasPreference(name)); EXPECT_TRUE(context->CanSetPreference(name)); CefRefPtr value; if (set) { value = CefValue::Create(); value->SetInt(expected); CefString error; EXPECT_TRUE(context->SetPreference(name, value, error)); EXPECT_TRUE(error.empty()); } value = context->GetPreference(name); EXPECT_TRUE(value.get()); EXPECT_EQ(VTYPE_INT, value->GetType()); EXPECT_EQ(expected, value->GetInt()) << *PendingAction(); } void ValidateDouble(CefRefPtr context, bool set, double expected, const char* name = kPrefTestDouble) { EXPECT_TRUE(context->HasPreference(name)); EXPECT_TRUE(context->CanSetPreference(name)); CefRefPtr value; if (set) { value = CefValue::Create(); value->SetDouble(expected); CefString error; EXPECT_TRUE(context->SetPreference(name, value, error)); EXPECT_TRUE(error.empty()); } value = context->GetPreference(name); EXPECT_TRUE(value.get()); EXPECT_EQ(VTYPE_DOUBLE, value->GetType()); EXPECT_EQ(expected, value->GetDouble()) << *PendingAction(); } void ValidateString(CefRefPtr context, bool set, const std::string& expected, const char* name = kPrefTestString) { EXPECT_TRUE(context->HasPreference(name)); EXPECT_TRUE(context->CanSetPreference(name)); CefRefPtr value; if (set) { value = CefValue::Create(); value->SetString(expected); CefString error; EXPECT_TRUE(context->SetPreference(name, value, error)); EXPECT_TRUE(error.empty()); } value = context->GetPreference(name); EXPECT_TRUE(value.get()); EXPECT_EQ(VTYPE_STRING, value->GetType()); EXPECT_STREQ(expected.c_str(), value->GetString().ToString().c_str()) << *PendingAction(); } void ValidateList(CefRefPtr context, bool set, CefRefPtr expected, const char* name = kPrefTestList) { EXPECT_TRUE(context->HasPreference(name)); EXPECT_TRUE(context->CanSetPreference(name)); CefRefPtr value; if (set) { value = CefValue::Create(); value->SetList(expected); CefString error; EXPECT_TRUE(context->SetPreference(name, value, error)); EXPECT_TRUE(error.empty()); } value = context->GetPreference(name); EXPECT_TRUE(value.get()); EXPECT_EQ(VTYPE_LIST, value->GetType()); CefRefPtr list_val = value->GetList(); EXPECT_TRUE(list_val); TestListEqual(expected, list_val); } void ValidateDict(CefRefPtr context, bool set, CefRefPtr expected, const char* name = kPrefTestDict) { EXPECT_TRUE(context->HasPreference(name)); EXPECT_TRUE(context->CanSetPreference(name)); CefRefPtr value; if (set) { value = CefValue::Create(); value->SetDictionary(expected); CefString error; EXPECT_TRUE(context->SetPreference(name, value, error)); EXPECT_TRUE(error.empty()); } value = context->GetPreference(name); EXPECT_TRUE(value.get()); EXPECT_EQ(VTYPE_DICTIONARY, value->GetType()); CefRefPtr dict_val = value->GetDictionary(); EXPECT_TRUE(dict_val); TestDictionaryEqual(expected, dict_val); } void ValidateNoExist(CefRefPtr context, bool set, const char* name = kPrefTestNoExist) { EXPECT_FALSE(context->HasPreference(name)); EXPECT_FALSE(context->CanSetPreference(name)); CefRefPtr value; if (set) { value = CefValue::Create(); value->SetBool(false); CefString error; EXPECT_FALSE(context->SetPreference(name, value, error)); EXPECT_FALSE(error.empty()); } value = context->GetPreference(name); EXPECT_FALSE(value.get()) << *PendingAction(); } void PopulateRootDefaults(CefRefPtr val) { // Should match the values in CefBrowserPrefStore::CreateService. val->SetBool(kPrefBool, true); val->SetInt(kPrefInt, 2); val->SetDouble(kPrefDouble, 5.0); val->SetString(kPrefString, "default"); val->SetList(kPrefList, CefListValue::Create()); val->SetDictionary(kPrefDict, CefDictionaryValue::Create()); } void ValidateRoot(CefRefPtr root, CefRefPtr expected, const char* name = kPrefTest) { EXPECT_TRUE(root->HasKey(kPrefTest)); EXPECT_EQ(VTYPE_DICTIONARY, root->GetType(kPrefTest)); CefRefPtr actual = root->GetDictionary(kPrefTest); TestDictionaryEqual(expected, actual); } // Validate getting default values. void ValidateDefaults(CefRefPtr context, bool reset, CefRefPtr event) { if (!CefCurrentlyOn(TID_UI)) { CefPostTask(TID_UI, base::Bind(ValidateDefaults, context, reset, event)); return; } if (reset) { // Reset default values. ValidateReset(context, kPrefTestBool); ValidateReset(context, kPrefTestInt); ValidateReset(context, kPrefTestDouble); ValidateReset(context, kPrefTestString); ValidateReset(context, kPrefTestList); ValidateReset(context, kPrefTestDict); } // Test default values. // Should match the values in CefBrowserPrefStore::CreateService. ValidateBool(context, false, true); ValidateInt(context, false, 2); ValidateDouble(context, false, 5.0); ValidateString(context, false, "default"); ValidateList(context, false, CefListValue::Create()); ValidateDict(context, false, CefDictionaryValue::Create()); ValidateNoExist(context, false); // Expected value of the tests root. CefRefPtr expected = CefDictionaryValue::Create(); PopulateRootDefaults(expected); // Test all preferences including defaults. ValidateRoot(context->GetAllPreferences(true), expected); // Test all preferences excluding defaults. EXPECT_FALSE(context->GetAllPreferences(false)->HasKey(kPrefTest)); event->Signal(); } void PopulateListValue(CefRefPtr val) { // Test list values. val->SetInt(0, 54); val->SetString(1, "foobar"); val->SetDouble(2, 99.7643); } void PopulateDictValue(CefRefPtr val) { // Test dictionary values. val->SetString("key1", "some string"); val->SetBool("key2", false); CefRefPtr list_val = CefListValue::Create(); PopulateListValue(list_val); val->SetList("key3", list_val); } void PopulateRootSet(CefRefPtr val) { CefRefPtr list_val = CefListValue::Create(); CefRefPtr dict_val = CefDictionaryValue::Create(); PopulateListValue(list_val); PopulateDictValue(dict_val); // Should match the values in ValidateSetGet and ValidateGet. val->SetBool(kPrefBool, true); val->SetInt(kPrefInt, 65); val->SetDouble(kPrefDouble, 54.5443); val->SetString(kPrefString, "My test string"); val->SetList(kPrefList, list_val); val->SetDictionary(kPrefDict, dict_val); } // Validate getting and setting values. void ValidateSetGet(CefRefPtr context, CefRefPtr event) { if (!CefCurrentlyOn(TID_UI)) { CefPostTask(TID_UI, base::Bind(ValidateSetGet, context, event)); return; } CefRefPtr list_val = CefListValue::Create(); CefRefPtr dict_val = CefDictionaryValue::Create(); PopulateListValue(list_val); PopulateDictValue(dict_val); // Test setting/getting values. // Should match the values in PopulateRootSet and ValidateGet. ValidateBool(context, true, true); ValidateInt(context, true, 65); ValidateDouble(context, true, 54.5443); ValidateString(context, true, "My test string"); ValidateList(context, true, list_val); ValidateDict(context, true, dict_val); ValidateNoExist(context, true); // Expected value of the tests root. CefRefPtr expected = CefDictionaryValue::Create(); PopulateRootSet(expected); // Validate all preferences including defaults. ValidateRoot(context->GetAllPreferences(true), expected); // Validate all preferences excluding defaults. ValidateRoot(context->GetAllPreferences(false), expected); event->Signal(); } // Validate getting values. void ValidateGet(CefRefPtr context, CefRefPtr event) { if (!CefCurrentlyOn(TID_UI)) { CefPostTask(TID_UI, base::Bind(ValidateGet, context, event)); return; } CefRefPtr list_val = CefListValue::Create(); CefRefPtr dict_val = CefDictionaryValue::Create(); PopulateListValue(list_val); PopulateDictValue(dict_val); // Test getting values. // Should match the values in PopulateRootSet and ValidateSetGet. ValidateBool(context, false, true); ValidateInt(context, false, 65); ValidateDouble(context, false, 54.5443); ValidateString(context, false, "My test string"); ValidateList(context, false, list_val); ValidateDict(context, false, dict_val); ValidateNoExist(context, false); // Expected value of the tests root. CefRefPtr expected = CefDictionaryValue::Create(); PopulateRootSet(expected); // Validate all preferences including defaults. ValidateRoot(context->GetAllPreferences(true), expected); // Validate all preferences excluding defaults. ValidateRoot(context->GetAllPreferences(false), expected); event->Signal(); } // No-op implementation. class TestRequestContextHandler : public CefRequestContextHandler { public: TestRequestContextHandler() {} explicit TestRequestContextHandler(CefRefPtr event) : event_(event) {} void OnRequestContextInitialized( CefRefPtr context) override { if (event_) { event_->Signal(); event_ = nullptr; } } private: CefRefPtr event_; IMPLEMENT_REFCOUNTING(TestRequestContextHandler); }; } // namespace // Verify default preference values on the global context. TEST(PreferenceTest, GlobalDefaults) { CefRefPtr event = CefWaitableEvent::CreateWaitableEvent(true, false); CefRefPtr context = CefRequestContext::GetGlobalContext(); EXPECT_TRUE(context.get()); ValidateDefaults(context, false, event); event->Wait(); } // Verify setting/getting preference values on the global context. TEST(PreferenceTest, GlobalSetGet) { CefRefPtr event = CefWaitableEvent::CreateWaitableEvent(true, false); CefRefPtr context = CefRequestContext::GetGlobalContext(); EXPECT_TRUE(context.get()); ValidateSetGet(context, event); event->Wait(); // Reset to the default values. ValidateDefaults(context, true, event); event->Wait(); } // Verify setting/getting preference values on shared global contexts. TEST(PreferenceTest, GlobalSetGetShared) { CefRefPtr event = CefWaitableEvent::CreateWaitableEvent(true, false); CefRefPtr context = CefRequestContext::GetGlobalContext(); EXPECT_TRUE(context.get()); // Sharing storage. CefRefPtr context2 = CefRequestContext::CreateContext(context, nullptr); EXPECT_TRUE(context2.get()); // Sharing storage. CefRefPtr context3 = CefRequestContext::CreateContext(context, new TestRequestContextHandler); EXPECT_TRUE(context3.get()); // Unassociated context. CefRequestContextSettings settings; CefRefPtr context4 = CefRequestContext::CreateContext( settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context4.get()); // Wait for the context to be fully initialized. event->Wait(); // Set/get the values on the first context. *PendingAction() = "Set/get the values on the first context"; ValidateSetGet(context, event); event->Wait(); // Get the values from the 2nd and 3rd contexts. They should be the same. *PendingAction() = "Get the values from the 2nd context."; ValidateGet(context2, event); event->Wait(); *PendingAction() = "Get the values from the 3rd context."; ValidateGet(context3, event); event->Wait(); // Get the values from the 4th context. *PendingAction() = "Get the values from the 4th context."; if (IsChromeRuntimeEnabled()) { // With the Chrome runtime, prefs set via an incognito profile will become // an overlay on top of the global (parent) profile. The incognito profile // shares the prefs in this case because they were set via the global // profile. ValidateGet(context4, event); } else { // They should be at the default. ValidateDefaults(context4, false, event); } event->Wait(); // Reset to the default values. *PendingAction() = "Reset to the default values."; ValidateDefaults(context, true, event); event->Wait(); } // Verify default preference values on a custom context. TEST(PreferenceTest, CustomDefaults) { CefRefPtr event = CefWaitableEvent::CreateWaitableEvent(true, false); CefRequestContextSettings settings; CefRefPtr context = CefRequestContext::CreateContext( settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context.get()); // Wait for the context to be fully initialized. event->Wait(); ValidateDefaults(context, false, event); event->Wait(); } // Verify setting/getting preference values on a custom context. TEST(PreferenceTest, CustomSetGet) { CefRefPtr event = CefWaitableEvent::CreateWaitableEvent(true, false); CefRequestContextSettings settings; CefRefPtr context = CefRequestContext::CreateContext( settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context.get()); // Wait for the context to be fully initialized. event->Wait(); ValidateSetGet(context, event); event->Wait(); // Reset to the default values. ValidateDefaults(context, true, event); event->Wait(); } // Verify setting/getting preference values on shared custom contexts. TEST(PreferenceTest, CustomSetGetShared) { CefRefPtr event = CefWaitableEvent::CreateWaitableEvent(true, false); CefRequestContextSettings settings; CefRefPtr context = CefRequestContext::CreateContext( settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context.get()); // Wait for the context to be fully initialized. event->Wait(); // Sharing storage. CefRefPtr context2 = CefRequestContext::CreateContext(context, nullptr); EXPECT_TRUE(context2.get()); // Sharing storage. CefRefPtr context3 = CefRequestContext::CreateContext(context, new TestRequestContextHandler); EXPECT_TRUE(context3.get()); // Unassociated context. CefRefPtr context4 = CefRequestContext::CreateContext( settings, new TestRequestContextHandler(event)); EXPECT_TRUE(context4.get()); // Wait for the context to be fully initialized. event->Wait(); // Set/get the values on the first context. *PendingAction() = "Set/get the values on the first context"; ValidateSetGet(context, event); event->Wait(); // Get the values from the 2nd and 3d contexts. They should be the same. *PendingAction() = "Get the values from the 2nd context."; ValidateGet(context2, event); event->Wait(); *PendingAction() = "Get the values from the 3rd context."; ValidateGet(context3, event); event->Wait(); // Get the values from the 4th context. They should be at the default. // This works with the Chrome runtime because the preference changes only // exist in the other incognito profile's overlay. *PendingAction() = "Get the values from the 4th context."; ValidateDefaults(context4, false, event); event->Wait(); // Reset to the default values. *PendingAction() = "Reset to the default values."; ValidateDefaults(context, true, event); event->Wait(); } // Entry point for creating preference browser test objects. // Called from client_app_delegates.cc. void CreatePreferenceBrowserTests( client::ClientAppBrowser::DelegateSet& delegates) { delegates.insert(new PreferenceBrowserTest); }