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"});
104 BOOST_CHECK_EXCEPTION(xor_file.size(), std::ios_base::failure,
HasReason{
"AutoFile::size: file handle is nullptr"});
109 const char* mode =
"wb";
111 const char* mode =
"wbx";
113 AutoFile xor_file{raw_file(mode), obfuscation};
114 xor_file <<
test1 << test2;
116 BOOST_REQUIRE_EQUAL(xor_file.fclose(), 0);
120 AutoFile non_xor_file{raw_file(
"rb")};
121 std::vector<std::byte> raw(7);
122 non_xor_file >> std::span{raw};
125 BOOST_CHECK_EXCEPTION(non_xor_file.ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: end of file"});
129 AutoFile xor_file{raw_file(
"rb"), obfuscation};
130 std::vector<std::byte> read1, read2;
131 xor_file >> read1 >> read2;
135 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
139 AutoFile xor_file{raw_file(
"rb"), obfuscation};
140 std::vector<std::byte> read2;
146 BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: end of file"});
147 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
156 unsigned char bytes[] = {3, 4, 5, 6};
157 std::vector<unsigned char> vch;
164 BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
166 BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
170 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
172 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
177 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
179 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
184 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
186 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
191 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
193 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
197 BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
199 BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
204 BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
206 BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
212 std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
257 std::vector<uint8_t>
data{0x82, 0xa7, 0x31};
271 bit_writer.Write(0, 1);
272 bit_writer.Write(2, 2);
273 bit_writer.Write(6, 3);
274 bit_writer.Write(11, 4);
275 bit_writer.Write(1, 5);
276 bit_writer.Write(32, 6);
277 bit_writer.Write(7, 7);
278 bit_writer.Write(30497, 16);
282 uint32_t serialized_int1;
283 data >> serialized_int1;
285 uint16_t serialized_int2;
286 data >> serialized_int2;
311 const Obfuscation obfuscation{
"ffffffffffffffff"_hex};
319 const Obfuscation obfuscation{
"ff0fff0fff0fff0f"_hex};
329 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
333 for (uint8_t j = 0; j < 40; ++j) {
336 file.seek(0, SEEK_SET);
343 }
catch (
const std::exception& e) {
345 "Rewind limit must be less than buffer size") !=
nullptr);
379 }
catch (
const std::exception& e) {
381 "Attempt to position past buffer limit") !=
nullptr);
389 for (uint8_t j = 3; j < 10; ++j) {
422 for (uint8_t j = 0; j <
sizeof(a); ++j) {
432 }
catch (
const std::exception& e) {
434 "BufferedFile::Fill: end of file") !=
nullptr);
452 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
454 fs::remove(streams_test_filename);
459 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
462 for (uint8_t j = 0; j < 40; ++j) {
465 file.seek(0, SEEK_SET);
494 }
catch (
const std::exception& e) {
495 BOOST_CHECK(strstr(e.what(),
"Attempt to position past buffer limit") !=
nullptr);
502 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
503 fs::remove(streams_test_filename);
511 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
512 for (
int rep = 0; rep < 50; ++rep) {
514 size_t fileSize = m_rng.randrange(256);
515 for (uint8_t i = 0; i < fileSize; ++i) {
518 file.seek(0, SEEK_SET);
520 size_t bufSize = m_rng.randrange(300) + 1;
521 size_t rewindSize = m_rng.randrange(bufSize);
523 size_t currentPos = 0;
525 for (
int step = 0; step < 100; ++step) {
526 if (currentPos >= fileSize)
537 switch (m_rng.randrange(6)) {
540 if (currentPos + 1 > fileSize)
542 bf.SetLimit(currentPos + 1);
544 for (uint8_t i = 0; i < 1; ++i) {
552 if (currentPos + 2 > fileSize)
554 bf.SetLimit(currentPos + 2);
556 for (uint8_t i = 0; i < 2; ++i) {
564 if (currentPos + 5 > fileSize)
566 bf.SetLimit(currentPos + 5);
568 for (uint8_t i = 0; i < 5; ++i) {
577 size_t skip_length{
static_cast<size_t>(m_rng.randrange(5))};
578 if (currentPos + skip_length > fileSize)
continue;
579 bf.SetLimit(currentPos + skip_length);
580 bf.SkipTo(currentPos + skip_length);
581 currentPos += skip_length;
586 size_t find = currentPos + m_rng.randrange(8);
587 if (find >= fileSize)
589 bf.FindByte(std::byte(find));
594 bf.SetLimit(currentPos + 1);
602 size_t requestPos = m_rng.randrange(maxPos + 4);
603 bool okay = bf.SetPos(requestPos);
608 currentPos = bf.GetPos();
611 if (requestPos <= maxPos &&
612 maxPos > rewindSize &&
613 requestPos >= maxPos - rewindSize) {
620 if (maxPos < currentPos)
623 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
625 fs::remove(streams_test_filename);
630 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
631 const size_t buf_size{1 + m_rng.randrange(file_size)};
639 AutoFile f{test_file.Open(pos,
false), obfuscation};
640 f.
write(m_rng.randbytes<std::byte>(file_size));
641 BOOST_REQUIRE_EQUAL(f.fclose(), 0);
646 AutoFile direct_file{test_file.Open(pos,
true), obfuscation};
648 AutoFile buffered_file{test_file.Open(pos,
true), obfuscation};
649 BufferedReader buffered_reader{std::move(buffered_file), buf_size};
651 for (
size_t total_read{0}; total_read < file_size;) {
652 const size_t read{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_read))};
655 direct_file.read(direct_file_buffer);
658 buffered_reader.read(buffered_buffer);
660 BOOST_CHECK_EQUAL_COLLECTIONS(
661 direct_file_buffer.begin(), direct_file_buffer.end(),
662 buffered_buffer.begin(), buffered_buffer.end()
670 BOOST_CHECK_EXCEPTION(direct_file.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
675 BOOST_CHECK_EXCEPTION(buffered_reader.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
679 fs::remove(test_file.FileName(pos));
684 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
685 const size_t buf_size{1 + m_rng.randrange(file_size)};
693 DataBuffer test_data{m_rng.randbytes<std::byte>(file_size)};
695 AutoFile direct_file{test_direct.Open(pos,
false), obfuscation};
697 AutoFile buffered_file{test_buffered.Open(pos,
false), obfuscation};
701 for (
size_t total_written{0}; total_written < file_size;) {
702 const size_t write_size{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_written))};
704 auto current_span = std::span{test_data}.subspan(total_written, write_size);
705 direct_file.write(current_span);
706 buffered.write(current_span);
708 total_written += write_size;
711 BOOST_REQUIRE_EQUAL(buffered_file.fclose(), 0);
712 BOOST_REQUIRE_EQUAL(direct_file.fclose(), 0);
718 AutoFile verify_direct{test_direct.Open(pos,
true), obfuscation};
719 verify_direct.
read(direct_result);
722 BOOST_CHECK_EXCEPTION(verify_direct.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
727 AutoFile verify_buffered{test_buffered.Open(pos,
true), obfuscation};
728 verify_buffered.
read(buffered_result);
731 BOOST_CHECK_EXCEPTION(verify_buffered.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
734 BOOST_CHECK_EQUAL_COLLECTIONS(
735 direct_result.begin(), direct_result.end(),
736 buffered_result.begin(), buffered_result.end()
739 fs::remove(test_direct.FileName(pos));
740 fs::remove(test_buffered.FileName(pos));
745 const uint32_t v1{m_rng.rand32()}, v2{m_rng.rand32()}, v3{m_rng.rand32()};
746 const fs::path test_file{m_args.GetDataDirBase() /
"test_buffered_write_read.bin"};
753 f.
write(std::as_bytes(std::span{&v3, 1}));
755 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
759 uint32_t _v1{0}, _v2{0}, _v3{0};
761 BufferedReader f(std::move(file),
sizeof(v1) +
sizeof(v2) +
sizeof(v3));
763 f.
read(std::as_writable_bytes(std::span{&_v3, 1}));
769 BOOST_CHECK_EXCEPTION(f.
read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
772 fs::remove(test_file);
779 const std::string
data{
"bitcoin"};
784 hash_verifier >> result;
791 const fs::path path = m_args.GetDataDirBase() /
"size_pos_test.bin";
793 for (uint8_t j = 0; j < 10; ++j) {
820 BOOST_CHECK_EXCEPTION(f >> end, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
822 BOOST_REQUIRE_EQUAL(f.fclose(), 0);
#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.