mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-09 11:27:28 -03:00
test: Validate error messages on fail
The `ccoins_add` and `ccoins_write` tests check the actual exception error messages now instead of just that they fail for the given parameters. This enables us testing different exceptions in a more fine-grained way in later changes.
This commit is contained in:
parent
d5f8d607ab
commit
c0b4b2c1ee
1 changed files with 130 additions and 131 deletions
|
@ -15,6 +15,8 @@
|
|||
#include <util/strencodings.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
@ -559,17 +561,15 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
|
|||
}
|
||||
|
||||
const static COutPoint OUTPOINT;
|
||||
const static CAmount SPENT = -1;
|
||||
const static CAmount ABSENT = -2;
|
||||
const static CAmount FAIL = -3;
|
||||
const static CAmount VALUE1 = 100;
|
||||
const static CAmount VALUE2 = 200;
|
||||
const static CAmount VALUE3 = 300;
|
||||
constexpr CAmount SPENT {-1};
|
||||
constexpr CAmount ABSENT{-2};
|
||||
constexpr CAmount VALUE1{100};
|
||||
constexpr CAmount VALUE2{200};
|
||||
constexpr CAmount VALUE3{300};
|
||||
|
||||
const static char DIRTY = CCoinsCacheEntry::DIRTY;
|
||||
const static char FRESH = CCoinsCacheEntry::FRESH;
|
||||
const static char CLEAN = 0;
|
||||
const static char NO_ENTRY = -1;
|
||||
constexpr char DIRTY{CCoinsCacheEntry::DIRTY};
|
||||
constexpr char FRESH{CCoinsCacheEntry::FRESH};
|
||||
constexpr char CLEAN{0};
|
||||
|
||||
struct CoinEntry {
|
||||
const CAmount value;
|
||||
|
@ -581,25 +581,27 @@ struct CoinEntry {
|
|||
friend std::ostream& operator<<(std::ostream& os, const CoinEntry& e) { return os << e.value << ", " << e.flags; }
|
||||
};
|
||||
|
||||
using MaybeCoin = std::optional<CoinEntry>;
|
||||
using MaybeCoin = std::optional<CoinEntry>;
|
||||
using CoinOrError = std::variant<MaybeCoin, std::string>;
|
||||
|
||||
const static CoinEntry MISSING = CoinEntry{ABSENT, NO_ENTRY}; // TODO std::nullopt
|
||||
const static CoinEntry FAIL_NO_ENTRY = CoinEntry{FAIL, NO_ENTRY}; // TODO validate error messages
|
||||
constexpr MaybeCoin MISSING {std::nullopt};
|
||||
constexpr MaybeCoin SPENT_DIRTY {{SPENT, DIRTY}};
|
||||
constexpr MaybeCoin SPENT_DIRTY_FRESH {{SPENT, DIRTY | FRESH}};
|
||||
constexpr MaybeCoin SPENT_FRESH {{SPENT, FRESH}};
|
||||
constexpr MaybeCoin SPENT_CLEAN {{SPENT, CLEAN}};
|
||||
constexpr MaybeCoin VALUE1_DIRTY {{VALUE1, DIRTY}};
|
||||
constexpr MaybeCoin VALUE1_DIRTY_FRESH{{VALUE1, DIRTY | FRESH}};
|
||||
constexpr MaybeCoin VALUE1_FRESH {{VALUE1, FRESH}};
|
||||
constexpr MaybeCoin VALUE1_CLEAN {{VALUE1, CLEAN}};
|
||||
constexpr MaybeCoin VALUE2_DIRTY {{VALUE2, DIRTY}};
|
||||
constexpr MaybeCoin VALUE2_DIRTY_FRESH{{VALUE2, DIRTY | FRESH}};
|
||||
constexpr MaybeCoin VALUE2_FRESH {{VALUE2, FRESH}};
|
||||
constexpr MaybeCoin VALUE2_CLEAN {{VALUE2, CLEAN}};
|
||||
constexpr MaybeCoin VALUE3_DIRTY {{VALUE3, DIRTY}};
|
||||
constexpr MaybeCoin VALUE3_DIRTY_FRESH{{VALUE3, DIRTY | FRESH}};
|
||||
|
||||
const static CoinEntry SPENT_DIRTY = CoinEntry{SPENT, DIRTY};
|
||||
const static CoinEntry SPENT_DIRTY_FRESH = CoinEntry{SPENT, DIRTY | FRESH};
|
||||
const static CoinEntry SPENT_FRESH = CoinEntry{SPENT, FRESH};
|
||||
const static CoinEntry SPENT_CLEAN = CoinEntry{SPENT, CLEAN};
|
||||
const static CoinEntry VALUE1_DIRTY = CoinEntry{VALUE1, DIRTY};
|
||||
const static CoinEntry VALUE1_DIRTY_FRESH = CoinEntry{VALUE1, DIRTY | FRESH};
|
||||
const static CoinEntry VALUE1_FRESH = CoinEntry{VALUE1, FRESH};
|
||||
const static CoinEntry VALUE1_CLEAN = CoinEntry{VALUE1, CLEAN};
|
||||
const static CoinEntry VALUE2_DIRTY = CoinEntry{VALUE2, DIRTY};
|
||||
const static CoinEntry VALUE2_DIRTY_FRESH = CoinEntry{VALUE2, DIRTY | FRESH};
|
||||
const static CoinEntry VALUE2_FRESH = CoinEntry{VALUE2, FRESH};
|
||||
const static CoinEntry VALUE2_CLEAN = CoinEntry{VALUE2, CLEAN};
|
||||
const static CoinEntry VALUE3_DIRTY = CoinEntry{VALUE3, DIRTY};
|
||||
const static CoinEntry VALUE3_DIRTY_FRESH = CoinEntry{VALUE3, DIRTY | FRESH};
|
||||
constexpr auto EX_OVERWRITE_UNSPENT{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"};
|
||||
constexpr auto EX_FRESH_MISAPPLIED {"FRESH flag misapplied to coin that exists in parent cache"};
|
||||
|
||||
static void SetCoinsValue(const CAmount value, Coin& coin)
|
||||
{
|
||||
|
@ -615,18 +617,13 @@ static void SetCoinsValue(const CAmount value, Coin& coin)
|
|||
|
||||
static size_t InsertCoinsMapEntry(CCoinsMap& map, CoinsCachePair& sentinel, const CoinEntry& cache_coin)
|
||||
{
|
||||
if (cache_coin.value == ABSENT) {
|
||||
assert(cache_coin.flags == NO_ENTRY);
|
||||
return 0;
|
||||
}
|
||||
assert(cache_coin.flags != NO_ENTRY);
|
||||
CCoinsCacheEntry entry;
|
||||
SetCoinsValue(cache_coin.value, entry.coin);
|
||||
auto inserted = map.emplace(OUTPOINT, std::move(entry));
|
||||
assert(inserted.second);
|
||||
if (cache_coin.flags & DIRTY) CCoinsCacheEntry::SetDirty(*inserted.first, sentinel);
|
||||
if (cache_coin.flags & FRESH) CCoinsCacheEntry::SetFresh(*inserted.first, sentinel);
|
||||
return inserted.first->second.coin.DynamicMemoryUsage();
|
||||
auto [iter, inserted] = map.emplace(OUTPOINT, std::move(entry));
|
||||
assert(inserted);
|
||||
if (cache_coin.flags & DIRTY) CCoinsCacheEntry::SetDirty(*iter, sentinel);
|
||||
if (cache_coin.flags & FRESH) CCoinsCacheEntry::SetFresh(*iter, sentinel);
|
||||
return iter->second.coin.DynamicMemoryUsage();
|
||||
}
|
||||
|
||||
MaybeCoin GetCoinsMapEntry(const CCoinsMap& map, const COutPoint& outp = OUTPOINT)
|
||||
|
@ -639,13 +636,13 @@ MaybeCoin GetCoinsMapEntry(const CCoinsMap& map, const COutPoint& outp = OUTPOIN
|
|||
return MISSING;
|
||||
}
|
||||
|
||||
void WriteCoinsViewEntry(CCoinsView& view, const CoinEntry& cache_coin)
|
||||
void WriteCoinsViewEntry(CCoinsView& view, const MaybeCoin& cache_coin)
|
||||
{
|
||||
CoinsCachePair sentinel{};
|
||||
sentinel.second.SelfRef(sentinel);
|
||||
CCoinsMapMemoryResource resource;
|
||||
CCoinsMap map{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource};
|
||||
auto usage{InsertCoinsMapEntry(map, sentinel, cache_coin)};
|
||||
auto usage{cache_coin ? InsertCoinsMapEntry(map, sentinel, *cache_coin) : 0};
|
||||
auto cursor{CoinsViewCacheCursor(usage, sentinel, map, /*will_erase=*/true)};
|
||||
BOOST_CHECK(view.BatchWrite(cursor, {}));
|
||||
}
|
||||
|
@ -653,10 +650,11 @@ void WriteCoinsViewEntry(CCoinsView& view, const CoinEntry& cache_coin)
|
|||
class SingleEntryCacheTest
|
||||
{
|
||||
public:
|
||||
SingleEntryCacheTest(const CAmount base_value, const CoinEntry& cache_coin)
|
||||
SingleEntryCacheTest(const CAmount base_value, const MaybeCoin& cache_coin)
|
||||
{
|
||||
WriteCoinsViewEntry(base, CoinEntry{base_value, base_value == ABSENT ? NO_ENTRY : DIRTY}); // TODO complete state should be absent
|
||||
cache.usage() += InsertCoinsMapEntry(cache.map(), cache.sentinel(), cache_coin);
|
||||
auto base_cache_coin{base_value == ABSENT ? MISSING : CoinEntry{base_value, DIRTY}};
|
||||
WriteCoinsViewEntry(base, base_cache_coin);
|
||||
if (cache_coin) cache.usage() += InsertCoinsMapEntry(cache.map(), cache.sentinel(), *cache_coin);
|
||||
}
|
||||
|
||||
CCoinsView root;
|
||||
|
@ -664,7 +662,7 @@ public:
|
|||
CCoinsViewCacheTest cache{&base};
|
||||
};
|
||||
|
||||
static void CheckAccessCoin(const CAmount base_value, const CoinEntry& cache_coin, const CoinEntry& expected)
|
||||
static void CheckAccessCoin(const CAmount base_value, const MaybeCoin& cache_coin, const MaybeCoin& expected)
|
||||
{
|
||||
SingleEntryCacheTest test{base_value, cache_coin};
|
||||
test.cache.AccessCoin(OUTPOINT);
|
||||
|
@ -710,7 +708,7 @@ BOOST_AUTO_TEST_CASE(ccoins_access)
|
|||
CheckAccessCoin(VALUE1, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH);
|
||||
}
|
||||
|
||||
static void CheckSpendCoins(const CAmount base_value, const CoinEntry& cache_coin, const CoinEntry& expected)
|
||||
static void CheckSpendCoins(const CAmount base_value, const MaybeCoin& cache_coin, const MaybeCoin& expected)
|
||||
{
|
||||
SingleEntryCacheTest test{base_value, cache_coin};
|
||||
test.cache.SpendCoin(OUTPOINT);
|
||||
|
@ -756,17 +754,17 @@ BOOST_AUTO_TEST_CASE(ccoins_spend)
|
|||
CheckSpendCoins(VALUE1, VALUE2_DIRTY_FRESH, MISSING );
|
||||
}
|
||||
|
||||
static void CheckAddCoin(const CAmount base_value, const CoinEntry& cache_coin, const CAmount modify_value, const CoinEntry& expected, const bool coinbase)
|
||||
static void CheckAddCoin(const CAmount base_value, const MaybeCoin& cache_coin, const CAmount modify_value, const CoinOrError& expected, const bool coinbase)
|
||||
{
|
||||
SingleEntryCacheTest test{base_value, cache_coin};
|
||||
try {
|
||||
CTxOut output;
|
||||
output.nValue = modify_value;
|
||||
test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase), coinbase);
|
||||
bool possible_overwrite{coinbase};
|
||||
auto add_coin{[&] { test.cache.AddCoin(OUTPOINT, Coin{CTxOut{modify_value, CScript{}}, 1, coinbase}, possible_overwrite); }};
|
||||
if (auto* expected_coin{std::get_if<MaybeCoin>(&expected)}) {
|
||||
add_coin();
|
||||
test.cache.SelfTest();
|
||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), expected);
|
||||
} catch (std::logic_error&) {
|
||||
BOOST_CHECK_EQUAL(FAIL_NO_ENTRY, expected);
|
||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), *expected_coin);
|
||||
} else {
|
||||
BOOST_CHECK_EXCEPTION(add_coin(), std::logic_error, HasReason(std::get<std::string>(expected)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -776,41 +774,42 @@ BOOST_AUTO_TEST_CASE(ccoins_add)
|
|||
* writing a modification to the coin, and then checking the resulting
|
||||
* entry in the cache after the modification. Verify behavior with the
|
||||
* AddCoin coinbase argument set to false, and to true.
|
||||
* Base Cache Write Expected Coinbase
|
||||
* Base Cache Write Expected Coinbase
|
||||
*/
|
||||
for (auto base_value : {ABSENT, SPENT, VALUE1}) {
|
||||
CheckAddCoin(base_value, MISSING, VALUE3, VALUE3_DIRTY_FRESH, false);
|
||||
CheckAddCoin(base_value, MISSING, VALUE3, VALUE3_DIRTY, true );
|
||||
CheckAddCoin(base_value, MISSING, VALUE3, VALUE3_DIRTY_FRESH, false);
|
||||
CheckAddCoin(base_value, MISSING, VALUE3, VALUE3_DIRTY, true );
|
||||
|
||||
CheckAddCoin(base_value, SPENT_CLEAN, VALUE3, VALUE3_DIRTY_FRESH, false);
|
||||
CheckAddCoin(base_value, SPENT_CLEAN, VALUE3, VALUE3_DIRTY, true );
|
||||
CheckAddCoin(base_value, SPENT_FRESH, VALUE3, VALUE3_DIRTY_FRESH, false);
|
||||
CheckAddCoin(base_value, SPENT_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
||||
CheckAddCoin(base_value, SPENT_DIRTY, VALUE3, VALUE3_DIRTY, false);
|
||||
CheckAddCoin(base_value, SPENT_DIRTY, VALUE3, VALUE3_DIRTY, true );
|
||||
CheckAddCoin(base_value, SPENT_DIRTY_FRESH, VALUE3, VALUE3_DIRTY_FRESH, false);
|
||||
CheckAddCoin(base_value, SPENT_DIRTY_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
||||
CheckAddCoin(base_value, SPENT_CLEAN, VALUE3, VALUE3_DIRTY_FRESH, false);
|
||||
CheckAddCoin(base_value, SPENT_CLEAN, VALUE3, VALUE3_DIRTY, true );
|
||||
CheckAddCoin(base_value, SPENT_FRESH, VALUE3, VALUE3_DIRTY_FRESH, false);
|
||||
CheckAddCoin(base_value, SPENT_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
||||
CheckAddCoin(base_value, SPENT_DIRTY, VALUE3, VALUE3_DIRTY, false);
|
||||
CheckAddCoin(base_value, SPENT_DIRTY, VALUE3, VALUE3_DIRTY, true );
|
||||
CheckAddCoin(base_value, SPENT_DIRTY_FRESH, VALUE3, VALUE3_DIRTY_FRESH, false);
|
||||
CheckAddCoin(base_value, SPENT_DIRTY_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
||||
|
||||
CheckAddCoin(base_value, VALUE2_CLEAN, VALUE3, FAIL_NO_ENTRY, false);
|
||||
CheckAddCoin(base_value, VALUE2_CLEAN, VALUE3, VALUE3_DIRTY, true );
|
||||
CheckAddCoin(base_value, VALUE2_FRESH, VALUE3, FAIL_NO_ENTRY, false);
|
||||
CheckAddCoin(base_value, VALUE2_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
||||
CheckAddCoin(base_value, VALUE2_DIRTY, VALUE3, FAIL_NO_ENTRY, false);
|
||||
CheckAddCoin(base_value, VALUE2_DIRTY, VALUE3, VALUE3_DIRTY, true );
|
||||
CheckAddCoin(base_value, VALUE2_DIRTY_FRESH, VALUE3, FAIL_NO_ENTRY, false);
|
||||
CheckAddCoin(base_value, VALUE2_DIRTY_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
||||
CheckAddCoin(base_value, VALUE2_CLEAN, VALUE3, EX_OVERWRITE_UNSPENT, false);
|
||||
CheckAddCoin(base_value, VALUE2_CLEAN, VALUE3, VALUE3_DIRTY, true );
|
||||
CheckAddCoin(base_value, VALUE2_FRESH, VALUE3, EX_OVERWRITE_UNSPENT, false);
|
||||
CheckAddCoin(base_value, VALUE2_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
||||
CheckAddCoin(base_value, VALUE2_DIRTY, VALUE3, EX_OVERWRITE_UNSPENT, false);
|
||||
CheckAddCoin(base_value, VALUE2_DIRTY, VALUE3, VALUE3_DIRTY, true );
|
||||
CheckAddCoin(base_value, VALUE2_DIRTY_FRESH, VALUE3, EX_OVERWRITE_UNSPENT, false);
|
||||
CheckAddCoin(base_value, VALUE2_DIRTY_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
||||
}
|
||||
}
|
||||
|
||||
void CheckWriteCoins(const CoinEntry& parent, const CoinEntry& child, const CoinEntry& expected)
|
||||
void CheckWriteCoins(const MaybeCoin& parent, const MaybeCoin& child, const CoinOrError& expected)
|
||||
{
|
||||
SingleEntryCacheTest test{ABSENT, parent};
|
||||
try {
|
||||
WriteCoinsViewEntry(test.cache, child);
|
||||
auto write_coins{[&] { WriteCoinsViewEntry(test.cache, child); }};
|
||||
if (auto* expected_coin{std::get_if<MaybeCoin>(&expected)}) {
|
||||
write_coins();
|
||||
test.cache.SelfTest(/*sanity_check=*/false);
|
||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), expected);
|
||||
} catch (std::logic_error&) {
|
||||
BOOST_CHECK_EQUAL(FAIL_NO_ENTRY, expected);
|
||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), *expected_coin);
|
||||
} else {
|
||||
BOOST_CHECK_EXCEPTION(write_coins(), std::logic_error, HasReason(std::get<std::string>(expected)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -821,67 +820,67 @@ BOOST_AUTO_TEST_CASE(ccoins_write)
|
|||
* after the write.
|
||||
* Parent Child Expected
|
||||
*/
|
||||
CheckWriteCoins(MISSING, MISSING, MISSING );
|
||||
CheckWriteCoins(MISSING, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(MISSING, SPENT_DIRTY_FRESH, MISSING );
|
||||
CheckWriteCoins(MISSING, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(MISSING, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH);
|
||||
CheckWriteCoins(SPENT_CLEAN, MISSING, SPENT_CLEAN );
|
||||
CheckWriteCoins(SPENT_FRESH, MISSING, SPENT_FRESH );
|
||||
CheckWriteCoins(SPENT_DIRTY, MISSING, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, MISSING, SPENT_DIRTY_FRESH );
|
||||
CheckWriteCoins(MISSING, MISSING, MISSING );
|
||||
CheckWriteCoins(MISSING, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(MISSING, SPENT_DIRTY_FRESH, MISSING );
|
||||
CheckWriteCoins(MISSING, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(MISSING, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH );
|
||||
CheckWriteCoins(SPENT_CLEAN, MISSING, SPENT_CLEAN );
|
||||
CheckWriteCoins(SPENT_FRESH, MISSING, SPENT_FRESH );
|
||||
CheckWriteCoins(SPENT_DIRTY, MISSING, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, MISSING, SPENT_DIRTY_FRESH );
|
||||
|
||||
CheckWriteCoins(SPENT_CLEAN, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_CLEAN, SPENT_DIRTY_FRESH, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_FRESH, SPENT_DIRTY, MISSING );
|
||||
CheckWriteCoins(SPENT_FRESH, SPENT_DIRTY_FRESH, MISSING );
|
||||
CheckWriteCoins(SPENT_DIRTY, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY, SPENT_DIRTY_FRESH, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, SPENT_DIRTY, MISSING );
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, SPENT_DIRTY_FRESH, MISSING );
|
||||
CheckWriteCoins(SPENT_CLEAN, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_CLEAN, SPENT_DIRTY_FRESH, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_FRESH, SPENT_DIRTY, MISSING );
|
||||
CheckWriteCoins(SPENT_FRESH, SPENT_DIRTY_FRESH, MISSING );
|
||||
CheckWriteCoins(SPENT_DIRTY, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY, SPENT_DIRTY_FRESH, SPENT_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, SPENT_DIRTY, MISSING );
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, SPENT_DIRTY_FRESH, MISSING );
|
||||
|
||||
CheckWriteCoins(SPENT_CLEAN, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(SPENT_CLEAN, VALUE2_DIRTY_FRESH, VALUE2_DIRTY );
|
||||
CheckWriteCoins(SPENT_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH);
|
||||
CheckWriteCoins(SPENT_FRESH, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH);
|
||||
CheckWriteCoins(SPENT_DIRTY, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY, VALUE2_DIRTY_FRESH, VALUE2_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH);
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH);
|
||||
CheckWriteCoins(SPENT_CLEAN, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(SPENT_CLEAN, VALUE2_DIRTY_FRESH, VALUE2_DIRTY );
|
||||
CheckWriteCoins(SPENT_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH );
|
||||
CheckWriteCoins(SPENT_FRESH, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH );
|
||||
CheckWriteCoins(SPENT_DIRTY, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY, VALUE2_DIRTY_FRESH, VALUE2_DIRTY );
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH );
|
||||
CheckWriteCoins(SPENT_DIRTY_FRESH, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH );
|
||||
|
||||
CheckWriteCoins(VALUE1_CLEAN, MISSING, VALUE1_CLEAN );
|
||||
CheckWriteCoins(VALUE1_FRESH, MISSING, VALUE1_FRESH );
|
||||
CheckWriteCoins(VALUE1_DIRTY, MISSING, VALUE1_DIRTY );
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, MISSING, VALUE1_DIRTY_FRESH);
|
||||
CheckWriteCoins(VALUE1_CLEAN, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(VALUE1_CLEAN, SPENT_DIRTY_FRESH, FAIL_NO_ENTRY );
|
||||
CheckWriteCoins(VALUE1_FRESH, SPENT_DIRTY, MISSING );
|
||||
CheckWriteCoins(VALUE1_FRESH, SPENT_DIRTY_FRESH, FAIL_NO_ENTRY );
|
||||
CheckWriteCoins(VALUE1_DIRTY, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(VALUE1_DIRTY, SPENT_DIRTY_FRESH, FAIL_NO_ENTRY );
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, SPENT_DIRTY, MISSING );
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, SPENT_DIRTY_FRESH, FAIL_NO_ENTRY );
|
||||
CheckWriteCoins(VALUE1_CLEAN, MISSING, VALUE1_CLEAN );
|
||||
CheckWriteCoins(VALUE1_FRESH, MISSING, VALUE1_FRESH );
|
||||
CheckWriteCoins(VALUE1_DIRTY, MISSING, VALUE1_DIRTY );
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, MISSING, VALUE1_DIRTY_FRESH );
|
||||
CheckWriteCoins(VALUE1_CLEAN, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(VALUE1_CLEAN, SPENT_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||
CheckWriteCoins(VALUE1_FRESH, SPENT_DIRTY, MISSING );
|
||||
CheckWriteCoins(VALUE1_FRESH, SPENT_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||
CheckWriteCoins(VALUE1_DIRTY, SPENT_DIRTY, SPENT_DIRTY );
|
||||
CheckWriteCoins(VALUE1_DIRTY, SPENT_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, SPENT_DIRTY, MISSING );
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, SPENT_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||
|
||||
CheckWriteCoins(VALUE1_CLEAN, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(VALUE1_CLEAN, VALUE2_DIRTY_FRESH, FAIL_NO_ENTRY );
|
||||
CheckWriteCoins(VALUE1_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH);
|
||||
CheckWriteCoins(VALUE1_FRESH, VALUE2_DIRTY_FRESH, FAIL_NO_ENTRY );
|
||||
CheckWriteCoins(VALUE1_DIRTY, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(VALUE1_DIRTY, VALUE2_DIRTY_FRESH, FAIL_NO_ENTRY );
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH);
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY_FRESH, FAIL_NO_ENTRY );
|
||||
CheckWriteCoins(VALUE1_CLEAN, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(VALUE1_CLEAN, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||
CheckWriteCoins(VALUE1_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH );
|
||||
CheckWriteCoins(VALUE1_FRESH, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||
CheckWriteCoins(VALUE1_DIRTY, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||
CheckWriteCoins(VALUE1_DIRTY, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH );
|
||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||
|
||||
// The checks above omit cases where the child flags are not DIRTY, since
|
||||
// they would be too repetitive (the parent cache is never updated in these
|
||||
// cases). The loop below covers these cases and makes sure the parent cache
|
||||
// is always left unchanged.
|
||||
for (const CoinEntry parent : {MISSING,
|
||||
SPENT_CLEAN, SPENT_DIRTY, SPENT_FRESH, SPENT_DIRTY_FRESH,
|
||||
VALUE1_CLEAN, VALUE1_DIRTY, VALUE1_FRESH, VALUE1_DIRTY_FRESH}) {
|
||||
for (const CoinEntry child : {MISSING,
|
||||
SPENT_CLEAN, SPENT_FRESH,
|
||||
VALUE2_CLEAN, VALUE2_FRESH}) {
|
||||
auto expected{parent}; // TODO test failure cases as well
|
||||
for (const MaybeCoin& parent : {MISSING,
|
||||
SPENT_CLEAN, SPENT_DIRTY, SPENT_FRESH, SPENT_DIRTY_FRESH,
|
||||
VALUE1_CLEAN, VALUE1_DIRTY, VALUE1_FRESH, VALUE1_DIRTY_FRESH}) {
|
||||
for (const MaybeCoin& child : {MISSING,
|
||||
SPENT_CLEAN, SPENT_FRESH,
|
||||
VALUE2_CLEAN, VALUE2_FRESH}) {
|
||||
auto expected{CoinOrError{parent}}; // TODO test failure cases as well
|
||||
CheckWriteCoins(parent, child, expected);
|
||||
}
|
||||
}
|
||||
|
@ -977,7 +976,7 @@ void TestFlushBehavior(
|
|||
|
||||
// --- 5. Ensuring the entry is no longer in the cache
|
||||
//
|
||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), MISSING);
|
||||
BOOST_CHECK(!GetCoinsMapEntry(view->map(), outp));
|
||||
view->AccessCoin(outp);
|
||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, CLEAN));
|
||||
}
|
||||
|
@ -1052,7 +1051,7 @@ void TestFlushBehavior(
|
|||
all_caches[0]->Sync();
|
||||
|
||||
// Ensure there is no sign of the coin after spend/flush.
|
||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(all_caches[0]->map(), outp), MISSING);
|
||||
BOOST_CHECK(!GetCoinsMapEntry(all_caches[0]->map(), outp));
|
||||
BOOST_CHECK(!all_caches[0]->HaveCoinInCache(outp));
|
||||
BOOST_CHECK(!base.HaveCoin(outp));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue