From 1eac5673774354a6f9b0f7953c4ab977a9da11c8 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Thu, 8 Aug 2024 14:14:50 +0000 Subject: [PATCH 01/47] test basic flow --- crates/cast/tests/cli/main.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 91d04f031c960..942059f51bf99 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -21,14 +21,22 @@ casttest!(latest_block, |_prj, cmd| { // Call `cast find-block` cmd.args(["block", "latest", "--rpc-url", eth_rpc_url.as_str()]); - let output = cmd.stdout_lossy(); - assert!(output.contains("transactions:")); - assert!(output.contains("gasUsed")); + cmd.assert_success().stdout_eq(str![[r#" +... +gasUsed [..] +... +transactions: [ +... +] + +"#]]); // cmd.cast_fuse().args(["block", "15007840", "-f", "hash", "--rpc-url", eth_rpc_url.as_str()]); - let output = cmd.stdout_lossy(); - assert_eq!(output.trim(), "0x950091817a57e22b6c1f3b951a15f52d41ac89b299cc8f9c89bb6d185f80c415") + cmd.assert_success().stdout_eq(str![[r#" +0x950091817a57e22b6c1f3b951a15f52d41ac89b299cc8f9c89bb6d185f80c415 + +"#]]); }); // tests that the `cast find-block` command works correctly From fcc447cd26586e33351397c9a875f52b9c31e61f Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Thu, 8 Aug 2024 14:32:26 +0000 Subject: [PATCH 02/47] establish required test list by build errors --- crates/test-utils/src/util.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 9b6380e0771fe..a875f66a89cc0 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -893,18 +893,18 @@ impl TestCommand { /// Executes the command and returns the stderr as lossy `String`. /// /// **Note**: This function checks whether the command was successful. - #[track_caller] - pub fn stdout_lossy(&mut self) -> String { - lossy_string(&self.output().stdout) - } + // #[track_caller] + // pub fn stdout_lossy(&mut self) -> String { + // lossy_string(&self.output().stdout) + // } /// Executes the command and returns the stderr as lossy `String`. /// /// **Note**: This function does **not** check whether the command was successful. - #[track_caller] - pub fn stderr_lossy(&mut self) -> String { - lossy_string(&self.unchecked_output().stderr) - } + // #[track_caller] + // pub fn stderr_lossy(&mut self) -> String { + // lossy_string(&self.unchecked_output().stderr) + // } /// Returns the output but does not expect that the command was successful #[track_caller] From 29083f572a4f4aef85316f74d851bdc32cee26e9 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Thu, 8 Aug 2024 14:56:00 +0000 Subject: [PATCH 03/47] experiment with abstractions --- crates/forge/tests/cli/svm.rs | 15 ++++++++++++++- crates/test-utils/src/util.rs | 16 ++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/crates/forge/tests/cli/svm.rs b/crates/forge/tests/cli/svm.rs index 8403053d84d6a..c69808aa3e21b 100644 --- a/crates/forge/tests/cli/svm.rs +++ b/crates/forge/tests/cli/svm.rs @@ -57,5 +57,18 @@ contract CounterTest is Test {{ "# ); prj.add_test("Counter", &src).unwrap(); - cmd.arg("test").stdout_lossy().contains("[PASS]"); + cmd.arg("test").assert_success().stdout_eq(str![[r#" +... +Ran 1 test for test/Counter.sol:CounterTest +[PASS] testAssert() (gas: [..]) +Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in [..] ([..] CPU time) +... +Ran 2 tests for test/Counter.t.sol:CounterTest +[PASS] testFuzz_SetNumber(uint256) (runs: [..], Îŧ: [..], ~: [..]) +[PASS] test_Increment() (gas: [..]) +Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in [..] ([..] CPU time) + +Ran 2 test suites in [..] ([..] CPU time): 3 tests passed, 0 failed, 0 skipped (3 total tests) + +"#]]); }); diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index a875f66a89cc0..9b6380e0771fe 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -893,18 +893,18 @@ impl TestCommand { /// Executes the command and returns the stderr as lossy `String`. /// /// **Note**: This function checks whether the command was successful. - // #[track_caller] - // pub fn stdout_lossy(&mut self) -> String { - // lossy_string(&self.output().stdout) - // } + #[track_caller] + pub fn stdout_lossy(&mut self) -> String { + lossy_string(&self.output().stdout) + } /// Executes the command and returns the stderr as lossy `String`. /// /// **Note**: This function does **not** check whether the command was successful. - // #[track_caller] - // pub fn stderr_lossy(&mut self) -> String { - // lossy_string(&self.unchecked_output().stderr) - // } + #[track_caller] + pub fn stderr_lossy(&mut self) -> String { + lossy_string(&self.unchecked_output().stderr) + } /// Returns the output but does not expect that the command was successful #[track_caller] From dfd7129b85bdc9334ce755b7964e6d9dac513eff Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Thu, 8 Aug 2024 15:03:17 +0000 Subject: [PATCH 04/47] basic test with stderr --- crates/cast/tests/cli/main.rs | 10 +++++----- crates/forge/tests/cli/svm.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 942059f51bf99..bad197fdfb14a 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -673,11 +673,11 @@ casttest!(mktx_requires_to, |_prj, cmd| { "--private-key", "0x0000000000000000000000000000000000000000000000000000000000000001", ]); - let output = cmd.stderr_lossy(); - assert_eq!( - output.trim(), - "Error: \nMust specify a recipient address or contract code to deploy" - ); + cmd.assert_failure().stderr_eq(str![[r#" +Error: +Must specify a recipient address or contract code to deploy + +"#]]); }); casttest!(mktx_signer_from_mismatch, |_prj, cmd| { diff --git a/crates/forge/tests/cli/svm.rs b/crates/forge/tests/cli/svm.rs index c69808aa3e21b..195ba5d56762d 100644 --- a/crates/forge/tests/cli/svm.rs +++ b/crates/forge/tests/cli/svm.rs @@ -64,7 +64,7 @@ Ran 1 test for test/Counter.sol:CounterTest Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in [..] ([..] CPU time) ... Ran 2 tests for test/Counter.t.sol:CounterTest -[PASS] testFuzz_SetNumber(uint256) (runs: [..], Îŧ: [..], ~: [..]) +[PASS] testFuzz_SetNumber(uint256) (runs: [..], [..]: [..], [..]: [..]) [PASS] test_Increment() (gas: [..]) Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in [..] ([..] CPU time) From 03f6e20075d471c68243b0862bf415a3d01fbfdf Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Thu, 8 Aug 2024 15:14:22 +0000 Subject: [PATCH 05/47] move over the stderr lossy tests --- crates/cast/tests/cli/main.rs | 22 +++++++++++++--------- crates/forge/tests/cli/config.rs | 6 +++++- crates/forge/tests/cli/script.rs | 31 +++++++++++++++++++++---------- crates/test-utils/src/util.rs | 15 --------------- 4 files changed, 39 insertions(+), 35 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index bad197fdfb14a..268a0f70134db 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -691,10 +691,14 @@ casttest!(mktx_signer_from_mismatch, |_prj, cmd| { "1", "0x0000000000000000000000000000000000000001", ]); - let output = cmd.stderr_lossy(); - assert!( - output.contains("The specified sender via CLI/env vars does not match the sender configured via\nthe hardware wallet's HD Path.") - ); + cmd.assert_failure().stderr_eq(str![[r#" +Error: +The specified sender via CLI/env vars does not match the sender configured via +the hardware wallet's HD Path. +Please use the `--hd-path ` parameter to specify the BIP32 Path which +corresponds to the sender, or let foundry automatically detect it by not specifying any sender address. + +"#]]); }); casttest!(mktx_signer_from_match, |_prj, cmd| { @@ -761,11 +765,11 @@ casttest!(send_requires_to, |_prj, cmd| { "--private-key", "0x0000000000000000000000000000000000000000000000000000000000000001", ]); - let output = cmd.stderr_lossy(); - assert_eq!( - output.trim(), - "Error: \nMust specify a recipient address or contract code to deploy" - ); + cmd.assert_failure().stderr_eq(str![[r#" +Error: +Must specify a recipient address or contract code to deploy + +"#]]); }); casttest!(storage, |_prj, cmd| { diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index fcec5f15a84a7..fa3bcc8d30b46 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -373,7 +373,11 @@ contract Foo {} // fails to use solc that does not exist cmd.forge_fuse().args(["build", "--use", "this/solc/does/not/exist"]); - assert!(cmd.stderr_lossy().contains("`solc` this/solc/does/not/exist does not exist")); + cmd.assert_failure().stderr_eq(str![[r#" +Error: +`solc` this/solc/does/not/exist does not exist + +"#]]); // `OTHER_SOLC_VERSION` was installed in previous step, so we can use the path to this directly let local_solc = Solc::find_or_install(&OTHER_SOLC_VERSION.parse().unwrap()).unwrap(); diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index de3a3b544199c..13a3941008472 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -125,10 +125,11 @@ forgetest_async!(assert_exit_code_error_on_failure_script, |prj, cmd| { cmd.arg("script").arg(script); // run command and assert error exit code - cmd.assert_err(); + cmd.assert_failure().stderr_eq(str![[r#" +Error: +script failed: revert: failed - let output = cmd.stderr_lossy(); - assert!(output.contains("script failed: revert: failed")); +"#]]); }); // Tests that execution throws upon encountering a revert in the script with --json option. @@ -141,10 +142,11 @@ forgetest_async!(assert_exit_code_error_on_failure_script_with_json, |prj, cmd| cmd.arg("script").arg(script).arg("--json"); // run command and assert error exit code - cmd.assert_err(); + cmd.assert_failure().stderr_eq(str![[r#" +Error: +script failed: revert: failed - let output = cmd.stderr_lossy(); - assert!(output.contains("script failed: revert: failed")); +"#]]); }); // Tests that the manually specified gas limit is used when using the --unlocked option @@ -1192,7 +1194,11 @@ contract Script { .unwrap(); cmd.arg("script").args([&script.to_string_lossy(), "--sig", "run"]); - assert!(cmd.stderr_lossy().contains("Multiple functions with the same name")); + cmd.assert_failure().stderr_eq(str![[r#" +Error: +Multiple functions with the same name `run` found in the ABI + +"#]]); }); forgetest_async!(can_decode_custom_errors, |prj, cmd| { @@ -1226,7 +1232,10 @@ contract CustomErrorScript is Script { .unwrap(); cmd.arg("script").arg(script).args(["--tc", "CustomErrorScript"]); - assert!(cmd.stderr_lossy().contains("script failed: CustomError()")); + cmd.assert_failure().stderr_eq(str![[r#" +Error: +script failed: CustomError() +"#]]); }); // https://github.com/foundry-rs/foundry/issues/7620 @@ -1352,8 +1361,10 @@ contract SimpleScript is Script { "--unlocked", ]); - let output = cmd.stderr_lossy(); - assert!(output.contains("missing CREATE2 deployer")); + cmd.assert_failure().stderr_eq(str![[r#" +Error: +script failed: missing CREATE2 deployer +"#]]); }); forgetest_async!(can_switch_forks_in_setup, |prj, cmd| { diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 9b6380e0771fe..d380ba98c96e8 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -898,14 +898,6 @@ impl TestCommand { lossy_string(&self.output().stdout) } - /// Executes the command and returns the stderr as lossy `String`. - /// - /// **Note**: This function does **not** check whether the command was successful. - #[track_caller] - pub fn stderr_lossy(&mut self) -> String { - lossy_string(&self.unchecked_output().stderr) - } - /// Returns the output but does not expect that the command was successful #[track_caller] pub fn unchecked_output(&mut self) -> Output { @@ -1083,9 +1075,6 @@ pub trait OutputExt { /// Ensure the command wrote the expected data to `stderr`. fn stderr_matches_path(&self, expected_path: impl AsRef); - /// Returns the stderr as lossy string - fn stderr_lossy(&self) -> String; - /// Returns the stdout as lossy string fn stdout_lossy(&self) -> String; } @@ -1136,10 +1125,6 @@ impl OutputExt for Output { similar_asserts::assert_eq!(normalize_output(&err), normalize_output(&expected)); } - fn stderr_lossy(&self) -> String { - lossy_string(&self.stderr) - } - fn stdout_lossy(&self) -> String { lossy_string(&self.stdout) } From 87241617f6b65b438fa18c4fbf0c3b8699201c39 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Thu, 8 Aug 2024 15:40:26 +0000 Subject: [PATCH 06/47] add `get_stdout_lossy` helper --- crates/forge/tests/cli/build.rs | 12 ++++++++---- crates/forge/tests/cli/create.rs | 4 ++-- crates/test-utils/src/util.rs | 9 ++++++++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index 6cb17d0d4872b..0844be2a32c53 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -31,10 +31,14 @@ forgetest_init!(exact_build_output, |prj, cmd| { // tests build output is as expected forgetest_init!(build_sizes_no_forge_std, |prj, cmd| { cmd.args(["build", "--sizes"]); - let stdout = cmd.stdout_lossy(); - assert!(!stdout.contains("console"), "\n{stdout}"); - assert!(!stdout.contains("std"), "\n{stdout}"); - assert!(stdout.contains("Counter"), "\n{stdout}"); + cmd.assert_success().stdout_eq(str![ + r#" +... +| Contract | Size (B) | Margin (B) | +|----------|----------|------------| +... +"# + ]); }); // tests that skip key in config can be used to skip non-compilable contract diff --git a/crates/forge/tests/cli/create.rs b/crates/forge/tests/cli/create.rs index 6aaa4f536c44a..a41b0c094fed5 100644 --- a/crates/forge/tests/cli/create.rs +++ b/crates/forge/tests/cli/create.rs @@ -107,8 +107,8 @@ where cmd.arg("create"); cmd.args(info.create_args()).arg(contract_path); - let out = cmd.stdout_lossy(); - let _address = utils::parse_deployed_address(out.as_str()) + let out = cmd.get_stdout_lossy(); + let _address = utils::parse_deployed_address(&out) .unwrap_or_else(|| panic!("Failed to parse deployer {out}")); } } diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index d380ba98c96e8..5229af8a0dd81 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -912,6 +912,13 @@ impl TestCommand { output } + /// Runs the command, asserts that it resulted in success and returns the output as a lossy + /// string. + #[track_caller] + pub fn get_stdout_lossy(&mut self) -> String { + lossy_string(&self.assert_success().get_output().stdout) + } + /// Runs the command and asserts that it resulted in success #[track_caller] pub fn assert_success(&mut self) -> OutputAssert { @@ -1156,7 +1163,7 @@ pub fn dir_list>(dir: P) -> Vec { .collect() } -fn lossy_string(bytes: &[u8]) -> String { +pub fn lossy_string(bytes: &[u8]) -> String { String::from_utf8_lossy(bytes).replace("\r\n", "\n") } From 093c59a40160692a84c03f6da56216a8ae90bec2 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Thu, 8 Aug 2024 16:00:12 +0000 Subject: [PATCH 07/47] TestCommand will require a cleanup to route as much through Snapbox as possible, including execute and assertions --- crates/forge/tests/cli/create.rs | 4 ++-- crates/test-utils/src/util.rs | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/crates/forge/tests/cli/create.rs b/crates/forge/tests/cli/create.rs index a41b0c094fed5..6aaa4f536c44a 100644 --- a/crates/forge/tests/cli/create.rs +++ b/crates/forge/tests/cli/create.rs @@ -107,8 +107,8 @@ where cmd.arg("create"); cmd.args(info.create_args()).arg(contract_path); - let out = cmd.get_stdout_lossy(); - let _address = utils::parse_deployed_address(&out) + let out = cmd.stdout_lossy(); + let _address = utils::parse_deployed_address(out.as_str()) .unwrap_or_else(|| panic!("Failed to parse deployer {out}")); } } diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 5229af8a0dd81..77c39e2b9cde3 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -912,13 +912,6 @@ impl TestCommand { output } - /// Runs the command, asserts that it resulted in success and returns the output as a lossy - /// string. - #[track_caller] - pub fn get_stdout_lossy(&mut self) -> String { - lossy_string(&self.assert_success().get_output().stdout) - } - /// Runs the command and asserts that it resulted in success #[track_caller] pub fn assert_success(&mut self) -> OutputAssert { From 51647a24572cf45709f00d60c0a8786af33e79b1 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 23 Aug 2024 10:01:48 +0000 Subject: [PATCH 08/47] fix placeholder redacts --- crates/forge/tests/cli/svm.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/forge/tests/cli/svm.rs b/crates/forge/tests/cli/svm.rs index 195ba5d56762d..ab8db41f8a8b0 100644 --- a/crates/forge/tests/cli/svm.rs +++ b/crates/forge/tests/cli/svm.rs @@ -60,15 +60,15 @@ contract CounterTest is Test {{ cmd.arg("test").assert_success().stdout_eq(str![[r#" ... Ran 1 test for test/Counter.sol:CounterTest -[PASS] testAssert() (gas: [..]) -Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in [..] ([..] CPU time) +[PASS] testAssert() ([GAS]) +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] ... Ran 2 tests for test/Counter.t.sol:CounterTest -[PASS] testFuzz_SetNumber(uint256) (runs: [..], [..]: [..], [..]: [..]) -[PASS] test_Increment() (gas: [..]) -Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in [..] ([..] CPU time) +[PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS]) +[PASS] test_Increment() ([GAS]) +Suite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED] -Ran 2 test suites in [..] ([..] CPU time): 3 tests passed, 0 failed, 0 skipped (3 total tests) +Ran 2 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests) "#]]); }); From 454f4bf299e221947d3a67618c6321a6990bbb21 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 23 Aug 2024 10:20:32 +0000 Subject: [PATCH 09/47] move tests --- crates/forge/tests/cli/cmd.rs | 56 +++++++++++++++++++++-------------- crates/test-utils/src/util.rs | 1 + 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 9160973e9b024..e6418fba27fa1 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1566,9 +1566,12 @@ forgetest_init!(can_use_absolute_imports, |prj, cmd| { ) .unwrap(); - cmd.arg("build"); - let stdout = cmd.stdout_lossy(); - assert!(stdout.contains("Compiler run successful")); + cmd.arg("build").assert_success().stdout_eq(str![[r#" +Compiling 3 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); }); // @@ -1609,9 +1612,12 @@ contract MyTest is IMyTest {} ) .unwrap(); - cmd.arg("build"); - let stdout = cmd.stdout_lossy(); - assert!(stdout.contains("Compiler run successful"), "{stdout}"); + cmd.arg("build").assert_success().stdout_eq(str![[r#" +Compiling 4 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); }); // checks `forge inspect irOptimized works @@ -1645,37 +1651,43 @@ forgetest_init!(can_install_missing_deps_build, |prj, cmd| { let forge_std_dir = prj.root().join("lib/forge-std"); pretty_err(&forge_std_dir, fs::remove_dir_all(&forge_std_dir)); - cmd.arg("build"); + // Build the project + cmd.arg("build").assert_success().stdout_eq(str![[r#" +Missing dependencies found. Installing now... - let output = cmd.stdout_lossy(); - assert!(output.contains("Missing dependencies found. Installing now"), "{output}"); +Updating dependencies in [LIB_DIR] +Compiling 26 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! - // re-run - let output = cmd.stdout_lossy(); - assert!(!output.contains("Missing dependencies found. Installing now"), "{output}"); - assert!(output.contains("No files changed, compilation skipped"), "{output}"); +"#]]); + + // Expect compilation to be skipped as no files have changed + cmd.arg("build").assert_success().stdout_eq(str![[r#" +No files changed, compilation skipped + +"#]]); }); // checks that extra output works forgetest_init!(can_build_skip_contracts, |prj, cmd| { prj.clear(); - // only builds the single template contract `src/*` + // Only builds the single template contract `src/*` cmd.args(["build", "--skip", "tests", "--skip", "scripts"]).assert_success().stdout_eq(str![[ r#" -... -Compiling 1 files [..] -[..] +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] Compiler run successful! -... + "# ]]); - // re-run command - let out = cmd.stdout_lossy(); + // Expect compilation to be skipped as no files have changed + cmd.arg("build").assert_success().stdout_eq(str![[r#" +No files changed, compilation skipped - // unchanged - assert!(out.contains("No files changed, compilation skipped"), "{}", out); +"#]]); }); forgetest_init!(can_build_skip_glob, |prj, cmd| { diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index bb7d579e04ee0..e07312e601131 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -1092,6 +1092,7 @@ fn test_redactions() -> snapbox::Redactions { ("[FILE]", r"-->.*\.sol"), ("[FILE]", r"Location(.|\n)*\.rs(.|\n)*Backtrace"), ("[TX_HASH]", r"Transaction hash: 0x[0-9A-Fa-f]{64}"), + ("[LIB_DIR]", r"/tmp/[^/]+-[^/]+/lib"), ]; for (placeholder, re) in redactions { r.insert(placeholder, Regex::new(re).expect(re)).expect(re); From f3b407496a13a5e44fb30c97d65364766a658532 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 23 Aug 2024 10:43:17 +0000 Subject: [PATCH 10/47] update tests --- crates/cast/tests/cli/main.rs | 74 +++++++++++++++++++++++------------ crates/test-utils/src/util.rs | 1 + 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 82af8e64e1294..d88756bf6cdc2 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -48,23 +48,24 @@ casttest!(finds_block, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); // Call `cast find-block` - cmd.args(["find-block", "--rpc-url", eth_rpc_url.as_str(), ×tamp]); - let output = cmd.stdout_lossy(); - println!("{output}"); + // + cmd.args(["find-block", "--rpc-url", eth_rpc_url.as_str(), ×tamp]) + .assert_success() + .stdout_eq(str![[r#" +14428082 - // Expect successful block query - // Query: 1647843609, Mar 21 2022 06:20:09 UTC - // Output block: https://etherscan.io/block/14428082 - // Output block time: Mar 21 2022 06:20:09 UTC - assert!(output.contains("14428082"), "{}", output); +"#]]); }); // tests that we can create a new wallet with keystore casttest!(new_wallet_keystore_with_password, |_prj, cmd| { - cmd.args(["wallet", "new", ".", "--unsafe-password", "test"]); - let out = cmd.stdout_lossy(); - assert!(out.contains("Created new encrypted keystore file")); - assert!(out.contains("Address")); + cmd.args(["wallet", "new", ".", "--unsafe-password", "test"]).assert_success().stdout_eq(str![ + [r#" +Created new encrypted keystore file: [..] +[ADDRESS] + +"#] + ]); }); // tests that we can get the address of a keystore file @@ -81,9 +82,12 @@ casttest!(wallet_address_keystore_with_password_file, |_prj, cmd| { .unwrap(), "--password-file", keystore_dir.join("password-ec554").to_str().unwrap(), - ]); - let out = cmd.stdout_lossy(); - assert!(out.contains("0xeC554aeAFE75601AaAb43Bd4621A22284dB566C2")); + ]) + .assert_success() + .stdout_eq(str![[r#" +0xeC554aeAFE75601AaAb43Bd4621A22284dB566C2 + +"#]]); }); // tests that `cast wallet sign message` outputs the expected signature @@ -93,17 +97,29 @@ casttest!(wallet_sign_message_utf8_data, |_prj, cmd| { let msg = "test"; let expected = "0xfe28833983d6faa0715c7e8c3873c725ddab6fa5bf84d40e780676e463e6bea20fc6aea97dc273a98eb26b0914e224c8dd5c615ceaab69ddddcf9b0ae3de0e371c"; - cmd.args(["wallet", "sign", "--private-key", pk, msg]); - let output = cmd.stdout_lossy(); - assert_eq!(output.trim(), expected); + cmd.args(["wallet", "sign", "--private-key", pk, msg]).assert_success().stdout_eq(str![[r#" +0xfe28833983d6faa0715c7e8c3873c725ddab6fa5bf84d40e780676e463e6bea20fc6aea97dc273a98eb26b0914e224c8dd5c615ceaab69ddddcf9b0ae3de0e371c + +"#]]); // Success. cmd.cast_fuse() .args(["wallet", "verify", "-a", address, msg, expected]) - .assert_non_empty_stdout(); + .assert_success() + .stdout_eq(str![[r#" +Validation succeeded. Address 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf signed this message. + +"#]]); // Fail. - cmd.cast_fuse().args(["wallet", "verify", "-a", address, "other msg", expected]).assert_err(); + cmd.cast_fuse() + .args(["wallet", "verify", "-a", address, "other msg", expected]) + .assert_failure() + .stderr_eq(str![[r#" +Error: +Validation failed. Address 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf did not sign this message. + +"#]]); }); // tests that `cast wallet sign message` outputs the expected signature, given a 0x-prefixed data @@ -225,9 +241,12 @@ casttest!(wallet_private_key_from_mnemonic_option, |_prj, cmd| { "test test test test test test test test test test test junk", "--mnemonic-index", "1", - ]); - let output = cmd.stdout_lossy(); - assert_eq!(output.trim(), "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"); + ]) + .assert_success() + .stdout_eq(str![[r#" +0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d + +"#]]); }); // tests that `cast wallet private-key` with derivation path outputs the private key @@ -239,9 +258,12 @@ casttest!(wallet_private_key_with_derivation_path, |_prj, cmd| { "test test test test test test test test test test test junk", "--mnemonic-derivation-path", "m/44'/60'/0'/0/1", - ]); - let output = cmd.stdout_lossy(); - assert_eq!(output.trim(), "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"); + ]) + .assert_success() + .stdout_eq(str![[r#" +0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d + +"#]]); }); // tests that `cast wallet import` creates a keystore for a private key and that `cast wallet diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index e07312e601131..595d6495110a0 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -1092,6 +1092,7 @@ fn test_redactions() -> snapbox::Redactions { ("[FILE]", r"-->.*\.sol"), ("[FILE]", r"Location(.|\n)*\.rs(.|\n)*Backtrace"), ("[TX_HASH]", r"Transaction hash: 0x[0-9A-Fa-f]{64}"), + ("[ADDRESS]", r"Address: 0x[0-9A-Fa-f]{40}"), ("[LIB_DIR]", r"/tmp/[^/]+-[^/]+/lib"), ]; for (placeholder, re) in redactions { From 2208afff18e6e756735e4aa430dd553101eef839 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 23 Aug 2024 10:47:44 +0000 Subject: [PATCH 11/47] fix tests --- crates/forge/tests/cli/test_cmd.rs | 33 ++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 3b0cbfb7f24e7..669f2794e05c6 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -128,7 +128,7 @@ forgetest!(can_fuzz_array_params, |prj, cmd| { r#" import "./test.sol"; contract ATest is DSTest { - function testArray(uint64[2] calldata values) external { + function testArray(uint64[2] calldata) external { assertTrue(true); } } @@ -136,8 +136,18 @@ contract ATest is DSTest { ) .unwrap(); - cmd.arg("test"); - cmd.stdout_lossy().contains("[PASS]"); + cmd.arg("test").assert_success().stdout_eq(str![[r#" +Compiling 2 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for src/ATest.t.sol:ATest +[PASS] testArray(uint64[2]) (runs: 256, [AVG_GAS]) +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#]]); }); // tests that `bytecode_hash` will be sanitized @@ -151,7 +161,7 @@ forgetest!(can_test_pre_bytecode_hash, |prj, cmd| { pragma solidity 0.5.17; import "./test.sol"; contract ATest is DSTest { - function testArray(uint64[2] calldata values) external { + function testArray(uint64[2] calldata) external { assertTrue(true); } } @@ -159,8 +169,19 @@ contract ATest is DSTest { ) .unwrap(); - cmd.arg("test"); - cmd.stdout_lossy().contains("[PASS]"); + cmd.arg("test").assert_success().stdout_eq(str![[r#" +Compiling 2 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for src/ATest.t.sol:ATest +[PASS] testArray(uint64[2]) (runs: 256, [AVG_GAS]) +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#]]); + // cmd.stdout_lossy().contains("[PASS]"); }); // tests that using the --match-path option only runs files matching the path From 517d41230962f1e3bdee7dbbe191e50a4a8d5994 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 23 Aug 2024 11:03:23 +0000 Subject: [PATCH 12/47] improve tests --- crates/cast/tests/cli/main.rs | 71 +++++++++++++++++++++++++----- crates/forge/tests/cli/test_cmd.rs | 71 ++++++++++++++++++++++++------ 2 files changed, 118 insertions(+), 24 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index d88756bf6cdc2..64be100841371 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -196,25 +196,74 @@ casttest!(wallet_list_local_accounts, |prj, cmd| { cmd.set_current_dir(prj.root()); // empty results - cmd.cast_fuse().args(["wallet", "list", "--dir", "keystore"]); - let list_output = cmd.stdout_lossy(); - assert!(list_output.is_empty()); + cmd.cast_fuse() + .args(["wallet", "list", "--dir", "keystore"]) + .assert_success() + .stdout_eq(str![""]); // create 10 wallets - cmd.cast_fuse().args(["wallet", "new", "keystore", "-n", "10", "--unsafe-password", "test"]); - cmd.stdout_lossy(); + cmd.cast_fuse() + .args(["wallet", "new", "keystore", "-n", "10", "--unsafe-password", "test"]) + .assert_success() + .stdout_eq(str![[r#" +Created new encrypted keystore file: [..] +[ADDRESS] +Created new encrypted keystore file: [..] +[ADDRESS] +Created new encrypted keystore file: [..] +[ADDRESS] +Created new encrypted keystore file: [..] +[ADDRESS] +Created new encrypted keystore file: [..] +[ADDRESS] +Created new encrypted keystore file: [..] +[ADDRESS] +Created new encrypted keystore file: [..] +[ADDRESS] +Created new encrypted keystore file: [..] +[ADDRESS] +Created new encrypted keystore file: [..] +[ADDRESS] +Created new encrypted keystore file: [..] +[ADDRESS] + +"#]]); // test list new wallet - cmd.cast_fuse().args(["wallet", "list", "--dir", "keystore"]); - let list_output = cmd.stdout_lossy(); - assert_eq!(list_output.matches('\n').count(), 10); + cmd.cast_fuse().args(["wallet", "list", "--dir", "keystore"]).assert_success().stdout_eq(str![ + [r#" +[..] (Local) +[..] (Local) +[..] (Local) +[..] (Local) +[..] (Local) +[..] (Local) +[..] (Local) +[..] (Local) +[..] (Local) +[..] (Local) + +"#] + ]); }); // tests that `cast wallet new-mnemonic --entropy` outputs the expected mnemonic casttest!(wallet_mnemonic_from_entropy, |_prj, cmd| { - cmd.args(["wallet", "new-mnemonic", "--entropy", "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c"]); - let output = cmd.stdout_lossy(); - assert!(output.contains("test test test test test test test test test test test junk")); + cmd.args(["wallet", "new-mnemonic", "--entropy", "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c"]) + .assert_success() + .stdout_eq(str![[r#" +Generating mnemonic from provided entropy... +Successfully generated a new mnemonic. +Phrase: +test test test test test test test test test test test junk + +Accounts: +- Account 0: +Address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +Private key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + + +"#]]); }); // tests that `cast wallet private-key` with arguments outputs the private key diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 669f2794e05c6..49979e86fc005 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -181,7 +181,6 @@ Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) "#]]); - // cmd.stdout_lossy().contains("[PASS]"); }); // tests that using the --match-path option only runs files matching the path @@ -958,9 +957,23 @@ forgetest_init!(should_show_logs_when_fuzz_test, |prj, cmd| { "#, ) .unwrap(); - cmd.args(["test", "-vv"]); - let stdout = cmd.stdout_lossy(); - assert!(stdout.contains("inside fuzz test, x is:"), "\n{stdout}"); + cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" +Compiling 23 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for test/ContractFuzz.t.sol:ContractFuzz +[PASS] testFuzzConsoleLog(uint256) (runs: 3, [AVG_GAS]) +Logs: + inside fuzz test, x is: [..] + inside fuzz test, x is: [..] + inside fuzz test, x is: [..] + +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#]]); }); // tests that `forge test` with inline config `show_logs = true` for fuzz tests will @@ -989,9 +1002,23 @@ forgetest_init!(should_show_logs_when_fuzz_test_inline_config, |prj, cmd| { "#, ) .unwrap(); - cmd.args(["test", "-vv"]); - let stdout = cmd.stdout_lossy(); - assert!(stdout.contains("inside fuzz test, x is:"), "\n{stdout}"); + cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" +Compiling 23 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for test/ContractFuzz.t.sol:ContractFuzz +[PASS] testFuzzConsoleLog(uint256) (runs: 3, [AVG_GAS]) +Logs: + inside fuzz test, x is: [..] + inside fuzz test, x is: [..] + inside fuzz test, x is: [..] + +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#]]); }); // tests that `forge test` with config `show_logs: false` for fuzz tests will not display @@ -1021,9 +1048,18 @@ forgetest_init!(should_not_show_logs_when_fuzz_test, |prj, cmd| { "#, ) .unwrap(); - cmd.args(["test", "-vv"]); - let stdout = cmd.stdout_lossy(); - assert!(!stdout.contains("inside fuzz test, x is:"), "\n{stdout}"); + cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" +Compiling 23 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for test/ContractFuzz.t.sol:ContractFuzz +[PASS] testFuzzConsoleLog(uint256) (runs: 3, [AVG_GAS]) +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#]]); }); // tests that `forge test` with inline config `show_logs = false` for fuzz tests will not @@ -1052,9 +1088,18 @@ forgetest_init!(should_not_show_logs_when_fuzz_test_inline_config, |prj, cmd| { "#, ) .unwrap(); - cmd.args(["test", "-vv"]); - let stdout = cmd.stdout_lossy(); - assert!(!stdout.contains("inside fuzz test, x is:"), "\n{stdout}"); + cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" +Compiling 23 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for test/ContractFuzz.t.sol:ContractFuzz +[PASS] testFuzzConsoleLog(uint256) (runs: 3, [AVG_GAS]) +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#]]); }); // tests internal functions trace From d887bf4c5d4907bfa5915dfcaeda77e1aab516a3 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 23 Aug 2024 11:42:14 +0000 Subject: [PATCH 13/47] continue --- crates/cast/tests/cli/main.rs | 64 ++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 64be100841371..55eaf530a07a2 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -379,9 +379,11 @@ casttest!(estimate_function_gas, |_prj, cmd| { "deposit()", "--rpc-url", eth_rpc_url.as_str(), - ]); - let out: u32 = cmd.stdout_lossy().trim().parse().unwrap(); + ]) + .assert_success(); + // ensure we get a positive non-error value for gas estimate + let out: u32 = cmd.stdout_lossy().trim().parse().unwrap(); assert!(out.ge(&0)); }); @@ -400,10 +402,11 @@ casttest!(estimate_contract_deploy_gas, |_prj, cmd| { "100", "Test", "TST", - ]); + ]) + .assert_success(); - let gas: u32 = cmd.stdout_lossy().trim().parse().unwrap(); // ensure we get a positive non-error value for gas estimate + let gas: u32 = cmd.stdout_lossy().trim().parse().unwrap(); assert!(gas > 0); }); @@ -488,9 +491,12 @@ casttest!(rpc_no_args, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); // Call `cast rpc eth_chainId` - cmd.args(["rpc", "--rpc-url", eth_rpc_url.as_str(), "eth_chainId"]); - let output = cmd.stdout_lossy(); - assert_eq!(output.trim_end(), r#""0x1""#); + cmd.args(["rpc", "--rpc-url", eth_rpc_url.as_str(), "eth_chainId"]).assert_success().stdout_eq( + str![[r#" +"0x1" + +"#]], + ); }); // test for cast_rpc without arguments using websocket @@ -498,9 +504,12 @@ casttest!(ws_rpc_no_args, |_prj, cmd| { let eth_rpc_url = next_ws_rpc_endpoint(); // Call `cast rpc eth_chainId` - cmd.args(["rpc", "--rpc-url", eth_rpc_url.as_str(), "eth_chainId"]); - let output = cmd.stdout_lossy(); - assert_eq!(output.trim_end(), r#""0x1""#); + cmd.args(["rpc", "--rpc-url", eth_rpc_url.as_str(), "eth_chainId"]).assert_success().stdout_eq( + str![[r#" +"0x1" + +"#]], + ); }); // test for cast_rpc with arguments @@ -508,9 +517,12 @@ casttest!(rpc_with_args, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); // Call `cast rpc eth_getBlockByNumber 0x123 false` - cmd.args(["rpc", "--rpc-url", eth_rpc_url.as_str(), "eth_getBlockByNumber", "0x123", "false"]); - let output = cmd.stdout_lossy(); - assert!(output.contains(r#""number":"0x123""#), "{}", output); + cmd.args(["rpc", "--rpc-url", eth_rpc_url.as_str(), "eth_getBlockByNumber", "0x123", "false"]) + .assert_success() + .stdout_eq(str![[r#" +{"number":"0x123","hash":"0xc5dab4e189004a1312e9db43a40abb2de91ad7dd25e75880bf36016d8e9df524","transactions":[],"totalDifficulty":"0x4dea420908b","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","extraData":"0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32","nonce":"0x29d6547c196e00e0","miner":"0xbb7b8287f3f0a933474a79eae42cbca977791171","difficulty":"0x494433b31","gasLimit":"0x1388","gasUsed":"0x0","uncles":[],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x220","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","stateRoot":"0x3fe6bd17aa85376c7d566df97d9f2e536f37f7a87abb3a6f9e2891cf9442f2e4","mixHash":"0x943056aa305aa6d22a3c06110942980342d1f4d4b11c17711961436a0f963ea0","parentHash":"0x7abfd11e862ccde76d6ea8ee20978aac26f4bcb55de1188cc0335be13e817017","timestamp":"0x55ba4564"} + +"#]]); }); // test for cast_rpc with raw params @@ -525,9 +537,12 @@ casttest!(rpc_raw_params, |_prj, cmd| { "eth_getBlockByNumber", "--raw", r#"["0x123", false]"#, - ]); - let output = cmd.stdout_lossy(); - assert!(output.contains(r#""number":"0x123""#), "{}", output); + ]) + .assert_success() + .stdout_eq(str![[r#" +{"number":"0x123","hash":"0xc5dab4e189004a1312e9db43a40abb2de91ad7dd25e75880bf36016d8e9df524","transactions":[],"totalDifficulty":"0x4dea420908b","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","extraData":"0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32","nonce":"0x29d6547c196e00e0","miner":"0xbb7b8287f3f0a933474a79eae42cbca977791171","difficulty":"0x494433b31","gasLimit":"0x1388","gasUsed":"0x0","uncles":[],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x220","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","stateRoot":"0x3fe6bd17aa85376c7d566df97d9f2e536f37f7a87abb3a6f9e2891cf9442f2e4","mixHash":"0x943056aa305aa6d22a3c06110942980342d1f4d4b11c17711961436a0f963ea0","parentHash":"0x7abfd11e862ccde76d6ea8ee20978aac26f4bcb55de1188cc0335be13e817017","timestamp":"0x55ba4564"} + +"#]]); }); // test for cast_rpc with direct params @@ -539,17 +554,20 @@ casttest!(rpc_raw_params_stdin, |_prj, cmd| { |mut stdin| { stdin.write_all(b"\n[\n\"0x123\",\nfalse\n]\n").unwrap(); }, - ); - let output = cmd.stdout_lossy(); - assert!(output.contains(r#""number":"0x123""#), "{}", output); + ) + .assert_success() + .stdout_eq(str![[r#" +{"number":"0x123","hash":"0xc5dab4e189004a1312e9db43a40abb2de91ad7dd25e75880bf36016d8e9df524","transactions":[],"totalDifficulty":"0x4dea420908b","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","extraData":"0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32","nonce":"0x29d6547c196e00e0","miner":"0xbb7b8287f3f0a933474a79eae42cbca977791171","difficulty":"0x494433b31","gasLimit":"0x1388","gasUsed":"0x0","uncles":[],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x220","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","stateRoot":"0x3fe6bd17aa85376c7d566df97d9f2e536f37f7a87abb3a6f9e2891cf9442f2e4","mixHash":"0x943056aa305aa6d22a3c06110942980342d1f4d4b11c17711961436a0f963ea0","parentHash":"0x7abfd11e862ccde76d6ea8ee20978aac26f4bcb55de1188cc0335be13e817017","timestamp":"0x55ba4564"} + +"#]]); }); // checks `cast calldata` can handle arrays casttest!(calldata_array, |_prj, cmd| { - cmd.args(["calldata", "propose(string[])", "[\"\"]"]); - let out = cmd.stdout_lossy(); - assert_eq!(out.trim(),"0xcde2baba0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" - ); + cmd.args(["calldata", "propose(string[])", "[\"\"]"]).assert_success().stdout_eq(str![[r#" +0xcde2baba0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 + +"#]]); }); // From 3546cc6b349baa56c9a56c54b279e4c47586dc47 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 23 Aug 2024 11:47:45 +0000 Subject: [PATCH 14/47] continue --- crates/cast/tests/cli/main.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 55eaf530a07a2..9eb3fbb902397 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -580,10 +580,14 @@ casttest!(run_succeeds, |_prj, cmd| { "--quick", "--rpc-url", rpc.as_str(), - ]); - let output = cmd.stdout_lossy(); - assert!(output.contains("Transaction successfully executed")); - assert!(!output.contains("Revert")); + ]) + .assert_success() + .stdout_eq(str![[r#" +... +Transaction successfully executed. +[GAS] + +"#]]); }); // tests that `cast --to-base` commands are working correctly. From 364d08181e7382cd5d3358713b33dd2f137a2b4c Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 23 Aug 2024 13:23:16 +0000 Subject: [PATCH 15/47] clean up --- crates/forge/tests/cli/build.rs | 1 + crates/test-utils/src/util.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index a89b034d0745b..0b1de40b3fc14 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -60,6 +60,7 @@ forgetest_init!(build_sizes_no_forge_std, |prj, cmd| { ... | Contract | Size (B) | Margin (B) | |----------|----------|------------| +| Counter | [..] ... "# ]); diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 595d6495110a0..8999a9fc5ae5f 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -1199,7 +1199,7 @@ pub fn dir_list>(dir: P) -> Vec { .collect() } -pub fn lossy_string(bytes: &[u8]) -> String { +fn lossy_string(bytes: &[u8]) -> String { String::from_utf8_lossy(bytes).replace("\r\n", "\n") } From 8cc0df2f2a5aba8f67793676a2e6d68eaae54c68 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 23 Aug 2024 13:55:41 +0000 Subject: [PATCH 16/47] clean up --- crates/cast/tests/cli/main.rs | 85 ++++++++++++++++----- crates/cast/tests/fixtures/cast_logs.stdout | 13 ---- crates/test-utils/src/util.rs | 81 -------------------- 3 files changed, 68 insertions(+), 111 deletions(-) delete mode 100644 crates/cast/tests/fixtures/cast_logs.stdout diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 9eb3fbb902397..6f734224a4ade 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -7,7 +7,6 @@ use foundry_test_utils::{ casttest, rpc::{next_http_rpc_endpoint, next_rpc_endpoint, next_ws_rpc_endpoint}, str, - util::OutputExt, }; use std::{fs, io::Write, path::Path, str::FromStr}; @@ -685,11 +684,24 @@ casttest!(logs_topics, |_prj, cmd| { "12421182", "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b", - ]); + ]) + .assert_success() + .stdout_eq(str![[r#" +- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE + blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c + blockNumber: 12421182 + data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 + logIndex: 15 + removed: false + topics: [ + 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef + 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b + 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 + ] + transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 + transactionIndex: 8 - cmd.unchecked_output().stdout_matches_path( - Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cast_logs.stdout"), - ); +"#]]); }); casttest!(logs_topic_2, |_prj, cmd| { @@ -706,11 +718,24 @@ casttest!(logs_topic_2, |_prj, cmd| { "", "0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1", /* Filter on the * `to` address */ - ]); + ]) + .assert_success() + .stdout_eq(str![[r#" +- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE + blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c + blockNumber: 12421182 + data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 + logIndex: 15 + removed: false + topics: [ + 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef + 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b + 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 + ] + transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 + transactionIndex: 8 - cmd.unchecked_output().stdout_matches_path( - Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cast_logs.stdout"), - ); +"#]]); }); casttest!(logs_sig, |_prj, cmd| { @@ -725,11 +750,24 @@ casttest!(logs_sig, |_prj, cmd| { "12421182", "Transfer(address indexed from, address indexed to, uint256 value)", "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - ]); + ]) + .assert_success() + .stdout_eq(str![[r#" +- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE + blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c + blockNumber: 12421182 + data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 + logIndex: 15 + removed: false + topics: [ + 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef + 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b + 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 + ] + transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 + transactionIndex: 8 - cmd.unchecked_output().stdout_matches_path( - Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cast_logs.stdout"), - ); +"#]]); }); casttest!(logs_sig_2, |_prj, cmd| { @@ -745,11 +783,24 @@ casttest!(logs_sig_2, |_prj, cmd| { "Transfer(address indexed from, address indexed to, uint256 value)", "", "0x68A99f89E475a078645f4BAC491360aFe255Dff1", - ]); + ]) + .assert_success() + .stdout_eq(str![[r#" +- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE + blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c + blockNumber: 12421182 + data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 + logIndex: 15 + removed: false + topics: [ + 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef + 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b + 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 + ] + transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 + transactionIndex: 8 - cmd.unchecked_output().stdout_matches_path( - Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cast_logs.stdout"), - ); +"#]]); }); casttest!(mktx, |_prj, cmd| { diff --git a/crates/cast/tests/fixtures/cast_logs.stdout b/crates/cast/tests/fixtures/cast_logs.stdout deleted file mode 100644 index 1729394f671ee..0000000000000 --- a/crates/cast/tests/fixtures/cast_logs.stdout +++ /dev/null @@ -1,13 +0,0 @@ -- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE - blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c - blockNumber: 12421182 - data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 - logIndex: 15 - removed: false - topics: [ - 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef - 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b - 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 - ] - transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 - transactionIndex: 8 diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 8999a9fc5ae5f..2e3d1a6dbeead 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -1109,65 +1109,11 @@ fn test_redactions() -> snapbox::Redactions { /// fixture. Since `forge` commands may emit colorized output depending on whether the current /// terminal is tty, the path argument can be wrapped in [tty_fixture_path()] pub trait OutputExt { - /// Ensure the command wrote the expected data to `stdout`. - fn stdout_matches_content(&self, expected: &str); - - /// Ensure the command wrote the expected data to `stdout`. - fn stdout_matches_path(&self, expected_path: impl AsRef); - - /// Ensure the command wrote the expected data to `stderr`. - fn stderr_matches_path(&self, expected_path: impl AsRef); - /// Returns the stdout as lossy string fn stdout_lossy(&self) -> String; } -/// Patterns to remove from fixtures before comparing output -/// -/// This should strip everything that can vary from run to run, like elapsed time, file paths -static IGNORE_IN_FIXTURES: LazyLock = LazyLock::new(|| { - let re = &[ - // solc version - r" ?Solc(?: version)? \d+.\d+.\d+", - r" with(?: Solc)? \d+.\d+.\d+", - // solc runs - r"runs: \d+, Îŧ: \d+, ~: \d+", - // elapsed time - r"(?:finished)? ?in .*?s(?: \(.*?s CPU time\))?", - // file paths - r"-->.*\.sol", - r"Location(.|\n)*\.rs(.|\n)*Backtrace", - // other - r"Transaction hash: 0x[0-9A-Fa-f]{64}", - ]; - Regex::new(&format!("({})", re.join("|"))).unwrap() -}); - -pub fn normalize_output(s: &str) -> String { - let s = s.replace("\r\n", "\n").replace('\\', "/"); - IGNORE_IN_FIXTURES.replace_all(&s, "").into_owned() -} - impl OutputExt for Output { - #[track_caller] - fn stdout_matches_content(&self, expected: &str) { - let out = lossy_string(&self.stdout); - similar_asserts::assert_eq!(normalize_output(&out), normalize_output(expected)); - } - - #[track_caller] - fn stdout_matches_path(&self, expected_path: impl AsRef) { - let expected = fs::read_to_string(expected_path).unwrap(); - self.stdout_matches_content(&expected); - } - - #[track_caller] - fn stderr_matches_path(&self, expected_path: impl AsRef) { - let expected = fs::read_to_string(expected_path).unwrap(); - let err = lossy_string(&self.stderr); - similar_asserts::assert_eq!(normalize_output(&err), normalize_output(&expected)); - } - fn stdout_lossy(&self) -> String { lossy_string(&self.stdout) } @@ -1202,30 +1148,3 @@ pub fn dir_list>(dir: P) -> Vec { fn lossy_string(bytes: &[u8]) -> String { String::from_utf8_lossy(bytes).replace("\r\n", "\n") } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn tty_path_works() { - let path = "tests/fixture/test.stdout"; - if *IS_TTY { - assert_eq!(tty_fixture_path(path), PathBuf::from("tests/fixture/test.tty.stdout")); - } else { - assert_eq!(tty_fixture_path(path), PathBuf::from(path)); - } - } - - #[test] - fn fixture_regex_matches() { - assert!(IGNORE_IN_FIXTURES.is_match( - r" -Location: - cli/src/compile.rs:151 - -Backtrace omitted. - " - )); - } -} From f19cf03b00c76224db41c6f85c392b493a1dee62 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 10:04:57 +0000 Subject: [PATCH 17/47] match against "Updating dependencies in" --- crates/forge/tests/cli/cmd.rs | 2 +- crates/test-utils/src/util.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index e6418fba27fa1..924dbba4efa7a 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1655,7 +1655,7 @@ forgetest_init!(can_install_missing_deps_build, |prj, cmd| { cmd.arg("build").assert_success().stdout_eq(str![[r#" Missing dependencies found. Installing now... -Updating dependencies in [LIB_DIR] +[UPDATING_DEPENDENCIES] Compiling 26 files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 2e3d1a6dbeead..c11664abe5d70 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -1093,7 +1093,7 @@ fn test_redactions() -> snapbox::Redactions { ("[FILE]", r"Location(.|\n)*\.rs(.|\n)*Backtrace"), ("[TX_HASH]", r"Transaction hash: 0x[0-9A-Fa-f]{64}"), ("[ADDRESS]", r"Address: 0x[0-9A-Fa-f]{40}"), - ("[LIB_DIR]", r"/tmp/[^/]+-[^/]+/lib"), + ("[UPDATING_DEPENDENCIES]", r"Updating dependencies in .*"), ]; for (placeholder, re) in redactions { r.insert(placeholder, Regex::new(re).expect(re)).expect(re); From ca325369fe9ef8a73f6cac5880ae68e00b4c288b Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 11:12:49 +0000 Subject: [PATCH 18/47] fix broken tests, make sure to clear consistently to force recompilation where expected --- Cargo.lock | 2 -- crates/forge/tests/cli/cmd.rs | 25 ++++++++++++++++++++----- crates/forge/tests/cli/script.rs | 4 +++- crates/test-utils/Cargo.toml | 2 -- crates/test-utils/src/util.rs | 30 ------------------------------ 5 files changed, 23 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66b4357a48705..f332d0454d086 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4047,11 +4047,9 @@ dependencies = [ "rand", "regex", "serde_json", - "similar-asserts", "snapbox", "tracing", "tracing-subscriber", - "walkdir", ] [[package]] diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 924dbba4efa7a..ab3f4f3d1d861 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1634,19 +1634,34 @@ forgetest_init!(can_bind, |_prj, cmd| { // checks missing dependencies are auto installed forgetest_init!(can_install_missing_deps_test, |prj, cmd| { + prj.clear(); + // wipe forge-std let forge_std_dir = prj.root().join("lib/forge-std"); pretty_err(&forge_std_dir, fs::remove_dir_all(&forge_std_dir)); - cmd.arg("test"); + cmd.arg("test").assert_success().stdout_eq(str![[r#" +Missing dependencies found. Installing now... - let output = cmd.stdout_lossy(); - assert!(output.contains("Missing dependencies found. Installing now"), "{}", output); - assert!(output.contains("[PASS]"), "{}", output); +[UPDATING_DEPENDENCIES] +Compiling 25 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 2 tests for test/Counter.t.sol:CounterTest +[PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS]) +[PASS] test_Increment() ([GAS]) +Suite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests) + +"#]]); }); // checks missing dependencies are auto installed forgetest_init!(can_install_missing_deps_build, |prj, cmd| { + prj.clear(); + // wipe forge-std let forge_std_dir = prj.root().join("lib/forge-std"); pretty_err(&forge_std_dir, fs::remove_dir_all(&forge_std_dir)); @@ -1656,7 +1671,7 @@ forgetest_init!(can_install_missing_deps_build, |prj, cmd| { Missing dependencies found. Installing now... [UPDATING_DEPENDENCIES] -Compiling 26 files with [SOLC_VERSION] +Compiling 27 files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 376a86b08423f..e44cbe48dcc2b 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -1241,7 +1241,7 @@ forgetest_async!(can_sign_with_script_wallet_multiple, |prj, cmd| { forgetest_async!(fails_with_function_name_and_overloads, |prj, cmd| { let script = prj .add_script( - "Sctipt.s.sol", + "Script.s.sol", r#" contract Script { function run() external {} @@ -1294,6 +1294,7 @@ contract CustomErrorScript is Script { cmd.assert_failure().stderr_eq(str![[r#" Error: script failed: CustomError() + "#]]); }); @@ -1423,6 +1424,7 @@ contract SimpleScript is Script { cmd.assert_failure().stderr_eq(str![[r#" Error: script failed: missing CREATE2 deployer + "#]]); }); diff --git a/crates/test-utils/Cargo.toml b/crates/test-utils/Cargo.toml index 960e22124f4ac..ca0f60d0d64c2 100644 --- a/crates/test-utils/Cargo.toml +++ b/crates/test-utils/Cargo.toml @@ -25,12 +25,10 @@ alloy-provider.workspace = true eyre.workspace = true fd-lock = "4.0.0" parking_lot.workspace = true -similar-asserts.workspace = true regex = "1" serde_json.workspace = true tracing.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } -walkdir.workspace = true rand.workspace = true snapbox = { version = "0.6.9", features = ["json", "regex"] } diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index c11664abe5d70..ee67d28a073a7 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -1104,10 +1104,6 @@ fn test_redactions() -> snapbox::Redactions { } /// Extension trait for [`Output`]. -/// -/// These function will read the path's content and assert that the process' output matches the -/// fixture. Since `forge` commands may emit colorized output depending on whether the current -/// terminal is tty, the path argument can be wrapped in [tty_fixture_path()] pub trait OutputExt { /// Returns the stdout as lossy string fn stdout_lossy(&self) -> String; @@ -1119,32 +1115,6 @@ impl OutputExt for Output { } } -/// Returns the fixture path depending on whether the current terminal is tty -/// -/// This is useful in combination with [OutputExt] -pub fn tty_fixture_path(path: impl AsRef) -> PathBuf { - let path = path.as_ref(); - if *IS_TTY { - return if let Some(ext) = path.extension().and_then(|s| s.to_str()) { - path.with_extension(format!("tty.{ext}")) - } else { - path.with_extension("tty") - } - } - path.to_path_buf() -} - -/// Return a recursive listing of all files and directories in the given -/// directory. This is useful for debugging transient and odd failures in -/// integration tests. -pub fn dir_list>(dir: P) -> Vec { - walkdir::WalkDir::new(dir) - .follow_links(true) - .into_iter() - .map(|result| result.unwrap().path().to_string_lossy().into_owned()) - .collect() -} - fn lossy_string(bytes: &[u8]) -> String { String::from_utf8_lossy(bytes).replace("\r\n", "\n") } From 7bc0a8a5438a53b8881172e32d142223a1a4075e Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 11:58:59 +0000 Subject: [PATCH 19/47] port more tests --- crates/cast/tests/cli/main.rs | 206 +++++++++++++++++++--------------- 1 file changed, 115 insertions(+), 91 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 6f734224a4ade..d920b1b53446b 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -382,8 +382,8 @@ casttest!(estimate_function_gas, |_prj, cmd| { .assert_success(); // ensure we get a positive non-error value for gas estimate - let out: u32 = cmd.stdout_lossy().trim().parse().unwrap(); - assert!(out.ge(&0)); + let output: u32 = cmd.stdout_lossy().trim().parse().unwrap(); + assert!(output.ge(&0)); }); // tests that `cast estimate --create` is working correctly. @@ -405,8 +405,8 @@ casttest!(estimate_contract_deploy_gas, |_prj, cmd| { .assert_success(); // ensure we get a positive non-error value for gas estimate - let gas: u32 = cmd.stdout_lossy().trim().parse().unwrap(); - assert!(gas > 0); + let output: u32 = cmd.stdout_lossy().trim().parse().unwrap(); + assert!(output > 0); }); // tests that the `cast upload-signatures` command works correctly @@ -414,19 +414,16 @@ casttest!(upload_signatures, |_prj, cmd| { // test no prefix is accepted as function cmd.args(["upload-signature", "transfer(address,uint256)"]); let output = cmd.stdout_lossy(); - assert!(output.contains("Function transfer(address,uint256): 0xa9059cbb"), "{}", output); // test event prefix cmd.args(["upload-signature", "event Transfer(address,uint256)"]); let output = cmd.stdout_lossy(); - assert!(output.contains("Event Transfer(address,uint256): 0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2"), "{}", output); // test error prefix cmd.args(["upload-signature", "error ERC20InsufficientBalance(address,uint256,uint256)"]); let output = cmd.stdout_lossy(); - assert!( output.contains("Function ERC20InsufficientBalance(address,uint256,uint256): 0xe450d38c"), "{}", @@ -441,7 +438,6 @@ casttest!(upload_signatures, |_prj, cmd| { "approve(address,uint256)", ]); let output = cmd.stdout_lossy(); - assert!(output.contains("Event Transfer(address,uint256): 0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2"), "{}", output); assert!(output.contains("Function transfer(address,uint256): 0xa9059cbb"), "{}", output); assert!(output.contains("Function approve(address,uint256): 0x095ea7b3"), "{}", output); @@ -460,7 +456,6 @@ casttest!(upload_signatures, |_prj, cmd| { .as_str(), ]); let output = cmd.stdout_lossy(); - assert!(output.contains("Event Transfer(address,uint256): 0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2"), "{}", output); assert!(output.contains("Function transfer(address,uint256): 0xa9059cbb"), "{}", output); assert!(output.contains("Function approve(address,uint256): 0x095ea7b3"), "{}", output); @@ -475,14 +470,18 @@ casttest!(upload_signatures, |_prj, cmd| { // tests that the `cast to-rlp` and `cast from-rlp` commands work correctly casttest!(rlp, |_prj, cmd| { - cmd.args(["--to-rlp", "[\"0xaa\", [[\"bb\"]], \"0xcc\"]"]); - let out = cmd.stdout_lossy(); - assert!(out.contains("0xc881aac3c281bb81cc"), "{}", out); + cmd.args(["--to-rlp", "[\"0xaa\", [[\"bb\"]], \"0xcc\"]"]).assert_success().stdout_eq(str![[ + r#" +0xc881aac3c281bb81cc + +"# + ]]); cmd.cast_fuse(); - cmd.args(["--from-rlp", "0xcbc58455556666c0c0c2c1c0"]); - let out = cmd.stdout_lossy(); - assert!(out.contains("[[\"0x55556666\"],[],[],[[[]]]]"), "{}", out); + cmd.args(["--from-rlp", "0xcbc58455556666c0c0c2c1c0"]).assert_success().stdout_eq(str![[r#" +[["0x55556666"],[],[],[[[]]]] + +"#]]); }); // test for cast_rpc without arguments @@ -622,25 +621,33 @@ casttest!(receipt_revert_reason, |_prj, cmd| { let rpc = next_http_rpc_endpoint(); // - cmd.cast_fuse().args([ - "receipt", - "0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e", - "--rpc-url", - rpc.as_str(), - ]); + cmd.cast_fuse() + .args([ + "receipt", + "0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e", + "--rpc-url", + rpc.as_str(), + ]) + .assert_success(); let output = cmd.stdout_lossy(); assert!(!output.contains("revertReason")); // - cmd.cast_fuse().args([ - "receipt", - "0x0e07d8b53ed3d91314c80e53cf25bcde02084939395845cbb625b029d568135c", - "--rpc-url", - rpc.as_str(), - ]); - let output = cmd.stdout_lossy(); - assert!(output.contains("revertReason")); - assert!(output.contains("Transaction too old")); + cmd.cast_fuse() + .args([ + "receipt", + "0x0e07d8b53ed3d91314c80e53cf25bcde02084939395845cbb625b029d568135c", + "--rpc-url", + rpc.as_str(), + ]) + .assert_success() + .stdout_eq(str![[r#" +... +status 0 (failed) +... +revertReason Transaction too old, data: [..] + +"#]]); }); // tests that `cast --parse-bytes32-address` command is working correctly. @@ -648,9 +655,12 @@ casttest!(parse_bytes32_address, |_prj, cmd| { cmd.args([ "--parse-bytes32-address", "0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045", - ]); - let output = cmd.stdout_lossy(); - assert_eq!(output.trim(), "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045") + ]) + .assert_success() + .stdout_eq(str![[r#" +0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 + +"#]]); }); casttest!(access_list, |_prj, cmd| { @@ -664,12 +674,26 @@ casttest!(access_list, |_prj, cmd| { rpc.as_str(), "--gas-limit", // need to set this for alchemy.io to avoid "intrinsic gas too low" error "100000", - ]); + ]) + .assert_success() + .stdout_eq(str![[r#" +[GAS] +access list: +- address: 0xBb2b8038a1640196FbE3e38816F3e67Cba72D940 + keys: + 0x000000000000000000000000000000000000000000000000000000000000000c + 0x0000000000000000000000000000000000000000000000000000000000000006 + 0x0000000000000000000000000000000000000000000000000000000000000007 + 0x0000000000000000000000000000000000000000000000000000000000000008 +- address: 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 + keys: + 0x0d2a19d3ac39dc6cc6fd07423195495e18679bd8c7dd610aa1db7cd784a683a8 + 0x0000000000000000000000000000000000000000000000000000000000000005 +- address: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + keys: + 0x7fba2702a7d6e85ac783a88eacdc48e51310443458071f6db9ac66f8ca7068b8 - let output = cmd.stdout_lossy(); - assert!(output.contains("address: 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599")); - assert!(output.contains("0x0d2a19d3ac39dc6cc6fd07423195495e18679bd8c7dd610aa1db7cd784a683a8")); - assert!(output.contains("0x7fba2702a7d6e85ac783a88eacdc48e51310443458071f6db9ac66f8ca7068b8")); +"#]]); }); casttest!(logs_topics, |_prj, cmd| { @@ -821,12 +845,10 @@ casttest!(mktx, |_prj, cmd| { "--priority-gas-price", "1000000000", "0x0000000000000000000000000000000000000001", - ]); - let output = cmd.stdout_lossy(); - assert_eq!( - output.trim(), - "0x02f86b0180843b9aca008502540be4008252089400000000000000000000000000000000000000016480c001a070d55e79ed3ac9fc8f51e78eb91fd054720d943d66633f2eb1bc960f0126b0eca052eda05a792680de3181e49bab4093541f75b49d1ecbe443077b3660c836016a" - ); + ]).assert_success().stdout_eq(str![[r#" +0x02f86b0180843b9aca008502540be4008252089400000000000000000000000000000000000000016480c001a070d55e79ed3ac9fc8f51e78eb91fd054720d943d66633f2eb1bc960f0126b0eca052eda05a792680de3181e49bab4093541f75b49d1ecbe443077b3660c836016a + +"#]]); }); // ensure recipient or code is required @@ -882,43 +904,39 @@ casttest!(mktx_signer_from_match, |_prj, cmd| { "--priority-gas-price", "1000000000", "0x0000000000000000000000000000000000000001", - ]); - let output = cmd.stdout_lossy(); - assert_eq!( - output.trim(), - "0x02f86b0180843b9aca008502540be4008252089400000000000000000000000000000000000000018080c001a0cce9a61187b5d18a89ecd27ec675e3b3f10d37f165627ef89a15a7fe76395ce8a07537f5bffb358ffbef22cda84b1c92f7211723f9e09ae037e81686805d3e5505" - ); + ]).assert_success().stdout_eq(str![[r#" +0x02f86b0180843b9aca008502540be4008252089400000000000000000000000000000000000000018080c001a0cce9a61187b5d18a89ecd27ec675e3b3f10d37f165627ef89a15a7fe76395ce8a07537f5bffb358ffbef22cda84b1c92f7211723f9e09ae037e81686805d3e5505 + +"#]]); }); // tests that the raw encoded transaction is returned casttest!(tx_raw, |_prj, cmd| { let rpc = next_http_rpc_endpoint(); - // + // cmd.cast_fuse().args([ "tx", "0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e", "raw", "--rpc-url", rpc.as_str(), - ]); - let output = cmd.stdout_lossy(); + ]).assert_success().stdout_eq(str![[r#" +0xf86d824c548502743b65088275309491da5bf3f8eb72724e6f50ec6c3d199c6355c59c87a0a73f33e9e4cc8025a0428518b1748a08bbeb2392ea055b418538944d30adfc2accbbfa8362a401d3a4a07d6093ab2580efd17c11b277de7664fce56e6953cae8e925bec3313399860470 - // - assert_eq!( - output.trim(), - "0xf86d824c548502743b65088275309491da5bf3f8eb72724e6f50ec6c3d199c6355c59c87a0a73f33e9e4cc8025a0428518b1748a08bbeb2392ea055b418538944d30adfc2accbbfa8362a401d3a4a07d6093ab2580efd17c11b277de7664fce56e6953cae8e925bec3313399860470" - ); +"#]]); + // cmd.cast_fuse().args([ "tx", "0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e", "--raw", "--rpc-url", rpc.as_str(), - ]); - let output2 = cmd.stdout_lossy(); - assert_eq!(output, output2); + ]).assert_success().stdout_eq(str![[r#" +0xf86d824c548502743b65088275309491da5bf3f8eb72724e6f50ec6c3d199c6355c59c87a0a73f33e9e4cc8025a0428518b1748a08bbeb2392ea055b418538944d30adfc2accbbfa8362a401d3a4a07d6093ab2580efd17c11b277de7664fce56e6953cae8e925bec3313399860470 + +"#]]); }); // ensure receipt or code is required @@ -936,48 +954,54 @@ Must specify a recipient address or contract code to deploy }); casttest!(storage, |_prj, cmd| { - let empty = "0x0000000000000000000000000000000000000000000000000000000000000000"; - let rpc = next_http_rpc_endpoint(); - cmd.cast_fuse().args(["storage", "vitalik.eth", "1", "--rpc-url", &rpc]); - assert_eq!(cmd.stdout_lossy().trim(), empty); + cmd.cast_fuse() + .args(["storage", "vitalik.eth", "1", "--rpc-url", &rpc]) + .assert_success() + .stdout_eq(str![[r#" +0x0000000000000000000000000000000000000000000000000000000000000000 + +"#]]); let rpc = next_http_rpc_endpoint(); - cmd.cast_fuse().args(["storage", "vitalik.eth", "0x01", "--rpc-url", &rpc]); - assert_eq!(cmd.stdout_lossy().trim(), empty); + cmd.cast_fuse() + .args(["storage", "vitalik.eth", "0x01", "--rpc-url", &rpc]) + .assert_success() + .stdout_eq(str![[r#" +0x0000000000000000000000000000000000000000000000000000000000000000 + +"#]]); let rpc = next_http_rpc_endpoint(); let usdt = "0xdac17f958d2ee523a2206206994597c13d831ec7"; let decimals_slot = "0x09"; - let six = "0x0000000000000000000000000000000000000000000000000000000000000006"; - cmd.cast_fuse().args(["storage", usdt, decimals_slot, "--rpc-url", &rpc]); - assert_eq!(cmd.stdout_lossy().trim(), six); + cmd.cast_fuse() + .args(["storage", usdt, decimals_slot, "--rpc-url", &rpc]) + .assert_success() + .stdout_eq(str![[r#" +0x0000000000000000000000000000000000000000000000000000000000000006 + +"#]]); let rpc = next_http_rpc_endpoint(); let total_supply_slot = "0x01"; - let issued = "0x000000000000000000000000000000000000000000000000000000174876e800"; let block_before = "4634747"; let block_after = "4634748"; - cmd.cast_fuse().args([ - "storage", - usdt, - total_supply_slot, - "--rpc-url", - &rpc, - "--block", - block_before, - ]); - assert_eq!(cmd.stdout_lossy().trim(), empty); - cmd.cast_fuse().args([ - "storage", - usdt, - total_supply_slot, - "--rpc-url", - &rpc, - "--block", - block_after, - ]); - assert_eq!(cmd.stdout_lossy().trim(), issued); + cmd.cast_fuse() + .args(["storage", usdt, total_supply_slot, "--rpc-url", &rpc, "--block", block_before]) + .assert_success() + .stdout_eq(str![[r#" +0x0000000000000000000000000000000000000000000000000000000000000000 + +"#]]); + + cmd.cast_fuse() + .args(["storage", usdt, total_supply_slot, "--rpc-url", &rpc, "--block", block_after]) + .assert_success() + .stdout_eq(str![[r#" +0x000000000000000000000000000000000000000000000000000000174876e800 + +"#]]); }); // From b9e6206bb7c1a65c619cdc53b05d354eea88eb76 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 12:08:46 +0000 Subject: [PATCH 20/47] additional tests --- crates/cast/tests/cli/main.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index d920b1b53446b..7990370b1859c 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1086,10 +1086,8 @@ casttest!(interface_no_constructor, |prj, cmd| { let path = prj.root().join("interface.json"); fs::write(&path, interface).unwrap(); // Call `cast find-block` - cmd.args(["interface"]).arg(&path); - let output = cmd.stdout_lossy(); - - let s = r#"// SPDX-License-Identifier: UNLICENSED + cmd.args(["interface"]).arg(&path).assert_success().stdout_eq(str![[ + r#"// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.4; interface Interface { @@ -1108,8 +1106,10 @@ interface Interface { uint256[] memory minIncomingAssetAmounts_ ); function redeem(address _vaultProxy, bytes memory, bytes memory _assetData) external; -}"#; - assert_eq!(output.trim(), s); +} + +"# + ]]); }); // tests that fetches WETH interface from etherscan @@ -1117,10 +1117,9 @@ interface Interface { casttest!(fetch_weth_interface_from_etherscan, |_prj, cmd| { let weth_address = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; let api_key = "ZUB97R31KSYX7NYVW6224Q6EYY6U56H591"; - cmd.args(["interface", "--etherscan-api-key", api_key, weth_address]); - let output = cmd.stdout_lossy(); - - let weth_interface = r#"// SPDX-License-Identifier: UNLICENSED + cmd.args(["interface", "--etherscan-api-key", api_key, weth_address]) + .assert_success() + .stdout_eq(str![[r#"// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.4; interface WETH9 { @@ -1142,8 +1141,9 @@ interface WETH9 { function transfer(address dst, uint256 wad) external returns (bool); function transferFrom(address src, address dst, uint256 wad) external returns (bool); function withdraw(uint256 wad) external; -}"#; - assert_eq!(output.trim(), weth_interface); +} + +"#]]); }); const ENS_NAME: &str = "emo.eth"; From 0d76da1f8a660386709c93de83bc5127417d0c1c Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 12:21:20 +0000 Subject: [PATCH 21/47] more tests --- crates/cast/tests/cli/main.rs | 67 +++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 7990370b1859c..5d7fb92aea5ac 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1,7 +1,7 @@ //! Contains various tests for checking cast commands use alloy_chains::NamedChain; -use alloy_primitives::{address, b256, Address, B256}; +use alloy_primitives::{b256, B256}; use anvil::{Hardfork, NodeConfig}; use foundry_test_utils::{ casttest, @@ -1146,50 +1146,65 @@ interface WETH9 { "#]]); }); -const ENS_NAME: &str = "emo.eth"; -const ENS_NAMEHASH: B256 = - b256!("0a21aaf2f6414aa664deb341d1114351fdb023cad07bf53b28e57c26db681910"); -const ENS_ADDRESS: Address = address!("28679A1a632125fbBf7A68d850E50623194A709E"); - casttest!(ens_namehash, |_prj, cmd| { - cmd.args(["namehash", ENS_NAME]); - let out = cmd.stdout_lossy().trim().parse::(); - assert_eq!(out, Ok(ENS_NAMEHASH)); + cmd.args(["namehash", "emo.eth"]).assert_success().stdout_eq(str![[r#" +0x0a21aaf2f6414aa664deb341d1114351fdb023cad07bf53b28e57c26db681910 + +"#]]); }); casttest!(ens_lookup, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); - cmd.args(["lookup-address", &ENS_ADDRESS.to_string(), "--rpc-url", ð_rpc_url, "--verify"]); - let out = cmd.stdout_lossy(); - assert_eq!(out.trim(), ENS_NAME); + cmd.args([ + "lookup-address", + "0x28679A1a632125fbBf7A68d850E50623194A709E", + "--rpc-url", + ð_rpc_url, + "--verify", + ]) + .assert_success() + .stdout_eq(str![[r#" +emo.eth + +"#]]); }); casttest!(ens_resolve, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); - cmd.args(["resolve-name", ENS_NAME, "--rpc-url", ð_rpc_url, "--verify"]); - let out = cmd.stdout_lossy().trim().parse::
(); - assert_eq!(out, Ok(ENS_ADDRESS)); + cmd.args(["resolve-name", "emo.eth", "--rpc-url", ð_rpc_url, "--verify"]) + .assert_success() + .stdout_eq(str![[r#" +0x28679A1a632125fbBf7A68d850E50623194A709E + +"#]]); }); casttest!(ens_resolve_no_dot_eth, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); - let name = ENS_NAME.strip_suffix(".eth").unwrap(); - cmd.args(["resolve-name", name, "--rpc-url", ð_rpc_url, "--verify"]); - let (_out, err) = cmd.unchecked_output_lossy(); - assert!(err.contains("not found"), "{err:?}"); + cmd.args(["resolve-name", "emo", "--rpc-url", ð_rpc_url, "--verify"]) + .assert_failure() + .stderr_eq(str![[r#" +Error: +ENS resolver not found for name "emo" + +"#]]); }); casttest!(index7201, |_prj, cmd| { - let tests = - [("example.main", "0x183a6125c38840424c4a85fa12bab2ab606c4b6d0e7cc73c0c06ba5300eab500")]; - for (id, expected) in tests { - cmd.cast_fuse(); - assert_eq!(cmd.args(["index-erc7201", id]).stdout_lossy().trim(), expected); - } + cmd.args(["index-erc7201", "example.main"]).assert_success().stdout_eq(str![[r#" +0x183a6125c38840424c4a85fa12bab2ab606c4b6d0e7cc73c0c06ba5300eab500 + +"#]]); }); casttest!(index7201_unknown_formula_id, |_prj, cmd| { - cmd.args(["index-7201", "test", "--formula-id", "unknown"]).assert_err(); + cmd.args(["index-erc7201", "test", "--formula-id", "unknown"]).assert_failure().stderr_eq( + str![[r#" +Error: +unsupported formula ID: unknown + +"#]], + ); }); casttest!(block_number, |_prj, cmd| { From 417e2a50418f51772e769bd48627358ad71c20df Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 12:25:29 +0000 Subject: [PATCH 22/47] clean up --- crates/forge/tests/cli/test_cmd.rs | 62 ++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 49979e86fc005..ecda1ec3e40a9 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -913,22 +913,52 @@ contract PrecompileLabelsTest is Test { ) .unwrap(); - let output = cmd.args(["test", "-vvvv"]).stdout_lossy(); - assert!(output.contains("VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D]")); - assert!(output.contains("console: [0x000000000000000000636F6e736F6c652e6c6f67]")); - assert!(output.contains("Create2Deployer: [0x4e59b44847b379578588920cA78FbF26c0B4956C]")); - assert!(output.contains("DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38]")); - assert!(output.contains("DefaultTestContract: [0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84]")); - assert!(output.contains("ECRecover: [0x0000000000000000000000000000000000000001]")); - assert!(output.contains("SHA-256: [0x0000000000000000000000000000000000000002]")); - assert!(output.contains("RIPEMD-160: [0x0000000000000000000000000000000000000003]")); - assert!(output.contains("Identity: [0x0000000000000000000000000000000000000004]")); - assert!(output.contains("ModExp: [0x0000000000000000000000000000000000000005]")); - assert!(output.contains("ECAdd: [0x0000000000000000000000000000000000000006]")); - assert!(output.contains("ECMul: [0x0000000000000000000000000000000000000007]")); - assert!(output.contains("ECPairing: [0x0000000000000000000000000000000000000008]")); - assert!(output.contains("Blake2F: [0x0000000000000000000000000000000000000009]")); - assert!(output.contains("PointEvaluation: [0x000000000000000000000000000000000000000A]")); + cmd.args(["test", "-vvvv"]).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 1 test for test/Contract.t.sol:PrecompileLabelsTest +[PASS] testPrecompileLabels() ([GAS]) +Traces: + [9474] PrecompileLabelsTest::testPrecompileLabels() + ├─ [0] VM::deal(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(console: [0x000000000000000000636F6e736F6c652e6c6f67], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(Create2Deployer: [0x4e59b44847b379578588920cA78FbF26c0B4956C], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(DefaultTestContract: [0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(ECRecover: [0x0000000000000000000000000000000000000001], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(SHA-256: [0x0000000000000000000000000000000000000002], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(RIPEMD-160: [0x0000000000000000000000000000000000000003], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(Identity: [0x0000000000000000000000000000000000000004], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(ModExp: [0x0000000000000000000000000000000000000005], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(ECAdd: [0x0000000000000000000000000000000000000006], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(ECMul: [0x0000000000000000000000000000000000000007], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(ECPairing: [0x0000000000000000000000000000000000000008], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(Blake2F: [0x0000000000000000000000000000000000000009], 1000000000000000000 [1e18]) + │ └─ ← [Return] + ├─ [0] VM::deal(PointEvaluation: [0x000000000000000000000000000000000000000A], 1000000000000000000 [1e18]) + │ └─ ← [Return] + └─ ← [Stop] + +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#]]); }); // tests that `forge test` with config `show_logs: true` for fuzz tests will From 6d50901f7c26fdaa6e97b72f5a71b4f9cfd5561e Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 12:36:42 +0000 Subject: [PATCH 23/47] avoid unnecessary fuse --- crates/cast/tests/cli/main.rs | 51 ++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 5d7fb92aea5ac..9aee651540d36 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -621,14 +621,13 @@ casttest!(receipt_revert_reason, |_prj, cmd| { let rpc = next_http_rpc_endpoint(); // - cmd.cast_fuse() - .args([ - "receipt", - "0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e", - "--rpc-url", - rpc.as_str(), - ]) - .assert_success(); + cmd.args([ + "receipt", + "0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e", + "--rpc-url", + rpc.as_str(), + ]) + .assert_success(); let output = cmd.stdout_lossy(); assert!(!output.contains("revertReason")); @@ -915,7 +914,7 @@ casttest!(tx_raw, |_prj, cmd| { let rpc = next_http_rpc_endpoint(); // - cmd.cast_fuse().args([ + cmd.args([ "tx", "0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e", "raw", @@ -955,13 +954,12 @@ Must specify a recipient address or contract code to deploy casttest!(storage, |_prj, cmd| { let rpc = next_http_rpc_endpoint(); - cmd.cast_fuse() - .args(["storage", "vitalik.eth", "1", "--rpc-url", &rpc]) - .assert_success() - .stdout_eq(str![[r#" + cmd.args(["storage", "vitalik.eth", "1", "--rpc-url", &rpc]).assert_success().stdout_eq(str![ + [r#" 0x0000000000000000000000000000000000000000000000000000000000000000 -"#]]); +"#] + ]); let rpc = next_http_rpc_endpoint(); cmd.cast_fuse() @@ -1006,8 +1004,7 @@ casttest!(storage, |_prj, cmd| { // casttest!(storage_layout, |_prj, cmd| { - cmd.cast_fuse() - .args([ + cmd.args([ "storage", "--rpc-url", next_rpc_endpoint(NamedChain::Optimism).as_str(), @@ -1054,7 +1051,8 @@ casttest!(storage_layout, |_prj, cmd| { casttest!(balance, |_prj, cmd| { let rpc = next_http_rpc_endpoint(); let usdt = "0xdac17f958d2ee523a2206206994597c13d831ec7"; - cmd.cast_fuse().args([ + + cmd.args([ "balance", "0x0000000000000000000000000000000000000000", "--erc20", @@ -1062,6 +1060,7 @@ casttest!(balance, |_prj, cmd| { "--rpc-url", &rpc, ]); + cmd.cast_fuse().args([ "balance", "0x0000000000000000000000000000000000000000", @@ -1236,6 +1235,7 @@ casttest!(send_eip7702, async |_prj, cmd| { let (_api, handle) = anvil::spawn(NodeConfig::test().with_hardfork(Some(Hardfork::PragueEOF))).await; let endpoint = handle.http_endpoint(); + cmd.args([ "send", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", @@ -1258,12 +1258,13 @@ casttest!(send_eip7702, async |_prj, cmd| { }); casttest!(hash_message, |_prj, cmd| { - let tests = [ - ("hello", "0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750"), - ("0x68656c6c6f", "0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750"), - ]; - for (message, expected) in tests { - cmd.cast_fuse(); - assert_eq!(cmd.args(["hash-message", message]).stdout_lossy().trim(), expected); - } + cmd.args(["hash-message", "hello"]).assert_success().stdout_eq(str![[r#" +0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750 + +"#]]); + + cmd.cast_fuse().args(["hash-message", "0x68656c6c6f"]).assert_success().stdout_eq(str![[r#" +0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750 + +"#]]); }); From 641ef3a2006ac896f937d85cfd7e1fc4ca75d7a9 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 13:51:19 +0000 Subject: [PATCH 24/47] fix malformed test + full output comparison asserting specific layout, not negative assertion --- crates/cast/tests/cli/main.rs | 93 +++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 25 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 9aee651540d36..e4b734e4a833e 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -7,6 +7,7 @@ use foundry_test_utils::{ casttest, rpc::{next_http_rpc_endpoint, next_rpc_endpoint, next_ws_rpc_endpoint}, str, + util::OutputExt, }; use std::{fs, io::Write, path::Path, str::FromStr}; @@ -627,9 +628,29 @@ casttest!(receipt_revert_reason, |_prj, cmd| { "--rpc-url", rpc.as_str(), ]) - .assert_success(); - let output = cmd.stdout_lossy(); - assert!(!output.contains("revertReason")); + .assert_success() + .stdout_eq(str![[r#" + +blockHash 0x2cfe65be49863676b6dbc04d58176a14f39b123f1e2f4fea0383a2d82c2c50d0 +blockNumber 16239315 +contractAddress +cumulativeGasUsed 10743428 +effectiveGasPrice 10539984136 +from 0x199D5ED7F45F4eE35960cF22EAde2076e95B253F +gasUsed 21000 +logs [] +logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +root +status 1 (success) +transactionHash 0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e +transactionIndex 116 +type 0 +blobGasPrice +blobGasUsed +authorizationList +to 0x91da5bf3F8Eb72724E6f50Ec6C3D199C6355c59c + +"#]]); // cmd.cast_fuse() @@ -641,10 +662,26 @@ casttest!(receipt_revert_reason, |_prj, cmd| { ]) .assert_success() .stdout_eq(str![[r#" -... + +blockHash 0x883f974b17ca7b28cb970798d1c80f4d4bb427473dc6d39b2a7fe24edc02902d +blockNumber 14839405 +contractAddress +cumulativeGasUsed 20273649 +effectiveGasPrice 21491736378 +from 0x3cF412d970474804623bb4e3a42dE13F9bCa5436 +gasUsed 24952 +logs [] +logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +root status 0 (failed) -... -revertReason Transaction too old, data: [..] +transactionHash 0x0e07d8b53ed3d91314c80e53cf25bcde02084939395845cbb625b029d568135c +transactionIndex 173 +type 2 +blobGasPrice +blobGasUsed +authorizationList +to 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45 +revertReason Transaction too old, data: "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000135472616e73616374696f6e20746f6f206f6c6400000000000000000000000000" "#]]); }); @@ -1052,26 +1089,32 @@ casttest!(balance, |_prj, cmd| { let rpc = next_http_rpc_endpoint(); let usdt = "0xdac17f958d2ee523a2206206994597c13d831ec7"; - cmd.args([ - "balance", - "0x0000000000000000000000000000000000000000", - "--erc20", - usdt, - "--rpc-url", - &rpc, - ]); - - cmd.cast_fuse().args([ - "balance", - "0x0000000000000000000000000000000000000000", - "--erc721", - usdt, - "--rpc-url", - &rpc, - ]); + let usdt_result = cmd + .args([ + "balance", + "0x0000000000000000000000000000000000000000", + "--erc20", + usdt, + "--rpc-url", + &rpc, + ]) + .assert_success() + .get_output() + .stdout_lossy(); - let usdt_result = cmd.stdout_lossy(); - let alias_result = cmd.stdout_lossy(); + let alias_result = cmd + .cast_fuse() + .args([ + "balance", + "0x0000000000000000000000000000000000000000", + "--erc721", + usdt, + "--rpc-url", + &rpc, + ]) + .assert_success() + .get_output() + .stdout_lossy(); assert_ne!(usdt_result, "0x0000000000000000000000000000000000000000000000000000000000000000"); assert_eq!(alias_result, usdt_result); From 9d3dce22278e3f29d4cd75cd74a843f47d506375 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 14:14:10 +0000 Subject: [PATCH 25/47] access list ordering is not consistent --- crates/cast/tests/cli/main.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index e4b734e4a833e..3cc5ce58e08fd 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -715,19 +715,15 @@ casttest!(access_list, |_prj, cmd| { .stdout_eq(str![[r#" [GAS] access list: -- address: 0xBb2b8038a1640196FbE3e38816F3e67Cba72D940 +- address: [..] keys: - 0x000000000000000000000000000000000000000000000000000000000000000c - 0x0000000000000000000000000000000000000000000000000000000000000006 - 0x0000000000000000000000000000000000000000000000000000000000000007 - 0x0000000000000000000000000000000000000000000000000000000000000008 -- address: 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 +... +- address: [..] keys: - 0x0d2a19d3ac39dc6cc6fd07423195495e18679bd8c7dd610aa1db7cd784a683a8 - 0x0000000000000000000000000000000000000000000000000000000000000005 -- address: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 +... +- address: [..] keys: - 0x7fba2702a7d6e85ac783a88eacdc48e51310443458071f6db9ac66f8ca7068b8 +... "#]]); }); From 3741cf67ba50899ce134607a7ea908fea7c272fa Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 14:28:51 +0000 Subject: [PATCH 26/47] enforce block layout --- crates/cast/tests/cli/main.rs | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 3cc5ce58e08fd..2ac485a0e631e 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -24,9 +24,28 @@ casttest!(latest_block, |_prj, cmd| { // Call `cast find-block` cmd.args(["block", "latest", "--rpc-url", eth_rpc_url.as_str()]); cmd.assert_success().stdout_eq(str![[r#" -... -gasUsed [..] -... + + +baseFeePerGas [..] +difficulty [..] +extraData [..] +gasLimit [..] +gasUsed [..] +hash [..] +logsBloom [..] +miner [..] +mixHash [..] +nonce [..] +number [..] +parentHash [..] +transactionsRoot [..] +receiptsRoot [..] +sha3Uncles [..] +size [..] +stateRoot [..] +timestamp [..] +withdrawalsRoot [..] +totalDifficulty [..] transactions: [ ... ] @@ -1096,7 +1115,9 @@ casttest!(balance, |_prj, cmd| { ]) .assert_success() .get_output() - .stdout_lossy(); + .stdout_lossy() + .trim() + .to_string(); let alias_result = cmd .cast_fuse() @@ -1110,9 +1131,11 @@ casttest!(balance, |_prj, cmd| { ]) .assert_success() .get_output() - .stdout_lossy(); + .stdout_lossy() + .trim() + .to_string(); - assert_ne!(usdt_result, "0x0000000000000000000000000000000000000000000000000000000000000000"); + assert_ne!(usdt_result, "0"); assert_eq!(alias_result, usdt_result); }); From 18ede7b431e76edc8a7a1623febaccb18da01928 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 14:37:54 +0000 Subject: [PATCH 27/47] use stdout_eq file with relative path as dynamic joined CARGO_MANIFEST_DIR does not work --- crates/cast/tests/cli/main.rs | 70 ++------------------- crates/cast/tests/fixtures/cast_logs.stdout | 13 ++++ 2 files changed, 18 insertions(+), 65 deletions(-) create mode 100644 crates/cast/tests/fixtures/cast_logs.stdout diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 2ac485a0e631e..4bf22e8cbf63b 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -4,7 +4,7 @@ use alloy_chains::NamedChain; use alloy_primitives::{b256, B256}; use anvil::{Hardfork, NodeConfig}; use foundry_test_utils::{ - casttest, + casttest, file, rpc::{next_http_rpc_endpoint, next_rpc_endpoint, next_ws_rpc_endpoint}, str, util::OutputExt, @@ -761,22 +761,7 @@ casttest!(logs_topics, |_prj, cmd| { "0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b", ]) .assert_success() - .stdout_eq(str![[r#" -- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE - blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c - blockNumber: 12421182 - data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 - logIndex: 15 - removed: false - topics: [ - 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef - 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b - 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 - ] - transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 - transactionIndex: 8 - -"#]]); + .stdout_eq(file!["../fixtures/cast_logs.stdout"]); }); casttest!(logs_topic_2, |_prj, cmd| { @@ -795,22 +780,7 @@ casttest!(logs_topic_2, |_prj, cmd| { * `to` address */ ]) .assert_success() - .stdout_eq(str![[r#" -- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE - blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c - blockNumber: 12421182 - data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 - logIndex: 15 - removed: false - topics: [ - 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef - 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b - 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 - ] - transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 - transactionIndex: 8 - -"#]]); + .stdout_eq(file!["../fixtures/cast_logs.stdout"]); }); casttest!(logs_sig, |_prj, cmd| { @@ -827,22 +797,7 @@ casttest!(logs_sig, |_prj, cmd| { "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", ]) .assert_success() - .stdout_eq(str![[r#" -- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE - blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c - blockNumber: 12421182 - data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 - logIndex: 15 - removed: false - topics: [ - 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef - 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b - 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 - ] - transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 - transactionIndex: 8 - -"#]]); + .stdout_eq(file!["../fixtures/cast_logs.stdout"]); }); casttest!(logs_sig_2, |_prj, cmd| { @@ -860,22 +815,7 @@ casttest!(logs_sig_2, |_prj, cmd| { "0x68A99f89E475a078645f4BAC491360aFe255Dff1", ]) .assert_success() - .stdout_eq(str![[r#" -- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE - blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c - blockNumber: 12421182 - data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 - logIndex: 15 - removed: false - topics: [ - 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef - 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b - 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 - ] - transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 - transactionIndex: 8 - -"#]]); + .stdout_eq(file!["../fixtures/cast_logs.stdout"]); }); casttest!(mktx, |_prj, cmd| { diff --git a/crates/cast/tests/fixtures/cast_logs.stdout b/crates/cast/tests/fixtures/cast_logs.stdout new file mode 100644 index 0000000000000..1729394f671ee --- /dev/null +++ b/crates/cast/tests/fixtures/cast_logs.stdout @@ -0,0 +1,13 @@ +- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE + blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c + blockNumber: 12421182 + data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302 + logIndex: 15 + removed: false + topics: [ + 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef + 0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b + 0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1 + ] + transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7 + transactionIndex: 8 From e050f18a6d8f2039f7c452a2b518a1c389242e27 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 15:14:29 +0000 Subject: [PATCH 28/47] continue migrating tests --- crates/forge/tests/cli/build.rs | 5 +- crates/forge/tests/cli/cmd.rs | 101 +++++++++++++++++++------------- 2 files changed, 62 insertions(+), 44 deletions(-) diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index 0b1de40b3fc14..a5a34446148a9 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -54,13 +54,12 @@ Compiler run successful! // tests build output is as expected forgetest_init!(build_sizes_no_forge_std, |prj, cmd| { - cmd.args(["build", "--sizes"]); - cmd.assert_success().stdout_eq(str![ + cmd.args(["build", "--sizes"]).assert_success().stdout_eq(str![ r#" ... | Contract | Size (B) | Margin (B) | |----------|----------|------------| -| Counter | [..] +| Counter | 247 | 24,329 | ... "# ]); diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index ab3f4f3d1d861..3338b80063f88 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -659,10 +659,30 @@ contract Greeter { ) .unwrap(); - cmd.arg("build"); + cmd.arg("build").assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. + [FILE]:5:18: + | +5 | function foo(uint256 a) public { + | ^^^^^^^^^ + +Warning (2072): Unused local variable. + [FILE]:6:9: + | +6 | uint256 x = 1; + | ^^^^^^^^^ + +Warning (2018): Function state mutability can be restricted to pure + [FILE]:5:5: + | +5 | function foo(uint256 a) public { + | ^ (Relevant source part starts here and spans across multiple lines). + - let output = cmd.stdout_lossy(); - assert!(output.contains("Warning"), "{output}"); +"#]]); }); // Tests that direct import paths are handled correctly @@ -700,13 +720,12 @@ library FooLib { ) .unwrap(); - cmd.arg("build"); - - assert!(cmd.stdout_lossy().ends_with( - " + cmd.arg("build").assert_success().stdout_eq(str![[r#" +Compiling 2 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] Compiler run successful! -" - )); + +"#]]); }); // tests that the `inspect` command works correctly @@ -726,17 +745,18 @@ contract Foo { ) .unwrap(); - let check_output = |output: String| { - let output = output.trim(); - assert!(output.starts_with("0x") && hex::decode(output).is_ok(), "{output}"); - }; + cmd.arg("inspect").arg(contract_name).arg("bytecode").assert_success().stdout_eq(str![[r#" +0x60806040[..] - cmd.arg("inspect").arg(contract_name).arg("bytecode"); - check_output(cmd.stdout_lossy()); +"#]]); let info = format!("src/{}:{}", path.file_name().unwrap().to_string_lossy(), contract_name); - cmd.forge_fuse().arg("inspect").arg(info).arg("bytecode"); - check_output(cmd.stdout_lossy()); + cmd.forge_fuse().arg("inspect").arg(info).arg("bytecode").assert_success().stdout_eq(str![[ + r#" +0x60806040[..] + +"# + ]]); }); // test that `forge snapshot` commands work @@ -1808,45 +1828,44 @@ Compiler run successful! forgetest_init!(can_build_sizes_repeatedly, |prj, cmd| { prj.clear_cache(); - cmd.args(["build", "--sizes"]); - let out = cmd.stdout_lossy(); - - // contains: Counter ┆ 0.247 ┆ 24.329 - assert!(out.contains(TEMPLATE_CONTRACT)); + cmd.args(["build", "--sizes"]).assert_success().stdout_eq(str![[r#" +Compiling 27 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +| Contract | Size (B) | Margin (B) | +|----------|----------|------------| +| Counter | 247 | 24,329 | - // get the entire table - let table = out.split("Compiler run successful!").nth(1).unwrap().trim(); - let unchanged = cmd.stdout_lossy(); - assert!(unchanged.contains(table), "{}", table); +"#]]); }); // checks that build --names includes all contracts even if unchanged forgetest_init!(can_build_names_repeatedly, |prj, cmd| { prj.clear_cache(); - cmd.args(["build", "--names"]); - let out = cmd.stdout_lossy(); - - assert!(out.contains(TEMPLATE_CONTRACT)); - - // get the entire list - let list = out.split("Compiler run successful!").nth(1).unwrap().trim(); + cmd.args(["build", "--names"]).assert_success().stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + compiler version: [..] + - [..] +... - let unchanged = cmd.stdout_lossy(); - assert!(unchanged.contains(list), "{}", list); +"#]]); }); // forgetest_init!(can_inspect_counter_pretty, |prj, cmd| { - cmd.args(["inspect", "src/Counter.sol:Counter", "abi", "--pretty"]); - let output = cmd.stdout_lossy(); - assert_eq!( - output.trim(), - "interface Counter { + cmd.args(["inspect", "src/Counter.sol:Counter", "abi", "--pretty"]).assert_success().stdout_eq( + str![[r#" +interface Counter { function increment() external; function number() external view returns (uint256); function setNumber(uint256 newNumber) external; -}" +} + + +"#]], ); }); From d51e33a26fcb398612cf1cc9c0d40438287c0dd5 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 15:19:40 +0000 Subject: [PATCH 29/47] more tests --- crates/forge/tests/cli/cmd.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 3338b80063f88..d3cc48444647c 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -813,20 +813,27 @@ contract A { ) .unwrap(); - cmd.args(["build", "--force"]); - let out = cmd.stdout_lossy(); - // expect no warning as path is ignored - assert!(out.contains("Compiler run successful!")); - assert!(!out.contains("Compiler run successful with warnings:")); + cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); // Reconfigure without ignored paths or error codes and check for warnings // need to reset empty error codes as default would set some error codes prj.write_config(Config { ignored_error_codes: vec![], ..Default::default() }); - let out = cmd.stdout_lossy(); - // expect warnings as path is not ignored - assert!(out.contains("Compiler run successful with warnings:"), "{out}"); - assert!(out.contains("Warning") && out.contains("SPDX-License-Identifier"), "{out}"); + cmd.args(["build"]).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +[FILE] + + +"#]]); }); // test that `forge build` does not print `(with warnings)` if there arent any From bdede9b6bfc56a47bd453a49beb5df534ea709df Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 15:48:04 +0000 Subject: [PATCH 30/47] more tests --- crates/forge/tests/cli/cmd.rs | 124 ++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index d3cc48444647c..c7a413201f08b 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -824,7 +824,7 @@ Compiler run successful! // need to reset empty error codes as default would set some error codes prj.write_config(Config { ignored_error_codes: vec![], ..Default::default() }); - cmd.args(["build"]).assert_success().stdout_eq(str![[r#" + cmd.forge_fuse().args(["build", "--force"]).assert_success().stdout_eq(str![[r#" Compiling 1 files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful with warnings: @@ -836,39 +836,6 @@ Warning: SPDX license identifier not provided in source file. Before publishing, "#]]); }); -// test that `forge build` does not print `(with warnings)` if there arent any -forgetest!(can_compile_without_warnings, |prj, cmd| { - let config = Config { - ignored_error_codes: vec![SolidityErrorCode::SpdxLicenseNotProvided], - ..Default::default() - }; - prj.write_config(config); - prj.add_raw_source( - "A", - r" -pragma solidity *; -contract A { - function testExample() public {} -} - ", - ) - .unwrap(); - - cmd.args(["build", "--force"]); - let out = cmd.stdout_lossy(); - // no warnings - assert!(out.contains("Compiler run successful!")); - assert!(!out.contains("Compiler run successful with warnings:")); - - // don't ignore errors - let config = Config { ignored_error_codes: vec![], ..Default::default() }; - prj.write_config(config); - let out = cmd.stdout_lossy(); - - assert!(out.contains("Compiler run successful with warnings:"), "{out}"); - assert!(out.contains("Warning") && out.contains("SPDX-License-Identifier"), "{out}"); -}); - // test that `forge build` compiles when severity set to error, fails when set to warning, and // handles ignored error codes as an exception forgetest!(can_fail_compile_with_warnings, |prj, cmd| { @@ -886,14 +853,30 @@ contract A { .unwrap(); // there are no errors - cmd.args(["build", "--force"]); - let out = cmd.stdout_lossy(); - assert!(out.contains("Compiler run successful with warnings:"), "{out}"); + cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +[FILE] + + +"#]]); // warning fails to compile let config = Config { ignored_error_codes: vec![], deny_warnings: true, ..Default::default() }; prj.write_config(config); - cmd.assert_err(); + + cmd.forge_fuse().args(["build", "--force"]).assert_failure().stderr_eq(str![[r#" +Error: +Compiler run failed: +Warning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +[FILE] + + +"#]]); // ignores error code and compiles let config = Config { @@ -902,10 +885,13 @@ contract A { ..Default::default() }; prj.write_config(config); - let out = cmd.stdout_lossy(); - assert!(out.contains("Compiler run successful!")); - assert!(!out.contains("Compiler run successful with warnings:")); + cmd.forge_fuse().args(["build", "--force"]).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); }); // test that a failing `forge build` does not impact followup builds @@ -937,8 +923,13 @@ contract BTest is DSTest { ) .unwrap(); - cmd.arg("build"); - cmd.assert_non_empty_stdout(); + cmd.arg("build").assert_success().stdout_eq(str![[r#" +Compiling 3 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); + prj.assert_cache_exists(); prj.assert_artifacts_dir_exists(); @@ -955,16 +946,34 @@ contract CTest is DSTest { prj.add_source("CTest.t.sol", syntax_err).unwrap(); // `forge build --force` which should fail - cmd.arg("--force"); - cmd.assert_err(); + cmd.forge_fuse().args(["build", "--force"]).assert_failure().stderr_eq(str![[r#" +Error: +Compiler run failed: +Error (2314): Expected ';' but got identifier + [FILE]:7:19: + | +7 | THIS WILL CAUSE AN ERROR + | ^^^^^ + + +"#]]); // but ensure this cleaned cache and artifacts assert!(!prj.paths().artifacts.exists()); assert!(!prj.cache().exists()); // still errors - cmd.forge_fuse().arg("build"); - cmd.assert_err(); + cmd.forge_fuse().args(["build", "--force"]).assert_failure().stderr_eq(str![[r#" +Error: +Compiler run failed: +Error (2314): Expected ';' but got identifier + [FILE]:7:19: + | +7 | THIS WILL CAUSE AN ERROR + | ^^^^^ + + +"#]]); // resolve the error by replacing the file prj.add_source( @@ -980,7 +989,14 @@ contract CTest is DSTest { ) .unwrap(); - cmd.assert_non_empty_stdout(); + cmd.forge_fuse().args(["build", "--force"]).assert_success().stdout_eq(str![[r#" +Compiling 4 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); + + // cmd.assert_non_empty_stdout(); prj.assert_cache_exists(); prj.assert_artifacts_dir_exists(); @@ -989,7 +1005,17 @@ contract CTest is DSTest { // introduce the error again but building without force prj.add_source("CTest.t.sol", syntax_err).unwrap(); - cmd.assert_err(); + cmd.forge_fuse().arg("build").assert_failure().stderr_eq(str![[r#" +Error: +Compiler run failed: +Error (2314): Expected ';' but got identifier + [FILE]:7:19: + | +7 | THIS WILL CAUSE AN ERROR + | ^^^^^ + + +"#]]); // ensure unchanged cache file let cache_after = fs::read_to_string(prj.cache()).unwrap(); From fadbda3915fe9805257ee1bc938f5193c9e6c116 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 16:08:46 +0000 Subject: [PATCH 31/47] improve tests --- crates/forge/tests/cli/cmd.rs | 67 +++++++++++++++++++++----------- crates/forge/tests/cli/config.rs | 44 ++++++++++++++------- 2 files changed, 74 insertions(+), 37 deletions(-) diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index c7a413201f08b..352a4332de7cf 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1,7 +1,6 @@ //! Contains various tests for checking forge's commands use crate::constants::*; -use alloy_primitives::hex; use foundry_compilers::artifacts::{remappings::Remapping, ConfigurableContractArtifact, Metadata}; use foundry_config::{ parse_with_profile, BasicConfig, Chain, Config, FuzzConfig, InvariantConfig, SolidityErrorCode, @@ -1151,8 +1150,9 @@ forgetest!( let package_mod = git_mod.join("forge-5980-test"); // install main dependency - cmd.forge_fuse().args(["install", "evalir/forge-5980-test", "--no-commit"]); - cmd.assert_non_empty_stdout(); + cmd.forge_fuse() + .args(["install", "evalir/forge-5980-test", "--no-commit"]) + .assert_non_empty_stdout(); // assert paths exist assert!(package.exists()); @@ -1164,8 +1164,7 @@ forgetest!( // try to update the top-level dependency; there should be no update for this dependency, // but its sub-dependency has upstream (breaking) changes; forge should not attempt to // update the sub-dependency - cmd.forge_fuse().args(["update", "lib/forge-5980-test"]); - cmd.stdout_lossy(); + cmd.forge_fuse().args(["update", "lib/forge-5980-test"]).assert_empty_stdout(); // add explicit remappings for test file let config = Config { @@ -1195,9 +1194,12 @@ contract CounterCopy is Counter { .unwrap(); // build and check output - cmd.forge_fuse().arg("build"); - let output = cmd.stdout_lossy(); - assert!(output.contains("Compiler run successful",)); + cmd.forge_fuse().arg("build").assert_success().stdout_eq(str![[r#" +Compiling 3 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); } ); @@ -1298,23 +1300,36 @@ contract ContractThreeTest is DSTest { gas_reports_ignore: (vec![]), ..Default::default() }); - cmd.forge_fuse(); - let first_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + + let first_out = cmd + .forge_fuse() + .arg("test") + .arg("--gas-report") + .assert_success() + .get_output() + .stdout_lossy(); assert!(first_out.contains("foo") && first_out.contains("bar") && first_out.contains("baz")); - cmd.forge_fuse(); prj.write_config(Config { gas_reports: (vec![]), ..Default::default() }); - cmd.forge_fuse(); - let second_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + let second_out = cmd + .forge_fuse() + .arg("test") + .arg("--gas-report") + .assert_success() + .get_output() + .stdout_lossy(); assert!(second_out.contains("foo") && second_out.contains("bar") && second_out.contains("baz")); - cmd.forge_fuse(); prj.write_config(Config { gas_reports: (vec!["*".to_string()]), ..Default::default() }); - cmd.forge_fuse(); - let third_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + let third_out = cmd + .forge_fuse() + .arg("test") + .arg("--gas-report") + .assert_success() + .get_output() + .stdout_lossy(); assert!(third_out.contains("foo") && third_out.contains("bar") && third_out.contains("baz")); - cmd.forge_fuse(); prj.write_config(Config { gas_reports: (vec![ "ContractOne".to_string(), @@ -1323,8 +1338,13 @@ contract ContractThreeTest is DSTest { ]), ..Default::default() }); - cmd.forge_fuse(); - let fourth_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + let fourth_out = cmd + .forge_fuse() + .arg("test") + .arg("--gas-report") + .assert_success() + .get_output() + .stdout_lossy(); assert!(fourth_out.contains("foo") && fourth_out.contains("bar") && fourth_out.contains("baz")); }); @@ -1422,7 +1442,8 @@ contract ContractThreeTest is DSTest { // report for One prj.write_config(Config { gas_reports: vec!["ContractOne".to_string()], ..Default::default() }); cmd.forge_fuse(); - let first_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + let first_out = + cmd.arg("test").arg("--gas-report").assert_success().get_output().stdout_lossy(); assert!( first_out.contains("foo") && !first_out.contains("bar") && !first_out.contains("baz"), "foo:\n{first_out}" @@ -1431,7 +1452,8 @@ contract ContractThreeTest is DSTest { // report for Two prj.write_config(Config { gas_reports: vec!["ContractTwo".to_string()], ..Default::default() }); cmd.forge_fuse(); - let second_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + let second_out = + cmd.arg("test").arg("--gas-report").assert_success().get_output().stdout_lossy(); assert!( !second_out.contains("foo") && second_out.contains("bar") && !second_out.contains("baz"), "bar:\n{second_out}" @@ -1443,7 +1465,8 @@ contract ContractThreeTest is DSTest { ..Default::default() }); cmd.forge_fuse(); - let third_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + let third_out = + cmd.arg("test").arg("--gas-report").assert_success().get_output().stdout_lossy(); assert!( !third_out.contains("foo") && !third_out.contains("bar") && third_out.contains("baz"), "baz:\n{third_out}" diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index ffb64a4f1be0b..e238a7ee6d7b2 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -14,7 +14,7 @@ use foundry_config::{ use foundry_evm::opts::EvmOpts; use foundry_test_utils::{ foundry_compilers::artifacts::{remappings::Remapping, EvmVersion}, - util::{pretty_err, TestCommand, OTHER_SOLC_VERSION}, + util::{pretty_err, OutputExt, TestCommand, OTHER_SOLC_VERSION}, }; use path_slash::PathBufExt; use similar_asserts::assert_eq; @@ -159,10 +159,10 @@ forgetest!(can_extract_config_values, |prj, cmd| { // tests config gets printed to std out forgetest!(can_show_config, |prj, cmd| { - cmd.arg("config"); let expected = Config::load_with_root(prj.root()).to_string_pretty().unwrap().trim().to_string(); - assert_eq!(expected, cmd.stdout_lossy().trim().to_string()); + let output = cmd.arg("config").assert_success().get_output().stdout_lossy().trim().to_string(); + assert_eq!(expected, output); }); // checks that config works @@ -187,9 +187,9 @@ forgetest_init!(can_override_config, |prj, cmd| { Remapping::from(profile.remappings[0].clone()).to_string() ); - cmd.arg("config"); - let expected = profile.to_string_pretty().unwrap(); - assert_eq!(expected.trim().to_string(), cmd.stdout_lossy().trim().to_string()); + let expected = profile.to_string_pretty().unwrap().trim().to_string(); + let output = cmd.arg("config").assert_success().get_output().stdout_lossy().trim().to_string(); + assert_eq!(expected, output); // remappings work let remappings_txt = @@ -235,9 +235,16 @@ forgetest_init!(can_override_config, |prj, cmd| { std::env::remove_var("DAPP_REMAPPINGS"); pretty_err(&remappings_txt, fs::remove_file(&remappings_txt)); - cmd.set_cmd(prj.forge_bin()).args(["config", "--basic"]); - let expected = profile.into_basic().to_string_pretty().unwrap(); - assert_eq!(expected.trim().to_string(), cmd.stdout_lossy().trim().to_string()); + let expected = profile.into_basic().to_string_pretty().unwrap().trim().to_string(); + let output = cmd + .forge_fuse() + .args(["config", "--basic"]) + .assert_success() + .get_output() + .stdout_lossy() + .trim() + .to_string(); + assert_eq!(expected, output); }); forgetest_init!(can_parse_remappings_correctly, |prj, cmd| { @@ -254,9 +261,9 @@ forgetest_init!(can_parse_remappings_correctly, |prj, cmd| { // the loaded config has resolved, absolute paths assert_eq!("forge-std/=lib/forge-std/src/", Remapping::from(r.clone()).to_string()); - cmd.arg("config"); - let expected = profile.to_string_pretty().unwrap(); - assert_eq!(expected.trim().to_string(), cmd.stdout_lossy().trim().to_string()); + let expected = profile.to_string_pretty().unwrap().trim().to_string(); + let output = cmd.arg("config").assert_success().get_output().stdout_lossy().trim().to_string(); + assert_eq!(expected, output); let install = |cmd: &mut TestCommand, dep: &str| { cmd.forge_fuse().args(["install", dep, "--no-commit"]); @@ -287,9 +294,16 @@ forgetest_init!(can_parse_remappings_correctly, |prj, cmd| { ); pretty_err(&remappings_txt, fs::remove_file(&remappings_txt)); - cmd.set_cmd(prj.forge_bin()).args(["config", "--basic"]); - let expected = profile.into_basic().to_string_pretty().unwrap(); - assert_eq!(expected.trim().to_string(), cmd.stdout_lossy().trim().to_string()); + let expected = profile.into_basic().to_string_pretty().unwrap().trim().to_string(); + let output = cmd + .forge_fuse() + .args(["config", "--basic"]) + .assert_success() + .get_output() + .stdout_lossy() + .trim() + .to_string(); + assert_eq!(expected, output); }); forgetest_init!(can_detect_config_vals, |prj, _cmd| { From 4fb9e0efaa17a932039f8fcff236fd5199898e4a Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 16:10:43 +0000 Subject: [PATCH 32/47] restore test --- crates/forge/tests/cli/cmd.rs | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 352a4332de7cf..ed9cd43521d74 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -832,6 +832,47 @@ Warning: SPDX license identifier not provided in source file. Before publishing, [FILE] +"#]]); +}); + +// test that `forge build` does not print `(with warnings)` if there arent any +forgetest!(can_compile_without_warnings, |prj, cmd| { + let config = Config { + ignored_error_codes: vec![SolidityErrorCode::SpdxLicenseNotProvided], + ..Default::default() + }; + prj.write_config(config); + prj.add_raw_source( + "A", + r" +pragma solidity *; +contract A { + function testExample() public {} +} + ", + ) + .unwrap(); + + cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); + + // don't ignore errors + let config = Config { ignored_error_codes: vec![], ..Default::default() }; + prj.write_config(config); + + cmd.forge_fuse().args(["build", "--force"]).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +[FILE] + + "#]]); }); From 758d4407bcd524f3db382b62c8931e34a6b1fe80 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Mon, 26 Aug 2024 17:03:32 +0000 Subject: [PATCH 33/47] replace stdout_lossy, unify access --- crates/cast/tests/cli/main.rs | 91 ++++--- crates/forge/tests/cli/cmd.rs | 9 +- crates/forge/tests/cli/config.rs | 44 ++-- crates/forge/tests/cli/create.rs | 50 ++-- crates/forge/tests/cli/script.rs | 365 +++++++++++++++++++---------- crates/forge/tests/cli/test_cmd.rs | 30 ++- crates/forge/tests/cli/verify.rs | 58 +++-- crates/test-utils/src/util.rs | 17 -- 8 files changed, 420 insertions(+), 244 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 4bf22e8cbf63b..54376394ada7b 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -379,7 +379,7 @@ casttest!(wallet_import_and_decrypt, |prj, cmd| { ]); // get the PK out of the output (last word in the output) - let decrypt_output = decrypt_output.stdout_lossy(); + let decrypt_output = decrypt_output.assert_success().get_output().stdout_lossy(); let private_key_string = decrypt_output.split_whitespace().last().unwrap(); // check that the decrypted private key matches the imported private key let decrypted_private_key = B256::from_str(private_key_string).unwrap(); @@ -390,19 +390,24 @@ casttest!(wallet_import_and_decrypt, |prj, cmd| { // tests that `cast estimate` is working correctly. casttest!(estimate_function_gas, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); - cmd.args([ - "estimate", - "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", // vitalik.eth - "--value", - "100", - "deposit()", - "--rpc-url", - eth_rpc_url.as_str(), - ]) - .assert_success(); // ensure we get a positive non-error value for gas estimate - let output: u32 = cmd.stdout_lossy().trim().parse().unwrap(); + let output: u32 = cmd + .args([ + "estimate", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", // vitalik.eth + "--value", + "100", + "deposit()", + "--rpc-url", + eth_rpc_url.as_str(), + ]) + .assert_success() + .get_output() + .stdout_lossy() + .trim() + .parse() + .unwrap(); assert!(output.ge(&0)); }); @@ -411,39 +416,45 @@ casttest!(estimate_contract_deploy_gas, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); // sample contract code bytecode. Wouldn't run but is valid bytecode that the estimate method // accepts and could be deployed. - cmd.args([ - "estimate", - "--rpc-url", - eth_rpc_url.as_str(), - "--create", - "0000", - "ERC20(uint256,string,string)", - "100", - "Test", - "TST", - ]) - .assert_success(); + let output = cmd + .args([ + "estimate", + "--rpc-url", + eth_rpc_url.as_str(), + "--create", + "0000", + "ERC20(uint256,string,string)", + "100", + "Test", + "TST", + ]) + .assert_success() + .get_output() + .stdout_lossy(); // ensure we get a positive non-error value for gas estimate - let output: u32 = cmd.stdout_lossy().trim().parse().unwrap(); + let output: u32 = output.trim().parse().unwrap(); assert!(output > 0); }); // tests that the `cast upload-signatures` command works correctly casttest!(upload_signatures, |_prj, cmd| { // test no prefix is accepted as function - cmd.args(["upload-signature", "transfer(address,uint256)"]); - let output = cmd.stdout_lossy(); + let output = cmd + .args(["upload-signature", "transfer(address,uint256)"]) + .assert_success() + .get_output() + .stdout_lossy(); assert!(output.contains("Function transfer(address,uint256): 0xa9059cbb"), "{}", output); // test event prefix cmd.args(["upload-signature", "event Transfer(address,uint256)"]); - let output = cmd.stdout_lossy(); + let output = cmd.assert_success().get_output().stdout_lossy(); assert!(output.contains("Event Transfer(address,uint256): 0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2"), "{}", output); // test error prefix cmd.args(["upload-signature", "error ERC20InsufficientBalance(address,uint256,uint256)"]); - let output = cmd.stdout_lossy(); + let output = cmd.assert_success().get_output().stdout_lossy(); assert!( output.contains("Function ERC20InsufficientBalance(address,uint256,uint256): 0xe450d38c"), "{}", @@ -457,7 +468,7 @@ casttest!(upload_signatures, |_prj, cmd| { "transfer(address,uint256)", "approve(address,uint256)", ]); - let output = cmd.stdout_lossy(); + let output = cmd.assert_success().get_output().stdout_lossy(); assert!(output.contains("Event Transfer(address,uint256): 0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2"), "{}", output); assert!(output.contains("Function transfer(address,uint256): 0xa9059cbb"), "{}", output); assert!(output.contains("Function approve(address,uint256): 0x095ea7b3"), "{}", output); @@ -475,7 +486,7 @@ casttest!(upload_signatures, |_prj, cmd| { .unwrap() .as_str(), ]); - let output = cmd.stdout_lossy(); + let output = cmd.assert_success().get_output().stdout_lossy(); assert!(output.contains("Event Transfer(address,uint256): 0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2"), "{}", output); assert!(output.contains("Function transfer(address,uint256): 0xa9059cbb"), "{}", output); assert!(output.contains("Function approve(address,uint256): 0x095ea7b3"), "{}", output); @@ -626,11 +637,11 @@ casttest!(to_base, |_prj, cmd| { if subcmd == "--to-base" { for base in ["bin", "oct", "dec", "hex"] { cmd.cast_fuse().args([subcmd, value, base]); - assert!(!cmd.stdout_lossy().trim().is_empty()); + assert!(!cmd.assert_success().get_output().stdout_lossy().trim().is_empty()); } } else { cmd.cast_fuse().args([subcmd, value]); - assert!(!cmd.stdout_lossy().trim().is_empty()); + assert!(!cmd.assert_success().get_output().stdout_lossy().trim().is_empty()); } } } @@ -1210,13 +1221,21 @@ unsupported formula ID: unknown casttest!(block_number, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); - let s = cmd.args(["block-number", "--rpc-url", eth_rpc_url.as_str()]).stdout_lossy(); + let s = cmd + .args(["block-number", "--rpc-url", eth_rpc_url.as_str()]) + .assert_success() + .get_output() + .stdout_lossy(); assert!(s.trim().parse::().unwrap() > 0, "{s}") }); casttest!(block_number_latest, |_prj, cmd| { let eth_rpc_url = next_http_rpc_endpoint(); - let s = cmd.args(["block-number", "--rpc-url", eth_rpc_url.as_str(), "latest"]).stdout_lossy(); + let s = cmd + .args(["block-number", "--rpc-url", eth_rpc_url.as_str(), "latest"]) + .assert_success() + .get_output() + .stdout_lossy(); assert!(s.trim().parse::().unwrap() > 0, "{s}") }); @@ -1229,6 +1248,8 @@ casttest!(block_number_hash, |_prj, cmd| { eth_rpc_url.as_str(), "0x88e96d4537bea4d9c05d12549907b32561d3bf31f45aae734cdc119f13406cb6", ]) + .assert_success() + .get_output() .stdout_lossy(); assert_eq!(s.trim().parse::().unwrap(), 1, "{s}") }); diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index ed9cd43521d74..8df9955a71de4 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1612,7 +1612,8 @@ contract ContractThreeTest is DSTest { ..Default::default() }); cmd.forge_fuse(); - let first_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + let first_out = + cmd.arg("test").arg("--gas-report").assert_success().get_output().stdout_lossy(); assert!(!first_out.contains("foo") && first_out.contains("bar") && first_out.contains("baz")); // ignore ContractTwo @@ -1623,7 +1624,8 @@ contract ContractThreeTest is DSTest { ..Default::default() }); cmd.forge_fuse(); - let second_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + let second_out = + cmd.arg("test").arg("--gas-report").assert_success().get_output().stdout_lossy(); assert!( second_out.contains("foo") && !second_out.contains("bar") && second_out.contains("baz") ); @@ -1640,7 +1642,8 @@ contract ContractThreeTest is DSTest { ..Default::default() }); cmd.forge_fuse(); - let third_out = cmd.arg("test").arg("--gas-report").stdout_lossy(); + let third_out = + cmd.arg("test").arg("--gas-report").assert_success().get_output().stdout_lossy(); assert!(third_out.contains("foo") && third_out.contains("bar") && third_out.contains("baz")); }); diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index e238a7ee6d7b2..b2a687ef5e87e 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -361,9 +361,8 @@ contract Greeter {} let config = Config { solc: Some(OTHER_SOLC_VERSION.into()), ..Default::default() }; prj.write_config(config); - cmd.arg("build"); - - assert!(cmd.stdout_lossy().contains("Compiler run successful!")); + let output = cmd.arg("build").assert_success().get_output().stdout_lossy(); + assert!(output.contains("Compiler run successful!")); }); // tests that `--use ` works @@ -377,15 +376,21 @@ contract Foo {} ) .unwrap(); - cmd.args(["build", "--use", OTHER_SOLC_VERSION]); - let stdout = cmd.stdout_lossy(); - assert!(stdout.contains("Compiler run successful")); + let output = cmd + .args(["build", "--use", OTHER_SOLC_VERSION]) + .assert_success() + .get_output() + .stdout_lossy(); + assert!(output.contains("Compiler run successful")); - cmd.forge_fuse() + let output = cmd + .forge_fuse() .args(["build", "--force", "--use", &format!("solc:{OTHER_SOLC_VERSION}")]) - .root_arg(); - let stdout = cmd.stdout_lossy(); - assert!(stdout.contains("Compiler run successful")); + .root_arg() + .assert_success() + .get_output() + .stdout_lossy(); + assert!(output.contains("Compiler run successful")); // fails to use solc that does not exist cmd.forge_fuse().args(["build", "--use", "this/solc/does/not/exist"]); @@ -397,9 +402,15 @@ Error: // `OTHER_SOLC_VERSION` was installed in previous step, so we can use the path to this directly let local_solc = Solc::find_or_install(&OTHER_SOLC_VERSION.parse().unwrap()).unwrap(); - cmd.forge_fuse().args(["build", "--force", "--use"]).arg(local_solc.solc).root_arg(); - let stdout = cmd.stdout_lossy(); - assert!(stdout.contains("Compiler run successful")); + let output = cmd + .forge_fuse() + .args(["build", "--force", "--use"]) + .arg(local_solc.solc) + .root_arg() + .assert_success() + .get_output() + .stdout_lossy(); + assert!(output.contains("Compiler run successful")); }); // test to ensure yul optimizer can be set as intended @@ -722,8 +733,11 @@ forgetest_init!(can_resolve_symlink_fs_permissions, |prj, cmd| { // tests if evm version is normalized for config output forgetest!(normalize_config_evm_version, |_prj, cmd| { - cmd.args(["config", "--use", "0.8.0", "--json"]); - let output = cmd.stdout_lossy(); + let output = cmd + .args(["config", "--use", "0.8.0", "--json"]) + .assert_success() + .get_output() + .stdout_lossy(); let config: Config = serde_json::from_str(&output).unwrap(); assert_eq!(config.evm_version, EvmVersion::Istanbul); }); diff --git a/crates/forge/tests/cli/create.rs b/crates/forge/tests/cli/create.rs index c7071dcf586fa..2a3454f3426b1 100644 --- a/crates/forge/tests/cli/create.rs +++ b/crates/forge/tests/cli/create.rs @@ -10,7 +10,7 @@ use foundry_compilers::artifacts::{remappings::Remapping, BytecodeHash}; use foundry_config::Config; use foundry_test_utils::{ forgetest, forgetest_async, str, - util::{TestCommand, TestProject}, + util::{OutputExt, TestCommand, TestProject}, }; use std::str::FromStr; @@ -104,12 +104,16 @@ where { if let Some(info) = info { let contract_path = f(&prj); - cmd.arg("create"); - cmd.args(info.create_args()).arg(contract_path); - let out = cmd.stdout_lossy(); - let _address = utils::parse_deployed_address(out.as_str()) - .unwrap_or_else(|| panic!("Failed to parse deployer {out}")); + let output = cmd + .arg("create") + .args(info.create_args()) + .arg(contract_path) + .assert_success() + .get_output() + .stdout_lossy(); + let _address = utils::parse_deployed_address(output.as_str()) + .unwrap_or_else(|| panic!("Failed to parse deployer {output}")); } } @@ -323,15 +327,29 @@ contract UniswapV2Swap { ) .unwrap(); - cmd.forge_fuse().args([ - "create", - "./src/UniswapV2Swap.sol:UniswapV2Swap", - "--rpc-url", - rpc.as_str(), - "--private-key", - pk.as_str(), - ]); + cmd.forge_fuse() + .args([ + "create", + "./src/UniswapV2Swap.sol:UniswapV2Swap", + "--rpc-url", + rpc.as_str(), + "--private-key", + pk.as_str(), + ]) + .assert_success() + .stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (2018): Function state mutability can be restricted to pure + [FILE]:6:5: + | +6 | function pairInfo() public view returns (uint reserveA, uint reserveB, uint totalSupply) { + | ^ (Relevant source part starts here and spans across multiple lines). + +Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3 +[TX_HASH] - let (stdout, _) = cmd.output_lossy(); - assert!(stdout.contains("Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3")); +"#]]); }); diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index e44cbe48dcc2b..44b90fc018a62 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -3,7 +3,7 @@ use crate::constants::TEMPLATE_CONTRACT; use alloy_primitives::{hex, Address, Bytes}; use anvil::{spawn, NodeConfig}; -use foundry_test_utils::{rpc, ScriptOutcome, ScriptTester}; +use foundry_test_utils::{rpc, util::OutputExt, ScriptOutcome, ScriptTester}; use regex::Regex; use serde_json::Value; use std::{env, path::PathBuf, str::FromStr}; @@ -184,7 +184,7 @@ contract GasWaster { } } contract DeployScript is Script { - function run() external returns (uint256 result, uint8) { + function run() external { vm.startBroadcast(); GasWaster gasWaster = new GasWaster(); gasWaster.wasteGas{gas: 500000}(200000); @@ -215,11 +215,66 @@ contract DeployScript is Script { "--slow", "--broadcast", "--unlocked", - ]); + ]) + .assert_success() + .stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (2018): Function state mutability can be restricted to view + [FILE]:7:5: + | +7 | function wasteGas(uint256 minGas) public { + | ^ (Relevant source part starts here and spans across multiple lines). + +Traces: + [81040] DeployScript::run() + ├─ [0] VM::startBroadcast() + │ └─ ← [Return] + ├─ [45299] → new GasWaster@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + │ └─ ← [Return] 226 bytes of code + ├─ [226] GasWaster::wasteGas(200000 [2e5]) + │ └─ ← [Stop] + └─ ← [Stop] - let output = cmd.stdout_lossy(); - assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); - assert!(output.contains("Gas limit was set in script to 500000")); + +Script ran successfully. + +## Setting up 1 EVM. +========================== +Simulated On-chain Traces: + +Gas limit was set in script to 500000 + [45299] → new GasWaster@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + └─ ← [Return] 226 bytes of code + + [226] GasWaster::wasteGas(200000 [2e5]) + └─ ← [Stop] + + +========================== + +Chain 1 + +Estimated gas price: [..] + +Estimated total gas used for script: [..] + +Estimated amount required: [..] + +========================== + + +========================== + +ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. + +Transactions saved to: [..] + +Sensitive values saved to: [..] + + +"#]]); }); // Tests that the manually specified gas limit is used. @@ -256,21 +311,26 @@ contract DeployScript is Script { "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string(); cmd.set_current_dir(prj.root()); - cmd.args([ - "script", - &deploy_contract, - "--root", - prj.root().to_str().unwrap(), - "--fork-url", - &handle.http_endpoint(), - "-vvvvv", - "--slow", - "--broadcast", - "--private-key", - &private_key, - ]); + let output = cmd + .args([ + "script", + &deploy_contract, + "--root", + prj.root().to_str().unwrap(), + "--fork-url", + &handle.http_endpoint(), + "-vvvvv", + "--slow", + "--broadcast", + "--private-key", + &private_key, + ]) + .assert_success() + .get_output() + .stdout_lossy(); + + println!("{}", output); - let output = cmd.stdout_lossy(); assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); assert!(output.contains("Gas limit was set in script to 500000")); }); @@ -388,22 +448,24 @@ contract DeployScript is Script { "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string(); cmd.set_current_dir(prj.root()); - cmd.args([ - "script", - &deploy_contract, - "--root", - prj.root().to_str().unwrap(), - "--fork-url", - &handle.http_endpoint(), - "-vvvvv", - "--broadcast", - "--slow", - "--skip-simulation", - "--private-key", - &private_key, - ]); - - let output = cmd.stdout_lossy(); + let output = cmd + .args([ + "script", + &deploy_contract, + "--root", + prj.root().to_str().unwrap(), + "--fork-url", + &handle.http_endpoint(), + "-vvvvv", + "--broadcast", + "--slow", + "--skip-simulation", + "--private-key", + &private_key, + ]) + .assert_success() + .get_output() + .stdout_lossy(); assert!(output.contains("SKIPPING ON CHAIN SIMULATION")); assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); @@ -439,26 +501,28 @@ contract RunScript is Script { let run_script = prj.add_source("RunScript", &run_code).unwrap(); let run_contract = run_script.display().to_string() + ":RunScript"; - cmd.forge_fuse(); - cmd.set_current_dir(prj.root()); - cmd.args([ - "script", - &run_contract, - "--root", - prj.root().to_str().unwrap(), - "--fork-url", - &handle.http_endpoint(), - "-vvvvv", - "--broadcast", - "--slow", - "--skip-simulation", - "--gas-estimate-multiplier", - "200", - "--private-key", - &private_key, - ]); + let output = cmd + .forge_fuse() + .args([ + "script", + &run_contract, + "--root", + prj.root().to_str().unwrap(), + "--fork-url", + &handle.http_endpoint(), + "-vvvvv", + "--broadcast", + "--slow", + "--skip-simulation", + "--gas-estimate-multiplier", + "200", + "--private-key", + &private_key, + ]) + .assert_success() + .get_output() + .stdout_lossy(); - let output = cmd.stdout_lossy(); assert!(output.contains("SKIPPING ON CHAIN SIMULATION")); assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); }); @@ -845,16 +909,21 @@ contract Script0 is Script { ) .unwrap(); - cmd.arg("script").arg(script).args([ - "--tc", - "Script0", - "--sender", - "0x00a329c0648769A73afAc7F9381E08FB43dBEA72", - "--rpc-url", - handle.http_endpoint().as_str(), - ]); - - assert!(cmd.stdout_lossy().contains("SIMULATION COMPLETE")); + let output = cmd + .arg("script") + .arg(script) + .args([ + "--tc", + "Script0", + "--sender", + "0x00a329c0648769A73afAc7F9381E08FB43dBEA72", + "--rpc-url", + handle.http_endpoint().as_str(), + ]) + .assert_success() + .get_output() + .stdout_lossy(); + assert!(output.contains("SIMULATION COMPLETE")); let run_latest = foundry_common::fs::json_files(&prj.root().join("broadcast")) .find(|path| path.ends_with("run-latest.json")) @@ -929,16 +998,21 @@ contract Script0 is Script { ) .unwrap(); - cmd.arg("script").arg(script).args([ - "--tc", - "Script0", - "--sender", - "0x00a329c0648769A73afAc7F9381E08FB43dBEA72", - "--rpc-url", - handle.http_endpoint().as_str(), - ]); - - assert!(cmd.stdout_lossy().contains("SIMULATION COMPLETE")); + let output = cmd + .arg("script") + .arg(script) + .args([ + "--tc", + "Script0", + "--sender", + "0x00a329c0648769A73afAc7F9381E08FB43dBEA72", + "--rpc-url", + handle.http_endpoint().as_str(), + ]) + .assert_success() + .get_output() + .stdout_lossy(); + assert!(output.contains("SIMULATION COMPLETE")); let run_latest = foundry_common::fs::json_files(&prj.root().join("broadcast")) .find(|file| file.ends_with("run-latest.json")) @@ -1070,8 +1144,14 @@ contract ContractC { ) .unwrap(); - cmd.arg("script").arg(script).args(["--tc", "ScriptTxOrigin"]); - assert!(cmd.stdout_lossy().contains("Script ran successfully.")); + let output = cmd + .arg("script") + .arg(script) + .args(["--tc", "ScriptTxOrigin"]) + .assert_success() + .get_output() + .stdout_lossy(); + assert!(output.contains("Script ran successfully.")); }); forgetest_async!(assert_can_create_multiple_contracts_with_correct_nonce, |prj, cmd| { @@ -1116,8 +1196,14 @@ contract NestedCreateFail is Script { ) .unwrap(); - cmd.arg("script").arg(script).args(["--tc", "NestedCreateFail"]); - assert!(cmd.stdout_lossy().contains("Script ran successfully.")); + let output = cmd + .arg("script") + .arg(script) + .args(["--tc", "NestedCreateFail"]) + .assert_success() + .get_output() + .stdout_lossy(); + assert!(output.contains("Script ran successfully.")); }); forgetest_async!(assert_can_detect_target_contract_with_interfaces, |prj, cmd| { @@ -1134,8 +1220,14 @@ interface Interface {} ) .unwrap(); - cmd.arg("script").arg(script); - assert!(cmd.stdout_lossy().contains("Script ran successfully.")); + cmd.arg("script").arg(script).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Script ran successfully. +[GAS] + +"#]]); }); forgetest_async!(assert_can_detect_unlinked_target_with_libraries, |prj, cmd| { @@ -1156,8 +1248,16 @@ contract Script { ) .unwrap(); - cmd.arg("script").arg(script); - assert!(cmd.stdout_lossy().contains("Script ran successfully.")); + cmd.arg("script").arg(script).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Script ran successfully. +[GAS] + +If you wish to simulate on-chain transactions pass a RPC URL. + +"#]]); }); forgetest_async!(assert_can_resume_with_additional_contracts, |prj, cmd| { @@ -1322,37 +1422,42 @@ contract SimpleScript is Script { // Firstly run script with non-zero gas prices to ensure that eth_feeHistory contains non-zero // values. - cmd.args([ - "script", - "SimpleScript", - "--fork-url", - &handle.http_endpoint(), - "--sender", - format!("{dev:?}").as_str(), - "--broadcast", - "--unlocked", - "--with-gas-price", - "2000000", - "--priority-gas-price", - "100000", - ]); - - let output = cmd.stdout_lossy(); + let output = cmd + .args([ + "script", + "SimpleScript", + "--fork-url", + &handle.http_endpoint(), + "--sender", + format!("{dev:?}").as_str(), + "--broadcast", + "--unlocked", + "--with-gas-price", + "2000000", + "--priority-gas-price", + "100000", + ]) + .assert_success() + .get_output() + .stdout_lossy(); assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); // Ensure that we can correctly estimate gas when base fee is zero but priority fee is not. - cmd.forge_fuse().args([ - "script", - "SimpleScript", - "--fork-url", - &handle.http_endpoint(), - "--sender", - format!("{dev:?}").as_str(), - "--broadcast", - "--unlocked", - ]); - - let output = cmd.stdout_lossy(); + let output = cmd + .forge_fuse() + .args([ + "script", + "SimpleScript", + "--fork-url", + &handle.http_endpoint(), + "--sender", + format!("{dev:?}").as_str(), + "--broadcast", + "--unlocked", + ]) + .assert_success() + .get_output() + .stdout_lossy(); assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); }); @@ -1376,16 +1481,18 @@ contract SimpleScript is Script { let (_api, handle) = spawn(NodeConfig::test()).await; - cmd.args([ - "script", - "SimpleScript", - "--fork-url", - &handle.http_endpoint(), - "--broadcast", - "--unlocked", - ]); - - let output = cmd.stdout_lossy(); + let output = cmd + .args([ + "script", + "SimpleScript", + "--fork-url", + &handle.http_endpoint(), + "--broadcast", + "--unlocked", + ]) + .assert_success() + .get_output() + .stdout_lossy(); assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); }); @@ -1463,9 +1570,21 @@ contract SimpleScript is Script { &url, "--sender", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - ]); + ]) + .assert_success() + .stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (2018): Function state mutability can be restricted to view + [FILE]:13:5: + | +13 | function run() external { + | ^ (Relevant source part starts here and spans across multiple lines). + +Script ran successfully. - cmd.stdout_lossy(); +"#]]); }); // Asserts that running the same script twice only deploys library once. diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index ecda1ec3e40a9..e6341c90d76fa 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -4,7 +4,7 @@ use alloy_primitives::U256; use foundry_config::{Config, FuzzConfig}; use foundry_test_utils::{ rpc, str, - util::{OTHER_SOLC_VERSION, SOLC_VERSION}, + util::{OutputExt, OTHER_SOLC_VERSION, SOLC_VERSION}, }; use similar_asserts::assert_eq; use std::{path::PathBuf, str::FromStr}; @@ -1307,29 +1307,37 @@ contract DeterministicRandomnessTest is Test { // Run the test twice with the same seed and verify the outputs are the same. let seed1 = "0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"; - cmd.args(["test", "--fuzz-seed", seed1, "-vv"]).assert_success(); - let out1 = cmd.stdout_lossy(); + let out1 = cmd + .args(["test", "--fuzz-seed", seed1, "-vv"]) + .assert_success() + .get_output() + .stdout_lossy(); let res1 = extract_test_result(&out1); - cmd.forge_fuse(); - cmd.args(["test", "--fuzz-seed", seed1, "-vv"]).assert_success(); - let out2 = cmd.stdout_lossy(); + let out2 = cmd + .forge_fuse() + .args(["test", "--fuzz-seed", seed1, "-vv"]) + .assert_success() + .get_output() + .stdout_lossy(); let res2 = extract_test_result(&out2); assert_eq!(res1, res2); // Run the test with another seed and verify the output differs. let seed2 = "0xb1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"; - cmd.forge_fuse(); - cmd.args(["test", "--fuzz-seed", seed2, "-vv"]).assert_success(); - let out3 = cmd.stdout_lossy(); + let out3 = cmd + .forge_fuse() + .args(["test", "--fuzz-seed", seed2, "-vv"]) + .assert_success() + .get_output() + .stdout_lossy(); let res3 = extract_test_result(&out3); assert_ne!(res3, res1); // Run the test without a seed and verify the outputs differs once again. cmd.forge_fuse(); - cmd.args(["test", "-vv"]).assert_success(); - let out4 = cmd.stdout_lossy(); + let out4 = cmd.args(["test", "-vv"]).assert_success().get_output().stdout_lossy(); let res4 = extract_test_result(&out4); assert_ne!(res4, res1); assert_ne!(res4, res3); diff --git a/crates/forge/tests/cli/verify.rs b/crates/forge/tests/cli/verify.rs index 2f1f1368d1907..a518974c4419d 100644 --- a/crates/forge/tests/cli/verify.rs +++ b/crates/forge/tests/cli/verify.rs @@ -5,7 +5,7 @@ use crate::utils::{self, EnvExternalities}; use foundry_common::retry::Retry; use foundry_test_utils::{ forgetest, - util::{TestCommand, TestProject}, + util::{OutputExt, TestCommand, TestProject}, }; use std::time::Duration; @@ -132,11 +132,15 @@ fn verify_on_chain(info: Option, prj: TestProject, mut cmd: Te add_verify_target(&prj); let contract_path = "src/Verify.sol:Verify"; - cmd.arg("create").args(info.create_args()).arg(contract_path); - - let out = cmd.stdout_lossy(); - let address = utils::parse_deployed_address(out.as_str()) - .unwrap_or_else(|| panic!("Failed to parse deployer {out}")); + let output = cmd + .arg("create") + .args(info.create_args()) + .arg(contract_path) + .assert_success() + .get_output() + .stdout_lossy(); + let address = utils::parse_deployed_address(output.as_str()) + .unwrap_or_else(|| panic!("Failed to parse deployer {output}")); cmd.forge_fuse().arg("verify-contract").root_arg().args([ "--chain-id".to_string(), @@ -161,15 +165,21 @@ fn guess_constructor_args(info: Option, prj: TestProject, mut add_verify_target_with_constructor(&prj); let contract_path = "src/Verify.sol:Verify"; - cmd.arg("create").args(info.create_args()).arg(contract_path).args(vec![ - "--constructor-args", - "(239,SomeString)", - "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", - ]); - - let out = cmd.stdout_lossy(); - let address = utils::parse_deployed_address(out.as_str()) - .unwrap_or_else(|| panic!("Failed to parse deployer {out}")); + let output = cmd + .arg("create") + .args(info.create_args()) + .arg(contract_path) + .args(vec![ + "--constructor-args", + "(239,SomeString)", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + ]) + .assert_success() + .get_output() + .stdout_lossy(); + + let address = utils::parse_deployed_address(output.as_str()) + .unwrap_or_else(|| panic!("Failed to parse deployer {output}")); cmd.forge_fuse().arg("verify-contract").root_arg().args([ "--rpc-url".to_string(), @@ -195,15 +205,15 @@ fn create_verify_on_chain(info: Option, prj: TestProject, mut add_single_verify_target_file(&prj); let contract_path = "src/Verify.sol:Verify"; - cmd.arg("create").args(info.create_args()).args([ - contract_path, - "--etherscan-api-key", - info.etherscan.as_str(), - "--verify", - ]); - - let out = cmd.stdout_lossy(); - assert!(out.contains("Contract successfully verified"), "{}", out); + let output = cmd + .arg("create") + .args(info.create_args()) + .args([contract_path, "--etherscan-api-key", info.etherscan.as_str(), "--verify"]) + .assert_success() + .get_output() + .stdout_lossy(); + + assert!(output.contains("Contract successfully verified"), "{}", output); } } diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index ee67d28a073a7..da1de2b6075c1 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -881,15 +881,6 @@ impl TestCommand { self.ensure_success(&output) } - /// Executes the command and returns the `(stdout, stderr)` of the output as lossy `String`s. - /// - /// Expects the command to be successful. - #[track_caller] - pub fn output_lossy(&mut self) -> (String, String) { - let output = self.output(); - (lossy_string(&output.stdout), lossy_string(&output.stderr)) - } - /// Executes the command and returns the `(stdout, stderr)` of the output as lossy `String`s. /// /// Does not expect the command to be successful. @@ -899,14 +890,6 @@ impl TestCommand { (lossy_string(&output.stdout), lossy_string(&output.stderr)) } - /// Executes the command and returns the stderr as lossy `String`. - /// - /// **Note**: This function checks whether the command was successful. - #[track_caller] - pub fn stdout_lossy(&mut self) -> String { - lossy_string(&self.output().stdout) - } - /// Returns the output but does not expect that the command was successful #[track_caller] pub fn unchecked_output(&mut self) -> Output { From cac4eefc3214513f0131f37e9db1d427aa0f183b Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 10:36:42 +0000 Subject: [PATCH 34/47] replace more lossy stdout tests --- crates/forge/tests/cli/script.rs | 252 ++++++++++++++++++++++++------- 1 file changed, 200 insertions(+), 52 deletions(-) diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 44b90fc018a62..e70bc1ec37b3c 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -292,7 +292,7 @@ contract GasWaster { } } contract DeployScript is Script { - function run() external returns (uint256 result, uint8) { + function run() external { vm.startBroadcast(); GasWaster gasWaster = new GasWaster(); gasWaster.wasteGas{gas: 500000}(200000); @@ -311,28 +311,78 @@ contract DeployScript is Script { "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string(); cmd.set_current_dir(prj.root()); - let output = cmd - .args([ - "script", - &deploy_contract, - "--root", - prj.root().to_str().unwrap(), - "--fork-url", - &handle.http_endpoint(), - "-vvvvv", - "--slow", - "--broadcast", - "--private-key", - &private_key, - ]) - .assert_success() - .get_output() - .stdout_lossy(); + cmd.args([ + "script", + &deploy_contract, + "--root", + prj.root().to_str().unwrap(), + "--fork-url", + &handle.http_endpoint(), + "-vvvvv", + "--slow", + "--broadcast", + "--private-key", + &private_key, + ]) + .assert_success() + .stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful with warnings: +Warning (2018): Function state mutability can be restricted to view + [FILE]:7:5: + | +7 | function wasteGas(uint256 minGas) public { + | ^ (Relevant source part starts here and spans across multiple lines). - println!("{}", output); +Traces: + [81040] DeployScript::run() + ├─ [0] VM::startBroadcast() + │ └─ ← [Return] + ├─ [45299] → new GasWaster@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + │ └─ ← [Return] 226 bytes of code + ├─ [226] GasWaster::wasteGas(200000 [2e5]) + │ └─ ← [Stop] + └─ ← [Stop] - assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); - assert!(output.contains("Gas limit was set in script to 500000")); + +Script ran successfully. + +## Setting up 1 EVM. +========================== +Simulated On-chain Traces: + +Gas limit was set in script to 500000 + [45299] → new GasWaster@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + └─ ← [Return] 226 bytes of code + + [226] GasWaster::wasteGas(200000 [2e5]) + └─ ← [Stop] + + +========================== + +Chain 1 + +Estimated gas price: [..] + +Estimated total gas used for script: [..] + +Estimated amount required: [..] + +========================== + + +========================== + +ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. + +Transactions saved to: [..] + +Sensitive values saved to: [..] + + +"#]]); }); // Tests that the run command can run functions with arguments @@ -420,20 +470,24 @@ import "forge-std/Script.sol"; contract HashChecker { bytes32 public lastHash; + function update() public { bytes32 newHash = blockhash(block.number - 1); require(newHash != lastHash, "Hash didn't change"); lastHash = newHash; } - function checkLastHash() public { + function checkLastHash() public view { require(lastHash != bytes32(0), "Hash shouldn't be zero"); } } + contract DeployScript is Script { - function run() external returns (uint256 result, uint8) { + HashChecker public hashChecker; + + function run() external { vm.startBroadcast(); - HashChecker hashChecker = new HashChecker(); + hashChecker = new HashChecker(); } }"#, ) @@ -448,27 +502,49 @@ contract DeployScript is Script { "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string(); cmd.set_current_dir(prj.root()); - let output = cmd - .args([ - "script", - &deploy_contract, - "--root", - prj.root().to_str().unwrap(), - "--fork-url", - &handle.http_endpoint(), - "-vvvvv", - "--broadcast", - "--slow", - "--skip-simulation", - "--private-key", - &private_key, - ]) - .assert_success() - .get_output() - .stdout_lossy(); + cmd.args([ + "script", + &deploy_contract, + "--root", + prj.root().to_str().unwrap(), + "--fork-url", + &handle.http_endpoint(), + "-vvvvv", + "--broadcast", + "--slow", + "--skip-simulation", + "--private-key", + &private_key, + ]) + .assert_success() + .stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Traces: + [116040] DeployScript::run() + ├─ [0] VM::startBroadcast() + │ └─ ← [Return] + ├─ [75723] → new HashChecker@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + │ └─ ← [Return] 378 bytes of code + └─ ← [Stop] - assert!(output.contains("SKIPPING ON CHAIN SIMULATION")); - assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); + +Script ran successfully. + +SKIPPING ON CHAIN SIMULATION. + + +========================== + +ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. + +Transactions saved to: [..] + +Sensitive values saved to: [..] + + +"#]]); let run_log = std::fs::read_to_string("broadcast/DeployScript.sol/1/run-latest.json").unwrap(); let run_object: Value = serde_json::from_str(&run_log).unwrap(); @@ -484,9 +560,11 @@ import "forge-std/Script.sol"; import { HashChecker } from "./DeployScript.sol"; contract RunScript is Script { - function run() external returns (uint256 result, uint8) { + HashChecker public hashChecker; + + function run() external { vm.startBroadcast(); - HashChecker hashChecker = HashChecker(CONTRACT_ADDRESS); + hashChecker = HashChecker(CONTRACT_ADDRESS); uint numUpdates = 8; vm.roll(block.number - numUpdates); for(uint i = 0; i < numUpdates; i++) { @@ -501,8 +579,7 @@ contract RunScript is Script { let run_script = prj.add_source("RunScript", &run_code).unwrap(); let run_contract = run_script.display().to_string() + ":RunScript"; - let output = cmd - .forge_fuse() + cmd.forge_fuse() .args([ "script", &run_contract, @@ -520,11 +597,82 @@ contract RunScript is Script { &private_key, ]) .assert_success() - .get_output() - .stdout_lossy(); + .stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Traces: + [51327] RunScript::run() + ├─ [0] VM::startBroadcast() + │ └─ ← [Return] + ├─ [0] VM::roll([..]) + │ └─ ← [Return] + ├─ [0] VM::roll([..]) + │ └─ ← [Return] + ├─ [22394] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + │ └─ ← [Stop] + ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + │ └─ ← [Stop] + ├─ [0] VM::roll([..]) + │ └─ ← [Return] + ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + │ └─ ← [Stop] + ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + │ └─ ← [Stop] + ├─ [0] VM::roll([..]) + │ └─ ← [Return] + ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + │ └─ ← [Stop] + ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + │ └─ ← [Stop] + ├─ [0] VM::roll([..]) + │ └─ ← [Return] + ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + │ └─ ← [Stop] + ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + │ └─ ← [Stop] + ├─ [0] VM::roll([..]) + │ └─ ← [Return] + ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + │ └─ ← [Stop] + ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + │ └─ ← [Stop] + ├─ [0] VM::roll([..]) + │ └─ ← [Return] + ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + │ └─ ← [Stop] + ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + │ └─ ← [Stop] + ├─ [0] VM::roll([..]) + │ └─ ← [Return] + ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + │ └─ ← [Stop] + ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + │ └─ ← [Stop] + ├─ [0] VM::roll([..]) + │ └─ ← [Return] + ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + │ └─ ← [Stop] + ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + │ └─ ← [Stop] + └─ ← [Stop] - assert!(output.contains("SKIPPING ON CHAIN SIMULATION")); - assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); + +Script ran successfully. + +SKIPPING ON CHAIN SIMULATION. + + +========================== + +ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. + +Transactions saved to: [..] + +Sensitive values saved to: [..] + + +"#]]); }); forgetest_async!(can_deploy_script_without_lib, |prj, cmd| { From feedee950c3304c9652b6461bb939d21cb43e03a Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 10:56:49 +0000 Subject: [PATCH 35/47] continue porting tests --- crates/forge/tests/cli/build.rs | 2 +- crates/forge/tests/cli/cmd.rs | 2 +- crates/forge/tests/cli/script.rs | 298 ++++++++++++++++++++++------- crates/forge/tests/cli/test_cmd.rs | 14 +- 4 files changed, 240 insertions(+), 76 deletions(-) diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index a5a34446148a9..52b70f71293ec 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -45,7 +45,7 @@ contract Dummy { // tests build output is as expected forgetest_init!(exact_build_output, |prj, cmd| { cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 27 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 8df9955a71de4..039d6d5467a41 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1929,7 +1929,7 @@ forgetest_init!(can_build_sizes_repeatedly, |prj, cmd| { prj.clear_cache(); cmd.args(["build", "--sizes"]).assert_success().stdout_eq(str![[r#" -Compiling 27 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! | Contract | Size (B) | Margin (B) | diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index e70bc1ec37b3c..18b472c9233ff 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -1036,6 +1036,9 @@ contract A { int c; bytes32 d; bool e; + bytes f; + Point g; + string h; constructor(address _a, uint _b, int _c, bytes32 _d, bool _e, bytes memory _f, Point memory _g, string memory _h) { a = _a; @@ -1043,6 +1046,9 @@ contract A { c = _c; d = _d; e = _e; + f = _f; + g = _g; + h = _h; } } @@ -1057,7 +1063,7 @@ contract Script0 is Script { ) .unwrap(); - let output = cmd + cmd .arg("script") .arg(script) .args([ @@ -1069,9 +1075,35 @@ contract Script0 is Script { handle.http_endpoint().as_str(), ]) .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("SIMULATION COMPLETE")); + .stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +... +Script ran successfully. + +## Setting up 1 EVM. + +========================== + +Chain 31337 + +Estimated gas price: [..] + +Estimated total gas used for script: [..] + +Estimated amount required: [..] + +========================== + +SIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more. + +Transactions saved to: [..] + +Sensitive values saved to: [..] + + +"#]]); let run_latest = foundry_common::fs::json_files(&prj.root().join("broadcast")) .find(|path| path.ends_with("run-latest.json")) @@ -1146,7 +1178,7 @@ contract Script0 is Script { ) .unwrap(); - let output = cmd + cmd .arg("script") .arg(script) .args([ @@ -1158,9 +1190,35 @@ contract Script0 is Script { handle.http_endpoint().as_str(), ]) .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("SIMULATION COMPLETE")); + .stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +... +Script ran successfully. + +## Setting up 1 EVM. + +========================== + +Chain 31337 + +Estimated gas price: [..] + +Estimated total gas used for script: [..] + +Estimated amount required: [..] + +========================== + +SIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more. + +Transactions saved to: [..] + +Sensitive values saved to: [..] + + +"#]]); let run_latest = foundry_common::fs::json_files(&prj.root().join("broadcast")) .find(|file| file.ends_with("run-latest.json")) @@ -1292,14 +1350,18 @@ contract ContractC { ) .unwrap(); - let output = cmd - .arg("script") - .arg(script) - .args(["--tc", "ScriptTxOrigin"]) - .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("Script ran successfully.")); + cmd.arg("script").arg(script).args(["--tc", "ScriptTxOrigin"]).assert_success().stdout_eq( + str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Script ran successfully. +[GAS] + +If you wish to simulate on-chain transactions pass a RPC URL. + +"#]], + ); }); forgetest_async!(assert_can_create_multiple_contracts_with_correct_nonce, |prj, cmd| { @@ -1318,18 +1380,20 @@ contract Contract { console.log(tx.origin); } } + contract SubContract { constructor() { console.log(tx.origin); } } + contract BadContract { constructor() { - // new SubContract(); + new SubContract(); console.log(tx.origin); } } -contract NestedCreateFail is Script { +contract NestedCreate is Script { function run() public { address sender = address(uint160(uint(keccak256("woops")))); @@ -1344,14 +1408,23 @@ contract NestedCreateFail is Script { ) .unwrap(); - let output = cmd - .arg("script") - .arg(script) - .args(["--tc", "NestedCreateFail"]) - .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("Script ran successfully.")); + cmd.arg("script").arg(script).args(["--tc", "NestedCreate"]).assert_success().stdout_eq(str![ + [r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Script ran successfully. +[GAS] + +== Logs == + 0x159E2f2F1C094625A2c6c8bF59526d91454c2F3c + 0x159E2f2F1C094625A2c6c8bF59526d91454c2F3c + 0x159E2f2F1C094625A2c6c8bF59526d91454c2F3c + +If you wish to simulate on-chain transactions pass a RPC URL. + +"#] + ]); }); forgetest_async!(assert_can_detect_target_contract_with_interfaces, |prj, cmd| { @@ -1555,9 +1628,9 @@ forgetest_async!(can_run_zero_base_fee, |prj, cmd| { import "forge-std/Script.sol"; contract SimpleScript is Script { - function run() external { + function run() external returns (bool success) { vm.startBroadcast(); - address(0).call(""); + (success, ) = address(0).call(""); } } "#, @@ -1570,29 +1643,59 @@ contract SimpleScript is Script { // Firstly run script with non-zero gas prices to ensure that eth_feeHistory contains non-zero // values. - let output = cmd - .args([ - "script", - "SimpleScript", - "--fork-url", - &handle.http_endpoint(), - "--sender", - format!("{dev:?}").as_str(), - "--broadcast", - "--unlocked", - "--with-gas-price", - "2000000", - "--priority-gas-price", - "100000", - ]) - .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); + cmd.args([ + "script", + "SimpleScript", + "--fork-url", + &handle.http_endpoint(), + "--sender", + format!("{dev:?}").as_str(), + "--broadcast", + "--unlocked", + "--with-gas-price", + "2000000", + "--priority-gas-price", + "100000", + ]) + .assert_success() + .stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +... +Script ran successfully. + +== Return == +success: bool true + +## Setting up 1 EVM. + +========================== + +Chain 31337 + +Estimated gas price: [..] + +Estimated total gas used for script: [..] + +Estimated amount required: [..] + +========================== + + +========================== + +ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. + +Transactions saved to: [..] + +Sensitive values saved to: [..] + + +"#]]); // Ensure that we can correctly estimate gas when base fee is zero but priority fee is not. - let output = cmd - .forge_fuse() + cmd.forge_fuse() .args([ "script", "SimpleScript", @@ -1604,9 +1707,39 @@ contract SimpleScript is Script { "--unlocked", ]) .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); + .stdout_eq(str![[r#" +No files changed, compilation skipped +... +Script ran successfully. + +== Return == +success: bool true + +## Setting up 1 EVM. + +========================== + +Chain 31337 + +Estimated gas price: [..] + +Estimated total gas used for script: [..] + +Estimated amount required: [..] + +========================== + + +========================== + +ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. + +Transactions saved to: [..] + +Sensitive values saved to: [..] + + +"#]]); }); // https://github.com/foundry-rs/foundry/pull/7742 @@ -1618,9 +1751,9 @@ forgetest_async!(unlocked_no_sender, |prj, cmd| { import "forge-std/Script.sol"; contract SimpleScript is Script { - function run() external { + function run() external returns (bool success) { vm.startBroadcast(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); - address(0).call(""); + (success, ) = address(0).call(""); } } "#, @@ -1629,19 +1762,50 @@ contract SimpleScript is Script { let (_api, handle) = spawn(NodeConfig::test()).await; - let output = cmd - .args([ - "script", - "SimpleScript", - "--fork-url", - &handle.http_endpoint(), - "--broadcast", - "--unlocked", - ]) - .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("ONCHAIN EXECUTION COMPLETE & SUCCESSFUL")); + cmd.args([ + "script", + "SimpleScript", + "--fork-url", + &handle.http_endpoint(), + "--broadcast", + "--unlocked", + ]) + .assert_success() + .stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +... +Script ran successfully. + +== Return == +success: bool true + +## Setting up 1 EVM. + +========================== + +Chain 31337 + +Estimated gas price: [..] + +Estimated total gas used for script: [..] + +Estimated amount required: [..] + +========================== + + +========================== + +ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. + +Transactions saved to: [..] + +Sensitive values saved to: [..] + + +"#]]); }); // https://github.com/foundry-rs/foundry/issues/7833 diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index e6341c90d76fa..93daef83e160a 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -758,7 +758,7 @@ contract CounterTest is Test { // make sure there are only 61 runs (with proptest shrinking same test results in 298 runs) cmd.args(["test"]).assert_failure().stdout_eq(str![[r#" -Compiling 23 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -809,7 +809,7 @@ contract CounterTest is Test { // make sure invariant test exit early with 0 runs cmd.args(["test"]).assert_failure().stdout_eq(str![[r#" -Compiling 23 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -988,7 +988,7 @@ forgetest_init!(should_show_logs_when_fuzz_test, |prj, cmd| { ) .unwrap(); cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" -Compiling 23 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1033,7 +1033,7 @@ forgetest_init!(should_show_logs_when_fuzz_test_inline_config, |prj, cmd| { ) .unwrap(); cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" -Compiling 23 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1079,7 +1079,7 @@ forgetest_init!(should_not_show_logs_when_fuzz_test, |prj, cmd| { ) .unwrap(); cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" -Compiling 23 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1119,7 +1119,7 @@ forgetest_init!(should_not_show_logs_when_fuzz_test_inline_config, |prj, cmd| { ) .unwrap(); cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" -Compiling 23 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1180,7 +1180,7 @@ contract SimpleContractTest is Test { ) .unwrap(); cmd.args(["test", "-vvvv", "--decode-internal"]).assert_success().stdout_eq(str![[r#" -Compiling 24 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! From 12cec9fb558a5de8573b595d326a12d576871d71 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 11:02:34 +0000 Subject: [PATCH 36/47] more tests --- crates/forge/tests/cli/config.rs | 44 +++++++++++++++++++------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index b2a687ef5e87e..290ada151e60c 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -361,8 +361,12 @@ contract Greeter {} let config = Config { solc: Some(OTHER_SOLC_VERSION.into()), ..Default::default() }; prj.write_config(config); - let output = cmd.arg("build").assert_success().get_output().stdout_lossy(); - assert!(output.contains("Compiler run successful!")); + cmd.arg("build").assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); }); // tests that `--use ` works @@ -376,21 +380,23 @@ contract Foo {} ) .unwrap(); - let output = cmd - .args(["build", "--use", OTHER_SOLC_VERSION]) - .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("Compiler run successful")); + cmd.args(["build", "--use", OTHER_SOLC_VERSION]).assert_success().stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! - let output = cmd - .forge_fuse() +"#]]); + + cmd.forge_fuse() .args(["build", "--force", "--use", &format!("solc:{OTHER_SOLC_VERSION}")]) .root_arg() .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("Compiler run successful")); + .stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); // fails to use solc that does not exist cmd.forge_fuse().args(["build", "--use", "this/solc/does/not/exist"]); @@ -402,15 +408,17 @@ Error: // `OTHER_SOLC_VERSION` was installed in previous step, so we can use the path to this directly let local_solc = Solc::find_or_install(&OTHER_SOLC_VERSION.parse().unwrap()).unwrap(); - let output = cmd - .forge_fuse() + cmd.forge_fuse() .args(["build", "--force", "--use"]) .arg(local_solc.solc) .root_arg() .assert_success() - .get_output() - .stdout_lossy(); - assert!(output.contains("Compiler run successful")); + .stdout_eq(str![[r#" +Compiling 1 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); }); // test to ensure yul optimizer can be set as intended From ac8390fdc5445812a20a37f85e0d7cd8f9df5497 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 11:05:42 +0000 Subject: [PATCH 37/47] clean up --- crates/forge/tests/cli/script.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 18b472c9233ff..add352935ad25 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -3,7 +3,7 @@ use crate::constants::TEMPLATE_CONTRACT; use alloy_primitives::{hex, Address, Bytes}; use anvil::{spawn, NodeConfig}; -use foundry_test_utils::{rpc, util::OutputExt, ScriptOutcome, ScriptTester}; +use foundry_test_utils::{rpc, ScriptOutcome, ScriptTester}; use regex::Regex; use serde_json::Value; use std::{env, path::PathBuf, str::FromStr}; From e6efa6847d716219810ae6ba546852d74d38b829 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 11:26:54 +0000 Subject: [PATCH 38/47] use redactions for scripts, enforce stricter regex --- crates/forge/tests/cli/script.rs | 78 ++++++++++++++++---------------- crates/test-utils/src/util.rs | 5 ++ 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index add352935ad25..fc0164b905f05 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -256,11 +256,11 @@ Gas limit was set in script to 500000 Chain 1 -Estimated gas price: [..] +[ESTIMATED_GAS_PRICE] -Estimated total gas used for script: [..] +[ESTIMATED_TOTAL_GAS_USED] -Estimated amount required: [..] +[ESTIMATED_AMOUNT_REQUIRED] ========================== @@ -269,9 +269,9 @@ Estimated amount required: [..] ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. -Transactions saved to: [..] +[SAVED_TRANSACTIONS] -Sensitive values saved to: [..] +[SAVED_SENSITIVE_VALUES] "#]]); @@ -364,11 +364,11 @@ Gas limit was set in script to 500000 Chain 1 -Estimated gas price: [..] +[ESTIMATED_GAS_PRICE] -Estimated total gas used for script: [..] +[ESTIMATED_TOTAL_GAS_USED] -Estimated amount required: [..] +[ESTIMATED_AMOUNT_REQUIRED] ========================== @@ -377,9 +377,9 @@ Estimated amount required: [..] ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. -Transactions saved to: [..] +[SAVED_TRANSACTIONS] -Sensitive values saved to: [..] +[SAVED_SENSITIVE_VALUES] "#]]); @@ -539,9 +539,9 @@ SKIPPING ON CHAIN SIMULATION. ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. -Transactions saved to: [..] +[SAVED_TRANSACTIONS] -Sensitive values saved to: [..] +[SAVED_SENSITIVE_VALUES] "#]]); @@ -667,9 +667,9 @@ SKIPPING ON CHAIN SIMULATION. ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. -Transactions saved to: [..] +[SAVED_TRANSACTIONS] -Sensitive values saved to: [..] +[SAVED_SENSITIVE_VALUES] "#]]); @@ -1088,19 +1088,19 @@ Script ran successfully. Chain 31337 -Estimated gas price: [..] +[ESTIMATED_GAS_PRICE] -Estimated total gas used for script: [..] +[ESTIMATED_TOTAL_GAS_USED] -Estimated amount required: [..] +[ESTIMATED_AMOUNT_REQUIRED] ========================== SIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more. -Transactions saved to: [..] +[SAVED_TRANSACTIONS] -Sensitive values saved to: [..] +[SAVED_SENSITIVE_VALUES] "#]]); @@ -1203,19 +1203,19 @@ Script ran successfully. Chain 31337 -Estimated gas price: [..] +[ESTIMATED_GAS_PRICE] -Estimated total gas used for script: [..] +[ESTIMATED_TOTAL_GAS_USED] -Estimated amount required: [..] +[ESTIMATED_AMOUNT_REQUIRED] ========================== SIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more. -Transactions saved to: [..] +[SAVED_TRANSACTIONS] -Sensitive values saved to: [..] +[SAVED_SENSITIVE_VALUES] "#]]); @@ -1674,11 +1674,11 @@ success: bool true Chain 31337 -Estimated gas price: [..] +[ESTIMATED_GAS_PRICE] -Estimated total gas used for script: [..] +[ESTIMATED_TOTAL_GAS_USED] -Estimated amount required: [..] +[ESTIMATED_AMOUNT_REQUIRED] ========================== @@ -1687,9 +1687,9 @@ Estimated amount required: [..] ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. -Transactions saved to: [..] +[SAVED_TRANSACTIONS] -Sensitive values saved to: [..] +[SAVED_SENSITIVE_VALUES] "#]]); @@ -1721,11 +1721,11 @@ success: bool true Chain 31337 -Estimated gas price: [..] +[ESTIMATED_GAS_PRICE] -Estimated total gas used for script: [..] +[ESTIMATED_TOTAL_GAS_USED] -Estimated amount required: [..] +[ESTIMATED_AMOUNT_REQUIRED] ========================== @@ -1734,9 +1734,9 @@ Estimated amount required: [..] ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. -Transactions saved to: [..] +[SAVED_TRANSACTIONS] -Sensitive values saved to: [..] +[SAVED_SENSITIVE_VALUES] "#]]); @@ -1787,11 +1787,11 @@ success: bool true Chain 31337 -Estimated gas price: [..] +[ESTIMATED_GAS_PRICE] -Estimated total gas used for script: [..] +[ESTIMATED_TOTAL_GAS_USED] -Estimated amount required: [..] +[ESTIMATED_AMOUNT_REQUIRED] ========================== @@ -1800,9 +1800,9 @@ Estimated amount required: [..] ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. -Transactions saved to: [..] +[SAVED_TRANSACTIONS] -Sensitive values saved to: [..] +[SAVED_SENSITIVE_VALUES] "#]]); diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index da1de2b6075c1..db03da6f21dce 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -1077,6 +1077,11 @@ fn test_redactions() -> snapbox::Redactions { ("[TX_HASH]", r"Transaction hash: 0x[0-9A-Fa-f]{64}"), ("[ADDRESS]", r"Address: 0x[0-9A-Fa-f]{40}"), ("[UPDATING_DEPENDENCIES]", r"Updating dependencies in .*"), + ("[SAVED_TRANSACTIONS]", r"Transactions saved to: .*\.json"), + ("[SAVED_SENSITIVE_VALUES]", r"Sensitive values saved to: .*\.json"), + ("[ESTIMATED_GAS_PRICE]", r"Estimated gas price:\s*(\d+(\.\d+)?)\s*gwei"), + ("[ESTIMATED_TOTAL_GAS_USED]", r"Estimated total gas used for script: \d+"), + ("[ESTIMATED_AMOUNT_REQUIRED]", r"Estimated amount required:\s*(\d+(\.\d+)?)\s*ETH"), ]; for (placeholder, re) in redactions { r.insert(placeholder, Regex::new(re).expect(re)).expect(re); From 73d8b88adcd33720b01bbdbd9b2f5ecba97428c1 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 12:00:37 +0000 Subject: [PATCH 39/47] start porting more tests using undesired helpers --- crates/cast/tests/cli/main.rs | 45 ++++++++++++++------- crates/forge/tests/cli/cmd.rs | 65 +++++++++++++++++++++--------- crates/forge/tests/cli/test_cmd.rs | 29 +++++++++++-- crates/test-utils/src/util.rs | 34 +++++----------- crates/verify/src/etherscan/mod.rs | 9 ++++- 5 files changed, 118 insertions(+), 64 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 54376394ada7b..a812cacab6d6c 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -13,8 +13,21 @@ use std::{fs, io::Write, path::Path, str::FromStr}; // tests `--help` is printed to std out casttest!(print_help, |_prj, cmd| { - cmd.arg("--help"); - cmd.assert_non_empty_stdout(); + cmd.arg("--help").assert_success().stdout_eq(str![[r#" +Perform Ethereum RPC calls from the comfort of your command line + +Usage: cast + +Commands: +... + +Options: + -h, --help Print help + -V, --version Print version + +Find more information in the book: http://book.getfoundry.sh/reference/cast/cast.html + +"#]]); }); // tests that the `cast block` command works correctly @@ -348,19 +361,23 @@ casttest!(wallet_import_and_decrypt, |prj, cmd| { b256!("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"); // import private key - cmd.cast_fuse().args([ - "wallet", - "import", - account_name, - "--private-key", - &test_private_key.to_string(), - "-k", - "keystore", - "--unsafe-password", - "test", - ]); + cmd.cast_fuse() + .args([ + "wallet", + "import", + account_name, + "--private-key", + &test_private_key.to_string(), + "-k", + "keystore", + "--unsafe-password", + "test", + ]) + .assert_success() + .stdout_eq(str![[r#" +`testAccount` keystore was saved successfully. [ADDRESS] - cmd.assert_non_empty_stdout(); +"#]]); // check that the keystore file was created let keystore_file = keystore_path.join(account_name); diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 039d6d5467a41..a176a5ecae5a9 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -20,8 +20,21 @@ use std::{ // tests `--help` is printed to std out forgetest!(print_help, |_prj, cmd| { - cmd.arg("--help"); - cmd.assert_non_empty_stdout(); + cmd.arg("--help").assert_success().stdout_eq(str![[r#" +Build, test, fuzz, debug and deploy Solidity contracts + +Usage: forge + +Commands: +... + +Options: + -h, --help Print help + -V, --version Print version + +Find more information in the book: http://book.getfoundry.sh/reference/forge/forge.html + +"#]]); }); // checks that `clean` can be invoked even if out and cache don't exist @@ -51,10 +64,9 @@ forgetest!( fs::write(block2_file, "{}").unwrap(); fs::create_dir_all(etherscan_cache_dir).unwrap(); - cmd.args(["cache", "ls"]); - let output_string = String::from_utf8_lossy(&cmd.output().stdout).to_string(); - let output_lines = output_string.split('\n').collect::>(); - println!("{output_string}"); + let output = cmd.args(["cache", "ls"]).assert_success().get_output().stdout_lossy(); + let output_lines = output.split('\n').collect::>(); + println!("{output}"); assert_eq!(output_lines.len(), 6); assert!(output_lines[0].starts_with("-ī¸ mainnet (")); @@ -268,8 +280,7 @@ forgetest!(can_init_no_git, |prj, cmd| { forgetest!(can_init_quiet, |prj, cmd| { prj.wipe(); - cmd.arg("init").arg(prj.root()).arg("-q"); - let _ = cmd.output(); + cmd.arg("init").arg(prj.root()).arg("-q").assert_success().stdout_eq(str![[r#""#]]); }); // `forge init foobar` works with dir argument @@ -320,8 +331,12 @@ forgetest!(can_init_with_dir_and_template_and_branch, |prj, cmd| { // `forge init --force` works on non-empty dirs forgetest!(can_init_non_empty, |prj, cmd| { prj.create_file("README.md", "non-empty dir"); - cmd.arg("init").arg(prj.root()); - cmd.assert_err(); + cmd.arg("init").arg(prj.root()).assert_failure().stderr_eq(str![[r#" +Error: +Cannot run `init` on a non-empty directory. +Run with the `--force` flag to initialize regardless. + +"#]]); cmd.arg("--force"); cmd.assert_non_empty_stdout(); @@ -344,8 +359,12 @@ forgetest!(can_init_in_empty_repo, |prj, cmd| { assert!(status.success()); assert!(root.join(".git").exists()); - cmd.arg("init").arg(root); - cmd.assert_err(); + cmd.arg("init").arg(root).assert_failure().stderr_eq(str![[r#" +Error: +Cannot run `init` on a non-empty directory. +Run with the `--force` flag to initialize regardless. + +"#]]); cmd.arg("--force"); cmd.assert_non_empty_stdout(); @@ -370,8 +389,12 @@ forgetest!(can_init_in_non_empty_repo, |prj, cmd| { prj.create_file("README.md", "non-empty dir"); prj.create_file(".gitignore", "not foundry .gitignore"); - cmd.arg("init").arg(root); - cmd.assert_err(); + cmd.arg("init").arg(root).assert_failure().stderr_eq(str![[r#" +Error: +Cannot run `init` on a non-empty directory. +Run with the `--force` flag to initialize regardless. + +"#]]); cmd.arg("--force"); cmd.assert_non_empty_stdout(); @@ -439,8 +462,13 @@ forgetest!(can_init_template_with_branch, |prj, cmd| { // checks that init fails when the provided template doesn't exist forgetest!(fail_init_nonexistent_template, |prj, cmd| { prj.wipe(); - cmd.args(["init", "--template", "a"]).arg(prj.root()); - cmd.assert_non_empty_stderr(); + cmd.args(["init", "--template", "a"]).arg(prj.root()).assert_failure().stderr_eq(str![[r#" +remote: Not Found +fatal: repository 'https://github.com/a/' not found +Error: +git fetch exited with code 128 + +"#]]); }); // checks that clone works @@ -528,7 +556,7 @@ forgetest!(can_clone_keep_directory_structure, |prj, cmd| { eprintln!("Skipping test due to 502 Bad Gateway: {}", cmd.make_error_message(&out, false)); return } - cmd.ensure_success(&out).unwrap(); + cmd.assert_success(); let s = read_string(&foundry_toml); let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1; @@ -563,8 +591,7 @@ forgetest_init!(can_clean_config, |prj, cmd| { let artifact = prj.root().join(format!("custom-out/{TEMPLATE_TEST_CONTRACT_ARTIFACT_JSON}")); assert!(artifact.exists()); - cmd.forge_fuse().arg("clean"); - cmd.output(); + cmd.forge_fuse().arg("clean").assert_success().stdout_eq(str![[r#""#]]); assert!(!artifact.exists()); }); diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 93daef83e160a..a9f64cc48d48f 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -468,7 +468,7 @@ forgetest_init!(exit_code_error_on_fail_fast, |prj, cmd| { cmd.args(["test", "--fail-fast"]); // run command and assert error exit code - cmd.assert_err(); + cmd.assert_empty_stderr(); }); forgetest_init!(exit_code_error_on_fail_fast_with_json, |prj, cmd| { @@ -479,7 +479,7 @@ forgetest_init!(exit_code_error_on_fail_fast_with_json, |prj, cmd| { cmd.args(["test", "--fail-fast", "--json"]); // run command and assert error exit code - cmd.assert_err(); + cmd.assert_empty_stderr(); }); // @@ -856,8 +856,29 @@ contract ReplayFailuresTest is Test { ) .unwrap(); - cmd.args(["test"]); - cmd.assert_err(); + cmd.args(["test"]).assert_failure().stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 4 tests for test/ReplayFailures.t.sol:ReplayFailuresTest +[PASS] testA() ([GAS]) +[FAIL. Reason: revert: testB failed] testB() ([GAS]) +[PASS] testC() ([GAS]) +[FAIL. Reason: revert: testD failed] testD() ([GAS]) +Suite result: FAILED. 2 passed; 2 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 2 tests passed, 2 failed, 0 skipped (4 total tests) + +Failing tests: +Encountered 2 failing tests in test/ReplayFailures.t.sol:ReplayFailuresTest +[FAIL. Reason: revert: testB failed] testB() ([GAS]) +[FAIL. Reason: revert: testD failed] testD() ([GAS]) + +Encountered a total of 2 failing tests, 2 tests succeeded + +"#]]); + // Test failure filter should be persisted. assert!(prj.root().join("cache/test-failures").exists()); diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index db03da6f21dce..543e5ba4c2b1b 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -11,7 +11,7 @@ use foundry_compilers::{ use foundry_config::Config; use parking_lot::Mutex; use regex::Regex; -use snapbox::cmd::OutputAssert; +use snapbox::{cmd::OutputAssert, str}; use std::{ env, ffi::OsStr, @@ -382,8 +382,7 @@ pub fn try_setup_forge_remote( let prj = TestProject::with_project(tmp); if config.run_build { let mut cmd = prj.forge_command(); - cmd.arg("build"); - cmd.ensure_execute_success().wrap_err("`forge build` unsuccessful")?; + cmd.arg("build").assert_success(); } for addon in config.run_commands { debug_assert!(!addon.is_empty()); @@ -951,24 +950,6 @@ impl TestCommand { fs::write(format!("{}.stderr", name.display()), &output.stderr).unwrap(); } - /// Runs the command and asserts that it **failed** (resulted in an error exit code). - #[track_caller] - pub fn assert_err(&mut self) { - let out = self.execute(); - if out.status.success() { - self.make_panic(&out, true); - } - } - - /// Runs the command and asserts that it **failed** and something was printed to stderr. - #[track_caller] - pub fn assert_non_empty_stderr(&mut self) { - let out = self.execute(); - if out.status.success() || out.stderr.is_empty() { - self.make_panic(&out, true); - } - } - /// Runs the command and asserts that it **succeeded** and something was printed to stdout. #[track_caller] pub fn assert_non_empty_stdout(&mut self) { @@ -981,10 +962,13 @@ impl TestCommand { /// Runs the command and asserts that it **failed** nothing was printed to stdout. #[track_caller] pub fn assert_empty_stdout(&mut self) { - let out = self.execute(); - if !out.status.success() || !out.stderr.is_empty() { - self.make_panic(&out, true); - } + self.assert_success().stdout_eq(str![[r#""#]]); + } + + /// Runs the command and asserts that it **failed** nothing was printed to stderr. + #[track_caller] + pub fn assert_empty_stderr(&mut self) { + self.assert_failure().stderr_eq(str![[r#""#]]); } #[track_caller] diff --git a/crates/verify/src/etherscan/mod.rs b/crates/verify/src/etherscan/mod.rs index 9136c200d7a29..ff437f39c3e77 100644 --- a/crates/verify/src/etherscan/mod.rs +++ b/crates/verify/src/etherscan/mod.rs @@ -455,7 +455,7 @@ mod tests { use super::*; use clap::Parser; use foundry_common::fs; - use foundry_test_utils::forgetest_async; + use foundry_test_utils::{forgetest_async, str}; use tempfile::tempdir; #[test] @@ -566,7 +566,12 @@ mod tests { prj.add_source("Counter1", "contract Counter {}").unwrap(); prj.add_source("Counter2", "contract Counter {}").unwrap(); - cmd.args(["build", "--force"]).ensure_execute_success().unwrap(); + cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" +Compiling 2 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); let args = VerifyArgs::parse_from([ "foundry-cli", From 26f85147ab5f277aac2a8325e9920e9a3a1089a7 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 13:30:23 +0000 Subject: [PATCH 40/47] remove assert_non_empty_stdout helper, enforce stdout layouts --- crates/forge/tests/cli/cmd.rs | 256 ++++++++++++++++++++++------- crates/forge/tests/cli/config.rs | 37 ++++- crates/forge/tests/cli/debug.rs | 13 +- crates/forge/tests/cli/script.rs | 83 +++++++--- crates/forge/tests/cli/test_cmd.rs | 15 +- crates/test-utils/src/macros.rs | 2 +- crates/test-utils/src/util.rs | 16 +- 7 files changed, 309 insertions(+), 113 deletions(-) diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index a176a5ecae5a9..e341d62e94b82 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -224,8 +224,14 @@ forgetest!(can_init_repo_with_config, |prj, cmd| { let foundry_toml = prj.root().join(Config::FILE_NAME); assert!(!foundry_toml.exists()); - cmd.args(["init", "--force"]).arg(prj.root()); - cmd.assert_non_empty_stdout(); + cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); let s = read_string(&foundry_toml); let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1; @@ -267,8 +273,13 @@ https://github.com/foundry-rs/foundry/issues/new/choose forgetest!(can_init_no_git, |prj, cmd| { prj.wipe(); - cmd.arg("init").arg(prj.root()).arg("--no-git"); - cmd.assert_non_empty_stdout(); + cmd.arg("init").arg(prj.root()).arg("--no-git").assert_success().stdout_eq(str![[r#" +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std + Initialized forge project + +"#]]); prj.assert_config_exists(); assert!(!prj.root().join(".git").exists()); @@ -294,10 +305,14 @@ forgetest!(can_init_with_dir, |prj, cmd| { // `forge init foobar --template [template]` works with dir argument forgetest!(can_init_with_dir_and_template, |prj, cmd| { - cmd.args(["init", "foobar", "--template", "foundry-rs/forge-template"]); + cmd.args(["init", "foobar", "--template", "foundry-rs/forge-template"]) + .assert_success() + .stdout_eq(str![[r#" +Initializing [..] from https://github.com/foundry-rs/forge-template... + Initialized forge project + +"#]]); - cmd.assert_success(); - cmd.assert_non_empty_stdout(); assert!(prj.root().join("foobar/.git").exists()); assert!(prj.root().join("foobar/foundry.toml").exists()); assert!(prj.root().join("foobar/lib/forge-std").exists()); @@ -316,10 +331,14 @@ forgetest!(can_init_with_dir_and_template_and_branch, |prj, cmd| { "foundry-rs/forge-template", "--branch", "test/deployments", - ]); + ]) + .assert_success() + .stdout_eq(str![[r#" +Initializing [..] from https://github.com/foundry-rs/forge-template... + Initialized forge project + +"#]]); - cmd.assert_success(); - cmd.assert_non_empty_stdout(); assert!(prj.root().join("foobar/.dapprc").exists()); assert!(prj.root().join("foobar/lib/ds-test").exists()); // assert that gitmodules were correctly initialized @@ -338,8 +357,15 @@ Run with the `--force` flag to initialize regardless. "#]]); - cmd.arg("--force"); - cmd.assert_non_empty_stdout(); + cmd.arg("--force").assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); + assert!(prj.root().join(".git").exists()); assert!(prj.root().join("lib/forge-std").exists()); }); @@ -366,8 +392,14 @@ Run with the `--force` flag to initialize regardless. "#]]); - cmd.arg("--force"); - cmd.assert_non_empty_stdout(); + cmd.arg("--force").assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); assert!(root.join("lib/forge-std").exists()); }); @@ -396,8 +428,14 @@ Run with the `--force` flag to initialize regardless. "#]]); - cmd.arg("--force"); - cmd.assert_non_empty_stdout(); + cmd.arg("--force").assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); assert!(root.join("lib/forge-std").exists()); // not overwritten @@ -410,8 +448,13 @@ Run with the `--force` flag to initialize regardless. forgetest!(can_init_vscode, |prj, cmd| { prj.wipe(); - cmd.arg("init").arg(prj.root()).arg("--vscode"); - cmd.assert_non_empty_stdout(); + cmd.arg("init").arg(prj.root()).arg("--vscode").assert_success().stdout_eq(str![[r#" +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); let settings = prj.root().join(".vscode/settings.json"); assert!(settings.is_file()); @@ -433,8 +476,16 @@ forgetest!(can_init_vscode, |prj, cmd| { // checks that forge can init with template forgetest!(can_init_template, |prj, cmd| { prj.wipe(); - cmd.args(["init", "--template", "foundry-rs/forge-template"]).arg(prj.root()); - cmd.assert_non_empty_stdout(); + + cmd.args(["init", "--template", "foundry-rs/forge-template"]) + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" +Initializing [..] from https://github.com/foundry-rs/forge-template... + Initialized forge project + +"#]]); + assert!(prj.root().join(".git").exists()); assert!(prj.root().join("foundry.toml").exists()); assert!(prj.root().join("lib/forge-std").exists()); @@ -448,8 +499,14 @@ forgetest!(can_init_template, |prj, cmd| { forgetest!(can_init_template_with_branch, |prj, cmd| { prj.wipe(); cmd.args(["init", "--template", "foundry-rs/forge-template", "--branch", "test/deployments"]) - .arg(prj.root()); - cmd.assert_non_empty_stdout(); + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" +Initializing [..] from https://github.com/foundry-rs/forge-template... + Initialized forge project + +"#]]); + assert!(prj.root().join(".git").exists()); assert!(prj.root().join(".dapprc").exists()); assert!(prj.root().join("lib/ds-test").exists()); @@ -484,8 +541,20 @@ forgetest!(can_clone, |prj, cmd| { next_etherscan_api_key().as_str(), "0x044b75f554b886A065b9567891e45c79542d7357", ]) - .arg(prj.root()); - cmd.assert_non_empty_stdout(); + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" +Downloading the source code of 0x044b75f554b886A065b9567891e45c79542d7357 from Etherscan... +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project +Collecting the creation information of 0x044b75f554b886A065b9567891e45c79542d7357 from Etherscan... +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); let s = read_string(&foundry_toml); let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1; @@ -502,8 +571,8 @@ forgetest!(can_clone_quiet, |prj, cmd| { "--quiet", "0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec", ]) - .arg(prj.root()); - cmd.assert_empty_stdout(); + .arg(prj.root()) + .assert_empty_stdout(); }); // checks that clone works with --no-remappings-txt @@ -520,8 +589,20 @@ forgetest!(can_clone_no_remappings_txt, |prj, cmd| { "--no-remappings-txt", "0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf", ]) - .arg(prj.root()); - cmd.assert_non_empty_stdout(); + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" +Downloading the source code of 0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf from Etherscan... +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project +Collecting the creation information of 0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf from Etherscan... +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); let s = read_string(&foundry_toml); let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1; @@ -534,14 +615,15 @@ forgetest!(can_clone_keep_directory_structure, |prj, cmd| { let foundry_toml = prj.root().join(Config::FILE_NAME); assert!(!foundry_toml.exists()); - cmd.args([ - "clone", - "--etherscan-api-key", - next_etherscan_api_key().as_str(), - "--keep-directory-structure", - "0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf", - ]) - .arg(prj.root()); + cmd.forge_fuse() + .args([ + "clone", + "--etherscan-api-key", + next_etherscan_api_key().as_str(), + "--keep-directory-structure", + "0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf", + ]) + .arg(prj.root()); let out = cmd.unchecked_output(); if out.stdout_lossy().contains("502 Bad Gateway") { // etherscan nginx proxy issue, skip this test: @@ -556,7 +638,7 @@ forgetest!(can_clone_keep_directory_structure, |prj, cmd| { eprintln!("Skipping test due to 502 Bad Gateway: {}", cmd.make_error_message(&out, false)); return } - cmd.assert_success(); + cmd.ensure_success(&out).unwrap(); let s = read_string(&foundry_toml); let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1; @@ -584,14 +666,18 @@ forgetest!(can_clean_hardhat, PathStyle::HardHat, |prj, cmd| { forgetest_init!(can_clean_config, |prj, cmd| { let config = Config { out: "custom-out".into(), ..Default::default() }; prj.write_config(config); - cmd.arg("build"); - cmd.assert_non_empty_stdout(); + cmd.arg("build").assert_success().stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); // default test contract is written in custom out directory let artifact = prj.root().join(format!("custom-out/{TEMPLATE_TEST_CONTRACT_ARTIFACT_JSON}")); assert!(artifact.exists()); - cmd.forge_fuse().arg("clean").assert_success().stdout_eq(str![[r#""#]]); + cmd.forge_fuse().arg("clean").assert_empty_stdout(); assert!(!artifact.exists()); }); @@ -620,16 +706,28 @@ forgetest_init!(can_clean_test_cache, |prj, cmd| { // checks that extra output works forgetest_init!(can_emit_extra_output, |prj, cmd| { - cmd.args(["build", "--extra-output", "metadata"]); - cmd.assert_non_empty_stdout(); + cmd.args(["build", "--extra-output", "metadata"]).assert_success().stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); let artifact_path = prj.paths().artifacts.join(TEMPLATE_CONTRACT_ARTIFACT_JSON); let artifact: ConfigurableContractArtifact = foundry_compilers::utils::read_json_file(&artifact_path).unwrap(); assert!(artifact.metadata.is_some()); - cmd.forge_fuse().args(["build", "--extra-output-files", "metadata", "--force"]).root_arg(); - cmd.assert_non_empty_stdout(); + cmd.forge_fuse() + .args(["build", "--extra-output-files", "metadata", "--force"]) + .root_arg() + .assert_success() + .stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); let metadata_path = prj.paths().artifacts.join(format!("{TEMPLATE_CONTRACT_ARTIFACT_BASE}.metadata.json")); @@ -638,8 +736,14 @@ forgetest_init!(can_emit_extra_output, |prj, cmd| { // checks that extra output works forgetest_init!(can_emit_multiple_extra_output, |prj, cmd| { - cmd.args(["build", "--extra-output", "metadata", "ir-optimized", "--extra-output", "ir"]); - cmd.assert_non_empty_stdout(); + cmd.args(["build", "--extra-output", "metadata", "ir-optimized", "--extra-output", "ir"]) + .assert_success() + .stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); let artifact_path = prj.paths().artifacts.join(TEMPLATE_CONTRACT_ARTIFACT_JSON); let artifact: ConfigurableContractArtifact = @@ -657,8 +761,14 @@ forgetest_init!(can_emit_multiple_extra_output, |prj, cmd| { "evm.bytecode.sourceMap", "--force", ]) - .root_arg(); - cmd.assert_non_empty_stdout(); + .root_arg() + .assert_success() + .stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +"#]]); let metadata_path = prj.paths().artifacts.join(format!("{TEMPLATE_CONTRACT_ARTIFACT_BASE}.metadata.json")); @@ -1063,7 +1173,6 @@ Compiler run successful! "#]]); - // cmd.assert_non_empty_stdout(); prj.assert_cache_exists(); prj.assert_artifacts_dir_exists(); @@ -1101,8 +1210,15 @@ forgetest!(can_install_and_remove, |prj, cmd| { let forge_std_mod = git_mod.join("forge-std"); let install = |cmd: &mut TestCommand| { - cmd.forge_fuse().args(["install", "foundry-rs/forge-std", "--no-commit"]); - cmd.assert_non_empty_stdout(); + cmd.forge_fuse() + .args(["install", "foundry-rs/forge-std", "--no-commit"]) + .assert_success() + .stdout_eq(str![[r#" +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + +"#]]); + assert!(forge_std.exists()); assert!(forge_std_mod.exists()); @@ -1111,8 +1227,14 @@ forgetest!(can_install_and_remove, |prj, cmd| { }; let remove = |cmd: &mut TestCommand, target: &str| { - cmd.forge_fuse().args(["remove", "--force", target]); - cmd.assert_non_empty_stdout(); + // TODO: flaky behavior with URL, sometimes it is None, sometimes it is Some("https://github.com/lib/forge-std") + cmd.forge_fuse().args(["remove", "--force", target]).assert_success().stdout_eq(str![[ + r#" +Removing 'forge-std' in [..], (url: [..], tag: None) + +"# + ]]); + assert!(!forge_std.exists()); assert!(!forge_std_mod.exists()); let submods = read_string(&git_mod_file); @@ -1156,8 +1278,15 @@ forgetest!(can_reinstall_after_manual_remove, |prj, cmd| { let forge_std_mod = git_mod.join("forge-std"); let install = |cmd: &mut TestCommand| { - cmd.forge_fuse().args(["install", "foundry-rs/forge-std", "--no-commit"]); - cmd.assert_non_empty_stdout(); + cmd.forge_fuse() + .args(["install", "foundry-rs/forge-std", "--no-commit"]) + .assert_success() + .stdout_eq(str![[r#" +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + +"#]]); + assert!(forge_std.exists()); assert!(forge_std_mod.exists()); @@ -1220,7 +1349,12 @@ forgetest!( // install main dependency cmd.forge_fuse() .args(["install", "evalir/forge-5980-test", "--no-commit"]) - .assert_non_empty_stdout(); + .assert_success() + .stdout_eq(str![[r#" +Installing forge-5980-test in [..] (url: Some("https://github.com/evalir/forge-5980-test"), tag: None) + Installed forge-5980-test + +"#]]); // assert paths exist assert!(package.exists()); @@ -1775,8 +1909,14 @@ forgetest_init!(can_inspect_ir_optimized, |_prj, cmd| { // checks forge bind works correctly on the default project forgetest_init!(can_bind, |_prj, cmd| { - cmd.arg("bind"); - cmd.assert_non_empty_stdout(); + cmd.arg("bind").assert_success().stdout_eq(str![[r#" +Compiling [..] files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Generating bindings for [..] contracts +Bindings have been generated to [..] + +"#]]); }); // checks missing dependencies are auto installed diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 290ada151e60c..7d3c38cba6186 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -266,8 +266,13 @@ forgetest_init!(can_parse_remappings_correctly, |prj, cmd| { assert_eq!(expected, output); let install = |cmd: &mut TestCommand, dep: &str| { - cmd.forge_fuse().args(["install", dep, "--no-commit"]); - cmd.assert_non_empty_stdout(); + cmd.forge_fuse().args(["install", dep, "--no-commit"]).assert_success().stdout_eq(str![[ + r#" +Installing solmate in [..] (url: Some("https://github.com/transmissions11/solmate"), tag: None) + Installed solmate + +"# + ]]); }; install(&mut cmd, "transmissions11/solmate"); @@ -607,8 +612,13 @@ forgetest!(can_update_libs_section, |prj, cmd| { let init = Config { libs: vec!["node_modules".into()], ..Default::default() }; prj.write_config(init); - cmd.args(["install", "foundry-rs/forge-std", "--no-commit"]); - cmd.assert_non_empty_stdout(); + cmd.args(["install", "foundry-rs/forge-std", "--no-commit"]).assert_success().stdout_eq(str![ + [r#" +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + +"#] + ]); let config = cmd.forge_fuse().config(); // `lib` was added automatically @@ -616,8 +626,14 @@ forgetest!(can_update_libs_section, |prj, cmd| { assert_eq!(config.libs, expected); // additional install don't edit `libs` - cmd.forge_fuse().args(["install", "dapphub/ds-test", "--no-commit"]); - cmd.assert_non_empty_stdout(); + cmd.forge_fuse() + .args(["install", "dapphub/ds-test", "--no-commit"]) + .assert_success() + .stdout_eq(str![[r#" +Installing ds-test in [..] (url: Some("https://github.com/dapphub/ds-test"), tag: None) + Installed ds-test + +"#]]); let config = cmd.forge_fuse().config(); assert_eq!(config.libs, expected); @@ -628,8 +644,13 @@ forgetest!(can_update_libs_section, |prj, cmd| { forgetest!(config_emit_warnings, |prj, cmd| { cmd.git_init(); - cmd.args(["install", "foundry-rs/forge-std", "--no-commit"]); - cmd.assert_non_empty_stdout(); + cmd.args(["install", "foundry-rs/forge-std", "--no-commit"]).assert_success().stdout_eq(str![ + [r#" +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + +"#] + ]); let faulty_toml = r"[default] src = 'src' diff --git a/crates/forge/tests/cli/debug.rs b/crates/forge/tests/cli/debug.rs index 3e3d08c7e2ad7..8ee1eb3f27753 100644 --- a/crates/forge/tests/cli/debug.rs +++ b/crates/forge/tests/cli/debug.rs @@ -7,8 +7,14 @@ forgetest_async!( #[ignore = "ran manually"] manual_debug_setup, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()).assert_non_empty_stdout(); - cmd.forge_fuse(); + cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); prj.add_source("Counter2.sol", r#" contract A { @@ -74,8 +80,7 @@ contract Script0 is Script, Test { ) .unwrap(); - cmd.args(["build"]).assert_success(); - cmd.forge_fuse(); + cmd.forge_fuse().args(["build"]).assert_success(); cmd.args([ "script", diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index fc0164b905f05..734c32a368701 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -1015,12 +1015,17 @@ struct Transaction { // test we output arguments forgetest_async!(can_execute_script_with_arguments, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()); - cmd.assert_non_empty_stdout(); - cmd.forge_fuse(); + cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); let (_api, handle) = spawn(NodeConfig::test()).await; - let script = prj .add_script( + let script = prj.add_script( "Counter.s.sol", r#" import "forge-std/Script.sol"; @@ -1064,6 +1069,7 @@ contract Script0 is Script { .unwrap(); cmd + .forge_fuse() .arg("script") .arg(script) .args([ @@ -1131,9 +1137,14 @@ SIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet // test we output arguments forgetest_async!(can_execute_script_with_arguments_nested_deploy, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()); - cmd.assert_non_empty_stdout(); - cmd.forge_fuse(); + cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); let (_api, handle) = spawn(NodeConfig::test()).await; let script = prj @@ -1179,6 +1190,7 @@ contract Script0 is Script { .unwrap(); cmd + .forge_fuse() .arg("script") .arg(script) .args([ @@ -1292,9 +1304,14 @@ forgetest_async!(does_script_override_correctly, |prj, cmd| { }); forgetest_async!(assert_tx_origin_is_not_overritten, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()); - cmd.assert_non_empty_stdout(); - cmd.forge_fuse(); + cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); let script = prj .add_script( @@ -1350,8 +1367,12 @@ contract ContractC { ) .unwrap(); - cmd.arg("script").arg(script).args(["--tc", "ScriptTxOrigin"]).assert_success().stdout_eq( - str![[r#" + cmd.forge_fuse() + .arg("script") + .arg(script) + .args(["--tc", "ScriptTxOrigin"]) + .assert_success() + .stdout_eq(str![[r#" Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1360,14 +1381,18 @@ Script ran successfully. If you wish to simulate on-chain transactions pass a RPC URL. -"#]], - ); +"#]]); }); forgetest_async!(assert_can_create_multiple_contracts_with_correct_nonce, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()); - cmd.assert_non_empty_stdout(); - cmd.forge_fuse(); + cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); let script = prj .add_script( @@ -1408,8 +1433,12 @@ contract NestedCreate is Script { ) .unwrap(); - cmd.arg("script").arg(script).args(["--tc", "NestedCreate"]).assert_success().stdout_eq(str![ - [r#" + cmd.forge_fuse() + .arg("script") + .arg(script) + .args(["--tc", "NestedCreate"]) + .assert_success() + .stdout_eq(str![[r#" Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1423,8 +1452,7 @@ Script ran successfully. If you wish to simulate on-chain transactions pass a RPC URL. -"#] - ]); +"#]]); }); forgetest_async!(assert_can_detect_target_contract_with_interfaces, |prj, cmd| { @@ -1582,9 +1610,14 @@ Multiple functions with the same name `run` found in the ABI }); forgetest_async!(can_decode_custom_errors, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()); - cmd.assert_non_empty_stdout(); - cmd.forge_fuse(); + cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" +Target directory is not empty, but `--force` was specified +Initializing [..]... +Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) + Installed forge-std [..] + Initialized forge project + +"#]]); let script = prj .add_script( @@ -1611,7 +1644,7 @@ contract CustomErrorScript is Script { ) .unwrap(); - cmd.arg("script").arg(script).args(["--tc", "CustomErrorScript"]); + cmd.forge_fuse().arg("script").arg(script).args(["--tc", "CustomErrorScript"]); cmd.assert_failure().stderr_eq(str![[r#" Error: script failed: CustomError() diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index a9f64cc48d48f..72225ad65f176 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -314,8 +314,19 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) // checks that forge test repeatedly produces the same output #[cfg(not(feature = "isolate-by-default"))] forgetest_init!(can_test_repeatedly, |_prj, cmd| { - cmd.arg("test"); - cmd.assert_non_empty_stdout(); + cmd.arg("test").assert_success().stdout_eq(str![[r#" +Compiling 24 files with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + +Ran 2 tests for test/Counter.t.sol:CounterTest +[PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS]) +[PASS] test_Increment() ([GAS]) +Suite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests) + +"#]]); for _ in 0..5 { cmd.assert_success().stdout_eq(str![[r#" diff --git a/crates/test-utils/src/macros.rs b/crates/test-utils/src/macros.rs index 064a94ef2d6d0..cc92bb040607d 100644 --- a/crates/test-utils/src/macros.rs +++ b/crates/test-utils/src/macros.rs @@ -15,7 +15,7 @@ /// // adds `init` to forge's command arguments /// cmd.arg("init"); /// // executes forge and panics if the command failed or output is empty -/// cmd.assert_non_empty_stdout(); +/// cmd.assert_success().stdout_eq(str![[r#""#]]); /// }); /// ``` /// diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 543e5ba4c2b1b..71b44ae7cae10 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -204,7 +204,7 @@ impl ExtTester { } test_cmd.env("FOUNDRY_INVARIANT_DEPTH", "15"); - test_cmd.assert_non_empty_stdout(); + test_cmd.assert_success(); } } @@ -950,15 +950,6 @@ impl TestCommand { fs::write(format!("{}.stderr", name.display()), &output.stderr).unwrap(); } - /// Runs the command and asserts that it **succeeded** and something was printed to stdout. - #[track_caller] - pub fn assert_non_empty_stdout(&mut self) { - let out = self.execute(); - if !out.status.success() || out.stdout.is_empty() { - self.make_panic(&out, false); - } - } - /// Runs the command and asserts that it **failed** nothing was printed to stdout. #[track_caller] pub fn assert_empty_stdout(&mut self) { @@ -980,11 +971,6 @@ impl TestCommand { } } - #[track_caller] - fn make_panic(&self, out: &Output, expected_fail: bool) -> ! { - panic!("{}", self.make_error_message(out, expected_fail)) - } - #[track_caller] fn make_error(&self, out: &Output, expected_fail: bool) -> eyre::Report { eyre::eyre!("{}", self.make_error_message(out, expected_fail)) From 3671909472075f9c1b7c97efca818ad1a0929714 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 14:22:51 +0000 Subject: [PATCH 41/47] use snapbox inside of helpers --- crates/forge/benches/test.rs | 9 +- crates/forge/tests/cli/cmd.rs | 38 +++--- crates/forge/tests/cli/config.rs | 16 +-- crates/forge/tests/cli/soldeer.rs | 2 +- crates/forge/tests/cli/verify.rs | 4 +- crates/test-utils/src/script.rs | 6 +- crates/test-utils/src/util.rs | 197 +++++++----------------------- 7 files changed, 91 insertions(+), 181 deletions(-) diff --git a/crates/forge/benches/test.rs b/crates/forge/benches/test.rs index 7646a3c214a33..593bce3d320d5 100644 --- a/crates/forge/benches/test.rs +++ b/crates/forge/benches/test.rs @@ -1,5 +1,8 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use foundry_test_utils::{util::setup_forge_remote, TestCommand, TestProject}; +use foundry_test_utils::{ + util::{lossy_string, setup_forge_remote}, + TestCommand, TestProject, +}; /// Returns a cloned and `forge built` `solmate` project fn built_solmate() -> (TestProject, TestCommand) { @@ -15,7 +18,9 @@ fn forge_test_benchmark(c: &mut Criterion) { let mut cmd = prj.forge_command(); cmd.arg("test"); b.iter(|| { - cmd.print_output(); + let output = cmd.execute(); + println!("stdout:\n{}", lossy_string(&output.stdout)); + println!("\nstderr:\n{}", lossy_string(&output.stderr)); }); }); } diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index e341d62e94b82..89de746fc2fcd 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -291,7 +291,7 @@ Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std forgetest!(can_init_quiet, |prj, cmd| { prj.wipe(); - cmd.arg("init").arg(prj.root()).arg("-q").assert_success().stdout_eq(str![[r#""#]]); + cmd.arg("init").arg(prj.root()).arg("-q").assert_empty_stdout(); }); // `forge init foobar` works with dir argument @@ -615,7 +615,8 @@ forgetest!(can_clone_keep_directory_structure, |prj, cmd| { let foundry_toml = prj.root().join(Config::FILE_NAME); assert!(!foundry_toml.exists()); - cmd.forge_fuse() + let output = cmd + .forge_fuse() .args([ "clone", "--etherscan-api-key", @@ -623,9 +624,12 @@ forgetest!(can_clone_keep_directory_structure, |prj, cmd| { "--keep-directory-structure", "0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf", ]) - .arg(prj.root()); - let out = cmd.unchecked_output(); - if out.stdout_lossy().contains("502 Bad Gateway") { + .arg(prj.root()) + .assert_success() + .get_output() + .stdout_lossy(); + + if output.contains("502 Bad Gateway") { // etherscan nginx proxy issue, skip this test: // // stdout: @@ -635,10 +639,9 @@ forgetest!(can_clone_keep_directory_structure, |prj, cmd| { // Gateway\r\n\r\n

502 Bad // Gateway

\r\n
nginx
\r\n\r\n\r\n" - eprintln!("Skipping test due to 502 Bad Gateway: {}", cmd.make_error_message(&out, false)); - return + eprintln!("Skipping test due to 502 Bad Gateway"); + return; } - cmd.ensure_success(&out).unwrap(); let s = read_string(&foundry_toml); let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1; @@ -698,8 +701,7 @@ forgetest_init!(can_clean_test_cache, |prj, cmd| { assert!(fuzz_cache_dir.exists()); assert!(invariant_cache_dir.exists()); - cmd.forge_fuse().arg("clean"); - cmd.output(); + cmd.forge_fuse().arg("clean").assert_empty_stdout(); assert!(!fuzz_cache_dir.exists()); assert!(!invariant_cache_dir.exists()); }); @@ -925,8 +927,16 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) "#]]); - cmd.arg("--check"); - let _ = cmd.output(); + cmd.arg("--check").assert_success().stdout_eq(str![[r#" +No files changed, compilation skipped + +Ran 1 test for src/ATest.t.sol:ATest +[PASS] testExample() ([GAS]) +Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED] + +Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) + +"#]]); }); // test that `forge build` does not print `(with warnings)` if file path is ignored @@ -1259,8 +1269,8 @@ forgetest!(can_install_empty, |prj, cmd| { // create initial commit fs::write(prj.root().join("README.md"), "Initial commit").unwrap(); - cmd.git_add().unwrap(); - cmd.git_commit("Initial commit").unwrap(); + cmd.git_add(); + cmd.git_commit("Initial commit"); cmd.forge_fuse().args(["install"]); cmd.assert_empty_stdout(); diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 7d3c38cba6186..efe5608de0b41 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -660,16 +660,12 @@ Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std fs::write(prj.root().join("foundry.toml"), faulty_toml).unwrap(); fs::write(prj.root().join("lib").join("forge-std").join("foundry.toml"), faulty_toml).unwrap(); - cmd.forge_fuse().args(["config"]); - let output = cmd.execute(); - assert!(output.status.success()); - assert_eq!( - String::from_utf8_lossy(&output.stderr) - .lines() - .filter(|line| line.contains("unknown config section") && line.contains("[default]")) - .count(), - 1, - ); + cmd.forge_fuse().args(["config"]).assert_success().stderr_eq(str![[r#" +warning: Found unknown config section in foundry.toml: [default] +This notation for profiles has been deprecated and may result in the profile not being registered in future versions. +Please use [profile.default] instead or run `forge config --fix`. + +"#]]); }); forgetest_init!(can_skip_remappings_auto_detection, |prj, cmd| { diff --git a/crates/forge/tests/cli/soldeer.rs b/crates/forge/tests/cli/soldeer.rs index 1a62578d1b67a..99c6219fcead2 100644 --- a/crates/forge/tests/cli/soldeer.rs +++ b/crates/forge/tests/cli/soldeer.rs @@ -250,7 +250,7 @@ forgesoldeer!(login, |prj, cmd| { let command = "login"; cmd.arg("soldeer").arg(command); - let output = cmd.unchecked_output(); + let output = cmd.execute(); // On login, we can only check if the prompt is displayed in the stdout let stdout = String::from_utf8(output.stdout).expect("Could not parse the output"); diff --git a/crates/forge/tests/cli/verify.rs b/crates/forge/tests/cli/verify.rs index a518974c4419d..c8ce2c25f1bfc 100644 --- a/crates/forge/tests/cli/verify.rs +++ b/crates/forge/tests/cli/verify.rs @@ -77,7 +77,7 @@ fn parse_verification_result(cmd: &mut TestCommand, retries: u32) -> eyre::Resul // give etherscan some time to verify the contract let retry = Retry::new(retries, Some(Duration::from_secs(30))); retry.run(|| -> eyre::Result<()> { - let output = cmd.unchecked_output(); + let output = cmd.execute(); let out = String::from_utf8_lossy(&output.stdout); println!("{out}"); if out.contains("Contract successfully verified") { @@ -97,7 +97,7 @@ fn await_verification_response(info: EnvExternalities, mut cmd: TestCommand) { let retry = Retry::new(5, Some(Duration::from_secs(60))); retry .run(|| -> eyre::Result { - let output = cmd.unchecked_output(); + let output = cmd.execute(); let out = String::from_utf8_lossy(&output.stdout); utils::parse_verification_guid(&out).ok_or_else(|| { eyre::eyre!( diff --git a/crates/test-utils/src/script.rs b/crates/test-utils/src/script.rs index 0bc4d399db527..9b018573261f0 100644 --- a/crates/test-utils/src/script.rs +++ b/crates/test-utils/src/script.rs @@ -1,4 +1,4 @@ -use crate::{init_tracing, TestCommand}; +use crate::{init_tracing, util::lossy_string, TestCommand}; use alloy_primitives::Address; use alloy_provider::Provider; use eyre::Result; @@ -221,7 +221,9 @@ impl ScriptTester { } pub fn run(&mut self, expected: ScriptOutcome) -> &mut Self { - let (stdout, stderr) = self.cmd.unchecked_output_lossy(); + let out = self.cmd.execute(); + let (stdout, stderr) = (lossy_string(&out.stdout), lossy_string(&out.stderr)); + trace!(target: "tests", "STDOUT\n{stdout}\n\nSTDERR\n{stderr}"); let output = if expected.is_err() { &stderr } else { &stdout }; diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 71b44ae7cae10..037ad67a4b554 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -828,126 +828,59 @@ impl TestCommand { self } - /// Does not apply [`snapbox`] redactions to the command output. - pub fn with_no_redact(&mut self) -> &mut Self { - self.redact_output = false; - self - } - /// Returns the `Config` as spit out by `forge config` #[track_caller] pub fn config(&mut self) -> Config { self.cmd.args(["config", "--json"]); - let output = self.output(); - let c = lossy_string(&output.stdout); - let config = serde_json::from_str(c.as_ref()).unwrap(); + let output = self.assert().success().get_output().stdout_lossy(); + let config = serde_json::from_str(output.as_ref()).unwrap(); self.forge_fuse(); config } /// Runs `git init` inside the project's dir #[track_caller] - pub fn git_init(&self) -> Output { + pub fn git_init(&self) { let mut cmd = Command::new("git"); cmd.arg("init").current_dir(self.project.root()); - let output = cmd.output().unwrap(); - self.ensure_success(&output).unwrap(); - output - } - - /// Returns a new [Command] that is inside the current project dir - pub fn cmd_in_current_dir(&self, program: &str) -> Command { - let mut cmd = Command::new(program); - cmd.current_dir(self.project.root()); - cmd + let output = OutputAssert::new(cmd.output().unwrap()); + output.success(); } /// Runs `git add .` inside the project's dir #[track_caller] - pub fn git_add(&self) -> Result<()> { - let mut cmd = self.cmd_in_current_dir("git"); + pub fn git_add(&self) { + let mut cmd = Command::new("git"); + cmd.current_dir(self.project.root()); cmd.arg("add").arg("."); - let output = cmd.output()?; - self.ensure_success(&output) + let output = OutputAssert::new(cmd.output().unwrap()); + output.success(); } /// Runs `git commit .` inside the project's dir #[track_caller] - pub fn git_commit(&self, msg: &str) -> Result<()> { - let mut cmd = self.cmd_in_current_dir("git"); + pub fn git_commit(&self, msg: &str) { + let mut cmd = Command::new("git"); + cmd.current_dir(self.project.root()); cmd.arg("commit").arg("-m").arg(msg); - let output = cmd.output()?; - self.ensure_success(&output) - } - - /// Executes the command and returns the `(stdout, stderr)` of the output as lossy `String`s. - /// - /// Does not expect the command to be successful. - #[track_caller] - pub fn unchecked_output_lossy(&mut self) -> (String, String) { - let output = self.unchecked_output(); - (lossy_string(&output.stdout), lossy_string(&output.stderr)) - } - - /// Returns the output but does not expect that the command was successful - #[track_caller] - pub fn unchecked_output(&mut self) -> Output { - self.execute() - } - - /// Gets the output of a command. If the command failed, then this panics. - #[track_caller] - pub fn output(&mut self) -> Output { - let output = self.execute(); - self.ensure_success(&output).unwrap(); - output - } - - /// Executes command, applies stdin function and returns output - #[track_caller] - pub fn execute(&mut self) -> Output { - self.try_execute().unwrap() + let output = OutputAssert::new(cmd.output().unwrap()); + output.success(); } + /// Runs the command, returning a [`snapbox`] object to assert the command output. #[track_caller] - pub fn try_execute(&mut self) -> std::io::Result { - eprintln!("executing {:?}", self.cmd); - let mut child = - self.cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::piped()).spawn()?; - if let Some(fun) = self.stdin_fun.take() { - fun(child.stdin.take().unwrap()); - } - child.wait_with_output() - } - - /// Executes command and expects an successful result - #[track_caller] - pub fn ensure_execute_success(&mut self) -> Result { - let out = self.try_execute()?; - self.ensure_success(&out)?; - Ok(out) - } - - /// Runs the command and prints its output - /// You have to pass --nocapture to cargo test or the print won't be displayed. - /// The full command would be: cargo test -- --nocapture - #[track_caller] - pub fn print_output(&mut self) { - let output = self.execute(); - println!("stdout:\n{}", lossy_string(&output.stdout)); - println!("\nstderr:\n{}", lossy_string(&output.stderr)); + pub fn assert(&mut self) -> OutputAssert { + let assert = OutputAssert::new(self.execute()); + if self.redact_output { + return assert.with_assert(test_assert()); + }; + assert } - /// Writes the content of the output to new fixture files + /// Runs the command and asserts that it resulted in success. #[track_caller] - pub fn write_fixtures(&mut self, name: impl AsRef) { - let name = name.as_ref(); - if let Some(parent) = name.parent() { - fs::create_dir_all(parent).unwrap(); - } - let output = self.execute(); - fs::write(format!("{}.stdout", name.display()), &output.stdout).unwrap(); - fs::write(format!("{}.stderr", name.display()), &output.stderr).unwrap(); + pub fn assert_success(&mut self) -> OutputAssert { + self.assert().success() } /// Runs the command and asserts that it **failed** nothing was printed to stdout. @@ -956,75 +889,39 @@ impl TestCommand { self.assert_success().stdout_eq(str![[r#""#]]); } - /// Runs the command and asserts that it **failed** nothing was printed to stderr. - #[track_caller] - pub fn assert_empty_stderr(&mut self) { - self.assert_failure().stderr_eq(str![[r#""#]]); - } - + /// Runs the command and asserts that it failed. #[track_caller] - pub fn ensure_success(&self, out: &Output) -> Result<()> { - if out.status.success() { - Ok(()) - } else { - Err(self.make_error(out, false)) - } + pub fn assert_failure(&mut self) -> OutputAssert { + self.assert().failure() } + /// Runs the command and asserts that it **failed** nothing was printed to stderr. #[track_caller] - fn make_error(&self, out: &Output, expected_fail: bool) -> eyre::Report { - eyre::eyre!("{}", self.make_error_message(out, expected_fail)) - } - - pub fn make_error_message(&self, out: &Output, expected_fail: bool) -> String { - let msg = if expected_fail { - "expected failure but command succeeded!" - } else { - "command failed but expected success!" - }; - format!( - "\ ---- {:?} --- -{msg} - -status: {} - -paths: -{} - -stdout: -{} - -stderr: -{}", - self.cmd, - out.status, - self.project.inner.paths(), - lossy_string(&out.stdout), - lossy_string(&out.stderr), - ) + pub fn assert_empty_stderr(&mut self) { + self.assert_failure().stderr_eq(str![[r#""#]]); } - /// Runs the command, returning a [`snapbox`] object to assert the command output. - #[track_caller] - pub fn assert(&mut self) -> OutputAssert { - let assert = OutputAssert::new(self.execute()); - if self.redact_output { - return assert.with_assert(test_assert()); - }; - assert + /// Does not apply [`snapbox`] redactions to the command output. + pub fn with_no_redact(&mut self) -> &mut Self { + self.redact_output = false; + self } - /// Runs the command and asserts that it resulted in success. + /// Executes command, applies stdin function and returns output #[track_caller] - pub fn assert_success(&mut self) -> OutputAssert { - self.assert().success() + pub fn execute(&mut self) -> Output { + self.try_execute().unwrap() } - /// Runs the command and asserts that it failed. #[track_caller] - pub fn assert_failure(&mut self) -> OutputAssert { - self.assert().failure() + pub fn try_execute(&mut self) -> std::io::Result { + eprintln!("executing {:?}", self.cmd); + let mut child = + self.cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::piped()).spawn()?; + if let Some(fun) = self.stdin_fun.take() { + fun(child.stdin.take().unwrap()); + } + child.wait_with_output() } } @@ -1073,6 +970,6 @@ impl OutputExt for Output { } } -fn lossy_string(bytes: &[u8]) -> String { +pub fn lossy_string(bytes: &[u8]) -> String { String::from_utf8_lossy(bytes).replace("\r\n", "\n") } From 360646fcd175eff2d414cff31d0a148c56e4fc62 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 14:35:49 +0000 Subject: [PATCH 42/47] replace cmd.execute --- crates/forge/tests/cli/soldeer.rs | 78 +++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/crates/forge/tests/cli/soldeer.rs b/crates/forge/tests/cli/soldeer.rs index 99c6219fcead2..b65b8b676d154 100644 --- a/crates/forge/tests/cli/soldeer.rs +++ b/crates/forge/tests/cli/soldeer.rs @@ -7,14 +7,22 @@ use std::{ use foundry_test_utils::forgesoldeer; use std::io::Write; + forgesoldeer!(install_dependency, |prj, cmd| { let command = "install"; let dependency = "forge-std~1.8.1"; let foundry_file = prj.root().join("foundry.toml"); - cmd.arg("soldeer").args([command, dependency]); - cmd.execute(); + cmd.arg("soldeer").args([command, dependency]).assert_success().stdout_eq(str![[r#" +đŸĻŒ Running soldeer install đŸĻŒ + +Dependency forge-std-[..] downloaded! +Writing forge-std~[..] to the lock file. +The dependency forge-std-[..] was unzipped! +Adding dependency forge-std-[..] to the config file +Added a new dependency to remappings @forge-std-[..] +"#]]); // Making sure the path was created to the dependency and that foundry.toml exists // meaning that the dependencies were installed correctly @@ -57,8 +65,15 @@ forgesoldeer!(install_dependency_git, |prj, cmd| { let foundry_file = prj.root().join("foundry.toml"); - cmd.arg("soldeer").args([command, dependency, git]); - cmd.execute(); + cmd.arg("soldeer").args([command, dependency, git]).assert_success().stdout_eq(str![[r#" +đŸĻŒ Running soldeer install đŸĻŒ + +Successfully downloaded forge-std~1.8.1 the dependency via git +Dependency forge-std-1.8.1 downloaded! +Writing forge-std~1.8.1 to the lock file. +Adding dependency forge-std-1.8.1 to the config file +Added a new dependency to remappings @forge-std-1.8.1 +"#]]); // Making sure the path was created to the dependency and that README.md exists // meaning that the dependencies were installed correctly @@ -102,8 +117,19 @@ forgesoldeer!(install_dependency_git_commit, |prj, cmd| { let foundry_file = prj.root().join("foundry.toml"); - cmd.arg("soldeer").args([command, dependency, git, rev_flag, commit]); - cmd.execute(); + cmd.arg("soldeer") + .args([command, dependency, git, rev_flag, commit]) + .assert_success() + .stdout_eq(str![[r#" +đŸĻŒ Running soldeer install đŸĻŒ + +Successfully downloaded forge-std~1.8.1 the dependency via git +Dependency forge-std-1.8.1 downloaded! +Writing forge-std~1.8.1 to the lock file. +Adding dependency forge-std-1.8.1 to the config file +Added a new dependency to remappings @forge-std-1.8.1 + +"#]]); // Making sure the path was created to the dependency and that README.md exists // meaning that the dependencies were installed correctly @@ -155,8 +181,15 @@ forge-std = { version = "1.8.1" } eprintln!("Couldn't write to file: {e}"); } - cmd.arg("soldeer").arg(command); - cmd.execute(); + cmd.arg("soldeer").arg(command).assert_success().stdout_eq(str![[r#" +đŸĻŒ Running soldeer update đŸĻŒ + +Dependency forge-std-1.8.1 downloaded! +The dependency forge-std-1.8.1 was unzipped! +Writing forge-std~1.8.1 to the lock file. +Added a new dependency to remappings @forge-std-1.8.1 + +"#]]); // Making sure the path was created to the dependency and that foundry.toml exists // meaning that the dependencies were installed correctly @@ -209,8 +242,15 @@ forge-std = "1.8.1" eprintln!("Couldn't write to file: {e}"); } - cmd.arg("soldeer").arg(command); - cmd.execute(); + cmd.arg("soldeer").arg(command).assert_success().stdout_eq(str![[r#" +đŸĻŒ Running soldeer update đŸĻŒ + +Dependency forge-std-1.8.1 downloaded! +The dependency forge-std-1.8.1 was unzipped! +Writing forge-std~1.8.1 to the lock file. +Added a new dependency to remappings @forge-std-1.8.1 + +"#]]); // Making sure the path was created to the dependency and that foundry.toml exists // meaning that the dependencies were installed correctly @@ -249,12 +289,20 @@ forge-std = "1.8.1" forgesoldeer!(login, |prj, cmd| { let command = "login"; - cmd.arg("soldeer").arg(command); - let output = cmd.execute(); + cmd.arg("soldeer") + .arg(command) + .assert_failure() + .stderr_eq(str![[r#" +Error: +Failed to run soldeer Invalid email + +"#]]) + .stdout_eq(str![[r#" +đŸĻŒ Running soldeer login đŸĻŒ - // On login, we can only check if the prompt is displayed in the stdout - let stdout = String::from_utf8(output.stdout).expect("Could not parse the output"); - assert!(stdout.contains("Please enter your email")); +â„šī¸ If you do not have an account, please go to soldeer.xyz to create one. +📧 Please enter your email: +"#]]); }); fn read_file_to_string(path: &Path) -> String { From 290fc742e5fbab1b35a2eee0d18ee32e0910aa96 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 14:54:35 +0000 Subject: [PATCH 43/47] fix CI tests --- crates/cast/tests/cli/main.rs | 2 +- crates/forge/tests/cli/cmd.rs | 9 ++++++-- crates/forge/tests/cli/soldeer.rs | 34 +++++------------------------- crates/forge/tests/cli/test_cmd.rs | 6 ++++-- 4 files changed, 17 insertions(+), 34 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index a812cacab6d6c..8ece9ef65dedf 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -16,7 +16,7 @@ casttest!(print_help, |_prj, cmd| { cmd.arg("--help").assert_success().stdout_eq(str![[r#" Perform Ethereum RPC calls from the comfort of your command line -Usage: cast +Usage: cast[..] Commands: ... diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 89de746fc2fcd..544602c9c9188 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -23,7 +23,7 @@ forgetest!(print_help, |_prj, cmd| { cmd.arg("--help").assert_success().stdout_eq(str![[r#" Build, test, fuzz, debug and deploy Solidity contracts -Usage: forge +Usage: forge[..] Commands: ... @@ -708,6 +708,8 @@ forgetest_init!(can_clean_test_cache, |prj, cmd| { // checks that extra output works forgetest_init!(can_emit_extra_output, |prj, cmd| { + prj.clear(); + cmd.args(["build", "--extra-output", "metadata"]).assert_success().stdout_eq(str![[r#" Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] @@ -1112,6 +1114,7 @@ contract BTest is DSTest { cmd.arg("build").assert_success().stdout_eq(str![[r#" Compiling 3 files with [SOLC_VERSION] +... [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1918,7 +1921,9 @@ forgetest_init!(can_inspect_ir_optimized, |_prj, cmd| { }); // checks forge bind works correctly on the default project -forgetest_init!(can_bind, |_prj, cmd| { +forgetest_init!(can_bind, |prj, cmd| { + prj.clear(); + cmd.arg("bind").assert_success().stdout_eq(str![[r#" Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] diff --git a/crates/forge/tests/cli/soldeer.rs b/crates/forge/tests/cli/soldeer.rs index b65b8b676d154..b16bf261b7508 100644 --- a/crates/forge/tests/cli/soldeer.rs +++ b/crates/forge/tests/cli/soldeer.rs @@ -16,12 +16,7 @@ forgesoldeer!(install_dependency, |prj, cmd| { cmd.arg("soldeer").args([command, dependency]).assert_success().stdout_eq(str![[r#" đŸĻŒ Running soldeer install đŸĻŒ - -Dependency forge-std-[..] downloaded! -Writing forge-std~[..] to the lock file. -The dependency forge-std-[..] was unzipped! -Adding dependency forge-std-[..] to the config file -Added a new dependency to remappings @forge-std-[..] +... "#]]); // Making sure the path was created to the dependency and that foundry.toml exists @@ -67,12 +62,7 @@ forgesoldeer!(install_dependency_git, |prj, cmd| { cmd.arg("soldeer").args([command, dependency, git]).assert_success().stdout_eq(str![[r#" đŸĻŒ Running soldeer install đŸĻŒ - -Successfully downloaded forge-std~1.8.1 the dependency via git -Dependency forge-std-1.8.1 downloaded! -Writing forge-std~1.8.1 to the lock file. -Adding dependency forge-std-1.8.1 to the config file -Added a new dependency to remappings @forge-std-1.8.1 +... "#]]); // Making sure the path was created to the dependency and that README.md exists @@ -122,13 +112,7 @@ forgesoldeer!(install_dependency_git_commit, |prj, cmd| { .assert_success() .stdout_eq(str![[r#" đŸĻŒ Running soldeer install đŸĻŒ - -Successfully downloaded forge-std~1.8.1 the dependency via git -Dependency forge-std-1.8.1 downloaded! -Writing forge-std~1.8.1 to the lock file. -Adding dependency forge-std-1.8.1 to the config file -Added a new dependency to remappings @forge-std-1.8.1 - +... "#]]); // Making sure the path was created to the dependency and that README.md exists @@ -183,11 +167,7 @@ forge-std = { version = "1.8.1" } cmd.arg("soldeer").arg(command).assert_success().stdout_eq(str![[r#" đŸĻŒ Running soldeer update đŸĻŒ - -Dependency forge-std-1.8.1 downloaded! -The dependency forge-std-1.8.1 was unzipped! -Writing forge-std~1.8.1 to the lock file. -Added a new dependency to remappings @forge-std-1.8.1 +... "#]]); @@ -244,11 +224,7 @@ forge-std = "1.8.1" cmd.arg("soldeer").arg(command).assert_success().stdout_eq(str![[r#" đŸĻŒ Running soldeer update đŸĻŒ - -Dependency forge-std-1.8.1 downloaded! -The dependency forge-std-1.8.1 was unzipped! -Writing forge-std~1.8.1 to the lock file. -Added a new dependency to remappings @forge-std-1.8.1 +... "#]]); diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 72225ad65f176..8056eef2278b8 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -313,9 +313,11 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) // checks that forge test repeatedly produces the same output #[cfg(not(feature = "isolate-by-default"))] -forgetest_init!(can_test_repeatedly, |_prj, cmd| { +forgetest_init!(can_test_repeatedly, |prj, cmd| { + prj.clear(); + cmd.arg("test").assert_success().stdout_eq(str![[r#" -Compiling 24 files with [SOLC_VERSION] +Compiling [..] files with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! From 5e161921eea3997240a4a6e6733be4b7e7cc0bbd Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 15:06:29 +0000 Subject: [PATCH 44/47] soldeer has inconsistent spelling for some reason --- crates/forge/tests/cli/soldeer.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/forge/tests/cli/soldeer.rs b/crates/forge/tests/cli/soldeer.rs index b16bf261b7508..aa742d53d9612 100644 --- a/crates/forge/tests/cli/soldeer.rs +++ b/crates/forge/tests/cli/soldeer.rs @@ -15,7 +15,7 @@ forgesoldeer!(install_dependency, |prj, cmd| { let foundry_file = prj.root().join("foundry.toml"); cmd.arg("soldeer").args([command, dependency]).assert_success().stdout_eq(str![[r#" -đŸĻŒ Running soldeer install đŸĻŒ +đŸĻŒ Running [..]oldeer install đŸĻŒ ... "#]]); @@ -61,7 +61,7 @@ forgesoldeer!(install_dependency_git, |prj, cmd| { let foundry_file = prj.root().join("foundry.toml"); cmd.arg("soldeer").args([command, dependency, git]).assert_success().stdout_eq(str![[r#" -đŸĻŒ Running soldeer install đŸĻŒ +đŸĻŒ Running [..]oldeer install đŸĻŒ ... "#]]); @@ -111,7 +111,7 @@ forgesoldeer!(install_dependency_git_commit, |prj, cmd| { .args([command, dependency, git, rev_flag, commit]) .assert_success() .stdout_eq(str![[r#" -đŸĻŒ Running soldeer install đŸĻŒ +đŸĻŒ Running [..]oldeer install đŸĻŒ ... "#]]); @@ -166,7 +166,7 @@ forge-std = { version = "1.8.1" } } cmd.arg("soldeer").arg(command).assert_success().stdout_eq(str![[r#" -đŸĻŒ Running soldeer update đŸĻŒ +đŸĻŒ Running [..]oldeer update đŸĻŒ ... "#]]); @@ -223,7 +223,7 @@ forge-std = "1.8.1" } cmd.arg("soldeer").arg(command).assert_success().stdout_eq(str![[r#" -đŸĻŒ Running soldeer update đŸĻŒ +đŸĻŒ Running [..]oldeer update đŸĻŒ ... "#]]); @@ -270,11 +270,11 @@ forgesoldeer!(login, |prj, cmd| { .assert_failure() .stderr_eq(str![[r#" Error: -Failed to run soldeer Invalid email +Failed to run [..]oldeer Invalid email "#]]) .stdout_eq(str![[r#" -đŸĻŒ Running soldeer login đŸĻŒ +đŸĻŒ Running [..]oldeer login đŸĻŒ â„šī¸ If you do not have an account, please go to soldeer.xyz to create one. 📧 Please enter your email: From 0bb60c6e4f43d5337164824cde22924f7f33909b Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 15:20:18 +0000 Subject: [PATCH 45/47] attempt fix flaky test --- crates/forge/tests/cli/soldeer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/forge/tests/cli/soldeer.rs b/crates/forge/tests/cli/soldeer.rs index abe108e36b341..292f1407624a5 100644 --- a/crates/forge/tests/cli/soldeer.rs +++ b/crates/forge/tests/cli/soldeer.rs @@ -273,7 +273,7 @@ forgesoldeer!(login, |prj, cmd| { .assert_failure() .stderr_eq(str![[r#" Error: -Failed to run [..]oldeer Invalid email +Failed to run [..] "#]]) .stdout_eq(str![[r#" From 88bc479342f927958e8185a1ce8cd20352fde312 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Tue, 27 Aug 2024 15:26:54 +0000 Subject: [PATCH 46/47] no idea why soldeer is so spotty --- crates/forge/tests/cli/soldeer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/forge/tests/cli/soldeer.rs b/crates/forge/tests/cli/soldeer.rs index 292f1407624a5..21666edbb493b 100644 --- a/crates/forge/tests/cli/soldeer.rs +++ b/crates/forge/tests/cli/soldeer.rs @@ -278,7 +278,7 @@ Failed to run [..] "#]]) .stdout_eq(str![[r#" đŸĻŒ Running [..]oldeer login đŸĻŒ - +... â„šī¸ If you do not have an account, please go to soldeer.xyz to create one. 📧 Please enter your email: "#]]); From a1877348129f6b7988087312197af0bab86f21b2 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Wed, 28 Aug 2024 09:46:54 +0000 Subject: [PATCH 47/47] make tests more robust, redact "Compiling N files" with [COMPILING_FILES] --- crates/forge/tests/cli/build.rs | 2 +- crates/forge/tests/cli/cmd.rs | 66 ++++++++++++------------- crates/forge/tests/cli/config.rs | 8 +-- crates/forge/tests/cli/create.rs | 10 ++-- crates/forge/tests/cli/script.rs | 78 +++++++++++++++--------------- crates/forge/tests/cli/test_cmd.rs | 40 +++++++-------- crates/test-utils/src/util.rs | 1 + crates/verify/src/etherscan/mod.rs | 2 +- 8 files changed, 104 insertions(+), 103 deletions(-) diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index 52b70f71293ec..d9861f19e392d 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -45,7 +45,7 @@ contract Dummy { // tests build output is as expected forgetest_init!(exact_build_output, |prj, cmd| { cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 544602c9c9188..1a8d2cb7e08c9 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -550,7 +550,7 @@ Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std Installed forge-std [..] Initialized forge project Collecting the creation information of 0x044b75f554b886A065b9567891e45c79542d7357 from Etherscan... -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -598,7 +598,7 @@ Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std Installed forge-std [..] Initialized forge project Collecting the creation information of 0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf from Etherscan... -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -670,7 +670,7 @@ forgetest_init!(can_clean_config, |prj, cmd| { let config = Config { out: "custom-out".into(), ..Default::default() }; prj.write_config(config); cmd.arg("build").assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -711,7 +711,7 @@ forgetest_init!(can_emit_extra_output, |prj, cmd| { prj.clear(); cmd.args(["build", "--extra-output", "metadata"]).assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -727,7 +727,7 @@ Compiler run successful! .root_arg() .assert_success() .stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -743,7 +743,7 @@ forgetest_init!(can_emit_multiple_extra_output, |prj, cmd| { cmd.args(["build", "--extra-output", "metadata", "ir-optimized", "--extra-output", "ir"]) .assert_success() .stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -768,7 +768,7 @@ Compiler run successful! .root_arg() .assert_success() .stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -800,7 +800,7 @@ contract Greeter { .unwrap(); cmd.arg("build").assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful with warnings: Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning. @@ -861,7 +861,7 @@ library FooLib { .unwrap(); cmd.arg("build").assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -917,7 +917,7 @@ contract ATest is DSTest { .unwrap(); cmd.args(["snapshot"]).assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -962,7 +962,7 @@ contract A { .unwrap(); cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -973,7 +973,7 @@ Compiler run successful! prj.write_config(Config { ignored_error_codes: vec![], ..Default::default() }); cmd.forge_fuse().args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful with warnings: Warning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. @@ -1003,7 +1003,7 @@ contract A { .unwrap(); cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1014,7 +1014,7 @@ Compiler run successful! prj.write_config(config); cmd.forge_fuse().args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful with warnings: Warning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. @@ -1043,7 +1043,7 @@ contract A { // there are no errors cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful with warnings: Warning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. @@ -1076,7 +1076,7 @@ Warning: SPDX license identifier not provided in source file. Before publishing, prj.write_config(config); cmd.forge_fuse().args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1113,7 +1113,7 @@ contract BTest is DSTest { .unwrap(); cmd.arg("build").assert_success().stdout_eq(str![[r#" -Compiling 3 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] ... [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1180,7 +1180,7 @@ contract CTest is DSTest { .unwrap(); cmd.forge_fuse().args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 4 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1410,7 +1410,7 @@ contract CounterCopy is Counter { // build and check output cmd.forge_fuse().arg("build").assert_success().stdout_eq(str![[r#" -Compiling 3 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1861,7 +1861,7 @@ forgetest_init!(can_use_absolute_imports, |prj, cmd| { .unwrap(); cmd.arg("build").assert_success().stdout_eq(str![[r#" -Compiling 3 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1907,7 +1907,7 @@ contract MyTest is IMyTest {} .unwrap(); cmd.arg("build").assert_success().stdout_eq(str![[r#" -Compiling 4 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1925,7 +1925,7 @@ forgetest_init!(can_bind, |prj, cmd| { prj.clear(); cmd.arg("bind").assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Generating bindings for [..] contracts @@ -1946,7 +1946,7 @@ forgetest_init!(can_install_missing_deps_test, |prj, cmd| { Missing dependencies found. Installing now... [UPDATING_DEPENDENCIES] -Compiling 25 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1973,7 +1973,7 @@ forgetest_init!(can_install_missing_deps_build, |prj, cmd| { Missing dependencies found. Installing now... [UPDATING_DEPENDENCIES] -Compiling 27 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1993,7 +1993,7 @@ forgetest_init!(can_build_skip_contracts, |prj, cmd| { // Only builds the single template contract `src/*` cmd.args(["build", "--skip", "tests", "--skip", "scripts"]).assert_success().stdout_eq(str![[ r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -2022,7 +2022,7 @@ function test_run() external {} cmd.args(["build", "--skip", "*/test/**", "--skip", "*/script/**", "--force"]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -2032,7 +2032,7 @@ Compiler run successful! .args(["build", "--skip", "./test/**", "--skip", "./script/**", "--force"]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -2069,7 +2069,7 @@ function test_bar() external {} // Build 2 files within test dir prj.clear(); cmd.args(["build", "test", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -2079,7 +2079,7 @@ Compiler run successful! prj.clear(); cmd.forge_fuse(); cmd.args(["build", "src", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -2089,7 +2089,7 @@ Compiler run successful! prj.clear(); cmd.forge_fuse(); cmd.args(["build", "src", "test", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 3 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -2099,7 +2099,7 @@ Compiler run successful! prj.clear(); cmd.forge_fuse(); cmd.args(["build", "test/Bar.sol", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -2111,7 +2111,7 @@ forgetest_init!(can_build_sizes_repeatedly, |prj, cmd| { prj.clear_cache(); cmd.args(["build", "--sizes"]).assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! | Contract | Size (B) | Margin (B) | @@ -2127,7 +2127,7 @@ forgetest_init!(can_build_names_repeatedly, |prj, cmd| { prj.clear_cache(); cmd.args(["build", "--names"]).assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! compiler version: [..] diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 9a77f6c8f0907..2cb11e72f1861 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -368,7 +368,7 @@ contract Greeter {} prj.write_config(config); cmd.arg("build").assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -387,7 +387,7 @@ contract Foo {} .unwrap(); cmd.args(["build", "--use", OTHER_SOLC_VERSION]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -398,7 +398,7 @@ Compiler run successful! .root_arg() .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -420,7 +420,7 @@ Error: .root_arg() .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! diff --git a/crates/forge/tests/cli/create.rs b/crates/forge/tests/cli/create.rs index 2a3454f3426b1..ebf8c81dbcc1e 100644 --- a/crates/forge/tests/cli/create.rs +++ b/crates/forge/tests/cli/create.rs @@ -155,7 +155,7 @@ forgetest_async!(can_create_template_contract, |prj, cmd| { ]); cmd.assert().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 @@ -196,7 +196,7 @@ forgetest_async!(can_create_using_unlocked, |prj, cmd| { ]); cmd.assert().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 @@ -253,7 +253,7 @@ contract ConstructorContract { ]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 @@ -290,7 +290,7 @@ contract TupleArrayConstructorContract { ]) .assert() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 @@ -338,7 +338,7 @@ contract UniswapV2Swap { ]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful with warnings: Warning (2018): Function state mutability can be restricted to pure diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 734c32a368701..6ef99d9d11bde 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -54,7 +54,7 @@ contract Demo { .unwrap(); cmd.arg("script").arg(script).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Script ran successfully. @@ -113,7 +113,7 @@ contract Demo { cmd.arg("script").arg(script).arg("--sig").arg("myFunction()").assert_success().stdout_eq( str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Script ran successfully. @@ -218,7 +218,7 @@ contract DeployScript is Script { ]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful with warnings: Warning (2018): Function state mutability can be restricted to view @@ -231,7 +231,7 @@ Traces: [81040] DeployScript::run() ├─ [0] VM::startBroadcast() │ └─ ← [Return] - ├─ [45299] → new GasWaster@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + ├─ [45299] → new GasWaster@[..] │ └─ ← [Return] 226 bytes of code ├─ [226] GasWaster::wasteGas(200000 [2e5]) │ └─ ← [Stop] @@ -245,7 +245,7 @@ Script ran successfully. Simulated On-chain Traces: Gas limit was set in script to 500000 - [45299] → new GasWaster@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + [45299] → new GasWaster@[..] └─ ← [Return] 226 bytes of code [226] GasWaster::wasteGas(200000 [2e5]) @@ -326,7 +326,7 @@ contract DeployScript is Script { ]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful with warnings: Warning (2018): Function state mutability can be restricted to view @@ -339,7 +339,7 @@ Traces: [81040] DeployScript::run() ├─ [0] VM::startBroadcast() │ └─ ← [Return] - ├─ [45299] → new GasWaster@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + ├─ [45299] → new GasWaster@[..] │ └─ ← [Return] 226 bytes of code ├─ [226] GasWaster::wasteGas(200000 [2e5]) │ └─ ← [Stop] @@ -353,7 +353,7 @@ Script ran successfully. Simulated On-chain Traces: Gas limit was set in script to 500000 - [45299] → new GasWaster@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + [45299] → new GasWaster@[..] └─ ← [Return] 226 bytes of code [226] GasWaster::wasteGas(200000 [2e5]) @@ -412,7 +412,7 @@ contract Demo { .arg("2") .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Script ran successfully. @@ -443,7 +443,7 @@ contract Demo { .unwrap(); cmd.arg("script").arg(script).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Script ran successfully. @@ -518,14 +518,14 @@ contract DeployScript is Script { ]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Traces: [116040] DeployScript::run() ├─ [0] VM::startBroadcast() │ └─ ← [Return] - ├─ [75723] → new HashChecker@0x1c32f8818e38a50d37d1E98c72B9516a50985227 + ├─ [75723] → new HashChecker@[..] │ └─ ← [Return] 378 bytes of code └─ ← [Stop] @@ -598,7 +598,7 @@ contract RunScript is Script { ]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Traces: @@ -609,51 +609,51 @@ Traces: │ └─ ← [Return] ├─ [0] VM::roll([..]) │ └─ ← [Return] - ├─ [22394] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + ├─ [22394] [..]::update() │ └─ ← [Stop] - ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + ├─ [239] [..]::checkLastHash() [staticcall] │ └─ ← [Stop] ├─ [0] VM::roll([..]) │ └─ ← [Return] - ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + ├─ [494] [..]::update() │ └─ ← [Stop] - ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + ├─ [239] [..]::checkLastHash() [staticcall] │ └─ ← [Stop] ├─ [0] VM::roll([..]) │ └─ ← [Return] - ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + ├─ [494] [..]::update() │ └─ ← [Stop] - ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + ├─ [239] [..]::checkLastHash() [staticcall] │ └─ ← [Stop] ├─ [0] VM::roll([..]) │ └─ ← [Return] - ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + ├─ [494] [..]::update() │ └─ ← [Stop] - ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + ├─ [239] [..]::checkLastHash() [staticcall] │ └─ ← [Stop] ├─ [0] VM::roll([..]) │ └─ ← [Return] - ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + ├─ [494] [..]::update() │ └─ ← [Stop] - ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + ├─ [239] [..]::checkLastHash() [staticcall] │ └─ ← [Stop] ├─ [0] VM::roll([..]) │ └─ ← [Return] - ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + ├─ [494] [..]::update() │ └─ ← [Stop] - ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + ├─ [239] [..]::checkLastHash() [staticcall] │ └─ ← [Stop] ├─ [0] VM::roll([..]) │ └─ ← [Return] - ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + ├─ [494] [..]::update() │ └─ ← [Stop] - ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + ├─ [239] [..]::checkLastHash() [staticcall] │ └─ ← [Stop] ├─ [0] VM::roll([..]) │ └─ ← [Return] - ├─ [494] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::update() + ├─ [494] [..]::update() │ └─ ← [Stop] - ├─ [239] 0x1c32f8818e38a50d37d1E98c72B9516a50985227::checkLastHash() [staticcall] + ├─ [239] [..]::checkLastHash() [staticcall] │ └─ ← [Stop] └─ ← [Stop] @@ -1082,7 +1082,7 @@ contract Script0 is Script { ]) .assert_success() .stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! ... @@ -1203,7 +1203,7 @@ contract Script0 is Script { ]) .assert_success() .stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! ... @@ -1275,7 +1275,7 @@ contract Demo { .args(["--skip", "tests", "--skip", TEMPLATE_CONTRACT]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Script ran successfully. @@ -1373,7 +1373,7 @@ contract ContractC { .args(["--tc", "ScriptTxOrigin"]) .assert_success() .stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Script ran successfully. @@ -1439,7 +1439,7 @@ contract NestedCreate is Script { .args(["--tc", "NestedCreate"]) .assert_success() .stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Script ran successfully. @@ -1470,7 +1470,7 @@ interface Interface {} .unwrap(); cmd.arg("script").arg(script).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Script ran successfully. @@ -1498,7 +1498,7 @@ contract Script { .unwrap(); cmd.arg("script").arg(script).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! Script ran successfully. @@ -1692,7 +1692,7 @@ contract SimpleScript is Script { ]) .assert_success() .stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! ... @@ -1805,7 +1805,7 @@ contract SimpleScript is Script { ]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! ... @@ -1918,7 +1918,7 @@ contract SimpleScript is Script { ]) .assert_success() .stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful with warnings: Warning (2018): Function state mutability can be restricted to view diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index 7d121a4dc6c6b..1804a46138a48 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -137,7 +137,7 @@ contract ATest is DSTest { .unwrap(); cmd.arg("test").assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -170,7 +170,7 @@ contract ATest is DSTest { .unwrap(); cmd.arg("test").assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -214,7 +214,7 @@ contract FailTest is DSTest { .unwrap(); cmd.args(["test", "--match-path", "*src/ATest.t.sol"]).assert_success().stdout_eq(str![[r#" -Compiling 3 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -261,7 +261,7 @@ contract FailTest is DSTest { let test_path = test_path.to_string_lossy(); cmd.args(["test", "--match-path", test_path.as_ref()]).assert_success().stdout_eq(str![[r#" -Compiling 3 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -298,7 +298,7 @@ contract MyTest is DSTest { .unwrap(); cmd.arg("test").assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -317,7 +317,7 @@ forgetest_init!(can_test_repeatedly, |prj, cmd| { prj.clear(); cmd.arg("test").assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -372,7 +372,7 @@ contract ContractTest is DSTest { prj.write_config(config); cmd.arg("test").assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -389,7 +389,7 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) prj.write_config(config); cmd.forge_fuse().arg("test").assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -450,7 +450,7 @@ contract ContractTest is Test { .unwrap(); cmd.arg("test").assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -522,7 +522,7 @@ contract USDTCallingTest is Test { .unwrap(); cmd.args(["test", "-vvvv"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -568,7 +568,7 @@ contract CustomTypesTest is Test { .unwrap(); cmd.args(["test", "-vvvv"]).assert_failure().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -771,7 +771,7 @@ contract CounterTest is Test { // make sure there are only 61 runs (with proptest shrinking same test results in 298 runs) cmd.args(["test"]).assert_failure().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -822,7 +822,7 @@ contract CounterTest is Test { // make sure invariant test exit early with 0 runs cmd.args(["test"]).assert_failure().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -870,7 +870,7 @@ contract ReplayFailuresTest is Test { .unwrap(); cmd.args(["test"]).assert_failure().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -948,7 +948,7 @@ contract PrecompileLabelsTest is Test { .unwrap(); cmd.args(["test", "-vvvv"]).assert_success().stdout_eq(str![[r#" -Compiling 1 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1022,7 +1022,7 @@ forgetest_init!(should_show_logs_when_fuzz_test, |prj, cmd| { ) .unwrap(); cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1067,7 +1067,7 @@ forgetest_init!(should_show_logs_when_fuzz_test_inline_config, |prj, cmd| { ) .unwrap(); cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1113,7 +1113,7 @@ forgetest_init!(should_not_show_logs_when_fuzz_test, |prj, cmd| { ) .unwrap(); cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1153,7 +1153,7 @@ forgetest_init!(should_not_show_logs_when_fuzz_test_inline_config, |prj, cmd| { ) .unwrap(); cmd.args(["test", "-vv"]).assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! @@ -1214,7 +1214,7 @@ contract SimpleContractTest is Test { ) .unwrap(); cmd.args(["test", "-vvvv", "--decode-internal"]).assert_success().stdout_eq(str![[r#" -Compiling [..] files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 63d657213ba62..4b9f8f53ee2c4 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -947,6 +947,7 @@ fn test_redactions() -> snapbox::Redactions { ("[AVG_GAS]", r"Îŧ: \d+, ~: \d+"), ("[FILE]", r"-->.*\.sol"), ("[FILE]", r"Location(.|\n)*\.rs(.|\n)*Backtrace"), + ("[COMPILING_FILES]", r"Compiling \d+ files?"), ("[TX_HASH]", r"Transaction hash: 0x[0-9A-Fa-f]{64}"), ("[ADDRESS]", r"Address: 0x[0-9A-Fa-f]{40}"), ("[UPDATING_DEPENDENCIES]", r"Updating dependencies in .*"), diff --git a/crates/verify/src/etherscan/mod.rs b/crates/verify/src/etherscan/mod.rs index ff437f39c3e77..0a1d39c1956a1 100644 --- a/crates/verify/src/etherscan/mod.rs +++ b/crates/verify/src/etherscan/mod.rs @@ -567,7 +567,7 @@ mod tests { prj.add_source("Counter2", "contract Counter {}").unwrap(); cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" -Compiling 2 files with [SOLC_VERSION] +[COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful!