text: // 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 UTIL_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_
  #define UTIL_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_
  
  #include <iostream>
  #include <string>
  
  #include "snappy-stubs-internal.h"
  
  #include <stdio.h>
  #include <stdarg.h>
  
  #ifdef HAVE_SYS_MMAN_H
  #include <sys/mman.h>
  #endif
  
  #ifdef HAVE_SYS_RESOURCE_H
  #include <sys/resource.h>
  #endif
  
  #ifdef HAVE_SYS_TIME_H
  #include <sys/time.h>
  #endif
  
  #ifdef HAVE_WINDOWS_H
  #define WIN32_LEAN_AND_MEAN
  #include <windows.h>
  #endif
  
  #include <string>
  
  #ifdef HAVE_GTEST
  
  #include <gtest/gtest.h>
  #undef TYPED_TEST
  #define TYPED_TEST TEST
  #define INIT_GTEST(argc, argv) ::testing::InitGoogleTest(argc, *argv)
  
  #else
  
  // Stubs for if the user doesn't have Google Test installed.
  
  #define TEST(test_case, test_subcase) \
    void Test_ ## test_case ## _ ## test_subcase()
  #define INIT_GTEST(argc, argv)
  
  #define TYPED_TEST TEST
  #define EXPECT_EQ CHECK_EQ
  #define EXPECT_NE CHECK_NE
  #define EXPECT_FALSE(cond) CHECK(!(cond))
  
  #endif
  
  #ifdef HAVE_GFLAGS
  
  #include <gflags/gflags.h>
  
  // 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) \
    INIT_GTEST(argc, argv); \
    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) \
    INIT_GTEST(argc, argv)
  
  #endif
  
  #ifdef HAVE_LIBZ
  #include "zlib.h"
  #endif
  
  #ifdef HAVE_LIBLZO2
  #include "lzo/lzo1x.h"
  #endif
  
  #ifdef HAVE_LIBLZF
  extern "C" {
  #include "lzf.h"
  }
  #endif
  
  #ifdef HAVE_LIBFASTLZ
  #include "fastlz.h"
  #endif
  
  #ifdef HAVE_LIBQUICKLZ
  #include "quicklz.h"
  #endif
  
  namespace {
  
  namespace File {
    void Init() { }
  }  // namespace File
  
  namespace file {
    int Defaults() { }
  
    class DummyStatus {
     public:
      void CheckSuccess() { }
    };
  
    DummyStatus GetContents(const string& filename, string* data, int unused) {
      FILE* fp = fopen(filename.c_str(), "rb");
      if (fp == NULL) {
        perror(filename.c_str());
        exit(1);
      }
  
      data->clear();
      while (!feof(fp)) {
        char buf[4096];
        size_t ret = fread(buf, 1, 4096, fp);
        if (ret == 0 && ferror(fp)) {
          perror("fread");
          exit(1);
        }
        data->append(string(buf, ret));
      }
  
      fclose(fp);
    }
  
    DummyStatus SetContents(const string& filename,
                            const string& str,
                            int unused) {
      FILE* fp = fopen(filename.c_str(), "wb");
      if (fp == NULL) {
        perror(filename.c_str());
        exit(1);
      }
  
      int ret = fwrite(str.data(), str.size(), 1, fp);
      if (ret != 1) {
        perror("fwrite");
        exit(1);
      }
  
      fclose(fp);
    }
  }  // namespace file
  
  }  // namespace
  
  namespace snappy {
  
  #define FLAGS_test_random_seed 301
  typedef string TypeParam;
  
  void Test_CorruptedTest_VerifyCorrupted();
  void Test_Snappy_SimpleTests();
  void Test_Snappy_MaxBlowup();
  void Test_Snappy_RandomData();
  void Test_Snappy_FourByteOffset();
  void Test_SnappyCorruption_TruncatedVarint();
  void Test_SnappyCorruption_UnterminatedVarint();
  void Test_Snappy_ReadPastEndOfBuffer();
  void Test_Snappy_FindMatchLength();
  void Test_Snappy_FindMatchLengthRandom();
  
  string ReadTestDataFile(const string& base, size_t size_limit);
  
  string ReadTestDataFile(const string& base);
  
  // A sprintf() variant that returns a std::string.
  // Not safe for general use due to truncation issues.
  string StringPrintf(const char* format, ...);
  
  // A simple, non-cryptographically-secure random generator.
  class ACMRandom {
   public:
    explicit ACMRandom(uint32 seed) : seed_(seed) {}
  
    int32 Next();
  
    int32 Uniform(int32 n) {
      return Next() % n;
    }
    uint8 Rand8() {
      return static_cast<uint8>((Next() >> 1) & 0x000000ff);
    }
    bool OneIn(int X) { return Uniform(X) == 0; }
  
    // Skewed: pick "base" uniformly from range [0,max_log] and then
    // return "base" random bits.  The effect is to pick a number in the
    // range [0,2^max_log-1] with bias towards smaller numbers.
    int32 Skewed(int max_log);
  
   private:
    static const uint32 M = 2147483647L;   // 2^31-1
    uint32 seed_;
  };
  
  inline int32 ACMRandom::Next() {
    static const uint64 A = 16807;  // bits 14, 8, 7, 5, 2, 1, 0
    // We are computing
    //       seed_ = (seed_ * A) % M,    where M = 2^31-1
    //
    // seed_ must not be zero or M, or else all subsequent computed values
    // will be zero or M respectively.  For all other values, seed_ will end
    // up cycling through every number in [1,M-1]
    uint64 product = seed_ * A;
  
    // Compute (product % M) using the fact that ((x << 31) % M) == x.
    seed_ = (product >> 31) + (product & M);
    // The first reduction may overflow by 1 bit, so we may need to repeat.
    // mod == M is not possible; using > allows the faster sign-bit-based test.
    if (seed_ > M) {
      seed_ -= M;
    }
    return seed_;
  }
  
  inline int32 ACMRandom::Skewed(int max_log) {
    const int32 base = (Next() - 1) % (max_log+1);
    return (Next() - 1) & ((1u << base)-1);
  }
  
  // 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<double>(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 real_time_us_;
  #ifdef WIN32
    LARGE_INTEGER start_;
  #else
    struct timeval start_;
  #endif
  };
  
  // Minimalistic microbenchmark framework.
  
  typedef void (*BenchmarkFunction)(int, int);
  
  class Benchmark {
   public:
    Benchmark(const string& name, BenchmarkFunction function) :
        name_(name), function_(function) {}
  
    Benchmark* DenseRange(int start, int stop) {
      start_ = start;
      stop_ = stop;
      return this;
    }
  
    void Run();
  
   private:
    const string name_;
    const BenchmarkFunction function_;
    int start_, stop_;
  };
  #define BENCHMARK(benchmark_name) \
    Benchmark* Benchmark_ ## benchmark_name = \
            (new Benchmark(#benchmark_name, benchmark_name))
  
  extern Benchmark* Benchmark_BM_UFlat;
  extern Benchmark* Benchmark_BM_UIOVec;
  extern Benchmark* Benchmark_BM_UValidate;
  extern Benchmark* Benchmark_BM_ZFlat;
  
  void ResetBenchmarkTiming();
  void StartBenchmarkTiming();
  void StopBenchmarkTiming();
  void SetBenchmarkLabel(const string& str);
  void SetBenchmarkBytesProcessed(int64 bytes);
  
  #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
  
  DECLARE_bool(run_microbenchmarks);
  
  static void RunSpecifiedBenchmarks() {
    if (!FLAGS_run_microbenchmarks) {
      return;
    }
  
    fprintf(stderr, "Running microbenchmarks.\n");
  #ifndef NDEBUG
    fprintf(stderr, "WARNING: Compiled with assertions enabled, will be slow.\n");
  #endif
  #ifndef __OPTIMIZE__
    fprintf(stderr, "WARNING: Compiled without optimization, will be slow.\n");
  #endif
    fprintf(stderr, "Benchmark            Time(ns)    CPU(ns) Iterations\n");
    fprintf(stderr, "---------------------------------------------------\n");
  
    snappy::Benchmark_BM_UFlat->Run();
    snappy::Benchmark_BM_UIOVec->Run();
    snappy::Benchmark_BM_UValidate->Run();
    snappy::Benchmark_BM_ZFlat->Run();
  
    fprintf(stderr, "\n");
  }
  
  #ifndef HAVE_GTEST
  
  static inline int RUN_ALL_TESTS() {
    fprintf(stderr, "Running correctness tests.\n");
    snappy::Test_CorruptedTest_VerifyCorrupted();
    snappy::Test_Snappy_SimpleTests();
    snappy::Test_Snappy_MaxBlowup();
    snappy::Test_Snappy_RandomData();
    snappy::Test_Snappy_FourByteOffset();
    snappy::Test_SnappyCorruption_TruncatedVarint();
    snappy::Test_SnappyCorruption_UnterminatedVarint();
    snappy::Test_Snappy_ReadPastEndOfBuffer();
    snappy::Test_Snappy_FindMatchLength();
    snappy::Test_Snappy_FindMatchLengthRandom();
    fprintf(stderr, "All tests passed.\n");
  
    return 0;
  }
  
  #endif  // HAVE_GTEST
  
  // For main().
  namespace snappy {
  
  static void CompressFile(const char* fname);
  static void UncompressFile(const char* fname);
  static void MeasureFile(const char* fname);
  
  // Logging.
  
  #define LOG(level) LogMessage()
  #define VLOG(level) true ? (void)0 : \
      snappy::LogMessageVoidify() & snappy::LogMessage()
  
  class LogMessage {
   public:
    LogMessage() { }
    ~LogMessage() {
      cerr << endl;
    }
  
    LogMessage& operator<<(const std::string& msg) {
      cerr << msg;
      return *this;
    }
    LogMessage& operator<<(int x) {
      cerr << x;
      return *this;
    }
  };
  
  // Asserts, both versions activated in debug mode only,
  // and ones that are always active.
  
  #define CRASH_UNLESS(condition) \
      PREDICT_TRUE(condition) ? (void)0 : \
      snappy::LogMessageVoidify() & snappy::LogMessageCrash()
  
  class LogMessageCrash : public LogMessage {
   public:
    LogMessageCrash() { }
    ~LogMessageCrash() {
      cerr << endl;
      abort();
    }
  };
  
  // 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))
  
  }  // namespace
  
  using snappy::CompressFile;
  using snappy::UncompressFile;
  using snappy::MeasureFile;
  
  #endif  // UTIL_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_
  