1// Copyright (c) 2006-2008 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 <string>
6
7#include "base/pickle.h"
8#include "base/string_util.h"
9#include "testing/gtest/include/gtest/gtest.h"
10#include "third_party/WebKit/Source/WebKit/chromium/public/WebHTTPBody.h"
11#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
12#include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h"
13#include "webkit/glue/glue_serialize.h"
14#include "webkit/glue/web_io_operators.h"
15
16using WebKit::WebData;
17using WebKit::WebHistoryItem;
18using WebKit::WebHTTPBody;
19using WebKit::WebPoint;
20using WebKit::WebString;
21using WebKit::WebUChar;
22using WebKit::WebVector;
23
24namespace {
25class GlueSerializeTest : public testing::Test {
26 public:
27  // Makes a FormData with some random data.
28  WebHTTPBody MakeFormData() {
29    WebHTTPBody http_body;
30    http_body.initialize();
31
32    const char d1[] = "first data block";
33    http_body.appendData(WebData(d1, sizeof(d1)-1));
34
35    http_body.appendFile(WebString::fromUTF8("file.txt"));
36
37    const char d2[] = "data the second";
38    http_body.appendData(WebData(d2, sizeof(d2)-1));
39
40    return http_body;
41  }
42
43  // Constructs a HistoryItem with some random data and an optional child.
44  WebHistoryItem MakeHistoryItem(bool with_form_data, bool pregnant) {
45    WebHistoryItem item;
46    item.initialize();
47
48    item.setURLString(WebString::fromUTF8("urlString"));
49    item.setOriginalURLString(WebString::fromUTF8("originalURLString"));
50    item.setTarget(WebString::fromUTF8("target"));
51    item.setParent(WebString::fromUTF8("parent"));
52    item.setTitle(WebString::fromUTF8("title"));
53    item.setAlternateTitle(WebString::fromUTF8("alternateTitle"));
54    item.setLastVisitedTime(13.37);
55    item.setScrollOffset(WebPoint(42, -42));
56    item.setIsTargetItem(true);
57    item.setVisitCount(42*42);
58
59    WebVector<WebString> document_state(size_t(3));
60    document_state[0] = WebString::fromUTF8("state1");
61    document_state[1] = WebString::fromUTF8("state2");
62    document_state[2] = WebString::fromUTF8("state AWESOME");
63    item.setDocumentState(document_state);
64
65    // Form Data
66    if (with_form_data) {
67      item.setHTTPBody(MakeFormData());
68      item.setHTTPContentType(WebString::fromUTF8("formContentType"));
69    }
70
71    // Setting the FormInfo causes the referrer to be set, so we set the
72    // referrer after setting the form info.
73    item.setReferrer(WebString::fromUTF8("referrer"));
74
75    // Children
76    if (pregnant)
77      item.appendToChildren(MakeHistoryItem(false, false));
78
79    return item;
80  }
81
82  // Checks that a == b.
83  void HistoryItemExpectEqual(const WebHistoryItem& a,
84                              const WebHistoryItem& b) {
85    EXPECT_EQ(string16(a.urlString()), string16(b.urlString()));
86    EXPECT_EQ(string16(a.originalURLString()), string16(b.originalURLString()));
87    EXPECT_EQ(string16(a.target()), string16(b.target()));
88    EXPECT_EQ(string16(a.parent()), string16(b.parent()));
89    EXPECT_EQ(string16(a.title()), string16(b.title()));
90    EXPECT_EQ(string16(a.alternateTitle()), string16(b.alternateTitle()));
91    EXPECT_EQ(a.lastVisitedTime(), b.lastVisitedTime());
92    EXPECT_EQ(a.scrollOffset(), b.scrollOffset());
93    EXPECT_EQ(a.isTargetItem(), b.isTargetItem());
94    EXPECT_EQ(a.visitCount(), b.visitCount());
95    EXPECT_EQ(string16(a.referrer()), string16(b.referrer()));
96
97    const WebVector<WebString>& a_docstate = a.documentState();
98    const WebVector<WebString>& b_docstate = b.documentState();
99    EXPECT_EQ(a_docstate.size(), b_docstate.size());
100    for (size_t i = 0, c = a_docstate.size(); i < c; ++i)
101      EXPECT_EQ(string16(a_docstate[i]), string16(b_docstate[i]));
102
103    // Form Data
104    const WebHTTPBody& a_body = a.httpBody();
105    const WebHTTPBody& b_body = b.httpBody();
106    EXPECT_EQ(!a_body.isNull(), !b_body.isNull());
107    if (!a_body.isNull() && !b_body.isNull()) {
108      EXPECT_EQ(a_body.elementCount(), b_body.elementCount());
109      WebHTTPBody::Element a_elem, b_elem;
110      for (size_t i = 0; a_body.elementAt(i, a_elem) &&
111                         b_body.elementAt(i, b_elem); ++i) {
112        EXPECT_EQ(a_elem.type, b_elem.type);
113        if (a_elem.type == WebHTTPBody::Element::TypeData) {
114          EXPECT_EQ(std::string(a_elem.data.data(), a_elem.data.size()),
115                    std::string(b_elem.data.data(), b_elem.data.size()));
116        } else {
117          EXPECT_EQ(string16(a_elem.filePath), string16(b_elem.filePath));
118        }
119      }
120    }
121    EXPECT_EQ(string16(a.httpContentType()), string16(b.httpContentType()));
122
123    // Children
124    const WebVector<WebHistoryItem>& a_children = a.children();
125    const WebVector<WebHistoryItem>& b_children = b.children();
126    EXPECT_EQ(a_children.size(), b_children.size());
127    for (size_t i = 0, c = a_children.size(); i < c; ++i)
128      HistoryItemExpectEqual(a_children[i], b_children[i]);
129  }
130};
131
132// Test old versions of serialized data to ensure that newer versions of code
133// can still read history items written by previous versions.
134TEST_F(GlueSerializeTest, BackwardsCompatibleTest) {
135  const WebHistoryItem& item = MakeHistoryItem(false, false);
136
137  // Make sure version 3 (current version) can read versions 1 and 2.
138  for (int i = 1; i <= 2; i++) {
139    std::string serialized_item;
140    webkit_glue::HistoryItemToVersionedString(item, i, &serialized_item);
141    const WebHistoryItem& deserialized_item =
142        webkit_glue::HistoryItemFromString(serialized_item);
143    ASSERT_FALSE(item.isNull());
144    ASSERT_FALSE(deserialized_item.isNull());
145    HistoryItemExpectEqual(item, deserialized_item);
146  }
147}
148
149// Makes sure that a HistoryItem remains intact after being serialized and
150// deserialized.
151TEST_F(GlueSerializeTest, HistoryItemSerializeTest) {
152  const WebHistoryItem& item = MakeHistoryItem(true, true);
153  const std::string& serialized_item = webkit_glue::HistoryItemToString(item);
154  const WebHistoryItem& deserialized_item =
155      webkit_glue::HistoryItemFromString(serialized_item);
156
157  ASSERT_FALSE(item.isNull());
158  ASSERT_FALSE(deserialized_item.isNull());
159  HistoryItemExpectEqual(item, deserialized_item);
160}
161
162// Checks that broken messages don't take out our process.
163TEST_F(GlueSerializeTest, BadMessagesTest) {
164  {
165    Pickle p;
166    // Version 1
167    p.WriteInt(1);
168    // Empty strings.
169    for (int i = 0; i < 6; ++i)
170      p.WriteInt(-1);
171    // Bad real number.
172    p.WriteInt(-1);
173    std::string s(static_cast<const char*>(p.data()), p.size());
174    webkit_glue::HistoryItemFromString(s);
175  }
176  {
177    double d = 0;
178    Pickle p;
179    // Version 1
180    p.WriteInt(1);
181    // Empty strings.
182    for (int i = 0; i < 6; ++i)
183      p.WriteInt(-1);
184    // More misc fields.
185    p.WriteData(reinterpret_cast<const char*>(&d), sizeof(d));
186    p.WriteInt(1);
187    p.WriteInt(1);
188    p.WriteInt(0);
189    p.WriteInt(0);
190    p.WriteInt(-1);
191    p.WriteInt(0);
192    // WebForm
193    p.WriteInt(1);
194    p.WriteInt(WebHTTPBody::Element::TypeData);
195    std::string s(static_cast<const char*>(p.data()), p.size());
196    webkit_glue::HistoryItemFromString(s);
197  }
198}
199
200}  // namespace
201