aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorKunoiSayami <[email protected]>2021-11-07 20:06:38 +0800
committerKunoiSayami <[email protected]>2021-11-07 20:06:38 +0800
commitc0b9d06b6688088fd167b0c1f897934185074c01 (patch)
tree9543894bd44991ed60e127a49d3aab69a2d0f6fe /utils
parent779128d348ce00ef89f2144cb91453ebabd16519 (diff)
feat: Add googletest
Signed-off-by: KunoiSayami <[email protected]>
Diffstat (limited to 'utils')
-rw-r--r--utils/random.h57
-rw-r--r--utils/testutil.cpp51
-rw-r--r--utils/testutil.cuh88
3 files changed, 196 insertions, 0 deletions
diff --git a/utils/random.h b/utils/random.h
new file mode 100644
index 0000000..2b04757
--- /dev/null
+++ b/utils/random.h
@@ -0,0 +1,57 @@
+#ifndef CLEVELDB_RANDOM_H
+#define CLEVELDB_RANDOM_H
+#include <cstdint>
+
+namespace cleveldb {
+
+// A very simple random number generator. Not especially good at
+// generating truly random bits, but good enough for our needs in this
+// package.
+ class Random {
+ private:
+ uint32_t seed_;
+
+ public:
+ explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) {
+ // Avoid bad seeds.
+ if (seed_ == 0 || seed_ == 2147483647L) {
+ seed_ = 1;
+ }
+ }
+ uint32_t Next() {
+ static const uint32_t M = 2147483647L; // 2^31-1
+ static const uint64_t 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_t product = seed_ * A;
+
+ // Compute (product % M) using the fact that ((x << 31) % M) == x.
+ seed_ = static_cast<uint32_t>((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_;
+ }
+ // Returns a uniformly distributed value in the range [0..n-1]
+ // REQUIRES: n > 0
+ uint32_t Uniform(int n) { return Next() % n; }
+
+ // Randomly returns true ~"1/n" of the time, and false otherwise.
+ // REQUIRES: n > 0
+ bool OneIn(int n) { return (Next() % n) == 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 exponential bias towards smaller numbers.
+ uint32_t Skewed(int max_log) { return Uniform(1 << Uniform(max_log + 1)); }
+ };
+
+} // namespace cleveldb
+#endif //CLEVELDB_RANDOM_H
diff --git a/utils/testutil.cpp b/utils/testutil.cpp
new file mode 100644
index 0000000..1d3e04c
--- /dev/null
+++ b/utils/testutil.cpp
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#include "util/testutil.h"
+
+#include <string>
+
+#include "util/random.h"
+
+namespace cleveldb {
+ namespace test {
+
+ Slice RandomString(Random* rnd, int len, std::string* dst) {
+ dst->resize(len);
+ for (int i = 0; i < len; i++) {
+ (*dst)[i] = static_cast<char>(' ' + rnd->Uniform(95)); // ' ' .. '~'
+ }
+ return Slice(*dst);
+ }
+
+ std::string RandomKey(Random* rnd, int len) {
+ // Make sure to generate a wide variety of characters so we
+ // test the boundary conditions for short-key optimizations.
+ static const char kTestChars[] = {'\0', '\1', 'a', 'b', 'c',
+ 'd', 'e', '\xfd', '\xfe', '\xff'};
+ std::string result;
+ for (int i = 0; i < len; i++) {
+ result += kTestChars[rnd->Uniform(sizeof(kTestChars))];
+ }
+ return result;
+ }
+
+ Slice CompressibleString(Random* rnd, double compressed_fraction, size_t len,
+ std::string* dst) {
+ int raw = static_cast<int>(len * compressed_fraction);
+ if (raw < 1) raw = 1;
+ std::string raw_data;
+ RandomString(rnd, raw, &raw_data);
+
+ // Duplicate the random data until we have filled "len" bytes
+ dst->clear();
+ while (dst->size() < len) {
+ dst->append(raw_data);
+ }
+ dst->resize(len);
+ return Slice(*dst);
+ }
+
+ } // namespace test
+} // namespace leveldb
diff --git a/utils/testutil.cuh b/utils/testutil.cuh
new file mode 100644
index 0000000..f33e691
--- /dev/null
+++ b/utils/testutil.cuh
@@ -0,0 +1,88 @@
+#ifndef CLEVELDB_TESTUTIL_CUH
+
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_
+#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "helpers/memenv/memenv.h"
+#include "leveldb/env.h"
+#include "leveldb/slice.h"
+#include "util/random.h"
+
+namespace cleveldb {
+ namespace test {
+
+ MATCHER(IsOK, "") { return arg.ok(); }
+
+// Macros for testing the results of functions that return leveldb::Status or
+// absl::StatusOr<T> (for any type T).
+#define EXPECT_LEVELDB_OK(expression) \
+ EXPECT_THAT(expression, leveldb::test::IsOK())
+#define ASSERT_LEVELDB_OK(expression) \
+ ASSERT_THAT(expression, leveldb::test::IsOK())
+
+// Returns the random seed used at the start of the current test run.
+ inline int RandomSeed() {
+ return testing::UnitTest::GetInstance()->random_seed();
+ }
+
+// Store in *dst a random string of length "len" and return a Slice that
+// references the generated data.
+ Slice RandomString(Random* rnd, int len, std::string* dst);
+
+// Return a random key with the specified length that may contain interesting
+// characters (e.g. \x00, \xff, etc.).
+ std::string RandomKey(Random* rnd, int len);
+
+// Store in *dst a string of length "len" that will compress to
+// "N*compressed_fraction" bytes and return a Slice that references
+// the generated data.
+ Slice CompressibleString(Random* rnd, double compressed_fraction, size_t len,
+ std::string* dst);
+
+// A wrapper that allows injection of errors.
+ class ErrorEnv : public EnvWrapper {
+ public:
+ bool writable_file_error_;
+ int num_writable_file_errors_;
+
+ ErrorEnv()
+ : EnvWrapper(NewMemEnv(Env::Default())),
+ writable_file_error_(false),
+ num_writable_file_errors_(0) {}
+ ~ErrorEnv() override { delete target(); }
+
+ Status NewWritableFile(const std::string& fname,
+ WritableFile** result) override {
+ if (writable_file_error_) {
+ ++num_writable_file_errors_;
+ *result = nullptr;
+ return Status::IOError(fname, "fake error");
+ }
+ return target()->NewWritableFile(fname, result);
+ }
+
+ Status NewAppendableFile(const std::string& fname,
+ WritableFile** result) override {
+ if (writable_file_error_) {
+ ++num_writable_file_errors_;
+ *result = nullptr;
+ return Status::IOError(fname, "fake error");
+ }
+ return target()->NewAppendableFile(fname, result);
+ }
+ };
+
+} // namespace test
+} // namespace leveldb
+
+#endif // STORAGE_LEVELDB_UTIL_TESTUTIL_H_
+
+#define CLEVELDB_TESTUTIL_CUH
+
+#endif //CLEVELDB_TESTUTIL_CUH