1 // Copyright (c) 2012 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.
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop.h"
10 #include "chrome/browser/sessions/session_types.h"
11 #include "chrome/browser/sessions/session_types_test_helper.h"
12 #include "chrome/browser/sync/glue/session_model_associator.h"
13 #include "chrome/browser/sync/glue/synced_tab_delegate.h"
14 #include "chrome/browser/sync/profile_sync_service_mock.h"
15 #include "chrome/common/chrome_notification_types.h"
16 #include "chrome/common/url_constants.h"
17 #include "chrome/test/base/profile_mock.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/common/page_transition_types.h"
22 #include "content/public/test/test_browser_thread.h"
23 #include "googleurl/src/gurl.h"
24 #include "sync/protocol/session_specifics.pb.h"
25 #include "sync/util/time.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 using content::BrowserThread
;
30 using testing::NiceMock
;
31 using testing::Return
;
32 using testing::StrictMock
;
35 namespace browser_sync
{
37 class SyncSessionModelAssociatorTest
: public testing::Test
{
39 SyncSessionModelAssociatorTest()
40 : ui_thread_(BrowserThread::UI
, &message_loop_
),
41 sync_service_(&profile_
),
42 model_associator_(&sync_service_
, true) {}
44 // Helper methods to avoid having to friend individual tests.
45 bool GetFavicon(std::string page_url
, std::string
* favicon
) {
46 return model_associator_
.GetSyncedFaviconForPageURL(page_url
, favicon
);
49 void LoadTabFavicon(const sync_pb::SessionTab
& tab
) {
50 model_associator_
.LoadForeignTabFavicon(tab
);
53 size_t NumFavicons() {
54 return model_associator_
.NumFaviconsForTesting();
57 void DecrementFavicon(std::string url
) {
58 model_associator_
.DecrementAndCleanFaviconForURL(url
);
61 static GURL
GetCurrentVirtualURL(const SyncedTabDelegate
& tab_delegate
) {
62 return SessionModelAssociator::GetCurrentVirtualURL(tab_delegate
);
65 static void SetSessionTabFromDelegate(
66 const SyncedTabDelegate
& tab_delegate
,
68 SessionTab
* session_tab
) {
69 SessionModelAssociator::SetSessionTabFromDelegate(
76 MessageLoopForUI message_loop_
;
77 content::TestBrowserThread ui_thread_
;
78 NiceMock
<ProfileMock
> profile_
;
79 NiceMock
<ProfileSyncServiceMock
> sync_service_
;
82 SessionModelAssociator model_associator_
;
87 TEST_F(SyncSessionModelAssociatorTest
, SessionWindowHasNoTabsToSync
) {
89 ASSERT_TRUE(SessionWindowHasNoTabsToSync(win
));
90 scoped_ptr
<SessionTab
> tab(new SessionTab());
91 win
.tabs
.push_back(tab
.release());
92 ASSERT_TRUE(SessionWindowHasNoTabsToSync(win
));
94 SessionTypesTestHelper::CreateNavigation("about:bubba", "title");
95 win
.tabs
[0]->navigations
.push_back(nav
);
96 ASSERT_FALSE(SessionWindowHasNoTabsToSync(win
));
99 TEST_F(SyncSessionModelAssociatorTest
, ShouldSyncSessionTab
) {
101 ASSERT_FALSE(ShouldSyncSessionTab(tab
));
103 SessionTypesTestHelper::CreateNavigation(
104 chrome::kChromeUINewTabURL
, "title");
105 tab
.navigations
.push_back(nav
);
106 // NewTab does not count as valid if it's the only navigation.
107 ASSERT_FALSE(ShouldSyncSessionTab(tab
));
109 SessionTypesTestHelper::CreateNavigation("about:bubba", "title");
110 tab
.navigations
.push_back(nav2
);
111 // Once there's another navigation, the tab is valid.
112 ASSERT_TRUE(ShouldSyncSessionTab(tab
));
115 TEST_F(SyncSessionModelAssociatorTest
,
116 ShouldSyncSessionTabIgnoresFragmentForNtp
) {
118 ASSERT_FALSE(ShouldSyncSessionTab(tab
));
120 SessionTypesTestHelper::CreateNavigation(
121 std::string(chrome::kChromeUINewTabURL
) + "#bookmarks", "title");
122 tab
.navigations
.push_back(nav
);
123 // NewTab does not count as valid if it's the only navigation.
124 ASSERT_FALSE(ShouldSyncSessionTab(tab
));
129 TEST_F(SyncSessionModelAssociatorTest
, PopulateSessionHeader
) {
130 sync_pb::SessionHeader header_s
;
131 header_s
.set_client_name("Client 1");
132 header_s
.set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_WIN
);
134 SyncedSession session
;
135 base::Time time
= base::Time::Now();
136 SessionModelAssociator::PopulateSessionHeaderFromSpecifics(
137 header_s
, time
, &session
);
138 ASSERT_EQ("Client 1", session
.session_name
);
139 ASSERT_EQ(SyncedSession::TYPE_WIN
, session
.device_type
);
140 ASSERT_EQ(time
, session
.modified_time
);
143 TEST_F(SyncSessionModelAssociatorTest
, PopulateSessionWindow
) {
144 sync_pb::SessionWindow window_s
;
146 window_s
.set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED
);
147 window_s
.set_selected_tab_index(1);
149 std::string tag
= "tag";
150 SyncedSessionTracker tracker
;
151 SyncedSession
* session
= tracker
.GetSession(tag
);
152 tracker
.PutWindowInSession(tag
, 0);
153 SessionModelAssociator::PopulateSessionWindowFromSpecifics(
154 tag
, window_s
, base::Time(), session
->windows
[0], &tracker
);
155 ASSERT_EQ(1U, session
->windows
[0]->tabs
.size());
156 ASSERT_EQ(1, session
->windows
[0]->selected_tab_index
);
157 ASSERT_EQ(1, session
->windows
[0]->type
);
158 ASSERT_EQ(1U, tracker
.num_synced_sessions());
159 ASSERT_EQ(1U, tracker
.num_synced_tabs(std::string("tag")));
162 TEST_F(SyncSessionModelAssociatorTest
, TabNodePool
) {
163 SessionModelAssociator::TabNodePool
pool(NULL
);
164 pool
.set_machine_tag("tag");
165 ASSERT_TRUE(pool
.empty());
166 ASSERT_TRUE(pool
.full());
167 ASSERT_EQ(0U, pool
.capacity());
170 ASSERT_FALSE(pool
.empty());
171 ASSERT_TRUE(pool
.full());
172 ASSERT_EQ(2U, pool
.capacity());
173 ASSERT_EQ(10, pool
.GetFreeTabNode()); // Returns last free tab.
174 ASSERT_FALSE(pool
.empty());
175 ASSERT_FALSE(pool
.full());
176 ASSERT_EQ(2U, pool
.capacity());
177 ASSERT_EQ(5, pool
.GetFreeTabNode()); // Returns last free tab.
178 ASSERT_TRUE(pool
.empty());
179 ASSERT_FALSE(pool
.full());
180 ASSERT_EQ(2U, pool
.capacity());
181 // Release them in reverse order.
182 pool
.FreeTabNode(10);
184 ASSERT_EQ(2U, pool
.capacity());
185 ASSERT_FALSE(pool
.empty());
186 ASSERT_TRUE(pool
.full());
187 ASSERT_EQ(5, pool
.GetFreeTabNode()); // Returns last free tab.
188 ASSERT_FALSE(pool
.empty());
189 ASSERT_FALSE(pool
.full());
190 ASSERT_EQ(2U, pool
.capacity());
191 ASSERT_FALSE(pool
.empty());
192 ASSERT_FALSE(pool
.full());
193 ASSERT_EQ(2U, pool
.capacity());
194 ASSERT_EQ(10, pool
.GetFreeTabNode()); // Returns last free tab.
195 ASSERT_TRUE(pool
.empty());
196 ASSERT_FALSE(pool
.full());
197 ASSERT_EQ(2U, pool
.capacity());
198 // Release them again.
199 pool
.FreeTabNode(10);
201 ASSERT_FALSE(pool
.empty());
202 ASSERT_TRUE(pool
.full());
203 ASSERT_EQ(2U, pool
.capacity());
205 ASSERT_TRUE(pool
.empty());
206 ASSERT_TRUE(pool
.full());
207 ASSERT_EQ(0U, pool
.capacity());
212 class SyncedTabDelegateMock
: public SyncedTabDelegate
{
214 SyncedTabDelegateMock() {}
215 virtual ~SyncedTabDelegateMock() {}
217 MOCK_CONST_METHOD0(GetWindowId
, SessionID::id_type());
218 MOCK_CONST_METHOD0(GetSessionId
, SessionID::id_type());
219 MOCK_CONST_METHOD0(IsBeingDestroyed
, bool());
220 MOCK_CONST_METHOD0(profile
, Profile
*());
221 MOCK_CONST_METHOD0(GetExtensionAppId
, std::string());
222 MOCK_CONST_METHOD0(GetCurrentEntryIndex
, int());
223 MOCK_CONST_METHOD0(GetEntryCount
, int());
224 MOCK_CONST_METHOD0(GetPendingEntryIndex
, int());
225 MOCK_CONST_METHOD0(GetPendingEntry
, content::NavigationEntry
*());
226 MOCK_CONST_METHOD1(GetEntryAtIndex
, content::NavigationEntry
*(int i
));
227 MOCK_CONST_METHOD0(GetActiveEntry
, content::NavigationEntry
*());
228 MOCK_CONST_METHOD0(IsPinned
, bool());
231 class SyncRefreshListener
: public content::NotificationObserver
{
233 SyncRefreshListener() : notified_of_refresh_(false) {
234 registrar_
.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL
,
235 content::NotificationService::AllSources());
238 void Observe(int type
,
239 const content::NotificationSource
& source
,
240 const content::NotificationDetails
& details
) {
241 if (type
== chrome::NOTIFICATION_SYNC_REFRESH_LOCAL
) {
242 notified_of_refresh_
= true;
246 bool notified_of_refresh() const { return notified_of_refresh_
; }
249 bool notified_of_refresh_
;
250 content::NotificationRegistrar registrar_
;
253 // Test that AttemptSessionsDataRefresh() triggers the
254 // NOTIFICATION_SYNC_REFRESH_LOCAL notification.
255 TEST_F(SyncSessionModelAssociatorTest
, TriggerSessionRefresh
) {
256 SyncRefreshListener refresh_listener
;
258 EXPECT_FALSE(refresh_listener
.notified_of_refresh());
259 model_associator_
.AttemptSessionsDataRefresh();
260 EXPECT_TRUE(refresh_listener
.notified_of_refresh());
263 // Test that we exclude tabs with only chrome:// and file:// schemed navigations
264 // from ShouldSyncTab(..).
265 TEST_F(SyncSessionModelAssociatorTest
, ValidTabs
) {
266 NiceMock
<SyncedTabDelegateMock
> tab_mock
;
268 // A null entry shouldn't crash.
269 EXPECT_CALL(tab_mock
, GetCurrentEntryIndex()).WillRepeatedly(Return(0));
270 EXPECT_CALL(tab_mock
, GetEntryAtIndex(0)).WillRepeatedly(
271 Return((content::NavigationEntry
*)NULL
));
272 EXPECT_CALL(tab_mock
, GetEntryCount()).WillRepeatedly(Return(1));
273 EXPECT_CALL(tab_mock
, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
274 EXPECT_FALSE(model_associator_
.ShouldSyncTab(tab_mock
));
276 // A chrome:// entry isn't valid.
277 scoped_ptr
<content::NavigationEntry
> entry(
278 content::NavigationEntry::Create());
279 entry
->SetVirtualURL(GURL("chrome://preferences/"));
280 testing::Mock::VerifyAndClearExpectations(&tab_mock
);
281 EXPECT_CALL(tab_mock
, GetCurrentEntryIndex()).WillRepeatedly(Return(0));
282 EXPECT_CALL(tab_mock
, GetEntryAtIndex(0)).WillRepeatedly(Return(entry
.get()));
283 EXPECT_CALL(tab_mock
, GetEntryCount()).WillRepeatedly(Return(1));
284 EXPECT_CALL(tab_mock
, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
285 EXPECT_FALSE(model_associator_
.ShouldSyncTab(tab_mock
));
287 // A file:// entry isn't valid, even in addition to another entry.
288 scoped_ptr
<content::NavigationEntry
> entry2(
289 content::NavigationEntry::Create());
290 entry2
->SetVirtualURL(GURL("file://bla"));
291 testing::Mock::VerifyAndClearExpectations(&tab_mock
);
292 EXPECT_CALL(tab_mock
, GetCurrentEntryIndex()).WillRepeatedly(Return(0));
293 EXPECT_CALL(tab_mock
, GetEntryAtIndex(0)).WillRepeatedly(Return(entry
.get()));
294 EXPECT_CALL(tab_mock
, GetEntryAtIndex(1)).WillRepeatedly(
295 Return(entry2
.get()));
296 EXPECT_CALL(tab_mock
, GetEntryCount()).WillRepeatedly(Return(2));
297 EXPECT_CALL(tab_mock
, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
298 EXPECT_FALSE(model_associator_
.ShouldSyncTab(tab_mock
));
300 // Add a valid scheme entry to tab, making the tab valid.
301 scoped_ptr
<content::NavigationEntry
> entry3(
302 content::NavigationEntry::Create());
303 entry3
->SetVirtualURL(GURL("http://www.google.com"));
304 testing::Mock::VerifyAndClearExpectations(&tab_mock
);
305 EXPECT_CALL(tab_mock
, GetCurrentEntryIndex()).WillRepeatedly(Return(0));
306 EXPECT_CALL(tab_mock
, GetEntryAtIndex(0)).WillRepeatedly(
307 Return(entry
.get()));
308 EXPECT_CALL(tab_mock
, GetEntryAtIndex(1)).WillRepeatedly(
309 Return(entry2
.get()));
310 EXPECT_CALL(tab_mock
, GetEntryAtIndex(2)).WillRepeatedly(
311 Return(entry3
.get()));
312 EXPECT_CALL(tab_mock
, GetEntryCount()).WillRepeatedly(Return(3));
313 EXPECT_CALL(tab_mock
, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
314 EXPECT_TRUE(model_associator_
.ShouldSyncTab(tab_mock
));
317 // Create tab specifics with an empty favicon. Ensure it gets ignored and not
318 // stored into the synced favicon lookups.
319 TEST_F(SyncSessionModelAssociatorTest
, LoadEmptyFavicon
) {
320 std::string favicon
= "";
321 std::string favicon_url
= "http://www.faviconurl.com/favicon.ico";
322 std::string page_url
= "http://www.faviconurl.com/page.html";
323 sync_pb::SessionTab tab
;
324 tab
.set_favicon(favicon
);
325 tab
.set_favicon_source(favicon_url
);
326 tab
.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON
);
327 sync_pb::TabNavigation
* navigation
= tab
.add_navigation();
328 navigation
->set_virtual_url(page_url
);
329 tab
.set_current_navigation_index(0);
331 std::string synced_favicon
;
332 EXPECT_FALSE(GetFavicon(page_url
, &synced_favicon
));
333 EXPECT_TRUE(synced_favicon
.empty());
335 EXPECT_FALSE(GetFavicon(page_url
, &synced_favicon
));
336 EXPECT_TRUE(synced_favicon
.empty());
339 // Create tab specifics with a non-web favicon. Ensure it gets ignored and not
340 // stored into the synced favicon lookups.
341 TEST_F(SyncSessionModelAssociatorTest
, LoadNonWebFavicon
) {
342 std::string favicon
= "these are icon synced_favicon";
343 std::string favicon_url
= "http://www.faviconurl.com/favicon.ico";
344 std::string page_url
= "http://www.faviconurl.com/page.html";
345 sync_pb::SessionTab tab
;
346 tab
.set_favicon(favicon
);
347 tab
.set_favicon_source(favicon_url
);
348 // Set favicon type to an unsupported value (1 == WEB_FAVICON).
349 tab
.mutable_unknown_fields()->AddVarint(9, 2);
350 sync_pb::TabNavigation
* navigation
= tab
.add_navigation();
351 navigation
->set_virtual_url(page_url
);
352 tab
.set_current_navigation_index(0);
354 std::string synced_favicon
;
355 EXPECT_FALSE(GetFavicon(page_url
, &synced_favicon
));
356 EXPECT_TRUE(synced_favicon
.empty());
358 EXPECT_FALSE(GetFavicon(page_url
, &synced_favicon
));
359 EXPECT_TRUE(synced_favicon
.empty());
362 // Create tab specifics with a valid favicon. Ensure it gets stored in the
363 // synced favicon lookups and is accessible by the page url.
364 TEST_F(SyncSessionModelAssociatorTest
, LoadValidFavicon
) {
365 std::string favicon
= "these are icon synced_favicon";
366 std::string favicon_url
= "http://www.faviconurl.com/favicon.ico";
367 std::string page_url
= "http://www.faviconurl.com/page.html";
368 sync_pb::SessionTab tab
;
369 tab
.set_favicon(favicon
);
370 tab
.set_favicon_source(favicon_url
);
371 tab
.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON
);
372 sync_pb::TabNavigation
* navigation
= tab
.add_navigation();
373 navigation
->set_virtual_url(page_url
);
374 tab
.set_current_navigation_index(0);
376 std::string synced_favicon
;
377 EXPECT_FALSE(GetFavicon(page_url
, &synced_favicon
));
378 EXPECT_TRUE(synced_favicon
.empty());
380 EXPECT_TRUE(GetFavicon(page_url
, &synced_favicon
));
381 ASSERT_FALSE(synced_favicon
.empty());
382 EXPECT_EQ(favicon
, synced_favicon
);
385 // Create tab specifics with a valid favicon, load it, then load tab specifics
386 // with a new favicon for the same favicon source but different page. Ensure the
387 // new favicon overwrites the old favicon for both page urls.
388 TEST_F(SyncSessionModelAssociatorTest
, UpdateValidFavicon
) {
389 std::string favicon_url
= "http://www.faviconurl.com/favicon.ico";
391 std::string favicon
= "these are icon synced_favicon";
392 std::string page_url
= "http://www.faviconurl.com/page.html";
393 sync_pb::SessionTab tab
;
394 tab
.set_favicon(favicon
);
395 tab
.set_favicon_source(favicon_url
);
396 tab
.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON
);
397 sync_pb::TabNavigation
* navigation
= tab
.add_navigation();
398 navigation
->set_virtual_url(page_url
);
399 tab
.set_current_navigation_index(0);
401 std::string synced_favicon
;
402 EXPECT_FALSE(GetFavicon(page_url
, &synced_favicon
));
403 EXPECT_TRUE(synced_favicon
.empty());
405 EXPECT_TRUE(GetFavicon(page_url
, &synced_favicon
));
406 ASSERT_FALSE(synced_favicon
.empty());
407 EXPECT_EQ(favicon
, synced_favicon
);
409 // Now have a new page with same favicon source but newer favicon data.
410 std::string favicon2
= "these are new icon synced_favicon";
411 std::string page_url2
= "http://www.faviconurl.com/page2.html";
412 sync_pb::SessionTab tab2
;
413 tab2
.set_favicon(favicon2
);
414 tab2
.set_favicon_source(favicon_url
);
415 tab2
.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON
);
416 sync_pb::TabNavigation
* navigation2
= tab2
.add_navigation();
417 navigation2
->set_virtual_url(page_url2
);
418 tab2
.set_current_navigation_index(0);
420 // Verify the favicons for both pages match the newest favicon.
421 synced_favicon
.clear();
422 EXPECT_FALSE(GetFavicon(page_url2
, &synced_favicon
));
423 EXPECT_TRUE(synced_favicon
.empty());
424 LoadTabFavicon(tab2
);
425 EXPECT_TRUE(GetFavicon(page_url2
, &synced_favicon
));
426 ASSERT_FALSE(synced_favicon
.empty());
427 EXPECT_EQ(favicon2
, synced_favicon
);
428 EXPECT_NE(favicon
, synced_favicon
);
429 synced_favicon
.clear();
430 EXPECT_TRUE(GetFavicon(page_url
, &synced_favicon
));
431 ASSERT_FALSE(synced_favicon
.empty());
432 EXPECT_EQ(favicon2
, synced_favicon
);
433 EXPECT_NE(favicon
, synced_favicon
);
436 // Ensure that favicon cleanup cleans up favicons no longer being used and
437 // doesn't touch those favicons still in use.
438 TEST_F(SyncSessionModelAssociatorTest
, FaviconCleanup
) {
439 EXPECT_EQ(NumFavicons(), 0U);
441 std::string double_favicon
= "these are icon synced_favicon";
442 std::string double_favicon_url
= "http://www.faviconurl.com/favicon.ico";
443 std::string page_url
= "http://www.faviconurl.com/page.html";
444 sync_pb::SessionTab tab
;
445 tab
.set_favicon(double_favicon
);
446 tab
.set_favicon_source(double_favicon_url
);
447 tab
.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON
);
448 sync_pb::TabNavigation
* navigation
= tab
.add_navigation();
449 navigation
->set_virtual_url(page_url
);
450 tab
.set_current_navigation_index(0);
452 EXPECT_EQ(1U, NumFavicons());
454 // Add another page using the first favicon.
455 std::string page_url2
= "http://www.faviconurl.com/page2.html";
456 tab
.mutable_navigation(0)->set_virtual_url(page_url2
);
458 EXPECT_EQ(1U, NumFavicons());
460 // Add a favicon with a single user.
461 std::string single_favicon
= "different favicon synced_favicon";
462 std::string single_favicon_url
= "http://www.single_favicon_page.com/x.ico";
463 std::string single_favicon_page
= "http://www.single_favicon_page.com/x.html";
464 tab
.set_favicon(single_favicon
);
465 tab
.set_favicon_source(single_favicon_url
);
466 tab
.mutable_navigation(0)->set_virtual_url(single_favicon_page
);
468 EXPECT_EQ(2U, NumFavicons());
470 // Decrementing a favicon used by one page should remove it.
471 std::string synced_favicon
;
472 EXPECT_TRUE(GetFavicon(single_favicon_page
, &synced_favicon
));
473 EXPECT_EQ(synced_favicon
, single_favicon
);
474 DecrementFavicon(single_favicon_page
);
475 synced_favicon
.clear();
476 EXPECT_FALSE(GetFavicon(single_favicon_page
, &synced_favicon
));
477 EXPECT_TRUE(synced_favicon
.empty());
478 EXPECT_EQ(1U, NumFavicons());
480 // Decrementing a favicon used by two pages shouldn't remove it.
481 synced_favicon
.clear();
482 EXPECT_TRUE(GetFavicon(page_url
, &synced_favicon
));
483 EXPECT_EQ(synced_favicon
, double_favicon
);
484 synced_favicon
.clear();
485 EXPECT_TRUE(GetFavicon(page_url2
, &synced_favicon
));
486 EXPECT_EQ(synced_favicon
, double_favicon
);
487 DecrementFavicon(page_url
);
488 EXPECT_EQ(1U, NumFavicons());
489 synced_favicon
.clear();
490 EXPECT_TRUE(GetFavicon(page_url
, &synced_favicon
));
491 EXPECT_EQ(synced_favicon
, double_favicon
);
492 synced_favicon
.clear();
493 EXPECT_TRUE(GetFavicon(page_url2
, &synced_favicon
));
494 EXPECT_EQ(synced_favicon
, double_favicon
);
495 EXPECT_EQ(1U, NumFavicons());
497 // Attempting to decrement a page that's already removed should do nothing.
498 DecrementFavicon(single_favicon_page
);
499 EXPECT_EQ(1U, NumFavicons());
501 // Attempting to decrement an empty url should do nothing.
502 DecrementFavicon("");
503 EXPECT_EQ(1U, NumFavicons());
505 // Decrementing the second and only remaining page should remove the favicon.
506 // Both pages that referred to it should now fail to look up their favicon.
507 DecrementFavicon(page_url2
);
508 synced_favicon
.clear();
509 EXPECT_FALSE(GetFavicon(page_url
, &synced_favicon
));
510 EXPECT_TRUE(synced_favicon
.empty());
511 EXPECT_EQ(0U, NumFavicons());
512 synced_favicon
.clear();
513 EXPECT_FALSE(GetFavicon(page_url2
, &synced_favicon
));
514 EXPECT_TRUE(synced_favicon
.empty());
515 EXPECT_EQ(0U, NumFavicons());
518 // TODO(akalin): We should really use a fake for SyncedTabDelegate.
520 // Make sure GetCurrentVirtualURL() returns the virtual URL of the pending
521 // entry if the current entry is pending.
522 TEST_F(SyncSessionModelAssociatorTest
, GetCurrentVirtualURLPending
) {
523 StrictMock
<SyncedTabDelegateMock
> tab_mock
;
524 scoped_ptr
<content::NavigationEntry
> entry(
525 content::NavigationEntry::Create());
526 entry
->SetVirtualURL(GURL("http://www.google.com"));
527 EXPECT_CALL(tab_mock
, GetCurrentEntryIndex()).WillOnce(Return(0));
528 EXPECT_CALL(tab_mock
, GetPendingEntryIndex()).WillOnce(Return(0));
529 EXPECT_CALL(tab_mock
, GetPendingEntry()).WillOnce(Return(entry
.get()));
530 EXPECT_EQ(entry
->GetVirtualURL(), GetCurrentVirtualURL(tab_mock
));
533 // Make sure GetCurrentVirtualURL() returns the virtual URL of the current
534 // entry if the current entry is non-pending.
535 TEST_F(SyncSessionModelAssociatorTest
, GetCurrentVirtualURLNonPending
) {
536 StrictMock
<SyncedTabDelegateMock
> tab_mock
;
537 scoped_ptr
<content::NavigationEntry
> entry(
538 content::NavigationEntry::Create());
539 entry
->SetVirtualURL(GURL("http://www.google.com"));
540 EXPECT_CALL(tab_mock
, GetCurrentEntryIndex()).WillOnce(Return(0));
541 EXPECT_CALL(tab_mock
, GetPendingEntryIndex()).WillOnce(Return(-1));
542 EXPECT_CALL(tab_mock
, GetEntryAtIndex(0)).WillOnce(Return(entry
.get()));
543 EXPECT_EQ(entry
->GetVirtualURL(), GetCurrentVirtualURL(tab_mock
));
546 const base::Time kTime1
= base::Time::FromInternalValue(100);
547 const base::Time kTime2
= base::Time::FromInternalValue(105);
548 const base::Time kTime3
= base::Time::FromInternalValue(110);
549 const base::Time kTime4
= base::Time::FromInternalValue(120);
550 const base::Time kTime5
= base::Time::FromInternalValue(130);
552 // Populate the mock tab delegate with some data and navigation
553 // entries and make sure that setting a SessionTab from it preserves
554 // those entries (and clobbers any existing data).
555 TEST_F(SyncSessionModelAssociatorTest
, SetSessionTabFromDelegate
) {
556 // Create a tab with three valid entries.
557 NiceMock
<SyncedTabDelegateMock
> tab_mock
;
558 EXPECT_CALL(tab_mock
, GetSessionId()).WillRepeatedly(Return(0));
559 scoped_ptr
<content::NavigationEntry
> entry1(
560 content::NavigationEntry::Create());
561 entry1
->SetVirtualURL(GURL("http://www.google.com"));
562 entry1
->SetTimestamp(kTime1
);
563 scoped_ptr
<content::NavigationEntry
> entry2(
564 content::NavigationEntry::Create());
565 entry2
->SetVirtualURL(GURL("http://www.noodle.com"));
566 entry2
->SetTimestamp(kTime2
);
567 scoped_ptr
<content::NavigationEntry
> entry3(
568 content::NavigationEntry::Create());
569 entry3
->SetVirtualURL(GURL("http://www.doodle.com"));
570 entry3
->SetTimestamp(kTime3
);
571 EXPECT_CALL(tab_mock
, GetCurrentEntryIndex()).WillRepeatedly(Return(2));
572 EXPECT_CALL(tab_mock
, GetEntryAtIndex(0)).WillRepeatedly(
573 Return(entry1
.get()));
574 EXPECT_CALL(tab_mock
, GetEntryAtIndex(1)).WillRepeatedly(
575 Return(entry2
.get()));
576 EXPECT_CALL(tab_mock
, GetEntryAtIndex(2)).WillRepeatedly(
577 Return(entry3
.get()));
578 EXPECT_CALL(tab_mock
, GetEntryCount()).WillRepeatedly(Return(3));
579 EXPECT_CALL(tab_mock
, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
581 SessionTab session_tab
;
582 session_tab
.window_id
.set_id(1);
583 session_tab
.tab_id
.set_id(1);
584 session_tab
.tab_visual_index
= 1;
585 session_tab
.current_navigation_index
= 1;
586 session_tab
.pinned
= true;
587 session_tab
.extension_app_id
= "app id";
588 session_tab
.user_agent_override
= "override";
589 session_tab
.timestamp
= kTime5
;
590 session_tab
.navigations
.push_back(
591 SessionTypesTestHelper::CreateNavigation(
592 "http://www.example.com", "Example"));
593 session_tab
.session_storage_persistent_id
= "persistent id";
594 SetSessionTabFromDelegate(tab_mock
, kTime4
, &session_tab
);
596 EXPECT_EQ(0, session_tab
.window_id
.id());
597 EXPECT_EQ(0, session_tab
.tab_id
.id());
598 EXPECT_EQ(0, session_tab
.tab_visual_index
);
599 EXPECT_EQ(2, session_tab
.current_navigation_index
);
600 EXPECT_FALSE(session_tab
.pinned
);
601 EXPECT_TRUE(session_tab
.extension_app_id
.empty());
602 EXPECT_TRUE(session_tab
.user_agent_override
.empty());
603 EXPECT_EQ(kTime4
, session_tab
.timestamp
);
604 ASSERT_EQ(3u, session_tab
.navigations
.size());
605 EXPECT_EQ(entry1
->GetVirtualURL(),
606 session_tab
.navigations
[0].virtual_url());
607 EXPECT_EQ(entry2
->GetVirtualURL(),
608 session_tab
.navigations
[1].virtual_url());
609 EXPECT_EQ(entry3
->GetVirtualURL(),
610 session_tab
.navigations
[2].virtual_url());
612 SessionTypesTestHelper::GetTimestamp(session_tab
.navigations
[0]));
614 SessionTypesTestHelper::GetTimestamp(session_tab
.navigations
[1]));
616 SessionTypesTestHelper::GetTimestamp(session_tab
.navigations
[2]));
617 EXPECT_TRUE(session_tab
.session_storage_persistent_id
.empty());
622 } // namespace browser_sync