OLD | NEW |
---|---|
(Empty) | |
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 <math.h> | |
6 | |
7 #include "base/base64.h" | |
8 #include "base/file_util.h" | |
9 #include "base/path_service.h" | |
10 #include "base/pickle.h" | |
11 #include "base/stringprintf.h" | |
12 #include "base/strings/string_util.h" | |
13 #include "base/strings/utf_string_conversions.h" | |
14 #include "content/common/page_state_serialization.h" | |
15 #include "content/public/common/content_paths.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 | |
18 namespace content { | |
19 namespace { | |
20 | |
21 #if defined(OS_WIN) | |
22 inline bool isnan(double num) { return !!_isnan(num); } | |
23 #endif | |
24 | |
25 base::NullableString16 NS16(const char* s) { | |
26 return s ? base::NullableString16(ASCIIToUTF16(s), false) : | |
27 base::NullableString16(); | |
28 } | |
29 | |
30 //----------------------------------------------------------------------------- | |
31 | |
32 template <typename T> | |
33 void ExpectEquality(const T& a, const T& b) { | |
34 EXPECT_EQ(a, b); | |
35 } | |
36 | |
37 template <typename T> | |
38 void ExpectEquality(const std::vector<T>& a, const std::vector<T>& b) { | |
39 EXPECT_EQ(a.size(), b.size()); | |
40 for (size_t i = 0; i < std::min(a.size(), b.size()); ++i) | |
41 ExpectEquality(a[i], b[i]); | |
jamesr
2013/06/21 23:24:53
i think EXPECT_EQ(a[i], b[i]) should work here
darin (slow to review)
2013/06/24 08:02:10
This ExpectEquality call is needed to handle these
| |
42 } | |
43 | |
44 template <> | |
45 void ExpectEquality(const ExplodedHttpBodyElement& a, | |
46 const ExplodedHttpBodyElement& b) { | |
47 EXPECT_EQ(a.type, b.type); | |
48 EXPECT_EQ(a.data, b.data); | |
49 EXPECT_EQ(a.file_path, b.file_path); | |
50 EXPECT_EQ(a.url, b.url); | |
51 EXPECT_EQ(a.file_start, b.file_start); | |
52 EXPECT_EQ(a.file_length, b.file_length); | |
53 if (!(isnan(a.file_modification_time) && isnan(b.file_modification_time))) | |
54 EXPECT_DOUBLE_EQ(a.file_modification_time, b.file_modification_time); | |
55 } | |
56 | |
57 template <> | |
58 void ExpectEquality(const ExplodedHttpBody& a, const ExplodedHttpBody& b) { | |
59 EXPECT_EQ(a.http_content_type, b.http_content_type); | |
60 EXPECT_EQ(a.identifier, b.identifier); | |
61 EXPECT_EQ(a.contains_passwords, b.contains_passwords); | |
62 EXPECT_EQ(a.is_null, b.is_null); | |
63 ExpectEquality(a.elements, b.elements); | |
64 } | |
65 | |
66 template <> | |
67 void ExpectEquality(const ExplodedFrameState& a, const ExplodedFrameState& b) { | |
68 EXPECT_EQ(a.url_string, b.url_string); | |
69 EXPECT_EQ(a.original_url_string, b.original_url_string); | |
70 EXPECT_EQ(a.referrer, b.referrer); | |
71 EXPECT_EQ(a.target, b.target); | |
72 EXPECT_EQ(a.parent, b.parent); | |
73 EXPECT_EQ(a.title, b.title); | |
74 EXPECT_EQ(a.alternate_title, b.alternate_title); | |
75 EXPECT_EQ(a.state_object, b.state_object); | |
76 ExpectEquality(a.document_state, b.document_state); | |
77 EXPECT_EQ(a.scroll_offset, b.scroll_offset); | |
78 EXPECT_EQ(a.item_sequence_number, b.item_sequence_number); | |
79 EXPECT_EQ(a.document_sequence_number, b.document_sequence_number); | |
80 EXPECT_EQ(a.visit_count, b.visit_count); | |
81 EXPECT_EQ(a.visited_time, b.visited_time); | |
82 EXPECT_EQ(a.page_scale_factor, b.page_scale_factor); | |
jamesr
2013/06/21 23:24:53
file_modificiation_time has checks for nan, but fo
| |
83 EXPECT_EQ(a.is_target_item, b.is_target_item); | |
84 ExpectEquality(a.http_body, b.http_body); | |
85 ExpectEquality(a.children, b.children); | |
86 } | |
87 | |
88 void ExpectEquality(const ExplodedPageState& a, const ExplodedPageState& b) { | |
89 ExpectEquality(a.referenced_files, b.referenced_files); | |
90 ExpectEquality(a.top, b.top); | |
91 } | |
92 | |
93 //----------------------------------------------------------------------------- | |
94 | |
95 class PageStateSerializationTest : public testing::Test { | |
96 public: | |
97 void PopulateFrameState(ExplodedFrameState* frame_state) { | |
98 // Invent some data for the various fields. | |
99 frame_state->url_string = NS16("http://dev.chromium.org/"); | |
100 frame_state->original_url_string = frame_state->url_string; | |
101 frame_state->referrer = NS16("https://www.google.com/search?q=dev.chromium.o rg"); | |
102 frame_state->target = NS16("foo"); | |
103 frame_state->parent = NS16("bar"); | |
104 frame_state->title = NS16("The Chromium Projects"); | |
105 frame_state->alternate_title = NS16(NULL); | |
106 frame_state->state_object = NS16(NULL); | |
107 frame_state->document_state.push_back(NS16("1")); | |
108 frame_state->document_state.push_back(NS16("q")); | |
109 frame_state->document_state.push_back(NS16("text")); | |
110 frame_state->document_state.push_back(NS16("dev.chromium.org")); | |
111 frame_state->scroll_offset = gfx::Point(0, 100); | |
112 frame_state->item_sequence_number = 1; | |
113 frame_state->document_sequence_number = 2; | |
114 frame_state->visit_count = 10; | |
115 frame_state->visited_time = 12345.0; | |
116 frame_state->page_scale_factor = 2.0; | |
117 frame_state->is_target_item = true; | |
118 } | |
119 | |
120 void PopulateHttpBody(ExplodedHttpBody* http_body, | |
121 std::vector<base::NullableString16>* referenced_files) { | |
122 http_body->is_null = false; | |
123 http_body->identifier = 12345; | |
124 http_body->contains_passwords = false; | |
125 http_body->http_content_type = NS16("text/foo"); | |
126 | |
127 ExplodedHttpBodyElement e1; | |
128 e1.type = WebKit::WebHTTPBody::Element::TypeData; | |
129 e1.data = "foo"; | |
130 http_body->elements.push_back(e1); | |
131 | |
132 ExplodedHttpBodyElement e2; | |
133 e2.type = WebKit::WebHTTPBody::Element::TypeFile; | |
134 e2.file_path = NS16("file.txt"); | |
135 e2.file_start = 100; | |
136 e2.file_length = 1024; | |
137 e2.file_modification_time = 9999.0; | |
138 http_body->elements.push_back(e2); | |
139 | |
140 referenced_files->push_back(e2.file_path); | |
141 } | |
142 | |
143 void PopulateFrameStateForBackwardsCompatTest( | |
144 ExplodedFrameState* frame_state, | |
145 bool is_child) { | |
146 frame_state->url_string = NS16("http://chromium.org/"); | |
147 frame_state->original_url_string = frame_state->url_string; | |
148 frame_state->referrer = NS16("http://google.com/"); | |
149 if (!is_child) | |
150 frame_state->target = NS16("target"); | |
151 frame_state->parent = NS16("parent"); | |
152 frame_state->title = NS16("title"); | |
153 frame_state->alternate_title = NS16("alternateTitle"); | |
154 frame_state->scroll_offset = gfx::Point(42, -42); | |
155 frame_state->item_sequence_number = 123; | |
156 frame_state->document_sequence_number = 456; | |
157 frame_state->visit_count = 42*42; | |
158 frame_state->visited_time = 13.37; | |
159 frame_state->page_scale_factor = 2.0f; | |
160 frame_state->is_target_item = true; | |
161 | |
162 frame_state->document_state.push_back( | |
163 NS16("\n\r?% WebKit serialized form state version 8 \n\r=&")); | |
164 frame_state->document_state.push_back(NS16("form key")); | |
165 frame_state->document_state.push_back(NS16("1")); | |
166 frame_state->document_state.push_back(NS16("foo")); | |
167 frame_state->document_state.push_back(NS16("file")); | |
168 frame_state->document_state.push_back(NS16("2")); | |
169 frame_state->document_state.push_back(NS16("file.txt")); | |
170 frame_state->document_state.push_back(NS16("displayName")); | |
171 | |
172 if (!is_child) { | |
173 frame_state->http_body.http_content_type = NS16("foo/bar"); | |
174 frame_state->http_body.identifier = 789; | |
175 frame_state->http_body.is_null = false; | |
176 | |
177 ExplodedHttpBodyElement e1; | |
178 e1.type = WebKit::WebHTTPBody::Element::TypeData; | |
179 e1.data = "first data block"; | |
180 frame_state->http_body.elements.push_back(e1); | |
181 | |
182 ExplodedHttpBodyElement e2; | |
183 e2.type = WebKit::WebHTTPBody::Element::TypeFile; | |
184 e2.file_path = NS16("file.txt"); | |
185 frame_state->http_body.elements.push_back(e2); | |
186 | |
187 ExplodedHttpBodyElement e3; | |
188 e3.type = WebKit::WebHTTPBody::Element::TypeData; | |
189 e3.data = "data the second"; | |
190 frame_state->http_body.elements.push_back(e3); | |
191 | |
192 ExplodedFrameState child_state; | |
193 PopulateFrameStateForBackwardsCompatTest(&child_state, true); | |
194 frame_state->children.push_back(child_state); | |
195 } | |
196 } | |
197 | |
198 void PopulatePageStateForBackwardsCompatTest(ExplodedPageState* page_state) { | |
199 page_state->referenced_files.push_back(NS16("file.txt")); | |
200 PopulateFrameStateForBackwardsCompatTest(&page_state->top, false); | |
201 } | |
202 | |
203 void TestBackwardsCompat(int version) { | |
204 const char* suffix = ""; | |
205 | |
206 #if defined(OS_ANDROID) | |
207 // Unfortunately, the format of version 11 is different on Android, so we | |
208 // need to use a special reference file. | |
209 if (version == 11) | |
210 suffix = "_android"; | |
211 #endif | |
212 | |
213 base::FilePath path; | |
214 PathService::Get(content::DIR_TEST_DATA, &path); | |
215 path = path.AppendASCII("page_state").AppendASCII( | |
216 base::StringPrintf("serialized_v%d%s.dat", version, suffix)); | |
217 | |
218 std::string file_contents; | |
219 if (!file_util::ReadFileToString(path, &file_contents)) { | |
220 ADD_FAILURE() << "File not found: " << path.value(); | |
221 return; | |
222 } | |
223 | |
224 std::string trimmed_contents; | |
225 EXPECT_TRUE(RemoveChars(file_contents, "\r\n", &trimmed_contents)); | |
226 | |
227 std::string encoded; | |
228 EXPECT_TRUE(base::Base64Decode(trimmed_contents, &encoded)); | |
229 | |
230 ExplodedPageState output; | |
231 EXPECT_TRUE(DecodePageState(encoded, &output)); | |
232 | |
233 ExplodedPageState expected; | |
234 PopulatePageStateForBackwardsCompatTest(&expected); | |
235 | |
236 ExpectEquality(expected, output); | |
237 } | |
238 }; | |
239 | |
240 TEST_F(PageStateSerializationTest, BasicEmpty) { | |
241 ExplodedPageState input; | |
242 | |
243 std::string encoded; | |
244 EXPECT_TRUE(EncodePageState(input, &encoded)); | |
245 | |
246 ExplodedPageState output; | |
247 EXPECT_TRUE(DecodePageState(encoded, &output)); | |
248 | |
249 ExpectEquality(input, output); | |
250 } | |
251 | |
252 TEST_F(PageStateSerializationTest, BasicFrame) { | |
253 ExplodedPageState input; | |
254 PopulateFrameState(&input.top); | |
255 | |
256 std::string encoded; | |
257 EXPECT_TRUE(EncodePageState(input, &encoded)); | |
258 | |
259 ExplodedPageState output; | |
260 EXPECT_TRUE(DecodePageState(encoded, &output)); | |
261 | |
262 ExpectEquality(input, output); | |
263 } | |
264 | |
265 TEST_F(PageStateSerializationTest, BasicFramePOST) { | |
266 ExplodedPageState input; | |
267 PopulateFrameState(&input.top); | |
268 PopulateHttpBody(&input.top.http_body, &input.referenced_files); | |
269 | |
270 std::string encoded; | |
271 EXPECT_TRUE(EncodePageState(input, &encoded)); | |
272 | |
273 ExplodedPageState output; | |
274 EXPECT_TRUE(DecodePageState(encoded, &output)); | |
275 | |
276 ExpectEquality(input, output); | |
277 } | |
278 | |
279 TEST_F(PageStateSerializationTest, BasicFrameSet) { | |
280 ExplodedPageState input; | |
281 PopulateFrameState(&input.top); | |
282 | |
283 // Add some child frames. | |
284 for (int i = 0; i < 4; ++i) { | |
285 ExplodedFrameState child_state; | |
286 PopulateFrameState(&child_state); | |
287 input.top.children.push_back(child_state); | |
288 } | |
289 | |
290 std::string encoded; | |
291 EXPECT_TRUE(EncodePageState(input, &encoded)); | |
292 | |
293 ExplodedPageState output; | |
294 EXPECT_TRUE(DecodePageState(encoded, &output)); | |
295 | |
296 ExpectEquality(input, output); | |
297 } | |
298 | |
299 TEST_F(PageStateSerializationTest, BasicFrameSetPOST) { | |
300 ExplodedPageState input; | |
301 PopulateFrameState(&input.top); | |
302 | |
303 // Add some child frames. | |
304 for (int i = 0; i < 4; ++i) { | |
305 ExplodedFrameState child_state; | |
306 PopulateFrameState(&child_state); | |
307 | |
308 // Simulate a form POST on a subframe. | |
309 if (i == 2) | |
310 PopulateHttpBody(&child_state.http_body, &input.referenced_files); | |
311 | |
312 input.top.children.push_back(child_state); | |
313 } | |
314 | |
315 std::string encoded; | |
316 EncodePageState(input, &encoded); | |
317 | |
318 ExplodedPageState output; | |
319 DecodePageState(encoded, &output); | |
320 | |
321 ExpectEquality(input, output); | |
322 } | |
323 | |
324 TEST_F(PageStateSerializationTest, BadMessagesTest1) { | |
325 Pickle p; | |
326 // Version 14 | |
327 p.WriteInt(14); | |
328 // Empty strings. | |
329 for (int i = 0; i < 6; ++i) | |
330 p.WriteInt(-1); | |
331 // Bad real number. | |
332 p.WriteInt(-1); | |
333 | |
334 std::string s(static_cast<const char*>(p.data()), p.size()); | |
335 | |
336 ExplodedPageState output; | |
337 EXPECT_FALSE(DecodePageState(s, &output)); | |
338 } | |
339 | |
340 TEST_F(PageStateSerializationTest, BadMessagesTest2) { | |
341 double d = 0; | |
jamesr
2013/06/21 23:24:53
should 0.0 according to http://google-styleguide.g
| |
342 Pickle p; | |
343 // Version 14 | |
344 p.WriteInt(14); | |
345 // Empty strings. | |
346 for (int i = 0; i < 6; ++i) | |
347 p.WriteInt(-1); | |
348 // More misc fields. | |
349 p.WriteData(reinterpret_cast<const char*>(&d), sizeof(d)); | |
350 p.WriteInt(1); | |
351 p.WriteInt(1); | |
352 p.WriteInt(0); | |
353 p.WriteInt(0); | |
354 p.WriteInt(-1); | |
355 p.WriteInt(0); | |
356 // WebForm | |
357 p.WriteInt(1); | |
358 p.WriteInt(WebKit::WebHTTPBody::Element::TypeData); | |
359 | |
360 std::string s(static_cast<const char*>(p.data()), p.size()); | |
361 | |
362 ExplodedPageState output; | |
363 EXPECT_FALSE(DecodePageState(s, &output)); | |
364 } | |
365 | |
366 TEST_F(PageStateSerializationTest, DumpExpectedPageStateForBackwardsCompat) { | |
367 // Comment out this return statement to enable this code. Use this code to | |
368 // generate data, based on the current serialization format, for the | |
369 // BackwardsCompat_vXX tests. | |
370 return; | |
371 | |
372 ExplodedPageState state; | |
373 PopulatePageStateForBackwardsCompatTest(&state); | |
374 | |
375 std::string encoded; | |
376 EXPECT_TRUE(EncodePageState(state, &encoded)); | |
377 | |
378 std::string base64; | |
379 EXPECT_TRUE(base::Base64Encode(encoded, &base64)); | |
380 | |
381 base::FilePath path; | |
382 PathService::Get(base::DIR_TEMP, &path); | |
383 path = path.AppendASCII("expected.dat"); | |
384 | |
385 FILE* fp = file_util::OpenFile(path, "wb"); | |
386 ASSERT_TRUE(fp); | |
387 | |
388 const size_t kRowSize = 76; | |
389 for (size_t offset = 0; offset < base64.size(); offset += kRowSize) { | |
390 size_t length = std::min(base64.size() - offset, kRowSize); | |
391 std::string segment(&base64[offset], length); | |
392 segment.push_back('\n'); | |
393 fwrite(segment.data(), segment.size(), 1, fp); | |
jamesr
2013/06/21 23:24:53
does fwrite() compile on windows? i'd expect a cal
darin (slow to review)
2013/06/24 08:02:10
Yes (the windows try bots are happy). file_util::
| |
394 } | |
395 | |
396 file_util::CloseFile(fp); | |
397 } | |
398 | |
399 TEST_F(PageStateSerializationTest, BackwardsCompat_v11) { | |
400 TestBackwardsCompat(11); | |
401 } | |
402 | |
403 TEST_F(PageStateSerializationTest, BackwardsCompat_v12) { | |
404 TestBackwardsCompat(12); | |
405 } | |
406 | |
407 TEST_F(PageStateSerializationTest, BackwardsCompat_v13) { | |
408 TestBackwardsCompat(13); | |
409 } | |
410 | |
411 TEST_F(PageStateSerializationTest, BackwardsCompat_v14) { | |
412 TestBackwardsCompat(14); | |
413 } | |
414 | |
415 } // namespace | |
416 } // namespace content | |
OLD | NEW |