1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ash/clipboard/clipboard_nudge_controller.h"
6 
7 #include "ash/clipboard/clipboard_history.h"
8 #include "ash/clipboard/clipboard_history_controller_impl.h"
9 #include "ash/clipboard/clipboard_nudge_constants.h"
10 #include "ash/session/session_controller_impl.h"
11 #include "ash/shell.h"
12 #include "ash/test/ash_test_base.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "base/test/simple_test_clock.h"
16 #include "chromeos/constants/chromeos_features.h"
17 #include "ui/base/clipboard/clipboard_data.h"
18 #include "ui/base/clipboard/clipboard_non_backed.h"
19 
20 namespace ash {
21 
22 class ClipboardNudgeControllerTest : public AshTestBase {
23  public:
24   ClipboardNudgeControllerTest() = default;
25   ClipboardNudgeControllerTest(const ClipboardNudgeControllerTest&) = delete;
26   ClipboardNudgeControllerTest& operator=(const ClipboardNudgeControllerTest&) =
27       delete;
28   ~ClipboardNudgeControllerTest() override = default;
29 
clock()30   base::SimpleTestClock* clock() { return &test_clock_; }
31 
32   // AshTestBase:
SetUp()33   void SetUp() override {
34     scoped_feature_list_.InitAndEnableFeature(
35         chromeos::features::kClipboardHistory);
36     AshTestBase::SetUp();
37     nudge_controller_ =
38         Shell::Get()->clipboard_history_controller()->nudge_controller();
39     nudge_controller_->OverrideClockForTesting(&test_clock_);
40     test_clock_.Advance(base::TimeDelta::FromSeconds(360));
41   }
42 
TearDown()43   void TearDown() override {
44     nudge_controller_->ClearClockOverrideForTesting();
45     AshTestBase::TearDown();
46   }
47 
48   // Owned by ClipboardHistoryController.
49   ClipboardNudgeController* nudge_controller_;
50 
51  private:
52   base::test::ScopedFeatureList scoped_feature_list_;
53   base::SimpleTestClock test_clock_;
54 };
55 
56 // Checks that clipboard state advances after the nudge controller is fed the
57 // right event type.
TEST_F(ClipboardNudgeControllerTest,ShouldShowNudgeAfterCorrectSequence)58 TEST_F(ClipboardNudgeControllerTest, ShouldShowNudgeAfterCorrectSequence) {
59   EXPECT_EQ(ClipboardState::kInit,
60             nudge_controller_->GetClipboardStateForTesting());
61   // Checks that the first copy advances state as expected.
62   nudge_controller_->OnClipboardHistoryItemAdded(
63       ClipboardHistoryItem(ui::ClipboardData()));
64   EXPECT_EQ(ClipboardState::kFirstCopy,
65             nudge_controller_->GetClipboardStateForTesting());
66 
67   // Checks that the first paste advances state as expected.
68   nudge_controller_->OnClipboardDataRead();
69   EXPECT_EQ(ClipboardState::kFirstPaste,
70             nudge_controller_->GetClipboardStateForTesting());
71 
72   // Checks that the second copy advances state as expected.
73   nudge_controller_->OnClipboardHistoryItemAdded(
74       ClipboardHistoryItem(ui::ClipboardData()));
75   EXPECT_EQ(ClipboardState::kSecondCopy,
76             nudge_controller_->GetClipboardStateForTesting());
77 
78   // Check that clipbaord nudge has not yet been created.
79   EXPECT_FALSE(nudge_controller_->GetClipboardNudgeForTesting());
80 
81   // Checks that the second paste resets state as expected.
82   nudge_controller_->OnClipboardDataRead();
83   EXPECT_EQ(ClipboardState::kInit,
84             nudge_controller_->GetClipboardStateForTesting());
85 
86   // Check that clipbaord nudge has been created.
87   EXPECT_TRUE(nudge_controller_->GetClipboardNudgeForTesting());
88 }
89 
90 // Checks that the clipboard state does not advace if too much time passes
91 // during the copy paste sequence.
TEST_F(ClipboardNudgeControllerTest,NudgeTimeOut)92 TEST_F(ClipboardNudgeControllerTest, NudgeTimeOut) {
93   // Perform copy -> paste -> copy sequence.
94   nudge_controller_->OnClipboardHistoryItemAdded(
95       ClipboardHistoryItem(ui::ClipboardData()));
96   nudge_controller_->OnClipboardDataRead();
97   nudge_controller_->OnClipboardHistoryItemAdded(
98       ClipboardHistoryItem(ui::ClipboardData()));
99 
100   // Advance time to cause the nudge timer to time out.
101   clock()->Advance(kMaxTimeBetweenPaste);
102   nudge_controller_->OnClipboardDataRead();
103 
104   // Paste event should reset clipboard state to |kFirstPaste| instead of to
105   // |kShouldShowNudge|.
106   EXPECT_NE(ClipboardState::kShouldShowNudge,
107             nudge_controller_->GetClipboardStateForTesting());
108   EXPECT_EQ(ClipboardState::kFirstPaste,
109             nudge_controller_->GetClipboardStateForTesting());
110 }
111 
112 // Checks that multiple pastes refreshes the |kMaxTimeBetweenPaste| timer that
113 // determines whether too much time has passed to show the nudge.
TEST_F(ClipboardNudgeControllerTest,NudgeDoesNotTimeOutWithSparsePastes)114 TEST_F(ClipboardNudgeControllerTest, NudgeDoesNotTimeOutWithSparsePastes) {
115   nudge_controller_->OnClipboardHistoryItemAdded(
116       ClipboardHistoryItem(ui::ClipboardData()));
117   nudge_controller_->OnClipboardDataRead();
118   EXPECT_EQ(ClipboardState::kFirstPaste,
119             nudge_controller_->GetClipboardStateForTesting());
120 
121   // Perform 5 pastes over 2.5*|kMaxTimeBetweenPaste|.
122   for (int paste_cycle = 0; paste_cycle < 5; paste_cycle++) {
123     SCOPED_TRACE("paste cycle " + base::NumberToString(paste_cycle));
124     clock()->Advance(kMaxTimeBetweenPaste / 2);
125     nudge_controller_->OnClipboardDataRead();
126     EXPECT_EQ(ClipboardState::kFirstPaste,
127               nudge_controller_->GetClipboardStateForTesting());
128   }
129 
130   // Check that clipbaord nudge has not yet been created.
131   EXPECT_FALSE(nudge_controller_->GetClipboardNudgeForTesting());
132 
133   // Check that HandleClipboardChanged() will advance nudge_controller's
134   // ClipboardState.
135   nudge_controller_->OnClipboardHistoryItemAdded(
136       ClipboardHistoryItem(ui::ClipboardData()));
137   EXPECT_EQ(ClipboardState::kSecondCopy,
138             nudge_controller_->GetClipboardStateForTesting());
139   nudge_controller_->OnClipboardDataRead();
140   EXPECT_EQ(ClipboardState::kInit,
141             nudge_controller_->GetClipboardStateForTesting());
142 
143   // Check that clipbaord nudge has been created.
144   EXPECT_TRUE(nudge_controller_->GetClipboardNudgeForTesting());
145 }
146 
147 // Checks that consecutive copy events does not advance the clipboard state.
TEST_F(ClipboardNudgeControllerTest,RepeatedCopyDoesNotAdvanceState)148 TEST_F(ClipboardNudgeControllerTest, RepeatedCopyDoesNotAdvanceState) {
149   nudge_controller_->OnClipboardHistoryItemAdded(
150       ClipboardHistoryItem(ui::ClipboardData()));
151   EXPECT_EQ(ClipboardState::kFirstCopy,
152             nudge_controller_->GetClipboardStateForTesting());
153   nudge_controller_->OnClipboardHistoryItemAdded(
154       ClipboardHistoryItem(ui::ClipboardData()));
155   EXPECT_EQ(ClipboardState::kFirstCopy,
156             nudge_controller_->GetClipboardStateForTesting());
157 }
158 
159 // Checks that consecutive paste events does not advance the clipboard state.
TEST_F(ClipboardNudgeControllerTest,RepeatedPasteDoesNotAdvanceState)160 TEST_F(ClipboardNudgeControllerTest, RepeatedPasteDoesNotAdvanceState) {
161   nudge_controller_->OnClipboardHistoryItemAdded(
162       ClipboardHistoryItem(ui::ClipboardData()));
163   EXPECT_EQ(ClipboardState::kFirstCopy,
164             nudge_controller_->GetClipboardStateForTesting());
165   nudge_controller_->OnClipboardDataRead();
166   EXPECT_EQ(ClipboardState::kFirstPaste,
167             nudge_controller_->GetClipboardStateForTesting());
168   nudge_controller_->OnClipboardDataRead();
169   EXPECT_EQ(ClipboardState::kFirstPaste,
170             nudge_controller_->GetClipboardStateForTesting());
171 }
172 
173 // Verifies that administrative events does not advance clipboard state.
TEST_F(ClipboardNudgeControllerTest,AdminWriteDoesNotAdvanceState)174 TEST_F(ClipboardNudgeControllerTest, AdminWriteDoesNotAdvanceState) {
175   nudge_controller_->OnClipboardHistoryItemAdded(
176       ClipboardHistoryItem(ui::ClipboardData()));
177   nudge_controller_->OnClipboardDataRead();
178   EXPECT_EQ(ClipboardState::kFirstPaste,
179             nudge_controller_->GetClipboardStateForTesting());
180 
181   auto data = std::make_unique<ui::ClipboardData>();
182   data->set_text("test");
183   // Write the data to the clipboard, clipboard state should not advance.
184   ui::ClipboardNonBacked::GetForCurrentThread()->WriteClipboardData(
185       std::move(data));
186   EXPECT_EQ(ClipboardState::kFirstPaste,
187             nudge_controller_->GetClipboardStateForTesting());
188 }
189 
190 }  // namespace ash
191