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.
4
5#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
6
7#include "chrome/app/chrome_command_ids.h"
8#include "chrome/browser/prefs/browser_prefs.h"
9#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
10#include "chrome/browser/ui/browser.h"
11#include "chrome/browser/ui/global_error/global_error.h"
12#include "chrome/browser/ui/global_error/global_error_service.h"
13#include "chrome/browser/ui/global_error/global_error_service_factory.h"
14#include "chrome/browser/ui/tabs/tab_strip_model.h"
15#include "chrome/test/base/browser_with_test_window_test.h"
16#include "chrome/test/base/menu_model_test.h"
17#include "chrome/test/base/testing_browser_process.h"
18#include "chrome/test/base/testing_io_thread_state.h"
19#include "chrome/test/base/testing_pref_service_syncable.h"
20#include "chrome/test/base/testing_profile.h"
21#include "grit/generated_resources.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24namespace {
25
26// Error class has a menu item.
27class MenuError : public GlobalError {
28 public:
29  explicit MenuError(int command_id)
30      : command_id_(command_id),
31        execute_count_(0) {
32  }
33
34  int execute_count() { return execute_count_; }
35
36  virtual bool HasMenuItem() OVERRIDE { return true; }
37  virtual int MenuItemCommandID() OVERRIDE { return command_id_; }
38  virtual base::string16 MenuItemLabel() OVERRIDE { return base::string16(); }
39  virtual void ExecuteMenuItem(Browser* browser) OVERRIDE { execute_count_++; }
40
41  virtual bool HasBubbleView() OVERRIDE { return false; }
42  virtual bool HasShownBubbleView() OVERRIDE { return false; }
43  virtual void ShowBubbleView(Browser* browser) OVERRIDE { ADD_FAILURE(); }
44  virtual GlobalErrorBubbleViewBase* GetBubbleView() OVERRIDE { return NULL; }
45
46 private:
47  int command_id_;
48  int execute_count_;
49
50  DISALLOW_COPY_AND_ASSIGN(MenuError);
51};
52
53} // namespace
54
55class WrenchMenuModelTest : public BrowserWithTestWindowTest,
56                            public ui::AcceleratorProvider {
57 public:
58  // Don't handle accelerators.
59  virtual bool GetAcceleratorForCommandId(
60      int command_id,
61      ui::Accelerator* accelerator) OVERRIDE { return false; }
62
63 protected:
64  virtual void SetUp() OVERRIDE {
65    prefs_.reset(new TestingPrefServiceSimple());
66    chrome::RegisterLocalState(prefs_->registry());
67
68    TestingBrowserProcess::GetGlobal()->SetLocalState(prefs_.get());
69    testing_io_thread_state_.reset(new chrome::TestingIOThreadState());
70    BrowserWithTestWindowTest::SetUp();
71  }
72
73  virtual void TearDown() OVERRIDE {
74    BrowserWithTestWindowTest::TearDown();
75    testing_io_thread_state_.reset();
76    TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
77    DestroyBrowserAndProfile();
78  }
79
80 private:
81  scoped_ptr<TestingPrefServiceSimple> prefs_;
82  scoped_ptr<chrome::TestingIOThreadState> testing_io_thread_state_;
83};
84
85// Copies parts of MenuModelTest::Delegate and combines them with the
86// WrenchMenuModel since WrenchMenuModel is now a SimpleMenuModel::Delegate and
87// not derived from SimpleMenuModel.
88class TestWrenchMenuModel : public WrenchMenuModel {
89 public:
90  TestWrenchMenuModel(ui::AcceleratorProvider* provider,
91                      Browser* browser)
92      : WrenchMenuModel(provider, browser, false),
93        execute_count_(0),
94        checked_count_(0),
95        enable_count_(0) {
96  }
97
98  // Testing overrides to ui::SimpleMenuModel::Delegate:
99  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
100    bool val = WrenchMenuModel::IsCommandIdChecked(command_id);
101    if (val)
102      checked_count_++;
103    return val;
104  }
105
106  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
107    ++enable_count_;
108    return true;
109  }
110
111  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
112    ++execute_count_;
113  }
114
115  int execute_count_;
116  mutable int checked_count_;
117  mutable int enable_count_;
118};
119
120TEST_F(WrenchMenuModelTest, Basics) {
121  TestWrenchMenuModel model(this, browser());
122  int itemCount = model.GetItemCount();
123
124  // Verify it has items. The number varies by platform, so we don't check
125  // the exact number.
126  EXPECT_GT(itemCount, 10);
127
128  // Execute a couple of the items and make sure it gets back to our delegate.
129  // We can't use CountEnabledExecutable() here because the encoding menu's
130  // delegate is internal, it doesn't use the one we pass in.
131  // Note: The new menu has a spacing separator at the first slot.
132  model.ActivatedAt(1);
133  EXPECT_TRUE(model.IsEnabledAt(1));
134  // Make sure to use the index that is not separator in all configurations.
135  model.ActivatedAt(2);
136  EXPECT_TRUE(model.IsEnabledAt(2));
137  EXPECT_EQ(model.execute_count_, 2);
138  EXPECT_EQ(model.enable_count_, 2);
139
140  model.execute_count_ = 0;
141  model.enable_count_ = 0;
142
143  // Choose something from the bookmark submenu and make sure it makes it back
144  // to the delegate as well.
145  int bookmarksModelIndex = -1;
146  for (int i = 0; i < itemCount; ++i) {
147    if (model.GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) {
148      bookmarksModelIndex = i;
149      break;
150    }
151  }
152  EXPECT_GT(bookmarksModelIndex, -1);
153  ui::MenuModel* bookmarksModel = model.GetSubmenuModelAt(bookmarksModelIndex);
154  EXPECT_TRUE(bookmarksModel);
155  // The bookmarks model may be empty until we tell it we're going to show it.
156  bookmarksModel->MenuWillShow();
157  EXPECT_GT(bookmarksModel->GetItemCount(), 1);
158  bookmarksModel->ActivatedAt(1);
159  EXPECT_TRUE(bookmarksModel->IsEnabledAt(1));
160  EXPECT_EQ(model.execute_count_, 1);
161  EXPECT_EQ(model.enable_count_, 1);
162}
163
164// Tests global error menu items in the wrench menu.
165TEST_F(WrenchMenuModelTest, GlobalError) {
166  // Make sure services required for tests are initialized.
167  GlobalErrorService* service =
168      GlobalErrorServiceFactory::GetForProfile(browser()->profile());
169  ProfileOAuth2TokenServiceFactory::GetForProfile(browser()->profile());
170  const int command1 = 1234567;
171  // AddGlobalError takes ownership of error1.
172  MenuError* error1 = new MenuError(command1);
173  service->AddGlobalError(error1);
174  const int command2 = 1234568;
175  // AddGlobalError takes ownership of error2.
176  MenuError* error2 = new MenuError(command2);
177  service->AddGlobalError(error2);
178
179  WrenchMenuModel model(this, browser(), false);
180  int index1 = model.GetIndexOfCommandId(command1);
181  EXPECT_GT(index1, -1);
182  int index2 = model.GetIndexOfCommandId(command2);
183  EXPECT_GT(index2, -1);
184
185  EXPECT_TRUE(model.IsEnabledAt(index1));
186  EXPECT_EQ(0, error1->execute_count());
187  model.ActivatedAt(index1);
188  EXPECT_EQ(1, error1->execute_count());
189
190  EXPECT_TRUE(model.IsEnabledAt(index2));
191  EXPECT_EQ(0, error2->execute_count());
192  model.ActivatedAt(index2);
193  EXPECT_EQ(1, error1->execute_count());
194}
195
196class EncodingMenuModelTest : public BrowserWithTestWindowTest,
197                              public MenuModelTest {
198};
199
200TEST_F(EncodingMenuModelTest, IsCommandIdCheckedWithNoTabs) {
201  EncodingMenuModel model(browser());
202  ASSERT_EQ(NULL, browser()->tab_strip_model()->GetActiveWebContents());
203  EXPECT_FALSE(model.IsCommandIdChecked(IDC_ENCODING_ISO88591));
204}
205