1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google Inc. nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 // Various stubs for the unit tests for the open-source version of Snappy.
30 
31 #ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_
32 #define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_
33 
34 #include <iostream>
35 #include <string>
36 
37 #include "snappy-stubs-internal.h"
38 
39 #include <stdio.h>
40 #include <stdarg.h>
41 
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45 
46 #ifdef HAVE_SYS_RESOURCE_H
47 #include <sys/resource.h>
48 #endif
49 
50 #ifdef HAVE_SYS_TIME_H
51 #include <sys/time.h>
52 #endif
53 
54 #ifdef HAVE_WINDOWS_H
55 #include <windows.h>
56 #endif
57 
58 #ifdef HAVE_GTEST
59 
60 #include <gtest/gtest.h>
61 #undef TYPED_TEST
62 #define TYPED_TEST TEST
63 #define INIT_GTEST(argc, argv) ::testing::InitGoogleTest(argc, *argv)
64 
65 #else
66 
67 // Stubs for if the user doesn't have Google Test installed.
68 
69 #define TEST(test_case, test_subcase) \
70   void Test_ ## test_case ## _ ## test_subcase()
71 #define INIT_GTEST(argc, argv)
72 
73 #define TYPED_TEST TEST
74 #define EXPECT_EQ CHECK_EQ
75 #define EXPECT_NE CHECK_NE
76 #define EXPECT_FALSE(cond) CHECK(!(cond))
77 
78 #endif
79 
80 #ifdef HAVE_GFLAGS
81 
82 #include <gflags/gflags.h>
83 
84 // This is tricky; both gflags and Google Test want to look at the command line
85 // arguments. Google Test seems to be the most happy with unknown arguments,
86 // though, so we call it first and hope for the best.
87 #define InitGoogle(argv0, argc, argv, remove_flags) \
88   INIT_GTEST(argc, argv); \
89   google::ParseCommandLineFlags(argc, argv, remove_flags);
90 
91 #else
92 
93 // If we don't have the gflags package installed, these can only be
94 // changed at compile time.
95 #define DEFINE_int32(flag_name, default_value, description) \
96   static int FLAGS_ ## flag_name = default_value;
97 
98 #define InitGoogle(argv0, argc, argv, remove_flags) \
99   INIT_GTEST(argc, argv)
100 
101 #endif
102 
103 #ifdef HAVE_LIBZ
104 #include "zlib.h"
105 #endif
106 
107 #ifdef HAVE_LIBLZO2
108 #include "lzo/lzo1x.h"
109 #endif
110 
111 namespace {
112 
113 namespace file {
Defaults()114   int Defaults() { return 0; }
115 
116   class DummyStatus {
117    public:
CheckSuccess()118     void CheckSuccess() { }
119   };
120 
GetContents(const std::string & filename,std::string * data,int unused)121   DummyStatus GetContents(
122       const std::string& filename, std::string* data, int unused) {
123     FILE* fp = fopen(filename.c_str(), "rb");
124     if (fp == NULL) {
125       perror(filename.c_str());
126       exit(1);
127     }
128 
129     data->clear();
130     while (!feof(fp)) {
131       char buf[4096];
132       size_t ret = fread(buf, 1, 4096, fp);
133       if (ret == 0 && ferror(fp)) {
134         perror("fread");
135         exit(1);
136       }
137       data->append(std::string(buf, ret));
138     }
139 
140     fclose(fp);
141 
142     return DummyStatus();
143   }
144 
SetContents(const std::string & filename,const std::string & str,int unused)145   inline DummyStatus SetContents(
146       const std::string& filename, const std::string& str, int unused) {
147     FILE* fp = fopen(filename.c_str(), "wb");
148     if (fp == NULL) {
149       perror(filename.c_str());
150       exit(1);
151     }
152 
153     int ret = fwrite(str.data(), str.size(), 1, fp);
154     if (ret != 1) {
155       perror("fwrite");
156       exit(1);
157     }
158 
159     fclose(fp);
160 
161     return DummyStatus();
162   }
163 }  // namespace file
164 
165 }  // namespace
166 
167 namespace snappy {
168 
169 #define FLAGS_test_random_seed 301
170 using TypeParam = std::string;
171 
172 void Test_CorruptedTest_VerifyCorrupted();
173 void Test_Snappy_SimpleTests();
174 void Test_Snappy_MaxBlowup();
175 void Test_Snappy_RandomData();
176 void Test_Snappy_FourByteOffset();
177 void Test_SnappyCorruption_TruncatedVarint();
178 void Test_SnappyCorruption_UnterminatedVarint();
179 void Test_SnappyCorruption_OverflowingVarint();
180 void Test_Snappy_ReadPastEndOfBuffer();
181 void Test_Snappy_FindMatchLength();
182 void Test_Snappy_FindMatchLengthRandom();
183 
184 std::string ReadTestDataFile(const std::string& base, size_t size_limit);
185 
186 std::string ReadTestDataFile(const std::string& base);
187 
188 // A sprintf() variant that returns a std::string.
189 // Not safe for general use due to truncation issues.
190 std::string StrFormat(const char* format, ...);
191 
192 // A wall-time clock. This stub is not super-accurate, nor resistant to the
193 // system time changing.
194 class CycleTimer {
195  public:
CycleTimer()196   CycleTimer() : real_time_us_(0) {}
197 
Start()198   void Start() {
199 #ifdef WIN32
200     QueryPerformanceCounter(&start_);
201 #else
202     gettimeofday(&start_, NULL);
203 #endif
204   }
205 
Stop()206   void Stop() {
207 #ifdef WIN32
208     LARGE_INTEGER stop;
209     LARGE_INTEGER frequency;
210     QueryPerformanceCounter(&stop);
211     QueryPerformanceFrequency(&frequency);
212 
213     double elapsed = static_cast<double>(stop.QuadPart - start_.QuadPart) /
214         frequency.QuadPart;
215     real_time_us_ += elapsed * 1e6 + 0.5;
216 #else
217     struct timeval stop;
218     gettimeofday(&stop, NULL);
219 
220     real_time_us_ += 1000000 * (stop.tv_sec - start_.tv_sec);
221     real_time_us_ += (stop.tv_usec - start_.tv_usec);
222 #endif
223   }
224 
Get()225   double Get() {
226     return real_time_us_ * 1e-6;
227   }
228 
229  private:
230   int64 real_time_us_;
231 #ifdef WIN32
232   LARGE_INTEGER start_;
233 #else
234   struct timeval start_;
235 #endif
236 };
237 
238 // Minimalistic microbenchmark framework.
239 
240 typedef void (*BenchmarkFunction)(int, int);
241 
242 class Benchmark {
243  public:
Benchmark(const std::string & name,BenchmarkFunction function)244   Benchmark(const std::string& name, BenchmarkFunction function)
245       : name_(name), function_(function) {}
246 
DenseRange(int start,int stop)247   Benchmark* DenseRange(int start, int stop) {
248     start_ = start;
249     stop_ = stop;
250     return this;
251   }
252 
253   void Run();
254 
255  private:
256   const std::string name_;
257   const BenchmarkFunction function_;
258   int start_, stop_;
259 };
260 #define BENCHMARK(benchmark_name) \
261   Benchmark* Benchmark_ ## benchmark_name = \
262           (new Benchmark(#benchmark_name, benchmark_name))
263 
264 extern Benchmark* Benchmark_BM_UFlat;
265 extern Benchmark* Benchmark_BM_UIOVec;
266 extern Benchmark* Benchmark_BM_UValidate;
267 extern Benchmark* Benchmark_BM_ZFlat;
268 extern Benchmark* Benchmark_BM_ZFlatAll;
269 extern Benchmark* Benchmark_BM_ZFlatIncreasingTableSize;
270 
271 void ResetBenchmarkTiming();
272 void StartBenchmarkTiming();
273 void StopBenchmarkTiming();
274 void SetBenchmarkLabel(const std::string& str);
275 void SetBenchmarkBytesProcessed(int64 bytes);
276 
277 #ifdef HAVE_LIBZ
278 
279 // Object-oriented wrapper around zlib.
280 class ZLib {
281  public:
282   ZLib();
283   ~ZLib();
284 
285   // Wipe a ZLib object to a virgin state.  This differs from Reset()
286   // in that it also breaks any state.
287   void Reinit();
288 
289   // Call this to make a zlib buffer as good as new.  Here's the only
290   // case where they differ:
291   //    CompressChunk(a); CompressChunk(b); CompressChunkDone();   vs
292   //    CompressChunk(a); Reset(); CompressChunk(b); CompressChunkDone();
293   // You'll want to use Reset(), then, when you interrupt a compress
294   // (or uncompress) in the middle of a chunk and want to start over.
295   void Reset();
296 
297   // According to the zlib manual, when you Compress, the destination
298   // buffer must have size at least src + .1%*src + 12.  This function
299   // helps you calculate that.  Augment this to account for a potential
300   // gzip header and footer, plus a few bytes of slack.
MinCompressbufSize(int uncompress_size)301   static int MinCompressbufSize(int uncompress_size) {
302     return uncompress_size + uncompress_size/1000 + 40;
303   }
304 
305   // Compresses the source buffer into the destination buffer.
306   // sourceLen is the byte length of the source buffer.
307   // Upon entry, destLen is the total size of the destination buffer,
308   // which must be of size at least MinCompressbufSize(sourceLen).
309   // Upon exit, destLen is the actual size of the compressed buffer.
310   //
311   // This function can be used to compress a whole file at once if the
312   // input file is mmap'ed.
313   //
314   // Returns Z_OK if success, Z_MEM_ERROR if there was not
315   // enough memory, Z_BUF_ERROR if there was not enough room in the
316   // output buffer. Note that if the output buffer is exactly the same
317   // size as the compressed result, we still return Z_BUF_ERROR.
318   // (check CL#1936076)
319   int Compress(Bytef *dest, uLongf *destLen,
320                const Bytef *source, uLong sourceLen);
321 
322   // Uncompresses the source buffer into the destination buffer.
323   // The destination buffer must be long enough to hold the entire
324   // decompressed contents.
325   //
326   // Returns Z_OK on success, otherwise, it returns a zlib error code.
327   int Uncompress(Bytef *dest, uLongf *destLen,
328                  const Bytef *source, uLong sourceLen);
329 
330   // Uncompress data one chunk at a time -- ie you can call this
331   // more than once.  To get this to work you need to call per-chunk
332   // and "done" routines.
333   //
334   // Returns Z_OK if success, Z_MEM_ERROR if there was not
335   // enough memory, Z_BUF_ERROR if there was not enough room in the
336   // output buffer.
337 
338   int UncompressAtMost(Bytef *dest, uLongf *destLen,
339                        const Bytef *source, uLong *sourceLen);
340 
341   // Checks gzip footer information, as needed.  Mostly this just
342   // makes sure the checksums match.  Whenever you call this, it
343   // will assume the last 8 bytes from the previous UncompressChunk
344   // call are the footer.  Returns true iff everything looks ok.
345   bool UncompressChunkDone();
346 
347  private:
348   int InflateInit();       // sets up the zlib inflate structure
349   int DeflateInit();       // sets up the zlib deflate structure
350 
351   // These init the zlib data structures for compressing/uncompressing
352   int CompressInit(Bytef *dest, uLongf *destLen,
353                    const Bytef *source, uLong *sourceLen);
354   int UncompressInit(Bytef *dest, uLongf *destLen,
355                      const Bytef *source, uLong *sourceLen);
356   // Initialization method to be called if we hit an error while
357   // uncompressing. On hitting an error, call this method before
358   // returning the error.
359   void UncompressErrorInit();
360 
361   // Helper function for Compress
362   int CompressChunkOrAll(Bytef *dest, uLongf *destLen,
363                          const Bytef *source, uLong sourceLen,
364                          int flush_mode);
365   int CompressAtMostOrAll(Bytef *dest, uLongf *destLen,
366                           const Bytef *source, uLong *sourceLen,
367                           int flush_mode);
368 
369   // Likewise for UncompressAndUncompressChunk
370   int UncompressChunkOrAll(Bytef *dest, uLongf *destLen,
371                            const Bytef *source, uLong sourceLen,
372                            int flush_mode);
373 
374   int UncompressAtMostOrAll(Bytef *dest, uLongf *destLen,
375                             const Bytef *source, uLong *sourceLen,
376                             int flush_mode);
377 
378   // Initialization method to be called if we hit an error while
379   // compressing. On hitting an error, call this method before
380   // returning the error.
381   void CompressErrorInit();
382 
383   int compression_level_;   // compression level
384   int window_bits_;         // log base 2 of the window size used in compression
385   int mem_level_;           // specifies the amount of memory to be used by
386                             // compressor (1-9)
387   z_stream comp_stream_;    // Zlib stream data structure
388   bool comp_init_;          // True if we have initialized comp_stream_
389   z_stream uncomp_stream_;  // Zlib stream data structure
390   bool uncomp_init_;        // True if we have initialized uncomp_stream_
391 
392   // These are used only with chunked compression.
393   bool first_chunk_;       // true if we need to emit headers with this chunk
394 };
395 
396 #endif  // HAVE_LIBZ
397 
398 }  // namespace snappy
399 
400 DECLARE_bool(run_microbenchmarks);
401 
RunSpecifiedBenchmarks()402 static inline void RunSpecifiedBenchmarks() {
403   if (!FLAGS_run_microbenchmarks) {
404     return;
405   }
406 
407   fprintf(stderr, "Running microbenchmarks.\n");
408 #ifndef NDEBUG
409   fprintf(stderr, "WARNING: Compiled with assertions enabled, will be slow.\n");
410 #endif
411 #ifndef __OPTIMIZE__
412   fprintf(stderr, "WARNING: Compiled without optimization, will be slow.\n");
413 #endif
414   fprintf(stderr, "Benchmark            Time(ns)    CPU(ns) Iterations\n");
415   fprintf(stderr, "---------------------------------------------------\n");
416 
417   snappy::Benchmark_BM_UFlat->Run();
418   snappy::Benchmark_BM_UIOVec->Run();
419   snappy::Benchmark_BM_UValidate->Run();
420   snappy::Benchmark_BM_ZFlat->Run();
421   snappy::Benchmark_BM_ZFlatAll->Run();
422   snappy::Benchmark_BM_ZFlatIncreasingTableSize->Run();
423 
424   fprintf(stderr, "\n");
425 }
426 
427 #ifndef HAVE_GTEST
428 
RUN_ALL_TESTS()429 static inline int RUN_ALL_TESTS() {
430   fprintf(stderr, "Running correctness tests.\n");
431   snappy::Test_CorruptedTest_VerifyCorrupted();
432   snappy::Test_Snappy_SimpleTests();
433   snappy::Test_Snappy_MaxBlowup();
434   snappy::Test_Snappy_RandomData();
435   snappy::Test_Snappy_FourByteOffset();
436   snappy::Test_SnappyCorruption_TruncatedVarint();
437   snappy::Test_SnappyCorruption_UnterminatedVarint();
438   snappy::Test_SnappyCorruption_OverflowingVarint();
439   snappy::Test_Snappy_ReadPastEndOfBuffer();
440   snappy::Test_Snappy_FindMatchLength();
441   snappy::Test_Snappy_FindMatchLengthRandom();
442   fprintf(stderr, "All tests passed.\n");
443 
444   return 0;
445 }
446 
447 #endif  // HAVE_GTEST
448 
449 // For main().
450 namespace snappy {
451 
452 // Logging.
453 
454 #define LOG(level) LogMessage()
455 #define VLOG(level) true ? (void)0 : \
456     snappy::LogMessageVoidify() & snappy::LogMessage()
457 
458 class LogMessage {
459  public:
LogMessage()460   LogMessage() { }
~LogMessage()461   ~LogMessage() {
462     std::cerr << std::endl;
463   }
464 
465   LogMessage& operator<<(const std::string& msg) {
466     std::cerr << msg;
467     return *this;
468   }
469   LogMessage& operator<<(int x) {
470     std::cerr << x;
471     return *this;
472   }
473 };
474 
475 // Asserts, both versions activated in debug mode only,
476 // and ones that are always active.
477 
478 #define CRASH_UNLESS(condition) \
479     SNAPPY_PREDICT_TRUE(condition) ? (void)0 : \
480     snappy::LogMessageVoidify() & snappy::LogMessageCrash()
481 
482 #ifdef _MSC_VER
483 // ~LogMessageCrash calls abort() and therefore never exits. This is by design
484 // so temporarily disable warning C4722.
485 #pragma warning(push)
486 #pragma warning(disable:4722)
487 #endif
488 
489 class LogMessageCrash : public LogMessage {
490  public:
LogMessageCrash()491   LogMessageCrash() { }
~LogMessageCrash()492   ~LogMessageCrash() {
493     std::cerr << std::endl;
494     abort();
495   }
496 };
497 
498 #ifdef _MSC_VER
499 #pragma warning(pop)
500 #endif
501 
502 // This class is used to explicitly ignore values in the conditional
503 // logging macros.  This avoids compiler warnings like "value computed
504 // is not used" and "statement has no effect".
505 
506 class LogMessageVoidify {
507  public:
LogMessageVoidify()508   LogMessageVoidify() { }
509   // This has to be an operator with a precedence lower than << but
510   // higher than ?:
511   void operator&(const LogMessage&) { }
512 };
513 
514 #define CHECK(cond) CRASH_UNLESS(cond)
515 #define CHECK_LE(a, b) CRASH_UNLESS((a) <= (b))
516 #define CHECK_GE(a, b) CRASH_UNLESS((a) >= (b))
517 #define CHECK_EQ(a, b) CRASH_UNLESS((a) == (b))
518 #define CHECK_NE(a, b) CRASH_UNLESS((a) != (b))
519 #define CHECK_LT(a, b) CRASH_UNLESS((a) < (b))
520 #define CHECK_GT(a, b) CRASH_UNLESS((a) > (b))
521 #define CHECK_OK(cond) (cond).CheckSuccess()
522 
523 }  // namespace snappy
524 
525 #endif  // THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_
526