- add sources.
[platform/framework/web/crosswalk.git] / src / content / common / page_state_serialization_unittest.cc
1 // Copyright 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/strings/string_util.h"
12 #include "base/strings/stringprintf.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]);
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.filesystem_url, b.filesystem_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   EXPECT_EQ(a.blob_uuid, b.blob_uuid);
56 }
57
58 template <>
59 void ExpectEquality(const ExplodedHttpBody& a, const ExplodedHttpBody& b) {
60   EXPECT_EQ(a.http_content_type, b.http_content_type);
61   EXPECT_EQ(a.identifier, b.identifier);
62   EXPECT_EQ(a.contains_passwords, b.contains_passwords);
63   EXPECT_EQ(a.is_null, b.is_null);
64   ExpectEquality(a.elements, b.elements);
65 }
66
67 template <>
68 void ExpectEquality(const ExplodedFrameState& a, const ExplodedFrameState& b) {
69   EXPECT_EQ(a.url_string, b.url_string);
70   EXPECT_EQ(a.original_url_string, b.original_url_string);
71   EXPECT_EQ(a.referrer, b.referrer);
72   EXPECT_EQ(a.target, b.target);
73   EXPECT_EQ(a.state_object, b.state_object);
74   ExpectEquality(a.document_state, b.document_state);
75   EXPECT_EQ(a.scroll_offset, b.scroll_offset);
76   EXPECT_EQ(a.item_sequence_number, b.item_sequence_number);
77   EXPECT_EQ(a.document_sequence_number, b.document_sequence_number);
78   EXPECT_EQ(a.target_frame_id, b.target_frame_id);
79   EXPECT_EQ(a.page_scale_factor, b.page_scale_factor);
80   ExpectEquality(a.http_body, b.http_body);
81   ExpectEquality(a.children, b.children);
82 }
83
84 void ExpectEquality(const ExplodedPageState& a, const ExplodedPageState& b) {
85   ExpectEquality(a.referenced_files, b.referenced_files);
86   ExpectEquality(a.top, b.top);
87 }
88
89 //-----------------------------------------------------------------------------
90
91 class PageStateSerializationTest : public testing::Test {
92  public:
93   void PopulateFrameState(ExplodedFrameState* frame_state) {
94     // Invent some data for the various fields.
95     frame_state->url_string = NS16("http://dev.chromium.org/");
96     frame_state->original_url_string = frame_state->url_string;
97     frame_state->referrer = NS16("https://www.google.com/search?q=dev.chromium.org");
98     frame_state->target = NS16("foo");
99     frame_state->state_object = NS16(NULL);
100     frame_state->document_state.push_back(NS16("1"));
101     frame_state->document_state.push_back(NS16("q"));
102     frame_state->document_state.push_back(NS16("text"));
103     frame_state->document_state.push_back(NS16("dev.chromium.org"));
104     frame_state->scroll_offset = gfx::Point(0, 100);
105     frame_state->item_sequence_number = 1;
106     frame_state->document_sequence_number = 2;
107     frame_state->target_frame_id = 3;
108     frame_state->page_scale_factor = 2.0;
109   }
110
111   void PopulateHttpBody(ExplodedHttpBody* http_body,
112                         std::vector<base::NullableString16>* referenced_files) {
113     http_body->is_null = false;
114     http_body->identifier = 12345;
115     http_body->contains_passwords = false;
116     http_body->http_content_type = NS16("text/foo");
117
118     ExplodedHttpBodyElement e1;
119     e1.type = WebKit::WebHTTPBody::Element::TypeData;
120     e1.data = "foo";
121     http_body->elements.push_back(e1);
122
123     ExplodedHttpBodyElement e2;
124     e2.type = WebKit::WebHTTPBody::Element::TypeFile;
125     e2.file_path = NS16("file.txt");
126     e2.file_start = 100;
127     e2.file_length = 1024;
128     e2.file_modification_time = 9999.0;
129     http_body->elements.push_back(e2);
130
131     referenced_files->push_back(e2.file_path);
132   }
133
134   void PopulateFrameStateForBackwardsCompatTest(
135       ExplodedFrameState* frame_state,
136       bool is_child) {
137     frame_state->url_string = NS16("http://chromium.org/");
138     frame_state->original_url_string = frame_state->url_string;
139     frame_state->referrer = NS16("http://google.com/");
140     if (!is_child)
141       frame_state->target = NS16("target");
142     frame_state->scroll_offset = gfx::Point(42, -42);
143     frame_state->item_sequence_number = 123;
144     frame_state->document_sequence_number = 456;
145     frame_state->target_frame_id = 0;
146     frame_state->page_scale_factor = 2.0f;
147
148     frame_state->document_state.push_back(
149         NS16("\n\r?% WebKit serialized form state version 8 \n\r=&"));
150     frame_state->document_state.push_back(NS16("form key"));
151     frame_state->document_state.push_back(NS16("1"));
152     frame_state->document_state.push_back(NS16("foo"));
153     frame_state->document_state.push_back(NS16("file"));
154     frame_state->document_state.push_back(NS16("2"));
155     frame_state->document_state.push_back(NS16("file.txt"));
156     frame_state->document_state.push_back(NS16("displayName"));
157
158     if (!is_child) {
159       frame_state->http_body.http_content_type = NS16("foo/bar");
160       frame_state->http_body.identifier = 789;
161       frame_state->http_body.is_null = false;
162
163       ExplodedHttpBodyElement e1;
164       e1.type = WebKit::WebHTTPBody::Element::TypeData;
165       e1.data = "first data block";
166       frame_state->http_body.elements.push_back(e1);
167
168       ExplodedHttpBodyElement e2;
169       e2.type = WebKit::WebHTTPBody::Element::TypeFile;
170       e2.file_path = NS16("file.txt");
171       frame_state->http_body.elements.push_back(e2);
172
173       ExplodedHttpBodyElement e3;
174       e3.type = WebKit::WebHTTPBody::Element::TypeData;
175       e3.data = "data the second";
176       frame_state->http_body.elements.push_back(e3);
177
178       ExplodedFrameState child_state;
179       PopulateFrameStateForBackwardsCompatTest(&child_state, true);
180       frame_state->children.push_back(child_state);
181     }
182   }
183
184   void PopulatePageStateForBackwardsCompatTest(ExplodedPageState* page_state) {
185     page_state->referenced_files.push_back(NS16("file.txt"));
186     PopulateFrameStateForBackwardsCompatTest(&page_state->top, false);
187   }
188
189   void TestBackwardsCompat(int version) {
190     const char* suffix = "";
191
192 #if defined(OS_ANDROID)
193     // Unfortunately, the format of version 11 is different on Android, so we
194     // need to use a special reference file.
195     if (version == 11)
196       suffix = "_android";
197 #endif
198
199     base::FilePath path;
200     PathService::Get(content::DIR_TEST_DATA, &path);
201     path = path.AppendASCII("page_state").AppendASCII(
202         base::StringPrintf("serialized_v%d%s.dat", version, suffix));
203
204     std::string file_contents;
205     if (!base::ReadFileToString(path, &file_contents)) {
206       ADD_FAILURE() << "File not found: " << path.value();
207       return;
208     }
209
210     std::string trimmed_contents;
211     EXPECT_TRUE(RemoveChars(file_contents, "\r\n", &trimmed_contents));
212
213     std::string encoded;
214     EXPECT_TRUE(base::Base64Decode(trimmed_contents, &encoded));
215
216     ExplodedPageState output;
217 #if defined(OS_ANDROID)
218     // Because version 11 of the file format unfortunately bakes in the device
219     // scale factor on Android, perform this test by assuming a preset device
220     // scale factor, ignoring the device scale factor of the current device.
221     const float kPresetDeviceScaleFactor = 2.0f;
222     EXPECT_TRUE(DecodePageStateWithDeviceScaleFactorForTesting(
223         encoded,
224         kPresetDeviceScaleFactor,
225         &output));
226 #else
227     EXPECT_TRUE(DecodePageState(encoded, &output));
228 #endif
229
230     ExplodedPageState expected;
231     PopulatePageStateForBackwardsCompatTest(&expected);
232
233     ExpectEquality(expected, output);
234   }
235 };
236
237 TEST_F(PageStateSerializationTest, BasicEmpty) {
238   ExplodedPageState input;
239
240   std::string encoded;
241   EXPECT_TRUE(EncodePageState(input, &encoded));
242
243   ExplodedPageState output;
244   EXPECT_TRUE(DecodePageState(encoded, &output));
245
246   ExpectEquality(input, output);
247 }
248
249 TEST_F(PageStateSerializationTest, BasicFrame) {
250   ExplodedPageState input;
251   PopulateFrameState(&input.top);
252
253   std::string encoded;
254   EXPECT_TRUE(EncodePageState(input, &encoded));
255
256   ExplodedPageState output;
257   EXPECT_TRUE(DecodePageState(encoded, &output));
258
259   ExpectEquality(input, output);
260 }
261
262 TEST_F(PageStateSerializationTest, BasicFramePOST) {
263   ExplodedPageState input;
264   PopulateFrameState(&input.top);
265   PopulateHttpBody(&input.top.http_body, &input.referenced_files);
266
267   std::string encoded;
268   EXPECT_TRUE(EncodePageState(input, &encoded));
269
270   ExplodedPageState output;
271   EXPECT_TRUE(DecodePageState(encoded, &output));
272
273   ExpectEquality(input, output);
274 }
275
276 TEST_F(PageStateSerializationTest, BasicFrameSet) {
277   ExplodedPageState input;
278   PopulateFrameState(&input.top);
279
280   // Add some child frames.
281   for (int i = 0; i < 4; ++i) {
282     ExplodedFrameState child_state;
283     PopulateFrameState(&child_state);
284     input.top.children.push_back(child_state);
285   }
286
287   std::string encoded;
288   EXPECT_TRUE(EncodePageState(input, &encoded));
289
290   ExplodedPageState output;
291   EXPECT_TRUE(DecodePageState(encoded, &output));
292
293   ExpectEquality(input, output);
294 }
295
296 TEST_F(PageStateSerializationTest, BasicFrameSetPOST) {
297   ExplodedPageState input;
298   PopulateFrameState(&input.top);
299
300   // Add some child frames.
301   for (int i = 0; i < 4; ++i) {
302     ExplodedFrameState child_state;
303     PopulateFrameState(&child_state);
304
305     // Simulate a form POST on a subframe.
306     if (i == 2)
307       PopulateHttpBody(&child_state.http_body, &input.referenced_files);
308
309     input.top.children.push_back(child_state);
310   }
311
312   std::string encoded;
313   EncodePageState(input, &encoded);
314
315   ExplodedPageState output;
316   DecodePageState(encoded, &output);
317
318   ExpectEquality(input, output);
319 }
320
321 TEST_F(PageStateSerializationTest, BadMessagesTest1) {
322   Pickle p;
323   // Version 14
324   p.WriteInt(14);
325   // Empty strings.
326   for (int i = 0; i < 6; ++i)
327     p.WriteInt(-1);
328   // Bad real number.
329   p.WriteInt(-1);
330
331   std::string s(static_cast<const char*>(p.data()), p.size());
332
333   ExplodedPageState output;
334   EXPECT_FALSE(DecodePageState(s, &output));
335 }
336
337 TEST_F(PageStateSerializationTest, BadMessagesTest2) {
338   double d = 0;
339   Pickle p;
340   // Version 14
341   p.WriteInt(14);
342   // Empty strings.
343   for (int i = 0; i < 6; ++i)
344     p.WriteInt(-1);
345   // More misc fields.
346   p.WriteData(reinterpret_cast<const char*>(&d), sizeof(d));
347   p.WriteInt(1);
348   p.WriteInt(1);
349   p.WriteInt(0);
350   p.WriteInt(0);
351   p.WriteInt(-1);
352   p.WriteInt(0);
353   // WebForm
354   p.WriteInt(1);
355   p.WriteInt(WebKit::WebHTTPBody::Element::TypeData);
356
357   std::string s(static_cast<const char*>(p.data()), p.size());
358
359   ExplodedPageState output;
360   EXPECT_FALSE(DecodePageState(s, &output));
361 }
362
363 TEST_F(PageStateSerializationTest, DumpExpectedPageStateForBackwardsCompat) {
364   // Comment out this return statement to enable this code.  Use this code to
365   // generate data, based on the current serialization format, for the
366   // BackwardsCompat_vXX tests.
367   return;
368
369   ExplodedPageState state;
370   PopulatePageStateForBackwardsCompatTest(&state);
371
372   std::string encoded;
373   EXPECT_TRUE(EncodePageState(state, &encoded));
374
375   std::string base64;
376   EXPECT_TRUE(base::Base64Encode(encoded, &base64));
377
378   base::FilePath path;
379   PathService::Get(base::DIR_TEMP, &path);
380   path = path.AppendASCII("expected.dat");
381
382   FILE* fp = file_util::OpenFile(path, "wb");
383   ASSERT_TRUE(fp);
384
385   const size_t kRowSize = 76;
386   for (size_t offset = 0; offset < base64.size(); offset += kRowSize) {
387     size_t length = std::min(base64.size() - offset, kRowSize);
388     std::string segment(&base64[offset], length);
389     segment.push_back('\n');
390     fwrite(segment.data(), segment.size(), 1, fp);
391   }
392
393   fclose(fp);
394 }
395
396 #if !defined(OS_ANDROID)
397 // TODO(darin): Re-enable for Android once this test accounts for systems with
398 //              a device scale factor not equal to 2.
399 TEST_F(PageStateSerializationTest, BackwardsCompat_v11) {
400   TestBackwardsCompat(11);
401 }
402 #endif
403
404 TEST_F(PageStateSerializationTest, BackwardsCompat_v12) {
405   TestBackwardsCompat(12);
406 }
407
408 TEST_F(PageStateSerializationTest, BackwardsCompat_v13) {
409   TestBackwardsCompat(13);
410 }
411
412 TEST_F(PageStateSerializationTest, BackwardsCompat_v14) {
413   TestBackwardsCompat(14);
414 }
415
416 TEST_F(PageStateSerializationTest, BackwardsCompat_v15) {
417   TestBackwardsCompat(15);
418 }
419
420 TEST_F(PageStateSerializationTest, BackwardsCompat_v16) {
421   TestBackwardsCompat(16);
422 }
423
424 }  // namespace
425 }  // namespace content