14#include <boost/test/unit_test.hpp>
16using namespace std::string_literals;
25 auto apply_random_xor_chunks{[&](std::span<std::byte> target,
const Obfuscation& obfuscation) {
26 for (
size_t offset{0}; offset < target.size();) {
27 const size_t chunk_size{1 + m_rng.randrange(target.size() - offset)};
28 obfuscation(target.subspan(offset, chunk_size), offset);
33 for (
size_t test{0}; test < 100; ++test) {
34 const size_t write_size{1 + m_rng.randrange(100U)};
35 const std::vector original{m_rng.randbytes<std::byte>(write_size)};
36 std::vector roundtrip{original};
38 const auto key_bytes{m_rng.randbool() ? m_rng.randbytes<
Obfuscation::KEY_SIZE>() : std::array<std::byte, Obfuscation::KEY_SIZE>{}};
40 apply_random_xor_chunks(roundtrip, obfuscation);
42 for (
size_t i{0}; i < original.size(); ++i) {
46 apply_random_xor_chunks(roundtrip, obfuscation);
47 BOOST_CHECK_EQUAL_COLLECTIONS(roundtrip.begin(), roundtrip.end(), original.begin(), original.end());
72 std::vector<std::byte> key_out;
74 ds_out << obfuscation;
78 BOOST_CHECK_EQUAL_COLLECTIONS(key_in.begin(), key_in.end(), key_out.begin(), key_out.end());
86 const Obfuscation non_null_obf{
"ff00ff00ff00ff00"_hex};
92 fs::path xor_path{m_args.GetDataDirBase() /
"test_xor.bin"};
93 auto raw_file{[&](
const auto& mode) {
return fsbridge::fopen(xor_path, mode); }};
94 const std::vector<uint8_t>
test1{1, 2, 3};
95 const std::vector<uint8_t> test2{4, 5};
96 const Obfuscation obfuscation{
"ff00ff00ff00ff00"_hex};
100 AutoFile xor_file{raw_file(
"rb"), obfuscation};
101 BOOST_CHECK_EXCEPTION(xor_file << std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::write: file handle is nullptr"});
102 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: file handle is nullptr"});
103 BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: file handle is nullptr"});
108 const char* mode =
"wb";
110 const char* mode =
"wbx";
112 AutoFile xor_file{raw_file(mode), obfuscation};
113 xor_file <<
test1 << test2;
114 BOOST_REQUIRE_EQUAL(xor_file.fclose(), 0);
118 AutoFile non_xor_file{raw_file(
"rb")};
119 std::vector<std::byte> raw(7);
120 non_xor_file >> std::span{raw};
123 BOOST_CHECK_EXCEPTION(non_xor_file.ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: end of file"});
126 AutoFile xor_file{raw_file(
"rb"), obfuscation};
127 std::vector<std::byte> read1, read2;
128 xor_file >> read1 >> read2;
132 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
135 AutoFile xor_file{raw_file(
"rb"), obfuscation};
136 std::vector<std::byte> read2;
142 BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: end of file"});
143 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
151 unsigned char bytes[] = {3, 4, 5, 6};
152 std::vector<unsigned char> vch;
159 BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
161 BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
165 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
167 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
172 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
174 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
179 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
181 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
186 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
188 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
192 BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
194 BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
199 BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
201 BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
207 std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
252 std::vector<uint8_t>
data{0x82, 0xa7, 0x31};
266 bit_writer.Write(0, 1);
267 bit_writer.Write(2, 2);
268 bit_writer.Write(6, 3);
269 bit_writer.Write(11, 4);
270 bit_writer.Write(1, 5);
271 bit_writer.Write(32, 6);
272 bit_writer.Write(7, 7);
273 bit_writer.Write(30497, 16);
277 uint32_t serialized_int1;
278 data >> serialized_int1;
280 uint16_t serialized_int2;
281 data >> serialized_int2;
306 const Obfuscation obfuscation{
"ffffffffffffffff"_hex};
314 const Obfuscation obfuscation{
"ff0fff0fff0fff0f"_hex};
324 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
328 for (uint8_t j = 0; j < 40; ++j) {
331 file.seek(0, SEEK_SET);
338 }
catch (
const std::exception& e) {
340 "Rewind limit must be less than buffer size") !=
nullptr);
374 }
catch (
const std::exception& e) {
376 "Attempt to position past buffer limit") !=
nullptr);
384 for (uint8_t j = 3; j < 10; ++j) {
417 for (uint8_t j = 0; j <
sizeof(a); ++j) {
427 }
catch (
const std::exception& e) {
429 "BufferedFile::Fill: end of file") !=
nullptr);
447 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
449 fs::remove(streams_test_filename);
454 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
457 for (uint8_t j = 0; j < 40; ++j) {
460 file.seek(0, SEEK_SET);
489 }
catch (
const std::exception& e) {
490 BOOST_CHECK(strstr(e.what(),
"Attempt to position past buffer limit") !=
nullptr);
497 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
498 fs::remove(streams_test_filename);
506 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
507 for (
int rep = 0; rep < 50; ++rep) {
509 size_t fileSize = m_rng.randrange(256);
510 for (uint8_t i = 0; i < fileSize; ++i) {
513 file.seek(0, SEEK_SET);
515 size_t bufSize = m_rng.randrange(300) + 1;
516 size_t rewindSize = m_rng.randrange(bufSize);
518 size_t currentPos = 0;
520 for (
int step = 0; step < 100; ++step) {
521 if (currentPos >= fileSize)
532 switch (m_rng.randrange(6)) {
535 if (currentPos + 1 > fileSize)
537 bf.SetLimit(currentPos + 1);
539 for (uint8_t i = 0; i < 1; ++i) {
547 if (currentPos + 2 > fileSize)
549 bf.SetLimit(currentPos + 2);
551 for (uint8_t i = 0; i < 2; ++i) {
559 if (currentPos + 5 > fileSize)
561 bf.SetLimit(currentPos + 5);
563 for (uint8_t i = 0; i < 5; ++i) {
572 size_t skip_length{
static_cast<size_t>(m_rng.randrange(5))};
573 if (currentPos + skip_length > fileSize)
continue;
574 bf.SetLimit(currentPos + skip_length);
575 bf.SkipTo(currentPos + skip_length);
576 currentPos += skip_length;
581 size_t find = currentPos + m_rng.randrange(8);
582 if (find >= fileSize)
584 bf.FindByte(std::byte(find));
589 bf.SetLimit(currentPos + 1);
597 size_t requestPos = m_rng.randrange(maxPos + 4);
598 bool okay = bf.SetPos(requestPos);
603 currentPos = bf.GetPos();
606 if (requestPos <= maxPos &&
607 maxPos > rewindSize &&
608 requestPos >= maxPos - rewindSize) {
615 if (maxPos < currentPos)
618 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
620 fs::remove(streams_test_filename);
625 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
626 const size_t buf_size{1 + m_rng.randrange(file_size)};
634 AutoFile f{test_file.Open(pos,
false), obfuscation};
635 f.
write(m_rng.randbytes<std::byte>(file_size));
636 BOOST_REQUIRE_EQUAL(f.fclose(), 0);
641 AutoFile direct_file{test_file.Open(pos,
true), obfuscation};
643 AutoFile buffered_file{test_file.Open(pos,
true), obfuscation};
644 BufferedReader buffered_reader{std::move(buffered_file), buf_size};
646 for (
size_t total_read{0}; total_read < file_size;) {
647 const size_t read{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_read))};
650 direct_file.read(direct_file_buffer);
653 buffered_reader.read(buffered_buffer);
655 BOOST_CHECK_EQUAL_COLLECTIONS(
656 direct_file_buffer.begin(), direct_file_buffer.end(),
657 buffered_buffer.begin(), buffered_buffer.end()
665 BOOST_CHECK_EXCEPTION(direct_file.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
670 BOOST_CHECK_EXCEPTION(buffered_reader.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
674 fs::remove(test_file.FileName(pos));
679 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
680 const size_t buf_size{1 + m_rng.randrange(file_size)};
688 DataBuffer test_data{m_rng.randbytes<std::byte>(file_size)};
690 AutoFile direct_file{test_direct.Open(pos,
false), obfuscation};
692 AutoFile buffered_file{test_buffered.Open(pos,
false), obfuscation};
696 for (
size_t total_written{0}; total_written < file_size;) {
697 const size_t write_size{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_written))};
699 auto current_span = std::span{test_data}.subspan(total_written, write_size);
700 direct_file.write(current_span);
701 buffered.write(current_span);
703 total_written += write_size;
706 BOOST_REQUIRE_EQUAL(buffered_file.fclose(), 0);
707 BOOST_REQUIRE_EQUAL(direct_file.fclose(), 0);
713 AutoFile verify_direct{test_direct.Open(pos,
true), obfuscation};
714 verify_direct.
read(direct_result);
717 BOOST_CHECK_EXCEPTION(verify_direct.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
722 AutoFile verify_buffered{test_buffered.Open(pos,
true), obfuscation};
723 verify_buffered.
read(buffered_result);
726 BOOST_CHECK_EXCEPTION(verify_buffered.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
729 BOOST_CHECK_EQUAL_COLLECTIONS(
730 direct_result.begin(), direct_result.end(),
731 buffered_result.begin(), buffered_result.end()
734 fs::remove(test_direct.FileName(pos));
735 fs::remove(test_buffered.FileName(pos));
740 const uint32_t v1{m_rng.rand32()}, v2{m_rng.rand32()}, v3{m_rng.rand32()};
741 const fs::path test_file{m_args.GetDataDirBase() /
"test_buffered_write_read.bin"};
748 f.
write(std::as_bytes(std::span{&v3, 1}));
750 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
754 uint32_t _v1{0}, _v2{0}, _v3{0};
756 BufferedReader f(std::move(file),
sizeof(v1) +
sizeof(v2) +
sizeof(v3));
758 f.
read(std::as_writable_bytes(std::span{&_v3, 1}));
764 BOOST_CHECK_EXCEPTION(f.
read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
767 fs::remove(test_file);
774 const std::string
data{
"bitcoin"};
779 hash_verifier >> result;
#define Assert(val)
Identity function.
Non-refcounted RAII wrapper for FILE*.
void ignore(size_t nSize)
void write(std::span< const std::byte > src)
void read(std::span< std::byte > dst)
Wrapper around an AutoFile& that implements a ring buffer to deserialize from.
void SkipTo(const uint64_t file_pos)
Move the read position ahead in the stream to the given position.
Wrapper that buffers reads from an underlying stream.
void read(std::span< std::byte > dst)
Wrapper that buffers writes to an underlying stream.
void write(std::span< const std::byte > src)
Double ended buffer combining vector and stream-like interfaces.
FlatFileSeq represents a sequence of numbered files storing raw data.
BOOST_CHECK_EXCEPTION predicates to check the specific validation error.
Reads data from an underlying stream, while hashing the read data.
Writes data to an underlying source stream, while hashing the written data.
static constexpr size_t KEY_SIZE
Minimal stream for reading from an existing byte array by std::span.
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
FILE * fopen(const fs::path &p, const char *mode)
static const unsigned int BLOCKFILE_CHUNK_SIZE
The pre-allocation chunk size for blk?????.dat files (since 0.8)
""_hex is a compile-time user-defined literal returning a std::array<std::byte>, equivalent to ParseH...
#define BOOST_CHECK_THROW(stmt, excMatch)
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
std::vector< std::byte > DataBuffer
BOOST_AUTO_TEST_CASE(xor_random_chunks)
@ ZEROS
Seed with a compile time constant of zeros.