Commit f2305334 authored by nancylingwang's avatar nancylingwang Committed by Commit Bot

Add load icon unit tests.

This CL adds unit tests to verify:
1. Loading compressed icons.
2. Loading icons from the resource.
3. Loading icons from the compressed data.

BUG=1083331

Change-Id: I35d0ff87e7f8a1f5099408f194572b3c527b3213
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2418692Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Commit-Queue: Nancy Wang <nancylingwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808897}
parent 73c03a58
...@@ -36,12 +36,15 @@ ...@@ -36,12 +36,15 @@
#include "extensions/grit/extensions_browser_resources.h" #include "extensions/grit/extensions_browser_resources.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/layout.h" #include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_unittest_util.h" #include "ui/gfx/image/image_unittest_util.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/arc/icon_decode_request.h" #include "chrome/browser/chromeos/arc/icon_decode_request.h"
#include "chrome/browser/ui/app_list/icon_standardizer.h" #include "chrome/browser/ui/app_list/icon_standardizer.h"
#include "chrome/grit/chrome_unscaled_resources.h"
#include "components/arc/mojom/intent_helper.mojom.h" #include "components/arc/mojom/intent_helper.mojom.h"
#endif #endif
...@@ -91,6 +94,17 @@ void VerifyIcon(const gfx::ImageSkia& src, const gfx::ImageSkia& dst) { ...@@ -91,6 +94,17 @@ void VerifyIcon(const gfx::ImageSkia& src, const gfx::ImageSkia& dst) {
} }
} }
void VerifyCompressedIcon(const std::vector<uint8_t>& src_data,
apps::mojom::IconValuePtr& icon) {
ASSERT_FALSE(icon.is_null());
ASSERT_EQ(apps::mojom::IconType::kCompressed, icon->icon_type);
ASSERT_FALSE(icon->is_placeholder_icon);
ASSERT_TRUE(icon->compressed.has_value());
ASSERT_FALSE(icon->compressed.value().empty());
ASSERT_EQ(src_data, icon->compressed.value());
}
} // namespace } // namespace
class AppIconFactoryTest : public testing::Test { class AppIconFactoryTest : public testing::Test {
...@@ -147,6 +161,87 @@ class AppIconFactoryTest : public testing::Test { ...@@ -147,6 +161,87 @@ class AppIconFactoryTest : public testing::Test {
return png_data_as_string; return png_data_as_string;
} }
void RunLoadIconFromCompressedData(const std::string png_data_as_string,
apps::mojom::IconType icon_type,
apps::IconEffects icon_effects,
apps::mojom::IconValuePtr& output_icon) {
apps::LoadIconFromCompressedData(
icon_type, kSizeInDip, icon_effects, png_data_as_string,
base::BindOnce(
[](apps::mojom::IconValuePtr* result,
base::OnceClosure load_app_icon_callback,
apps::mojom::IconValuePtr icon) {
*result = std::move(icon);
std::move(load_app_icon_callback).Run();
},
&output_icon, run_loop_.QuitClosure()));
run_loop_.Run();
ASSERT_FALSE(output_icon.is_null());
ASSERT_EQ(icon_type, output_icon->icon_type);
ASSERT_FALSE(output_icon->is_placeholder_icon);
ASSERT_FALSE(output_icon->uncompressed.isNull());
EnsureRepresentationsLoaded(output_icon->uncompressed);
}
void GenerateIconFromCompressedData(const std::string& compressed_icon,
float scale,
gfx::ImageSkia& output_image_skia) {
std::vector<uint8_t> compressed_data(compressed_icon.begin(),
compressed_icon.end());
SkBitmap decoded;
ASSERT_TRUE(gfx::PNGCodec::Decode(compressed_data.data(),
compressed_data.size(), &decoded));
output_image_skia = gfx::ImageSkia(gfx::ImageSkiaRep(decoded, scale));
#if defined(OS_CHROMEOS)
if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
output_image_skia = app_list::CreateStandardIconImage(output_image_skia);
}
#endif
EnsureRepresentationsLoaded(output_image_skia);
}
#if defined(OS_CHROMEOS)
void RunLoadIconFromResource(apps::mojom::IconType icon_type,
apps::IconEffects icon_effects,
apps::mojom::IconValuePtr& output_icon) {
bool is_placeholder_icon = false;
apps::LoadIconFromResource(icon_type, kSizeInDip,
IDR_LOGO_CROSTINI_DEFAULT_192,
is_placeholder_icon, icon_effects,
base::BindOnce(
[](apps::mojom::IconValuePtr* result,
base::OnceClosure load_app_icon_callback,
apps::mojom::IconValuePtr icon) {
*result = std::move(icon);
std::move(load_app_icon_callback).Run();
},
&output_icon, run_loop_.QuitClosure()));
run_loop_.Run();
}
void GenerateCrostiniPenguinIcon(gfx::ImageSkia& output_image_skia) {
output_image_skia =
*(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_LOGO_CROSTINI_DEFAULT_192));
output_image_skia = gfx::ImageSkiaOperations::CreateResizedImage(
output_image_skia, skia::ImageOperations::RESIZE_BEST,
gfx::Size(kSizeInDip, kSizeInDip));
EnsureRepresentationsLoaded(output_image_skia);
}
void GenerateCrostiniPenguinCompressedIcon(std::vector<uint8_t>& output) {
base::StringPiece data =
ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_LOGO_CROSTINI_DEFAULT_192);
output = std::vector<uint8_t>(data.begin(), data.end());
}
#endif
protected: protected:
content::BrowserTaskEnvironment task_env_{}; content::BrowserTaskEnvironment task_env_{};
base::ScopedTempDir tmp_dir_{}; base::ScopedTempDir tmp_dir_{};
...@@ -230,7 +325,72 @@ TEST_F(AppIconFactoryTest, LoadFromFileFallbackDoesNotReturn) { ...@@ -230,7 +325,72 @@ TEST_F(AppIconFactoryTest, LoadFromFileFallbackDoesNotReturn) {
EXPECT_FALSE(result.is_null()); EXPECT_FALSE(result.is_null());
} }
TEST_F(AppIconFactoryTest, LoadIconFromCompressedData) {
std::string png_data_as_string = GetPngData("icon_100p.png");
auto icon_type = apps::mojom::IconType::kUncompressed;
auto icon_effects = apps::IconEffects::kNone;
if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
icon_type = apps::mojom::IconType::kStandard;
icon_effects = apps::IconEffects::kCrOsStandardIcon;
}
apps::mojom::IconValuePtr result;
RunLoadIconFromCompressedData(png_data_as_string, icon_type, icon_effects,
result);
float scale = 1.0;
gfx::ImageSkia src_image_skia;
GenerateIconFromCompressedData(png_data_as_string, scale, src_image_skia);
ASSERT_FALSE(src_image_skia.isNull());
ASSERT_TRUE(src_image_skia.HasRepresentation(scale));
ASSERT_TRUE(result->uncompressed.HasRepresentation(scale));
ASSERT_TRUE(gfx::test::AreBitmapsEqual(
src_image_skia.GetRepresentation(scale).GetBitmap(),
result->uncompressed.GetRepresentation(scale).GetBitmap()));
}
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
TEST_F(AppIconFactoryTest, LoadCrostiniPenguinIcon) {
auto icon_type = apps::mojom::IconType::kUncompressed;
auto icon_effects = apps::IconEffects::kNone;
if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
icon_type = apps::mojom::IconType::kStandard;
icon_effects = apps::IconEffects::kCrOsStandardIcon;
}
apps::mojom::IconValuePtr result;
RunLoadIconFromResource(icon_type, icon_effects, result);
EXPECT_FALSE(result.is_null());
EXPECT_EQ(icon_type, result->icon_type);
EXPECT_FALSE(result->is_placeholder_icon);
EnsureRepresentationsLoaded(result->uncompressed);
gfx::ImageSkia src_image_skia;
GenerateCrostiniPenguinIcon(src_image_skia);
VerifyIcon(src_image_skia, result->uncompressed);
}
TEST_F(AppIconFactoryTest, LoadCrostiniPenguinCompressedIcon) {
auto icon_effects = apps::IconEffects::kNone;
if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
icon_effects = apps::IconEffects::kCrOsStandardIcon;
}
apps::mojom::IconValuePtr result;
RunLoadIconFromResource(apps::mojom::IconType::kCompressed, icon_effects,
result);
std::vector<uint8_t> src_data;
GenerateCrostiniPenguinCompressedIcon(src_data);
VerifyCompressedIcon(src_data, result);
}
TEST_F(AppIconFactoryTest, ArcNonAdaptiveIconToImageSkia) { TEST_F(AppIconFactoryTest, ArcNonAdaptiveIconToImageSkia) {
arc::IconDecodeRequest::DisableSafeDecodingForTesting(); arc::IconDecodeRequest::DisableSafeDecodingForTesting();
std::string png_data_as_string = GetPngData("icon_100p.png"); std::string png_data_as_string = GetPngData("icon_100p.png");
...@@ -472,6 +632,26 @@ class WebAppIconFactoryTest : public ChromeRenderViewHostTestHarness { ...@@ -472,6 +632,26 @@ class WebAppIconFactoryTest : public ChromeRenderViewHostTestHarness {
EnsureRepresentationsLoaded(output_image_skia); EnsureRepresentationsLoaded(output_image_skia);
} }
void GenerateWebAppCompressedIcon(const std::string& app_id,
IconPurpose purpose,
const std::vector<int>& sizes_px,
apps::ScaleToSize scale_to_size_in_px,
std::vector<uint8_t>& result) {
gfx::ImageSkia image_skia;
GenerateWebAppIcon(app_id, purpose, sizes_px, scale_to_size_in_px,
image_skia);
const float scale = 1.0;
const gfx::ImageSkiaRep& image_skia_rep =
image_skia.GetRepresentation(scale);
ASSERT_EQ(image_skia_rep.scale(), scale);
const SkBitmap& bitmap = image_skia_rep.GetBitmap();
const bool discard_transparency = false;
ASSERT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, discard_transparency,
&result));
}
void LoadIconFromWebApp(const std::string& app_id, void LoadIconFromWebApp(const std::string& app_id,
apps::IconEffects icon_effects, apps::IconEffects icon_effects,
gfx::ImageSkia& output_image_skia) { gfx::ImageSkia& output_image_skia) {
...@@ -498,6 +678,25 @@ class WebAppIconFactoryTest : public ChromeRenderViewHostTestHarness { ...@@ -498,6 +678,25 @@ class WebAppIconFactoryTest : public ChromeRenderViewHostTestHarness {
EnsureRepresentationsLoaded(output_image_skia); EnsureRepresentationsLoaded(output_image_skia);
} }
void LoadCompressedIconBlockingFromWebApp(
const std::string& app_id,
apps::IconEffects icon_effects,
apps::mojom::IconValuePtr& output_data) {
base::RunLoop run_loop;
apps::LoadIconFromWebApp(profile(), apps::mojom::IconType::kCompressed,
kSizeInDip, app_id, icon_effects,
base::BindOnce(
[](apps::mojom::IconValuePtr* result,
base::OnceClosure load_app_icon_callback,
apps::mojom::IconValuePtr icon) {
*result = std::move(icon);
std::move(load_app_icon_callback).Run();
},
&output_data, run_loop.QuitClosure()));
run_loop.Run();
}
web_app::WebAppIconManager& icon_manager() { return *icon_manager_; } web_app::WebAppIconManager& icon_manager() { return *icon_manager_; }
web_app::WebAppProvider& web_app_provider() { return *web_app_provider_; } web_app::WebAppProvider& web_app_provider() { return *web_app_provider_; }
...@@ -538,6 +737,35 @@ TEST_F(WebAppIconFactoryTest, LoadNonMaskableIcon) { ...@@ -538,6 +737,35 @@ TEST_F(WebAppIconFactoryTest, LoadNonMaskableIcon) {
VerifyIcon(src_image_skia, dst_image_skia); VerifyIcon(src_image_skia, dst_image_skia);
} }
TEST_F(WebAppIconFactoryTest, LoadNonMaskableCompressedIcon) {
auto web_app = CreateWebApp();
const std::string app_id = web_app->app_id();
const int kIconSize1 = 96;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
std::vector<uint8_t> src_data;
GenerateWebAppCompressedIcon(app_id, IconPurpose::ANY, sizes_px,
{{1.0, kIconSize1}, {2.0, kIconSize2}},
src_data);
apps::mojom::IconValuePtr icon;
LoadCompressedIconBlockingFromWebApp(
app_id,
apps::IconEffects::kRoundCorners | apps::IconEffects::kCrOsStandardIcon,
icon);
VerifyCompressedIcon(src_data, icon);
}
TEST_F(WebAppIconFactoryTest, LoadMaskableIcon) { TEST_F(WebAppIconFactoryTest, LoadMaskableIcon) {
auto web_app = CreateWebApp(); auto web_app = CreateWebApp();
const std::string app_id = web_app->app_id(); const std::string app_id = web_app->app_id();
...@@ -582,6 +810,52 @@ TEST_F(WebAppIconFactoryTest, LoadMaskableIcon) { ...@@ -582,6 +810,52 @@ TEST_F(WebAppIconFactoryTest, LoadMaskableIcon) {
VerifyIcon(src_image_skia, dst_image_skia); VerifyIcon(src_image_skia, dst_image_skia);
} }
TEST_F(WebAppIconFactoryTest, LoadMaskableCompressedIcon) {
auto web_app = CreateWebApp();
const std::string app_id = web_app->app_id();
const int kIconSize1 = 128;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
WriteIcons(app_id, {IconPurpose::ANY, IconPurpose::MASKABLE}, sizes_px,
colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, {kIconSize1});
web_app->SetDownloadedIconSizes(IconPurpose::MASKABLE, {kIconSize2});
RegisterApp(std::move(web_app));
std::vector<uint8_t> src_data;
apps::mojom::IconValuePtr icon;
#if defined(OS_CHROMEOS)
ASSERT_TRUE(
icon_manager().HasIcons(app_id, IconPurpose::MASKABLE, {kIconSize2}));
GenerateWebAppCompressedIcon(app_id, IconPurpose::MASKABLE, {kIconSize2},
{{1.0, kIconSize2}, {2.0, kIconSize2}},
src_data);
LoadCompressedIconBlockingFromWebApp(
app_id,
apps::IconEffects::kRoundCorners |
apps::IconEffects::kCrOsStandardBackground |
apps::IconEffects::kCrOsStandardMask,
icon);
#else
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, {kIconSize1}));
GenerateWebAppCompressedIcon(app_id, IconPurpose::ANY, {kIconSize1},
{{1.0, kIconSize1}, {2.0, kIconSize1}},
src_data);
LoadCompressedIconBlockingFromWebApp(app_id, apps::IconEffects::kRoundCorners,
icon);
#endif
VerifyCompressedIcon(src_data, icon);
}
TEST_F(WebAppIconFactoryTest, LoadNonMaskableIconWithMaskableIcon) { TEST_F(WebAppIconFactoryTest, LoadNonMaskableIconWithMaskableIcon) {
auto web_app = CreateWebApp(); auto web_app = CreateWebApp();
const std::string app_id = web_app->app_id(); const std::string app_id = web_app->app_id();
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_unittest_util.h" #include "ui/gfx/image/image_unittest_util.h"
...@@ -284,6 +285,22 @@ class ExtensionAppTest : public AppServiceAppModelBuilderTest { ...@@ -284,6 +285,22 @@ class ExtensionAppTest : public AppServiceAppModelBuilderTest {
output_image_skia = app_list::CreateStandardIconImage(output_image_skia); output_image_skia = app_list::CreateStandardIconImage(output_image_skia);
} }
void GenerateExtensionAppCompressedIcon(const std::string app_id,
std::vector<uint8_t>& result) {
gfx::ImageSkia image_skia;
GenerateExtensionAppIcon(app_id, image_skia);
const float scale = 1.0;
const gfx::ImageSkiaRep& image_skia_rep =
image_skia.GetRepresentation(scale);
ASSERT_EQ(image_skia_rep.scale(), scale);
const SkBitmap& bitmap = image_skia_rep.GetBitmap();
const bool discard_transparency = false;
ASSERT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, discard_transparency,
&result));
}
std::vector<std::string> default_apps_; std::vector<std::string> default_apps_;
}; };
...@@ -577,6 +594,41 @@ TEST_P(ExtensionAppTest, LoadIcon) { ...@@ -577,6 +594,41 @@ TEST_P(ExtensionAppTest, LoadIcon) {
VerifyIcon(src_image_skia, item->icon()); VerifyIcon(src_image_skia, item->icon());
} }
TEST_P(ExtensionAppTest, LoadCompressedIcon) {
// Generate the source icon for comparing.
std::vector<uint8_t> src_data;
GenerateExtensionAppCompressedIcon(kPackagedApp1Id, src_data);
apps::IconEffects icon_effects =
(base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon))
? apps::IconEffects::kCrOsStandardIcon
: apps::IconEffects::kNone;
base::RunLoop run_loop;
apps::mojom::IconValuePtr dst_icon;
apps::LoadIconFromExtension(
apps::mojom::IconType::kCompressed,
ash::AppListConfig::instance().grid_icon_dimension(), profile(),
kPackagedApp1Id, icon_effects,
base::BindOnce(
[](apps::mojom::IconValuePtr* output_icon,
base::OnceClosure load_app_icon_callback,
apps::mojom::IconValuePtr icon) {
*output_icon = std::move(icon);
std::move(load_app_icon_callback).Run();
},
&dst_icon, run_loop.QuitClosure()));
run_loop.Run();
ASSERT_FALSE(dst_icon.is_null());
ASSERT_EQ(apps::mojom::IconType::kCompressed, dst_icon->icon_type);
ASSERT_FALSE(dst_icon->is_placeholder_icon);
ASSERT_TRUE(dst_icon->compressed.has_value());
ASSERT_FALSE(dst_icon->compressed.value().empty());
ASSERT_EQ(src_data, dst_icon->compressed.value());
}
// This test adds a bookmark app to the app list. // This test adds a bookmark app to the app list.
TEST_P(BookmarkAppBuilderTest, BookmarkAppList) { TEST_P(BookmarkAppBuilderTest, BookmarkAppList) {
const std::string kAppName = "Bookmark App"; const std::string kAppName = "Bookmark App";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment