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 | |
73 | namespace 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(). |
79 | class OptionsStub { |
80 | public: |
81 | OptionsStub(); |
82 | OptionsStub(const OptionsStub &) = delete; |
83 | OptionsStub &operator=(const OptionsStub &) = delete; |
84 | ~OptionsStub(); |
85 | }; |
86 | |
87 | const 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(). |
94 | class StatusStub { |
95 | public: |
96 | StatusStub(); |
97 | StatusStub(const StatusStub &); |
98 | StatusStub &operator=(const StatusStub &); |
99 | ~StatusStub(); |
100 | |
101 | bool ok(); |
102 | }; |
103 | |
104 | StatusStub GetContents(const std::string &file_name, std::string *output, |
105 | const OptionsStub & /* options */); |
106 | |
107 | StatusStub SetContents(const std::string &file_name, const std::string &content, |
108 | const OptionsStub & /* options */); |
109 | |
110 | } // namespace file |
111 | |
112 | namespace snappy { |
113 | |
114 | #define FLAGS_test_random_seed 301 |
115 | |
116 | std::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. |
120 | std::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. |
124 | class 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 | |
169 | class LogMessage { |
170 | public: |
171 | inline LogMessage() = default; |
172 | ~LogMessage(); |
173 | |
174 | LogMessage &operator<<(const std::string &message); |
175 | LogMessage &operator<<(int number); |
176 | }; |
177 | |
178 | class 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 | |
188 | class 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. |
222 | class 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 | |