blob: ff268ab9bbd2581f43c5663d482069fa92028ff9 [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
temporal40ee5512008-07-10 02:12:20 +00003// http://code.google.com/p/protobuf/
4//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34//
35// This file contains tests and benchmarks.
36
37#include <vector>
38
39#include <google/protobuf/io/coded_stream.h>
40
41#include <limits.h>
42
43#include <google/protobuf/stubs/common.h>
44#include <google/protobuf/testing/googletest.h>
45#include <gtest/gtest.h>
46#include <google/protobuf/io/zero_copy_stream_impl.h>
47#include <google/protobuf/stubs/strutil.h>
48
49
50// This declares an unsigned long long integer literal in a portable way.
51// (The original macro is way too big and ruins my formatting.)
52#undef ULL
53#define ULL(x) GOOGLE_ULONGLONG(x)
54
55namespace google {
56namespace protobuf {
57namespace io {
58namespace {
59
60// ===================================================================
61// Data-Driven Test Infrastructure
62
63// TEST_1D and TEST_2D are macros I'd eventually like to see added to
64// gTest. These macros can be used to declare tests which should be
65// run multiple times, once for each item in some input array. TEST_1D
66// tests all cases in a single input array. TEST_2D tests all
67// combinations of cases from two arrays. The arrays must be statically
68// defined such that the GOOGLE_ARRAYSIZE() macro works on them. Example:
69//
70// int kCases[] = {1, 2, 3, 4}
71// TEST_1D(MyFixture, MyTest, kCases) {
72// EXPECT_GT(kCases_case, 0);
73// }
74//
75// This test iterates through the numbers 1, 2, 3, and 4 and tests that
76// they are all grater than zero. In case of failure, the exact case
77// which failed will be printed. The case type must be printable using
78// ostream::operator<<.
79
kenton@google.com2d6daa72009-01-22 01:27:00 +000080// TODO(kenton): gTest now supports "parameterized tests" which would be
81// a better way to accomplish this. Rewrite when time permits.
82
temporal40ee5512008-07-10 02:12:20 +000083#define TEST_1D(FIXTURE, NAME, CASES) \
84 class FIXTURE##_##NAME##_DD : public FIXTURE { \
85 protected: \
86 template <typename CaseType> \
87 void DoSingleCase(const CaseType& CASES##_case); \
88 }; \
89 \
90 TEST_F(FIXTURE##_##NAME##_DD, NAME) { \
91 for (int i = 0; i < GOOGLE_ARRAYSIZE(CASES); i++) { \
92 SCOPED_TRACE(testing::Message() \
93 << #CASES " case #" << i << ": " << CASES[i]); \
94 DoSingleCase(CASES[i]); \
95 } \
96 } \
97 \
98 template <typename CaseType> \
99 void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType& CASES##_case)
100
101#define TEST_2D(FIXTURE, NAME, CASES1, CASES2) \
102 class FIXTURE##_##NAME##_DD : public FIXTURE { \
103 protected: \
104 template <typename CaseType1, typename CaseType2> \
105 void DoSingleCase(const CaseType1& CASES1##_case, \
106 const CaseType2& CASES2##_case); \
107 }; \
108 \
109 TEST_F(FIXTURE##_##NAME##_DD, NAME) { \
110 for (int i = 0; i < GOOGLE_ARRAYSIZE(CASES1); i++) { \
111 for (int j = 0; j < GOOGLE_ARRAYSIZE(CASES2); j++) { \
112 SCOPED_TRACE(testing::Message() \
113 << #CASES1 " case #" << i << ": " << CASES1[i] << ", " \
114 << #CASES2 " case #" << j << ": " << CASES2[j]); \
115 DoSingleCase(CASES1[i], CASES2[j]); \
116 } \
117 } \
118 } \
119 \
120 template <typename CaseType1, typename CaseType2> \
121 void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType1& CASES1##_case, \
122 const CaseType2& CASES2##_case)
123
124// ===================================================================
125
126class CodedStreamTest : public testing::Test {
127 protected:
128 static const int kBufferSize = 1024 * 64;
129 static uint8 buffer_[kBufferSize];
130};
131
132uint8 CodedStreamTest::buffer_[CodedStreamTest::kBufferSize];
133
134// We test each operation over a variety of block sizes to insure that
135// we test cases where reads or writes cross buffer boundaries, cases
136// where they don't, and cases where there is so much buffer left that
137// we can use special optimized paths that don't worry about bounds
138// checks.
139const int kBlockSizes[] = {1, 2, 3, 5, 7, 13, 32, 1024};
140
141// -------------------------------------------------------------------
142// Varint tests.
143
144struct VarintCase {
145 uint8 bytes[10]; // Encoded bytes.
146 int size; // Encoded size, in bytes.
147 uint64 value; // Parsed value.
148};
149
150inline std::ostream& operator<<(std::ostream& os, const VarintCase& c) {
151 return os << c.value;
152}
153
154VarintCase kVarintCases[] = {
155 // 32-bit values
156 {{0x00} , 1, 0},
157 {{0x01} , 1, 1},
158 {{0x7f} , 1, 127},
159 {{0xa2, 0x74}, 2, (0x22 << 0) | (0x74 << 7)}, // 14882
160 {{0xbe, 0xf7, 0x92, 0x84, 0x0b}, 5, // 2961488830
161 (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
162 (ULL(0x0b) << 28)},
163
164 // 64-bit
165 {{0xbe, 0xf7, 0x92, 0x84, 0x1b}, 5, // 7256456126
166 (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
167 (ULL(0x1b) << 28)},
168 {{0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49}, 8, // 41256202580718336
169 (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
170 (ULL(0x43) << 28) | (ULL(0x49) << 35) | (ULL(0x24) << 42) |
171 (ULL(0x49) << 49)},
172 // 11964378330978735131
173 {{0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01}, 10,
174 (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
175 (ULL(0x3b) << 28) | (ULL(0x56) << 35) | (ULL(0x00) << 42) |
176 (ULL(0x05) << 49) | (ULL(0x26) << 56) | (ULL(0x01) << 63)},
177};
178
179TEST_2D(CodedStreamTest, ReadVarint32, kVarintCases, kBlockSizes) {
180 memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size);
181 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
182
183 {
184 CodedInputStream coded_input(&input);
185
186 uint32 value;
187 EXPECT_TRUE(coded_input.ReadVarint32(&value));
188 EXPECT_EQ(static_cast<uint32>(kVarintCases_case.value), value);
189 }
190
191 EXPECT_EQ(kVarintCases_case.size, input.ByteCount());
192}
193
194TEST_2D(CodedStreamTest, ReadTag, kVarintCases, kBlockSizes) {
195 memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size);
196 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
197
198 {
199 CodedInputStream coded_input(&input);
200
201 uint32 expected_value = static_cast<uint32>(kVarintCases_case.value);
202 EXPECT_EQ(expected_value, coded_input.ReadTag());
203
204 EXPECT_TRUE(coded_input.LastTagWas(expected_value));
205 EXPECT_FALSE(coded_input.LastTagWas(expected_value + 1));
206 }
207
208 EXPECT_EQ(kVarintCases_case.size, input.ByteCount());
209}
210
liujisi@google.com33165fe2010-11-02 13:14:58 +0000211// This is the regression test that verifies that there is no issues
212// with the empty input buffers handling.
213TEST_F(CodedStreamTest, EmptyInputBeforeEos) {
214 class In : public ZeroCopyInputStream {
215 public:
216 In() : count_(0) {}
217 private:
218 virtual bool Next(const void** data, int* size) {
219 *data = NULL;
220 *size = 0;
221 return count_++ < 2;
222 }
223 virtual void BackUp(int count) {
224 GOOGLE_LOG(FATAL) << "Tests never call this.";
225 }
226 virtual bool Skip(int count) {
227 GOOGLE_LOG(FATAL) << "Tests never call this.";
228 return false;
229 }
230 virtual int64 ByteCount() const { return 0; }
231 int count_;
232 } in;
233 CodedInputStream input(&in);
234 input.ReadTag();
235 EXPECT_TRUE(input.ConsumedEntireMessage());
236}
237
temporal40ee5512008-07-10 02:12:20 +0000238TEST_1D(CodedStreamTest, ExpectTag, kVarintCases) {
239 // Leave one byte at the beginning of the buffer so we can read it
240 // to force the first buffer to be loaded.
241 buffer_[0] = '\0';
242 memcpy(buffer_ + 1, kVarintCases_case.bytes, kVarintCases_case.size);
243 ArrayInputStream input(buffer_, sizeof(buffer_));
244
245 {
246 CodedInputStream coded_input(&input);
247
248 // Read one byte to force coded_input.Refill() to be called. Otherwise,
249 // ExpectTag() will return a false negative.
250 uint8 dummy;
251 coded_input.ReadRaw(&dummy, 1);
252 EXPECT_EQ((uint)'\0', (uint)dummy);
253
254 uint32 expected_value = static_cast<uint32>(kVarintCases_case.value);
255
256 // ExpectTag() produces false negatives for large values.
257 if (kVarintCases_case.size <= 2) {
258 EXPECT_FALSE(coded_input.ExpectTag(expected_value + 1));
259 EXPECT_TRUE(coded_input.ExpectTag(expected_value));
260 } else {
261 EXPECT_FALSE(coded_input.ExpectTag(expected_value));
262 }
263 }
264
265 if (kVarintCases_case.size <= 2) {
266 EXPECT_EQ(kVarintCases_case.size + 1, input.ByteCount());
267 } else {
268 EXPECT_EQ(1, input.ByteCount());
269 }
270}
271
kenton@google.comfccb1462009-12-18 02:11:36 +0000272TEST_1D(CodedStreamTest, ExpectTagFromArray, kVarintCases) {
273 memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size);
274
275 const uint32 expected_value = static_cast<uint32>(kVarintCases_case.value);
276
277 // If the expectation succeeds, it should return a pointer past the tag.
278 if (kVarintCases_case.size <= 2) {
279 EXPECT_TRUE(NULL ==
280 CodedInputStream::ExpectTagFromArray(buffer_,
281 expected_value + 1));
282 EXPECT_TRUE(buffer_ + kVarintCases_case.size ==
283 CodedInputStream::ExpectTagFromArray(buffer_, expected_value));
284 } else {
285 EXPECT_TRUE(NULL ==
286 CodedInputStream::ExpectTagFromArray(buffer_, expected_value));
287 }
288}
289
temporal40ee5512008-07-10 02:12:20 +0000290TEST_2D(CodedStreamTest, ReadVarint64, kVarintCases, kBlockSizes) {
291 memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size);
292 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
293
294 {
295 CodedInputStream coded_input(&input);
296
297 uint64 value;
298 EXPECT_TRUE(coded_input.ReadVarint64(&value));
299 EXPECT_EQ(kVarintCases_case.value, value);
300 }
301
302 EXPECT_EQ(kVarintCases_case.size, input.ByteCount());
303}
304
305TEST_2D(CodedStreamTest, WriteVarint32, kVarintCases, kBlockSizes) {
306 if (kVarintCases_case.value > ULL(0x00000000FFFFFFFF)) {
307 // Skip this test for the 64-bit values.
308 return;
309 }
310
311 ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
312
313 {
314 CodedOutputStream coded_output(&output);
315
kenton@google.comd37d46d2009-04-25 02:53:47 +0000316 coded_output.WriteVarint32(static_cast<uint32>(kVarintCases_case.value));
317 EXPECT_FALSE(coded_output.HadError());
temporal40ee5512008-07-10 02:12:20 +0000318
319 EXPECT_EQ(kVarintCases_case.size, coded_output.ByteCount());
320 }
321
322 EXPECT_EQ(kVarintCases_case.size, output.ByteCount());
323 EXPECT_EQ(0,
324 memcmp(buffer_, kVarintCases_case.bytes, kVarintCases_case.size));
325}
326
327TEST_2D(CodedStreamTest, WriteVarint64, kVarintCases, kBlockSizes) {
328 ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
329
330 {
331 CodedOutputStream coded_output(&output);
332
kenton@google.comd37d46d2009-04-25 02:53:47 +0000333 coded_output.WriteVarint64(kVarintCases_case.value);
334 EXPECT_FALSE(coded_output.HadError());
temporal40ee5512008-07-10 02:12:20 +0000335
336 EXPECT_EQ(kVarintCases_case.size, coded_output.ByteCount());
337 }
338
339 EXPECT_EQ(kVarintCases_case.size, output.ByteCount());
340 EXPECT_EQ(0,
341 memcmp(buffer_, kVarintCases_case.bytes, kVarintCases_case.size));
342}
343
344// This test causes gcc 3.3.5 (and earlier?) to give the cryptic error:
345// "sorry, unimplemented: `method_call_expr' not supported by dump_expr"
346#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
347
348int32 kSignExtendedVarintCases[] = {
349 0, 1, -1, 1237894, -37895138
350};
351
352TEST_2D(CodedStreamTest, WriteVarint32SignExtended,
353 kSignExtendedVarintCases, kBlockSizes) {
354 ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
355
356 {
357 CodedOutputStream coded_output(&output);
358
kenton@google.comd37d46d2009-04-25 02:53:47 +0000359 coded_output.WriteVarint32SignExtended(kSignExtendedVarintCases_case);
360 EXPECT_FALSE(coded_output.HadError());
temporal40ee5512008-07-10 02:12:20 +0000361
362 if (kSignExtendedVarintCases_case < 0) {
363 EXPECT_EQ(10, coded_output.ByteCount());
364 } else {
365 EXPECT_LE(coded_output.ByteCount(), 5);
366 }
367 }
368
369 if (kSignExtendedVarintCases_case < 0) {
370 EXPECT_EQ(10, output.ByteCount());
371 } else {
372 EXPECT_LE(output.ByteCount(), 5);
373 }
374
375 // Read value back in as a varint64 and insure it matches.
376 ArrayInputStream input(buffer_, sizeof(buffer_));
377
378 {
379 CodedInputStream coded_input(&input);
380
381 uint64 value;
382 EXPECT_TRUE(coded_input.ReadVarint64(&value));
383
384 EXPECT_EQ(kSignExtendedVarintCases_case, static_cast<int64>(value));
385 }
386
387 EXPECT_EQ(output.ByteCount(), input.ByteCount());
388}
389
390#endif
391
392
393// -------------------------------------------------------------------
394// Varint failure test.
395
396struct VarintErrorCase {
397 uint8 bytes[12];
398 int size;
399 bool can_parse;
400};
401
402inline std::ostream& operator<<(std::ostream& os, const VarintErrorCase& c) {
403 return os << "size " << c.size;
404}
405
406const VarintErrorCase kVarintErrorCases[] = {
407 // Control case. (Insures that there isn't something else wrong that
408 // makes parsing always fail.)
409 {{0x00}, 1, true},
410
411 // No input data.
412 {{}, 0, false},
413
414 // Input ends unexpectedly.
415 {{0xf0, 0xab}, 2, false},
416
417 // Input ends unexpectedly after 32 bits.
418 {{0xf0, 0xab, 0xc9, 0x9a, 0xf8, 0xb2}, 6, false},
419
420 // Longer than 10 bytes.
421 {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01},
422 11, false},
423};
424
425TEST_2D(CodedStreamTest, ReadVarint32Error, kVarintErrorCases, kBlockSizes) {
426 memcpy(buffer_, kVarintErrorCases_case.bytes, kVarintErrorCases_case.size);
427 ArrayInputStream input(buffer_, kVarintErrorCases_case.size,
428 kBlockSizes_case);
429 CodedInputStream coded_input(&input);
430
431 uint32 value;
432 EXPECT_EQ(kVarintErrorCases_case.can_parse, coded_input.ReadVarint32(&value));
433}
434
435TEST_2D(CodedStreamTest, ReadVarint64Error, kVarintErrorCases, kBlockSizes) {
436 memcpy(buffer_, kVarintErrorCases_case.bytes, kVarintErrorCases_case.size);
437 ArrayInputStream input(buffer_, kVarintErrorCases_case.size,
438 kBlockSizes_case);
439 CodedInputStream coded_input(&input);
440
441 uint64 value;
442 EXPECT_EQ(kVarintErrorCases_case.can_parse, coded_input.ReadVarint64(&value));
443}
444
445// -------------------------------------------------------------------
446// VarintSize
447
448struct VarintSizeCase {
449 uint64 value;
450 int size;
451};
452
453inline std::ostream& operator<<(std::ostream& os, const VarintSizeCase& c) {
454 return os << c.value;
455}
456
457VarintSizeCase kVarintSizeCases[] = {
458 {0u, 1},
459 {1u, 1},
460 {127u, 1},
461 {128u, 2},
462 {758923u, 3},
463 {4000000000u, 5},
464 {ULL(41256202580718336), 8},
465 {ULL(11964378330978735131), 10},
466};
467
468TEST_1D(CodedStreamTest, VarintSize32, kVarintSizeCases) {
469 if (kVarintSizeCases_case.value > 0xffffffffu) {
470 // Skip 64-bit values.
471 return;
472 }
473
474 EXPECT_EQ(kVarintSizeCases_case.size,
475 CodedOutputStream::VarintSize32(
476 static_cast<uint32>(kVarintSizeCases_case.value)));
477}
478
479TEST_1D(CodedStreamTest, VarintSize64, kVarintSizeCases) {
480 EXPECT_EQ(kVarintSizeCases_case.size,
481 CodedOutputStream::VarintSize64(kVarintSizeCases_case.value));
482}
483
484// -------------------------------------------------------------------
485// Fixed-size int tests
486
487struct Fixed32Case {
488 uint8 bytes[sizeof(uint32)]; // Encoded bytes.
489 uint32 value; // Parsed value.
490};
491
492struct Fixed64Case {
493 uint8 bytes[sizeof(uint64)]; // Encoded bytes.
494 uint64 value; // Parsed value.
495};
496
497inline std::ostream& operator<<(std::ostream& os, const Fixed32Case& c) {
498 return os << "0x" << hex << c.value << dec;
499}
500
501inline std::ostream& operator<<(std::ostream& os, const Fixed64Case& c) {
502 return os << "0x" << hex << c.value << dec;
503}
504
505Fixed32Case kFixed32Cases[] = {
506 {{0xef, 0xcd, 0xab, 0x90}, 0x90abcdefu},
507 {{0x12, 0x34, 0x56, 0x78}, 0x78563412u},
508};
509
510Fixed64Case kFixed64Cases[] = {
511 {{0xef, 0xcd, 0xab, 0x90, 0x12, 0x34, 0x56, 0x78}, ULL(0x7856341290abcdef)},
512 {{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, ULL(0x8877665544332211)},
513};
514
515TEST_2D(CodedStreamTest, ReadLittleEndian32, kFixed32Cases, kBlockSizes) {
516 memcpy(buffer_, kFixed32Cases_case.bytes, sizeof(kFixed32Cases_case.bytes));
517 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
518
519 {
520 CodedInputStream coded_input(&input);
521
522 uint32 value;
523 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
524 EXPECT_EQ(kFixed32Cases_case.value, value);
525 }
526
527 EXPECT_EQ(sizeof(uint32), input.ByteCount());
528}
529
530TEST_2D(CodedStreamTest, ReadLittleEndian64, kFixed64Cases, kBlockSizes) {
531 memcpy(buffer_, kFixed64Cases_case.bytes, sizeof(kFixed64Cases_case.bytes));
532 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
533
534 {
535 CodedInputStream coded_input(&input);
536
537 uint64 value;
538 EXPECT_TRUE(coded_input.ReadLittleEndian64(&value));
539 EXPECT_EQ(kFixed64Cases_case.value, value);
540 }
541
542 EXPECT_EQ(sizeof(uint64), input.ByteCount());
543}
544
545TEST_2D(CodedStreamTest, WriteLittleEndian32, kFixed32Cases, kBlockSizes) {
546 ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
547
548 {
549 CodedOutputStream coded_output(&output);
550
kenton@google.comd37d46d2009-04-25 02:53:47 +0000551 coded_output.WriteLittleEndian32(kFixed32Cases_case.value);
552 EXPECT_FALSE(coded_output.HadError());
temporal40ee5512008-07-10 02:12:20 +0000553
554 EXPECT_EQ(sizeof(uint32), coded_output.ByteCount());
555 }
556
557 EXPECT_EQ(sizeof(uint32), output.ByteCount());
558 EXPECT_EQ(0, memcmp(buffer_, kFixed32Cases_case.bytes, sizeof(uint32)));
559}
560
561TEST_2D(CodedStreamTest, WriteLittleEndian64, kFixed64Cases, kBlockSizes) {
562 ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
563
564 {
565 CodedOutputStream coded_output(&output);
566
kenton@google.comd37d46d2009-04-25 02:53:47 +0000567 coded_output.WriteLittleEndian64(kFixed64Cases_case.value);
568 EXPECT_FALSE(coded_output.HadError());
temporal40ee5512008-07-10 02:12:20 +0000569
570 EXPECT_EQ(sizeof(uint64), coded_output.ByteCount());
571 }
572
573 EXPECT_EQ(sizeof(uint64), output.ByteCount());
574 EXPECT_EQ(0, memcmp(buffer_, kFixed64Cases_case.bytes, sizeof(uint64)));
575}
576
kenton@google.comfccb1462009-12-18 02:11:36 +0000577// Tests using the static methods to read fixed-size values from raw arrays.
578
579TEST_1D(CodedStreamTest, ReadLittleEndian32FromArray, kFixed32Cases) {
580 memcpy(buffer_, kFixed32Cases_case.bytes, sizeof(kFixed32Cases_case.bytes));
581
582 uint32 value;
583 const uint8* end = CodedInputStream::ReadLittleEndian32FromArray(
584 buffer_, &value);
585 EXPECT_EQ(kFixed32Cases_case.value, value);
586 EXPECT_TRUE(end == buffer_ + sizeof(value));
587}
588
589TEST_1D(CodedStreamTest, ReadLittleEndian64FromArray, kFixed64Cases) {
590 memcpy(buffer_, kFixed64Cases_case.bytes, sizeof(kFixed64Cases_case.bytes));
591
592 uint64 value;
593 const uint8* end = CodedInputStream::ReadLittleEndian64FromArray(
594 buffer_, &value);
595 EXPECT_EQ(kFixed64Cases_case.value, value);
596 EXPECT_TRUE(end == buffer_ + sizeof(value));
597}
598
temporal40ee5512008-07-10 02:12:20 +0000599// -------------------------------------------------------------------
600// Raw reads and writes
601
kenton@google.comfccb1462009-12-18 02:11:36 +0000602const char kRawBytes[] = "Some bytes which will be written and read raw.";
temporal40ee5512008-07-10 02:12:20 +0000603
604TEST_1D(CodedStreamTest, ReadRaw, kBlockSizes) {
605 memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
606 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
607 char read_buffer[sizeof(kRawBytes)];
608
609 {
610 CodedInputStream coded_input(&input);
611
612 EXPECT_TRUE(coded_input.ReadRaw(read_buffer, sizeof(kRawBytes)));
613 EXPECT_EQ(0, memcmp(kRawBytes, read_buffer, sizeof(kRawBytes)));
614 }
615
616 EXPECT_EQ(sizeof(kRawBytes), input.ByteCount());
617}
618
619TEST_1D(CodedStreamTest, WriteRaw, kBlockSizes) {
620 ArrayOutputStream output(buffer_, sizeof(buffer_), kBlockSizes_case);
621
622 {
623 CodedOutputStream coded_output(&output);
624
kenton@google.comd37d46d2009-04-25 02:53:47 +0000625 coded_output.WriteRaw(kRawBytes, sizeof(kRawBytes));
626 EXPECT_FALSE(coded_output.HadError());
temporal40ee5512008-07-10 02:12:20 +0000627
628 EXPECT_EQ(sizeof(kRawBytes), coded_output.ByteCount());
629 }
630
631 EXPECT_EQ(sizeof(kRawBytes), output.ByteCount());
632 EXPECT_EQ(0, memcmp(buffer_, kRawBytes, sizeof(kRawBytes)));
633}
634
635TEST_1D(CodedStreamTest, ReadString, kBlockSizes) {
636 memcpy(buffer_, kRawBytes, sizeof(kRawBytes));
637 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
638
639 {
640 CodedInputStream coded_input(&input);
641
642 string str;
643 EXPECT_TRUE(coded_input.ReadString(&str, strlen(kRawBytes)));
644 EXPECT_EQ(kRawBytes, str);
645 }
646
647 EXPECT_EQ(strlen(kRawBytes), input.ByteCount());
648}
649
650// Check to make sure ReadString doesn't crash on impossibly large strings.
651TEST_1D(CodedStreamTest, ReadStringImpossiblyLarge, kBlockSizes) {
652 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
653
654 {
655 CodedInputStream coded_input(&input);
656
657 string str;
658 // Try to read a gigabyte.
659 EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
660 }
661}
662
kenton@google.comfccb1462009-12-18 02:11:36 +0000663TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnStack) {
664 // Same test as above, except directly use a buffer. This used to cause
665 // crashes while the above did not.
666 uint8 buffer[8];
667 CodedInputStream coded_input(buffer, 8);
668 string str;
669 EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
670}
671
672TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) {
673 scoped_array<uint8> buffer(new uint8[8]);
674 CodedInputStream coded_input(buffer.get(), 8);
675 string str;
676 EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
677}
678
temporal40ee5512008-07-10 02:12:20 +0000679
680// -------------------------------------------------------------------
681// Skip
682
683const char kSkipTestBytes[] =
684 "<Before skipping><To be skipped><After skipping>";
685const char kSkipOutputTestBytes[] =
686 "-----------------<To be skipped>----------------";
687
688TEST_1D(CodedStreamTest, SkipInput, kBlockSizes) {
689 memcpy(buffer_, kSkipTestBytes, sizeof(kSkipTestBytes));
690 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
691
692 {
693 CodedInputStream coded_input(&input);
694
695 string str;
696 EXPECT_TRUE(coded_input.ReadString(&str, strlen("<Before skipping>")));
697 EXPECT_EQ("<Before skipping>", str);
698 EXPECT_TRUE(coded_input.Skip(strlen("<To be skipped>")));
699 EXPECT_TRUE(coded_input.ReadString(&str, strlen("<After skipping>")));
700 EXPECT_EQ("<After skipping>", str);
701 }
702
703 EXPECT_EQ(strlen(kSkipTestBytes), input.ByteCount());
704}
705
706// -------------------------------------------------------------------
kenton@google.com2d6daa72009-01-22 01:27:00 +0000707// GetDirectBufferPointer
708
709TEST_F(CodedStreamTest, GetDirectBufferPointerInput) {
710 ArrayInputStream input(buffer_, sizeof(buffer_), 8);
711 CodedInputStream coded_input(&input);
712
713 const void* ptr;
714 int size;
715
716 EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
717 EXPECT_EQ(buffer_, ptr);
718 EXPECT_EQ(8, size);
719
720 // Peeking again should return the same pointer.
721 EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
722 EXPECT_EQ(buffer_, ptr);
723 EXPECT_EQ(8, size);
724
725 // Skip forward in the same buffer then peek again.
726 EXPECT_TRUE(coded_input.Skip(3));
727 EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
728 EXPECT_EQ(buffer_ + 3, ptr);
729 EXPECT_EQ(5, size);
730
731 // Skip to end of buffer and peek -- should get next buffer.
732 EXPECT_TRUE(coded_input.Skip(5));
733 EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
734 EXPECT_EQ(buffer_ + 8, ptr);
735 EXPECT_EQ(8, size);
736}
737
kenton@google.comfccb1462009-12-18 02:11:36 +0000738TEST_F(CodedStreamTest, GetDirectBufferPointerInlineInput) {
739 ArrayInputStream input(buffer_, sizeof(buffer_), 8);
740 CodedInputStream coded_input(&input);
741
742 const void* ptr;
743 int size;
744
745 coded_input.GetDirectBufferPointerInline(&ptr, &size);
746 EXPECT_EQ(buffer_, ptr);
747 EXPECT_EQ(8, size);
748
749 // Peeking again should return the same pointer.
750 coded_input.GetDirectBufferPointerInline(&ptr, &size);
751 EXPECT_EQ(buffer_, ptr);
752 EXPECT_EQ(8, size);
753
754 // Skip forward in the same buffer then peek again.
755 EXPECT_TRUE(coded_input.Skip(3));
756 coded_input.GetDirectBufferPointerInline(&ptr, &size);
757 EXPECT_EQ(buffer_ + 3, ptr);
758 EXPECT_EQ(5, size);
759
760 // Skip to end of buffer and peek -- should return false and provide an empty
761 // buffer. It does not try to Refresh().
762 EXPECT_TRUE(coded_input.Skip(5));
763 coded_input.GetDirectBufferPointerInline(&ptr, &size);
764 EXPECT_EQ(buffer_ + 8, ptr);
765 EXPECT_EQ(0, size);
766}
767
kenton@google.com2d6daa72009-01-22 01:27:00 +0000768TEST_F(CodedStreamTest, GetDirectBufferPointerOutput) {
769 ArrayOutputStream output(buffer_, sizeof(buffer_), 8);
770 CodedOutputStream coded_output(&output);
771
772 void* ptr;
773 int size;
774
775 EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
776 EXPECT_EQ(buffer_, ptr);
777 EXPECT_EQ(8, size);
778
779 // Peeking again should return the same pointer.
780 EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
781 EXPECT_EQ(buffer_, ptr);
782 EXPECT_EQ(8, size);
783
784 // Skip forward in the same buffer then peek again.
785 EXPECT_TRUE(coded_output.Skip(3));
786 EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
787 EXPECT_EQ(buffer_ + 3, ptr);
788 EXPECT_EQ(5, size);
789
790 // Skip to end of buffer and peek -- should get next buffer.
791 EXPECT_TRUE(coded_output.Skip(5));
792 EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
793 EXPECT_EQ(buffer_ + 8, ptr);
794 EXPECT_EQ(8, size);
795
796 // Skip over multiple buffers.
797 EXPECT_TRUE(coded_output.Skip(22));
798 EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
799 EXPECT_EQ(buffer_ + 30, ptr);
800 EXPECT_EQ(2, size);
801}
802
803// -------------------------------------------------------------------
temporal40ee5512008-07-10 02:12:20 +0000804// Limits
805
806TEST_1D(CodedStreamTest, BasicLimit, kBlockSizes) {
807 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
808
809 {
810 CodedInputStream coded_input(&input);
811
812 EXPECT_EQ(-1, coded_input.BytesUntilLimit());
813 CodedInputStream::Limit limit = coded_input.PushLimit(8);
814
815 // Read until we hit the limit.
816 uint32 value;
817 EXPECT_EQ(8, coded_input.BytesUntilLimit());
818 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
819 EXPECT_EQ(4, coded_input.BytesUntilLimit());
820 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
821 EXPECT_EQ(0, coded_input.BytesUntilLimit());
822 EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
823 EXPECT_EQ(0, coded_input.BytesUntilLimit());
824
825 coded_input.PopLimit(limit);
826
827 EXPECT_EQ(-1, coded_input.BytesUntilLimit());
828 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
829 }
830
831 EXPECT_EQ(12, input.ByteCount());
832}
833
834// Test what happens when we push two limits where the second (top) one is
835// shorter.
836TEST_1D(CodedStreamTest, SmallLimitOnTopOfBigLimit, kBlockSizes) {
837 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
838
839 {
840 CodedInputStream coded_input(&input);
841
842 EXPECT_EQ(-1, coded_input.BytesUntilLimit());
843 CodedInputStream::Limit limit1 = coded_input.PushLimit(8);
844 EXPECT_EQ(8, coded_input.BytesUntilLimit());
845 CodedInputStream::Limit limit2 = coded_input.PushLimit(4);
846
847 uint32 value;
848
849 // Read until we hit limit2, the top and shortest limit.
850 EXPECT_EQ(4, coded_input.BytesUntilLimit());
851 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
852 EXPECT_EQ(0, coded_input.BytesUntilLimit());
853 EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
854 EXPECT_EQ(0, coded_input.BytesUntilLimit());
855
856 coded_input.PopLimit(limit2);
857
858 // Read until we hit limit1.
859 EXPECT_EQ(4, coded_input.BytesUntilLimit());
860 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
861 EXPECT_EQ(0, coded_input.BytesUntilLimit());
862 EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
863 EXPECT_EQ(0, coded_input.BytesUntilLimit());
864
865 coded_input.PopLimit(limit1);
866
867 // No more limits.
868 EXPECT_EQ(-1, coded_input.BytesUntilLimit());
869 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
870 }
871
872 EXPECT_EQ(12, input.ByteCount());
873}
874
875// Test what happens when we push two limits where the second (top) one is
876// longer. In this case, the top limit is shortened to match the previous
877// limit.
878TEST_1D(CodedStreamTest, BigLimitOnTopOfSmallLimit, kBlockSizes) {
879 ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case);
880
881 {
882 CodedInputStream coded_input(&input);
883
884 EXPECT_EQ(-1, coded_input.BytesUntilLimit());
885 CodedInputStream::Limit limit1 = coded_input.PushLimit(4);
886 EXPECT_EQ(4, coded_input.BytesUntilLimit());
887 CodedInputStream::Limit limit2 = coded_input.PushLimit(8);
888
889 uint32 value;
890
891 // Read until we hit limit2. Except, wait! limit1 is shorter, so
892 // we end up hitting that first, despite having 4 bytes to go on
893 // limit2.
894 EXPECT_EQ(4, coded_input.BytesUntilLimit());
895 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
896 EXPECT_EQ(0, coded_input.BytesUntilLimit());
897 EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
898 EXPECT_EQ(0, coded_input.BytesUntilLimit());
899
900 coded_input.PopLimit(limit2);
901
902 // OK, popped limit2, now limit1 is on top, which we've already hit.
903 EXPECT_EQ(0, coded_input.BytesUntilLimit());
904 EXPECT_FALSE(coded_input.ReadLittleEndian32(&value));
905 EXPECT_EQ(0, coded_input.BytesUntilLimit());
906
907 coded_input.PopLimit(limit1);
908
909 // No more limits.
910 EXPECT_EQ(-1, coded_input.BytesUntilLimit());
911 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
912 }
913
914 EXPECT_EQ(8, input.ByteCount());
915}
916
917TEST_F(CodedStreamTest, ExpectAtEnd) {
918 // Test ExpectAtEnd(), which is based on limits.
919 ArrayInputStream input(buffer_, sizeof(buffer_));
920 CodedInputStream coded_input(&input);
921
922 EXPECT_FALSE(coded_input.ExpectAtEnd());
923
924 CodedInputStream::Limit limit = coded_input.PushLimit(4);
925
926 uint32 value;
927 EXPECT_TRUE(coded_input.ReadLittleEndian32(&value));
928 EXPECT_TRUE(coded_input.ExpectAtEnd());
929
930 coded_input.PopLimit(limit);
931 EXPECT_FALSE(coded_input.ExpectAtEnd());
932}
933
934TEST_F(CodedStreamTest, NegativeLimit) {
935 // Check what happens when we push a negative limit.
936 ArrayInputStream input(buffer_, sizeof(buffer_));
937 CodedInputStream coded_input(&input);
938
939 CodedInputStream::Limit limit = coded_input.PushLimit(-1234);
940 // BytesUntilLimit() returns -1 to mean "no limit", which actually means
941 // "the limit is INT_MAX relative to the beginning of the stream".
942 EXPECT_EQ(-1, coded_input.BytesUntilLimit());
943 coded_input.PopLimit(limit);
944}
945
946TEST_F(CodedStreamTest, NegativeLimitAfterReading) {
947 // Check what happens when we push a negative limit.
948 ArrayInputStream input(buffer_, sizeof(buffer_));
949 CodedInputStream coded_input(&input);
950 ASSERT_TRUE(coded_input.Skip(128));
951
952 CodedInputStream::Limit limit = coded_input.PushLimit(-64);
953 // BytesUntilLimit() returns -1 to mean "no limit", which actually means
954 // "the limit is INT_MAX relative to the beginning of the stream".
955 EXPECT_EQ(-1, coded_input.BytesUntilLimit());
956 coded_input.PopLimit(limit);
957}
958
959TEST_F(CodedStreamTest, OverflowLimit) {
960 // Check what happens when we push a limit large enough that its absolute
961 // position is more than 2GB into the stream.
962 ArrayInputStream input(buffer_, sizeof(buffer_));
963 CodedInputStream coded_input(&input);
964 ASSERT_TRUE(coded_input.Skip(128));
965
966 CodedInputStream::Limit limit = coded_input.PushLimit(INT_MAX);
967 // BytesUntilLimit() returns -1 to mean "no limit", which actually means
968 // "the limit is INT_MAX relative to the beginning of the stream".
969 EXPECT_EQ(-1, coded_input.BytesUntilLimit());
970 coded_input.PopLimit(limit);
971}
972
973TEST_F(CodedStreamTest, TotalBytesLimit) {
974 ArrayInputStream input(buffer_, sizeof(buffer_));
975 CodedInputStream coded_input(&input);
976 coded_input.SetTotalBytesLimit(16, -1);
977
978 string str;
979 EXPECT_TRUE(coded_input.ReadString(&str, 16));
980
981 vector<string> errors;
982
983 {
984 ScopedMemoryLog error_log;
985 EXPECT_FALSE(coded_input.ReadString(&str, 1));
986 errors = error_log.GetMessages(ERROR);
987 }
988
989 ASSERT_EQ(1, errors.size());
990 EXPECT_PRED_FORMAT2(testing::IsSubstring,
991 "A protocol message was rejected because it was too big", errors[0]);
992
993 coded_input.SetTotalBytesLimit(32, -1);
994 EXPECT_TRUE(coded_input.ReadString(&str, 16));
995}
996
997TEST_F(CodedStreamTest, TotalBytesLimitNotValidMessageEnd) {
998 // total_bytes_limit_ is not a valid place for a message to end.
999
1000 ArrayInputStream input(buffer_, sizeof(buffer_));
1001 CodedInputStream coded_input(&input);
1002
1003 // Set both total_bytes_limit and a regular limit at 16 bytes.
1004 coded_input.SetTotalBytesLimit(16, -1);
1005 CodedInputStream::Limit limit = coded_input.PushLimit(16);
1006
1007 // Read 16 bytes.
1008 string str;
1009 EXPECT_TRUE(coded_input.ReadString(&str, 16));
1010
1011 // Read a tag. Should fail, but report being a valid endpoint since it's
1012 // a regular limit.
1013 EXPECT_EQ(0, coded_input.ReadTag());
1014 EXPECT_TRUE(coded_input.ConsumedEntireMessage());
1015
1016 // Pop the limit.
1017 coded_input.PopLimit(limit);
1018
1019 // Read a tag. Should fail, and report *not* being a valid endpoint, since
1020 // this time we're hitting the total bytes limit.
1021 EXPECT_EQ(0, coded_input.ReadTag());
1022 EXPECT_FALSE(coded_input.ConsumedEntireMessage());
1023}
1024
liujisi@google.com33165fe2010-11-02 13:14:58 +00001025
temporal40ee5512008-07-10 02:12:20 +00001026TEST_F(CodedStreamTest, RecursionLimit) {
1027 ArrayInputStream input(buffer_, sizeof(buffer_));
1028 CodedInputStream coded_input(&input);
1029 coded_input.SetRecursionLimit(4);
1030
1031 // This is way too much testing for a counter.
1032 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 1
1033 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 2
1034 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 3
1035 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 4
1036 EXPECT_FALSE(coded_input.IncrementRecursionDepth()); // 5
1037 EXPECT_FALSE(coded_input.IncrementRecursionDepth()); // 6
1038 coded_input.DecrementRecursionDepth(); // 5
1039 EXPECT_FALSE(coded_input.IncrementRecursionDepth()); // 6
1040 coded_input.DecrementRecursionDepth(); // 5
1041 coded_input.DecrementRecursionDepth(); // 4
1042 coded_input.DecrementRecursionDepth(); // 3
1043 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 4
1044 EXPECT_FALSE(coded_input.IncrementRecursionDepth()); // 5
1045 coded_input.DecrementRecursionDepth(); // 4
1046 coded_input.DecrementRecursionDepth(); // 3
1047 coded_input.DecrementRecursionDepth(); // 2
1048 coded_input.DecrementRecursionDepth(); // 1
1049 coded_input.DecrementRecursionDepth(); // 0
1050 coded_input.DecrementRecursionDepth(); // 0
1051 coded_input.DecrementRecursionDepth(); // 0
1052 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 1
1053 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 2
1054 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 3
1055 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 4
1056 EXPECT_FALSE(coded_input.IncrementRecursionDepth()); // 5
1057
1058 coded_input.SetRecursionLimit(6);
1059 EXPECT_TRUE(coded_input.IncrementRecursionDepth()); // 6
1060 EXPECT_FALSE(coded_input.IncrementRecursionDepth()); // 7
1061}
1062
1063class ReallyBigInputStream : public ZeroCopyInputStream {
1064 public:
1065 ReallyBigInputStream() : backup_amount_(0), buffer_count_(0) {}
1066 ~ReallyBigInputStream() {}
1067
1068 // implements ZeroCopyInputStream ----------------------------------
1069 bool Next(const void** data, int* size) {
1070 // We only expect BackUp() to be called at the end.
1071 EXPECT_EQ(0, backup_amount_);
1072
1073 switch (buffer_count_++) {
1074 case 0:
1075 *data = buffer_;
1076 *size = sizeof(buffer_);
1077 return true;
1078 case 1:
1079 // Return an enormously large buffer that, when combined with the 1k
1080 // returned already, should overflow the total_bytes_read_ counter in
1081 // CodedInputStream. Note that we'll only read the first 1024 bytes
1082 // of this buffer so it's OK that we have it point at buffer_.
1083 *data = buffer_;
1084 *size = INT_MAX;
1085 return true;
1086 default:
1087 return false;
1088 }
1089 }
1090
1091 void BackUp(int count) {
1092 backup_amount_ = count;
1093 }
1094
1095 bool Skip(int count) { GOOGLE_LOG(FATAL) << "Not implemented."; return false; }
1096 int64 ByteCount() const { GOOGLE_LOG(FATAL) << "Not implemented."; return 0; }
1097
1098 int backup_amount_;
1099
1100 private:
1101 char buffer_[1024];
1102 int64 buffer_count_;
1103};
1104
1105TEST_F(CodedStreamTest, InputOver2G) {
1106 // CodedInputStream should gracefully handle input over 2G and call
1107 // input.BackUp() with the correct number of bytes on destruction.
1108 ReallyBigInputStream input;
1109
1110 vector<string> errors;
1111
1112 {
1113 ScopedMemoryLog error_log;
1114 CodedInputStream coded_input(&input);
1115 string str;
1116 EXPECT_TRUE(coded_input.ReadString(&str, 512));
1117 EXPECT_TRUE(coded_input.ReadString(&str, 1024));
1118 errors = error_log.GetMessages(ERROR);
1119 }
1120
1121 EXPECT_EQ(INT_MAX - 512, input.backup_amount_);
1122 EXPECT_EQ(0, errors.size());
1123}
1124
1125// ===================================================================
1126
1127
1128} // namespace
1129} // namespace io
1130} // namespace protobuf
1131} // namespace google