zero_copy_stream_unittest.cc 31 KB

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