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_ui.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
15 class MockBubbleUI
: public BubbleUI
{
18 ~MockBubbleUI() override
{ Destroyed(); }
20 MOCK_METHOD0(Show
, void());
21 MOCK_METHOD0(Close
, void());
22 MOCK_METHOD0(UpdateAnchorPosition
, void());
24 // To verify destructor call.
25 MOCK_METHOD0(Destroyed
, void());
28 class MockBubbleDelegate
: public BubbleDelegate
{
30 MockBubbleDelegate() {}
31 ~MockBubbleDelegate() override
{ Destroyed(); }
33 // Default bubble shows UI and closes when asked to close.
34 static scoped_ptr
<MockBubbleDelegate
> Default();
36 // Stubborn bubble shows UI and doesn't want to close.
37 static scoped_ptr
<MockBubbleDelegate
> Stubborn();
39 MOCK_METHOD1(ShouldClose
, bool(BubbleCloseReason reason
));
41 // A scoped_ptr can't be returned in MOCK_METHOD.
42 MOCK_METHOD0(BuildBubbleUIMock
, BubbleUI
*());
43 scoped_ptr
<BubbleUI
> BuildBubbleUI() override
{
44 return make_scoped_ptr(BuildBubbleUIMock());
47 // To verify destructor call.
48 MOCK_METHOD0(Destroyed
, void());
52 scoped_ptr
<MockBubbleDelegate
> MockBubbleDelegate::Default() {
53 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
54 EXPECT_CALL(*delegate
, BuildBubbleUIMock())
55 .WillOnce(testing::Return(new MockBubbleUI
));
56 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
57 .WillOnce(testing::Return(true));
58 return make_scoped_ptr(delegate
);
62 scoped_ptr
<MockBubbleDelegate
> MockBubbleDelegate::Stubborn() {
63 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
64 EXPECT_CALL(*delegate
, BuildBubbleUIMock())
65 .WillOnce(testing::Return(new MockBubbleUI
));
66 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
67 .WillRepeatedly(testing::Return(false));
68 return make_scoped_ptr(delegate
);
71 // Helper class used to test chaining another bubble.
72 class DelegateChainHelper
{
74 DelegateChainHelper(BubbleManager
* manager
,
75 scoped_ptr
<BubbleDelegate
> next_delegate
);
77 // Will show the bubble in |next_delegate_|.
78 void Chain() { manager_
->ShowBubble(next_delegate_
.Pass()); }
80 // True if the bubble was taken by the bubble manager.
81 bool BubbleWasTaken() { return !next_delegate_
; }
84 BubbleManager
* manager_
; // Weak.
85 scoped_ptr
<BubbleDelegate
> next_delegate_
;
88 DelegateChainHelper::DelegateChainHelper(
89 BubbleManager
* manager
,
90 scoped_ptr
<BubbleDelegate
> next_delegate
)
91 : manager_(manager
), next_delegate_(next_delegate
.Pass()) {}
93 class BubbleManagerTest
: public testing::Test
{
96 ~BubbleManagerTest() override
{}
98 void SetUp() override
;
99 void TearDown() override
;
102 scoped_ptr
<BubbleManager
> manager_
;
105 BubbleManagerTest::BubbleManagerTest() {}
107 void BubbleManagerTest::SetUp() {
108 testing::Test::SetUp();
109 manager_
.reset(new BubbleManager
);
112 void BubbleManagerTest::TearDown() {
114 testing::Test::TearDown();
117 TEST_F(BubbleManagerTest
, ManagerShowsBubbleUI
) {
118 // Manager will delete bubble_ui.
119 MockBubbleUI
* bubble_ui
= new MockBubbleUI
;
120 EXPECT_CALL(*bubble_ui
, Destroyed());
121 EXPECT_CALL(*bubble_ui
, Show());
122 EXPECT_CALL(*bubble_ui
, Close());
123 EXPECT_CALL(*bubble_ui
, UpdateAnchorPosition()).Times(0);
125 // Manager will delete delegate.
126 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
127 EXPECT_CALL(*delegate
, Destroyed());
128 EXPECT_CALL(*delegate
, BuildBubbleUIMock())
129 .WillOnce(testing::Return(bubble_ui
));
130 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
131 .WillOnce(testing::Return(true));
133 manager_
->ShowBubble(make_scoped_ptr(delegate
));
136 TEST_F(BubbleManagerTest
, ManagerUpdatesBubbleUI
) {
137 // Manager will delete bubble_ui.
138 MockBubbleUI
* bubble_ui
= new MockBubbleUI
;
139 EXPECT_CALL(*bubble_ui
, Destroyed());
140 EXPECT_CALL(*bubble_ui
, Show());
141 EXPECT_CALL(*bubble_ui
, Close());
142 EXPECT_CALL(*bubble_ui
, UpdateAnchorPosition());
144 // Manager will delete delegate.
145 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
146 EXPECT_CALL(*delegate
, Destroyed());
147 EXPECT_CALL(*delegate
, BuildBubbleUIMock())
148 .WillOnce(testing::Return(bubble_ui
));
149 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
150 .WillOnce(testing::Return(true));
152 manager_
->ShowBubble(make_scoped_ptr(delegate
));
153 manager_
->UpdateAllBubbleAnchors();
156 TEST_F(BubbleManagerTest
, CloseOnReferenceInvalidatesReference
) {
157 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
159 ASSERT_TRUE(ref
->CloseBubble(BUBBLE_CLOSE_FOCUS_LOST
));
164 TEST_F(BubbleManagerTest
, CloseOnStubbornReferenceDoesNotInvalidate
) {
165 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
167 ASSERT_FALSE(ref
->CloseBubble(BUBBLE_CLOSE_FOCUS_LOST
));
172 TEST_F(BubbleManagerTest
, CloseInvalidatesReference
) {
173 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
175 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FOCUS_LOST
));
180 TEST_F(BubbleManagerTest
, CloseAllInvalidatesReference
) {
181 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
183 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
188 TEST_F(BubbleManagerTest
, DestroyInvalidatesReference
) {
189 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
196 TEST_F(BubbleManagerTest
, CloseInvalidatesStubbornReference
) {
197 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
199 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
204 TEST_F(BubbleManagerTest
, CloseAllInvalidatesStubbornReference
) {
205 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
207 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FORCED
);
212 TEST_F(BubbleManagerTest
, DestroyInvalidatesStubbornReference
) {
213 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
220 TEST_F(BubbleManagerTest
, CloseDoesNotInvalidateStubbornReference
) {
221 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
223 ASSERT_FALSE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FOCUS_LOST
));
228 TEST_F(BubbleManagerTest
, CloseAllDoesNotInvalidateStubbornReference
) {
229 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
231 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
236 TEST_F(BubbleManagerTest
, CloseAllInvalidatesMixAppropriately
) {
237 BubbleReference stubborn_ref1
=
238 manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
239 BubbleReference normal_ref1
=
240 manager_
->ShowBubble(MockBubbleDelegate::Default());
241 BubbleReference stubborn_ref2
=
242 manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
243 BubbleReference normal_ref2
=
244 manager_
->ShowBubble(MockBubbleDelegate::Default());
245 BubbleReference stubborn_ref3
=
246 manager_
->ShowBubble(MockBubbleDelegate::Stubborn());
247 BubbleReference normal_ref3
=
248 manager_
->ShowBubble(MockBubbleDelegate::Default());
250 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
252 ASSERT_TRUE(stubborn_ref1
);
253 ASSERT_TRUE(stubborn_ref2
);
254 ASSERT_TRUE(stubborn_ref3
);
255 ASSERT_FALSE(normal_ref1
);
256 ASSERT_FALSE(normal_ref2
);
257 ASSERT_FALSE(normal_ref3
);
260 TEST_F(BubbleManagerTest
, UpdateAllShouldWorkWithoutBubbles
) {
261 // Manager shouldn't crash if bubbles have never been added.
262 manager_
->UpdateAllBubbleAnchors();
264 // Add a bubble and close it.
265 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
266 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
268 // Bubble should NOT get an update event because it's already closed.
269 manager_
->UpdateAllBubbleAnchors();
272 TEST_F(BubbleManagerTest
, CloseAllShouldWorkWithoutBubbles
) {
273 // Manager shouldn't crash if bubbles have never been added.
274 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
276 // Add a bubble and close it.
277 BubbleReference ref
= manager_
->ShowBubble(MockBubbleDelegate::Default());
278 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
280 // Bubble should NOT get a close event because it's already closed.
281 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST
);
284 TEST_F(BubbleManagerTest
, AllowBubbleChainingOnClose
) {
285 scoped_ptr
<BubbleDelegate
> chained_delegate
= MockBubbleDelegate::Default();
286 DelegateChainHelper
chain_helper(manager_
.get(), chained_delegate
.Pass());
288 // Manager will delete delegate.
289 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
290 EXPECT_CALL(*delegate
, BuildBubbleUIMock())
291 .WillOnce(testing::Return(new MockBubbleUI
));
292 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
293 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
294 &chain_helper
, &DelegateChainHelper::Chain
),
295 testing::Return(true)));
297 BubbleReference ref
= manager_
->ShowBubble(make_scoped_ptr(delegate
));
298 ASSERT_TRUE(manager_
->CloseBubble(ref
, BUBBLE_CLOSE_FORCED
));
300 ASSERT_TRUE(chain_helper
.BubbleWasTaken());
303 TEST_F(BubbleManagerTest
, AllowBubbleChainingOnCloseAll
) {
304 scoped_ptr
<BubbleDelegate
> chained_delegate
= MockBubbleDelegate::Default();
305 DelegateChainHelper
chain_helper(manager_
.get(), chained_delegate
.Pass());
307 // Manager will delete delegate.
308 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
309 EXPECT_CALL(*delegate
, BuildBubbleUIMock())
310 .WillOnce(testing::Return(new MockBubbleUI
));
311 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
312 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
313 &chain_helper
, &DelegateChainHelper::Chain
),
314 testing::Return(true)));
316 manager_
->ShowBubble(make_scoped_ptr(delegate
));
317 manager_
->CloseAllBubbles(BUBBLE_CLOSE_FORCED
);
319 ASSERT_TRUE(chain_helper
.BubbleWasTaken());
322 TEST_F(BubbleManagerTest
, BubblesDoNotChainOnDestroy
) {
323 // Manager will delete delegate.
324 MockBubbleDelegate
* chained_delegate
= new MockBubbleDelegate
;
325 EXPECT_CALL(*chained_delegate
, BuildBubbleUIMock()).Times(0);
326 EXPECT_CALL(*chained_delegate
, ShouldClose(testing::_
)).Times(0);
328 DelegateChainHelper
chain_helper(manager_
.get(),
329 make_scoped_ptr(chained_delegate
));
331 // Manager will delete delegate.
332 MockBubbleDelegate
* delegate
= new MockBubbleDelegate
;
333 EXPECT_CALL(*delegate
, BuildBubbleUIMock())
334 .WillOnce(testing::Return(new MockBubbleUI
));
335 EXPECT_CALL(*delegate
, ShouldClose(testing::_
))
336 .WillOnce(testing::DoAll(testing::InvokeWithoutArgs(
337 &chain_helper
, &DelegateChainHelper::Chain
),
338 testing::Return(true)));
340 manager_
->ShowBubble(make_scoped_ptr(delegate
));
343 // The manager will take the bubble, but not show it.
344 ASSERT_TRUE(chain_helper
.BubbleWasTaken());