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


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:07:02