diff options
Diffstat (limited to 'ext/librethinkdbxx/test/testlib.h')
-rw-r--r-- | ext/librethinkdbxx/test/testlib.h | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/ext/librethinkdbxx/test/testlib.h b/ext/librethinkdbxx/test/testlib.h new file mode 100644 index 00000000..5b795436 --- /dev/null +++ b/ext/librethinkdbxx/test/testlib.h @@ -0,0 +1,231 @@ +#pragma once + +#include <sstream> +#include <cstdio> +#include <stack> +#include <cmath> +#include <regex> + +#include <rethinkdb.h> + +namespace R = RethinkDB; + +extern std::vector<std::pair<const char*, bool>> section; +extern int failed; +extern int count; +extern std::unique_ptr<R::Connection> conn; +extern int verbosity; + +const char* indent(); + +void enter_section(const char* name); +void section_cleanup(); +void exit_section(); + +#define TEST_DO(code) \ + if (verbosity > 1) fprintf(stderr, "%sTEST: %s\n", indent(), #code); \ + code + +#define TEST_EQ(code, expected) \ + do { \ + if (verbosity > 1) fprintf(stderr, "%sTEST: %s\n", indent(), #code); \ + try { test_eq(#code, (code), (expected)); } \ + catch (const R::Error& error) { test_eq(#code, error, (expected)); } \ + } while (0) + +struct err { + err(const char* type_, std::string message_, R::Array&& backtrace_ = {}) : + type(type_), message(message_), backtrace(std::move(backtrace_)) { } + + std::string convert_type() const { + return type; + } + + static std::string trim_message(std::string msg) { + size_t i = msg.find(":\n"); + if (i != std::string::npos) { + return msg.substr(0, i + 1); + } + return msg; + } + + std::string type; + std::string message; + R::Array backtrace; +}; + +struct err_regex { + err_regex(const char* type_, const char* message_, R::Array&& backtrace_ = {}) : + type(type_), message(message_), backtrace(std::move(backtrace_)) { } + std::string type; + std::string message; + R::Array backtrace; + std::string regex() const { + return type + ": " + message; + } +}; + +R::Object regex(const char* pattern); + +bool match(const char* pattern, const char* string); + +R::Object partial(R::Object&& object); +R::Object partial(R::Array&& array); +R::Datum uuid(); +R::Object arrlen(int n, R::Datum&& datum); +R::Object arrlen(int n); +R::Term new_table(); +std::string repeat(std::string&& s, int n); +R::Term fetch(R::Cursor& cursor, int count = -1, double timeout = 1); +R::Object bag(R::Array&& array); +R::Object bag(R::Datum&& d); + +struct temp_table { + temp_table() { + char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + char name_[15] = "temp_"; + for (unsigned int i = 5; i + 1 < sizeof name_; ++i) { + name_[i] = chars[random() % (sizeof chars - 1)]; + } + name_[14] = 0; + R::table_create(name_).run(*conn); + name = name_; + } + + ~temp_table() { + try { + R::table_drop(name).run(*conn); + } catch (const R::Error &e) { + if(!strstr(e.message.c_str(), "does not exist")){ + printf("error dropping temp_table: %s\n", e.message.c_str()); + } + } + } + + R::Term table() { return R::table(name); } + std::string name; +}; + +void clean_slate(); + +// std::string to_string(const R::Cursor&); +std::string to_string(const R::Term&); +std::string to_string(const R::Datum&); +std::string to_string(const R::Error&); +std::string to_string(const err_regex&); +std::string to_string(const err&); + +bool equal(const R::Datum&, const R::Datum&); +bool equal(const R::Error&, const err_regex&); +bool equal(const R::Error&, const err&); + +template <class T> +bool equal(const T& a, const err& b) { + return false; +} + +template <class T> +bool equal(const T& a, const err_regex& b) { + return false; +} + +template <class T> +bool equal(const R::Error& a, const T& b) { + return false; +} + +std::string truncate(std::string&&); + +template <class T, class U> +void test_eq(const char* code, const T val, const U expected) { + + try { + count ++; + if (!equal(val, expected)) { + failed++; + for (auto& it : section) { + if (it.second) { + printf("%sSection: %s\n", indent(), it.first); + it.second = false; + } + } + try { + printf("%sFAILURE in ‘%s’:\n%s Expected: ‘%s’\n%s but got: ‘%s’\n", + indent(), code, + indent(), truncate(to_string(expected)).c_str(), + indent(), truncate(to_string(val)).c_str()); + } catch (const R::Error& e) { + printf("%sFAILURE: Failed to print failure description: %s\n", indent(), e.message.c_str()); + } catch (...) { + printf("%sFAILURE: Failed to print failure description\n", indent()); + } + } + } catch (const std::regex_error& rx_err) { + printf("%sSKIP: error with regex (likely a buggy regex implementation): %s\n", indent(), rx_err.what()); + } +} + +template <class U> +void test_eq(const char* code, const R::Cursor& val, const U expected) { + try { + R::Datum result = val.to_datum(); + test_eq(code, result, expected); + } catch (R::Error& error) { + test_eq(code, error, expected); + } +} + +int len(const R::Datum&); + +R::Term wait(int n); + +#define PacificTimeZone() (-7 * 3600) +#define UTCTimeZone() (0) + +extern R::Datum nil; + +inline R::Cursor maybe_run(R::Cursor& c, R::Connection&, R::OptArgs&& o = {}) { + return std::move(c); +} + +inline R::Cursor maybe_run(R::Term q, R::Connection& c, R::OptArgs&& o = {}) { + return q.run(c, std::move(o)); +} + +inline int operator+(R::Datum a, int b) { + return a.extract_number() + b; +} + +inline R::Array operator*(R::Array arr, int n) { + R::Array ret; + for(int i = 0; i < n; i++) { + for(const auto& it: arr) { + ret.push_back(it); + } + } + return ret; +} + +inline R::Array array_range(int x, int y) { + R::Array ret; + for(int i = x; i < y; ++i) { + ret.push_back(i); + } + return ret; +} + +template <class F> +inline R::Array array_map(F f, R::Array a){ + R::Array ret; + for(R::Datum& d: a) { + ret.push_back(f(d.extract_number())); + } + return ret; +} + +R::Array append(R::Array lhs, R::Array rhs); + +template <class T> +std::string str(T x){ + return to_string(x); +} |