From d80033e69d9542605fed21da06601f8201da6618 Mon Sep 17 00:00:00 2001 From: "akalin@chromium.org" Date: Fri, 16 Oct 2009 10:32:04 +0000 Subject: Made sync code build and pass unit tests on OS X. Major changes: - Moved sync_setup_{flow,wizard} to sync directory. - Made browser_with_test_window_test compile on non-Windows platform. - Moved localized contents font util functions to app/. BUG=23073 TEST=trybot Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=29253 Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=29255 Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=29258 Review URL: http://codereview.chromium.org/279004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29263 0039d316-1c4b-4281-b951-d872f2087c98 --- app/app.gyp | 8 +- app/gfx/font_util.cc | 39 +++ app/gfx/font_util.h | 29 ++ chrome/browser/browser_window.h | 2 +- chrome/browser/sync/engine/syncer.cc | 2 +- chrome/browser/sync/engine/syncer_thread.cc | 2 +- chrome/browser/sync/profile_sync_service.h | 2 +- chrome/browser/sync/sync_setup_flow.cc | 304 +++++++++++++++++ chrome/browser/sync/sync_setup_flow.h | 189 +++++++++++ chrome/browser/sync/sync_setup_wizard.cc | 199 +++++++++++ chrome/browser/sync/sync_setup_wizard.h | 82 +++++ chrome/browser/sync/sync_setup_wizard_unittest.cc | 376 +++++++++++++++++++++ .../browser/sync/util/character_set_converters.h | 15 + chrome/browser/sync/util/event_sys_unittest.cc | 4 +- chrome/browser/sync/util/user_settings_unittest.cc | 12 +- .../browser/tab_contents/tab_contents_view_mac.mm | 12 +- chrome/browser/views/sync/sync_setup_flow.cc | 301 ----------------- chrome/browser/views/sync/sync_setup_flow.h | 189 ----------- chrome/browser/views/sync/sync_setup_wizard.cc | 199 ----------- chrome/browser/views/sync/sync_setup_wizard.h | 81 ----- .../views/sync/sync_setup_wizard_unittest.cc | 376 --------------------- chrome/chrome.gyp | 26 +- chrome/test/browser_with_test_window_test.cc | 4 + chrome/test/sync/engine/mock_server_connection.cc | 5 +- .../sync/engine/test_directory_setter_upper.cc | 6 - chrome/test/test_browser_window.h | 10 +- .../libjingle/files/talk/base/autodetectproxy.cc | 2 +- views/window/window.cc | 33 +- views/window/window.h | 10 - 29 files changed, 1287 insertions(+), 1232 deletions(-) create mode 100644 app/gfx/font_util.cc create mode 100644 app/gfx/font_util.h create mode 100644 chrome/browser/sync/sync_setup_flow.cc create mode 100644 chrome/browser/sync/sync_setup_flow.h create mode 100644 chrome/browser/sync/sync_setup_wizard.cc create mode 100644 chrome/browser/sync/sync_setup_wizard.h create mode 100644 chrome/browser/sync/sync_setup_wizard_unittest.cc delete mode 100644 chrome/browser/views/sync/sync_setup_flow.cc delete mode 100644 chrome/browser/views/sync/sync_setup_flow.h delete mode 100644 chrome/browser/views/sync/sync_setup_wizard.cc delete mode 100644 chrome/browser/views/sync/sync_setup_wizard.h delete mode 100644 chrome/browser/views/sync/sync_setup_wizard_unittest.cc diff --git a/app/app.gyp b/app/app.gyp index c7ef0c7..329eb04 100644 --- a/app/app.gyp +++ b/app/app.gyp @@ -92,14 +92,16 @@ 'gfx/codec/jpeg_codec.h', 'gfx/codec/png_codec.cc', 'gfx/codec/png_codec.h', + 'gfx/color_utils.cc', + 'gfx/color_utils.h', + 'gfx/favicon_size.h', 'gfx/font.h', 'gfx/font_gtk.cc', 'gfx/font_mac.mm', 'gfx/font_skia.cc', + 'gfx/font_util.h', + 'gfx/font_util.cc', 'gfx/font_win.cc', - 'gfx/color_utils.cc', - 'gfx/color_utils.h', - 'gfx/favicon_size.h', 'gfx/gdi_util.cc', 'gfx/gdi_util.h', 'gfx/gtk_util.cc', diff --git a/app/gfx/font_util.cc b/app/gfx/font_util.cc new file mode 100644 index 0000000..278677c --- /dev/null +++ b/app/gfx/font_util.cc @@ -0,0 +1,39 @@ +// Copyright (c) 2009 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 "app/gfx/font_util.h" + +#include "app/gfx/font.h" +#include "app/l10n_util.h" +#include "base/logging.h" + +namespace gfx { + +int GetLocalizedContentsWidthForFont(int col_resource_id, + const gfx::Font& font) { + double chars = 0; + StringToDouble(WideToUTF8(l10n_util::GetString(col_resource_id)), &chars); + int width = font.GetExpectedTextWidth(static_cast(chars)); + DCHECK(width > 0); + return width; +} + +int GetLocalizedContentsHeightForFont(int row_resource_id, + const gfx::Font& font) { + double lines = 0; + StringToDouble(WideToUTF8(l10n_util::GetString(row_resource_id)), &lines); + int height = static_cast(font.height() * lines); + DCHECK(height > 0); + return height; +} + +gfx::Size GetLocalizedContentsSizeForFont(int col_resource_id, + int row_resource_id, + const gfx::Font& font) { + return gfx::Size(GetLocalizedContentsWidthForFont(col_resource_id, font), + GetLocalizedContentsHeightForFont(row_resource_id, font)); +} + +} // namespace gfx + diff --git a/app/gfx/font_util.h b/app/gfx/font_util.h new file mode 100644 index 0000000..36bc693 --- /dev/null +++ b/app/gfx/font_util.h @@ -0,0 +1,29 @@ +// Copyright (c) 2006-2009 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. + +#ifndef APP_GFX_FONT_UTIL_H_ +#define APP_GFX_FONT_UTIL_H_ + +#include "base/gfx/size.h" + +namespace gfx { + +class Font; + +// Returns the preferred size of the contents view of a window based on +// its localized size data and the given font. The width in cols is held in a +// localized string resource identified by |col_resource_id|, the height in the +// same fashion. +int GetLocalizedContentsWidthForFont(int col_resource_id, + const gfx::Font& font); +int GetLocalizedContentsHeightForFont(int row_resource_id, + const gfx::Font& font); +gfx::Size GetLocalizedContentsSizeForFont(int col_resource_id, + int row_resource_id, + const gfx::Font& font); + +} // namespace gfx + +#endif // APP_GFX_FONT_UTIL_H_ + diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index a83fbbd..f417166 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -31,7 +31,7 @@ class Rect; // BrowserWindow interface // An interface implemented by the "view" of the Browser window. // -// NOTE: All getters except GetTabStrip() may return NULL. +// NOTE: All getters may return NULL. class BrowserWindow { public: // Show the window, or activates it if it's already visible. diff --git a/chrome/browser/sync/engine/syncer.cc b/chrome/browser/sync/engine/syncer.cc index 9274edf..de8b1b2 100644 --- a/chrome/browser/sync/engine/syncer.cc +++ b/chrome/browser/sync/engine/syncer.cc @@ -118,7 +118,7 @@ void Syncer::SyncShare(SyncerSession* session, // Reset silenced_until_, it is the callers responsibility to honor throttles. silenced_until_ = session->silenced_until(); - SyncerStep next_step; + SyncerStep next_step = current_step; while (!ExitRequested()) { switch (current_step) { case SYNCER_BEGIN: diff --git a/chrome/browser/sync/engine/syncer_thread.cc b/chrome/browser/sync/engine/syncer_thread.cc index 073b5ea..0861940 100644 --- a/chrome/browser/sync/engine/syncer_thread.cc +++ b/chrome/browser/sync/engine/syncer_thread.cc @@ -75,7 +75,7 @@ int UserIdleTime() { } int64 idle_time; // in nanoseconds - Boolean success; + Boolean success = false; if (CFGetTypeID(object) == CFNumberGetTypeID()) { success = CFNumberGetValue((CFNumberRef)object, kCFNumberSInt64Type, diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index fab7ea5..9eedbef 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h @@ -20,7 +20,7 @@ #include "chrome/browser/sync/glue/change_processor.h" #include "chrome/browser/sync/glue/model_associator.h" #include "chrome/browser/sync/glue/sync_backend_host.h" -#include "chrome/browser/views/sync/sync_setup_wizard.h" +#include "chrome/browser/sync/sync_setup_wizard.h" #include "chrome/common/notification_registrar.h" #include "googleurl/src/gurl.h" diff --git a/chrome/browser/sync/sync_setup_flow.cc b/chrome/browser/sync/sync_setup_flow.cc new file mode 100644 index 0000000..2784572 --- /dev/null +++ b/chrome/browser/sync/sync_setup_flow.cc @@ -0,0 +1,304 @@ +// Copyright (c) 2009 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. + +#ifdef CHROME_PERSONALIZATION + +#include "chrome/browser/sync/sync_setup_flow.h" + +#include "app/gfx/font.h" +#include "app/gfx/font_util.h" +#include "base/histogram.h" +#include "base/json_reader.h" +#include "base/json_writer.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/sync/auth_error_state.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/pref_names.h" +#include "grit/locale_settings.h" + +// XPath expression for finding specific iframes. +static const wchar_t* kLoginIFrameXPath = L"//iframe[@id='login']"; +static const wchar_t* kMergeIFrameXPath = L"//iframe[@id='merge']"; +static const wchar_t* kDoneIframeXPath = L"//iframe[@id='done']"; + +// Helper function to read the JSON string from the Value parameter. +static std::string GetJsonResponse(const Value* content) { + if (!content || !content->IsType(Value::TYPE_LIST)) { + NOTREACHED(); + return std::string(); + } + const ListValue* args = static_cast(content); + if (args->GetSize() != 1) { + NOTREACHED(); + return std::string(); + } + + std::string result; + Value* value = NULL; + if (!args->Get(0, &value) || !value->GetAsString(&result)) { + NOTREACHED(); + return std::string(); + } + + return result; +} + +void FlowHandler::RegisterMessages() { + dom_ui_->RegisterMessageCallback("SubmitAuth", + NewCallback(this, &FlowHandler::HandleSubmitAuth)); + dom_ui_->RegisterMessageCallback("SubmitMergeAndSync", + NewCallback(this, &FlowHandler::HandleSubmitMergeAndSync)); +} + +static bool GetUsernameAndPassword(const std::string& json, + std::string* username, std::string* password) { + scoped_ptr parsed_value(JSONReader::Read(json, false)); + if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) + return false; + + DictionaryValue* result = static_cast(parsed_value.get()); + if (!result->GetString(L"user", username) || + !result->GetString(L"pass", password)) { + return false; + } + return true; +} + +void FlowHandler::HandleSubmitAuth(const Value* value) { + std::string json(GetJsonResponse(value)); + std::string username, password; + if (json.empty()) + return; + + if (!GetUsernameAndPassword(json, &username, &password)) { + // The page sent us something that we didn't understand. + // This probably indicates a programming error. + NOTREACHED(); + return; + } + + if (flow_) + flow_->OnUserSubmittedAuth(username, password); +} + +void FlowHandler::HandleSubmitMergeAndSync(const Value* value) { + if (flow_) + flow_->OnUserAcceptedMergeAndSync(); +} + +// Called by SyncSetupFlow::Advance. +void FlowHandler::ShowGaiaLogin(const DictionaryValue& args) { + std::string json; + JSONWriter::Write(&args, false, &json); + std::wstring javascript = std::wstring(L"showGaiaLogin") + + L"(" + UTF8ToWide(json) + L");"; + ExecuteJavascriptInIFrame(kLoginIFrameXPath, javascript); +} + +void FlowHandler::ShowGaiaSuccessAndClose() { + ExecuteJavascriptInIFrame(kLoginIFrameXPath, L"showGaiaSuccessAndClose();"); +} + +void FlowHandler::ShowGaiaSuccessAndSettingUp() { + ExecuteJavascriptInIFrame(kLoginIFrameXPath, + L"showGaiaSuccessAndSettingUp();"); +} + +void FlowHandler::ShowMergeAndSync() { + if (dom_ui_) // NULL during testing. + dom_ui_->CallJavascriptFunction(L"showMergeAndSync"); +} + +void FlowHandler::ShowSetupDone(const std::wstring& user) { + StringValue synced_to_string(WideToUTF8(l10n_util::GetStringF( + IDS_SYNC_NTP_SYNCED_TO, user))); + std::string json; + JSONWriter::Write(&synced_to_string, false, &json); + std::wstring javascript = std::wstring(L"setSyncedToUser") + + L"(" + UTF8ToWide(json) + L");"; + ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); + + if (dom_ui_) + dom_ui_->CallJavascriptFunction(L"showSetupDone", synced_to_string); +} + +void FlowHandler::ShowFirstTimeDone(const std::wstring& user) { + ExecuteJavascriptInIFrame(kDoneIframeXPath, + L"setShowFirstTimeSetupSummary();"); + ShowSetupDone(user); +} + +void FlowHandler::ShowMergeAndSyncError() { + ExecuteJavascriptInIFrame(kMergeIFrameXPath, L"showMergeAndSyncError();"); +} + +void FlowHandler::ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, + const std::wstring& js) { + if (dom_ui_) { + RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host(); + rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js); + } +} + +SyncSetupFlow::~SyncSetupFlow() { + flow_handler_->set_flow(NULL); +} + +void SyncSetupFlow::GetDialogSize(gfx::Size* size) const { + PrefService* prefs = service_->profile()->GetPrefs(); + gfx::Font approximate_web_font = gfx::Font::CreateFont( + prefs->GetString(prefs::kWebKitSansSerifFontFamily), + prefs->GetInteger(prefs::kWebKitDefaultFontSize)); + + gfx::Size s = gfx::GetLocalizedContentsSizeForFont( + IDS_SYNC_SETUP_WIZARD_WIDTH_CHARS, + IDS_SYNC_SETUP_WIZARD_HEIGHT_LINES, + approximate_web_font); + + size->set_width(s.width()); + size->set_height(s.height()); +} + +// A callback to notify the delegate that the dialog closed. +void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) { + DCHECK(json_retval.empty()); + container_->set_flow(NULL); // Sever ties from the wizard. + if (current_state_ == SyncSetupWizard::DONE || + current_state_ == SyncSetupWizard::DONE_FIRST_TIME) { + service_->SetSyncSetupCompleted(); + } + + // Record the state at which the user cancelled the signon dialog. + switch (current_state_) { + case SyncSetupWizard::GAIA_LOGIN: + ProfileSyncService::SyncEvent( + ProfileSyncService::CANCEL_FROM_SIGNON_WITHOUT_AUTH); + break; + case SyncSetupWizard::GAIA_SUCCESS: + ProfileSyncService::SyncEvent( + ProfileSyncService::CANCEL_DURING_SIGNON); + break; + case SyncSetupWizard::MERGE_AND_SYNC: + ProfileSyncService::SyncEvent( + ProfileSyncService::CANCEL_DURING_SIGNON_AFTER_MERGE); + break; + case SyncSetupWizard::DONE_FIRST_TIME: + case SyncSetupWizard::DONE: + UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedAuthorizationTime", + base::TimeTicks::Now() - login_start_time_); + break; + default: + break; + } + + service_->OnUserCancelledDialog(); + delete this; +} + +// static +void SyncSetupFlow::GetArgsForGaiaLogin(const ProfileSyncService* service, + DictionaryValue* args) { + AuthErrorState error(service->GetAuthErrorState()); + if (!service->last_attempted_user_email().empty()) { + args->SetString(L"user", service->last_attempted_user_email()); + args->SetInteger(L"error", error); + } else { + std::wstring user(UTF16ToWide(service->GetAuthenticatedUsername())); + args->SetString(L"user", user); + args->SetInteger(L"error", user.empty() ? 0 : error); + } +} + +void SyncSetupFlow::GetDOMMessageHandlers( + std::vector* handlers) const { + handlers->push_back(flow_handler_); +} + +bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) { + switch (state) { + case SyncSetupWizard::GAIA_LOGIN: + return current_state_ == SyncSetupWizard::GAIA_LOGIN; + case SyncSetupWizard::GAIA_SUCCESS: + return current_state_ == SyncSetupWizard::GAIA_LOGIN; + case SyncSetupWizard::MERGE_AND_SYNC: + return current_state_ == SyncSetupWizard::GAIA_SUCCESS; + case SyncSetupWizard::FATAL_ERROR: + return true; // You can always hit the panic button. + case SyncSetupWizard::DONE_FIRST_TIME: + case SyncSetupWizard::DONE: + return current_state_ == SyncSetupWizard::MERGE_AND_SYNC || + current_state_ == SyncSetupWizard::GAIA_SUCCESS; + default: + NOTREACHED() << "Unhandled State: " << state; + return false; + } +} + +void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) { + if (!ShouldAdvance(advance_state)) + return; + switch (advance_state) { + case SyncSetupWizard::GAIA_LOGIN: { + DictionaryValue args; + SyncSetupFlow::GetArgsForGaiaLogin(service_, &args); + flow_handler_->ShowGaiaLogin(args); + break; + } + case SyncSetupWizard::GAIA_SUCCESS: + if (end_state_ == SyncSetupWizard::GAIA_SUCCESS) + flow_handler_->ShowGaiaSuccessAndClose(); + else + flow_handler_->ShowGaiaSuccessAndSettingUp(); + break; + case SyncSetupWizard::MERGE_AND_SYNC: + flow_handler_->ShowMergeAndSync(); + break; + case SyncSetupWizard::FATAL_ERROR: + if (current_state_ == SyncSetupWizard::MERGE_AND_SYNC) + flow_handler_->ShowMergeAndSyncError(); + break; + case SyncSetupWizard::DONE_FIRST_TIME: + flow_handler_->ShowFirstTimeDone( + UTF16ToWide(service_->GetAuthenticatedUsername())); + break; + case SyncSetupWizard::DONE: + flow_handler_->ShowSetupDone( + UTF16ToWide(service_->GetAuthenticatedUsername())); + break; + default: + NOTREACHED() << "Invalid advance state: " << advance_state; + } + current_state_ = advance_state; +} + +// static +SyncSetupFlow* SyncSetupFlow::Run(ProfileSyncService* service, + SyncSetupFlowContainer* container, + SyncSetupWizard::State start, + SyncSetupWizard::State end) { + DictionaryValue args; + if (start == SyncSetupWizard::GAIA_LOGIN) + SyncSetupFlow::GetArgsForGaiaLogin(service, &args); + std::string json_args; + JSONWriter::Write(&args, false, &json_args); + + Browser* b = BrowserList::GetLastActive(); + if (!b) + return NULL; + + FlowHandler* handler = new FlowHandler(); + SyncSetupFlow* flow = new SyncSetupFlow(start, end, json_args, + container, handler, service); + handler->set_flow(flow); + b->BrowserShowHtmlDialog(flow, NULL); + return flow; +} + +#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/sync_setup_flow.h b/chrome/browser/sync/sync_setup_flow.h new file mode 100644 index 0000000..32e3db1 --- /dev/null +++ b/chrome/browser/sync/sync_setup_flow.h @@ -0,0 +1,189 @@ +// Copyright (c) 2006-2008 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. + +#ifdef CHROME_PERSONALIZATION + +#ifndef CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_ +#define CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_ + +#include +#include + +#include "app/l10n_util.h" +#include "base/time.h" +#include "chrome/browser/dom_ui/html_dialog_ui.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/sync_setup_wizard.h" +#include "grit/generated_resources.h" +#include "testing/gtest/include/gtest/gtest_prod.h" + +class FlowHandler; +class SyncSetupFlowContainer; + +// The state machine used by SyncSetupWizard, exposed in its own header +// to facilitate testing of SyncSetupWizard. This class is used to open and +// run the html dialog and deletes itself when the dialog closes. +class SyncSetupFlow : public HtmlDialogUIDelegate { + public: + virtual ~SyncSetupFlow(); + + // Runs a flow from |start| to |end|, and does the work of actually showing + // the HTML dialog. |container| is kept up-to-date with the lifetime of the + // flow (e.g it is emptied on dialog close). + static SyncSetupFlow* Run(ProfileSyncService* service, + SyncSetupFlowContainer* container, + SyncSetupWizard::State start, + SyncSetupWizard::State end); + + // Fills |args| with "user" and "error" arguments by querying |service|. + static void GetArgsForGaiaLogin( + const ProfileSyncService* service, + DictionaryValue* args); + + // Triggers a state machine transition to advance_state. + void Advance(SyncSetupWizard::State advance_state); + + // HtmlDialogUIDelegate implementation. + // Get the HTML file path for the content to load in the dialog. + virtual GURL GetDialogContentURL() const { + return GURL("chrome://syncresources/setup"); + } + + // HtmlDialogUIDelegate implementation. + virtual void GetDOMMessageHandlers( + std::vector* handlers) const; + + // HtmlDialogUIDelegate implementation. + // Get the size of the dialog. + virtual void GetDialogSize(gfx::Size* size) const; + + // HtmlDialogUIDelegate implementation. + // Gets the JSON string input to use when opening the dialog. + virtual std::string GetDialogArgs() const { + return dialog_start_args_; + } + + // HtmlDialogUIDelegate implementation. + // A callback to notify the delegate that the dialog closed. + virtual void OnDialogClosed(const std::string& json_retval); + + // HtmlDialogUIDelegate implementation. + virtual std::wstring GetDialogTitle() const { + return l10n_util::GetString(IDS_SYNC_MY_BOOKMARKS_LABEL); + } + + // HtmlDialogUIDelegate implementation. + virtual bool IsDialogModal() const { + return false; + } + + void OnUserSubmittedAuth(const std::string& username, + const std::string& password) { + service_->OnUserSubmittedAuth(username, password); + } + + void OnUserAcceptedMergeAndSync() { + service_->OnUserAcceptedMergeAndSync(); + } + + private: + FRIEND_TEST(SyncSetupWizardTest, InitialStepLogin); + FRIEND_TEST(SyncSetupWizardTest, InitialStepMergeAndSync); + FRIEND_TEST(SyncSetupWizardTest, DialogCancelled); + FRIEND_TEST(SyncSetupWizardTest, InvalidTransitions); + FRIEND_TEST(SyncSetupWizardTest, FullSuccessfulRunSetsPref); + FRIEND_TEST(SyncSetupWizardTest, DiscreteRun); + + // Use static Run method to get an instance. + SyncSetupFlow(SyncSetupWizard::State start_state, + SyncSetupWizard::State end_state, + const std::string& args, SyncSetupFlowContainer* container, + FlowHandler* handler, ProfileSyncService* service) + : container_(container), + dialog_start_args_(args), + current_state_(start_state), + end_state_(end_state), + login_start_time_(base::TimeTicks::Now()), + flow_handler_(handler), + service_(service) { + } + + // Returns true if |this| should transition its state machine to |state| + // based on |current_state_|, or false if that would be nonsense or is + // a no-op. + bool ShouldAdvance(SyncSetupWizard::State state); + + SyncSetupFlowContainer* container_; // Our container. Don't own this. + std::string dialog_start_args_; // The args to pass to the initial page. + + SyncSetupWizard::State current_state_; + SyncSetupWizard::State end_state_; // The goal. + + // Time that the GAIA_LOGIN step was received. + base::TimeTicks login_start_time_; + + // The handler needed for the entire flow. We don't own this. + FlowHandler* flow_handler_; + + // We need this to write the sentinel "setup completed" pref. + ProfileSyncService* service_; + + DISALLOW_COPY_AND_ASSIGN(SyncSetupFlow); +}; + +// A really simple wrapper for a SyncSetupFlow so that we don't have to +// add any public methods to the public SyncSetupWizard interface to notify it +// when the dialog closes. +class SyncSetupFlowContainer { + public: + SyncSetupFlowContainer() : flow_(NULL) { } + void set_flow(SyncSetupFlow* flow) { + DCHECK(!flow_ || !flow); + flow_ = flow; + } + + SyncSetupFlow* get_flow() { return flow_; } + private: + SyncSetupFlow* flow_; + + DISALLOW_COPY_AND_ASSIGN(SyncSetupFlowContainer); +}; + +// The FlowHandler connects the state machine to the dialog backing HTML and +// JS namespace by implementing DOMMessageHandler and being invoked by the +// SyncSetupFlow. Exposed here to facilitate testing. +class FlowHandler : public DOMMessageHandler { + public: + FlowHandler() {} + virtual ~FlowHandler() {} + + // DOMMessageHandler implementation. + virtual void RegisterMessages(); + + // Callbacks from the page. + void HandleSubmitAuth(const Value* value); + void HandleSubmitMergeAndSync(const Value* value); + + // These functions control which part of the HTML is visible. + void ShowGaiaLogin(const DictionaryValue& args); + void ShowGaiaSuccessAndClose(); + void ShowGaiaSuccessAndSettingUp(); + void ShowMergeAndSync(); + void ShowMergeAndSyncError(); + void ShowSetupDone(const std::wstring& user); + void ShowFirstTimeDone(const std::wstring& user); + + void set_flow(SyncSetupFlow* flow) { + flow_ = flow; + } + + private: + void ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, + const std::wstring& js); + SyncSetupFlow* flow_; + DISALLOW_COPY_AND_ASSIGN(FlowHandler); +}; + +#endif // CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_ +#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/sync_setup_wizard.cc b/chrome/browser/sync/sync_setup_wizard.cc new file mode 100644 index 0000000..7d00ab9 --- /dev/null +++ b/chrome/browser/sync/sync_setup_wizard.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2006-2008 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. + +#ifdef CHROME_PERSONALIZATION + +#include "chrome/browser/sync/sync_setup_wizard.h" + +#include "app/resource_bundle.h" +#include "base/message_loop.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/dom_ui/chrome_url_data_manager.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/sync_setup_flow.h" +#include "chrome/common/jstemplate_builder.h" +#include "chrome/common/url_constants.h" +#include "grit/app_resources.h" +#include "grit/browser_resources.h" + +class SyncResourcesSource : public ChromeURLDataManager::DataSource { + public: + SyncResourcesSource() + : DataSource(chrome::kSyncResourcesHost, MessageLoop::current()) { + } + virtual ~SyncResourcesSource() { } + + virtual void StartDataRequest(const std::string& path, int request_id); + + virtual std::string GetMimeType(const std::string& path) const { + if (path == chrome::kSyncThrobberPath) + return "image/png"; + else + return "text/html"; + } + private: + DISALLOW_COPY_AND_ASSIGN(SyncResourcesSource); +}; + +void SyncResourcesSource::StartDataRequest(const std::string& path_raw, + int request_id) { + scoped_refptr html_bytes(new RefCountedBytes); + if (path_raw == chrome::kSyncThrobberPath) { + ResourceBundle::GetSharedInstance().LoadImageResourceBytes(IDR_THROBBER, + &html_bytes->data); + SendResponse(request_id, html_bytes); + return; + } + + std::string response; + if (path_raw == chrome::kSyncGaiaLoginPath) { + DictionaryValue localized_strings; + localized_strings.SetString(L"settingupsync", + l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP_SYNC)); + localized_strings.SetString(L"introduction", + l10n_util::GetString(IDS_SYNC_LOGIN_INTRODUCTION)); + localized_strings.SetString(L"signinprefix", + l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_PREFIX)); + localized_strings.SetString(L"signinsuffix", + l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_SUFFIX)); + localized_strings.SetString(L"cannotbeblank", + l10n_util::GetString(IDS_SYNC_CANNOT_BE_BLANK)); + localized_strings.SetString(L"emaillabel", + l10n_util::GetString(IDS_SYNC_LOGIN_EMAIL)); + localized_strings.SetString(L"passwordlabel", + l10n_util::GetString(IDS_SYNC_LOGIN_PASSWORD)); + localized_strings.SetString(L"invalidcredentials", + l10n_util::GetString(IDS_SYNC_INVALID_USER_CREDENTIALS)); + localized_strings.SetString(L"signin", + l10n_util::GetString(IDS_SYNC_SIGNIN)); + localized_strings.SetString(L"couldnotconnect", + l10n_util::GetString(IDS_SYNC_LOGIN_COULD_NOT_CONNECT)); + localized_strings.SetString(L"cannotaccessaccount", + l10n_util::GetString(IDS_SYNC_CANNOT_ACCESS_ACCOUNT)); + localized_strings.SetString(L"createaccount", + l10n_util::GetString(IDS_SYNC_CREATE_ACCOUNT)); + localized_strings.SetString(L"cancel", + l10n_util::GetString(IDS_CANCEL)); + localized_strings.SetString(L"settingup", + l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP)); + localized_strings.SetString(L"success", + l10n_util::GetString(IDS_SYNC_SUCCESS)); + localized_strings.SetString(L"errorsigningin", + l10n_util::GetString(IDS_SYNC_ERROR_SIGNING_IN)); + static const base::StringPiece html(ResourceBundle::GetSharedInstance() + .GetRawDataResource(IDR_GAIA_LOGIN_HTML)); + SetFontAndTextDirection(&localized_strings); + response = jstemplate_builder::GetI18nTemplateHtml( + html, &localized_strings); + } else if (path_raw == chrome::kSyncMergeAndSyncPath) { + DictionaryValue localized_strings; + localized_strings.SetString(L"introduction", + l10n_util::GetString(IDS_SYNC_MERGE_INTRODUCTION)); + localized_strings.SetString(L"mergeandsynclabel", + l10n_util::GetString(IDS_SYNC_MERGE_AND_SYNC_LABEL)); + localized_strings.SetString(L"abortlabel", + l10n_util::GetString(IDS_ABORT)); + localized_strings.SetString(L"closelabel", + l10n_util::GetString(IDS_CLOSE)); + localized_strings.SetString(L"mergeandsyncwarning", + l10n_util::GetString(IDS_SYNC_MERGE_WARNING)); + localized_strings.SetString(L"setuperror", + l10n_util::GetString(IDS_SYNC_SETUP_ERROR)); + + static const base::StringPiece html(ResourceBundle::GetSharedInstance() + .GetRawDataResource(IDR_MERGE_AND_SYNC_HTML)); + SetFontAndTextDirection(&localized_strings); + response = jstemplate_builder::GetI18nTemplateHtml( + html, &localized_strings); + } else if (path_raw == chrome::kSyncSetupDonePath) { + DictionaryValue localized_strings; + localized_strings.SetString(L"success", + l10n_util::GetString(IDS_SYNC_SUCCESS)); + localized_strings.SetString(L"setupsummary", + l10n_util::GetString(IDS_SYNC_SETUP_ALL_DONE)); + localized_strings.SetString(L"firsttimesetupsummary", + l10n_util::GetString(IDS_SYNC_SETUP_FIRST_TIME_ALL_DONE)); + localized_strings.SetString(L"okay", + l10n_util::GetString(IDS_SYNC_SETUP_OK_BUTTON_LABEL)); + static const base::StringPiece html(ResourceBundle::GetSharedInstance() + .GetRawDataResource(IDR_SYNC_SETUP_DONE_HTML)); + SetFontAndTextDirection(&localized_strings); + response = jstemplate_builder::GetI18nTemplateHtml( + html, &localized_strings); + } else if (path_raw == chrome::kSyncSetupFlowPath) { + static const base::StringPiece html(ResourceBundle::GetSharedInstance() + .GetRawDataResource(IDR_SYNC_SETUP_FLOW_HTML)); + response = html.as_string(); + } + // Send the response. + html_bytes->data.resize(response.size()); + std::copy(response.begin(), response.end(), html_bytes->data.begin()); + SendResponse(request_id, html_bytes); +} + +SyncSetupWizard::SyncSetupWizard(ProfileSyncService* service) + : service_(service), + flow_container_(new SyncSetupFlowContainer()) { + // Register data sources for HTML content we require. + // g_browser_process and/or io_thread may not exist during testing. + if (g_browser_process && g_browser_process->io_thread()) { + // Add our network layer data source for 'cloudy' URLs. + g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(&chrome_url_data_manager, + &ChromeURLDataManager::AddDataSource, + new SyncResourcesSource())); + } +} + +SyncSetupWizard::~SyncSetupWizard() { + delete flow_container_; +} + +void SyncSetupWizard::Step(State advance_state) { + SyncSetupFlow* flow = flow_container_->get_flow(); + if (flow) { + // A setup flow is in progress and dialog is currently showing. + flow->Advance(advance_state); + } else if (!service_->profile()->GetPrefs()->GetBoolean( + prefs::kSyncHasSetupCompleted)) { + if (IsTerminalState(advance_state)) + return; + // No flow is in progress, and we have never escorted the user all the + // way through the wizard flow. + flow_container_->set_flow( + SyncSetupFlow::Run(service_, flow_container_, advance_state, DONE)); + } else { + // No flow in in progress, but we've finished the wizard flow once before. + // This is just a discrete run. + if (IsTerminalState(advance_state)) + return; // Nothing to do. + flow_container_->set_flow(SyncSetupFlow::Run(service_, flow_container_, + advance_state, GetEndStateForDiscreteRun(advance_state))); + } +} + +// static +bool SyncSetupWizard::IsTerminalState(State advance_state) { + return advance_state == GAIA_SUCCESS || + advance_state == DONE || + advance_state == DONE_FIRST_TIME || + advance_state == FATAL_ERROR; +} + +bool SyncSetupWizard::IsVisible() const { + return flow_container_->get_flow() != NULL; +} + +// static +SyncSetupWizard::State SyncSetupWizard::GetEndStateForDiscreteRun( + State start_state) { + State result = start_state == GAIA_LOGIN ? GAIA_SUCCESS : DONE; + DCHECK_NE(DONE, result) << + "Invalid start state for discrete run: " << start_state; + return result; +} + +#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/sync_setup_wizard.h b/chrome/browser/sync/sync_setup_wizard.h new file mode 100644 index 0000000..d8a0d95 --- /dev/null +++ b/chrome/browser/sync/sync_setup_wizard.h @@ -0,0 +1,82 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_BROWSER_SYNC_SYNC_SETUP_WIZARD_H_ +#define CHROME_BROWSER_SYNC_SYNC_SETUP_WIZARD_H_ + +#include "base/basictypes.h" + +#if defined(OS_LINUX) +typedef struct _GtkWidget GtkWidget; +typedef struct _GtkWindow GtkWindow; +#else +class SyncSetupFlowContainer; +#endif + +class ProfileSyncService; + +class SyncSetupWizard { + public: + enum State { + // Show the Google Account login UI. + GAIA_LOGIN = 0, + // A login attempt succeeded. Depending on initial conditions, this may + // cause a transition to DONE, or to wait for an explicit transition (via + // Step) to the next state. + GAIA_SUCCESS, + // The user needs to accept a merge and sync warning to proceed. + MERGE_AND_SYNC, + // The panic switch. Something went terribly wrong during setup and we + // can't recover. + FATAL_ERROR, + // A final state for when setup completes and it is possible it is the + // user's first time (globally speaking) as the cloud doesn't have any + // bookmarks. We show additional info in this case to explain setting up + // more computers. + DONE_FIRST_TIME, + // A catch-all done case for any setup process. + DONE + }; + + explicit SyncSetupWizard(ProfileSyncService* service); + ~SyncSetupWizard(); + + // Advances the wizard to the specified state if possible, or opens a + // new dialog starting at |advance_state|. If the wizard has never ran + // through to completion, it will always attempt to do so. Otherwise, e.g + // for a transient auth failure, it will just run as far as is necessary + // based on |advance_state| (so for auth failure, up to GAIA_SUCCESS). + void Step(State advance_state); + + // Whether or not a dialog is currently showing. Useful to determine + // if various buttons in the UI should be enabled or disabled. + bool IsVisible() const; + +#if defined(OS_LINUX) + void SetVisible(bool visible) { visible_ = visible; } +#endif + + private: + // If we just need to pop open an individual dialog, say to collect + // gaia credentials in the event of a steady-state auth failure, this is + // a "discrete" run (as in not a continuous wizard flow). This returns + // the end state to pass to Run for a given |start_state|. + static State GetEndStateForDiscreteRun(State start_state); + + // Helper to return whether |state| warrants starting a new flow. + static bool IsTerminalState(State state); + + ProfileSyncService* service_; + +#if defined(OS_LINUX) + bool visible_; +#else + SyncSetupFlowContainer* flow_container_; +#endif + + DISALLOW_COPY_AND_ASSIGN(SyncSetupWizard); +}; + +#endif // CHROME_BROWSER_SYNC_SYNC_SETUP_WIZARD_H_ + diff --git a/chrome/browser/sync/sync_setup_wizard_unittest.cc b/chrome/browser/sync/sync_setup_wizard_unittest.cc new file mode 100644 index 0000000..3a04746 --- /dev/null +++ b/chrome/browser/sync/sync_setup_wizard_unittest.cc @@ -0,0 +1,376 @@ +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef CHROME_PERSONALIZATION + +#include "testing/gtest/include/gtest/gtest.h" + +#include "base/json_writer.h" +#include "base/scoped_ptr.h" +#include "base/stl_util-inl.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/sync_setup_flow.h" +#include "chrome/browser/sync/sync_setup_wizard.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/test/browser_with_test_window_test.h" +#include "chrome/test/testing_profile.h" +#include "chrome/test/test_browser_window.h" + +static const char* kTestUser = "chrome.p13n.test@gmail.com"; +static const char* kTestPassword = "passwd"; + +// A PSS subtype to inject. +class ProfileSyncServiceForWizardTest : public ProfileSyncService { + public: + explicit ProfileSyncServiceForWizardTest(Profile* profile) + : ProfileSyncService(profile), user_accepted_merge_and_sync_(false), + user_cancelled_dialog_(false) { + RegisterPreferences(); + } + + virtual ~ProfileSyncServiceForWizardTest() { } + + virtual void OnUserSubmittedAuth(const std::string& username, + const std::string& password) { + username_ = username; + password_ = password; + } + virtual void OnUserAcceptedMergeAndSync() { + user_accepted_merge_and_sync_ = true; + } + virtual void OnUserCancelledDialog() { + user_cancelled_dialog_ = true; + } + + virtual string16 GetAuthenticatedUsername() const { + return UTF8ToUTF16(username_); + } + + void set_auth_state(const std::string& last_email, AuthErrorState state) { + last_attempted_user_email_ = last_email; + last_auth_error_ = state; + } + + void ResetTestStats() { + username_.clear(); + password_.clear(); + user_accepted_merge_and_sync_ = false; + user_cancelled_dialog_ = false; + } + + std::string username_; + std::string password_; + bool user_accepted_merge_and_sync_; + bool user_cancelled_dialog_; + + private: + DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceForWizardTest); +}; + +class TestingProfileWithSyncService : public TestingProfile { + public: + TestingProfileWithSyncService() { + sync_service_.reset(new ProfileSyncServiceForWizardTest(this)); + } + + virtual ProfileSyncService* GetProfileSyncService() { + return sync_service_.get(); + } + private: + scoped_ptr sync_service_; +}; + +class TestBrowserWindowForWizardTest : public TestBrowserWindow { + public: + explicit TestBrowserWindowForWizardTest(Browser* browser) + : TestBrowserWindow(browser), flow_(NULL), + was_show_html_dialog_called_(false) { + } + + virtual ~TestBrowserWindowForWizardTest() { + if (flow_.get()) { + // In real life, the handlers are destroyed by the DOMUI infrastructure, + // which calls GetDOMMessageHandlers to take ownership. This does not + // exist in our test, so we perform cleanup manually. + std::vector handlers; + flow_->GetDOMMessageHandlers(&handlers); + // The handler contract is that they are valid for the lifetime of the + // HTMLDialogUIDelegate, but are cleaned up after the dialog is closed + // and/or deleted. + flow_.reset(); + STLDeleteElements(&handlers); + } + } + + // We intercept this call to hijack the flow created and then use it to + // drive the wizard as if we were the HTML page. + virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, + gfx::NativeWindow parent_window) { + flow_.reset(static_cast(delegate)); + was_show_html_dialog_called_ = true; + } + + bool TestAndResetWasShowHTMLDialogCalled() { + bool ret = was_show_html_dialog_called_; + was_show_html_dialog_called_ = false; + return ret; + } + + // Simulates the user (or browser view hierarchy) closing the html dialog. + // Handles cleaning up the delegate and associated handlers. + void CloseDialog() { + if (flow_.get()) { + std::vector handlers; + flow_->GetDOMMessageHandlers(&handlers); + // The flow deletes itself here. Don't use reset(). + flow_.release()->OnDialogClosed(""); + STLDeleteElements(&handlers); + } + } + + SyncSetupFlow* flow() { return flow_.get(); } + + private: + // In real life, this is owned by the view that is opened by the browser. We + // mock all that out, so we need to take ownership so the flow doesn't leak. + scoped_ptr flow_; + + bool was_show_html_dialog_called_; +}; + +class SyncSetupWizardTest : public BrowserWithTestWindowTest { + public: + SyncSetupWizardTest() : test_window_(NULL), wizard_(NULL) { } + virtual ~SyncSetupWizardTest() { } + virtual void SetUp() { + set_profile(new TestingProfileWithSyncService()); + profile()->CreateBookmarkModel(false); + // Wait for the bookmarks model to load. + profile()->BlockUntilBookmarkModelLoaded(); + set_browser(new Browser(Browser::TYPE_NORMAL, profile())); + test_window_ = new TestBrowserWindowForWizardTest(browser()); + set_window(test_window_); + browser()->set_window(window()); + BrowserList::SetLastActive(browser()); + service_ = static_cast( + profile()->GetProfileSyncService()); + wizard_.reset(new SyncSetupWizard(service_)); + } + + virtual void TearDown() { + test_window_ = NULL; + service_ = NULL; + wizard_.reset(); + } + + TestBrowserWindowForWizardTest* test_window_; + scoped_ptr wizard_; + ProfileSyncServiceForWizardTest* service_; +}; + +TEST_F(SyncSetupWizardTest, InitialStepLogin) { + DictionaryValue dialog_args; + SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); + std::string json_start_args; + JSONWriter::Write(&dialog_args, false, &json_start_args); + ListValue credentials; + std::string auth = "{\"user\":\""; + auth += std::string(kTestUser) + "\",\"pass\":\""; + auth += std::string(kTestPassword) + "\"}"; + credentials.Append(new StringValue(auth)); + + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->flow()); + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->end_state_); + EXPECT_EQ(json_start_args, test_window_->flow()->dialog_start_args_); + + // Simulate the user submitting credentials. + test_window_->flow()->flow_handler_->HandleSubmitAuth(&credentials); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + EXPECT_EQ(kTestUser, service_->username_); + EXPECT_EQ(kTestPassword, service_->password_); + EXPECT_FALSE(service_->user_accepted_merge_and_sync_); + EXPECT_FALSE(service_->user_cancelled_dialog_); + service_->ResetTestStats(); + + // Simulate failed credentials. + service_->set_auth_state(kTestUser, AUTH_ERROR_INVALID_GAIA_CREDENTIALS); + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + dialog_args.Clear(); + SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); + EXPECT_TRUE(2 == dialog_args.GetSize()); + std::string actual_user; + dialog_args.GetString(L"user", &actual_user); + EXPECT_EQ(kTestUser, actual_user); + int error = -1; + dialog_args.GetInteger(L"error", &error); + EXPECT_EQ(static_cast(AUTH_ERROR_INVALID_GAIA_CREDENTIALS), error); + service_->set_auth_state(kTestUser, AUTH_ERROR_NONE); + + // Simulate success. + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::GAIA_SUCCESS, + test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::DONE); // No merge and sync. + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->current_state_); +} + +TEST_F(SyncSetupWizardTest, InitialStepMergeAndSync) { + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->end_state_); + + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, + test_window_->flow()->current_state_); + + test_window_->flow()->flow_handler_->HandleSubmitMergeAndSync(NULL); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, + test_window_->flow()->current_state_); + EXPECT_EQ(std::string(), service_->username_); + EXPECT_EQ(std::string(), service_->password_); + EXPECT_TRUE(service_->user_accepted_merge_and_sync_); + EXPECT_FALSE(service_->user_cancelled_dialog_); + service_->ResetTestStats(); + wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); // No merge and sync. + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::DONE_FIRST_TIME, + test_window_->flow()->current_state_); +} + +TEST_F(SyncSetupWizardTest, DialogCancelled) { + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + // Simulate the user closing the dialog. + test_window_->CloseDialog(); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_TRUE(service_->user_cancelled_dialog_); + EXPECT_EQ(std::string(), service_->username_); + EXPECT_EQ(std::string(), service_->password_); + EXPECT_FALSE(service_->user_accepted_merge_and_sync_); + + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + test_window_->CloseDialog(); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_TRUE(service_->user_cancelled_dialog_); + EXPECT_EQ(std::string(), service_->username_); + EXPECT_EQ(std::string(), service_->password_); + EXPECT_FALSE(service_->user_accepted_merge_and_sync_); +} + +TEST_F(SyncSetupWizardTest, InvalidTransitions) { + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::DONE); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::DONE); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, + test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, + test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::FATAL_ERROR); + EXPECT_EQ(SyncSetupWizard::FATAL_ERROR, test_window_->flow()->current_state_); +} + +TEST_F(SyncSetupWizardTest, FullSuccessfulRunSetsPref) { + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + wizard_->Step(SyncSetupWizard::DONE); + test_window_->CloseDialog(); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_TRUE(service_->profile()->GetPrefs()->GetBoolean( + prefs::kSyncHasSetupCompleted)); +} + +TEST_F(SyncSetupWizardTest, FirstFullSuccessfulRunSetsPref) { + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); + test_window_->CloseDialog(); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_TRUE(service_->profile()->GetPrefs()->GetBoolean( + prefs::kSyncHasSetupCompleted)); +} + +TEST_F(SyncSetupWizardTest, DiscreteRun) { + DictionaryValue dialog_args; + // For a discrete run, we need to have ran through setup once. + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + wizard_->Step(SyncSetupWizard::DONE); + test_window_->CloseDialog(); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_EQ(SyncSetupWizard::GAIA_SUCCESS, test_window_->flow()->end_state_); + + service_->set_auth_state(kTestUser, AUTH_ERROR_INVALID_GAIA_CREDENTIALS); + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_TRUE(wizard_->IsVisible()); + SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); + EXPECT_TRUE(2 == dialog_args.GetSize()); + std::string actual_user; + dialog_args.GetString(L"user", &actual_user); + EXPECT_EQ(kTestUser, actual_user); + int error = -1; + dialog_args.GetInteger(L"error", &error); + EXPECT_EQ(static_cast(AUTH_ERROR_INVALID_GAIA_CREDENTIALS), error); + service_->set_auth_state(kTestUser, AUTH_ERROR_NONE); + + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); +} + +#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/util/character_set_converters.h b/chrome/browser/sync/util/character_set_converters.h index 1db32c7..6a833ee 100644 --- a/chrome/browser/sync/util/character_set_converters.h +++ b/chrome/browser/sync/util/character_set_converters.h @@ -136,6 +136,21 @@ inline void AppendPathStringToUTF8(const PathString& wide, return AppendPathStringToUTF8(wide.data(), wide.length(), output_string); } +// Versions of UTF8ToPathString/PathStringToUTF8 that return the converted +// string directly. Any errors encountered will CHECK(). These functions are +// intended to be used only for testing. + +inline PathString UTF8ToPathStringQuick(const std::string &utf8) { + PathString wide; + CHECK(UTF8ToPathString(utf8.data(), utf8.size(), &wide)); + return wide; +} + +inline std::string PathStringToUTF8Quick(const PathString& wide) { + std::string utf8; + PathStringToUTF8(wide.data(), wide.size(), &utf8); + return utf8; +} inline bool Append(const PathChar* wide, int size, std::string* output_string) { diff --git a/chrome/browser/sync/util/event_sys_unittest.cc b/chrome/browser/sync/util/event_sys_unittest.cc index 814ed46..c39ea9a 100644 --- a/chrome/browser/sync/util/event_sys_unittest.cc +++ b/chrome/browser/sync/util/event_sys_unittest.cc @@ -87,8 +87,8 @@ class EventLogger { } void HandlePairEvent(const string& name, const TestEvent& event) { - const char* what_changed; - int new_value; + const char* what_changed = NULL; + int new_value = 0; Hookups::iterator dead; switch (event.what_happened) { case TestEvent::A_CHANGED: diff --git a/chrome/browser/sync/util/user_settings_unittest.cc b/chrome/browser/sync/util/user_settings_unittest.cc index 952c86b..02f3fd8 100644 --- a/chrome/browser/sync/util/user_settings_unittest.cc +++ b/chrome/browser/sync/util/user_settings_unittest.cc @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE entry. +#include + #include "base/file_util.h" #include "base/test/test_file_util.h" #include "chrome/browser/sync/syncable/directory_manager.h" +#include "chrome/browser/sync/util/character_set_converters.h" #include "chrome/browser/sync/util/user_settings.h" #include "chrome/browser/sync/util/query_helpers.h" #include "testing/gtest/include/gtest/gtest.h" @@ -40,15 +43,10 @@ class UserSettingsTest : public testing::Test { ExecOrDie(primer_handle, "CREATE TABLE shares" " (email, share_name, file_name," " PRIMARY KEY(email, share_name) ON CONFLICT REPLACE)"); -#if OS_WIN - // Populate a share. - ExecOrDie(primer_handle, "INSERT INTO shares values ( ?, ?, ?)", - "foo@foo.com", "foo@foo.com", WideToUTF8(kOldStyleSyncDataDB)); -#elif OS_LINUX // Populate a share. ExecOrDie(primer_handle, "INSERT INTO shares values ( ?, ?, ?)", - "foo@foo.com", "foo@foo.com", kOldStyleSyncDataDB); -#endif + "foo@foo.com", "foo@foo.com", + browser_sync::PathStringToUTF8Quick(kOldStyleSyncDataDB)); sqlite3_close(primer_handle); } diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.mm b/chrome/browser/tab_contents/tab_contents_view_mac.mm index 21b4970..c966ee8 100644 --- a/chrome/browser/tab_contents/tab_contents_view_mac.mm +++ b/chrome/browser/tab_contents/tab_contents_view_mac.mm @@ -16,6 +16,7 @@ #include "chrome/browser/cocoa/sad_tab_view.h" #import "chrome/browser/cocoa/web_drag_source.h" #import "chrome/browser/cocoa/web_drop_target.h" +#include "chrome/browser/renderer_host/render_view_host_factory.h" #include "chrome/browser/renderer_host/render_widget_host.h" #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" #include "chrome/browser/tab_contents/render_view_context_menu_mac.h" @@ -71,7 +72,16 @@ void TabContentsViewMac::CreateView(const gfx::Size& initial_size) { RenderWidgetHostView* TabContentsViewMac::CreateViewForWidget( RenderWidgetHost* render_widget_host) { - DCHECK(!render_widget_host->view()); + if (render_widget_host->view()) { + // During testing, the view will already be set up in most cases to the + // test view, so we don't want to clobber it with a real one. To verify that + // this actually is happening (and somebody isn't accidentally creating the + // view twice), we check for the RVH Factory, which will be set when we're + // making special ones (which go along with the special views). + DCHECK(RenderViewHostFactory::has_factory()); + return render_widget_host->view(); + } + RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(render_widget_host); diff --git a/chrome/browser/views/sync/sync_setup_flow.cc b/chrome/browser/views/sync/sync_setup_flow.cc deleted file mode 100644 index 01a5728..0000000 --- a/chrome/browser/views/sync/sync_setup_flow.cc +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) 2009 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. - -#ifdef CHROME_PERSONALIZATION - -#include "chrome/browser/views/sync/sync_setup_flow.h" - -#include "app/gfx/font.h" -#include "base/histogram.h" -#include "base/json_reader.h" -#include "base/json_writer.h" -#include "base/string_util.h" -#include "base/values.h" -#include "chrome/browser/browser.h" -#include "chrome/browser/browser_list.h" -#include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/browser/sync/auth_error_state.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/common/pref_names.h" -#include "grit/locale_settings.h" -#include "views/window/window.h" - -// XPath expression for finding specific iframes. -static const wchar_t* kLoginIFrameXPath = L"//iframe[@id='login']"; -static const wchar_t* kMergeIFrameXPath = L"//iframe[@id='merge']"; -static const wchar_t* kDoneIframeXPath = L"//iframe[@id='done']"; - -// Helper function to read the JSON string from the Value parameter. -static std::string GetJsonResponse(const Value* content) { - if (!content || !content->IsType(Value::TYPE_LIST)) { - NOTREACHED(); - return std::string(); - } - const ListValue* args = static_cast(content); - if (args->GetSize() != 1) { - NOTREACHED(); - return std::string(); - } - - std::string result; - Value* value = NULL; - if (!args->Get(0, &value) || !value->GetAsString(&result)) { - NOTREACHED(); - return std::string(); - } - - return result; -} - -void FlowHandler::RegisterMessages() { - dom_ui_->RegisterMessageCallback("SubmitAuth", - NewCallback(this, &FlowHandler::HandleSubmitAuth)); - dom_ui_->RegisterMessageCallback("SubmitMergeAndSync", - NewCallback(this, &FlowHandler::HandleSubmitMergeAndSync)); -} - -static bool GetUsernameAndPassword(const std::string& json, - std::string* username, std::string* password) { - scoped_ptr parsed_value(JSONReader::Read(json, false)); - if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) - return false; - - DictionaryValue* result = static_cast(parsed_value.get()); - if (!result->GetString(L"user", username) || - !result->GetString(L"pass", password)) { - return false; - } - return true; -} - -void FlowHandler::HandleSubmitAuth(const Value* value) { - std::string json(GetJsonResponse(value)); - std::string username, password; - if (json.empty()) - return; - - if (!GetUsernameAndPassword(json, &username, &password)) { - // The page sent us something that we didn't understand. - // This probably indicates a programming error. - NOTREACHED(); - return; - } - - if (flow_) - flow_->OnUserSubmittedAuth(username, password); -} - -void FlowHandler::HandleSubmitMergeAndSync(const Value* value) { - if (flow_) - flow_->OnUserAcceptedMergeAndSync(); -} - -// Called by SyncSetupFlow::Advance. -void FlowHandler::ShowGaiaLogin(const DictionaryValue& args) { - std::string json; - JSONWriter::Write(&args, false, &json); - std::wstring javascript = std::wstring(L"showGaiaLogin") + - L"(" + UTF8ToWide(json) + L");"; - ExecuteJavascriptInIFrame(kLoginIFrameXPath, javascript); -} - -void FlowHandler::ShowGaiaSuccessAndClose() { - ExecuteJavascriptInIFrame(kLoginIFrameXPath, L"showGaiaSuccessAndClose();"); -} - -void FlowHandler::ShowGaiaSuccessAndSettingUp() { - ExecuteJavascriptInIFrame(kLoginIFrameXPath, - L"showGaiaSuccessAndSettingUp();"); -} - -void FlowHandler::ShowMergeAndSync() { - if (dom_ui_) // NULL during testing. - dom_ui_->CallJavascriptFunction(L"showMergeAndSync"); -} - -void FlowHandler::ShowSetupDone(const std::wstring& user) { - StringValue synced_to_string(WideToUTF8(l10n_util::GetStringF( - IDS_SYNC_NTP_SYNCED_TO, user))); - std::string json; - JSONWriter::Write(&synced_to_string, false, &json); - std::wstring javascript = std::wstring(L"setSyncedToUser") + - L"(" + UTF8ToWide(json) + L");"; - ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); - - if (dom_ui_) - dom_ui_->CallJavascriptFunction(L"showSetupDone", synced_to_string); -} - -void FlowHandler::ShowFirstTimeDone(const std::wstring& user) { - ExecuteJavascriptInIFrame(kDoneIframeXPath, - L"setShowFirstTimeSetupSummary();"); - ShowSetupDone(user); -} - -void FlowHandler::ShowMergeAndSyncError() { - ExecuteJavascriptInIFrame(kMergeIFrameXPath, L"showMergeAndSyncError();"); -} - -void FlowHandler::ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, - const std::wstring& js) { - if (dom_ui_) { - RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host(); - rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js); - } -} - -SyncSetupFlow::~SyncSetupFlow() { - flow_handler_->set_flow(NULL); -} - -void SyncSetupFlow::GetDialogSize(gfx::Size* size) const { - PrefService* prefs = service_->profile()->GetPrefs(); - gfx::Font approximate_web_font = gfx::Font::CreateFont( - prefs->GetString(prefs::kWebKitSansSerifFontFamily), - prefs->GetInteger(prefs::kWebKitDefaultFontSize)); - - gfx::Size s = views::Window::GetLocalizedContentsSizeForFont( - IDS_SYNC_SETUP_WIZARD_WIDTH_CHARS, - IDS_SYNC_SETUP_WIZARD_HEIGHT_LINES, - approximate_web_font); - - size->set_width(s.width()); - size->set_height(s.height()); -} - -// A callback to notify the delegate that the dialog closed. -void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) { - DCHECK(json_retval.empty()); - container_->set_flow(NULL); // Sever ties from the wizard. - if (current_state_ == SyncSetupWizard::DONE || - current_state_ == SyncSetupWizard::DONE_FIRST_TIME) { - service_->SetSyncSetupCompleted(); - } - - // Record the state at which the user cancelled the signon dialog. - switch (current_state_) { - case SyncSetupWizard::GAIA_LOGIN: - ProfileSyncService::SyncEvent( - ProfileSyncService::CANCEL_FROM_SIGNON_WITHOUT_AUTH); - break; - case SyncSetupWizard::GAIA_SUCCESS: - ProfileSyncService::SyncEvent( - ProfileSyncService::CANCEL_DURING_SIGNON); - break; - case SyncSetupWizard::MERGE_AND_SYNC: - ProfileSyncService::SyncEvent( - ProfileSyncService::CANCEL_DURING_SIGNON_AFTER_MERGE); - break; - case SyncSetupWizard::DONE_FIRST_TIME: - case SyncSetupWizard::DONE: - UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedAuthorizationTime", - base::TimeTicks::Now() - login_start_time_); - break; - default: - break; - } - - service_->OnUserCancelledDialog(); - delete this; -} - -// static -void SyncSetupFlow::GetArgsForGaiaLogin(const ProfileSyncService* service, - DictionaryValue* args) { - AuthErrorState error(service->GetAuthErrorState()); - if (!service->last_attempted_user_email().empty()) { - args->SetString(L"user", service->last_attempted_user_email()); - args->SetInteger(L"error", error); - } else { - std::wstring user(UTF16ToWide(service->GetAuthenticatedUsername())); - args->SetString(L"user", user); - args->SetInteger(L"error", user.empty() ? 0 : error); - } -} - -void SyncSetupFlow::GetDOMMessageHandlers( - std::vector* handlers) const { - handlers->push_back(flow_handler_); -} - -bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) { - switch (state) { - case SyncSetupWizard::GAIA_LOGIN: - return current_state_ == SyncSetupWizard::GAIA_LOGIN; - case SyncSetupWizard::GAIA_SUCCESS: - return current_state_ == SyncSetupWizard::GAIA_LOGIN; - case SyncSetupWizard::MERGE_AND_SYNC: - return current_state_ == SyncSetupWizard::GAIA_SUCCESS; - case SyncSetupWizard::FATAL_ERROR: - return true; // You can always hit the panic button. - case SyncSetupWizard::DONE_FIRST_TIME: - case SyncSetupWizard::DONE: - return current_state_ == SyncSetupWizard::MERGE_AND_SYNC || - current_state_ == SyncSetupWizard::GAIA_SUCCESS; - default: - NOTREACHED() << "Unhandled State: " << state; - return false; - } -} - -void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) { - if (!ShouldAdvance(advance_state)) - return; - switch (advance_state) { - case SyncSetupWizard::GAIA_LOGIN: { - DictionaryValue args; - SyncSetupFlow::GetArgsForGaiaLogin(service_, &args); - flow_handler_->ShowGaiaLogin(args); - break; - } - case SyncSetupWizard::GAIA_SUCCESS: - if (end_state_ == SyncSetupWizard::GAIA_SUCCESS) - flow_handler_->ShowGaiaSuccessAndClose(); - else - flow_handler_->ShowGaiaSuccessAndSettingUp(); - break; - case SyncSetupWizard::MERGE_AND_SYNC: - flow_handler_->ShowMergeAndSync(); - break; - case SyncSetupWizard::FATAL_ERROR: - if (current_state_ == SyncSetupWizard::MERGE_AND_SYNC) - flow_handler_->ShowMergeAndSyncError(); - break; - case SyncSetupWizard::DONE_FIRST_TIME: - flow_handler_->ShowFirstTimeDone(service_->GetAuthenticatedUsername()); - break; - case SyncSetupWizard::DONE: - flow_handler_->ShowSetupDone(service_->GetAuthenticatedUsername()); - break; - default: - NOTREACHED() << "Invalid advance state: " << advance_state; - } - current_state_ = advance_state; -} - -// static -SyncSetupFlow* SyncSetupFlow::Run(ProfileSyncService* service, - SyncSetupFlowContainer* container, - SyncSetupWizard::State start, - SyncSetupWizard::State end) { - DictionaryValue args; - if (start == SyncSetupWizard::GAIA_LOGIN) - SyncSetupFlow::GetArgsForGaiaLogin(service, &args); - std::string json_args; - JSONWriter::Write(&args, false, &json_args); - - Browser* b = BrowserList::GetLastActive(); - if (!b) - return NULL; - - FlowHandler* handler = new FlowHandler(); - SyncSetupFlow* flow = new SyncSetupFlow(start, end, json_args, - container, handler, service); - handler->set_flow(flow); - b->BrowserShowHtmlDialog(flow, NULL); - return flow; -} - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/views/sync/sync_setup_flow.h b/chrome/browser/views/sync/sync_setup_flow.h deleted file mode 100644 index 4bc7d60..0000000 --- a/chrome/browser/views/sync/sync_setup_flow.h +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifdef CHROME_PERSONALIZATION - -#ifndef CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_FLOW_H_ -#define CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_FLOW_H_ - -#include -#include - -#include "app/l10n_util.h" -#include "base/time.h" -#include "chrome/browser/dom_ui/html_dialog_ui.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/browser/views/sync/sync_setup_wizard.h" -#include "grit/generated_resources.h" -#include "testing/gtest/include/gtest/gtest_prod.h" - -class FlowHandler; -class SyncSetupFlowContainer; - -// The state machine used by SyncSetupWizard, exposed in its own header -// to facilitate testing of SyncSetupWizard. This class is used to open and -// run the html dialog and deletes itself when the dialog closes. -class SyncSetupFlow : public HtmlDialogUIDelegate { - public: - virtual ~SyncSetupFlow(); - - // Runs a flow from |start| to |end|, and does the work of actually showing - // the HTML dialog. |container| is kept up-to-date with the lifetime of the - // flow (e.g it is emptied on dialog close). - static SyncSetupFlow* Run(ProfileSyncService* service, - SyncSetupFlowContainer* container, - SyncSetupWizard::State start, - SyncSetupWizard::State end); - - // Fills |args| with "user" and "error" arguments by querying |service|. - static void GetArgsForGaiaLogin( - const ProfileSyncService* service, - DictionaryValue* args); - - // Triggers a state machine transition to advance_state. - void Advance(SyncSetupWizard::State advance_state); - - // HtmlDialogUIDelegate implementation. - // Get the HTML file path for the content to load in the dialog. - virtual GURL GetDialogContentURL() const { - return GURL("chrome://syncresources/setup"); - } - - // HtmlDialogUIDelegate implementation. - virtual void GetDOMMessageHandlers( - std::vector* handlers) const; - - // HtmlDialogUIDelegate implementation. - // Get the size of the dialog. - virtual void GetDialogSize(gfx::Size* size) const; - - // HtmlDialogUIDelegate implementation. - // Gets the JSON string input to use when opening the dialog. - virtual std::string GetDialogArgs() const { - return dialog_start_args_; - } - - // HtmlDialogUIDelegate implementation. - // A callback to notify the delegate that the dialog closed. - virtual void OnDialogClosed(const std::string& json_retval); - - // HtmlDialogUIDelegate implementation. - virtual std::wstring GetDialogTitle() const { - return l10n_util::GetString(IDS_SYNC_MY_BOOKMARKS_LABEL); - } - - // HtmlDialogUIDelegate implementation. - virtual bool IsDialogModal() const { - return false; - } - - void OnUserSubmittedAuth(const std::string& username, - const std::string& password) { - service_->OnUserSubmittedAuth(username, password); - } - - void OnUserAcceptedMergeAndSync() { - service_->OnUserAcceptedMergeAndSync(); - } - - private: - FRIEND_TEST(SyncSetupWizardTest, InitialStepLogin); - FRIEND_TEST(SyncSetupWizardTest, InitialStepMergeAndSync); - FRIEND_TEST(SyncSetupWizardTest, DialogCancelled); - FRIEND_TEST(SyncSetupWizardTest, InvalidTransitions); - FRIEND_TEST(SyncSetupWizardTest, FullSuccessfulRunSetsPref); - FRIEND_TEST(SyncSetupWizardTest, DiscreteRun); - - // Use static Run method to get an instance. - SyncSetupFlow(SyncSetupWizard::State start_state, - SyncSetupWizard::State end_state, - const std::string& args, SyncSetupFlowContainer* container, - FlowHandler* handler, ProfileSyncService* service) - : container_(container), - dialog_start_args_(args), - current_state_(start_state), - end_state_(end_state), - login_start_time_(base::TimeTicks::Now()), - flow_handler_(handler), - service_(service) { - } - - // Returns true if |this| should transition its state machine to |state| - // based on |current_state_|, or false if that would be nonsense or is - // a no-op. - bool ShouldAdvance(SyncSetupWizard::State state); - - SyncSetupFlowContainer* container_; // Our container. Don't own this. - std::string dialog_start_args_; // The args to pass to the initial page. - - SyncSetupWizard::State current_state_; - SyncSetupWizard::State end_state_; // The goal. - - // Time that the GAIA_LOGIN step was received. - base::TimeTicks login_start_time_; - - // The handler needed for the entire flow. We don't own this. - FlowHandler* flow_handler_; - - // We need this to write the sentinel "setup completed" pref. - ProfileSyncService* service_; - - DISALLOW_COPY_AND_ASSIGN(SyncSetupFlow); -}; - -// A really simple wrapper for a SyncSetupFlow so that we don't have to -// add any public methods to the public SyncSetupWizard interface to notify it -// when the dialog closes. -class SyncSetupFlowContainer { - public: - SyncSetupFlowContainer() : flow_(NULL) { } - void set_flow(SyncSetupFlow* flow) { - DCHECK(!flow_ || !flow); - flow_ = flow; - } - - SyncSetupFlow* get_flow() { return flow_; } - private: - SyncSetupFlow* flow_; - - DISALLOW_COPY_AND_ASSIGN(SyncSetupFlowContainer); -}; - -// The FlowHandler connects the state machine to the dialog backing HTML and -// JS namespace by implementing DOMMessageHandler and being invoked by the -// SyncSetupFlow. Exposed here to facilitate testing. -class FlowHandler : public DOMMessageHandler { - public: - FlowHandler() {} - virtual ~FlowHandler() {} - - // DOMMessageHandler implementation. - virtual void RegisterMessages(); - - // Callbacks from the page. - void HandleSubmitAuth(const Value* value); - void HandleSubmitMergeAndSync(const Value* value); - - // These functions control which part of the HTML is visible. - void ShowGaiaLogin(const DictionaryValue& args); - void ShowGaiaSuccessAndClose(); - void ShowGaiaSuccessAndSettingUp(); - void ShowMergeAndSync(); - void ShowMergeAndSyncError(); - void ShowSetupDone(const std::wstring& user); - void ShowFirstTimeDone(const std::wstring& user); - - void set_flow(SyncSetupFlow* flow) { - flow_ = flow; - } - - private: - void ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, - const std::wstring& js); - SyncSetupFlow* flow_; - DISALLOW_COPY_AND_ASSIGN(FlowHandler); -}; - -#endif // CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_FLOW_H_ -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/views/sync/sync_setup_wizard.cc b/chrome/browser/views/sync/sync_setup_wizard.cc deleted file mode 100644 index 31afcea..0000000 --- a/chrome/browser/views/sync/sync_setup_wizard.cc +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifdef CHROME_PERSONALIZATION - -#include "chrome/browser/views/sync/sync_setup_wizard.h" - -#include "app/resource_bundle.h" -#include "base/message_loop.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/pref_service.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/dom_ui/chrome_url_data_manager.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/browser/views/sync/sync_setup_flow.h" -#include "chrome/common/jstemplate_builder.h" -#include "chrome/common/url_constants.h" -#include "grit/app_resources.h" -#include "grit/browser_resources.h" - -class SyncResourcesSource : public ChromeURLDataManager::DataSource { - public: - SyncResourcesSource() - : DataSource(chrome::kSyncResourcesHost, MessageLoop::current()) { - } - virtual ~SyncResourcesSource() { } - - virtual void StartDataRequest(const std::string& path, int request_id); - - virtual std::string GetMimeType(const std::string& path) const { - if (path == chrome::kSyncThrobberPath) - return "image/png"; - else - return "text/html"; - } - private: - DISALLOW_COPY_AND_ASSIGN(SyncResourcesSource); -}; - -void SyncResourcesSource::StartDataRequest(const std::string& path_raw, - int request_id) { - scoped_refptr html_bytes(new RefCountedBytes); - if (path_raw == chrome::kSyncThrobberPath) { - ResourceBundle::GetSharedInstance().LoadImageResourceBytes(IDR_THROBBER, - &html_bytes->data); - SendResponse(request_id, html_bytes); - return; - } - - std::string response; - if (path_raw == chrome::kSyncGaiaLoginPath) { - DictionaryValue localized_strings; - localized_strings.SetString(L"settingupsync", - l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP_SYNC)); - localized_strings.SetString(L"introduction", - l10n_util::GetString(IDS_SYNC_LOGIN_INTRODUCTION)); - localized_strings.SetString(L"signinprefix", - l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_PREFIX)); - localized_strings.SetString(L"signinsuffix", - l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_SUFFIX)); - localized_strings.SetString(L"cannotbeblank", - l10n_util::GetString(IDS_SYNC_CANNOT_BE_BLANK)); - localized_strings.SetString(L"emaillabel", - l10n_util::GetString(IDS_SYNC_LOGIN_EMAIL)); - localized_strings.SetString(L"passwordlabel", - l10n_util::GetString(IDS_SYNC_LOGIN_PASSWORD)); - localized_strings.SetString(L"invalidcredentials", - l10n_util::GetString(IDS_SYNC_INVALID_USER_CREDENTIALS)); - localized_strings.SetString(L"signin", - l10n_util::GetString(IDS_SYNC_SIGNIN)); - localized_strings.SetString(L"couldnotconnect", - l10n_util::GetString(IDS_SYNC_LOGIN_COULD_NOT_CONNECT)); - localized_strings.SetString(L"cannotaccessaccount", - l10n_util::GetString(IDS_SYNC_CANNOT_ACCESS_ACCOUNT)); - localized_strings.SetString(L"createaccount", - l10n_util::GetString(IDS_SYNC_CREATE_ACCOUNT)); - localized_strings.SetString(L"cancel", - l10n_util::GetString(IDS_CANCEL)); - localized_strings.SetString(L"settingup", - l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP)); - localized_strings.SetString(L"success", - l10n_util::GetString(IDS_SYNC_SUCCESS)); - localized_strings.SetString(L"errorsigningin", - l10n_util::GetString(IDS_SYNC_ERROR_SIGNING_IN)); - static const base::StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_GAIA_LOGIN_HTML)); - SetFontAndTextDirection(&localized_strings); - response = jstemplate_builder::GetI18nTemplateHtml( - html, &localized_strings); - } else if (path_raw == chrome::kSyncMergeAndSyncPath) { - DictionaryValue localized_strings; - localized_strings.SetString(L"introduction", - l10n_util::GetString(IDS_SYNC_MERGE_INTRODUCTION)); - localized_strings.SetString(L"mergeandsynclabel", - l10n_util::GetString(IDS_SYNC_MERGE_AND_SYNC_LABEL)); - localized_strings.SetString(L"abortlabel", - l10n_util::GetString(IDS_ABORT)); - localized_strings.SetString(L"closelabel", - l10n_util::GetString(IDS_CLOSE)); - localized_strings.SetString(L"mergeandsyncwarning", - l10n_util::GetString(IDS_SYNC_MERGE_WARNING)); - localized_strings.SetString(L"setuperror", - l10n_util::GetString(IDS_SYNC_SETUP_ERROR)); - - static const base::StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_MERGE_AND_SYNC_HTML)); - SetFontAndTextDirection(&localized_strings); - response = jstemplate_builder::GetI18nTemplateHtml( - html, &localized_strings); - } else if (path_raw == chrome::kSyncSetupDonePath) { - DictionaryValue localized_strings; - localized_strings.SetString(L"success", - l10n_util::GetString(IDS_SYNC_SUCCESS)); - localized_strings.SetString(L"setupsummary", - l10n_util::GetString(IDS_SYNC_SETUP_ALL_DONE)); - localized_strings.SetString(L"firsttimesetupsummary", - l10n_util::GetString(IDS_SYNC_SETUP_FIRST_TIME_ALL_DONE)); - localized_strings.SetString(L"okay", - l10n_util::GetString(IDS_SYNC_SETUP_OK_BUTTON_LABEL)); - static const base::StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_SYNC_SETUP_DONE_HTML)); - SetFontAndTextDirection(&localized_strings); - response = jstemplate_builder::GetI18nTemplateHtml( - html, &localized_strings); - } else if (path_raw == chrome::kSyncSetupFlowPath) { - static const base::StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_SYNC_SETUP_FLOW_HTML)); - response = html.as_string(); - } - // Send the response. - html_bytes->data.resize(response.size()); - std::copy(response.begin(), response.end(), html_bytes->data.begin()); - SendResponse(request_id, html_bytes); -} - -SyncSetupWizard::SyncSetupWizard(ProfileSyncService* service) - : service_(service), - flow_container_(new SyncSetupFlowContainer()) { - // Register data sources for HTML content we require. - // g_browser_process and/or io_thread may not exist during testing. - if (g_browser_process && g_browser_process->io_thread()) { - // Add our network layer data source for 'cloudy' URLs. - g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(&chrome_url_data_manager, - &ChromeURLDataManager::AddDataSource, - new SyncResourcesSource())); - } -} - -SyncSetupWizard::~SyncSetupWizard() { - delete flow_container_; -} - -void SyncSetupWizard::Step(State advance_state) { - SyncSetupFlow* flow = flow_container_->get_flow(); - if (flow) { - // A setup flow is in progress and dialog is currently showing. - flow->Advance(advance_state); - } else if (!service_->profile()->GetPrefs()->GetBoolean( - prefs::kSyncHasSetupCompleted)) { - if (IsTerminalState(advance_state)) - return; - // No flow is in progress, and we have never escorted the user all the - // way through the wizard flow. - flow_container_->set_flow( - SyncSetupFlow::Run(service_, flow_container_, advance_state, DONE)); - } else { - // No flow in in progress, but we've finished the wizard flow once before. - // This is just a discrete run. - if (IsTerminalState(advance_state)) - return; // Nothing to do. - flow_container_->set_flow(SyncSetupFlow::Run(service_, flow_container_, - advance_state, GetEndStateForDiscreteRun(advance_state))); - } -} - -// static -bool SyncSetupWizard::IsTerminalState(State advance_state) { - return advance_state == GAIA_SUCCESS || - advance_state == DONE || - advance_state == DONE_FIRST_TIME || - advance_state == FATAL_ERROR; -} - -bool SyncSetupWizard::IsVisible() const { - return flow_container_->get_flow() != NULL; -} - -// static -SyncSetupWizard::State SyncSetupWizard::GetEndStateForDiscreteRun( - State start_state) { - State result = start_state == GAIA_LOGIN ? GAIA_SUCCESS : DONE; - DCHECK_NE(DONE, result) << - "Invalid start state for discrete run: " << start_state; - return result; -} - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/views/sync/sync_setup_wizard.h b/chrome/browser/views/sync/sync_setup_wizard.h deleted file mode 100644 index 1d36f61..0000000 --- a/chrome/browser/views/sync/sync_setup_wizard.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifndef CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_WIZARD_H_ -#define CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_WIZARD_H_ - -#include "base/basictypes.h" - -#if defined(OS_WIN) -class SyncSetupFlowContainer; -#elif defined(OS_LINUX) -typedef struct _GtkWidget GtkWidget; -typedef struct _GtkWindow GtkWindow; -#endif - -class ProfileSyncService; - -class SyncSetupWizard { - public: - enum State { - // Show the Google Account login UI. - GAIA_LOGIN = 0, - // A login attempt succeeded. Depending on initial conditions, this may - // cause a transition to DONE, or to wait for an explicit transition (via - // Step) to the next state. - GAIA_SUCCESS, - // The user needs to accept a merge and sync warning to proceed. - MERGE_AND_SYNC, - // The panic switch. Something went terribly wrong during setup and we - // can't recover. - FATAL_ERROR, - // A final state for when setup completes and it is possible it is the - // user's first time (globally speaking) as the cloud doesn't have any - // bookmarks. We show additional info in this case to explain setting up - // more computers. - DONE_FIRST_TIME, - // A catch-all done case for any setup process. - DONE - }; - - explicit SyncSetupWizard(ProfileSyncService* service); - ~SyncSetupWizard(); - - // Advances the wizard to the specified state if possible, or opens a - // new dialog starting at |advance_state|. If the wizard has never ran - // through to completion, it will always attempt to do so. Otherwise, e.g - // for a transient auth failure, it will just run as far as is necessary - // based on |advance_state| (so for auth failure, up to GAIA_SUCCESS). - void Step(State advance_state); - - // Whether or not a dialog is currently showing. Useful to determine - // if various buttons in the UI should be enabled or disabled. - bool IsVisible() const; - -#if defined(OS_LINUX) - void SetVisible(bool visible) { visible_ = visible; } -#endif - - private: - // If we just need to pop open an individual dialog, say to collect - // gaia credentials in the event of a steady-state auth failure, this is - // a "discrete" run (as in not a continuous wizard flow). This returns - // the end state to pass to Run for a given |start_state|. - static State GetEndStateForDiscreteRun(State start_state); - - // Helper to return whether |state| warrants starting a new flow. - static bool IsTerminalState(State state); - - ProfileSyncService* service_; - -#if defined(OS_WIN) - SyncSetupFlowContainer* flow_container_; -#elif defined(OS_LINUX) - bool visible_; -#endif - - DISALLOW_COPY_AND_ASSIGN(SyncSetupWizard); -}; - -#endif // CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_WIZARD_H_ diff --git a/chrome/browser/views/sync/sync_setup_wizard_unittest.cc b/chrome/browser/views/sync/sync_setup_wizard_unittest.cc deleted file mode 100644 index fec7ef3..0000000 --- a/chrome/browser/views/sync/sync_setup_wizard_unittest.cc +++ /dev/null @@ -1,376 +0,0 @@ -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef CHROME_PERSONALIZATION - -#include "testing/gtest/include/gtest/gtest.h" - -#include "base/json_writer.h" -#include "base/scoped_ptr.h" -#include "base/stl_util-inl.h" -#include "chrome/browser/browser.h" -#include "chrome/browser/browser_list.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/browser/views/sync/sync_setup_flow.h" -#include "chrome/browser/views/sync/sync_setup_wizard.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/pref_service.h" -#include "chrome/test/browser_with_test_window_test.h" -#include "chrome/test/testing_profile.h" -#include "chrome/test/test_browser_window.h" - -static const char* kTestUser = "chrome.p13n.test@gmail.com"; -static const char* kTestPassword = "passwd"; - -// A PSS subtype to inject. -class ProfileSyncServiceForWizardTest : public ProfileSyncService { - public: - explicit ProfileSyncServiceForWizardTest(Profile* profile) - : ProfileSyncService(profile), user_accepted_merge_and_sync_(false), - user_cancelled_dialog_(false) { - RegisterPreferences(); - } - - virtual ~ProfileSyncServiceForWizardTest() { } - - virtual void OnUserSubmittedAuth(const std::string& username, - const std::string& password) { - username_ = username; - password_ = password; - } - virtual void OnUserAcceptedMergeAndSync() { - user_accepted_merge_and_sync_ = true; - } - virtual void OnUserCancelledDialog() { - user_cancelled_dialog_ = true; - } - - virtual string16 GetAuthenticatedUsername() const { - return UTF8ToUTF16(username_); - } - - void set_auth_state(const std::string& last_email, AuthErrorState state) { - last_attempted_user_email_ = last_email; - last_auth_error_ = state; - } - - void ResetTestStats() { - username_.clear(); - password_.clear(); - user_accepted_merge_and_sync_ = false; - user_cancelled_dialog_ = false; - } - - std::string username_; - std::string password_; - bool user_accepted_merge_and_sync_; - bool user_cancelled_dialog_; - - private: - DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceForWizardTest); -}; - -class TestingProfileWithSyncService : public TestingProfile { - public: - TestingProfileWithSyncService() { - sync_service_.reset(new ProfileSyncServiceForWizardTest(this)); - } - - virtual ProfileSyncService* GetProfileSyncService() { - return sync_service_.get(); - } - private: - scoped_ptr sync_service_; -}; - -class TestBrowserWindowForWizardTest : public TestBrowserWindow { - public: - explicit TestBrowserWindowForWizardTest(Browser* browser) - : TestBrowserWindow(browser), flow_(NULL), - was_show_html_dialog_called_(false) { - } - - virtual ~TestBrowserWindowForWizardTest() { - if (flow_.get()) { - // In real life, the handlers are destroyed by the DOMUI infrastructure, - // which calls GetDOMMessageHandlers to take ownership. This does not - // exist in our test, so we perform cleanup manually. - std::vector handlers; - flow_->GetDOMMessageHandlers(&handlers); - // The handler contract is that they are valid for the lifetime of the - // HTMLDialogUIDelegate, but are cleaned up after the dialog is closed - // and/or deleted. - flow_.reset(); - STLDeleteElements(&handlers); - } - } - - // We intercept this call to hijack the flow created and then use it to - // drive the wizard as if we were the HTML page. - virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, - gfx::NativeWindow parent_window) { - flow_.reset(static_cast(delegate)); - was_show_html_dialog_called_ = true; - } - - bool TestAndResetWasShowHTMLDialogCalled() { - bool ret = was_show_html_dialog_called_; - was_show_html_dialog_called_ = false; - return ret; - } - - // Simulates the user (or browser view hierarchy) closing the html dialog. - // Handles cleaning up the delegate and associated handlers. - void CloseDialog() { - if (flow_.get()) { - std::vector handlers; - flow_->GetDOMMessageHandlers(&handlers); - // The flow deletes itself here. Don't use reset(). - flow_.release()->OnDialogClosed(""); - STLDeleteElements(&handlers); - } - } - - SyncSetupFlow* flow() { return flow_.get(); } - - private: - // In real life, this is owned by the view that is opened by the browser. We - // mock all that out, so we need to take ownership so the flow doesn't leak. - scoped_ptr flow_; - - bool was_show_html_dialog_called_; -}; - -class SyncSetupWizardTest : public BrowserWithTestWindowTest { - public: - SyncSetupWizardTest() : test_window_(NULL), wizard_(NULL) { } - virtual ~SyncSetupWizardTest() { } - virtual void SetUp() { - set_profile(new TestingProfileWithSyncService()); - profile()->CreateBookmarkModel(false); - // Wait for the bookmarks model to load. - profile()->BlockUntilBookmarkModelLoaded(); - set_browser(new Browser(Browser::TYPE_NORMAL, profile())); - test_window_ = new TestBrowserWindowForWizardTest(browser()); - set_window(test_window_); - browser()->set_window(window()); - BrowserList::SetLastActive(browser()); - service_ = static_cast( - profile()->GetProfileSyncService()); - wizard_.reset(new SyncSetupWizard(service_)); - } - - virtual void TearDown() { - test_window_ = NULL; - service_ = NULL; - wizard_.reset(); - } - - TestBrowserWindowForWizardTest* test_window_; - scoped_ptr wizard_; - ProfileSyncServiceForWizardTest* service_; -}; - -TEST_F(SyncSetupWizardTest, InitialStepLogin) { - DictionaryValue dialog_args; - SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); - std::string json_start_args; - JSONWriter::Write(&dialog_args, false, &json_start_args); - ListValue credentials; - std::string auth = "{\"user\":\""; - auth += std::string(kTestUser) + "\",\"pass\":\""; - auth += std::string(kTestPassword) + "\"}"; - credentials.Append(new StringValue(auth)); - - EXPECT_FALSE(wizard_->IsVisible()); - EXPECT_FALSE(test_window_->flow()); - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); - EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->end_state_); - EXPECT_EQ(json_start_args, test_window_->flow()->dialog_start_args_); - - // Simulate the user submitting credentials. - test_window_->flow()->flow_handler_->HandleSubmitAuth(&credentials); - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); - EXPECT_EQ(kTestUser, service_->username_); - EXPECT_EQ(kTestPassword, service_->password_); - EXPECT_FALSE(service_->user_accepted_merge_and_sync_); - EXPECT_FALSE(service_->user_cancelled_dialog_); - service_->ResetTestStats(); - - // Simulate failed credentials. - service_->set_auth_state(kTestUser, AUTH_ERROR_INVALID_GAIA_CREDENTIALS); - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); - dialog_args.Clear(); - SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); - EXPECT_TRUE(2 == dialog_args.GetSize()); - std::string actual_user; - dialog_args.GetString(L"user", &actual_user); - EXPECT_EQ(kTestUser, actual_user); - int error = -1; - dialog_args.GetInteger(L"error", &error); - EXPECT_EQ(static_cast(AUTH_ERROR_INVALID_GAIA_CREDENTIALS), error); - service_->set_auth_state(kTestUser, AUTH_ERROR_NONE); - - // Simulate success. - wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - EXPECT_EQ(SyncSetupWizard::GAIA_SUCCESS, - test_window_->flow()->current_state_); - - wizard_->Step(SyncSetupWizard::DONE); // No merge and sync. - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->current_state_); -} - -TEST_F(SyncSetupWizardTest, InitialStepMergeAndSync) { - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->end_state_); - - wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); - wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, - test_window_->flow()->current_state_); - - test_window_->flow()->flow_handler_->HandleSubmitMergeAndSync(NULL); - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, - test_window_->flow()->current_state_); - EXPECT_EQ(std::string(), service_->username_); - EXPECT_EQ(std::string(), service_->password_); - EXPECT_TRUE(service_->user_accepted_merge_and_sync_); - EXPECT_FALSE(service_->user_cancelled_dialog_); - service_->ResetTestStats(); - wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); // No merge and sync. - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - EXPECT_EQ(SyncSetupWizard::DONE_FIRST_TIME, - test_window_->flow()->current_state_); -} - -TEST_F(SyncSetupWizardTest, DialogCancelled) { - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - // Simulate the user closing the dialog. - test_window_->CloseDialog(); - EXPECT_FALSE(wizard_->IsVisible()); - EXPECT_TRUE(service_->user_cancelled_dialog_); - EXPECT_EQ(std::string(), service_->username_); - EXPECT_EQ(std::string(), service_->password_); - EXPECT_FALSE(service_->user_accepted_merge_and_sync_); - - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - EXPECT_TRUE(wizard_->IsVisible()); - EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - - wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); - test_window_->CloseDialog(); - EXPECT_FALSE(wizard_->IsVisible()); - EXPECT_TRUE(service_->user_cancelled_dialog_); - EXPECT_EQ(std::string(), service_->username_); - EXPECT_EQ(std::string(), service_->password_); - EXPECT_FALSE(service_->user_accepted_merge_and_sync_); -} - -TEST_F(SyncSetupWizardTest, InvalidTransitions) { - wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); - EXPECT_FALSE(wizard_->IsVisible()); - EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - - wizard_->Step(SyncSetupWizard::DONE); - EXPECT_FALSE(wizard_->IsVisible()); - EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - - wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); - EXPECT_FALSE(wizard_->IsVisible()); - EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); - EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); - - wizard_->Step(SyncSetupWizard::DONE); - EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); - wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); - EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); - - wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); - wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); - EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, - test_window_->flow()->current_state_); - - wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); - EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, - test_window_->flow()->current_state_); - - wizard_->Step(SyncSetupWizard::FATAL_ERROR); - EXPECT_EQ(SyncSetupWizard::FATAL_ERROR, test_window_->flow()->current_state_); -} - -TEST_F(SyncSetupWizardTest, FullSuccessfulRunSetsPref) { - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); - wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); - wizard_->Step(SyncSetupWizard::DONE); - test_window_->CloseDialog(); - EXPECT_FALSE(wizard_->IsVisible()); - EXPECT_TRUE(service_->profile()->GetPrefs()->GetBoolean( - prefs::kSyncHasSetupCompleted)); -} - -TEST_F(SyncSetupWizardTest, FirstFullSuccessfulRunSetsPref) { - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); - wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); - wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); - test_window_->CloseDialog(); - EXPECT_FALSE(wizard_->IsVisible()); - EXPECT_TRUE(service_->profile()->GetPrefs()->GetBoolean( - prefs::kSyncHasSetupCompleted)); -} - -TEST_F(SyncSetupWizardTest, DiscreteRun) { - DictionaryValue dialog_args; - // For a discrete run, we need to have ran through setup once. - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); - wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); - wizard_->Step(SyncSetupWizard::DONE); - test_window_->CloseDialog(); - EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); - - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - EXPECT_EQ(SyncSetupWizard::GAIA_SUCCESS, test_window_->flow()->end_state_); - - service_->set_auth_state(kTestUser, AUTH_ERROR_INVALID_GAIA_CREDENTIALS); - wizard_->Step(SyncSetupWizard::GAIA_LOGIN); - EXPECT_TRUE(wizard_->IsVisible()); - SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); - EXPECT_TRUE(2 == dialog_args.GetSize()); - std::string actual_user; - dialog_args.GetString(L"user", &actual_user); - EXPECT_EQ(kTestUser, actual_user); - int error = -1; - dialog_args.GetInteger(L"error", &error); - EXPECT_EQ(static_cast(AUTH_ERROR_INVALID_GAIA_CREDENTIALS), error); - service_->set_auth_state(kTestUser, AUTH_ERROR_NONE); - - wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); - EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); -} - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 1222730..8c47be4 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -155,7 +155,7 @@ }], # branding ], # conditions }], # OS=="mac" - ['OS=="win"', { + ['OS=="win" or OS=="mac"', { # Whether or not browser sync code is built in. 'chrome_personalization%': 1, }, { @@ -205,7 +205,7 @@ ['OS=="linux" and toolkit_views==1', {'sources/': [ ['include', '_views\\.cc$'], ]}], - ['OS=="win" and chrome_personalization==1', { + ['(OS=="win" or OS=="mac") and chrome_personalization==1', { 'defines': ['CHROME_PERSONALIZATION=1'], }], # chrome_personalization==1 ], @@ -2045,6 +2045,10 @@ 'browser/sync/glue/sync_backend_host.h', 'browser/sync/profile_sync_service.cc', 'browser/sync/profile_sync_service.h', + 'browser/sync/sync_setup_flow.cc', + 'browser/sync/sync_setup_flow.h', + 'browser/sync/sync_setup_wizard.cc', + 'browser/sync/sync_setup_wizard.h', 'browser/sync/sync_status_ui_helper.cc', 'browser/sync/sync_status_ui_helper.h', 'browser/tab_contents/constrained_window.h', @@ -2294,10 +2298,6 @@ 'browser/views/star_toggle.h', 'browser/views/status_bubble_views.cc', 'browser/views/status_bubble_views.h', - 'browser/views/sync/sync_setup_flow.cc', - 'browser/views/sync/sync_setup_flow.h', - 'browser/views/sync/sync_setup_wizard.cc', - 'browser/views/sync/sync_setup_wizard.h', 'browser/views/tab_icon_view.cc', 'browser/views/tab_icon_view.h', 'browser/views/tab_contents/tab_contents_container.cc', @@ -3922,6 +3922,7 @@ 'test/perf/mem_usage_mac.cc', 'test/perf/mem_usage_win.cc', 'test/perf/mem_usage.h', + 'test/test_browser_window.h', 'test/testing_profile.cc', 'test/testing_profile.h', 'test/ui_test_utils.cc', @@ -4552,6 +4553,7 @@ 'browser/sync/glue/bookmark_model_worker_unittest.cc', 'browser/sync/glue/http_bridge_unittest.cc', 'browser/sync/profile_sync_service_unittest.cc', + 'browser/sync/sync_setup_wizard_unittest.cc', 'browser/tab_contents/navigation_controller_unittest.cc', 'browser/tab_contents/navigation_entry_unittest.cc', 'browser/tab_contents/render_view_host_manager_unittest.cc', @@ -4563,7 +4565,6 @@ 'browser/utility_process_host_unittest.cc', 'browser/views/bookmark_context_menu_test.cc', 'browser/views/bookmark_editor_view_unittest.cc', - 'browser/views/sync/sync_setup_wizard_unittest.cc', 'browser/visitedlink_unittest.cc', 'browser/webdata/web_database_unittest.cc', 'browser/window_sizer_unittest.cc', @@ -4634,6 +4635,8 @@ 'browser/renderer_host/gtk_key_bindings_handler_unittest.cc', ], 'sources!': [ + # TODO(akalin): Figure out why this unittest fails on linux. + 'browser/browser_commands_unittest.cc', 'browser/views/bookmark_context_menu_test.cc', 'browser/gtk/options/cookies_view_unittest.cc', # Compact Language Detection (cld) is not supported in linux yet. @@ -4756,8 +4759,6 @@ 'browser/bookmarks/bookmark_drag_data_unittest.cc', 'browser/bookmarks/bookmark_folder_tree_model_unittest.cc', 'browser/bookmarks/bookmark_table_model_unittest.cc', - # Need to port browser_with_test_window_test.* first - 'browser/browser_commands_unittest.cc', 'browser/browser_unittest.cc', 'browser/extensions/extension_process_manager_unittest.cc', 'browser/importer/importer_unittest.cc', @@ -4769,11 +4770,8 @@ 'browser/views/bookmark_editor_view_unittest.cc', 'browser/views/find_bar_host_unittest.cc', 'browser/views/keyword_editor_view_unittest.cc', - 'browser/views/sync/sync_setup_wizard_unittest.cc', 'common/chrome_plugin_unittest.cc', 'common/net/url_util_unittest.cc', - 'test/browser_with_test_window_test.cc', - 'test/browser_with_test_window_test.h', ], }], ['chrome_personalization==1', { @@ -6711,6 +6709,10 @@ '-lsecur32.lib', ], }, + }, { # else: OS != "win" + 'sources!': [ + 'browser/sync/util/data_encryption_unittest.cc', + ], }], ['OS=="linux"', { 'defines': [ diff --git a/chrome/test/browser_with_test_window_test.cc b/chrome/test/browser_with_test_window_test.cc index 3e3fb93..8dede7c 100644 --- a/chrome/test/browser_with_test_window_test.cc +++ b/chrome/test/browser_with_test_window_test.cc @@ -12,7 +12,9 @@ BrowserWithTestWindowTest::BrowserWithTestWindowTest() : rph_factory_(), rvh_factory_(&rph_factory_) { +#if defined(OS_WIN) OleInitialize(NULL); +#endif } void BrowserWithTestWindowTest::SetUp() { @@ -38,7 +40,9 @@ BrowserWithTestWindowTest::~BrowserWithTestWindowTest() { MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask); MessageLoop::current()->Run(); +#if defined(OS_WIN) OleUninitialize(); +#endif } TestRenderViewHost* BrowserWithTestWindowTest::TestRenderViewHostForTab( diff --git a/chrome/test/sync/engine/mock_server_connection.cc b/chrome/test/sync/engine/mock_server_connection.cc index 372d408..b2af891 100644 --- a/chrome/test/sync/engine/mock_server_connection.cc +++ b/chrome/test/sync/engine/mock_server_connection.cc @@ -43,9 +43,9 @@ MockConnectionManager::MockConnectionManager(DirectoryManager* dirmgr, directory_name_(name), mid_commit_callback_function_(NULL), mid_commit_observer_(NULL), - client_command_(NULL), throttling_(false), fail_non_periodic_get_updates_(false), + client_command_(NULL), next_position_in_parent_(2) { server_reachable_ = true; }; @@ -405,4 +405,5 @@ void MockConnectionManager::ThrottleNextRequest( throttling_ = true; if (visitor) visitor->VisitAtomically(); -} \ No newline at end of file +} + diff --git a/chrome/test/sync/engine/test_directory_setter_upper.cc b/chrome/test/sync/engine/test_directory_setter_upper.cc index 2685795..9e910f0 100644 --- a/chrome/test/sync/engine/test_directory_setter_upper.cc +++ b/chrome/test/sync/engine/test_directory_setter_upper.cc @@ -85,12 +85,6 @@ void ManuallyOpenedTestDirectorySetterUpper::TearDown() { TestDirectorySetterUpper::TearDown(); } } - -static PathString UTF8ToPathStringQuick(const std::string &str) { - PathString ret; - CHECK(browser_sync::UTF8ToPathString(str.data(), str.size(), &ret)); - return ret; -} TriggeredOpenTestDirectorySetterUpper::TriggeredOpenTestDirectorySetterUpper( const std::string& name) diff --git a/chrome/test/test_browser_window.h b/chrome/test/test_browser_window.h index 8aa657d..d785415 100644 --- a/chrome/test/test_browser_window.h +++ b/chrome/test/test_browser_window.h @@ -7,18 +7,14 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_window.h" -#include "chrome/browser/views/tabs/tab_strip.h" #include "chrome/test/test_location_bar.h" // An implementation of BrowserWindow used for testing. TestBrowserWindow only -// contains a valid TabStrip, all other getters return NULL. +// contains a valid LocationBar, all other getters return NULL. // See BrowserWithTestWindowTest for an example of using this class. class TestBrowserWindow : public BrowserWindow { public: - explicit TestBrowserWindow(Browser* browser) - : tab_strip_(browser->tabstrip_model()) { - tab_strip_.InitTabStripButtons(); - } + explicit TestBrowserWindow(Browser* browser) {} virtual ~TestBrowserWindow() {} virtual void Init() {} @@ -91,8 +87,6 @@ class TestBrowserWindow : public BrowserWindow { virtual void DestroyBrowser() {} private: - TabStrip tab_strip_; - TestLocationBar location_bar_; DISALLOW_COPY_AND_ASSIGN(TestBrowserWindow); diff --git a/third_party/libjingle/files/talk/base/autodetectproxy.cc b/third_party/libjingle/files/talk/base/autodetectproxy.cc index aa2feed..917c548 100644 --- a/third_party/libjingle/files/talk/base/autodetectproxy.cc +++ b/third_party/libjingle/files/talk/base/autodetectproxy.cc @@ -26,7 +26,7 @@ */ #include "talk/base/autodetectproxy.h" -#include "talk/base/httpcommon.h" +#include "talk/base/httpcommon-inl.h" #include "talk/xmpp/xmppclientsettings.h" #include "talk/base/proxydetect.h" diff --git a/views/window/window.cc b/views/window/window.cc index 9f69172..18b4d51 100644 --- a/views/window/window.cc +++ b/views/window/window.cc @@ -5,7 +5,7 @@ #include "views/window/window.h" #include "app/gfx/font.h" -#include "app/l10n_util.h" +#include "app/gfx/font_util.h" #include "app/resource_bundle.h" #include "base/gfx/size.h" #include "base/string_util.h" @@ -14,44 +14,17 @@ namespace views { // static -int Window::GetLocalizedContentsWidthForFont(int col_resource_id, - const gfx::Font& font) { - double chars = 0; - StringToDouble(WideToUTF8(l10n_util::GetString(col_resource_id)), &chars); - int width = font.GetExpectedTextWidth(static_cast(chars)); - DCHECK(width > 0); - return width; -} - -// static int Window::GetLocalizedContentsWidth(int col_resource_id) { - return GetLocalizedContentsWidthForFont(col_resource_id, + return gfx::GetLocalizedContentsWidthForFont(col_resource_id, ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont)); } // static -int Window::GetLocalizedContentsHeightForFont(int row_resource_id, - const gfx::Font& font) { - double lines = 0; - StringToDouble(WideToUTF8(l10n_util::GetString(row_resource_id)), &lines); - int height = static_cast(font.height() * lines); - DCHECK(height > 0); - return height; -} - -// static int Window::GetLocalizedContentsHeight(int row_resource_id) { - return GetLocalizedContentsHeightForFont(row_resource_id, + return gfx::GetLocalizedContentsHeightForFont(row_resource_id, ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont)); } -gfx::Size Window::GetLocalizedContentsSizeForFont(int col_resource_id, - int row_resource_id, - const gfx::Font& font) { - return gfx::Size(GetLocalizedContentsWidthForFont(col_resource_id, font), - GetLocalizedContentsHeightForFont(row_resource_id, font)); -} - // static gfx::Size Window::GetLocalizedContentsSize(int col_resource_id, int row_resource_id) { diff --git a/views/window/window.h b/views/window/window.h index f2f9e34..becb8d0 100644 --- a/views/window/window.h +++ b/views/window/window.h @@ -43,16 +43,6 @@ class Window { static gfx::Size GetLocalizedContentsSize(int col_resource_id, int row_resource_id); - // These versions of GetLocalizedContents allow a font to be specified - // other than the default UI font. - static int GetLocalizedContentsWidthForFont(int col_resource_id, - const gfx::Font& font); - static int GetLocalizedContentsHeightForFont(int row_resource_id, - const gfx::Font& font); - static gfx::Size GetLocalizedContentsSizeForFont(int col_resource_id, - int row_resource_id, - const gfx::Font& font); - // Closes all windows that aren't identified as "app windows" via // IsAppWindow. Called during application shutdown when the last "app window" // is closed. -- cgit v1.1