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

randombit / botan / 11951261165

21 Nov 2024 10:24AM UTC coverage: 91.24% (+0.2%) from 91.063%
11951261165

push

github

web-flow
Merge pull request #3883 from Rohde-Schwarz/pqc/classic_mceliece

PQC: Classic McEliece

93268 of 102223 relevant lines covered (91.24%)

11456149.0 hits per line

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

95.48
/src/tests/test_utils.cpp
1
/*
2
* (C) 2015,2018,2024 Jack Lloyd
3
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
4
* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include "tests.h"
10
#include <botan/version.h>
11
#include <botan/internal/bit_ops.h>
12
#include <botan/internal/calendar.h>
13
#include <botan/internal/charset.h>
14
#include <botan/internal/cpuid.h>
15
#include <botan/internal/fmt.h>
16
#include <botan/internal/int_utils.h>
17
#include <botan/internal/loadstor.h>
18
#include <botan/internal/parsing.h>
19
#include <botan/internal/rounding.h>
20
#include <botan/internal/stl_util.h>
21

22
#include <bit>
23
#include <ctime>
24
#include <functional>
25

26
#if defined(BOTAN_HAS_POLY_DBL)
27
   #include <botan/internal/poly_dbl.h>
28
#endif
29

30
#if defined(BOTAN_HAS_UUID)
31
   #include <botan/uuid.h>
32
#endif
33

34
namespace Botan_Tests {
35

36
namespace {
37

38
class Utility_Function_Tests final : public Test {
×
39
   public:
40
      std::vector<Test::Result> run() override {
1✔
41
         std::vector<Test::Result> results;
1✔
42

43
         results.push_back(test_checked_add());
2✔
44
         results.push_back(test_checked_mul());
2✔
45
         results.push_back(test_checked_cast());
2✔
46
         results.push_back(test_round_up());
2✔
47
         results.push_back(test_loadstore());
2✔
48
         results.push_back(test_loadstore_ambiguity());
2✔
49
         results.push_back(test_loadstore_fallback());
2✔
50
         results.push_back(test_loadstore_constexpr());
2✔
51
         return Botan::concat(results, test_copy_out_be_le());
3✔
52
      }
1✔
53

54
   private:
55
      Test::Result test_checked_add() {
1✔
56
         Test::Result result("checked_add");
1✔
57

58
         const size_t large = static_cast<size_t>(-5);
1✔
59
         const size_t zero = 0;
1✔
60

61
         for(int si = -15; si != 15; ++si) {
31✔
62
            const size_t i = static_cast<size_t>(si);
30✔
63
            auto sum1 = Botan::checked_add<size_t>(i, zero, zero, zero, large);
30✔
64
            auto sum2 = Botan::checked_add<size_t>(large, zero, zero, zero, i);
30✔
65

66
            result.confirm("checked_add looks at all args", sum1 == sum2);
90✔
67

68
            if(i < 5) {
30✔
69
               result.test_eq("checked_add worked", sum1.value(), i + large);
10✔
70
            } else {
71
               result.confirm("checked_add did not return a result", !sum1.has_value());
50✔
72
            }
73
         }
74

75
         auto& rng = Test::rng();
1✔
76

77
         for(size_t i = 0; i != 100; ++i) {
101✔
78
            const uint16_t x = Botan::make_uint16(rng.next_byte(), rng.next_byte());
100✔
79
            const uint16_t y = Botan::make_uint16(rng.next_byte(), rng.next_byte());
100✔
80

81
            const uint32_t ref = static_cast<uint32_t>(x) + y;
100✔
82

83
            if(auto z = Botan::checked_add(x, y)) {
200✔
84
               result.test_int_eq("checked_add adds", z.value(), ref);
92✔
85
            } else {
86
               result.confirm("checked_add checks", (ref >> 16) > 0);
108✔
87
            }
88
         }
89

90
         return result;
1✔
91
      }
×
92

93
      Test::Result test_checked_mul() {
1✔
94
         Test::Result result("checked_mul");
1✔
95

96
         auto& rng = Test::rng();
1✔
97

98
         for(size_t i = 0; i != 100; ++i) {
101✔
99
            const uint16_t x = Botan::make_uint16(rng.next_byte(), rng.next_byte());
100✔
100
            const uint16_t y = Botan::make_uint16(rng.next_byte(), rng.next_byte());
100✔
101

102
            const uint32_t ref = static_cast<uint32_t>(x) * y;
100✔
103

104
            if(auto z = Botan::checked_mul(x, y)) {
200✔
105
               result.test_int_eq("checked_mul multiplies", z.value(), ref);
×
106
            } else {
107
               result.confirm("checked_mul checks", (ref >> 16) > 0);
200✔
108
            }
109
         }
110

111
         return result;
1✔
112
      }
×
113

114
      Test::Result test_checked_cast() {
1✔
115
         Test::Result result("checked_cast");
1✔
116

117
         const uint32_t large = static_cast<uint32_t>(-1);
1✔
118
         const uint32_t is_16_bits = 0x8123;
1✔
119
         const uint32_t is_8_bits = 0x89;
1✔
120

121
         result.test_throws("checked_cast checks", [&] { Botan::checked_cast_to<uint16_t>(large); });
3✔
122
         result.test_throws("checked_cast checks", [&] { Botan::checked_cast_to<uint8_t>(large); });
3✔
123

124
         result.test_int_eq("checked_cast converts", Botan::checked_cast_to<uint32_t>(large), large);
2✔
125
         result.test_int_eq("checked_cast converts", Botan::checked_cast_to<uint16_t>(is_16_bits), 0x8123);
2✔
126
         result.test_int_eq("checked_cast converts", Botan::checked_cast_to<uint8_t>(is_8_bits), 0x89);
2✔
127

128
         return result;
1✔
129
      }
×
130

131
      Test::Result test_round_up() {
1✔
132
         Test::Result result("Util round_up");
1✔
133

134
         // clang-format off
135
         const std::vector<size_t> inputs = {
1✔
136
            0, 1, 2, 3, 4, 9, 10, 32, 99, 100, 101, 255, 256, 1000, 10000,
137
            65535, 65536, 65537,
138
         };
1✔
139

140
         const std::vector<size_t> alignments = {
1✔
141
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 32, 50, 64, 100, 512, 521,
142
            1000, 1023, 1024, 1025, 10000, 65535, 65536
143
         };
1✔
144
         // clang-format on
145

146
         for(size_t i : inputs) {
19✔
147
            for(size_t m : alignments) {
450✔
148
               try {
432✔
149
                  const size_t z = Botan::round_up(i, m);
432✔
150

151
                  result.confirm("z % m == 0", z % m == 0);
864✔
152
                  result.confirm("z >= i", z >= i);
864✔
153
                  result.confirm("z <= i + m", z <= i + m);
864✔
154
               } catch(Botan::Exception& e) {
×
155
                  result.test_failure(Botan::fmt("round_up({},{})", i, m), e.what());
×
156
               }
×
157
            }
158
         }
159

160
         result.test_throws("Integer overflow is detected", []() { Botan::round_up(static_cast<size_t>(-1), 1024); });
2✔
161

162
         return result;
1✔
163
      }
1✔
164

165
      using TestInt64 = Botan::Strong<uint64_t, struct TestInt64_>;
166
      using TestInt32 = Botan::Strong<uint32_t, struct TestInt64_>;
167
      using TestVectorSink = Botan::Strong<std::vector<uint8_t>, struct TestVectorSink_>;
168

169
      enum class TestEnum64 : uint64_t {
170
         _1 = 0x1234567890ABCDEF,
171
         _2 = 0xEFCDAB9078563412,
172
      };
173

174
      enum class TestEnum32 : uint32_t {
175
         _1 = 0x12345678,
176
         _2 = 0x78563412,
177
      };
178

179
      static Test::Result test_loadstore() {
1✔
180
         Test::Result result("Util load/store");
1✔
181

182
         const std::vector<uint8_t> membuf = Botan::hex_decode("00112233445566778899AABBCCDDEEFF");
1✔
183
         const uint8_t* mem = membuf.data();
1✔
184

185
         const uint16_t in16 = 0x1234;
1✔
186
         const uint32_t in32 = 0xA0B0C0D0;
1✔
187
         const uint64_t in64 = 0xABCDEF0123456789;
1✔
188

189
         result.test_is_eq<uint8_t>(Botan::get_byte<0>(in32), 0xA0);
1✔
190
         result.test_is_eq<uint8_t>(Botan::get_byte<1>(in32), 0xB0);
1✔
191
         result.test_is_eq<uint8_t>(Botan::get_byte<2>(in32), 0xC0);
1✔
192
         result.test_is_eq<uint8_t>(Botan::get_byte<3>(in32), 0xD0);
1✔
193

194
         result.test_is_eq<uint16_t>(Botan::make_uint16(0xAA, 0xBB), 0xAABB);
1✔
195
         result.test_is_eq<uint32_t>(Botan::make_uint32(0x01, 0x02, 0x03, 0x04), 0x01020304);
1✔
196

197
         result.test_is_eq<uint16_t>(Botan::load_be<uint16_t>(mem, 0), 0x0011);
1✔
198
         result.test_is_eq<uint16_t>(Botan::load_be<uint16_t>(mem, 1), 0x2233);
1✔
199
         result.test_is_eq<uint16_t>(Botan::load_be<uint16_t>(mem, 2), 0x4455);
1✔
200
         result.test_is_eq<uint16_t>(Botan::load_be<uint16_t>(mem, 3), 0x6677);
1✔
201

202
         result.test_is_eq<uint16_t>(Botan::load_le<uint16_t>(mem, 0), 0x1100);
1✔
203
         result.test_is_eq<uint16_t>(Botan::load_le<uint16_t>(mem, 1), 0x3322);
1✔
204
         result.test_is_eq<uint16_t>(Botan::load_le<uint16_t>(mem, 2), 0x5544);
1✔
205
         result.test_is_eq<uint16_t>(Botan::load_le<uint16_t>(mem, 3), 0x7766);
1✔
206

207
         result.test_is_eq<uint32_t>(Botan::load_be<uint32_t>(mem, 0), 0x00112233);
1✔
208
         result.test_is_eq<uint32_t>(Botan::load_be<uint32_t>(mem, 1), 0x44556677);
1✔
209
         result.test_is_eq<uint32_t>(Botan::load_be<uint32_t>(mem, 2), 0x8899AABB);
1✔
210
         result.test_is_eq<uint32_t>(Botan::load_be<uint32_t>(mem, 3), 0xCCDDEEFF);
1✔
211

212
         result.test_is_eq<uint32_t>(Botan::load_le<uint32_t>(mem, 0), 0x33221100);
1✔
213
         result.test_is_eq<uint32_t>(Botan::load_le<uint32_t>(mem, 1), 0x77665544);
1✔
214
         result.test_is_eq<uint32_t>(Botan::load_le<uint32_t>(mem, 2), 0xBBAA9988);
1✔
215
         result.test_is_eq<uint32_t>(Botan::load_le<uint32_t>(mem, 3), 0xFFEEDDCC);
1✔
216

217
         result.test_is_eq<uint64_t>(Botan::load_be<uint64_t>(mem, 0), 0x0011223344556677);
1✔
218
         result.test_is_eq<uint64_t>(Botan::load_be<uint64_t>(mem, 1), 0x8899AABBCCDDEEFF);
1✔
219

220
         result.test_is_eq<uint64_t>(Botan::load_le<uint64_t>(mem, 0), 0x7766554433221100);
1✔
221
         result.test_is_eq<uint64_t>(Botan::load_le<uint64_t>(mem, 1), 0xFFEEDDCCBBAA9988);
1✔
222

223
         // Check misaligned loads:
224
         result.test_is_eq<uint16_t>(Botan::load_be<uint16_t>(mem + 1, 0), 0x1122);
1✔
225
         result.test_is_eq<uint16_t>(Botan::load_le<uint16_t>(mem + 3, 0), 0x4433);
1✔
226

227
         result.test_is_eq<uint32_t>(Botan::load_be<uint32_t>(mem + 1, 1), 0x55667788);
1✔
228
         result.test_is_eq<uint32_t>(Botan::load_le<uint32_t>(mem + 3, 1), 0xAA998877);
1✔
229

230
         result.test_is_eq<uint64_t>(Botan::load_be<uint64_t>(mem + 1, 0), 0x1122334455667788);
1✔
231
         result.test_is_eq<uint64_t>(Botan::load_le<uint64_t>(mem + 7, 0), 0xEEDDCCBBAA998877);
1✔
232
         result.test_is_eq<uint64_t>(Botan::load_le<uint64_t>(mem + 5, 0), 0xCCBBAA9988776655);
1✔
233

234
         uint8_t outbuf[16] = {0};
1✔
235

236
         for(size_t offset = 0; offset != 7; ++offset) {
8✔
237
            uint8_t* out = outbuf + offset;
7✔
238

239
            Botan::store_be(in16, out);
7✔
240
            result.test_is_eq<uint8_t>(out[0], 0x12);
7✔
241
            result.test_is_eq<uint8_t>(out[1], 0x34);
7✔
242

243
            Botan::store_le(in16, out);
7✔
244
            result.test_is_eq<uint8_t>(out[0], 0x34);
7✔
245
            result.test_is_eq<uint8_t>(out[1], 0x12);
7✔
246

247
            Botan::store_be(in32, out);
7✔
248
            result.test_is_eq<uint8_t>(out[0], 0xA0);
7✔
249
            result.test_is_eq<uint8_t>(out[1], 0xB0);
7✔
250
            result.test_is_eq<uint8_t>(out[2], 0xC0);
7✔
251
            result.test_is_eq<uint8_t>(out[3], 0xD0);
7✔
252

253
            Botan::store_le(in32, out);
7✔
254
            result.test_is_eq<uint8_t>(out[0], 0xD0);
7✔
255
            result.test_is_eq<uint8_t>(out[1], 0xC0);
7✔
256
            result.test_is_eq<uint8_t>(out[2], 0xB0);
7✔
257
            result.test_is_eq<uint8_t>(out[3], 0xA0);
7✔
258

259
            Botan::store_be(in64, out);
7✔
260
            result.test_is_eq<uint8_t>(out[0], 0xAB);
7✔
261
            result.test_is_eq<uint8_t>(out[1], 0xCD);
7✔
262
            result.test_is_eq<uint8_t>(out[2], 0xEF);
7✔
263
            result.test_is_eq<uint8_t>(out[3], 0x01);
7✔
264
            result.test_is_eq<uint8_t>(out[4], 0x23);
7✔
265
            result.test_is_eq<uint8_t>(out[5], 0x45);
7✔
266
            result.test_is_eq<uint8_t>(out[6], 0x67);
7✔
267
            result.test_is_eq<uint8_t>(out[7], 0x89);
7✔
268

269
            Botan::store_le(in64, out);
7✔
270
            result.test_is_eq<uint8_t>(out[0], 0x89);
7✔
271
            result.test_is_eq<uint8_t>(out[1], 0x67);
7✔
272
            result.test_is_eq<uint8_t>(out[2], 0x45);
7✔
273
            result.test_is_eq<uint8_t>(out[3], 0x23);
7✔
274
            result.test_is_eq<uint8_t>(out[4], 0x01);
7✔
275
            result.test_is_eq<uint8_t>(out[5], 0xEF);
7✔
276
            result.test_is_eq<uint8_t>(out[6], 0xCD);
7✔
277
            result.test_is_eq<uint8_t>(out[7], 0xAB);
7✔
278
         }
279

280
         std::array<uint8_t, 8> outarr;
1✔
281
         uint16_t i0, i1, i2, i3;
1✔
282
         Botan::store_be(in64, outarr);
1✔
283

284
         Botan::load_be(outarr, i0, i1, i2, i3);
1✔
285
         result.test_is_eq<uint16_t>(i0, 0xABCD);
1✔
286
         result.test_is_eq<uint16_t>(i1, 0xEF01);
1✔
287
         result.test_is_eq<uint16_t>(i2, 0x2345);
1✔
288
         result.test_is_eq<uint16_t>(i3, 0x6789);
1✔
289

290
         Botan::load_le(std::span{outarr}.first<6>(), i0, i1, i2);
1✔
291
         result.test_is_eq<uint16_t>(i0, 0xCDAB);
1✔
292
         result.test_is_eq<uint16_t>(i1, 0x01EF);
1✔
293
         result.test_is_eq<uint16_t>(i2, 0x4523);
1✔
294
         result.test_is_eq<uint16_t>(i3, 0x6789);  // remains unchanged
1✔
295

296
         Botan::store_le(in64, outarr);
1✔
297

298
         Botan::load_le(outarr, i0, i1, i2, i3);
1✔
299
         result.test_is_eq<uint16_t>(i0, 0x6789);
1✔
300
         result.test_is_eq<uint16_t>(i1, 0x2345);
1✔
301
         result.test_is_eq<uint16_t>(i2, 0xEF01);
1✔
302
         result.test_is_eq<uint16_t>(i3, 0xABCD);
1✔
303

304
         Botan::load_be(std::span{outarr}.first<6>(), i0, i1, i2);
1✔
305
         result.test_is_eq<uint16_t>(i0, 0x8967);
1✔
306
         result.test_is_eq<uint16_t>(i1, 0x4523);
1✔
307
         result.test_is_eq<uint16_t>(i2, 0x01EF);
1✔
308
         result.test_is_eq<uint16_t>(i3, 0xABCD);  // remains unchanged
1✔
309

310
         i0 = 0xAA11;
1✔
311
         i1 = 0xBB22;
1✔
312
         i2 = 0xCC33;
1✔
313
         i3 = 0xDD44;
1✔
314
         Botan::store_be(outarr, i0, i1, i2, i3);
1✔
315
         result.test_is_eq(outarr, {0xAA, 0x11, 0xBB, 0x22, 0xCC, 0x33, 0xDD, 0x44});
1✔
316
         std::vector<uint8_t> outvec(8);
1✔
317
         Botan::store_be(outvec, i0, i1, i2, i3);
1✔
318
         result.test_is_eq(outvec, Botan::hex_decode("AA11BB22CC33DD44"));
1✔
319

320
         Botan::store_le(outarr, i0, i1, i2, i3);
1✔
321
         result.test_is_eq(outarr, {0x11, 0xAA, 0x22, 0xBB, 0x33, 0xCC, 0x44, 0xDD});
1✔
322
         Botan::store_le(outvec, i0, i1, i2, i3);
1✔
323
         result.test_is_eq(outvec, Botan::hex_decode("11AA22BB33CC44DD"));
1✔
324

325
#if !defined(BOTAN_TERMINATE_ON_ASSERTS)
326
         std::vector<uint8_t> sink56bits(7);
327
         std::vector<uint8_t> sink72bits(9);
328
         result.test_throws("store_le with a buffer that is too small",
329
                            [&] { Botan::store_le(sink56bits, i0, i1, i2, i3); });
330
         result.test_throws("store_le with a buffer that is too big",
331
                            [&] { Botan::store_le(sink72bits, i0, i1, i2, i3); });
332
         result.test_throws("store_be with a buffer that is too small",
333
                            [&] { Botan::store_be(sink56bits, i0, i1, i2, i3); });
334
         result.test_throws("store_be with a buffer that is too big",
335
                            [&] { Botan::store_be(sink72bits, i0, i1, i2, i3); });
336
#endif
337

338
         // can store multiple values straight into a collection
339
         auto out64_array_be = Botan::store_be(i0, i1, i2, i3);
1✔
340
         auto out64_vec_be = Botan::store_be<std::vector<uint8_t>>(i0, i1, i2, i3);
1✔
341
         auto out64_strong_be = Botan::store_be<TestVectorSink>(i0, i1, i2, i3);
1✔
342
         result.test_is_eq(out64_array_be, {0xAA, 0x11, 0xBB, 0x22, 0xCC, 0x33, 0xDD, 0x44});
1✔
343
         result.test_is_eq(out64_vec_be, Botan::hex_decode("AA11BB22CC33DD44"));
1✔
344
         result.test_is_eq(out64_strong_be, TestVectorSink(Botan::hex_decode("AA11BB22CC33DD44")));
2✔
345
         auto out64_array_le = Botan::store_le(i0, i1, i2, i3);
1✔
346
         auto out64_vec_le = Botan::store_le<std::vector<uint8_t>>(i0, i1, i2, i3);
1✔
347
         auto out64_strong_le = Botan::store_le<TestVectorSink>(i0, i1, i2, i3);
1✔
348
         result.test_is_eq(out64_array_le, {0x11, 0xAA, 0x22, 0xBB, 0x33, 0xCC, 0x44, 0xDD});
1✔
349
         result.test_is_eq(out64_vec_le, Botan::hex_decode("11AA22BB33CC44DD"));
1✔
350
         result.test_is_eq(out64_strong_le, TestVectorSink(Botan::hex_decode("11AA22BB33CC44DD")));
2✔
351

352
         result.test_is_eq(in16, Botan::load_be(Botan::store_be(in16)));
1✔
353
         result.test_is_eq(in32, Botan::load_be(Botan::store_be(in32)));
1✔
354
         result.test_is_eq(in64, Botan::load_be(Botan::store_be(in64)));
1✔
355

356
         result.test_is_eq(in16, Botan::load_le(Botan::store_le(in16)));
1✔
357
         result.test_is_eq(in32, Botan::load_le(Botan::store_le(in32)));
1✔
358
         result.test_is_eq(in64, Botan::load_le(Botan::store_le(in64)));
1✔
359

360
         // Test that the runtime detects incompatible range sizes
361
#if !defined(BOTAN_TERMINATE_ON_ASSERTS)
362
         std::vector<uint16_t> too_big16(4);
363
         std::vector<uint16_t> too_small16(1);
364
         result.test_throws("load_le with incompatible buffers",
365
                            [&] { Botan::load_le(too_big16, Botan::hex_decode("BAADB00B")); });
366
         result.test_throws("load_le with incompatible buffers",
367
                            [&] { Botan::load_le(too_small16, Botan::hex_decode("BAADB00B")); });
368
         result.test_throws("load_be with incompatible buffers",
369
                            [&] { Botan::load_be(too_big16, Botan::hex_decode("BAADB00B")); });
370
         result.test_throws("load_be with incompatible buffers",
371
                            [&] { Botan::load_be(too_small16, Botan::hex_decode("BAADB00B")); });
372

373
         std::vector<uint8_t> too_big8(4);
374
         std::vector<uint8_t> too_small8(1);
375
         result.test_throws("store_le with incompatible buffers",
376
                            [&] { Botan::store_le(too_big8, std::array<uint16_t, 1>{}); });
377
         result.test_throws("store_le with incompatible buffers",
378
                            [&] { Botan::store_le(too_small8, std::array<uint16_t, 1>{}); });
379
         result.test_throws("store_be with incompatible buffers",
380
                            [&] { Botan::store_be(too_big8, std::array<uint16_t, 1>{}); });
381
         result.test_throws("store_be with incompatible buffers",
382
                            [&] { Botan::store_be(too_small8, std::array<uint16_t, 1>{}); });
383
#endif
384

385
         // Test store of entire ranges
386
         std::array<uint16_t, 2> in16_array = {0x0A0B, 0x0C0D};
1✔
387
         result.test_is_eq(Botan::store_be<std::vector<uint8_t>>(in16_array), Botan::hex_decode("0A0B0C0D"));
3✔
388
         result.test_is_eq(Botan::store_le<std::vector<uint8_t>>(in16_array), Botan::hex_decode("0B0A0D0C"));
3✔
389

390
         std::vector<uint16_t> in16_vector = {0x0A0B, 0x0C0D};
1✔
391
         result.test_is_eq(Botan::store_be<std::vector<uint8_t>>(in16_vector), Botan::hex_decode("0A0B0C0D"));
3✔
392
         result.test_is_eq(Botan::store_le<std::vector<uint8_t>>(in16_vector), Botan::hex_decode("0B0A0D0C"));
3✔
393

394
         std::array<uint8_t, 4> out_array;
1✔
395
         Botan::store_be(out_array, in16_array);
1✔
396
         result.test_is_eq(out_array, std::array<uint8_t, 4>{0x0A, 0x0B, 0x0C, 0x0D});
1✔
397
         Botan::store_le(out_array, in16_array);
1✔
398
         result.test_is_eq(out_array, std::array<uint8_t, 4>{0x0B, 0x0A, 0x0D, 0x0C});
1✔
399

400
         const auto be_inferred = Botan::store_be(in16_array);
1✔
401
         result.test_is_eq(be_inferred, std::array<uint8_t, 4>{0x0A, 0x0B, 0x0C, 0x0D});
1✔
402
         const auto le_inferred = Botan::store_le(in16_array);
1✔
403
         result.test_is_eq(le_inferred, std::array<uint8_t, 4>{0x0B, 0x0A, 0x0D, 0x0C});
1✔
404

405
         // Test load of entire ranges
406
         const auto in_buffer = Botan::hex_decode("AABBCCDD");
1✔
407
         auto out16_array_be = Botan::load_be<std::array<uint16_t, 2>>(in_buffer);
1✔
408
         result.test_is_eq<uint16_t>(out16_array_be[0], 0xAABB);
1✔
409
         result.test_is_eq<uint16_t>(out16_array_be[1], 0xCCDD);
1✔
410
         auto out16_vec_be = Botan::load_be<std::vector<uint16_t>>(in_buffer);
1✔
411
         result.test_eq_sz("be-vector has expected size", out16_vec_be.size(), 2);
1✔
412
         result.test_is_eq<uint16_t>(out16_vec_be[0], 0xAABB);
1✔
413
         result.test_is_eq<uint16_t>(out16_vec_be[1], 0xCCDD);
1✔
414

415
         auto out16_array_le = Botan::load_le<std::array<uint16_t, 2>>(in_buffer);
1✔
416
         result.test_is_eq<uint16_t>(out16_array_le[0], 0xBBAA);
1✔
417
         result.test_is_eq<uint16_t>(out16_array_le[1], 0xDDCC);
1✔
418
         auto out16_vec_le = Botan::load_le<Botan::secure_vector<uint16_t>>(in_buffer);
1✔
419
         result.test_eq_sz("le-vector has expected size", out16_vec_be.size(), 2);
1✔
420
         result.test_is_eq<uint16_t>(out16_vec_le[0], 0xBBAA);
1✔
421
         result.test_is_eq<uint16_t>(out16_vec_le[1], 0xDDCC);
1✔
422

423
         // Test loading/storing of strong type integers
424
         const TestInt64 in64_strong{0xABCDEF0123456789};
1✔
425
         const TestInt32 in32_strong{0xABCDEF01};
1✔
426

427
         result.test_is_eq(Botan::store_be<std::vector<uint8_t>>(in64_strong), Botan::hex_decode("ABCDEF0123456789"));
3✔
428
         result.test_is_eq(Botan::store_le<std::vector<uint8_t>>(in64_strong), Botan::hex_decode("8967452301EFCDAB"));
3✔
429
         result.test_is_eq(Botan::store_be<std::vector<uint8_t>>(in32_strong), Botan::hex_decode("ABCDEF01"));
3✔
430
         result.test_is_eq(Botan::store_le<std::vector<uint8_t>>(in32_strong), Botan::hex_decode("01EFCDAB"));
3✔
431

432
         result.test_is_eq(Botan::load_be<TestInt64>(Botan::hex_decode("ABCDEF0123456789")), in64_strong);
2✔
433
         result.test_is_eq(Botan::load_le<TestInt64>(Botan::hex_decode("8967452301EFCDAB")), in64_strong);
2✔
434
         result.test_is_eq(Botan::load_be<TestInt32>(Botan::hex_decode("ABCDEF01")), in32_strong);
2✔
435
         result.test_is_eq(Botan::load_le<TestInt32>(Botan::hex_decode("01EFCDAB")), in32_strong);
2✔
436

437
         std::vector<TestInt64> some_in64_strongs{TestInt64{0xABCDEF0123456789}, TestInt64{0x0123456789ABCDEF}};
1✔
438
         result.test_is_eq(Botan::store_be<std::vector<uint8_t>>(some_in64_strongs),
3✔
439
                           Botan::hex_decode("ABCDEF01234567890123456789ABCDEF"));
1✔
440
         result.test_is_eq(Botan::store_le<std::vector<uint8_t>>(some_in64_strongs),
3✔
441
                           Botan::hex_decode("8967452301EFCDABEFCDAB8967452301"));
1✔
442

443
         const auto in64_strongs_le =
1✔
444
            Botan::load_le<std::array<TestInt64, 2>>(Botan::hex_decode("8967452301EFCDABEFCDAB8967452301"));
2✔
445
         result.test_is_eq(in64_strongs_le[0], TestInt64{0xABCDEF0123456789});
1✔
446
         result.test_is_eq(in64_strongs_le[1], TestInt64{0x0123456789ABCDEF});
1✔
447

448
         const auto in64_strongs_be =
1✔
449
            Botan::load_be<std::vector<TestInt64>>(Botan::hex_decode("ABCDEF01234567890123456789ABCDEF"));
2✔
450
         result.test_is_eq(in64_strongs_be[0], TestInt64{0xABCDEF0123456789});
1✔
451
         result.test_is_eq(in64_strongs_be[1], TestInt64{0x0123456789ABCDEF});
1✔
452

453
         // Test loading/storing of enum types with different endianness
454
         const auto in64_enum_le = Botan::load_le<TestEnum64>(Botan::hex_decode("1234567890ABCDEF"));
2✔
455
         result.test_is_eq(in64_enum_le, TestEnum64::_2);
1✔
456
         const auto in64_enum_be = Botan::load_be<TestEnum64>(Botan::hex_decode("1234567890ABCDEF"));
2✔
457
         result.test_is_eq(in64_enum_be, TestEnum64::_1);
1✔
458
         result.test_is_eq(Botan::store_le<std::vector<uint8_t>>(TestEnum64::_1),
2✔
459
                           Botan::hex_decode("EFCDAB9078563412"));
1✔
460
         result.test_is_eq<std::array<uint8_t, 8>>(Botan::store_be(TestEnum64::_2),
1✔
461
                                                   {0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12});
462

463
         const auto in32_enum_le = Botan::load_le<TestEnum32>(Botan::hex_decode("78563412"));
2✔
464
         result.test_is_eq(in32_enum_le, TestEnum32::_1);
1✔
465
         const auto in32_enum_be = Botan::load_be<TestEnum32>(Botan::hex_decode("78563412"));
2✔
466
         result.test_is_eq(in32_enum_be, TestEnum32::_2);
1✔
467
         result.test_is_eq(Botan::store_le<std::vector<uint8_t>>(TestEnum32::_1), Botan::hex_decode("78563412"));
2✔
468
         result.test_is_eq<std::array<uint8_t, 4>>(Botan::store_be(TestEnum32::_2), {0x78, 0x56, 0x34, 0x12});
1✔
469

470
         return result;
2✔
471
      }
11✔
472

473
      template <std::unsigned_integral T>
474
      static T fb_load_be(std::array<const uint8_t, sizeof(T)> in) {
3✔
475
         return Botan::detail::fallback_load_any<Botan::detail::Endianness::Big, T>(in);
3✔
476
      }
477

478
      template <std::unsigned_integral T>
479
      static T fb_load_le(std::array<const uint8_t, sizeof(T)> in) {
3✔
480
         return Botan::detail::fallback_load_any<Botan::detail::Endianness::Little, T>(in);
3✔
481
      }
482

483
      template <std::unsigned_integral T>
484
      static decltype(auto) fb_store_be(const T in) {
3✔
485
         std::array<uint8_t, sizeof(T)> out;
486
         Botan::detail::fallback_store_any<Botan::detail::Endianness::Big, T>(in, out);
1✔
487
         return out;
2✔
488
      }
489

490
      template <std::unsigned_integral T>
491
      static decltype(auto) fb_store_le(const T in) {
3✔
492
         std::array<uint8_t, sizeof(T)> out;
493
         Botan::detail::fallback_store_any<Botan::detail::Endianness::Little, T>(in, out);
1✔
494
         return out;
2✔
495
      }
496

497
      template <size_t N>
498
      using a = std::array<uint8_t, N>;
499

500
      static Test::Result test_loadstore_ambiguity() {
1✔
501
         // This is a regression test for a (probable) compiler bug in Xcode 15
502
         // where it would fail to compile the load/store functions for size_t
503
         //
504
         // It seems that this platform defines uint64_t as "unsigned long long"
505
         // and size_t as "unsigned long". Both are 64-bits but the compiler
506
         // was unable to disambiguate the two in reverse_bytes in bswap.h
507

508
         const uint32_t in32 = 0x01234567;
1✔
509
         const uint64_t in64 = 0x0123456789ABCDEF;
1✔
510
         const size_t inszt = 0x87654321;
1✔
511

512
         Test::Result result("Util load/store ambiguity");
1✔
513
         const auto out_be_32 = Botan::store_be(in32);
1✔
514
         const auto out_le_32 = Botan::store_le(in32);
1✔
515
         const auto out_be_64 = Botan::store_be(in64);
1✔
516
         const auto out_le_64 = Botan::store_le(in64);
1✔
517
         const auto out_be_szt = Botan::store_be(inszt);
1✔
518
         const auto out_le_szt = Botan::store_le(inszt);
1✔
519

520
         result.test_is_eq<uint32_t>("be 32", Botan::load_be<uint32_t>(out_be_32), in32);
1✔
521
         result.test_is_eq<uint32_t>("le 32", Botan::load_le<uint32_t>(out_le_32), in32);
1✔
522
         result.test_is_eq<uint64_t>("be 64", Botan::load_be<uint64_t>(out_be_64), in64);
1✔
523
         result.test_is_eq<uint64_t>("le 64", Botan::load_le<uint64_t>(out_le_64), in64);
1✔
524
         result.test_is_eq<size_t>("be szt", Botan::load_be<size_t>(out_be_szt), inszt);
1✔
525
         result.test_is_eq<size_t>("le szt", Botan::load_le<size_t>(out_le_szt), inszt);
1✔
526

527
         return result;
1✔
528
      }
×
529

530
      static Test::Result test_loadstore_fallback() {
1✔
531
         // The fallback implementation is only used if we don't know the
532
         // endianness of the target at compile time. This makes sure that the
533
         // fallback implementation is correct. On all typical platforms it
534
         // won't be called in production.
535
         Test::Result result("Util load/store fallback");
1✔
536

537
         result.test_is_eq<uint16_t>("lLE 16", fb_load_le<uint16_t>({1, 2}), 0x0201);
1✔
538
         result.test_is_eq<uint32_t>("lLE 32", fb_load_le<uint32_t>({1, 2, 3, 4}), 0x04030201);
1✔
539
         result.test_is_eq<uint64_t>("lLE 64", fb_load_le<uint64_t>({1, 2, 3, 4, 5, 6, 7, 8}), 0x0807060504030201);
1✔
540

541
         result.test_is_eq<uint16_t>("lBE 16", fb_load_be<uint16_t>({1, 2}), 0x0102);
1✔
542
         result.test_is_eq<uint32_t>("lBE 32", fb_load_be<uint32_t>({1, 2, 3, 4}), 0x01020304);
1✔
543
         result.test_is_eq<uint64_t>("lBE 64", fb_load_be<uint64_t>({1, 2, 3, 4, 5, 6, 7, 8}), 0x0102030405060708);
1✔
544

545
         result.test_is_eq<a<2>>("sLE 16", fb_store_le<uint16_t>(0x0201), {1, 2});
1✔
546
         result.test_is_eq<a<4>>("sLE 32", fb_store_le<uint32_t>(0x04030201), {1, 2, 3, 4});
1✔
547
         result.test_is_eq<a<8>>("sLE 64", fb_store_le<uint64_t>(0x0807060504030201), {1, 2, 3, 4, 5, 6, 7, 8});
1✔
548

549
         result.test_is_eq<a<2>>("sBE 16", fb_store_be<uint16_t>(0x0102), {1, 2});
1✔
550
         result.test_is_eq<a<4>>("sBE 32", fb_store_be<uint32_t>(0x01020304), {1, 2, 3, 4});
1✔
551
         result.test_is_eq<a<8>>("sBE 64", fb_store_be<uint64_t>(0x0102030405060708), {1, 2, 3, 4, 5, 6, 7, 8});
1✔
552

553
         return result;
1✔
554
      }
×
555

556
      static Test::Result test_loadstore_constexpr() {
1✔
557
         Test::Result result("Util load/store constexpr");
1✔
558

559
         constexpr uint16_t in16 = 0x1234;
1✔
560
         constexpr uint32_t in32 = 0xA0B0C0D0;
1✔
561
         constexpr uint64_t in64 = 0xABCDEF0123456789;
1✔
562

563
         // clang-format off
564
         constexpr std::array<uint8_t, 16> cex_mem = {
1✔
565
            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
566
         };
567
         // clang-format on
568

569
         // get_byte<> w/ 16bit
570
         constexpr auto cex_byte_16_0 = Botan::get_byte<0>(in16);
1✔
571
         result.test_is_eq<uint8_t>(cex_byte_16_0, 0x12);
1✔
572
         constexpr auto cex_byte_16_1 = Botan::get_byte<1>(in16);
1✔
573
         result.test_is_eq<uint8_t>(cex_byte_16_1, 0x34);
1✔
574

575
         // get_byte<> w/ 32bit
576
         constexpr auto cex_byte_32_0 = Botan::get_byte<0>(in32);
1✔
577
         result.test_is_eq<uint8_t>(cex_byte_32_0, 0xA0);
1✔
578
         constexpr auto cex_byte_32_1 = Botan::get_byte<1>(in32);
1✔
579
         result.test_is_eq<uint8_t>(cex_byte_32_1, 0xB0);
1✔
580
         constexpr auto cex_byte_32_2 = Botan::get_byte<2>(in32);
1✔
581
         result.test_is_eq<uint8_t>(cex_byte_32_2, 0xC0);
1✔
582
         constexpr auto cex_byte_32_3 = Botan::get_byte<3>(in32);
1✔
583
         result.test_is_eq<uint8_t>(cex_byte_32_3, 0xD0);
1✔
584

585
         // get_byte<> w/ 64bit
586
         constexpr auto cex_byte_64_0 = Botan::get_byte<0>(in64);
1✔
587
         result.test_is_eq<uint8_t>(cex_byte_64_0, 0xAB);
1✔
588
         constexpr auto cex_byte_64_1 = Botan::get_byte<1>(in64);
1✔
589
         result.test_is_eq<uint8_t>(cex_byte_64_1, 0xCD);
1✔
590
         constexpr auto cex_byte_64_2 = Botan::get_byte<2>(in64);
1✔
591
         result.test_is_eq<uint8_t>(cex_byte_64_2, 0xEF);
1✔
592
         constexpr auto cex_byte_64_3 = Botan::get_byte<3>(in64);
1✔
593
         result.test_is_eq<uint8_t>(cex_byte_64_3, 0x01);
1✔
594
         constexpr auto cex_byte_64_4 = Botan::get_byte<4>(in64);
1✔
595
         result.test_is_eq<uint8_t>(cex_byte_64_4, 0x23);
1✔
596
         constexpr auto cex_byte_64_5 = Botan::get_byte<5>(in64);
1✔
597
         result.test_is_eq<uint8_t>(cex_byte_64_5, 0x45);
1✔
598
         constexpr auto cex_byte_64_6 = Botan::get_byte<6>(in64);
1✔
599
         result.test_is_eq<uint8_t>(cex_byte_64_6, 0x67);
1✔
600
         constexpr auto cex_byte_64_7 = Botan::get_byte<7>(in64);
1✔
601
         result.test_is_eq<uint8_t>(cex_byte_64_7, 0x89);
1✔
602

603
         // make_uintXX()
604
         constexpr auto cex_uint16_t = Botan::make_uint16(0x12, 0x34);
1✔
605
         result.test_is_eq<uint16_t>(cex_uint16_t, in16);
1✔
606
         constexpr auto cex_uint32_t = Botan::make_uint32(0xA0, 0xB0, 0xC0, 0xD0);
1✔
607
         result.test_is_eq<uint32_t>(cex_uint32_t, in32);
1✔
608
         constexpr auto cex_uint64_t = Botan::make_uint64(0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89);
1✔
609
         result.test_is_eq<uint64_t>(cex_uint64_t, in64);
1✔
610

611
         // store_le/be with a single integer
612
         constexpr std::array<uint8_t, 2> cex_store_le16 = Botan::store_le(in16);
1✔
613
         result.test_is_eq(cex_store_le16, std::array<uint8_t, 2>{0x34, 0x12});
1✔
614
         constexpr std::array<uint8_t, 4> cex_store_le32 = Botan::store_le(in32);
1✔
615
         result.test_is_eq(cex_store_le32, std::array<uint8_t, 4>{0xD0, 0xC0, 0xB0, 0xA0});
1✔
616
         constexpr std::array<uint8_t, 8> cex_store_le64 = Botan::store_le(in64);
1✔
617
         result.test_is_eq(cex_store_le64, std::array<uint8_t, 8>{0x89, 0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB});
1✔
618

619
         constexpr std::array<uint8_t, 2> cex_store_be16 = Botan::store_be(in16);
1✔
620
         result.test_is_eq(cex_store_be16, std::array<uint8_t, 2>{0x12, 0x34});
1✔
621
         constexpr std::array<uint8_t, 4> cex_store_be32 = Botan::store_be(in32);
1✔
622
         result.test_is_eq(cex_store_be32, std::array<uint8_t, 4>{0xA0, 0xB0, 0xC0, 0xD0});
1✔
623
         constexpr std::array<uint8_t, 8> cex_store_be64 = Botan::store_be(in64);
1✔
624
         result.test_is_eq(cex_store_be64, std::array<uint8_t, 8>{0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89});
1✔
625

626
         // store_le/be with multiple integers, both as a parameter pack and a range (std::array for constexpr)
627
         constexpr std::array<uint8_t, 16> cex_store_le16s =
1✔
628
            Botan::store_le(in16, in16, in16, in16, in16, in16, in16, in16);
629
         constexpr std::array<uint8_t, 16> cex_store_le16s2 =
1✔
630
            Botan::store_le(std::array{in16, in16, in16, in16, in16, in16, in16, in16});
631
         result.test_is_eq(
1✔
632
            cex_store_le16s,
633
            {0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12});
634
         result.test_is_eq(cex_store_le16s, cex_store_le16s2);
1✔
635
         constexpr std::array<uint8_t, 16> cex_store_le32s = Botan::store_le(in32, in32, in32, in32);
1✔
636
         constexpr std::array<uint8_t, 16> cex_store_le32s2 = Botan::store_le(std::array{in32, in32, in32, in32});
1✔
637
         result.test_is_eq(
1✔
638
            cex_store_le32s,
639
            {0xD0, 0xC0, 0xB0, 0xA0, 0xD0, 0xC0, 0xB0, 0xA0, 0xD0, 0xC0, 0xB0, 0xA0, 0xD0, 0xC0, 0xB0, 0xA0});
640
         result.test_is_eq(cex_store_le32s, cex_store_le32s2);
1✔
641
         constexpr std::array<uint8_t, 16> cex_store_le64s = Botan::store_le(in64, in64);
1✔
642
         constexpr std::array<uint8_t, 16> cex_store_le64s2 = Botan::store_le(std::array{in64, in64});
1✔
643
         result.test_is_eq(
1✔
644
            cex_store_le64s,
645
            {0x89, 0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB});
646
         result.test_is_eq(cex_store_le64s, cex_store_le64s2);
1✔
647

648
         constexpr std::array<uint8_t, 16> cex_store_be16s =
1✔
649
            Botan::store_be(in16, in16, in16, in16, in16, in16, in16, in16);
650
         constexpr std::array<uint8_t, 16> cex_store_be16s2 =
1✔
651
            Botan::store_be(std::array{in16, in16, in16, in16, in16, in16, in16, in16});
652
         result.test_is_eq(
1✔
653
            cex_store_be16s,
654
            {0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34});
655
         result.test_is_eq(cex_store_be16s, cex_store_be16s2);
1✔
656
         constexpr std::array<uint8_t, 16> cex_store_be32s = Botan::store_be(in32, in32, in32, in32);
1✔
657
         constexpr std::array<uint8_t, 16> cex_store_be32s2 = Botan::store_be(std::array{in32, in32, in32, in32});
1✔
658
         result.test_is_eq(
1✔
659
            cex_store_be32s,
660
            {0xA0, 0xB0, 0xC0, 0xD0, 0xA0, 0xB0, 0xC0, 0xD0, 0xA0, 0xB0, 0xC0, 0xD0, 0xA0, 0xB0, 0xC0, 0xD0});
661
         result.test_is_eq(cex_store_be32s, cex_store_be32s2);
1✔
662
         constexpr std::array<uint8_t, 16> cex_store_be64s = Botan::store_be(in64, in64);
1✔
663
         constexpr std::array<uint8_t, 16> cex_store_be64s2 = Botan::store_be(std::array{in64, in64});
1✔
664
         result.test_is_eq(
1✔
665
            cex_store_be64s,
666
            {0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89});
667
         result.test_is_eq(cex_store_be64s, cex_store_be64s2);
1✔
668

669
         // load_le/be a single integer
670
         constexpr uint16_t cex_load_le16 = Botan::load_le<uint16_t>(cex_store_le16);
1✔
671
         result.test_is_eq(cex_load_le16, in16);
1✔
672
         constexpr uint32_t cex_load_le32 = Botan::load_le<uint32_t>(cex_store_le32);
1✔
673
         result.test_is_eq(cex_load_le32, in32);
1✔
674
         constexpr uint64_t cex_load_le64 = Botan::load_le<uint64_t>(cex_store_le64);
1✔
675
         result.test_is_eq(cex_load_le64, in64);
1✔
676

677
         constexpr uint16_t cex_load_be16 = Botan::load_be<uint16_t>(cex_store_be16);
1✔
678
         result.test_is_eq(cex_load_be16, in16);
1✔
679
         constexpr uint32_t cex_load_be32 = Botan::load_be<uint32_t>(cex_store_be32);
1✔
680
         result.test_is_eq(cex_load_be32, in32);
1✔
681
         constexpr uint64_t cex_load_be64 = Botan::load_be<uint64_t>(cex_store_be64);
1✔
682
         result.test_is_eq(cex_load_be64, in64);
1✔
683

684
         // load_le/be multiple integers into a std::array for constexpr
685
         constexpr auto cex_load_le16s = Botan::load_le<std::array<uint16_t, cex_mem.size() / 2>>(cex_mem);
1✔
686
         result.test_is_eq(cex_load_le16s, {0x1100, 0x3322, 0x5544, 0x7766, 0x9988, 0xBBAA, 0xDDCC, 0xFFEE});
1✔
687
         constexpr auto cex_load_le32s = Botan::load_le<std::array<uint32_t, cex_mem.size() / 4>>(cex_mem);
1✔
688
         result.test_is_eq(cex_load_le32s, {0x33221100, 0x77665544, 0xBBAA9988, 0xFFEEDDCC});
1✔
689
         constexpr auto cex_load_le64s = Botan::load_le<std::array<uint64_t, cex_mem.size() / 8>>(cex_mem);
1✔
690
         result.test_is_eq(cex_load_le64s, {0x7766554433221100, 0xFFEEDDCCBBAA9988});
1✔
691

692
         constexpr auto cex_load_be16s = Botan::load_be<std::array<uint16_t, cex_mem.size() / 2>>(cex_mem);
1✔
693
         result.test_is_eq(cex_load_be16s, {0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xAABB, 0xCCDD, 0xEEFF});
1✔
694
         constexpr auto cex_load_be32s = Botan::load_be<std::array<uint32_t, cex_mem.size() / 4>>(cex_mem);
1✔
695
         result.test_is_eq(cex_load_be32s, {0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF});
1✔
696
         constexpr auto cex_load_be64s = Botan::load_be<std::array<uint64_t, cex_mem.size() / 8>>(cex_mem);
1✔
697
         result.test_is_eq(cex_load_be64s, {0x0011223344556677, 0x8899AABBCCDDEEFF});
1✔
698

699
         return result;
1✔
700
      }
×
701

702
      static std::vector<Test::Result> test_copy_out_be_le() {
1✔
703
         return {
1✔
704
            CHECK("copy_out_be with 16bit input (word aligned)",
705
                  [&](auto& result) {
1✔
706
                     std::vector<uint8_t> out_vector(4);
1✔
707
                     const std::array<uint16_t, 2> in_array = {0x0A0B, 0x0C0D};
1✔
708
                     Botan::copy_out_be(out_vector, in_array);
1✔
709
                     result.test_is_eq(out_vector, Botan::hex_decode("0A0B0C0D"));
2✔
710
                  }),
1✔
711

712
            CHECK("copy_out_be with 16bit input (partial words)",
713
                  [&](auto& result) {
1✔
714
                     std::vector<uint8_t> out_vector(3);
1✔
715
                     const std::array<uint16_t, 2> in_array = {0x0A0B, 0x0C0D};
1✔
716
                     Botan::copy_out_be(out_vector, in_array);
1✔
717
                     result.test_is_eq(out_vector, Botan::hex_decode("0A0B0C"));
2✔
718
                  }),
1✔
719

720
            CHECK("copy_out_le with 16bit input (word aligned)",
721
                  [&](auto& result) {
1✔
722
                     std::vector<uint8_t> out_vector(4);
1✔
723
                     const std::array<uint16_t, 2> in_array = {0x0A0B, 0x0C0D};
1✔
724
                     Botan::copy_out_le(out_vector, in_array);
1✔
725
                     result.test_is_eq(out_vector, Botan::hex_decode("0B0A0D0C"));
2✔
726
                  }),
1✔
727

728
            CHECK("copy_out_le with 16bit input (partial words)",
729
                  [&](auto& result) {
1✔
730
                     std::vector<uint8_t> out_vector(3);
1✔
731
                     const std::array<uint16_t, 2> in_array = {0x0A0B, 0x0C0D};
1✔
732
                     Botan::copy_out_le(out_vector, in_array);
1✔
733
                     result.test_is_eq(out_vector, Botan::hex_decode("0B0A0D"));
2✔
734
                  }),
1✔
735

736
            CHECK("copy_out_be with 64bit input (word aligned)",
737
                  [&](auto& result) {
1✔
738
                     std::vector<uint8_t> out_vector(16);
1✔
739
                     const std::array<uint64_t, 2> in_array = {0x0A0B0C0D0E0F1011, 0x1213141516171819};
1✔
740
                     Botan::copy_out_be(out_vector, in_array);
1✔
741
                     result.test_is_eq(out_vector, Botan::hex_decode("0A0B0C0D0E0F10111213141516171819"));
2✔
742
                  }),
1✔
743

744
            CHECK("copy_out_le with 64bit input (word aligned)",
745
                  [&](auto& result) {
1✔
746
                     std::vector<uint8_t> out_vector(16);
1✔
747
                     const std::array<uint64_t, 2> in_array = {0x0A0B0C0D0E0F1011, 0x1213141516171819};
1✔
748
                     Botan::copy_out_le(out_vector, in_array);
1✔
749
                     result.test_is_eq(out_vector, Botan::hex_decode("11100F0E0D0C0B0A1918171615141312"));
2✔
750
                  }),
1✔
751

752
            CHECK("copy_out_be with 64bit input (partial words)",
753
                  [&](auto& result) {
1✔
754
                     std::vector<uint8_t> out_vector(15);
1✔
755
                     const std::array<uint64_t, 2> in_array = {0x0A0B0C0D0E0F1011, 0x1213141516171819};
1✔
756
                     Botan::copy_out_be(out_vector, in_array);
1✔
757
                     result.test_is_eq(out_vector, Botan::hex_decode("0A0B0C0D0E0F101112131415161718"));
2✔
758
                  }),
1✔
759

760
            CHECK("copy_out_le with 64bit input (partial words)",
761
                  [&](auto& result) {
1✔
762
                     std::vector<uint8_t> out_vector(15);
1✔
763
                     const std::array<uint64_t, 2> in_array = {0x0A0B0C0D0E0F1011, 0x1213141516171819};
1✔
764
                     Botan::copy_out_le(out_vector, in_array);
1✔
765
                     result.test_is_eq(out_vector, Botan::hex_decode("11100F0E0D0C0B0A19181716151413"));
2✔
766
                  }),
1✔
767
         };
9✔
768
      }
1✔
769
};
770

771
BOTAN_REGISTER_SMOKE_TEST("utils", "util", Utility_Function_Tests);
772

773
class BitOps_Tests final : public Test {
×
774
   public:
775
      std::vector<Test::Result> run() override {
1✔
776
         std::vector<Test::Result> results;
1✔
777

778
         results.push_back(test_power_of_2());
2✔
779
         results.push_back(test_ctz());
2✔
780
         results.push_back(test_sig_bytes());
2✔
781
         results.push_back(test_popcount());
2✔
782
         results.push_back(test_reverse_bits());
2✔
783

784
         return results;
1✔
785
      }
×
786

787
   private:
788
      template <typename T>
789
      void test_ctz(Test::Result& result, T val, size_t expected) {
6✔
790
         result.test_eq("ctz(" + std::to_string(val) + ")", Botan::ctz<T>(val), expected);
24✔
791
      }
6✔
792

793
      Test::Result test_ctz() {
1✔
794
         Test::Result result("ctz");
1✔
795
         test_ctz<uint32_t>(result, 0, 32);
1✔
796
         test_ctz<uint32_t>(result, 1, 0);
1✔
797
         test_ctz<uint32_t>(result, 0x80, 7);
1✔
798
         test_ctz<uint32_t>(result, 0x8000000, 27);
1✔
799
         test_ctz<uint32_t>(result, 0x8100000, 20);
1✔
800
         test_ctz<uint32_t>(result, 0x80000000, 31);
1✔
801

802
         return result;
1✔
803
      }
×
804

805
      template <typename T>
806
      void test_sig_bytes(Test::Result& result, T val, size_t expected) {
14✔
807
         result.test_eq("significant_bytes(" + std::to_string(val) + ")", Botan::significant_bytes<T>(val), expected);
56✔
808
      }
14✔
809

810
      Test::Result test_sig_bytes() {
1✔
811
         Test::Result result("significant_bytes");
1✔
812
         test_sig_bytes<uint32_t>(result, 0, 0);
1✔
813
         test_sig_bytes<uint32_t>(result, 1, 1);
1✔
814
         test_sig_bytes<uint32_t>(result, 0x80, 1);
1✔
815
         test_sig_bytes<uint32_t>(result, 255, 1);
1✔
816
         test_sig_bytes<uint32_t>(result, 256, 2);
1✔
817
         test_sig_bytes<uint32_t>(result, 65535, 2);
1✔
818
         test_sig_bytes<uint32_t>(result, 65536, 3);
1✔
819
         test_sig_bytes<uint32_t>(result, 0x80000000, 4);
1✔
820

821
         test_sig_bytes<uint64_t>(result, 0, 0);
1✔
822
         test_sig_bytes<uint64_t>(result, 1, 1);
1✔
823
         test_sig_bytes<uint64_t>(result, 0x80, 1);
1✔
824
         test_sig_bytes<uint64_t>(result, 256, 2);
1✔
825
         test_sig_bytes<uint64_t>(result, 0x80000000, 4);
1✔
826
         test_sig_bytes<uint64_t>(result, 0x100000000, 5);
1✔
827

828
         return result;
1✔
829
      }
×
830

831
      template <typename T>
832
      void test_power_of_2(Test::Result& result, T val, bool expected) {
15✔
833
         result.test_eq("power_of_2(" + std::to_string(val) + ")", Botan::is_power_of_2<T>(val), expected);
75✔
834
      }
15✔
835

836
      Test::Result test_power_of_2() {
1✔
837
         Test::Result result("is_power_of_2");
1✔
838

839
         test_power_of_2<uint32_t>(result, 0, false);
1✔
840
         test_power_of_2<uint32_t>(result, 1, false);
1✔
841
         test_power_of_2<uint32_t>(result, 2, true);
1✔
842
         test_power_of_2<uint32_t>(result, 3, false);
1✔
843
         test_power_of_2<uint32_t>(result, 0x8000, true);
1✔
844
         test_power_of_2<uint32_t>(result, 0x8001, false);
1✔
845
         test_power_of_2<uint32_t>(result, 0x8000000, true);
1✔
846

847
         test_power_of_2<uint64_t>(result, 0, false);
1✔
848
         test_power_of_2<uint64_t>(result, 1, false);
1✔
849
         test_power_of_2<uint64_t>(result, 2, true);
1✔
850
         test_power_of_2<uint64_t>(result, 3, false);
1✔
851
         test_power_of_2<uint64_t>(result, 0x8000, true);
1✔
852
         test_power_of_2<uint64_t>(result, 0x8001, false);
1✔
853
         test_power_of_2<uint64_t>(result, 0x8000000, true);
1✔
854
         test_power_of_2<uint64_t>(result, 0x100000000000, true);
1✔
855

856
         return result;
1✔
857
      }
×
858

859
      template <typename T>
860
      auto pc(T val) -> decltype(Botan::ct_popcount(val)) {
2✔
861
         return Botan::ct_popcount(val);
10✔
862
      }
863

864
      template <typename T>
865
      auto random_pc(Test::Result& result) {
4✔
866
         auto n = Botan::load_le<T>(Test::rng().random_array<sizeof(T)>());
4✔
867
         result.test_is_eq<size_t>(Botan::fmt("popcount({}) == {}", n, std::popcount(n)), pc(n), std::popcount(n));
4✔
868
      }
4✔
869

870
      Test::Result test_popcount() {
1✔
871
         Test::Result result("popcount");
1✔
872

873
         result.test_is_eq<uint8_t>("popcount<uint8_t>(0)", pc<uint8_t>(0), 0);
1✔
874
         result.test_is_eq<uint8_t>("popcount<uint16_t>(0)", pc<uint16_t>(0), 0);
1✔
875
         result.test_is_eq<uint8_t>("popcount<uint32_t>(0)", pc<uint32_t>(0), 0);
1✔
876
         result.test_is_eq<uint8_t>("popcount<uint64_t>(0)", pc<uint64_t>(0), 0);
1✔
877

878
         result.test_is_eq<uint8_t>("popcount<uint8_t>(1)", pc<uint8_t>(1), 1);
1✔
879
         result.test_is_eq<uint8_t>("popcount<uint16_t>(1)", pc<uint16_t>(1), 1);
1✔
880
         result.test_is_eq<uint8_t>("popcount<uint32_t>(1)", pc<uint32_t>(1), 1);
1✔
881
         result.test_is_eq<uint8_t>("popcount<uint64_t>(1)", pc<uint64_t>(1), 1);
1✔
882

883
         result.test_is_eq<uint8_t>("popcount<uint8_t>(0xAA)", pc<uint8_t>(0xAA), 4);
1✔
884
         result.test_is_eq<uint8_t>("popcount<uint16_t>(0xAAAA)", pc<uint16_t>(0xAAAA), 8);
1✔
885
         result.test_is_eq<uint8_t>("popcount<uint32_t>(0xAAAA...)", pc<uint32_t>(0xAAAAAAAA), 16);
1✔
886
         result.test_is_eq<uint8_t>("popcount<uint64_t>(0xAAAA...)", pc<uint64_t>(0xAAAAAAAAAAAAAAAA), 32);
1✔
887

888
         result.test_is_eq<uint8_t>("popcount<uint8_t>(0xFF)", pc<uint8_t>(0xFF), 8);
1✔
889
         result.test_is_eq<uint8_t>("popcount<uint16_t>(0xFFFF)", pc<uint16_t>(0xFFFF), 16);
1✔
890
         result.test_is_eq<uint8_t>("popcount<uint32_t>(0xFFFF...)", pc<uint32_t>(0xFFFFFFFF), 32);
1✔
891
         result.test_is_eq<uint8_t>("popcount<uint64_t>(0xFFFF...)", pc<uint64_t>(0xFFFFFFFFFFFFFFFF), 64);
1✔
892

893
         random_pc<uint8_t>(result);
1✔
894
         random_pc<uint16_t>(result);
1✔
895
         random_pc<uint32_t>(result);
1✔
896
         random_pc<uint64_t>(result);
1✔
897

898
         return result;
1✔
899
      }
×
900

901
      Test::Result test_reverse_bits() {
1✔
902
         Test::Result result("reverse_bits");
1✔
903

904
         result.test_is_eq<uint8_t>("rev(0u8)", Botan::ct_reverse_bits<uint8_t>(0b00000000), 0b00000000);
1✔
905
         result.test_is_eq<uint8_t>("rev(1u8)", Botan::ct_reverse_bits<uint8_t>(0b01010101), 0b10101010);
1✔
906
         result.test_is_eq<uint8_t>("rev(2u8)", Botan::ct_reverse_bits<uint8_t>(0b01001011), 0b11010010);
1✔
907

908
         result.test_is_eq<uint16_t>(
1✔
909
            "rev(0u16)", Botan::ct_reverse_bits<uint16_t>(0b0000000000000000), 0b0000000000000000);
1✔
910
         result.test_is_eq<uint16_t>(
1✔
911
            "rev(1u16)", Botan::ct_reverse_bits<uint16_t>(0b0101010101010101), 0b1010101010101010);
1✔
912
         result.test_is_eq<uint16_t>(
1✔
913
            "rev(2u16)", Botan::ct_reverse_bits<uint16_t>(0b0100101101011010), 0b0101101011010010);
1✔
914

915
         result.test_is_eq<uint32_t>("rev(0u32)", Botan::ct_reverse_bits<uint32_t>(0xFFFFFFFF), 0xFFFFFFFF);
1✔
916
         result.test_is_eq<uint32_t>("rev(1u32)", Botan::ct_reverse_bits<uint32_t>(0x55555555), 0xAAAAAAAA);
1✔
917
         result.test_is_eq<uint32_t>("rev(2u32)", Botan::ct_reverse_bits<uint32_t>(0x4B6A2C1D), 0xB83456D2);
1✔
918

919
         result.test_is_eq<uint64_t>(
1✔
920
            "rev(0u64)", Botan::ct_reverse_bits<uint64_t>(0xF0E0D0C005040302), 0x40C020A0030B070F);
1✔
921
         result.test_is_eq<uint64_t>(
1✔
922
            "rev(1u64)", Botan::ct_reverse_bits<uint64_t>(0x5555555555555555), 0xAAAAAAAAAAAAAAAA);
1✔
923
         result.test_is_eq<uint64_t>(
1✔
924
            "rev(2u64)", Botan::ct_reverse_bits<uint64_t>(0x4B6A2C1D5E7F8A90), 0x951FE7AB83456D2);
1✔
925

926
         return result;
1✔
927
      }
×
928
};
929

930
BOTAN_REGISTER_TEST("utils", "bit_ops", BitOps_Tests);
931

932
#if defined(BOTAN_HAS_POLY_DBL)
933

934
class Poly_Double_Tests final : public Text_Based_Test {
×
935
   public:
936
      Poly_Double_Tests() : Text_Based_Test("poly_dbl.vec", "In,Out") {}
2✔
937

938
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
82✔
939
         Test::Result result("Polynomial doubling");
82✔
940
         const std::vector<uint8_t> in = vars.get_req_bin("In");
82✔
941
         const std::vector<uint8_t> out = vars.get_req_bin("Out");
82✔
942

943
         std::vector<uint8_t> b = in;
82✔
944
         Botan::poly_double_n(b.data(), b.size());
82✔
945

946
         result.test_eq("Expected value", b, out);
82✔
947
         return result;
82✔
948
      }
246✔
949
};
950

951
BOTAN_REGISTER_TEST("utils", "poly_dbl", Poly_Double_Tests);
952

953
#endif
954

955
class Version_Tests final : public Test {
×
956
   public:
957
      std::vector<Test::Result> run() override {
1✔
958
         Test::Result result("Versions");
1✔
959

960
         result.confirm("Version datestamp matches macro", Botan::version_datestamp() == BOTAN_VERSION_DATESTAMP);
2✔
961

962
         const char* version_cstr = Botan::version_cstr();
1✔
963
         std::string version_str = Botan::version_string();
1✔
964
         result.test_eq("Same version string", version_str, std::string(version_cstr));
2✔
965

966
         const char* sversion_cstr = Botan::short_version_cstr();
1✔
967
         std::string sversion_str = Botan::short_version_string();
1✔
968
         result.test_eq("Same short version string", sversion_str, std::string(sversion_cstr));
2✔
969

970
         std::string expected_sversion = std::to_string(BOTAN_VERSION_MAJOR) + "." +
3✔
971
                                         std::to_string(BOTAN_VERSION_MINOR) + "." +
3✔
972
                                         std::to_string(BOTAN_VERSION_PATCH);
2✔
973

974
#if defined(BOTAN_VERSION_SUFFIX)
975
         expected_sversion += BOTAN_VERSION_SUFFIX_STR;
976
#endif
977

978
         result.test_eq("Short version string has expected format", sversion_str, expected_sversion);
1✔
979

980
         const std::string version_check_ok =
1✔
981
            Botan::runtime_version_check(BOTAN_VERSION_MAJOR, BOTAN_VERSION_MINOR, BOTAN_VERSION_PATCH);
1✔
982

983
         result.confirm("Correct version no warning", version_check_ok.empty());
2✔
984

985
         const std::string version_check_bad = Botan::runtime_version_check(1, 19, 42);
1✔
986

987
         const std::string expected_error =
1✔
988
            "Warning: linked version (" + sversion_str + ") does not match version built against (1.19.42)\n";
2✔
989

990
         result.test_eq("Expected warning text", version_check_bad, expected_error);
1✔
991

992
         return {result};
3✔
993
      }
2✔
994
};
995

996
BOTAN_REGISTER_TEST("utils", "versioning", Version_Tests);
997

998
class Date_Format_Tests final : public Text_Based_Test {
×
999
   public:
1000
      Date_Format_Tests() : Text_Based_Test("dates.vec", "Date") {}
2✔
1001

1002
      static std::vector<uint32_t> parse_date(const std::string& s) {
8✔
1003
         const std::vector<std::string> parts = Botan::split_on(s, ',');
8✔
1004
         if(parts.size() != 6) {
8✔
1005
            throw Test_Error("Bad date format '" + s + "'");
×
1006
         }
1007

1008
         std::vector<uint32_t> u32s;
8✔
1009
         u32s.reserve(parts.size());
8✔
1010
         for(const auto& sub : parts) {
56✔
1011
            u32s.push_back(Botan::to_u32bit(sub));
48✔
1012
         }
1013
         return u32s;
8✔
1014
      }
8✔
1015

1016
      Test::Result run_one_test(const std::string& type, const VarMap& vars) override {
8✔
1017
         const std::string date_str = vars.get_req_str("Date");
8✔
1018
         Test::Result result("Date parsing");
8✔
1019

1020
         const std::vector<uint32_t> d = parse_date(date_str);
8✔
1021

1022
         if(type == "valid" || type == "valid.not_std" || type == "valid.64_bit_time_t") {
8✔
1023
            Botan::calendar_point c(d[0], d[1], d[2], d[3], d[4], d[5]);
8✔
1024
            result.test_is_eq(date_str + " year", c.year(), d[0]);
8✔
1025
            result.test_is_eq(date_str + " month", c.month(), d[1]);
8✔
1026
            result.test_is_eq(date_str + " day", c.day(), d[2]);
8✔
1027
            result.test_is_eq(date_str + " hour", c.hour(), d[3]);
8✔
1028
            result.test_is_eq(date_str + " minute", c.minutes(), d[4]);
8✔
1029
            result.test_is_eq(date_str + " second", c.seconds(), d[5]);
8✔
1030

1031
            if(type == "valid.not_std" ||
8✔
1032
               (type == "valid.64_bit_time_t" && c.year() > 2037 && sizeof(std::time_t) == 4)) {
1033
               result.test_throws("valid but out of std::timepoint range", [c]() { c.to_std_timepoint(); });
12✔
1034
            } else {
1035
               Botan::calendar_point c2(c.to_std_timepoint());
5✔
1036
               result.test_is_eq(date_str + " year", c2.year(), d[0]);
5✔
1037
               result.test_is_eq(date_str + " month", c2.month(), d[1]);
5✔
1038
               result.test_is_eq(date_str + " day", c2.day(), d[2]);
5✔
1039
               result.test_is_eq(date_str + " hour", c2.hour(), d[3]);
5✔
1040
               result.test_is_eq(date_str + " minute", c2.minutes(), d[4]);
5✔
1041
               result.test_is_eq(date_str + " second", c2.seconds(), d[5]);
10✔
1042
            }
1043
         } else if(type == "invalid") {
×
1044
            result.test_throws("invalid date", [d]() { Botan::calendar_point c(d[0], d[1], d[2], d[3], d[4], d[5]); });
×
1045
         } else {
1046
            throw Test_Error("Unexpected header '" + type + "' in date format tests");
×
1047
         }
1048

1049
         return result;
16✔
1050
      }
8✔
1051

1052
      std::vector<Test::Result> run_final_tests() override {
1✔
1053
         Test::Result result("calendar_point::to_string");
1✔
1054
         Botan::calendar_point d(2008, 5, 15, 9, 30, 33);
1✔
1055
         // desired format: <YYYY>-<MM>-<dd>T<HH>:<mm>:<ss>
1056
         result.test_eq("calendar_point::to_string", d.to_string(), "2008-05-15T09:30:33");
2✔
1057
         return {result};
3✔
1058
      }
2✔
1059
};
1060

1061
BOTAN_REGISTER_TEST("utils", "util_dates", Date_Format_Tests);
1062

1063
class Charset_Tests final : public Text_Based_Test {
×
1064
   public:
1065
      Charset_Tests() : Text_Based_Test("charset.vec", "In,Out") {}
2✔
1066

1067
      Test::Result run_one_test(const std::string& type, const VarMap& vars) override {
8✔
1068
         Test::Result result("Charset");
8✔
1069

1070
         const std::vector<uint8_t> in = vars.get_req_bin("In");
8✔
1071
         const std::vector<uint8_t> expected = vars.get_req_bin("Out");
8✔
1072

1073
         std::string converted;
8✔
1074

1075
         if(type == "UCS2-UTF8") {
8✔
1076
            converted = Botan::ucs2_to_utf8(in.data(), in.size());
4✔
1077
         } else if(type == "UCS4-UTF8") {
4✔
1078
            converted = Botan::ucs4_to_utf8(in.data(), in.size());
1✔
1079
         } else if(type == "LATIN1-UTF8") {
3✔
1080
            converted = Botan::latin1_to_utf8(in.data(), in.size());
3✔
1081
         } else {
1082
            throw Test_Error("Unexpected header '" + type + "' in charset tests");
×
1083
         }
1084

1085
         result.test_eq(
16✔
1086
            "string converted successfully", std::vector<uint8_t>(converted.begin(), converted.end()), expected);
8✔
1087

1088
         return result;
8✔
1089
      }
24✔
1090
};
1091

1092
BOTAN_REGISTER_TEST("utils", "charset", Charset_Tests);
1093

1094
class Hostname_Tests final : public Text_Based_Test {
×
1095
   public:
1096
      Hostname_Tests() : Text_Based_Test("hostnames.vec", "Issued,Hostname") {}
2✔
1097

1098
      Test::Result run_one_test(const std::string& type, const VarMap& vars) override {
44✔
1099
         Test::Result result("Hostname Matching");
44✔
1100

1101
         const std::string issued = vars.get_req_str("Issued");
44✔
1102
         const std::string hostname = vars.get_req_str("Hostname");
44✔
1103
         const bool expected = (type == "Invalid") ? false : true;
44✔
1104

1105
         const std::string what = hostname + ((expected == true) ? " matches " : " does not match ") + issued;
88✔
1106
         result.test_eq(what, Botan::host_wildcard_match(issued, hostname), expected);
44✔
1107

1108
         return result;
44✔
1109
      }
44✔
1110
};
1111

1112
BOTAN_REGISTER_TEST("utils", "hostname", Hostname_Tests);
1113

1114
class IPv4_Parsing_Tests final : public Text_Based_Test {
×
1115
   public:
1116
      IPv4_Parsing_Tests() : Text_Based_Test("utils/ipv4.vec", "IPv4") {}
2✔
1117

1118
      Test::Result run_one_test(const std::string& status, const VarMap& vars) override {
47✔
1119
         Test::Result result("IPv4 parsing");
47✔
1120

1121
         const std::string input = vars.get_req_str("IPv4");
47✔
1122
         const bool valid = (status == "Valid");
47✔
1123

1124
         auto ipv4 = Botan::string_to_ipv4(input);
47✔
1125

1126
         result.test_eq("string_to_ipv4 accepts only valid", valid, ipv4.has_value());
47✔
1127

1128
         if(ipv4) {
47✔
1129
            const std::string rt = Botan::ipv4_to_string(ipv4.value());
13✔
1130
            result.test_eq("ipv4_to_string and string_to_ipv4 round trip", input, rt);
26✔
1131
         }
13✔
1132

1133
         return result;
47✔
1134
      }
47✔
1135
};
1136

1137
BOTAN_REGISTER_TEST("utils", "ipv4_parse", IPv4_Parsing_Tests);
1138

1139
class ReadKV_Tests final : public Text_Based_Test {
×
1140
   public:
1141
      ReadKV_Tests() : Text_Based_Test("utils/read_kv.vec", "Input,Expected") {}
2✔
1142

1143
      Test::Result run_one_test(const std::string& status, const VarMap& vars) override {
16✔
1144
         Test::Result result("read_kv");
16✔
1145

1146
         const bool is_valid = (status == "Valid");
16✔
1147

1148
         const std::string input = vars.get_req_str("Input");
16✔
1149
         const std::string expected = vars.get_req_str("Expected");
16✔
1150

1151
         if(is_valid) {
16✔
1152
            confirm_kv(result, Botan::read_kv(input), split_group(expected));
14✔
1153
         } else {
1154
            // In this case "expected" is the expected exception message
1155
            result.test_throws("Invalid key value input throws exception", expected, [&]() { Botan::read_kv(input); });
36✔
1156
         }
1157
         return result;
16✔
1158
      }
16✔
1159

1160
   private:
1161
      static std::vector<std::string> split_group(const std::string& str) {
7✔
1162
         std::vector<std::string> elems;
7✔
1163
         if(str.empty()) {
7✔
1164
            return elems;
1165
         }
1166

1167
         std::string substr;
6✔
1168
         for(auto i = str.begin(); i != str.end(); ++i) {
115✔
1169
            if(*i == '|') {
109✔
1170
               elems.push_back(substr);
16✔
1171
               substr.clear();
16✔
1172
            } else {
1173
               substr += *i;
202✔
1174
            }
1175
         }
1176

1177
         if(!substr.empty()) {
6✔
1178
            elems.push_back(substr);
6✔
1179
         }
1180

1181
         return elems;
6✔
1182
      }
6✔
1183

1184
      static void confirm_kv(Test::Result& result,
7✔
1185
                             const std::map<std::string, std::string>& kv,
1186
                             const std::vector<std::string>& expected) {
1187
         if(!result.test_eq("expected size", expected.size() % 2, size_t(0))) {
7✔
1188
            return;
1189
         }
1190

1191
         for(size_t i = 0; i != expected.size(); i += 2) {
18✔
1192
            auto j = kv.find(expected[i]);
11✔
1193
            if(result.confirm("Found key", j != kv.end())) {
22✔
1194
               result.test_eq("Matching value", j->second, expected[i + 1]);
22✔
1195
            }
1196
         }
1197

1198
         result.test_eq("KV has same size as expected", kv.size(), expected.size() / 2);
14✔
1199
      }
1200
};
1201

1202
BOTAN_REGISTER_TEST("utils", "util_read_kv", ReadKV_Tests);
1203

1204
class CPUID_Tests final : public Test {
×
1205
   public:
1206
      std::vector<Test::Result> run() override {
1✔
1207
         Test::Result result("CPUID");
1✔
1208

1209
         result.confirm("Endian is either little or big",
2✔
1210
                        Botan::CPUID::is_big_endian() || Botan::CPUID::is_little_endian());
1211

1212
         if(Botan::CPUID::is_little_endian()) {
1✔
1213
            result.test_eq("If endian is little, it is not also big endian", Botan::CPUID::is_big_endian(), false);
1✔
1214
         } else {
1215
            result.test_eq("If endian is big, it is not also little endian", Botan::CPUID::is_little_endian(), false);
1216
         }
1217

1218
         const std::string cpuid_string = Botan::CPUID::to_string();
1✔
1219
         result.test_success("CPUID::to_string doesn't crash");
1✔
1220

1221
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
1222

1223
         if(Botan::CPUID::has_sse2()) {
1✔
1224
            result.confirm("Output string includes sse2", cpuid_string.find("sse2") != std::string::npos);
2✔
1225

1226
            Botan::CPUID::clear_cpuid_bit(Botan::CPUID::CPUID_SSE2_BIT);
1✔
1227

1228
            result.test_eq("After clearing cpuid bit, has_sse2 returns false", Botan::CPUID::has_sse2(), false);
1✔
1229

1230
            Botan::CPUID::initialize();  // reset state
1✔
1231
            result.test_eq("After reinitializing, has_sse2 returns true", Botan::CPUID::has_sse2(), true);
2✔
1232
         }
1233
#endif
1234

1235
         return {result};
3✔
1236
      }
2✔
1237
};
1238

1239
BOTAN_REGISTER_SERIALIZED_TEST("utils", "cpuid", CPUID_Tests);
1240

1241
#if defined(BOTAN_HAS_UUID)
1242

1243
class UUID_Tests : public Test {
×
1244
   public:
1245
      std::vector<Test::Result> run() override {
1✔
1246
         Test::Result result("UUID");
1✔
1247

1248
         const Botan::UUID empty_uuid;
1✔
1249
         const Botan::UUID random_uuid1(this->rng());
1✔
1250
         const Botan::UUID random_uuid2(this->rng());
1✔
1251
         const Botan::UUID loaded_uuid(std::vector<uint8_t>(16, 4));
1✔
1252

1253
         result.test_throws("Cannot load wrong number of bytes", []() { Botan::UUID u(std::vector<uint8_t>(15)); });
3✔
1254

1255
         result.test_eq("Empty UUID is empty", empty_uuid.is_valid(), false);
1✔
1256
         result.confirm("Empty UUID equals another empty UUID", empty_uuid == Botan::UUID());
2✔
1257

1258
         result.test_throws("Empty UUID cannot become a string", [&]() { empty_uuid.to_string(); });
3✔
1259

1260
         result.test_eq("Random UUID not empty", random_uuid1.is_valid(), true);
1✔
1261
         result.test_eq("Random UUID not empty", random_uuid2.is_valid(), true);
1✔
1262

1263
         result.confirm("Random UUIDs are distinct", random_uuid1 != random_uuid2);
2✔
1264
         result.confirm("Random UUIDs not equal to empty", random_uuid1 != empty_uuid);
2✔
1265

1266
         const std::string uuid4_str = loaded_uuid.to_string();
1✔
1267
         result.test_eq("String matches expected", uuid4_str, "04040404-0404-0404-0404-040404040404");
2✔
1268

1269
         const std::string uuid_r1_str = random_uuid1.to_string();
1✔
1270
         result.confirm("UUID from string matches", Botan::UUID(uuid_r1_str) == random_uuid1);
2✔
1271

1272
         class AllSame_RNG : public Botan::RandomNumberGenerator {
×
1273
            public:
1274
               explicit AllSame_RNG(uint8_t b) : m_val(b) {}
2✔
1275

1276
               void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> /* ignored */) override {
2✔
1277
                  for(auto& byte : output) {
34✔
1278
                     byte = m_val;
32✔
1279
                  }
1280
               }
2✔
1281

1282
               std::string name() const override { return "zeros"; }
×
1283

1284
               bool accepts_input() const override { return false; }
×
1285

1286
               void clear() override {}
×
1287

1288
               bool is_seeded() const override { return true; }
×
1289

1290
            private:
1291
               uint8_t m_val;
1292
         };
1293

1294
         AllSame_RNG zeros(0x00);
1✔
1295
         const Botan::UUID zero_uuid(zeros);
1✔
1296
         result.test_eq("Zero UUID matches expected", zero_uuid.to_string(), "00000000-0000-4000-8000-000000000000");
2✔
1297

1298
         AllSame_RNG ones(0xFF);
1✔
1299
         const Botan::UUID ones_uuid(ones);
1✔
1300
         result.test_eq("Ones UUID matches expected", ones_uuid.to_string(), "FFFFFFFF-FFFF-4FFF-BFFF-FFFFFFFFFFFF");
2✔
1301

1302
         return {result};
3✔
1303
      }
6✔
1304
};
1305

1306
BOTAN_REGISTER_TEST("utils", "uuid", UUID_Tests);
1307

1308
#endif
1309

1310
class Formatter_Tests : public Test {
×
1311
   public:
1312
      std::vector<Test::Result> run() override {
1✔
1313
         Test::Result result("Format utility");
1✔
1314

1315
         /*
1316
         In a number of these tests, we are not strictly depending on the
1317
         behavior, for instance checking `fmt("{}") == "{}"` is more about
1318
         checking that we don't crash, rather than we return that precise string.
1319
         */
1320

1321
         result.test_eq("test 1", Botan::fmt("hi"), "hi");
2✔
1322
         result.test_eq("test 2", Botan::fmt("ignored", 5), "ignored");
2✔
1323
         result.test_eq("test 3", Botan::fmt("answer is {}", 42), "answer is 42");
2✔
1324
         result.test_eq("test 4", Botan::fmt("{", 5), "{");
2✔
1325
         result.test_eq("test 4", Botan::fmt("{}"), "{}");
2✔
1326
         result.test_eq("test 5", Botan::fmt("{} == '{}'", 5, "five"), "5 == 'five'");
2✔
1327

1328
         return {result};
3✔
1329
      }
2✔
1330
};
1331

1332
BOTAN_REGISTER_TEST("utils", "fmt", Formatter_Tests);
1333

1334
class ScopedCleanup_Tests : public Test {
×
1335
   public:
1336
      std::vector<Test::Result> run() override {
1✔
1337
         return {
1✔
1338
            CHECK("leaving a scope results in cleanup",
1339
                  [](Test::Result& result) {
1✔
1340
                     bool ran = false;
1✔
1341
                     {
1✔
1342
                        auto clean = Botan::scoped_cleanup([&] { ran = true; });
1✔
1343
                     }
1✔
1344
                     result.confirm("cleanup ran", ran);
2✔
1345
                  }),
1✔
1346

1347
            CHECK("leaving a function, results in cleanup",
1348
                  [](Test::Result& result) {
1✔
1349
                     bool ran = false;
1✔
1350
                     bool fn_called = false;
1✔
1351
                     auto fn = [&] {
2✔
1352
                        auto clean = Botan::scoped_cleanup([&] { ran = true; });
1✔
1353
                        fn_called = true;
1✔
1354
                     };
2✔
1355

1356
                     result.confirm("cleanup not yet ran", !ran);
2✔
1357
                     fn();
1✔
1358
                     result.confirm("fn called", fn_called);
2✔
1359
                     result.confirm("cleanup ran", ran);
2✔
1360
                  }),
1✔
1361

1362
            CHECK("stack unwinding results in cleanup",
1363
                  [](Test::Result& result) {
1✔
1364
                     bool ran = false;
1✔
1365
                     bool fn_called = false;
1✔
1366
                     bool exception_caught = false;
1✔
1367
                     auto fn = [&] {
2✔
1368
                        auto clean = Botan::scoped_cleanup([&] { ran = true; });
1✔
1369
                        fn_called = true;
1✔
1370
                        throw std::runtime_error("test");
1✔
1371
                     };
2✔
1372

1373
                     result.confirm("cleanup not yet ran", !ran);
2✔
1374
                     try {
1✔
1375
                        fn();
1✔
1376
                     } catch(const std::exception&) {
1✔
1377
                        exception_caught = true;
1✔
1378
                     }
1✔
1379

1380
                     result.confirm("fn called", fn_called);
2✔
1381
                     result.confirm("cleanup ran", ran);
2✔
1382
                     result.confirm("exception caught", exception_caught);
2✔
1383
                  }),
1✔
1384

1385
            CHECK("cleanup isn't called after disengaging",
1386
                  [](Test::Result& result) {
1✔
1387
                     bool ran = false;
1✔
1388
                     {
1✔
1389
                        auto clean = Botan::scoped_cleanup([&] { ran = true; });
1✔
1390
                        clean.disengage();
1✔
1391
                     }
1✔
1392
                     result.confirm("cleanup not ran", !ran);
2✔
1393
                  }),
1✔
1394

1395
         };
5✔
1396
      }
1✔
1397
};
1398

1399
BOTAN_REGISTER_TEST("utils", "scoped_cleanup", ScopedCleanup_Tests);
1400

1401
}  // namespace
1402

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

© 2025 Coveralls, Inc