1 // Copyright 2015 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.
5 #include "components/bubble/bubble_manager.h"
7 #include "components/bubble/bubble_controller.h"
8 #include "components/bubble/bubble_delegate.h"
9 #include "components/bubble/bubble_reference.h"
10 #include "components/bubble/bubble_ui.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
16 class MockBubbleUi
: public BubbleUi
{
19 ~MockBubbleUi() override
{ Destroyed(); }
21 MOCK_METHOD1(Show
, void(BubbleReference
));
22 MOCK_METHOD0(Close
, void());
23 MOCK_METHOD0(UpdateAnchorPosition
, void());
25 // To verify destructor call.
26 MOCK_METHOD0(Destroyed
, void());
29 class MockBubbleDelegate
: public BubbleDelegate
{
31 MockBubbleDelegate() {}
32 ~MockBubbleDelegate() override
{ Destroyed(); }
34 // Default bubble shows UI and closes when asked to close.
35 static scoped_ptr
<MockBubbleDelegate
> Default();
37 // Stubborn bubble shows UI and doesn't want to close.
38 static scoped_ptr
<MockBubbleDelegate
> Stubborn();
40 MOCK_METHOD1(ShouldClose
, bool(BubbleCloseReason reason
));
42 // A scoped_ptr can't be returned in MOCK_METHOD.
43 MOCK_METHOD0(BuildBubbleUiMock
, BubbleUi
*());
44 scoped_ptr
<BubbleUi
> BuildBubbleUi() override
{
45 return make_scoped_ptr(BuildBubbleUiMock());
48 MOCK_METHOD1(UpdateBubbleUi
, bool(BubbleUi
*));
50 // To verify destructor call.
51 MOCK_METHOD0(Destroyed
, void());
55 scoped_ptr
<MockBubbleDelegate
> MockBubbleDelegate::Default() {
56 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
57 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
58 .WillOnce(testing::Return(new MockBubbleUi
));
59 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
60 .WillOnce(testing::Return(true));
61 return make_scoped_ptr(delegate
);
65 scoped_ptr
<MockBubbleDelegate
> MockBubbleDelegate::Stubborn() {
66 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
67 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
68 .WillOnce(testing::Return(new MockBubbleUi
));
69 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
70 .WillRepeatedly(testing::Return(false));
71 return make_scoped_ptr(delegate
);
74 // Helper class used to test chaining another bubble.
75 class DelegateChainHelper
{
77 DelegateChainHelper(BubbleManager
* manager
,
78 scoped_ptr
<BubbleDelegate
> next_delegate
);
80 // Will show the bubble in |next_delegate_|.
81 void Chain() { manager_
->ShowBubble(next_delegate_
.Pass()); }
83 // True if the bubble was taken by the bubble manager.
84 bool BubbleWasTaken() { return !next_delegate_
; }
87 BubbleManager
* manager_
; // Weak.
88 scoped_ptr
<BubbleDelegate
> next_delegate_
;
91 DelegateChainHelper::DelegateChainHelper(
92 BubbleManager
* manager
,
93 scoped_ptr
<BubbleDelegate
> next_delegate
)
94 : manager_(manager
), next_delegate_(next_delegate
.Pass()) {}
96 class BubbleManagerTest
: public testing::Test
{
99 ~BubbleManagerTest() override
{}
101 void SetUp() override
;
102 void TearDown() override
;
105 scoped_ptr
<BubbleManager
> manager_
;
108 BubbleManagerTest::BubbleManagerTest() {}
110 void BubbleManagerTest::SetUp() {
111 testing::Test::SetUp();
112 manager_
.reset(new BubbleManager
);
115 void BubbleManagerTest::TearDown() {
117 testing::Test::TearDown();
120 TEST_F(BubbleManagerTest
, ManagerShowsBubbleUi
) {
121 // Manager will delete bubble_ui.
122 MockBubbleUi
* bubble_ui
= new MockBubbleUi
;
123 EXPECT_CALL(*bubble_ui
, Destroyed());
124 EXPECT_CALL(*bubble_ui
, Show(testing::_
));
125 EXPECT_CALL(*bubble_ui
, Close());
126 EXPECT_CALL(*bubble_ui
, UpdateAnchorPosition()).Times(0);
128 // Manager will delete delegate.
129 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
130 EXPECT_CALL(*delegate
, Destroyed());
131 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
132 .WillOnce(testing::Return(bubble_ui
));
133 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
134 .WillOnce(testing::Return(true));
136 manager_
->ShowBubble(make_scoped_ptr(delegate
));
139 TEST_F(BubbleManagerTest
, ManagerUpdatesBubbleUi
) {
140 // Manager will delete bubble_ui.
141 MockBubbleUi
* bubble_ui
= new MockBubbleUi
;
142 EXPECT_CALL(*bubble_ui
, Destroyed());
143 EXPECT_CALL(*bubble_ui
, Show(testing::_
));
144 EXPECT_CALL(*bubble_ui
, Close());
145 EXPECT_CALL(*bubble_ui
, UpdateAnchorPosition());
147 // Manager will delete delegate.
148 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
149 EXPECT_CALL(*delegate
, Destroyed());
150 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
151 .WillOnce(testing::Return(bubble_ui
));
152 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
153 .WillOnce(testing::Return(true));
155 manager_
->ShowBubble(make_scoped_ptr(delegate
));
156 manager_
->UpdateAllBubbleAnchors();
159 TEST_F(BubbleManagerTest
, CloseOnReferenceInvalidatesReference
) {
160 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
162 ASSERT_TRUE(ref
->CloseBubble(BUBBLE_CLOSE_FOCUS_LOST
));
167 TEST_F(BubbleManagerTest
, CloseOnStubbornReferenceDoesNotInvalidate
) {
168 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
170 ASSERT_FALSE(ref
->CloseBubble(BUBBLE_CLOSE_FOCUS_LOST
));
175 TEST_F(BubbleManagerTest
, CloseInvalidatesReference
) {
176 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
178 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FOCUS_LOST
));
183 TEST_F(BubbleManagerTest
, CloseAllInvalidatesReference
) {
184 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
186 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
191 TEST_F(BubbleManagerTest
, DestroyInvalidatesReference
) {
192 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
199 TEST_F(BubbleManagerTest
, CloseInvalidatesStubbornReference
) {
200 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
202 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
207 TEST_F(BubbleManagerTest
, CloseAllInvalidatesStubbornReference
) {
208 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
210 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FORCED
);
215 TEST_F(BubbleManagerTest
, DestroyInvalidatesStubbornReference
) {
216 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
223 TEST_F(BubbleManagerTest
, CloseDoesNotInvalidateStubbornReference
) {
224 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
226 ASSERT_FALSE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FOCUS_LOST
));
231 TEST_F(BubbleManagerTest
, CloseAllDoesNotInvalidateStubbornReference
) {
232 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
234 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
239 TEST_F(BubbleManagerTest
, CloseAllInvalidatesMixAppropriately
) {
240 BubbleReference stubborn_ref1
=
241 manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
242 BubbleReference normal_ref1
=
243 manager_
->ShowBubble(MockBubbleDelegate::Default());
244 BubbleReference stubborn_ref2
=
245 manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
246 BubbleReference normal_ref2
=
247 manager_
->ShowBubble(MockBubbleDelegate::Default());
248 BubbleReference stubborn_ref3
=
249 manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
250 BubbleReference normal_ref3
=
251 manager_
->ShowBubble(MockBubbleDelegate::Default());
253 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
255 ASSERT_TRUE(stubborn_ref1
);
256 ASSERT_TRUE(stubborn_ref2
);
257 ASSERT_TRUE(stubborn_ref3
);
258 ASSERT_FALSE(normal_ref1
);
259 ASSERT_FALSE(normal_ref2
);
260 ASSERT_FALSE(normal_ref3
);
263 TEST_F(BubbleManagerTest
, UpdateAllShouldWorkWithoutBubbles
) {
264 // Manager shouldn't crash if bubbles have never been added.
265 manager_
->UpdateAllBubbleAnchors();
267 // Add a bubble and close it.
268 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
269 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
271 // Bubble should NOT get an update event because it's already closed.
272 manager_
->UpdateAllBubbleAnchors();
275 TEST_F(BubbleManagerTest
, CloseAllShouldWorkWithoutBubbles
) {
276 // Manager shouldn't crash if bubbles have never been added.
277 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
279 // Add a bubble and close it.
280 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
281 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
283 // Bubble should NOT get a close event because it's already closed.
284 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
287 TEST_F(BubbleManagerTest
, AllowBubbleChainingOnClose
) {
288 scoped_ptr
<BubbleDelegate
> chained_delegate
= MockBubbleDelegate::Default();
289 DelegateChainHelper
chain_helper(manager_
.get(), chained_delegate
.Pass());
291 // Manager will delete delegate.
292 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
293 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
294 .WillOnce(testing::Return(new MockBubbleUi
));
295 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
296 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
297 &chain_helper
, &DelegateChainHelper::Chain
),
298 testing::Return(true)));
300 BubbleReference ref
= manager_
->ShowBubble(make_scoped_ptr(delegate
));
301 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
303 ASSERT_TRUE(chain_helper
.BubbleWasTaken());
306 TEST_F(BubbleManagerTest
, AllowBubbleChainingOnCloseAll
) {
307 scoped_ptr
<BubbleDelegate
> chained_delegate
= MockBubbleDelegate::Default();
308 DelegateChainHelper
chain_helper(manager_
.get(), chained_delegate
.Pass());
310 // Manager will delete delegate.
311 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
312 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
313 .WillOnce(testing::Return(new MockBubbleUi
));
314 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
315 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
316 &chain_helper
, &DelegateChainHelper::Chain
),
317 testing::Return(true)));
319 manager_
->ShowBubble(make_scoped_ptr(delegate
));
320 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FORCED
);
322 ASSERT_TRUE(chain_helper
.BubbleWasTaken());
325 TEST_F(BubbleManagerTest
, BubblesDoNotChainOnDestroy
) {
326 // Manager will delete delegate.
327 MockBubbleDelegate
* chained_delegate
= new MockBubbleDelegate
;
328 EXPECT_CALL(*chained_delegate
, BuildBubbleUiMock()).Times(0);
329 EXPECT_CALL(*chained_delegate
, ShouldClose(testing::_
)).Times(0);
331 DelegateChainHelper
chain_helper(manager_
.get(),
332 make_scoped_ptr(chained_delegate
));
334 // Manager will delete delegate.
335 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
336 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
337 .WillOnce(testing::Return(new MockBubbleUi
));
338 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
339 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
340 &chain_helper
, &DelegateChainHelper::Chain
),
341 testing::Return(true)));
343 manager_
->ShowBubble(make_scoped_ptr(delegate
));
346 // The manager will take the bubble, but not show it.
347 ASSERT_TRUE(chain_helper
.BubbleWasTaken());
350 TEST_F(BubbleManagerTest
, BubbleUpdatesTrue
) {
351 MockBubbleUi
* bubble_ui
= new MockBubbleUi
;
352 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
353 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
354 .WillOnce(testing::Return(bubble_ui
));
355 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
356 .WillOnce(testing::Return(true));
357 EXPECT_CALL(*delegate
, UpdateBubbleUi(bubble_ui
))
358 .WillOnce(testing::Return(true));
360 BubbleReference ref
= manager_
->ShowBubble(make_scoped_ptr(delegate
));
361 ASSERT_TRUE(ref
->UpdateBubbleUi());
364 TEST_F(BubbleManagerTest
, BubbleUpdatesFalse
) {
365 MockBubbleUi
* bubble_ui
= new MockBubbleUi
;
366 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
367 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
368 .WillOnce(testing::Return(bubble_ui
));
369 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
370 .WillOnce(testing::Return(true));
371 EXPECT_CALL(*delegate
, UpdateBubbleUi(bubble_ui
))
372 .WillOnce(testing::Return(false));
374 BubbleReference ref
= manager_
->ShowBubble(make_scoped_ptr(delegate
));
375 ASSERT_FALSE(ref
->UpdateBubbleUi());