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. 19class ExtensionIconManagerTest : public testing::Test { 20 public: 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 28 virtual ~ExtensionIconManagerTest() {} 29 30 void ImageLoadObserved() { 31 unwaited_image_loads_++; 32 if (waiting_) { 33 MessageLoop::current()->Quit(); 34 } 35 } 36 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: 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. 69class TestIconManager : public ExtensionIconManager { 70 public: 71 explicit TestIconManager(ExtensionIconManagerTest* test) : test_(test) {} 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. 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. 91SkBitmap 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. 99TEST_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