LCOV - code coverage report
Current view: top level - src/test - coinscachepair_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 99.2 % 129 128
Test Date: 2026-08-25 06:16:57 Functions: 100.0 % 9 9
Branches: 51.0 % 612 312

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2024-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <coins.h>
       6                 :             : 
       7                 :             : #include <boost/test/unit_test.hpp>
       8                 :             : 
       9                 :             : #include <list>
      10                 :             : 
      11                 :             : BOOST_AUTO_TEST_SUITE(coinscachepair_tests)
      12                 :             : 
      13                 :             : static constexpr auto NUM_NODES{4};
      14                 :             : 
      15                 :           3 : std::list<CoinsCachePair> CreatePairs(CoinsCachePair& sentinel)
      16                 :             : {
      17                 :           3 :     std::list<CoinsCachePair> nodes;
      18         [ +  + ]:          15 :     for (auto i{0}; i < NUM_NODES; ++i) {
      19         [ +  - ]:          12 :         nodes.emplace_back();
      20                 :             : 
      21                 :          12 :         auto node{std::prev(nodes.end())};
      22                 :          12 :         CCoinsCacheEntry::SetDirty(*node, sentinel);
      23                 :             : 
      24   [ +  -  +  -  :          24 :         BOOST_CHECK(node->second.IsDirty());
                   +  - ]
      25   [ +  -  +  -  :          24 :         BOOST_CHECK(!node->second.IsFresh());
                   +  - ]
      26   [ +  -  +  - ]:          12 :         BOOST_CHECK_EQUAL(node->second.Next(), &sentinel);
      27   [ +  -  +  - ]:          12 :         BOOST_CHECK_EQUAL(sentinel.second.Prev(), &(*node));
      28                 :             : 
      29         [ +  + ]:          12 :         if (i > 0) {
      30   [ +  -  +  - ]:           9 :             BOOST_CHECK_EQUAL(std::prev(node)->second.Next(), &(*node));
      31   [ +  -  +  - ]:           9 :             BOOST_CHECK_EQUAL(node->second.Prev(), &(*std::prev(node)));
      32                 :             :         }
      33                 :             :     }
      34                 :           3 :     return nodes;
      35                 :           0 : }
      36                 :             : 
      37   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(linked_list_iteration)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      38                 :             : {
      39                 :           1 :     CoinsCachePair sentinel;
      40         [ +  - ]:           1 :     sentinel.second.SelfRef(sentinel);
      41         [ +  - ]:           1 :     auto nodes{CreatePairs(sentinel)};
      42                 :             : 
      43                 :             :     // Check iterating through pairs is identical to iterating through a list
      44                 :           1 :     auto node{sentinel.second.Next()};
      45         [ +  + ]:           5 :     for (const auto& expected : nodes) {
      46   [ +  -  +  - ]:           4 :         BOOST_CHECK_EQUAL(&expected, node);
      47                 :           4 :         node = node->second.Next();
      48                 :             :     }
      49   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(node, &sentinel);
      50                 :             : 
      51                 :             :     // Check iterating through pairs is identical to iterating through a list
      52                 :             :     // Clear the state during iteration
      53                 :           1 :     node = sentinel.second.Next();
      54         [ +  + ]:           5 :     for (const auto& expected : nodes) {
      55   [ +  -  +  - ]:           4 :         BOOST_CHECK_EQUAL(&expected, node);
      56         [ +  - ]:           4 :         auto next = node->second.Next();
      57         [ +  - ]:           4 :         node->second.SetClean();
      58                 :           4 :         node = next;
      59                 :             :     }
      60   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(node, &sentinel);
      61                 :             :     // Check that sentinel's next and prev are itself
      62   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel);
      63   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel);
      64                 :             : 
      65                 :             :     // Delete the nodes from the list to make sure there are no dangling pointers
      66         [ +  + ]:           5 :     for (auto it{nodes.begin()}; it != nodes.end(); it = nodes.erase(it)) {
      67   [ +  -  +  -  :           8 :         BOOST_CHECK(!it->second.IsDirty());
                   +  - ]
      68   [ +  -  +  - ]:           8 :         BOOST_CHECK(!it->second.IsFresh());
      69                 :             :     }
      70                 :           1 : }
      71                 :             : 
      72   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(linked_list_iterate_erase)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      73                 :             : {
      74                 :           1 :     CoinsCachePair sentinel;
      75         [ +  - ]:           1 :     sentinel.second.SelfRef(sentinel);
      76         [ +  - ]:           1 :     auto nodes{CreatePairs(sentinel)};
      77                 :             : 
      78                 :             :     // Check iterating through pairs is identical to iterating through a list
      79                 :             :     // Erase the nodes as we iterate through, but don't clear state
      80                 :             :     // The state will be cleared by the CCoinsCacheEntry's destructor
      81                 :           1 :     auto node{sentinel.second.Next()};
      82         [ +  + ]:           5 :     for (auto expected{nodes.begin()}; expected != nodes.end(); expected = nodes.erase(expected)) {
      83   [ +  -  +  - ]:           4 :         BOOST_CHECK_EQUAL(&(*expected), node);
      84                 :           4 :         node = node->second.Next();
      85                 :             :     }
      86   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(node, &sentinel);
      87                 :             : 
      88                 :             :     // Check that sentinel's next and prev are itself
      89   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel);
      90   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel);
      91                 :           1 : }
      92                 :             : 
      93   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(linked_list_random_deletion)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      94                 :             : {
      95                 :           1 :     CoinsCachePair sentinel;
      96         [ +  - ]:           1 :     sentinel.second.SelfRef(sentinel);
      97         [ +  - ]:           1 :     auto nodes{CreatePairs(sentinel)};
      98                 :             : 
      99                 :             :     // Create linked list sentinel->n1->n2->n3->n4->sentinel
     100                 :           1 :     auto n1{nodes.begin()};
     101                 :           1 :     auto n2{std::next(n1)};
     102                 :           1 :     auto n3{std::next(n2)};
     103                 :           1 :     auto n4{std::next(n3)};
     104                 :             : 
     105                 :             :     // Delete n2
     106                 :             :     // sentinel->n1->n3->n4->sentinel
     107                 :           1 :     nodes.erase(n2);
     108                 :             :     // Check that n1 now points to n3, and n3 still points to n4
     109                 :             :     // Also check that state was not altered
     110   [ +  -  +  -  :           2 :     BOOST_CHECK(n1->second.IsDirty());
                   +  - ]
     111   [ +  -  +  -  :           2 :     BOOST_CHECK(!n1->second.IsFresh());
                   +  - ]
     112   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n1->second.Next(), &(*n3));
     113   [ +  -  +  -  :           2 :     BOOST_CHECK(n3->second.IsDirty());
                   +  - ]
     114   [ +  -  +  -  :           2 :     BOOST_CHECK(!n3->second.IsFresh());
                   +  - ]
     115   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n3->second.Next(), &(*n4));
     116   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n3->second.Prev(), &(*n1));
     117                 :             : 
     118                 :             :     // Delete n1
     119                 :             :     // sentinel->n3->n4->sentinel
     120                 :           1 :     nodes.erase(n1);
     121                 :             :     // Check that sentinel now points to n3, and n3 still points to n4
     122                 :             :     // Also check that state was not altered
     123   [ +  -  +  -  :           2 :     BOOST_CHECK(n3->second.IsDirty());
                   +  - ]
     124   [ +  -  +  -  :           2 :     BOOST_CHECK(!n3->second.IsFresh());
                   +  - ]
     125   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Next(), &(*n3));
     126   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n3->second.Next(), &(*n4));
     127   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n3->second.Prev(), &sentinel);
     128                 :             : 
     129                 :             :     // Delete n4
     130                 :             :     // sentinel->n3->sentinel
     131                 :           1 :     nodes.erase(n4);
     132                 :             :     // Check that sentinel still points to n3, and n3 points to sentinel
     133                 :             :     // Also check that state was not altered
     134   [ +  -  +  -  :           2 :     BOOST_CHECK(n3->second.IsDirty());
                   +  - ]
     135   [ +  -  +  -  :           2 :     BOOST_CHECK(!n3->second.IsFresh());
                   +  - ]
     136   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Next(), &(*n3));
     137   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n3->second.Next(), &sentinel);
     138   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Prev(), &(*n3));
     139                 :             : 
     140                 :             :     // Delete n3
     141                 :             :     // sentinel->sentinel
     142                 :           1 :     nodes.erase(n3);
     143                 :             :     // Check that sentinel's next and prev are itself
     144   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel);
     145   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel);
     146                 :           1 : }
     147                 :             : 
     148   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(linked_list_set_state)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     149                 :             : {
     150                 :           1 :     CoinsCachePair sentinel;
     151                 :           1 :     sentinel.second.SelfRef(sentinel);
     152                 :           1 :     CoinsCachePair n1;
     153                 :           1 :     CoinsCachePair n2;
     154                 :             : 
     155                 :             :     // Check that setting DIRTY inserts it into linked list and sets state
     156                 :           1 :     CCoinsCacheEntry::SetDirty(n1, sentinel);
     157   [ +  -  +  -  :           2 :     BOOST_CHECK(n1.second.IsDirty());
                   +  - ]
     158   [ +  -  +  -  :           2 :     BOOST_CHECK(!n1.second.IsFresh());
                   +  - ]
     159   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n1.second.Next(), &sentinel);
     160   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n1.second.Prev(), &sentinel);
     161   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Next(), &n1);
     162   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n1);
     163                 :             : 
     164                 :             :     // Check that setting FRESH on new node inserts it after n1
     165                 :           1 :     CCoinsCacheEntry::SetFresh(n2, sentinel);
     166   [ +  -  +  -  :           2 :     BOOST_CHECK(n2.second.IsFresh());
                   +  - ]
     167   [ +  -  +  -  :           2 :     BOOST_CHECK(!n2.second.IsDirty());
                   +  - ]
     168   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel);
     169   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n2.second.Prev(), &n1);
     170   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n1.second.Next(), &n2);
     171   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2);
     172                 :             : 
     173                 :             :     // Check that we can set extra state, but they don't change our position
     174                 :           1 :     CCoinsCacheEntry::SetFresh(n1, sentinel);
     175   [ +  -  +  -  :           2 :     BOOST_CHECK(n1.second.IsDirty());
                   +  - ]
     176   [ +  -  +  -  :           2 :     BOOST_CHECK(n1.second.IsFresh());
                   +  - ]
     177   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n1.second.Next(), &n2);
     178   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n1.second.Prev(), &sentinel);
     179   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Next(), &n1);
     180   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n2.second.Prev(), &n1);
     181                 :             : 
     182                 :             :     // Check that we can clear state then re-set it
     183         [ +  - ]:           1 :     n1.second.SetClean();
     184   [ +  -  +  -  :           2 :     BOOST_CHECK(!n1.second.IsDirty());
                   +  - ]
     185   [ +  -  +  -  :           2 :     BOOST_CHECK(!n1.second.IsFresh());
                   +  - ]
     186   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Next(), &n2);
     187   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2);
     188   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel);
     189   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n2.second.Prev(), &sentinel);
     190                 :             : 
     191                 :             :     // Calling `SetClean` a second time has no effect
     192         [ -  + ]:           1 :     n1.second.SetClean();
     193   [ +  -  +  -  :           2 :     BOOST_CHECK(!n1.second.IsDirty());
                   +  - ]
     194   [ +  -  +  -  :           2 :     BOOST_CHECK(!n1.second.IsFresh());
                   +  - ]
     195   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Next(), &n2);
     196   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2);
     197   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel);
     198   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n2.second.Prev(), &sentinel);
     199                 :             : 
     200                 :             :     // Adding DIRTY re-inserts it after n2
     201                 :           1 :     CCoinsCacheEntry::SetDirty(n1, sentinel);
     202   [ +  -  +  -  :           2 :     BOOST_CHECK(n1.second.IsDirty());
                   +  - ]
     203   [ +  -  +  -  :           2 :     BOOST_CHECK(!n1.second.IsFresh());
                   +  - ]
     204   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n2.second.Next(), &n1);
     205   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n1.second.Prev(), &n2);
     206   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(n1.second.Next(), &sentinel);
     207   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n1);
     208                 :           1 : }
     209                 :             : 
     210                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1