bitcoin/src/test/flatfile_tests.cpp
Vasil Dimov 06105d8da8 util: explicitly close all AutoFiles that have been written
There is no way to report a close error from `AutoFile` destructor.
Such an error could be serious if the file has been written to because
it may mean the file is now corrupted (same as if write fails).

So, change all users of `AutoFile` that use it to write data to
explicitly close the file and handle a possible error.

Github-Pull: #29307
Rebased-From: dba783538683cfc6af209c640c2d019648493f31
2024-11-09 19:18:20 +00:00

134 lines
4.2 KiB
C++

// Copyright (c) 2019-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <clientversion.h>
#include <common/args.h>
#include <flatfile.h>
#include <streams.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(flatfile_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(flatfile_filename)
{
const auto data_dir = m_args.GetDataDirBase();
FlatFilePos pos(456, 789);
FlatFileSeq seq1(data_dir, "a", 16 * 1024);
BOOST_CHECK_EQUAL(seq1.FileName(pos), data_dir / "a00456.dat");
FlatFileSeq seq2(data_dir / "a", "b", 16 * 1024);
BOOST_CHECK_EQUAL(seq2.FileName(pos), data_dir / "a" / "b00456.dat");
// Check default constructor IsNull
assert(FlatFilePos{}.IsNull());
}
BOOST_AUTO_TEST_CASE(flatfile_open)
{
const auto data_dir = m_args.GetDataDirBase();
FlatFileSeq seq(data_dir, "a", 16 * 1024);
std::string line1("A purely peer-to-peer version of electronic cash would allow online "
"payments to be sent directly from one party to another without going "
"through a financial institution.");
std::string line2("Digital signatures provide part of the solution, but the main benefits are "
"lost if a trusted third party is still required to prevent double-spending.");
size_t pos1 = 0;
size_t pos2 = pos1 + GetSerializeSize(line1);
// Write first line to file.
{
AutoFile file{seq.Open(FlatFilePos(0, pos1))};
file << LIMITED_STRING(line1, 256);
BOOST_REQUIRE_EQUAL(file.fclose(), 0);
}
// Attempt to append to file opened in read-only mode.
{
AutoFile file{seq.Open(FlatFilePos(0, pos2), true)};
BOOST_CHECK_THROW(file << LIMITED_STRING(line2, 256), std::ios_base::failure);
}
// Append second line to file.
{
AutoFile file{seq.Open(FlatFilePos(0, pos2))};
file << LIMITED_STRING(line2, 256);
BOOST_REQUIRE_EQUAL(file.fclose(), 0);
}
// Read text from file in read-only mode.
{
std::string text;
AutoFile file{seq.Open(FlatFilePos(0, pos1), true)};
file >> LIMITED_STRING(text, 256);
BOOST_CHECK_EQUAL(text, line1);
file >> LIMITED_STRING(text, 256);
BOOST_CHECK_EQUAL(text, line2);
}
// Read text from file with position offset.
{
std::string text;
AutoFile file{seq.Open(FlatFilePos(0, pos2))};
file >> LIMITED_STRING(text, 256);
BOOST_CHECK_EQUAL(text, line2);
BOOST_REQUIRE_EQUAL(file.fclose(), 0);
}
// Ensure another file in the sequence has no data.
{
std::string text;
AutoFile file{seq.Open(FlatFilePos(1, pos2))};
BOOST_CHECK_THROW(file >> LIMITED_STRING(text, 256), std::ios_base::failure);
BOOST_REQUIRE_EQUAL(file.fclose(), 0);
}
}
BOOST_AUTO_TEST_CASE(flatfile_allocate)
{
const auto data_dir = m_args.GetDataDirBase();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
BOOST_CHECK_EQUAL(seq.Allocate(FlatFilePos(0, 0), 1, out_of_space), 100U);
BOOST_CHECK_EQUAL(fs::file_size(seq.FileName(FlatFilePos(0, 0))), 100U);
BOOST_CHECK(!out_of_space);
BOOST_CHECK_EQUAL(seq.Allocate(FlatFilePos(0, 99), 1, out_of_space), 0U);
BOOST_CHECK_EQUAL(fs::file_size(seq.FileName(FlatFilePos(0, 99))), 100U);
BOOST_CHECK(!out_of_space);
BOOST_CHECK_EQUAL(seq.Allocate(FlatFilePos(0, 99), 2, out_of_space), 101U);
BOOST_CHECK_EQUAL(fs::file_size(seq.FileName(FlatFilePos(0, 99))), 200U);
BOOST_CHECK(!out_of_space);
}
BOOST_AUTO_TEST_CASE(flatfile_flush)
{
const auto data_dir = m_args.GetDataDirBase();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
seq.Allocate(FlatFilePos(0, 0), 1, out_of_space);
// Flush without finalize should not truncate file.
seq.Flush(FlatFilePos(0, 1));
BOOST_CHECK_EQUAL(fs::file_size(seq.FileName(FlatFilePos(0, 1))), 100U);
// Flush with finalize should truncate file.
seq.Flush(FlatFilePos(0, 1), true);
BOOST_CHECK_EQUAL(fs::file_size(seq.FileName(FlatFilePos(0, 1))), 1U);
}
BOOST_AUTO_TEST_SUITE_END()