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.
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/notifications/notification.h"
11 #include "chrome/browser/notifications/notification_test_util.h"
12 #include "chrome/browser/notifications/notification_ui_manager.h"
13 #include "chrome/browser/notifications/sync_notifier/sync_notifier_test_utils.h"
14 #include "chrome/browser/notifications/sync_notifier/synced_notification.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/test/test_browser_thread.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/skia/include/core/SkBitmap.h"
20 #include "ui/message_center/message_center_util.h"
21 #include "ui/message_center/notification_types.h"
23 using syncer::SyncData;
24 using notifier::SyncedNotification;
25 using sync_pb::EntitySpecifics;
26 using sync_pb::SyncedNotificationSpecifics;
29 const int kNotificationPriority = static_cast<int>(
30 message_center::LOW_PRIORITY);
32 bool UseRichNotifications() {
33 return message_center::IsRichNotificationEnabled();
40 // Stub out the NotificationUIManager for unit testing.
41 class StubNotificationUIManager : public NotificationUIManager {
43 StubNotificationUIManager()
44 : notification_(GURL(),
48 new MockNotificationDelegate("stub")) {}
49 virtual ~StubNotificationUIManager() {}
51 // Adds a notification to be displayed. Virtual for unit test override.
52 virtual void Add(const Notification& notification, Profile* profile)
54 // Make a deep copy of the notification that we can inspect.
55 notification_ = notification;
59 virtual bool Update(const Notification& notification, Profile* profile)
61 // Make a deep copy of the notification that we can inspect.
62 notification_ = notification;
67 // Returns true if any notifications match the supplied ID, either currently
68 // displayed or in the queue.
69 virtual const Notification* FindById(const std::string& id) const OVERRIDE {
70 return (notification_.id() == id) ? ¬ification_ : NULL;
73 // Removes any notifications matching the supplied ID, either currently
74 // displayed or in the queue. Returns true if anything was removed.
75 virtual bool CancelById(const std::string& notification_id) OVERRIDE {
76 dismissed_id_ = notification_id;
80 virtual std::set<std::string> GetAllIdsByProfileAndSourceOrigin(
82 const GURL& source) OVERRIDE {
83 std::set<std::string> notification_ids;
84 if (source == notification_.origin_url() &&
85 profile->IsSameProfile(profile_))
86 notification_ids.insert(notification_.notification_id());
87 return notification_ids;
90 // Removes notifications matching the |source_origin| (which could be an
91 // extension ID). Returns true if anything was removed.
92 virtual bool CancelAllBySourceOrigin(const GURL& source_origin) OVERRIDE {
96 // Removes notifications matching |profile|. Returns true if any were removed.
97 virtual bool CancelAllByProfile(Profile* profile) OVERRIDE {
101 // Cancels all pending notifications and closes anything currently showing.
102 // Used when the app is terminating.
103 virtual void CancelAll() OVERRIDE {}
105 // Test hook to get the notification so we can check it
106 const Notification& notification() const { return notification_; }
108 // Test hook to check the ID of the last notification cancelled.
109 std::string& dismissed_id() { return dismissed_id_; }
112 DISALLOW_COPY_AND_ASSIGN(StubNotificationUIManager);
113 Notification notification_;
115 std::string dismissed_id_;
118 class SyncedNotificationTest : public testing::Test {
120 SyncedNotificationTest()
121 : ui_thread_(content::BrowserThread::UI, &message_loop_) {}
122 virtual ~SyncedNotificationTest() {}
124 // Methods from testing::Test.
126 virtual void SetUp() OVERRIDE {
127 sync_data1_ = CreateSyncData(kTitle1, kText1, kIconUrl1, kImageUrl1,
128 kAppId1, kKey1, kUnread);
129 sync_data2_ = CreateSyncData(kTitle2, kText2, kIconUrl2, kImageUrl2,
130 kAppId2, kKey2, kUnread);
131 // Notification 3 will have the same ID as notification1, but different
133 sync_data3_ = CreateSyncData(kTitle3, kText3, kIconUrl3, kImageUrl3,
134 kAppId1, kKey1, kUnread);
135 // Notification 4 will be the same as 1, but the read state will be 'read'.
136 sync_data4_ = CreateSyncData(kTitle1, kText1, kIconUrl1, kImageUrl1,
137 kAppId1, kKey1, kDismissed);
139 notification1_.reset(new SyncedNotification(sync_data1_));
140 notification2_.reset(new SyncedNotification(sync_data2_));
141 notification3_.reset(new SyncedNotification(sync_data3_));
142 notification4_.reset(new SyncedNotification(sync_data4_));
145 virtual void TearDown() OVERRIDE {
148 virtual void AddButtonBitmaps(SyncedNotification* notification,
149 unsigned int how_many) {
150 for (unsigned int i = 0; i < how_many; ++i) {
151 notification->button_bitmaps_.push_back(gfx::Image());
155 scoped_ptr<SyncedNotification> notification1_;
156 scoped_ptr<SyncedNotification> notification2_;
157 scoped_ptr<SyncedNotification> notification3_;
158 scoped_ptr<SyncedNotification> notification4_;
159 syncer::SyncData sync_data1_;
160 syncer::SyncData sync_data2_;
161 syncer::SyncData sync_data3_;
162 syncer::SyncData sync_data4_;
165 base::MessageLoopForIO message_loop_;
166 content::TestBrowserThread ui_thread_;
168 DISALLOW_COPY_AND_ASSIGN(SyncedNotificationTest);
171 // test simple accessors
173 TEST_F(SyncedNotificationTest, GetAppIdTest) {
174 std::string found_app_id = notification1_->GetAppId();
175 std::string expected_app_id(kAppId1);
177 EXPECT_EQ(found_app_id, expected_app_id);
180 TEST_F(SyncedNotificationTest, GetKeyTest) {
181 std::string found_key = notification1_->GetKey();
182 std::string expected_key(kKey1);
184 EXPECT_EQ(expected_key, found_key);
187 TEST_F(SyncedNotificationTest, GetTitleTest) {
188 std::string found_title = notification1_->GetTitle();
189 std::string expected_title(kTitle1);
191 EXPECT_EQ(expected_title, found_title);
194 TEST_F(SyncedNotificationTest, GetIconURLTest) {
195 std::string found_icon_url = notification1_->GetAppIconUrl().spec();
196 std::string expected_icon_url(kIconUrl1);
198 EXPECT_EQ(expected_icon_url, found_icon_url);
201 TEST_F(SyncedNotificationTest, GetReadStateTest) {
202 SyncedNotification::ReadState found_state1 =
203 notification1_->GetReadState();
204 SyncedNotification::ReadState expected_state1(SyncedNotification::kUnread);
206 EXPECT_EQ(expected_state1, found_state1);
208 SyncedNotification::ReadState found_state2 =
209 notification4_->GetReadState();
210 SyncedNotification::ReadState expected_state2(SyncedNotification::kDismissed);
212 EXPECT_EQ(expected_state2, found_state2);
215 // TODO(petewil): Improve ctor to pass in an image and type so this test can
216 // pass on actual data.
217 TEST_F(SyncedNotificationTest, GetImageURLTest) {
218 GURL found_image_url = notification1_->GetImageUrl();
219 GURL expected_image_url = GURL(kImageUrl1);
221 EXPECT_EQ(expected_image_url, found_image_url);
224 // TODO(petewil): test with a multi-line message
225 TEST_F(SyncedNotificationTest, GetTextTest) {
226 std::string found_text = notification1_->GetText();
227 std::string expected_text(kText1);
229 EXPECT_EQ(expected_text, found_text);
232 TEST_F(SyncedNotificationTest, GetCreationTimeTest) {
233 uint64 found_time = notification1_->GetCreationTime();
234 EXPECT_EQ(kFakeCreationTime, found_time);
237 TEST_F(SyncedNotificationTest, GetPriorityTest) {
238 double found_priority = notification1_->GetPriority();
239 EXPECT_EQ(static_cast<double>(kNotificationPriority), found_priority);
242 TEST_F(SyncedNotificationTest, GetButtonCountTest) {
243 int found_button_count = notification1_->GetButtonCount();
244 EXPECT_EQ(2, found_button_count);
247 TEST_F(SyncedNotificationTest, GetNotificationCountTest) {
248 int found_notification_count = notification1_->GetNotificationCount();
249 EXPECT_EQ(3, found_notification_count);
252 TEST_F(SyncedNotificationTest, GetDefaultDestinationDataTest) {
253 std::string default_destination_title =
254 notification1_->GetDefaultDestinationTitle();
255 GURL default_destination_icon_url =
256 notification1_->GetDefaultDestinationIconUrl();
257 GURL default_destination_url =
258 notification1_->GetDefaultDestinationUrl();
259 EXPECT_EQ(std::string(kDefaultDestinationTitle), default_destination_title);
260 EXPECT_EQ(GURL(kDefaultDestinationIconUrl),
261 default_destination_icon_url);
262 EXPECT_EQ(GURL(kDefaultDestinationUrl), default_destination_url);
265 TEST_F(SyncedNotificationTest, GetButtonDataTest) {
266 std::string button_one_title = notification1_->GetButtonTitle(0);
267 GURL button_one_icon_url = notification1_->GetButtonIconUrl(0);
268 GURL button_one_url = notification1_->GetButtonUrl(0);
269 std::string button_two_title = notification1_->GetButtonTitle(1);
270 GURL button_two_icon_url = notification1_->GetButtonIconUrl(1);
271 GURL button_two_url = notification1_->GetButtonUrl(1);
272 EXPECT_EQ(std::string(kButtonOneTitle), button_one_title);
273 EXPECT_EQ(GURL(kButtonOneIconUrl), button_one_icon_url);
274 EXPECT_EQ(GURL(kButtonOneUrl), button_one_url);
275 EXPECT_EQ(std::string(kButtonTwoTitle), button_two_title);
276 EXPECT_EQ(GURL(kButtonTwoIconUrl), button_two_icon_url);
277 EXPECT_EQ(GURL(kButtonTwoUrl), button_two_url);
280 TEST_F(SyncedNotificationTest, ContainedNotificationTest) {
281 std::string notification_title1 =
282 notification1_->GetContainedNotificationTitle(0);
283 std::string notification_title2 =
284 notification1_->GetContainedNotificationTitle(1);
285 std::string notification_title3 =
286 notification1_->GetContainedNotificationTitle(2);
287 std::string notification_message1 =
288 notification1_->GetContainedNotificationMessage(0);
289 std::string notification_message2 =
290 notification1_->GetContainedNotificationMessage(1);
291 std::string notification_message3 =
292 notification1_->GetContainedNotificationMessage(2);
294 EXPECT_EQ(std::string(kContainedTitle1), notification_title1);
295 EXPECT_EQ(std::string(kContainedTitle2), notification_title2);
296 EXPECT_EQ(std::string(kContainedTitle3), notification_title3);
297 EXPECT_EQ(std::string(kContainedMessage1), notification_message1);
298 EXPECT_EQ(std::string(kContainedMessage2), notification_message2);
299 EXPECT_EQ(std::string(kContainedMessage3), notification_message3);
302 // test that EqualsIgnoringReadState works as we expect
303 TEST_F(SyncedNotificationTest, EqualsIgnoringReadStateTest) {
304 EXPECT_TRUE(notification1_->EqualsIgnoringReadState(*notification1_));
305 EXPECT_TRUE(notification2_->EqualsIgnoringReadState(*notification2_));
306 EXPECT_FALSE(notification1_->EqualsIgnoringReadState(*notification2_));
307 EXPECT_FALSE(notification1_->EqualsIgnoringReadState(*notification3_));
308 EXPECT_TRUE(notification1_->EqualsIgnoringReadState(*notification4_));
311 TEST_F(SyncedNotificationTest, UpdateTest) {
312 scoped_ptr<SyncedNotification> notification5;
313 notification5.reset(new SyncedNotification(sync_data1_));
315 // update with the sync data from notification2, and ensure they are equal.
316 notification5->Update(sync_data2_);
317 EXPECT_TRUE(notification5->EqualsIgnoringReadState(*notification2_));
318 EXPECT_EQ(notification5->GetReadState(), notification2_->GetReadState());
319 EXPECT_FALSE(notification5->EqualsIgnoringReadState(*notification1_));
322 TEST_F(SyncedNotificationTest, ShowTest) {
324 if (!UseRichNotifications())
327 StubNotificationUIManager notification_manager;
329 // Call the method under test using the pre-populated data.
330 notification1_->Show(¬ification_manager, NULL, NULL);
332 const Notification notification = notification_manager.notification();
334 // Check the base fields of the notification.
335 EXPECT_EQ(message_center::NOTIFICATION_TYPE_IMAGE, notification.type());
336 EXPECT_EQ(std::string(kTitle1), UTF16ToUTF8(notification.title()));
337 EXPECT_EQ(std::string(kText1), UTF16ToUTF8(notification.message()));
338 EXPECT_EQ(std::string(kExpectedOriginUrl), notification.origin_url().spec());
339 EXPECT_EQ(std::string(kKey1), UTF16ToUTF8(notification.replace_id()));
341 EXPECT_EQ(kFakeCreationTime, notification.timestamp().ToDoubleT());
342 EXPECT_EQ(kNotificationPriority, notification.priority());
345 TEST_F(SyncedNotificationTest, DismissTest) {
347 if (!UseRichNotifications())
350 StubNotificationUIManager notification_manager;
352 // Call the method under test using a dismissed notification.
353 notification4_->Show(¬ification_manager, NULL, NULL);
355 EXPECT_EQ(std::string(kKey1), notification_manager.dismissed_id());
358 TEST_F(SyncedNotificationTest, AddBitmapToFetchQueueTest) {
359 scoped_ptr<SyncedNotification> notification6;
360 notification6.reset(new SyncedNotification(sync_data1_));
362 // Add two bitmaps to the queue.
363 notification6->AddBitmapToFetchQueue(GURL(kIconUrl1));
364 notification6->AddBitmapToFetchQueue(GURL(kIconUrl2));
366 EXPECT_EQ(2, notification6->active_fetcher_count_);
367 EXPECT_EQ(GURL(kIconUrl1), notification6->fetchers_[0]->url());
368 EXPECT_EQ(GURL(kIconUrl2), notification6->fetchers_[1]->url());
370 notification6->AddBitmapToFetchQueue(GURL(kIconUrl2));
371 EXPECT_EQ(2, notification6->active_fetcher_count_);
374 TEST_F(SyncedNotificationTest, OnFetchCompleteTest) {
375 if (!UseRichNotifications())
378 StubNotificationUIManager notification_manager;
380 // Set up the internal state that FetchBitmaps() would have set.
381 notification1_->notification_manager_ = ¬ification_manager;
383 // Add the bitmaps to the queue for us to match up.
384 notification1_->AddBitmapToFetchQueue(GURL(kIconUrl1));
385 notification1_->AddBitmapToFetchQueue(GURL(kImageUrl1));
386 notification1_->AddBitmapToFetchQueue(GURL(kButtonOneIconUrl));
387 notification1_->AddBitmapToFetchQueue(GURL(kButtonTwoIconUrl));
389 EXPECT_EQ(4, notification1_->active_fetcher_count_);
391 // Put some realistic looking bitmap data into the url_fetcher.
394 // Put a real bitmap into "bitmap". 2x2 bitmap of green 32 bit pixels.
395 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
396 bitmap.allocPixels();
397 bitmap.eraseColor(SK_ColorGREEN);
399 // Allocate the button_bitmaps_ array as the calling function normally would.
400 AddButtonBitmaps(notification1_.get(), 2);
402 notification1_->OnFetchComplete(GURL(kIconUrl1), &bitmap);
403 EXPECT_EQ(3, notification1_->active_fetcher_count_);
405 // When we call OnFetchComplete on the last bitmap, show should be called.
406 notification1_->OnFetchComplete(GURL(kImageUrl1), &bitmap);
407 EXPECT_EQ(2, notification1_->active_fetcher_count_);
409 notification1_->OnFetchComplete(GURL(kButtonOneIconUrl), &bitmap);
410 EXPECT_EQ(1, notification1_->active_fetcher_count_);
412 notification1_->OnFetchComplete(GURL(kButtonTwoIconUrl), &bitmap);
413 EXPECT_EQ(0, notification1_->active_fetcher_count_);
415 // Since we check Show() thoroughly in its own test, we only check cursorily.
416 EXPECT_EQ(message_center::NOTIFICATION_TYPE_IMAGE,
417 notification_manager.notification().type());
418 EXPECT_EQ(std::string(kTitle1),
419 UTF16ToUTF8(notification_manager.notification().title()));
420 EXPECT_EQ(std::string(kText1),
421 UTF16ToUTF8(notification_manager.notification().message()));
423 // TODO(petewil): Check that the bitmap in the notification is what we expect.
424 // This fails today, the type info is different.
425 // EXPECT_TRUE(gfx::BitmapsAreEqual(
426 // image, notification1_->GetAppIconBitmap()));
429 TEST_F(SyncedNotificationTest, QueueBitmapFetchJobsTest) {
430 if (!UseRichNotifications())
433 StubNotificationUIManager notification_manager;
435 notification1_->QueueBitmapFetchJobs(¬ification_manager, NULL, NULL);
437 // There should be 4 urls in the queue, icon, image, and two buttons.
438 EXPECT_EQ(4, notification1_->active_fetcher_count_);
441 // TODO(petewil): Add a test for a notification being read and or deleted.
443 } // namespace notifier