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

randombit / botan / 27930394332

22 Jun 2026 02:29AM UTC coverage: 89.361% (-2.3%) from 91.664%
27930394332

push

github

randombit
Escape control chars in X509_Certificate::to_string

111792 of 125101 relevant lines covered (89.36%)

10818223.53 hits per line

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

99.59
/src/tests/test_utils_bitvector.cpp
1
/*
2
 * (C) 2023-2024 Jack Lloyd
3
 * (C) 2023-2024 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
#if defined(BOTAN_HAS_BITVECTOR)
11
   #include <botan/hex.h>
12
   #include <botan/rng.h>
13
   #include <botan/internal/bitvector.h>
14
   #include <botan/internal/fmt.h>
15
   #include <algorithm>
16
   #include <numeric>
17
   #include <set>
18
#endif
19

20
namespace Botan_Tests {
21

22
namespace {
23

24
#if defined(BOTAN_HAS_BITVECTOR)
25

26
/// Returns a random number in the range [min, max)
27
size_t rand_in_range(Botan::RandomNumberGenerator& rng, size_t min, size_t max) {
124✔
28
   if(min == max) {
124✔
29
      return min;
30
   }
31

32
   const size_t val = Botan::load_le<size_t>(rng.random_array<sizeof(size_t)>());
124✔
33
   return min + (val % (max - min));
124✔
34
}
35

36
/// Returns @p n integers smaller than @p upper_bound in random order
37
std::vector<size_t> rand_indices(Botan::RandomNumberGenerator& rng, size_t n, size_t upper_bound) {
3✔
38
   auto shuffle = [&](std::vector<size_t>& v) {
6✔
39
      // Fisher-Yates shuffle
40
      if(v.size() < 2) {
3✔
41
         return;
42
      }
43
      for(size_t i = 0; i < v.size() - 1; ++i) {
121✔
44
         auto j = rand_in_range(rng, i, v.size());
118✔
45
         std::swap(v[i], v[j]);
118✔
46
      }
47
   };
3✔
48

49
   std::vector<size_t> indices(upper_bound);
3✔
50
   std::iota(indices.begin(), indices.end(), 0);
3✔
51
   shuffle(indices);
3✔
52
   indices.resize(n);
3✔
53
   return indices;
3✔
54
}
×
55

56
/// Create an empty bitvector of random size and chose a random number of points of interests
57
std::pair<Botan::bitvector, std::set<size_t>> rnd_bitvector_with_rnd_pois(Botan::RandomNumberGenerator& rng) {
3✔
58
   const Botan::bitvector bv(rand_in_range(rng, 0, 65));
3✔
59
   const size_t no_poi = rand_in_range(rng, 0, bv.size());
3✔
60
   auto points_of_interest = rand_indices(rng, no_poi, bv.size());
3✔
61

62
   return {bv, {points_of_interest.begin(), points_of_interest.end()}};
6✔
63
}
6✔
64

65
template <size_t mod>
66
auto pattern_generator(size_t offset = 0) {
79✔
67
   return [i = offset]() mutable -> bool {
5,209✔
68
      const bool result = (i % mod) != 0;
5,209✔
69
      ++i;
5,209✔
70
      return result;
71
   };
72
}
73

74
std::vector<Test::Result> test_bitvector_bitwise_accessors(Botan::RandomNumberGenerator& rng) {
1✔
75
   return {
1✔
76
      CHECK("default constructed bitvector",
77
            [](auto& result) {
1✔
78
               const Botan::bitvector bv;
1✔
79
               result.test_is_true("default constructed bitvector is empty", bv.empty());
1✔
80
               result.test_sz_eq("default constructed bitvector has zero size", bv.size(), size_t(0));
1✔
81
            }),
1✔
82

83
      CHECK("preallocated construction of bitvector",
84
            [](auto& result) {
1✔
85
               Botan::bitvector bv(10);
1✔
86
               result.test_is_true("allocated bitvector is not empty", !bv.empty());
1✔
87
               result.test_sz_eq("allocated bitvector has allocated size", bv.size(), size_t(10));
1✔
88
               for(size_t i = 0; i < 10; ++i) {
11✔
89
                  result.test_is_true("bit not set yet", !bv.at(i));
10✔
90
               }
91
            }),
1✔
92

93
      CHECK("setting bits",
94
            [&](auto& result) {
1✔
95
               auto [bv, ones] = rnd_bitvector_with_rnd_pois(rng);
1✔
96

97
               for(const size_t i : ones) {
1✔
98
                  if(rng.next_byte() % 2 == 0) {
×
99
                     bv.set(i);
×
100
                  } else {
101
                     bv.at(i) = true;
×
102
                  }
103
               }
104
               for(size_t i = 0; i < bv.size(); ++i) {
36✔
105
                  result.test_is_true(Botan::fmt("bit {} in expected state", i), bv.at(i) == ones.contains(i));
105✔
106
               }
107
            }),
1✔
108

109
      CHECK("unsetting bits",
110
            [&](auto& result) {
1✔
111
               auto [bv, zeros] = rnd_bitvector_with_rnd_pois(rng);
1✔
112
               for(auto b : bv) {
45✔
113
                  b.set();
43✔
114
               }
115

116
               for(const size_t i : zeros) {
3✔
117
                  if(rng.next_byte() % 2 == 0) {
2✔
118
                     bv.unset(i);
1✔
119
                  } else {
120
                     bv.at(i) = false;
1✔
121
                  }
122
               }
123
               for(size_t i = 0; i < bv.size(); ++i) {
44✔
124
                  result.test_is_true(Botan::fmt("bit {} in expected state", i), bv.at(i) == !zeros.contains(i));
129✔
125
               }
126
            }),
1✔
127

128
      CHECK("flipping bits",
129
            [&](auto& result) {
1✔
130
               auto [bv, ones] = rnd_bitvector_with_rnd_pois(rng);
1✔
131

132
               for(size_t i = 0; i < bv.size(); ++i) {
44✔
133
                  if(std::find(ones.begin(), ones.end(), i) == ones.end()) {
86✔
134
                     bv.set(i);
21✔
135
                  }
136
                  bv.flip(i);
43✔
137
               }
138
               for(size_t i = 0; i < bv.size(); ++i) {
44✔
139
                  result.test_is_true(Botan::fmt("bit {} in expected state", i), bv.at(i) == ones.contains(i));
129✔
140
               }
141
            }),
1✔
142

143
      CHECK("accessors validate offsets",
144
            [](auto& result) {
1✔
145
               Botan::bitvector bv(10);
1✔
146
               result.template test_throws<Botan::Invalid_Argument>(
1✔
147
                  ".at() const out of range", [&] { const_cast<const decltype(bv)&>(bv).at(10); });
2✔
148
               result.template test_throws<Botan::Invalid_Argument>(".at() out of range", [&] { bv.at(10); });
2✔
149
               result.template test_throws<Botan::Invalid_Argument>(".set() out of range", [&] { bv.set(10); });
2✔
150
               result.template test_throws<Botan::Invalid_Argument>(".unset() out of range", [&] { bv.unset(10); });
2✔
151
               result.template test_throws<Botan::Invalid_Argument>(".flip() out of range", [&] { bv.flip(10); });
2✔
152
            }),
1✔
153

154
      CHECK("multiblock handling",
155
            [](auto& result) {
1✔
156
               Botan::bitvector bv(128);
1✔
157
               result.test_sz_eq("has more than 64 bits", bv.size(), 128);
1✔
158
               bv.set(1).set(63).set(64).set(127);
1✔
159
               for(size_t i = 0; i < bv.size(); ++i) {
129✔
160
                  const bool expected = (i == 1 || i == 63 || i == 64 || i == 127);
128✔
161
                  result.test_bool_eq(Botan::fmt("bit {} in expected state", i), bv.at(i), expected);
256✔
162
               }
163
            }),
1✔
164

165
      CHECK("subscript operator",
166
            [](auto& result) {
1✔
167
               Botan::bitvector bv(128);
1✔
168
               bv[0].set();
1✔
169
               bv[1] = true;
1✔
170
               bv[2].flip();
1✔
171
               bv[64] = true;
1✔
172
               bv[80] = true;
1✔
173
               result.test_is_true("bit 0", bv[0]);
1✔
174
               result.test_is_true("bit 1", bv[1]);
1✔
175
               result.test_is_true("bit 2", bv[2]);
1✔
176
               result.test_is_true("bit 3", !bv[3]);
1✔
177
               result.test_is_true("bit 64", bv[64]);
1✔
178
               result.test_is_true("bit 80", bv[80]);
1✔
179
            }),
1✔
180

181
      CHECK("subscript operator does not validate offsets",
182
            [](auto& result) {
1✔
183
               Botan::bitvector bv(10);
1✔
184
               result.template test_throws<Botan::Invalid_Argument>(".at() out of range", [&] { bv.at(10); });
2✔
185
               // Technically the next line is undefined behaviour.
186
               // Though, the current implementation detail won't
187
               // cause issues, which might change!
188
               result.test_no_throw("subscript out of range", [&] { bv[10]; });
1✔
189
            }),
1✔
190

191
      CHECK("bitwise assignment modifiers",
192
            [](auto& result) {
1✔
193
               Botan::bitvector bv(4);
1✔
194

195
               result.require("precondition", !bv[0] && !bv[1]);
1✔
196
               bv[0] &= 1;  // NOLINT(*-use-bool-literals)
1✔
197
               result.test_is_true("bv[0] still 0", !bv[0]);
1✔
198
               bv[0].set();
1✔
199
               bv[0] &= 1;  // NOLINT(*-use-bool-literals)
1✔
200
               result.test_is_true("bv[0] still 1", bv[0]);
1✔
201
               bv[0] &= false;
1✔
202
               result.test_is_true("bv[0] now 0 again", !bv[0]);
1✔
203
               bv[0] &= !bv[1];
1✔
204
               result.test_is_true("bv[0] still 0 once more", !bv[0]);
1✔
205

206
               result.require("precondition 2", !bv[1] && !bv[2]);
1✔
207
               bv[1] |= 1;  // NOLINT(modernize-use-bool-literals)
1✔
208
               result.test_is_true("bv[1] is now 1", bv[1]);
1✔
209
               bv[1] |= 0;  // NOLINT(modernize-use-bool-literals)
1✔
210
               result.test_is_true("bv[1] is still 1", bv[1]);
1✔
211
               bv[1].unset();
1✔
212
               bv[1] |= false;
1✔
213
               result.test_is_true("bv[1] is 0", !bv[1]);
1✔
214
               bv[1] |= !bv[2];
1✔
215
               result.test_is_true("bv[1] is 1 again", bv[1]);
1✔
216

217
               result.require("precondition 3", !bv[2] && !bv[3]);
1✔
218
               bv[2] ^= 0;  // NOLINT(modernize-use-bool-literals)
1✔
219
               result.test_is_true("bv[2] is still 0", !bv[2]);
1✔
220
               bv[2] ^= true;
1✔
221
               result.test_is_true("bv[2] is now 1", bv[2]);
1✔
222
               bv[2] ^= !bv[3];
1✔
223
               result.test_is_true("bv[2] is 0 again", !bv[2]);
1✔
224
            }),
1✔
225

226
      CHECK("CT::Choice bit modifiers",
227
            [](auto& result) {
1✔
228
               Botan::bitvector bv(6);
1✔
229

230
               bv[0] = Botan::CT::Choice::yes();
1✔
231
               bv[1] = Botan::CT::Choice::no();
1✔
232
               bv[2] |= Botan::CT::Choice::yes();
1✔
233
               bv[3].set();
1✔
234
               bv[3] &= Botan::CT::Choice::no();
1✔
235
               bv[4] ^= Botan::CT::Choice::yes();
1✔
236

237
               result.test_is_true("CT::Choice assignment set", bv[0]);
1✔
238
               result.test_is_true("CT::Choice assignment cleared", !bv[1]);
1✔
239
               result.test_is_true("CT::Choice or", bv[2]);
1✔
240
               result.test_is_true("CT::Choice and", !bv[3]);
1✔
241
               result.test_is_true("CT::Choice xor", bv[4]);
1✔
242
               result.test_is_true("CT::Choice untouched", !bv[5]);
1✔
243
            }),
1✔
244
   };
12✔
245
}
1✔
246

247
std::vector<Test::Result> test_bitvector_capacity(Botan::RandomNumberGenerator& /*rng*/) {
1✔
248
   return {
1✔
249
      CHECK("default constructed bitvector",
250
            [](auto& result) {
1✔
251
               const Botan::bitvector bv;
1✔
252
               result.test_is_true("empty", bv.empty());
1✔
253
               result.test_sz_eq("no size", bv.size(), size_t(0));
1✔
254
               result.test_sz_eq("no capacity", bv.capacity(), size_t(0));
1✔
255
            }),
1✔
256

257
      CHECK("allocated bitvector has capacity",
258
            [](auto& result) {
1✔
259
               const Botan::bitvector bv(1);
1✔
260
               result.test_is_true("empty", !bv.empty());
1✔
261
               result.test_sz_eq("small size", bv.size(), size_t(1));
1✔
262
               result.test_sz_gte("a little capacity", bv.capacity(), size_t(8));
1✔
263
            }),
1✔
264

265
      CHECK("reserved bitvector has capacity",
266
            [](auto& result) {
1✔
267
               Botan::bitvector bv;
1✔
268
               result.test_sz_eq("no size", bv.size(), size_t(0));
1✔
269
               result.test_sz_eq("no capacity", bv.capacity(), size_t(0));
1✔
270

271
               bv.reserve(64);
1✔
272
               result.test_sz_eq("no size", bv.size(), size_t(0));
1✔
273
               result.test_sz_gte("no capacity", bv.capacity(), size_t(64));
1✔
274

275
               bv.reserve(128);
1✔
276
               result.test_sz_eq("no size", bv.size(), size_t(0));
1✔
277
               result.test_sz_gte("no capacity", bv.capacity(), size_t(128));
1✔
278
            }),
1✔
279

280
      CHECK("push_back() extends bitvector",
281
            [](Test::Result& result) {
1✔
282
               Botan::bitvector bv;
1✔
283
               result.test_is_true("empty", bv.empty());
1✔
284
               result.test_sz_eq("no size", bv.size(), size_t(0));
1✔
285

286
               bv.push_back(true);
1✔
287
               bv.push_back(false);
1✔
288
               bv.push_back(true);
1✔
289
               bv.push_back(false);
1✔
290
               bv.push_back(Botan::CT::Choice::yes());
1✔
291
               bv.push_back(Botan::CT::Choice::no());
1✔
292

293
               result.test_is_true("not empty", !bv.empty());
1✔
294
               result.test_sz_eq("some size", bv.size(), size_t(6));
1✔
295
               result.test_sz_gte("capacity is typically bigger than size", bv.capacity(), size_t(8));
1✔
296

297
               result.test_is_true("bit 0", bv.at(0));
1✔
298
               result.test_is_true("bit 1", !bv.at(1));
1✔
299
               result.test_is_true("bit 2", bv.at(2));
1✔
300
               result.test_is_true("bit 3", !bv.at(3));
1✔
301
               result.test_is_true("bit 4", bv.at(4));
1✔
302
               result.test_is_true("bit 5", !bv.at(5));
1✔
303

304
               result.test_throws("bit 6 is not yet allocated", [&] { bv.at(6); });
2✔
305
            }),
1✔
306

307
      CHECK("pop_back() shortens bitvector",
308
            [](Test::Result& result) {
1✔
309
               Botan::bitvector bv;
1✔
310
               bv.push_back(true);
1✔
311
               bv.push_back(false);
1✔
312
               bv.push_back(true);
1✔
313
               bv.push_back(false);
1✔
314
               result.test_is_true("last is false", !bv.back());
1✔
315

316
               bv.pop_back();
1✔
317
               result.test_sz_eq("size() == 3", bv.size(), 3);
1✔
318
               result.test_is_true("last is true", bv.back());
1✔
319

320
               bv.pop_back();
1✔
321
               result.test_sz_eq("size() == 2", bv.size(), 2);
1✔
322
               result.test_is_true("last is false", !bv.back());
1✔
323

324
               bv.pop_back();
1✔
325
               result.test_sz_eq("size() == 1", bv.size(), 1);
1✔
326
               result.test_is_true("last is true", bv.back());
1✔
327
               result.test_is_true("first is true", bv.front());
1✔
328

329
               bv.pop_back();
1✔
330
               result.test_is_true("empty", bv.empty());
1✔
331

332
               result.test_throws("bit 4 is not yet allocated", [&] { bv.at(4); });
2✔
333
            }),
1✔
334

335
      CHECK("resize()",
336
            [](auto& result) {
1✔
337
               Botan::bitvector bv(10);
1✔
338
               bv[0] = true;
1✔
339
               bv[5] = true;
1✔
340
               bv[9] = true;
1✔
341

342
               bv.resize(8);
1✔
343
               result.test_sz_eq("size is reduced", bv.size(), size_t(8));
1✔
344

345
               for(size_t i = 0; i < bv.size(); ++i) {
9✔
346
                  const bool expected = (i == 0 || i == 5);
8✔
347
                  result.test_bool_eq(Botan::fmt("{} is as expected", i), bv[i], expected);
16✔
348
               }
349

350
               bv.resize(0);
1✔
351
               result.test_is_true("resize(0) empties buffer", bv.empty());
1✔
352

353
               bv.resize(8);
1✔
354
               result.test_is_true("0 is false", !bv[0]);
1✔
355
               result.test_is_true("5 is false", !bv[5]);
1✔
356
            }),
1✔
357

358
      CHECK("binary bitwise and comparison operators",
359
            [](Test::Result& result) {
1✔
360
               Botan::bitvector a(8);
1✔
361
               a.set(0).set(3);
1✔
362
               Botan::bitvector b(8);
1✔
363
               b.set(1).set(3);
1✔
364
               Botan::bitvector c(8);
1✔
365
               c.set(0).set(3);  // same is a
1✔
366

367
               result.test_is_true("equal bitvectors compare equal", a == c);
2✔
368
               result.test_is_true("different bitvectors do not compare equal", !(a == b));
2✔
369
               result.test_is_true("different bitvectors compare not equal", a != b);
2✔
370
               result.test_is_true("equal bitvectors do not compare not equal", !(a != c));
2✔
371

372
               auto or_ab = a | b;
1✔
373
               result.test_is_true("OR sets union bit 0", or_ab.at(0).is_set());
1✔
374
               result.test_is_true("OR sets union bit 1", or_ab.at(1).is_set());
1✔
375
               result.test_is_true("OR sets union bit 3", or_ab.at(3).is_set());
1✔
376
               result.test_is_true("OR leaves unset bit 2", !or_ab.at(2).is_set());
1✔
377

378
               auto and_ab = a & b;
1✔
379
               result.test_is_true("AND keeps common bit 3", and_ab.at(3).is_set());
1✔
380
               result.test_is_true("AND clears non-common bit 0", !and_ab.at(0).is_set());
1✔
381
               result.test_is_true("AND clears non-common bit 1", !and_ab.at(1).is_set());
1✔
382

383
               auto xor_ab = a ^ b;
1✔
384
               result.test_is_true("XOR sets differing bit 0", xor_ab.at(0).is_set());
1✔
385
               result.test_is_true("XOR sets differing bit 1", xor_ab.at(1).is_set());
1✔
386
               result.test_is_true("XOR clears common bit 3", !xor_ab.at(3).is_set());
1✔
387
            }),
6✔
388

389
      CHECK("comparison and reduction of empty bitvectors",
390
            [](Test::Result& result) {
1✔
391
               const Botan::bitvector empty1;
1✔
392
               const Botan::bitvector empty2;
1✔
393
               result.test_is_true("empty is empty", empty1.empty());
1✔
394
               result.test_sz_eq("empty has zero size", empty1.size(), size_t(0));
1✔
395

396
               // Full-range reductions on an empty bitvector must not throw or
397
               // terminate (the underlying buffer may be null).
398
               result.test_is_true("empty none()", empty1.none());
1✔
399
               result.test_is_true("empty none_vartime()", empty1.none_vartime());
1✔
400
               result.test_is_true("empty !any()", !empty1.any());
1✔
401
               result.test_is_true("empty !any_vartime()", !empty1.any_vartime());
1✔
402
               result.test_is_true("empty all()", empty1.all());
1✔
403
               result.test_is_true("empty all_vartime()", empty1.all_vartime());
1✔
404
               result.test_sz_eq("empty hamming_weight()", empty1.hamming_weight(), size_t(0));
1✔
405

406
               // Two empty bitvectors compare equal. equals() is constant-time
407
               // and noexcept, so a throw here would call std::terminate().
408
               result.test_is_true("empty equals empty", empty1.equals(empty2));
1✔
409
               result.test_is_true("empty equals_vartime empty", empty1.equals_vartime(empty2));
2✔
410
               result.test_is_true("empty == empty", empty1 == empty2);
2✔
411
               result.test_is_true("empty not != empty", !(empty1 != empty2));
2✔
412

413
               // Mismatched sizes must compare unequal without touching blocks.
414
               const Botan::bitvector nonempty(8);
1✔
415
               result.test_is_true("empty does not equal non-empty", !empty1.equals(nonempty));
1✔
416
               result.test_is_true("empty does not equal_vartime non-empty", !empty1.equals_vartime(nonempty));
2✔
417
               result.test_is_true("empty != non-empty", empty1 != nonempty);
2✔
418

419
               // Same coverage for the secure allocator, whose empty buffer is
420
               // likewise potentially null.
421
               const Botan::secure_bitvector sempty1;
1✔
422
               const Botan::secure_bitvector sempty2;
1✔
423
               result.test_is_true("empty secure none()", sempty1.none());
1✔
424
               result.test_is_true("empty secure equals empty", sempty1.equals(sempty2));
1✔
425
               result.test_is_true("empty secure == empty", sempty1 == sempty2);
2✔
426
            }),
2✔
427
   };
9✔
428
}
1✔
429

430
std::vector<Test::Result> test_bitvector_subvector(Botan::RandomNumberGenerator& /*rng*/) {
1✔
431
   auto make_bitpattern = [&]<typename T>(T& bitvector, size_t pattern_offset = 0) {
21✔
432
      auto next = pattern_generator<3>(pattern_offset);
20✔
433

434
      if constexpr(std::unsigned_integral<T>) {
435
         for(size_t i = 0; i < sizeof(T) * 8; ++i) {
316✔
436
            bitvector |= static_cast<T>(next()) << i;
304✔
437
         }
438
      } else {
439
         for(auto& i : bitvector) {
1,616✔
440
            i = next();
800✔
441
         }
442
      }
443
   };
8✔
444

445
   auto bitpattern_at = [&]<std::unsigned_integral T>(T /* ignored */, size_t pattern_offset) -> T {
13✔
446
      T bitvector = 0;
12✔
447
      make_bitpattern(bitvector, pattern_offset);
24✔
448
      return bitvector;
449
   };
1✔
450

451
   auto check_bitpattern = [&](auto& result, auto& bitvector, size_t offset = 0) {
44✔
452
      using bv_t = std::remove_cvref_t<decltype(bitvector)>;
453
      auto next = pattern_generator<3>(offset);
43✔
454

455
      if constexpr(std::unsigned_integral<bv_t>) {
456
         for(size_t i = 0; i < sizeof(bv_t) * 8; ++i) {
496✔
457
            result.test_bool_eq(Botan::fmt("{} is as expected", i), (bitvector & (bv_t(1) << i)) != 0, next());
960✔
458
         }
459
      } else {
460
         for(size_t i = 0; i < bitvector.size(); ++i) {
2,056✔
461
            result.test_bool_eq(Botan::fmt("{} is as expected", i), bitvector[i], next());
4,058✔
462
         }
463
      }
464
   };
43✔
465

466
   auto check_bitpattern_with_zero_region = [&](auto& result, auto& bitvector, std::pair<size_t, size_t> zero_region) {
13✔
467
      auto next = pattern_generator<3>();
12✔
468
      for(size_t i = 0; i < bitvector.size(); ++i) {
1,212✔
469
         const bool i_in_range = (zero_region.first <= i && i < zero_region.second);
1,200✔
470
         const bool expected = next();
1,200✔
471
         result.test_bool_eq(Botan::fmt("{} is as expected", i), bitvector[i], !i_in_range && expected);
2,400✔
472
      }
473
   };
12✔
474

475
   return {
1✔
476
      CHECK("range errors are caught",
477
            [&](auto& result) {
1✔
478
               const Botan::bitvector bv(100);
1✔
479
               result.template test_throws<Botan::Invalid_Argument>("out of range", [&] { bv.subvector(0, 101); });
2✔
480
               result.template test_throws<Botan::Invalid_Argument>("out of range", [&] { bv.subvector(90, 11); });
2✔
481
               result.template test_throws<Botan::Invalid_Argument>("out of range", [&] { bv.subvector(100, 1); });
2✔
482
               result.template test_throws<Botan::Invalid_Argument>("out of range", [&] { bv.subvector(101, 0); });
2✔
483
            }),
1✔
484

485
      CHECK("empty copy is allowed",
486
            [&](auto& result) {
1✔
487
               const Botan::bitvector bv1(100);
1✔
488
               auto bv2 = bv1.subvector(0, 0);
1✔
489
               result.test_sz_eq("empty at 0", bv2.size(), size_t(0));
1✔
490
               auto bv3 = bv1.subvector(10, 0);
1✔
491
               result.test_sz_eq("empty at 10", bv3.size(), size_t(0));
1✔
492
               auto bv4 = bv1.subvector(100, 0);
1✔
493
               result.test_sz_eq("empty at 100", bv3.size(), size_t(0));
1✔
494
            }),
2✔
495

496
      CHECK("byte-aligned copy",
497
            [&](auto& result) {
1✔
498
               Botan::bitvector bv1(100);
1✔
499
               make_bitpattern(bv1);
1✔
500

501
               auto bv2 = bv1.subvector(16, 58);
1✔
502
               result.test_sz_eq("size is as requested", bv2.size(), size_t(58));
1✔
503
               check_bitpattern(result, bv2, 16);
1✔
504

505
               auto bv3 = bv1.subvector(32);  // copy until the end
1✔
506
               result.test_sz_eq("size is as expected", bv3.size(), size_t(68));
1✔
507
               check_bitpattern(result, bv3, 32);
1✔
508
            }),
3✔
509

510
      CHECK("byte-aligned 2",
511
            [&](auto& result) {
1✔
512
               Botan::bitvector bv1(100);
1✔
513
               make_bitpattern(bv1);
1✔
514

515
               auto bv2 = bv1.subvector(8, 91);
1✔
516
               result.test_sz_eq("size is as expected", bv2.size(), size_t(91));
1✔
517
               check_bitpattern(result, bv2, 8);
1✔
518

519
               auto bv3 = bv1.subvector(16, 58);
1✔
520
               result.test_sz_eq("size is as requested", bv3.size(), size_t(58));
1✔
521
               check_bitpattern(result, bv3, 16);
1✔
522

523
               auto bv4 = bv1.subvector(24);  // copy until the end
1✔
524
               result.test_sz_eq("size is as expected", bv4.size(), size_t(100 - 24));
1✔
525
               check_bitpattern(result, bv4, 24);
1✔
526

527
               auto bv5 = bv1.subvector(32);  // copy until the end
1✔
528
               result.test_sz_eq("size is as expected", bv5.size(), size_t(100 - 32));
1✔
529
               check_bitpattern(result, bv5, 32);
1✔
530

531
               auto bv6 = bv1.subvector(48, 51);  // copy until the end
1✔
532
               result.test_sz_eq("size is as expected", bv6.size(), size_t(51));
1✔
533
               check_bitpattern(result, bv6, 48);
1✔
534
            }),
6✔
535

536
      CHECK("byte-aligned copy must zero-out unused bits",
537
            [&](auto& result) {
1✔
538
               Botan::bitvector bv1(100);
1✔
539
               make_bitpattern(bv1);
1✔
540

541
               auto bv2 = bv1.subvector(16, 17);
1✔
542
               result.test_sz_eq("size is as requested", bv2.size(), size_t(17));
1✔
543
               check_bitpattern(result, bv2, 16);
1✔
544

545
               bv2.resize(32);
1✔
546
               for(size_t i = 17; i < bv2.size(); ++i) {
16✔
547
                  result.test_is_true("tail is zero", !bv2[i]);
15✔
548
               }
549
            }),
2✔
550

551
      CHECK("unaligned copy",
552
            [&](auto& result) {
1✔
553
               Botan::bitvector bv1(100);
1✔
554
               make_bitpattern(bv1);
1✔
555

556
               auto bv2 = bv1.subvector(19, 69);
1✔
557
               result.test_sz_eq("size is as requested", bv2.size(), size_t(69));
1✔
558
               check_bitpattern(result, bv2, 19);
1✔
559

560
               auto bv3 = bv1.subvector(21);  // copy until the end
1✔
561
               result.test_sz_eq("size is as expected", bv3.size(), size_t(79));
1✔
562
               check_bitpattern(result, bv3, 21);
1✔
563

564
               auto bv4 = bv1.subvector(1, 16);
1✔
565
               result.test_sz_eq("size is as expected", bv4.size(), size_t(16));
1✔
566
               check_bitpattern(result, bv4, 1);
1✔
567

568
               auto bv5 = bv1.subvector(1, 32);
1✔
569
               result.test_sz_eq("size is as expected", bv5.size(), size_t(32));
1✔
570
               check_bitpattern(result, bv5, 1);
1✔
571

572
               auto bv6 = bv5.subvector(1, 12);
1✔
573
               result.test_sz_eq("size is as expected", bv6.size(), size_t(12));
1✔
574
               check_bitpattern(result, bv6, 1 + 1);
1✔
575

576
               auto bv7 = bv1.subvector(17, 67);
1✔
577
               result.test_sz_eq("size is as expected", bv7.size(), size_t(67));
1✔
578
               check_bitpattern(result, bv7, 17);
1✔
579

580
               auto bv8 = bv1.subvector(33);  // copy until the end
1✔
581
               result.test_sz_eq("size is as expected", bv8.size(), size_t(67));
1✔
582
               check_bitpattern(result, bv8, 33);
1✔
583
            }),
8✔
584

585
      CHECK("byte-aligned unsigned integer subvector",
586
            [&](auto& result) {
1✔
587
               Botan::bitvector bv1(100);
1✔
588
               make_bitpattern(bv1);
1✔
589

590
               const auto u8_0 = bv1.subvector<uint8_t>(0);
1✔
591
               const auto u8_32 = bv1.subvector<uint8_t>(32);
1✔
592
               check_bitpattern(result, u8_0, 0);
1✔
593
               check_bitpattern(result, u8_32, 32);
1✔
594

595
               const auto u16_0 = bv1.subvector<uint16_t>(0);
1✔
596
               const auto u16_56 = bv1.subvector<uint16_t>(56);
1✔
597
               check_bitpattern(result, u16_0, 0);
1✔
598
               check_bitpattern(result, u16_56, 56);
1✔
599

600
               const auto u32_0 = bv1.subvector<uint32_t>(0);
1✔
601
               const auto u32_48 = bv1.subvector<uint32_t>(48);
1✔
602
               check_bitpattern(result, u32_0, 0);
1✔
603
               check_bitpattern(result, u32_48, 48);
1✔
604

605
               const auto u64_0 = bv1.subvector<uint64_t>(0);
1✔
606
               const auto u64_32 = bv1.subvector<uint64_t>(32);
1✔
607
               check_bitpattern(result, u64_0, 0);
1✔
608
               check_bitpattern(result, u64_32, 32);
1✔
609

610
               result.test_throws("out of range (uint8_t)", [&] { bv1.subvector<uint8_t>(93); });
2✔
611
               result.test_throws("out of range (uint16_t)", [&] { bv1.subvector<uint16_t>(85); });
2✔
612
               result.test_throws("out of range (uint32_t)", [&] { bv1.subvector<uint32_t>(69); });
2✔
613
               result.test_throws("out of range (uint64_t)", [&] { bv1.subvector<uint64_t>(37); });
2✔
614
            }),
1✔
615

616
      CHECK("unaligned unsigned integer subvector",
617
            [&](Test::Result& result) {
1✔
618
               Botan::bitvector bv1(100);
1✔
619
               make_bitpattern(bv1);
1✔
620

621
               const auto u8_3 = bv1.subvector<uint8_t>(3);
1✔
622
               const auto u8_92 = bv1.subvector<uint8_t>(92);
1✔
623
               check_bitpattern(result, u8_3, 3);
1✔
624
               check_bitpattern(result, u8_92, 92);
1✔
625

626
               const auto u16_7 = bv1.subvector<uint16_t>(7);
1✔
627
               const auto u16_84 = bv1.subvector<uint16_t>(84);
1✔
628
               check_bitpattern(result, u16_7, 7);
1✔
629
               check_bitpattern(result, u16_84, 84);
1✔
630

631
               const auto u32_11 = bv1.subvector<uint32_t>(11);
1✔
632
               const auto u32_68 = bv1.subvector<uint32_t>(68);
1✔
633
               check_bitpattern(result, u32_11, 11);
1✔
634
               check_bitpattern(result, u32_68, 68);
1✔
635

636
               const auto u64_21 = bv1.subvector<uint64_t>(21);
1✔
637
               const auto u64_36 = bv1.subvector<uint64_t>(36);
1✔
638
               check_bitpattern(result, u64_21, 21);
1✔
639
               check_bitpattern(result, u64_36, 36);
1✔
640
            }),
1✔
641

642
      CHECK("byte-aligned unsigned integer subvector replacement",
643
            [&](auto& result) {
1✔
644
               Botan::bitvector bv1(100);
1✔
645
               make_bitpattern(bv1);
1✔
646

647
               bv1.subvector_replace(0, uint8_t(0));
1✔
648
               check_bitpattern_with_zero_region(result, bv1, {0, 8});
1✔
649
               bv1.subvector_replace(0, bitpattern_at(uint8_t(0), 0));
2✔
650
               check_bitpattern(result, bv1);
1✔
651

652
               bv1.subvector_replace(32, uint8_t(0));
1✔
653
               check_bitpattern_with_zero_region(result, bv1, {32, 32 + 8});
1✔
654
               bv1.subvector_replace(32, bitpattern_at(uint8_t(0), 32));
2✔
655
               check_bitpattern(result, bv1);
1✔
656

657
               bv1.subvector_replace(56, uint16_t(0));
1✔
658
               check_bitpattern_with_zero_region(result, bv1, {56, 56 + 16});
1✔
659
               bv1.subvector_replace(56, bitpattern_at(uint16_t(0), 56));
2✔
660
               check_bitpattern(result, bv1);
1✔
661

662
               bv1.subvector_replace(48, uint32_t(0));
1✔
663
               check_bitpattern_with_zero_region(result, bv1, {48, 48 + 32});
1✔
664
               bv1.subvector_replace(48, bitpattern_at(uint32_t(0), 48));
2✔
665
               check_bitpattern(result, bv1);
1✔
666

667
               bv1.subvector_replace(16, uint64_t(0));
1✔
668
               check_bitpattern_with_zero_region(result, bv1, {16, 16 + 64});
1✔
669
               bv1.subvector_replace(16, bitpattern_at(uint64_t(0), 16));
2✔
670
               check_bitpattern(result, bv1);
1✔
671

672
               result.test_throws("out of range (uint8_t)", [&] { bv1.subvector_replace<uint8_t>(93, 42); });
2✔
673
               result.test_throws("out of range (uint16_t)", [&] { bv1.subvector_replace<uint16_t>(85, 42); });
2✔
674
               result.test_throws("out of range (uint32_t)", [&] { bv1.subvector_replace<uint32_t>(69, 42); });
2✔
675
               result.test_throws("out of range (uint64_t)", [&] { bv1.subvector_replace<uint64_t>(37, 42); });
2✔
676
            }),
1✔
677

678
      CHECK("unaligned unsigned integer subvector replacement",
679
            [&](auto& result) {
1✔
680
               Botan::bitvector bv1(100);
1✔
681
               make_bitpattern(bv1);
1✔
682

683
               bv1.subvector_replace(3, uint8_t(0));
1✔
684
               check_bitpattern_with_zero_region(result, bv1, {3, 3 + 8});
1✔
685
               bv1.subvector_replace(3, bitpattern_at(uint8_t(0), 3));
2✔
686
               check_bitpattern(result, bv1);
1✔
687

688
               bv1.subvector_replace(92, uint8_t(0));
1✔
689
               check_bitpattern_with_zero_region(result, bv1, {92, 92 + 8});
1✔
690
               bv1.subvector_replace(92, bitpattern_at(uint8_t(0), 92));
2✔
691
               check_bitpattern(result, bv1);
1✔
692

693
               bv1.subvector_replace(7, uint16_t(0));
1✔
694
               check_bitpattern_with_zero_region(result, bv1, {7, 7 + 16});
1✔
695
               bv1.subvector_replace(7, bitpattern_at(uint16_t(0), 7));
2✔
696
               check_bitpattern(result, bv1);
1✔
697

698
               bv1.subvector_replace(84, uint16_t(0));
1✔
699
               check_bitpattern_with_zero_region(result, bv1, {84, 84 + 16});
1✔
700
               bv1.subvector_replace(84, bitpattern_at(uint16_t(0), 84));
2✔
701
               check_bitpattern(result, bv1);
1✔
702

703
               bv1.subvector_replace(11, uint32_t(0));
1✔
704
               check_bitpattern_with_zero_region(result, bv1, {11, 11 + 32});
1✔
705
               bv1.subvector_replace(11, bitpattern_at(uint32_t(0), 11));
2✔
706
               check_bitpattern(result, bv1);
1✔
707

708
               bv1.subvector_replace(68, uint32_t(0));
1✔
709
               check_bitpattern_with_zero_region(result, bv1, {68, 68 + 32});
1✔
710
               bv1.subvector_replace(68, bitpattern_at(uint32_t(0), 68));
2✔
711
               check_bitpattern(result, bv1);
1✔
712

713
               bv1.subvector_replace(21, uint64_t(0));
1✔
714
               check_bitpattern_with_zero_region(result, bv1, {21, 21 + 64});
1✔
715
               bv1.subvector_replace(21, bitpattern_at(uint64_t(0), 21));
2✔
716
               check_bitpattern(result, bv1);
1✔
717
            }),
1✔
718
   };
11✔
719
}
1✔
720

721
std::vector<Test::Result> test_bitvector_global_modifiers_and_predicates(Botan::RandomNumberGenerator& /*rng*/) {
1✔
722
   auto make_bitpattern = [](auto& bitvector) {
3✔
723
      auto next = pattern_generator<5>();
2✔
724
      for(auto& i : bitvector) {
400✔
725
         i = next();
198✔
726
      }
727
   };
2✔
728

729
   auto check_bitpattern = [](auto& result, auto& bitvector) {
2✔
730
      auto next = pattern_generator<5>();
1✔
731
      for(size_t i = 0; i < bitvector.size(); ++i) {
100✔
732
         result.test_bool_eq(Botan::fmt("{} is as expected", i), bitvector[i], next());
198✔
733
      }
734
   };
1✔
735

736
   auto check_flipped_bitpattern = [](auto& result, auto& bitvector) {
2✔
737
      auto next = pattern_generator<5>();
1✔
738
      for(size_t i = 0; i < bitvector.size(); ++i) {
100✔
739
         result.test_bool_eq(Botan::fmt("{} is as expected", i), bitvector[i], !next());
198✔
740
      }
741
   };
1✔
742

743
   return {
1✔
744
      CHECK("one bit",
745
            [](auto& result) {
1✔
746
               Botan::bitvector bv;
1✔
747
               bv.push_back(true);
1✔
748

749
               bv.flip();
1✔
750
               result.test_is_true("bit is flipped", !bv[0]);
1✔
751

752
               // check that unused bits aren't flipped
753
               bv.resize(8);
1✔
754
               for(auto&& b : bv) {
10✔
755
                  result.test_is_true("all bits are false", !b);
8✔
756
               }
757
               bv.resize(1);
1✔
758

759
               bv.flip();
1✔
760
               result.test_is_true("bit is flipped again", bv[0]);
1✔
761
            }),
1✔
762

763
      CHECK("bits in many blocks",
764
            [&](auto& result) {
1✔
765
               Botan::bitvector bv(99);
1✔
766

767
               make_bitpattern(bv);
1✔
768
               bv.flip();
1✔
769
               check_flipped_bitpattern(result, bv);
1✔
770

771
               bv = ~bv;
2✔
772
               check_bitpattern(result, bv);
1✔
773

774
               bv.resize(112);
1✔
775
               for(size_t i = 99; i < bv.size(); ++i) {
14✔
776
                  result.test_is_true("just-allocated bit is not set", !bv[i]);
13✔
777
               }
778
            }),
1✔
779

780
      CHECK("set and unset",
781
            [&](auto& result) {
1✔
782
               Botan::bitvector bv(99);
1✔
783

784
               make_bitpattern(bv);
1✔
785
               bv.set();
1✔
786
               bv.resize(128);
1✔
787
               for(size_t i = 0; i < bv.size(); ++i) {
129✔
788
                  const bool expected = (i < 99);
128✔
789
                  result.test_bool_eq("only set bits are set", bv[i], expected);
128✔
790
               }
791

792
               bv.unset();
1✔
793
               for(auto&& b : bv) {
130✔
794
                  result.test_is_true("bit is not set", !b);
128✔
795
               }
796
            }),
1✔
797

798
      CHECK("any, none and all",
799
            [&](auto& result) {
1✔
800
               Botan::bitvector bv(99);
1✔
801

802
               result.test_is_true("default construction yields all-zero", bv.none_vartime());
1✔
803
               result.test_is_true("default construction yields all-zero 2", !bv.any_vartime());
1✔
804
               result.test_is_true("default construction yields all-zero 3", !bv.all_vartime());
1✔
805
               result.test_is_true("default construction yields all-zero 4", bv.none());
1✔
806
               result.test_is_true("default construction yields all-zero 5", !bv.any());
1✔
807
               result.test_is_true("default construction yields all-zero 6", !bv.all());
1✔
808

809
               bv.set(42);
1✔
810
               result.test_is_true("setting a bit means there's a bit set", !bv.none_vartime());
1✔
811
               result.test_is_true("setting a bit means there's a bit set 2", bv.any_vartime());
1✔
812
               result.test_is_true("setting a bit means there's not all bits set", !bv.all_vartime());
1✔
813
               result.test_is_true("setting a bit means there's a bit set 3", !bv.none());
1✔
814
               result.test_is_true("setting a bit means there's a bit set 4", bv.any());
1✔
815
               result.test_is_true("setting a bit means there's not all bits set 2", !bv.all());
1✔
816

817
               bv.set();
1✔
818
               result.test_is_true("setting all bits means there's a bit set", !bv.none_vartime());
1✔
819
               result.test_is_true("setting all bits means there's a bit set 2", bv.any_vartime());
1✔
820
               result.test_is_true("setting all bits means all bits are set", bv.all_vartime());
1✔
821
               result.test_is_true("setting all bits means there's a bit set 3", !bv.none());
1✔
822
               result.test_is_true("setting all bits means there's a bit set 4", bv.any());
1✔
823
               result.test_is_true("setting all bits means all bits are set 2", bv.all());
1✔
824

825
               bv.unset(97);
1✔
826
               result.test_is_true("a single 0 at the end means that there's a bit set", !bv.none_vartime());
1✔
827
               result.test_is_true("a single 0 at the end means that there are bits set", bv.any_vartime());
1✔
828
               result.test_is_true("a single 0 at the end means that there are not all bits set", !bv.all_vartime());
1✔
829
               result.test_is_true("a single 0 at the end means that there's a bit set 2", !bv.none());
1✔
830
               result.test_is_true("a single 0 at the end means that there are bits set 2", bv.any());
1✔
831
               result.test_is_true("a single 0 at the end means that there are not all bits set 2", !bv.all());
1✔
832

833
               bv.unset();
1✔
834
               result.test_is_true("unsetting all bits means there's no bit set", bv.none_vartime());
1✔
835
               result.test_is_true("unsetting all bits means there's no bit set 2", !bv.any_vartime());
1✔
836
               result.test_is_true("unsetting all bits means there's not all bits set", !bv.all_vartime());
1✔
837
               result.test_is_true("unsetting all bits means there's no bit set 3", bv.none());
1✔
838
               result.test_is_true("unsetting all bits means there's no bit set 4", !bv.any());
1✔
839
               result.test_is_true("unsetting all bits means there's not all bits set 2", !bv.all());
1✔
840
            }),
1✔
841

842
      CHECK("hamming weight oddness",
843
            [](auto& result) {
1✔
844
               const auto even = Botan::hex_decode("FE3410CB0278E4D26602");
1✔
845
               const auto odd = Botan::hex_decode("BB2418C2B4F288921203");
1✔
846

847
               result.test_is_true("odd hamming", Botan::bitvector(odd).has_odd_hamming_weight().as_bool());
2✔
848
               result.test_is_true("even hamming", !Botan::bitvector(even).has_odd_hamming_weight().as_bool());
2✔
849
            }),
2✔
850

851
      CHECK("hamming weight",
852
            [](auto& result) {
1✔
853
               auto naive_count = [](const auto& v) {
5✔
854
                  size_t weight = 0;
5✔
855
                  for(const auto& bit : v) {
440✔
856
                     weight += bit.template as<size_t>();
430✔
857
                  }
858
                  return weight;
5✔
859
               };
860

861
               // the last three bits of this bitvector are set, then there's a gap
862
               auto bv = Botan::bitvector(Botan::hex_decode("FE3410CB0278E4D26602E0"));
2✔
863
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(37));
1✔
864
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1✔
865

866
               bv.pop_back();
1✔
867
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(36));
1✔
868
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1✔
869

870
               bv.pop_back();
1✔
871
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(35));
1✔
872
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1✔
873

874
               bv.pop_back();
1✔
875
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(34));
1✔
876
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1✔
877

878
               bv.pop_back();
1✔
879
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(34));
1✔
880
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1✔
881
            }),
1✔
882
   };
7✔
883
}
1✔
884

885
std::vector<Test::Result> test_bitvector_binary_operators(Botan::RandomNumberGenerator& /*rng*/) {
1✔
886
   auto check_set = [](auto& result, auto bits, std::vector<size_t> set_bits) {
13✔
887
      for(size_t i = 0; i < bits.size(); ++i) {
252✔
888
         const bool should_be_set = std::find(set_bits.begin(), set_bits.end(), i) != set_bits.end();
240✔
889
         result.test_bool_eq(
240✔
890
            Botan::fmt("{} should {}be set", i, (!should_be_set ? "not " : "")), bits[i], should_be_set);
661✔
891
      }
892
   };
12✔
893

894
   auto is_secure_allocator = []<template <typename> typename AllocatorT>(auto& result,
7✔
895
                                                                          const Botan::bitvector_base<AllocatorT>&) {
896
      result.test_is_true("allocator is Botan::secure_allocator<>",
12✔
897
                          std::same_as<Botan::secure_allocator<uint8_t>, AllocatorT<uint8_t>>);
898
   };
899

900
   auto is_standard_allocator = []<template <typename> typename AllocatorT>(auto& result,
4✔
901
                                                                            const Botan::bitvector_base<AllocatorT>&) {
902
      result.test_is_true("allocator is std::allocator<>", std::same_as<std::allocator<uint8_t>, AllocatorT<uint8_t>>);
6✔
903
   };
904

905
   return {
1✔
906
      CHECK("bitwise_equals",
907
            [&](auto& result) {
1✔
908
               Botan::bitvector lhs(20);
1✔
909
               lhs.set(0).set(4).set(15).set(16).set(19);
1✔
910
               Botan::bitvector rhs(20);
1✔
911
               rhs.set(1).set(4).set(16).set(17).set(18);
1✔
912

913
               result.test_is_false("Not equal bitvectors", lhs.equals_vartime(rhs));
1✔
914
               result.test_is_false("Not equal bitvectors 2", lhs.equals(rhs));
1✔
915

916
               lhs.unset().set(13);
1✔
917
               rhs.unset().set(13);
1✔
918

919
               result.test_is_true("equal bitvectors", lhs.equals_vartime(rhs));
1✔
920
               result.test_is_true("equal bitvectors 2", lhs.equals(rhs));
1✔
921
            }),
2✔
922

923
      CHECK("bitwise OR",
924
            [&](auto& result) {
1✔
925
               Botan::bitvector lhs(20);
1✔
926
               lhs.set(0).set(4).set(15).set(16).set(19);
1✔
927
               Botan::bitvector rhs(20);
1✔
928
               rhs.set(1).set(4).set(16).set(17).set(18);
1✔
929
               Botan::bitvector unary(20);
1✔
930
               unary.set(8);
1✔
931

932
               Botan::bitvector res = lhs | rhs;
1✔
933
               check_set(result, res, {0, 1, 4, 15, 16, 17, 18, 19});
4✔
934

935
               res |= unary;
1✔
936
               check_set(result, res, {0, 1, 4, 8, 15, 16, 17, 18, 19});
3✔
937

938
               is_standard_allocator(result, res);
1✔
939
            }),
4✔
940

941
      CHECK("bitwise AND",
942
            [&](auto& result) {
1✔
943
               Botan::bitvector lhs(20);
1✔
944
               lhs.set(0).set(4).set(15).set(16).set(18);
1✔
945
               Botan::bitvector rhs(20);
1✔
946
               rhs.set(1).set(4).set(16).set(17).set(18);
1✔
947
               Botan::bitvector unary(20);
1✔
948
               unary.set(8).set(16);
1✔
949

950
               Botan::bitvector res = lhs & rhs;
1✔
951
               check_set(result, res, {4, 16, 18});
4✔
952

953
               res &= unary;
1✔
954
               check_set(result, res, {16});
3✔
955

956
               is_standard_allocator(result, res);
1✔
957
            }),
4✔
958

959
      CHECK("bitwise XOR",
960
            [&](auto& result) {
1✔
961
               Botan::bitvector lhs(20);
1✔
962
               lhs.set(0).set(4).set(15).set(16).set(18);
1✔
963
               Botan::bitvector rhs(20);
1✔
964
               rhs.set(1).set(4).set(16).set(17).set(18);
1✔
965
               Botan::bitvector unary(20);
1✔
966
               unary.set(8).set(16);
1✔
967

968
               Botan::bitvector res = lhs ^ rhs;
1✔
969
               check_set(result, res, {0, 1, 15, 17});
4✔
970

971
               res ^= unary;
1✔
972
               check_set(result, res, {0, 1, 8, 15, 16, 17});
3✔
973

974
               is_standard_allocator(result, res);
1✔
975
            }),
4✔
976

977
      CHECK("bitwise operators with heterogeneous allocators",
978
            [&](auto& result) {
1✔
979
               Botan::bitvector lhs(20);
1✔
980
               lhs.set(0).set(4).set(15).set(16).set(18);
1✔
981
               Botan::secure_bitvector rhs(20);
1✔
982
               rhs.set(1).set(4).set(16).set(17).set(18);
1✔
983
               Botan::bitvector unary(20);
1✔
984
               unary.set(8).set(16);
1✔
985

986
               auto res1 = lhs | rhs;
1✔
987
               is_secure_allocator(result, res1);
1✔
988
               check_set(result, res1, {0, 1, 4, 15, 16, 17, 18});
3✔
989

990
               auto res2 = rhs | lhs;
1✔
991
               is_secure_allocator(result, res2);
1✔
992
               check_set(result, res2, {0, 1, 4, 15, 16, 17, 18});
3✔
993

994
               auto res3 = lhs & rhs;
1✔
995
               is_secure_allocator(result, res3);
1✔
996
               check_set(result, res3, {4, 16, 18});
3✔
997

998
               auto res4 = rhs & lhs;
1✔
999
               is_secure_allocator(result, res4);
1✔
1000
               check_set(result, res4, {4, 16, 18});
3✔
1001

1002
               auto res5 = lhs ^ rhs;
1✔
1003
               is_secure_allocator(result, res5);
1✔
1004
               check_set(result, res5, {0, 1, 15, 17});
3✔
1005

1006
               auto res6 = rhs ^ lhs;
1✔
1007
               is_secure_allocator(result, res6);
1✔
1008
               check_set(result, res6, {0, 1, 15, 17});
4✔
1009
            }),
9✔
1010
   };
6✔
1011
}
1✔
1012

1013
std::vector<Test::Result> test_bitvector_serialization(Botan::RandomNumberGenerator& /*rng*/) {
1✔
1014
   constexpr uint8_t outlen = 64;
1✔
1015
   const auto bytearray = [] {
1✔
1016
      std::array<uint8_t, outlen> out{};
1017
      for(uint8_t i = 0; i < outlen; ++i) {
1018
         out[i] = i;
1019
      }
1020
      return out;
1021
   }();
1022

1023
   auto validate_bytewise = [](auto& result, const auto& bv, std::span<const uint8_t> bytes) {
3✔
1024
      for(size_t i = 0; i < bytes.size(); ++i) {
129✔
1025
         const uint8_t b = (static_cast<uint8_t>(bv[0 + i * 8]) << 0) | (static_cast<uint8_t>(bv[1 + i * 8]) << 1) |
127✔
1026
                           (static_cast<uint8_t>(bv[2 + i * 8]) << 2) | (static_cast<uint8_t>(bv[3 + i * 8]) << 3) |
127✔
1027
                           (static_cast<uint8_t>(bv[4 + i * 8]) << 4) | (static_cast<uint8_t>(bv[5 + i * 8]) << 5) |
127✔
1028
                           (static_cast<uint8_t>(bv[6 + i * 8]) << 6) | (static_cast<uint8_t>(bv[7 + i * 8]) << 7);
127✔
1029

1030
         result.test_sz_eq(
254✔
1031
            Botan::fmt("byte {} is as expected", i), static_cast<size_t>(b), static_cast<size_t>(bytes[i]));
127✔
1032
      }
1033
   };
2✔
1034

1035
   return {
1✔
1036
      CHECK("empty byte-array",
1037
            [](auto& result) {
1✔
1038
               std::vector<uint8_t> bytes;
1✔
1039
               result.require("empty buffer", bytes.empty());
1✔
1040

1041
               const Botan::bitvector bv(bytes);
1✔
1042
               result.test_is_true("empty bit vector", bv.empty());
1✔
1043

1044
               auto rendered = bv.to_bytes();
1✔
1045
               result.test_is_true("empty bit vector renders an empty buffer", rendered.empty());
1✔
1046
            }),
1✔
1047

1048
      CHECK("to_bytes() uses secure_allocator if necessary",
1049
            [](auto& result) {
1✔
1050
               const Botan::bitvector bv;
1✔
1051
               const Botan::secure_bitvector sbv;
1✔
1052

1053
               auto rbv = bv.to_bytes();
1✔
1054
               auto rsbv = sbv.to_bytes();
1✔
1055

1056
               result.test_is_true("ordinary bitvector uses ordinary std::vector",
1✔
1057
                                   std::is_same_v<std::vector<uint8_t>, decltype(rbv)>);
1058
               result.test_is_true("secure bitvector uses secure_vector",
1✔
1059
                                   std::is_same_v<Botan::secure_vector<uint8_t>, decltype(rsbv)>);
1060
            }),
1✔
1061

1062
      CHECK("load all bits from byte-array (aligned data)",
1063
            [&](auto& result) {
1✔
1064
               const Botan::bitvector bv(bytearray);
1✔
1065
               validate_bytewise(result, bv, bytearray);
1✔
1066

1067
               const auto rbv = bv.to_bytes();
1✔
1068
               result.test_is_true("uint8_t rendered correctly", std::ranges::equal(bytearray, rbv));
2✔
1069
            }),
2✔
1070

1071
      CHECK("load all bits from byte-array (unaligned blocks)",
1072
            [&](auto& result) {
1✔
1073
               std::array<uint8_t, 63> unaligned_bytearray{};
1✔
1074
               Botan::copy_mem(unaligned_bytearray, std::span{bytearray}.first<unaligned_bytearray.size()>());
1✔
1075

1076
               const Botan::bitvector bv(unaligned_bytearray);
1✔
1077
               validate_bytewise(result, bv, unaligned_bytearray);
1✔
1078

1079
               const auto rbv = bv.to_bytes();
1✔
1080
               result.test_is_true("uint8_t rendered correctly", std::ranges::equal(unaligned_bytearray, rbv));
1✔
1081
            }),
3✔
1082

1083
      CHECK("load bits from byte-array (unaligned data)",
1084
            [&](auto& result) {
1✔
1085
               constexpr size_t bits_to_load = 31;
1✔
1086
               constexpr size_t bytes_to_load = Botan::ceil_tobytes(bits_to_load);
1✔
1087

1088
               Botan::bitvector bv(bytearray, bits_to_load);
1✔
1089

1090
               for(size_t i = 0; i < bits_to_load; ++i) {
32✔
1091
                  const bool expected = (i == 8) || (i == 17) || (i == 24) || (i == 25);
31✔
1092
                  result.test_bool_eq(Botan::fmt("bit {} is correct", i), bv.at(i), expected);
62✔
1093
               }
1094

1095
               const auto rbv = bv.to_bytes();
1✔
1096
               std::array<uint8_t, bytes_to_load> expected_bytes{};
1✔
1097
               Botan::copy_mem(expected_bytes, std::span{bytearray}.first<bytes_to_load>());
1✔
1098
               expected_bytes.back() &= (uint8_t(1) << (bits_to_load % 8)) - 1;
1✔
1099
               result.test_is_true("uint8_t rendered correctly", std::ranges::equal(expected_bytes, rbv));
1✔
1100
            }),
2✔
1101

1102
      CHECK("to_bytes(std::span) can handle non-zero out-memory",
1103
            [&](auto& result) {
1✔
1104
               constexpr size_t bits_to_load = 33;
1✔
1105
               constexpr size_t bytes_to_load = Botan::ceil_tobytes(bits_to_load);
1✔
1106

1107
               Botan::bitvector bv(bytearray, bits_to_load);
1✔
1108
               bv.set(32);
1✔
1109

1110
               std::array<uint8_t, bytes_to_load> out = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1✔
1111
               bv.to_bytes(out);
1✔
1112

1113
               result.test_u8_eq("uint8_t rendered correctly", out[4], 0x01);
1✔
1114
            }),
1✔
1115
   };
7✔
1116
}
1✔
1117

1118
std::vector<Test::Result> test_bitvector_constant_time_operations(Botan::RandomNumberGenerator& /*rng*/) {
1✔
1119
   constexpr Botan::CT::Choice yes = Botan::CT::Choice::yes();
1✔
1120
   constexpr Botan::CT::Choice no = Botan::CT::Choice::no();
1✔
1121

1122
   return {
1✔
1123
      CHECK("conditional XOR, block aligned",
1124
            [&](auto& result) {
1✔
1125
               Botan::bitvector bv1(Botan::hex_decode("BAADF00DCAFEBEEF"));
2✔
1126
               const Botan::secure_bitvector bv2(Botan::hex_decode("CAFEBEEFC001B33F"));
2✔
1127
               const auto initial_bv1 = bv1;
1✔
1128
               const auto xor_result = bv1 ^ bv2;
1✔
1129

1130
               bv1.ct_conditional_xor(no, bv2);
1✔
1131
               result.test_is_true("no change after false condition", bv1 == initial_bv1);
1✔
1132

1133
               bv1.ct_conditional_xor(yes, bv2);
1✔
1134
               result.test_is_true("XORed if condition was true", bv1 == xor_result);
1✔
1135
            }),
4✔
1136

1137
      CHECK("conditional XOR, byte aligned",
1138
            [&](auto& result) {
1✔
1139
               Botan::bitvector bv1(Botan::hex_decode("BAADF00DCAFEBEEF42"));
2✔
1140
               const Botan::secure_bitvector bv2(Botan::hex_decode("CAFEBEEFC001B33F13"));
2✔
1141
               const auto initial_bv1 = bv1;
1✔
1142
               const auto xor_result = bv1 ^ bv2;
1✔
1143

1144
               bv1.ct_conditional_xor(no, bv2);
1✔
1145
               result.test_is_true("no change after false condition", bv1 == initial_bv1);
1✔
1146

1147
               bv1.ct_conditional_xor(yes, bv2);
1✔
1148
               result.test_is_true("XORed if condition was true", bv1 == xor_result);
1✔
1149
            }),
4✔
1150

1151
      CHECK("conditional XOR, no alignment",
1152
            [&](auto& result) {
1✔
1153
               Botan::bitvector bv1(Botan::hex_decode("BAADF00DCAFEBEEF42"));
1✔
1154
               bv1.push_back(true);
1✔
1155
               bv1.push_back(false);
1✔
1156
               Botan::secure_bitvector bv2(Botan::hex_decode("CAFEBEEFC001B33F13"));
1✔
1157
               bv2.push_back(false);
1✔
1158
               bv2.push_back(false);
1✔
1159

1160
               const auto initial_bv1 = bv1;
1✔
1161
               const auto xor_result = bv1 ^ bv2;
1✔
1162

1163
               bv1.ct_conditional_xor(no, bv2);
1✔
1164
               result.test_is_true("no change after false condition", bv1 == initial_bv1);
1✔
1165

1166
               bv1.ct_conditional_xor(yes, bv2);
1✔
1167
               result.test_is_true("XORed if condition was true", bv1 == xor_result);
1✔
1168
            }),
4✔
1169
   };
4✔
1170
}
1✔
1171

1172
std::vector<Test::Result> test_bitvector_conditional_xor_workload(Botan::RandomNumberGenerator& /*rng*/) {
1✔
1173
   Test::Result res("Conditional XOR, Gauss Workload");
1✔
1174

1175
   auto rng = Test::new_rng("Conditional XOR, Gauss Workload");
1✔
1176

1177
   const size_t matrix_rows = 1664;
1✔
1178
   const size_t matrix_columns = 8192;
1✔
1179

1180
   std::vector<Botan::bitvector> bitvec_vec;
1✔
1181
   bitvec_vec.reserve(matrix_rows);
1✔
1182
   for(size_t i = 0; i < matrix_rows; ++i) {
1,665✔
1183
      bitvec_vec.push_back(Botan::bitvector(rng->random_vec(matrix_columns / 8)));
4,992✔
1184
   }
1185

1186
   // Simulate #ops of Gaussian Elimination
1187
   const size_t total_iter = matrix_rows * (3 * matrix_rows - 1) / 2;
1✔
1188
   const auto start = Test::timestamp();
1✔
1189
   for(size_t i = 0; i < total_iter; ++i) {
4,152,513✔
1190
      const auto choice = Botan::CT::Choice::from_int(static_cast<uint8_t>(rng->next_byte() % 2));
4,152,512✔
1191
      bitvec_vec.at(i % matrix_rows).ct_conditional_xor(choice, bitvec_vec.at(rng->next_byte() % matrix_rows));
4,152,512✔
1192
   }
1193
   res.set_ns_consumed(Test::timestamp() - start);
1✔
1194

1195
   res.test_is_true("Prevent compiler from optimizing away",
2✔
1196
                    bitvec_vec.at(0).any_vartime() || bitvec_vec.at(0).none_vartime());
1✔
1197
   return {res};
3✔
1198
}
3✔
1199

1200
std::vector<Test::Result> test_bitvector_iterators(Botan::RandomNumberGenerator& /*rng*/) {
1✔
1201
   return {
1✔
1202
      CHECK("Iterators: range-based for loop",
1203
            [](auto& result) {
1✔
1204
               Botan::bitvector bv(6);
1✔
1205
               bv.set(0).set(3).set(4);
1✔
1206

1207
               for(size_t i = 0; auto& ref : bv) {
8✔
1208
                  const bool expected = i == 0 || i == 3 || i == 4;
6✔
1209
                  result.test_bool_eq(Botan::fmt("bit {} is as expected", i), ref, expected);
6✔
1210
                  ++i;
6✔
1211
               }
1212

1213
               for(size_t i = 0; const auto& ref : bv) {
8✔
1214
                  const bool expected = i == 0 || i == 3 || i == 4;
6✔
1215
                  result.test_bool_eq(Botan::fmt("const bit {} is as expected", i), ref, expected);
6✔
1216
                  ++i;
6✔
1217
               }
1218

1219
               for(auto ref : bv) {
14✔
1220
                  ref = true;
6✔
1221
               }
1222

1223
               result.test_is_true("all bits are set", bv.all_vartime());
1✔
1224
            }),
1✔
1225

1226
      CHECK("Iterators: bare usage",
1227
            [](auto& result) {
1✔
1228
               Botan::bitvector bv(6);
1✔
1229
               bv.set(0).set(3).set(4);
1✔
1230

1231
               size_t i = 0;
1✔
1232
               for(auto itr = bv.begin(); itr != bv.end(); ++itr, ++i) {
7✔
1233
                  const bool expected = i == 0 || i == 3 || i == 4;
6✔
1234
                  result.test_bool_eq(Botan::fmt("bit {} is as expected", i), *itr, expected);
12✔
1235
               }
1236

1237
               i = 0;
1✔
1238
               for(auto itr = bv.cbegin(); itr != bv.cend(); itr++, ++i) {
7✔
1239
                  const bool expected = i == 0 || i == 3 || i == 4;
6✔
1240
                  result.test_bool_eq(Botan::fmt("const bit {} is as expected", i), itr->is_set(), expected);
12✔
1241
               }
1242

1243
               i = 6;
1✔
1244
               auto ritr = bv.end();
1✔
1245
               // NOLINTNEXTLINE(*-avoid-do-while)
1246
               do {
1247
                  --ritr;
6✔
1248
                  --i;
6✔
1249
                  const bool expected = i == 0 || i == 3 || i == 4;
6✔
1250
                  result.test_bool_eq(Botan::fmt("reverse bit {} is as expected", i), *ritr, expected);
6✔
1251
               } while(ritr != bv.begin());
11✔
1252

1253
               for(auto& itr : bv) {
8✔
1254
                  itr.flip();
6✔
1255
               }
1256

1257
               i = 0;
1✔
1258
               for(auto itr = bv.begin(); itr != bv.end(); ++itr, ++i) {
7✔
1259
                  const bool expected = i == 1 || i == 2 || i == 5;
6✔
1260
                  result.test_bool_eq(Botan::fmt("flipped bit {} is as expected", i), *itr, expected);
12✔
1261
               }
1262
            }),
1✔
1263

1264
      CHECK("Iterators: std::distance and std::advance",
1265
            [](auto& result) {
1✔
1266
               Botan::bitvector bv(6);
1✔
1267
               result.test_sz_eq("distance", static_cast<size_t>(std::distance(bv.begin(), bv.end())), 6);
2✔
1268
               result.test_sz_eq("const distance", static_cast<size_t>(std::distance(bv.cbegin(), bv.cend())), 6);
2✔
1269

1270
               auto b = bv.begin();
1✔
1271
               std::advance(b, 3);
1✔
1272
               result.test_sz_eq("half distance", static_cast<size_t>(std::distance(bv.begin(), b)), 3);
2✔
1273
            }),
1✔
1274

1275
      CHECK("Iterators: large bitvector",
1276
            [](auto& result) {
1✔
1277
               Botan::bitvector bv(500);
1✔
1278

1279
               for(auto itr = bv.begin(); itr != bv.end(); ++itr) {
1,001✔
1280
                  if(std::distance(bv.begin(), itr) % 2 == 0) {
1,000✔
1281
                     itr->set();
250✔
1282
                  }
1283
                  if(std::distance(bv.begin(), itr) % 3 == 0) {
1,000✔
1284
                     *itr = true;
167✔
1285
                  }
1286
               }
1287

1288
               for(size_t i = 0; const auto& bit : bv) {
502✔
1289
                  const bool expected = (i % 2 == 0) || (i % 3 == 0);
500✔
1290
                  result.test_bool_eq(Botan::fmt("bit {} is as expected", i), bit, expected);
500✔
1291
                  ++i;
500✔
1292
               }
1293
            }),
1✔
1294

1295
      CHECK("Iterators: satiesfies C++20 concepts",
1296
            [](auto& result) {
1✔
1297
               Botan::secure_bitvector bv(42);
1✔
1298
               auto ro_itr = bv.cbegin();
1✔
1299
               auto rw_itr = bv.begin();
1✔
1300

1301
               using ro = decltype(ro_itr);
1302
               using rw = decltype(rw_itr);
1303

1304
               result.test_is_true("ro input iterator", std::input_iterator<ro>);
1✔
1305
               result.test_is_true("rw input iterator", std::input_iterator<rw>);
1✔
1306
               result.test_is_true("ro is not an output iterator", !std::output_iterator<ro, bool>);
1✔
1307
               result.test_is_true("rw output iterator", std::output_iterator<rw, bool>);
1✔
1308
               result.test_is_true("ro bidirectional iterator", std::bidirectional_iterator<ro>);
1✔
1309
               result.test_is_true("rw bidirectional iterator", std::bidirectional_iterator<rw>);
1✔
1310
               result.test_is_true("ro not a contiguous iterator", !std::contiguous_iterator<ro>);
1✔
1311
               result.test_is_true("rw not a contiguous iterator", !std::contiguous_iterator<rw>);
1✔
1312
            }),
1✔
1313
   };
6✔
1314
}
1✔
1315

1316
using TestBitvector = Botan::Strong<Botan::bitvector, struct TestBitvector_>;
1317
using TestSecureBitvector = Botan::Strong<Botan::secure_bitvector, struct TestBitvector_>;
1318
using TestUInt32 = Botan::Strong<uint32_t, struct TestUInt32_>;
1319

1320
std::vector<Test::Result> test_bitvector_strongtype_adapter(Botan::RandomNumberGenerator& /*rng*/) {
1✔
1321
   Test::Result result("Bitvector in strong type");
1✔
1322

1323
   TestBitvector bv1(33);
1✔
1324

1325
   result.test_is_true("bv1 is not empty", !bv1.empty());
1✔
1326
   result.test_sz_eq("bv1 has size 33", bv1.size(), size_t(33));
1✔
1327

1328
   bv1[0] = true;
1✔
1329
   bv1.at(1) = true;
1✔
1330
   bv1.set(2);
2✔
1331
   bv1.unset(3);
2✔
1332
   bv1.flip(4);
2✔
1333
   bv1.push_back(true);
1✔
1334
   bv1.push_back(false);
1✔
1335
   bv1.pop_back();
1✔
1336

1337
   result.test_is_true("bv1 front is set", bv1.front());
1✔
1338
   result.test_is_true("bv1 back is set", bv1.back());
1✔
1339
   result.test_is_true("bv1 has some one bits", bv1.any_vartime());
1✔
1340
   result.test_is_true("bv1 is not all zero", !bv1.none_vartime());
1✔
1341
   result.test_is_true("bv1 is not all one", !bv1.all_vartime());
1✔
1342

1343
   result.test_is_true("hamming weight of bv1", bv1.has_odd_hamming_weight().as_bool());
1✔
1344

1345
   for(size_t i = 0; auto bit : bv1) {
36✔
1346
      const bool expected = (i == 0 || i == 1 || i == 2 || i == 4 || i == 33);
34✔
1347
      result.test_is_true(Botan::fmt("bv1 bit {} is set", i), bit == expected);
34✔
1348
      ++i;
34✔
1349
   }
1350

1351
   bv1.flip();
2✔
1352

1353
   for(size_t i = 0; auto bit : bv1) {
36✔
1354
      const bool expected = (i == 0 || i == 1 || i == 2 || i == 4 || i == 33);
34✔
1355
      result.test_is_true(Botan::fmt("bv1 bit {} is set", i), bit != expected);
34✔
1356
      ++i;
34✔
1357
   }
1358

1359
   auto bv2 = bv1.as<TestSecureBitvector>();
1✔
1360

1361
   auto bv3 = bv1 | bv2;
1✔
1362
   result.test_is_true("bv3 is a secure_bitvector", std::same_as<Botan::secure_bitvector, decltype(bv3)>);
1✔
1363

1364
   auto bv4 = bv2.subvector<TestSecureBitvector>(0, 5);
1✔
1365
   result.test_is_true("bv4 is a TestSecureBitvector", std::same_as<TestSecureBitvector, decltype(bv4)>);
1✔
1366

1367
   auto bv5 = bv2.subvector<TestUInt32>(1);
1✔
1368
   result.test_is_true("bv5 is a TestUInt32", std::same_as<TestUInt32, decltype(bv5)>);
1✔
1369
   result.test_u32_eq("bv5 has expected value", bv5.get(), 0xFFFFFFF4);
1✔
1370

1371
   const auto str = bv4.to_string();
1✔
1372
   result.test_str_eq("bv4 to_string", str, "00010");
1✔
1373

1374
   return {result};
3✔
1375
}
6✔
1376

1377
class BitVector_Tests final : public Test {
1✔
1378
   public:
1379
      std::vector<Test::Result> run() override {
1✔
1380
         std::vector<Test::Result> results;
1✔
1381
         auto& rng = Test::rng();
1✔
1382

1383
         const std::vector<std::function<std::vector<Test::Result>(Botan::RandomNumberGenerator&)>> funcs{
1✔
1384
            test_bitvector_bitwise_accessors,
1385
            test_bitvector_capacity,
1386
            test_bitvector_subvector,
1387
            test_bitvector_global_modifiers_and_predicates,
1388
            test_bitvector_binary_operators,
1389
            test_bitvector_serialization,
1390
            test_bitvector_constant_time_operations,
1391
            test_bitvector_conditional_xor_workload,
1392
            test_bitvector_iterators,
1393
            test_bitvector_strongtype_adapter,
1394
         };
11✔
1395

1396
         for(const auto& test_func : funcs) {
11✔
1397
            auto fn_results = test_func(rng);
10✔
1398
            results.insert(results.end(), fn_results.begin(), fn_results.end());
10✔
1399
         }
10✔
1400

1401
         return results;
1✔
1402
      }
2✔
1403
};
1404

1405
BOTAN_REGISTER_TEST("utils", "bitvector", BitVector_Tests);
1406

1407
#endif
1408

1409
}  // namespace
1410

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