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. 17class ExtensionToolbarModelTest : public ExtensionBrowserTest, 18 public ExtensionToolbarModel::Observer { 19 public: 20 virtual void SetUp() { 21 inserted_count_ = 0; 22 removed_count_ = 0; 23 moved_count_ = 0; 24 25 ExtensionBrowserTest::SetUp(); 26 } 27 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 36 virtual void CleanUpOnMainThread() { 37 model_->RemoveObserver(this); 38 } 39 40 virtual void BrowserActionAdded(const Extension* extension, int index) { 41 inserted_count_++; 42 } 43 44 virtual void BrowserActionRemoved(const Extension* extension) { 45 removed_count_++; 46 } 47 48 virtual void BrowserActionMoved(const Extension* extension, int index) { 49 moved_count_++; 50 } 51 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 68IN_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 108IN_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