Repository: bitcoin/bitcoin
File: src/test/coins_tests.cpp (C++)

Code before:
    char flags;
    uint256 txid;
    COutPoint outp;
    Coin coin;
    size_t cache_usage;

    auto flush_all = [&all_caches](bool erase) {
        // Flush in reverse order to ensure that flushes happen from children up.
        for (auto i = all_caches.rbegin(); i != all_caches.rend(); ++i) {
            auto cache = *i;
            cache->SetBestBlock(InsecureRand256());  // Hack to allow flushing.
            erase ? cache->Flush() : cache->Sync();
        }
    };

    txid = InsecureRand256();
    outp = COutPoint(txid, 0);
    coin = MakeCoin();
    // Ensure the coins views haven't seen this coin before.
    BOOST_CHECK(!base.HaveCoin(outp));
    BOOST_CHECK(!view->HaveCoin(outp));

    // --- 1. Adding a random coin to the child cache
    //
    Coin tmpCoin{coin};
    view->AddCoin(outp, std::move(tmpCoin), false);

    cache_usage = view->DynamicMemoryUsage();
    // `base` shouldn't have coin (no flush yet) but `view` should have cached it.
    BOOST_CHECK(!base.HaveCoin(outp));
    BOOST_CHECK(view->HaveCoin(outp));

    GetCoinsMapEntry(view->map(), value, flags, outp);
    BOOST_CHECK_EQUAL(value, coin.out.nValue);
    BOOST_CHECK_EQUAL(flags, DIRTY|FRESH);

    // --- 2. Flushing all caches (without erasing)
    //
    flush_all(/*erase*/ false);

    // CoinsMap usage should be unchanged since we didn't erase anything.
    BOOST_CHECK_EQUAL(cache_usage, view->DynamicMemoryUsage());

    // --- 3. Ensuring the entry still exists in the cache and has been written to parent
    //
    GetCoinsMapEntry(view->map(), value, flags, outp);
    BOOST_CHECK_EQUAL(value, coin.out.nValue);
    BOOST_CHECK_EQUAL(flags, 0);  // Flags should have been wiped.

    // Both views should now have the coin.
    BOOST_CHECK(base.HaveCoin(outp));

Review comment (refactor):
nit: I like the naming destinction between `Sync()` and `Flush()` in the code because it made it easier to parse and that naming could have been used more here in the test as well. Now the destinction it is kind of hidden behind this `do_erasing_flush` parameter.  There could have been a `sync_all` helper method for example. But it's probably not worth the effort of changing now.

Code after:
//!
//! 1. Adding a random coin to the child-most cache,
//! 2. Flushing all caches (without erasing),
//! 3. Ensure the entry still exists in the cache and has been written to parent,
//! 4. (if `do_erasing_flush`) Flushing the caches again (with erasing),
//! 5. (if `do_erasing_flush`) Ensure the entry has been written to the parent and is no longer in the cache,
//! 6. Spend the coin, ensure it no longer exists in the parent.
//!
void TestFlushBehavior(
    CCoinsViewCacheTest* view,
    CCoinsViewDB& base,
    std::vector<CCoinsViewCacheTest*>& all_caches,
    bool do_erasing_flush)
{
    CAmount value;
    char flags;
    size_t cache_usage;

    auto flush_all = [&all_caches](bool erase) {
        // Flush in reverse order to ensure that flushes happen from children up.
        for (auto i = all_caches.rbegin(); i != all_caches.rend(); ++i) {
            auto cache = *i;
            // hashBlock must be filled before flushing to disk; value is
            // unimportant here. This is normally done during connect/disconnect block.
            cache->SetBestBlock(InsecureRand256());
            erase ? cache->Flush() : cache->Sync();
        }
    };

    uint256 txid = InsecureRand256();
    COutPoint outp = COutPoint(txid, 0);
    Coin coin = MakeCoin();
    // Ensure the coins views haven't seen this coin before.
    BOOST_CHECK(!base.HaveCoin(outp));
    BOOST_CHECK(!view->HaveCoin(outp));

    // --- 1. Adding a random coin to the child cache
    //
    view->AddCoin(outp, Coin(coin), false);

    cache_usage = view->DynamicMemoryUsage();
    // `base` shouldn't have coin (no flush yet) but `view` should have cached it.
    BOOST_CHECK(!base.HaveCoin(outp));
    BOOST_CHECK(view->HaveCoin(outp));

    GetCoinsMapEntry(view->map(), value, flags, outp);
    BOOST_CHECK_EQUAL(value, coin.out.nValue);
    BOOST_CHECK_EQUAL(flags, DIRTY|FRESH);

    // --- 2. Flushing all caches (without erasing)
    //