]> git.cworth.org Git - apitrace/blob - thirdparty/snappy/snappy-test.h
649f26e7ac1fd2608aeb23f93bf7ab8101525829
[apitrace] / thirdparty / snappy / snappy-test.h
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 UTIL_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_
32 #define UTIL_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_
33
34 #include "snappy-stubs-internal.h"
35
36 #include <stdio.h>
37 #include <stdarg.h>
38
39 #ifdef HAVE_SYS_MMAN_H
40 #include <sys/mman.h>
41 #endif
42
43 #ifdef HAVE_SYS_RESOURCE_H
44 #include <sys/resource.h>
45 #endif
46
47 #include <sys/time.h>
48
49 #ifdef HAVE_WINDOWS_H
50 #define WIN32_LEAN_AND_MEAN
51 #include <windows.h>
52 #endif
53
54 #include <string>
55
56 #ifdef HAVE_GTEST
57
58 #include <gtest/gtest.h>
59 #undef TYPED_TEST
60 #define TYPED_TEST TEST
61 #define INIT_GTEST(argc, argv) ::testing::InitGoogleTest(argc, *argv)
62
63 #else
64
65 // Stubs for if the user doesn't have Google Test installed.
66
67 #define TEST(test_case, test_subcase) \
68   void Test_ ## test_case ## _ ## test_subcase()
69 #define INIT_GTEST(argc, argv)
70
71 #define TYPED_TEST TEST
72 #define EXPECT_EQ CHECK_EQ
73 #define EXPECT_NE CHECK_NE
74 #define EXPECT_FALSE(cond) CHECK(!(cond))
75
76 #endif
77
78 #ifdef HAVE_GFLAGS
79
80 #include <gflags/gflags.h>
81
82 // This is tricky; both gflags and Google Test want to look at the command line
83 // arguments. Google Test seems to be the most happy with unknown arguments,
84 // though, so we call it first and hope for the best.
85 #define InitGoogle(argv0, argc, argv, remove_flags) \
86   INIT_GTEST(argc, argv); \
87   google::ParseCommandLineFlags(argc, argv, remove_flags);
88
89 #else
90
91 // If we don't have the gflags package installed, these can only be
92 // changed at compile time.
93 #define DEFINE_int32(flag_name, default_value, description) \
94   static int FLAGS_ ## flag_name = default_value;
95
96 #define InitGoogle(argv0, argc, argv, remove_flags) \
97   INIT_GTEST(argc, argv)
98
99 #endif
100
101 #ifdef HAVE_LIBZ
102 #include "zlib.h"
103 #endif
104
105 #ifdef HAVE_LIBLZO2
106 #include "lzo/lzo1x.h"
107 #endif
108
109 #ifdef HAVE_LIBLZF
110 extern "C" {
111 #include "lzf.h"
112 }
113 #endif
114
115 #ifdef HAVE_LIBFASTLZ
116 #include "fastlz.h"
117 #endif
118
119 #ifdef HAVE_LIBQUICKLZ
120 #include "quicklz.h"
121 #endif
122
123 namespace {
124 namespace File {
125   void Init() { }
126
127   void ReadFileToStringOrDie(const char* filename, string* data) {
128     FILE* fp = fopen(filename, "rb");
129     if (fp == NULL) {
130       perror(filename);
131       exit(1);
132     }
133
134     data->clear();
135     while (!feof(fp)) {
136       char buf[4096];
137       size_t ret = fread(buf, 1, 4096, fp);
138       if (ret == -1) {
139         perror("fread");
140         exit(1);
141       }
142       data->append(string(buf, ret));
143     }
144
145     fclose(fp);
146   }
147
148   void ReadFileToStringOrDie(const string& filename, string* data) {
149     ReadFileToStringOrDie(filename.c_str(), data);
150   }
151
152   void WriteStringToFileOrDie(const string& str, const char* filename) {
153     FILE* fp = fopen(filename, "wb");
154     if (fp == NULL) {
155       perror(filename);
156       exit(1);
157     }
158
159     int ret = fwrite(str.data(), str.size(), 1, fp);
160     if (ret != 1) {
161       perror("fwrite");
162       exit(1);
163     }
164
165     fclose(fp);
166   }
167 }  // namespace File
168 }  // namespace
169
170 namespace snappy {
171
172 #define FLAGS_test_random_seed 301
173 typedef string TypeParam;
174
175 void Test_CorruptedTest_VerifyCorrupted();
176 void Test_Snappy_SimpleTests();
177 void Test_Snappy_MaxBlowup();
178 void Test_Snappy_RandomData();
179 void Test_Snappy_FourByteOffset();
180 void Test_SnappyCorruption_TruncatedVarint();
181 void Test_SnappyCorruption_UnterminatedVarint();
182 void Test_Snappy_ReadPastEndOfBuffer();
183 void Test_Snappy_FindMatchLength();
184 void Test_Snappy_FindMatchLengthRandom();
185
186 string ReadTestDataFile(const string& base);
187
188 // A sprintf() variant that returns a std::string.
189 // Not safe for general use due to truncation issues.
190 string StringPrintf(const char* format, ...);
191
192 // A simple, non-cryptographically-secure random generator.
193 class ACMRandom {
194  public:
195   explicit ACMRandom(uint32 seed) : seed_(seed) {}
196
197   int32 Next();
198
199   int32 Uniform(int32 n) {
200     return Next() % n;
201   }
202   uint8 Rand8() {
203     return static_cast<uint8>((Next() >> 1) & 0x000000ff);
204   }
205   bool OneIn(int X) { return Uniform(X) == 0; }
206
207   // Skewed: pick "base" uniformly from range [0,max_log] and then
208   // return "base" random bits.  The effect is to pick a number in the
209   // range [0,2^max_log-1] with bias towards smaller numbers.
210   int32 Skewed(int max_log);
211
212  private:
213   static const uint32 M = 2147483647L;   // 2^31-1
214   uint32 seed_;
215 };
216
217 inline int32 ACMRandom::Next() {
218   static const uint64 A = 16807;  // bits 14, 8, 7, 5, 2, 1, 0
219   // We are computing
220   //       seed_ = (seed_ * A) % M,    where M = 2^31-1
221   //
222   // seed_ must not be zero or M, or else all subsequent computed values
223   // will be zero or M respectively.  For all other values, seed_ will end
224   // up cycling through every number in [1,M-1]
225   uint64 product = seed_ * A;
226
227   // Compute (product % M) using the fact that ((x << 31) % M) == x.
228   seed_ = (product >> 31) + (product & M);
229   // The first reduction may overflow by 1 bit, so we may need to repeat.
230   // mod == M is not possible; using > allows the faster sign-bit-based test.
231   if (seed_ > M) {
232     seed_ -= M;
233   }
234   return seed_;
235 }
236
237 inline int32 ACMRandom::Skewed(int max_log) {
238   const int32 base = (Next() - 1) % (max_log+1);
239   return (Next() - 1) & ((1u << base)-1);
240 }
241
242 // A wall-time clock. This stub is not super-accurate, nor resistant to the
243 // system time changing.
244 class CycleTimer {
245  public:
246   CycleTimer() : real_time_us_(0) {}
247
248   void Start() {
249 #ifdef WIN32
250     QueryPerformanceCounter(&start_);
251 #else
252     gettimeofday(&start_, NULL);
253 #endif
254   }
255
256   void Stop() {
257 #ifdef WIN32
258     LARGE_INTEGER stop;
259     LARGE_INTEGER frequency;
260     QueryPerformanceCounter(&stop);
261     QueryPerformanceFrequency(&frequency);
262
263     double elapsed = static_cast<double>(stop.QuadPart - start_.QuadPart) /
264         frequency.QuadPart;
265     real_time_us_ += elapsed * 1e6 + 0.5;
266 #else
267     struct timeval stop;
268     gettimeofday(&stop, NULL);
269
270     real_time_us_ += 1000000 * (stop.tv_sec - start_.tv_sec);
271     real_time_us_ += (stop.tv_usec - start_.tv_usec);
272 #endif
273   }
274
275   double Get() {
276     return real_time_us_ * 1e-6;
277   }
278
279  private:
280   int64 real_time_us_;
281 #ifdef WIN32
282   LARGE_INTEGER start_;
283 #else
284   struct timeval start_;
285 #endif
286 };
287
288 // Minimalistic microbenchmark framework.
289
290 typedef void (*BenchmarkFunction)(int, int);
291
292 class Benchmark {
293  public:
294   Benchmark(const string& name, BenchmarkFunction function) :
295       name_(name), function_(function) {}
296
297   Benchmark* DenseRange(int start, int stop) {
298     start_ = start;
299     stop_ = stop;
300     return this;
301   }
302
303   void Run();
304
305  private:
306   const string name_;
307   const BenchmarkFunction function_;
308   int start_, stop_;
309 };
310 #define BENCHMARK(benchmark_name) \
311   Benchmark* Benchmark_ ## benchmark_name = \
312           (new Benchmark(#benchmark_name, benchmark_name))
313
314 extern Benchmark* Benchmark_BM_UFlat;
315 extern Benchmark* Benchmark_BM_UValidate;
316 extern Benchmark* Benchmark_BM_ZFlat;
317
318 void ResetBenchmarkTiming();
319 void StartBenchmarkTiming();
320 void StopBenchmarkTiming();
321 void SetBenchmarkLabel(const string& str);
322 void SetBenchmarkBytesProcessed(int64 bytes);
323
324 #ifdef HAVE_LIBZ
325
326 // Object-oriented wrapper around zlib.
327 class ZLib {
328  public:
329   ZLib();
330   ~ZLib();
331
332   // Wipe a ZLib object to a virgin state.  This differs from Reset()
333   // in that it also breaks any state.
334   void Reinit();
335
336   // Call this to make a zlib buffer as good as new.  Here's the only
337   // case where they differ:
338   //    CompressChunk(a); CompressChunk(b); CompressChunkDone();   vs
339   //    CompressChunk(a); Reset(); CompressChunk(b); CompressChunkDone();
340   // You'll want to use Reset(), then, when you interrupt a compress
341   // (or uncompress) in the middle of a chunk and want to start over.
342   void Reset();
343
344   // According to the zlib manual, when you Compress, the destination
345   // buffer must have size at least src + .1%*src + 12.  This function
346   // helps you calculate that.  Augment this to account for a potential
347   // gzip header and footer, plus a few bytes of slack.
348   static int MinCompressbufSize(int uncompress_size) {
349     return uncompress_size + uncompress_size/1000 + 40;
350   }
351
352   // Compresses the source buffer into the destination buffer.
353   // sourceLen is the byte length of the source buffer.
354   // Upon entry, destLen is the total size of the destination buffer,
355   // which must be of size at least MinCompressbufSize(sourceLen).
356   // Upon exit, destLen is the actual size of the compressed buffer.
357   //
358   // This function can be used to compress a whole file at once if the
359   // input file is mmap'ed.
360   //
361   // Returns Z_OK if success, Z_MEM_ERROR if there was not
362   // enough memory, Z_BUF_ERROR if there was not enough room in the
363   // output buffer. Note that if the output buffer is exactly the same
364   // size as the compressed result, we still return Z_BUF_ERROR.
365   // (check CL#1936076)
366   int Compress(Bytef *dest, uLongf *destLen,
367                const Bytef *source, uLong sourceLen);
368
369   // Uncompresses the source buffer into the destination buffer.
370   // The destination buffer must be long enough to hold the entire
371   // decompressed contents.
372   //
373   // Returns Z_OK on success, otherwise, it returns a zlib error code.
374   int Uncompress(Bytef *dest, uLongf *destLen,
375                  const Bytef *source, uLong sourceLen);
376
377   // Uncompress data one chunk at a time -- ie you can call this
378   // more than once.  To get this to work you need to call per-chunk
379   // and "done" routines.
380   //
381   // Returns Z_OK if success, Z_MEM_ERROR if there was not
382   // enough memory, Z_BUF_ERROR if there was not enough room in the
383   // output buffer.
384
385   int UncompressAtMost(Bytef *dest, uLongf *destLen,
386                        const Bytef *source, uLong *sourceLen);
387
388   // Checks gzip footer information, as needed.  Mostly this just
389   // makes sure the checksums match.  Whenever you call this, it
390   // will assume the last 8 bytes from the previous UncompressChunk
391   // call are the footer.  Returns true iff everything looks ok.
392   bool UncompressChunkDone();
393
394  private:
395   int InflateInit();       // sets up the zlib inflate structure
396   int DeflateInit();       // sets up the zlib deflate structure
397
398   // These init the zlib data structures for compressing/uncompressing
399   int CompressInit(Bytef *dest, uLongf *destLen,
400                    const Bytef *source, uLong *sourceLen);
401   int UncompressInit(Bytef *dest, uLongf *destLen,
402                      const Bytef *source, uLong *sourceLen);
403   // Initialization method to be called if we hit an error while
404   // uncompressing. On hitting an error, call this method before
405   // returning the error.
406   void UncompressErrorInit();
407
408   // Helper function for Compress
409   int CompressChunkOrAll(Bytef *dest, uLongf *destLen,
410                          const Bytef *source, uLong sourceLen,
411                          int flush_mode);
412   int CompressAtMostOrAll(Bytef *dest, uLongf *destLen,
413                           const Bytef *source, uLong *sourceLen,
414                           int flush_mode);
415
416   // Likewise for UncompressAndUncompressChunk
417   int UncompressChunkOrAll(Bytef *dest, uLongf *destLen,
418                            const Bytef *source, uLong sourceLen,
419                            int flush_mode);
420
421   int UncompressAtMostOrAll(Bytef *dest, uLongf *destLen,
422                             const Bytef *source, uLong *sourceLen,
423                             int flush_mode);
424
425   // Initialization method to be called if we hit an error while
426   // compressing. On hitting an error, call this method before
427   // returning the error.
428   void CompressErrorInit();
429
430   int compression_level_;   // compression level
431   int window_bits_;         // log base 2 of the window size used in compression
432   int mem_level_;           // specifies the amount of memory to be used by
433                             // compressor (1-9)
434   z_stream comp_stream_;    // Zlib stream data structure
435   bool comp_init_;          // True if we have initialized comp_stream_
436   z_stream uncomp_stream_;  // Zlib stream data structure
437   bool uncomp_init_;        // True if we have initialized uncomp_stream_
438
439   // These are used only with chunked compression.
440   bool first_chunk_;       // true if we need to emit headers with this chunk
441 };
442
443 #endif  // HAVE_LIBZ
444
445 }  // namespace snappy
446
447 DECLARE_bool(run_microbenchmarks);
448
449 static void RunSpecifiedBenchmarks() {
450   if (!FLAGS_run_microbenchmarks) {
451     return;
452   }
453
454   fprintf(stderr, "Running microbenchmarks.\n");
455 #ifndef NDEBUG
456   fprintf(stderr, "WARNING: Compiled with assertions enabled, will be slow.\n");
457 #endif
458 #ifndef __OPTIMIZE__
459   fprintf(stderr, "WARNING: Compiled without optimization, will be slow.\n");
460 #endif
461   fprintf(stderr, "Benchmark            Time(ns)    CPU(ns) Iterations\n");
462   fprintf(stderr, "---------------------------------------------------\n");
463
464   snappy::Benchmark_BM_UFlat->Run();
465   snappy::Benchmark_BM_UValidate->Run();
466   snappy::Benchmark_BM_ZFlat->Run();
467
468   fprintf(stderr, "\n");
469 }
470
471 #ifndef HAVE_GTEST
472
473 static inline int RUN_ALL_TESTS() {
474   fprintf(stderr, "Running correctness tests.\n");
475   snappy::Test_CorruptedTest_VerifyCorrupted();
476   snappy::Test_Snappy_SimpleTests();
477   snappy::Test_Snappy_MaxBlowup();
478   snappy::Test_Snappy_RandomData();
479   snappy::Test_Snappy_FourByteOffset();
480   snappy::Test_SnappyCorruption_TruncatedVarint();
481   snappy::Test_SnappyCorruption_UnterminatedVarint();
482   snappy::Test_Snappy_ReadPastEndOfBuffer();
483   snappy::Test_Snappy_FindMatchLength();
484   snappy::Test_Snappy_FindMatchLengthRandom();
485   fprintf(stderr, "All tests passed.\n");
486
487   return 0;
488 }
489
490 #endif  // HAVE_GTEST
491
492 // For main().
493 namespace snappy {
494
495 static void CompressFile(const char* fname);
496 static void UncompressFile(const char* fname);
497 static void MeasureFile(const char* fname);
498
499 }  // namespace
500
501 using snappy::CompressFile;
502 using snappy::UncompressFile;
503 using snappy::MeasureFile;
504
505 #endif  // UTIL_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_