Skip to content

Commit cd3cd85

Browse files
committed
Add tests, remove autoset
1 parent fa5e94b commit cd3cd85

File tree

4 files changed

+143
-13
lines changed

4 files changed

+143
-13
lines changed

crates/forge/src/cmd/test/mod.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ pub struct TestArgs {
187187

188188
/// Maximum integer value for fuzz tests.
189189
/// Accepts decimal, hex (0x...), or keywords: "u128", "u64".
190-
/// Auto-set to u64::MAX when --polkadot is used (unless explicitly set).
191190
#[arg(long, env = "FOUNDRY_FUZZ_INT_MAX", value_name = "VALUE")]
192191
pub fuzz_int_max: Option<String>,
193192

@@ -328,18 +327,6 @@ impl TestArgs {
328327
config.polkadot.polkadot = Some(PolkadotMode::Pvm);
329328
}
330329

331-
// Auto-set max_fuzz_int to u64::MAX for Polkadot mode if not explicitly set.
332-
// This prevents overflow errors since Polkadot uses:
333-
// - u64 for block numbers and timestamps (most restrictive)
334-
// - u128 for balances (can still be tested up to u64::MAX)
335-
if config.polkadot.polkadot.is_some()
336-
&& config.fuzz.max_fuzz_int.is_none()
337-
&& self.fuzz_int_max.is_none()
338-
{
339-
config.fuzz.max_fuzz_int = Some(U256::from(u64::MAX));
340-
tracing::info!("Auto-setting fuzz integer max to u64::MAX for Polkadot compatibility");
341-
}
342-
343330
let mut strategy = utils::get_executor_strategy(&config);
344331

345332
// Explicitly enable isolation for gas reports for more correct gas accounting.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//! Tests for max_fuzz_int configuration limiting fuzz values.
2+
3+
use crate::test_helpers::TEST_DATA_DEFAULT;
4+
use alloy_primitives::U256;
5+
use forge::result::{SuiteResult, TestStatus};
6+
use foundry_test_utils::Filter;
7+
8+
/// Test that max_fuzz_int properly limits unsigned integers to [0, max].
9+
/// With max_fuzz_int = 255, all uint256 values should be <= 255.
10+
#[tokio::test(flavor = "multi_thread")]
11+
async fn test_fuzz_max_int_uint_limited() {
12+
let max_value = U256::from(u8::MAX);
13+
14+
let filter =
15+
Filter::new("testFuzzUint256Limited", "FuzzMaxIntTest", ".*/revive/FuzzMaxInt.t.sol");
16+
let mut runner = TEST_DATA_DEFAULT.runner_with(|config| {
17+
config.fuzz.max_fuzz_int = Some(max_value);
18+
config.fuzz.runs = 1000;
19+
});
20+
let results = runner.test_collect(&filter).unwrap();
21+
22+
for (_, SuiteResult { test_results, .. }) in results {
23+
for (test_name, result) in test_results {
24+
assert_eq!(
25+
result.status,
26+
TestStatus::Success,
27+
"Test {} should pass with max_fuzz_int limiting uint256 values to [0, 255].\nReason: {:?}",
28+
test_name,
29+
result.reason
30+
);
31+
}
32+
}
33+
}
34+
35+
/// Test that max_fuzz_int properly limits signed integers to [-(max+1), max].
36+
/// With max_fuzz_int = 255, signed integers should be in range [-256, 255].
37+
#[tokio::test(flavor = "multi_thread")]
38+
async fn test_fuzz_max_int_int_limited() {
39+
let max_value = U256::from(u8::MAX);
40+
41+
let filter =
42+
Filter::new("testFuzzInt256Limited", "FuzzMaxIntTest", ".*/revive/FuzzMaxInt.t.sol");
43+
let mut runner = TEST_DATA_DEFAULT.runner_with(|config| {
44+
config.fuzz.max_fuzz_int = Some(max_value);
45+
config.fuzz.runs = 1000;
46+
});
47+
let results = runner.test_collect(&filter).unwrap();
48+
49+
for (_, SuiteResult { test_results, .. }) in results {
50+
for (test_name, result) in test_results {
51+
assert_eq!(
52+
result.status,
53+
TestStatus::Success,
54+
"Test {} should pass with max_fuzz_int limiting int256 values to [-256, 255].\nReason: {:?}",
55+
test_name,
56+
result.reason
57+
);
58+
}
59+
}
60+
}
61+
62+
/// Test that without max_fuzz_int, uint256 values can exceed 255.
63+
#[tokio::test(flavor = "multi_thread")]
64+
async fn test_fuzz_no_limit_uint_exceeds() {
65+
let filter =
66+
Filter::new("testFuzzUint256Unlimited", "FuzzNoLimitTest", ".*/revive/FuzzMaxInt.t.sol");
67+
let mut runner = TEST_DATA_DEFAULT.runner_with(|config| {
68+
config.fuzz.max_fuzz_int = None; // No limit
69+
config.fuzz.runs = 1000;
70+
config.fuzz.seed = Some(U256::from(42u32)); // Fixed seed for reproducibility
71+
});
72+
let results = runner.test_collect(&filter).unwrap();
73+
74+
for (_, SuiteResult { test_results, .. }) in results {
75+
for (test_name, result) in test_results {
76+
assert_eq!(
77+
result.status,
78+
TestStatus::Failure,
79+
"Test {} should FAIL without max_fuzz_int as fuzzer generates values > 255.\nReason: {:?}",
80+
test_name,
81+
result.reason
82+
);
83+
}
84+
}
85+
}
86+
87+
/// Test that without max_fuzz_int, int256 values can exceed [-256, 255] range.
88+
#[tokio::test(flavor = "multi_thread")]
89+
async fn test_fuzz_no_limit_int_exceeds() {
90+
let filter =
91+
Filter::new("testFuzzInt256Unlimited", "FuzzNoLimitTest", ".*/revive/FuzzMaxInt.t.sol");
92+
let mut runner = TEST_DATA_DEFAULT.runner_with(|config| {
93+
config.fuzz.max_fuzz_int = None; // No limit
94+
config.fuzz.runs = 1000;
95+
config.fuzz.seed = Some(U256::from(42u32)); // Fixed seed for reproducibility
96+
});
97+
let results = runner.test_collect(&filter).unwrap();
98+
99+
for (_, SuiteResult { test_results, .. }) in results {
100+
for (test_name, result) in test_results {
101+
assert_eq!(
102+
result.status,
103+
TestStatus::Failure,
104+
"Test {} should FAIL without max_fuzz_int as fuzzer generates values outside [-256, 255].\nReason: {:?}",
105+
test_name,
106+
result.reason
107+
);
108+
}
109+
}
110+
}

crates/forge/tests/it/revive/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub mod cheat_prank;
1010
mod cheat_snapshot;
1111
pub mod cheat_store;
1212
pub mod cheats_individual;
13+
pub mod fuzz_max_int;
1314
pub mod migration;
1415
pub mod record_accesses;
1516
pub mod tx_gas_price;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
pragma solidity ^0.8.18;
3+
4+
import "ds-test/test.sol";
5+
6+
contract FuzzMaxIntTest is DSTest {
7+
// Test that unsigned integers are limited to max_fuzz_int.
8+
// With max_fuzz_int = 255, all uint256 values should be <= 255.
9+
function testFuzzUint256Limited(uint256 val) public {
10+
assertTrue(val <= 255, "uint256 should be limited to max_fuzz_int (255)");
11+
}
12+
13+
// Test that signed integers are limited to [-(max+1), max].
14+
// With max_fuzz_int = 255, int256 should be in range [-256, 255].
15+
function testFuzzInt256Limited(int256 val) public {
16+
assertTrue(val >= -256, "int256 should be >= -(max_fuzz_int+1) = -256");
17+
assertTrue(val <= 255, "int256 should be <= max_fuzz_int = 255");
18+
}
19+
}
20+
21+
contract FuzzNoLimitTest is DSTest {
22+
// This test should fail without max_fuzz_int as fuzzer will generate values > 255.
23+
function testFuzzUint256Unlimited(uint256 val) public {
24+
assertTrue(val <= 255, "Expected to fail: fuzzer should generate values > 255");
25+
}
26+
27+
// This test should fail without max_fuzz_int as fuzzer will generate values outside [-256, 255].
28+
function testFuzzInt256Unlimited(int256 val) public {
29+
bool inRange = val >= -256 && val <= 255;
30+
assertTrue(inRange, "Expected to fail: fuzzer should generate values outside [-256, 255]");
31+
}
32+
}

0 commit comments

Comments
 (0)