| Index: chrome/browser/extensions/extension_action_icon_factory_unittest.cc
|
| diff --git a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cba10b1fe4abb433dc0c24a04d2c9052a6d049c0
|
| --- /dev/null
|
| +++ b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
|
| @@ -0,0 +1,253 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/extensions/extension_action_icon_factory.h"
|
| +
|
| +#include "base/file_util.h"
|
| +#include "base/json/json_file_value_serializer.h"
|
| +#include "base/message_loop.h"
|
| +#include "base/path_service.h"
|
| +#include "chrome/common/chrome_paths.h"
|
| +#include "chrome/common/extensions/extension.h"
|
| +#include "chrome/common/extensions/extension_action.h"
|
| +#include "content/public/test/test_browser_thread.h"
|
| +#include "grit/theme_resources.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "ui/base/resource/resource_bundle.h"
|
| +#include "ui/gfx/image/image_skia.h"
|
| +#include "ui/gfx/skia_util.h"
|
| +#include "webkit/glue/image_decoder.h"
|
| +
|
| +using content::BrowserThread;
|
| +using extensions::Extension;
|
| +
|
| +namespace {
|
| +
|
| +bool ImageRepsAreEqual(const gfx::ImageSkiaRep& image_rep1,
|
| + const gfx::ImageSkiaRep& image_rep2) {
|
| + return image_rep1.scale_factor() == image_rep2.scale_factor() &&
|
| + gfx::BitmapsAreEqual(image_rep1.sk_bitmap(), image_rep2.sk_bitmap());
|
| +}
|
| +
|
| +gfx::ImageSkiaRep CreateBlankRep(int size_dip, ui::ScaleFactor scale_factor) {
|
| + SkBitmap bitmap;
|
| + const float scale = ui::GetScaleFactorScale(scale_factor);
|
| + bitmap.setConfig(SkBitmap::kARGB_8888_Config,
|
| + static_cast<int>(size_dip * scale),
|
| + static_cast<int>(size_dip * scale));
|
| + bitmap.allocPixels();
|
| + bitmap.eraseColor(SkColorSetARGB(0, 0, 0, 0));
|
| + return gfx::ImageSkiaRep(bitmap, scale_factor);
|
| +}
|
| +
|
| +gfx::Image LoadIcon(const std::string& filename) {
|
| + FilePath path;
|
| + PathService::Get(chrome::DIR_TEST_DATA, &path);
|
| + path = path.AppendASCII("extensions/api_test").AppendASCII(filename);
|
| +
|
| + std::string file_contents;
|
| + file_util::ReadFileToString(path, &file_contents);
|
| + const unsigned char* data =
|
| + reinterpret_cast<const unsigned char*>(file_contents.data());
|
| +
|
| + SkBitmap bitmap;
|
| + webkit_glue::ImageDecoder decoder;
|
| + bitmap = decoder.Decode(data, file_contents.length());
|
| +
|
| + return gfx::Image(bitmap);
|
| +}
|
| +
|
| +class ExtensionActionIconFactoryTest
|
| + : public testing::Test,
|
| + public ExtensionActionIconFactory::Observer {
|
| + public:
|
| + ExtensionActionIconFactoryTest()
|
| + : quit_in_icon_updated_(false),
|
| + ui_thread_(BrowserThread::UI, &ui_loop_),
|
| + file_thread_(BrowserThread::FILE),
|
| + io_thread_(BrowserThread::IO) {
|
| + }
|
| +
|
| + virtual ~ExtensionActionIconFactoryTest() {}
|
| +
|
| + void WaitForIconUpdate() {
|
| + quit_in_icon_updated_ = true;
|
| + MessageLoop::current()->Run();
|
| + quit_in_icon_updated_ = false;
|
| + }
|
| +
|
| + scoped_refptr<Extension> CreateExtension(const char* name,
|
| + Extension::Location location) {
|
| + // Create and load an extension.
|
| + FilePath test_file;
|
| + if (!PathService::Get(chrome::DIR_TEST_DATA, &test_file)) {
|
| + EXPECT_FALSE(true);
|
| + return NULL;
|
| + }
|
| + test_file = test_file.AppendASCII("extensions/api_test").AppendASCII(name);
|
| + int error_code = 0;
|
| + std::string error;
|
| + JSONFileValueSerializer serializer(test_file.AppendASCII("manifest.json"));
|
| + scoped_ptr<DictionaryValue> valid_value(
|
| + static_cast<DictionaryValue*>(serializer.Deserialize(&error_code,
|
| + &error)));
|
| + EXPECT_EQ(0, error_code) << error;
|
| + if (error_code != 0)
|
| + return NULL;
|
| +
|
| + EXPECT_TRUE(valid_value.get());
|
| + if (!valid_value.get())
|
| + return NULL;
|
| +
|
| + return Extension::Create(test_file, location, *valid_value,
|
| + Extension::NO_FLAGS, &error);
|
| + }
|
| +
|
| + // testing::Test overrides:
|
| + virtual void SetUp() OVERRIDE {
|
| + file_thread_.Start();
|
| + io_thread_.Start();
|
| + }
|
| +
|
| + // ExtensionActionIconFactory::Observer overrides:
|
| + virtual void OnIconUpdated() OVERRIDE {
|
| + if (quit_in_icon_updated_)
|
| + MessageLoop::current()->Quit();
|
| + }
|
| +
|
| + gfx::ImageSkia GetFavicon() {
|
| + return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
|
| + IDR_EXTENSIONS_FAVICON);
|
| + }
|
| +
|
| + private:
|
| + bool quit_in_icon_updated_;
|
| + MessageLoop ui_loop_;
|
| + content::TestBrowserThread ui_thread_;
|
| + content::TestBrowserThread file_thread_;
|
| + content::TestBrowserThread io_thread_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ExtensionActionIconFactoryTest);
|
| +};
|
| +
|
| +// If there is no default icon, and the icon has not been set using |SetIcon|,
|
| +// the factory should return favicon.
|
| +TEST_F(ExtensionActionIconFactoryTest, NoIcons) {
|
| + // Load an extension that has browser action without default icon set in the
|
| + // manifest and does not call |SetIcon| by default.
|
| + scoped_refptr<Extension> extension(CreateExtension(
|
| + "browser_action/no_icon", Extension::INVALID));
|
| + ASSERT_TRUE(extension.get() != NULL);
|
| + ASSERT_TRUE(extension->browser_action());
|
| + ASSERT_FALSE(extension->browser_action()->default_icon());
|
| + ASSERT_TRUE(
|
| + extension->browser_action()->GetExplicitlySetIcon(0 /*tab id*/).isNull());
|
| +
|
| + gfx::ImageSkia favicon = GetFavicon();
|
| +
|
| + ExtensionActionIconFactory icon_factory(extension,
|
| + extension->browser_action(),
|
| + this);
|
| +
|
| + gfx::Image icon = icon_factory.GetIcon(0);
|
| +
|
| + EXPECT_TRUE(ImageRepsAreEqual(
|
| + favicon.GetRepresentation(ui::SCALE_FACTOR_100P),
|
| + icon.ToImageSkia()->GetRepresentation(ui::SCALE_FACTOR_100P)));
|
| +}
|
| +
|
| +// If the icon has been set using |SetIcon|, the factory should return that
|
| +// icon.
|
| +TEST_F(ExtensionActionIconFactoryTest, AfterSetIcon) {
|
| + // Load an extension that has browser action without default icon set in the
|
| + // manifest and does not call |SetIcon| by default (but has an browser action
|
| + // icon resource).
|
| + scoped_refptr<Extension> extension(CreateExtension(
|
| + "browser_action/no_icon", Extension::INVALID));
|
| + ASSERT_TRUE(extension.get() != NULL);
|
| + ASSERT_TRUE(extension->browser_action());
|
| + ASSERT_FALSE(extension->browser_action()->default_icon());
|
| + ASSERT_TRUE(
|
| + extension->browser_action()->GetExplicitlySetIcon(0 /*tab id*/).isNull());
|
| +
|
| + gfx::Image set_icon = LoadIcon("browser_action/no_icon/icon.png");
|
| + ASSERT_FALSE(set_icon.IsEmpty());
|
| +
|
| + extension->browser_action()->SetIcon(0, set_icon);
|
| +
|
| + ASSERT_FALSE(
|
| + extension->browser_action()->GetExplicitlySetIcon(0 /*tab id*/).isNull());
|
| +
|
| + ExtensionActionIconFactory icon_factory(extension,
|
| + extension->browser_action(),
|
| + this);
|
| +
|
| + gfx::Image icon = icon_factory.GetIcon(0);
|
| +
|
| + EXPECT_TRUE(ImageRepsAreEqual(
|
| + set_icon.ToImageSkia()->GetRepresentation(ui::SCALE_FACTOR_100P),
|
| + icon.ToImageSkia()->GetRepresentation(ui::SCALE_FACTOR_100P)));
|
| +
|
| + // It should still return favicon for another tabs.
|
| + icon = icon_factory.GetIcon(1);
|
| +
|
| + EXPECT_TRUE(ImageRepsAreEqual(
|
| + GetFavicon().GetRepresentation(ui::SCALE_FACTOR_100P),
|
| + icon.ToImageSkia()->GetRepresentation(ui::SCALE_FACTOR_100P)));
|
| +}
|
| +
|
| +// If there is a default icon, and the icon has not been set using |SetIcon|,
|
| +// the factory should return the default icon.
|
| +TEST_F(ExtensionActionIconFactoryTest, DefaultIcon) {
|
| + // Load an extension that has browser action without default icon set in the
|
| + // manifest and does not call |SetIcon| by default (but has an browser action
|
| + // icon resource).
|
| + scoped_refptr<Extension> extension(CreateExtension(
|
| + "browser_action/no_icon", Extension::INVALID));
|
| + ASSERT_TRUE(extension.get() != NULL);
|
| + ASSERT_TRUE(extension->browser_action());
|
| + ASSERT_FALSE(extension->browser_action()->default_icon());
|
| + ASSERT_TRUE(
|
| + extension->browser_action()->GetExplicitlySetIcon(0 /*tab id*/).isNull());
|
| +
|
| + gfx::Image default_icon = LoadIcon("browser_action/no_icon/icon.png");
|
| + ASSERT_FALSE(default_icon.IsEmpty());
|
| +
|
| + scoped_ptr<ExtensionIconSet> default_icon_set(new ExtensionIconSet());
|
| + default_icon_set->Add(19, "icon.png");
|
| +
|
| + extension->browser_action()->set_default_icon(default_icon_set.Pass());
|
| + ASSERT_TRUE(extension->browser_action()->default_icon());
|
| +
|
| + ExtensionActionIconFactory icon_factory(extension,
|
| + extension->browser_action(),
|
| + this);
|
| +
|
| + gfx::Image icon = icon_factory.GetIcon(0);
|
| +
|
| + // The icon should be loaded asynchronously. Initially a transparent icon
|
| + // should be returned.
|
| + EXPECT_TRUE(ImageRepsAreEqual(
|
| + CreateBlankRep(19, ui::SCALE_FACTOR_100P),
|
| + icon.ToImageSkia()->GetRepresentation(ui::SCALE_FACTOR_100P)));
|
| +
|
| + WaitForIconUpdate();
|
| +
|
| + icon = icon_factory.GetIcon(0);
|
| +
|
| + // The default icon representation should be loaded at this point.
|
| + EXPECT_TRUE(ImageRepsAreEqual(
|
| + default_icon.ToImageSkia()->GetRepresentation(ui::SCALE_FACTOR_100P),
|
| + icon.ToImageSkia()->GetRepresentation(ui::SCALE_FACTOR_100P)));
|
| +
|
| + // The same icon should be returned for the other tabs.
|
| + icon = icon_factory.GetIcon(1);
|
| +
|
| + EXPECT_TRUE(ImageRepsAreEqual(
|
| + default_icon.ToImageSkia()->GetRepresentation(ui::SCALE_FACTOR_100P),
|
| + icon.ToImageSkia()->GetRepresentation(ui::SCALE_FACTOR_100P)));
|
| +
|
| +}
|
| +
|
| +} // namespace
|
|
|