snappy-test.h (11496B)
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_