Advertisement
Petrovi4

test_framework.h

Aug 27th, 2022
899
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.06 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <iostream>
  4. #include <map>
  5. #include <set>
  6. #include <sstream>
  7. #include <stdexcept>
  8. #include <string>
  9. #include <unordered_map>
  10. #include <unordered_set>
  11. #include <vector>
  12.  
  13. namespace TestRunnerPrivate {
  14.  
  15. template <class Map>
  16. std::ostream& PrintMap(std::ostream& os, const Map& m) {
  17.     os << "{";
  18.     bool first = true;
  19.     for (const auto& kv : m) {
  20.         if (!first) {
  21.             os << ", ";
  22.         }
  23.         first = false;
  24.         os << kv.first << ": " << kv.second;
  25.     }
  26.     return os << "}";
  27. }
  28.  
  29. template <class Set>
  30. std::ostream& PrintSet(std::ostream& os, const Set& s) {
  31.     os << "{";
  32.     bool first = true;
  33.     for (const auto& x : s) {
  34.         if (!first) {
  35.             os << ", ";
  36.         }
  37.         first = false;
  38.         os << x;
  39.     }
  40.     return os << "}";
  41. }
  42.  
  43. }  // namespace TestRunnerPrivate
  44.  
  45. template <class T>
  46. std::ostream& operator<<(std::ostream& os, const std::vector<T>& s) {
  47.     os << "{";
  48.     bool first = true;
  49.     for (const auto& x : s) {
  50.         if (!first) {
  51.             os << ", ";
  52.         }
  53.         first = false;
  54.         os << x;
  55.     }
  56.     return os << "}";
  57. }
  58.  
  59. template <class T, class C>
  60. std::ostream& operator<<(std::ostream& os, const std::set<T, C>& s) {
  61.     return TestRunnerPrivate::PrintSet(os, s);
  62. }
  63.  
  64. template <class T, class H, class Eq>
  65. std::ostream& operator<<(std::ostream& os, const std::unordered_set<T, H, Eq>& s) {
  66.     return TestRunnerPrivate::PrintSet(os, s);
  67. }
  68.  
  69. template <class K, class V, class C>
  70. std::ostream& operator<<(std::ostream& os, const std::map<K, V, C>& m) {
  71.     return TestRunnerPrivate::PrintMap(os, m);
  72. }
  73.  
  74. template <class K, class V, class H, class Eq>
  75. std::ostream& operator<<(std::ostream& os, const std::unordered_map<K, V, H, Eq>& m) {
  76.     return TestRunnerPrivate::PrintMap(os, m);
  77. }
  78.  
  79. /**
  80.  * Сравнивает значения t и u. Если они не равны, тест проваливается.
  81.  * Строка hint содержит подсказку, которая выводится, если тест провален.
  82.  *
  83.  * Пример:
  84.  *  void Test() {
  85.  *      Assert("Hello "s + "world"s, "Hello world"s, "String concatenation error"s);
  86.  *  }
  87.  */
  88. template <class T, class U>
  89. void AssertEqual(const T& t, const U& u, const std::string& hint = {}) {
  90.     if (!(t == u)) {
  91.         std::ostringstream os;
  92.         os << "Assertion failed: " << t << " != " << u;
  93.         if (!hint.empty()) {
  94.             os << " hint: " << hint;
  95.         }
  96.         throw std::runtime_error(os.str());
  97.     }
  98. }
  99.  
  100. /**
  101.  * Проверяет истинность значения b, если нет, тест проваливается.
  102.  * Строка hint содержит подсказку, которая выводится, если тест провален.
  103.  */
  104. inline void Assert(bool b, const std::string& hint) {
  105.     AssertEqual(b, true, hint);
  106. }
  107.  
  108. /**
  109.  * Класс TestRunner запускает тест-функции.
  110.  * Пример:
  111.  *  void Test1() {
  112.  *      // ...
  113.  *  }
  114.  *
  115.  *  void Test2() {
  116.  *      // ...
  117.  *  }
  118.  *
  119.  *  int main() {
  120.  *      TestRunner tr;
  121.  *      // Запускает функцию Test1. Если тест будет провален, его имя будет выведено как
  122.  *      // First test
  123.  *      tr.RunTest(Test1, "First test"s);
  124.  *      // Если имя теста, совпадает с именем тест-функции, можно использовать максро RUN_TEST:
  125.  *      RUN_TEST(tr, Test2); // Аналогично tr.RunTest(Test2, "Test2");
  126.  *  }
  127.  */
  128. class TestRunner {
  129. public:
  130.     template <class TestFunc>
  131.     void RunTest(TestFunc func, const std::string& test_name) {
  132.         try {
  133.             func();
  134.             std::cerr << test_name << " OK" << std::endl;
  135.         } catch (std::exception& e) {
  136.             ++fail_count;
  137.             std::cerr << test_name << " fail: " << e.what() << std::endl;
  138.         } catch (...) {
  139.             ++fail_count;
  140.             std::cerr << "Unknown exception caught" << std::endl;
  141.         }
  142.     }
  143.  
  144.     ~TestRunner() {
  145.         std::cerr.flush();
  146.         if (fail_count > 0) {
  147.             std::cerr << fail_count << " unit tests failed. Terminate" << std::endl;
  148.             exit(1);
  149.         }
  150.     }
  151.  
  152. private:
  153.     int fail_count = 0;
  154. };
  155.  
  156. #ifndef FILE_NAME
  157. #define FILE_NAME __FILE__
  158. #endif
  159.  
  160. /**
  161.  * Макрос ASSERT_EQUAL проверяет значения выражений x и y на равенство.
  162.  * Если значения не равны, тест считается проваленным.
  163.  *
  164.  * Пример:
  165.  *  void Test() {
  166.  *      ASSERT_EQUAL(2 + 2, 4);
  167.  *      ASSERT_EQUAL(2 + 2, 5); // Эта проверка не сработает, и тест будет провален
  168.  *  }
  169.  */
  170. #define ASSERT_EQUAL(x, y)                                                                       \
  171.     {                                                                                            \
  172.         std::ostringstream __assert_equal_private_os;                                            \
  173.         __assert_equal_private_os << #x << " != " << #y << ", " << FILE_NAME << ":" << __LINE__; \
  174.         AssertEqual(x, y, __assert_equal_private_os.str());                                      \
  175.     }
  176.  
  177. /**
  178.  * Макрос ASSERT проверяет истинность выражения x. Выражение x должно
  179.  * конвертироваться к типу bool.
  180.  * Если выражение x ложно, тест считается проваленным. Если выражение x истинно,
  181.  * выполнение теста продолжается.
  182.  *
  183.  * Пример:
  184.  *  void Test() {
  185.  *      ASSERT(2 + 2 == 4);
  186.  *      ASSERT(2); // число 2 при преобразовании к bool станет значением true
  187.  *      ASSERT(false); // здесь тест провалится
  188.  *      string user_name = "Harry Potter"s;
  189.  *      // Если раскомментировать следующую строку, программа не скомпилируется,
  190.  *      // так как string не может быть преобразован к типу bool.
  191.  *      // ASSERT(user_name);
  192.  *  }
  193.  */
  194. #define ASSERT(x)                                                                   \
  195.     {                                                                               \
  196.         std::ostringstream __assert_private_os;                                     \
  197.         __assert_private_os << #x << " is false, " << FILE_NAME << ":" << __LINE__; \
  198.         Assert(static_cast<bool>(x), __assert_private_os.str());                    \
  199.     }
  200.  
  201. /**
  202.  * Макрос RUN_TEST служит для удобного запуска тест-функции func.
  203.  * Параметр tr задаёт имя переменной типа TestRunner.
  204.  *
  205.  * Пример:
  206.  *  void Test1() {
  207.  *      // Содержимое тест-функции ...
  208.  *  }
  209.  *
  210.  *  void Test2() {
  211.  *      // Содержимое тест-функции ...
  212.  *  }
  213.  *
  214.  *  int main() {
  215.  *      TestRunner tr;
  216.  *      RUN_TEST(tr, Test1);
  217.  *      RUN_TEST(tr, Test2);
  218.  *  }
  219.  */
  220. #define RUN_TEST(tr, func) tr.RunTest(func, #func)
  221.  
  222. /**
  223.  * Макрос ASSERT_THROWS проверяет, что при вычислении выражения expr будет
  224.  * выброшено исключение типа expected_exception.
  225.  * Если исключение выброшено не будет, либо выбросится исключение другого типа,
  226.  * тест считается проваленным.
  227.  *
  228.  * Пример:
  229.  *  void Test() {
  230.  *      using namespace std;
  231.  *      ASSERT_THROWS(stoi("not-a-number"s), invalid_argument);
  232.  *  }
  233.  */
  234. #define ASSERT_THROWS(expr, expected_exception)                                                   \
  235.     {                                                                                             \
  236.         bool __assert_private_flag = true;                                                        \
  237.         try {                                                                                     \
  238.             expr;                                                                                 \
  239.             __assert_private_flag = false;                                                        \
  240.         } catch (expected_exception&) {                                                           \
  241.         } catch (...) {                                                                           \
  242.             std::ostringstream __assert_private_os;                                               \
  243.             __assert_private_os << "Expression " #expr                                            \
  244.                                    " threw an unexpected exception"                               \
  245.                                    " " FILE_NAME ":"                                              \
  246.                                 << __LINE__;                                                      \
  247.             Assert(false, __assert_private_os.str());                                             \
  248.         }                                                                                         \
  249.         if (!__assert_private_flag) {                                                             \
  250.             std::ostringstream __assert_private_os;                                               \
  251.             __assert_private_os << "Expression " #expr                                            \
  252.                                    " is expected to throw " #expected_exception " " FILE_NAME ":" \
  253.                                 << __LINE__;                                                      \
  254.             Assert(false, __assert_private_os.str());                                             \
  255.         }                                                                                         \
  256.     }
  257.  
  258. /**
  259.  * Макрос ASSERT_DOESNT_THROW проверяет, что при вычислении выражения expr
  260.  * не будет выброшено никаких исключений.
  261.  * Если при вычислении выражения expr выбросится исключение, тест будет провален.
  262.  *
  263.  * Пример:
  264.  *  void Test() {
  265.  *      vector<int> v;
  266.  *      v.push_back(1);
  267.  *      ASSERT_DOESNT_THROW(v.at(0)));
  268.  *  }
  269.  */
  270. #define ASSERT_DOESNT_THROW(expr)                               \
  271.     try {                                                       \
  272.         expr;                                                   \
  273.     } catch (...) {                                             \
  274.         std::ostringstream __assert_private_os;                 \
  275.         __assert_private_os << "Expression " #expr              \
  276.                                " threw an unexpected exception" \
  277.                                " " FILE_NAME ":"                \
  278.                             << __LINE__;                        \
  279.         Assert(false, __assert_private_os.str());               \
  280.     }
  281.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement