diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7d3a3ef9fa96..d816ea2e5d37 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,9 +49,28 @@ jobs: with: target: ${{ matrix.target }} - uses: taiki-e/install-action@nextest - # - uses: taiki-e/setup-cross-toolchain-action@v1 - # with: - # target: ${{ matrix.target }} + + # External tests dependencies + - name: Setup Python + if: contains(matrix.name, 'external') + uses: actions/setup-python@v4 + with: + python-version: 3.11 + - name: Setup Node.js + if: contains(matrix.name, 'external') + uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Install pnpm + if: contains(matrix.name, 'external') + uses: pnpm/action-setup@v2 + with: + version: latest + run_install: false + - name: Install Vyper + if: contains(matrix.name, 'external') + run: pip install vyper + - name: Forge RPC cache uses: actions/cache@v3 with: @@ -61,7 +80,6 @@ jobs: key: rpc-cache-${{ hashFiles('crates/forge/tests/rpc-cache-keyfile') }} - uses: Swatinem/rust-cache@v2 with: - # key: ${{ matrix.target }} cache-on-failure: true - name: Setup Git config run: | diff --git a/crates/anvil/tests/it/otterscan.rs b/crates/anvil/tests/it/otterscan.rs index c6643dc2bd1d..41745f0fa8e1 100644 --- a/crates/anvil/tests/it/otterscan.rs +++ b/crates/anvil/tests/it/otterscan.rs @@ -232,9 +232,12 @@ async fn can_call_ots_has_code() { .await .unwrap()); - client.send_transaction(deploy_tx, None).await.unwrap(); + let pending = client.send_transaction(deploy_tx, None).await.unwrap(); + let receipt = pending.await.unwrap().unwrap(); let num = client.get_block_number().await.unwrap(); + assert_eq!(num, receipt.block_number.unwrap()); + // code is detected after deploying assert!(api.ots_has_code(pending_contract_address, BlockNumber::Number(num)).await.unwrap()); diff --git a/crates/evm/traces/src/decoder/mod.rs b/crates/evm/traces/src/decoder/mod.rs index 617fc48b5a24..ccb9d47c0b07 100644 --- a/crates/evm/traces/src/decoder/mod.rs +++ b/crates/evm/traces/src/decoder/mod.rs @@ -431,7 +431,7 @@ impl CallTraceDecoder { let &[t0, ..] = raw_log.topics() else { return }; let mut events = Vec::new(); - let events = match self.events.get(&(t0, raw_log.topics().len())) { + let events = match self.events.get(&(t0, raw_log.topics().len() - 1)) { Some(es) => es, None => { if let Some(identifier) = &self.signature_identifier { diff --git a/crates/evm/traces/src/lib.rs b/crates/evm/traces/src/lib.rs index a1fcd52fc1f3..18c53aeace00 100644 --- a/crates/evm/traces/src/lib.rs +++ b/crates/evm/traces/src/lib.rs @@ -207,8 +207,7 @@ impl fmt::Display for CallTraceArena { let node = &arena.arena[idx]; // Display trace header - f.write_str(left)?; - node.trace.fmt(f)?; + writeln!(f, "{left}{}", node.trace)?; // Display logs and subcalls let left_prefix = format!("{child}{BRANCH}"); diff --git a/crates/forge/tests/cli/ext_integration.rs b/crates/forge/tests/cli/ext_integration.rs index 3574222a2fad..b188ae3e4673 100644 --- a/crates/forge/tests/cli/ext_integration.rs +++ b/crates/forge/tests/cli/ext_integration.rs @@ -11,6 +11,7 @@ forgetest_external!( forgetest_external!(stringutils, "Arachnid/solidity-stringutils"); forgetest_external!(lootloose, "gakonst/lootloose"); forgetest_external!(lil_web3, "m1guelpf/lil-web3"); +forgetest_external!(snekmate, "pcaversaccio/snekmate"); // Forking tests diff --git a/crates/test-utils/src/macros.rs b/crates/test-utils/src/macros.rs index 053741ac069a..fb8ee4e0b83f 100644 --- a/crates/test-utils/src/macros.rs +++ b/crates/test-utils/src/macros.rs @@ -147,31 +147,18 @@ macro_rules! forgetest_external { prj.wipe(); // Clone the external repository - let git_clone = - $crate::util::clone_remote(&format!("https://github.com/{}", $repo), prj.root()) - .expect("Could not clone repository. Is git installed?"); - assert!( - git_clone.status.success(), - "could not clone repository:\nstdout:\n{}\nstderr:\n{}", - String::from_utf8_lossy(&git_clone.stdout), - String::from_utf8_lossy(&git_clone.stderr) - ); + $crate::util::clone_remote(concat!("https://github.com/", $repo), prj.root().to_str().unwrap()); - // We just run make install, but we do not care if it worked or not, - // since some repositories do not have that target - let make_install = Command::new("make") - .arg("install") - .current_dir(prj.root()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status(); + // Run common installation commands + $crate::util::run_install_commands(prj.root()); // Run the tests cmd.arg("test").args($forge_opts).args([ "--optimize", - "--optimizer-runs", - "20000", + "--optimizer-runs=20000", + "--fuzz-runs=256", "--ffi", + "-vvvvv", ]); cmd.set_env("FOUNDRY_FUZZ_RUNS", "1"); diff --git a/crates/test-utils/src/util.rs b/crates/test-utils/src/util.rs index 7b784e2e0142..7e5ada1f2159 100644 --- a/crates/test-utils/src/util.rs +++ b/crates/test-utils/src/util.rs @@ -76,21 +76,44 @@ pub fn initialize(target: impl AsRef) { } } -/// Clones a remote repository into the specified directory. -pub fn clone_remote( - repo_url: &str, - target_dir: impl AsRef, -) -> std::io::Result { - Command::new("git") - .args([ - "clone", - "--depth", - "1", - "--recursive", - repo_url, - target_dir.as_ref().to_str().expect("Target path for git clone does not exist"), - ]) - .output() +/// Clones a remote repository into the specified directory. Panics if the command fails. +pub fn clone_remote(repo_url: &str, target_dir: &str) { + let mut cmd = Command::new("git"); + let status = cmd + .args(["clone", "--depth=1", "--recursive", "--shallow-submodules", repo_url, target_dir]) + .status() + .unwrap(); + if !status.success() { + panic!("{cmd:?}"); + } + eprintln!(); +} + +/// Runs common installation commands, such as `make` and `npm`. Continues if any command fails. +pub fn run_install_commands(root: &Path) { + let root_files = + std::fs::read_dir(root).unwrap().flatten().map(|x| x.path()).collect::>(); + let contains = |path: &str| root_files.iter().any(|p| p.to_str().unwrap().contains(path)); + let run = |args: &[&str]| { + let mut cmd = Command::new(args[0]); + cmd.args(&args[1..]).current_dir(root).stdout(Stdio::null()).stderr(Stdio::null()); + let st = cmd.status(); + eprintln!("\n\n{cmd:?} -> {st:?}"); + }; + let maybe_run = |path: &str, args: &[&str]| { + let c = contains(path); + if c { + run(args); + } + c + }; + + maybe_run("Makefile", &["make", "install"]); + let pnpm = maybe_run("pnpm-lock.yaml", &["pnpm", "install", "--prefer-offline"]); + let yarn = maybe_run("yarn.lock", &["yarn", "install", "--prefer-offline"]); + if !pnpm && !yarn && contains("package.json") { + run(&["npm", "install"]); + } } /// Setup an empty test project and return a command pointing to the forge diff --git a/testdata/cheats/UnixTime.t.sol b/testdata/cheats/UnixTime.t.sol index 9e689a223543..8a03ee9ca512 100644 --- a/testdata/cheats/UnixTime.t.sol +++ b/testdata/cheats/UnixTime.t.sol @@ -6,7 +6,9 @@ import "./Vm.sol"; contract UnixTimeTest is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); - uint256 errMargin = 100; // allow errors of up to errMargin milliseconds + + // This is really wide because CI sucks. + uint256 constant errMargin = 300; function testUnixTimeAgainstDate() public { string[] memory inputs = new string[](2);