Skip to content

Commit f064a6e

Browse files
committed
Merge rust-bitcoin#3804: Introduce cargo-mutants workflow
bfba2a8 Kill remaining mutants (Shing Him Ng) 871fa08 Fix typo in serde docs (Shing Him Ng) 462c7a1 Add weekly cargo-mutants workflow (Shing Him Ng) Pull request description: This PR introduces `cargo-mutants` via a Github weekly workflow, similar to how the formatter job runs. It can also be updated to run against [incremental changes in a PR](https://mutants.rs/pr-diff.html) or to create an issues that list the new mutants. To address rust-bitcoin#3796, I've configured it to only run in `units` for now since that's nearing 1.0. Here's a [sample run](https://github.com/shinghim/rust-bitcoin/actions/runs/12457984710) i did in my fork, if anyone would like to see what's in the `mutants-out` artifact that gets generated. ACKs for top commit: tcharding: ACK bfba2a8 apoelstra: ACK bfba2a8; successfully ran local tests Tree-SHA512: e4a44b6f5121e4238c1c3576616f551f4f43349cf5fd5ac1d6331f958a4458753a55519bdafc16965cb2e67201ef6c91b188c79ffcc222f780c421df9a701063
2 parents 11f5012 + bfba2a8 commit f064a6e

File tree

7 files changed

+72
-6
lines changed

7 files changed

+72
-6
lines changed

.cargo/mutants.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
additional_cargo_args = ["--all-features"]
2+
examine_globs = ["units/src/**/*.rs"]
3+
exclude_globs = [
4+
"units/src/amount/verification.rs" # kani tests
5+
]
6+
exclude_re = [
7+
"impl Debug",
8+
"impl Arbitrary",
9+
"impl Display",
10+
".*Error",
11+
# --------------------------------------------Crate-specific exclusions--------------------------------------------
12+
# Units
13+
# src/amount/mod.rs
14+
"parse_signed_to_satoshi", # Can't kill all mutants since there is no denomination smaller than Satoshi
15+
"fmt_satoshi_in", # Related to formatting/display
16+
"dec_width", # Replacing num /= 10 with num %=10 in a loop causes a timeout due to infinite loop
17+
# src/fee_rate/serde.rs
18+
"as_sat_per_kwu::opt::deserialize::<impl Visitor for VisitOpt>.*", # Replaces return value with Ok(Default::default()), which is the same as Ok(None)
19+
"as_sat_per_vb_floor::opt::deserialize::<impl Visitor for VisitOpt>.*", # Replaces return value with Ok(Default::default()), which is the same as Ok(None)
20+
"as_sat_per_vb_ceil::opt::deserialize::<impl Visitor for VisitOpt>.*", # Replaces return value with Ok(Default::default()), which is the same as Ok(None)
21+
# src/amount/serde.rs
22+
"as_sat::opt::deserialize::<impl Visitor for VisitOptAmt<X>>.*", # Replaces return value with Ok(Default::default()), which is the same as Ok(None)
23+
"as_btc::opt::deserialize::<impl Visitor for VisitOptAmt<X>>.*", # Replaces return value with Ok(Default::default()), which is the same as Ok(None)
24+
"as_str::opt::deserialize::<impl Visitor for VisitOptAmt<X>>.*", # Replaces return value with Ok(Default::default()), which is the same as Ok(None)
25+
# src/locktime/relative.rs
26+
"Time::to_consensus_u32" # It will replace | with ^, which will return the same value since the XOR is always taken against the u16 and an all-zero bitmask
27+
]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Weekly cargo-mutants
2+
on:
3+
schedule:
4+
- cron: "0 0 * * 0" # runs weekly on Sunday at 00:00
5+
workflow_dispatch: # allows manual triggering
6+
jobs:
7+
cargo-mutants:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
- uses: taiki-e/install-action@v2
12+
with:
13+
tool: cargo-mutants
14+
- run: cargo mutants --in-place --no-shuffle
15+
- uses: actions/upload-artifact@v4
16+
if: always()
17+
with:
18+
name: mutants.out
19+
path: mutants.out
20+
- name: Check for new mutants
21+
if: always()
22+
run: |
23+
if [ -s mutants.out/missed.txt ]; then
24+
echo "New missed mutants found"
25+
gh issue create \
26+
--title "New Mutants Found" \
27+
--body "$(cat <<EOF
28+
Displaying up to the first 10 mutants:
29+
30+
$(head -n 10 mutants.out/missed.txt)
31+
32+
For the complete list, please check the [mutants.out artifact](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}).
33+
EOF
34+
)"
35+
echo "create_issue=true" >> $GITHUB_ENV
36+
else
37+
echo "No new mutants found"
38+
echo "create_issue=false" >> $GITHUB_ENV
39+
fi
40+
env:
41+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ hashes/target
1414

1515
# Test artifacts
1616
bitcoin/dep_test
17+
mutants.out*
1718

1819
# Fuzz artifacts
1920
hfuzz_target

units/src/amount/tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,10 +1014,12 @@ fn sum_amounts() {
10141014
assert_eq!([].iter().sum::<SignedAmount>(), SignedAmount::ZERO);
10151015

10161016
let amounts = [sat(42), sat(1337), sat(21)];
1017+
assert_eq!(amounts.iter().sum::<Amount>(), sat(1400));
10171018
let sum = amounts.into_iter().sum::<Amount>();
10181019
assert_eq!(sum, sat(1400));
10191020

10201021
let amounts = [ssat(-42), ssat(1337), ssat(21)];
1022+
assert_eq!(amounts.iter().sum::<SignedAmount>(), ssat(1316));
10211023
let sum = amounts.into_iter().sum::<SignedAmount>();
10221024
assert_eq!(sum, ssat(1316));
10231025
}

units/src/fee_rate/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ impl FeeRate {
6969
pub const fn to_sat_per_vb_floor(self) -> u64 { self.0 / (1000 / 4) }
7070

7171
/// Converts to sat/vB rounding up.
72-
/// TODO: cargo-mutants will try to replace - with /, which results in 1000 / 4 / 1 which is also 250.
73-
/// Since we're addressing the mutants before introducing the cargo-mutants workflow, come back later
74-
/// and skip this function in the mutants.toml config file
7572
pub const fn to_sat_per_vb_ceil(self) -> u64 { (self.0 + (1000 / 4 - 1)) / (1000 / 4) }
7673

7774
/// Checked multiplication.

units/src/fee_rate/serde.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ pub mod as_sat_per_vb_ceil {
171171
//! Serialize and deserialize [`FeeRate`] denominated in satoshis per virtual byte.
172172
//!
173173
//! When serializing use ceil division to convert per kwu to per virtual byte.
174-
//! Use with `#[serde(with = "fee_rate::serde::as_sat_per_vb")]`.
174+
//! Use with `#[serde(with = "fee_rate::serde::as_sat_per_vb_ceil")]`.
175175
176176
use serde::{Deserialize, Deserializer, Serialize, Serializer};
177177

units/src/locktime/relative.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ impl Time {
116116

117117
/// Returns the `u32` value used to encode this locktime in an nSequence field or
118118
/// argument to `OP_CHECKSEQUENCEVERIFY`.
119-
/// TODO: Skip this in cargo-mutants. It will replace | with ^, which will return the same
120-
/// value since the XOR is always taken against the u16 and an all-zero bitmask
121119
#[inline]
122120
pub const fn to_consensus_u32(self) -> u32 {
123121
(1u32 << 22) | self.0 as u32 // cast safety: u32 is wider than u16 on all architectures

0 commit comments

Comments
 (0)