15#include <boost/test/unit_test.hpp>
17using namespace std::string_literals;
26 auto apply_random_xor_chunks{[&](std::span<std::byte> target,
const Obfuscation& obfuscation) {
27 for (
size_t offset{0}; offset < target.size();) {
28 const size_t chunk_size{1 + m_rng.randrange(target.size() - offset)};
29 obfuscation(target.subspan(offset, chunk_size), offset);
34 for (
size_t test{0}; test < 100; ++test) {
35 const size_t write_size{1 + m_rng.randrange(100U)};
36 const std::vector original{m_rng.randbytes<std::byte>(write_size)};
37 std::vector roundtrip{original};
39 const auto key_bytes{m_rng.randbool() ? m_rng.randbytes<
Obfuscation::KEY_SIZE>() : std::array<std::byte, Obfuscation::KEY_SIZE>{}};
41 apply_random_xor_chunks(roundtrip, obfuscation);
43 for (
size_t i{0}; i < original.size(); ++i) {
47 apply_random_xor_chunks(roundtrip, obfuscation);
48 BOOST_CHECK_EQUAL_COLLECTIONS(roundtrip.begin(), roundtrip.end(), original.begin(), original.end());
73 std::vector<std::byte> key_out;
75 ds_out << obfuscation;
79 BOOST_CHECK_EQUAL_COLLECTIONS(key_in.begin(), key_in.end(), key_out.begin(), key_out.end());
87 const Obfuscation non_null_obf{
"ff00ff00ff00ff00"_hex};
93 fs::path xor_path{m_args.GetDataDirBase() /
"test_xor.bin"};
94 auto raw_file{[&](
const auto& mode) {
return fsbridge::fopen(xor_path, mode); }};
95 const std::vector<uint8_t>
test1{1, 2, 3};
96 const std::vector<uint8_t> test2{4, 5};
97 const Obfuscation obfuscation{
"ff00ff00ff00ff00"_hex};
101 AutoFile xor_file{raw_file(
"rb"), obfuscation};
102 BOOST_CHECK_EXCEPTION(xor_file << std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::write: file handle is nullptr"});
103 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: file handle is nullptr"});
104 BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: file handle is nullptr"});
105 BOOST_CHECK_EXCEPTION(xor_file.size(), std::ios_base::failure,
HasReason{
"AutoFile::size: file handle is nullptr"});
110 const char* mode =
"wb";
112 const char* mode =
"wbx";
114 AutoFile xor_file{raw_file(mode), obfuscation};
115 xor_file <<
test1 << test2;
117 BOOST_REQUIRE_EQUAL(xor_file.fclose(), 0);
121 AutoFile non_xor_file{raw_file(
"rb")};
122 std::vector<std::byte> raw(7);
123 non_xor_file >> std::span{raw};
126 BOOST_CHECK_EXCEPTION(non_xor_file.ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: end of file"});
130 AutoFile xor_file{raw_file(
"rb"), obfuscation};
131 std::vector<std::byte> read1, read2;
132 xor_file >> read1 >> read2;
136 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
140 AutoFile xor_file{raw_file(
"rb"), obfuscation};
141 std::vector<std::byte> read2;
147 BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure,
HasReason{
"AutoFile::ignore: end of file"});
148 BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
157 unsigned char bytes[] = {3, 4, 5, 6};
158 std::vector<unsigned char> vch;
165 BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
167 BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
171 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
173 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
178 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
180 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
185 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
187 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
192 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
194 BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
198 BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
200 BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
205 BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
207 BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
215 unsigned char bytes[] = {3, 4, 5, 6};
216 std::array<std::byte, 8> arr{};
224 SpanWriter{std::span{arr}.subspan(2), a, bytes, b};
228 std::array<std::byte, 1> small{};
235 std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
280 std::vector<uint8_t>
data{0x82, 0xa7, 0x31};
294 bit_writer.Write(0, 1);
295 bit_writer.Write(2, 2);
296 bit_writer.Write(6, 3);
297 bit_writer.Write(11, 4);
298 bit_writer.Write(1, 5);
299 bit_writer.Write(32, 6);
300 bit_writer.Write(7, 7);
301 bit_writer.Write(30497, 16);
305 uint32_t serialized_int1;
306 data >> serialized_int1;
308 uint16_t serialized_int2;
309 data >> serialized_int2;
334 const Obfuscation obfuscation{
"ffffffffffffffff"_hex};
342 const Obfuscation obfuscation{
"ff0fff0fff0fff0f"_hex};
352 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
356 for (uint8_t j = 0; j < 40; ++j) {
359 file.seek(0, SEEK_SET);
366 }
catch (
const std::exception& e) {
368 "Rewind limit must be less than buffer size") !=
nullptr);
402 }
catch (
const std::exception& e) {
404 "Attempt to position past buffer limit") !=
nullptr);
412 for (uint8_t j = 3; j < 10; ++j) {
445 for (uint8_t j = 0; j <
sizeof(a); ++j) {
455 }
catch (
const std::exception& e) {
457 "BufferedFile::Fill: end of file") !=
nullptr);
475 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
477 fs::remove(streams_test_filename);
482 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
485 for (uint8_t j = 0; j < 40; ++j) {
488 file.seek(0, SEEK_SET);
517 }
catch (
const std::exception& e) {
518 BOOST_CHECK(strstr(e.what(),
"Attempt to position past buffer limit") !=
nullptr);
525 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
526 fs::remove(streams_test_filename);
534 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
535 for (
int rep = 0; rep < 50; ++rep) {
537 size_t fileSize = m_rng.randrange(256);
538 for (uint8_t i = 0; i < fileSize; ++i) {
541 file.seek(0, SEEK_SET);
543 size_t bufSize = m_rng.randrange(300) + 1;
544 size_t rewindSize = m_rng.randrange(bufSize);
546 size_t currentPos = 0;
548 for (
int step = 0; step < 100; ++step) {
549 if (currentPos >= fileSize)
560 switch (m_rng.randrange(6)) {
563 if (currentPos + 1 > fileSize)
565 bf.SetLimit(currentPos + 1);
567 for (uint8_t i = 0; i < 1; ++i) {
575 if (currentPos + 2 > fileSize)
577 bf.SetLimit(currentPos + 2);
579 for (uint8_t i = 0; i < 2; ++i) {
587 if (currentPos + 5 > fileSize)
589 bf.SetLimit(currentPos + 5);
591 for (uint8_t i = 0; i < 5; ++i) {
600 size_t skip_length{
static_cast<size_t>(m_rng.randrange(5))};
601 if (currentPos + skip_length > fileSize)
continue;
602 bf.SetLimit(currentPos + skip_length);
603 bf.SkipTo(currentPos + skip_length);
604 currentPos += skip_length;
609 size_t find = currentPos + m_rng.randrange(8);
610 if (find >= fileSize)
612 bf.FindByte(std::byte(find));
617 bf.SetLimit(currentPos + 1);
625 size_t requestPos = m_rng.randrange(maxPos + 4);
626 bool okay = bf.SetPos(requestPos);
631 currentPos = bf.GetPos();
634 if (requestPos <= maxPos &&
635 maxPos > rewindSize &&
636 requestPos >= maxPos - rewindSize) {
643 if (maxPos < currentPos)
646 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
648 fs::remove(streams_test_filename);
653 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
654 const size_t buf_size{1 + m_rng.randrange(file_size)};
662 AutoFile f{test_file.Open(pos,
false), obfuscation};
663 f.
write(m_rng.randbytes<std::byte>(file_size));
664 BOOST_REQUIRE_EQUAL(f.fclose(), 0);
669 AutoFile direct_file{test_file.Open(pos,
true), obfuscation};
671 AutoFile buffered_file{test_file.Open(pos,
true), obfuscation};
672 BufferedReader buffered_reader{std::move(buffered_file), buf_size};
674 for (
size_t total_read{0}; total_read < file_size;) {
675 const size_t read{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_read))};
678 direct_file.read(direct_file_buffer);
681 buffered_reader.read(buffered_buffer);
683 BOOST_CHECK_EQUAL_COLLECTIONS(
684 direct_file_buffer.begin(), direct_file_buffer.end(),
685 buffered_buffer.begin(), buffered_buffer.end()
693 BOOST_CHECK_EXCEPTION(direct_file.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
698 BOOST_CHECK_EXCEPTION(buffered_reader.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
702 fs::remove(test_file.FileName(pos));
707 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
708 const size_t buf_size{1 + m_rng.randrange(file_size)};
716 DataBuffer test_data{m_rng.randbytes<std::byte>(file_size)};
718 AutoFile direct_file{test_direct.Open(pos,
false), obfuscation};
720 AutoFile buffered_file{test_buffered.Open(pos,
false), obfuscation};
724 for (
size_t total_written{0}; total_written < file_size;) {
725 const size_t write_size{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_written))};
727 auto current_span = std::span{test_data}.subspan(total_written, write_size);
728 direct_file.write(current_span);
729 buffered.write(current_span);
731 total_written += write_size;
734 BOOST_REQUIRE_EQUAL(buffered_file.fclose(), 0);
735 BOOST_REQUIRE_EQUAL(direct_file.fclose(), 0);
741 AutoFile verify_direct{test_direct.Open(pos,
true), obfuscation};
742 verify_direct.
read(direct_result);
745 BOOST_CHECK_EXCEPTION(verify_direct.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
750 AutoFile verify_buffered{test_buffered.Open(pos,
true), obfuscation};
751 verify_buffered.
read(buffered_result);
754 BOOST_CHECK_EXCEPTION(verify_buffered.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
757 BOOST_CHECK_EQUAL_COLLECTIONS(
758 direct_result.begin(), direct_result.end(),
759 buffered_result.begin(), buffered_result.end()
762 fs::remove(test_direct.FileName(pos));
763 fs::remove(test_buffered.FileName(pos));
768 const uint32_t v1{m_rng.rand32()}, v2{m_rng.rand32()}, v3{m_rng.rand32()};
769 const fs::path test_file{m_args.GetDataDirBase() /
"test_buffered_write_read.bin"};
776 f.
write(std::as_bytes(std::span{&v3, 1}));
778 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
782 uint32_t _v1{0}, _v2{0}, _v3{0};
784 BufferedReader f(std::move(file),
sizeof(v1) +
sizeof(v2) +
sizeof(v3));
786 f.
read(std::as_writable_bytes(std::span{&_v3, 1}));
792 BOOST_CHECK_EXCEPTION(f.
read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
795 fs::remove(test_file);
802 const std::string
data{
"bitcoin"};
807 hash_verifier >> result;
814 const fs::path path = m_args.GetDataDirBase() /
"size_pos_test.bin";
816 for (uint8_t j = 0; j < 10; ++j) {
843 BOOST_CHECK_EXCEPTION(f >> end, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
845 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.
Minimal stream for writing to an existing span of bytes.
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.