Fix search results being clipped in app list.
[chromium-blink-merge.git] / ui / message_center / cocoa / notification_controller_unittest.mm
blob41573e1528c0199da328a21ce04e5f0ecd13f9a3
1 // Copyright (c) 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 "ui/message_center/cocoa/notification_controller.h"
7 #include "base/mac/foundation_util.h"
8 #include "base/mac/scoped_nsobject.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "third_party/skia/include/core/SkBitmap.h"
13 #import "ui/base/cocoa/hover_image_button.h"
14 #import "ui/gfx/test/ui_cocoa_test_helper.h"
15 #include "ui/message_center/fake_message_center.h"
16 #include "ui/message_center/message_center_style.h"
17 #include "ui/message_center/notification.h"
18 #include "ui/message_center/notification_types.h"
20 using base::ASCIIToUTF16;
21 using base::UTF8ToUTF16;
23 namespace {
25 class MockMessageCenter : public message_center::FakeMessageCenter {
26  public:
27   MockMessageCenter()
28       : last_removed_by_user_(false),
29         remove_count_(0),
30         last_clicked_index_(-1) {}
32   void RemoveNotification(const std::string& id, bool by_user) override {
33     last_removed_id_ = id;
34     last_removed_by_user_ = by_user;
35     ++remove_count_;
36   }
38   void ClickOnNotificationButton(const std::string& id,
39                                  int button_index) override {
40     last_clicked_id_ = id;
41     last_clicked_index_ = button_index;
42   }
44   const std::string& last_removed_id() const { return last_removed_id_; }
45   bool last_removed_by_user() const { return last_removed_by_user_; }
46   int remove_count() const { return remove_count_; }
47   const std::string& last_clicked_id() const { return last_clicked_id_; }
48   int last_clicked_index() const { return last_clicked_index_; }
50  private:
51   std::string last_removed_id_;
52   bool last_removed_by_user_;
53   int remove_count_;
55   std::string last_clicked_id_;
56   int last_clicked_index_;
58   DISALLOW_COPY_AND_ASSIGN(MockMessageCenter);
61 }  // namespace
63 @implementation MCNotificationController (TestingInterface)
64 - (NSButton*)closeButton {
65   return closeButton_.get();
68 - (NSImageView*)smallImageView {
69   return smallImage_.get();
72 - (NSButton*)secondButton {
73   // The buttons are in Cocoa-y-order, so the 2nd button is first.
74   NSView* view = [[bottomView_ subviews] objectAtIndex:0];
75   return base::mac::ObjCCastStrict<NSButton>(view);
78 - (NSArray*)bottomSubviews {
79   return [bottomView_ subviews];
82 - (NSImageView*)iconView {
83   return icon_.get();
86 - (NSTextView*)titleView {
87   return title_.get();
90 - (NSTextView*)messageView {
91   return message_.get();
94 - (NSTextView*)contextMessageView {
95   return contextMessage_.get();
98 - (NSView*)listView {
99   return listView_.get();
101 @end
103 namespace message_center {
105 class NotificationControllerTest : public ui::CocoaTest {
106  public:
107   NSImage* TestIcon() {
108     return [NSImage imageNamed:NSImageNameUser];
109   }
111  protected:
112   message_center::NotifierId DummyNotifierId() {
113     return message_center::NotifierId();
114   }
117 TEST_F(NotificationControllerTest, BasicLayout) {
118   scoped_ptr<message_center::Notification> notification(
119       new message_center::Notification(
120           message_center::NOTIFICATION_TYPE_SIMPLE,
121           "",
122           ASCIIToUTF16("Added to circles"),
123           ASCIIToUTF16("Jonathan and 5 others"),
124           gfx::Image(),
125           base::string16(),
126           DummyNotifierId(),
127           message_center::RichNotificationData(),
128           NULL));
129   gfx::Image testIcon([TestIcon() retain]);
130   notification->set_icon(testIcon);
131   notification->set_small_image(testIcon);
133   base::scoped_nsobject<MCNotificationController> controller(
134       [[MCNotificationController alloc] initWithNotification:notification.get()
135                                                messageCenter:NULL]);
136   [controller view];
138   EXPECT_EQ(TestIcon(), [[controller iconView] image]);
139   EXPECT_EQ(TestIcon(), [[controller smallImageView] image]);
140   EXPECT_EQ(base::SysNSStringToUTF16([[controller titleView] string]),
141             notification->title());
142   EXPECT_EQ(base::SysNSStringToUTF16([[controller messageView] string]),
143             notification->message());
144   EXPECT_EQ(controller.get(), [[controller closeButton] target]);
147 TEST_F(NotificationControllerTest, OverflowText) {
148   scoped_ptr<message_center::Notification> notification(
149       new message_center::Notification(
150           message_center::NOTIFICATION_TYPE_SIMPLE,
151           "",
152           ASCIIToUTF16("This is a much longer title that should wrap "
153                        "multiple lines."),
154           ASCIIToUTF16("And even the message is long. This sure is a wordy "
155                        "notification. Are you really going to read this "
156                        "entire thing?"),
157           gfx::Image(),
158           base::string16(),
159           DummyNotifierId(),
160           message_center::RichNotificationData(),
161           NULL));
162   base::scoped_nsobject<MCNotificationController> controller(
163       [[MCNotificationController alloc] initWithNotification:notification.get()
164                                                messageCenter:NULL]);
165   [controller view];
167   EXPECT_GT(NSHeight([[controller view] frame]),
168             message_center::kNotificationIconSize);
171 TEST_F(NotificationControllerTest, Close) {
172   scoped_ptr<message_center::Notification> notification(
173       new message_center::Notification(
174           message_center::NOTIFICATION_TYPE_SIMPLE,
175           "an_id",
176           base::string16(),
177           base::string16(),
178           gfx::Image(),
179           base::string16(),
180           DummyNotifierId(),
181           message_center::RichNotificationData(),
182           NULL));
183   MockMessageCenter message_center;
185   base::scoped_nsobject<MCNotificationController> controller(
186       [[MCNotificationController alloc] initWithNotification:notification.get()
187                                                messageCenter:&message_center]);
188   [controller view];
190   [[controller closeButton] performClick:nil];
192   EXPECT_EQ(1, message_center.remove_count());
193   EXPECT_EQ("an_id", message_center.last_removed_id());
194   EXPECT_TRUE(message_center.last_removed_by_user());
197 TEST_F(NotificationControllerTest, Update) {
198   scoped_ptr<message_center::Notification> notification(
199       new message_center::Notification(
200           message_center::NOTIFICATION_TYPE_SIMPLE,
201           "",
202           ASCIIToUTF16("A simple title"),
203           ASCIIToUTF16("This message isn't too long and should fit in the"
204                        "default bounds."),
205           gfx::Image(),
206           base::string16(),
207           DummyNotifierId(),
208           message_center::RichNotificationData(),
209           NULL));
210   base::scoped_nsobject<MCNotificationController> controller(
211       [[MCNotificationController alloc] initWithNotification:notification.get()
212                                                messageCenter:NULL]);
214   // Set up the default layout.
215   [controller view];
216   EXPECT_EQ(NSHeight([[controller view] frame]),
217             message_center::kNotificationIconSize);
218   EXPECT_FALSE([[controller iconView] image]);
219   EXPECT_FALSE([[controller smallImageView] image]);
221   // Update the icon.
222   gfx::Image testIcon([TestIcon() retain]);
223   notification->set_icon(testIcon);
224   notification->set_small_image(testIcon);
225   [controller updateNotification:notification.get()];
226   EXPECT_EQ(TestIcon(), [[controller iconView] image]);
227   EXPECT_EQ(TestIcon(), [[controller smallImageView] image]);
228   EXPECT_EQ(NSHeight([[controller view] frame]),
229             message_center::kNotificationIconSize);
232 TEST_F(NotificationControllerTest, Buttons) {
233   message_center::RichNotificationData optional;
234   message_center::ButtonInfo button1(UTF8ToUTF16("button1"));
235   optional.buttons.push_back(button1);
236   message_center::ButtonInfo button2(UTF8ToUTF16("button2"));
237   optional.buttons.push_back(button2);
239   scoped_ptr<message_center::Notification> notification(
240       new message_center::Notification(
241           message_center::NOTIFICATION_TYPE_BASE_FORMAT,
242           "an_id",
243           base::string16(),
244           base::string16(),
245           gfx::Image(),
246           base::string16(),
247           DummyNotifierId(),
248           optional,
249           NULL));
250   MockMessageCenter message_center;
252   base::scoped_nsobject<MCNotificationController> controller(
253       [[MCNotificationController alloc] initWithNotification:notification.get()
254                                                messageCenter:&message_center]);
255   [controller view];
257   [[controller secondButton] performClick:nil];
259   EXPECT_EQ("an_id", message_center.last_clicked_id());
260   EXPECT_EQ(1, message_center.last_clicked_index());
263 TEST_F(NotificationControllerTest, Image) {
264   scoped_ptr<message_center::Notification> notification(
265       new message_center::Notification(
266           message_center::NOTIFICATION_TYPE_BASE_FORMAT,
267           "an_id",
268           base::string16(),
269           base::string16(),
270           gfx::Image(),
271           base::string16(),
272           DummyNotifierId(),
273           message_center::RichNotificationData(),
274           NULL));
275   NSImage* image = [NSImage imageNamed:NSImageNameFolder];
276   notification->set_image(gfx::Image([image retain]));
278   MockMessageCenter message_center;
280   base::scoped_nsobject<MCNotificationController> controller(
281       [[MCNotificationController alloc] initWithNotification:notification.get()
282                                                messageCenter:&message_center]);
283   [controller view];
285   ASSERT_EQ(1u, [[controller bottomSubviews] count]);
286   ASSERT_TRUE([[[[controller bottomSubviews] lastObject] contentView]
287       isKindOfClass:[NSImageView class]]);
288   EXPECT_EQ(image,
289       [[[[controller bottomSubviews] lastObject] contentView] image]);
292 TEST_F(NotificationControllerTest, List) {
293   message_center::RichNotificationData optional;
294   message_center::NotificationItem item1(
295       UTF8ToUTF16("First title"), UTF8ToUTF16("first message"));
296   optional.items.push_back(item1);
297   message_center::NotificationItem item2(
298       UTF8ToUTF16("Second title"),
299       UTF8ToUTF16("second slightly longer message"));
300   optional.items.push_back(item2);
301   message_center::NotificationItem item3(
302       UTF8ToUTF16(""),    // Test for empty string.
303       UTF8ToUTF16(" "));  // Test for string containing only spaces.
304   optional.items.push_back(item3);
305   optional.context_message = UTF8ToUTF16("Context Message");
307   scoped_ptr<message_center::Notification> notification(
308       new message_center::Notification(
309           message_center::NOTIFICATION_TYPE_BASE_FORMAT,
310           "an_id",
311           UTF8ToUTF16("Notification Title"),
312           UTF8ToUTF16("Notification Message - should be hidden"),
313           gfx::Image(),
314           base::string16(),
315           DummyNotifierId(),
316           optional,
317           NULL));
319   MockMessageCenter message_center;
320   base::scoped_nsobject<MCNotificationController> controller(
321       [[MCNotificationController alloc] initWithNotification:notification.get()
322                                                messageCenter:&message_center]);
323   [controller view];
325   EXPECT_FALSE([[controller titleView] isHidden]);
326   EXPECT_TRUE([[controller messageView] isHidden]);
327   EXPECT_FALSE([[controller contextMessageView] isHidden]);
329   EXPECT_EQ(3u, [[[controller listView] subviews] count]);
330   EXPECT_LT(NSMaxY([[controller listView] frame]),
331             NSMinY([[controller titleView] frame]));
334 TEST_F(NotificationControllerTest, NoMessage) {
335   message_center::RichNotificationData optional;
336   optional.context_message = UTF8ToUTF16("Context Message");
338   scoped_ptr<message_center::Notification> notification(
339       new message_center::Notification(
340           message_center::NOTIFICATION_TYPE_BASE_FORMAT,
341           "an_id",
342           UTF8ToUTF16("Notification Title"),
343           UTF8ToUTF16(""),
344           gfx::Image(),
345           base::string16(),
346           DummyNotifierId(),
347           optional,
348           NULL));
350   MockMessageCenter message_center;
351   base::scoped_nsobject<MCNotificationController> controller(
352       [[MCNotificationController alloc] initWithNotification:notification.get()
353                                                messageCenter:&message_center]);
354   [controller view];
356   EXPECT_FALSE([[controller titleView] isHidden]);
357   EXPECT_TRUE([[controller messageView] isHidden]);
358   EXPECT_FALSE([[controller contextMessageView] isHidden]);
361 TEST_F(NotificationControllerTest, MessageSize) {
362   message_center::RichNotificationData data;
363   std::string id("id");
364   NotifierId notifier_id(NotifierId::APPLICATION, "notifier");
365   scoped_ptr<Notification> notification(new Notification(
366       NOTIFICATION_TYPE_BASE_FORMAT,
367       id,
368       base::UTF8ToUTF16(""),
369       ASCIIToUTF16("And\neven\nthe\nmessage is long.\nThis sure is wordy"),
370       gfx::Image(),
371       base::string16() /* display_source */,
372       notifier_id,
373       data,
374       NULL /* delegate */));
376   base::scoped_nsobject<MCNotificationController> controller(
377       [[MCNotificationController alloc] initWithNotification:notification.get()
378                                                messageCenter:NULL]);
380   // Set up the default layout.
381   [controller view];
383   auto compute_message_lines = ^{
384       NSString* string = [[[controller messageView] textStorage] string];
385       unsigned numberOfLines, index, stringLength = [string length];
386       for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++)
387         index = NSMaxRange([string lineRangeForRange:NSMakeRange(index, 0)]);
389       return numberOfLines;
390   };
392   // Message and no title: 5 lines.
393   EXPECT_EQ(5u, compute_message_lines());
395   // Message and one line title: 5 lines.
396   notification->set_title(ASCIIToUTF16("one line"));
397   [controller updateNotification:notification.get()];
398   EXPECT_EQ(5u, compute_message_lines());
400   // Message and two line title: 3 lines.
401   notification->set_title(ASCIIToUTF16("two\nlines"));
402   [controller updateNotification:notification.get()];
403   EXPECT_EQ(3u, compute_message_lines());
405   // Message, image and no title: 2 lines.
406   SkBitmap bitmap;
407   bitmap.allocN32Pixels(2, 2);
408   bitmap.eraseColor(SK_ColorGREEN);
409   notification->set_title(ASCIIToUTF16(""));
410   notification->set_image(gfx::Image::CreateFrom1xBitmap(bitmap));
411   [controller updateNotification:notification.get()];
412   EXPECT_EQ(2u, compute_message_lines());
414   // Message, image and one line title: 2 lines.
415   notification->set_title(ASCIIToUTF16("one line"));
416   [controller updateNotification:notification.get()];
417   EXPECT_EQ(2u, compute_message_lines());
419   // Message, image and two line title: 1 lines.
420   notification->set_title(ASCIIToUTF16("two\nlines"));
421   [controller updateNotification:notification.get()];
422   EXPECT_EQ(1u, compute_message_lines());
424   // Same as above, but context message takes away from message lines.
425   notification->set_context_message(base::UTF8ToUTF16("foo"));
426   notification->set_title(ASCIIToUTF16(""));
427   [controller updateNotification:notification.get()];
428   EXPECT_EQ(1u, compute_message_lines());
430   notification->set_title(ASCIIToUTF16("one line"));
431   [controller updateNotification:notification.get()];
432   EXPECT_EQ(1u, compute_message_lines());
434   notification->set_title(ASCIIToUTF16("two\nlines"));
435   [controller updateNotification:notification.get()];
436   EXPECT_EQ(0u, compute_message_lines());
439 }  // namespace message_center