Remove boost as a unit test runner #35713

pull rustaceanrob wants to merge 14 commits into bitcoin:master from rustaceanrob:remove-boost-test changing 159 files +1613 −370
  1. rustaceanrob commented at 2:23 PM on July 13, 2026: member

    Continued from #35587. tl;dr: Make an equivalent test runner to boost with simpler macros and tighter coupling to bitcoin-specific code.

    Motivation

    There are a number of problems with using dependencies in general. Bugs must either be promptly upstreamed or patched, projects may be abandoned, and they are not tailored to a particular use case. This PR removes boost for writing and running unit tests. In the case of Boost.Test, there are a number of issues which are listed below.

    My problems with Boost.Test

    Macros

    When using boost, there are 3 ways of writing the same thing, each with different outcomes

    • BOOST_CHECK(expr1 == expr2): failures show the expression, but no values for expr1 and expr2
    • BOOST_CHECK_EQUAL(expr1, expr2): failures show the expression and values, but requires developers remember CHECK_EQUAL and does not use usual operands
    • BOOST_TEST(expr1 == expr2): failures show the expression and values, and developers may use familiar operands (==, !=)

    All three are preserved to maintain backwards compatibility - presumably, but this results in all 3 being used throughout the repository. As a bonus there is a 4th way, with added context

    • BOOST_CHECK_MESSAGE(expr1 == expr2, "the context"): failures show the expression and message, but no values for expr1 and expr2

    To make debugging and review easier, all of these should be unified to a single macro. Test sites use operands, print helpful messages - values are always included, and do not vary in approach (deciding between BOOST_TEST, CHECK, and BOOST_CHECK_EQUAL is unintuitive)

    <details> <summary>Example boost outputs</summary>

    BOOST_AUTO_TEST_CASE(mustfail)
    {
        auto a{1};
        auto b{2};
        BOOST_CHECK(a == b);
        BOOST_CHECK_EQUAL(a, b);
        BOOST_TEST(a == b);
        COutPoint outpoint_1{Txid{"0000000000000000000000000000000000000000000000000000000000000100"}, 0};
        COutPoint outpoint_2{Txid{"0000000000000000000000000000000000000000000000000000000000000100"}, 1};
        BOOST_CHECK(outpoint_1 == outpoint_2);
        // Doesn't even compile
        // BOOST_TEST(outpoint_1 == outpoint_2);
        // BOOST_CHECK_EQUAL(outpoint_1, outpoint_2);
    }
    
    Running 1 test case...
    test/argsman_tests.cpp(31): error: in "argsman_tests/mustfail": check a == b has failed
    test/argsman_tests.cpp(32): error: in "argsman_tests/mustfail": check a == b has failed [1 != 2]
    test/argsman_tests.cpp(33): error: in "argsman_tests/mustfail": check a == b has failed [1 != 2]
    test/argsman_tests.cpp(36): error: in "argsman_tests/mustfail": check outpoint_1 == outpoint_2 has failed
    

    </details>

    <details> <summary>New outputs</summary>

    TEST_CASE(mustfail)
    {
        auto a{1};
        auto b{2};
        CHECK(a == b);
        COutPoint outpoint_1{Txid{"0000000000000000000000000000000000000000000000000000000000000100"}, 0};
        COutPoint outpoint_2{Txid{"0000000000000000000000000000000000000000000000000000000000000100"}, 1};
        CHECK(outpoint_1 == outpoint_2);
    }
    
    Running 1 test cases...
    [FAIL]: test/argsman_tests.cpp:30: CHECK(a == b)
    1 == 2
    
    [FAIL]: test/argsman_tests.cpp:33: CHECK(outpoint_1 == outpoint_2)
    COutPoint(0000000000, 0) == COutPoint(0000000000, 1)
    
    [FAIL] mustfail (2/2 checks failed)
    

    </details>

    No repository context

    Many types implement ToString, but boost has no way of meaningfully using these representations (will change w/ future std::format). With a repository-specific test runner we can use these today. See example above.

    Not extensible

    With the test runner in this repository we can add things such as #35139, implement string representations for more types, and implement ideas from #8670.

    Other issues

    More issues with boost are raised in #34666, #8670. This PR does not resolve all of them, but one it does address immediately is banning comparisons of integers with different signs, previously allowed by boost. Using a test runner within the source also makes IWYU easier to work with.

    High level changes

    For those running tests, not a tremendous amount has changed in this PR. For instance, the doc page remains valid. Changes to the runner options include anything that is not help, run_test, log_level, list_content. This includes catch_system_errors which is always no. The log_levels have been reduced to 5 levels.

    Changes in writing tests

    • CHECK to compare two values with any ==, !=, >, etc
    • CHECK(a == b, "my message") to append a message
    • REQUIRE, same as CHECK, but will fail the test immediately
    • TEST_CASE(name) to add a test
    • FIXTURE_TEST_CASE(name, Fixture) to add a test with a fixture
    • TEST_SUITE_BEGIN/END to declare a suite, optionally with fixture for each test in the suite

    Migration

    Boost.Test is removed in this PR, but the macros are aliased by BOOST_* counterparts so there are no merge conflicts. The idea would be to migrate test files to the new macros when there are no/low number of conflicts on that file.

    <details> <summary>Commits</summary>

    The addition of the framework:

    • test: Add header-only framework to util

    Migration script (majority of the file changes):

    • scripted-diff: Migrate tests to header-only framework

    Low usage count macro removals:

    • test: Remove low usage BOOST macros

    Required for expression decomposition:

    • test: Unroll && conditions in macros
    • test: Wrap || expressions in macros
    • test: Wrap bitwise & expressions in macros

    To pass CI

    • test: Use lambda for CRecipient to avoid gcc12 uninitialized warning

    Build and config

    • depends: drop test from Boost libraries
    • cmake: drop vcpkg Boost Test check
    • vcpkg: drop boost-test dependency

    </details>

  2. DrahtBot commented at 2:23 PM on July 13, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35713.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    Concept ACK josibake

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35855 (guix: update time-machine to acf3d19725c9f588ccc60095067d91fe9c578ea7 by fanquake)
    • #35847 (test: move more tests to baseindex_tests and run them for all indexes by mzumsande)
    • #35831 (argsman, cli: Allow options after non-option arguments (GNU-style) by pablomartin4btc)
    • #35797 (psbt: support output metadata updates before inputs are added by l0rinc)
    • #35744 (coins: prevent DB resize from invalidating cursors by l0rinc)
    • #35729 (refactor: test: Unroll && conditions in macros by rustaceanrob)
    • #35662 (script: make txdata non-default-constructible by l0rinc)
    • #35569 (Encapsulation for CTransaction by purpleKarrot)
    • #35531 (txindex: hash keys and pack positions to reduce disk usage by andrewtoth)
    • #34864 (coins: tighten cache entry state invariants by l0rinc)
    • #34075 (fees: Introduce Mempool Based Fee Estimation to reduce overestimation by ismaelsadeeq)
    • #29278 (Wallet: Add maxfeerate wallet startup option by ismaelsadeeq)
    • #26022 (Add util::ResultPtr class by ryanofsky)
    • #25665 (refactor: Add util::Result failure types and ability to merge result values by ryanofsky)
    • #25573 (guix: produce a -static-pie bitcoind by fanquake)
    • #17783 (common: Disallow calling IsArgSet() on ALLOW_LIST options by ryanofsky)
    • #17581 (refactor: Remove settings merge reverse precedence code by ryanofsky)
    • #17580 (refactor: Add ALLOW_LIST flags and enforce usage in CheckArgFlags by ryanofsky)
    • #17493 (util: Forbid ambiguous multiple assignments in config file by ryanofsky)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

    LLM Linter (✨ experimental)

    Possible typos and grammar issues:

    • is implement with the \runner()` function->is implemented with the `runner()` function` [wrong verb form]
    • does not having a meaningful output -> does not have a meaningful output [grammatical error]

    <sup>2026-08-01 13:17:11</sup>

  3. josibake commented at 2:28 PM on July 13, 2026: member

    Moving over my original ACK from the previous PR: #35587 (comment)


    Strong Concept ACK!

    Love to see it. While I broadly agree with the author's reasons stated in the PR, the ones I'll highlight specifically are:

    • No repository context
    • Not extensible

    Having our own simple, in house test framework gives us the ability to customise it for exactly our needs. I believe we should do everything in our power to make testing an easy, intuitive, and feature rich experience as this helps to remove barriers to people writing and interpreting tests.

    In particular, as a longer term project I am looking at ways to improve concurrency in our testing to help speed up CI. As @purpleKarrot points out:

    The Boost.Test framework is notoriously bad at this. When selecting a single test, it spams out information about all tests that are not selected. While it can provide information about what tests are available, that output is optimized for human readability and very hard to parse by a test driver. We can definitely do better with a custom test framework!

  4. in src/test/util/framework.h:140 in ae1ee1b007 outdated
     135 | +        os << value;
     136 | +        return os.str();
     137 | +    } else if constexpr (has_to_string<T>) {
     138 | +        return value.ToString();
     139 | +    } else {
     140 | +        return typeid(T).name();
    


    maflcko commented at 2:41 PM on July 13, 2026:

    As explained in #35625 (comment), I still don't think this makes sense. The only change is that some compile-time type name may be printed for both sides.

    This should remain a compile failure, like it is on current master.


    rustaceanrob commented at 9:38 AM on July 14, 2026:

    Agree this should be a static assert but I haven't gotten to this yet because BOOST_CHECK doesn't require a meaningful string representation. There are many types that would then require a ToString or similar for stringify to work properly. I have a couple ideas of how to do this.


    maflcko commented at 9:54 AM on July 14, 2026:

    Why not just keep the pre-existing approach of using the helpers from src/test/util/common.h (std::ostream& operator<<)?


    rustaceanrob commented at 10:20 AM on July 14, 2026:

    Those don't cover most of the types. For instance, a few random ones, ByRatio<FeeFrac> and Coin do not have a ToString or <<.


    maflcko commented at 11:14 AM on July 14, 2026:

    Ok, I see. It could make sense to split this fix up into its own pull request? Otherwise, it looks like it is hidden in a single line in a ~1500line pull request.

    To explain the background:

    • No code today (in master) exists that compares Coin in the test framework with pretty debug output.
    • If someone were to trigger pretty output, e.g. by using BOOST_CHECK_EQUAL, then the compilation would fail:
    diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
    index 6ae5f2b7cb..9ba2e67e30 100644
    --- a/src/test/coins_tests.cpp
    +++ b/src/test/coins_tests.cpp
    @@ -168,3 +168,3 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
                     AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));
    -            BOOST_CHECK(coin == entry);
    +            BOOST_CHECK_EQUAL(coin,entry);
     
    

    To fix this, I think it would be fine to provide a ToString or operator<<, maybe in a separate pull request? However, I haven't checked how many classes are affected in total.

    Maybe there is a better solution available (we don't have C++26, heh), but I think whatever the solution is, should (and can) be a separate pull request. Also, seems fine to keep it here, but I think this pull request should try to preserve the behavior, or at least list all behavior changes and why they are done.


    rustaceanrob commented at 1:52 PM on July 14, 2026:

    I think some have a natural fix, like if HexStr(v) works than it is probably a good representation. Also, if an type implements a v.Serialize then we can also pass that as a hex string, which should be suitable for debugging (maybe the typeid as a prefix to the hex string). Also std::vector<Foo> for Foo with a stringifyable can just print the list of Foo. Same goes for std::pair and some others.

    For the rest of the cases, I was thinking it could be possible to add a macro BOOST_NO_DISPLAY_CHECK. All of these callsites can be fixed by adding a ToString or << as that file is migrated to new macros.


    maflcko commented at 1:57 PM on July 14, 2026:

    Ah nice. Hex could work here.

    Though, for a vector I am not sure if it makes sense to dump the full list. See check_eq_collections in https://github.com/bitcoin/bitcoin/pull/35139/changes, which only prints the failing index. IIRC this is also what boost does.


    maflcko commented at 3:39 PM on July 15, 2026:

    I think the fallback return typeid(T).name(); still exists in the latest push and is still wrong.

    The correct lowest fallback is still a compilation-failure, just like the prior behavior with boost.


    rustaceanrob commented at 3:56 PM on July 15, 2026:

    Yeah, agree, however there are around 80 callsites that still do not have a string representation. Some of which appear to be the wrong check, like using BOOST_CHECK on two ranges instead of BOOST_CHECK_EQUAL_RANGES. Others would need a custom ToString or <<.

    For the time being, in a separate commit after the scripted diff, I was going to introduce the static assert and a macro CHECK_NO_DISPLAY that omits the stringify for those sites. I am also open to other approaches.


    maflcko commented at 12:22 PM on July 16, 2026:

    Yeah, seems fine to have way to skip having to provide a stringifier. One hacky way would be to just use double-braces: CHECK((a==b)), but that may be a bit ugly and unintuitive. CHECK_NO_DISPLAY sounds fine.

    The benefit of the static assert is that it can print the problem and solution at compile time, instead of silently running into issues without any suggestion on how to fix them. E.g. something like:

            static_assert(requires(std::ostream& os) { os << value; }, "Please provide an operator<<(std::ostream&, const T&) for formatting. Otherwise, a test failure will not be able to display the differing objects. Alternatively, use CHECK_NO_DISPLAY to disable display of the objects completely.");
    

    rustaceanrob commented at 12:32 PM on July 20, 2026:

    01be0daef8f8e003d4cda75cf5b226fa0eff0696 and efa00a2cded95fb39ca820a2eae4da527da6e89a updates stringify overloads and 05397f7c0881265f1b108e8e2544c889d7c8b830 moves to a static_assert. In doing this exercise I saw a lot of BOOST_CHECK(r1 == r2) that compares two ranges, where almost certainly it would be better to use BOOST_CHECK_EQUAL_COLLECTIONS. I think it would be a nice property to allow devs to use CHECK(r1 == r2), so I added a concept that checks if a developer is trying to compare two ranges and that type does not already have a ToString or <<. This allowed me two remove the CHECK_EQUAL_COLLECTIONS macro entirely, which I prefer.

    Unfortunately, two iterators are compared quite a few times in the tests, however it is difficult to make a meaningful stringify for these cases. I am hoping to leave those conversions to CHECK_NO_DISPLAY as followup, so as to not completely bloat this PR.

  5. in src/test/dbwrapper_tests.cpp:360 in 421271dbcc
     355 | @@ -356,8 +356,8 @@ BOOST_AUTO_TEST_CASE(iterator_ordering)
     356 |      for (const int seek_start : {0x00, 0x80}) {
     357 |          it->Seek((uint8_t)seek_start);
     358 |          for (unsigned int x=seek_start; x<255; ++x) {
     359 | -            uint8_t key;
     360 | -            uint32_t value;
    


    fanquake commented at 8:39 AM on July 14, 2026:

    In 6eaefedb79598eedf00b24e4e480a7e005440e40:

    libboost_unit_test_framework is prebuilt without MSan/UBSan,

    We don't use any Boost libraries (header-only since #24301), so not sure how the library missing instrumentation could be the cause of issues here?


    maflcko commented at 9:02 AM on July 14, 2026:

    Maybe this is just one of the GCC false positive bugs about -w-uninit? Though, hard to tell without seeing the exact compiler/sanitizer output in the commit message.

    Maybe the commit messages could be expanded with the exact output?


    rustaceanrob commented at 9:06 AM on July 14, 2026:

    I'm running the CI on a different branch to see if this still fails. If so, I'll paste some output.


    rustaceanrob commented at 11:49 AM on July 14, 2026:

    Looks like an older state of the framwork or commit history was causing this, dropped the commit.


    maflcko commented at 12:08 PM on July 14, 2026:

    Could still make sense to expand the other commit with the exact failure reason.

    Stuff like 9e1247067dbf51fab4a532a8ffda707361886021 looks like bugs in the bitcoin core code itself. About 17b37d2fdded4cb02203a07e27408f4001abe894 I wonder what the error was.


    rustaceanrob commented at 2:10 PM on July 14, 2026:

    For the constexpr commits, it is a linker error, which I will add to the commit messages:

    undefined reference to `LockedPool::ARENA_SIZE'
    clang++: error: linker command failed with exit code 1 (use -v to see invocation)
    ninja: build stopped: subcommand failed.
    

    AFICT there are no downsides to const -> constexpr, so it feels like these commits should belong in a broader sweep, but then again I don't see much of a motivation to do so outside of this PR. Would there be any benefit?


    maflcko commented at 2:53 PM on July 14, 2026:

    Ah, it is a linker error due to the missing inline via constexpr. Thanks for explaining.

    For reference, the compile failure for the other commit would be something like:

    error: invalid operands to binary expression ('const AddressPosition' and 'const AddressPosition')
      851 |                     (void)(ref==ref);
          |                            ~~~^ ~~~
    src/addrman.h:76:10: note: candidate function not viable: 'this' argument has type 'const AddressPosition', but method is not marked const
       76 |     bool operator==(AddressPosition other) {
          |          ^
    

    rustaceanrob commented at 12:47 PM on July 22, 2026:

    683a06f0869e471239a75f672eb1f8841c424c26 circumvents the linker issue by just removing the use of const T& for the static const class member variables. I looked at the number of static const member variables in src and there were quite a few, so I would rather not convert all of these to constexpr at the moment.


    maflcko commented at 1:27 PM on July 22, 2026:

    I mean it looks like ODR violations that just happen to get optimized away by the compiler, but I guess there is no tool to find/fix all of them?


    rustaceanrob commented at 3:47 PM on July 22, 2026:

    I think https://github.com/llvm/llvm-project/pull/162741 would do it but looks a bit stalled


    fanquake commented at 4:06 PM on July 22, 2026:

    I think it'd be fine to open a PR that just changes all class usage of static const to static constexpr? That seems straightforward, and correct (happy to do). Somewhat related, I had been looking at debug symbols (from the 31.1 release), to check where symbols were being duplicated across TUs, rather than squashed to a single definition by the linker; MAX_SCRIPT_ELEMENT_SIZE is one of a few. Fixing these is basically just changing static const -> inline constexpr, which also seems worthwhile, and if anything, shrinks our release binary.


    maflcko commented at 12:37 PM on July 30, 2026:

    Everything in this thread is resolved and it can be closed?


    rustaceanrob commented at 12:42 PM on July 30, 2026:

    Somewhat related, I had been looking at debug symbols (from the 31.1 release), to check where symbols were being duplicated across TUs, rather than squashed to a single definition by the linker; MAX_SCRIPT_ELEMENT_SIZE is one of a few. Fixing these is basically just changing static const -> inline constexpr, which also seems worthwhile

    Perhaps this can be made an issue if there are other associated changes or this impact on the binary size is noticeable.


    maflcko commented at 6:14 PM on July 30, 2026:

    Did some inline constexpr scripted diff in #35852. Let's see what reviewers think.

  6. in src/test/util/framework.h:66 in 421271dbcc outdated
      61 | +    {
      62 | +        registry().emplace_back(TestCase{current_test_suite(), name, fn});
      63 | +    }
      64 | +};
      65 | +
      66 | +/** Path that the test binary */
    


    maflcko commented at 9:16 AM on July 14, 2026:

    llm-nit: (Also looks like the LLM broke down):

    Possible typos and grammar issues:

    • /** Path that the test binary */ -> /** Path to the test binary */ [the original comment is grammatically incomplete and अस्पष्ट]
  7. rustaceanrob commented at 9:38 AM on July 14, 2026: member

    Draft while I work on #35713 (review)

  8. rustaceanrob marked this as a draft on Jul 14, 2026
  9. rustaceanrob force-pushed on Jul 14, 2026
  10. rustaceanrob force-pushed on Jul 14, 2026
  11. DrahtBot added the label CI failed on Jul 14, 2026
  12. DrahtBot removed the label CI failed on Jul 14, 2026
  13. rustaceanrob force-pushed on Jul 15, 2026
  14. rustaceanrob force-pushed on Jul 15, 2026
  15. DrahtBot added the label CI failed on Jul 15, 2026
  16. DrahtBot commented at 12:03 PM on July 15, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task OpenBSD Cross: https://github.com/bitcoin/bitcoin/actions/runs/29411082055/job/87338055592</sub> <sub>LLM reason (✨ experimental): CI failed due to a linker error: undefined symbol HexStr(std::span<const unsigned char,...>) while building test_kernel (missing HexStr implementation).</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  17. rustaceanrob marked this as ready for review on Jul 15, 2026
  18. DrahtBot removed the label CI failed on Jul 15, 2026
  19. rustaceanrob marked this as a draft on Jul 15, 2026
  20. rustaceanrob force-pushed on Jul 20, 2026
  21. rustaceanrob force-pushed on Jul 20, 2026
  22. DrahtBot added the label CI failed on Jul 20, 2026
  23. DrahtBot commented at 10:54 AM on July 20, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task NetBSD Cross: https://github.com/bitcoin/bitcoin/actions/runs/29734060337/job/88325092997</sub> <sub>LLM reason (✨ experimental): CI failed during compilation of test_kernel.cpp due to Clang errors (notably ambiguous Txid and missing operator<< needed by the test framework for BOOST_CHECK output).</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  24. DrahtBot removed the label CI failed on Jul 20, 2026
  25. rustaceanrob force-pushed on Jul 20, 2026
  26. rustaceanrob marked this as ready for review on Jul 20, 2026
  27. rustaceanrob force-pushed on Jul 22, 2026
  28. rustaceanrob referenced this in commit 075e7f4218 on Jul 22, 2026
  29. DrahtBot added the label CI failed on Jul 22, 2026
  30. fanquake referenced this in commit 6ced9ad782 on Jul 22, 2026
  31. rustaceanrob force-pushed on Jul 22, 2026
  32. DrahtBot removed the label CI failed on Jul 22, 2026
  33. fanquake referenced this in commit fb22682c45 on Jul 24, 2026
  34. fanquake referenced this in commit 3a2c52f9d7 on Jul 24, 2026
  35. rustaceanrob force-pushed on Jul 24, 2026
  36. rustaceanrob force-pushed on Jul 26, 2026
  37. rustaceanrob force-pushed on Jul 26, 2026
  38. rustaceanrob force-pushed on Jul 28, 2026
  39. DrahtBot added the label Needs rebase on Jul 29, 2026
  40. rustaceanrob force-pushed on Jul 29, 2026
  41. DrahtBot removed the label Needs rebase on Jul 29, 2026
  42. maflcko commented at 8:09 AM on July 30, 2026: member

    Could rebase and drop the unused boost workaround in guix?

    +# Use LINK_WARNING_AS_ERROR when using CMake 4.x
    +case "$HOST" in
    +    riscv64-linux-gnu) ;; # https://github.com/boostorg/test/issues/345
    +    *) HOST_LDFLAGS="${HOST_LDFLAGS} -Wl,--fatal-warnings" ;;
    +esac
    +
    
  43. rustaceanrob force-pushed on Jul 30, 2026
  44. rustaceanrob commented at 9:40 AM on July 30, 2026: member

    Given the response to #35729, which I was surprised to see pushback on, I found a solution to preserve && and || at the cost of the debug output. By implementing operator bool we can chain operations within the macros to preserve the perceived expressiveness of writing two conditions in one check. In the current state, this makes the loss of debug output implicit, but the PR becomes a lot more concise. We can revisit if we should delete the && and || at a later point, or perhaps fix these as files are migrated.

  45. test: Remove low usage `BOOST` macros
    `BOOST_TEST`: There is only a single case of this macro and the if conditional that
    triggers it may simply be used in a `BOOST_REQUIRE`
    
    `BOOST_TEST_INFO`: In the case of `descriptor_tests.cpp`, the info is only used to get the
    diagonsics of `BOOST_CHECK_EQUAL` along with the human readable form of
    the descriptor. This is irrelevant if the test framework implements
    expression decomposition, which will print the string representation on
    failure (e.g. `BOOST_TEST`).
    
    Removing `BOOST_TEST_INFO_SCOPE` requires a few duplications, but these are
    very little cost compared to a port of this macro, which does not appear
    critically useful.
    
    `BOOST_CHECK_CLOSE`: This is only used in a single test and would be a low-motivation add to
    porting the test framework. A lambda is sufficient to enforce the check.
    6a94b35f76
  46. test: Move `Coin` `==` operator out of anon namespace
    The lookup for `==` is unqualified with Boost.Test, but when doing the
    `==` lookup in the later migration commit this causes a compiler error
    as the `==` is being looked up outside of the namespace within
    `framework.h`:
    
    ```
    In file included from /home/rob/bitcoin-core/bitcoin/src/test/coins_tests.cpp:26:
    /home/rob/bitcoin-core/bitcoin/src/test/util/framework.h:417:18: error: invalid operands to binary expression ('const Coin' and 'const Coin')
      417 |     DECOMPOSE_OP(==, std::cmp_equal)
          |     ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
    /home/rob/bitcoin-core/bitcoin/src/test/util/framework.h:411:57: note: expanded from macro 'DECOMPOSE_OP'
      411 |                 btc_test_result = static_cast<bool>(lhs op rhs);                                                   \
          |                                                     ~~~ ^  ~~~
    /home/rob/bitcoin-core/bitcoin/src/test/coins_tests.cpp:177:30: note: in instantiation of function template specialization 'framework::CapturedExpression<Coin>::operator==<Coin>' requested here
      177 |             BOOST_CHECK(coin == entry);
          |                              ^
    /home/rob/bitcoin-core/bitcoin/src/support/allocators/pool.h:350:6: note: candidate template ignored: could not match 'const PoolAllocator<T1, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>' against 'const Coin'
      350 | bool operator==(const PoolAllocator<T1, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& a,
          |      ^
    /home/rob/bitcoin-core/bitcoin/src/support/allocators/pool.h:350:6: note: candidate template ignored: could not match 'const PoolAllocator<T1, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>' against 'const Coin'
    ```
    3856827ed7
  47. test: Use lambda for `CRecipient` to avoid gcc12 uninitialized warning
    gcc12 warns with uninitialized when boost is not used for this test.
    Unfortunately, I think this is a false positive, as `CRecipient` seems
    obivously initialized?
    
    ref: https://github.com/boostorg/variant2/issues/55
    
    error:
    ```
    >::_Vector_impl::<anonymous>.std::_Vector_base<unsigned char, std::allocator<unsigned char> >::_Vector_impl_data::_M_end_of_storage’ may be used uninitialized [-Werror=maybe-uninitialized]
    
    367 | _M_impl._M_end_of_storage - _M_impl._M_start);
    
    | ~~~~~~~~^~~~~~~~~~~~~~~~~
    
    /home/runner/work/_temp/src/wallet/test/spend_tests.cpp: In lambda function:
    
    /home/runner/work/_temp/src/wallet/test/spend_tests.cpp:47:20: note: ‘recipient’ declared here
    
    47 | CRecipient recipient{PubKeyDestination({}), 50 * COIN - leftover_input_amount, /*subtract_fee=*/true};
    
    | ^~~~~~~~~
    
    cc1plus: all warnings being treated as errors
    
    gmake[2]: *** [src/test/CMakeFiles/test_bitcoin.dir/build.make:2142: src/test/CMakeFiles/test_bitcoin.dir/__/wallet/test/spend_tests.cpp.o] Error 1
    
    gmake[1]: *** [CMakeFiles/Makefile2:2621: src/test/CMakeFiles/test_bitcoin.dir/all] Error 2
    
    gmake: *** [Makefile:146: all] Error 2
    
    Command '['docker', 'exec', '--env', 'DANGER_RUN_CI_ON_HOST=1', 'e5149787b8a1739029b127ba5d3b9cf034d955ca907ea03ab0cfe5de2af9e8d9', '/home/runner/work/_temp/ci/test/03_test_script.sh']' returned non-zero exit status 2.
    ```
    1b4adfba26
  48. test: Wrap bitwise `&` expressions in macros
    Logical operators are not usable with test frameworks that decompose
    expressions, as introduced in a later commit.
    
    ref: https://catch2-temp.readthedocs.io/en/latest/assertions.html#other-limitations
    ref: https://fekir.info/post/decomposing-an-expression/
    a01560995a
  49. test: Unroll `&&` conditions in macros
    Using `&&` in `BOOST_CHECK` is problematic as failures will not indicate
    which condition failed. By unrolling these checks, the user knows
    exactly which expression is the failing case.
    
    As an example, here is a line that would be particularly hard to debug
    if it failed:
    
    ```
    src/test/net_tests.cpp
    
    BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "headers" && std::ranges::equal((*ret)[1]->m_recv, MakeByteSpan(msg_data_2)));
    ```
    
    If any one of these conditions fail, the whole expression fails, with no
    values printed or indication as to which condition failed.
    
    This is also required when using test macros that support value
    decomposition, which requires `&&` and `||` are `delete`. Examples
    include `BOOST_TEST`, doctest, Catch2, etc.
    
    ref: https://catch2-temp.readthedocs.io/en/latest/assertions.html#other-limitations
    ref: https://fekir.info/post/decomposing-an-expression/
    e6cd818319
  50. test: Wrap `||` expressions in macros
    The `||` is not usable with `BOOST_TEST` and other modern test
    frameworks like Catch2. This is due to operator precedence used in such
    macros. Here is an additional opinion from Catch2:
    
    > There is no simple rewrite rule for ||, but I generally believe
    that if you have || in your test expression, you should rethink your tests.
    
    ref: https://catch2-temp.readthedocs.io/en/latest/assertions.html#other-limitations
    ref: https://fekir.info/post/decomposing-an-expression/
    3fc37f7e46
  51. test: Add header-only framework to util 0ed7a1a44e
  52. scripted-diff: Migrate tests to header-only framework
    This migrates the test runner, boost header imports, and linter.
    `include <memory>` line is to fix an IWYU.
    
    -BEGIN VERIFY SCRIPT-
    mv src/test/new_main.cpp src/test/main.cpp
    git grep -l '<boost/test/unit_test.hpp>' | xargs sed -i 's|<boost/test/unit_test.hpp>|<test/util/framework.h>|'
    sed -i 's|BOOST_TEST_MODULE Bitcoin Kernel Test Suite|BITCOIN_TEST_MAIN|; s|<boost/test/included/unit_test.hpp>|<test/util/framework.h>|' src/test/kernel/test_kernel.cpp
    sed -i 's|boost::unit_test::framework::master_test_suite().argv\[0\]|framework::executable_path()|' src/test/system_tests.cpp
    sed -i '/boost\/test\/\(included\/\)\?unit_test.hpp/d' test/lint/lint-includes.py
    sed -i 's| --catch_system_error=no||' src/test/CMakeLists.txt
    sed -i 's|#include <test/util/framework.h>|&\n\n#include <memory>|' src/test/result_tests.cpp
    -END VERIFY SCRIPT-
    cb7fce79c1
  53. test: Add `stringify` in tests when applicable
    For types used in more than one TU, they are added to `stringfy.h`.
    Otherwise, `stringify` is defined at the top the test file.
    e1ede36e31
  54. test: Require `stringify` implementation or explicit omission
    If there is no meaningful string representation for a type being
    checked, this fails with a `static_assert`. If the test writer does not
    want to add a string representation, there is a `CHECK_NO_DISPLAY` macro
    for explicit opt-out.
    fec57f54f1
  55. depends: drop test from Boost libraries c9dd02ecbe
  56. cmake: drop vcpkg Boost Test check 8dac989dc1
  57. vcpkg: drop boost-test dependency 9f7cba766f
  58. guix: Drop `Boost.Test` unused workaround fff8bc3a7a
  59. rustaceanrob force-pushed on Aug 1, 2026
  60. rustaceanrob commented at 10:20 AM on August 3, 2026: member

    I walked back the comment above on the basis that the test framework should not hide debug behavior implicitly. && and || are delete in the latest push, which also includes the changes from #35729 once more.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-08-04 00:50 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me