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 DISALLOW_COPY_AND_ASSIGN(MockBubbleUi
);
32 class MockBubbleDelegate
: public BubbleDelegate
{
34 MockBubbleDelegate() {}
35 ~MockBubbleDelegate() override
{ Destroyed(); }
37 // Default bubble shows UI and closes when asked to close.
38 static scoped_ptr
<MockBubbleDelegate
> Default();
40 // Stubborn bubble shows UI and doesn't want to close.
41 static scoped_ptr
<MockBubbleDelegate
> Stubborn();
43 MOCK_METHOD1(ShouldClose
, bool(BubbleCloseReason reason
));
45 // A scoped_ptr can't be returned in MOCK_METHOD.
46 MOCK_METHOD0(BuildBubbleUiMock
, BubbleUi
*());
47 scoped_ptr
<BubbleUi
> BuildBubbleUi() override
{
48 return make_scoped_ptr(BuildBubbleUiMock());
51 MOCK_METHOD1(UpdateBubbleUi
, bool(BubbleUi
*));
53 MOCK_CONST_METHOD0(GetName
, std::string());
55 // To verify destructor call.
56 MOCK_METHOD0(Destroyed
, void());
59 DISALLOW_COPY_AND_ASSIGN(MockBubbleDelegate
);
63 scoped_ptr
<MockBubbleDelegate
> MockBubbleDelegate::Default() {
64 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
65 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
66 .WillOnce(testing::Return(new MockBubbleUi
));
67 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
68 .WillOnce(testing::Return(true));
69 return make_scoped_ptr(delegate
);
73 scoped_ptr
<MockBubbleDelegate
> MockBubbleDelegate::Stubborn() {
74 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
75 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
76 .WillOnce(testing::Return(new MockBubbleUi
));
77 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
78 .WillRepeatedly(testing::Return(false));
79 return make_scoped_ptr(delegate
);
82 // Helper class used to test chaining another bubble.
83 class DelegateChainHelper
{
85 DelegateChainHelper(BubbleManager
* manager
,
86 scoped_ptr
<BubbleDelegate
> next_delegate
);
88 // Will show the bubble in |next_delegate_|.
89 void Chain() { manager_
->ShowBubble(next_delegate_
.Pass()); }
91 // True if the bubble was taken by the bubble manager.
92 bool BubbleWasTaken() { return !next_delegate_
; }
95 BubbleManager
* manager_
; // Weak.
96 scoped_ptr
<BubbleDelegate
> next_delegate_
;
98 DISALLOW_COPY_AND_ASSIGN(DelegateChainHelper
);
101 DelegateChainHelper::DelegateChainHelper(
102 BubbleManager
* manager
,
103 scoped_ptr
<BubbleDelegate
> next_delegate
)
104 : manager_(manager
), next_delegate_(next_delegate
.Pass()) {}
106 class MockBubbleManagerObserver
: public BubbleManager::BubbleManagerObserver
{
108 MockBubbleManagerObserver() {}
109 ~MockBubbleManagerObserver() override
{}
111 MOCK_METHOD1(OnBubbleNeverShown
, void(BubbleReference
));
112 MOCK_METHOD2(OnBubbleClosed
, void(BubbleReference
, BubbleCloseReason
));
115 DISALLOW_COPY_AND_ASSIGN(MockBubbleManagerObserver
);
118 class BubbleManagerTest
: public testing::Test
{
121 ~BubbleManagerTest() override
{}
123 void SetUp() override
;
124 void TearDown() override
;
127 scoped_ptr
<BubbleManager
> manager_
;
130 DISALLOW_COPY_AND_ASSIGN(BubbleManagerTest
);
133 BubbleManagerTest::BubbleManagerTest() {}
135 void BubbleManagerTest::SetUp() {
136 testing::Test::SetUp();
137 manager_
.reset(new BubbleManager
);
140 void BubbleManagerTest::TearDown() {
142 testing::Test::TearDown();
145 TEST_F(BubbleManagerTest
, ManagerShowsBubbleUi
) {
146 // Manager will delete bubble_ui.
147 MockBubbleUi
* bubble_ui
= new MockBubbleUi
;
148 EXPECT_CALL(*bubble_ui
, Destroyed());
149 EXPECT_CALL(*bubble_ui
, Show(testing::_
));
150 EXPECT_CALL(*bubble_ui
, Close());
151 EXPECT_CALL(*bubble_ui
, UpdateAnchorPosition()).Times(0);
153 // Manager will delete delegate.
154 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
155 EXPECT_CALL(*delegate
, Destroyed());
156 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
157 .WillOnce(testing::Return(bubble_ui
));
158 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
159 .WillOnce(testing::Return(true));
161 manager_
->ShowBubble(make_scoped_ptr(delegate
));
164 TEST_F(BubbleManagerTest
, ManagerUpdatesBubbleUi
) {
165 // Manager will delete bubble_ui.
166 MockBubbleUi
* bubble_ui
= new MockBubbleUi
;
167 EXPECT_CALL(*bubble_ui
, Destroyed());
168 EXPECT_CALL(*bubble_ui
, Show(testing::_
));
169 EXPECT_CALL(*bubble_ui
, Close());
170 EXPECT_CALL(*bubble_ui
, UpdateAnchorPosition());
172 // Manager will delete delegate.
173 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
174 EXPECT_CALL(*delegate
, Destroyed());
175 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
176 .WillOnce(testing::Return(bubble_ui
));
177 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
178 .WillOnce(testing::Return(true));
180 manager_
->ShowBubble(make_scoped_ptr(delegate
));
181 manager_
->UpdateAllBubbleAnchors();
184 TEST_F(BubbleManagerTest
, CloseOnReferenceInvalidatesReference
) {
185 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
187 ASSERT_TRUE(ref
->CloseBubble(BUBBLE_CLOSE_FOCUS_LOST
));
192 TEST_F(BubbleManagerTest
, CloseOnStubbornReferenceDoesNotInvalidate
) {
193 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
195 ASSERT_FALSE(ref
->CloseBubble(BUBBLE_CLOSE_FOCUS_LOST
));
200 TEST_F(BubbleManagerTest
, CloseInvalidatesReference
) {
201 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
203 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FOCUS_LOST
));
208 TEST_F(BubbleManagerTest
, CloseAllInvalidatesReference
) {
209 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
211 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
216 TEST_F(BubbleManagerTest
, DestroyInvalidatesReference
) {
217 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
224 TEST_F(BubbleManagerTest
, CloseInvalidatesStubbornReference
) {
225 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
227 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
232 TEST_F(BubbleManagerTest
, CloseAllInvalidatesStubbornReference
) {
233 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
235 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FORCED
);
240 TEST_F(BubbleManagerTest
, DestroyInvalidatesStubbornReference
) {
241 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
248 TEST_F(BubbleManagerTest
, CloseDoesNotInvalidateStubbornReference
) {
249 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
251 ASSERT_FALSE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FOCUS_LOST
));
256 TEST_F(BubbleManagerTest
, CloseAllDoesNotInvalidateStubbornReference
) {
257 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
259 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
264 TEST_F(BubbleManagerTest
, CloseAllInvalidatesMixAppropriately
) {
265 BubbleReference stubborn_ref1
=
266 manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
267 BubbleReference normal_ref1
=
268 manager_
->ShowBubble(MockBubbleDelegate::Default());
269 BubbleReference stubborn_ref2
=
270 manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
271 BubbleReference normal_ref2
=
272 manager_
->ShowBubble(MockBubbleDelegate::Default());
273 BubbleReference stubborn_ref3
=
274 manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
275 BubbleReference normal_ref3
=
276 manager_
->ShowBubble(MockBubbleDelegate::Default());
278 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
280 ASSERT_TRUE(stubborn_ref1
);
281 ASSERT_TRUE(stubborn_ref2
);
282 ASSERT_TRUE(stubborn_ref3
);
283 ASSERT_FALSE(normal_ref1
);
284 ASSERT_FALSE(normal_ref2
);
285 ASSERT_FALSE(normal_ref3
);
288 TEST_F(BubbleManagerTest
, UpdateAllShouldWorkWithoutBubbles
) {
289 // Manager shouldn't crash if bubbles have never been added.
290 manager_
->UpdateAllBubbleAnchors();
292 // Add a bubble and close it.
293 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
294 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
296 // Bubble should NOT get an update event because it's already closed.
297 manager_
->UpdateAllBubbleAnchors();
300 TEST_F(BubbleManagerTest
, CloseAllShouldWorkWithoutBubbles
) {
301 // Manager shouldn't crash if bubbles have never been added.
302 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
304 // Add a bubble and close it.
305 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
306 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
308 // Bubble should NOT get a close event because it's already closed.
309 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
312 TEST_F(BubbleManagerTest
, AllowBubbleChainingOnClose
) {
313 scoped_ptr
<BubbleDelegate
> chained_delegate
= MockBubbleDelegate::Default();
314 DelegateChainHelper
chain_helper(manager_
.get(), chained_delegate
.Pass());
316 // Manager will delete delegate.
317 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
318 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
319 .WillOnce(testing::Return(new MockBubbleUi
));
320 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
321 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
322 &chain_helper
, &DelegateChainHelper::Chain
),
323 testing::Return(true)));
325 BubbleReference ref
= manager_
->ShowBubble(make_scoped_ptr(delegate
));
326 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
328 ASSERT_TRUE(chain_helper
.BubbleWasTaken());
331 TEST_F(BubbleManagerTest
, AllowBubbleChainingOnCloseAll
) {
332 scoped_ptr
<BubbleDelegate
> chained_delegate
= MockBubbleDelegate::Default();
333 DelegateChainHelper
chain_helper(manager_
.get(), chained_delegate
.Pass());
335 // Manager will delete delegate.
336 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
337 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
338 .WillOnce(testing::Return(new MockBubbleUi
));
339 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
340 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
341 &chain_helper
, &DelegateChainHelper::Chain
),
342 testing::Return(true)));
344 manager_
->ShowBubble(make_scoped_ptr(delegate
));
345 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FORCED
);
347 ASSERT_TRUE(chain_helper
.BubbleWasTaken());
350 TEST_F(BubbleManagerTest
, BubblesDoNotChainOnDestroy
) {
351 // Manager will delete delegate.
352 MockBubbleDelegate
* chained_delegate
= new MockBubbleDelegate
;
353 EXPECT_CALL(*chained_delegate
, BuildBubbleUiMock()).Times(0);
354 EXPECT_CALL(*chained_delegate
, ShouldClose(testing::_
)).Times(0);
356 DelegateChainHelper
chain_helper(manager_
.get(),
357 make_scoped_ptr(chained_delegate
));
359 // Manager will delete delegate.
360 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
361 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
362 .WillOnce(testing::Return(new MockBubbleUi
));
363 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
364 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
365 &chain_helper
, &DelegateChainHelper::Chain
),
366 testing::Return(true)));
368 manager_
->ShowBubble(make_scoped_ptr(delegate
));
371 // The manager will take the bubble, but not show it.
372 ASSERT_TRUE(chain_helper
.BubbleWasTaken());
375 TEST_F(BubbleManagerTest
, BubbleUpdatesTrue
) {
376 MockBubbleUi
* bubble_ui
= new MockBubbleUi
;
377 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
378 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
379 .WillOnce(testing::Return(bubble_ui
));
380 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
381 .WillOnce(testing::Return(true));
382 EXPECT_CALL(*delegate
, UpdateBubbleUi(bubble_ui
))
383 .WillOnce(testing::Return(true));
385 BubbleReference ref
= manager_
->ShowBubble(make_scoped_ptr(delegate
));
386 ASSERT_TRUE(ref
->UpdateBubbleUi());
389 TEST_F(BubbleManagerTest
, BubbleUpdatesFalse
) {
390 MockBubbleUi
* bubble_ui
= new MockBubbleUi
;
391 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
392 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
393 .WillOnce(testing::Return(bubble_ui
));
394 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
395 .WillOnce(testing::Return(true));
396 EXPECT_CALL(*delegate
, UpdateBubbleUi(bubble_ui
))
397 .WillOnce(testing::Return(false));
399 BubbleReference ref
= manager_
->ShowBubble(make_scoped_ptr(delegate
));
400 ASSERT_FALSE(ref
->UpdateBubbleUi());
403 TEST_F(BubbleManagerTest
, BubbleCloseReasonIsCalled
) {
404 MockBubbleManagerObserver metrics
;
405 EXPECT_CALL(metrics
, OnBubbleNeverShown(testing::_
)).Times(0);
406 EXPECT_CALL(metrics
, OnBubbleClosed(testing::_
, BUBBLE_CLOSE_ACCEPTED
));
407 manager_
->AddBubbleManagerObserver(&metrics
);
409 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
410 ref
->CloseBubble(BUBBLE_CLOSE_ACCEPTED
);
412 // Destroy to verify no events are sent to |metrics| in destructor.
416 TEST_F(BubbleManagerTest
, BubbleCloseNeverShownIsCalled
) {
417 MockBubbleManagerObserver metrics
;
418 // |chained_delegate| should never be shown.
419 EXPECT_CALL(metrics
, OnBubbleNeverShown(testing::_
));
420 // |delegate| should be forced to close when the manager is destroyed.
421 EXPECT_CALL(metrics
, OnBubbleClosed(testing::_
, BUBBLE_CLOSE_FORCED
));
422 manager_
->AddBubbleManagerObserver(&metrics
);
424 // Manager will delete delegate.
425 MockBubbleDelegate
* chained_delegate
= new MockBubbleDelegate
;
426 EXPECT_CALL(*chained_delegate
, BuildBubbleUiMock()).Times(0);
427 EXPECT_CALL(*chained_delegate
, ShouldClose(testing::_
)).Times(0);
429 DelegateChainHelper
chain_helper(manager_
.get(),
430 make_scoped_ptr(chained_delegate
));
432 // Manager will delete delegate.
433 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
434 EXPECT_CALL(*delegate
, BuildBubbleUiMock())
435 .WillOnce(testing::Return(new MockBubbleUi
));
436 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
437 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
438 &chain_helper
, &DelegateChainHelper::Chain
),
439 testing::Return(true)));
441 manager_
->ShowBubble(make_scoped_ptr(delegate
));
444 // The manager will take the bubble, but not show it.
445 ASSERT_TRUE(chain_helper
.BubbleWasTaken());