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/tray_view_controller.h" 6 7#include "base/mac/scoped_nsobject.h" 8#include "base/message_loop/message_loop.h" 9#include "base/run_loop.h" 10#include "base/strings/utf_string_conversions.h" 11#import "ui/gfx/test/ui_cocoa_test_helper.h" 12#include "ui/message_center/fake_notifier_settings_provider.h" 13#include "ui/message_center/message_center.h" 14#include "ui/message_center/message_center_impl.h" 15#include "ui/message_center/message_center_style.h" 16#include "ui/message_center/notification.h" 17#include "ui/message_center/notifier_settings.h" 18 19using base::ASCIIToUTF16; 20 21namespace message_center { 22 23class TrayViewControllerTest : public ui::CocoaTest { 24 public: 25 TrayViewControllerTest() 26 : center_(NULL) { 27 } 28 29 virtual void SetUp() OVERRIDE { 30 ui::CocoaTest::SetUp(); 31 message_center::MessageCenter::Initialize(); 32 center_ = message_center::MessageCenter::Get(); 33 center_->DisableTimersForTest(); 34 tray_.reset([[MCTrayViewController alloc] initWithMessageCenter:center_]); 35 [tray_ setAnimationDuration:0.002]; 36 [tray_ setAnimateClearingNextNotificationDelay:0.001]; 37 [tray_ setAnimationEndedCallback:^{ 38 if (nested_run_loop_.get()) 39 nested_run_loop_->Quit(); 40 }]; 41 [tray_ view]; // Create the view. 42 } 43 44 virtual void TearDown() OVERRIDE { 45 tray_.reset(); 46 message_center::MessageCenter::Shutdown(); 47 ui::CocoaTest::TearDown(); 48 } 49 50 void WaitForAnimationEnded() { 51 if (![tray_ isAnimating]) 52 return; 53 nested_run_loop_.reset(new base::RunLoop()); 54 nested_run_loop_->Run(); 55 nested_run_loop_.reset(); 56 } 57 58 protected: 59 message_center::NotifierId DummyNotifierId() { 60 return message_center::NotifierId(); 61 } 62 63 message_center::MessageCenter* center_; // Weak, global. 64 65 base::MessageLoopForUI message_loop_; 66 scoped_ptr<base::RunLoop> nested_run_loop_; 67 base::scoped_nsobject<MCTrayViewController> tray_; 68}; 69 70TEST_F(TrayViewControllerTest, AddRemoveOne) { 71 NSScrollView* view = [[tray_ scrollView] documentView]; 72 EXPECT_EQ(0u, [[view subviews] count]); 73 scoped_ptr<message_center::Notification> notification_data; 74 notification_data.reset(new message_center::Notification( 75 message_center::NOTIFICATION_TYPE_SIMPLE, 76 "1", 77 ASCIIToUTF16("First notification"), 78 ASCIIToUTF16("This is a simple test."), 79 gfx::Image(), 80 base::string16(), 81 DummyNotifierId(), 82 message_center::RichNotificationData(), 83 NULL)); 84 center_->AddNotification(notification_data.Pass()); 85 [tray_ onMessageCenterTrayChanged]; 86 ASSERT_EQ(1u, [[view subviews] count]); 87 88 // The view should have padding around it. 89 NSView* notification = [[view subviews] objectAtIndex:0]; 90 NSRect notification_frame = [notification frame]; 91 EXPECT_CGFLOAT_EQ(2 * message_center::kMarginBetweenItems, 92 NSHeight([view frame]) - NSHeight(notification_frame)); 93 EXPECT_CGFLOAT_EQ(2 * message_center::kMarginBetweenItems, 94 NSWidth([view frame]) - NSWidth(notification_frame)); 95 EXPECT_GT(NSHeight([[tray_ view] frame]), 96 NSHeight([[tray_ scrollView] frame])); 97 98 center_->RemoveNotification("1", true); 99 [tray_ onMessageCenterTrayChanged]; 100 EXPECT_EQ(0u, [[view subviews] count]); 101 // The empty tray is now 100px tall to accommodate 102 // the empty message. 103 EXPECT_CGFLOAT_EQ(message_center::kMinScrollViewHeight, 104 NSHeight([view frame])); 105} 106 107TEST_F(TrayViewControllerTest, AddThreeClearAll) { 108 NSScrollView* view = [[tray_ scrollView] documentView]; 109 EXPECT_EQ(0u, [[view subviews] count]); 110 scoped_ptr<message_center::Notification> notification; 111 notification.reset(new message_center::Notification( 112 message_center::NOTIFICATION_TYPE_SIMPLE, 113 "1", 114 ASCIIToUTF16("First notification"), 115 ASCIIToUTF16("This is a simple test."), 116 gfx::Image(), 117 base::string16(), 118 DummyNotifierId(), 119 message_center::RichNotificationData(), 120 NULL)); 121 center_->AddNotification(notification.Pass()); 122 notification.reset(new message_center::Notification( 123 message_center::NOTIFICATION_TYPE_SIMPLE, 124 "2", 125 ASCIIToUTF16("Second notification"), 126 ASCIIToUTF16("This is a simple test."), 127 gfx::Image(), 128 base::string16(), 129 DummyNotifierId(), 130 message_center::RichNotificationData(), 131 NULL)); 132 center_->AddNotification(notification.Pass()); 133 notification.reset(new message_center::Notification( 134 message_center::NOTIFICATION_TYPE_SIMPLE, 135 "3", 136 ASCIIToUTF16("Third notification"), 137 ASCIIToUTF16("This is a simple test."), 138 gfx::Image(), 139 base::string16(), 140 DummyNotifierId(), 141 message_center::RichNotificationData(), 142 NULL)); 143 center_->AddNotification(notification.Pass()); 144 [tray_ onMessageCenterTrayChanged]; 145 ASSERT_EQ(3u, [[view subviews] count]); 146 147 [tray_ clearAllNotifications:nil]; 148 WaitForAnimationEnded(); 149 [tray_ onMessageCenterTrayChanged]; 150 151 EXPECT_EQ(0u, [[view subviews] count]); 152 // The empty tray is now 100px tall to accommodate 153 // the empty message. 154 EXPECT_CGFLOAT_EQ(message_center::kMinScrollViewHeight, 155 NSHeight([view frame])); 156} 157 158TEST_F(TrayViewControllerTest, NoClearAllWhenNoNotifications) { 159 EXPECT_TRUE([tray_ pauseButton]); 160 EXPECT_TRUE([tray_ clearAllButton]); 161 162 // With no notifications, the clear all button should be hidden. 163 EXPECT_TRUE([[tray_ clearAllButton] isHidden]); 164 EXPECT_LT(NSMinX([[tray_ clearAllButton] frame]), 165 NSMinX([[tray_ pauseButton] frame])); 166 167 // Add a notification. 168 scoped_ptr<message_center::Notification> notification; 169 notification.reset(new message_center::Notification( 170 message_center::NOTIFICATION_TYPE_SIMPLE, 171 "1", 172 ASCIIToUTF16("First notification"), 173 ASCIIToUTF16("This is a simple test."), 174 gfx::Image(), 175 base::string16(), 176 DummyNotifierId(), 177 message_center::RichNotificationData(), 178 NULL)); 179 center_->AddNotification(notification.Pass()); 180 [tray_ onMessageCenterTrayChanged]; 181 182 // Clear all should now be visible. 183 EXPECT_FALSE([[tray_ clearAllButton] isHidden]); 184 EXPECT_GT(NSMinX([[tray_ clearAllButton] frame]), 185 NSMinX([[tray_ pauseButton] frame])); 186 187 // Adding a second notification should keep things still visible. 188 notification.reset(new message_center::Notification( 189 message_center::NOTIFICATION_TYPE_SIMPLE, 190 "2", 191 ASCIIToUTF16("Second notification"), 192 ASCIIToUTF16("This is a simple test."), 193 gfx::Image(), 194 base::string16(), 195 DummyNotifierId(), 196 message_center::RichNotificationData(), 197 NULL)); 198 center_->AddNotification(notification.Pass()); 199 [tray_ onMessageCenterTrayChanged]; 200 EXPECT_FALSE([[tray_ clearAllButton] isHidden]); 201 EXPECT_GT(NSMinX([[tray_ clearAllButton] frame]), 202 NSMinX([[tray_ pauseButton] frame])); 203 204 // Clear all notifications. 205 [tray_ clearAllNotifications:nil]; 206 WaitForAnimationEnded(); 207 [tray_ onMessageCenterTrayChanged]; 208 209 // The button should be hidden again. 210 EXPECT_TRUE([[tray_ clearAllButton] isHidden]); 211 EXPECT_LT(NSMinX([[tray_ clearAllButton] frame]), 212 NSMinX([[tray_ pauseButton] frame])); 213} 214 215namespace { 216 217Notifier* NewNotifier(const std::string& id, 218 const std::string& title, 219 bool enabled) { 220 NotifierId notifier_id(NotifierId::APPLICATION, id); 221 return new Notifier(notifier_id, base::UTF8ToUTF16(title), enabled); 222} 223 224} // namespace 225 226 227TEST_F(TrayViewControllerTest, Settings) { 228 std::vector<Notifier*> notifiers; 229 notifiers.push_back(NewNotifier("id", "title", /*enabled=*/true)); 230 notifiers.push_back(NewNotifier("id2", "other title", /*enabled=*/false)); 231 232 FakeNotifierSettingsProvider provider(notifiers); 233 center_->SetNotifierSettingsProvider(&provider); 234 235 CGFloat trayHeight = NSHeight([[tray_ view] frame]); 236 EXPECT_EQ(0, provider.closed_called_count()); 237 238 [tray_ showSettings:nil]; 239 EXPECT_FALSE(center_->IsMessageCenterVisible()); 240 241 // There are 0 notifications, but 2 notifiers. The settings pane should be 242 // higher than the empty tray bubble. 243 EXPECT_LT(trayHeight, NSHeight([[tray_ view] frame])); 244 245 [tray_ showMessages:nil]; 246 EXPECT_EQ(1, provider.closed_called_count()); 247 EXPECT_TRUE(center_->IsMessageCenterVisible()); 248 249 // The tray should be back at its previous height now. 250 EXPECT_EQ(trayHeight, NSHeight([[tray_ view] frame])); 251 252 // Clean up since this frame owns FakeNotifierSettingsProvider. 253 center_->SetNotifierSettingsProvider(NULL); 254} 255 256TEST_F(TrayViewControllerTest, EmptyCenter) { 257 EXPECT_FALSE([[tray_ emptyDescription] isHidden]); 258 259 // With no notifications, the divider should be hidden. 260 EXPECT_TRUE([[tray_ divider] isHidden]); 261 EXPECT_TRUE([[tray_ scrollView] isHidden]); 262 263 scoped_ptr<message_center::Notification> notification; 264 notification.reset(new message_center::Notification( 265 message_center::NOTIFICATION_TYPE_SIMPLE, 266 "1", 267 ASCIIToUTF16("First notification"), 268 ASCIIToUTF16("This is a simple test."), 269 gfx::Image(), 270 base::string16(), 271 DummyNotifierId(), 272 message_center::RichNotificationData(), 273 NULL)); 274 center_->AddNotification(notification.Pass()); 275 [tray_ onMessageCenterTrayChanged]; 276 277 EXPECT_FALSE([[tray_ divider] isHidden]); 278 EXPECT_FALSE([[tray_ scrollView] isHidden]); 279 EXPECT_TRUE([[tray_ emptyDescription] isHidden]); 280} 281 282} // namespace message_center 283