Last active
April 24, 2025 21:20
-
-
Save moodmosaic/5886807f96afbe81ad3f7dd68186b808 to your computer and use it in GitHub Desktop.
madhouse-rs playground
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# Test run summary | |
# ================ | |
# | |
# Basic test run: | |
# ./play.sh | |
# | |
# MADHOUSE mode (randomized fuzzing): | |
# MADHOUSE=1 ./play.sh | |
# | |
# Navigate to preserved temp directory after failure: | |
# cd /tmp/play-<random>/ | |
# | |
# Enter test crate subdirectory: | |
# cd counter/ | |
# | |
# Re-run failed test with shrink iteration cap: | |
# MADHOUSE=1 PROPTEST_MAX_SHRINK_ITERS=50 cargo test | |
# | |
# Typical failure: | |
# Counter value exceeded maximum allowed. | |
# | |
# Failing inputs are saved in: | |
# counter/proptest-regressions/lib.txt | |
# | |
# Test commands: | |
# INCREMENT(n) | |
# DECREMENT(n) | |
# | |
# Observed behavior: | |
# - Normal runs test a few hand-picked inputs. | |
# - MADHOUSE mode generates large randomized sequences. | |
# - Panics if counter exceeds hardcoded max (100). | |
# | |
# Cleanup: | |
# Temp dirs preserved only on failure. | |
set -e | |
tmp=$(mktemp -d /tmp/play-XXXXXXXX) | |
echo "Using temp dir: $tmp" | |
cleanup() { | |
if [ $? -ne 0 ]; then | |
echo | |
echo "Test failed. Temp project preserved at:" | |
echo " $tmp" | |
else | |
rm -rf "$tmp" | |
fi | |
} | |
trap cleanup EXIT | |
cargo new --lib "$tmp/counter" >/dev/null | |
cd "$tmp/counter" | |
cat > Cargo.toml <<EOF | |
[package] | |
name = "counter" | |
version = "0.1.0" | |
edition = "2021" | |
[dependencies] | |
madhouse = { git = "https://github.com/stacks-network/madhouse-rs.git", rev = "4e993262740c80682dae112876f9252a759538a5" } | |
proptest = { git = "https://github.com/proptest-rs/proptest.git", rev = "c9bdf18c232665b2b740c667c81866b598d06dc7" } | |
EOF | |
cat > src/lib.rs <<'EOF' | |
use madhouse::*; | |
use proptest::prelude::*; | |
use std::sync::Arc; | |
#[derive(Debug, Clone, Default)] | |
struct CounterState { | |
value: u32, | |
} | |
impl State for CounterState {} | |
#[derive(Clone, Debug)] | |
struct CounterContext; | |
impl Default for CounterContext { | |
fn default() -> Self { | |
CounterContext | |
} | |
} | |
impl TestContext for CounterContext {} | |
#[derive(Clone, Debug)] | |
struct Increment { | |
amount: u32, | |
} | |
impl Command<CounterState, CounterContext> for Increment { | |
fn check(&self, _: &CounterState) -> bool { | |
true | |
} | |
fn apply(&self, state: &mut CounterState) { | |
state.value += self.amount; | |
assert!( | |
state.value <= 100, | |
"Counter value exceeded maximum allowed: {}", | |
state.value | |
); | |
} | |
fn label(&self) -> String { | |
format!("INCREMENT({})", self.amount) | |
} | |
fn build(_: Arc<CounterContext>) | |
-> impl Strategy<Value = CommandWrapper<CounterState, CounterContext>> | |
{ | |
(1..=50u32).prop_map(|amount| { | |
CommandWrapper::new(Increment { amount }) | |
}) | |
} | |
} | |
#[derive(Clone, Debug)] | |
struct Decrement { | |
amount: u32, | |
} | |
impl Command<CounterState, CounterContext> for Decrement { | |
fn check(&self, state: &CounterState) -> bool { | |
state.value >= self.amount | |
} | |
fn apply(&self, state: &mut CounterState) { | |
state.value -= self.amount; | |
} | |
fn label(&self) -> String { | |
format!("DECREMENT({})", self.amount) | |
} | |
fn build(_: Arc<CounterContext>) | |
-> impl Strategy<Value = CommandWrapper<CounterState, CounterContext>> | |
{ | |
(1..=10u32).prop_map(|amount| { | |
CommandWrapper::new(Decrement { amount }) | |
}) | |
} | |
} | |
#[test] | |
fn test_counter_increment() { | |
let ctx = Arc::new(CounterContext::default()); | |
scenario![ctx, Increment, Decrement]; | |
} | |
EOF | |
"$@" cargo test -- --nocapture |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
nikos@debian-linux:~/play$ ./play.sh | |
Using temp dir: /tmp/play-b88B4mna | |
Creating library `counter` package | |
running 1 test | |
=== New Test Run (deterministic mode) === | |
Selected: | |
01. INCREMENT(38) | |
02. DECREMENT(6) | |
Executed: | |
01. INCREMENT(38) (42.00ns) | |
02. DECREMENT(6) (42.00ns) | |
test test_counter_increment ... ok | |
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
Doc-tests counter | |
running 0 tests | |
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
nikos@debian-linux:~/play$ MADHOUSE=1 ./play.sh | |
Using temp dir: /tmp/play-K6rke7L9 | |
running 1 test | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. DECREMENT(6) | |
02. DECREMENT(3) | |
03. DECREMENT(1) | |
04. DECREMENT(4) | |
05. DECREMENT(8) | |
06. INCREMENT(15) | |
Executed: | |
01. INCREMENT(15) (84.00ns) | |
test test_counter_increment ... ok | |
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
Doc-tests counter | |
running 0 tests | |
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
nikos@debian-linux:~/play$ MADHOUSE=1 ./play.sh | |
Using temp dir: /tmp/play-CGtyEoye | |
Creating library `counter` package | |
running 1 test | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(11) | |
02. DECREMENT(5) | |
03. DECREMENT(5) | |
04. DECREMENT(9) | |
05. DECREMENT(6) | |
06. INCREMENT(32) | |
07. DECREMENT(3) | |
08. DECREMENT(6) | |
09. INCREMENT(28) | |
10. DECREMENT(6) | |
11. DECREMENT(2) | |
Executed: | |
01. INCREMENT(11) (83.00ns) | |
02. DECREMENT(5) (42.00ns) | |
03. DECREMENT(5) (0.00ns) | |
04. INCREMENT(32) (42.00ns) | |
05. DECREMENT(3) (0.00ns) | |
06. DECREMENT(6) (42.00ns) | |
07. INCREMENT(28) (0.00ns) | |
08. DECREMENT(6) (42.00ns) | |
09. DECREMENT(2) (0.00ns) | |
test test_counter_increment ... ok | |
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
Doc-tests counter | |
running 0 tests | |
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
nikos@debian-linux:~/play$ MADHOUSE=1 ./play.sh | |
Using temp dir: /tmp/play-rzzoSh2k | |
running 1 test | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. DECREMENT(7) | |
02. INCREMENT(37) | |
Executed: | |
01. INCREMENT(37) (42.00ns) | |
test test_counter_increment ... ok | |
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
Doc-tests counter | |
running 0 tests | |
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
nikos@debian-linux:~/play$ MADHOUSE=1 ./play.sh | |
Using temp dir: /tmp/play-I3QUKSS3 | |
running 1 test | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 108 | |
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace | |
proptest: Saving this and future failures in /tmp/play-I3QUKSS3/counter/proptest-regressions/lib.txt | |
proptest: If this test was run on a CI system, you may wish to add the following line to your copy of the file. (You may need to create it.) | |
cc 665578fc6cc5394c2021bf132da80bee0fa7191fe27581039fb7dd8b9362353d | |
thread 'test_counter_increment' panicked at src/lib.rs:81:5: | |
Test failed: Counter value exceeded maximum allowed: 108. | |
minimal failing input: commands = [ | |
DECREMENT(8), | |
INCREMENT(38), | |
INCREMENT(25), | |
DECREMENT(8), | |
INCREMENT(43), | |
INCREMENT(10), | |
DECREMENT(5), | |
INCREMENT(36), | |
] | |
successes: 0 | |
local rejects: 0 | |
global rejects: 0 | |
test test_counter_increment ... FAILED | |
failures: | |
failures: | |
test_counter_increment | |
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
error: test failed, to rerun pass `--lib` | |
Test failed. Temp project preserved at: | |
/tmp/play-I3QUKSS3 | |
nikos@debian-linux:~/play$ cd /tmp/play-I3QUKSS3/ | |
nikos@debian-linux:/tmp/play-I3QUKSS3$ PROPTEST_MAX_SHRINK_ITERS=50 cargo test | |
error: could not find `Cargo.toml` in `/tmp/play-I3QUKSS3` or any parent directory | |
nikos@debian-linux:/tmp/play-I3QUKSS3$ ls | |
counter | |
nikos@debian-linux:/tmp/play-I3QUKSS3$ cd counter/ | |
nikos@debian-linux:/tmp/play-I3QUKSS3/counter$ MADHOUSE=1 PROPTEST_MAX_SHRINK_ITERS=50 cargo test | |
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.02s | |
Running unittests src/lib.rs (target/debug/deps/counter-ff4bc7cc425d0391) | |
running 1 test | |
test test_counter_increment ... FAILED | |
failures: | |
---- test_counter_increment stdout ---- | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 108 | |
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 108 | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 101 | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. DECREMENT(8) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
04. DECREMENT(5) | |
05. INCREMENT(36) | |
Executed: | |
01. INCREMENT(43) (42.00ns) | |
02. INCREMENT(10) (42.00ns) | |
03. DECREMENT(5) (0.00ns) | |
04. INCREMENT(36) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 101 | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 109 | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(25) | |
02. INCREMENT(10) | |
03. DECREMENT(5) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(25) (41.00ns) | |
02. INCREMENT(10) (42.00ns) | |
03. DECREMENT(5) (42.00ns) | |
04. INCREMENT(36) (41.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 109 | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(25) | |
02. INCREMENT(43) | |
03. DECREMENT(5) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(25) (41.00ns) | |
02. INCREMENT(43) (42.00ns) | |
03. DECREMENT(5) (42.00ns) | |
04. INCREMENT(36) (41.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 109 | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 114 | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(25) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
Executed: | |
01. INCREMENT(25) (41.00ns) | |
02. INCREMENT(43) (42.00ns) | |
03. INCREMENT(10) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 114 | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 102 | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(7) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(7) (0.00ns) | |
02. INCREMENT(43) (0.00ns) | |
03. INCREMENT(10) (0.00ns) | |
04. INCREMENT(36) (0.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(10) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(10) (42.00ns) | |
02. INCREMENT(43) (42.00ns) | |
03. INCREMENT(10) (41.00ns) | |
04. INCREMENT(36) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 101 | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(11) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(11) (41.00ns) | |
02. INCREMENT(43) (0.00ns) | |
03. INCREMENT(10) (42.00ns) | |
04. INCREMENT(36) (41.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 101 | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(22) | |
03. INCREMENT(10) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(12) (42.00ns) | |
02. INCREMENT(22) (0.00ns) | |
03. INCREMENT(10) (42.00ns) | |
04. INCREMENT(36) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(33) | |
03. INCREMENT(10) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(12) (0.00ns) | |
02. INCREMENT(33) (0.00ns) | |
03. INCREMENT(10) (42.00ns) | |
04. INCREMENT(36) (0.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(38) | |
03. INCREMENT(10) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(12) (0.00ns) | |
02. INCREMENT(38) (0.00ns) | |
03. INCREMENT(10) (0.00ns) | |
04. INCREMENT(36) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(41) | |
03. INCREMENT(10) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(12) (0.00ns) | |
02. INCREMENT(41) (42.00ns) | |
03. INCREMENT(10) (0.00ns) | |
04. INCREMENT(36) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(42) | |
03. INCREMENT(10) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(12) (0.00ns) | |
02. INCREMENT(42) (0.00ns) | |
03. INCREMENT(10) (42.00ns) | |
04. INCREMENT(36) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 101 | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(43) | |
03. INCREMENT(5) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(12) (0.00ns) | |
02. INCREMENT(43) (0.00ns) | |
03. INCREMENT(5) (0.00ns) | |
04. INCREMENT(36) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(43) | |
03. INCREMENT(8) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(12) (0.00ns) | |
02. INCREMENT(43) (0.00ns) | |
03. INCREMENT(8) (41.00ns) | |
04. INCREMENT(36) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(43) | |
03. INCREMENT(9) | |
04. INCREMENT(36) | |
Executed: | |
01. INCREMENT(12) (42.00ns) | |
02. INCREMENT(43) (41.00ns) | |
03. INCREMENT(9) (0.00ns) | |
04. INCREMENT(36) (0.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 101 | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
04. INCREMENT(18) | |
Executed: | |
01. INCREMENT(12) (41.00ns) | |
02. INCREMENT(43) (42.00ns) | |
03. INCREMENT(10) (42.00ns) | |
04. INCREMENT(18) (0.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
04. INCREMENT(27) | |
Executed: | |
01. INCREMENT(12) (41.00ns) | |
02. INCREMENT(43) (0.00ns) | |
03. INCREMENT(10) (0.00ns) | |
04. INCREMENT(27) (0.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
04. INCREMENT(32) | |
Executed: | |
01. INCREMENT(12) (0.00ns) | |
02. INCREMENT(43) (0.00ns) | |
03. INCREMENT(10) (0.00ns) | |
04. INCREMENT(32) (0.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
04. INCREMENT(34) | |
Executed: | |
01. INCREMENT(12) (42.00ns) | |
02. INCREMENT(43) (41.00ns) | |
03. INCREMENT(10) (42.00ns) | |
04. INCREMENT(34) (42.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
Selected: | |
01. INCREMENT(12) | |
02. INCREMENT(43) | |
03. INCREMENT(10) | |
04. INCREMENT(35) | |
Executed: | |
01. INCREMENT(12) (42.00ns) | |
02. INCREMENT(43) (0.00ns) | |
03. INCREMENT(10) (0.00ns) | |
04. INCREMENT(35) (0.00ns) | |
=== New Test Run (MADHOUSE mode) === | |
thread 'test_counter_increment' panicked at src/lib.rs:32:9: | |
Counter value exceeded maximum allowed: 101 | |
thread 'test_counter_increment' panicked at src/lib.rs:81:5: | |
Test failed: Counter value exceeded maximum allowed: 101. | |
minimal failing input: commands = [ | |
INCREMENT(12), | |
INCREMENT(43), | |
INCREMENT(10), | |
INCREMENT(36), | |
] | |
successes: 0 | |
local rejects: 0 | |
global rejects: 0 | |
failures: | |
test_counter_increment | |
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
error: test failed, to rerun pass `--lib` | |
nikos@debian-linux:/tmp/play-I3QUKSS3/counter$ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment