15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_file_value_serializer.h" 6ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h" 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_icon_manager.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/test/base/testing_profile.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/test/test_browser_thread.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/id_util.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skia_util.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::Extension; 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::Manifest; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Our test class that takes care of managing the necessary threads for loading 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// extension icons, and waiting for those loads to happen. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ExtensionIconManagerTest : public testing::Test { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionIconManagerTest() : 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unwaited_image_loads_(0), 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_(false), 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui_thread_(BrowserThread::UI, &ui_loop_), 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_thread_(BrowserThread::FILE), 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_thread_(BrowserThread::IO) {} 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~ExtensionIconManagerTest() {} 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ImageLoadObserved() { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unwaited_image_loads_++; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (waiting_) { 3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->Quit(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void WaitForImageLoad() { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (unwaited_image_loads_ == 0) { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_ = true; 4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->Run(); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiting_ = false; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_GT(unwaited_image_loads_, 0); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unwaited_image_loads_--; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void SetUp() { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_thread_.Start(); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_thread_.Start(); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The number of observed image loads that have not been waited for. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int unwaited_image_loads_; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Whether we are currently waiting for an image load. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool waiting_; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop ui_loop_; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::TestBrowserThread ui_thread_; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::TestBrowserThread file_thread_; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::TestBrowserThread io_thread_; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ExtensionIconManagerTest); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is a specialization of ExtensionIconManager, with a special override to 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// call back to the test when an icon has completed loading. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TestIconManager : public ExtensionIconManager { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit TestIconManager(ExtensionIconManagerTest* test) : test_(test) {} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~TestIconManager() {} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Overrides the ImageLoader callback, and calls through to the base class' 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // implementation. Then it lets the test know that an image load was observed. 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnImageLoaded(const std::string& extension_id, 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Image& image) OVERRIDE { 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionIconManager::OnImageLoaded(extension_id, image); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_->ImageLoadObserved(); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionIconManagerTest* test_; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(TestIconManager); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the default icon that ExtensionIconManager gives when an extension 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// doesn't have an icon. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkBitmap GetDefaultIcon() { 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string dummy_id = extensions::id_util::GenerateId("whatever"); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionIconManager manager; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return manager.GetIcon(dummy_id); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests loading an icon for an extension, removing it, then re-loading it. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ExtensionIconManagerTest, LoadRemoveLoad) { 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<Profile> profile(new TestingProfile()); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap default_icon = GetDefaultIcon(); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath test_dir; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath manifest_path = test_dir.AppendASCII( 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "extensions/image_loading_tracker/app.json"); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JSONFileValueSerializer serializer(manifest_path); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> manifest( 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<DictionaryValue*>(serializer.Deserialize(NULL, NULL))); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(manifest.get() != NULL); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string error; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<Extension> extension(Extension::Create( 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) manifest_path.DirName(), Manifest::INVALID_LOCATION, *manifest.get(), 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Extension::NO_FLAGS, &error)); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(extension.get()); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestIconManager icon_manager(this); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load the icon and grab the bitmap. 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_manager.LoadIcon(profile.get(), extension.get()); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WaitForImageLoad(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap first_icon = icon_manager.GetIcon(extension->id()); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(gfx::BitmapsAreEqual(first_icon, default_icon)); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove the icon from the manager. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_manager.RemoveIcon(extension->id()); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now re-load the icon - we should get the same result bitmap (and not the 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // default icon). 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_manager.LoadIcon(profile.get(), extension.get()); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WaitForImageLoad(); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap second_icon = icon_manager.GetIcon(extension->id()); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(gfx::BitmapsAreEqual(second_icon, default_icon)); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(gfx::BitmapsAreEqual(first_icon, second_icon)); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(FILE_MANAGER_EXTENSION) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests loading an icon for a component extension. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ExtensionIconManagerTest, LoadComponentExtensionResource) { 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<Profile> profile(new TestingProfile()); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap default_icon = GetDefaultIcon(); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath test_dir; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath manifest_path = test_dir.AppendASCII( 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "extensions/file_manager/app.json"); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JSONFileValueSerializer serializer(manifest_path); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> manifest( 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<DictionaryValue*>(serializer.Deserialize(NULL, NULL))); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(manifest.get() != NULL); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string error; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<Extension> extension(Extension::Create( 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) manifest_path.DirName(), Manifest::COMPONENT, *manifest.get(), 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Extension::NO_FLAGS, &error)); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(extension.get()); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestIconManager icon_manager(this); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load the icon and grab the bitmap. 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_manager.LoadIcon(profile.get(), extension.get()); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WaitForImageLoad(); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap first_icon = icon_manager.GetIcon(extension->id()); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(gfx::BitmapsAreEqual(first_icon, default_icon)); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove the icon from the manager. 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_manager.RemoveIcon(extension->id()); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now re-load the icon - we should get the same result bitmap (and not the 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // default icon). 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_manager.LoadIcon(profile.get(), extension.get()); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WaitForImageLoad(); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap second_icon = icon_manager.GetIcon(extension->id()); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(gfx::BitmapsAreEqual(second_icon, default_icon)); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(gfx::BitmapsAreEqual(first_icon, second_icon)); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 184