Chromium Code Reviews| 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 |