chromium/ash/shelf/shelf_button_pressed_metric_tracker_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/shelf/shelf_button_pressed_metric_tracker.h"

#include <utility>

#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_button_pressed_metric_tracker_test_api.h"
#include "ash/shelf/shelf_view_test_api.h"
#include "ash/test/ash_test_base.h"
#include "base/memory/raw_ptr.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/simple_test_tick_clock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/test/test_event.h"
#include "ui/views/controls/button/button.h"

namespace ash {
namespace {

// A simple light weight test double dummy for a views::Button.
class DummyButton : public views::Button {
 public:
  DummyButton();

  DummyButton(const DummyButton&) = delete;
  DummyButton& operator=(const DummyButton&) = delete;
};

DummyButton::DummyButton() : views::Button(views::Button::PressedCallback()) {}

// Test fixture for the ShelfButtonPressedMetricTracker class. Relies on
// AshTestBase to initilize the UserMetricsRecorder and it's dependencies.
class ShelfButtonPressedMetricTrackerTest : public AshTestBase {
 public:
  static const char*
      kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName;

  ShelfButtonPressedMetricTrackerTest();

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

  ~ShelfButtonPressedMetricTrackerTest() override;

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

  // Calls ButtonPressed on the test target with the given |event|
  // and dummy values for the |sender| and |performed_action| parameters.
  void ButtonPressed(const ui::Event& event);

  // Calls ButtonPressed on the test target with the given |performed_action|
  // and dummy values for the |event| and |sender| parameters.
  void ButtonPressed(ShelfAction performed_action);

  // Calls ButtonPressed on the test target with the given |sender| and
  // |performed_action| and a dummy value for the |event| parameter.
  void ButtonPressed(const views::Button* sender, ShelfAction performed_action);

 protected:
  // The test target. Not owned.
  raw_ptr<ShelfButtonPressedMetricTracker, DanglingUntriaged> metric_tracker_;

  // The TickClock injected in to the test target.
  base::SimpleTestTickClock tick_clock_;
};

const char* ShelfButtonPressedMetricTrackerTest::
    kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName =
        ShelfButtonPressedMetricTracker::
            kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName;

ShelfButtonPressedMetricTrackerTest::ShelfButtonPressedMetricTrackerTest() =
    default;

ShelfButtonPressedMetricTrackerTest::~ShelfButtonPressedMetricTrackerTest() =
    default;

void ShelfButtonPressedMetricTrackerTest::SetUp() {
  AshTestBase::SetUp();

  Shelf* shelf = GetPrimaryShelf();
  ShelfViewTestAPI shelf_view_test_api(shelf->GetShelfViewForTesting());

  metric_tracker_ = shelf_view_test_api.shelf_button_pressed_metric_tracker();

  ShelfButtonPressedMetricTrackerTestAPI test_api(metric_tracker_);

  test_api.SetTickClock(&tick_clock_);

  // Ensure the TickClock->NowTicks() doesn't return base::TimeTicks because
  // ShelfButtonPressedMetricTracker interprets that value as unset.
  tick_clock_.Advance(base::Milliseconds(100));
}

void ShelfButtonPressedMetricTrackerTest::TearDown() {
  AshTestBase::TearDown();
}

void ShelfButtonPressedMetricTrackerTest::ButtonPressed(
    const ui::Event& event) {
  const DummyButton kDummyButton;
  metric_tracker_->ButtonPressed(event, &kDummyButton, SHELF_ACTION_NONE);
}

void ShelfButtonPressedMetricTrackerTest::ButtonPressed(
    ShelfAction performed_action) {
  const ui::test::TestEvent kDummyEvent(ui::EventType::kGestureTap);
  const DummyButton kDummyButton;
  metric_tracker_->ButtonPressed(kDummyEvent, &kDummyButton, performed_action);
}

void ShelfButtonPressedMetricTrackerTest::ButtonPressed(
    const views::Button* sender,
    ShelfAction performed_action) {
  const ui::test::TestEvent kDummyEvent(ui::EventType::kGestureTap);
  metric_tracker_->ButtonPressed(kDummyEvent, sender, performed_action);
}

}  // namespace

// Verifies that a Launcher_ButtonPressed_Mouse UMA user action is recorded when
// a button is pressed by a mouse event.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       Launcher_ButtonPressed_MouseIsRecordedWhenIconActivatedByMouse) {
  const ui::MouseEvent mouse_event(ui::EventType::kMousePressed, gfx::Point(),
                                   gfx::Point(), base::TimeTicks(), 0, 0);

  base::UserActionTester user_action_tester;
  ButtonPressed(mouse_event);
  EXPECT_EQ(1,
            user_action_tester.GetActionCount("Launcher_ButtonPressed_Mouse"));
}

// Verifies that a Launcher_ButtonPressed_Touch UMA user action is recorded when
// a button is pressed by a touch event.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       Launcher_ButtonPressed_MouseIsRecordedWhenIconActivatedByTouch) {
  const ui::TouchEvent touch_event(
      ui::EventType::kGestureTap, gfx::Point(), base::TimeTicks(),
      ui::PointerDetails(ui::EventPointerType::kTouch, 0));

  base::UserActionTester user_action_tester;
  ButtonPressed(touch_event);
  EXPECT_EQ(1,
            user_action_tester.GetActionCount("Launcher_ButtonPressed_Touch"));
}

// Verifies that a Launcher_LaunchTask UMA user action is recorded when
// pressing a button causes a new window to be created.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       Launcher_LaunchTaskIsRecordedWhenNewWindowIsCreated) {
  base::UserActionTester user_action_tester;
  ButtonPressed(SHELF_ACTION_NEW_WINDOW_CREATED);
  EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_LaunchTask"));
}

// Verifies that a Launcher_MinimizeTask UMA user action is recorded when
// pressing a button causes an existing window to be minimized.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       Launcher_MinimizeTaskIsRecordedWhenWindowIsMinimized) {
  base::UserActionTester user_action_tester;
  ButtonPressed(SHELF_ACTION_WINDOW_MINIMIZED);
  EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_MinimizeTask"));
}

// Verifies that a Launcher_SwitchTask UMA user action is recorded when
// pressing a button causes an existing window to be activated.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       Launcher_SwitchTaskIsRecordedWhenExistingWindowIsActivated) {
  base::UserActionTester user_action_tester;
  ButtonPressed(SHELF_ACTION_WINDOW_ACTIVATED);
  EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_SwitchTask"));
}

// Verify that a window activation action will record a data point if it was
// subsequent to a minimize action.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       VerifyDataRecordedAfterMinimizedAndSubsequentActivatedAction) {
  const DummyButton kDummyButton;

  base::HistogramTester histogram_tester;

  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED);
  histogram_tester.ExpectTotalCount(
      kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 0);

  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED);
  histogram_tester.ExpectTotalCount(
      kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1);
}

// Verify that a multiple window activation actions will record a single data
// point if they are subsequent to a minimize action.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       VerifyDataRecordedAfterMinimizedAndMultipleSubsequentActivatedActions) {
  const DummyButton kDummyButton;

  base::HistogramTester histogram_tester;

  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED);
  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED);
  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED);

  histogram_tester.ExpectTotalCount(
      kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1);
}

// Verify that a window activation action will not record a data point if it was
// not subsequent to a minimize action.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       VerifyDataRecordedAfterMinimizedAndNonSubsequentActivatedAction) {
  const DummyButton kDummyButton;

  base::HistogramTester histogram_tester;

  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED);
  ButtonPressed(&kDummyButton, SHELF_ACTION_APP_LIST_SHOWN);
  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED);

  histogram_tester.ExpectTotalCount(
      kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 0);
}

// Verify no data is recorded if a second source button is pressed in between
// subsequent minimized and activated actions on the same source.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       VerifyDataRecordedAfterMinimizedButtonA) {
  const DummyButton kDummyButton;
  const DummyButton kSecondDummyButton;

  base::HistogramTester histogram_tester;

  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED);
  ButtonPressed(&kSecondDummyButton, SHELF_ACTION_WINDOW_MINIMIZED);
  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED);

  histogram_tester.ExpectTotalCount(
      kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 0);
}

// Verify the data value recorded when a window activation action is subsequent
// to a minimize action.
TEST_F(ShelfButtonPressedMetricTrackerTest,
       VerifyTheValueRecordedBySubsequentMinimizedAndActivateActions) {
  const int kTimeDeltaInMilliseconds = 17;
  const DummyButton kDummyButton;

  base::HistogramTester histogram_tester;

  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED);
  tick_clock_.Advance(base::Milliseconds(kTimeDeltaInMilliseconds));
  ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED);

  histogram_tester.ExpectTotalCount(
      kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1);
  histogram_tester.ExpectBucketCount(
      kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName,
      kTimeDeltaInMilliseconds, 1);
}

}  // namespace ash