diff --git a/crates/forge/src/gas_report.rs b/crates/forge/src/gas_report.rs index 59c417b97097..6c53bd9e6e75 100644 --- a/crates/forge/src/gas_report.rs +++ b/crates/forge/src/gas_report.rs @@ -9,6 +9,7 @@ use comfy_table::{presets::ASCII_MARKDOWN, *}; use foundry_common::{calc, TestFunctionExt}; use foundry_evm::traces::CallKind; use serde::{Deserialize, Serialize}; +use serde_json::json; use std::{collections::BTreeMap, fmt::Display}; use yansi::Paint; @@ -156,59 +157,136 @@ impl GasReport { impl Display for GasReport { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - for (name, contract) in &self.contracts { - if contract.functions.is_empty() { - trace!(name, "gas report contract without functions"); - continue; - } + match self.report_type { + GasReportKind::Markdown => { + for (name, contract) in &self.contracts { + if contract.functions.is_empty() { + trace!(name, "gas report contract without functions"); + continue; + } - if self.report_type == GasReportKind::JSON { - writeln!(f, "{}", serde_json::to_string(&contract).unwrap())?; - continue; + let table = self.format_table_output(contract, name); + writeln!(f, "{table}")?; + writeln!(f, "\n")?; + } + } + GasReportKind::JSON => { + writeln!(f, "{}", &self.format_json_output())?; } - - let mut table = Table::new(); - table.load_preset(ASCII_MARKDOWN); - table.set_header([Cell::new(format!("{name} contract")) - .add_attribute(Attribute::Bold) - .fg(Color::Green)]); - table.add_row([ - Cell::new("Deployment Cost").add_attribute(Attribute::Bold).fg(Color::Cyan), - Cell::new("Deployment Size").add_attribute(Attribute::Bold).fg(Color::Cyan), - ]); - table.add_row([contract.gas.to_string(), contract.size.to_string()]); - - table.add_row([ - Cell::new("Function Name").add_attribute(Attribute::Bold).fg(Color::Magenta), - Cell::new("min").add_attribute(Attribute::Bold).fg(Color::Green), - Cell::new("avg").add_attribute(Attribute::Bold).fg(Color::Yellow), - Cell::new("median").add_attribute(Attribute::Bold).fg(Color::Yellow), - Cell::new("max").add_attribute(Attribute::Bold).fg(Color::Red), - Cell::new("# calls").add_attribute(Attribute::Bold), - ]); - contract.functions.iter().for_each(|(fname, sigs)| { - sigs.iter().for_each(|(sig, gas_info)| { - // show function signature if overloaded else name - let fn_display = - if sigs.len() == 1 { fname.clone() } else { sig.replace(':', "") }; - - table.add_row([ - Cell::new(fn_display).add_attribute(Attribute::Bold), - Cell::new(gas_info.min.to_string()).fg(Color::Green), - Cell::new(gas_info.mean.to_string()).fg(Color::Yellow), - Cell::new(gas_info.median.to_string()).fg(Color::Yellow), - Cell::new(gas_info.max.to_string()).fg(Color::Red), - Cell::new(gas_info.calls.to_string()), - ]); - }) - }); - writeln!(f, "{table}")?; - writeln!(f, "\n")?; } + Ok(()) } } +impl GasReport { + fn format_json_output(&self) -> String { + #[inline] + fn format_gas_info(gas_info: &GasInfo) -> serde_json::Value { + json!({ + "calls": gas_info.calls, + "min": gas_info.min, + "mean": gas_info.mean, + "median": gas_info.median, + "max": gas_info.max, + }) + } + + serde_json::to_string( + &self + .contracts + .iter() + .filter_map(|(name, contract)| { + if contract.functions.is_empty() { + trace!(name, "gas report contract without functions"); + return None; + } + + let functions = contract + .functions + .iter() + .map(|(fname, sigs)| { + // If there is only one signature, display the gas info directly. + let function_value = if sigs.len() == 1 { + format_gas_info(sigs.values().next().unwrap()) + } else { + // If there are multiple signatures, e.g. overloads like: + // - `foo(uint256)` + // - `foo(int256)` + // display the gas info as a map with the signature as the key. + let signatures = sigs + .iter() + .map(|(sig, gas_info)| { + let display_name = sig.replace(':', ""); + (display_name, format_gas_info(gas_info)) + }) + .collect::>(); + + json!(signatures) + }; + + (fname.to_string(), function_value) + }) + .collect::>(); + + Some(json!({ + "contract": name, + "deployment": { + "gas": contract.gas, + "size": contract.size, + }, + "functions": functions, + })) + }) + .collect::>(), + ) + .unwrap() + } + + // Helper function to format the table output + fn format_table_output(&self, contract: &ContractInfo, name: &str) -> Table { + let mut table = Table::new(); + table.load_preset(ASCII_MARKDOWN); + table.set_header([Cell::new(format!("{name} contract")) + .add_attribute(Attribute::Bold) + .fg(Color::Green)]); + + table.add_row([ + Cell::new("Deployment Cost").add_attribute(Attribute::Bold).fg(Color::Cyan), + Cell::new("Deployment Size").add_attribute(Attribute::Bold).fg(Color::Cyan), + ]); + table.add_row([contract.gas.to_string(), contract.size.to_string()]); + + table.add_row([ + Cell::new("Function Name").add_attribute(Attribute::Bold).fg(Color::Magenta), + Cell::new("min").add_attribute(Attribute::Bold).fg(Color::Green), + Cell::new("avg").add_attribute(Attribute::Bold).fg(Color::Yellow), + Cell::new("median").add_attribute(Attribute::Bold).fg(Color::Yellow), + Cell::new("max").add_attribute(Attribute::Bold).fg(Color::Red), + Cell::new("# calls").add_attribute(Attribute::Bold), + ]); + + contract.functions.iter().for_each(|(fname, sigs)| { + sigs.iter().for_each(|(sig, gas_info)| { + // Show function signature if overloaded else display function name. + let display_name = + if sigs.len() == 1 { fname.to_string() } else { sig.replace(':', "") }; + + table.add_row([ + Cell::new(display_name).add_attribute(Attribute::Bold), + Cell::new(gas_info.min.to_string()).fg(Color::Green), + Cell::new(gas_info.mean.to_string()).fg(Color::Yellow), + Cell::new(gas_info.median.to_string()).fg(Color::Yellow), + Cell::new(gas_info.max.to_string()).fg(Color::Red), + Cell::new(gas_info.calls.to_string()), + ]); + }) + }); + + table + } +} + #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct ContractInfo { pub gas: u64, diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 6177e973dce6..48b73ac626ec 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -1591,16 +1591,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); prj.write_config(Config { gas_reports: (vec![]), ..Default::default() }); cmd.forge_fuse().arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" @@ -1630,16 +1675,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); prj.write_config(Config { gas_reports: (vec!["*".to_string()]), ..Default::default() }); cmd.forge_fuse().arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" @@ -1669,16 +1759,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); prj.write_config(Config { gas_reports: (vec![ @@ -1715,16 +1850,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); }); forgetest!(gas_report_some_contracts, |prj, cmd| { @@ -1745,14 +1925,29 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + } +] +"#]] + .is_json(), + ); // report for Two prj.write_config(Config { gas_reports: vec!["ContractTwo".to_string()], ..Default::default() }); @@ -1770,8 +1965,26 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { "#]]); cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( str![[r#" -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines(), +[ + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), ); // report for Three @@ -1791,17 +2004,32 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + } +] +"#]] + .is_json(), + ); }); -forgetest!(gas_ignore_some_contracts, |prj, cmd| { +forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { prj.insert_ds_test(); prj.add_source("Contracts.sol", GAS_REPORT_CONTRACTS).unwrap(); @@ -1831,15 +2059,45 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); // ignore ContractTwo cmd.forge_fuse(); @@ -1868,17 +2126,51 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + } +] +"#]] + .is_json(), + ); - // ignore ContractThree + // If the user listed the contract in 'gas_reports' (the foundry.toml field) a + // report for the contract is generated even if it's listed in the ignore + // list. This is addressed this way because getting a report you don't expect is + // preferable than not getting one you expect. A warning is printed to stderr + // indicating the "double listing". cmd.forge_fuse(); prj.write_config(Config { gas_reports: (vec![ @@ -1890,7 +2182,10 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { ..Default::default() }); cmd.forge_fuse(); - cmd.arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" + cmd.arg("test") + .arg("--gas-report") + .assert_success() + .stdout_eq(str![[r#" ... | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| @@ -1915,18 +2210,183 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { | Function Name | min | avg | median | max | # calls | | bar | 64984 | 64984 | 64984 | 64984 | 1 | ... - +"#]]) + .stderr_eq(str![[r#" +... +warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. +... "#]]); cmd.forge_fuse() .arg("test") .arg("--gas-report") .arg("--json") .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + .stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ) + .stderr_eq(str![[r#" +... +warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. +... +"#]]); +}); + +forgetest!(gas_report_multiple_selectors, |prj, cmd| { + prj.insert_ds_test(); + prj.add_source( + "Counter.sol", + r#" +contract Counter { + uint256 public a; + int256 public b; + + function setNumber(uint256 x) public { + a = x; + } + + function setNumber(int256 x) public { + b = x; + } +} +"#, + ) + .unwrap(); + + prj.add_source( + "CounterTest.t.sol", + r#" +import "./test.sol"; +import {Counter} from "./Counter.sol"; + +contract CounterTest is DSTest { + Counter public counter; + + function setUp() public { + counter = new Counter(); + counter.setNumber(uint256(0)); + counter.setNumber(int256(0)); + } + + function test_Increment() public { + counter.setNumber(uint256(counter.a() + 1)); + counter.setNumber(int256(counter.b() + 1)); + } +} +"#, + ) + .unwrap(); + + cmd.arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" +... +| src/Counter.sol:Counter contract | | | | | | +|----------------------------------|-----------------|-------|--------|-------|---------| +| Deployment Cost | Deployment Size | | | | | +| 101137 | 250 | | | | | +| Function Name | min | avg | median | max | # calls | +| a | 2261 | 2261 | 2261 | 2261 | 1 | +| b | 2305 | 2305 | 2305 | 2305 | 1 | +| setNumber(int256) | 23648 | 33604 | 33604 | 43560 | 2 | +| setNumber(uint256) | 23604 | 33560 | 33560 | 43516 | 2 | +... +"#]]); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Counter.sol:Counter", + "deployment": { + "gas": 101137, + "size": 250 + }, + "functions": { + "a": { + "calls": 1, + "min": 2261, + "mean": 2261, + "median": 2261, + "max": 2261 + }, + "b": { + "calls": 1, + "min": 2305, + "mean": 2305, + "median": 2305, + "max": 2305 + }, + "setNumber": { + "setNumber(int256)": { + "calls": 2, + "min": 23648, + "mean": 33604, + "median": 33604, + "max": 43560 + }, + "setNumber(uint256)": { + "calls": 2, + "min": 23604, + "mean": 33560, + "median": 33560, + "max": 43516 + } + } + } + } +] +"#]] + .is_json(), + ); }); forgetest_init!(can_use_absolute_imports, |prj, cmd| {