1// Copyright (c) 2012 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/basictypes.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/pickle.h"
10#include "base/strings/string16.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13// Remove when this file is in the base namespace.
14using base::string16;
15
16namespace {
17
18const int testint = 2093847192;
19const std::string teststr("Hello world");  // note non-aligned string length
20const std::wstring testwstr(L"Hello, world");
21const char testdata[] = "AAA\0BBB\0";
22const int testdatalen = arraysize(testdata) - 1;
23const bool testbool1 = false;
24const bool testbool2 = true;
25const uint16 testuint16 = 32123;
26const float testfloat = 3.1415926935f;
27const double testdouble = 2.71828182845904523;
28
29// checks that the result
30void VerifyResult(const Pickle& pickle) {
31  PickleIterator iter(pickle);
32
33  int outint;
34  EXPECT_TRUE(pickle.ReadInt(&iter, &outint));
35  EXPECT_EQ(testint, outint);
36
37  std::string outstr;
38  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
39  EXPECT_EQ(teststr, outstr);
40
41  std::wstring outwstr;
42  EXPECT_TRUE(pickle.ReadWString(&iter, &outwstr));
43  EXPECT_EQ(testwstr, outwstr);
44
45  bool outbool;
46  EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
47  EXPECT_FALSE(outbool);
48  EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
49  EXPECT_TRUE(outbool);
50
51  uint16 outuint16;
52  EXPECT_TRUE(pickle.ReadUInt16(&iter, &outuint16));
53  EXPECT_EQ(testuint16, outuint16);
54
55  float outfloat;
56  EXPECT_TRUE(pickle.ReadFloat(&iter, &outfloat));
57  EXPECT_EQ(testfloat, outfloat);
58
59  double outdouble;
60  EXPECT_TRUE(pickle.ReadDouble(&iter, &outdouble));
61  EXPECT_EQ(testdouble, outdouble);
62
63  const char* outdata;
64  int outdatalen;
65  EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
66  EXPECT_EQ(testdatalen, outdatalen);
67  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);
68
69  // reads past the end should fail
70  EXPECT_FALSE(pickle.ReadInt(&iter, &outint));
71}
72
73}  // namespace
74
75TEST(PickleTest, EncodeDecode) {
76  Pickle pickle;
77
78  EXPECT_TRUE(pickle.WriteInt(testint));
79  EXPECT_TRUE(pickle.WriteString(teststr));
80  EXPECT_TRUE(pickle.WriteWString(testwstr));
81  EXPECT_TRUE(pickle.WriteBool(testbool1));
82  EXPECT_TRUE(pickle.WriteBool(testbool2));
83  EXPECT_TRUE(pickle.WriteUInt16(testuint16));
84  EXPECT_TRUE(pickle.WriteFloat(testfloat));
85  EXPECT_TRUE(pickle.WriteDouble(testdouble));
86  EXPECT_TRUE(pickle.WriteData(testdata, testdatalen));
87  VerifyResult(pickle);
88
89  // test copy constructor
90  Pickle pickle2(pickle);
91  VerifyResult(pickle2);
92
93  // test operator=
94  Pickle pickle3;
95  pickle3 = pickle;
96  VerifyResult(pickle3);
97}
98
99// Tests that we can handle really small buffers.
100TEST(PickleTest, SmallBuffer) {
101  scoped_ptr<char[]> buffer(new char[1]);
102
103  // We should not touch the buffer.
104  Pickle pickle(buffer.get(), 1);
105
106  PickleIterator iter(pickle);
107  int data;
108  EXPECT_FALSE(pickle.ReadInt(&iter, &data));
109}
110
111// Tests that we can handle improper headers.
112TEST(PickleTest, BigSize) {
113  int buffer[] = { 0x56035200, 25, 40, 50 };
114
115  Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer));
116
117  PickleIterator iter(pickle);
118  int data;
119  EXPECT_FALSE(pickle.ReadInt(&iter, &data));
120}
121
122TEST(PickleTest, UnalignedSize) {
123  int buffer[] = { 10, 25, 40, 50 };
124
125  Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer));
126
127  PickleIterator iter(pickle);
128  int data;
129  EXPECT_FALSE(pickle.ReadInt(&iter, &data));
130}
131
132TEST(PickleTest, ZeroLenStr) {
133  Pickle pickle;
134  EXPECT_TRUE(pickle.WriteString(std::string()));
135
136  PickleIterator iter(pickle);
137  std::string outstr;
138  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
139  EXPECT_EQ("", outstr);
140}
141
142TEST(PickleTest, ZeroLenWStr) {
143  Pickle pickle;
144  EXPECT_TRUE(pickle.WriteWString(std::wstring()));
145
146  PickleIterator iter(pickle);
147  std::string outstr;
148  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
149  EXPECT_EQ("", outstr);
150}
151
152TEST(PickleTest, BadLenStr) {
153  Pickle pickle;
154  EXPECT_TRUE(pickle.WriteInt(-2));
155
156  PickleIterator iter(pickle);
157  std::string outstr;
158  EXPECT_FALSE(pickle.ReadString(&iter, &outstr));
159}
160
161TEST(PickleTest, BadLenWStr) {
162  Pickle pickle;
163  EXPECT_TRUE(pickle.WriteInt(-1));
164
165  PickleIterator iter(pickle);
166  std::wstring woutstr;
167  EXPECT_FALSE(pickle.ReadWString(&iter, &woutstr));
168}
169
170TEST(PickleTest, FindNext) {
171  Pickle pickle;
172  EXPECT_TRUE(pickle.WriteInt(1));
173  EXPECT_TRUE(pickle.WriteString("Domo"));
174
175  const char* start = reinterpret_cast<const char*>(pickle.data());
176  const char* end = start + pickle.size();
177
178  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end));
179  EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1));
180  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1));
181}
182
183TEST(PickleTest, FindNextWithIncompleteHeader) {
184  size_t header_size = sizeof(Pickle::Header);
185  scoped_ptr<char[]> buffer(new char[header_size - 1]);
186  memset(buffer.get(), 0x1, header_size - 1);
187
188  const char* start = buffer.get();
189  const char* end = start + header_size - 1;
190
191  EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end));
192}
193
194#if defined(COMPILER_MSVC)
195#pragma warning(push)
196#pragma warning(disable: 4146)
197#endif
198TEST(PickleTest, FindNextOverflow) {
199  size_t header_size = sizeof(Pickle::Header);
200  size_t header_size2 = 2 * header_size;
201  size_t payload_received = 100;
202  scoped_ptr<char[]> buffer(new char[header_size2 + payload_received]);
203  const char* start = buffer.get();
204  Pickle::Header* header = reinterpret_cast<Pickle::Header*>(buffer.get());
205  const char* end = start + header_size2 + payload_received;
206  // It is impossible to construct an overflow test otherwise.
207  if (sizeof(size_t) > sizeof(header->payload_size) ||
208      sizeof(uintptr_t) > sizeof(header->payload_size))
209    return;
210
211  header->payload_size = -(reinterpret_cast<uintptr_t>(start) + header_size2);
212  EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end));
213
214  header->payload_size = -header_size2;
215  EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end));
216
217  header->payload_size = 0;
218  end = start + header_size;
219  EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end));
220}
221#if defined(COMPILER_MSVC)
222#pragma warning(pop)
223#endif
224
225TEST(PickleTest, GetReadPointerAndAdvance) {
226  Pickle pickle;
227
228  PickleIterator iter(pickle);
229  EXPECT_FALSE(iter.GetReadPointerAndAdvance(1));
230
231  EXPECT_TRUE(pickle.WriteInt(1));
232  EXPECT_TRUE(pickle.WriteInt(2));
233  int bytes = sizeof(int) * 2;
234
235  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(0));
236  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(1));
237  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(-1));
238  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes));
239  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes + 1));
240  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MAX));
241  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MIN));
242}
243
244TEST(PickleTest, Resize) {
245  size_t unit = Pickle::kPayloadUnit;
246  scoped_ptr<char[]> data(new char[unit]);
247  char* data_ptr = data.get();
248  for (size_t i = 0; i < unit; i++)
249    data_ptr[i] = 'G';
250
251  // construct a message that will be exactly the size of one payload unit,
252  // note that any data will have a 4-byte header indicating the size
253  const size_t payload_size_after_header = unit - sizeof(uint32);
254  Pickle pickle;
255  pickle.WriteData(data_ptr,
256      static_cast<int>(payload_size_after_header - sizeof(uint32)));
257  size_t cur_payload = payload_size_after_header;
258
259  // note: we assume 'unit' is a power of 2
260  EXPECT_EQ(unit, pickle.capacity_after_header());
261  EXPECT_EQ(pickle.payload_size(), payload_size_after_header);
262
263  // fill out a full page (noting data header)
264  pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32)));
265  cur_payload += unit;
266  EXPECT_EQ(unit * 2, pickle.capacity_after_header());
267  EXPECT_EQ(cur_payload, pickle.payload_size());
268
269  // one more byte should double the capacity
270  pickle.WriteData(data_ptr, 1);
271  cur_payload += 8;
272  EXPECT_EQ(unit * 4, pickle.capacity_after_header());
273  EXPECT_EQ(cur_payload, pickle.payload_size());
274}
275
276namespace {
277
278struct CustomHeader : Pickle::Header {
279  int blah;
280};
281
282}  // namespace
283
284TEST(PickleTest, HeaderPadding) {
285  const uint32 kMagic = 0x12345678;
286
287  Pickle pickle(sizeof(CustomHeader));
288  pickle.WriteInt(kMagic);
289
290  // this should not overwrite the 'int' payload
291  pickle.headerT<CustomHeader>()->blah = 10;
292
293  PickleIterator iter(pickle);
294  int result;
295  ASSERT_TRUE(pickle.ReadInt(&iter, &result));
296
297  EXPECT_EQ(static_cast<uint32>(result), kMagic);
298}
299
300TEST(PickleTest, EqualsOperator) {
301  Pickle source;
302  source.WriteInt(1);
303
304  Pickle copy_refs_source_buffer(static_cast<const char*>(source.data()),
305                                 source.size());
306  Pickle copy;
307  copy = copy_refs_source_buffer;
308  ASSERT_EQ(source.size(), copy.size());
309}
310
311TEST(PickleTest, EvilLengths) {
312  Pickle source;
313  std::string str(100000, 'A');
314  EXPECT_TRUE(source.WriteData(str.c_str(), 100000));
315  // ReadString16 used to have its read buffer length calculation wrong leading
316  // to out-of-bounds reading.
317  PickleIterator iter(source);
318  string16 str16;
319  EXPECT_FALSE(source.ReadString16(&iter, &str16));
320
321  // And check we didn't break ReadString16.
322  str16 = (wchar_t) 'A';
323  Pickle str16_pickle;
324  EXPECT_TRUE(str16_pickle.WriteString16(str16));
325  iter = PickleIterator(str16_pickle);
326  EXPECT_TRUE(str16_pickle.ReadString16(&iter, &str16));
327  EXPECT_EQ(1U, str16.length());
328
329  // Check we don't fail in a length check with invalid String16 size.
330  // (1<<31) * sizeof(char16) == 0, so this is particularly evil.
331  Pickle bad_len;
332  EXPECT_TRUE(bad_len.WriteInt(1 << 31));
333  iter = PickleIterator(bad_len);
334  EXPECT_FALSE(bad_len.ReadString16(&iter, &str16));
335
336  // Check we don't fail in a length check with large WStrings.
337  Pickle big_len;
338  EXPECT_TRUE(big_len.WriteInt(1 << 30));
339  iter = PickleIterator(big_len);
340  std::wstring wstr;
341  EXPECT_FALSE(big_len.ReadWString(&iter, &wstr));
342}
343
344// Check we can write zero bytes of data and 'data' can be NULL.
345TEST(PickleTest, ZeroLength) {
346  Pickle pickle;
347  EXPECT_TRUE(pickle.WriteData(NULL, 0));
348
349  PickleIterator iter(pickle);
350  const char* outdata;
351  int outdatalen;
352  EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
353  EXPECT_EQ(0, outdatalen);
354  // We can't assert that outdata is NULL.
355}
356
357// Check that ReadBytes works properly with an iterator initialized to NULL.
358TEST(PickleTest, ReadBytes) {
359  Pickle pickle;
360  int data = 0x7abcd;
361  EXPECT_TRUE(pickle.WriteBytes(&data, sizeof(data)));
362
363  PickleIterator iter(pickle);
364  const char* outdata_char = NULL;
365  EXPECT_TRUE(pickle.ReadBytes(&iter, &outdata_char, sizeof(data)));
366
367  int outdata;
368  memcpy(&outdata, outdata_char, sizeof(outdata));
369  EXPECT_EQ(data, outdata);
370}
371