Chromium Code Reviews| Index: chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image_unittest.cc |
| diff --git a/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image_unittest.cc b/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d109dd14d769ad84cb526afe866daaf8d61044e6 |
| --- /dev/null |
| +++ b/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image_unittest.cc |
| @@ -0,0 +1,255 @@ |
| +// Copyright 2015 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/ui/app_list/search/launcher_search/extension_badged_icon_image.h" |
| + |
| +#include "chrome/browser/chromeos/launcher_search_provider/error_reporter.h" |
| +#include "extensions/common/manifest_constants.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "ui/gfx/canvas.h" |
| +#include "ui/gfx/geometry/rect.h" |
| +#include "ui/gfx/geometry/size.h" |
| +#include "ui/gfx/image/canvas_image_source.h" |
| +#include "ui/gfx/image/image_skia.h" |
| +#include "ui/gfx/image/image_unittest_util.h" |
| +#include "url/gurl.h" |
| + |
| +using chromeos::launcher_search_provider::ErrorReporter; |
| + |
| +namespace app_list { |
| +namespace { |
|
Matt Giuca
2015/05/05 04:25:30
nit: blank line above
yawano
2015/05/07 06:24:55
Done.
|
| + |
| +const char kFakeExtensionId[] = "foo"; |
|
Matt Giuca
2015/05/05 04:25:30
kTestExtensionId
kTestCustomIconURL
yawano
2015/05/07 06:24:55
Done.
|
| +const char kFakeCustomIconURL[] = "chrome-extension://foo/bar"; |
| + |
| +// Generates badged image source. This image source generates following image. |
| +// # |primary_fill_color| |
|
Matt Giuca
2015/05/05 04:25:30
I found it pretty hard to understand this comment
yawano
2015/05/07 06:24:55
Done.
|
| +// * |secondary_fill_color| |
| +// |
| +// ### |
| +// #** |
| +// #** |
| +class BadgedImageSource : public gfx::CanvasImageSource { |
| + public: |
| + BadgedImageSource(const gfx::Size& image_size, |
| + const SkColor primary_fill_color) |
| + : CanvasImageSource(image_size, false), |
| + primary_fill_color_(primary_fill_color), |
| + secondary_fill_color_(SK_ColorTRANSPARENT) {} |
| + |
| + BadgedImageSource(const gfx::Size& image_size, |
| + const SkColor primary_fill_color, |
| + const SkColor secondary_fill_color) |
| + : CanvasImageSource(image_size, false), |
| + primary_fill_color_(primary_fill_color), |
| + secondary_fill_color_(secondary_fill_color) {} |
| + |
| + void Draw(gfx::Canvas* canvas) override { |
| + canvas->FillRect(gfx::Rect(size()), primary_fill_color_); |
| + |
| + const int badge_dimension = size().width() * 2 / 3; |
| + const int offset = size().width() - badge_dimension; |
| + canvas->FillRect( |
| + gfx::Rect(offset, offset, badge_dimension, badge_dimension), |
| + secondary_fill_color_); |
| + } |
| + |
| + private: |
| + const SkColor primary_fill_color_; |
| + const SkColor secondary_fill_color_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(BadgedImageSource); |
| +}; |
| + |
| +// Test implementation of ExtensionBadgedIconImage. |
| +class ExtensionBadgedIconImageTestImpl : public ExtensionBadgedIconImage { |
| + public: |
| + using ExtensionBadgedIconImage::ExtensionBadgedIconImage; // Use base class |
|
Matt Giuca
2015/05/05 04:25:30
Nit: Don't wrap inline comments like this, just pl
yawano
2015/05/07 06:24:55
Done.
|
| + // constructor. |
| + |
| + const gfx::ImageSkia& LoadExtensionIcon() override { |
| + // Returns 32x32 black image. |
| + extension_icon_ = gfx::ImageSkia( |
| + new BadgedImageSource(icon_size_, SK_ColorBLACK), icon_size_); |
| + return extension_icon_; |
| + } |
| + |
| + // Calls OnExtensionIconImageChnaged callback with |extension_icon|. |
| + void LoadExtensionIconAsync(const gfx::ImageSkia& image) { |
| + OnExtensionIconChanged(image); |
| + } |
| + |
| + void LoadExtensionIconResource() override { |
| + // For success case, returns 32x32 blue image. |
| + is_load_extension_icon_resource_called_ = true; |
| + } |
| + |
| + bool IsLoadExtensionIconResourceCalled() const { |
| + return is_load_extension_icon_resource_called_; |
| + } |
| + |
| + // Calls OnCustomIconLoaded callback with |custom_icon|. Sets an empty image |
| + // for simulating a failure case. |
| + void CallOnCustomIconLoaded(gfx::ImageSkia custom_icon) { |
| + OnCustomIconLoaded(custom_icon); |
| + } |
| + |
| + private: |
| + gfx::ImageSkia extension_icon_; |
| + bool is_load_extension_icon_resource_called_ = false; |
| +}; |
| + |
| +// Mocks error reporter to test error message. |
| +class MockErrorReporter : public ErrorReporter { |
|
Matt Giuca
2015/05/05 04:25:30
nit: This is a fake, not a mock. FakeErrorReporter
yawano
2015/05/07 06:24:55
Done.
|
| + public: |
| + MockErrorReporter() : ErrorReporter(nullptr, -1) {} |
| + void Warn(const std::string& message) override { last_message_ = message; } |
| + |
| + const std::string& GetLastWarningMessage() { return last_message_; } |
| + |
| + protected: |
| + ~MockErrorReporter() override {} |
| + |
| + private: |
| + std::string last_message_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MockErrorReporter); |
| +}; |
| + |
| +// Creates a fake extension with |extension_id|. |
| +scoped_refptr<extensions::Extension> CreateFakeExtension( |
|
Matt Giuca
2015/05/05 04:25:30
CreateTestExtension
(It's not a fake extension, i
yawano
2015/05/07 06:24:55
Done.
|
| + const std::string& extension_id) { |
| + base::DictionaryValue manifest; |
| + std::string error; |
| + manifest.SetStringWithoutPathExpansion(extensions::manifest_keys::kVersion, |
| + "1"); |
| + manifest.SetStringWithoutPathExpansion(extensions::manifest_keys::kName, |
| + "FakeExtension"); |
| + return extensions::Extension::Create( |
| + base::FilePath(), extensions::Manifest::UNPACKED, manifest, |
| + extensions::Extension::NO_FLAGS, extension_id, &error); |
| +} |
| + |
| +// Returns true if icon image of |badged_icon_image| equals to |expected_image|. |
| +bool IsEqual(const gfx::ImageSkia& expected_image, |
| + const ExtensionBadgedIconImage& badged_icon_image) { |
| + return gfx::test::IsEqual( |
| + expected_image.GetRepresentation(1.0).sk_bitmap(), |
| + badged_icon_image.GetIconImage().GetRepresentation(1.0).sk_bitmap()); |
| +} |
| + |
| +} // namespace |
| + |
| +class ExtensionBadgedIconImageTest : public testing::Test { |
| + protected: |
| + void SetUp() override { |
| + extension_ = CreateFakeExtension(kFakeExtensionId); |
| + error_reporter_ = new MockErrorReporter(); |
| + } |
| + |
| + scoped_refptr<extensions::Extension> extension_; |
| + scoped_refptr<MockErrorReporter> error_reporter_; |
| +}; |
| + |
| +TEST_F(ExtensionBadgedIconImageTest, WithoutCustomIconSuccessCase) { |
| + GURL icon_url; |
|
Matt Giuca
2015/05/05 04:25:30
GURL icon_url; // No custom icon.
(Add this comm
yawano
2015/05/07 06:24:55
Done.
|
| + ExtensionBadgedIconImageTestImpl impl(icon_url /* no custom icon*/, nullptr, |
| + nullptr, 32, error_reporter_); |
| + impl.LoadResources(); |
| + |
| + // Icon should be black image. |
| + gfx::Size icon_size(32, 32); |
| + gfx::ImageSkia expected_image(new BadgedImageSource(icon_size, SK_ColorBLACK), |
| + icon_size); |
| + ASSERT_TRUE(IsEqual(expected_image, impl)); |
| +} |
| + |
| +TEST_F(ExtensionBadgedIconImageTest, ExtensionIconAsyncLoadSuccessCase) { |
| + GURL icon_url; |
| + ExtensionBadgedIconImageTestImpl impl(icon_url /* no custom icon */, nullptr, |
| + nullptr, 32, error_reporter_); |
| + impl.LoadResources(); |
| + |
| + // Extension icon is loaded as async. |
| + gfx::Size icon_size(32, 32); |
| + gfx::ImageSkia extension_icon(new BadgedImageSource(icon_size, SK_ColorGREEN), |
| + icon_size); |
| + impl.LoadExtensionIconAsync(extension_icon); |
| + |
| + gfx::ImageSkia expected_image(new BadgedImageSource(icon_size, SK_ColorGREEN), |
| + icon_size); |
| + ASSERT_TRUE(IsEqual(expected_image, impl)); |
| +} |
| + |
| +TEST_F(ExtensionBadgedIconImageTest, WithCustomIconSuccessCase) { |
| + GURL icon_url(kFakeCustomIconURL); |
| + ExtensionBadgedIconImageTestImpl impl(icon_url, nullptr, extension_.get(), 32, |
| + error_reporter_); |
| + ASSERT_FALSE(impl.IsLoadExtensionIconResourceCalled()); |
| + impl.LoadResources(); |
| + |
| + // Asserts that LoadExtensionIconResource is called. |
| + ASSERT_TRUE(impl.IsLoadExtensionIconResourceCalled()); |
| + |
| + // Load custom icon as async. |
| + gfx::Size icon_size(32, 32); |
| + gfx::ImageSkia custom_icon(new BadgedImageSource(icon_size, SK_ColorGREEN), |
| + icon_size); |
| + impl.CallOnCustomIconLoaded(custom_icon); |
| + |
| + gfx::ImageSkia expected_image( |
| + new BadgedImageSource(icon_size, SK_ColorGREEN, SK_ColorBLACK), |
| + icon_size); |
| + ASSERT_TRUE(IsEqual(expected_image, impl)); |
| +} |
| + |
| +TEST_F(ExtensionBadgedIconImageTest, InvalidCustomIconUrl) { |
| + std::string invalid_url = |
|
Matt Giuca
2015/05/05 04:25:30
// Use a really long URL (for testing the string t
yawano
2015/05/07 06:24:55
Done.
|
| + "chrome-extension://foo2/bar/" |
| + "901234567890123456789012345678901234567890123456789012345678901234567890" |
| + "1"; |
| + ASSERT_EQ(101U, invalid_url.size()); |
| + |
| + GURL icon_url(invalid_url); |
| + ExtensionBadgedIconImageTestImpl impl(icon_url, nullptr, extension_.get(), 32, |
| + error_reporter_); |
| + impl.LoadResources(); |
| + |
| + // Warning message should be provided. |
| + ASSERT_EQ( |
| + "[chrome.launcherSearchProvider.setSearchResults] Invalid icon URL: " |
| + "chrome-extension://foo2/bar/" |
| + "901234567890123456789012345678901234567890123456789012345678901234567..." |
| + ". Must have a valid URL within chrome-extension://foo.", |
| + error_reporter_->GetLastWarningMessage()); |
| + |
| + // LoadExtensionIconResource should not be called. |
| + ASSERT_FALSE(impl.IsLoadExtensionIconResourceCalled()); |
| +} |
| + |
| +TEST_F(ExtensionBadgedIconImageTest, FailedToLoadCustomIcon) { |
| + GURL icon_url(kFakeCustomIconURL); |
| + ExtensionBadgedIconImageTestImpl impl(icon_url, nullptr, extension_.get(), 32, |
| + error_reporter_); |
| + impl.LoadResources(); |
| + ASSERT_TRUE(impl.IsLoadExtensionIconResourceCalled()); |
| + |
| + // Fails to load custom icon by passing an empty image. |
| + gfx::ImageSkia custom_icon; |
| + impl.CallOnCustomIconLoaded(custom_icon); |
| + |
| + // Warning message should be shown. |
| + ASSERT_EQ( |
| + "[chrome.launcherSearchProvider.setSearchResults] Failed to load icon " |
| + "URL: chrome-extension://foo/bar", |
| + error_reporter_->GetLastWarningMessage()); |
| + |
| + // Icon should be extension icon. |
| + gfx::Size icon_size(32, 32); |
| + gfx::ImageSkia expected_image(new BadgedImageSource(icon_size, SK_ColorBLACK), |
| + icon_size); |
| + ASSERT_TRUE(IsEqual(expected_image, impl)); |
| +} |
| + |
| +} // namespace app_list |