LCOV - code coverage report
Current view: top level - src/test - util_not_null_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 66.2 % 130 86
Test Date: 2026-10-11 07:59:32 Functions: 83.3 % 30 25
Branches: 49.8 % 964 480

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or https://opensource.org/license/mit/.
       4                 :             : 
       5                 :             : #include <sync.h>
       6                 :             : #include <test/util/common.h>
       7                 :             : #include <util/not_null.h>
       8                 :             : 
       9                 :             : #include <boost/test/unit_test.hpp>
      10                 :             : 
      11                 :             : #include <memory>
      12                 :             : #include <set>
      13                 :             : #include <type_traits>
      14                 :             : #include <unordered_set>
      15                 :             : 
      16                 :             : BOOST_AUTO_TEST_SUITE(util_not_null_tests)
      17                 :             : 
      18                 :             : static_assert(std::is_same_v<util::NotNullUniquePtr<int>, util::NotNull<std::unique_ptr<int>>>);
      19                 :             : static_assert(std::is_same_v<util::NotNullSharedPtr<int>, util::NotNull<std::shared_ptr<int>>>);
      20                 :             : 
      21                 :             : template <class P>
      22                 :             : concept NotNullConstructible = requires { typename std::bool_constant<(util::NotNull{P{}}, true)>; };
      23                 :             : 
      24   [ +  -  +  -  :           6 : BOOST_AUTO_TEST_CASE(check_ctor)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      25                 :             : {
      26                 :           0 :     struct SomePtr {
      27                 :             :         constexpr bool operator==(std::nullptr_t) const { return false; }
      28                 :             :     };
      29                 :           0 :     struct NullPtr {
      30                 :             :         constexpr bool operator==(std::nullptr_t) const { return true; }
      31                 :             :     };
      32                 :             : 
      33                 :           0 :     static_assert(NotNullConstructible<SomePtr>);
      34                 :           0 :     static_assert(!NotNullConstructible<NullPtr>);
      35                 :           0 :     static_assert(!NotNullConstructible<std::nullptr_t>);
      36                 :           0 :     static_assert(!NotNullConstructible<int*>);
      37                 :           0 : }
      38                 :             : 
      39                 :             : template <class T>
      40                 :             : concept NotNullType = requires { typename util::NotNull<T>; };
      41                 :             : 
      42   [ +  -  +  -  :           6 : BOOST_AUTO_TEST_CASE(check_ctor_ref)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      43                 :             : {
      44                 :           0 :     static_assert(!NotNullType<std::shared_ptr<int>&>);
      45                 :           0 :     static_assert(!NotNullType<int*&>);
      46                 :           0 : }
      47                 :             : 
      48   [ +  -  +  -  :           6 : BOOST_AUTO_TEST_CASE(check_ctor_conv)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      49                 :             : {
      50                 :           0 :     using Ptr = std::shared_ptr<int>;
      51                 :           0 :     using NNPtr = util::NotNullSharedPtr<int>;
      52                 :             : 
      53                 :             :     // For context: std::shared_ptr's raw pointer constructor is explicit
      54                 :           0 :     static_assert(std::constructible_from<Ptr, int*>);
      55                 :           0 :     static_assert(!std::convertible_to<int*, Ptr>);
      56                 :             : 
      57                 :             :     // util::NotNull's constructor is explicit
      58                 :           0 :     static_assert(std::constructible_from<NNPtr, Ptr>);
      59                 :           0 :     static_assert(!std::convertible_to<Ptr, NNPtr>);
      60                 :             : 
      61                 :             :     // For context: std::reference_wrapper's constructor is implicit
      62                 :           0 :     using Ref = std::reference_wrapper<int>;
      63                 :           0 :     static_assert(std::constructible_from<Ref, int&>);
      64                 :           0 :     static_assert(std::convertible_to<int&, Ref>);
      65                 :             : 
      66                 :           0 :     using UniqPtr = std::unique_ptr<int>;
      67                 :           0 :     using NNUniqPtr = util::NotNullUniquePtr<int>;
      68                 :             : 
      69                 :             :     // NNPtr can be copied, but NNUniqPtr can not:
      70                 :           0 :     static_assert(std::is_nothrow_constructible_v<NNPtr, NNPtr&>);
      71                 :           0 :     static_assert(std::is_nothrow_constructible_v<NNPtr, const NNPtr&>);
      72                 :           0 :     static_assert(std::is_nothrow_constructible_v<NNUniqPtr, NNUniqPtr&&>);
      73                 :           0 :     static_assert(!std::is_constructible_v<NNUniqPtr, NNUniqPtr&>);
      74                 :           0 :     static_assert(!std::is_constructible_v<NNUniqPtr, const NNUniqPtr&>);
      75                 :           0 :     static_assert(!std::is_constructible_v<NNPtr, const NNUniqPtr&>);
      76                 :             : 
      77                 :             :     // NNPtr from NNUniqPtr may throw:
      78                 :           0 :     static_assert(!std::is_nothrow_constructible_v<NNPtr, NNUniqPtr&&>);
      79                 :           0 :     static_assert(std::is_constructible_v<NNPtr, NNUniqPtr&&>);
      80                 :             : 
      81                 :             :     // Extraction is implicit:
      82                 :           0 :     static_assert(std::convertible_to<NNUniqPtr&&, UniqPtr>);
      83                 :           0 :     static_assert(std::convertible_to<const NNPtr&, Ptr>);
      84                 :           0 :     static_assert(std::convertible_to<NNPtr&&, Ptr>);
      85                 :           0 : }
      86                 :             : 
      87                 :             : template <class Target, class Source>
      88                 :             : concept NotNullCopyConvertible = requires {
      89                 :             :     typename std::bool_constant<([] {
      90                 :             :         util::NotNull<Source> copy_source{Source{}};
      91                 :             :         util::NotNull<Target>{copy_source};
      92                 :             :         return true;
      93                 :             :     }())>;
      94                 :             : };
      95                 :             : 
      96                 :             : template <class Target, class Source>
      97                 :             : concept NotNullMoveConvertible = requires { typename std::bool_constant<(util::NotNull<Target>{util::NotNull<Source>{Source{}}}, true)>; };
      98                 :             : 
      99   [ +  -  +  -  :           6 : BOOST_AUTO_TEST_CASE(check_cross_type_conversion)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     100                 :             : {
     101                 :           0 :     struct SomePtr;
     102                 :           0 :     struct NullPtr {
     103                 :             :         constexpr NullPtr(const SomePtr&) {}
     104                 :             :         constexpr bool operator==(std::nullptr_t) const { return true; }
     105                 :             :     };
     106                 :           0 :     struct SomePtr {
     107                 :             :         constexpr explicit operator bool() const { return true; }
     108                 :             :         constexpr bool operator==(std::nullptr_t) const { return false; }
     109                 :             :     };
     110                 :             : 
     111                 :             :     // Assume checks failed conversions during constant evaluation.
     112                 :             : #if !defined(_MSC_VER)
     113                 :             :     // MSVC does not reject this failed constant evaluation in a requires-expression.
     114                 :             :     // See https://github.com/bitcoin/bitcoin/issues/36153.
     115                 :           0 :     static_assert(!NotNullCopyConvertible<NullPtr, SomePtr>);
     116                 :           0 :     static_assert(!NotNullMoveConvertible<NullPtr, SomePtr>);
     117                 :             : #endif
     118                 :           0 : }
     119                 :             : 
     120   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(check_null_smart_pointer)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     121                 :             : {
     122                 :             :     // This conversion can throw, allowing the test hook to observe Assert.
     123                 :           1 :     static_assert(!std::is_nothrow_constructible_v<util::NotNullSharedPtr<int>, std::unique_ptr<int>>);
     124         [ +  - ]:           1 :     test_only_CheckFailuresAreExceptionsNotAborts mock_checks{};
     125   [ +  -  -  +  :           3 :     BOOST_CHECK_EXCEPTION(util::NotNullSharedPtr<int>{std::unique_ptr<int>{nullptr}}, NonFatalCheckError,
          -  -  -  -  -  
          +  +  -  +  -  
             +  -  +  - ]
     126                 :             :                           HasReason{"Internal bug detected: m_ptr != nullptr"});
     127                 :           1 : }
     128                 :             : 
     129                 :             : template <class P>
     130                 :             : concept NullptrComparable = requires(P val) { val == nullptr; };
     131                 :             : template <class P>
     132                 :             : concept HasOperatorBool = requires(P val) { bool{val}; };
     133                 :             : 
     134   [ +  -  +  -  :           6 : BOOST_AUTO_TEST_CASE(check_nullptr_compare)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     135                 :             : {
     136                 :             :     // The deleted ctor for nullptr also disallows nullptr compare:
     137                 :           0 :     static_assert(NullptrComparable<std::shared_ptr<int>>);
     138                 :           0 :     static_assert(!NullptrComparable<util::NotNullSharedPtr<int>>);
     139                 :             : 
     140                 :           0 :     static_assert(HasOperatorBool<std::shared_ptr<int>>);
     141                 :           0 :     static_assert(!HasOperatorBool<util::NotNullSharedPtr<int>>);
     142                 :           0 : }
     143                 :             : 
     144   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(check_nocopy_ptr)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     145                 :             : {
     146                 :           1 :     using NoCopyPtr = std::unique_ptr<int>;
     147                 :           1 :     {
     148                 :           1 :         NoCopyPtr no_copy_ptr{std::make_unique<int>()};
     149                 :           1 :         util::NotNull no_copy{std::move(no_copy_ptr)};
     150                 :           1 :         NoCopyPtr extract{std::move(no_copy)};
     151                 :           1 :         (void)extract;
     152                 :           1 :     }
     153                 :           1 :     {
     154                 :           1 :         util::NotNull no_copy{NoCopyPtr{std::make_unique<int>()}};
     155                 :           1 :         NoCopyPtr extract{std::move(no_copy).get()};
     156                 :           1 :         (void)extract;
     157                 :           1 :     }
     158                 :           1 : }
     159                 :             : 
     160   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(check_derived)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     161                 :             : {
     162                 :           2 :     struct MyBase {
     163                 :           2 :         virtual ~MyBase() = default;
     164                 :             :     };
     165                 :           2 :     struct MyDerived : public MyBase {
     166                 :             :     };
     167                 :             : 
     168         [ -  + ]:           1 :     util::NotNull p{std::make_shared<MyDerived>()};
     169   [ +  -  -  + ]:           1 :     util::NotNull q{std::make_shared<MyBase>()};
     170         [ -  + ]:           1 :     q = p;
     171                 :           1 :     const bool same_ptr{q == p};
     172   [ +  -  +  -  :           2 :     BOOST_CHECK(same_ptr);
                   +  - ]
     173                 :             : 
     174         [ +  - ]:           1 :     util::NotNull nn_derived{std::make_unique<MyDerived>()};
     175         [ +  - ]:           1 :     util::NotNull nn_base{std::make_unique<MyBase>()};
     176                 :           1 :     nn_base = std::move(nn_derived);
     177                 :           1 :     std::unique_ptr<MyBase> base_inner{std::move(nn_base)};
     178   [ +  -  +  - ]:           3 : }
     179                 :             : 
     180   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(check_move)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     181                 :             : {
     182                 :           1 :     auto a{std::make_unique<int>()};
     183                 :           1 :     util::NotNull box{std::move(a)};
     184         [ +  - ]:           1 :     auto new_box{std::move(box)};
     185                 :             : 
     186         [ +  - ]:           1 :     auto b{std::make_shared<int>()};
     187                 :           1 :     util::NotNull arc{b};
     188         [ +  - ]:           1 :     auto new_arc{std::move(arc)};
     189   [ -  +  +  - ]:           2 : }
     190                 :             : 
     191   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(check_swap)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     192                 :             : {
     193                 :           1 :     util::NotNull box_a{std::make_unique<int>(1)};
     194         [ +  - ]:           1 :     util::NotNull box_b{std::make_unique<int>(2)};
     195                 :           1 :     static_assert(std::is_nothrow_swappable_v<decltype(box_a)>);
     196   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*box_a - *box_b, -1);
     197                 :           1 :     swap(box_a, box_b);
     198   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*box_a - *box_b, 1);
     199                 :           1 : }
     200                 :             : 
     201   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(check_deref)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     202                 :             : {
     203                 :           1 :     util::NotNull p{std::make_unique<int>(2)};
     204         [ +  - ]:           1 :     *p = 3;
     205   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*p, 3);
     206         [ +  - ]:           1 :     *p.get() = 4;
     207   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*p, 4);
     208                 :           1 : }
     209                 :             : 
     210   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(check_compare_set)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     211                 :             : {
     212                 :           1 :     auto a{std::make_shared<int>(1)};
     213         [ +  - ]:           1 :     auto b{std::make_shared<int>(2)};
     214         [ +  - ]:           1 :     std::set<util::NotNullSharedPtr<int>> uniq{};
     215         [ +  - ]:           1 :     uniq.emplace(a);
     216         [ +  - ]:           1 :     uniq.emplace(a);
     217         [ +  - ]:           1 :     uniq.emplace(b);
     218   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(uniq.size(), 2);
     219   [ +  -  +  - ]:           3 : }
     220                 :             : 
     221   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(check_hash_set)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     222                 :             : {
     223                 :           1 :     auto a{std::make_shared<int>(1)};
     224         [ +  - ]:           1 :     auto b{std::make_shared<int>(2)};
     225         [ +  - ]:           1 :     std::unordered_set<util::NotNullSharedPtr<int>> uniq{};
     226         [ +  - ]:           1 :     uniq.emplace(a);
     227         [ +  - ]:           1 :     uniq.emplace(a);
     228         [ +  - ]:           1 :     uniq.emplace(b);
     229   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(uniq.size(), 2);
     230   [ +  -  +  - ]:           3 : }
     231                 :             : 
     232   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(check_tsa)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     233                 :             : {
     234                 :           2 :     struct Thing {
     235                 :             :         Mutex mutex{};
     236                 :             :         int a GUARDED_BY(mutex){2};
     237                 :             :     };
     238         [ -  + ]:           1 :     const util::NotNull p{std::make_shared<Thing>()};
     239                 :             :     // Clang thread safety annotation (TSA) may not be able to derive that
     240                 :             :     // operator-> and operator* refer to the same object. So use a named
     241                 :             :     // reference before taking the lock.
     242         [ +  - ]:           1 :     Thing& ref{*p};
     243         [ +  - ]:           1 :     LOCK(ref.mutex);
     244   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(ref.a, 2);
                   +  - ]
     245         [ +  - ]:           2 : }
     246                 :             : 
     247                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1