| Index: content/common/page_state_serialization_unittest.cc
|
| diff --git a/content/common/page_state_serialization_unittest.cc b/content/common/page_state_serialization_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c960ee2ab148e4dc47af35a4142c7988305bf1e4
|
| --- /dev/null
|
| +++ b/content/common/page_state_serialization_unittest.cc
|
| @@ -0,0 +1,416 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <math.h>
|
| +
|
| +#include "base/base64.h"
|
| +#include "base/file_util.h"
|
| +#include "base/path_service.h"
|
| +#include "base/pickle.h"
|
| +#include "base/stringprintf.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "content/common/page_state_serialization.h"
|
| +#include "content/public/common/content_paths.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace content {
|
| +namespace {
|
| +
|
| +#if defined(OS_WIN)
|
| +inline bool isnan(double num) { return !!_isnan(num); }
|
| +#endif
|
| +
|
| +base::NullableString16 NS16(const char* s) {
|
| + return s ? base::NullableString16(ASCIIToUTF16(s), false) :
|
| + base::NullableString16();
|
| +}
|
| +
|
| +//-----------------------------------------------------------------------------
|
| +
|
| +template <typename T>
|
| +void ExpectEquality(const T& a, const T& b) {
|
| + EXPECT_EQ(a, b);
|
| +}
|
| +
|
| +template <typename T>
|
| +void ExpectEquality(const std::vector<T>& a, const std::vector<T>& b) {
|
| + EXPECT_EQ(a.size(), b.size());
|
| + for (size_t i = 0; i < std::min(a.size(), b.size()); ++i)
|
| + ExpectEquality(a[i], b[i]);
|
| +}
|
| +
|
| +template <>
|
| +void ExpectEquality(const ExplodedHttpBodyElement& a,
|
| + const ExplodedHttpBodyElement& b) {
|
| + EXPECT_EQ(a.type, b.type);
|
| + EXPECT_EQ(a.data, b.data);
|
| + EXPECT_EQ(a.file_path, b.file_path);
|
| + EXPECT_EQ(a.url, b.url);
|
| + EXPECT_EQ(a.file_start, b.file_start);
|
| + EXPECT_EQ(a.file_length, b.file_length);
|
| + if (!(isnan(a.file_modification_time) && isnan(b.file_modification_time)))
|
| + EXPECT_DOUBLE_EQ(a.file_modification_time, b.file_modification_time);
|
| +}
|
| +
|
| +template <>
|
| +void ExpectEquality(const ExplodedHttpBody& a, const ExplodedHttpBody& b) {
|
| + EXPECT_EQ(a.http_content_type, b.http_content_type);
|
| + EXPECT_EQ(a.identifier, b.identifier);
|
| + EXPECT_EQ(a.contains_passwords, b.contains_passwords);
|
| + EXPECT_EQ(a.is_null, b.is_null);
|
| + ExpectEquality(a.elements, b.elements);
|
| +}
|
| +
|
| +template <>
|
| +void ExpectEquality(const ExplodedFrameState& a, const ExplodedFrameState& b) {
|
| + EXPECT_EQ(a.url_string, b.url_string);
|
| + EXPECT_EQ(a.original_url_string, b.original_url_string);
|
| + EXPECT_EQ(a.referrer, b.referrer);
|
| + EXPECT_EQ(a.target, b.target);
|
| + EXPECT_EQ(a.parent, b.parent);
|
| + EXPECT_EQ(a.title, b.title);
|
| + EXPECT_EQ(a.alternate_title, b.alternate_title);
|
| + EXPECT_EQ(a.state_object, b.state_object);
|
| + ExpectEquality(a.document_state, b.document_state);
|
| + EXPECT_EQ(a.scroll_offset, b.scroll_offset);
|
| + EXPECT_EQ(a.item_sequence_number, b.item_sequence_number);
|
| + EXPECT_EQ(a.document_sequence_number, b.document_sequence_number);
|
| + EXPECT_EQ(a.visit_count, b.visit_count);
|
| + EXPECT_EQ(a.visited_time, b.visited_time);
|
| + EXPECT_EQ(a.page_scale_factor, b.page_scale_factor);
|
| + EXPECT_EQ(a.is_target_item, b.is_target_item);
|
| + ExpectEquality(a.http_body, b.http_body);
|
| + ExpectEquality(a.children, b.children);
|
| +}
|
| +
|
| +void ExpectEquality(const ExplodedPageState& a, const ExplodedPageState& b) {
|
| + ExpectEquality(a.referenced_files, b.referenced_files);
|
| + ExpectEquality(a.top, b.top);
|
| +}
|
| +
|
| +//-----------------------------------------------------------------------------
|
| +
|
| +class PageStateSerializationTest : public testing::Test {
|
| + public:
|
| + void PopulateFrameState(ExplodedFrameState* frame_state) {
|
| + // Invent some data for the various fields.
|
| + frame_state->url_string = NS16("http://dev.chromium.org/");
|
| + frame_state->original_url_string = frame_state->url_string;
|
| + frame_state->referrer = NS16("https://www.google.com/search?q=dev.chromium.org");
|
| + frame_state->target = NS16("foo");
|
| + frame_state->parent = NS16("bar");
|
| + frame_state->title = NS16("The Chromium Projects");
|
| + frame_state->alternate_title = NS16(NULL);
|
| + frame_state->state_object = NS16(NULL);
|
| + frame_state->document_state.push_back(NS16("1"));
|
| + frame_state->document_state.push_back(NS16("q"));
|
| + frame_state->document_state.push_back(NS16("text"));
|
| + frame_state->document_state.push_back(NS16("dev.chromium.org"));
|
| + frame_state->scroll_offset = gfx::Point(0, 100);
|
| + frame_state->item_sequence_number = 1;
|
| + frame_state->document_sequence_number = 2;
|
| + frame_state->visit_count = 10;
|
| + frame_state->visited_time = 12345.0;
|
| + frame_state->page_scale_factor = 2.0;
|
| + frame_state->is_target_item = true;
|
| + }
|
| +
|
| + void PopulateHttpBody(ExplodedHttpBody* http_body,
|
| + std::vector<base::NullableString16>* referenced_files) {
|
| + http_body->is_null = false;
|
| + http_body->identifier = 12345;
|
| + http_body->contains_passwords = false;
|
| + http_body->http_content_type = NS16("text/foo");
|
| +
|
| + ExplodedHttpBodyElement e1;
|
| + e1.type = WebKit::WebHTTPBody::Element::TypeData;
|
| + e1.data = "foo";
|
| + http_body->elements.push_back(e1);
|
| +
|
| + ExplodedHttpBodyElement e2;
|
| + e2.type = WebKit::WebHTTPBody::Element::TypeFile;
|
| + e2.file_path = NS16("file.txt");
|
| + e2.file_start = 100;
|
| + e2.file_length = 1024;
|
| + e2.file_modification_time = 9999.0;
|
| + http_body->elements.push_back(e2);
|
| +
|
| + referenced_files->push_back(e2.file_path);
|
| + }
|
| +
|
| + void PopulateFrameStateForBackwardsCompatTest(
|
| + ExplodedFrameState* frame_state,
|
| + bool is_child) {
|
| + frame_state->url_string = NS16("http://chromium.org/");
|
| + frame_state->original_url_string = frame_state->url_string;
|
| + frame_state->referrer = NS16("http://google.com/");
|
| + if (!is_child)
|
| + frame_state->target = NS16("target");
|
| + frame_state->parent = NS16("parent");
|
| + frame_state->title = NS16("title");
|
| + frame_state->alternate_title = NS16("alternateTitle");
|
| + frame_state->scroll_offset = gfx::Point(42, -42);
|
| + frame_state->item_sequence_number = 123;
|
| + frame_state->document_sequence_number = 456;
|
| + frame_state->visit_count = 42*42;
|
| + frame_state->visited_time = 13.37;
|
| + frame_state->page_scale_factor = 2.0f;
|
| + frame_state->is_target_item = true;
|
| +
|
| + frame_state->document_state.push_back(
|
| + NS16("\n\r?% WebKit serialized form state version 8 \n\r=&"));
|
| + frame_state->document_state.push_back(NS16("form key"));
|
| + frame_state->document_state.push_back(NS16("1"));
|
| + frame_state->document_state.push_back(NS16("foo"));
|
| + frame_state->document_state.push_back(NS16("file"));
|
| + frame_state->document_state.push_back(NS16("2"));
|
| + frame_state->document_state.push_back(NS16("file.txt"));
|
| + frame_state->document_state.push_back(NS16("displayName"));
|
| +
|
| + if (!is_child) {
|
| + frame_state->http_body.http_content_type = NS16("foo/bar");
|
| + frame_state->http_body.identifier = 789;
|
| + frame_state->http_body.is_null = false;
|
| +
|
| + ExplodedHttpBodyElement e1;
|
| + e1.type = WebKit::WebHTTPBody::Element::TypeData;
|
| + e1.data = "first data block";
|
| + frame_state->http_body.elements.push_back(e1);
|
| +
|
| + ExplodedHttpBodyElement e2;
|
| + e2.type = WebKit::WebHTTPBody::Element::TypeFile;
|
| + e2.file_path = NS16("file.txt");
|
| + frame_state->http_body.elements.push_back(e2);
|
| +
|
| + ExplodedHttpBodyElement e3;
|
| + e3.type = WebKit::WebHTTPBody::Element::TypeData;
|
| + e3.data = "data the second";
|
| + frame_state->http_body.elements.push_back(e3);
|
| +
|
| + ExplodedFrameState child_state;
|
| + PopulateFrameStateForBackwardsCompatTest(&child_state, true);
|
| + frame_state->children.push_back(child_state);
|
| + }
|
| + }
|
| +
|
| + void PopulatePageStateForBackwardsCompatTest(ExplodedPageState* page_state) {
|
| + page_state->referenced_files.push_back(NS16("file.txt"));
|
| + PopulateFrameStateForBackwardsCompatTest(&page_state->top, false);
|
| + }
|
| +
|
| + void TestBackwardsCompat(int version) {
|
| + const char* suffix = "";
|
| +
|
| +#if defined(OS_ANDROID)
|
| + // Unfortunately, the format of version 11 is different on Android, so we
|
| + // need to use a special reference file.
|
| + if (version == 11)
|
| + suffix = "_android";
|
| +#endif
|
| +
|
| + base::FilePath path;
|
| + PathService::Get(content::DIR_TEST_DATA, &path);
|
| + path = path.AppendASCII("page_state").AppendASCII(
|
| + base::StringPrintf("serialized_v%d%s.dat", version, suffix));
|
| +
|
| + std::string file_contents;
|
| + if (!file_util::ReadFileToString(path, &file_contents)) {
|
| + ADD_FAILURE() << "File not found: " << path.value();
|
| + return;
|
| + }
|
| +
|
| + std::string trimmed_contents;
|
| + EXPECT_TRUE(RemoveChars(file_contents, "\r\n", &trimmed_contents));
|
| +
|
| + std::string encoded;
|
| + EXPECT_TRUE(base::Base64Decode(trimmed_contents, &encoded));
|
| +
|
| + ExplodedPageState output;
|
| + EXPECT_TRUE(DecodePageState(encoded, &output));
|
| +
|
| + ExplodedPageState expected;
|
| + PopulatePageStateForBackwardsCompatTest(&expected);
|
| +
|
| + ExpectEquality(expected, output);
|
| + }
|
| +};
|
| +
|
| +TEST_F(PageStateSerializationTest, BasicEmpty) {
|
| + ExplodedPageState input;
|
| +
|
| + std::string encoded;
|
| + EXPECT_TRUE(EncodePageState(input, &encoded));
|
| +
|
| + ExplodedPageState output;
|
| + EXPECT_TRUE(DecodePageState(encoded, &output));
|
| +
|
| + ExpectEquality(input, output);
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BasicFrame) {
|
| + ExplodedPageState input;
|
| + PopulateFrameState(&input.top);
|
| +
|
| + std::string encoded;
|
| + EXPECT_TRUE(EncodePageState(input, &encoded));
|
| +
|
| + ExplodedPageState output;
|
| + EXPECT_TRUE(DecodePageState(encoded, &output));
|
| +
|
| + ExpectEquality(input, output);
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BasicFramePOST) {
|
| + ExplodedPageState input;
|
| + PopulateFrameState(&input.top);
|
| + PopulateHttpBody(&input.top.http_body, &input.referenced_files);
|
| +
|
| + std::string encoded;
|
| + EXPECT_TRUE(EncodePageState(input, &encoded));
|
| +
|
| + ExplodedPageState output;
|
| + EXPECT_TRUE(DecodePageState(encoded, &output));
|
| +
|
| + ExpectEquality(input, output);
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BasicFrameSet) {
|
| + ExplodedPageState input;
|
| + PopulateFrameState(&input.top);
|
| +
|
| + // Add some child frames.
|
| + for (int i = 0; i < 4; ++i) {
|
| + ExplodedFrameState child_state;
|
| + PopulateFrameState(&child_state);
|
| + input.top.children.push_back(child_state);
|
| + }
|
| +
|
| + std::string encoded;
|
| + EXPECT_TRUE(EncodePageState(input, &encoded));
|
| +
|
| + ExplodedPageState output;
|
| + EXPECT_TRUE(DecodePageState(encoded, &output));
|
| +
|
| + ExpectEquality(input, output);
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BasicFrameSetPOST) {
|
| + ExplodedPageState input;
|
| + PopulateFrameState(&input.top);
|
| +
|
| + // Add some child frames.
|
| + for (int i = 0; i < 4; ++i) {
|
| + ExplodedFrameState child_state;
|
| + PopulateFrameState(&child_state);
|
| +
|
| + // Simulate a form POST on a subframe.
|
| + if (i == 2)
|
| + PopulateHttpBody(&child_state.http_body, &input.referenced_files);
|
| +
|
| + input.top.children.push_back(child_state);
|
| + }
|
| +
|
| + std::string encoded;
|
| + EncodePageState(input, &encoded);
|
| +
|
| + ExplodedPageState output;
|
| + DecodePageState(encoded, &output);
|
| +
|
| + ExpectEquality(input, output);
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BadMessagesTest1) {
|
| + Pickle p;
|
| + // Version 14
|
| + p.WriteInt(14);
|
| + // Empty strings.
|
| + for (int i = 0; i < 6; ++i)
|
| + p.WriteInt(-1);
|
| + // Bad real number.
|
| + p.WriteInt(-1);
|
| +
|
| + std::string s(static_cast<const char*>(p.data()), p.size());
|
| +
|
| + ExplodedPageState output;
|
| + EXPECT_FALSE(DecodePageState(s, &output));
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BadMessagesTest2) {
|
| + double d = 0;
|
| + Pickle p;
|
| + // Version 14
|
| + p.WriteInt(14);
|
| + // Empty strings.
|
| + for (int i = 0; i < 6; ++i)
|
| + p.WriteInt(-1);
|
| + // More misc fields.
|
| + p.WriteData(reinterpret_cast<const char*>(&d), sizeof(d));
|
| + p.WriteInt(1);
|
| + p.WriteInt(1);
|
| + p.WriteInt(0);
|
| + p.WriteInt(0);
|
| + p.WriteInt(-1);
|
| + p.WriteInt(0);
|
| + // WebForm
|
| + p.WriteInt(1);
|
| + p.WriteInt(WebKit::WebHTTPBody::Element::TypeData);
|
| +
|
| + std::string s(static_cast<const char*>(p.data()), p.size());
|
| +
|
| + ExplodedPageState output;
|
| + EXPECT_FALSE(DecodePageState(s, &output));
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, DumpExpectedPageStateForBackwardsCompat) {
|
| + // Comment out this return statement to enable this code. Use this code to
|
| + // generate data, based on the current serialization format, for the
|
| + // BackwardsCompat_vXX tests.
|
| + return;
|
| +
|
| + ExplodedPageState state;
|
| + PopulatePageStateForBackwardsCompatTest(&state);
|
| +
|
| + std::string encoded;
|
| + EXPECT_TRUE(EncodePageState(state, &encoded));
|
| +
|
| + std::string base64;
|
| + EXPECT_TRUE(base::Base64Encode(encoded, &base64));
|
| +
|
| + base::FilePath path;
|
| + PathService::Get(base::DIR_TEMP, &path);
|
| + path = path.AppendASCII("expected.dat");
|
| +
|
| + FILE* fp = file_util::OpenFile(path, "wb");
|
| + ASSERT_TRUE(fp);
|
| +
|
| + const size_t kRowSize = 76;
|
| + for (size_t offset = 0; offset < base64.size(); offset += kRowSize) {
|
| + size_t length = std::min(base64.size() - offset, kRowSize);
|
| + std::string segment(&base64[offset], length);
|
| + segment.push_back('\n');
|
| + fwrite(segment.data(), segment.size(), 1, fp);
|
| + }
|
| +
|
| + fclose(fp);
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BackwardsCompat_v11) {
|
| + TestBackwardsCompat(11);
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BackwardsCompat_v12) {
|
| + TestBackwardsCompat(12);
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BackwardsCompat_v13) {
|
| + TestBackwardsCompat(13);
|
| +}
|
| +
|
| +TEST_F(PageStateSerializationTest, BackwardsCompat_v14) {
|
| + TestBackwardsCompat(14);
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace content
|
|
|