foundationdb/bindings/c/test/apitester/TesterUtil.h

180 lines
5.8 KiB
C++

/*
* TesterUtil.h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifndef APITESTER_UTIL_H
#define APITESTER_UTIL_H
#include <random>
#include <ostream>
#include <optional>
#include <fmt/format.h>
#include <chrono>
#include "test/fdb_api.hpp"
#undef ERROR
#define ERROR(name, number, description) enum { error_code_##name = number };
#include "flow/error_definitions.h"
namespace fmt {
// fmt::format formatting for std::optional<T>
template <typename T>
struct formatter<std::optional<T>> : fmt::formatter<T> {
template <typename FormatContext>
auto format(const std::optional<T>& opt, FormatContext& ctx) {
if (opt) {
fmt::formatter<T>::format(*opt, ctx);
return ctx.out();
}
return fmt::format_to(ctx.out(), "<empty>");
}
};
} // namespace fmt
namespace FdbApiTester {
fdb::ByteString lowerCase(fdb::BytesRef str);
class Random {
public:
Random();
static Random& get();
int randomInt(int min, int max);
template <class StringType>
StringType randomStringLowerCase(int minLength, int maxLength) {
int length = randomInt(minLength, maxLength);
StringType str;
str.reserve(length);
for (int i = 0; i < length; i++) {
str += (char)randomInt('a', 'z');
}
return str;
}
fdb::ByteString randomByteStringLowerCase(int minLength, int maxLength) {
return randomStringLowerCase<fdb::ByteString>(minLength, maxLength);
}
bool randomBool(double trueRatio);
std::mt19937 random;
};
class TesterError : public std::runtime_error {
public:
explicit TesterError(const char* message) : std::runtime_error(message) {}
explicit TesterError(const std::string& message) : std::runtime_error(message) {}
TesterError(const TesterError&) = default;
TesterError& operator=(const TesterError&) = default;
TesterError(TesterError&&) = default;
TesterError& operator=(TesterError&&) = default;
};
void print_internal_error(const char* msg, const char* file, int line);
#define ASSERT(condition) \
do { \
if (!(condition)) { \
print_internal_error(#condition, __FILE__, __LINE__); \
abort(); \
} \
} while (false) // For use in destructors, where throwing exceptions is extremely dangerous
using TimePoint = std::chrono::steady_clock::time_point;
using TimeDuration = std::chrono::microseconds::rep;
static inline TimePoint timeNow() {
return std::chrono::steady_clock::now();
}
static inline TimeDuration timeElapsedInUs(const TimePoint& start, const TimePoint& end) {
return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
}
static inline TimeDuration timeElapsedInUs(const TimePoint& start) {
return timeElapsedInUs(start, timeNow());
}
static inline double microsecToSec(TimeDuration timeUs) {
return timeUs / 1000000.0;
}
std::optional<fdb::Value> copyValueRef(fdb::future_var::ValueRef::Type value);
using KeyValueArray = std::pair<std::vector<fdb::KeyValue>, bool>;
KeyValueArray copyKeyValueArray(fdb::future_var::KeyValueRefArray::Type array);
using KeyRangeArray = std::vector<fdb::KeyRange>;
KeyRangeArray copyKeyRangeArray(fdb::future_var::KeyRangeRefArray::Type array);
using GranuleSummaryArray = std::vector<fdb::GranuleSummary>;
GranuleSummaryArray copyGranuleSummaryArray(fdb::future_var::GranuleSummaryRefArray::Type array);
using GranuleDescriptionArray = std::vector<fdb::GranuleDescription>;
GranuleDescriptionArray copyGranuleDescriptionArray(fdb::future_var::GranuleDescriptionRefArray::Type array);
using GranuleMutationArray = std::vector<fdb::GranuleMutation>;
GranuleMutationArray copyGranuleMutationArray(fdb::future_var::GranuleMutationRefArray::Type array);
static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__, "Do not support non-little-endian systems");
// Converts a little-endian encoded number into an integral type.
template <class T, typename = std::enable_if_t<std::is_integral<T>::value>>
static T toInteger(fdb::BytesRef value) {
ASSERT(value.size() == sizeof(T));
T output;
memcpy(&output, value.data(), value.size());
return output;
}
// Converts an integral type to a little-endian encoded byte string.
template <class T, typename = std::enable_if_t<std::is_integral<T>::value>>
static fdb::ByteString toByteString(T value) {
fdb::ByteString output(sizeof(T), 0);
memcpy(output.data(), (const uint8_t*)&value, sizeof(value));
return output;
}
// Creates a temporary file; file gets destroyed/deleted along with object destruction.
struct TmpFile {
public:
~TmpFile();
void create(std::string_view dir, std::string_view prefix);
void write(std::string_view data);
void remove();
const std::string& getFileName() const { return filename; }
private:
std::string filename;
};
} // namespace FdbApiTester
#endif