mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04: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 <util/strencodings.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
@ -559,17 +561,15 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
|
||||||
}
|
}
|
||||||
|
|
||||||
const static COutPoint OUTPOINT;
|
const static COutPoint OUTPOINT;
|
||||||
const static CAmount SPENT = -1;
|
constexpr CAmount SPENT {-1};
|
||||||
const static CAmount ABSENT = -2;
|
constexpr CAmount ABSENT{-2};
|
||||||
const static CAmount FAIL = -3;
|
constexpr CAmount VALUE1{100};
|
||||||
const static CAmount VALUE1 = 100;
|
constexpr CAmount VALUE2{200};
|
||||||
const static CAmount VALUE2 = 200;
|
constexpr CAmount VALUE3{300};
|
||||||
const static CAmount VALUE3 = 300;
|
|
||||||
|
|
||||||
const static char DIRTY = CCoinsCacheEntry::DIRTY;
|
constexpr char DIRTY{CCoinsCacheEntry::DIRTY};
|
||||||
const static char FRESH = CCoinsCacheEntry::FRESH;
|
constexpr char FRESH{CCoinsCacheEntry::FRESH};
|
||||||
const static char CLEAN = 0;
|
constexpr char CLEAN{0};
|
||||||
const static char NO_ENTRY = -1;
|
|
||||||
|
|
||||||
struct CoinEntry {
|
struct CoinEntry {
|
||||||
const CAmount value;
|
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; }
|
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
|
constexpr MaybeCoin MISSING {std::nullopt};
|
||||||
const static CoinEntry FAIL_NO_ENTRY = CoinEntry{FAIL, NO_ENTRY}; // TODO validate error messages
|
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};
|
constexpr auto EX_OVERWRITE_UNSPENT{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"};
|
||||||
const static CoinEntry SPENT_DIRTY_FRESH = CoinEntry{SPENT, DIRTY | FRESH};
|
constexpr auto EX_FRESH_MISAPPLIED {"FRESH flag misapplied to coin that exists in parent cache"};
|
||||||
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};
|
|
||||||
|
|
||||||
static void SetCoinsValue(const CAmount value, Coin& coin)
|
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)
|
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;
|
CCoinsCacheEntry entry;
|
||||||
SetCoinsValue(cache_coin.value, entry.coin);
|
SetCoinsValue(cache_coin.value, entry.coin);
|
||||||
auto inserted = map.emplace(OUTPOINT, std::move(entry));
|
auto [iter, inserted] = map.emplace(OUTPOINT, std::move(entry));
|
||||||
assert(inserted.second);
|
assert(inserted);
|
||||||
if (cache_coin.flags & DIRTY) CCoinsCacheEntry::SetDirty(*inserted.first, sentinel);
|
if (cache_coin.flags & DIRTY) CCoinsCacheEntry::SetDirty(*iter, sentinel);
|
||||||
if (cache_coin.flags & FRESH) CCoinsCacheEntry::SetFresh(*inserted.first, sentinel);
|
if (cache_coin.flags & FRESH) CCoinsCacheEntry::SetFresh(*iter, sentinel);
|
||||||
return inserted.first->second.coin.DynamicMemoryUsage();
|
return iter->second.coin.DynamicMemoryUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeCoin GetCoinsMapEntry(const CCoinsMap& map, const COutPoint& outp = OUTPOINT)
|
MaybeCoin GetCoinsMapEntry(const CCoinsMap& map, const COutPoint& outp = OUTPOINT)
|
||||||
|
@ -639,13 +636,13 @@ MaybeCoin GetCoinsMapEntry(const CCoinsMap& map, const COutPoint& outp = OUTPOIN
|
||||||
return MISSING;
|
return MISSING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteCoinsViewEntry(CCoinsView& view, const CoinEntry& cache_coin)
|
void WriteCoinsViewEntry(CCoinsView& view, const MaybeCoin& cache_coin)
|
||||||
{
|
{
|
||||||
CoinsCachePair sentinel{};
|
CoinsCachePair sentinel{};
|
||||||
sentinel.second.SelfRef(sentinel);
|
sentinel.second.SelfRef(sentinel);
|
||||||
CCoinsMapMemoryResource resource;
|
CCoinsMapMemoryResource resource;
|
||||||
CCoinsMap map{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &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)};
|
auto cursor{CoinsViewCacheCursor(usage, sentinel, map, /*will_erase=*/true)};
|
||||||
BOOST_CHECK(view.BatchWrite(cursor, {}));
|
BOOST_CHECK(view.BatchWrite(cursor, {}));
|
||||||
}
|
}
|
||||||
|
@ -653,10 +650,11 @@ void WriteCoinsViewEntry(CCoinsView& view, const CoinEntry& cache_coin)
|
||||||
class SingleEntryCacheTest
|
class SingleEntryCacheTest
|
||||||
{
|
{
|
||||||
public:
|
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
|
auto base_cache_coin{base_value == ABSENT ? MISSING : CoinEntry{base_value, DIRTY}};
|
||||||
cache.usage() += InsertCoinsMapEntry(cache.map(), cache.sentinel(), cache_coin);
|
WriteCoinsViewEntry(base, base_cache_coin);
|
||||||
|
if (cache_coin) cache.usage() += InsertCoinsMapEntry(cache.map(), cache.sentinel(), *cache_coin);
|
||||||
}
|
}
|
||||||
|
|
||||||
CCoinsView root;
|
CCoinsView root;
|
||||||
|
@ -664,7 +662,7 @@ public:
|
||||||
CCoinsViewCacheTest cache{&base};
|
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};
|
SingleEntryCacheTest test{base_value, cache_coin};
|
||||||
test.cache.AccessCoin(OUTPOINT);
|
test.cache.AccessCoin(OUTPOINT);
|
||||||
|
@ -710,7 +708,7 @@ BOOST_AUTO_TEST_CASE(ccoins_access)
|
||||||
CheckAccessCoin(VALUE1, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH);
|
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};
|
SingleEntryCacheTest test{base_value, cache_coin};
|
||||||
test.cache.SpendCoin(OUTPOINT);
|
test.cache.SpendCoin(OUTPOINT);
|
||||||
|
@ -756,17 +754,17 @@ BOOST_AUTO_TEST_CASE(ccoins_spend)
|
||||||
CheckSpendCoins(VALUE1, VALUE2_DIRTY_FRESH, MISSING );
|
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};
|
SingleEntryCacheTest test{base_value, cache_coin};
|
||||||
try {
|
bool possible_overwrite{coinbase};
|
||||||
CTxOut output;
|
auto add_coin{[&] { test.cache.AddCoin(OUTPOINT, Coin{CTxOut{modify_value, CScript{}}, 1, coinbase}, possible_overwrite); }};
|
||||||
output.nValue = modify_value;
|
if (auto* expected_coin{std::get_if<MaybeCoin>(&expected)}) {
|
||||||
test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase), coinbase);
|
add_coin();
|
||||||
test.cache.SelfTest();
|
test.cache.SelfTest();
|
||||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), expected);
|
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), *expected_coin);
|
||||||
} catch (std::logic_error&) {
|
} else {
|
||||||
BOOST_CHECK_EQUAL(FAIL_NO_ENTRY, expected);
|
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
|
* writing a modification to the coin, and then checking the resulting
|
||||||
* entry in the cache after the modification. Verify behavior with the
|
* entry in the cache after the modification. Verify behavior with the
|
||||||
* AddCoin coinbase argument set to false, and to true.
|
* 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}) {
|
for (auto base_value : {ABSENT, SPENT, VALUE1}) {
|
||||||
CheckAddCoin(base_value, MISSING, VALUE3, VALUE3_DIRTY_FRESH, false);
|
CheckAddCoin(base_value, MISSING, VALUE3, VALUE3_DIRTY_FRESH, false);
|
||||||
CheckAddCoin(base_value, MISSING, VALUE3, VALUE3_DIRTY, true );
|
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_FRESH, false);
|
||||||
CheckAddCoin(base_value, SPENT_CLEAN, VALUE3, VALUE3_DIRTY, true );
|
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, false);
|
||||||
CheckAddCoin(base_value, SPENT_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
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, false);
|
||||||
CheckAddCoin(base_value, SPENT_DIRTY, VALUE3, VALUE3_DIRTY, true );
|
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, false);
|
||||||
CheckAddCoin(base_value, SPENT_DIRTY_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
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, EX_OVERWRITE_UNSPENT, false);
|
||||||
CheckAddCoin(base_value, VALUE2_CLEAN, VALUE3, VALUE3_DIRTY, true );
|
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, EX_OVERWRITE_UNSPENT, false);
|
||||||
CheckAddCoin(base_value, VALUE2_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
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, EX_OVERWRITE_UNSPENT, false);
|
||||||
CheckAddCoin(base_value, VALUE2_DIRTY, VALUE3, VALUE3_DIRTY, true );
|
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, EX_OVERWRITE_UNSPENT, false);
|
||||||
CheckAddCoin(base_value, VALUE2_DIRTY_FRESH, VALUE3, VALUE3_DIRTY_FRESH, true );
|
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};
|
SingleEntryCacheTest test{ABSENT, parent};
|
||||||
try {
|
auto write_coins{[&] { WriteCoinsViewEntry(test.cache, child); }};
|
||||||
WriteCoinsViewEntry(test.cache, child);
|
if (auto* expected_coin{std::get_if<MaybeCoin>(&expected)}) {
|
||||||
|
write_coins();
|
||||||
test.cache.SelfTest(/*sanity_check=*/false);
|
test.cache.SelfTest(/*sanity_check=*/false);
|
||||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), expected);
|
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), *expected_coin);
|
||||||
} catch (std::logic_error&) {
|
} else {
|
||||||
BOOST_CHECK_EQUAL(FAIL_NO_ENTRY, expected);
|
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.
|
* after the write.
|
||||||
* Parent Child Expected
|
* Parent Child Expected
|
||||||
*/
|
*/
|
||||||
CheckWriteCoins(MISSING, MISSING, MISSING );
|
CheckWriteCoins(MISSING, MISSING, MISSING );
|
||||||
CheckWriteCoins(MISSING, SPENT_DIRTY, SPENT_DIRTY );
|
CheckWriteCoins(MISSING, SPENT_DIRTY, SPENT_DIRTY );
|
||||||
CheckWriteCoins(MISSING, SPENT_DIRTY_FRESH, MISSING );
|
CheckWriteCoins(MISSING, SPENT_DIRTY_FRESH, MISSING );
|
||||||
CheckWriteCoins(MISSING, VALUE2_DIRTY, VALUE2_DIRTY );
|
CheckWriteCoins(MISSING, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||||
CheckWriteCoins(MISSING, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH);
|
CheckWriteCoins(MISSING, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH );
|
||||||
CheckWriteCoins(SPENT_CLEAN, MISSING, SPENT_CLEAN );
|
CheckWriteCoins(SPENT_CLEAN, MISSING, SPENT_CLEAN );
|
||||||
CheckWriteCoins(SPENT_FRESH, MISSING, SPENT_FRESH );
|
CheckWriteCoins(SPENT_FRESH, MISSING, SPENT_FRESH );
|
||||||
CheckWriteCoins(SPENT_DIRTY, MISSING, SPENT_DIRTY );
|
CheckWriteCoins(SPENT_DIRTY, MISSING, SPENT_DIRTY );
|
||||||
CheckWriteCoins(SPENT_DIRTY_FRESH, MISSING, SPENT_DIRTY_FRESH );
|
CheckWriteCoins(SPENT_DIRTY_FRESH, MISSING, SPENT_DIRTY_FRESH );
|
||||||
|
|
||||||
CheckWriteCoins(SPENT_CLEAN, SPENT_DIRTY, SPENT_DIRTY );
|
CheckWriteCoins(SPENT_CLEAN, SPENT_DIRTY, SPENT_DIRTY );
|
||||||
CheckWriteCoins(SPENT_CLEAN, SPENT_DIRTY_FRESH, SPENT_DIRTY );
|
CheckWriteCoins(SPENT_CLEAN, SPENT_DIRTY_FRESH, SPENT_DIRTY );
|
||||||
CheckWriteCoins(SPENT_FRESH, SPENT_DIRTY, MISSING );
|
CheckWriteCoins(SPENT_FRESH, SPENT_DIRTY, MISSING );
|
||||||
CheckWriteCoins(SPENT_FRESH, SPENT_DIRTY_FRESH, MISSING );
|
CheckWriteCoins(SPENT_FRESH, SPENT_DIRTY_FRESH, MISSING );
|
||||||
CheckWriteCoins(SPENT_DIRTY, SPENT_DIRTY, SPENT_DIRTY );
|
CheckWriteCoins(SPENT_DIRTY, SPENT_DIRTY, SPENT_DIRTY );
|
||||||
CheckWriteCoins(SPENT_DIRTY, SPENT_DIRTY_FRESH, SPENT_DIRTY );
|
CheckWriteCoins(SPENT_DIRTY, SPENT_DIRTY_FRESH, SPENT_DIRTY );
|
||||||
CheckWriteCoins(SPENT_DIRTY_FRESH, SPENT_DIRTY, MISSING );
|
CheckWriteCoins(SPENT_DIRTY_FRESH, SPENT_DIRTY, MISSING );
|
||||||
CheckWriteCoins(SPENT_DIRTY_FRESH, SPENT_DIRTY_FRESH, MISSING );
|
CheckWriteCoins(SPENT_DIRTY_FRESH, SPENT_DIRTY_FRESH, MISSING );
|
||||||
|
|
||||||
CheckWriteCoins(SPENT_CLEAN, VALUE2_DIRTY, VALUE2_DIRTY );
|
CheckWriteCoins(SPENT_CLEAN, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||||
CheckWriteCoins(SPENT_CLEAN, VALUE2_DIRTY_FRESH, VALUE2_DIRTY );
|
CheckWriteCoins(SPENT_CLEAN, VALUE2_DIRTY_FRESH, VALUE2_DIRTY );
|
||||||
CheckWriteCoins(SPENT_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH);
|
CheckWriteCoins(SPENT_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH );
|
||||||
CheckWriteCoins(SPENT_FRESH, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH);
|
CheckWriteCoins(SPENT_FRESH, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH );
|
||||||
CheckWriteCoins(SPENT_DIRTY, VALUE2_DIRTY, VALUE2_DIRTY );
|
CheckWriteCoins(SPENT_DIRTY, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||||
CheckWriteCoins(SPENT_DIRTY, VALUE2_DIRTY_FRESH, 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, VALUE2_DIRTY_FRESH );
|
||||||
CheckWriteCoins(SPENT_DIRTY_FRESH, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH);
|
CheckWriteCoins(SPENT_DIRTY_FRESH, VALUE2_DIRTY_FRESH, VALUE2_DIRTY_FRESH );
|
||||||
|
|
||||||
CheckWriteCoins(VALUE1_CLEAN, MISSING, VALUE1_CLEAN );
|
CheckWriteCoins(VALUE1_CLEAN, MISSING, VALUE1_CLEAN );
|
||||||
CheckWriteCoins(VALUE1_FRESH, MISSING, VALUE1_FRESH );
|
CheckWriteCoins(VALUE1_FRESH, MISSING, VALUE1_FRESH );
|
||||||
CheckWriteCoins(VALUE1_DIRTY, MISSING, VALUE1_DIRTY );
|
CheckWriteCoins(VALUE1_DIRTY, MISSING, VALUE1_DIRTY );
|
||||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, MISSING, VALUE1_DIRTY_FRESH);
|
CheckWriteCoins(VALUE1_DIRTY_FRESH, MISSING, VALUE1_DIRTY_FRESH );
|
||||||
CheckWriteCoins(VALUE1_CLEAN, SPENT_DIRTY, SPENT_DIRTY );
|
CheckWriteCoins(VALUE1_CLEAN, SPENT_DIRTY, SPENT_DIRTY );
|
||||||
CheckWriteCoins(VALUE1_CLEAN, SPENT_DIRTY_FRESH, FAIL_NO_ENTRY );
|
CheckWriteCoins(VALUE1_CLEAN, SPENT_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||||
CheckWriteCoins(VALUE1_FRESH, SPENT_DIRTY, MISSING );
|
CheckWriteCoins(VALUE1_FRESH, SPENT_DIRTY, MISSING );
|
||||||
CheckWriteCoins(VALUE1_FRESH, SPENT_DIRTY_FRESH, FAIL_NO_ENTRY );
|
CheckWriteCoins(VALUE1_FRESH, SPENT_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||||
CheckWriteCoins(VALUE1_DIRTY, SPENT_DIRTY, SPENT_DIRTY );
|
CheckWriteCoins(VALUE1_DIRTY, SPENT_DIRTY, SPENT_DIRTY );
|
||||||
CheckWriteCoins(VALUE1_DIRTY, SPENT_DIRTY_FRESH, FAIL_NO_ENTRY );
|
CheckWriteCoins(VALUE1_DIRTY, SPENT_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, SPENT_DIRTY, MISSING );
|
CheckWriteCoins(VALUE1_DIRTY_FRESH, SPENT_DIRTY, MISSING );
|
||||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, SPENT_DIRTY_FRESH, FAIL_NO_ENTRY );
|
CheckWriteCoins(VALUE1_DIRTY_FRESH, SPENT_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||||
|
|
||||||
CheckWriteCoins(VALUE1_CLEAN, VALUE2_DIRTY, VALUE2_DIRTY );
|
CheckWriteCoins(VALUE1_CLEAN, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||||
CheckWriteCoins(VALUE1_CLEAN, VALUE2_DIRTY_FRESH, FAIL_NO_ENTRY );
|
CheckWriteCoins(VALUE1_CLEAN, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||||
CheckWriteCoins(VALUE1_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH);
|
CheckWriteCoins(VALUE1_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH );
|
||||||
CheckWriteCoins(VALUE1_FRESH, VALUE2_DIRTY_FRESH, FAIL_NO_ENTRY );
|
CheckWriteCoins(VALUE1_FRESH, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||||
CheckWriteCoins(VALUE1_DIRTY, VALUE2_DIRTY, VALUE2_DIRTY );
|
CheckWriteCoins(VALUE1_DIRTY, VALUE2_DIRTY, VALUE2_DIRTY );
|
||||||
CheckWriteCoins(VALUE1_DIRTY, VALUE2_DIRTY_FRESH, FAIL_NO_ENTRY );
|
CheckWriteCoins(VALUE1_DIRTY, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH);
|
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH );
|
||||||
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY_FRESH, FAIL_NO_ENTRY );
|
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
|
||||||
|
|
||||||
// The checks above omit cases where the child flags are not DIRTY, since
|
// 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
|
// 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
|
// cases). The loop below covers these cases and makes sure the parent cache
|
||||||
// is always left unchanged.
|
// is always left unchanged.
|
||||||
for (const CoinEntry parent : {MISSING,
|
for (const MaybeCoin& parent : {MISSING,
|
||||||
SPENT_CLEAN, SPENT_DIRTY, SPENT_FRESH, SPENT_DIRTY_FRESH,
|
SPENT_CLEAN, SPENT_DIRTY, SPENT_FRESH, SPENT_DIRTY_FRESH,
|
||||||
VALUE1_CLEAN, VALUE1_DIRTY, VALUE1_FRESH, VALUE1_DIRTY_FRESH}) {
|
VALUE1_CLEAN, VALUE1_DIRTY, VALUE1_FRESH, VALUE1_DIRTY_FRESH}) {
|
||||||
for (const CoinEntry child : {MISSING,
|
for (const MaybeCoin& child : {MISSING,
|
||||||
SPENT_CLEAN, SPENT_FRESH,
|
SPENT_CLEAN, SPENT_FRESH,
|
||||||
VALUE2_CLEAN, VALUE2_FRESH}) {
|
VALUE2_CLEAN, VALUE2_FRESH}) {
|
||||||
auto expected{parent}; // TODO test failure cases as well
|
auto expected{CoinOrError{parent}}; // TODO test failure cases as well
|
||||||
CheckWriteCoins(parent, child, expected);
|
CheckWriteCoins(parent, child, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -977,7 +976,7 @@ void TestFlushBehavior(
|
||||||
|
|
||||||
// --- 5. Ensuring the entry is no longer in the cache
|
// --- 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);
|
view->AccessCoin(outp);
|
||||||
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, CLEAN));
|
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, CLEAN));
|
||||||
}
|
}
|
||||||
|
@ -1052,7 +1051,7 @@ void TestFlushBehavior(
|
||||||
all_caches[0]->Sync();
|
all_caches[0]->Sync();
|
||||||
|
|
||||||
// Ensure there is no sign of the coin after spend/flush.
|
// 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(!all_caches[0]->HaveCoinInCache(outp));
|
||||||
BOOST_CHECK(!base.HaveCoin(outp));
|
BOOST_CHECK(!base.HaveCoin(outp));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue