1 // Copyright (c) 2011 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 "base/message_loop.h"
6 #include "base/path_service.h"
7 #include "base/values.h"
8 #include "chrome/browser/extensions/extension_icon_manager.h"
9 #include "chrome/common/chrome_paths.h"
10 #include "chrome/common/extensions/extension.h"
11 #include "chrome/common/extensions/extension_resource.h"
12 #include "content/browser/browser_thread.h"
13 #include "content/common/json_value_serializer.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/gfx/skia_util.h"
16
17 // Our test class that takes care of managing the necessary threads for loading
18 // extension icons, and waiting for those loads to happen.
19 class ExtensionIconManagerTest : public testing::Test {
20 public:
ExtensionIconManagerTest()21 ExtensionIconManagerTest() :
22 unwaited_image_loads_(0),
23 waiting_(false),
24 ui_thread_(BrowserThread::UI, &ui_loop_),
25 file_thread_(BrowserThread::FILE),
26 io_thread_(BrowserThread::IO) {}
27
~ExtensionIconManagerTest()28 virtual ~ExtensionIconManagerTest() {}
29
ImageLoadObserved()30 void ImageLoadObserved() {
31 unwaited_image_loads_++;
32 if (waiting_) {
33 MessageLoop::current()->Quit();
34 }
35 }
36
WaitForImageLoad()37 void WaitForImageLoad() {
38 if (unwaited_image_loads_ == 0) {
39 waiting_ = true;
40 MessageLoop::current()->Run();
41 waiting_ = false;
42 }
43 ASSERT_GT(unwaited_image_loads_, 0);
44 unwaited_image_loads_--;
45 }
46
47 private:
SetUp()48 virtual void SetUp() {
49 file_thread_.Start();
50 io_thread_.Start();
51 }
52
53 // The number of observed image loads that have not been waited for.
54 int unwaited_image_loads_;
55
56 // Whether we are currently waiting for an image load.
57 bool waiting_;
58
59 MessageLoop ui_loop_;
60 BrowserThread ui_thread_;
61 BrowserThread file_thread_;
62 BrowserThread io_thread_;
63
64 DISALLOW_COPY_AND_ASSIGN(ExtensionIconManagerTest);
65 };
66
67 // This is a specialization of ExtensionIconManager, with a special override to
68 // call back to the test when an icon has completed loading.
69 class TestIconManager : public ExtensionIconManager {
70 public:
TestIconManager(ExtensionIconManagerTest * test)71 explicit TestIconManager(ExtensionIconManagerTest* test) : test_(test) {}
~TestIconManager()72 virtual ~TestIconManager() {}
73
74 // Implements the ImageLoadingTracker::Observer interface, and calls through
75 // to the base class' implementation. Then it lets the test know that an
76 // image load was observed.
OnImageLoaded(SkBitmap * image,const ExtensionResource & resource,int index)77 virtual void OnImageLoaded(SkBitmap* image, const ExtensionResource& resource,
78 int index) {
79 ExtensionIconManager::OnImageLoaded(image, resource, index);
80 test_->ImageLoadObserved();
81 }
82
83 private:
84 ExtensionIconManagerTest* test_;
85
86 DISALLOW_COPY_AND_ASSIGN(TestIconManager);
87 };
88
89 // Returns the default icon that ExtensionIconManager gives when an extension
90 // doesn't have an icon.
GetDefaultIcon()91 SkBitmap GetDefaultIcon() {
92 std::string dummy_id;
93 EXPECT_TRUE(Extension::GenerateId(std::string("whatever"), &dummy_id));
94 ExtensionIconManager manager;
95 return manager.GetIcon(dummy_id);
96 }
97
98 // Tests loading an icon for an extension, removing it, then re-loading it.
TEST_F(ExtensionIconManagerTest,LoadRemoveLoad)99 TEST_F(ExtensionIconManagerTest, LoadRemoveLoad) {
100 SkBitmap default_icon = GetDefaultIcon();
101
102 FilePath test_dir;
103 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
104 FilePath manifest_path = test_dir.AppendASCII(
105 "extensions/image_loading_tracker/app.json");
106
107 JSONFileValueSerializer serializer(manifest_path);
108 scoped_ptr<DictionaryValue> manifest(
109 static_cast<DictionaryValue*>(serializer.Deserialize(NULL, NULL)));
110 ASSERT_TRUE(manifest.get() != NULL);
111
112 scoped_refptr<Extension> extension(Extension::Create(
113 manifest_path.DirName(), Extension::INVALID, *manifest.get(),
114 Extension::STRICT_ERROR_CHECKS, NULL));
115 ASSERT_TRUE(extension.get());
116 TestIconManager icon_manager(this);
117
118 // Load the icon and grab the bitmap.
119 icon_manager.LoadIcon(extension.get());
120 WaitForImageLoad();
121 SkBitmap first_icon = icon_manager.GetIcon(extension->id());
122 EXPECT_FALSE(gfx::BitmapsAreEqual(first_icon, default_icon));
123
124 // Remove the icon from the manager.
125 icon_manager.RemoveIcon(extension->id());
126
127 // Now re-load the icon - we should get the same result bitmap (and not the
128 // default icon).
129 icon_manager.LoadIcon(extension.get());
130 WaitForImageLoad();
131 SkBitmap second_icon = icon_manager.GetIcon(extension->id());
132 EXPECT_FALSE(gfx::BitmapsAreEqual(second_icon, default_icon));
133
134 EXPECT_TRUE(gfx::BitmapsAreEqual(first_icon, second_icon));
135 }
136