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#if HAVE_CONFIG_H
35#include "config.h"
36#endif
37
38#include "snappy-stubs-internal.h"
39
40#if HAVE_SYS_MMAN_H
41#include <sys/mman.h>
42#endif
43
44#if HAVE_SYS_RESOURCE_H
45#include <sys/resource.h>
46#endif
47
48#if HAVE_SYS_TIME_H
49#include <sys/time.h>
50#endif
51
52#if HAVE_WINDOWS_H
53// Needed to be able to use std::max without workarounds in the source code.
54// https://support.microsoft.com/en-us/help/143208/prb-using-stl-in-windows-program-can-cause-min-max-conflicts
55#define NOMINMAX
56#include <windows.h>
57#endif
58
59#define InitGoogle(argv0, argc, argv, remove_flags) ((void)(0))
60
61#if HAVE_LIBZ
62#include "zlib.h"
63#endif
64
65#if HAVE_LIBLZO2
66#include "lzo/lzo1x.h"
67#endif
68
69#if HAVE_LIBLZ4
70#include "lz4.h"
71#endif
72
73namespace file {
74
75// Stubs the class file::Options.
76//
77// This class should not be instantiated explicitly. It should only be used by
78// passing file::Defaults() to file::GetContents() / file::SetContents().
79class OptionsStub {
80 public:
81 OptionsStub();
82 OptionsStub(const OptionsStub &) = delete;
83 OptionsStub &operator=(const OptionsStub &) = delete;
84 ~OptionsStub();
85};
86
87const OptionsStub &Defaults();
88
89// Stubs the class absl::Status.
90//
91// This class should not be instantiated explicitly. It should only be used by
92// passing the result of file::GetContents() / file::SetContents() to
93// CHECK_OK().
94class StatusStub {
95 public:
96 StatusStub();
97 StatusStub(const StatusStub &);
98 StatusStub &operator=(const StatusStub &);
99 ~StatusStub();
100
101 bool ok();
102};
103
104StatusStub GetContents(const std::string &file_name, std::string *output,
105 const OptionsStub & /* options */);
106
107StatusStub SetContents(const std::string &file_name, const std::string &content,
108 const OptionsStub & /* options */);
109
110} // namespace file
111
112namespace snappy {
113
114#define FLAGS_test_random_seed 301
115
116std::string ReadTestDataFile(const std::string& base, size_t size_limit);
117
118// A std::sprintf() variant that returns a std::string.
119// Not safe for general use due to truncation issues.
120std::string StrFormat(const char* format, ...);
121
122// A wall-time clock. This stub is not super-accurate, nor resistant to the
123// system time changing.
124class CycleTimer {
125 public:
126 inline CycleTimer() : real_time_us_(0) {}
127 inline ~CycleTimer() = default;
128
129 inline void Start() {
130#ifdef WIN32
131 QueryPerformanceCounter(&start_);
132#else
133 ::gettimeofday(&start_, nullptr);
134#endif
135 }
136
137 inline void Stop() {
138#ifdef WIN32
139 LARGE_INTEGER stop;
140 LARGE_INTEGER frequency;
141 QueryPerformanceCounter(&stop);
142 QueryPerformanceFrequency(&frequency);
143
144 double elapsed = static_cast<double>(stop.QuadPart - start_.QuadPart) /
145 frequency.QuadPart;
146 real_time_us_ += elapsed * 1e6 + 0.5;
147#else
148 struct ::timeval stop;
149 ::gettimeofday(&stop, nullptr);
150
151 real_time_us_ += 1000000 * (stop.tv_sec - start_.tv_sec);
152 real_time_us_ += (stop.tv_usec - start_.tv_usec);
153#endif
154 }
155
156 inline double Get() { return real_time_us_ * 1e-6; }
157
158 private:
159 int64_t real_time_us_;
160#ifdef WIN32
161 LARGE_INTEGER start_;
162#else
163 struct ::timeval start_;
164#endif
165};
166
167// Logging.
168
169class LogMessage {
170 public:
171 inline LogMessage() = default;
172 ~LogMessage();
173
174 LogMessage &operator<<(const std::string &message);
175 LogMessage &operator<<(int number);
176};
177
178class LogMessageCrash : public LogMessage {
179 public:
180 inline LogMessageCrash() = default;
181 ~LogMessageCrash();
182};
183
184// This class is used to explicitly ignore values in the conditional
185// logging macros. This avoids compiler warnings like "value computed
186// is not used" and "statement has no effect".
187
188class LogMessageVoidify {
189 public:
190 inline LogMessageVoidify() = default;
191 inline ~LogMessageVoidify() = default;
192
193 // This has to be an operator with a precedence lower than << but
194 // higher than ?:
195 inline void operator&(const LogMessage &) {}
196};
197
198// Asserts, both versions activated in debug mode only,
199// and ones that are always active.
200
201#define CRASH_UNLESS(condition) \
202 SNAPPY_PREDICT_TRUE(condition) \
203 ? (void)0 \
204 : snappy::LogMessageVoidify() & snappy::LogMessageCrash()
205
206#define LOG(level) LogMessage()
207#define VLOG(level) \
208 true ? (void)0 : snappy::LogMessageVoidify() & snappy::LogMessage()
209
210#define CHECK(cond) CRASH_UNLESS(cond)
211#define CHECK_LE(a, b) CRASH_UNLESS((a) <= (b))
212#define CHECK_GE(a, b) CRASH_UNLESS((a) >= (b))
213#define CHECK_EQ(a, b) CRASH_UNLESS((a) == (b))
214#define CHECK_NE(a, b) CRASH_UNLESS((a) != (b))
215#define CHECK_LT(a, b) CRASH_UNLESS((a) < (b))
216#define CHECK_GT(a, b) CRASH_UNLESS((a) > (b))
217#define CHECK_OK(cond) (cond).ok()
218
219#if HAVE_LIBZ
220
221// Object-oriented wrapper around zlib.
222class ZLib {
223 public:
224 ZLib();
225 ~ZLib();
226
227 // Wipe a ZLib object to a virgin state. This differs from Reset()
228 // in that it also breaks any state.
229 void Reinit();
230
231 // Call this to make a zlib buffer as good as new. Here's the only
232 // case where they differ:
233 // CompressChunk(a); CompressChunk(b); CompressChunkDone(); vs
234 // CompressChunk(a); Reset(); CompressChunk(b); CompressChunkDone();
235 // You'll want to use Reset(), then, when you interrupt a compress
236 // (or uncompress) in the middle of a chunk and want to start over.
237 void Reset();
238
239 // According to the zlib manual, when you Compress, the destination
240 // buffer must have size at least src + .1%*src + 12. This function
241 // helps you calculate that. Augment this to account for a potential
242 // gzip header and footer, plus a few bytes of slack.
243 static int MinCompressbufSize(int uncompress_size) {
244 return uncompress_size + uncompress_size/1000 + 40;
245 }
246
247 // Compresses the source buffer into the destination buffer.
248 // sourceLen is the byte length of the source buffer.
249 // Upon entry, destLen is the total size of the destination buffer,
250 // which must be of size at least MinCompressbufSize(sourceLen).
251 // Upon exit, destLen is the actual size of the compressed buffer.
252 //
253 // This function can be used to compress a whole file at once if the
254 // input file is mmap'ed.
255 //
256 // Returns Z_OK if success, Z_MEM_ERROR if there was not
257 // enough memory, Z_BUF_ERROR if there was not enough room in the
258 // output buffer. Note that if the output buffer is exactly the same
259 // size as the compressed result, we still return Z_BUF_ERROR.
260 // (check CL#1936076)
261 int Compress(Bytef *dest, uLongf *destLen,
262 const Bytef *source, uLong sourceLen);
263
264 // Uncompresses the source buffer into the destination buffer.
265 // The destination buffer must be long enough to hold the entire
266 // decompressed contents.
267 //
268 // Returns Z_OK on success, otherwise, it returns a zlib error code.
269 int Uncompress(Bytef *dest, uLongf *destLen,
270 const Bytef *source, uLong sourceLen);
271
272 // Uncompress data one chunk at a time -- ie you can call this
273 // more than once. To get this to work you need to call per-chunk
274 // and "done" routines.
275 //
276 // Returns Z_OK if success, Z_MEM_ERROR if there was not
277 // enough memory, Z_BUF_ERROR if there was not enough room in the
278 // output buffer.
279
280 int UncompressAtMost(Bytef *dest, uLongf *destLen,
281 const Bytef *source, uLong *sourceLen);
282
283 // Checks gzip footer information, as needed. Mostly this just
284 // makes sure the checksums match. Whenever you call this, it
285 // will assume the last 8 bytes from the previous UncompressChunk
286 // call are the footer. Returns true iff everything looks ok.
287 bool UncompressChunkDone();
288
289 private:
290 int InflateInit(); // sets up the zlib inflate structure
291 int DeflateInit(); // sets up the zlib deflate structure
292
293 // These init the zlib data structures for compressing/uncompressing
294 int CompressInit(Bytef *dest, uLongf *destLen,
295 const Bytef *source, uLong *sourceLen);
296 int UncompressInit(Bytef *dest, uLongf *destLen,
297 const Bytef *source, uLong *sourceLen);
298 // Initialization method to be called if we hit an error while
299 // uncompressing. On hitting an error, call this method before
300 // returning the error.
301 void UncompressErrorInit();
302
303 // Helper function for Compress
304 int CompressChunkOrAll(Bytef *dest, uLongf *destLen,
305 const Bytef *source, uLong sourceLen,
306 int flush_mode);
307 int CompressAtMostOrAll(Bytef *dest, uLongf *destLen,
308 const Bytef *source, uLong *sourceLen,
309 int flush_mode);
310
311 // Likewise for UncompressAndUncompressChunk
312 int UncompressChunkOrAll(Bytef *dest, uLongf *destLen,
313 const Bytef *source, uLong sourceLen,
314 int flush_mode);
315
316 int UncompressAtMostOrAll(Bytef *dest, uLongf *destLen,
317 const Bytef *source, uLong *sourceLen,
318 int flush_mode);
319
320 // Initialization method to be called if we hit an error while
321 // compressing. On hitting an error, call this method before
322 // returning the error.
323 void CompressErrorInit();
324
325 int compression_level_; // compression level
326 int window_bits_; // log base 2 of the window size used in compression
327 int mem_level_; // specifies the amount of memory to be used by
328 // compressor (1-9)
329 z_stream comp_stream_; // Zlib stream data structure
330 bool comp_init_; // True if we have initialized comp_stream_
331 z_stream uncomp_stream_; // Zlib stream data structure
332 bool uncomp_init_; // True if we have initialized uncomp_stream_
333
334 // These are used only with chunked compression.
335 bool first_chunk_; // true if we need to emit headers with this chunk
336};
337
338#endif // HAVE_LIBZ
339
340} // namespace snappy
341
342#endif // THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_
343