// Copyright 2011 Google Inc. All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Various stubs for the unit tests for the open-source version of Snappy. #ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_ #define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_ #include #include #include #include #include "snappy-stubs-internal.h" #ifdef HAVE_SYS_MMAN_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_WINDOWS_H // Needed to be able to use std::max without workarounds in the source code. // https://support.microsoft.com/en-us/help/143208/prb-using-stl-in-windows-program-can-cause-min-max-conflicts #define NOMINMAX #include #endif #ifdef HAVE_GFLAGS #include // This is tricky; both gflags and Google Test want to look at the command line // arguments. Google Test seems to be the most happy with unknown arguments, // though, so we call it first and hope for the best. #define InitGoogle(argv0, argc, argv, remove_flags) \ google::ParseCommandLineFlags(argc, argv, remove_flags); #else // If we don't have the gflags package installed, these can only be // changed at compile time. #define DEFINE_int32(flag_name, default_value, description) \ static int FLAGS_ ## flag_name = default_value; #define InitGoogle(argv0, argc, argv, remove_flags) ((void)(0)) #endif #ifdef HAVE_LIBZ #include "zlib.h" #endif #ifdef HAVE_LIBLZO2 #include "lzo/lzo1x.h" #endif #ifdef HAVE_LIBLZ4 #include "lz4.h" #endif namespace file { // Stubs the class file::Options. // // This class should not be instantiated explicitly. It should only be used by // passing file::Defaults() to file::GetContents() / file::SetContents(). class OptionsStub { public: OptionsStub(); OptionsStub(const OptionsStub &) = delete; OptionsStub &operator=(const OptionsStub &) = delete; ~OptionsStub(); }; const OptionsStub &Defaults(); // Stubs the class absl::Status. // // This class should not be instantiated explicitly. It should only be used by // passing the result of file::GetContents() / file::SetContents() to // CHECK_OK(). class StatusStub { public: StatusStub(); StatusStub(const StatusStub &); StatusStub &operator=(const StatusStub &); ~StatusStub(); bool ok(); }; StatusStub GetContents(const std::string &file_name, std::string *output, const OptionsStub & /* options */); StatusStub SetContents(const std::string &file_name, const std::string &content, const OptionsStub & /* options */); } // namespace file namespace snappy { #define FLAGS_test_random_seed 301 std::string ReadTestDataFile(const std::string& base, size_t size_limit); std::string ReadTestDataFile(const std::string& base); // A std::sprintf() variant that returns a std::string. // Not safe for general use due to truncation issues. std::string StrFormat(const char* format, ...); // A wall-time clock. This stub is not super-accurate, nor resistant to the // system time changing. class CycleTimer { public: CycleTimer() : real_time_us_(0) {} void Start() { #ifdef WIN32 QueryPerformanceCounter(&start_); #else gettimeofday(&start_, NULL); #endif } void Stop() { #ifdef WIN32 LARGE_INTEGER stop; LARGE_INTEGER frequency; QueryPerformanceCounter(&stop); QueryPerformanceFrequency(&frequency); double elapsed = static_cast(stop.QuadPart - start_.QuadPart) / frequency.QuadPart; real_time_us_ += elapsed * 1e6 + 0.5; #else struct timeval stop; gettimeofday(&stop, NULL); real_time_us_ += 1000000 * (stop.tv_sec - start_.tv_sec); real_time_us_ += (stop.tv_usec - start_.tv_usec); #endif } double Get() { return real_time_us_ * 1e-6; } private: int64_t real_time_us_; #ifdef WIN32 LARGE_INTEGER start_; #else struct timeval start_; #endif }; #ifdef HAVE_LIBZ // Object-oriented wrapper around zlib. class ZLib { public: ZLib(); ~ZLib(); // Wipe a ZLib object to a virgin state. This differs from Reset() // in that it also breaks any state. void Reinit(); // Call this to make a zlib buffer as good as new. Here's the only // case where they differ: // CompressChunk(a); CompressChunk(b); CompressChunkDone(); vs // CompressChunk(a); Reset(); CompressChunk(b); CompressChunkDone(); // You'll want to use Reset(), then, when you interrupt a compress // (or uncompress) in the middle of a chunk and want to start over. void Reset(); // According to the zlib manual, when you Compress, the destination // buffer must have size at least src + .1%*src + 12. This function // helps you calculate that. Augment this to account for a potential // gzip header and footer, plus a few bytes of slack. static int MinCompressbufSize(int uncompress_size) { return uncompress_size + uncompress_size/1000 + 40; } // Compresses the source buffer into the destination buffer. // sourceLen is the byte length of the source buffer. // Upon entry, destLen is the total size of the destination buffer, // which must be of size at least MinCompressbufSize(sourceLen). // Upon exit, destLen is the actual size of the compressed buffer. // // This function can be used to compress a whole file at once if the // input file is mmap'ed. // // Returns Z_OK if success, Z_MEM_ERROR if there was not // enough memory, Z_BUF_ERROR if there was not enough room in the // output buffer. Note that if the output buffer is exactly the same // size as the compressed result, we still return Z_BUF_ERROR. // (check CL#1936076) int Compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); // Uncompresses the source buffer into the destination buffer. // The destination buffer must be long enough to hold the entire // decompressed contents. // // Returns Z_OK on success, otherwise, it returns a zlib error code. int Uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); // Uncompress data one chunk at a time -- ie you can call this // more than once. To get this to work you need to call per-chunk // and "done" routines. // // Returns Z_OK if success, Z_MEM_ERROR if there was not // enough memory, Z_BUF_ERROR if there was not enough room in the // output buffer. int UncompressAtMost(Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen); // Checks gzip footer information, as needed. Mostly this just // makes sure the checksums match. Whenever you call this, it // will assume the last 8 bytes from the previous UncompressChunk // call are the footer. Returns true iff everything looks ok. bool UncompressChunkDone(); private: int InflateInit(); // sets up the zlib inflate structure int DeflateInit(); // sets up the zlib deflate structure // These init the zlib data structures for compressing/uncompressing int CompressInit(Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen); int UncompressInit(Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen); // Initialization method to be called if we hit an error while // uncompressing. On hitting an error, call this method before // returning the error. void UncompressErrorInit(); // Helper function for Compress int CompressChunkOrAll(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int flush_mode); int CompressAtMostOrAll(Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen, int flush_mode); // Likewise for UncompressAndUncompressChunk int UncompressChunkOrAll(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int flush_mode); int UncompressAtMostOrAll(Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen, int flush_mode); // Initialization method to be called if we hit an error while // compressing. On hitting an error, call this method before // returning the error. void CompressErrorInit(); int compression_level_; // compression level int window_bits_; // log base 2 of the window size used in compression int mem_level_; // specifies the amount of memory to be used by // compressor (1-9) z_stream comp_stream_; // Zlib stream data structure bool comp_init_; // True if we have initialized comp_stream_ z_stream uncomp_stream_; // Zlib stream data structure bool uncomp_init_; // True if we have initialized uncomp_stream_ // These are used only with chunked compression. bool first_chunk_; // true if we need to emit headers with this chunk }; #endif // HAVE_LIBZ } // namespace snappy // For main(). namespace snappy { // Logging. #define LOG(level) LogMessage() #define VLOG(level) true ? (void)0 : \ snappy::LogMessageVoidify() & snappy::LogMessage() class LogMessage { public: LogMessage() { } ~LogMessage() { std::cerr << std::endl; } LogMessage& operator<<(const std::string& msg) { std::cerr << msg; return *this; } LogMessage& operator<<(int x) { std::cerr << x; return *this; } }; // Asserts, both versions activated in debug mode only, // and ones that are always active. #define CRASH_UNLESS(condition) \ SNAPPY_PREDICT_TRUE(condition) ? (void)0 : \ snappy::LogMessageVoidify() & snappy::LogMessageCrash() #ifdef _MSC_VER // ~LogMessageCrash calls std::abort() and therefore never exits. This is by // design, so temporarily disable warning C4722. #pragma warning(push) #pragma warning(disable:4722) #endif class LogMessageCrash : public LogMessage { public: LogMessageCrash() { } ~LogMessageCrash() { std::cerr << std::endl; std::abort(); } }; #ifdef _MSC_VER #pragma warning(pop) #endif // This class is used to explicitly ignore values in the conditional // logging macros. This avoids compiler warnings like "value computed // is not used" and "statement has no effect". class LogMessageVoidify { public: LogMessageVoidify() { } // This has to be an operator with a precedence lower than << but // higher than ?: void operator&(const LogMessage&) { } }; #define CHECK(cond) CRASH_UNLESS(cond) #define CHECK_LE(a, b) CRASH_UNLESS((a) <= (b)) #define CHECK_GE(a, b) CRASH_UNLESS((a) >= (b)) #define CHECK_EQ(a, b) CRASH_UNLESS((a) == (b)) #define CHECK_NE(a, b) CRASH_UNLESS((a) != (b)) #define CHECK_LT(a, b) CRASH_UNLESS((a) < (b)) #define CHECK_GT(a, b) CRASH_UNLESS((a) > (b)) #define CHECK_OK(cond) (cond).CheckSuccess() } // namespace snappy #endif // THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_