Roll src/third_party/skia d32087a:1052f51
[chromium-blink-merge.git] / ui / message_center / cocoa / notification_controller_unittest.mm
blob5b5999c25adc4212acbcdfd6761b337d30bb2bf6
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           ASCIIToUTF16("Added to circles"),
122           ASCIIToUTF16("Jonathan and 5 others"), gfx::Image(), base::string16(),
123           GURL(), DummyNotifierId(), message_center::RichNotificationData(),
124           NULL));
125   gfx::Image testIcon([TestIcon() retain]);
126   notification->set_icon(testIcon);
127   notification->set_small_image(testIcon);
129   base::scoped_nsobject<MCNotificationController> controller(
130       [[MCNotificationController alloc] initWithNotification:notification.get()
131                                                messageCenter:NULL]);
132   [controller view];
134   EXPECT_EQ(TestIcon(), [[controller iconView] image]);
135   EXPECT_EQ(TestIcon(), [[controller smallImageView] image]);
136   EXPECT_EQ(base::SysNSStringToUTF16([[controller titleView] string]),
137             notification->title());
138   EXPECT_EQ(base::SysNSStringToUTF16([[controller messageView] string]),
139             notification->message());
140   EXPECT_EQ(controller.get(), [[controller closeButton] target]);
143 TEST_F(NotificationControllerTest, OverflowText) {
144   scoped_ptr<message_center::Notification> notification(
145       new message_center::Notification(
146           message_center::NOTIFICATION_TYPE_SIMPLE, "",
147           ASCIIToUTF16("This is a much longer title that should wrap "
148                        "multiple lines."),
149           ASCIIToUTF16("And even the message is long. This sure is a wordy "
150                        "notification. Are you really going to read this "
151                        "entire thing?"),
152           gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
153           message_center::RichNotificationData(), NULL));
154   base::scoped_nsobject<MCNotificationController> controller(
155       [[MCNotificationController alloc] initWithNotification:notification.get()
156                                                messageCenter:NULL]);
157   [controller view];
159   EXPECT_GT(NSHeight([[controller view] frame]),
160             message_center::kNotificationIconSize);
163 TEST_F(NotificationControllerTest, Close) {
164   scoped_ptr<message_center::Notification> notification(
165       new message_center::Notification(
166           message_center::NOTIFICATION_TYPE_SIMPLE, "an_id", base::string16(),
167           base::string16(), gfx::Image(), base::string16(), GURL(),
168           DummyNotifierId(), message_center::RichNotificationData(), NULL));
169   MockMessageCenter message_center;
171   base::scoped_nsobject<MCNotificationController> controller(
172       [[MCNotificationController alloc] initWithNotification:notification.get()
173                                                messageCenter:&message_center]);
174   [controller view];
176   [[controller closeButton] performClick:nil];
178   EXPECT_EQ(1, message_center.remove_count());
179   EXPECT_EQ("an_id", message_center.last_removed_id());
180   EXPECT_TRUE(message_center.last_removed_by_user());
183 TEST_F(NotificationControllerTest, Update) {
184   scoped_ptr<message_center::Notification> notification(
185       new message_center::Notification(
186           message_center::NOTIFICATION_TYPE_SIMPLE, "",
187           ASCIIToUTF16("A simple title"),
188           ASCIIToUTF16("This message isn't too long and should fit in the"
189                        "default bounds."),
190           gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
191           message_center::RichNotificationData(), NULL));
192   base::scoped_nsobject<MCNotificationController> controller(
193       [[MCNotificationController alloc] initWithNotification:notification.get()
194                                                messageCenter:NULL]);
196   // Set up the default layout.
197   [controller view];
198   EXPECT_EQ(NSHeight([[controller view] frame]),
199             message_center::kNotificationIconSize);
200   EXPECT_FALSE([[controller iconView] image]);
201   EXPECT_FALSE([[controller smallImageView] image]);
203   // Update the icon.
204   gfx::Image testIcon([TestIcon() retain]);
205   notification->set_icon(testIcon);
206   notification->set_small_image(testIcon);
207   [controller updateNotification:notification.get()];
208   EXPECT_EQ(TestIcon(), [[controller iconView] image]);
209   EXPECT_EQ(TestIcon(), [[controller smallImageView] image]);
210   EXPECT_EQ(NSHeight([[controller view] frame]),
211             message_center::kNotificationIconSize);
214 TEST_F(NotificationControllerTest, Buttons) {
215   message_center::RichNotificationData optional;
216   message_center::ButtonInfo button1(UTF8ToUTF16("button1"));
217   optional.buttons.push_back(button1);
218   message_center::ButtonInfo button2(UTF8ToUTF16("button2"));
219   optional.buttons.push_back(button2);
221   scoped_ptr<message_center::Notification> notification(
222       new message_center::Notification(
223           message_center::NOTIFICATION_TYPE_BASE_FORMAT, "an_id",
224           base::string16(), base::string16(), gfx::Image(), base::string16(),
225           GURL(), DummyNotifierId(), optional, NULL));
226   MockMessageCenter message_center;
228   base::scoped_nsobject<MCNotificationController> controller(
229       [[MCNotificationController alloc] initWithNotification:notification.get()
230                                                messageCenter:&message_center]);
231   [controller view];
233   [[controller secondButton] performClick:nil];
235   EXPECT_EQ("an_id", message_center.last_clicked_id());
236   EXPECT_EQ(1, message_center.last_clicked_index());
239 TEST_F(NotificationControllerTest, Image) {
240   scoped_ptr<message_center::Notification> notification(
241       new message_center::Notification(
242           message_center::NOTIFICATION_TYPE_BASE_FORMAT, "an_id",
243           base::string16(), base::string16(), gfx::Image(), base::string16(),
244           GURL(), DummyNotifierId(), message_center::RichNotificationData(),
245           NULL));
246   NSImage* image = [NSImage imageNamed:NSImageNameFolder];
247   notification->set_image(gfx::Image([image retain]));
249   MockMessageCenter message_center;
251   base::scoped_nsobject<MCNotificationController> controller(
252       [[MCNotificationController alloc] initWithNotification:notification.get()
253                                                messageCenter:&message_center]);
254   [controller view];
256   ASSERT_EQ(1u, [[controller bottomSubviews] count]);
257   ASSERT_TRUE([[[[controller bottomSubviews] lastObject] contentView]
258       isKindOfClass:[NSImageView class]]);
259   EXPECT_EQ(image,
260       [[[[controller bottomSubviews] lastObject] contentView] image]);
263 TEST_F(NotificationControllerTest, List) {
264   message_center::RichNotificationData optional;
265   message_center::NotificationItem item1(
266       UTF8ToUTF16("First title"), UTF8ToUTF16("first message"));
267   optional.items.push_back(item1);
268   message_center::NotificationItem item2(
269       UTF8ToUTF16("Second title"),
270       UTF8ToUTF16("second slightly longer message"));
271   optional.items.push_back(item2);
272   message_center::NotificationItem item3(
273       UTF8ToUTF16(""),    // Test for empty string.
274       UTF8ToUTF16(" "));  // Test for string containing only spaces.
275   optional.items.push_back(item3);
276   optional.context_message = UTF8ToUTF16("Context Message");
278   scoped_ptr<message_center::Notification> notification(
279       new message_center::Notification(
280           message_center::NOTIFICATION_TYPE_BASE_FORMAT, "an_id",
281           UTF8ToUTF16("Notification Title"),
282           UTF8ToUTF16("Notification Message - should be hidden"), gfx::Image(),
283           base::string16(), GURL(), DummyNotifierId(), optional, NULL));
285   MockMessageCenter message_center;
286   base::scoped_nsobject<MCNotificationController> controller(
287       [[MCNotificationController alloc] initWithNotification:notification.get()
288                                                messageCenter:&message_center]);
289   [controller view];
291   EXPECT_FALSE([[controller titleView] isHidden]);
292   EXPECT_TRUE([[controller messageView] isHidden]);
293   EXPECT_FALSE([[controller contextMessageView] isHidden]);
295   EXPECT_EQ(3u, [[[controller listView] subviews] count]);
296   EXPECT_LT(NSMaxY([[controller listView] frame]),
297             NSMinY([[controller titleView] frame]));
300 TEST_F(NotificationControllerTest, NoMessage) {
301   message_center::RichNotificationData optional;
302   optional.context_message = UTF8ToUTF16("Context Message");
304   scoped_ptr<message_center::Notification> notification(
305       new message_center::Notification(
306           message_center::NOTIFICATION_TYPE_BASE_FORMAT, "an_id",
307           UTF8ToUTF16("Notification Title"), UTF8ToUTF16(""), gfx::Image(),
308           base::string16(), GURL(), DummyNotifierId(), optional, NULL));
310   MockMessageCenter message_center;
311   base::scoped_nsobject<MCNotificationController> controller(
312       [[MCNotificationController alloc] initWithNotification:notification.get()
313                                                messageCenter:&message_center]);
314   [controller view];
316   EXPECT_FALSE([[controller titleView] isHidden]);
317   EXPECT_TRUE([[controller messageView] isHidden]);
318   EXPECT_FALSE([[controller contextMessageView] isHidden]);
321 TEST_F(NotificationControllerTest, MessageSize) {
322   message_center::RichNotificationData data;
323   std::string id("id");
324   NotifierId notifier_id(NotifierId::APPLICATION, "notifier");
325   scoped_ptr<Notification> notification(new Notification(
326       NOTIFICATION_TYPE_BASE_FORMAT, id, base::UTF8ToUTF16(""),
327       ASCIIToUTF16("And\neven\nthe\nmessage is long.\nThis sure is wordy"),
328       gfx::Image(), base::string16() /* display_source */, GURL(), notifier_id,
329       data, NULL /* delegate */));
331   base::scoped_nsobject<MCNotificationController> controller(
332       [[MCNotificationController alloc] initWithNotification:notification.get()
333                                                messageCenter:NULL]);
335   // Set up the default layout.
336   [controller view];
338   auto compute_message_lines = ^{
339       NSString* string = [[[controller messageView] textStorage] string];
340       unsigned numberOfLines, index, stringLength = [string length];
341       for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++)
342         index = NSMaxRange([string lineRangeForRange:NSMakeRange(index, 0)]);
344       return numberOfLines;
345   };
347   // Message and no title: 5 lines.
348   EXPECT_EQ(5u, compute_message_lines());
350   // Message and one line title: 5 lines.
351   notification->set_title(ASCIIToUTF16("one line"));
352   [controller updateNotification:notification.get()];
353   EXPECT_EQ(5u, compute_message_lines());
355   // Message and two line title: 3 lines.
356   notification->set_title(ASCIIToUTF16("two\nlines"));
357   [controller updateNotification:notification.get()];
358   EXPECT_EQ(3u, compute_message_lines());
360   // Message, image and no title: 2 lines.
361   SkBitmap bitmap;
362   bitmap.allocN32Pixels(2, 2);
363   bitmap.eraseColor(SK_ColorGREEN);
364   notification->set_title(ASCIIToUTF16(""));
365   notification->set_image(gfx::Image::CreateFrom1xBitmap(bitmap));
366   [controller updateNotification:notification.get()];
367   EXPECT_EQ(2u, compute_message_lines());
369   // Message, image and one line title: 2 lines.
370   notification->set_title(ASCIIToUTF16("one line"));
371   [controller updateNotification:notification.get()];
372   EXPECT_EQ(2u, compute_message_lines());
374   // Message, image and two line title: 1 lines.
375   notification->set_title(ASCIIToUTF16("two\nlines"));
376   [controller updateNotification:notification.get()];
377   EXPECT_EQ(1u, compute_message_lines());
379   // Same as above, but context message takes away from message lines.
380   notification->set_context_message(UTF8ToUTF16("foo"));
381   notification->set_title(ASCIIToUTF16(""));
382   [controller updateNotification:notification.get()];
383   EXPECT_EQ(1u, compute_message_lines());
385   notification->set_title(ASCIIToUTF16("one line"));
386   [controller updateNotification:notification.get()];
387   EXPECT_EQ(1u, compute_message_lines());
389   notification->set_title(ASCIIToUTF16("two\nlines"));
390   [controller updateNotification:notification.get()];
391   EXPECT_EQ(0u, compute_message_lines());
394 }  // namespace message_center