1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
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
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.
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.
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
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
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
57 #include <sys/types.h>
63 #include <google/protobuf/io/zero_copy_stream_impl.h>
64 #include <google/protobuf/io/coded_stream.h>
67 #include <google/protobuf/io/gzip_stream.h>
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>
81 #define pipe(fds) _pipe(fds, 4096, O_BINARY)
86 #define O_BINARY _O_BINARY
88 #define O_BINARY 0 // If this isn't defined, the platform doesn't need it.
92 class IoTest : public testing::Test {
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
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);
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);
120 string Compress(const string& data, const GzipOutputStream::Options& options);
121 string Uncompress(const string& data);
124 static const int kBlockSizes[];
125 static const int kBlockSizeCount;
128 const int IoTest::kBlockSizes[] = {-1, 1, 2, 5, 7, 10, 23, 64};
129 const int IoTest::kBlockSizeCount = GOOGLE_ARRAYSIZE(IoTest::kBlockSizes);
131 bool IoTest::WriteToOutput(ZeroCopyOutputStream* output,
132 const void* data, int size) {
133 const uint8* in = reinterpret_cast<const uint8*>(data);
140 if (!output->Next(&out, &out_size)) {
143 EXPECT_GT(out_size, 0);
145 if (in_size <= out_size) {
146 memcpy(out, in, in_size);
147 output->BackUp(out_size - in_size);
151 memcpy(out, in, out_size);
157 #define MAX_REPEATED_ZEROS 100
159 int IoTest::ReadFromInput(ZeroCopyInputStream* input, void* data, int size) {
160 uint8* out = reinterpret_cast<uint8*>(data);
166 int repeated_zeros = 0;
169 if (!input->Next(&in, &in_size)) {
170 return size - out_size;
172 EXPECT_GT(in_size, -1);
178 EXPECT_LT(repeated_zeros, MAX_REPEATED_ZEROS);
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);
185 return size; // Copied all of it.
188 memcpy(out, in, in_size);
194 void IoTest::WriteString(ZeroCopyOutputStream* output, const string& str) {
195 EXPECT_TRUE(WriteToOutput(output, str.c_str(), str.size()));
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());
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");
213 EXPECT_EQ(output->ByteCount(), 68);
215 int result = output->ByteCount();
219 // Reads text from an input stream and expects it to match what WriteStuff()
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");
231 EXPECT_EQ(input->ByteCount(), 68);
234 EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
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");
245 EXPECT_EQ(output->ByteCount(), 200055);
247 int result = output->ByteCount();
251 // Reads text from an input stream and expects it to match what WriteStuff()
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");
262 EXPECT_EQ(input->ByteCount(), 200055);
265 EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
268 // ===================================================================
270 TEST_F(IoTest, ArrayIo) {
271 const int kBufferSize = 256;
272 uint8 buffer[kBufferSize];
274 for (int i = 0; i < kBlockSizeCount; i++) {
275 for (int j = 0; j < kBlockSizeCount; j++) {
278 ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
279 size = WriteStuff(&output);
282 ArrayInputStream input(buffer, size, kBlockSizes[j]);
289 TEST_F(IoTest, TwoSessionWrite) {
290 // Test that two concatenated write sessions read correctly
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];
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();
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();
317 ArrayInputStream* input =
318 new ArrayInputStream(buffer, size, kBlockSizes[j]);
319 CodedInputStream* coded_input = new CodedInputStream(input);
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));
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));
336 delete [] temp_buffer;
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];
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;
356 GzipOutputStream gzout(&output, options);
359 size = output.ByteCount();
362 ArrayInputStream input(buffer, size, kBlockSizes[j]);
363 GzipInputStream gzin(
364 &input, GzipInputStream::GZIP, gzip_buffer_size);
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];
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;
391 GzipOutputStream gzout(&output, options);
393 EXPECT_TRUE(gzout.Flush());
395 size = output.ByteCount();
398 ArrayInputStream input(buffer, size, kBlockSizes[j]);
399 GzipInputStream gzin(
400 &input, GzipInputStream::GZIP, gzip_buffer_size);
409 TEST_F(IoTest, GzipIoContiguousFlushes) {
410 const int kBufferSize = 2*1024;
411 uint8* buffer = new uint8[kBufferSize];
413 int block_size = kBlockSizes[4];
414 int gzip_buffer_size = block_size;
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;
423 GzipOutputStream gzout(&output, options);
425 EXPECT_TRUE(gzout.Flush());
426 EXPECT_TRUE(gzout.Flush());
428 size = output.ByteCount();
430 ArrayInputStream input(buffer, size, block_size);
431 GzipInputStream gzin(
432 &input, GzipInputStream::GZIP, gzip_buffer_size);
438 TEST_F(IoTest, GzipIoReadAfterFlush) {
439 const int kBufferSize = 2*1024;
440 uint8* buffer = new uint8[kBufferSize];
442 int block_size = kBlockSizes[4];
443 int gzip_buffer_size = block_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;
452 GzipOutputStream gzout(&output, options);
454 EXPECT_TRUE(gzout.Flush());
455 size = output.ByteCount();
457 ArrayInputStream input(buffer, size, block_size);
458 GzipInputStream gzin(
459 &input, GzipInputStream::GZIP, gzip_buffer_size);
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];
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;
482 GzipOutputStream gzout(&output, options);
485 size = output.ByteCount();
488 ArrayInputStream input(buffer, size, kBlockSizes[j]);
489 GzipInputStream gzin(
490 &input, GzipInputStream::ZLIB, gzip_buffer_size);
499 TEST_F(IoTest, ZlibIoInputAutodetect) {
500 const int kBufferSize = 2*1024;
501 uint8* buffer = new uint8[kBufferSize];
504 ArrayOutputStream output(buffer, kBufferSize);
505 GzipOutputStream::Options options;
506 options.format = GzipOutputStream::ZLIB;
507 GzipOutputStream gzout(&output, options);
510 size = output.ByteCount();
513 ArrayInputStream input(buffer, size);
514 GzipInputStream gzin(&input, GzipInputStream::AUTO);
518 ArrayOutputStream output(buffer, kBufferSize);
519 GzipOutputStream::Options options;
520 options.format = GzipOutputStream::GZIP;
521 GzipOutputStream gzout(&output, options);
524 size = output.ByteCount();
527 ArrayInputStream input(buffer, size);
528 GzipInputStream gzin(&input, GzipInputStream::AUTO);
534 string IoTest::Compress(const string& data,
535 const GzipOutputStream::Options& options) {
538 StringOutputStream output(&result);
539 GzipOutputStream gzout(&output, options);
540 WriteToOutput(&gzout, data.data(), data.size());
545 string IoTest::Uncompress(const string& data) {
548 ArrayInputStream input(data.data(), data.size());
549 GzipInputStream gzin(&input);
552 while (gzin.Next(&buffer, &size)) {
553 result.append(reinterpret_cast<const char*>(buffer), size);
559 TEST_F(IoTest, CompressionOptions) {
560 // Some ad-hoc testing of compression options.
563 File::ReadFileToStringOrDie(
564 TestSourceDir() + "/google/protobuf/testdata/golden_message",
567 GzipOutputStream::Options options;
568 string gzip_compressed = Compress(golden, options);
570 options.compression_level = 0;
571 string not_compressed = Compress(golden, options);
573 // Try zlib compression for fun.
574 options = GzipOutputStream::Options();
575 options.format = GzipOutputStream::ZLIB;
576 string zlib_compressed = Compress(golden, options);
578 // Uncompressed should be bigger than the original since it should have some
580 EXPECT_GT(not_compressed.size(), golden.size());
582 // Higher compression levels should result in smaller sizes.
583 EXPECT_LT(zlib_compressed.size(), not_compressed.size());
585 // ZLIB format should differ from GZIP format.
586 EXPECT_TRUE(zlib_compressed != gzip_compressed);
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);
594 TEST_F(IoTest, TwoSessionWriteGzip) {
595 // Test that two concatenated gzip streams can be read correctly
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];
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();
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();
628 ArrayInputStream* input =
629 new ArrayInputStream(buffer, size, kBlockSizes[j]);
630 GzipInputStream* gzin = new GzipInputStream(input);
631 CodedInputStream* coded_input = new CodedInputStream(gzin);
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;
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]
647 << " strB=" << strB << " in=" << temp_buffer;
655 delete [] temp_buffer;
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) {
666 StringOutputStream output(&str);
670 ArrayInputStream input(str.data(), str.size());
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";
680 for (int i = 0; i < kBlockSizeCount; i++) {
681 for (int j = 0; j < kBlockSizeCount; j++) {
682 // Make a temporary file.
684 open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0777);
688 FileOutputStream output(file, kBlockSizes[i]);
690 EXPECT_EQ(0, output.GetErrno());
694 ASSERT_NE(lseek(file, 0, SEEK_SET), (off_t)-1);
697 FileInputStream input(file, kBlockSizes[j]);
699 EXPECT_EQ(0, input.GetErrno());
708 TEST_F(IoTest, GzipFileIo) {
709 string filename = TestTempDir() + "/zero_copy_stream_test_file";
711 for (int i = 0; i < kBlockSizeCount; i++) {
712 for (int j = 0; j < kBlockSizeCount; j++) {
713 // Make a temporary file.
715 open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0777);
718 FileOutputStream output(file, kBlockSizes[i]);
719 GzipOutputStream gzout(&output);
720 WriteStuffLarge(&gzout);
723 EXPECT_EQ(0, output.GetErrno());
727 ASSERT_NE(lseek(file, 0, SEEK_SET), (off_t)-1);
730 FileInputStream input(file, kBlockSizes[j]);
731 GzipInputStream gzin(&input);
732 ReadStuffLarge(&gzin);
733 EXPECT_EQ(0, input.GetErrno());
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 {
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);
752 ~MsvcDebugDisabler() {
753 old_handler_ = _set_invalid_parameter_handler(old_handler_);
754 old_mode_ = _CrtSetReportMode(_CRT_ASSERT, old_mode_);
757 static void MyHandler(const wchar_t *expr,
761 uintptr_t pReserved) {
765 _invalid_parameter_handler old_handler_;
768 // Dummy constructor and destructor to ensure that GCC doesn't complain
769 // that debug_disabler is an unused variable.
770 MsvcDebugDisabler() {}
771 ~MsvcDebugDisabler() {}
775 // Test that FileInputStreams report errors correctly.
776 TEST_F(IoTest, FileReadError) {
777 MsvcDebugDisabler debug_disabler;
779 // -1 = invalid file descriptor.
780 FileInputStream input(-1);
784 EXPECT_FALSE(input.Next(&buffer, &size));
785 EXPECT_EQ(EBADF, input.GetErrno());
788 // Test that FileOutputStreams report errors correctly.
789 TEST_F(IoTest, FileWriteError) {
790 MsvcDebugDisabler debug_disabler;
792 // -1 = invalid file descriptor.
793 FileOutputStream input(-1);
798 // The first call to Next() succeeds because it doesn't have anything to
800 EXPECT_TRUE(input.Next(&buffer, &size));
802 // Second call fails.
803 EXPECT_FALSE(input.Next(&buffer, &size));
805 EXPECT_EQ(EBADF, input.GetErrno());
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) {
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);
821 FileOutputStream output(files[1], kBlockSizes[i]);
823 EXPECT_EQ(0, output.GetErrno());
825 close(files[1]); // Send EOF.
828 FileInputStream input(files[0], kBlockSizes[j]);
830 EXPECT_EQ(0, input.GetErrno());
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++) {
845 OstreamOutputStream output(&stream, kBlockSizes[i]);
847 EXPECT_FALSE(stream.fail());
851 IstreamInputStream input(&stream, kBlockSizes[j]);
853 EXPECT_TRUE(stream.eof());
861 OstreamOutputStream output(&stream, kBlockSizes[i]);
862 WriteStuffLarge(&output);
863 EXPECT_FALSE(stream.fail());
867 IstreamInputStream input(&stream, kBlockSizes[j]);
868 ReadStuffLarge(&input);
869 EXPECT_TRUE(stream.eof());
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];
883 ArrayOutputStream output(buffer, kBufferSize);
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.
899 ZeroCopyInputStream* streams[] =
900 {&input1, &input2, &input3, &input4, &input5, &input6, &input7};
902 // Create the concatenating stream and read.
903 ConcatenatingInputStream input(streams, GOOGLE_ARRAYSIZE(streams));
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
911 TEST_F(IoTest, LimitingInputStream) {
912 const int kBufferSize = 256;
913 uint8 buffer[kBufferSize];
916 ArrayOutputStream output(buffer, kBufferSize);
920 ArrayInputStream array_input(buffer, kBufferSize);
921 LimitingInputStream input(&array_input, output.ByteCount());
926 // Check that a zero-size array doesn't confuse the code.
927 TEST(ZeroSizeArray, Input) {
928 ArrayInputStream input(NULL, 0);
931 EXPECT_FALSE(input.Next(&data, &size));
934 TEST(ZeroSizeArray, Output) {
935 ArrayOutputStream output(NULL, 0);
938 EXPECT_FALSE(output.Next(&data, &size));
943 } // namespace protobuf
944 } // namespace google