GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: test/common/async_tests.h Lines: 60 68 88.2 %
Date: 2025-03-04 18:34:12 Branches: 44 92 47.8 %

Line Branch Exec Source
1
//
2
// Created by 4c3y (acey) on 21.09.22.
3
//
4
5
#ifndef LOG_TEST_COMMON_ASYNC_TESTS_H_
6
#define LOG_TEST_COMMON_ASYNC_TESTS_H_
7
8
#if __cplusplus >= 201703L
9
#include <mutex>
10
#endif
11
12
#include <test_utils.h>
13
#include <thread>
14
15
#define GET_CLASS_NAME(class_ptr, status) abi::__cxa_demangle(typeid(class_ptr).name(), nullptr, nullptr, status)
16
17
enum CompareType {
18
  EQUAL,
19
  IS_SUBSTRING,
20
  REMOVE_NUMBERS_FROM_STRING
21
};
22
23
enum StreamType {
24
  STDOUT,
25
  STDERR
26
};
27
28
struct AsyncTest {
29
  std::string class_name;
30
  std::string expected_output;
31
  std::function<void()> fn;
32
  CompareType compare_type;
33
  StreamType stream_type;
34
};
35
36
extern std::vector<AsyncTest> generateTests();
37
static std::vector<AsyncTest> tests = generateTests();
38
39
class TestResult {
40
 public:
41
192
  static inline TestResult &getInstance() {
42

192
    static TestResult instance{};
43
192
    return instance;
44
  }
45
46
  /**
47
   * Returns test result by test name
48
   * @param test_name
49
   * @return true on success otherwise false
50
   */
51
96
  inline bool get(const std::string &test_name) {
52
#if __cplusplus >= 201703L
53
192
    std::scoped_lock<std::mutex> lock(test_result_mutex_);
54
#elif __cplusplus >= 201103L
55
    std::lock_guard<std::mutex> lock(test_result_mutex_);
56
#endif
57
58
96
    LOG_INIT(*test_argv);
59
96
    if (!started_) {
60
5
      started_ = true;
61
5
      startAll();
62
    }
63
64

96
    if (test_results.find(test_name) == test_results.end()) {
65
      return false;
66
    }
67
68
96
    bool res = test_results.at(test_name);
69
96
    return res;
70
  }
71
72
 private:
73
5
  static inline void startAll() {
74
10
    std::vector<std::thread> thread_pool{};
75
101
    for (const auto &t: tests) {
76
96
      thread_pool.emplace_back(&TestResult::startTimed, &TestResult::getInstance(), t);
77
    }
78
79
101
    for (auto &t: thread_pool) {
80
96
      t.join();
81
    }
82
5
  }
83
84
2880
  static inline void startCapture(StreamType stream_type) {
85
2880
    switch (stream_type) {
86
1620
      case STDOUT: testing::internal::CaptureStdout();
87
1620
        return;
88
1260
      case STDERR: testing::internal::CaptureStderr();
89
1260
        return;
90
    }
91
  }
92
93
2880
  static inline std::string stopCapture(StreamType stream_type) {
94
2880
    switch (stream_type) {
95
1620
      case STDOUT: return testing::internal::GetCapturedStdout();
96
97
1260
      case STDERR: return testing::internal::GetCapturedStderr();
98
    }
99
    abort();
100
  }
101
102
96
  inline void startTimed(const AsyncTest &a) {
103
96
    bool test_status = true;
104
105
2976
    for (int i = 0; i < 30; i++) {
106
2880
      stdout_capture_mutex_.lock();
107
2880
      startCapture(a.stream_type);
108
2880
      a.fn();
109
5760
      std::string output = stopCapture(a.stream_type);
110
2880
      stdout_capture_mutex_.unlock();
111
112

2880
      if ((i == 0 || i % 4 == 0)) {
113

768
        if (!compare(a.compare_type, output, a.expected_output)) {
114
          std::cout << a.class_name << " failed. Output: " << output << " expected output: " << a.expected_output
115
                    << std::endl;
116
          test_status = false;
117
        }
118

2112
      } else if (!compare(a.compare_type, output, "")) {
119
        std::cout << a.class_name << " failed. Output: " << output << " expected output: " << "\"\"" << std::endl;
120
        test_status = false;
121
      }
122
2880
      usleep(250000.);
123
    }
124
96
    insert(a.class_name, test_status);
125
96
  }
126
127
  //gtest assertions only work on main thread
128
2880
  static inline bool compare(CompareType compare_type, const std::string &output, const std::string &expected_output) {
129

2880
    switch (compare_type) {
130
900
      case EQUAL:return compareEquality(output, expected_output);
131
1380
      case IS_SUBSTRING: return compareSubstring(output, expected_output);
132
600
      case REMOVE_NUMBERS_FROM_STRING: return compareRemoveNumbersFromString(output, expected_output);
133
      default:return false;
134
    }
135
  }
136
137
1380
  static inline bool compareSubstring(const std::string &output, const std::string &expected_output) {
138
1380
    if (expected_output.empty()) {
139
1132
      return output.empty();
140
    }
141
248
    return isSubstring(output, expected_output);
142
  };
143
144
900
  static inline bool compareEquality(const std::string &output, const std::string &expected_output) {
145
900
    return output == expected_output;
146
  };
147
148
600
  static inline bool compareRemoveNumbersFromString(const std::string &output, const std::string &expected_output) {
149
600
    return expected_output == removeNumbersFromString(output);
150
  }
151
152
96
  inline void insert(const std::string &test_name, bool test_status) {
153
96
    test_results.insert({test_name, test_status});
154
96
  }
155
156
5
  TestResult() = default;
157
158
  bool started_{false};
159
  std::mutex test_result_mutex_;
160
  std::mutex stdout_capture_mutex_;
161
  std::map<std::string, bool> test_results;
162
};
163
164
#endif //LOG_TEST_COMMON_ASYNC_TESTS_H_