diff --git a/crates/forge/bin/cmd/test/mod.rs b/crates/forge/bin/cmd/test/mod.rs index 6d53a4756bd7..0e87a4c66915 100644 --- a/crates/forge/bin/cmd/test/mod.rs +++ b/crates/forge/bin/cmd/test/mod.rs @@ -499,6 +499,7 @@ impl TestArgs { runner.decode_internal = InternalTraceMode::Full; } + // Run tests in a non-streaming fashion and collect results for serialization. if self.json { let results = runner.test_collect(filter); println!("{}", serde_json::to_string(&results)?); @@ -516,7 +517,7 @@ impl TestArgs { let libraries = runner.libraries.clone(); - // Run tests. + // Run tests in a streaming fashion. let (tx, rx) = channel::<(String, SuiteResult)>(); let timer = Instant::now(); let show_progress = config.show_progress; diff --git a/crates/forge/src/result.rs b/crates/forge/src/result.rs index 0e00bb5e2773..a6d7fded9c48 100644 --- a/crates/forge/src/result.rs +++ b/crates/forge/src/result.rs @@ -393,7 +393,6 @@ pub struct TestResult { pub kind: TestKind, /// Traces - #[serde(skip)] pub traces: Traces, /// Additional traces to use for gas report. diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 28362671b756..f8b54cc4126e 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -274,6 +274,47 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) "#]]); }); +const SIMPLE_CONTRACT: &str = r#" +import "./test.sol"; + +contract SimpleContract { + uint256 public num; + + function setValues(uint256 _num) public { + num = _num; + } +} + +contract SimpleContractTest is DSTest { + function test() public { + SimpleContract c = new SimpleContract(); + c.setValues(100); + } +} + "#; + +forgetest!(can_run_test_with_json_output_verbose, |prj, cmd| { + prj.insert_ds_test(); + + prj.add_source("Simple.t.sol", SIMPLE_CONTRACT).unwrap(); + + // Assert that with verbose output the json output includes the traces + cmd.args(["test", "-vvv", "--json"]) + .assert_success() + .stdout_eq(file!["../fixtures/SimpleContractTestVerbose.json": Json]); +}); + +forgetest!(can_run_test_with_json_output_non_verbose, |prj, cmd| { + prj.insert_ds_test(); + + prj.add_source("Simple.t.sol", SIMPLE_CONTRACT).unwrap(); + + // Assert that without verbose output the json output does not include the traces + cmd.args(["test", "--json"]) + .assert_success() + .stdout_eq(file!["../fixtures/SimpleContractTestNonVerbose.json": Json]); +}); + // tests that `forge test` will pick up tests that are stored in the `test = ` config value forgetest!(can_run_test_in_custom_test_folder, |prj, cmd| { prj.insert_ds_test(); diff --git a/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json b/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json new file mode 100644 index 000000000000..8fd8a0faef53 --- /dev/null +++ b/crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json @@ -0,0 +1,27 @@ +{ + "src/Simple.t.sol:SimpleContractTest": { + "duration": "{...}", + "test_results": { + "test()": { + "status": "Success", + "reason": null, + "counterexample": null, + "logs": [], + "kind": { + "Unit": { + "gas": "{...}" + } + }, + "traces": [], + "labeled_addresses": {}, + "duration": { + "secs": "{...}", + "nanos": "{...}" + }, + "breakpoints": {}, + "gas_snapshots": {} + } + }, + "warnings": [] + } +} \ No newline at end of file diff --git a/crates/forge/tests/fixtures/SimpleContractTestVerbose.json b/crates/forge/tests/fixtures/SimpleContractTestVerbose.json new file mode 100644 index 000000000000..c7f47cf53477 --- /dev/null +++ b/crates/forge/tests/fixtures/SimpleContractTestVerbose.json @@ -0,0 +1,172 @@ +{ + "src/Simple.t.sol:SimpleContractTest": { + "duration": "{...}", + "test_results": { + "test()": { + "status": "Success", + "reason": null, + "counterexample": null, + "logs": [], + "kind": { + "Unit": { + "gas": "{...}" + } + }, + "traces": [ + [ + "Deployment", + { + "arena": [ + { + "parent": null, + "children": [], + "idx": 0, + "trace": { + "depth": 0, + "success": true, + "caller": "0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38", + "address": "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496", + "maybe_precompile": false, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "CREATE", + "value": "0x0", + "data": "{...}", + "output": "{...}", + "gas_used": "{...}", + "gas_limit": "{...}", + "status": "Return", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [], + "ordering": [] + } + ] + } + ], + [ + "Execution", + { + "arena": [ + { + "parent": null, + "children": [ + 1, + 2 + ], + "idx": 0, + "trace": { + "depth": 0, + "success": true, + "caller": "0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38", + "address": "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496", + "maybe_precompile": null, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "CALL", + "value": "0x0", + "data": "0xf8a8fd6d", + "output": "0x", + "gas_used": "{...}", + "gas_limit": "{...}", + "status": "Stop", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [], + "ordering": [ + { + "Call": 0 + }, + { + "Call": 1 + } + ] + }, + { + "parent": 0, + "children": [], + "idx": 1, + "trace": { + "depth": 1, + "success": true, + "caller": "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496", + "address": "0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f", + "maybe_precompile": false, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "CREATE", + "value": "0x0", + "data": "{...}", + "output": "{...}", + "gas_used": "{...}", + "gas_limit": "{...}", + "status": "Return", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [], + "ordering": [] + }, + { + "parent": 0, + "children": [], + "idx": 2, + "trace": { + "depth": 1, + "success": true, + "caller": "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496", + "address": "0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f", + "maybe_precompile": null, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "CALL", + "value": "0x0", + "data": "0xe26d14740000000000000000000000000000000000000000000000000000000000000064", + "output": "0x", + "gas_used": "{...}", + "gas_limit": "{...}", + "status": "Stop", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [], + "ordering": [] + } + ] + } + ] + ], + "labeled_addresses": {}, + "duration": { + "secs": "{...}", + "nanos": "{...}" + }, + "breakpoints": {}, + "gas_snapshots": {} + } + }, + "warnings": [] + } +} \ No newline at end of file