-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: add isolate mode JS integration test
- Loading branch information
Showing
3 changed files
with
224 additions
and
81 deletions.
There are no files selected for viewing
99 changes: 99 additions & 0 deletions
99
js/integration-tests/solidity-tests/contracts/LastCallGasIsolated.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
pragma solidity ^0.8.24; | ||
|
||
import "./test.sol"; | ||
import "./Vm.sol"; | ||
|
||
contract Target { | ||
uint256 public slot0; | ||
|
||
function expandMemory(uint256 n) public pure returns (uint256) { | ||
uint256[] memory arr = new uint256[](n); | ||
|
||
for (uint256 i = 0; i < n; i++) { | ||
arr[i] = i; | ||
} | ||
|
||
return arr.length; | ||
} | ||
|
||
function setValue(uint256 value) public { | ||
slot0 = value; | ||
} | ||
|
||
function resetValue() public { | ||
slot0 = 0; | ||
} | ||
|
||
fallback() external {} | ||
} | ||
|
||
abstract contract LastCallGasFixture is DSTest { | ||
Vm constant vm = Vm(HEVM_ADDRESS); | ||
Target public target; | ||
|
||
struct Gas { | ||
uint64 gasTotalUsed; | ||
uint64 gasMemoryUsed; | ||
int64 gasRefunded; | ||
} | ||
|
||
function testRevertNoCachedLastCallGas() public { | ||
vm.expectRevert(); | ||
vm.lastCallGas(); | ||
} | ||
|
||
function _setup() internal { | ||
// Cannot be set in `setUp` due to `testRevertNoCachedLastCallGas` | ||
// relying on no calls being made before `lastCallGas` is called. | ||
target = new Target(); | ||
} | ||
|
||
function _performCall() internal returns (bool success) { | ||
(success,) = address(target).call(""); | ||
} | ||
|
||
function _performExpandMemory() internal view { | ||
target.expandMemory(1000); | ||
} | ||
|
||
function _performRefund() internal { | ||
target.setValue(1); | ||
target.resetValue(); | ||
} | ||
|
||
function _assertGas(Vm.Gas memory lhs, Gas memory rhs) internal { | ||
assertGt(lhs.gasLimit, 0); | ||
assertGt(lhs.gasRemaining, 0); | ||
assertEq(lhs.gasTotalUsed, rhs.gasTotalUsed); | ||
assertEq(lhs.gasMemoryUsed, rhs.gasMemoryUsed); | ||
assertEq(lhs.gasRefunded, rhs.gasRefunded); | ||
} | ||
} | ||
|
||
// Test that `lastCallGas` works correctly in isolate mode. | ||
contract LastCallGasIsolatedTest is LastCallGasFixture { | ||
function testRecordLastCallGas() public { | ||
_setup(); | ||
_performCall(); | ||
_assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 21065, gasMemoryUsed: 0, gasRefunded: 0})); | ||
|
||
_performCall(); | ||
_assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 21065, gasMemoryUsed: 0, gasRefunded: 0})); | ||
|
||
_performCall(); | ||
_assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 21065, gasMemoryUsed: 0, gasRefunded: 0})); | ||
} | ||
|
||
function testRecordGasMemory() public { | ||
_setup(); | ||
_performExpandMemory(); | ||
_assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 129820, gasMemoryUsed: 4994, gasRefunded: 0})); | ||
} | ||
|
||
function testRecordGasRefund() public { | ||
_setup(); | ||
_performRefund(); | ||
_assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 21400, gasMemoryUsed: 0, gasRefunded: 4800})); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { | ||
Artifact, | ||
ArtifactId, | ||
FuzzConfigArgs, | ||
InvariantConfigArgs, | ||
type SolidityTestRunnerConfigArgs, | ||
} from "@nomicfoundation/edr"; | ||
import { | ||
buildSolidityTestsInput, | ||
runAllSolidityTests, | ||
} from "@nomicfoundation/edr-helpers"; | ||
import hre from "hardhat"; | ||
|
||
export class TestContext { | ||
readonly rpcUrl = process.env.ALCHEMY_URL; | ||
readonly rpcCachePath: string = "./edr-cache"; | ||
readonly fuzzFailuresPersistDir: string = "./edr-cache/fuzz"; | ||
readonly invariantFailuresPersistDir: string = "./edr-cache/invariant"; | ||
readonly artifacts: Artifact[]; | ||
readonly testSuiteIds: ArtifactId[]; | ||
|
||
constructor(artifacts: Artifact[], testSuiteIds: ArtifactId[]) { | ||
this.artifacts = artifacts; | ||
this.testSuiteIds = testSuiteIds; | ||
} | ||
|
||
static async setup(): Promise<TestContext> { | ||
const results = await buildSolidityTestsInput(hre.artifacts); | ||
return new TestContext(results.artifacts, results.testSuiteIds); | ||
} | ||
|
||
defaultConfig(): SolidityTestRunnerConfigArgs { | ||
return { | ||
projectRoot: hre.config.paths.root, | ||
rpcCachePath: this.rpcCachePath, | ||
}; | ||
} | ||
|
||
fuzzConfig( | ||
config?: Omit<FuzzConfigArgs, "failurePersistDir"> | ||
): FuzzConfigArgs { | ||
return { | ||
failurePersistDir: this.fuzzFailuresPersistDir, | ||
...config, | ||
}; | ||
} | ||
|
||
invariantConfig( | ||
config?: Omit<InvariantConfigArgs, "failurePersistDir"> | ||
): InvariantConfigArgs { | ||
return { | ||
failurePersistDir: this.invariantFailuresPersistDir, | ||
...config, | ||
}; | ||
} | ||
|
||
async runTestsWithStats( | ||
contractName: string, | ||
config?: Omit<SolidityTestRunnerConfigArgs, "projectRoot"> | ||
): Promise<SolidityTestsRunResult> { | ||
let totalTests = 0; | ||
let failedTests = 0; | ||
|
||
const suiteResults = await runAllSolidityTests( | ||
this.artifacts, | ||
this.matchingTest(contractName), | ||
{ | ||
...this.defaultConfig(), | ||
...config, | ||
} | ||
); | ||
|
||
for (const suiteResult of suiteResults) { | ||
for (const testResult of suiteResult.testResults) { | ||
let failed = testResult.status === "Failure"; | ||
totalTests++; | ||
if (failed) { | ||
failedTests++; | ||
} | ||
} | ||
} | ||
return { totalTests, failedTests }; | ||
} | ||
|
||
matchingTest(contractName: string): ArtifactId[] { | ||
return this.matchingTests(new Set([contractName])); | ||
} | ||
matchingTests(testContractNames: Set<string>): ArtifactId[] { | ||
return this.testSuiteIds.filter((testSuiteId) => { | ||
return testContractNames.has(testSuiteId.name); | ||
}); | ||
} | ||
} | ||
|
||
interface SolidityTestsRunResult { | ||
totalTests: number; | ||
failedTests: number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters