// Copyright (c) 2012 The Chromium 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 "chrome/browser/ui/webui/sync_internals_ui.h" #include <cstddef> #include <string> #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/sync/profile_sync_service_mock.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/profile_mock.h" #include "content/public/browser/web_ui_controller.h" #include "content/public/test/test_browser_thread.h" #include "sync/js/js_arg_list.h" #include "sync/js/js_event_details.h" #include "sync/js/js_test_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using base::ASCIIToUTF16; // Rewrite to use WebUI testing infrastructure. Current code below is mostly // testing how WebUI concrete class serializes function parameters, and that // SyncInternalsUI::HandleJSEvent/HandleJsReply prefix the given function with // "chrome.sync." and postfix it with ".fire" or ".handleReply". // http://crbug.com/110517 /* namespace { using browser_sync::HasArgsAsList; using syncer::JsArgList; using syncer::JsEventDetails; using content::BrowserThread; using content::WebContents; using testing::_; using testing::Mock; using testing::NiceMock; using testing::Return; using testing::StrictMock; // Subclass of WebUI to mock out ExecuteJavascript. class TestSyncWebUI: public WebUI { public: explicit TestSyncWebUI(WebContents* web_contents) : WebUI(web_contents) {} virtual ~TestSyncWebUI() {} MOCK_METHOD1(ExecuteJavascript, void(const base::string16&)); }; // Tests with non-NULL ProfileSyncService. class SyncInternalsUITestWithService : public ChromeRenderViewHostTestHarness { protected: SyncInternalsUITestWithService() : sync_internals_ui_(NULL) {} virtual ~SyncInternalsUITestWithService() {} virtual void SetUp() { NiceMock<ProfileMock>* profile_mock = new NiceMock<ProfileMock>(); StrictMock<ProfileSyncServiceMock> profile_sync_service_mock; EXPECT_CALL(*profile_mock, GetProfileSyncService()) .WillOnce(Return(&profile_sync_service_mock)); browser_context_.reset(profile_mock); ChromeRenderViewHostTestHarness::SetUp(); EXPECT_CALL(profile_sync_service_mock, GetJsController()) .WillOnce(Return(mock_js_controller_.AsWeakPtr())); EXPECT_CALL(mock_js_controller_, AddJsEventHandler(_)); { // Needed by |sync_internals_ui_|'s constructor. The // message loop is provided by ChromeRenderViewHostTestHarness. content::TestBrowserThread ui_thread_(BrowserThread::UI, base::MessageLoopForUI::current()); // |sync_internals_ui_|'s constructor triggers all the // expectations above. web_ui_.reset(new TestSyncWebUI(web_contents())); sync_internals_ui_ = new SyncInternalsUI(web_ui_.get()); web_ui_->SetController(sync_internals_ui_); } Mock::VerifyAndClearExpectations(profile_mock); Mock::VerifyAndClearExpectations(&mock_js_controller_); } virtual void TearDown() { Mock::VerifyAndClearExpectations(&mock_js_controller_); // Called by |sync_internals_ui_|'s destructor. EXPECT_CALL(mock_js_controller_, RemoveJsEventHandler(sync_internals_ui_)); sync_internals_ui_ = NULL; web_ui_.reset(); ChromeRenderViewHostTestHarness::TearDown(); } StrictMock<browser_sync::MockJsController> mock_js_controller_; scoped_ptr<TestSyncWebUI> web_ui_; SyncInternalsUI* sync_internals_ui_; }; TEST_F(SyncInternalsUITestWithService, HandleJsEvent) { EXPECT_CALL(*web_ui_, ExecuteJavascript( ASCIIToUTF16("chrome.sync.testMessage.fire({});"))); sync_internals_ui_->HandleJsEvent("testMessage", JsEventDetails()); } TEST_F(SyncInternalsUITestWithService, HandleJsReply) { EXPECT_CALL( *web_ui_, ExecuteJavascript( ASCIIToUTF16("chrome.sync.testMessage.handleReply(5,true);"))); base::ListValue args; args.Append(base::Value::CreateIntegerValue(5)); args.Append(base::Value::CreateBooleanValue(true)); sync_internals_ui_->HandleJsReply("testMessage", JsArgList(&args)); } TEST_F(SyncInternalsUITestWithService, OnWebUISendBasic) { const std::string& name = "testName"; base::ListValue args; args.Append(base::Value::CreateIntegerValue(10)); EXPECT_CALL(mock_js_controller_, ProcessJsMessage(name, HasArgsAsList(args), _)); sync_internals_ui_->OverrideHandleWebUIMessage(GURL(), name, args); } // Tests with NULL ProfileSyncService. class SyncInternalsUITestWithoutService : public ChromeRenderViewHostTestHarness { protected: SyncInternalsUITestWithoutService() : sync_internals_ui_(NULL) {} virtual ~SyncInternalsUITestWithoutService() {} virtual void SetUp() { NiceMock<ProfileMock>* profile_mock = new NiceMock<ProfileMock>(); EXPECT_CALL(*profile_mock, GetProfileSyncService()) .WillOnce(Return(static_cast<ProfileSyncService*>(NULL))); browser_context_.reset(profile_mock); ChromeRenderViewHostTestHarness::SetUp(); { // Needed by |sync_internals_ui_|'s constructor. The // message loop is provided by ChromeRenderViewHostTestHarness. content::TestBrowserThread ui_thread_(BrowserThread::UI, base::MessageLoopForUI::current()); // |sync_internals_ui_|'s constructor triggers all the // expectations above. web_ui_.reset(new TestSyncWebUI(web_contents())); sync_internals_ui_ = new SyncInternalsUI(web_ui_.get()); web_ui_->SetController(sync_internals_ui_); } Mock::VerifyAndClearExpectations(profile_mock); } scoped_ptr<TestSyncWebUI> web_ui_; SyncInternalsUI* sync_internals_ui_; }; TEST_F(SyncInternalsUITestWithoutService, HandleJsEvent) { EXPECT_CALL(*web_ui_, ExecuteJavascript( ASCIIToUTF16("chrome.sync.testMessage.fire({});"))); sync_internals_ui_->HandleJsEvent("testMessage", JsEventDetails()); } TEST_F(SyncInternalsUITestWithoutService, HandleJsReply) { EXPECT_CALL( *web_ui_, ExecuteJavascript( ASCIIToUTF16("chrome.sync.testMessage.handleReply(5,true);"))); base::ListValue args; args.Append(base::Value::CreateIntegerValue(5)); args.Append(base::Value::CreateBooleanValue(true)); sync_internals_ui_->HandleJsReply( "testMessage", JsArgList(&args)); } TEST_F(SyncInternalsUITestWithoutService, OnWebUISendBasic) { const std::string& name = "testName"; base::ListValue args; args.Append(base::Value::CreateIntegerValue(5)); // Should drop the message. sync_internals_ui_->OverrideHandleWebUIMessage(GURL(), name, args); } // TODO(lipalani) - add a test case to test about:sync with a non null // service. TEST_F(SyncInternalsUITestWithoutService, OnWebUISendGetAboutInfo) { const char kAboutInfoCall[] = "chrome.sync.getAboutInfo.handleReply({\"summary\":\"SYNC DISABLED\"});"; EXPECT_CALL(*web_ui_, ExecuteJavascript(ASCIIToUTF16(kAboutInfoCall))); base::ListValue args; sync_internals_ui_->OverrideHandleWebUIMessage( GURL(), "getAboutInfo", args); } } // namespace */