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 #include "components/sessions/serialized_navigation_entry.h"
6
7 #include <cstddef>
8 #include <string>
9
10 #include "base/basictypes.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/pickle.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/time/time.h"
17 #include "content/public/browser/favicon_status.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/common/page_transition_types.h"
20 #include "content/public/common/referrer.h"
21 #include "sync/protocol/session_specifics.pb.h"
22 #include "sync/util/time.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
25 #include "url/gurl.h"
26
27 namespace sessions {
28 namespace {
29
30 const int kIndex = 3;
31 const int kUniqueID = 50;
32 const content::Referrer kReferrer =
33 content::Referrer(GURL("http://www.referrer.com"),
34 blink::WebReferrerPolicyAlways);
35 const GURL kVirtualURL("http://www.virtual-url.com");
36 const base::string16 kTitle = ASCIIToUTF16("title");
37 const content::PageState kPageState =
38 content::PageState::CreateFromEncodedData("page state");
39 const content::PageTransition kTransitionType =
40 static_cast<content::PageTransition>(
41 content::PAGE_TRANSITION_AUTO_SUBFRAME |
42 content::PAGE_TRANSITION_HOME_PAGE |
43 content::PAGE_TRANSITION_CLIENT_REDIRECT);
44 const bool kHasPostData = true;
45 const int64 kPostID = 100;
46 const GURL kOriginalRequestURL("http://www.original-request.com");
47 const bool kIsOverridingUserAgent = true;
48 const base::Time kTimestamp = syncer::ProtoTimeToTime(100);
49 const base::string16 kSearchTerms = ASCIIToUTF16("my search terms");
50 const GURL kFaviconURL("http://virtual-url.com/favicon.ico");
51 const int kHttpStatusCode = 404;
52
53 const int kPageID = 10;
54
55 // Create a NavigationEntry from the constants above.
MakeNavigationEntryForTest()56 scoped_ptr<content::NavigationEntry> MakeNavigationEntryForTest() {
57 scoped_ptr<content::NavigationEntry> navigation_entry(
58 content::NavigationEntry::Create());
59 navigation_entry->SetReferrer(kReferrer);
60 navigation_entry->SetVirtualURL(kVirtualURL);
61 navigation_entry->SetTitle(kTitle);
62 navigation_entry->SetPageState(kPageState);
63 navigation_entry->SetTransitionType(kTransitionType);
64 navigation_entry->SetHasPostData(kHasPostData);
65 navigation_entry->SetPostID(kPostID);
66 navigation_entry->SetOriginalRequestURL(kOriginalRequestURL);
67 navigation_entry->SetIsOverridingUserAgent(kIsOverridingUserAgent);
68 navigation_entry->SetTimestamp(kTimestamp);
69 navigation_entry->SetExtraData(kSearchTermsKey, kSearchTerms);
70 navigation_entry->GetFavicon().valid = true;
71 navigation_entry->GetFavicon().url = kFaviconURL;
72 navigation_entry->SetHttpStatusCode(kHttpStatusCode);
73 return navigation_entry.Pass();
74 }
75
76 // Create a sync_pb::TabNavigation from the constants above.
MakeSyncDataForTest()77 sync_pb::TabNavigation MakeSyncDataForTest() {
78 sync_pb::TabNavigation sync_data;
79 sync_data.set_virtual_url(kVirtualURL.spec());
80 sync_data.set_referrer(kReferrer.url.spec());
81 sync_data.set_title(UTF16ToUTF8(kTitle));
82 sync_data.set_state(kPageState.ToEncodedData());
83 sync_data.set_page_transition(
84 sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME);
85 sync_data.set_unique_id(kUniqueID);
86 sync_data.set_timestamp_msec(syncer::TimeToProtoTime(kTimestamp));
87 sync_data.set_redirect_type(sync_pb::SyncEnums::CLIENT_REDIRECT);
88 sync_data.set_navigation_home_page(true);
89 sync_data.set_search_terms(UTF16ToUTF8(kSearchTerms));
90 sync_data.set_favicon_url(kFaviconURL.spec());
91 sync_data.set_http_status_code(kHttpStatusCode);
92 return sync_data;
93 }
94
95 // Create a default SerializedNavigationEntry. All its fields should be
96 // initialized to their respective default values.
TEST(SerializedNavigationEntryTest,DefaultInitializer)97 TEST(SerializedNavigationEntryTest, DefaultInitializer) {
98 const SerializedNavigationEntry navigation;
99 EXPECT_EQ(-1, navigation.index());
100 EXPECT_EQ(0, navigation.unique_id());
101 EXPECT_EQ(GURL(), navigation.referrer().url);
102 EXPECT_EQ(blink::WebReferrerPolicyDefault, navigation.referrer().policy);
103 EXPECT_EQ(GURL(), navigation.virtual_url());
104 EXPECT_TRUE(navigation.title().empty());
105 EXPECT_FALSE(navigation.page_state().IsValid());
106 EXPECT_EQ(content::PAGE_TRANSITION_TYPED, navigation.transition_type());
107 EXPECT_FALSE(navigation.has_post_data());
108 EXPECT_EQ(-1, navigation.post_id());
109 EXPECT_EQ(GURL(), navigation.original_request_url());
110 EXPECT_FALSE(navigation.is_overriding_user_agent());
111 EXPECT_TRUE(navigation.timestamp().is_null());
112 EXPECT_TRUE(navigation.search_terms().empty());
113 EXPECT_FALSE(navigation.favicon_url().is_valid());
114 EXPECT_EQ(0, navigation.http_status_code());
115 }
116
117 // Create a SerializedNavigationEntry from a NavigationEntry. All its fields
118 // should match the NavigationEntry's.
TEST(SerializedNavigationEntryTest,FromNavigationEntry)119 TEST(SerializedNavigationEntryTest, FromNavigationEntry) {
120 const scoped_ptr<content::NavigationEntry> navigation_entry(
121 MakeNavigationEntryForTest());
122
123 const SerializedNavigationEntry& navigation =
124 SerializedNavigationEntry::FromNavigationEntry(kIndex, *navigation_entry);
125
126 EXPECT_EQ(kIndex, navigation.index());
127
128 EXPECT_EQ(navigation_entry->GetUniqueID(), navigation.unique_id());
129 EXPECT_EQ(kReferrer.url, navigation.referrer().url);
130 EXPECT_EQ(kReferrer.policy, navigation.referrer().policy);
131 EXPECT_EQ(kVirtualURL, navigation.virtual_url());
132 EXPECT_EQ(kTitle, navigation.title());
133 EXPECT_EQ(kPageState, navigation.page_state());
134 EXPECT_EQ(kTransitionType, navigation.transition_type());
135 EXPECT_EQ(kHasPostData, navigation.has_post_data());
136 EXPECT_EQ(kPostID, navigation.post_id());
137 EXPECT_EQ(kOriginalRequestURL, navigation.original_request_url());
138 EXPECT_EQ(kIsOverridingUserAgent, navigation.is_overriding_user_agent());
139 EXPECT_EQ(kTimestamp, navigation.timestamp());
140 EXPECT_EQ(kFaviconURL, navigation.favicon_url());
141 EXPECT_EQ(kHttpStatusCode, navigation.http_status_code());
142 }
143
144 // Create a SerializedNavigationEntry from a sync_pb::TabNavigation. All its
145 // fields should match the protocol buffer's if it exists there, and
146 // sbould be set to the default value otherwise.
TEST(SerializedNavigationEntryTest,FromSyncData)147 TEST(SerializedNavigationEntryTest, FromSyncData) {
148 const sync_pb::TabNavigation sync_data = MakeSyncDataForTest();
149
150 const SerializedNavigationEntry& navigation =
151 SerializedNavigationEntry::FromSyncData(kIndex, sync_data);
152
153 EXPECT_EQ(kIndex, navigation.index());
154 EXPECT_EQ(kUniqueID, navigation.unique_id());
155 EXPECT_EQ(kReferrer.url, navigation.referrer().url);
156 EXPECT_EQ(blink::WebReferrerPolicyDefault, navigation.referrer().policy);
157 EXPECT_EQ(kVirtualURL, navigation.virtual_url());
158 EXPECT_EQ(kTitle, navigation.title());
159 EXPECT_EQ(kPageState, navigation.page_state());
160 EXPECT_EQ(kTransitionType, navigation.transition_type());
161 EXPECT_FALSE(navigation.has_post_data());
162 EXPECT_EQ(-1, navigation.post_id());
163 EXPECT_EQ(GURL(), navigation.original_request_url());
164 EXPECT_FALSE(navigation.is_overriding_user_agent());
165 EXPECT_TRUE(navigation.timestamp().is_null());
166 EXPECT_EQ(kSearchTerms, navigation.search_terms());
167 EXPECT_EQ(kFaviconURL, navigation.favicon_url());
168 EXPECT_EQ(kHttpStatusCode, navigation.http_status_code());
169 }
170
171 // Create a SerializedNavigationEntry, pickle it, then create another one by
172 // unpickling. The new one should match the old one except for fields
173 // that aren't pickled, which should be set to default values.
TEST(SerializedNavigationEntryTest,Pickle)174 TEST(SerializedNavigationEntryTest, Pickle) {
175 const SerializedNavigationEntry& old_navigation =
176 SerializedNavigationEntry::FromNavigationEntry(
177 kIndex, *MakeNavigationEntryForTest());
178
179 Pickle pickle;
180 old_navigation.WriteToPickle(30000, &pickle);
181
182 SerializedNavigationEntry new_navigation;
183 PickleIterator pickle_iterator(pickle);
184 EXPECT_TRUE(new_navigation.ReadFromPickle(&pickle_iterator));
185
186 EXPECT_EQ(kIndex, new_navigation.index());
187
188 EXPECT_EQ(0, new_navigation.unique_id());
189 EXPECT_EQ(kReferrer.url, new_navigation.referrer().url);
190 EXPECT_EQ(kReferrer.policy, new_navigation.referrer().policy);
191 EXPECT_EQ(kVirtualURL, new_navigation.virtual_url());
192 EXPECT_EQ(kTitle, new_navigation.title());
193 EXPECT_FALSE(new_navigation.page_state().IsValid());
194 EXPECT_EQ(kTransitionType, new_navigation.transition_type());
195 EXPECT_EQ(kHasPostData, new_navigation.has_post_data());
196 EXPECT_EQ(-1, new_navigation.post_id());
197 EXPECT_EQ(kOriginalRequestURL, new_navigation.original_request_url());
198 EXPECT_EQ(kIsOverridingUserAgent, new_navigation.is_overriding_user_agent());
199 EXPECT_EQ(kTimestamp, new_navigation.timestamp());
200 EXPECT_EQ(kSearchTerms, new_navigation.search_terms());
201 EXPECT_EQ(kHttpStatusCode, new_navigation.http_status_code());
202 }
203
204 // Create a NavigationEntry, then create another one by converting to
205 // a SerializedNavigationEntry and back. The new one should match the old one
206 // except for fields that aren't preserved, which should be set to
207 // expected values.
TEST(SerializedNavigationEntryTest,ToNavigationEntry)208 TEST(SerializedNavigationEntryTest, ToNavigationEntry) {
209 const scoped_ptr<content::NavigationEntry> old_navigation_entry(
210 MakeNavigationEntryForTest());
211
212 const SerializedNavigationEntry& navigation =
213 SerializedNavigationEntry::FromNavigationEntry(kIndex,
214 *old_navigation_entry);
215
216 const scoped_ptr<content::NavigationEntry> new_navigation_entry(
217 navigation.ToNavigationEntry(kPageID, NULL));
218
219 EXPECT_EQ(kReferrer.url, new_navigation_entry->GetReferrer().url);
220 EXPECT_EQ(kReferrer.policy, new_navigation_entry->GetReferrer().policy);
221 EXPECT_EQ(kVirtualURL, new_navigation_entry->GetVirtualURL());
222 EXPECT_EQ(kTitle, new_navigation_entry->GetTitle());
223 EXPECT_EQ(kPageState, new_navigation_entry->GetPageState());
224 EXPECT_EQ(kPageID, new_navigation_entry->GetPageID());
225 EXPECT_EQ(content::PAGE_TRANSITION_RELOAD,
226 new_navigation_entry->GetTransitionType());
227 EXPECT_EQ(kHasPostData, new_navigation_entry->GetHasPostData());
228 EXPECT_EQ(kPostID, new_navigation_entry->GetPostID());
229 EXPECT_EQ(kOriginalRequestURL,
230 new_navigation_entry->GetOriginalRequestURL());
231 EXPECT_EQ(kIsOverridingUserAgent,
232 new_navigation_entry->GetIsOverridingUserAgent());
233 base::string16 search_terms;
234 new_navigation_entry->GetExtraData(kSearchTermsKey, &search_terms);
235 EXPECT_EQ(kSearchTerms, search_terms);
236 EXPECT_EQ(kHttpStatusCode, new_navigation_entry->GetHttpStatusCode());
237 }
238
239 // Create a NavigationEntry, convert it to a SerializedNavigationEntry, then
240 // create a sync protocol buffer from it. The protocol buffer should
241 // have matching fields to the NavigationEntry (when applicable).
TEST(SerializedNavigationEntryTest,ToSyncData)242 TEST(SerializedNavigationEntryTest, ToSyncData) {
243 const scoped_ptr<content::NavigationEntry> navigation_entry(
244 MakeNavigationEntryForTest());
245
246 const SerializedNavigationEntry& navigation =
247 SerializedNavigationEntry::FromNavigationEntry(kIndex, *navigation_entry);
248
249 const sync_pb::TabNavigation sync_data = navigation.ToSyncData();
250
251 EXPECT_EQ(kVirtualURL.spec(), sync_data.virtual_url());
252 EXPECT_EQ(kReferrer.url.spec(), sync_data.referrer());
253 EXPECT_EQ(kTitle, ASCIIToUTF16(sync_data.title()));
254 EXPECT_TRUE(sync_data.state().empty());
255 EXPECT_EQ(sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME,
256 sync_data.page_transition());
257 EXPECT_TRUE(sync_data.has_redirect_type());
258 EXPECT_EQ(navigation_entry->GetUniqueID(), sync_data.unique_id());
259 EXPECT_EQ(syncer::TimeToProtoTime(kTimestamp), sync_data.timestamp_msec());
260 EXPECT_EQ(kTimestamp.ToInternalValue(), sync_data.global_id());
261 EXPECT_EQ(kFaviconURL.spec(), sync_data.favicon_url());
262 EXPECT_EQ(kHttpStatusCode, sync_data.http_status_code());
263 }
264
265 // Ensure all transition types and qualifiers are converted to/from the sync
266 // SerializedNavigationEntry representation properly.
TEST(SerializedNavigationEntryTest,TransitionTypes)267 TEST(SerializedNavigationEntryTest, TransitionTypes) {
268 scoped_ptr<content::NavigationEntry> navigation_entry(
269 MakeNavigationEntryForTest());
270 for (uint32 core_type = content::PAGE_TRANSITION_LINK;
271 core_type != content::PAGE_TRANSITION_LAST_CORE; ++core_type) {
272 // Because qualifier is a uint32, left shifting will eventually overflow
273 // and hit zero again. SERVER_REDIRECT, as the last qualifier and also
274 // in place of the sign bit, is therefore the last transition before
275 // breaking.
276 for (uint32 qualifier = content::PAGE_TRANSITION_FORWARD_BACK;
277 qualifier != 0; qualifier <<= 1) {
278 if (qualifier == 0x08000000)
279 continue; // 0x08000000 is not a valid qualifier.
280 content::PageTransition transition =
281 static_cast<content::PageTransition>(core_type | qualifier);
282
283 navigation_entry->SetTransitionType(transition);
284 const SerializedNavigationEntry& navigation =
285 SerializedNavigationEntry::FromNavigationEntry(kIndex,
286 *navigation_entry);
287 const sync_pb::TabNavigation& sync_data = navigation.ToSyncData();
288 const SerializedNavigationEntry& constructed_nav =
289 SerializedNavigationEntry::FromSyncData(kIndex, sync_data);
290 const content::PageTransition constructed_transition =
291 constructed_nav.transition_type();
292
293 EXPECT_EQ(transition, constructed_transition);
294 }
295 }
296 }
297
298 } // namespace
299 } // namespace sessions
300