- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / protobuf / src / google / protobuf / io / zero_copy_stream_unittest.cc
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * 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.
18 //
19 // 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.
30
31 // Author: kenton@google.com (Kenton Varda)
32 //  Based on original Protocol Buffers design by
33 //  Sanjay Ghemawat, Jeff Dean, and others.
34 //
35 // Testing strategy:  For each type of I/O (array, string, file, etc.) we
36 // create an output stream and write some data to it, then create a
37 // corresponding input stream to read the same data back and expect it to
38 // match.  When the data is written, it is written in several small chunks
39 // of varying sizes, with a BackUp() after each chunk.  It is read back
40 // similarly, but with chunks separated at different points.  The whole
41 // process is run with a variety of block sizes for both the input and
42 // the output.
43 //
44 // TODO(kenton):  Rewrite this test to bring it up to the standards of all
45 //   the other proto2 tests.  May want to wait for gTest to implement
46 //   "parametized tests" so that one set of tests can be used on all the
47 //   implementations.
48
49 #include "config.h"
50
51 #ifdef _MSC_VER
52 #include <io.h>
53 #else
54 #include <unistd.h>
55 #endif
56 #include <stdlib.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <fcntl.h>
60 #include <errno.h>
61 #include <sstream>
62
63 #include <google/protobuf/io/zero_copy_stream_impl.h>
64 #include <google/protobuf/io/coded_stream.h>
65
66 #if HAVE_ZLIB
67 #include <google/protobuf/io/gzip_stream.h>
68 #endif
69
70 #include <google/protobuf/stubs/common.h>
71 #include <google/protobuf/testing/googletest.h>
72 #include <google/protobuf/testing/file.h>
73 #include <gtest/gtest.h>
74
75 namespace google {
76 namespace protobuf {
77 namespace io {
78 namespace {
79
80 #ifdef _WIN32
81 #define pipe(fds) _pipe(fds, 4096, O_BINARY)
82 #endif
83
84 #ifndef O_BINARY
85 #ifdef _O_BINARY
86 #define O_BINARY _O_BINARY
87 #else
88 #define O_BINARY 0     // If this isn't defined, the platform doesn't need it.
89 #endif
90 #endif
91
92 class IoTest : public testing::Test {
93  protected:
94   // Test helpers.
95
96   // Helper to write an array of data to an output stream.
97   bool WriteToOutput(ZeroCopyOutputStream* output, const void* data, int size);
98   // Helper to read a fixed-length array of data from an input stream.
99   int ReadFromInput(ZeroCopyInputStream* input, void* data, int size);
100   // Write a string to the output stream.
101   void WriteString(ZeroCopyOutputStream* output, const string& str);
102   // Read a number of bytes equal to the size of the given string and checks
103   // that it matches the string.
104   void ReadString(ZeroCopyInputStream* input, const string& str);
105   // Writes some text to the output stream in a particular order.  Returns
106   // the number of bytes written, incase the caller needs that to set up an
107   // input stream.
108   int WriteStuff(ZeroCopyOutputStream* output);
109   // Reads text from an input stream and expects it to match what
110   // WriteStuff() writes.
111   void ReadStuff(ZeroCopyInputStream* input);
112
113   // Similar to WriteStuff, but performs more sophisticated testing.
114   int WriteStuffLarge(ZeroCopyOutputStream* output);
115   // Reads and tests a stream that should have been written to
116   // via WriteStuffLarge().
117   void ReadStuffLarge(ZeroCopyInputStream* input);
118
119 #if HAVE_ZLIB
120   string Compress(const string& data, const GzipOutputStream::Options& options);
121   string Uncompress(const string& data);
122 #endif
123
124   static const int kBlockSizes[];
125   static const int kBlockSizeCount;
126 };
127
128 const int IoTest::kBlockSizes[] = {-1, 1, 2, 5, 7, 10, 23, 64};
129 const int IoTest::kBlockSizeCount = GOOGLE_ARRAYSIZE(IoTest::kBlockSizes);
130
131 bool IoTest::WriteToOutput(ZeroCopyOutputStream* output,
132                            const void* data, int size) {
133   const uint8* in = reinterpret_cast<const uint8*>(data);
134   int in_size = size;
135
136   void* out;
137   int out_size;
138
139   while (true) {
140     if (!output->Next(&out, &out_size)) {
141       return false;
142     }
143     EXPECT_GT(out_size, 0);
144
145     if (in_size <= out_size) {
146       memcpy(out, in, in_size);
147       output->BackUp(out_size - in_size);
148       return true;
149     }
150
151     memcpy(out, in, out_size);
152     in += out_size;
153     in_size -= out_size;
154   }
155 }
156
157 #define MAX_REPEATED_ZEROS 100
158
159 int IoTest::ReadFromInput(ZeroCopyInputStream* input, void* data, int size) {
160   uint8* out = reinterpret_cast<uint8*>(data);
161   int out_size = size;
162
163   const void* in;
164   int in_size = 0;
165
166   int repeated_zeros = 0;
167
168   while (true) {
169     if (!input->Next(&in, &in_size)) {
170       return size - out_size;
171     }
172     EXPECT_GT(in_size, -1);
173     if (in_size == 0) {
174       repeated_zeros++;
175     } else {
176       repeated_zeros = 0;
177     }
178     EXPECT_LT(repeated_zeros, MAX_REPEATED_ZEROS);
179
180     if (out_size <= in_size) {
181       memcpy(out, in, out_size);
182       if (in_size > out_size) {
183         input->BackUp(in_size - out_size);
184       }
185       return size;  // Copied all of it.
186     }
187
188     memcpy(out, in, in_size);
189     out += in_size;
190     out_size -= in_size;
191   }
192 }
193
194 void IoTest::WriteString(ZeroCopyOutputStream* output, const string& str) {
195   EXPECT_TRUE(WriteToOutput(output, str.c_str(), str.size()));
196 }
197
198 void IoTest::ReadString(ZeroCopyInputStream* input, const string& str) {
199   scoped_array<char> buffer(new char[str.size() + 1]);
200   buffer[str.size()] = '\0';
201   EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size());
202   EXPECT_STREQ(str.c_str(), buffer.get());
203 }
204
205 int IoTest::WriteStuff(ZeroCopyOutputStream* output) {
206   WriteString(output, "Hello world!\n");
207   WriteString(output, "Some te");
208   WriteString(output, "xt.  Blah blah.");
209   WriteString(output, "abcdefg");
210   WriteString(output, "01234567890123456789");
211   WriteString(output, "foobar");
212
213   EXPECT_EQ(output->ByteCount(), 68);
214
215   int result = output->ByteCount();
216   return result;
217 }
218
219 // Reads text from an input stream and expects it to match what WriteStuff()
220 // writes.
221 void IoTest::ReadStuff(ZeroCopyInputStream* input) {
222   ReadString(input, "Hello world!\n");
223   ReadString(input, "Some text.  ");
224   ReadString(input, "Blah ");
225   ReadString(input, "blah.");
226   ReadString(input, "abcdefg");
227   EXPECT_TRUE(input->Skip(20));
228   ReadString(input, "foo");
229   ReadString(input, "bar");
230
231   EXPECT_EQ(input->ByteCount(), 68);
232
233   uint8 byte;
234   EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
235 }
236
237 int IoTest::WriteStuffLarge(ZeroCopyOutputStream* output) {
238   WriteString(output, "Hello world!\n");
239   WriteString(output, "Some te");
240   WriteString(output, "xt.  Blah blah.");
241   WriteString(output, string(100000, 'x'));  // A very long string
242   WriteString(output, string(100000, 'y'));  // A very long string
243   WriteString(output, "01234567890123456789");
244
245   EXPECT_EQ(output->ByteCount(), 200055);
246
247   int result = output->ByteCount();
248   return result;
249 }
250
251 // Reads text from an input stream and expects it to match what WriteStuff()
252 // writes.
253 void IoTest::ReadStuffLarge(ZeroCopyInputStream* input) {
254   ReadString(input, "Hello world!\nSome text.  ");
255   EXPECT_TRUE(input->Skip(5));
256   ReadString(input, "blah.");
257   EXPECT_TRUE(input->Skip(100000 - 10));
258   ReadString(input, string(10, 'x') + string(100000 - 20000, 'y'));
259   EXPECT_TRUE(input->Skip(20000 - 10));
260   ReadString(input, "yyyyyyyyyy01234567890123456789");
261
262   EXPECT_EQ(input->ByteCount(), 200055);
263
264   uint8 byte;
265   EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
266 }
267
268 // ===================================================================
269
270 TEST_F(IoTest, ArrayIo) {
271   const int kBufferSize = 256;
272   uint8 buffer[kBufferSize];
273
274   for (int i = 0; i < kBlockSizeCount; i++) {
275     for (int j = 0; j < kBlockSizeCount; j++) {
276       int size;
277       {
278         ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
279         size = WriteStuff(&output);
280       }
281       {
282         ArrayInputStream input(buffer, size, kBlockSizes[j]);
283         ReadStuff(&input);
284       }
285     }
286   }
287 }
288
289 TEST_F(IoTest, TwoSessionWrite) {
290   // Test that two concatenated write sessions read correctly
291
292   static const char* strA = "0123456789";
293   static const char* strB = "WhirledPeas";
294   const int kBufferSize = 2*1024;
295   uint8* buffer = new uint8[kBufferSize];
296   char* temp_buffer = new char[40];
297
298   for (int i = 0; i < kBlockSizeCount; i++) {
299     for (int j = 0; j < kBlockSizeCount; j++) {
300       ArrayOutputStream* output =
301           new ArrayOutputStream(buffer, kBufferSize, kBlockSizes[i]);
302       CodedOutputStream* coded_output = new CodedOutputStream(output);
303       coded_output->WriteVarint32(strlen(strA));
304       coded_output->WriteRaw(strA, strlen(strA));
305       delete coded_output;  // flush
306       int64 pos = output->ByteCount();
307       delete output;
308       output = new ArrayOutputStream(
309           buffer + pos, kBufferSize - pos, kBlockSizes[i]);
310       coded_output = new CodedOutputStream(output);
311       coded_output->WriteVarint32(strlen(strB));
312       coded_output->WriteRaw(strB, strlen(strB));
313       delete coded_output;  // flush
314       int64 size = pos + output->ByteCount();
315       delete output;
316
317       ArrayInputStream* input =
318           new ArrayInputStream(buffer, size, kBlockSizes[j]);
319       CodedInputStream* coded_input = new CodedInputStream(input);
320       uint32 insize;
321       EXPECT_TRUE(coded_input->ReadVarint32(&insize));
322       EXPECT_EQ(strlen(strA), insize);
323       EXPECT_TRUE(coded_input->ReadRaw(temp_buffer, insize));
324       EXPECT_EQ(0, memcmp(temp_buffer, strA, insize));
325
326       EXPECT_TRUE(coded_input->ReadVarint32(&insize));
327       EXPECT_EQ(strlen(strB), insize);
328       EXPECT_TRUE(coded_input->ReadRaw(temp_buffer, insize));
329       EXPECT_EQ(0, memcmp(temp_buffer, strB, insize));
330
331       delete coded_input;
332       delete input;
333     }
334   }
335
336   delete [] temp_buffer;
337   delete [] buffer;
338 }
339
340 #if HAVE_ZLIB
341 TEST_F(IoTest, GzipIo) {
342   const int kBufferSize = 2*1024;
343   uint8* buffer = new uint8[kBufferSize];
344   for (int i = 0; i < kBlockSizeCount; i++) {
345     for (int j = 0; j < kBlockSizeCount; j++) {
346       for (int z = 0; z < kBlockSizeCount; z++) {
347         int gzip_buffer_size = kBlockSizes[z];
348         int size;
349         {
350           ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
351           GzipOutputStream::Options options;
352           options.format = GzipOutputStream::GZIP;
353           if (gzip_buffer_size != -1) {
354             options.buffer_size = gzip_buffer_size;
355           }
356           GzipOutputStream gzout(&output, options);
357           WriteStuff(&gzout);
358           gzout.Close();
359           size = output.ByteCount();
360         }
361         {
362           ArrayInputStream input(buffer, size, kBlockSizes[j]);
363           GzipInputStream gzin(
364               &input, GzipInputStream::GZIP, gzip_buffer_size);
365           ReadStuff(&gzin);
366         }
367       }
368     }
369   }
370   delete [] buffer;
371 }
372
373 TEST_F(IoTest, GzipIoWithFlush) {
374   const int kBufferSize = 2*1024;
375   uint8* buffer = new uint8[kBufferSize];
376   // We start with i = 4 as we want a block size > 6. With block size <= 6
377   // Flush() fills up the entire 2K buffer with flush markers and the test
378   // fails. See documentation for Flush() for more detail.
379   for (int i = 4; i < kBlockSizeCount; i++) {
380     for (int j = 0; j < kBlockSizeCount; j++) {
381       for (int z = 0; z < kBlockSizeCount; z++) {
382         int gzip_buffer_size = kBlockSizes[z];
383         int size;
384         {
385           ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
386           GzipOutputStream::Options options;
387           options.format = GzipOutputStream::GZIP;
388           if (gzip_buffer_size != -1) {
389             options.buffer_size = gzip_buffer_size;
390           }
391           GzipOutputStream gzout(&output, options);
392           WriteStuff(&gzout);
393           EXPECT_TRUE(gzout.Flush());
394           gzout.Close();
395           size = output.ByteCount();
396         }
397         {
398           ArrayInputStream input(buffer, size, kBlockSizes[j]);
399           GzipInputStream gzin(
400               &input, GzipInputStream::GZIP, gzip_buffer_size);
401           ReadStuff(&gzin);
402         }
403       }
404     }
405   }
406   delete [] buffer;
407 }
408
409 TEST_F(IoTest, GzipIoContiguousFlushes) {
410   const int kBufferSize = 2*1024;
411   uint8* buffer = new uint8[kBufferSize];
412
413   int block_size = kBlockSizes[4];
414   int gzip_buffer_size = block_size;
415   int size;
416
417   ArrayOutputStream output(buffer, kBufferSize, block_size);
418   GzipOutputStream::Options options;
419   options.format = GzipOutputStream::GZIP;
420   if (gzip_buffer_size != -1) {
421     options.buffer_size = gzip_buffer_size;
422   }
423   GzipOutputStream gzout(&output, options);
424   WriteStuff(&gzout);
425   EXPECT_TRUE(gzout.Flush());
426   EXPECT_TRUE(gzout.Flush());
427   gzout.Close();
428   size = output.ByteCount();
429
430   ArrayInputStream input(buffer, size, block_size);
431   GzipInputStream gzin(
432       &input, GzipInputStream::GZIP, gzip_buffer_size);
433   ReadStuff(&gzin);
434
435   delete [] buffer;
436 }
437
438 TEST_F(IoTest, GzipIoReadAfterFlush) {
439   const int kBufferSize = 2*1024;
440   uint8* buffer = new uint8[kBufferSize];
441
442   int block_size = kBlockSizes[4];
443   int gzip_buffer_size = block_size;
444   int size;
445   ArrayOutputStream output(buffer, kBufferSize, block_size);
446   GzipOutputStream::Options options;
447   options.format = GzipOutputStream::GZIP;
448   if (gzip_buffer_size != -1) {
449     options.buffer_size = gzip_buffer_size;
450   }
451
452   GzipOutputStream gzout(&output, options);
453   WriteStuff(&gzout);
454   EXPECT_TRUE(gzout.Flush());
455   size = output.ByteCount();
456
457   ArrayInputStream input(buffer, size, block_size);
458   GzipInputStream gzin(
459       &input, GzipInputStream::GZIP, gzip_buffer_size);
460   ReadStuff(&gzin);
461
462   gzout.Close();
463
464   delete [] buffer;
465 }
466
467 TEST_F(IoTest, ZlibIo) {
468   const int kBufferSize = 2*1024;
469   uint8* buffer = new uint8[kBufferSize];
470   for (int i = 0; i < kBlockSizeCount; i++) {
471     for (int j = 0; j < kBlockSizeCount; j++) {
472       for (int z = 0; z < kBlockSizeCount; z++) {
473         int gzip_buffer_size = kBlockSizes[z];
474         int size;
475         {
476           ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
477           GzipOutputStream::Options options;
478           options.format = GzipOutputStream::ZLIB;
479           if (gzip_buffer_size != -1) {
480             options.buffer_size = gzip_buffer_size;
481           }
482           GzipOutputStream gzout(&output, options);
483           WriteStuff(&gzout);
484           gzout.Close();
485           size = output.ByteCount();
486         }
487         {
488           ArrayInputStream input(buffer, size, kBlockSizes[j]);
489           GzipInputStream gzin(
490               &input, GzipInputStream::ZLIB, gzip_buffer_size);
491           ReadStuff(&gzin);
492         }
493       }
494     }
495   }
496   delete [] buffer;
497 }
498
499 TEST_F(IoTest, ZlibIoInputAutodetect) {
500   const int kBufferSize = 2*1024;
501   uint8* buffer = new uint8[kBufferSize];
502   int size;
503   {
504     ArrayOutputStream output(buffer, kBufferSize);
505     GzipOutputStream::Options options;
506     options.format = GzipOutputStream::ZLIB;
507     GzipOutputStream gzout(&output, options);
508     WriteStuff(&gzout);
509     gzout.Close();
510     size = output.ByteCount();
511   }
512   {
513     ArrayInputStream input(buffer, size);
514     GzipInputStream gzin(&input, GzipInputStream::AUTO);
515     ReadStuff(&gzin);
516   }
517   {
518     ArrayOutputStream output(buffer, kBufferSize);
519     GzipOutputStream::Options options;
520     options.format = GzipOutputStream::GZIP;
521     GzipOutputStream gzout(&output, options);
522     WriteStuff(&gzout);
523     gzout.Close();
524     size = output.ByteCount();
525   }
526   {
527     ArrayInputStream input(buffer, size);
528     GzipInputStream gzin(&input, GzipInputStream::AUTO);
529     ReadStuff(&gzin);
530   }
531   delete [] buffer;
532 }
533
534 string IoTest::Compress(const string& data,
535                         const GzipOutputStream::Options& options) {
536   string result;
537   {
538     StringOutputStream output(&result);
539     GzipOutputStream gzout(&output, options);
540     WriteToOutput(&gzout, data.data(), data.size());
541   }
542   return result;
543 }
544
545 string IoTest::Uncompress(const string& data) {
546   string result;
547   {
548     ArrayInputStream input(data.data(), data.size());
549     GzipInputStream gzin(&input);
550     const void* buffer;
551     int size;
552     while (gzin.Next(&buffer, &size)) {
553       result.append(reinterpret_cast<const char*>(buffer), size);
554     }
555   }
556   return result;
557 }
558
559 TEST_F(IoTest, CompressionOptions) {
560   // Some ad-hoc testing of compression options.
561
562   string golden;
563   File::ReadFileToStringOrDie(
564     TestSourceDir() + "/google/protobuf/testdata/golden_message",
565     &golden);
566
567   GzipOutputStream::Options options;
568   string gzip_compressed = Compress(golden, options);
569
570   options.compression_level = 0;
571   string not_compressed = Compress(golden, options);
572
573   // Try zlib compression for fun.
574   options = GzipOutputStream::Options();
575   options.format = GzipOutputStream::ZLIB;
576   string zlib_compressed = Compress(golden, options);
577
578   // Uncompressed should be bigger than the original since it should have some
579   // sort of header.
580   EXPECT_GT(not_compressed.size(), golden.size());
581
582   // Higher compression levels should result in smaller sizes.
583   EXPECT_LT(zlib_compressed.size(), not_compressed.size());
584
585   // ZLIB format should differ from GZIP format.
586   EXPECT_TRUE(zlib_compressed != gzip_compressed);
587
588   // Everything should decompress correctly.
589   EXPECT_TRUE(Uncompress(not_compressed) == golden);
590   EXPECT_TRUE(Uncompress(gzip_compressed) == golden);
591   EXPECT_TRUE(Uncompress(zlib_compressed) == golden);
592 }
593
594 TEST_F(IoTest, TwoSessionWriteGzip) {
595   // Test that two concatenated gzip streams can be read correctly
596
597   static const char* strA = "0123456789";
598   static const char* strB = "QuickBrownFox";
599   const int kBufferSize = 2*1024;
600   uint8* buffer = new uint8[kBufferSize];
601   char* temp_buffer = new char[40];
602
603   for (int i = 0; i < kBlockSizeCount; i++) {
604     for (int j = 0; j < kBlockSizeCount; j++) {
605       ArrayOutputStream* output =
606           new ArrayOutputStream(buffer, kBufferSize, kBlockSizes[i]);
607       GzipOutputStream* gzout = new GzipOutputStream(output);
608       CodedOutputStream* coded_output = new CodedOutputStream(gzout);
609       int32 outlen = strlen(strA) + 1;
610       coded_output->WriteVarint32(outlen);
611       coded_output->WriteRaw(strA, outlen);
612       delete coded_output;  // flush
613       delete gzout;  // flush
614       int64 pos = output->ByteCount();
615       delete output;
616       output = new ArrayOutputStream(
617           buffer + pos, kBufferSize - pos, kBlockSizes[i]);
618       gzout = new GzipOutputStream(output);
619       coded_output = new CodedOutputStream(gzout);
620       outlen = strlen(strB) + 1;
621       coded_output->WriteVarint32(outlen);
622       coded_output->WriteRaw(strB, outlen);
623       delete coded_output;  // flush
624       delete gzout;  // flush
625       int64 size = pos + output->ByteCount();
626       delete output;
627
628       ArrayInputStream* input =
629           new ArrayInputStream(buffer, size, kBlockSizes[j]);
630       GzipInputStream* gzin = new GzipInputStream(input);
631       CodedInputStream* coded_input = new CodedInputStream(gzin);
632       uint32 insize;
633       EXPECT_TRUE(coded_input->ReadVarint32(&insize));
634       EXPECT_EQ(strlen(strA) + 1, insize);
635       EXPECT_TRUE(coded_input->ReadRaw(temp_buffer, insize));
636       EXPECT_EQ(0, memcmp(temp_buffer, strA, insize))
637           << "strA=" << strA << " in=" << temp_buffer;
638
639       EXPECT_TRUE(coded_input->ReadVarint32(&insize));
640       EXPECT_EQ(strlen(strB) + 1, insize);
641       EXPECT_TRUE(coded_input->ReadRaw(temp_buffer, insize));
642       EXPECT_EQ(0, memcmp(temp_buffer, strB, insize))
643           << " out_block_size=" << kBlockSizes[i]
644           << " in_block_size=" << kBlockSizes[j]
645           << " pos=" << pos
646           << " size=" << size
647           << " strB=" << strB << " in=" << temp_buffer;
648
649       delete coded_input;
650       delete gzin;
651       delete input;
652     }
653   }
654
655   delete [] temp_buffer;
656   delete [] buffer;
657 }
658 #endif
659
660 // There is no string input, only string output.  Also, it doesn't support
661 // explicit block sizes.  So, we'll only run one test and we'll use
662 // ArrayInput to read back the results.
663 TEST_F(IoTest, StringIo) {
664   string str;
665   {
666     StringOutputStream output(&str);
667     WriteStuff(&output);
668   }
669   {
670     ArrayInputStream input(str.data(), str.size());
671     ReadStuff(&input);
672   }
673 }
674
675
676 // To test files, we create a temporary file, write, read, truncate, repeat.
677 TEST_F(IoTest, FileIo) {
678   string filename = TestTempDir() + "/zero_copy_stream_test_file";
679
680   for (int i = 0; i < kBlockSizeCount; i++) {
681     for (int j = 0; j < kBlockSizeCount; j++) {
682       // Make a temporary file.
683       int file =
684         open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0777);
685       ASSERT_GE(file, 0);
686
687       {
688         FileOutputStream output(file, kBlockSizes[i]);
689         WriteStuff(&output);
690         EXPECT_EQ(0, output.GetErrno());
691       }
692
693       // Rewind.
694       ASSERT_NE(lseek(file, 0, SEEK_SET), (off_t)-1);
695
696       {
697         FileInputStream input(file, kBlockSizes[j]);
698         ReadStuff(&input);
699         EXPECT_EQ(0, input.GetErrno());
700       }
701
702       close(file);
703     }
704   }
705 }
706
707 #if HAVE_ZLIB
708 TEST_F(IoTest, GzipFileIo) {
709   string filename = TestTempDir() + "/zero_copy_stream_test_file";
710
711   for (int i = 0; i < kBlockSizeCount; i++) {
712     for (int j = 0; j < kBlockSizeCount; j++) {
713       // Make a temporary file.
714       int file =
715         open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0777);
716       ASSERT_GE(file, 0);
717       {
718         FileOutputStream output(file, kBlockSizes[i]);
719         GzipOutputStream gzout(&output);
720         WriteStuffLarge(&gzout);
721         gzout.Close();
722         output.Flush();
723         EXPECT_EQ(0, output.GetErrno());
724       }
725
726       // Rewind.
727       ASSERT_NE(lseek(file, 0, SEEK_SET), (off_t)-1);
728
729       {
730         FileInputStream input(file, kBlockSizes[j]);
731         GzipInputStream gzin(&input);
732         ReadStuffLarge(&gzin);
733         EXPECT_EQ(0, input.GetErrno());
734       }
735
736       close(file);
737     }
738   }
739 }
740 #endif
741
742 // MSVC raises various debugging exceptions if we try to use a file
743 // descriptor of -1, defeating our tests below.  This class will disable
744 // these debug assertions while in scope.
745 class MsvcDebugDisabler {
746  public:
747 #if defined(_MSC_VER) && _MSC_VER >= 1400
748   MsvcDebugDisabler() {
749     old_handler_ = _set_invalid_parameter_handler(MyHandler);
750     old_mode_ = _CrtSetReportMode(_CRT_ASSERT, 0);
751   }
752   ~MsvcDebugDisabler() {
753     old_handler_ = _set_invalid_parameter_handler(old_handler_);
754     old_mode_ = _CrtSetReportMode(_CRT_ASSERT, old_mode_);
755   }
756
757   static void MyHandler(const wchar_t *expr,
758                         const wchar_t *func,
759                         const wchar_t *file,
760                         unsigned int line,
761                         uintptr_t pReserved) {
762     // do nothing
763   }
764
765   _invalid_parameter_handler old_handler_;
766   int old_mode_;
767 #else
768   // Dummy constructor and destructor to ensure that GCC doesn't complain
769   // that debug_disabler is an unused variable.
770   MsvcDebugDisabler() {}
771   ~MsvcDebugDisabler() {}
772 #endif
773 };
774
775 // Test that FileInputStreams report errors correctly.
776 TEST_F(IoTest, FileReadError) {
777   MsvcDebugDisabler debug_disabler;
778
779   // -1 = invalid file descriptor.
780   FileInputStream input(-1);
781
782   const void* buffer;
783   int size;
784   EXPECT_FALSE(input.Next(&buffer, &size));
785   EXPECT_EQ(EBADF, input.GetErrno());
786 }
787
788 // Test that FileOutputStreams report errors correctly.
789 TEST_F(IoTest, FileWriteError) {
790   MsvcDebugDisabler debug_disabler;
791
792   // -1 = invalid file descriptor.
793   FileOutputStream input(-1);
794
795   void* buffer;
796   int size;
797
798   // The first call to Next() succeeds because it doesn't have anything to
799   // write yet.
800   EXPECT_TRUE(input.Next(&buffer, &size));
801
802   // Second call fails.
803   EXPECT_FALSE(input.Next(&buffer, &size));
804
805   EXPECT_EQ(EBADF, input.GetErrno());
806 }
807
808 // Pipes are not seekable, so File{Input,Output}Stream ends up doing some
809 // different things to handle them.  We'll test by writing to a pipe and
810 // reading back from it.
811 TEST_F(IoTest, PipeIo) {
812   int files[2];
813
814   for (int i = 0; i < kBlockSizeCount; i++) {
815     for (int j = 0; j < kBlockSizeCount; j++) {
816       // Need to create a new pipe each time because ReadStuff() expects
817       // to see EOF at the end.
818       ASSERT_EQ(pipe(files), 0);
819
820       {
821         FileOutputStream output(files[1], kBlockSizes[i]);
822         WriteStuff(&output);
823         EXPECT_EQ(0, output.GetErrno());
824       }
825       close(files[1]);  // Send EOF.
826
827       {
828         FileInputStream input(files[0], kBlockSizes[j]);
829         ReadStuff(&input);
830         EXPECT_EQ(0, input.GetErrno());
831       }
832       close(files[0]);
833     }
834   }
835 }
836
837 // Test using C++ iostreams.
838 TEST_F(IoTest, IostreamIo) {
839   for (int i = 0; i < kBlockSizeCount; i++) {
840     for (int j = 0; j < kBlockSizeCount; j++) {
841       {
842         stringstream stream;
843
844         {
845           OstreamOutputStream output(&stream, kBlockSizes[i]);
846           WriteStuff(&output);
847           EXPECT_FALSE(stream.fail());
848         }
849
850         {
851           IstreamInputStream input(&stream, kBlockSizes[j]);
852           ReadStuff(&input);
853           EXPECT_TRUE(stream.eof());
854         }
855       }
856
857       {
858         stringstream stream;
859
860         {
861           OstreamOutputStream output(&stream, kBlockSizes[i]);
862           WriteStuffLarge(&output);
863           EXPECT_FALSE(stream.fail());
864         }
865
866         {
867           IstreamInputStream input(&stream, kBlockSizes[j]);
868           ReadStuffLarge(&input);
869           EXPECT_TRUE(stream.eof());
870         }
871       }
872     }
873   }
874 }
875
876 // To test ConcatenatingInputStream, we create several ArrayInputStreams
877 // covering a buffer and then concatenate them.
878 TEST_F(IoTest, ConcatenatingInputStream) {
879   const int kBufferSize = 256;
880   uint8 buffer[kBufferSize];
881
882   // Fill the buffer.
883   ArrayOutputStream output(buffer, kBufferSize);
884   WriteStuff(&output);
885
886   // Now split it up into multiple streams of varying sizes.
887   ASSERT_EQ(68, output.ByteCount());  // Test depends on this.
888   ArrayInputStream input1(buffer     , 12);
889   ArrayInputStream input2(buffer + 12,  7);
890   ArrayInputStream input3(buffer + 19,  6);
891   ArrayInputStream input4(buffer + 25, 15);
892   ArrayInputStream input5(buffer + 40,  0);
893   // Note:  We want to make sure we have a stream boundary somewhere between
894   // bytes 42 and 62, which is the range that it Skip()ed by ReadStuff().  This
895   // tests that a bug that existed in the original code for Skip() is fixed.
896   ArrayInputStream input6(buffer + 40, 10);
897   ArrayInputStream input7(buffer + 50, 18);  // Total = 68 bytes.
898
899   ZeroCopyInputStream* streams[] =
900     {&input1, &input2, &input3, &input4, &input5, &input6, &input7};
901
902   // Create the concatenating stream and read.
903   ConcatenatingInputStream input(streams, GOOGLE_ARRAYSIZE(streams));
904   ReadStuff(&input);
905 }
906
907 // To test LimitingInputStream, we write our golden text to a buffer, then
908 // create an ArrayInputStream that contains the whole buffer (not just the
909 // bytes written), then use a LimitingInputStream to limit it just to the
910 // bytes written.
911 TEST_F(IoTest, LimitingInputStream) {
912   const int kBufferSize = 256;
913   uint8 buffer[kBufferSize];
914
915   // Fill the buffer.
916   ArrayOutputStream output(buffer, kBufferSize);
917   WriteStuff(&output);
918
919   // Set up input.
920   ArrayInputStream array_input(buffer, kBufferSize);
921   LimitingInputStream input(&array_input, output.ByteCount());
922
923   ReadStuff(&input);
924 }
925
926 // Check that a zero-size array doesn't confuse the code.
927 TEST(ZeroSizeArray, Input) {
928   ArrayInputStream input(NULL, 0);
929   const void* data;
930   int size;
931   EXPECT_FALSE(input.Next(&data, &size));
932 }
933
934 TEST(ZeroSizeArray, Output) {
935   ArrayOutputStream output(NULL, 0);
936   void* data;
937   int size;
938   EXPECT_FALSE(output.Next(&data, &size));
939 }
940
941 }  // namespace
942 }  // namespace io
943 }  // namespace protobuf
944 }  // namespace google