chromium/ash/ambient/ui/ambient_slideshow_pixeltest.cc

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

#include <array>
#include <optional>
#include <tuple>

#include "ash/ambient/test/ambient_ash_test_base.h"
#include "ash/ambient/ui/media_string_view.h"
#include "ash/public/cpp/ambient/ambient_ui_model.h"
#include "ash/public/cpp/style/dark_light_mode_controller.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/test/pixel/ash_pixel_differ.h"
#include "ash/webui/personalization_app/mojom/personalization_app.mojom-shared.h"
#include "base/strings/strcat.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/constants/chromeos_features.h"
#include "services/media_session/public/cpp/media_metadata.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/display/display.h"

namespace ash {

namespace {

using TestParams = std::tuple<std::optional<media_session::MediaMetadata>,
                              /*dark_mode=*/bool,
                              /*rtl=*/bool,
                              /*jelly=*/bool>;

std::array<std::optional<media_session::MediaMetadata>, 3>
GetMediaMedataVariations() {
  media_session::MediaMetadata short_metadata;
  short_metadata.artist = u"artist";
  short_metadata.title = u"title";

  media_session::MediaMetadata long_metadata;
  long_metadata.artist = u"A super duper long artist name";
  long_metadata.title = u"A super duper long title";

  return {std::move(short_metadata), std::move(long_metadata), std::nullopt};
}

bool IsDarkMode(const TestParams& param) {
  return std::get<1>(param);
}

bool IsRtl(const TestParams& param) {
  return std::get<2>(param);
}

bool IsJellyEnabled(const TestParams& param) {
  return std::get<3>(param);
}

const std::optional<media_session::MediaMetadata>& GetMediaMetadata(
    const TestParams& param) {
  return std::get<std::optional<media_session::MediaMetadata>>(param);
}

std::string GetName(const testing::TestParamInfo<TestParams>& param_info) {
  const std::optional<media_session::MediaMetadata>& metadata =
      GetMediaMetadata(param_info.param);
  std::string metadata_description_text;
  if (!metadata.has_value()) {
    metadata_description_text = "Nomedia";
  } else if (metadata->artist == u"artist") {
    metadata_description_text = "Shortmedia";
  } else {
    metadata_description_text = "Longmedia";
  }
  std::vector<std::string> attributes = {
      metadata_description_text,
      IsDarkMode(param_info.param) ? "Dark" : "Light",
      IsRtl(param_info.param) ? "Rtl" : "Ltr"};
  if (!IsJellyEnabled(param_info.param)) {
    attributes.push_back("PreJelly");
  }
  return base::StrCat(attributes);
}

}  // namespace

class AmbientSlideshowPixelTest
    : public AmbientAshTestBase,
      public testing::WithParamInterface<TestParams> {
 public:
  std::optional<pixel_test::InitParams> CreatePixelTestInitParams()
      const override {
    pixel_test::InitParams pixel_test_init_params;
    pixel_test_init_params.under_rtl = IsRtl(GetParam());
    return pixel_test_init_params;
  }

  void SetUp() override {
    scoped_features_.InitWithFeatureState(chromeos::features::kJelly,
                                          IsJellyEnabled(GetParam()));
    AmbientAshTestBase::SetUp();
    SetAmbientTheme(personalization_app::mojom::AmbientTheme::kSlideshow);
    GetSessionControllerClient()->set_show_lock_screen_views(true);
    DarkLightModeController::Get()->SetDarkModeEnabledForTest(
        IsDarkMode(GetParam()));
    // Required for decoded image parameters below to exactly reflect what the
    // ambient photo pipeline produces.
    UseLosslessPhotoCompression(true);
    SetNextDecodedPhotoColor(SK_ColorGREEN);
    gfx::Size display_size = GetPrimaryDisplay().size();
    // Simplifies rendering to be consistent for pixel testing.
    SetDecodedPhotoSize(display_size.width(), display_size.height());
    // Set a very long photo refresh interval so the view we are looking
    // at does not animate out while screen capturing. By default two photo
    // views animate in/out to transition between photos every 60 seconds.
    AmbientUiModel::Get()->SetPhotoRefreshInterval(base::Hours(1));
    // Stop the clock and media info from moving around.
    DisableJitter();
  }

  void TearDown() override {
    CloseAmbientScreen();
    AmbientAshTestBase::TearDown();
  }

 private:
  base::test::ScopedFeatureList scoped_features_;
};

INSTANTIATE_TEST_SUITE_P(
    All,
    AmbientSlideshowPixelTest,
    testing::Combine(::testing::ValuesIn(GetMediaMedataVariations()),
                     testing::Bool(),
                     testing::Bool(),
                     testing::Bool()),
    &GetName);

TEST_P(AmbientSlideshowPixelTest, ShowMediaStringView) {
  SetAmbientShownAndWaitForWidgets();

  const std::optional<media_session::MediaMetadata>& media_metadata =
      GetMediaMetadata(GetParam());

  if (media_metadata.has_value()) {
    SimulateMediaMetadataChanged(media_metadata.value());
    SimulateMediaPlaybackStateChanged(
        media_session::mojom::MediaPlaybackState::kPlaying);
  }

  // Revision 1 is with Jelly enabled. Revision 0 is with Jelly disabled to
  // guard against regressions until the flag is fully launched.
  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
      "AmbientSlideshow",
      /*revision_number=*/IsJellyEnabled(GetParam()) ? 1 : 0,
      ash::Shell::GetPrimaryRootWindow()));
}

}  // namespace ash