Home | History | Annotate | Download | only in cocoa
      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.
      4 
      5 #import "ui/message_center/cocoa/notification_controller.h"
      6 
      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 #import "ui/base/cocoa/hover_image_button.h"
     13 #import "ui/base/test/ui_cocoa_test_helper.h"
     14 #include "ui/message_center/fake_message_center.h"
     15 #include "ui/message_center/message_center_style.h"
     16 #include "ui/message_center/notification.h"
     17 #include "ui/message_center/notification_types.h"
     18 
     19 namespace {
     20 
     21 class MockMessageCenter : public message_center::FakeMessageCenter {
     22  public:
     23   MockMessageCenter()
     24       : last_removed_by_user_(false),
     25         remove_count_(0),
     26         last_clicked_index_(-1) {}
     27 
     28   virtual void RemoveNotification(const std::string& id,
     29                                   bool by_user) OVERRIDE {
     30     last_removed_id_ = id;
     31     last_removed_by_user_ = by_user;
     32     ++remove_count_;
     33   }
     34 
     35   virtual void ClickOnNotificationButton(const std::string& id,
     36                                          int button_index) OVERRIDE {
     37     last_clicked_id_ = id;
     38     last_clicked_index_ = button_index;
     39   }
     40 
     41   const std::string& last_removed_id() const { return last_removed_id_; }
     42   bool last_removed_by_user() const { return last_removed_by_user_; }
     43   int remove_count() const { return remove_count_; }
     44   const std::string& last_clicked_id() const { return last_clicked_id_; }
     45   int last_clicked_index() const { return last_clicked_index_; }
     46 
     47  private:
     48   std::string last_removed_id_;
     49   bool last_removed_by_user_;
     50   int remove_count_;
     51 
     52   std::string last_clicked_id_;
     53   int last_clicked_index_;
     54 
     55   DISALLOW_COPY_AND_ASSIGN(MockMessageCenter);
     56 };
     57 
     58 }
     59 
     60 @implementation MCNotificationController (TestingInterface)
     61 - (NSButton*)closeButton {
     62   return closeButton_.get();
     63 }
     64 
     65 - (NSButton*)secondButton {
     66   // The buttons are in Cocoa-y-order, so the 2nd button is first.
     67   NSView* view = [[bottomView_ subviews] objectAtIndex:0];
     68   return base::mac::ObjCCastStrict<NSButton>(view);
     69 }
     70 
     71 - (NSArray*)bottomSubviews {
     72   return [bottomView_ subviews];
     73 }
     74 
     75 - (NSImageView*)iconView {
     76   return icon_.get();
     77 }
     78 
     79 - (NSTextField*)titleView {
     80   return title_.get();
     81 }
     82 
     83 - (NSTextField*)messageView {
     84   return message_.get();
     85 }
     86 
     87 - (NSView*)listItemView {
     88   return listItemView_.get();
     89 }
     90 @end
     91 
     92 class NotificationControllerTest : public ui::CocoaTest {
     93  public:
     94   NSImage* TestIcon() {
     95     return [NSImage imageNamed:NSImageNameUser];
     96   }
     97 };
     98 
     99 TEST_F(NotificationControllerTest, BasicLayout) {
    100   scoped_ptr<message_center::Notification> notification(
    101       new message_center::Notification(
    102           message_center::NOTIFICATION_TYPE_SIMPLE,
    103           "",
    104           ASCIIToUTF16("Added to circles"),
    105           ASCIIToUTF16("Jonathan and 5 others"),
    106           gfx::Image(),
    107           string16(),
    108           std::string(),
    109           message_center::RichNotificationData(),
    110           NULL));
    111   notification->set_icon(gfx::Image([TestIcon() retain]));
    112 
    113   base::scoped_nsobject<MCNotificationController> controller(
    114       [[MCNotificationController alloc] initWithNotification:notification.get()
    115                                                messageCenter:NULL]);
    116   [controller view];
    117 
    118   EXPECT_EQ(TestIcon(), [[controller iconView] image]);
    119   EXPECT_EQ(base::SysNSStringToUTF16([[controller titleView] stringValue]),
    120             notification->title());
    121   EXPECT_EQ(base::SysNSStringToUTF16([[controller messageView] stringValue]),
    122             notification->message());
    123   EXPECT_EQ(controller.get(), [[controller closeButton] target]);
    124 }
    125 
    126 TEST_F(NotificationControllerTest, OverflowText) {
    127   scoped_ptr<message_center::Notification> notification(
    128       new message_center::Notification(
    129           message_center::NOTIFICATION_TYPE_SIMPLE,
    130           "",
    131           ASCIIToUTF16("This is a much longer title that should wrap "
    132                        "multiple lines."),
    133           ASCIIToUTF16("And even the message is long. This sure is a wordy "
    134                        "notification. Are you really going to read this "
    135                        "entire thing?"),
    136           gfx::Image(),
    137           string16(),
    138           std::string(),
    139           message_center::RichNotificationData(),
    140           NULL));
    141   base::scoped_nsobject<MCNotificationController> controller(
    142       [[MCNotificationController alloc] initWithNotification:notification.get()
    143                                                messageCenter:NULL]);
    144   [controller view];
    145 
    146   EXPECT_GT(NSHeight([[controller view] frame]),
    147             message_center::kNotificationIconSize);
    148 }
    149 
    150 TEST_F(NotificationControllerTest, Close) {
    151   scoped_ptr<message_center::Notification> notification(
    152       new message_center::Notification(
    153           message_center::NOTIFICATION_TYPE_SIMPLE,
    154           "an_id",
    155           string16(),
    156           string16(),
    157           gfx::Image(),
    158           string16(),
    159           std::string(),
    160           message_center::RichNotificationData(),
    161           NULL));
    162   MockMessageCenter message_center;
    163 
    164   base::scoped_nsobject<MCNotificationController> controller(
    165       [[MCNotificationController alloc] initWithNotification:notification.get()
    166                                                messageCenter:&message_center]);
    167   [controller view];
    168 
    169   [[controller closeButton] performClick:nil];
    170 
    171   EXPECT_EQ(1, message_center.remove_count());
    172   EXPECT_EQ("an_id", message_center.last_removed_id());
    173   EXPECT_TRUE(message_center.last_removed_by_user());
    174 }
    175 
    176 TEST_F(NotificationControllerTest, Update) {
    177   scoped_ptr<message_center::Notification> notification(
    178       new message_center::Notification(
    179           message_center::NOTIFICATION_TYPE_SIMPLE,
    180           "",
    181           ASCIIToUTF16("A simple title"),
    182           ASCIIToUTF16("This message isn't too long and should fit in the"
    183                        "default bounds."),
    184           gfx::Image(),
    185           string16(),
    186           std::string(),
    187           message_center::RichNotificationData(),
    188           NULL));
    189   base::scoped_nsobject<MCNotificationController> controller(
    190       [[MCNotificationController alloc] initWithNotification:notification.get()
    191                                                messageCenter:NULL]);
    192 
    193   // Set up the default layout.
    194   [controller view];
    195   EXPECT_EQ(NSHeight([[controller view] frame]),
    196             message_center::kNotificationIconSize);
    197   EXPECT_FALSE([[controller iconView] image]);
    198 
    199   // Update the icon.
    200   notification->set_icon(gfx::Image([TestIcon() retain]));
    201   [controller updateNotification:notification.get()];
    202   EXPECT_EQ(TestIcon(), [[controller iconView] image]);
    203   EXPECT_EQ(NSHeight([[controller view] frame]),
    204             message_center::kNotificationIconSize);
    205 }
    206 
    207 TEST_F(NotificationControllerTest, Buttons) {
    208   message_center::RichNotificationData optional;
    209   message_center::ButtonInfo button1(UTF8ToUTF16("button1"));
    210   optional.buttons.push_back(button1);
    211   message_center::ButtonInfo button2(UTF8ToUTF16("button2"));
    212   optional.buttons.push_back(button2);
    213 
    214   scoped_ptr<message_center::Notification> notification(
    215       new message_center::Notification(
    216           message_center::NOTIFICATION_TYPE_BASE_FORMAT,
    217           "an_id",
    218           string16(),
    219           string16(),
    220           gfx::Image(),
    221           string16(),
    222           std::string(),
    223           optional,
    224           NULL));
    225   MockMessageCenter message_center;
    226 
    227   base::scoped_nsobject<MCNotificationController> controller(
    228       [[MCNotificationController alloc] initWithNotification:notification.get()
    229                                                messageCenter:&message_center]);
    230   [controller view];
    231 
    232   [[controller secondButton] performClick:nil];
    233 
    234   EXPECT_EQ("an_id", message_center.last_clicked_id());
    235   EXPECT_EQ(1, message_center.last_clicked_index());
    236 }
    237 
    238 TEST_F(NotificationControllerTest, Image) {
    239   scoped_ptr<message_center::Notification> notification(
    240       new message_center::Notification(
    241           message_center::NOTIFICATION_TYPE_BASE_FORMAT,
    242           "an_id",
    243           string16(),
    244           string16(),
    245           gfx::Image(),
    246           string16(),
    247           std::string(),
    248           message_center::RichNotificationData(),
    249           NULL));
    250   NSImage* image = [NSImage imageNamed:NSImageNameFolder];
    251   notification->set_image(gfx::Image([image retain]));
    252 
    253   MockMessageCenter message_center;
    254 
    255   base::scoped_nsobject<MCNotificationController> controller(
    256       [[MCNotificationController alloc] initWithNotification:notification.get()
    257                                                messageCenter:&message_center]);
    258   [controller view];
    259 
    260   ASSERT_EQ(1u, [[controller bottomSubviews] count]);
    261   ASSERT_TRUE([[[controller bottomSubviews] lastObject]
    262       isKindOfClass:[NSImageView class]]);
    263   EXPECT_EQ(image, [[[controller bottomSubviews] lastObject] image]);
    264 }
    265 
    266 TEST_F(NotificationControllerTest, List) {
    267   message_center::RichNotificationData optional;
    268   message_center::NotificationItem item1(
    269       UTF8ToUTF16("First title"), UTF8ToUTF16("first message"));
    270   optional.items.push_back(item1);
    271   message_center::NotificationItem item2(
    272       UTF8ToUTF16("Second title"),
    273       UTF8ToUTF16("second slightly longer message"));
    274   optional.items.push_back(item2);
    275 
    276   scoped_ptr<message_center::Notification> notification(
    277       new message_center::Notification(
    278           message_center::NOTIFICATION_TYPE_BASE_FORMAT,
    279           "an_id",
    280           UTF8ToUTF16("Notification Title"),
    281           UTF8ToUTF16("Notification Message - should be hidden"),
    282           gfx::Image(),
    283           string16(),
    284           std::string(),
    285           optional,
    286           NULL));
    287 
    288   MockMessageCenter message_center;
    289   base::scoped_nsobject<MCNotificationController> controller(
    290       [[MCNotificationController alloc] initWithNotification:notification.get()
    291                                                messageCenter:&message_center]);
    292   [controller view];
    293 
    294   EXPECT_FALSE([[controller titleView] isHidden]);
    295   EXPECT_TRUE([[controller messageView] isHidden]);
    296 
    297   EXPECT_EQ(2u, [[[controller listItemView] subviews] count]);
    298   EXPECT_LT(NSMaxY([[controller listItemView] frame]),
    299             NSMinY([[controller titleView] frame]));
    300 }
    301