// Copyright (c) 2011 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 <stdio.h>

#include "base/message_loop.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_service.h"
#include "net/base/mock_host_resolver.h"
#include "ui/base/events.h"
#include "ui/base/keycodes/keyboard_codes.h"

#if defined(OS_LINUX)
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#endif

#if defined(TOOLKIT_VIEWS)
#include "views/controls/textfield/native_textfield_views.h"
#include "views/events/event.h"
#endif

using base::Time;
using base::TimeDelta;

namespace {

const char kSearchKeyword[] = "foo";
const wchar_t kSearchKeywordKeys[] = {
  ui::VKEY_F, ui::VKEY_O, ui::VKEY_O, 0
};
const char kSearchURL[] = "http://www.foo.com/search?q={searchTerms}";
const char kSearchShortName[] = "foo";
const char kSearchText[] = "abc";
const wchar_t kSearchTextKeys[] = {
  ui::VKEY_A, ui::VKEY_B, ui::VKEY_C, 0
};
const char kSearchTextURL[] = "http://www.foo.com/search?q=abc";
const char kSearchSingleChar[] = "z";
const wchar_t kSearchSingleCharKeys[] = { ui::VKEY_Z, 0 };
const char kSearchSingleCharURL[] = "http://www.foo.com/search?q=z";

const char kHistoryPageURL[] = "chrome://history/#q=abc";

const char kDesiredTLDHostname[] = "www.bar.com";
const wchar_t kDesiredTLDKeys[] = {
  ui::VKEY_B, ui::VKEY_A, ui::VKEY_R, 0
};

const char kInlineAutocompleteText[] = "def";
const wchar_t kInlineAutocompleteTextKeys[] = {
  ui::VKEY_D, ui::VKEY_E, ui::VKEY_F, 0
};

// Hostnames that shall be blocked by host resolver.
const char *kBlockedHostnames[] = {
  "foo",
  "*.foo.com",
  "bar",
  "*.bar.com",
  "abc",
  "*.abc.com",
  "def",
  "*.def.com",
  "history",
  "z"
};

const struct TestHistoryEntry {
  const char* url;
  const char* title;
  const char* body;
  int visit_count;
  int typed_count;
  bool starred;
} kHistoryEntries[] = {
  {"http://www.bar.com/1", "Page 1", kSearchText, 10, 10, false },
  {"http://www.bar.com/2", "Page 2", kSearchText, 9, 9, false },
  {"http://www.bar.com/3", "Page 3", kSearchText, 8, 8, false },
  {"http://www.bar.com/4", "Page 4", kSearchText, 7, 7, false },
  {"http://www.bar.com/5", "Page 5", kSearchText, 6, 6, false },
  {"http://www.bar.com/6", "Page 6", kSearchText, 5, 5, false },
  {"http://www.bar.com/7", "Page 7", kSearchText, 4, 4, false },
  {"http://www.bar.com/8", "Page 8", kSearchText, 3, 3, false },
  {"http://www.bar.com/9", "Page 9", kSearchText, 2, 2, false },

  // To trigger inline autocomplete.
  {"http://www.def.com", "Page def", kSearchText, 10000, 10000, true },
};

#if defined(OS_LINUX)
// Returns the text stored in the PRIMARY clipboard.
std::string GetPrimarySelectionText() {
  GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
  DCHECK(clipboard);

  gchar* selection_text = gtk_clipboard_wait_for_text(clipboard);
  std::string result(selection_text ? selection_text : "");
  g_free(selection_text);
  return result;
}

// Stores the given text to clipboard.
void SetClipboardText(const char* text) {
  GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
  DCHECK(clipboard);

  gtk_clipboard_set_text(clipboard, text, -1);
}
#endif

#if defined(OS_MACOSX)
const int kCtrlOrCmdMask = ui::EF_COMMAND_DOWN;
#else
const int kCtrlOrCmdMask = ui::EF_CONTROL_DOWN;
#endif

}  // namespace

class AutocompleteEditViewTest : public InProcessBrowserTest,
                                 public NotificationObserver {
 protected:
  AutocompleteEditViewTest() {
    set_show_window(true);
  }

  virtual void SetUpOnMainThread() {
    ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    ASSERT_NO_FATAL_FAILURE(SetupComponents());
    browser()->FocusLocationBar();
#if defined(TOOLKIT_VIEWS)
    if (views::NativeTextfieldViews::IsTextfieldViewsEnabled())
      return;
#endif
    ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(),
                                             VIEW_ID_LOCATION_BAR));
  }

  static void GetAutocompleteEditViewForBrowser(
      const Browser* browser,
      AutocompleteEditView** edit_view) {
    BrowserWindow* window = browser->window();
    ASSERT_TRUE(window);
    LocationBar* loc_bar = window->GetLocationBar();
    ASSERT_TRUE(loc_bar);
    *edit_view = loc_bar->location_entry();
    ASSERT_TRUE(*edit_view);
  }

  void GetAutocompleteEditView(AutocompleteEditView** edit_view) {
    GetAutocompleteEditViewForBrowser(browser(), edit_view);
  }

  static void SendKeyForBrowser(const Browser* browser,
                                ui::KeyboardCode key,
                                int modifiers) {
    ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
        browser, key,
        (modifiers & ui::EF_CONTROL_DOWN) != 0,
        (modifiers & ui::EF_SHIFT_DOWN) != 0,
        (modifiers & ui::EF_ALT_DOWN) != 0,
        (modifiers & ui::EF_COMMAND_DOWN) != 0));
  }

  void SendKey(ui::KeyboardCode key, int modifiers) {
    SendKeyForBrowser(browser(), key, modifiers);
  }

  void SendKeySequence(const wchar_t* keys) {
    for (; *keys; ++keys)
      ASSERT_NO_FATAL_FAILURE(SendKey(static_cast<ui::KeyboardCode>(*keys), 0));
  }

  bool SendKeyAndWait(const Browser* browser,
                      ui::KeyboardCode key,
                      int modifiers,
                      NotificationType type,
                      const NotificationSource& source) WARN_UNUSED_RESULT {
    return ui_test_utils::SendKeyPressAndWait(
        browser, key,
        (modifiers & ui::EF_CONTROL_DOWN) != 0,
        (modifiers & ui::EF_SHIFT_DOWN) != 0,
        (modifiers & ui::EF_ALT_DOWN) != 0,
        (modifiers & ui::EF_COMMAND_DOWN) != 0,
        type, source);
  }

  void WaitForTabOpenOrCloseForBrowser(const Browser* browser,
                                       int expected_tab_count) {
    int tab_count = browser->tab_count();
    if (tab_count == expected_tab_count)
      return;

    NotificationRegistrar registrar;
    registrar.Add(this,
                  (tab_count < expected_tab_count ?
                   NotificationType::TAB_PARENTED :
                   NotificationType::TAB_CLOSED),
                   NotificationService::AllSources());

    while (!HasFailure() && browser->tab_count() != expected_tab_count)
      ui_test_utils::RunMessageLoop();

    ASSERT_EQ(expected_tab_count, browser->tab_count());
  }

  void WaitForTabOpenOrClose(int expected_tab_count) {
    WaitForTabOpenOrCloseForBrowser(browser(), expected_tab_count);
  }

  void WaitForAutocompleteControllerDone() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    AutocompleteController* controller =
        edit_view->model()->popup_model()->autocomplete_controller();
    ASSERT_TRUE(controller);

    if (controller->done())
      return;

    NotificationRegistrar registrar;
    registrar.Add(this,
                  NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_READY,
                  Source<AutocompleteController>(controller));

    while (!HasFailure() && !controller->done())
      ui_test_utils::RunMessageLoop();

    ASSERT_TRUE(controller->done());
  }

  void SetupSearchEngine() {
    TemplateURLModel* model = browser()->profile()->GetTemplateURLModel();
    ASSERT_TRUE(model);

    if (!model->loaded()) {
      NotificationRegistrar registrar;
      registrar.Add(this, NotificationType::TEMPLATE_URL_MODEL_LOADED,
                    Source<TemplateURLModel>(model));
      model->Load();
      ui_test_utils::RunMessageLoop();
    }

    ASSERT_TRUE(model->loaded());
    // Remove built-in template urls, like google.com, bing.com etc., as they
    // may appear as autocomplete suggests and interfere with our tests.
    model->SetDefaultSearchProvider(NULL);
    TemplateURLModel::TemplateURLVector builtins = model->GetTemplateURLs();
    for (TemplateURLModel::TemplateURLVector::const_iterator
         i = builtins.begin(); i != builtins.end(); ++i)
      model->Remove(*i);

    TemplateURL* template_url = new TemplateURL();
    template_url->SetURL(kSearchURL, 0, 0);
    template_url->set_keyword(UTF8ToUTF16(kSearchKeyword));
    template_url->set_short_name(UTF8ToUTF16(kSearchShortName));

    model->Add(template_url);
    model->SetDefaultSearchProvider(template_url);
  }

  void AddHistoryEntry(const TestHistoryEntry& entry, const Time& time) {
    Profile* profile = browser()->profile();
    HistoryService* history_service =
        profile->GetHistoryService(Profile::EXPLICIT_ACCESS);
    ASSERT_TRUE(history_service);

    if (!history_service->BackendLoaded()) {
      NotificationRegistrar registrar;
      registrar.Add(this, NotificationType::HISTORY_LOADED,
                    Source<Profile>(profile));
      ui_test_utils::RunMessageLoop();
    }

    BookmarkModel* bookmark_model = profile->GetBookmarkModel();
    ASSERT_TRUE(bookmark_model);

    if (!bookmark_model->IsLoaded()) {
      NotificationRegistrar registrar;
      registrar.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
                    Source<Profile>(profile));
      ui_test_utils::RunMessageLoop();
    }

    GURL url(entry.url);
    // Add everything in order of time. We don't want to have a time that
    // is "right now" or it will nondeterministically appear in the results.
    history_service->AddPageWithDetails(url, UTF8ToUTF16(entry.title),
                                        entry.visit_count,
                                        entry.typed_count, time, false,
                                        history::SOURCE_BROWSED);
    history_service->SetPageContents(url, UTF8ToUTF16(entry.body));
    if (entry.starred)
      bookmark_model->SetURLStarred(url, string16(), true);
  }

  void SetupHistory() {
    // Add enough history pages containing |kSearchText| to trigger
    // open history page url in autocomplete result.
    for (size_t i = 0; i < arraysize(kHistoryEntries); i++) {
      // Add everything in order of time. We don't want to have a time that
      // is "right now" or it will nondeterministically appear in the results.
      Time t = Time::Now() - TimeDelta::FromHours(i + 1);
      ASSERT_NO_FATAL_FAILURE(AddHistoryEntry(kHistoryEntries[i], t));
    }
  }

  void SetupHostResolver() {
    for (size_t i = 0; i < arraysize(kBlockedHostnames); ++i)
      host_resolver()->AddSimulatedFailure(kBlockedHostnames[i]);
  }

  void SetupComponents() {
    ASSERT_NO_FATAL_FAILURE(SetupHostResolver());
    ASSERT_NO_FATAL_FAILURE(SetupSearchEngine());
    ASSERT_NO_FATAL_FAILURE(SetupHistory());
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    switch (type.value) {
      case NotificationType::TAB_PARENTED:
      case NotificationType::TAB_CLOSED:
      case NotificationType::TEMPLATE_URL_MODEL_LOADED:
      case NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_READY:
      case NotificationType::HISTORY_LOADED:
      case NotificationType::BOOKMARK_MODEL_LOADED:
        break;
      default:
        FAIL() << "Unexpected notification type";
    }
    MessageLoopForUI::current()->Quit();
  }

  void BrowserAcceleratorsTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    int tab_count = browser()->tab_count();

    // Create a new Tab.
    browser()->NewTab();
    ASSERT_NO_FATAL_FAILURE(WaitForTabOpenOrClose(tab_count + 1));

    // Select the first Tab.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_1, kCtrlOrCmdMask));
    ASSERT_EQ(0, browser()->active_index());

    browser()->FocusLocationBar();

    // Select the second Tab.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_2, kCtrlOrCmdMask));
    ASSERT_EQ(1, browser()->active_index());

    browser()->FocusLocationBar();

    // Try ctrl-w to close a Tab.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_W, kCtrlOrCmdMask));
    ASSERT_NO_FATAL_FAILURE(WaitForTabOpenOrClose(tab_count));

    // Try ctrl-l to focus location bar.
    edit_view->SetUserText(ASCIIToUTF16("Hello world"));
    EXPECT_FALSE(edit_view->IsSelectAll());
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_L, kCtrlOrCmdMask));
    EXPECT_TRUE(edit_view->IsSelectAll());

    // Try editing the location bar text.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_RIGHT, 0));
    EXPECT_FALSE(edit_view->IsSelectAll());
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_S, 0));
    EXPECT_EQ(ASCIIToUTF16("Hello worlds"), edit_view->GetText());

    // Try ctrl-x to cut text.
#if defined(OS_MACOSX)
    // Mac uses alt-left/right to select a word.
    ASSERT_NO_FATAL_FAILURE(
        SendKey(ui::VKEY_LEFT, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN));
#else
    ASSERT_NO_FATAL_FAILURE(
        SendKey(ui::VKEY_LEFT, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN));
#endif
    EXPECT_FALSE(edit_view->IsSelectAll());
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_X, kCtrlOrCmdMask));
    EXPECT_EQ(ASCIIToUTF16("Hello "), edit_view->GetText());

#if !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
    // Try alt-f4 to close the browser.
    ASSERT_TRUE(SendKeyAndWait(
        browser(), ui::VKEY_F4, ui::EF_ALT_DOWN,
        NotificationType::BROWSER_CLOSED, Source<Browser>(browser())));
#endif
  }

  void PopupAcceleratorsTest() {
    // Create a popup.
    Browser* popup = CreateBrowserForPopup(browser()->profile());
    ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(popup));
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(
        GetAutocompleteEditViewForBrowser(popup, &edit_view));
    popup->FocusLocationBar();
    EXPECT_TRUE(edit_view->IsSelectAll());

#if !defined(OS_MACOSX)
    // Try ctrl-w to close the popup.
    // This piece of code doesn't work on Mac, because the Browser object won't
    // be destroyed before finishing the current message loop iteration, thus
    // No BROWSER_CLOSED notification will be sent.
    ASSERT_TRUE(SendKeyAndWait(
        popup, ui::VKEY_W, ui::EF_CONTROL_DOWN,
        NotificationType::BROWSER_CLOSED, Source<Browser>(popup)));

    // Create another popup.
    popup = CreateBrowserForPopup(browser()->profile());
    ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(popup));
    ASSERT_NO_FATAL_FAILURE(
        GetAutocompleteEditViewForBrowser(popup, &edit_view));
#endif

    // Set the edit text to "Hello world".
    edit_view->SetUserText(ASCIIToUTF16("Hello world"));
    popup->FocusLocationBar();
    EXPECT_TRUE(edit_view->IsSelectAll());

    // Try editing the location bar text -- should be disallowed.
    ASSERT_NO_FATAL_FAILURE(SendKeyForBrowser(popup, ui::VKEY_S, 0));
    EXPECT_EQ(ASCIIToUTF16("Hello world"), edit_view->GetText());
    EXPECT_TRUE(edit_view->IsSelectAll());

    ASSERT_NO_FATAL_FAILURE(
        SendKeyForBrowser(popup, ui::VKEY_X, kCtrlOrCmdMask));
    EXPECT_EQ(ASCIIToUTF16("Hello world"), edit_view->GetText());
    EXPECT_TRUE(edit_view->IsSelectAll());

#if !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
    // Try alt-f4 to close the popup.
    ASSERT_TRUE(SendKeyAndWait(
        popup, ui::VKEY_F4, ui::EF_ALT_DOWN,
        NotificationType::BROWSER_CLOSED, Source<Browser>(popup)));
#endif
  }

  void BackspaceInKeywordModeTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    // Trigger keyword hint mode.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchKeywordKeys));
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(kSearchKeyword, UTF16ToUTF8(edit_view->model()->keyword()));

    // Trigger keyword mode.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(kSearchKeyword, UTF16ToUTF8(edit_view->model()->keyword()));

    // Backspace without search text should bring back keyword hint mode.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(kSearchKeyword, UTF16ToUTF8(edit_view->model()->keyword()));

    // Trigger keyword mode again.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(kSearchKeyword, UTF16ToUTF8(edit_view->model()->keyword()));

    // Input something as search text.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchTextKeys));

    // Should stay in keyword mode while deleting search text by pressing
    // backspace.
    for (size_t i = 0; i < arraysize(kSearchText) - 1; ++i) {
      ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
      ASSERT_FALSE(edit_view->model()->is_keyword_hint());
      ASSERT_EQ(kSearchKeyword, UTF16ToUTF8(edit_view->model()->keyword()));
    }

    // Input something as search text.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchTextKeys));

    // Move cursor to the beginning of the search text.
#if defined(OS_MACOSX)
    // Home doesn't work on Mac trybot.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_A, ui::EF_CONTROL_DOWN));
#else
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_HOME, 0));
#endif
    // Backspace at the beginning of the search text shall turn off
    // the keyword mode.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(string16(), edit_view->model()->keyword());
    ASSERT_EQ(std::string(kSearchKeyword) + kSearchText,
              UTF16ToUTF8(edit_view->GetText()));
  }

  void EscapeTest() {
    ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIHistoryURL));
    browser()->FocusLocationBar();

    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    string16 old_text = edit_view->GetText();
    EXPECT_FALSE(old_text.empty());
    EXPECT_TRUE(edit_view->IsSelectAll());

    // Delete all text in omnibox.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
    EXPECT_TRUE(edit_view->GetText().empty());

    // Escape shall revert the text in omnibox.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_ESCAPE, 0));
    EXPECT_EQ(old_text, edit_view->GetText());
    EXPECT_TRUE(edit_view->IsSelectAll());
  }

  void DesiredTLDTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));
    AutocompletePopupModel* popup_model = edit_view->model()->popup_model();
    ASSERT_TRUE(popup_model);

    // Test ctrl-Enter.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kDesiredTLDKeys));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(popup_model->IsOpen());
    // ctrl-Enter triggers desired_tld feature, thus www.bar.com shall be
    // opened.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_RETURN, ui::EF_CONTROL_DOWN));

    GURL url = browser()->GetSelectedTabContents()->GetURL();
    EXPECT_STREQ(kDesiredTLDHostname, url.host().c_str());
  }

  void AltEnterTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    edit_view->SetUserText(ASCIIToUTF16(chrome::kChromeUIHistoryURL));
    int tab_count = browser()->tab_count();
    // alt-Enter opens a new tab.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_RETURN, ui::EF_ALT_DOWN));
    ASSERT_NO_FATAL_FAILURE(WaitForTabOpenOrClose(tab_count + 1));
  }

  void EnterToSearchTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));
    AutocompletePopupModel* popup_model = edit_view->model()->popup_model();
    ASSERT_TRUE(popup_model);

    // Test Enter to search.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchTextKeys));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(popup_model->IsOpen());

    // Check if the default match result is Search Primary Provider.
    ASSERT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED,
              popup_model->result().default_match()->type);

    // Open the default match.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_RETURN, 0));
    GURL url = browser()->GetSelectedTabContents()->GetURL();
    EXPECT_STREQ(kSearchTextURL, url.spec().c_str());

    // Test that entering a single character then Enter performs a search.
    browser()->FocusLocationBar();
    EXPECT_TRUE(edit_view->IsSelectAll());
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchSingleCharKeys));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(popup_model->IsOpen());
    EXPECT_EQ(kSearchSingleChar, UTF16ToUTF8(edit_view->GetText()));

    // Check if the default match result is Search Primary Provider.
    ASSERT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED,
              popup_model->result().default_match()->type);

    // Open the default match.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_RETURN, 0));
    url = browser()->GetSelectedTabContents()->GetURL();
    EXPECT_STREQ(kSearchSingleCharURL, url.spec().c_str());
  }

  void EscapeToDefaultMatchTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));
    AutocompletePopupModel* popup_model = edit_view->model()->popup_model();
    ASSERT_TRUE(popup_model);

    // Input something to trigger inline autocomplete.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kInlineAutocompleteTextKeys));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(popup_model->IsOpen());

    string16 old_text = edit_view->GetText();

    // Make sure inline autocomplete is triggerred.
    EXPECT_GT(old_text.length(), arraysize(kInlineAutocompleteText) - 1);

    size_t old_selected_line = popup_model->selected_line();
    EXPECT_EQ(0U, old_selected_line);

    // Move to another line with different text.
    size_t size = popup_model->result().size();
    while (popup_model->selected_line() < size - 1) {
      ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_DOWN, 0));
      ASSERT_NE(old_selected_line, popup_model->selected_line());
      if (old_text != edit_view->GetText())
        break;
    }

    EXPECT_NE(old_text, edit_view->GetText());

    // Escape shall revert back to the default match item.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_ESCAPE, 0));
    EXPECT_EQ(old_text, edit_view->GetText());
    EXPECT_EQ(old_selected_line, popup_model->selected_line());
  }

  void BasicTextOperationsTest() {
    ui_test_utils::NavigateToURL(browser(), GURL(chrome::kAboutBlankURL));
    browser()->FocusLocationBar();

    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    string16 old_text = edit_view->GetText();
    EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL), old_text);
    EXPECT_TRUE(edit_view->IsSelectAll());

    string16::size_type start, end;
    edit_view->GetSelectionBounds(&start, &end);
    EXPECT_EQ(0U, start);
    EXPECT_EQ(old_text.size(), end);

    // Move the cursor to the end.
#if defined(OS_MACOSX)
    // End doesn't work on Mac trybot.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_E, ui::EF_CONTROL_DOWN));
#else
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_END, 0));
#endif
    EXPECT_FALSE(edit_view->IsSelectAll());

    // Make sure the cursor is placed correctly.
    edit_view->GetSelectionBounds(&start, &end);
    EXPECT_EQ(old_text.size(), start);
    EXPECT_EQ(old_text.size(), end);

    // Insert one character at the end. Make sure we won't insert
    // anything after the special ZWS mark used in gtk implementation.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_A, 0));
    EXPECT_EQ(old_text + char16('a'), edit_view->GetText());

    // Delete one character from the end. Make sure we won't delete the special
    // ZWS mark used in gtk implementation.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
    EXPECT_EQ(old_text, edit_view->GetText());

    edit_view->SelectAll(true);
    EXPECT_TRUE(edit_view->IsSelectAll());
    edit_view->GetSelectionBounds(&start, &end);
    EXPECT_EQ(0U, start);
    EXPECT_EQ(old_text.size(), end);

    // Delete the content
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_DELETE, 0));
    EXPECT_TRUE(edit_view->IsSelectAll());
    edit_view->GetSelectionBounds(&start, &end);
    EXPECT_EQ(0U, start);
    EXPECT_EQ(0U, end);
    EXPECT_TRUE(edit_view->GetText().empty());

    // Check if RevertAll() can set text and cursor correctly.
    edit_view->RevertAll();
    EXPECT_FALSE(edit_view->IsSelectAll());
    EXPECT_EQ(old_text, edit_view->GetText());
    edit_view->GetSelectionBounds(&start, &end);
    EXPECT_EQ(old_text.size(), start);
    EXPECT_EQ(old_text.size(), end);
  }

  void AcceptKeywordBySpaceTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    string16 text = UTF8ToUTF16(kSearchKeyword);

    // Trigger keyword hint mode.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchKeywordKeys));
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(text, edit_view->GetText());

    // Trigger keyword mode by space.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_SPACE, 0));
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_TRUE(edit_view->GetText().empty());

    // Revert to keyword hint mode.
    edit_view->model()->ClearKeyword(string16());
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(text, edit_view->GetText());

    // Keyword should also be accepted by typing an ideographic space.
    edit_view->OnBeforePossibleChange();
    edit_view->SetWindowTextAndCaretPos(text + WideToUTF16(L"\x3000"),
                                        text.length() + 1);
    edit_view->OnAfterPossibleChange();
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_TRUE(edit_view->GetText().empty());

    // Revert to keyword hint mode.
    edit_view->model()->ClearKeyword(string16());
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(text, edit_view->GetText());

    // Keyword shouldn't be accepted by pasting.
    // Simulate pasting a whitespace to the end of content.
    edit_view->OnBeforePossibleChange();
    edit_view->model()->on_paste();
    edit_view->SetWindowTextAndCaretPos(text + char16(' '), text.length() + 1);
    edit_view->OnAfterPossibleChange();
    // Should be still in keyword hint mode.
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(text + char16(' '), edit_view->GetText());

    // Keyword shouldn't be accepted by pressing space with a trailing
    // whitespace.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_SPACE, 0));
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(text + ASCIIToUTF16("  "), edit_view->GetText());

    // Keyword shouldn't be accepted by deleting the trailing space.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(text + char16(' '), edit_view->GetText());

    // Keyword shouldn't be accepted by pressing space before a trailing space.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_LEFT, 0));
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_SPACE, 0));
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(text + ASCIIToUTF16("  "), edit_view->GetText());

    // Keyword should be accepted by pressing space in the middle of context and
    // just after the keyword.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_A, 0));
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_LEFT, 0));
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_SPACE, 0));
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(ASCIIToUTF16("a "), edit_view->GetText());

    // Keyword shouldn't be accepted by pasting "foo bar".
    edit_view->SetUserText(string16());
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_TRUE(edit_view->model()->keyword().empty());

    edit_view->OnBeforePossibleChange();
    edit_view->model()->on_paste();
    edit_view->SetWindowTextAndCaretPos(text + ASCIIToUTF16(" bar"),
                                        text.length() + 4);
    edit_view->OnAfterPossibleChange();
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_TRUE(edit_view->model()->keyword().empty());
    ASSERT_EQ(text + ASCIIToUTF16(" bar"), edit_view->GetText());

    // Keyword shouldn't be accepted for case like: "foo b|ar" -> "foo b |ar".
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_LEFT, 0));
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_LEFT, 0));
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_SPACE, 0));
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_TRUE(edit_view->model()->keyword().empty());
    ASSERT_EQ(text + ASCIIToUTF16(" b ar"), edit_view->GetText());

    // Keyword could be accepted by pressing space with a selected range at the
    // end of text.
    edit_view->OnBeforePossibleChange();
    edit_view->OnInlineAutocompleteTextMaybeChanged(
        text + ASCIIToUTF16("  "), text.length());
    edit_view->OnAfterPossibleChange();
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(text + ASCIIToUTF16("  "), edit_view->GetText());

    string16::size_type start, end;
    edit_view->GetSelectionBounds(&start, &end);
    ASSERT_NE(start, end);
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_SPACE, 0));
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_EQ(string16(), edit_view->GetText());

    edit_view->SetUserText(string16());

    // Space should accept keyword even when inline autocomplete is available.
    const TestHistoryEntry kHistoryFoobar = {
      "http://www.foobar.com", "Page foobar", kSearchText, 10000, 10000, true
    };

    // Add a history entry to trigger inline autocomplete when typing "foo".
    ASSERT_NO_FATAL_FAILURE(
        AddHistoryEntry(kHistoryFoobar, Time::Now() - TimeDelta::FromHours(1)));

    // Type "foo" to trigger inline autocomplete.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchKeywordKeys));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(edit_view->model()->popup_model()->IsOpen());
    ASSERT_NE(text, edit_view->GetText());

    // Keyword hint shouldn't be visible.
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_TRUE(edit_view->model()->keyword().empty());

    // Trigger keyword mode by space.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_SPACE, 0));
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(text, edit_view->model()->keyword());
    ASSERT_TRUE(edit_view->GetText().empty());
  }

  void NonSubstitutingKeywordTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));
    AutocompletePopupModel* popup_model = edit_view->model()->popup_model();
    ASSERT_TRUE(popup_model);

    TemplateURLModel* template_url_model =
        browser()->profile()->GetTemplateURLModel();

    // Add a non-default substituting keyword.
    TemplateURL* template_url = new TemplateURL();
    template_url->SetURL("http://abc.com/{searchTerms}", 0, 0);
    template_url->set_keyword(UTF8ToUTF16(kSearchText));
    template_url->set_short_name(UTF8ToUTF16("Search abc"));
    template_url_model->Add(template_url);

    edit_view->SetUserText(string16());

    // Non-default substituting keyword shouldn't be matched by default.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchTextKeys));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(popup_model->IsOpen());

    // Check if the default match result is Search Primary Provider.
    ASSERT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED,
              popup_model->result().default_match()->type);
    ASSERT_EQ(kSearchTextURL,
              popup_model->result().default_match()->destination_url.spec());

    edit_view->SetUserText(string16());
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_FALSE(popup_model->IsOpen());

    // Try a non-substituting keyword.
    template_url_model->Remove(template_url);
    template_url = new TemplateURL();
    template_url->SetURL("http://abc.com/", 0, 0);
    template_url->set_keyword(UTF8ToUTF16(kSearchText));
    template_url->set_short_name(UTF8ToUTF16("abc"));
    template_url_model->Add(template_url);

    // We always allow exact matches for non-substituting keywords.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchTextKeys));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(popup_model->IsOpen());
    ASSERT_EQ(AutocompleteMatch::HISTORY_KEYWORD,
              popup_model->result().default_match()->type);
    ASSERT_EQ("http://abc.com/",
              popup_model->result().default_match()->destination_url.spec());
  }

  void DeleteItemTest() {
    // Disable the search provider, to make sure the popup contains only history
    // items.
    TemplateURLModel* model = browser()->profile()->GetTemplateURLModel();
    model->SetDefaultSearchProvider(NULL);

    ui_test_utils::NavigateToURL(browser(), GURL(chrome::kAboutBlankURL));
    browser()->FocusLocationBar();

    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    AutocompletePopupModel* popup_model = edit_view->model()->popup_model();
    ASSERT_TRUE(popup_model);

    string16 old_text = edit_view->GetText();

    // Input something that can match history items.
    edit_view->SetUserText(ASCIIToUTF16("bar"));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(popup_model->IsOpen());

    // Delete the inline autocomplete part.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_DELETE, 0));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(popup_model->IsOpen());
    ASSERT_GE(popup_model->result().size(), 3U);

    string16 user_text = edit_view->GetText();
    ASSERT_EQ(ASCIIToUTF16("bar"), user_text);
    edit_view->SelectAll(true);
    ASSERT_TRUE(edit_view->IsSelectAll());

    // The first item should be the default match.
    size_t default_line = popup_model->selected_line();
    std::string default_url =
        popup_model->result().match_at(default_line).destination_url.spec();

    // Move down.
    edit_view->model()->OnUpOrDownKeyPressed(1);
    ASSERT_EQ(default_line + 1, popup_model->selected_line());
    string16 selected_text =
        popup_model->result().match_at(default_line + 1).fill_into_edit;
    // Temporary text is shown.
    ASSERT_EQ(selected_text, edit_view->GetText());
    ASSERT_FALSE(edit_view->IsSelectAll());

    // Delete the item.
    popup_model->TryDeletingCurrentItem();
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    // The selected line shouldn't be changed, because we have more than two
    // items.
    ASSERT_EQ(default_line + 1, popup_model->selected_line());
    // Make sure the item is really deleted.
    ASSERT_NE(selected_text,
              popup_model->result().match_at(default_line + 1).fill_into_edit);
    selected_text =
        popup_model->result().match_at(default_line + 1).fill_into_edit;
    // New temporary text is shown.
    ASSERT_EQ(selected_text, edit_view->GetText());

    // Revert to the default match.
    ASSERT_TRUE(edit_view->model()->OnEscapeKeyPressed());
    ASSERT_EQ(default_line, popup_model->selected_line());
    ASSERT_EQ(user_text, edit_view->GetText());
    ASSERT_TRUE(edit_view->IsSelectAll());

    // Move down and up to select the default match as temporary text.
    edit_view->model()->OnUpOrDownKeyPressed(1);
    ASSERT_EQ(default_line + 1, popup_model->selected_line());
    edit_view->model()->OnUpOrDownKeyPressed(-1);
    ASSERT_EQ(default_line, popup_model->selected_line());

    selected_text = popup_model->result().match_at(default_line).fill_into_edit;
    // New temporary text is shown.
    ASSERT_EQ(selected_text, edit_view->GetText());
    ASSERT_FALSE(edit_view->IsSelectAll());

    // Delete the default item.
    popup_model->TryDeletingCurrentItem();
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    // The selected line shouldn't be changed, but the default item should have
    // been changed.
    ASSERT_EQ(default_line, popup_model->selected_line());
    // Make sure the item is really deleted.
    ASSERT_NE(selected_text,
              popup_model->result().match_at(default_line).fill_into_edit);
    selected_text =
        popup_model->result().match_at(default_line).fill_into_edit;
    // New temporary text is shown.
    ASSERT_EQ(selected_text, edit_view->GetText());

    // As the current selected item is the new default item, pressing Escape key
    // should revert all directly.
    ASSERT_TRUE(edit_view->model()->OnEscapeKeyPressed());
    ASSERT_EQ(old_text, edit_view->GetText());
    ASSERT_TRUE(edit_view->IsSelectAll());
  }

  void TabMoveCursorToEndTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    edit_view->SetUserText(ASCIIToUTF16("Hello world"));

    // Move cursor to the beginning.
#if defined(OS_MACOSX)
    // Home doesn't work on Mac trybot.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_A, ui::EF_CONTROL_DOWN));
#else
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_HOME, 0));
#endif

    string16::size_type start, end;
    edit_view->GetSelectionBounds(&start, &end);
    EXPECT_EQ(0U, start);
    EXPECT_EQ(0U, end);

    // Pressing tab should move cursor to the end.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));

    edit_view->GetSelectionBounds(&start, &end);
    EXPECT_EQ(edit_view->GetText().size(), start);
    EXPECT_EQ(edit_view->GetText().size(), end);

    // The location bar should still have focus.
    ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));

    // Select all text.
    edit_view->SelectAll(true);
    EXPECT_TRUE(edit_view->IsSelectAll());
    edit_view->GetSelectionBounds(&start, &end);
    EXPECT_EQ(0U, start);
    EXPECT_EQ(edit_view->GetText().size(), end);

    // Pressing tab should move cursor to the end.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));

    edit_view->GetSelectionBounds(&start, &end);
    EXPECT_EQ(edit_view->GetText().size(), start);
    EXPECT_EQ(edit_view->GetText().size(), end);

    // The location bar should still have focus.
    ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));

    // Pressing tab when cursor is at the end should change focus.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));

    ASSERT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));
  }

  void PersistKeywordModeOnTabSwitch() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

    // Trigger keyword hint mode.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchKeywordKeys));
    ASSERT_TRUE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(kSearchKeyword, UTF16ToUTF8(edit_view->model()->keyword()));

    // Trigger keyword mode.
    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));
    ASSERT_FALSE(edit_view->model()->is_keyword_hint());
    ASSERT_EQ(kSearchKeyword, UTF16ToUTF8(edit_view->model()->keyword()));

    // Input something as search text.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchTextKeys));

    // Create a new tab.
    browser()->NewTab();

    // Switch back to the first tab.
    browser()->ActivateTabAt(0, true);

    // Make sure we're still in keyword mode.
    ASSERT_EQ(kSearchKeyword, UTF16ToUTF8(edit_view->model()->keyword()));
  }

  void CtrlKeyPressedWithInlineAutocompleteTest() {
    AutocompleteEditView* edit_view = NULL;
    ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));
    AutocompletePopupModel* popup_model = edit_view->model()->popup_model();
    ASSERT_TRUE(popup_model);

    // Input something to trigger inline autocomplete.
    ASSERT_NO_FATAL_FAILURE(SendKeySequence(kInlineAutocompleteTextKeys));
    ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
    ASSERT_TRUE(popup_model->IsOpen());

    string16 old_text = edit_view->GetText();

    // Make sure inline autocomplete is triggerred.
    EXPECT_GT(old_text.length(), arraysize(kInlineAutocompleteText) - 1);

    // Press ctrl key.
    edit_view->model()->OnControlKeyChanged(true);

    // Inline autocomplete should still be there.
    EXPECT_EQ(old_text, edit_view->GetText());
  }

};

// Test if ctrl-* accelerators are workable in omnibox.
// See http://crbug.com/19193: omnibox blocks ctrl-* commands
//
// Flaky on interactive tests (dbg), http://crbug.com/69433
IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, FLAKY_BrowserAccelerators) {
  BrowserAcceleratorsTest();
}

// Flakily fails and times out on Win only.  http://crbug.com/69941
#if defined(OS_WIN)
#define MAYBE_PopupAccelerators DISABLED_PopupAccelerators
#else
#define MAYBE_PopupAccelerators PopupAccelerators
#endif

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, MAYBE_PopupAccelerators) {
  PopupAcceleratorsTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, BackspaceInKeywordMode) {
  BackspaceInKeywordModeTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, Escape) {
  EscapeTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, DesiredTLD) {
  DesiredTLDTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, AltEnter) {
  AltEnterTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, EnterToSearch) {
  EnterToSearchTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, EscapeToDefaultMatch) {
  EscapeToDefaultMatchTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, BasicTextOperations) {
  BasicTextOperationsTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, AcceptKeywordBySpace) {
  AcceptKeywordBySpaceTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, NonSubstitutingKeywordTest) {
  NonSubstitutingKeywordTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, DeleteItem) {
  DeleteItemTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, TabMoveCursorToEnd) {
  TabMoveCursorToEndTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest,
                       PersistKeywordModeOnTabSwitch) {
  PersistKeywordModeOnTabSwitch();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest,
                       CtrlKeyPressedWithInlineAutocompleteTest) {
  CtrlKeyPressedWithInlineAutocompleteTest();
}

#if defined(OS_LINUX)
// TODO(oshima): enable these tests for views-implmentation when
// these featuers are supported.

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, UndoRedoLinux) {
  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kAboutBlankURL));
  browser()->FocusLocationBar();

  AutocompleteEditView* edit_view = NULL;
  ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));

  string16 old_text = edit_view->GetText();
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL), old_text);
  EXPECT_TRUE(edit_view->IsSelectAll());

  // Undo should clear the omnibox.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
  EXPECT_TRUE(edit_view->GetText().empty());

  // Nothing should happen if undo again.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
  EXPECT_TRUE(edit_view->GetText().empty());

  // Redo should restore the original text.
  ASSERT_NO_FATAL_FAILURE(
      SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN));
  EXPECT_EQ(old_text, edit_view->GetText());

  // Looks like the undo manager doesn't support restoring selection.
  EXPECT_FALSE(edit_view->IsSelectAll());

  // The cursor should be at the end.
  string16::size_type start, end;
  edit_view->GetSelectionBounds(&start, &end);
  EXPECT_EQ(old_text.size(), start);
  EXPECT_EQ(old_text.size(), end);

  // Delete two characters.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
  EXPECT_EQ(old_text.substr(0, old_text.size() - 2), edit_view->GetText());

  // Undo delete.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
  EXPECT_EQ(old_text, edit_view->GetText());

  // Redo delete.
  ASSERT_NO_FATAL_FAILURE(
      SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN));
  EXPECT_EQ(old_text.substr(0, old_text.size() - 2), edit_view->GetText());

  // Delete everything.
  edit_view->SelectAll(true);
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
  EXPECT_TRUE(edit_view->GetText().empty());

  // Undo delete everything.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
  EXPECT_EQ(old_text.substr(0, old_text.size() - 2), edit_view->GetText());

  // Undo delete two characters.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
  EXPECT_EQ(old_text, edit_view->GetText());

  // Undo again.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
  EXPECT_TRUE(edit_view->GetText().empty());
}

// See http://crbug.com/63860
IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, PrimarySelection) {
  AutocompleteEditView* edit_view = NULL;
  ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));
  edit_view->SetUserText(ASCIIToUTF16("Hello world"));
  EXPECT_FALSE(edit_view->IsSelectAll());

  // Move the cursor to the end.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_END, 0));

  // Select all text by pressing Shift+Home
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_HOME, ui::EF_SHIFT_DOWN));
  EXPECT_TRUE(edit_view->IsSelectAll());

  // The selected content should be saved to the PRIMARY clipboard.
  EXPECT_EQ("Hello world", GetPrimarySelectionText());

  // Move the cursor to the end.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_END, 0));
  EXPECT_FALSE(edit_view->IsSelectAll());

  // The content in the PRIMARY clipboard should not be cleared.
  EXPECT_EQ("Hello world", GetPrimarySelectionText());
}

// See http://crosbug.com/10306
IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest,
                       BackspaceDeleteHalfWidthKatakana) {
  AutocompleteEditView* edit_view = NULL;
  ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));
  // Insert text: ダ
  edit_view->SetUserText(UTF8ToUTF16("\357\276\200\357\276\236"));

  // Move the cursor to the end.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_END, 0));

  // Backspace should delete one character.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
  EXPECT_EQ(UTF8ToUTF16("\357\276\200"), edit_view->GetText());
}

// http://crbug.com/12316
IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, PasteReplacingAll) {
  AutocompleteEditView* edit_view = NULL;
  ASSERT_NO_FATAL_FAILURE(GetAutocompleteEditView(&edit_view));
  AutocompletePopupModel* popup_model = edit_view->model()->popup_model();
  ASSERT_TRUE(popup_model);

  SetClipboardText(kSearchText);

  // Paste text.
  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_V, ui::EF_CONTROL_DOWN));
  ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
  ASSERT_TRUE(popup_model->IsOpen());

  // Inline autocomplete shouldn't be triggered.
  ASSERT_EQ(ASCIIToUTF16("abc"), edit_view->GetText());
}
#endif

#if defined(TOOLKIT_VIEWS)
class AutocompleteEditViewViewsTest : public AutocompleteEditViewTest {
 public:
  AutocompleteEditViewViewsTest() {
    views::NativeTextfieldViews::SetEnableTextfieldViews(true);
  }
};

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest,
                       FLAKY_BrowserAccelerators) {
  BrowserAcceleratorsTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, MAYBE_PopupAccelerators) {
  PopupAcceleratorsTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, BackspaceInKeywordMode) {
  BackspaceInKeywordModeTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, Escape) {
  EscapeTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, DesiredTLD) {
  DesiredTLDTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, AltEnter) {
  AltEnterTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, EnterToSearch) {
  EnterToSearchTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, EscapeToDefaultMatch) {
  EscapeToDefaultMatchTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, BasicTextOperations) {
  BasicTextOperationsTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, AcceptKeywordBySpace) {
  AcceptKeywordBySpaceTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest,
                       NonSubstitutingKeywordTest) {
  NonSubstitutingKeywordTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest, DeleteItem) {
  DeleteItemTest();
}

// TODO(suzhe): This test is broken because of broken ViewID support when
// enabling AutocompleteEditViewViews.
IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest,
                       DISABLED_TabMoveCursorToEnd) {
  TabMoveCursorToEndTest();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest,
                       PersistKeywordModeOnTabSwitch) {
  PersistKeywordModeOnTabSwitch();
}

IN_PROC_BROWSER_TEST_F(AutocompleteEditViewViewsTest,
                       CtrlKeyPressedWithInlineAutocompleteTest) {
  CtrlKeyPressedWithInlineAutocompleteTest();
}

#endif