1 // Copyright (c) 2010 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/extensions/extension_browsertest.h"
6 #include "chrome/browser/extensions/extension_service.h"
7 #include "chrome/browser/extensions/extension_toolbar_model.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/common/chrome_switches.h"
11 #include "chrome/test/in_process_browser_test.h"
12
13 // An InProcessBrowserTest for testing the ExtensionToolbarModel.
14 // TODO(erikkay) It's unfortunate that this needs to be an in-proc browser test.
15 // It would be nice to refactor things so that ExtensionService could run
16 // without so much of the browser in place.
17 class ExtensionToolbarModelTest : public ExtensionBrowserTest,
18 public ExtensionToolbarModel::Observer {
19 public:
SetUp()20 virtual void SetUp() {
21 inserted_count_ = 0;
22 removed_count_ = 0;
23 moved_count_ = 0;
24
25 ExtensionBrowserTest::SetUp();
26 }
27
CreateBrowser(Profile * profile)28 virtual Browser* CreateBrowser(Profile* profile) {
29 Browser* b = InProcessBrowserTest::CreateBrowser(profile);
30 ExtensionService* service = b->profile()->GetExtensionService();
31 model_ = service->toolbar_model();
32 model_->AddObserver(this);
33 return b;
34 }
35
CleanUpOnMainThread()36 virtual void CleanUpOnMainThread() {
37 model_->RemoveObserver(this);
38 }
39
BrowserActionAdded(const Extension * extension,int index)40 virtual void BrowserActionAdded(const Extension* extension, int index) {
41 inserted_count_++;
42 }
43
BrowserActionRemoved(const Extension * extension)44 virtual void BrowserActionRemoved(const Extension* extension) {
45 removed_count_++;
46 }
47
BrowserActionMoved(const Extension * extension,int index)48 virtual void BrowserActionMoved(const Extension* extension, int index) {
49 moved_count_++;
50 }
51
ExtensionAt(int index)52 const Extension* ExtensionAt(int index) {
53 for (ExtensionList::iterator i = model_->begin(); i < model_->end(); ++i) {
54 if (index-- == 0)
55 return *i;
56 }
57 return NULL;
58 }
59
60 protected:
61 ExtensionToolbarModel* model_;
62
63 int inserted_count_;
64 int removed_count_;
65 int moved_count_;
66 };
67
IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest,Basic)68 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, Basic) {
69 CommandLine::ForCurrentProcess()->AppendSwitch(
70 switches::kEnableExperimentalExtensionApis);
71
72 // Load an extension with no browser action.
73 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
74 .AppendASCII("browser_action")
75 .AppendASCII("none")));
76
77 // This extension should not be in the model (has no browser action).
78 EXPECT_EQ(0, inserted_count_);
79 EXPECT_EQ(0u, model_->size());
80 ASSERT_EQ(NULL, ExtensionAt(0));
81
82 // Load an extension with a browser action.
83 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
84 .AppendASCII("browser_action")
85 .AppendASCII("basics")));
86
87 // We should now find our extension in the model.
88 EXPECT_EQ(1, inserted_count_);
89 EXPECT_EQ(1u, model_->size());
90 const Extension* extension = ExtensionAt(0);
91 ASSERT_TRUE(NULL != extension);
92 EXPECT_STREQ("A browser action with no icon that makes the page red",
93 extension->name().c_str());
94
95 // Should be a no-op, but still fires the events.
96 model_->MoveBrowserAction(extension, 0);
97 EXPECT_EQ(1, moved_count_);
98 EXPECT_EQ(1u, model_->size());
99 const Extension* extension2 = ExtensionAt(0);
100 EXPECT_EQ(extension, extension2);
101
102 UnloadExtension(extension->id());
103 EXPECT_EQ(1, removed_count_);
104 EXPECT_EQ(0u, model_->size());
105 EXPECT_EQ(NULL, ExtensionAt(0));
106 }
107
IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest,ReorderAndReinsert)108 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, ReorderAndReinsert) {
109 CommandLine::ForCurrentProcess()->AppendSwitch(
110 switches::kEnableExperimentalExtensionApis);
111
112 // Load an extension with a browser action.
113 FilePath extension_a_path(test_data_dir_.AppendASCII("api_test")
114 .AppendASCII("browser_action")
115 .AppendASCII("basics"));
116 ASSERT_TRUE(LoadExtension(extension_a_path));
117
118 // First extension loaded.
119 EXPECT_EQ(1, inserted_count_);
120 EXPECT_EQ(1u, model_->size());
121 const Extension* extensionA = ExtensionAt(0);
122 ASSERT_TRUE(NULL != extensionA);
123 EXPECT_STREQ("A browser action with no icon that makes the page red",
124 extensionA->name().c_str());
125
126 // Load another extension with a browser action.
127 FilePath extension_b_path(test_data_dir_.AppendASCII("api_test")
128 .AppendASCII("browser_action")
129 .AppendASCII("popup"));
130 ASSERT_TRUE(LoadExtension(extension_b_path));
131
132 // Second extension loaded.
133 EXPECT_EQ(2, inserted_count_);
134 EXPECT_EQ(2u, model_->size());
135 const Extension* extensionB = ExtensionAt(1);
136 ASSERT_TRUE(NULL != extensionB);
137 EXPECT_STREQ("Popup tester", extensionB->name().c_str());
138
139 // Load yet another extension with a browser action.
140 FilePath extension_c_path(test_data_dir_.AppendASCII("api_test")
141 .AppendASCII("browser_action")
142 .AppendASCII("remove_popup"));
143 ASSERT_TRUE(LoadExtension(extension_c_path));
144
145 // Third extension loaded.
146 EXPECT_EQ(3, inserted_count_);
147 EXPECT_EQ(3u, model_->size());
148 const Extension* extensionC = ExtensionAt(2);
149 ASSERT_TRUE(NULL != extensionC);
150 EXPECT_STREQ("A page action which removes a popup.",
151 extensionC->name().c_str());
152
153 // Order is now A, B, C. Let's put C first.
154 model_->MoveBrowserAction(extensionC, 0);
155 EXPECT_EQ(1, moved_count_);
156 EXPECT_EQ(3u, model_->size());
157 EXPECT_EQ(extensionC, ExtensionAt(0));
158 EXPECT_EQ(extensionA, ExtensionAt(1));
159 EXPECT_EQ(extensionB, ExtensionAt(2));
160 EXPECT_EQ(NULL, ExtensionAt(3));
161
162 // Order is now C, A, B. Let's put A last.
163 model_->MoveBrowserAction(extensionA, 2);
164 EXPECT_EQ(2, moved_count_);
165 EXPECT_EQ(3u, model_->size());
166 EXPECT_EQ(extensionC, ExtensionAt(0));
167 EXPECT_EQ(extensionB, ExtensionAt(1));
168 EXPECT_EQ(extensionA, ExtensionAt(2));
169 EXPECT_EQ(NULL, ExtensionAt(3));
170
171 // Order is now C, B, A. Let's remove B.
172 std::string idB = extensionB->id();
173 UnloadExtension(idB);
174 EXPECT_EQ(1, removed_count_);
175 EXPECT_EQ(2u, model_->size());
176 EXPECT_EQ(extensionC, ExtensionAt(0));
177 EXPECT_EQ(extensionA, ExtensionAt(1));
178 EXPECT_EQ(NULL, ExtensionAt(2));
179
180 // Load extension B again.
181 ASSERT_TRUE(LoadExtension(extension_b_path));
182
183 // Extension B loaded again.
184 EXPECT_EQ(4, inserted_count_);
185 EXPECT_EQ(3u, model_->size());
186 // Make sure it gets its old spot in the list. We should get the same
187 // extension again, otherwise the order has changed.
188 ASSERT_STREQ(idB.c_str(), ExtensionAt(1)->id().c_str());
189
190 // Unload B again.
191 UnloadExtension(idB);
192 EXPECT_EQ(2, removed_count_);
193 EXPECT_EQ(2u, model_->size());
194 EXPECT_EQ(extensionC, ExtensionAt(0));
195 EXPECT_EQ(extensionA, ExtensionAt(1));
196 EXPECT_EQ(NULL, ExtensionAt(2));
197
198 // Order is now C, A. Flip it.
199 model_->MoveBrowserAction(extensionA, 0);
200 EXPECT_EQ(3, moved_count_);
201 EXPECT_EQ(2u, model_->size());
202 EXPECT_EQ(extensionA, ExtensionAt(0));
203 EXPECT_EQ(extensionC, ExtensionAt(1));
204 EXPECT_EQ(NULL, ExtensionAt(2));
205
206 // Move A to the location it already occupies.
207 model_->MoveBrowserAction(extensionA, 0);
208 EXPECT_EQ(4, moved_count_);
209 EXPECT_EQ(2u, model_->size());
210 EXPECT_EQ(extensionA, ExtensionAt(0));
211 EXPECT_EQ(extensionC, ExtensionAt(1));
212 EXPECT_EQ(NULL, ExtensionAt(2));
213
214 // Order is now A, C. Remove C.
215 std::string idC = extensionC->id();
216 UnloadExtension(idC);
217 EXPECT_EQ(3, removed_count_);
218 EXPECT_EQ(1u, model_->size());
219 EXPECT_EQ(extensionA, ExtensionAt(0));
220 EXPECT_EQ(NULL, ExtensionAt(1));
221
222 // Load extension C again.
223 ASSERT_TRUE(LoadExtension(extension_c_path));
224
225 // Extension C loaded again.
226 EXPECT_EQ(5, inserted_count_);
227 EXPECT_EQ(2u, model_->size());
228 // Make sure it gets its old spot in the list (at the very end).
229 ASSERT_STREQ(idC.c_str(), ExtensionAt(1)->id().c_str());
230 }
231