Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / renderer_context_menu / spelling_menu_observer_browsertest.cc
1 // Copyright 2014 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.
4
5 #include "chrome/browser/renderer_context_menu/spelling_menu_observer.h"
6
7 #include <vector>
8
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
13 #include "chrome/browser/spellchecker/spelling_service_client.h"
14 #include "chrome/common/pref_names.h"
15 #include "chrome/test/base/in_process_browser_test.h"
16 #include "chrome/test/base/testing_profile.h"
17 #include "components/renderer_context_menu/render_view_context_menu_observer.h"
18
19 using content::RenderViewHost;
20 using content::WebContents;
21
22 namespace {
23
24 // A mock context menu used in this test. This class overrides virtual methods
25 // derived from the RenderViewContextMenuProxy class to monitor calls from the
26 // SpellingMenuObserver class.
27 class MockRenderViewContextMenu : public RenderViewContextMenuProxy {
28  public:
29   // A menu item used in this test. This test uses a vector of this struct to
30   // hold menu items added by this test.
31   struct MockMenuItem {
32     MockMenuItem()
33         : command_id(0),
34           enabled(false),
35           checked(false),
36           hidden(true) {
37     }
38     int command_id;
39     bool enabled;
40     bool checked;
41     bool hidden;
42     base::string16 title;
43   };
44
45   explicit MockRenderViewContextMenu(bool incognito);
46   virtual ~MockRenderViewContextMenu();
47
48   // RenderViewContextMenuProxy implementation.
49   virtual void AddMenuItem(int command_id,
50                            const base::string16& title) OVERRIDE;
51   virtual void AddCheckItem(int command_id,
52                             const base::string16& title) OVERRIDE;
53   virtual void AddSeparator() OVERRIDE;
54   virtual void AddSubMenu(int command_id,
55                           const base::string16& label,
56                           ui::MenuModel* model) OVERRIDE;
57   virtual void UpdateMenuItem(int command_id,
58                               bool enabled,
59                               bool hidden,
60                               const base::string16& title) OVERRIDE;
61   virtual RenderViewHost* GetRenderViewHost() const OVERRIDE;
62   virtual WebContents* GetWebContents() const OVERRIDE;
63   virtual content::BrowserContext* GetBrowserContext() const OVERRIDE;
64
65   // Attaches a RenderViewContextMenuObserver to be tested.
66   void SetObserver(RenderViewContextMenuObserver* observer);
67
68   // Returns the number of items added by the test.
69   size_t GetMenuSize() const;
70
71   // Returns the i-th item.
72   bool GetMenuItem(size_t i, MockMenuItem* item) const;
73
74   // Returns the writable profile used in this test.
75   PrefService* GetPrefs();
76
77  private:
78   // An observer used for initializing the status of menu items added in this
79   // test. A test should delete this RenderViewContextMenuObserver object.
80   RenderViewContextMenuObserver* observer_;
81
82   // A dummy profile used in this test. Call GetPrefs() when a test needs to
83   // change this profile and use PrefService methods.
84   scoped_ptr<TestingProfile> original_profile_;
85
86   // Either |original_profile_| or its incognito profile.
87   Profile* profile_;
88
89   // A list of menu items added by the SpellingMenuObserver class.
90   std::vector<MockMenuItem> items_;
91
92   DISALLOW_COPY_AND_ASSIGN(MockRenderViewContextMenu);
93 };
94
95 MockRenderViewContextMenu::MockRenderViewContextMenu(bool incognito)
96     : observer_(NULL) {
97   original_profile_ = TestingProfile::Builder().Build();
98   profile_ = incognito ? original_profile_->GetOffTheRecordProfile()
99                        : original_profile_.get();
100 }
101
102 MockRenderViewContextMenu::~MockRenderViewContextMenu() {
103 }
104
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);
114 }
115
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);
125 }
126
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);
134 }
135
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);
145 }
146
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;
158     }
159   }
160
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();
164 }
165
166 RenderViewHost* MockRenderViewContextMenu::GetRenderViewHost() const {
167   return NULL;
168 }
169
170 WebContents* MockRenderViewContextMenu::GetWebContents() const {
171   return NULL;
172 }
173
174 content::BrowserContext* MockRenderViewContextMenu::GetBrowserContext() const {
175   return profile_;
176 }
177
178 size_t MockRenderViewContextMenu::GetMenuSize() const {
179   return items_.size();
180 }
181
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;
192 }
193
194 void MockRenderViewContextMenu::SetObserver(
195     RenderViewContextMenuObserver* observer) {
196   observer_ = observer;
197 }
198
199 PrefService* MockRenderViewContextMenu::GetPrefs() {
200   return profile_->GetPrefs();
201 }
202
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();
208
209   virtual void SetUpOnMainThread() OVERRIDE {
210     Reset(false);
211   }
212
213   virtual void TearDownOnMainThread() OVERRIDE {
214     observer_.reset();
215     menu_.reset();
216   }
217
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());
223   }
224
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);
233   }
234
235   void ForceSuggestMode() {
236     menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
237     // Force a non-empty and non-"en" locale so SUGGEST is available.
238     menu()->GetPrefs()->SetString(prefs::kSpellCheckDictionary, "fr");
239     ASSERT_TRUE(SpellingServiceClient::IsAvailable(
240         menu()->GetBrowserContext(), SpellingServiceClient::SUGGEST));
241     ASSERT_FALSE(SpellingServiceClient::IsAvailable(
242         menu()->GetBrowserContext(), SpellingServiceClient::SPELLCHECK));
243   }
244
245   virtual ~SpellingMenuObserverTest();
246   MockRenderViewContextMenu* menu() { return menu_.get(); }
247   SpellingMenuObserver* observer() { return observer_.get(); }
248  private:
249   scoped_ptr<SpellingMenuObserver> observer_;
250   scoped_ptr<MockRenderViewContextMenu> menu_;
251   DISALLOW_COPY_AND_ASSIGN(SpellingMenuObserverTest);
252 };
253
254 SpellingMenuObserverTest::SpellingMenuObserverTest() {
255 }
256
257 SpellingMenuObserverTest::~SpellingMenuObserverTest() {
258 }
259
260 }  // namespace
261
262 // Tests that right-clicking a correct word does not add any items.
263 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, InitMenuWithCorrectWord) {
264   InitMenu("", NULL);
265   EXPECT_EQ(static_cast<size_t>(0), menu()->GetMenuSize());
266 }
267
268 // Tests that right-clicking a misspelled word adds four items:
269 // "No spelling suggestions", "Add to dictionary", "Ask Google for suggestions",
270 // and a separator.
271 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, InitMenuWithMisspelledWord) {
272   InitMenu("wiimode", NULL);
273   EXPECT_EQ(static_cast<size_t>(4), menu()->GetMenuSize());
274
275   // Read all the context-menu items added by this test and verify they are
276   // expected ones. We do not check the item titles to prevent resource changes
277   // from breaking this test. (I think it is not expected by those who change
278   // resources.)
279   MockRenderViewContextMenu::MockMenuItem item;
280   menu()->GetMenuItem(0, &item);
281   EXPECT_EQ(IDC_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS, item.command_id);
282   EXPECT_FALSE(item.enabled);
283   EXPECT_FALSE(item.hidden);
284   menu()->GetMenuItem(1, &item);
285   EXPECT_EQ(IDC_SPELLCHECK_ADD_TO_DICTIONARY, item.command_id);
286   EXPECT_TRUE(item.enabled);
287   EXPECT_FALSE(item.hidden);
288   menu()->GetMenuItem(2, &item);
289   EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE, item.command_id);
290   EXPECT_TRUE(item.enabled);
291   EXPECT_FALSE(item.checked);
292   EXPECT_FALSE(item.hidden);
293   menu()->GetMenuItem(3, &item);
294   EXPECT_EQ(-1, item.command_id);
295   EXPECT_FALSE(item.enabled);
296   EXPECT_FALSE(item.hidden);
297 }
298
299 // Tests that right-clicking a correct word when we enable spelling-service
300 // integration to verify an item "Ask Google for suggestions" is checked. Even
301 // though this meanu itself does not add this item, its sub-menu adds the item
302 // and calls SpellingMenuObserver::IsChecked() to check it.
303 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest,
304                        EnableSpellingServiceWithCorrectWord) {
305   menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
306   InitMenu("", NULL);
307
308   EXPECT_TRUE(
309       observer()->IsCommandIdChecked(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE));
310 }
311
312 // Tests that right-clicking a misspelled word when we enable spelling-service
313 // integration to verify an item "Ask Google for suggestions" is checked. (This
314 // test does not actually send JSON-RPC requests to the service because it makes
315 // this test flaky.)
316 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, EnableSpellingService) {
317   menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
318   menu()->GetPrefs()->SetString(prefs::kSpellCheckDictionary, std::string());
319
320   InitMenu("wiimode", NULL);
321   EXPECT_EQ(static_cast<size_t>(4), menu()->GetMenuSize());
322
323   // To avoid duplicates, this test reads only the "Ask Google for suggestions"
324   // item and verifies it is enabled and checked.
325   MockRenderViewContextMenu::MockMenuItem item;
326   menu()->GetMenuItem(2, &item);
327   EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE, item.command_id);
328   EXPECT_TRUE(item.enabled);
329   EXPECT_TRUE(item.checked);
330   EXPECT_FALSE(item.hidden);
331 }
332
333 // Test that there will be a separator after "no suggestions" if
334 // SpellingServiceClient::SUGGEST is on.
335 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, SeparatorAfterSuggestions) {
336   ForceSuggestMode();
337   InitMenu("jhhj", NULL);
338
339   // The test should see a top separator, "No spelling suggestions",
340   // "No more Google suggestions" (from SpellingService) and a separator
341   // as the first four items, then possibly more (not relevant here).
342   EXPECT_LT(4U, menu()->GetMenuSize());
343
344   MockRenderViewContextMenu::MockMenuItem item;
345   menu()->GetMenuItem(0, &item);
346   EXPECT_EQ(-1, item.command_id);
347   EXPECT_FALSE(item.enabled);
348   EXPECT_FALSE(item.hidden);
349
350   menu()->GetMenuItem(1, &item);
351   EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_SUGGESTION, item.command_id);
352   EXPECT_FALSE(item.enabled);
353   EXPECT_FALSE(item.hidden);
354
355   menu()->GetMenuItem(2, &item);
356   EXPECT_EQ(IDC_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS, item.command_id);
357   EXPECT_FALSE(item.enabled);
358   EXPECT_FALSE(item.hidden);
359
360   menu()->GetMenuItem(3, &item);
361   EXPECT_EQ(-1, item.command_id);
362   EXPECT_FALSE(item.enabled);
363   EXPECT_FALSE(item.hidden);
364 }
365
366 // Test that we don't show "No more suggestions from Google" if the spelling
367 // service is enabled and that there is only one suggestion.
368 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest,
369                        NoMoreSuggestionsNotDisplayed) {
370   menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
371
372   // Force a non-empty locale so SPELLCHECK is available.
373   menu()->GetPrefs()->SetString(prefs::kSpellCheckDictionary, "en");
374   EXPECT_TRUE(SpellingServiceClient::IsAvailable(
375       menu()->GetBrowserContext(), SpellingServiceClient::SPELLCHECK));
376   InitMenu("asdfkj", "asdf");
377
378   // The test should see a separator, a suggestion and another separator
379   // as the first two items, then possibly more (not relevant here).
380   EXPECT_LT(3U, menu()->GetMenuSize());
381
382   MockRenderViewContextMenu::MockMenuItem item;
383   menu()->GetMenuItem(0, &item);
384   EXPECT_EQ(-1, item.command_id);
385   EXPECT_FALSE(item.enabled);
386   EXPECT_FALSE(item.hidden);
387
388   menu()->GetMenuItem(1, &item);
389   EXPECT_EQ(IDC_SPELLCHECK_SUGGESTION_0, item.command_id);
390   EXPECT_TRUE(item.enabled);
391   EXPECT_FALSE(item.hidden);
392
393   menu()->GetMenuItem(2, &item);
394   EXPECT_EQ(-1, item.command_id);
395   EXPECT_FALSE(item.enabled);
396   EXPECT_FALSE(item.hidden);
397 }
398
399 // Test that "Ask Google For Suggestions" is grayed out when using an
400 // off the record profile.
401 // TODO(rlp): Include graying out of autocorrect in this test when autocorrect
402 // is functional.
403 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest,
404                        NoSpellingServiceWhenOffTheRecord) {
405   // Create a menu in an incognito profile.
406   Reset(true);
407
408   // This means spellchecking is allowed. Default is that the service is
409   // contacted but this test makes sure that if profile is incognito, that
410   // is not an option.
411   menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
412
413   // Force a non-empty locale so SUGGEST normally would be available.
414   menu()->GetPrefs()->SetString(prefs::kSpellCheckDictionary, "en");
415   EXPECT_FALSE(SpellingServiceClient::IsAvailable(
416       menu()->GetBrowserContext(), SpellingServiceClient::SUGGEST));
417   EXPECT_FALSE(SpellingServiceClient::IsAvailable(
418       menu()->GetBrowserContext(), SpellingServiceClient::SPELLCHECK));
419
420   InitMenu("sjxdjiiiiii", NULL);
421
422   // The test should see "No spelling suggestions" (from system checker).
423   // They should not see "No more Google suggestions" (from SpellingService) or
424   // a separator. The next 2 items should be "Add to Dictionary" followed
425   // by "Ask Google for suggestions" which should be disabled.
426   // TODO(rlp): add autocorrect here when it is functional.
427   EXPECT_LT(3U, menu()->GetMenuSize());
428
429   MockRenderViewContextMenu::MockMenuItem item;
430   menu()->GetMenuItem(0, &item);
431   EXPECT_EQ(IDC_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS, item.command_id);
432   EXPECT_FALSE(item.enabled);
433   EXPECT_FALSE(item.hidden);
434
435   menu()->GetMenuItem(1, &item);
436   EXPECT_EQ(IDC_SPELLCHECK_ADD_TO_DICTIONARY, item.command_id);
437   EXPECT_TRUE(item.enabled);
438   EXPECT_FALSE(item.hidden);
439
440   menu()->GetMenuItem(2, &item);
441   EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE, item.command_id);
442   EXPECT_FALSE(item.enabled);
443   EXPECT_FALSE(item.hidden);
444 }
445
446 // Test that the menu is preceeded by a separator if there are any suggestions,
447 // or if the SpellingServiceClient is available
448 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest, SuggestionsForceTopSeparator) {
449   menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, false);
450
451   // First case: Misspelled word, no suggestions, no spellcheck service.
452   InitMenu("asdfkj", NULL);
453   // See SpellingMenuObserverTest.InitMenuWithMisspelledWord on why 4 items.
454   EXPECT_EQ(static_cast<size_t>(4), menu()->GetMenuSize());
455   MockRenderViewContextMenu::MockMenuItem item;
456   menu()->GetMenuItem(0, &item);
457   EXPECT_NE(-1, item.command_id);
458
459   // Case #2. Misspelled word, suggestions, no spellcheck service.
460   Reset(false);
461   menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, false);
462   InitMenu("asdfkj", "asdf");
463
464   // Expect at least separator and 4 default entries.
465   EXPECT_LT(static_cast<size_t>(5), menu()->GetMenuSize());
466   // This test only cares that the first one is a separator.
467   menu()->GetMenuItem(0, &item);
468   EXPECT_EQ(-1, item.command_id);
469
470   // Case #3. Misspelled word, suggestion service is on.
471   Reset(false);
472   ForceSuggestMode();
473   InitMenu("asdfkj", NULL);
474
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);
481 }