chromium/chrome/browser/apps/app_service/app_icon/chrome_apps_icon_unittest.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>
#include <vector>

#include "base/barrier_callback.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/test/test_future.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_factory.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_test_util.h"
#include "chrome/browser/apps/icon_standardizer.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_service_test_base.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_constants.h"
#include "components/services/app_service/public/cpp/icon_types.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/image_loader.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_unittest_util.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/apps/app_service/app_icon/app_icon_decoder.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#endif

namespace apps {

const char kPackagedApp1Id[] =;

class ChromeAppsIconFactoryTest : public extensions::ExtensionServiceTestBase {};

TEST_F(ChromeAppsIconFactoryTest, LoadUncompressedIcon) {}

TEST_F(ChromeAppsIconFactoryTest, LoadStandardIcon) {}

TEST_F(ChromeAppsIconFactoryTest, LoadCompressedIcon) {}

TEST_F(ChromeAppsIconFactoryTest, LoadCompressedIconWithoutEffect) {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(ChromeAppsIconFactoryTest, GetCompressedIconData) {
  // Generate the source uncompressed icon for comparing.
  std::vector<uint8_t> src_data1;
  std::vector<uint8_t> src_data2;
  GenerateExtensionAppCompressedIcon(kPackagedApp1Id, /*scale=*/1.0, src_data1,
                                     /*skip_effects=*/true);
  GenerateExtensionAppCompressedIcon(kPackagedApp1Id, /*scale=*/2.0, src_data2,
                                     /*skip_effects=*/true);

  IconValuePtr icon1 = GetCompressedIconData(
      kPackagedApp1Id, ui::ResourceScaleFactor::k100Percent);
  IconValuePtr icon2 = GetCompressedIconData(
      kPackagedApp1Id, ui::ResourceScaleFactor::k200Percent);
  VerifyCompressedIcon(src_data1, *icon1);
  VerifyCompressedIcon(src_data2, *icon2);
}

class AppServiceChromeAppIconTest : public ChromeAppsIconFactoryTest {
 public:
  void SetUp() override {
    ChromeAppsIconFactoryTest::SetUp();

    proxy_ = AppServiceProxyFactory::GetForProfile(profile());
    fake_icon_loader_ = std::make_unique<apps::FakeIconLoader>(proxy_);
    OverrideAppServiceProxyInnerIconLoader(fake_icon_loader_.get());
  }

  void OverrideAppServiceProxyInnerIconLoader(apps::IconLoader* icon_loader) {
    app_service_proxy().OverrideInnerIconLoaderForTesting(icon_loader);
  }

  apps::IconValuePtr LoadIcon(const std::string& app_id, IconType icon_type) {
    base::test::TestFuture<apps::IconValuePtr> result;
    app_service_proxy().LoadIcon(app_id, icon_type, kSizeInDip,
                                 /*allow_placeholder_icon=*/false,
                                 result.GetCallback());
    return result.Take();
  }

  apps::IconValuePtr LoadIconWithIconEffects(const std::string& app_id,
                                             uint32_t icon_effects,
                                             IconType icon_type) {
    base::test::TestFuture<apps::IconValuePtr> result;
    app_service_proxy().LoadIconWithIconEffects(
        app_id, icon_effects, icon_type, kSizeInDip,
        /*allow_placeholder_icon=*/false, result.GetCallback());
    return result.Take();
  }

  // Call LoadIconWithIconEffects twice with the same parameters, to verify the
  // icon loading process can handle the icon loading request multiple times
  // with the same params.
  std::vector<apps::IconValuePtr> MultipleLoadIconWithIconEffects(
      const std::string& app_id,
      uint32_t icon_effects,
      IconType icon_type) {
    base::test::TestFuture<std::vector<apps::IconValuePtr>> result;
    auto barrier_callback =
        base::BarrierCallback<apps::IconValuePtr>(2, result.GetCallback());

    app_service_proxy().LoadIconWithIconEffects(
        app_id, icon_effects, icon_type, kSizeInDip,
        /*allow_placeholder_icon=*/false, barrier_callback);
    app_service_proxy().LoadIconWithIconEffects(
        app_id, icon_effects, icon_type, kSizeInDip,
        /*allow_placeholder_icon=*/false, barrier_callback);

    return result.Take();
  }

  AppServiceProxy& app_service_proxy() { return *proxy_; }

 private:
  raw_ptr<AppServiceProxy> proxy_;
  std::unique_ptr<apps::FakeIconLoader> fake_icon_loader_;
  data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
};

TEST_F(AppServiceChromeAppIconTest, GetCompressedIconDataForCompressedIcon) {
  // Generate the source compressed icon for comparing.
  std::vector<uint8_t> src_data;
  GenerateExtensionAppCompressedIcon(kPackagedApp1Id, /*scale=*/1.0, src_data,
                                     /*skip_effects=*/true);

  // Verify the icon reading and writing function in AppService for the
  // compressed icon.
  VerifyCompressedIcon(src_data,
                       *LoadIcon(kPackagedApp1Id, IconType::kCompressed));
}

TEST_F(AppServiceChromeAppIconTest, GetCompressedIconDataForStandardIcon) {
  // Generate the source uncompressed icon for comparing.
  gfx::ImageSkia src_image_skia;
  GenerateExtensionAppIcon(kPackagedApp1Id, src_image_skia);

  // Verify the icon reading and writing function in AppService for the
  // kStandard icon.
  auto ret = MultipleLoadIconWithIconEffects(
      kPackagedApp1Id, IconEffects::kCrOsStandardIcon, IconType::kStandard);

  ASSERT_EQ(2U, ret.size());
  ASSERT_EQ(apps::IconType::kStandard, ret[0]->icon_type);
  VerifyIcon(src_image_skia, ret[0]->uncompressed);
  ASSERT_EQ(apps::IconType::kStandard, ret[1]->icon_type);
  VerifyIcon(src_image_skia, ret[1]->uncompressed);
}

TEST_F(AppServiceChromeAppIconTest, GetCompressedIconDataForUncompressedIcon) {
  // Generate the source uncompressed icon for comparing.
  gfx::ImageSkia src_image_skia;
  GenerateExtensionAppIcon(kPackagedApp1Id, src_image_skia,
                           /*skip_effects=*/true);

  // Verify the icon reading and writing function in AppService for the
  // kUncompressed icon.
  auto ret = LoadIconWithIconEffects(kPackagedApp1Id, IconEffects::kNone,
                                     IconType::kUncompressed);

  ASSERT_EQ(apps::IconType::kUncompressed, ret->icon_type);
  VerifyIcon(src_image_skia, ret->uncompressed);
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

}  // namespace apps