LCOV - code coverage report
Current view: top level - src/test - coinscachepair_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 99.1 % 117 116
Test Date: 2025-01-19 05:08:01 Functions: 100.0 % 9 9
Branches: 51.1 % 558 285

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

Generated by: LCOV version 2.0-1