Skip to content

Conversation

@ZocoLini
Copy link
Collaborator

@ZocoLini ZocoLini commented Jan 8, 2026

Summary by CodeRabbit

  • Chores
    • Consolidated testing infrastructure by removing the separate shared test-utils crate and integrating test helpers into each crate.
    • Standardized and simplified test data creation across the codebase for more consistent test behavior.
    • Exposed test utilities behind feature flags so they are only included during testing or when explicitly enabled.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

Consolidates and removes the standalone test-utils crate; adds conditional test_utils modules and dummy constructors across multiple crates; updates workspace/CI to drop the centralized test-utils; refactors many tests to use in-crate dummy helpers instead of removed utilities.

Changes

Cohort / File(s) Summary
Workspace & CI
\.github/ci-groups.yml``, Cargo.toml
Removed dashcore-test-utils from CI group and workspace members.
Removed standalone test-utils crate
test-utils/Cargo.toml, test-utils/src/lib.rs, test-utils/src/builders.rs, test-utils/src/fixtures.rs, test-utils/src/helpers.rs, test-utils/src/macros.rs
Deleted the entire crate and its builders, fixtures, helpers, and macros (public APIs and tests removed).
dash: test utilities added
dash/Cargo.toml, dash/src/lib.rs, dash/src/test_utils/*
Added test-utils feature and a conditional test_utils module containing dummy constructors (address, block, header, filter, instantlock, transaction, chainlock).
dash-spv: feature + test utilities
dash-spv/Cargo.toml, dash-spv/src/lib.rs, dash-spv/src/test_utils/*
Added test-utils feature, new test_utils module and dummy constructors (ChainTip, ChainWork, Checkpoint, FilterMatch); removed use of external test utils.
dash-spv: tests refactored
dash-spv/src/chain/*, dash-spv/src/mempool_filter.rs, dash-spv/src/validation/instantlock.rs, dash-spv/src/storage/*, dash-spv/src/network/mod.rs, dash-spv/tests/block_download_test.rs, dash-spv/src/client/message_handler_test.rs, dash-spv/src/client/mod.rs
Rewrote many tests to use new dummy constructors and in-crate MockNetworkManager; removed/trimmed extensive test scaffolding and the test-only mock submodule.
key-wallet-manager: feature + mocks
key-wallet-manager/Cargo.toml, key-wallet-manager/src/lib.rs, key-wallet-manager/src/test_utils/*, key-wallet-manager/tests/spv_integration_tests.rs
Added test-utils feature, moved tokio to dependencies, replaced dashcore-test-utils dev-dep with feature-gated dashcore, and added MockWallet/NonMatchingMockWallet test utilities.
key-wallet: test helpers updated
key-wallet/Cargo.toml, key-wallet/src/test_utils/*, key-wallet/src/*, key-wallet/tests/*
Removed old test_address helper, renamed new_test -> dummy for UTXO factories, added dummy constructors for accounts/wallets; updated tests to use these dummies.
key-wallet-ffi & tests
key-wallet-ffi/src/utxo_tests.rs
Updated tests to call Utxo::dummy_batch(...) instead of new_test_batch(...).

Sequence Diagram(s)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I munched the old utils, hopped them apart,

Scattered dummy carrots into every crate's heart.
Tests now nibble neat bits, no central store to chase,
A tidy burrow of helpers, each in its own place. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 74.59% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'refactor: add test_utils modules' directly and accurately describes the primary change: introducing new test_utils modules across multiple crates in the repository.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ZocoLini ZocoLini marked this pull request as draft January 8, 2026 20:34
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (13)
key-wallet/src/test_utils/utxo.rs (1)

7-40: Consider parameterizing the network for broader test coverage.

The dummy constructors currently hardcode Network::Testnet (Line 32), which prevents creating dummy UTXOs for mainnet tests. According to coding guidelines, tests should cover both mainnet and testnet configurations. Consider adding a network parameter to dummy and dummy_batch methods, or providing separate constructors for each network.

As per coding guidelines, tests should cover both mainnet and testnet configurations.

♻️ Proposed refactor
 impl Utxo {
-    pub fn dummy(id: u8, value: u64, height: u32, coinbase: bool, confirmed: bool) -> Self {
-        Self::dummy_batch(id..id + 1, value, height, coinbase, confirmed).remove(0)
+    pub fn dummy(network: Network, id: u8, value: u64, height: u32, coinbase: bool, confirmed: bool) -> Self {
+        Self::dummy_batch(network, id..id + 1, value, height, coinbase, confirmed).remove(0)
     }

     pub fn dummy_batch(
+        network: Network,
         ids_range: Range<u8>,
         value: u64,
         height: u32,
         coinbase: bool,
         confirmed: bool,
     ) -> Vec<Self> {
         ids_range
             .enumerate()
             .map(|(i, id)| {
                 let outpoint = OutPoint::new(Txid::from([id; 32]), i as u32);

                 let txout = TxOut {
                     value,
                     script_pubkey: ScriptBuf::new(),
                 };

                 let mut utxo = Utxo::new(
                     outpoint,
                     txout,
-                    Address::dummy(Network::Testnet, id as usize),
+                    Address::dummy(network, id as usize),
                     height,
                     coinbase,
                 );
                 utxo.is_confirmed = confirmed;
                 utxo
             })
             .collect()
     }
 }
key-wallet-manager/src/test_utils/wallet.rs (3)

11-40: Add documentation for test mock API.

The MockWallet struct and its public methods lack documentation explaining their purpose, usage patterns, and how they differ from real wallet implementations. This is especially important for test utilities that will be used across multiple crates.

📝 Suggested documentation structure
+/// Mock wallet implementation for testing purposes.
+///
+/// This mock records all block and transaction processing operations and allows
+/// pre-configuring transaction effects for testing. Unlike real wallets, it:
+/// - Returns ALL transactions in a block as "relevant"
+/// - Always returns true for compact filter checks
+/// - Does not perform actual cryptographic operations
+///
+/// # Example
+/// ```no_run
+/// let mut wallet = MockWallet::new();
+/// wallet.set_effect(txid, 1000, vec!["address1".to_string()]).await;
+/// ```
 pub struct MockWallet {

19-26: Consider simplifying constructor with Default trait.

Since MockWallet derives Default, the new() method could delegate to Self::default() for consistency.

♻️ Simplified implementation
 impl MockWallet {
     pub fn new() -> Self {
-        Self {
-            processed_blocks: Arc::new(Mutex::new(Vec::new())),
-            processed_transactions: Arc::new(Mutex::new(Vec::new())),
-            effects: Arc::new(Mutex::new(BTreeMap::new())),
-        }
+        Self::default()
     }

83-86: Consider simplifying constructor with Default trait.

The new() method is redundant with the derived Default trait.

♻️ Simplified implementation
 impl NonMatchingMockWallet {
     pub fn new() -> Self {
-        Self {}
+        Self::default()
     }
 }
dash/src/test_utils/mod.rs (1)

1-6: Add module-level documentation.

The test utilities module lacks documentation explaining what utilities are provided and how they should be used. This is important for discoverability across the workspace.

📝 Suggested documentation
+//! Test utilities for the dashcore crate.
+//!
+//! This module provides dummy constructors and test helpers for various
+//! Dash types to facilitate deterministic testing. Available utilities:
+//!
+//! - `Address::dummy()` - Generate test addresses
+//! - `Block::dummy()` - Generate test blocks and headers
+//! - `ChainLock::dummy()` - Generate test chain locks
+//! - `FilterHeader::dummy()` - Generate test filter headers
+//! - `InstantLock::dummy()` - Generate test instant locks
+//! - `Transaction::dummy()` - Generate test transactions
+//!
+//! These utilities are only available when the `test-utils` feature is enabled
+//! or when building tests.
+
 mod address;
 mod block;
 mod chainlock;
 mod filter;
 mod instantlock;
 mod transaction;
dash-spv/src/test_utils/chain_tip.rs (2)

6-8: Consider parameterizing the network for test flexibility.

The method hardcodes Network::Dash, which limits testing flexibility. According to coding guidelines and learnings, tests should cover both mainnet and testnet configurations.

♻️ Proposed enhancement
-    pub fn dummy(height: u32, work_value: u8) -> ChainTip {
-        let mut header = genesis_block(Network::Dash).header;
+    pub fn dummy(network: Network, height: u32, work_value: u8) -> ChainTip {
+        let mut header = genesis_block(network).header;
         header.nonce = height; // Make it unique
 
         let chain_work = ChainWork::dummy(work_value);
 
         ChainTip::new(header, height, chain_work)
     }

Or provide separate convenience methods:

pub fn dummy_mainnet(height: u32, work_value: u8) -> ChainTip {
    Self::dummy(Network::Dash, height, work_value)
}

pub fn dummy_testnet(height: u32, work_value: u8) -> ChainTip {
    Self::dummy(Network::Testnet, height, work_value)
}

Based on learnings, tests should cover both mainnet and testnet configurations.


1-14: Add documentation explaining test-only behavior.

The dummy constructor lacks documentation and uses non-realistic values (nonce for uniqueness rather than proof-of-work). This should be clearly documented for test utility users.

📝 Suggested documentation
 impl ChainTip {
+    /// Creates a dummy ChainTip for testing purposes.
+    ///
+    /// This constructor creates a ChainTip with non-realistic values:
+    /// - Uses the genesis block header as a base
+    /// - Sets `nonce` to the `height` value for uniqueness (not actual PoW)
+    /// - Uses a dummy ChainWork derived from `work_value`
+    ///
+    /// # Parameters
+    /// - `height`: Block height, also used as nonce for uniqueness
+    /// - `work_value`: Value passed to `ChainWork::dummy()` for chain work calculation
+    ///
+    /// # Note
+    /// This is for testing only. Real blockchain headers have nonces derived from
+    /// proof-of-work mining, not arbitrary height values.
     pub fn dummy(height: u32, work_value: u8) -> ChainTip {
         let mut header = genesis_block(Network::Dash).header;
         header.nonce = height; // Make it unique
 
         let chain_work = ChainWork::dummy(work_value);
 
         ChainTip::new(header, height, chain_work)
     }
 }
key-wallet/src/wallet/managed_wallet_info/coin_selection.rs (1)

744-750: Consider using unique UTXO IDs for better test robustness.

While using id=0 for all test UTXOs works for these specific tests, consider whether future tests might benefit from unique IDs. This could help catch issues related to UTXO identification and prevent subtle bugs if the implementation ever relies on unique identifiers.

💡 Optional enhancement for future consideration
 let utxos = vec![
-    Utxo::dummy(0, 100, 100, false, true),
-    Utxo::dummy(0, 200, 100, false, true),
-    Utxo::dummy(0, 300, 100, false, true),
-    Utxo::dummy(0, 500, 100, false, true),
-    Utxo::dummy(0, 1000, 100, false, true),
-    Utxo::dummy(0, 2000, 100, false, true),
+    Utxo::dummy(1, 100, 100, false, true),
+    Utxo::dummy(2, 200, 100, false, true),
+    Utxo::dummy(3, 300, 100, false, true),
+    Utxo::dummy(4, 500, 100, false, true),
+    Utxo::dummy(5, 1000, 100, false, true),
+    Utxo::dummy(6, 2000, 100, false, true),
 ];

This change is not required for correctness but could improve test robustness if UTXO identification becomes relevant in future implementations.

dash/src/test_utils/instantlock.rs (2)

1-22: Consider parameterizing the network for flexibility.

The dummy constructor hardcodes Network::Testnet at line 10. While this works for most test scenarios, consider adding a network parameter to support both mainnet and testnet testing, consistent with the coding guideline to test both configurations.

♻️ Optional refactor to parameterize network
 impl InstantLock {
-    pub fn dummy(transaction_input_ids: Range<u8>) -> InstantLock {
-        let address = Address::dummy(crate::Network::Testnet, 0);
+    pub fn dummy(network: crate::Network, transaction_input_ids: Range<u8>) -> InstantLock {
+        let address = Address::dummy(network, 0);
         let tx = Transaction::dummy(&address, transaction_input_ids, &[COIN_VALUE]);
         let inputs = tx.input.iter().map(|input| input.previous_output).collect();
 
         InstantLock {
             version: 1,
             inputs,
             txid: tx.txid(),
             signature: BLSSignature::from([1; 96]),
             cyclehash: BlockHash::dummy(0),
         }
     }
 }

As per coding guidelines: Test both mainnet and testnet configurations.


8-22: Add documentation for the dummy constructor.

Consider adding a doc comment explaining the purpose of this test utility and when to use it. This helps maintain clarity as the codebase grows.

📝 Suggested documentation
 impl InstantLock {
+    /// Creates a dummy InstantLock for testing purposes.
+    ///
+    /// # Parameters
+    /// * `transaction_input_ids` - Range of input IDs to include in the transaction
+    ///
+    /// # Note
+    /// This creates an InstantLock with placeholder values suitable for testing.
+    /// The signature and cyclehash are not cryptographically valid.
     pub fn dummy(transaction_input_ids: Range<u8>) -> InstantLock {
dash/src/test_utils/transaction.rs (1)

17-23: Consider more appropriate script_sig for test realism.

Line 19 sets script_sig to address.script_pubkey(), which is semantically incorrect. The script_sig should contain an unlocking script (signature + public key), while script_pubkey is the locking script. This makes the dummy transactions technically invalid.

For test utilities that don't validate scripts, this may be acceptable, but it could cause issues if any tests attempt script validation. Consider either:

  1. Using an empty script_sig (ScriptBuf::new()) to clearly indicate these are invalid/dummy transactions
  2. Documenting this limitation in a comment
  3. If script validation is needed, generating a proper unlocking script
💡 Suggested documentation or alternative

Option 1: Add a comment explaining the limitation:

                TxIn {
                    previous_output: OutPoint::new(Txid::from(txid_bytes), i as u32),
+                   // Note: Using script_pubkey as script_sig for dummy data.
+                   // These transactions are not script-valid.
                    script_sig: address.script_pubkey(),
                    sequence: 0xffffffff,
                    witness: Witness::new(),
                }

Option 2: Use empty script_sig:

                TxIn {
                    previous_output: OutPoint::new(Txid::from(txid_bytes), i as u32),
-                   script_sig: address.script_pubkey(),
+                   script_sig: ScriptBuf::new(), // Dummy transaction, no valid unlocking script
                    sequence: 0xffffffff,
                    witness: Witness::new(),
                }
dash-spv/src/test_utils/checkpoint.rs (1)

7-31: Consider documenting the dummy constructor's test data patterns.

The dummy constructor generates deterministic test data with specific patterns (e.g., masternode list names only at 100k block intervals, chain work as height * 1000). Adding a doc comment explaining these patterns would help test authors understand what test data they're working with.

📝 Suggested documentation
 impl Checkpoint {
+    /// Creates a dummy checkpoint for testing purposes.
+    ///
+    /// Generates deterministic test data:
+    /// - Block hashes derived from height
+    /// - Chain work: 0x{height * 1000}
+    /// - Fixed target: 0x1d00ffff
+    /// - Masternode list names only at heights that are multiples of 100,000
     pub fn dummy(height: u32, timestamp: u32) -> Checkpoint {
dash-spv/src/validation/instantlock.rs (1)

122-122: Remove redundant import.

The use dashcore_hashes::Hash; statement is redundant as Hash is already imported at line 4 at the module level and is available to the test module.

♻️ Proposed fix
 #[cfg(test)]
 mod tests {
     use super::*;
-    use dashcore_hashes::Hash;

@ZocoLini ZocoLini force-pushed the refactor/test-utils-modules branch from b16ed28 to e5a22dd Compare January 8, 2026 20:52
@github-actions
Copy link

github-actions bot commented Jan 9, 2026

This PR has merge conflicts with the base branch. Please rebase or merge the base branch into your branch to resolve them.

@github-actions github-actions bot added the merge-conflict The PR conflicts with the target branch. label Jan 9, 2026
@github-actions github-actions bot added merge-conflict The PR conflicts with the target branch. and removed merge-conflict The PR conflicts with the target branch. labels Jan 9, 2026
@github-actions
Copy link

This PR has merge conflicts with the base branch. Please rebase or merge the base branch into your branch to resolve them.

@github-actions github-actions bot removed the merge-conflict The PR conflicts with the target branch. label Jan 14, 2026
@ZocoLini ZocoLini marked this pull request as ready for review January 14, 2026 19:32
@github-actions github-actions bot added the merge-conflict The PR conflicts with the target branch. label Jan 14, 2026
@github-actions
Copy link

This PR has merge conflicts with the base branch. Please rebase or merge the base branch into your branch to resolve them.

@github-actions github-actions bot removed the merge-conflict The PR conflicts with the target branch. label Jan 15, 2026
@xdustinface xdustinface changed the title Refactor: test utils modules refactor: test utils modules Jan 16, 2026
@xdustinface xdustinface changed the title refactor: test utils modules refactor: add test_utils modules Jan 16, 2026
@xdustinface xdustinface merged commit 9f1a9b4 into v0.42-dev Jan 16, 2026
82 of 83 checks passed
@xdustinface xdustinface deleted the refactor/test-utils-modules branch January 16, 2026 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants