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