test: add comprehensive bech32 unit tests based on BIP-173 :christmas_tree: #34149

pull bitcoinbrisbane wants to merge 1 commits into bitcoin:master from bitcoinbrisbane:bech32-tests-upstream changing 1 files +280 −0
  1. bitcoinbrisbane commented at 0:48 am on December 25, 2025: none

    Description

    This PR improves unit test coverage for the bech32 encoding implementation by adding 9 new test cases based on the BIP-173 specification.

    Motivation

    The existing bech32 tests cover the standard test vectors from BIP-173/350 but don’t extensively test edge cases and error detection properties. Since bech32 is used for SegWit and Taproot addresses, comprehensive testing is important to catch potential regressions.

    Changes

    New test cases added to src/test/bech32_tests.cpp:

    Test Description
    bech32_charset_encoding Verifies all 32 valid characters encode and decode correctly
    bech32_roundtrip_encoding Tests encode/decode round-trip for data sizes 0-40 bytes
    bech32_length_limits Tests the 90-character maximum length boundary
    bech32_hrp_limits Tests HRP edge cases: minimum length, boundary ASCII chars (33, 126), separator in HRP
    bech32_single_error_detection Verifies single-character errors are detected at every position
    bech32_transposition_detection Verifies adjacent character transpositions are detected
    bech32_multiple_error_detection Tests guaranteed detection of 2, 3, and 4 errors
    bech32_case_sensitivity Tests uppercase, lowercase, and mixed case handling per BIP-173
    bech32_checksum_properties Verifies checksum is exactly 6 characters and deterministic

    These tests cover the following BIP-173 specification requirements:

    • Character set validation (32-character alphabet)
    • Maximum length enforcement (90 characters)
    • Error detection guarantees (up to 4 errors)
    • Case sensitivity rules (reject mixed case)
    • Checksum properties (6-character BCH code)

    References


    PR Checklist

    • Tests pass locally: ctest --test-dir build -R bech32
    • Code follows existing style in bech32_tests.cpp
    • Comments reference BIP-173 sections where applicable
    • No new dependencies introduced
  2. test: add comprehensive bech32 unit tests based on BIP-173
    Add 9 new test cases to improve bech32 encoding test coverage:
    
    - bech32_charset_encoding: Verify all 32 valid characters map correctly
    - bech32_roundtrip_encoding: Test encode/decode round-trip for data 0-40 bytes
    - bech32_length_limits: Test 90-character limit boundary conditions
    - bech32_hrp_limits: Test HRP edge cases (min length, boundary ASCII, separator)
    - bech32_single_error_detection: Verify single-character errors detected
    - bech32_transposition_detection: Verify adjacent character swaps detected
    - bech32_multiple_error_detection: Test 2, 3, 4 error detection guarantee
    - bech32_case_sensitivity: Test uppercase/lowercase/mixed case handling
    - bech32_checksum_properties: Verify checksum is 6 chars and deterministic
    
    These tests cover BIP-173 specification requirements including:
    - Character set validation
    - Maximum length enforcement (90 chars)
    - Error detection guarantees (up to 4 errors)
    - Case sensitivity rules
    - Checksum properties
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
    b148416a59
  3. DrahtBot added the label Tests on Dec 25, 2025
  4. DrahtBot commented at 0:48 am on December 25, 2025: contributor

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

    Code Coverage & Benchmarks

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

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    User requested bot ignore billymcbip

    If your review is incorrectly listed, please copy-paste <!–meta-tag:bot-skip–> into the comment that the bot should ignore.

    LLM Linter (✨ experimental)

    Possible places where comparison-specific test macros should replace generic comparisons:

    • src/test/bech32_tests.cpp: BOOST_CHECK(decoded.encoding == bech32::Encoding::BECH32) -> use BOOST_CHECK_EQUAL(decoded.encoding, bech32::Encoding::BECH32)
    • src/test/bech32_tests.cpp: BOOST_CHECK(decoded.encoding == encoding) -> use BOOST_CHECK_EQUAL(decoded.encoding, encoding)
    • src/test/bech32_tests.cpp: BOOST_CHECK(decoded.data == data) -> use BOOST_CHECK_EQUAL(decoded.data, data)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_at_limit.encoding == bech32::Encoding::BECH32) -> use BOOST_CHECK_EQUAL(dec_at_limit.encoding, bech32::Encoding::BECH32)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_at_limit.data == max_data) -> use BOOST_CHECK_EQUAL(dec_at_limit.data, max_data)
    • src/test/bech32_tests.cpp: BOOST_CHECK(too_long.size() > 90U) -> use BOOST_CHECK_GT(too_long.size(), 90U)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_too_long.encoding == bech32::Encoding::INVALID) -> use BOOST_CHECK_EQUAL(dec_too_long.encoding, bech32::Encoding::INVALID)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_min.encoding == bech32::Encoding::BECH32) -> use BOOST_CHECK_EQUAL(dec_min.encoding, bech32::Encoding::BECH32)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_boundary.encoding == bech32::Encoding::BECH32) -> use BOOST_CHECK_EQUAL(dec_boundary.encoding, bech32::Encoding::BECH32)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_with_one.encoding == bech32::Encoding::BECH32) -> use BOOST_CHECK_EQUAL(dec_with_one.encoding, bech32::Encoding::BECH32)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_empty.encoding == bech32::Encoding::INVALID) -> use BOOST_CHECK_EQUAL(dec_empty.encoding, bech32::Encoding::INVALID)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_valid.encoding == bech32::Encoding::BECH32) -> use BOOST_CHECK_EQUAL(dec_valid.encoding, bech32::Encoding::BECH32)
    • src/test/bech32_tests.cpp: BOOST_CHECK_MESSAGE(dec_corrupted.encoding == bech32::Encoding::INVALID, “Single error at position " + std::to_string(pos) + " was not detected”) -> use BOOST_CHECK_MESSAGE(dec_corrupted.encoding == bech32::Encoding::INVALID, …) replaced by BOOST_CHECK_MESSAGE(dec_corrupted.encoding == bech32::Encoding::INVALID, …) or better: BOOST_CHECK_MESSAGE(dec_corrupted.encoding == bech32::Encoding::INVALID, …) → preferably BOOST_CHECK_EQUAL(dec_corrupted.encoding, bech32::Encoding::INVALID) with an explanatory message via BOOST_CHECK_MESSAGE if desired (e.g. BOOST_CHECK_MESSAGE( dec_corrupted.encoding == bech32::Encoding::INVALID, … ) → BOOST_CHECK_EQUAL(dec_corrupted.encoding, bech32::Encoding::INVALID) for clearer diagnostics
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_transposed.encoding == bech32::Encoding::INVALID) (inside BOOST_CHECK_MESSAGE) -> prefer BOOST_CHECK_EQUAL(dec_transposed.encoding, bech32::Encoding::INVALID) (or BOOST_CHECK_MESSAGE around that if a custom message is needed)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID) (multiple-error blocks) -> use BOOST_CHECK_EQUAL(dec.encoding, bech32::Encoding::INVALID)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_upper.encoding == bech32::Encoding::BECH32) -> use BOOST_CHECK_EQUAL(dec_upper.encoding, bech32::Encoding::BECH32)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_lower.encoding == bech32::Encoding::BECH32) -> use BOOST_CHECK_EQUAL(dec_lower.encoding, bech32::Encoding::BECH32)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_mixed.encoding == bech32::Encoding::INVALID) -> use BOOST_CHECK_EQUAL(dec_mixed.encoding, bech32::Encoding::INVALID)
    • src/test/bech32_tests.cpp: BOOST_CHECK(dec_mixed_hrp.encoding == bech32::Encoding::INVALID) -> use BOOST_CHECK_EQUAL(dec_mixed_hrp.encoding, bech32::Encoding::INVALID)
    • src/test/bech32_tests.cpp: BOOST_CHECK(checksum1 != checksum2) -> use BOOST_CHECK_NE(checksum1, checksum2)
    • src/test/bech32_tests.cpp: BOOST_CHECK(enc1 != enc_diff_hrp) -> use BOOST_CHECK_NE(enc1, enc_diff_hrp)

    Notes:

    • Where a custom message is already used with BOOST_CHECK_MESSAGE(…), prefer replacing the comparison with the matching BOOST_CHECK_EQUAL/BOOST_CHECK_NE and, if you need the message, wrap it similarly with BOOST_CHECK_MESSAGE(, ) or use BOOST_CHECK_MESSAGE with the comparison expression left as-is but consider switching to the comparison-specific macro for clearer failure diffs.
    • Some checks use logical combinations (e.g., BOOST_CHECK(c < ‘A’ || c > ‘Z’)) or negations (BOOST_CHECK(!encoded.empty())); these are fine as-is.
    • If any suggested replacement compares containers where BOOST_CHECK_EQUAL may not produce the most readable output, consider BOOST_CHECK_EQUAL_COLLECTIONS for sequences (but BOOST_CHECK_EQUAL is an acceptable first improvement).

    2025-12-25

  5. bitcoinbrisbane renamed this:
    test: add comprehensive bech32 unit tests based on BIP-173
    test: add comprehensive bech32 unit tests based on BIP-173 :christmas_tree:
    on Dec 25, 2025
  6. bitcoinbrisbane marked this as ready for review on Dec 25, 2025
  7. DevPatel-11 commented at 7:46 am on December 25, 2025: none

    I verified the implementation against BIP-173 specification. The test coverage is comprehensive:

    • Character Set: Tests all 32 valid bech32 characters encode/decode correctly
    • Length Limits: Verifies 90-character maximum and rejection of 91+ characters
    • Error Detection: Tests single errors at all positions, transpositions, and multi-error detection
    • HRP Edge Cases: Minimum length (1 char), boundary ASCII values (33, 126), separator handling
    • Round-trip Encoding: Tests data sizes 0-40 bytes with both BECH32 and BECH32M
    • Case Sensitivity: Proper mixed-case rejection per BIP-173

    Suggestions for improvement:

    Consider using more specific BOOST assertion macros for better error diagnostics:

    • Lines 180, 208, 210, 232, 234, 241, 255, 262, 269, 275: BOOST_CHECK(decoded.encoding == bech32::Encoding::BECH32)BOOST_CHECK_EQUAL(decoded.encoding, bech32::Encoding::BECH32)

    Similar pattern throughout for equality comparisons would provide clearer failure messages.

    Nit: In bech32_length_limits test, a brief comment explaining the 90-character calculation (HRP + separator + data + 6-char checksum) would be helpful for future readers.

  8. billymcbip commented at 10:23 pm on December 27, 2025: contributor
    Leaning concept ACK, approach NACK. I suggest reducing the size of the diff by adding your test cases to the four existing functions (valid/invalid bech32/bech32m).
  9. maflcko commented at 5:21 pm on January 1, 2026: member

    Are you still working on this?

    Personally, I fail to see what coverage you are adding. Everything should already be covered, but if something is missing, you’ll have to show that it isn’t, and then show that your added tests are hitting that.

  10. DrahtBot added the label CI failed on Jan 2, 2026
  11. DrahtBot commented at 12:55 pm on January 2, 2026: contributor

    🚧 At least one of the CI tasks failed. Task lint: https://github.com/bitcoin/bitcoin/actions/runs/20496389555/job/59311707292 LLM reason (✨ experimental): Lint check failed due to locale-dependence warning being treated as an error (lint-locale-dependence.py).

    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.

  12. dergoegge commented at 2:08 pm on January 2, 2026: member

    Co-Authored-By: Claude Opus 4.5 noreply@anthropic.com

    Maybe it would make sense to add this to drahtbot’s llm detection heuristics?

  13. fanquake commented at 2:12 pm on January 2, 2026: member
    Duplicate of #34148?
  14. fanquake closed this on Jan 2, 2026

  15. maflcko referenced this in commit 0945546dd0 on Jan 2, 2026
  16. maflcko referenced this in commit a75df77d60 on Jan 2, 2026
  17. maflcko commented at 2:37 pm on January 2, 2026: member

    Co-Authored-By: Claude Opus 4.5 noreply@anthropic.com

    Maybe it would make sense to add this to drahtbot’s llm detection heuristics?

    Sure, done in https://github.com/maflcko/DrahtBot/commit/a75df77d6055c8614845f10df4dd37ab03162b1d


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-01-07 03:13 UTC

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