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}}));
213 std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
258 std::vector<uint8_t>
data{0x82, 0xa7, 0x31};
272 bit_writer.Write(0, 1);
273 bit_writer.Write(2, 2);
274 bit_writer.Write(6, 3);
275 bit_writer.Write(11, 4);
276 bit_writer.Write(1, 5);
277 bit_writer.Write(32, 6);
278 bit_writer.Write(7, 7);
279 bit_writer.Write(30497, 16);
283 uint32_t serialized_int1;
284 data >> serialized_int1;
286 uint16_t serialized_int2;
287 data >> serialized_int2;
312 const Obfuscation obfuscation{
"ffffffffffffffff"_hex};
320 const Obfuscation obfuscation{
"ff0fff0fff0fff0f"_hex};
330 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
334 for (uint8_t j = 0; j < 40; ++j) {
337 file.seek(0, SEEK_SET);
344 }
catch (
const std::exception& e) {
346 "Rewind limit must be less than buffer size") !=
nullptr);
380 }
catch (
const std::exception& e) {
382 "Attempt to position past buffer limit") !=
nullptr);
390 for (uint8_t j = 3; j < 10; ++j) {
423 for (uint8_t j = 0; j <
sizeof(a); ++j) {
433 }
catch (
const std::exception& e) {
435 "BufferedFile::Fill: end of file") !=
nullptr);
453 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
455 fs::remove(streams_test_filename);
460 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
463 for (uint8_t j = 0; j < 40; ++j) {
466 file.seek(0, SEEK_SET);
495 }
catch (
const std::exception& e) {
496 BOOST_CHECK(strstr(e.what(),
"Attempt to position past buffer limit") !=
nullptr);
503 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
504 fs::remove(streams_test_filename);
512 fs::path streams_test_filename = m_args.GetDataDirBase() /
"streams_test_tmp";
513 for (
int rep = 0; rep < 50; ++rep) {
515 size_t fileSize = m_rng.randrange(256);
516 for (uint8_t i = 0; i < fileSize; ++i) {
519 file.seek(0, SEEK_SET);
521 size_t bufSize = m_rng.randrange(300) + 1;
522 size_t rewindSize = m_rng.randrange(bufSize);
524 size_t currentPos = 0;
526 for (
int step = 0; step < 100; ++step) {
527 if (currentPos >= fileSize)
538 switch (m_rng.randrange(6)) {
541 if (currentPos + 1 > fileSize)
543 bf.SetLimit(currentPos + 1);
545 for (uint8_t i = 0; i < 1; ++i) {
553 if (currentPos + 2 > fileSize)
555 bf.SetLimit(currentPos + 2);
557 for (uint8_t i = 0; i < 2; ++i) {
565 if (currentPos + 5 > fileSize)
567 bf.SetLimit(currentPos + 5);
569 for (uint8_t i = 0; i < 5; ++i) {
578 size_t skip_length{
static_cast<size_t>(m_rng.randrange(5))};
579 if (currentPos + skip_length > fileSize)
continue;
580 bf.SetLimit(currentPos + skip_length);
581 bf.SkipTo(currentPos + skip_length);
582 currentPos += skip_length;
587 size_t find = currentPos + m_rng.randrange(8);
588 if (find >= fileSize)
590 bf.FindByte(std::byte(find));
595 bf.SetLimit(currentPos + 1);
603 size_t requestPos = m_rng.randrange(maxPos + 4);
604 bool okay = bf.SetPos(requestPos);
609 currentPos = bf.GetPos();
612 if (requestPos <= maxPos &&
613 maxPos > rewindSize &&
614 requestPos >= maxPos - rewindSize) {
621 if (maxPos < currentPos)
624 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
626 fs::remove(streams_test_filename);
631 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
632 const size_t buf_size{1 + m_rng.randrange(file_size)};
640 AutoFile f{test_file.Open(pos,
false), obfuscation};
641 f.
write(m_rng.randbytes<std::byte>(file_size));
642 BOOST_REQUIRE_EQUAL(f.fclose(), 0);
647 AutoFile direct_file{test_file.Open(pos,
true), obfuscation};
649 AutoFile buffered_file{test_file.Open(pos,
true), obfuscation};
650 BufferedReader buffered_reader{std::move(buffered_file), buf_size};
652 for (
size_t total_read{0}; total_read < file_size;) {
653 const size_t read{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_read))};
656 direct_file.read(direct_file_buffer);
659 buffered_reader.read(buffered_buffer);
661 BOOST_CHECK_EQUAL_COLLECTIONS(
662 direct_file_buffer.begin(), direct_file_buffer.end(),
663 buffered_buffer.begin(), buffered_buffer.end()
671 BOOST_CHECK_EXCEPTION(direct_file.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
676 BOOST_CHECK_EXCEPTION(buffered_reader.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
680 fs::remove(test_file.FileName(pos));
685 const size_t file_size{1 + m_rng.randrange<
size_t>(1 << 17)};
686 const size_t buf_size{1 + m_rng.randrange(file_size)};
694 DataBuffer test_data{m_rng.randbytes<std::byte>(file_size)};
696 AutoFile direct_file{test_direct.Open(pos,
false), obfuscation};
698 AutoFile buffered_file{test_buffered.Open(pos,
false), obfuscation};
702 for (
size_t total_written{0}; total_written < file_size;) {
703 const size_t write_size{
Assert(std::min(1 + m_rng.randrange(m_rng.randbool() ? buf_size : 2 * buf_size), file_size - total_written))};
705 auto current_span = std::span{test_data}.subspan(total_written, write_size);
706 direct_file.write(current_span);
707 buffered.write(current_span);
709 total_written += write_size;
712 BOOST_REQUIRE_EQUAL(buffered_file.fclose(), 0);
713 BOOST_REQUIRE_EQUAL(direct_file.fclose(), 0);
719 AutoFile verify_direct{test_direct.Open(pos,
true), obfuscation};
720 verify_direct.
read(direct_result);
723 BOOST_CHECK_EXCEPTION(verify_direct.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
728 AutoFile verify_buffered{test_buffered.Open(pos,
true), obfuscation};
729 verify_buffered.
read(buffered_result);
732 BOOST_CHECK_EXCEPTION(verify_buffered.read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
735 BOOST_CHECK_EQUAL_COLLECTIONS(
736 direct_result.begin(), direct_result.end(),
737 buffered_result.begin(), buffered_result.end()
740 fs::remove(test_direct.FileName(pos));
741 fs::remove(test_buffered.FileName(pos));
746 const uint32_t v1{m_rng.rand32()}, v2{m_rng.rand32()}, v3{m_rng.rand32()};
747 const fs::path test_file{m_args.GetDataDirBase() /
"test_buffered_write_read.bin"};
754 f.
write(std::as_bytes(std::span{&v3, 1}));
756 BOOST_REQUIRE_EQUAL(file.fclose(), 0);
760 uint32_t _v1{0}, _v2{0}, _v3{0};
762 BufferedReader f(std::move(file),
sizeof(v1) +
sizeof(v2) +
sizeof(v3));
764 f.
read(std::as_writable_bytes(std::span{&_v3, 1}));
770 BOOST_CHECK_EXCEPTION(f.
read(excess_byte), std::ios_base::failure,
HasReason{
"end of file"});
773 fs::remove(test_file);
780 const std::string
data{
"bitcoin"};
785 hash_verifier >> result;
792 const fs::path path = m_args.GetDataDirBase() /
"size_pos_test.bin";
794 for (uint8_t j = 0; j < 10; ++j) {
821 BOOST_CHECK_EXCEPTION(f >> end, std::ios_base::failure,
HasReason{
"AutoFile::read: end of file"});
823 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.