Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / tab_contents / spelling_menu_observer_browsertest.cc
blobc523a435be86c27a178c82b2eea28bb862818f84
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/tab_contents/spelling_menu_observer.h"
7 #include <vector>
9 #include "base/command_line.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/app/chrome_command_ids.h"
13 #include "chrome/browser/spellchecker/spelling_service_client.h"
14 #include "chrome/browser/tab_contents/render_view_context_menu.h"
15 #include "chrome/browser/tab_contents/render_view_context_menu_observer.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "chrome/test/base/testing_profile.h"
21 using content::RenderViewHost;
22 using content::WebContents;
24 namespace {
26 // A mock context menu used in this test. This class overrides virtual methods
27 // derived from the RenderViewContextMenuProxy class to monitor calls from the
28 // SpellingMenuObserver class.
29 class MockRenderViewContextMenu : public RenderViewContextMenuProxy {
30 public:
31 // A menu item used in this test. This test uses a vector of this struct to
32 // hold menu items added by this test.
33 struct MockMenuItem {
34 MockMenuItem()
35 : command_id(0),
36 enabled(false),
37 checked(false),
38 hidden(true) {
40 int command_id;
41 bool enabled;
42 bool checked;
43 bool hidden;
44 base::string16 title;
47 explicit MockRenderViewContextMenu(bool incognito);
48 virtual ~MockRenderViewContextMenu();
50 // RenderViewContextMenuProxy implementation.
51 virtual void AddMenuItem(int command_id,
52 const base::string16& title) OVERRIDE;
53 virtual void AddCheckItem(int command_id,
54 const base::string16& title) OVERRIDE;
55 virtual void AddSeparator() OVERRIDE;
56 virtual void AddSubMenu(int command_id,
57 const base::string16& label,
58 ui::MenuModel* model) OVERRIDE;
59 virtual void UpdateMenuItem(int command_id,
60 bool enabled,
61 bool hidden,
62 const base::string16& title) OVERRIDE;
63 virtual RenderViewHost* GetRenderViewHost() const OVERRIDE;
64 virtual WebContents* GetWebContents() const OVERRIDE;
65 virtual Profile* GetProfile() const OVERRIDE;
67 // Attaches a RenderViewContextMenuObserver to be tested.
68 void SetObserver(RenderViewContextMenuObserver* observer);
70 // Returns the number of items added by the test.
71 size_t GetMenuSize() const;
73 // Returns the i-th item.
74 bool GetMenuItem(size_t i, MockMenuItem* item) const;
76 // Returns the writable profile used in this test.
77 PrefService* GetPrefs();
79 private:
80 // An observer used for initializing the status of menu items added in this
81 // test. A test should delete this RenderViewContextMenuObserver object.
82 RenderViewContextMenuObserver* observer_;
84 // A dummy profile used in this test. Call GetPrefs() when a test needs to
85 // change this profile and use PrefService methods.
86 scoped_ptr<TestingProfile> profile_;
88 // A list of menu items added by the SpellingMenuObserver class.
89 std::vector<MockMenuItem> items_;
91 DISALLOW_COPY_AND_ASSIGN(MockRenderViewContextMenu);
94 MockRenderViewContextMenu::MockRenderViewContextMenu(bool incognito)
95 : observer_(NULL) {
96 TestingProfile::Builder builder;
97 if (incognito)
98 builder.SetIncognito();
99 profile_ = builder.Build();
102 MockRenderViewContextMenu::~MockRenderViewContextMenu() {
105 void MockRenderViewContextMenu::AddMenuItem(int command_id,
106 const base::string16& title) {
107 MockMenuItem item;
108 item.command_id = command_id;
109 item.enabled = observer_->IsCommandIdEnabled(command_id);
110 item.checked = false;
111 item.hidden = false;
112 item.title = title;
113 items_.push_back(item);
116 void MockRenderViewContextMenu::AddCheckItem(int command_id,
117 const base::string16& title) {
118 MockMenuItem item;
119 item.command_id = command_id;
120 item.enabled = observer_->IsCommandIdEnabled(command_id);
121 item.checked = observer_->IsCommandIdChecked(command_id);
122 item.hidden = false;
123 item.title = title;
124 items_.push_back(item);
127 void MockRenderViewContextMenu::AddSeparator() {
128 MockMenuItem item;
129 item.command_id = -1;
130 item.enabled = false;
131 item.checked = false;
132 item.hidden = false;
133 items_.push_back(item);
136 void MockRenderViewContextMenu::AddSubMenu(int command_id,
137 const base::string16& label,
138 ui::MenuModel* model) {
139 MockMenuItem item;
140 item.command_id = -1;
141 item.enabled = false;
142 item.checked = false;
143 item.hidden = false;
144 items_.push_back(item);
147 void MockRenderViewContextMenu::UpdateMenuItem(int command_id,
148 bool enabled,
149 bool hidden,
150 const base::string16& title) {
151 for (std::vector<MockMenuItem>::iterator it = items_.begin();
152 it != items_.end(); ++it) {
153 if (it->command_id == command_id) {
154 it->enabled = enabled;
155 it->hidden = hidden;
156 it->title = title;
157 return;
161 // The SpellingMenuObserver class tries to change a menu item not added by the
162 // class. This is an unexpected behavior and we should stop now.
163 FAIL();
166 RenderViewHost* MockRenderViewContextMenu::GetRenderViewHost() const {
167 return NULL;
170 WebContents* MockRenderViewContextMenu::GetWebContents() const {
171 return NULL;
174 Profile* MockRenderViewContextMenu::GetProfile() const {
175 return profile_.get();
178 size_t MockRenderViewContextMenu::GetMenuSize() const {
179 return items_.size();
182 bool MockRenderViewContextMenu::GetMenuItem(size_t i,
183 MockMenuItem* item) const {
184 if (i >= items_.size())
185 return false;
186 item->command_id = items_[i].command_id;
187 item->enabled = items_[i].enabled;
188 item->checked = items_[i].checked;
189 item->hidden = items_[i].hidden;
190 item->title = items_[i].title;
191 return true;
194 void MockRenderViewContextMenu::SetObserver(
195 RenderViewContextMenuObserver* observer) {
196 observer_ = observer;
199 PrefService* MockRenderViewContextMenu::GetPrefs() {
200 return profile_->GetPrefs();
203 // A test class used in this file. This test should be a browser test because it
204 // accesses resources.
205 class SpellingMenuObserverTest : public InProcessBrowserTest {
206 public:
207 SpellingMenuObserverTest();
209 virtual void SetUpOnMainThread() OVERRIDE {
210 Reset(false);
213 virtual void CleanUpOnMainThread() OVERRIDE {
214 observer_.reset();
215 menu_.reset();
218 void Reset(bool incognito) {
219 observer_.reset();
220 menu_.reset(new MockRenderViewContextMenu(incognito));
221 observer_.reset(new SpellingMenuObserver(menu_.get()));
222 menu_->SetObserver(observer_.get());
225 void InitMenu(const char* word, const char* suggestion) {
226 content::ContextMenuParams params;
227 params.is_editable = true;
228 params.misspelled_word = base::ASCIIToUTF16(word);
229 params.dictionary_suggestions.clear();
230 if (suggestion)
231 params.dictionary_suggestions.push_back(base::ASCIIToUTF16(suggestion));
232 observer_->InitMenu(params);
235 virtual ~SpellingMenuObserverTest();
236 MockRenderViewContextMenu* menu() { return menu_.get(); }
237 SpellingMenuObserver* observer() { return observer_.get(); }
238 private:
239 scoped_ptr<SpellingMenuObserver> observer_;
240 scoped_ptr<MockRenderViewContextMenu> menu_;
241 DISALLOW_COPY_AND_ASSIGN(SpellingMenuObserverTest);
244 SpellingMenuObserverTest::SpellingMenuObserverTest() {
247 SpellingMenuObserverTest::~SpellingMenuObserverTest() {
250 } // namespace
252 // Tests that right-clicking a correct word does not add any items.
253 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, InitMenuWithCorrectWord) {
254 InitMenu("", NULL);
255 EXPECT_EQ(static_cast<size_t>(0), menu()->GetMenuSize());
258 // Tests that right-clicking a misspelled word adds four items:
259 // "No spelling suggestions", "Add to dictionary", "Ask Google for suggestions",
260 // and a separator.
261 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, InitMenuWithMisspelledWord) {
262 InitMenu("wiimode", NULL);
263 EXPECT_EQ(static_cast<size_t>(4), menu()->GetMenuSize());
265 // Read all the context-menu items added by this test and verify they are
266 // expected ones. We do not check the item titles to prevent resource changes
267 // from breaking this test. (I think it is not expected by those who change
268 // resources.)
269 MockRenderViewContextMenu::MockMenuItem item;
270 menu()->GetMenuItem(0, &item);
271 EXPECT_EQ(IDC_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS, item.command_id);
272 EXPECT_FALSE(item.enabled);
273 EXPECT_FALSE(item.hidden);
274 menu()->GetMenuItem(1, &item);
275 EXPECT_EQ(IDC_SPELLCHECK_ADD_TO_DICTIONARY, item.command_id);
276 EXPECT_TRUE(item.enabled);
277 EXPECT_FALSE(item.hidden);
278 menu()->GetMenuItem(2, &item);
279 EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE, item.command_id);
280 EXPECT_TRUE(item.enabled);
281 EXPECT_FALSE(item.checked);
282 EXPECT_FALSE(item.hidden);
283 menu()->GetMenuItem(3, &item);
284 EXPECT_EQ(-1, item.command_id);
285 EXPECT_FALSE(item.enabled);
286 EXPECT_FALSE(item.hidden);
289 // Tests that right-clicking a correct word when we enable spelling-service
290 // integration to verify an item "Ask Google for suggestions" is checked. Even
291 // though this meanu itself does not add this item, its sub-menu adds the item
292 // and calls SpellingMenuObserver::IsChecked() to check it.
293 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest,
294 EnableSpellingServiceWithCorrectWord) {
295 menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
296 InitMenu("", NULL);
298 EXPECT_TRUE(
299 observer()->IsCommandIdChecked(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE));
302 // Tests that right-clicking a misspelled word when we enable spelling-service
303 // integration to verify an item "Ask Google for suggestions" is checked. (This
304 // test does not actually send JSON-RPC requests to the service because it makes
305 // this test flaky.)
306 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, EnableSpellingService) {
307 menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
308 menu()->GetPrefs()->SetString(prefs::kSpellCheckDictionary, std::string());
310 InitMenu("wiimode", NULL);
311 EXPECT_EQ(static_cast<size_t>(4), menu()->GetMenuSize());
313 // To avoid duplicates, this test reads only the "Ask Google for suggestions"
314 // item and verifies it is enabled and checked.
315 MockRenderViewContextMenu::MockMenuItem item;
316 menu()->GetMenuItem(2, &item);
317 EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE, item.command_id);
318 EXPECT_TRUE(item.enabled);
319 EXPECT_TRUE(item.checked);
320 EXPECT_FALSE(item.hidden);
323 // Test that there will be a separator after "no suggestions" if
324 // SpellingServiceClient::SUGGEST is on.
325 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, SeparatorAfterSuggestions) {
326 menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
327 CommandLine* command_line = CommandLine::ForCurrentProcess();
328 command_line->AppendSwitch(switches::kUseSpellingSuggestions);
330 // Force a non-empty locale so SUGGEST is available.
331 menu()->GetPrefs()->SetString(prefs::kSpellCheckDictionary, "en");
332 EXPECT_TRUE(SpellingServiceClient::IsAvailable(menu()->GetProfile(),
333 SpellingServiceClient::SUGGEST));
335 InitMenu("jhhj", NULL);
337 // The test should see a top separator, "No spelling suggestions",
338 // "No more Google suggestions" (from SpellingService) and a separator
339 // as the first four items, then possibly more (not relevant here).
340 EXPECT_LT(4U, menu()->GetMenuSize());
342 MockRenderViewContextMenu::MockMenuItem item;
343 menu()->GetMenuItem(0, &item);
344 EXPECT_EQ(-1, item.command_id);
345 EXPECT_FALSE(item.enabled);
346 EXPECT_FALSE(item.hidden);
348 menu()->GetMenuItem(1, &item);
349 EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, item.command_id);
350 EXPECT_FALSE(item.enabled);
351 EXPECT_FALSE(item.hidden);
353 menu()->GetMenuItem(2, &item);
354 EXPECT_EQ(IDC_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS, item.command_id);
355 EXPECT_FALSE(item.enabled);
356 EXPECT_FALSE(item.hidden);
358 menu()->GetMenuItem(3, &item);
359 EXPECT_EQ(-1, item.command_id);
360 EXPECT_FALSE(item.enabled);
361 EXPECT_FALSE(item.hidden);
364 // Test that we don't show "No more suggestions from Google" if the spelling
365 // service is enabled and that there is only one suggestion.
366 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest,
367 NoMoreSuggestionsNotDisplayed) {
368 menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
370 // Force a non-empty locale so SPELLCHECK is available.
371 menu()->GetPrefs()->SetString(prefs::kSpellCheckDictionary, "en");
372 EXPECT_TRUE(SpellingServiceClient::IsAvailable(menu()->GetProfile(),
373 SpellingServiceClient::SPELLCHECK));
374 InitMenu("asdfkj", "asdf");
376 // The test should see a separator, a suggestion and another separator
377 // as the first two items, then possibly more (not relevant here).
378 EXPECT_LT(3U, menu()->GetMenuSize());
380 MockRenderViewContextMenu::MockMenuItem item;
381 menu()->GetMenuItem(0, &item);
382 EXPECT_EQ(-1, item.command_id);
383 EXPECT_FALSE(item.enabled);
384 EXPECT_FALSE(item.hidden);
386 menu()->GetMenuItem(1, &item);
387 EXPECT_EQ(IDC_SPELLCHECK_SUGGESTION_0, item.command_id);
388 EXPECT_TRUE(item.enabled);
389 EXPECT_FALSE(item.hidden);
391 menu()->GetMenuItem(2, &item);
392 EXPECT_EQ(-1, item.command_id);
393 EXPECT_FALSE(item.enabled);
394 EXPECT_FALSE(item.hidden);
397 // Test that "Ask Google For Suggestions" is grayed out when using an
398 // off the record profile.
399 // TODO(rlp): Include graying out of autocorrect in this test when autocorrect
400 // is functional.
401 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest,
402 NoSpellingServiceWhenOffTheRecord) {
403 // Create a menu in an incognito profile.
404 Reset(true);
406 // This means spellchecking is allowed. Default is that the service is
407 // contacted but this test makes sure that if profile is incognito, that
408 // is not an option.
409 menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
411 // Force a non-empty locale so SUGGEST normally would be available.
412 menu()->GetPrefs()->SetString(prefs::kSpellCheckDictionary, "en");
413 EXPECT_FALSE(SpellingServiceClient::IsAvailable(menu()->GetProfile(),
414 SpellingServiceClient::SUGGEST));
415 EXPECT_FALSE(SpellingServiceClient::IsAvailable(menu()->GetProfile(),
416 SpellingServiceClient::SPELLCHECK));
418 InitMenu("sjxdjiiiiii", NULL);
420 // The test should see "No spelling suggestions" (from system checker).
421 // They should not see "No more Google suggestions" (from SpellingService) or
422 // a separator. The next 2 items should be "Add to Dictionary" followed
423 // by "Ask Google for suggestions" which should be disabled.
424 // TODO(rlp): add autocorrect here when it is functional.
425 EXPECT_LT(3U, menu()->GetMenuSize());
427 MockRenderViewContextMenu::MockMenuItem item;
428 menu()->GetMenuItem(0, &item);
429 EXPECT_EQ(IDC_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS, item.command_id);
430 EXPECT_FALSE(item.enabled);
431 EXPECT_FALSE(item.hidden);
433 menu()->GetMenuItem(1, &item);
434 EXPECT_EQ(IDC_SPELLCHECK_ADD_TO_DICTIONARY, item.command_id);
435 EXPECT_TRUE(item.enabled);
436 EXPECT_FALSE(item.hidden);
438 menu()->GetMenuItem(2, &item);
439 EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE, item.command_id);
440 EXPECT_FALSE(item.enabled);
441 EXPECT_FALSE(item.hidden);
444 // Test that the menu is preceeded by a separator if there are any suggestions,
445 // or if the SpellingServiceClient is available
446 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, SuggestionsForceTopSeparator) {
447 menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, false);
449 // First case: Misspelled word, no suggestions, no spellcheck service.
450 InitMenu("asdfkj", NULL);
451 // See SpellingMenuObserverTest.InitMenuWithMisspelledWord on why 4 items.
452 EXPECT_EQ(static_cast<size_t>(4), menu()->GetMenuSize());
453 MockRenderViewContextMenu::MockMenuItem item;
454 menu()->GetMenuItem(0, &item);
455 EXPECT_NE(-1, item.command_id);
457 // Case #2. Misspelled word, suggestions, no spellcheck service.
458 Reset(false);
459 menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, false);
460 InitMenu("asdfkj", "asdf");
462 // Expect at least separator and 4 default entries.
463 EXPECT_LT(static_cast<size_t>(5), menu()->GetMenuSize());
464 // This test only cares that the first one is a separator.
465 menu()->GetMenuItem(0, &item);
466 EXPECT_EQ(-1, item.command_id);
468 // Case #3. Misspelled word, suggestion service is on.
469 Reset(false);
470 menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
471 CommandLine* command_line = CommandLine::ForCurrentProcess();
472 command_line->AppendSwitch(switches::kUseSpellingSuggestions);
473 InitMenu("asdfkj", NULL);
475 // Should have at least 2 entries. Separator, suggestion.
476 EXPECT_LT(2U, menu()->GetMenuSize());
477 menu()->GetMenuItem(0, &item);
478 EXPECT_EQ(-1, item.command_id);
479 menu()->GetMenuItem(1, &item);
480 EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, item.command_id);