Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / download / download_shelf_controller_unittest.mm
blobcbe05b38bb5ddb0c58f6ea5942d750a4ff81ca0e
1 // Copyright 2013 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 #import <Cocoa/Cocoa.h>
7 #import "base/mac/scoped_block.h"
8 #import "base/mac/scoped_nsobject.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "chrome/browser/download/download_shelf.h"
11 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
12 #import "chrome/browser/ui/cocoa/download/download_item_controller.h"
13 #import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
14 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
15 #include "content/public/test/mock_download_item.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/platform_test.h"
18 #import "third_party/ocmock/OCMock/OCMock.h"
19 #import "third_party/ocmock/gtest_support.h"
21 using ::testing::Return;
22 using ::testing::AnyNumber;
24 // Wraps a content::MockDownloadItem so it can be retained by the mock
25 // DownloadItemController.
26 @interface WrappedMockDownloadItem : NSObject {
27  @private
28   scoped_ptr<content::MockDownloadItem> download_;
30 - (id)initWithMockDownload:(scoped_ptr<content::MockDownloadItem>)download;
31 - (content::DownloadItem*)download;
32 - (content::MockDownloadItem*)mockDownload;
33 @end
35 @implementation WrappedMockDownloadItem
36 - (id)initWithMockDownload:(scoped_ptr<content::MockDownloadItem>)download {
37   if ((self = [super init])) {
38     download_ = download.Pass();
39   }
40   return self;
43 - (content::DownloadItem*)download {
44   return download_.get();
47 - (content::MockDownloadItem*)mockDownload {
48   return download_.get();
50 @end
52 // Test method for accessing the wrapped MockDownloadItem.
53 @interface DownloadItemController (DownloadShelfControllerTest) {
55 - (WrappedMockDownloadItem*)wrappedMockDownload;
56 @end
58 @implementation DownloadItemController (DownloadShelfControllerTest)
59 - (WrappedMockDownloadItem*)wrappedMockDownload {
60   return nil;
62 @end
64 @interface DownloadShelfController (Testing)
65 - (void)animationDidEnd:(NSAnimation*)animation;
66 @end
68 // Subclass of the DownloadShelfController to override scheduleAutoClose and
69 // cancelAutoClose. During regular operation, a scheduled autoClose waits for 5
70 // seconds before closing the shelf (unless it is cancelled during this
71 // time). For testing purposes, we count the number of invocations of
72 // {schedule,cancel}AutoClose instead of actually scheduling and cancelling.
73 @interface CountingDownloadShelfController : DownloadShelfController {
74  @public
75   int scheduleAutoCloseCount_;
76   int cancelAutoCloseCount_;
77   base::mac::ScopedBlock<dispatch_block_t> closeAnimationHandler_;
80 // Handler will be called at the end of a close animation.
81 - (void)setCloseAnimationHandler:(dispatch_block_t)handler;
82 @end
84 @implementation CountingDownloadShelfController
86 -(void)scheduleAutoClose {
87   ++scheduleAutoCloseCount_;
90 -(void)cancelAutoClose {
91   ++cancelAutoCloseCount_;
94 - (void)setCloseAnimationHandler:(dispatch_block_t)handler {
95   closeAnimationHandler_.reset(handler);
98 - (void)animationDidEnd:(NSAnimation*)animation {
99   [super animationDidEnd:animation];
100   if (closeAnimationHandler_)
101     closeAnimationHandler_.get()();
104 @end
106 namespace {
108 class DownloadShelfControllerTest : public CocoaProfileTest {
109  public:
110   void SetUp() override {
111     CocoaProfileTest::SetUp();
112     ASSERT_TRUE(browser());
114     resize_delegate_.reset([[ViewResizerPong alloc] init]);
115     shelf_.reset([[CountingDownloadShelfController alloc]
116                    initWithBrowser:browser()
117                     resizeDelegate:resize_delegate_.get()]);
118     EXPECT_TRUE([shelf_ view]);
119     [[test_window() contentView] addSubview:[shelf_ view]];
120   }
122   void TearDown() override {
123     if (shelf_.get()) {
124       shelf_.reset();
125     }
126     CocoaProfileTest::TearDown();
127   }
129  protected:
130   id CreateItemController();
132   base::scoped_nsobject<CountingDownloadShelfController> shelf_;
133   base::scoped_nsobject<ViewResizerPong> resize_delegate_;
136 id DownloadShelfControllerTest::CreateItemController() {
137   scoped_ptr<content::MockDownloadItem> download(
138       new ::testing::NiceMock<content::MockDownloadItem>);
139   ON_CALL(*download.get(), GetOpened())
140       .WillByDefault(Return(false));
141   ON_CALL(*download.get(), GetState())
142       .WillByDefault(Return(content::DownloadItem::IN_PROGRESS));
144   base::scoped_nsobject<WrappedMockDownloadItem> wrappedMockDownload(
145       [[WrappedMockDownloadItem alloc] initWithMockDownload:download.Pass()]);
147   id item_controller =
148       [OCMockObject mockForClass:[DownloadItemController class]];
149   base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
150   [[[item_controller stub] andCall:@selector(download)
151                           onObject:wrappedMockDownload.get()] download];
152   [[item_controller stub] updateVisibility:[OCMArg any]];
153   [[[item_controller stub]
154      andReturnValue:[NSValue valueWithSize:NSMakeSize(10,10)]] preferredSize];
155   [[[item_controller stub] andReturn:view.get()] view];
156   [[[item_controller stub]
157      andReturn:wrappedMockDownload.get()] wrappedMockDownload];
158   return [item_controller retain];
161 TEST_VIEW(DownloadShelfControllerTest, [shelf_ view]);
163 // Removing the last download from the shelf should cause it to close
164 // immediately.
165 TEST_F(DownloadShelfControllerTest, AddAndRemoveDownload) {
166   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
167   [shelf_ showDownloadShelf:YES
168                isUserAction:NO];
169   EXPECT_TRUE([shelf_ isVisible]);
170   EXPECT_TRUE([shelf_ bridge]->IsShowing());
171   [shelf_ add:item];
172   [shelf_ remove:item];
173   EXPECT_FALSE([shelf_ isVisible]);
174   EXPECT_FALSE([shelf_ bridge]->IsShowing());
175   // The shelf should be closed without scheduling an autoClose.
176   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
179 // Test that the shelf doesn't close automatically after a removal if there are
180 // active download items still on the shelf.
181 TEST_F(DownloadShelfControllerTest, AddAndRemoveWithActiveItem) {
182   base::scoped_nsobject<DownloadItemController> item1(CreateItemController());
183   base::scoped_nsobject<DownloadItemController> item2(CreateItemController());
184   [shelf_ showDownloadShelf:YES
185                isUserAction:NO];
186   EXPECT_TRUE([shelf_ isVisible]);
187   [shelf_ add:item1.get()];
188   [shelf_ add:item2.get()];
189   [shelf_ remove:item1.get()];
190   EXPECT_TRUE([shelf_ isVisible]);
191   [shelf_ remove:item2.get()];
192   EXPECT_FALSE([shelf_ isVisible]);
193   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
196 // DownloadShelf::Unhide() should cause the shelf to be displayed if there are
197 // active downloads on it.
198 TEST_F(DownloadShelfControllerTest, HideAndUnhide) {
199   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
200   [shelf_ showDownloadShelf:YES
201                isUserAction:NO];
202   EXPECT_TRUE([shelf_ isVisible]);
203   [shelf_ add:item.get()];
204   [shelf_ bridge]->Hide();
205   EXPECT_FALSE([shelf_ isVisible]);
206   [shelf_ bridge]->Unhide();
207   EXPECT_TRUE([shelf_ isVisible]);
208   [shelf_ remove:item.get()];
209   EXPECT_FALSE([shelf_ isVisible]);
212 // DownloadShelf::Unhide() shouldn't cause the shelf to be displayed if all
213 // active downloads are removed from the shelf while the shelf was hidden.
214 TEST_F(DownloadShelfControllerTest, HideAutocloseUnhide) {
215   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
216   [shelf_ showDownloadShelf:YES
217                isUserAction:NO];
218   EXPECT_TRUE([shelf_ isVisible]);
219   [shelf_ add:item.get()];
220   [shelf_ bridge]->Hide();
221   EXPECT_FALSE([shelf_ isVisible]);
222   [shelf_ remove:item.get()];
223   EXPECT_FALSE([shelf_ isVisible]);
224   [shelf_ bridge]->Unhide();
225   EXPECT_FALSE([shelf_ isVisible]);
228 // Test of autoclosing behavior after opening a download item. The mouse is on
229 // the download shelf at the time the autoclose is scheduled.
230 TEST_F(DownloadShelfControllerTest, AutoCloseAfterOpenWithMouseInShelf) {
231   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
232   [shelf_ showDownloadShelf:YES
233                isUserAction:NO];
234   EXPECT_TRUE([shelf_ isVisible]);
235   [shelf_ add:item.get()];
236   // Expect 2 cancelAutoClose calls: From the showDownloadShelf: call and the
237   // add: call.
238   EXPECT_EQ(2, shelf_.get()->cancelAutoCloseCount_);
239   shelf_.get()->cancelAutoCloseCount_ = 0;
241   // The mouse enters the shelf.
242   [shelf_ mouseEntered:nil];
243   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
245   // The download opens.
246   EXPECT_CALL(*[[item wrappedMockDownload] mockDownload], GetOpened())
247       .WillRepeatedly(Return(true));
248   [shelf_ downloadWasOpened:item.get()];
250   // The shelf should now be waiting for the mouse to exit.
251   EXPECT_TRUE([shelf_ isVisible]);
252   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
253   EXPECT_EQ(0, shelf_.get()->cancelAutoCloseCount_);
255   // The mouse exits the shelf. autoClose should be scheduled now.
256   [shelf_ mouseExited:nil];
257   EXPECT_EQ(1, shelf_.get()->scheduleAutoCloseCount_);
258   EXPECT_EQ(0, shelf_.get()->cancelAutoCloseCount_);
260   // The mouse enters the shelf again. The autoClose should be cancelled.
261   [shelf_ mouseEntered:nil];
262   EXPECT_EQ(1, shelf_.get()->scheduleAutoCloseCount_);
263   EXPECT_EQ(1, shelf_.get()->cancelAutoCloseCount_);
266 // Test of autoclosing behavior after opening a download item.
267 TEST_F(DownloadShelfControllerTest, AutoCloseAfterOpenWithMouseOffShelf) {
268   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
269   [shelf_ showDownloadShelf:YES
270                isUserAction:NO];
271   EXPECT_TRUE([shelf_ isVisible]);
272   [shelf_ add:item.get()];
274   // The download is opened.
275   EXPECT_CALL(*[[item wrappedMockDownload] mockDownload], GetOpened())
276       .WillRepeatedly(Return(true));
277   [shelf_ downloadWasOpened:item.get()];
279   // The shelf should be closed immediately since the mouse is not over the
280   // shelf.
281   EXPECT_FALSE([shelf_ isVisible]);
284 // Test that if the shelf is closed while an autoClose is pending, the pending
285 // autoClose is cancelled.
286 TEST_F(DownloadShelfControllerTest, CloseWithPendingAutoClose) {
287   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
288   [shelf_ showDownloadShelf:YES
289                isUserAction:NO];
290   EXPECT_TRUE([shelf_ isVisible]);
291   [shelf_ add:item.get()];
292   // Expect 2 cancelAutoClose calls: From the showDownloadShelf: call and the
293   // add: call.
294   EXPECT_EQ(2, shelf_.get()->cancelAutoCloseCount_);
295   shelf_.get()->cancelAutoCloseCount_ = 0;
297   // The mouse enters the shelf.
298   [shelf_ mouseEntered:nil];
299   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
301   // The download opens.
302   EXPECT_CALL(*[[item wrappedMockDownload] mockDownload], GetOpened())
303       .WillRepeatedly(Return(true));
304   [shelf_ downloadWasOpened:item.get()];
306   // The shelf should now be waiting for the mouse to exit. autoClose should not
307   // be scheduled yet.
308   EXPECT_TRUE([shelf_ isVisible]);
309   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
310   EXPECT_EQ(0, shelf_.get()->cancelAutoCloseCount_);
312   // The mouse exits the shelf. autoClose should be scheduled now.
313   [shelf_ mouseExited:nil];
314   EXPECT_EQ(1, shelf_.get()->scheduleAutoCloseCount_);
315   EXPECT_EQ(0, shelf_.get()->cancelAutoCloseCount_);
317   // Remove the download item. This should cause the download shelf to be hidden
318   // immediately. The pending autoClose should be cancelled.
319   [shelf_ remove:item];
320   EXPECT_EQ(1, shelf_.get()->scheduleAutoCloseCount_);
321   EXPECT_EQ(1, shelf_.get()->cancelAutoCloseCount_);
322   EXPECT_FALSE([shelf_ isVisible]);
325 // That that the shelf cancels a pending autoClose if a new download item is
326 // added to it.
327 TEST_F(DownloadShelfControllerTest, AddItemWithPendingAutoClose) {
328   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
329   [shelf_ showDownloadShelf:YES
330                isUserAction:NO];
331   EXPECT_TRUE([shelf_ isVisible]);
332   [shelf_ add:item.get()];
333   // Expect 2 cancelAutoClose calls: From the showDownloadShelf: call and the
334   // add: call.
335   EXPECT_EQ(2, shelf_.get()->cancelAutoCloseCount_);
336   shelf_.get()->cancelAutoCloseCount_ = 0;
338   // The mouse enters the shelf.
339   [shelf_ mouseEntered:nil];
340   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
342   // The download opens.
343   EXPECT_CALL(*[[item wrappedMockDownload] mockDownload], GetOpened())
344       .WillRepeatedly(Return(true));
345   [shelf_ downloadWasOpened:item.get()];
347   // The shelf should now be waiting for the mouse to exit. autoClose should not
348   // be scheduled yet.
349   EXPECT_TRUE([shelf_ isVisible]);
350   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
351   EXPECT_EQ(0, shelf_.get()->cancelAutoCloseCount_);
353   // The mouse exits the shelf. autoClose should be scheduled now.
354   [shelf_ mouseExited:nil];
355   EXPECT_EQ(1, shelf_.get()->scheduleAutoCloseCount_);
356   EXPECT_EQ(0, shelf_.get()->cancelAutoCloseCount_);
358   // Add a new download item. The pending autoClose should be cancelled.
359   base::scoped_nsobject<DownloadItemController> item2(CreateItemController());
360   [shelf_ add:item.get()];
361   EXPECT_EQ(1, shelf_.get()->scheduleAutoCloseCount_);
362   EXPECT_EQ(1, shelf_.get()->cancelAutoCloseCount_);
363   EXPECT_TRUE([shelf_ isVisible]);
366 // Test that pending autoClose calls are cancelled when exiting.
367 TEST_F(DownloadShelfControllerTest, CancelAutoCloseOnExit) {
368   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
369   [shelf_ showDownloadShelf:YES
370                isUserAction:NO];
371   EXPECT_TRUE([shelf_ isVisible]);
372   [shelf_ add:item.get()];
373   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
374   EXPECT_EQ(2, shelf_.get()->cancelAutoCloseCount_);
376   [shelf_ browserWillBeDestroyed];
377   EXPECT_EQ(0, shelf_.get()->scheduleAutoCloseCount_);
378   EXPECT_EQ(3, shelf_.get()->cancelAutoCloseCount_);
379   shelf_.reset();
382 // The view should not be hidden when the shelf is shown.
383 // The view should be hidden after the closing animation.
384 TEST_F(DownloadShelfControllerTest, ViewVisibility) {
385   [shelf_ showDownloadShelf:YES isUserAction:NO];
386   EXPECT_FALSE([[shelf_ view] isHidden]);
388   [shelf_ setCloseAnimationHandler:^{
389       base::MessageLoop::current()->QuitNow();
390   }];
391   [shelf_ showDownloadShelf:NO isUserAction:NO];
392   base::MessageLoop::current()->Run();
393   EXPECT_TRUE([[shelf_ view] isHidden]);
395   [shelf_ showDownloadShelf:YES isUserAction:NO];
396   EXPECT_FALSE([[shelf_ view] isHidden]);
399 }  // namespace