testlib.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #pragma once
  2. #include <sstream>
  3. #include <cstdio>
  4. #include <stack>
  5. #include <cmath>
  6. #include <regex>
  7. #include <rethinkdb.h>
  8. namespace R = RethinkDB;
  9. extern std::vector<std::pair<const char*, bool>> section;
  10. extern int failed;
  11. extern int count;
  12. extern std::unique_ptr<R::Connection> conn;
  13. extern int verbosity;
  14. const char* indent();
  15. void enter_section(const char* name);
  16. void section_cleanup();
  17. void exit_section();
  18. #define TEST_DO(code) \
  19. if (verbosity > 1) fprintf(stderr, "%sTEST: %s\n", indent(), #code); \
  20. code
  21. #define TEST_EQ(code, expected) \
  22. do { \
  23. if (verbosity > 1) fprintf(stderr, "%sTEST: %s\n", indent(), #code); \
  24. try { test_eq(#code, (code), (expected)); } \
  25. catch (const R::Error& error) { test_eq(#code, error, (expected)); } \
  26. } while (0)
  27. struct err {
  28. err(const char* type_, std::string message_, R::Array&& backtrace_ = {}) :
  29. type(type_), message(message_), backtrace(std::move(backtrace_)) { }
  30. std::string convert_type() const {
  31. return type;
  32. }
  33. static std::string trim_message(std::string msg) {
  34. size_t i = msg.find(":\n");
  35. if (i != std::string::npos) {
  36. return msg.substr(0, i + 1);
  37. }
  38. return msg;
  39. }
  40. std::string type;
  41. std::string message;
  42. R::Array backtrace;
  43. };
  44. struct err_regex {
  45. err_regex(const char* type_, const char* message_, R::Array&& backtrace_ = {}) :
  46. type(type_), message(message_), backtrace(std::move(backtrace_)) { }
  47. std::string type;
  48. std::string message;
  49. R::Array backtrace;
  50. std::string regex() const {
  51. return type + ": " + message;
  52. }
  53. };
  54. R::Object regex(const char* pattern);
  55. bool match(const char* pattern, const char* string);
  56. R::Object partial(R::Object&& object);
  57. R::Object partial(R::Array&& array);
  58. R::Datum uuid();
  59. R::Object arrlen(int n, R::Datum&& datum);
  60. R::Object arrlen(int n);
  61. R::Term new_table();
  62. std::string repeat(std::string&& s, int n);
  63. R::Term fetch(R::Cursor& cursor, int count = -1, double timeout = 1);
  64. R::Object bag(R::Array&& array);
  65. R::Object bag(R::Datum&& d);
  66. struct temp_table {
  67. temp_table() {
  68. char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  69. char name_[15] = "temp_";
  70. for (unsigned int i = 5; i + 1 < sizeof name_; ++i) {
  71. name_[i] = chars[random() % (sizeof chars - 1)];
  72. }
  73. name_[14] = 0;
  74. R::table_create(name_).run(*conn);
  75. name = name_;
  76. }
  77. ~temp_table() {
  78. try {
  79. R::table_drop(name).run(*conn);
  80. } catch (const R::Error &e) {
  81. if(!strstr(e.message.c_str(), "does not exist")){
  82. printf("error dropping temp_table: %s\n", e.message.c_str());
  83. }
  84. }
  85. }
  86. R::Term table() { return R::table(name); }
  87. std::string name;
  88. };
  89. void clean_slate();
  90. // std::string to_string(const R::Cursor&);
  91. std::string to_string(const R::Term&);
  92. std::string to_string(const R::Datum&);
  93. std::string to_string(const R::Error&);
  94. std::string to_string(const err_regex&);
  95. std::string to_string(const err&);
  96. bool equal(const R::Datum&, const R::Datum&);
  97. bool equal(const R::Error&, const err_regex&);
  98. bool equal(const R::Error&, const err&);
  99. template <class T>
  100. bool equal(const T& a, const err& b) {
  101. return false;
  102. }
  103. template <class T>
  104. bool equal(const T& a, const err_regex& b) {
  105. return false;
  106. }
  107. template <class T>
  108. bool equal(const R::Error& a, const T& b) {
  109. return false;
  110. }
  111. std::string truncate(std::string&&);
  112. template <class T, class U>
  113. void test_eq(const char* code, const T val, const U expected) {
  114. try {
  115. count ++;
  116. if (!equal(val, expected)) {
  117. failed++;
  118. for (auto& it : section) {
  119. if (it.second) {
  120. printf("%sSection: %s\n", indent(), it.first);
  121. it.second = false;
  122. }
  123. }
  124. try {
  125. printf("%sFAILURE in ‘%s’:\n%s Expected: ‘%s’\n%s but got: ‘%s’\n",
  126. indent(), code,
  127. indent(), truncate(to_string(expected)).c_str(),
  128. indent(), truncate(to_string(val)).c_str());
  129. } catch (const R::Error& e) {
  130. printf("%sFAILURE: Failed to print failure description: %s\n", indent(), e.message.c_str());
  131. } catch (...) {
  132. printf("%sFAILURE: Failed to print failure description\n", indent());
  133. }
  134. }
  135. } catch (const std::regex_error& rx_err) {
  136. printf("%sSKIP: error with regex (likely a buggy regex implementation): %s\n", indent(), rx_err.what());
  137. }
  138. }
  139. template <class U>
  140. void test_eq(const char* code, const R::Cursor& val, const U expected) {
  141. try {
  142. R::Datum result = val.to_datum();
  143. test_eq(code, result, expected);
  144. } catch (R::Error& error) {
  145. test_eq(code, error, expected);
  146. }
  147. }
  148. int len(const R::Datum&);
  149. R::Term wait(int n);
  150. #define PacificTimeZone() (-7 * 3600)
  151. #define UTCTimeZone() (0)
  152. extern R::Datum nil;
  153. inline R::Cursor maybe_run(R::Cursor& c, R::Connection&, R::OptArgs&& o = {}) {
  154. return std::move(c);
  155. }
  156. inline R::Cursor maybe_run(R::Term q, R::Connection& c, R::OptArgs&& o = {}) {
  157. return q.run(c, std::move(o));
  158. }
  159. inline int operator+(R::Datum a, int b) {
  160. return a.extract_number() + b;
  161. }
  162. inline R::Array operator*(R::Array arr, int n) {
  163. R::Array ret;
  164. for(int i = 0; i < n; i++) {
  165. for(const auto& it: arr) {
  166. ret.push_back(it);
  167. }
  168. }
  169. return ret;
  170. }
  171. inline R::Array array_range(int x, int y) {
  172. R::Array ret;
  173. for(int i = x; i < y; ++i) {
  174. ret.push_back(i);
  175. }
  176. return ret;
  177. }
  178. template <class F>
  179. inline R::Array array_map(F f, R::Array a){
  180. R::Array ret;
  181. for(R::Datum& d: a) {
  182. ret.push_back(f(d.extract_number()));
  183. }
  184. return ret;
  185. }
  186. R::Array append(R::Array lhs, R::Array rhs);
  187. template <class T>
  188. std::string str(T x){
  189. return to_string(x);
  190. }