Line data Source code
1 : // Copyright (c) 2012-2021 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include <fs.h>
6 : #include <streams.h>
7 : #include <test/util/random.h>
8 : #include <test/util/setup_common.h>
9 :
10 : #include <boost/test/unit_test.hpp>
11 :
12 : using namespace std::string_literals;
13 :
14 146 : BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
15 :
16 149 : BOOST_AUTO_TEST_CASE(streams_vector_writer)
17 : {
18 1 : unsigned char a(1);
19 1 : unsigned char b(2);
20 1 : unsigned char bytes[] = { 3, 4, 5, 6 };
21 1 : std::vector<unsigned char> vch;
22 :
23 : // Each test runs twice. Serializing a second time at the same starting
24 : // point should yield the same results, even if the first test grew the
25 : // vector.
26 :
27 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
28 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
29 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
30 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
31 1 : vch.clear();
32 :
33 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
34 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
35 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
36 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
37 1 : vch.clear();
38 :
39 1 : vch.resize(5, 0);
40 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
41 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
42 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
43 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
44 1 : vch.clear();
45 :
46 1 : vch.resize(4, 0);
47 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
48 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
49 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
50 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
51 1 : vch.clear();
52 :
53 1 : vch.resize(4, 0);
54 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
55 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
56 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
57 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
58 1 : vch.clear();
59 :
60 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, bytes);
61 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
62 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, bytes);
63 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
64 1 : vch.clear();
65 :
66 1 : vch.resize(4, 8);
67 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, bytes, b);
68 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
69 1 : CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, bytes, b);
70 1 : BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
71 1 : vch.clear();
72 1 : }
73 :
74 149 : BOOST_AUTO_TEST_CASE(streams_vector_reader)
75 : {
76 1 : std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
77 :
78 1 : SpanReader reader{SER_NETWORK, INIT_PROTO_VERSION, vch};
79 1 : BOOST_CHECK_EQUAL(reader.size(), 6U);
80 1 : BOOST_CHECK(!reader.empty());
81 :
82 : // Read a single byte as an unsigned char.
83 : unsigned char a;
84 1 : reader >> a;
85 1 : BOOST_CHECK_EQUAL(a, 1);
86 1 : BOOST_CHECK_EQUAL(reader.size(), 5U);
87 1 : BOOST_CHECK(!reader.empty());
88 :
89 : // Read a single byte as a int8_t.
90 : int8_t b;
91 1 : reader >> b;
92 1 : BOOST_CHECK_EQUAL(b, -1);
93 1 : BOOST_CHECK_EQUAL(reader.size(), 4U);
94 1 : BOOST_CHECK(!reader.empty());
95 :
96 : // Read a 4 bytes as an unsigned int.
97 : unsigned int c;
98 1 : reader >> c;
99 1 : BOOST_CHECK_EQUAL(c, 100992003U); // 3,4,5,6 in little-endian base-256
100 1 : BOOST_CHECK_EQUAL(reader.size(), 0U);
101 1 : BOOST_CHECK(reader.empty());
102 :
103 : // Reading after end of byte vector throws an error.
104 : signed int d;
105 2 : BOOST_CHECK_THROW(reader >> d, std::ios_base::failure);
106 :
107 : // Read a 4 bytes as a signed int from the beginning of the buffer.
108 1 : SpanReader new_reader{SER_NETWORK, INIT_PROTO_VERSION, vch};
109 1 : new_reader >> d;
110 1 : BOOST_CHECK_EQUAL(d, 67370753); // 1,255,3,4 in little-endian base-256
111 1 : BOOST_CHECK_EQUAL(new_reader.size(), 2U);
112 1 : BOOST_CHECK(!new_reader.empty());
113 :
114 : // Reading after end of byte vector throws an error even if the reader is
115 : // not totally empty.
116 2 : BOOST_CHECK_THROW(new_reader >> d, std::ios_base::failure);
117 3 : }
118 :
119 149 : BOOST_AUTO_TEST_CASE(streams_vector_reader_rvalue)
120 : {
121 1 : std::vector<uint8_t> data{0x82, 0xa7, 0x31};
122 1 : SpanReader reader{SER_NETWORK, INIT_PROTO_VERSION, data};
123 1 : uint32_t varint = 0;
124 : // Deserialize into r-value
125 1 : reader >> VARINT(varint);
126 1 : BOOST_CHECK_EQUAL(varint, 54321U);
127 1 : BOOST_CHECK(reader.empty());
128 1 : }
129 :
130 149 : BOOST_AUTO_TEST_CASE(bitstream_reader_writer)
131 : {
132 1 : CDataStream data(SER_NETWORK, INIT_PROTO_VERSION);
133 :
134 1 : BitStreamWriter<CDataStream> bit_writer(data);
135 1 : bit_writer.Write(0, 1);
136 1 : bit_writer.Write(2, 2);
137 1 : bit_writer.Write(6, 3);
138 1 : bit_writer.Write(11, 4);
139 1 : bit_writer.Write(1, 5);
140 1 : bit_writer.Write(32, 6);
141 1 : bit_writer.Write(7, 7);
142 1 : bit_writer.Write(30497, 16);
143 1 : bit_writer.Flush();
144 :
145 1 : CDataStream data_copy(data);
146 : uint32_t serialized_int1;
147 1 : data >> serialized_int1;
148 1 : BOOST_CHECK_EQUAL(serialized_int1, uint32_t{0x7700C35A}); // NOTE: Serialized as LE
149 : uint16_t serialized_int2;
150 1 : data >> serialized_int2;
151 1 : BOOST_CHECK_EQUAL(serialized_int2, uint16_t{0x1072}); // NOTE: Serialized as LE
152 :
153 1 : BitStreamReader<CDataStream> bit_reader(data_copy);
154 1 : BOOST_CHECK_EQUAL(bit_reader.Read(1), 0U);
155 1 : BOOST_CHECK_EQUAL(bit_reader.Read(2), 2U);
156 1 : BOOST_CHECK_EQUAL(bit_reader.Read(3), 6U);
157 1 : BOOST_CHECK_EQUAL(bit_reader.Read(4), 11U);
158 1 : BOOST_CHECK_EQUAL(bit_reader.Read(5), 1U);
159 1 : BOOST_CHECK_EQUAL(bit_reader.Read(6), 32U);
160 1 : BOOST_CHECK_EQUAL(bit_reader.Read(7), 7U);
161 1 : BOOST_CHECK_EQUAL(bit_reader.Read(16), 30497U);
162 2 : BOOST_CHECK_THROW(bit_reader.Read(8), std::ios_base::failure);
163 2 : }
164 :
165 149 : BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
166 : {
167 1 : std::vector<std::byte> in;
168 :
169 : // Degenerate case
170 : {
171 1 : CDataStream ds{in, 0, 0};
172 1 : ds.Xor({0x00, 0x00});
173 1 : BOOST_CHECK_EQUAL(""s, ds.str());
174 1 : }
175 :
176 1 : in.push_back(std::byte{0x0f});
177 1 : in.push_back(std::byte{0xf0});
178 :
179 : // Single character key
180 : {
181 1 : CDataStream ds{in, 0, 0};
182 1 : ds.Xor({0xff});
183 1 : BOOST_CHECK_EQUAL("\xf0\x0f"s, ds.str());
184 1 : }
185 :
186 : // Multi character key
187 :
188 1 : in.clear();
189 1 : in.push_back(std::byte{0xf0});
190 1 : in.push_back(std::byte{0x0f});
191 :
192 : {
193 1 : CDataStream ds{in, 0, 0};
194 1 : ds.Xor({0xff, 0x0f});
195 1 : BOOST_CHECK_EQUAL("\x0f\x00"s, ds.str());
196 1 : }
197 1 : }
198 :
199 149 : BOOST_AUTO_TEST_CASE(streams_buffered_file)
200 : {
201 1 : fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp";
202 1 : FILE* file = fsbridge::fopen(streams_test_filename, "w+b");
203 :
204 : // The value at each offset is the offset.
205 41 : for (uint8_t j = 0; j < 40; ++j) {
206 40 : fwrite(&j, 1, 1, file);
207 40 : }
208 1 : rewind(file);
209 :
210 : // The buffer size (second arg) must be greater than the rewind
211 : // amount (third arg).
212 : try {
213 1 : CBufferedFile bfbad(file, 25, 25, 222, 333);
214 0 : BOOST_CHECK(false);
215 1 : } catch (const std::exception& e) {
216 1 : BOOST_CHECK(strstr(e.what(),
217 : "Rewind limit must be less than buffer size") != nullptr);
218 1 : }
219 :
220 : // The buffer is 25 bytes, allow rewinding 10 bytes.
221 1 : CBufferedFile bf(file, 25, 10, 222, 333);
222 1 : BOOST_CHECK(!bf.eof());
223 :
224 : // These two members have no functional effect.
225 1 : BOOST_CHECK_EQUAL(bf.GetType(), 222);
226 1 : BOOST_CHECK_EQUAL(bf.GetVersion(), 333);
227 :
228 : uint8_t i;
229 1 : bf >> i;
230 1 : BOOST_CHECK_EQUAL(i, 0);
231 1 : bf >> i;
232 1 : BOOST_CHECK_EQUAL(i, 1);
233 :
234 : // After reading bytes 0 and 1, we're positioned at 2.
235 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 2U);
236 :
237 : // Rewind to offset 0, ok (within the 10 byte window).
238 1 : BOOST_CHECK(bf.SetPos(0));
239 1 : bf >> i;
240 1 : BOOST_CHECK_EQUAL(i, 0);
241 :
242 : // We can go forward to where we've been, but beyond may fail.
243 1 : BOOST_CHECK(bf.SetPos(2));
244 1 : bf >> i;
245 1 : BOOST_CHECK_EQUAL(i, 2);
246 :
247 : // If you know the maximum number of bytes that should be
248 : // read to deserialize the variable, you can limit the read
249 : // extent. The current file offset is 3, so the following
250 : // SetLimit() allows zero bytes to be read.
251 1 : BOOST_CHECK(bf.SetLimit(3));
252 : try {
253 1 : bf >> i;
254 0 : BOOST_CHECK(false);
255 1 : } catch (const std::exception& e) {
256 1 : BOOST_CHECK(strstr(e.what(),
257 : "Attempt to position past buffer limit") != nullptr);
258 1 : }
259 : // The default argument removes the limit completely.
260 1 : BOOST_CHECK(bf.SetLimit());
261 : // The read position should still be at 3 (no change).
262 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 3U);
263 :
264 : // Read from current offset, 3, forward until position 10.
265 8 : for (uint8_t j = 3; j < 10; ++j) {
266 7 : bf >> i;
267 7 : BOOST_CHECK_EQUAL(i, j);
268 7 : }
269 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 10U);
270 :
271 : // We're guaranteed (just barely) to be able to rewind to zero.
272 1 : BOOST_CHECK(bf.SetPos(0));
273 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 0U);
274 1 : bf >> i;
275 1 : BOOST_CHECK_EQUAL(i, 0);
276 :
277 : // We can set the position forward again up to the farthest
278 : // into the stream we've been, but no farther. (Attempting
279 : // to go farther may succeed, but it's not guaranteed.)
280 1 : BOOST_CHECK(bf.SetPos(10));
281 1 : bf >> i;
282 1 : BOOST_CHECK_EQUAL(i, 10);
283 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 11U);
284 :
285 : // Now it's only guaranteed that we can rewind to offset 1
286 : // (current read position, 11, minus rewind amount, 10).
287 1 : BOOST_CHECK(bf.SetPos(1));
288 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 1U);
289 1 : bf >> i;
290 1 : BOOST_CHECK_EQUAL(i, 1);
291 :
292 : // We can stream into large variables, even larger than
293 : // the buffer size.
294 1 : BOOST_CHECK(bf.SetPos(11));
295 : {
296 : uint8_t a[40 - 11];
297 1 : bf >> a;
298 30 : for (uint8_t j = 0; j < sizeof(a); ++j) {
299 29 : BOOST_CHECK_EQUAL(a[j], 11 + j);
300 29 : }
301 : }
302 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 40U);
303 :
304 : // We've read the entire file, the next read should throw.
305 : try {
306 1 : bf >> i;
307 0 : BOOST_CHECK(false);
308 1 : } catch (const std::exception& e) {
309 1 : BOOST_CHECK(strstr(e.what(),
310 : "CBufferedFile::Fill: end of file") != nullptr);
311 1 : }
312 : // Attempting to read beyond the end sets the EOF indicator.
313 1 : BOOST_CHECK(bf.eof());
314 :
315 : // Still at offset 40, we can go back 10, to 30.
316 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 40U);
317 1 : BOOST_CHECK(bf.SetPos(30));
318 1 : bf >> i;
319 1 : BOOST_CHECK_EQUAL(i, 30);
320 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 31U);
321 :
322 : // We're too far to rewind to position zero.
323 1 : BOOST_CHECK(!bf.SetPos(0));
324 : // But we should now be positioned at least as far back as allowed
325 : // by the rewind window (relative to our farthest read position, 40).
326 1 : BOOST_CHECK(bf.GetPos() <= 30U);
327 :
328 : // We can explicitly close the file, or the destructor will do it.
329 1 : bf.fclose();
330 :
331 1 : fs::remove(streams_test_filename);
332 4 : }
333 :
334 149 : BOOST_AUTO_TEST_CASE(streams_buffered_file_skip)
335 : {
336 1 : fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp";
337 1 : FILE* file = fsbridge::fopen(streams_test_filename, "w+b");
338 : // The value at each offset is the byte offset (e.g. byte 1 in the file has the value 0x01).
339 41 : for (uint8_t j = 0; j < 40; ++j) {
340 40 : fwrite(&j, 1, 1, file);
341 40 : }
342 1 : rewind(file);
343 :
344 : // The buffer is 25 bytes, allow rewinding 10 bytes.
345 1 : CBufferedFile bf(file, 25, 10, 222, 333);
346 :
347 : uint8_t i;
348 : // This is like bf >> (7-byte-variable), in that it will cause data
349 : // to be read from the file into memory, but it's not copied to us.
350 1 : bf.SkipTo(7);
351 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 7U);
352 1 : bf >> i;
353 1 : BOOST_CHECK_EQUAL(i, 7);
354 :
355 : // The bytes in the buffer up to offset 7 are valid and can be read.
356 1 : BOOST_CHECK(bf.SetPos(0));
357 1 : bf >> i;
358 1 : BOOST_CHECK_EQUAL(i, 0);
359 1 : bf >> i;
360 1 : BOOST_CHECK_EQUAL(i, 1);
361 :
362 1 : bf.SkipTo(11);
363 1 : bf >> i;
364 1 : BOOST_CHECK_EQUAL(i, 11);
365 :
366 : // SkipTo() honors the transfer limit; we can't position beyond the limit.
367 1 : bf.SetLimit(13);
368 : try {
369 1 : bf.SkipTo(14);
370 0 : BOOST_CHECK(false);
371 1 : } catch (const std::exception& e) {
372 1 : BOOST_CHECK(strstr(e.what(), "Attempt to position past buffer limit") != nullptr);
373 1 : }
374 :
375 : // We can position exactly to the transfer limit.
376 1 : bf.SkipTo(13);
377 1 : BOOST_CHECK_EQUAL(bf.GetPos(), 13U);
378 :
379 1 : bf.fclose();
380 1 : fs::remove(streams_test_filename);
381 2 : }
382 :
383 149 : BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
384 : {
385 : // Make this test deterministic.
386 1 : SeedInsecureRand(SeedRand::ZEROS);
387 :
388 1 : fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp";
389 51 : for (int rep = 0; rep < 50; ++rep) {
390 50 : FILE* file = fsbridge::fopen(streams_test_filename, "w+b");
391 50 : size_t fileSize = InsecureRandRange(256);
392 5731 : for (uint8_t i = 0; i < fileSize; ++i) {
393 5681 : fwrite(&i, 1, 1, file);
394 5681 : }
395 50 : rewind(file);
396 :
397 50 : size_t bufSize = InsecureRandRange(300) + 1;
398 50 : size_t rewindSize = InsecureRandRange(bufSize);
399 50 : CBufferedFile bf(file, bufSize, rewindSize, 222, 333);
400 50 : size_t currentPos = 0;
401 50 : size_t maxPos = 0;
402 3750 : for (int step = 0; step < 100; ++step) {
403 3723 : if (currentPos >= fileSize)
404 23 : break;
405 :
406 : // We haven't read to the end of the file yet.
407 3700 : BOOST_CHECK(!bf.eof());
408 3700 : BOOST_CHECK_EQUAL(bf.GetPos(), currentPos);
409 :
410 : // Pretend the file consists of a series of objects of varying
411 : // sizes; the boundaries of the objects can interact arbitrarily
412 : // with the CBufferFile's internal buffer. These first three
413 : // cases simulate objects of various sizes (1, 2, 5 bytes).
414 3700 : switch (InsecureRandRange(6)) {
415 : case 0: {
416 : uint8_t a[1];
417 638 : if (currentPos + 1 > fileSize)
418 0 : continue;
419 638 : bf.SetLimit(currentPos + 1);
420 638 : bf >> a;
421 1276 : for (uint8_t i = 0; i < 1; ++i) {
422 638 : BOOST_CHECK_EQUAL(a[i], currentPos);
423 638 : currentPos++;
424 638 : }
425 638 : break;
426 : }
427 : case 1: {
428 : uint8_t a[2];
429 619 : if (currentPos + 2 > fileSize)
430 7 : continue;
431 612 : bf.SetLimit(currentPos + 2);
432 612 : bf >> a;
433 1836 : for (uint8_t i = 0; i < 2; ++i) {
434 1224 : BOOST_CHECK_EQUAL(a[i], currentPos);
435 1224 : currentPos++;
436 1224 : }
437 612 : break;
438 : }
439 : case 2: {
440 : uint8_t a[5];
441 618 : if (currentPos + 5 > fileSize)
442 8 : continue;
443 610 : bf.SetLimit(currentPos + 5);
444 610 : bf >> a;
445 3660 : for (uint8_t i = 0; i < 5; ++i) {
446 3050 : BOOST_CHECK_EQUAL(a[i], currentPos);
447 3050 : currentPos++;
448 3050 : }
449 610 : break;
450 : }
451 : case 3: {
452 : // SkipTo is similar to the "read" cases above, except
453 : // we don't receive the data.
454 604 : size_t skip_length{static_cast<size_t>(InsecureRandRange(5))};
455 604 : if (currentPos + skip_length > fileSize) continue;
456 595 : bf.SetLimit(currentPos + skip_length);
457 595 : bf.SkipTo(currentPos + skip_length);
458 595 : currentPos += skip_length;
459 595 : break;
460 : }
461 : case 4: {
462 : // Find a byte value (that is at or ahead of the current position).
463 607 : size_t find = currentPos + InsecureRandRange(8);
464 607 : if (find >= fileSize)
465 7 : find = fileSize - 1;
466 607 : bf.FindByte(uint8_t(find));
467 : // The value at each offset is the offset.
468 607 : BOOST_CHECK_EQUAL(bf.GetPos(), find);
469 607 : currentPos = find;
470 :
471 607 : bf.SetLimit(currentPos + 1);
472 : uint8_t i;
473 607 : bf >> i;
474 607 : BOOST_CHECK_EQUAL(i, currentPos);
475 607 : currentPos++;
476 607 : break;
477 : }
478 : case 5: {
479 614 : size_t requestPos = InsecureRandRange(maxPos + 4);
480 614 : bool okay = bf.SetPos(requestPos);
481 : // The new position may differ from the requested position
482 : // because we may not be able to rewind beyond the rewind
483 : // window, and we may not be able to move forward beyond the
484 : // farthest position we've reached so far.
485 614 : currentPos = bf.GetPos();
486 614 : BOOST_CHECK_EQUAL(okay, currentPos == requestPos);
487 : // Check that we can position within the rewind window.
488 775 : if (requestPos <= maxPos &&
489 554 : maxPos > rewindSize &&
490 161 : requestPos >= maxPos - rewindSize) {
491 : // We requested a position within the rewind window.
492 63 : BOOST_CHECK(okay);
493 63 : }
494 614 : break;
495 : }
496 : }
497 3676 : if (maxPos < currentPos)
498 1420 : maxPos = currentPos;
499 3676 : }
500 50 : }
501 1 : fs::remove(streams_test_filename);
502 1 : }
503 :
504 149 : BOOST_AUTO_TEST_CASE(streams_hashed)
505 : {
506 1 : CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION);
507 1 : HashedSourceWriter hash_writer{stream};
508 1 : const std::string data{"bitcoin"};
509 1 : hash_writer << data;
510 :
511 1 : CHashVerifier hash_verifier{&stream};
512 1 : std::string result;
513 1 : hash_verifier >> result;
514 1 : BOOST_CHECK_EQUAL(data, result);
515 1 : BOOST_CHECK_EQUAL(hash_writer.GetHash(), hash_verifier.GetHash());
516 1 : }
517 :
518 146 : BOOST_AUTO_TEST_SUITE_END()
|