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