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

randombit / botan / 6253464532

19 Sep 2023 12:06AM UTC coverage: 91.748% (+0.02%) from 91.726%
6253464532

push

github

web-flow
Merge pull request #3693 from Rohde-Schwarz/refactor/alignment_buffer

Refactor: AlignmentBuffer<> helper for block-oriented Hashes

79472 of 86620 relevant lines covered (91.75%)

8492168.28 hits per line

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

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

8
#include "tests.h"
9

10
#include <botan/internal/alignment_buffer.h>
11
#include <botan/internal/stl_util.h>
12

13
#include <array>
14

15
namespace Botan_Tests {
16

17
namespace {
18

19
template <typename T>
20
std::vector<uint8_t> v(const T& container) {
1✔
21
   return {container.begin(), container.end()};
23✔
22
}
23

24
using StrongBuffer = Botan::Strong<std::vector<uint8_t>, struct StrongBuffer_>;
25

26
std::vector<Test::Result> test_buffer_slicer() {
1✔
27
   return {
1✔
28
      CHECK("Empty BufferSlicer",
29
            [](auto& result) {
1✔
30
               const std::vector<uint8_t> buffer(0);
1✔
31
               Botan::BufferSlicer s(buffer);
1✔
32
               result.confirm("empty slicer has no remaining bytes", s.remaining() == 0);
3✔
33
               result.confirm("empty slicer is empty()", s.empty());
2✔
34
               result.confirm("empty slicer can take() 0 bytes", s.take(0).empty());
2✔
35

36
               result.test_throws("empty slicer cannot emit bytes", [&]() { s.take(1); });
3✔
37
               result.test_throws("empty slicer cannot skip bytes", [&]() { s.skip(1); });
3✔
38
               result.test_throws("empty slicer cannot copy bytes", [&]() { s.copy_as_vector(1); });
4✔
39
            }),
1✔
40

41
      CHECK("Read from BufferSlicer",
42
            [](auto& result) {
1✔
43
               const std::vector<uint8_t> buffer{'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
1✔
44
               Botan::BufferSlicer s(buffer);
1✔
45

46
               result.test_eq("non-empty slicer has remaining bytes", s.remaining(), buffer.size());
2✔
47
               result.confirm("non-empty slicer is not empty()", !s.empty());
2✔
48

49
               const auto hello = s.take(5);
1✔
50
               result.require("has 5 bytes", hello.size() == 5);
1✔
51
               result.test_is_eq("took hello", hello[0], uint8_t('h'));
1✔
52
               result.test_is_eq("took hello", hello[1], uint8_t('e'));
1✔
53
               result.test_is_eq("took hello", hello[2], uint8_t('l'));
1✔
54
               result.test_is_eq("took hello", hello[3], uint8_t('l'));
1✔
55
               result.test_is_eq("took hello", hello[4], uint8_t('o'));
2✔
56

57
               result.test_eq("remaining bytes", s.remaining(), 6);
2✔
58

59
               s.skip(1);
1✔
60
               result.test_eq("remaining bytes", s.remaining(), 5);
2✔
61

62
               const auto wor = s.copy_as_vector(3);
1✔
63
               result.require("has 3 bytes", wor.size() == 3);
1✔
64
               result.test_is_eq("took wor...", wor[0], uint8_t('w'));
1✔
65
               result.test_is_eq("took wor...", wor[1], uint8_t('o'));
1✔
66
               result.test_is_eq("took wor...", wor[2], uint8_t('r'));
2✔
67
               result.test_eq("remaining bytes", s.remaining(), 2);
2✔
68

69
               std::vector<uint8_t> ld(2);
1✔
70
               s.copy_into(ld);
1✔
71
               result.test_is_eq("took ...ld", ld[0], uint8_t('l'));
1✔
72
               result.test_is_eq("took ...ld", ld[1], uint8_t('d'));
2✔
73

74
               result.confirm("empty", s.empty());
2✔
75
               result.test_eq("nothing remaining", s.remaining(), 0);
1✔
76

77
               result.test_throws("empty slicer cannot emit bytes", [&]() { s.take(1); });
3✔
78
               result.test_throws("empty slicer cannot skip bytes", [&]() { s.skip(1); });
3✔
79
               result.test_throws("empty slicer cannot copy bytes", [&]() { s.copy_as_vector(1); });
4✔
80
            }),
3✔
81

82
      CHECK("Strong type support",
83
            [](auto& result) {
1✔
84
               const Botan::secure_vector<uint8_t> secure_buffer{'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
1✔
85
               Botan::BufferSlicer s(secure_buffer);
1✔
86

87
               auto span1 = s.take(1);
1✔
88
               auto span2 = s.take<StrongBuffer>(2);
1✔
89
               auto vec1 = s.copy<StrongBuffer>(2);
1✔
90
               auto vec2 = s.copy_as_vector(2);
1✔
91
               auto vec3 = s.copy_as_secure_vector(2);
1✔
92
               StrongBuffer vec4(s.remaining());
1✔
93
               s.copy_into(vec4);
1✔
94

95
               const auto reproduce = Botan::concat_as<std::vector<uint8_t>>(span1, span2, vec1, vec2, vec3, vec4);
1✔
96
               result.test_eq("sliced into various types", reproduce, secure_buffer);
2✔
97
            }),
6✔
98
   };
4✔
99
}
100

101
std::vector<Test::Result> test_buffer_stuffer() {
1✔
102
   return {
1✔
103
      CHECK("Empty BufferStuffer",
104
            [](auto& result) {
1✔
105
               std::vector<uint8_t> empty_buffer;
1✔
106
               Botan::BufferStuffer s(empty_buffer);
1✔
107

108
               result.test_eq("has no capacity", s.remaining_capacity(), 0);
2✔
109
               result.confirm("is immediately full", s.full());
2✔
110
               result.confirm("can next() 0 bytes", s.next(0).empty());
2✔
111

112
               result.test_throws("cannot next() anything", [&]() { s.next(1); });
3✔
113
               result.test_throws("cannot append bytes", [&]() {
4✔
114
                  std::vector<uint8_t> some_bytes(42);
1✔
115
                  s.append(some_bytes);
1✔
116
               });
×
117
            }),
1✔
118

119
      CHECK("Fill BufferStuffer",
120
            [](auto& result) {
1✔
121
               std::vector<uint8_t> sink(11);
1✔
122
               Botan::BufferStuffer s(sink);
1✔
123

124
               result.test_eq("has some capacity", s.remaining_capacity(), sink.size());
2✔
125
               result.confirm("is not full", !s.full());
2✔
126

127
               auto n1 = s.next(5);
1✔
128
               result.require("got requested bytes", n1.size() == 5);
2✔
129
               n1[0] = 'h';
1✔
130
               n1[1] = 'e';
1✔
131
               n1[2] = 'l';
1✔
132
               n1[3] = 'l';
1✔
133
               n1[4] = 'o';
1✔
134

135
               auto n2 = s.next<StrongBuffer>(3);
1✔
136
               result.require("got requested bytes", n2.size() == 3);
1✔
137

138
               n2.get()[0] = ' ';
1✔
139
               n2.get()[1] = 'w';
1✔
140
               n2.get()[2] = 'o';
1✔
141

142
               result.test_eq("has 3 bytes remaining", s.remaining_capacity(), 3);
1✔
143

144
               std::vector<uint8_t> rld{'r', 'l', 'd'};
1✔
145
               s.append(rld);
1✔
146

147
               result.test_eq("has 0 bytes remaining", s.remaining_capacity(), 0);
2✔
148
               result.confirm("is full", s.full());
2✔
149

150
               result.test_throws("cannot next() anything", [&]() { s.next(1); });
3✔
151
               result.test_throws("cannot append bytes", [&]() {
4✔
152
                  std::vector<uint8_t> some_bytes(42);
1✔
153
                  s.append(some_bytes);
1✔
154
               });
×
155
            }),
2✔
156
   };
3✔
157
}
158

159
std::vector<Test::Result> test_alignment_buffer() {
1✔
160
   std::array<uint8_t, 32> data = {1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,
1✔
161
                                   17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
162
   std::array<uint8_t, 16> first_half_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
1✔
163
   std::array<uint8_t, 16> second_half_data = {17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
1✔
164

165
   return {
1✔
166
      CHECK("Fresh Alignment Buffer",
167
            [](auto& result) {
1✔
168
               Botan::AlignmentBuffer<uint8_t, 32> b;
1✔
169
               result.test_eq("size()", b.size(), 32);
2✔
170
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 0);
2✔
171
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 32);
2✔
172
               result.confirm("in_alignment()", b.in_alignment());
2✔
173
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
3✔
174
            }),
1✔
175

176
      CHECK("Fill Alignment Buffer",
177
            [=](auto& result) {
1✔
178
               Botan::AlignmentBuffer<uint8_t, 32> b;
1✔
179

180
               b.append(first_half_data);
1✔
181

182
               result.test_eq("size()", b.size(), 32);
2✔
183
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 16);
2✔
184
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 16);
2✔
185
               result.confirm("!in_alignment()", !b.in_alignment());
2✔
186
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
2✔
187

188
               b.append(second_half_data);
1✔
189

190
               result.test_eq("size()", b.size(), 32);
2✔
191
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 32);
2✔
192
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 0);
2✔
193
               result.confirm("!in_alignment()", !b.in_alignment());
2✔
194
               result.confirm("ready_to_consume()", b.ready_to_consume());
3✔
195
            }),
1✔
196

197
      CHECK("Consume Alignment Buffer",
198
            [=](auto& result) {
1✔
199
               Botan::AlignmentBuffer<uint8_t, 32> b;
1✔
200

201
               b.append(data);
1✔
202

203
               result.require("ready_to_consume()", b.ready_to_consume());
1✔
204
               const auto out = b.consume();
1✔
205

206
               result.test_eq("size()", b.size(), 32);
3✔
207
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 0);
2✔
208
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 32);
2✔
209
               result.confirm("in_alignment()", b.in_alignment());
2✔
210
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
3✔
211

212
               result.test_is_eq("in == out", v(data), v(out));
4✔
213
            }),
1✔
214

215
      CHECK("Clear Alignment Buffer",
216
            [=](auto& result) {
1✔
217
               Botan::AlignmentBuffer<uint8_t, 32> b;
1✔
218

219
               b.append(first_half_data);
1✔
220

221
               result.require("elements_in_buffer()", b.elements_in_buffer() == 16);
2✔
222
               b.clear();
1✔
223

224
               result.test_eq("size()", b.size(), 32);
2✔
225
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 0);
2✔
226
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 32);
2✔
227
               result.confirm("in_alignment()", b.in_alignment());
2✔
228
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
3✔
229
            }),
1✔
230

231
      CHECK("Add Zero-Padding to Alignment Buffer",
232
            [=](auto& result) {
1✔
233
               Botan::AlignmentBuffer<uint8_t, 32> b;
1✔
234

235
               b.append(first_half_data);
1✔
236

237
               result.require("elements_in_buffer()", b.elements_in_buffer() == 16);
2✔
238
               b.fill_up_with_zeros();
1✔
239

240
               result.test_eq("size()", b.size(), 32);
2✔
241
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 32);
2✔
242
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 0);
2✔
243
               result.confirm("!in_alignment()", !b.in_alignment());
2✔
244
               result.confirm("ready_to_consume()", b.ready_to_consume());
2✔
245

246
               const auto out = b.consume();
1✔
247

248
               result.test_is_eq("prefix", v(out.first(16)), v(first_half_data));
4✔
249
               result.test_is_eq("zero-padding", v(out.last(16)), std::vector<uint8_t>(16, 0));
4✔
250
            }),
1✔
251

252
      CHECK("Handle unaligned data in Alignment Buffer (no block-defer)",
253
            [=](auto& result) {
1✔
254
               Botan::AlignmentBuffer<uint8_t, 32> b;
1✔
255

256
               Botan::BufferSlicer first_half(first_half_data);
1✔
257
               Botan::BufferSlicer second_half(second_half_data);
1✔
258

259
               const auto r1 = b.handle_unaligned_data(first_half);
1✔
260
               result.confirm("half a block is not returned", !r1.has_value());
3✔
261
               result.confirm("first input is consumed", first_half.empty());
3✔
262

263
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 16);
2✔
264
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 16);
2✔
265
               result.confirm("!in_alignment()", !b.in_alignment());
2✔
266
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
2✔
267

268
               const auto r2 = b.handle_unaligned_data(second_half);
1✔
269
               result.require("second half completes block", r2.has_value());
2✔
270
               result.confirm("second input is consumed", second_half.empty());
3✔
271

272
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 0);
2✔
273
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 32);
2✔
274
               result.confirm("in_alignment()", b.in_alignment());
2✔
275
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
2✔
276

277
               result.test_is_eq("collected block is correct", v(r2.value()), v(data));
4✔
278
            }),
1✔
279

280
      CHECK("Aligned data is not buffered unneccesarily (no block-defer)",
281
            [=](auto& result) {
1✔
282
               Botan::AlignmentBuffer<uint8_t, 32> b;
1✔
283

284
               Botan::BufferSlicer full_block_1(data);
1✔
285
               const auto r1 = b.handle_unaligned_data(full_block_1);
1✔
286
               result.confirm("aligned data is not buffered", !r1.has_value());
3✔
287
               result.confirm("in_alignment()", b.in_alignment());
2✔
288
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
3✔
289
               result.test_eq("aligned data is not consumed", full_block_1.remaining(), 32);
1✔
290

291
               Botan::BufferSlicer half_block(first_half_data);
1✔
292
               Botan::BufferSlicer full_block_2(data);
1✔
293
               const auto r2 = b.handle_unaligned_data(half_block);
1✔
294
               result.confirm("unaligned data is buffered", !r2.has_value());
3✔
295
               result.confirm("!in_alignment()", !b.in_alignment());
2✔
296
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
3✔
297
               result.confirm("unaligned data is consumed", half_block.empty());
2✔
298

299
               const auto r3 = b.handle_unaligned_data(full_block_2);
1✔
300
               result.confirm("collected block is consumed", r3.has_value());
3✔
301
               result.confirm("in_alignment()", b.in_alignment());
2✔
302
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
3✔
303
               result.test_eq("input is consumed until alignment", full_block_2.remaining(), 16);
2✔
304
            }),
1✔
305

306
      CHECK("Handle unaligned data in Alignment Buffer (with block-defer)",
307
            [=](auto& result) {
1✔
308
               Botan::AlignmentBuffer<uint8_t, 32, Botan::AlignmentBufferFinalBlock::must_be_deferred> b;
1✔
309

310
               Botan::BufferSlicer first_half(first_half_data);
1✔
311
               Botan::BufferSlicer second_half(second_half_data);
1✔
312
               Botan::BufferSlicer third_half(first_half_data);
1✔
313

314
               const auto r1 = b.handle_unaligned_data(first_half);
1✔
315
               result.confirm("half a block is not returned", !r1.has_value());
3✔
316
               result.confirm("first input is consumed", first_half.empty());
3✔
317

318
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 16);
2✔
319
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 16);
2✔
320
               result.confirm("!in_alignment()", !b.in_alignment());
2✔
321
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
2✔
322

323
               const auto r2 = b.handle_unaligned_data(second_half);
1✔
324
               result.require("second half completes block but is not returned", !r2.has_value());
2✔
325
               result.confirm("second input is consumed", second_half.empty());
3✔
326

327
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 32);
2✔
328
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 0);
2✔
329
               result.confirm("!in_alignment()", !b.in_alignment());
2✔
330
               result.confirm("ready_to_consume()", b.ready_to_consume());
2✔
331

332
               const auto r3 = b.handle_unaligned_data(third_half);
1✔
333
               result.require("extra data pushes out block", r3.has_value());
2✔
334
               result.test_eq("third input is not consumed", third_half.remaining(), 16);
2✔
335

336
               result.test_eq("elements_in_buffer()", b.elements_in_buffer(), 0);
2✔
337
               result.test_eq("elements_until_alignment()", b.elements_until_alignment(), 32);
2✔
338
               result.confirm("in_alignment()", b.in_alignment());
2✔
339
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
2✔
340

341
               result.test_is_eq("collected block is correct", v(r3.value()), v(data));
4✔
342
            }),
1✔
343

344
      CHECK("Aligned data is not buffered unneccesarily (with block-defer)",
345
            [=](auto& result) {
1✔
346
               Botan::AlignmentBuffer<uint8_t, 32, Botan::AlignmentBufferFinalBlock::must_be_deferred> b;
1✔
347

348
               Botan::BufferSlicer full_block_1(data);
1✔
349
               const auto r1 = b.handle_unaligned_data(full_block_1);
1✔
350
               result.confirm("exactly aligned data is buffered", !r1.has_value());
3✔
351
               result.confirm("!in_alignment()", !b.in_alignment());
2✔
352
               result.confirm("ready_to_consume()", b.ready_to_consume());
3✔
353
               result.confirm("exactly aligned block is consumed", full_block_1.empty());
3✔
354

355
               Botan::BufferSlicer empty_input({});
1✔
356
               const auto r2 = b.handle_unaligned_data(empty_input);
1✔
357
               result.require("empty input does not push out buffer", !r2.has_value());
2✔
358
               result.confirm("!in_alignment()", !b.in_alignment());
2✔
359
               result.confirm("ready_to_consume()", b.ready_to_consume());
2✔
360

361
               const uint8_t extra_byte = 1;
1✔
362
               Botan::BufferSlicer one_extra_byte({&extra_byte, 1});
1✔
363
               const auto r3 = b.handle_unaligned_data(one_extra_byte);
1✔
364
               result.require("more data pushes out buffer", r3.has_value());
2✔
365
               result.confirm("in_alignment()", b.in_alignment());
2✔
366
               result.confirm("!ready_to_consume()", !b.ready_to_consume());
3✔
367
               result.test_eq("no input data is consumed", one_extra_byte.remaining(), 1);
1✔
368

369
               result.test_is_eq("collected block is correct", v(r3.value()), v(data));
4✔
370
            }),
1✔
371

372
      CHECK("Aligned data passthrough (no block-defer)",
373
            [=](auto& result) {
1✔
374
               Botan::AlignmentBuffer<uint8_t, 32> b;
1✔
375
               result.require("buffer is in alignment", b.in_alignment());
1✔
376

377
               Botan::BufferSlicer half_block(first_half_data);
1✔
378
               const auto [s1, r1] = b.aligned_data_to_process(half_block);
1✔
379
               result.confirm("not enough data for alignment processing", s1.empty());
2✔
380
               result.test_eq("not enough data for alignment processing", r1, 0);
2✔
381
               result.test_eq("(short) unaligned data is not consumed", half_block.remaining(), 16);
1✔
382

383
               const auto more_than_one_block = Botan::concat_as<std::vector<uint8_t>>(data, first_half_data);
1✔
384
               Botan::BufferSlicer one_and_a_half_block(more_than_one_block);
1✔
385
               const auto [s2, r2] = b.aligned_data_to_process(one_and_a_half_block);
1✔
386
               result.test_eq("data of one block for processing", s2.size(), 32);
1✔
387
               result.test_eq("one block for processing", r2, 1);
1✔
388
               result.test_is_eq(v(s2), v(data));
3✔
389
               result.test_eq("(middle) unaligned data is not consumed", one_and_a_half_block.remaining(), 16);
1✔
390

391
               const auto two_blocks_data = Botan::concat_as<std::vector<uint8_t>>(data, data);
1✔
392
               Botan::BufferSlicer two_blocks(two_blocks_data);
1✔
393
               const auto [s3, r3] = b.aligned_data_to_process(two_blocks);
1✔
394
               result.test_eq("data of two block for processing", s3.size(), 64);
1✔
395
               result.test_eq("two blocks for processing", r3, 2);
2✔
396
               result.test_is_eq(v(s3), two_blocks_data);
2✔
397
               result.test_eq("aligned data is fully consumed", two_blocks.remaining(), 0);
2✔
398
            }),
2✔
399

400
      CHECK("Aligned data blockwise (no block-defer)",
401
            [=](auto& result) {
1✔
402
               Botan::AlignmentBuffer<uint8_t, 32> b;
1✔
403
               result.require("buffer is in alignment", b.in_alignment());
1✔
404

405
               Botan::BufferSlicer half_block(first_half_data);
1✔
406
               const auto s1 = b.next_aligned_block_to_process(half_block);
1✔
407
               result.confirm("not enough data for alignment processing", !s1.has_value());
3✔
408
               result.test_eq("(short) unaligned data is not consumed", half_block.remaining(), 16);
1✔
409

410
               const auto more_than_one_block = Botan::concat_as<std::vector<uint8_t>>(data, first_half_data);
1✔
411
               Botan::BufferSlicer one_and_a_half_block(more_than_one_block);
1✔
412
               const auto s2 = b.next_aligned_block_to_process(one_and_a_half_block);
1✔
413
               result.require("one block for processing", s2.has_value());
2✔
414
               result.test_eq("data of one block for processing", s2->size(), 32);
1✔
415
               result.test_is_eq(v(s2.value()), v(data));
3✔
416
               result.test_eq("(middle) unaligned data is not consumed", one_and_a_half_block.remaining(), 16);
1✔
417

418
               const auto two_blocks_data = Botan::concat_as<std::vector<uint8_t>>(data, data);
1✔
419
               Botan::BufferSlicer two_blocks(two_blocks_data);
1✔
420
               const auto s3_1 = b.next_aligned_block_to_process(two_blocks);
1✔
421
               result.require("first block for processing", s3_1.has_value());
2✔
422
               result.test_eq("data of first block for processing", s3_1->size(), 32);
1✔
423
               result.test_is_eq(v(s3_1.value()), v(data));
3✔
424
               result.test_eq("first block is consumed", two_blocks.remaining(), 32);
1✔
425

426
               const auto s3_2 = b.next_aligned_block_to_process(two_blocks);
1✔
427
               result.require("second block for processing", s3_2.has_value());
2✔
428
               result.test_eq("data of second block for processing", s3_2->size(), 32);
1✔
429
               result.test_is_eq(v(s3_2.value()), v(data));
3✔
430
               result.test_eq("second block is consumed", two_blocks.remaining(), 0);
2✔
431
            }),
2✔
432

433
      CHECK("Aligned data passthrough (with block-defer)",
434
            [=](auto& result) {
1✔
435
               Botan::AlignmentBuffer<uint8_t, 32, Botan::AlignmentBufferFinalBlock::must_be_deferred> b;
1✔
436
               result.require("buffer is in alignment", b.in_alignment());
1✔
437

438
               Botan::BufferSlicer half_block(first_half_data);
1✔
439
               const auto [s1, r1] = b.aligned_data_to_process(half_block);
1✔
440
               result.confirm("not enough data for alignment processing", s1.empty());
2✔
441
               result.test_eq("not enough data for alignment processing", r1, 0);
2✔
442
               result.test_eq("(short) unaligned data is not consumed", half_block.remaining(), 16);
1✔
443

444
               const auto more_than_one_block = Botan::concat_as<std::vector<uint8_t>>(data, first_half_data);
1✔
445
               Botan::BufferSlicer one_and_a_half_block(more_than_one_block);
1✔
446
               const auto [s2, r2] = b.aligned_data_to_process(one_and_a_half_block);
1✔
447
               result.test_eq("data of one block for processing", s2.size(), 32);
1✔
448
               result.test_eq("one block for processing", r2, 1);
1✔
449
               result.test_is_eq(v(s2), v(data));
3✔
450
               result.test_eq("(middle) unaligned data is not consumed", one_and_a_half_block.remaining(), 16);
1✔
451

452
               const auto two_blocks_data = Botan::concat_as<std::vector<uint8_t>>(data, data);
1✔
453
               Botan::BufferSlicer two_blocks(two_blocks_data);
1✔
454
               const auto [s3, r3] = b.aligned_data_to_process(two_blocks);
1✔
455
               result.test_eq("data of first block for processing", s3.size(), 32);
1✔
456
               result.test_eq("one block for processing", r3, 1);
1✔
457
               result.test_is_eq(v(s3), v(data));
3✔
458
               result.test_eq("aligned data is partially consumed", two_blocks.remaining(), 32);
2✔
459
            }),
2✔
460

461
      CHECK("Aligned data blockwise (with block-defer)",
462
            [=](auto& result) {
1✔
463
               Botan::AlignmentBuffer<uint8_t, 32, Botan::AlignmentBufferFinalBlock::must_be_deferred> b;
1✔
464
               result.require("buffer is in alignment", b.in_alignment());
1✔
465

466
               Botan::BufferSlicer half_block(first_half_data);
1✔
467
               const auto s1 = b.next_aligned_block_to_process(half_block);
1✔
468
               result.confirm("not enough data for alignment processing", !s1.has_value());
3✔
469
               result.test_eq("(short) unaligned data is not consumed", half_block.remaining(), 16);
1✔
470

471
               const auto more_than_one_block = Botan::concat_as<std::vector<uint8_t>>(data, first_half_data);
1✔
472
               Botan::BufferSlicer one_and_a_half_block(more_than_one_block);
1✔
473
               const auto s2 = b.next_aligned_block_to_process(one_and_a_half_block);
1✔
474
               result.require("one block for processing", s2.has_value());
2✔
475
               result.test_eq("data of one block for processing", s2->size(), 32);
1✔
476
               result.test_is_eq(v(s2.value()), v(data));
3✔
477
               result.test_eq("(middle) unaligned data is not consumed", one_and_a_half_block.remaining(), 16);
1✔
478

479
               const auto two_blocks_data = Botan::concat_as<std::vector<uint8_t>>(data, data);
1✔
480
               Botan::BufferSlicer two_blocks(two_blocks_data);
1✔
481
               const auto s3_1 = b.next_aligned_block_to_process(two_blocks);
1✔
482
               result.require("first block for processing", s3_1.has_value());
2✔
483
               result.test_eq("data of first block for processing", s3_1->size(), 32);
1✔
484
               result.test_is_eq(v(s3_1.value()), v(data));
3✔
485
               result.test_eq("first block is consumed", two_blocks.remaining(), 32);
1✔
486

487
               const auto s3_2 = b.next_aligned_block_to_process(two_blocks);
1✔
488
               result.confirm("second block is not passed through", !s3_2.has_value());
3✔
489
               result.test_eq("second block is not consumed", two_blocks.remaining(), 32);
2✔
490
            }),
2✔
491
   };
14✔
492
}
493

494
BOTAN_REGISTER_TEST_FN("utils", "buffer_utilities", test_buffer_slicer, test_buffer_stuffer, test_alignment_buffer);
495

496
}  // namespace
497

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