chromium/ash/metrics/desktop_task_switch_metric_recorder_unittest.cc

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

#include "ash/metrics/desktop_task_switch_metric_recorder.h"

#include <memory>

#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/test/metrics/user_action_tester.h"
#include "ui/aura/client/window_types.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer_type.h"
#include "ui/events/test/event_generator.h"
#include "ui/wm/public/activation_client.h"

using wm::ActivationChangeObserver;

namespace ash {
namespace {

const char kDesktopTaskSwitchUserAction[] = "Desktop_SwitchTask";

// Test fixture for the DesktopTaskSwitchMetricsRecorder class. NOTE: This
// fixture extends AshTestBase so that the UserMetricsRecorder instance required
// by the test target can be obtained through Shell::Get()->metrics() and the
// test target is not the same instance as the one owned by the
// UserMetricsRecorder instance.
class DesktopTaskSwitchMetricRecorderTest : public AshTestBase {
 public:
  DesktopTaskSwitchMetricRecorderTest();

  DesktopTaskSwitchMetricRecorderTest(
      const DesktopTaskSwitchMetricRecorderTest&) = delete;
  DesktopTaskSwitchMetricRecorderTest& operator=(
      const DesktopTaskSwitchMetricRecorderTest&) = delete;

  ~DesktopTaskSwitchMetricRecorderTest() override;

  // AshTestBase:
  void SetUp() override;
  void TearDown() override;

  // Resets the recorded user action counts.
  void ResetActionCounts();

  // Returns the number of times the "Desktop_SwitchTask" user action was
  // recorded.
  int GetActionCount() const;

  // Creates a positionable window such that
  // window_util::IsWindowUserPositionable(...) would return true.
  std::unique_ptr<aura::Window> CreatePositionableWindow() const;

  // Creates a non-positionable window such that
  // window_util::IsWindowUserPositionable(...) would return false.
  std::unique_ptr<aura::Window> CreateNonPositionableWindow() const;

  // Wrapper to notify the test target's OnWindowActivated(...) method that
  // |window| was activated due to an INPUT_EVENT.
  void ActiveTaskWindowWithUserInput(aura::Window* window);

 protected:
  // Records UMA user action counts.
  std::unique_ptr<base::UserActionTester> user_action_tester_;

  // The test target.
  std::unique_ptr<DesktopTaskSwitchMetricRecorder> metrics_recorder_;
};

DesktopTaskSwitchMetricRecorderTest::DesktopTaskSwitchMetricRecorderTest() =
    default;

DesktopTaskSwitchMetricRecorderTest::~DesktopTaskSwitchMetricRecorderTest() =
    default;

void DesktopTaskSwitchMetricRecorderTest::SetUp() {
  AshTestBase::SetUp();
  metrics_recorder_ = std::make_unique<DesktopTaskSwitchMetricRecorder>();
  user_action_tester_ = std::make_unique<base::UserActionTester>();
}

void DesktopTaskSwitchMetricRecorderTest::TearDown() {
  user_action_tester_.reset();
  metrics_recorder_.reset();
  AshTestBase::TearDown();
}

void DesktopTaskSwitchMetricRecorderTest::ActiveTaskWindowWithUserInput(
    aura::Window* window) {
  metrics_recorder_->OnWindowActivated(
      ActivationChangeObserver::ActivationReason::INPUT_EVENT, window, nullptr);
}

void DesktopTaskSwitchMetricRecorderTest::ResetActionCounts() {
  user_action_tester_->ResetCounts();
}

int DesktopTaskSwitchMetricRecorderTest::GetActionCount() const {
  return user_action_tester_->GetActionCount(kDesktopTaskSwitchUserAction);
}

std::unique_ptr<aura::Window>
DesktopTaskSwitchMetricRecorderTest::CreatePositionableWindow() const {
  std::unique_ptr<aura::Window> window = std::make_unique<aura::Window>(
      aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate());
  window->SetType(aura::client::WINDOW_TYPE_NORMAL);
  window->Init(ui::LAYER_NOT_DRAWN);
  return window;
}

std::unique_ptr<aura::Window>
DesktopTaskSwitchMetricRecorderTest::CreateNonPositionableWindow() const {
  std::unique_ptr<aura::Window> window = std::make_unique<aura::Window>(
      aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate());
  window->SetType(aura::client::WINDOW_TYPE_UNKNOWN);
  window->Init(ui::LAYER_NOT_DRAWN);
  return window;
}

// Verify user action is recorded when a positionable window is activated given
// that a null window was activated last.
TEST_F(DesktopTaskSwitchMetricRecorderTest,
       ActivatePositionableWindowWhenNullWindowWasActivatedLast) {
  std::unique_ptr<aura::Window> null_window;
  std::unique_ptr<aura::Window> positionable_window =
      CreatePositionableWindow();

  ActiveTaskWindowWithUserInput(null_window.get());
  ResetActionCounts();

  ActiveTaskWindowWithUserInput(positionable_window.get());
  EXPECT_EQ(1, GetActionCount());
}

// Verify user action is recorded whena positionable window is activated given
// a different positionable window was activated last.
TEST_F(
    DesktopTaskSwitchMetricRecorderTest,
    ActivatePositionableWindowWhenADifferentPositionableWindowWasActivatedLast) {
  std::unique_ptr<aura::Window> positionable_window_1 =
      CreatePositionableWindow();
  std::unique_ptr<aura::Window> positionable_window_2 =
      CreatePositionableWindow();

  ActiveTaskWindowWithUserInput(positionable_window_1.get());
  ResetActionCounts();

  ActiveTaskWindowWithUserInput(positionable_window_2.get());
  EXPECT_EQ(1, GetActionCount());
}

// Verify user action is not recorded when a positionable window is activated
// given the same positionable window was activated last.
TEST_F(
    DesktopTaskSwitchMetricRecorderTest,
    ActivatePositionableWindowWhenTheSamePositionableWindowWasActivatedLast) {
  std::unique_ptr<aura::Window> positionable_window =
      CreatePositionableWindow();

  ActiveTaskWindowWithUserInput(positionable_window.get());
  ResetActionCounts();

  ActiveTaskWindowWithUserInput(positionable_window.get());
  EXPECT_EQ(0, GetActionCount());
}

// Verify user action is recorded when a positionable window is activated given
// a non-positionable window was activated last.
TEST_F(DesktopTaskSwitchMetricRecorderTest,
       ActivatePositionableWindowWhenANonPositionableWindowWasActivatedLast) {
  std::unique_ptr<aura::Window> non_positionable_window =
      CreateNonPositionableWindow();
  std::unique_ptr<aura::Window> positionable_window =
      CreatePositionableWindow();

  ActiveTaskWindowWithUserInput(non_positionable_window.get());
  ResetActionCounts();

  ActiveTaskWindowWithUserInput(positionable_window.get());
  EXPECT_EQ(1, GetActionCount());
}

// Verify user action is not recorded when a non-positionable window is
// activated between two activations of the same positionable window.
TEST_F(DesktopTaskSwitchMetricRecorderTest,
       ActivateNonPositionableWindowBetweenTwoPositionableWindowActivations) {
  std::unique_ptr<aura::Window> positionable_window =
      CreatePositionableWindow();
  std::unique_ptr<aura::Window> non_positionable_window =
      CreateNonPositionableWindow();

  ActiveTaskWindowWithUserInput(positionable_window.get());
  ResetActionCounts();

  ActiveTaskWindowWithUserInput(non_positionable_window.get());
  EXPECT_EQ(0, GetActionCount());

  ActiveTaskWindowWithUserInput(positionable_window.get());
  EXPECT_EQ(0, GetActionCount());
}

// Verify user action is not recorded when a null window is activated.
TEST_F(DesktopTaskSwitchMetricRecorderTest, ActivateNullWindow) {
  std::unique_ptr<aura::Window> positionable_window =
      CreatePositionableWindow();
  std::unique_ptr<aura::Window> null_window;

  ActiveTaskWindowWithUserInput(positionable_window.get());
  ResetActionCounts();

  ActiveTaskWindowWithUserInput(null_window.get());
  EXPECT_EQ(0, GetActionCount());
}

// Verify user action is not recorded when a non-positionable window is
// activated.
TEST_F(DesktopTaskSwitchMetricRecorderTest, ActivateNonPositionableWindow) {
  std::unique_ptr<aura::Window> positionable_window =
      CreatePositionableWindow();
  std::unique_ptr<aura::Window> non_positionable_window =
      CreateNonPositionableWindow();

  ActiveTaskWindowWithUserInput(positionable_window.get());
  ResetActionCounts();

  ActiveTaskWindowWithUserInput(non_positionable_window.get());
  EXPECT_EQ(0, GetActionCount());
}

// Verify user action is not recorded when the ActivationReason is not an
// INPUT_EVENT.
TEST_F(DesktopTaskSwitchMetricRecorderTest,
       ActivatePositionableWindowWithNonInputEventReason) {
  std::unique_ptr<aura::Window> positionable_window_1 =
      CreatePositionableWindow();
  std::unique_ptr<aura::Window> positionable_window_2 =
      CreatePositionableWindow();

  ActiveTaskWindowWithUserInput(positionable_window_1.get());
  ResetActionCounts();

  metrics_recorder_->OnWindowActivated(
      ActivationChangeObserver::ActivationReason::ACTIVATION_CLIENT,
      positionable_window_2.get(), nullptr);
  EXPECT_EQ(0, GetActionCount());
}

// Test fixture to test the integration of the DesktopTaskSwitchMetricsRecorder
// class with ash::Shell environment.
class DesktopTaskSwitchMetricRecorderWithShellIntegrationTest
    : public AshTestBase {
 public:
  DesktopTaskSwitchMetricRecorderWithShellIntegrationTest();

  DesktopTaskSwitchMetricRecorderWithShellIntegrationTest(
      const DesktopTaskSwitchMetricRecorderWithShellIntegrationTest&) = delete;
  DesktopTaskSwitchMetricRecorderWithShellIntegrationTest& operator=(
      const DesktopTaskSwitchMetricRecorderWithShellIntegrationTest&) = delete;

  ~DesktopTaskSwitchMetricRecorderWithShellIntegrationTest() override;

  // AshTestBase:
  void SetUp() override;
  void TearDown() override;

  // Returns the number of times the "Desktop_SwitchTask" user action was
  // recorded.
  int GetActionCount() const;

  // Creates a positionable window with the given |bounds| such that
  // window_util::IsWindowUserPositionable(...) would return true.
  aura::Window* CreatePositionableWindowInShellWithBounds(
      const gfx::Rect& bounds);

 protected:
  // Records UMA user action counts.
  std::unique_ptr<base::UserActionTester> user_action_tester_;

  // Delegate used when creating new windows using the
  // CreatePositionableWindowInShellWithBounds(...) method.
  aura::test::TestWindowDelegate test_window_delegate_;
};

DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::
    DesktopTaskSwitchMetricRecorderWithShellIntegrationTest() = default;

DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::
    ~DesktopTaskSwitchMetricRecorderWithShellIntegrationTest() = default;

void DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::SetUp() {
  AshTestBase::SetUp();
  user_action_tester_ = std::make_unique<base::UserActionTester>();
}

void DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::TearDown() {
  user_action_tester_.reset();
  AshTestBase::TearDown();
}

int DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::GetActionCount()
    const {
  return user_action_tester_->GetActionCount(kDesktopTaskSwitchUserAction);
}

aura::Window* DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::
    CreatePositionableWindowInShellWithBounds(const gfx::Rect& bounds) {
  return CreateTestWindowInShellWithDelegate(&test_window_delegate_, 0, bounds);
}

// Verify a user action is recorded when a positionable window is activated by
// a INPUT_EVENT.
TEST_F(DesktopTaskSwitchMetricRecorderWithShellIntegrationTest,
       ActivatePositionableWindowWithInputEvent) {
  aura::Window* positionable_window =
      CreatePositionableWindowInShellWithBounds(gfx::Rect(0, 0, 10, 10));

  ui::test::EventGenerator event_generator(Shell::GetPrimaryRootWindow());

  event_generator.MoveMouseToCenterOf(positionable_window);
  event_generator.ClickLeftButton();

  EXPECT_EQ(1, GetActionCount());
}

// Verify a user action is not recorded when a positionable window is activated
// by a non INPUT_EVENT.
TEST_F(DesktopTaskSwitchMetricRecorderWithShellIntegrationTest,
       ActivatePositionableWindowWithNonInputEvent) {
  aura::Window* positionable_window =
      CreatePositionableWindowInShellWithBounds(gfx::Rect(0, 0, 10, 10));

  Shell::Get()->activation_client()->ActivateWindow(positionable_window);

  EXPECT_EQ(0, GetActionCount());
}

}  // namespace
}  // namespace ash