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