1// Copyright (c) 2010, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include <ios>
31#include <string>
32#include <vector>
33
34#include "breakpad_googletest_includes.h"
35#include "common/using_std_string.h"
36#include "processor/binarystream.h"
37
38namespace {
39using std::ios_base;
40using std::vector;
41using google_breakpad::binarystream;
42
43
44class BinaryStreamBasicTest : public ::testing::Test {
45protected:
46  binarystream stream;
47};
48
49TEST_F(BinaryStreamBasicTest, ReadU8) {
50  uint8_t u8 = 0;
51  ASSERT_FALSE(stream.eof());
52  stream >> u8;
53  ASSERT_TRUE(stream.eof());
54  EXPECT_EQ(0U, u8);
55  stream.rewind();
56  stream.clear();
57  stream << (uint8_t)1;
58  ASSERT_FALSE(stream.eof());
59  stream >> u8;
60  EXPECT_EQ(1, u8);
61  EXPECT_FALSE(stream.eof());
62}
63
64TEST_F(BinaryStreamBasicTest, ReadU16) {
65  uint16_t u16 = 0;
66  ASSERT_FALSE(stream.eof());
67  stream >> u16;
68  ASSERT_TRUE(stream.eof());
69  EXPECT_EQ(0U, u16);
70  stream.rewind();
71  stream.clear();
72  stream << (uint16_t)1;
73  ASSERT_FALSE(stream.eof());
74  stream >> u16;
75  EXPECT_EQ(1, u16);
76  EXPECT_FALSE(stream.eof());
77}
78
79TEST_F(BinaryStreamBasicTest, ReadU32) {
80  uint32_t u32 = 0;
81  ASSERT_FALSE(stream.eof());
82  stream >> u32;
83  ASSERT_TRUE(stream.eof());
84  EXPECT_EQ(0U, u32);
85  stream.rewind();
86  stream.clear();
87  stream << (uint32_t)1;
88  ASSERT_FALSE(stream.eof());
89  stream >> u32;
90  EXPECT_EQ(1U, u32);
91  EXPECT_FALSE(stream.eof());
92}
93
94TEST_F(BinaryStreamBasicTest, ReadU64) {
95  uint64_t u64 = 0;
96  ASSERT_FALSE(stream.eof());
97  stream >> u64;
98  ASSERT_TRUE(stream.eof());
99  EXPECT_EQ(0U, u64);
100  stream.rewind();
101  stream.clear();
102  stream << (uint64_t)1;
103  ASSERT_FALSE(stream.eof());
104  stream >> u64;
105  EXPECT_EQ(1U, u64);
106  EXPECT_FALSE(stream.eof());
107}
108
109TEST_F(BinaryStreamBasicTest, ReadString) {
110  string s("");
111  ASSERT_FALSE(stream.eof());
112  stream >> s;
113  ASSERT_TRUE(stream.eof());
114  EXPECT_EQ("", s);
115  // write an empty string to the stream, read it back
116  s = "abcd";
117  stream.rewind();
118  stream.clear();
119  stream << string("");
120  stream >> s;
121  EXPECT_EQ("", s);
122  EXPECT_FALSE(stream.eof());
123  stream.rewind();
124  stream.clear();
125  stream << string("test");
126  ASSERT_FALSE(stream.eof());
127  stream >> s;
128  EXPECT_EQ("test", s);
129  EXPECT_FALSE(stream.eof());
130}
131
132TEST_F(BinaryStreamBasicTest, ReadEmptyString) {
133  string s("abc");
134  stream << string("");
135  stream >> s;
136  EXPECT_EQ("", s);
137}
138
139TEST_F(BinaryStreamBasicTest, ReadMultiU8) {
140  const uint8_t ea = 0, eb = 100, ec = 200, ed = 0xFF;
141  uint8_t a, b, c, d, e;
142  stream << ea << eb << ec << ed;
143  stream >> a >> b >> c >> d;
144  ASSERT_FALSE(stream.eof());
145  EXPECT_EQ(ea, a);
146  EXPECT_EQ(eb, b);
147  EXPECT_EQ(ec, c);
148  EXPECT_EQ(ed, d);
149  ASSERT_FALSE(stream.eof());
150  e = 0;
151  stream >> e;
152  EXPECT_EQ(0U, e);
153  ASSERT_TRUE(stream.eof());
154  // try reading all at once, including one past eof
155  stream.rewind();
156  stream.clear();
157  ASSERT_FALSE(stream.eof());
158  a = b = c = d = e = 0;
159  stream << ea << eb << ec << ed;
160  stream >> a >> b >> c >> d >> e;
161  EXPECT_EQ(ea, a);
162  EXPECT_EQ(eb, b);
163  EXPECT_EQ(ec, c);
164  EXPECT_EQ(ed, d);
165  EXPECT_EQ(0U, e);
166  EXPECT_TRUE(stream.eof());
167}
168
169TEST_F(BinaryStreamBasicTest, ReadMultiU16) {
170  const uint16_t ea = 0, eb = 0x100, ec = 0x8000, ed = 0xFFFF;
171  uint16_t a, b, c, d, e;
172  stream << ea << eb << ec << ed;
173  stream >> a >> b >> c >> d;
174  ASSERT_FALSE(stream.eof());
175  EXPECT_EQ(ea, a);
176  EXPECT_EQ(eb, b);
177  EXPECT_EQ(ec, c);
178  EXPECT_EQ(ed, d);
179  ASSERT_FALSE(stream.eof());
180  e = 0;
181  stream >> e;
182  EXPECT_EQ(0U, e);
183  EXPECT_TRUE(stream.eof());
184  // try reading all at once, including one past eof
185  stream.rewind();
186  stream.clear();
187  ASSERT_FALSE(stream.eof());
188  a = b = c = d = e = 0;
189  stream << ea << eb << ec << ed;
190  stream >> a >> b >> c >> d >> e;
191  EXPECT_EQ(ea, a);
192  EXPECT_EQ(eb, b);
193  EXPECT_EQ(ec, c);
194  EXPECT_EQ(ed, d);
195  EXPECT_EQ(0U, e);
196  EXPECT_TRUE(stream.eof());
197}
198
199TEST_F(BinaryStreamBasicTest, ReadMultiU32) {
200  const uint32_t ea = 0, eb = 0x10000, ec = 0x8000000, ed = 0xFFFFFFFF;
201  uint32_t a, b, c, d, e;
202  stream << ea << eb << ec << ed;
203  stream >> a >> b >> c >> d;
204  ASSERT_FALSE(stream.eof());
205  EXPECT_EQ(ea, a);
206  EXPECT_EQ(eb, b);
207  EXPECT_EQ(ec, c);
208  EXPECT_EQ(ed, d);
209  ASSERT_FALSE(stream.eof());
210  e = 0;
211  stream >> e;
212  EXPECT_EQ(0U, e);
213  EXPECT_TRUE(stream.eof());
214  // try reading all at once, including one past eof
215  stream.rewind();
216  stream.clear();
217  ASSERT_FALSE(stream.eof());
218  a = b = c = d = e = 0;
219  stream << ea << eb << ec << ed;
220  stream >> a >> b >> c >> d >> e;
221  EXPECT_EQ(ea, a);
222  EXPECT_EQ(eb, b);
223  EXPECT_EQ(ec, c);
224  EXPECT_EQ(ed, d);
225  EXPECT_EQ(0U, e);
226  EXPECT_TRUE(stream.eof());
227}
228
229TEST_F(BinaryStreamBasicTest, ReadMultiU64) {
230  const uint64_t ea = 0, eb = 0x10000, ec = 0x100000000ULL,
231    ed = 0xFFFFFFFFFFFFFFFFULL;
232  uint64_t a, b, c, d, e;
233  stream << ea << eb << ec << ed;
234  stream >> a >> b >> c >> d;
235  ASSERT_FALSE(stream.eof());
236  EXPECT_EQ(ea, a);
237  EXPECT_EQ(eb, b);
238  EXPECT_EQ(ec, c);
239  EXPECT_EQ(ed, d);
240  ASSERT_FALSE(stream.eof());
241  e = 0;
242  stream >> e;
243  EXPECT_EQ(0U, e);
244  EXPECT_TRUE(stream.eof());
245  // try reading all at once, including one past eof
246  stream.rewind();
247  stream.clear();
248  ASSERT_FALSE(stream.eof());
249  a = b = c = d = e = 0;
250  stream << ea << eb << ec << ed;
251  stream >> a >> b >> c >> d >> e;
252  EXPECT_EQ(ea, a);
253  EXPECT_EQ(eb, b);
254  EXPECT_EQ(ec, c);
255  EXPECT_EQ(ed, d);
256  EXPECT_EQ(0U, e);
257  EXPECT_TRUE(stream.eof());
258}
259
260TEST_F(BinaryStreamBasicTest, ReadMixed) {
261  const uint8_t e8 = 0x10;
262  const uint16_t e16 = 0x2020;
263  const uint32_t e32 = 0x30303030;
264  const uint64_t e64 = 0x4040404040404040ULL;
265  const string es = "test";
266  uint8_t u8 = 0;
267  uint16_t u16 = 0;
268  uint32_t u32 = 0;
269  uint64_t u64 = 0;
270  string s("test");
271  stream << e8 << e16 << e32 << e64 << es;
272  stream >> u8 >> u16 >> u32 >> u64 >> s;
273  EXPECT_FALSE(stream.eof());
274  EXPECT_EQ(e8, u8);
275  EXPECT_EQ(e16, u16);
276  EXPECT_EQ(e32, u32);
277  EXPECT_EQ(e64, u64);
278  EXPECT_EQ(es, s);
279}
280
281TEST_F(BinaryStreamBasicTest, ReadStringMissing) {
282  // ensure that reading a string where only the length is present fails
283  uint16_t u16 = 8;
284  stream << u16;
285  stream.rewind();
286  string s("");
287  stream >> s;
288  EXPECT_EQ("", s);
289  EXPECT_TRUE(stream.eof());
290}
291
292TEST_F(BinaryStreamBasicTest, ReadStringTruncated) {
293  // ensure that reading a string where not all the data is present fails
294  uint16_t u16 = 8;
295  stream << u16;
296  stream << (uint8_t)'t' << (uint8_t)'e' << (uint8_t)'s' << (uint8_t)'t';
297  stream.rewind();
298  string s("");
299  stream >> s;
300  EXPECT_EQ("", s);
301  EXPECT_TRUE(stream.eof());
302}
303
304TEST_F(BinaryStreamBasicTest, StreamByteLength) {
305  // Test that the stream buffer contains the right amount of data
306  stream << (uint8_t)0 << (uint16_t)1 << (uint32_t)2 << (uint64_t)3
307         << string("test");
308  string s = stream.str();
309  EXPECT_EQ(21U, s.length());
310}
311
312TEST_F(BinaryStreamBasicTest, AppendStreamResultsByteLength) {
313  // Test that appending the str() results from two streams
314  // gives the right byte length
315  binarystream stream2;
316  stream << (uint8_t)0 << (uint16_t)1;
317  stream2 << (uint32_t)0 << (uint64_t)2
318          << string("test");
319  string s = stream.str();
320  string s2 = stream2.str();
321  s.append(s2);
322  EXPECT_EQ(21U, s.length());
323}
324
325TEST_F(BinaryStreamBasicTest, StreamSetStr) {
326  const string es("test");
327  stream << es;
328  binarystream stream2;
329  stream2.str(stream.str());
330  string s;
331  stream2 >> s;
332  EXPECT_FALSE(stream2.eof());
333  EXPECT_EQ("test", s);
334  s = "";
335  stream2.str(stream.str());
336  stream2.rewind();
337  stream2 >> s;
338  EXPECT_FALSE(stream2.eof());
339  EXPECT_EQ("test", s);
340}
341
342class BinaryStreamU8Test : public ::testing::Test {
343protected:
344  binarystream stream;
345
346  void SetUp() {
347    stream << (uint8_t)1;
348  }
349};
350
351TEST_F(BinaryStreamU8Test, ReadU16) {
352  uint16_t u16 = 0;
353  ASSERT_FALSE(stream.eof());
354  stream >> u16;
355  ASSERT_TRUE(stream.eof());
356  EXPECT_EQ(0U, u16);
357}
358
359TEST_F(BinaryStreamU8Test, ReadU32) {
360  uint32_t u32 = 0;
361  ASSERT_FALSE(stream.eof());
362  stream >> u32;
363  ASSERT_TRUE(stream.eof());
364  EXPECT_EQ(0U, u32);
365}
366
367TEST_F(BinaryStreamU8Test, ReadU64) {
368  uint64_t u64 = 0;
369  ASSERT_FALSE(stream.eof());
370  stream >> u64;
371  ASSERT_TRUE(stream.eof());
372  EXPECT_EQ(0U, u64);
373}
374
375TEST_F(BinaryStreamU8Test, ReadString) {
376  string s("");
377  ASSERT_FALSE(stream.eof());
378  stream >> s;
379  ASSERT_TRUE(stream.eof());
380  EXPECT_EQ("", s);
381}
382
383
384TEST(BinaryStreamTest, InitWithData) {
385  const char *data = "abcd";
386  binarystream stream(data);
387  uint8_t a, b, c, d;
388  stream >> a >> b >> c >> d;
389  ASSERT_FALSE(stream.eof());
390  EXPECT_EQ('a', a);
391  EXPECT_EQ('b', b);
392  EXPECT_EQ('c', c);
393  EXPECT_EQ('d', d);
394}
395
396TEST(BinaryStreamTest, InitWithDataLeadingNull) {
397  const char *data = "\0abcd";
398  binarystream stream(data, 5);
399  uint8_t z, a, b, c, d;
400  stream >> z >> a >> b >> c >> d;
401  ASSERT_FALSE(stream.eof());
402  EXPECT_EQ(0U, z);
403  EXPECT_EQ('a', a);
404  EXPECT_EQ('b', b);
405  EXPECT_EQ('c', c);
406  EXPECT_EQ('d', d);
407}
408
409TEST(BinaryStreamTest, InitWithDataVector) {
410  vector<char> data;
411  data.push_back('a');
412  data.push_back('b');
413  data.push_back('c');
414  data.push_back('d');
415  data.push_back('e');
416  data.resize(4);
417  binarystream stream(&data[0], data.size());
418  uint8_t a, b, c, d;
419  stream >> a >> b >> c >> d;
420  ASSERT_FALSE(stream.eof());
421  EXPECT_EQ('a', a);
422  EXPECT_EQ('b', b);
423  EXPECT_EQ('c', c);
424  EXPECT_EQ('d', d);
425}
426
427} // namespace
428
429int main(int argc, char *argv[]) {
430  ::testing::InitGoogleTest(&argc, argv);
431  return RUN_ALL_TESTS();
432}
433