• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 21798667093

08 Feb 2026 01:06PM UTC coverage: 91.642% (+1.6%) from 90.068%
21798667093

push

github

web-flow
Merge pull request #5266 from randombit/jack/test-simd-fn

Remove support for AltiVec on 32-bit PowerPC

104029 of 113517 relevant lines covered (91.64%)

11219645.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.24
/src/tests/runner/test_runner.cpp
1
/*
2
* (C) 2017 Jack Lloyd
3
* (C) 2022 René Meusel, Rohde & Schwarz Cybersecurity
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include "../tests.h"
9

10
#include "test_runner.h"
11
#include "test_stdout_reporter.h"
12
#include "test_xml_reporter.h"
13

14
#include <botan/hex.h>
15
#include <botan/version.h>
16
#include <botan/internal/loadstor.h>
17

18
#if defined(BOTAN_HAS_CPUID)
19
   #include <botan/internal/cpuid.h>
20
#endif
21

22
#if defined(BOTAN_HAS_THREAD_UTILS)
23
   #include <botan/internal/rwlock.h>
24
   #include <botan/internal/thread_pool.h>
25
#endif
26

27
#include <shared_mutex>
28

29
namespace Botan_Tests {
30

31
Test_Runner::Test_Runner(std::ostream& out) : m_output(out) {}
1✔
32

33
Test_Runner::~Test_Runner() = default;
1✔
34

35
bool Test_Runner::run(const Test_Options& options) {
1✔
36
   if(!options.no_stdout()) {
1✔
37
      m_reporters.emplace_back(std::make_unique<StdoutReporter>(options, output()));
2✔
38
   }
39
   if(!options.xml_results_dir().empty()) {
1✔
40
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
41
      m_reporters.emplace_back(std::make_unique<XmlReporter>(options, options.xml_results_dir()));
2✔
42
#else
43
      output() << "Generating test report files is not supported on this platform\n";
44
#endif
45
   }
46

47
   auto req = Botan_Tests::Test::filter_registered_tests(options.requested_tests(), options.skip_tests());
1✔
48

49
   // TODO: Test runner should not be aware of certain test's environmental requirements.
50
   if(options.pkcs11_lib().empty()) {
1✔
51
      // do not run pkcs11 tests by default unless pkcs11-lib set
52
      for(auto iter = req.begin(); iter != req.end();) {
×
53
         if((*iter).find("pkcs11") != std::string::npos) {
×
54
            iter = req.erase(iter);
×
55
         } else {
56
            ++iter;
×
57
         }
58
      }
59
   }
60

61
   if(req.empty()) {
1✔
62
      throw Test_Error("No tests to run");
×
63
   }
64

65
   std::vector<uint8_t> seed = Botan::hex_decode(options.drbg_seed());
1✔
66
   if(seed.empty()) {
1✔
67
      const uint64_t ts = Botan_Tests::Test::timestamp();
1✔
68
      seed.resize(8);
1✔
69
      Botan::store_be(ts, seed.data());
1✔
70
   }
71

72
   for(auto& reporter : m_reporters) {
3✔
73
#if defined(BOTAN_HAS_CPUID)
74
      const std::string cpuid = Botan::CPUID::to_string();
2✔
75
      if(!cpuid.empty()) {
2✔
76
         reporter->set_property("CPU flags", cpuid);
4✔
77
      }
78
#endif
79

80
      if(!options.pkcs11_lib().empty()) {
2✔
81
         reporter->set_property("pkcs11 library", options.pkcs11_lib());
4✔
82
      }
83

84
      if(!options.provider().empty()) {
2✔
85
         reporter->set_property("provider", options.provider());
×
86
      }
87

88
      reporter->set_property("drbg_seed", Botan::hex_encode(seed));
4✔
89
   }
2✔
90

91
   Botan_Tests::Test::set_test_options(options);
1✔
92

93
   for(size_t i = 0; i != options.test_runs(); ++i) {
2✔
94
      Botan_Tests::Test::set_test_rng_seed(seed, i);
1✔
95

96
      for(const auto& reporter : m_reporters) {
3✔
97
         reporter->next_test_run();
2✔
98
      }
99

100
      const bool passed =
1✔
101
         (options.test_threads() == 1) ? run_tests(req) : run_tests_multithreaded(req, options.test_threads());
1✔
102

103
      for(const auto& reporter : m_reporters) {
3✔
104
         reporter->render();
2✔
105
      }
106

107
      if(!passed) {
1✔
108
         return false;
109
      }
110
   }
111

112
   return true;
113
}
1✔
114

115
namespace {
116

117
std::vector<Test::Result> run_a_test(const std::string& test_name) {
419✔
118
   std::vector<Test::Result> results;
419✔
119

120
   try {
419✔
121
      if(std::unique_ptr<Test> test = Test::get_test(test_name)) {
419✔
122
         std::vector<Test::Result> test_results = test->run();
419✔
123
         for(auto& result : test_results) {
51,111✔
124
            if(!result.code_location() && test->registration_location()) {
50,692✔
125
               // If a test result has no specific code location associated to it,
126
               // we fall back to the test case's registration location.
127
               result.set_code_location(test->registration_location().value());
50,692✔
128
            }
129
         }
130
         results.insert(results.end(), test_results.begin(), test_results.end());
419✔
131
      } else {
419✔
132
         results.push_back(Test::Result::Note(test_name, "Test missing or unavailable"));
×
133
      }
419✔
134
   } catch(std::exception& e) {
×
135
      results.push_back(Test::Result::Failure(test_name, e.what()));
×
136
   } catch(...) {
×
137
      results.push_back(Test::Result::Failure(test_name, "unknown exception"));
×
138
   }
×
139

140
   return results;
419✔
141
}
×
142

143
bool all_passed(const std::vector<Test::Result>& results) {
419✔
144
   return std::all_of(results.begin(), results.end(), [](const auto& r) { return r.tests_failed() == 0; });
13,081✔
145
}
146

147
}  // namespace
148

149
bool Test_Runner::run_tests_multithreaded(const std::vector<std::string>& tests_to_run, size_t test_threads) {
1✔
150
   // If 0 then we let thread pool select the count
151
   BOTAN_ASSERT_NOMSG(test_threads != 1);
1✔
152

153
#if !defined(BOTAN_HAS_THREAD_UTILS)
154
   output() << "Running tests in multiple threads not enabled in this build\n";
155
   return run_tests(tests_to_run);
156

157
#else
158
   Botan::Thread_Pool pool(test_threads);
1✔
159
   Botan::RWLock rwlock;
1✔
160

161
   std::vector<std::future<std::vector<Test::Result>>> fut_results;
1✔
162

163
   auto run_test_exclusive = [&](const std::string& test_name) {
22✔
164
      const std::unique_lock lk(rwlock);
21✔
165
      return run_a_test(test_name);
21✔
166
   };
21✔
167

168
   auto run_test_shared = [&](const std::string& test_name) {
399✔
169
      const std::shared_lock lk(rwlock);
398✔
170
      return run_a_test(test_name);
398✔
171
   };
398✔
172

173
   for(const auto& test_name : tests_to_run) {
420✔
174
      if(Test::test_needs_serialization(test_name)) {
419✔
175
         fut_results.push_back(pool.run(run_test_exclusive, test_name));
42✔
176
      } else {
177
         fut_results.push_back(pool.run(run_test_shared, test_name));
796✔
178
      }
179
   }
180

181
   bool passed = true;
182
   for(size_t i = 0; i != fut_results.size(); ++i) {
420✔
183
      for(auto& reporter : m_reporters) {
1,257✔
184
         reporter->waiting_for_next_results(tests_to_run[i]);
838✔
185
      }
186
      const auto results = fut_results[i].get();
419✔
187
      for(auto& reporter : m_reporters) {
1,257✔
188
         reporter->record(tests_to_run[i], results);
838✔
189
      }
190
      passed &= all_passed(results);
419✔
191
   }
419✔
192

193
   pool.shutdown();
1✔
194

195
   return passed;
1✔
196
#endif
197
}
2✔
198

199
bool Test_Runner::run_tests(const std::vector<std::string>& tests_to_run) {
×
200
   bool passed = true;
×
201
   for(const auto& test_name : tests_to_run) {
×
202
      for(auto& reporter : m_reporters) {
×
203
         reporter->waiting_for_next_results(test_name);
×
204
      }
205
      const auto results = run_a_test(test_name);
×
206

207
      for(auto& reporter : m_reporters) {
×
208
         reporter->record(test_name, results);
×
209
      }
210
      passed &= all_passed(results);
×
211
   }
×
212

213
   return passed;
×
214
}
215

216
}  // namespace Botan_Tests
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc