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

randombit / botan / 20712771074

05 Jan 2026 10:39AM UTC coverage: 90.422% (-0.007%) from 90.429%
20712771074

Pull #5209

github

web-flow
Merge 8ef1d9177 into cf0e68e34
Pull Request #5209: Improve support for running tests on Emscripten

101646 of 112413 relevant lines covered (90.42%)

12824143.69 hits per line

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

81.71
/src/tests/test_os_utils.cpp
1
/*
2
* Testing operating system specific wrapper code
3
* (C) 2017 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include "tests.h"
9

10
#if defined(BOTAN_HAS_OS_UTILS)
11
   #include <botan/internal/os_utils.h>
12
   #include <botan/internal/target_info.h>
13
#endif
14

15
namespace Botan_Tests {
16

17
#if defined(BOTAN_HAS_OS_UTILS)
18

19
namespace {
20

21
/*
22
uint32_t get_process_id();
23
uint64_t get_cpu_cycle_counter();
24
uint64_t get_system_timestamp_ns();
25
size_t get_memory_locking_limit();
26
void* allocate_locked_pages(size_t length);
27
void free_locked_pages(void* ptr, size_t length);
28
int run_cpu_instruction_probe(std::function<int ()> probe_fn);
29
*/
30

31
class OS_Utils_Tests final : public Test {
1✔
32
   public:
33
      std::vector<Test::Result> run() override {
1✔
34
         std::vector<Test::Result> results;
1✔
35

36
         results.push_back(test_get_process_id());
2✔
37
         results.push_back(test_get_cpu_cycle_counter());
2✔
38
         results.push_back(test_get_high_resolution_clock());
2✔
39
         results.push_back(test_get_cpu_numbers());
2✔
40
         results.push_back(test_get_system_timestamp());
2✔
41
         results.push_back(test_memory_locking());
2✔
42
         results.push_back(test_cpu_instruction_probe());
2✔
43

44
         return results;
1✔
45
      }
×
46

47
   private:
48
      static Test::Result test_get_process_id() {
1✔
49
         Test::Result result("OS::get_process_id");
1✔
50

51
         const uint32_t pid1 = Botan::OS::get_process_id();
1✔
52
         const uint32_t pid2 = Botan::OS::get_process_id();
1✔
53

54
         result.test_eq("PID same across calls", static_cast<size_t>(pid1), static_cast<size_t>(pid2));
1✔
55

56
   #if defined(BOTAN_TARGET_OS_IS_LLVM) || defined(BOTAN_TARGET_OS_IS_NONE)
57
         result.test_eq("PID is expected to be zero on this platform", pid1, size_t(0));
58
   #else
59
         result.test_ne("PID is non-zero on systems with processes", pid1, 0);
1✔
60
   #endif
61

62
         return result;
1✔
63
      }
×
64

65
      static Test::Result test_get_cpu_cycle_counter() {
1✔
66
         const size_t max_trials = 1024;
1✔
67
         const size_t max_repeats = 32;
1✔
68

69
         Test::Result result("OS::get_cpu_cycle_counter");
1✔
70

71
         const uint64_t proc_ts1 = Botan::OS::get_cpu_cycle_counter();
1✔
72

73
         if(proc_ts1 == 0) {
1✔
74
            const uint64_t proc_ts2 = Botan::OS::get_cpu_cycle_counter();
×
75
            result.test_is_eq("Disabled processor timestamp stays at zero", proc_ts1, proc_ts2);
×
76
            return result;
×
77
         }
78

79
         size_t counts = 0;
80
         while(counts < max_trials && (Botan::OS::get_cpu_cycle_counter() == proc_ts1)) {
1✔
81
            ++counts;
×
82
         }
83

84
         result.test_lt("CPU cycle counter eventually changes value", counts, max_repeats);
1✔
85

86
         return result;
1✔
87
      }
×
88

89
      static Test::Result test_get_high_resolution_clock() {
1✔
90
         // We can easily test progression; however, testing precision is trickier.
91
         // On very fast machines with very low clock resolution (like the web platform offers),
92
         // it may be necessary to make the call quite a few times to notice any change.
93
         constexpr auto max_trials = 32768;
1✔
94

95
         Test::Result result("OS::get_high_resolution_clock");
1✔
96

97
         // TODO better tests
98
         const auto hr_ts1 = Botan::OS::get_high_resolution_clock();
1✔
99
         result.confirm("high resolution timestamp value is never zero", hr_ts1 != 0);
2✔
100

101
         for(size_t trials = 0; trials < max_trials; ++trials) {
1✔
102
            if(hr_ts1 < Botan::OS::get_high_resolution_clock()) {
1✔
103
               result.test_success("high resolution clock made forward progress");
1✔
104
               return result;
1✔
105
            }
106
         }
107

108
         result.test_failure("high resolution clock didn't make forward progress, even after many trials");
×
109

110
         return result;
×
111
      }
×
112

113
      static Test::Result test_get_cpu_numbers() {
1✔
114
         Test::Result result("OS::get_cpu_available");
1✔
115

116
         const size_t ta = Botan::OS::get_cpu_available();
1✔
117

118
         result.test_gte("get_cpu_available is at least 1", ta, 1);
1✔
119

120
         return result;
1✔
121
      }
×
122

123
      static Test::Result test_get_system_timestamp() {
1✔
124
         // TODO better tests
125
         Test::Result result("OS::get_system_timestamp_ns");
1✔
126

127
         const uint64_t sys_ts1 = Botan::OS::get_system_timestamp_ns();
1✔
128
         result.confirm("System timestamp value is never zero", sys_ts1 != 0);
2✔
129

130
         // do something that consumes a little time
131
         Botan::OS::get_process_id();
1✔
132

133
         const uint64_t sys_ts2 = Botan::OS::get_system_timestamp_ns();
1✔
134

135
         result.confirm("System time moves forward", sys_ts1 <= sys_ts2);
2✔
136

137
         return result;
1✔
138
      }
×
139

140
      static Test::Result test_memory_locking() {
1✔
141
         Test::Result result("OS memory locked pages");
1✔
142

143
         // TODO any tests...
144

145
         return result;
1✔
146
      }
147

148
      static Test::Result test_cpu_instruction_probe() {
1✔
149
         Test::Result result("OS::run_cpu_instruction_probe");
1✔
150

151
         // OS::run_cpu_instruction_probe is only implemented on systems supporting Unix-style signals
152

153
         const std::function<int()> ok_fn = []() noexcept -> int { return 5; };
1✔
154
         const int run_rc = Botan::OS::run_cpu_instruction_probe(ok_fn);
1✔
155

156
         if(run_rc == -3) {
1✔
157
            result.test_note("run_cpu_instruction_probe not implemented on this platform");
×
158
            return {result};
×
159
         }
160

161
         result.confirm("Correct result returned by working probe fn", run_rc == 5);
2✔
162

163
         std::function<int()> crash_probe;
1✔
164

165
   #if defined(BOTAN_USE_GCC_INLINE_ASM)
166

167
      #if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY)
168
         crash_probe = []() noexcept -> int {
3✔
169
            asm volatile("ud2");  // NOLINT(*-no-assembler)
1✔
170
            return 3;
×
171
         };
1✔
172

173
      #elif defined(BOTAN_TARGET_ARCH_IS_ARM_FAMILY)
174
         //ARM: asm volatile (".word 0xf7f0a000\n");
175
         // illegal instruction in both ARM and Thumb modes
176
         crash_probe = []() noexcept -> int {
177
            asm volatile(".word 0xe7f0def0\n");  // NOLINT(*-no-assembler)
178
            return 3;
179
         };
180

181
      #else
182
               /*
183
         PPC: "The instruction with primary opcode 0, when the instruction does not consist
184
         entirely of binary zeros"
185
         Others ?
186
         */
187
      #endif
188

189
   #endif
190

191
         if(crash_probe) {
1✔
192
            const int crash_rc = Botan::OS::run_cpu_instruction_probe(crash_probe);
1✔
193
            result.confirm("Result for function executing undefined opcode", crash_rc < 0);
2✔
194
         }
195

196
         return result;
1✔
197
      }
2✔
198
};
199

200
BOTAN_REGISTER_TEST("utils", "os_utils", OS_Utils_Tests);
201

202
}  // namespace
203

204
#endif
205

206
}  // 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