Skip to content

Commit d4dc2ba

Browse files
committed
Use helper
1 parent bbb8ba5 commit d4dc2ba

File tree

5 files changed

+154
-182
lines changed

5 files changed

+154
-182
lines changed

packages/hardhat-chai-matchers/src/internal/emit.ts

+29-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type EthersT from "ethers";
2-
import type { Contract, Transaction } from "ethers";
2+
import type { Contract, Interface, Transaction } from "ethers";
33
import type { AssertWithSsfi, Ssfi } from "../utils";
44

55
import { AssertionError } from "chai";
@@ -8,19 +8,14 @@ import util from "util";
88
import { buildAssert } from "../utils";
99
import { ASSERTION_ABORTED, EMIT_MATCHER } from "./constants";
1010
import { HardhatChaiMatchersAssertionError } from "./errors";
11-
import { assertIsNotNull, preventAsyncMatcherChaining } from "./utils";
11+
import {
12+
assertArgsArraysEqual,
13+
assertIsNotNull,
14+
preventAsyncMatcherChaining,
15+
} from "./utils";
1216

1317
type EventFragment = EthersT.EventFragment;
1418
type Provider = EthersT.Provider;
15-
type AssertArgsArraysEqual = (
16-
context: any,
17-
Assertion: Chai.AssertionStatic,
18-
chaiUtils: Chai.ChaiUtils,
19-
expectedArgs: any[],
20-
log: any,
21-
assert: AssertWithSsfi,
22-
ssfi: Ssfi
23-
) => void;
2419

2520
export const EMIT_CALLED = "emitAssertionCalled";
2621

@@ -137,8 +132,7 @@ export async function emitWithArgs(
137132
Assertion: Chai.AssertionStatic,
138133
chaiUtils: Chai.ChaiUtils,
139134
expectedArgs: any[],
140-
ssfi: Ssfi,
141-
assertArgsArraysEqual: AssertArgsArraysEqual
135+
ssfi: Ssfi
142136
) {
143137
const negated = false; // .withArgs cannot be negated
144138
const assert = buildAssert(negated, ssfi);
@@ -150,8 +144,7 @@ export async function emitWithArgs(
150144
expectedArgs,
151145
context.logs,
152146
assert,
153-
ssfi,
154-
assertArgsArraysEqual
147+
ssfi
155148
);
156149
}
157150

@@ -162,38 +155,49 @@ const tryAssertArgsArraysEqual = (
162155
expectedArgs: any[],
163156
logs: any[],
164157
assert: AssertWithSsfi,
165-
ssfi: Ssfi,
166-
assertArgsArraysEqual: AssertArgsArraysEqual
158+
ssfi: Ssfi
167159
) => {
168-
if (logs.length === 1)
160+
const eventName = chaiUtils.flag(context, "eventName");
161+
if (logs.length === 1) {
162+
const parsedLog = (
163+
chaiUtils.flag(context, "contract").interface as Interface
164+
).parseLog(logs[0]);
165+
assertIsNotNull(parsedLog, "parsedLog");
166+
169167
return assertArgsArraysEqual(
170-
context,
171168
Assertion,
172-
chaiUtils,
173169
expectedArgs,
174-
logs[0],
170+
parsedLog.args,
171+
"event",
172+
eventName,
175173
assert,
176174
ssfi
177175
);
176+
}
178177
for (const index in logs) {
179178
if (index === undefined) {
180179
break;
181180
} else {
182181
try {
182+
const parsedLog = (
183+
chaiUtils.flag(context, "contract").interface as Interface
184+
).parseLog(logs[index]);
185+
assertIsNotNull(parsedLog, "parsedLog");
186+
183187
assertArgsArraysEqual(
184-
context,
185188
Assertion,
186-
chaiUtils,
187189
expectedArgs,
188-
logs[index],
190+
parsedLog.args,
191+
"event",
192+
eventName,
189193
assert,
190194
ssfi
191195
);
192196
return;
193197
} catch {}
194198
}
195199
}
196-
const eventName = chaiUtils.flag(context, "eventName");
200+
197201
assert(
198202
false,
199203
`The specified arguments (${util.inspect(

packages/hardhat-chai-matchers/src/internal/reverted/revertedWithCustomError.ts

+14-46
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import type EthersT from "ethers";
22

3-
import ordinal from "ordinal";
4-
53
import {
64
ASSERTION_ABORTED,
75
REVERTED_WITH_CUSTOM_ERROR_MATCHER,
86
} from "../constants";
9-
import { assertIsNotNull, preventAsyncMatcherChaining } from "../utils";
7+
import {
8+
assertArgsArraysEqual,
9+
assertIsNotNull,
10+
preventAsyncMatcherChaining,
11+
} from "../utils";
1012
import { buildAssert, Ssfi } from "../../utils";
1113
import {
1214
decodeReturnData,
@@ -186,7 +188,7 @@ function validateInput(
186188
export async function revertedWithCustomErrorWithArgs(
187189
context: any,
188190
Assertion: Chai.AssertionStatic,
189-
_utils: Chai.ChaiUtils,
191+
chaiUtils: Chai.ChaiUtils,
190192
expectedArgs: any[],
191193
ssfi: Ssfi
192194
) {
@@ -212,47 +214,13 @@ export async function revertedWithCustomErrorWithArgs(
212214
contractInterface.decodeErrorResult(errorFragment, returnData)
213215
);
214216

215-
new Assertion(actualArgs).to.have.same.length(
216-
expectedArgs.length,
217-
`expected ${expectedArgs.length} args but got ${actualArgs.length}`
217+
assertArgsArraysEqual(
218+
Assertion,
219+
expectedArgs,
220+
actualArgs,
221+
"custom error",
222+
customError.name,
223+
assert,
224+
ssfi
218225
);
219-
220-
for (const [i, actualArg] of actualArgs.entries()) {
221-
const expectedArg = expectedArgs[i];
222-
if (typeof expectedArg === "function") {
223-
const errorPrefix = `The predicate for the ${ordinal(
224-
i + 1
225-
)} custom error argument`;
226-
try {
227-
if (expectedArg(actualArg) === true) continue;
228-
} catch (e: any) {
229-
assert(
230-
false,
231-
`${errorPrefix} threw when called: ${e.message}`
232-
// no need for a negated message, since we disallow mixing .not. with
233-
// .withArgs
234-
);
235-
}
236-
assert(
237-
false,
238-
`${errorPrefix} returned false`
239-
// no need for a negated message, since we disallow mixing .not. with
240-
// .withArgs
241-
);
242-
} else if (Array.isArray(expectedArg)) {
243-
const expectedLength = expectedArg.length;
244-
const actualLength = actualArg.length;
245-
assert(
246-
expectedLength === actualLength,
247-
`Expected the ${ordinal(i + 1)} argument of the "${
248-
customError.name
249-
}" custom error to have ${expectedLength} ${
250-
expectedLength === 1 ? "element" : "elements"
251-
}, but it has ${actualLength}`
252-
);
253-
new Assertion(actualArg).to.deep.equal(expectedArg);
254-
} else {
255-
new Assertion(actualArg).to.equal(expectedArg);
256-
}
257-
}
258226
}

packages/hardhat-chai-matchers/src/internal/utils.ts

+84
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import type EthersT from "ethers";
2+
import ordinal from "ordinal";
3+
import { AssertWithSsfi, Ssfi } from "../utils";
14
import { PREVIOUS_MATCHER_NAME } from "./constants";
25
import {
36
HardhatChaiMatchersAssertionError,
@@ -40,3 +43,84 @@ export function preventAsyncMatcherChaining(
4043
previousMatcherName
4144
);
4245
}
46+
47+
export function assertArgsArraysEqual(
48+
Assertion: Chai.AssertionStatic,
49+
expectedArgs: any[],
50+
actualArgs: any[],
51+
tag: string,
52+
name: string,
53+
assert: AssertWithSsfi,
54+
ssfi: Ssfi
55+
) {
56+
const ethers = require("ethers") as typeof EthersT;
57+
assert(
58+
actualArgs.length === expectedArgs.length,
59+
`Expected "${name}" ${tag} to have ${expectedArgs.length} argument(s), but it has ${actualArgs.length}`
60+
);
61+
for (const [index, expectedArg] of expectedArgs.entries()) {
62+
const actualArg = actualArgs[index];
63+
if (typeof expectedArg === "function") {
64+
const errorPrefix = `The predicate for the ${ordinal(
65+
index + 1
66+
)} ${tag} argument`;
67+
try {
68+
if (expectedArg(actualArg) === true) continue;
69+
} catch (e: any) {
70+
assert(
71+
false,
72+
`${errorPrefix} threw when called: ${e.message}`
73+
// no need for a negated message, since we disallow mixing .not. with
74+
// .withArgs
75+
);
76+
}
77+
assert(
78+
false,
79+
`${errorPrefix} did not return true `
80+
// no need for a negated message, since we disallow mixing .not. with
81+
// .withArgs
82+
);
83+
} else if (expectedArg instanceof Uint8Array) {
84+
new Assertion(actualArg, undefined, ssfi, true).equal(
85+
ethers.hexlify(expectedArg)
86+
);
87+
} else if (
88+
expectedArg?.length !== undefined &&
89+
typeof expectedArg !== "string"
90+
) {
91+
const expectedLength = expectedArg.length;
92+
const actualLength = actualArg.length;
93+
assert(
94+
expectedLength === actualLength,
95+
`Expected the ${ordinal(
96+
index + 1
97+
)} argument of the "${name}" ${tag} to have ${expectedLength} ${
98+
expectedLength === 1 ? "element" : "elements"
99+
}, but it has ${actualLength}`
100+
);
101+
102+
for (let j = 0; j < expectedArg.length; j++) {
103+
new Assertion(actualArg[j], undefined, ssfi, true).equal(
104+
expectedArg[j]
105+
);
106+
}
107+
} else {
108+
if (actualArg.hash !== undefined && actualArg._isIndexed === true) {
109+
new Assertion(actualArg.hash, undefined, ssfi, true).to.not.equal(
110+
expectedArg,
111+
"The actual value was an indexed and hashed value of the event argument. The expected value provided to the assertion should be the actual event argument (the pre-image of the hash). You provided the hash itself. Please supply the actual event argument (the pre-image of the hash) instead."
112+
);
113+
const expectedArgBytes = ethers.isHexString(expectedArg)
114+
? ethers.getBytes(expectedArg)
115+
: ethers.toUtf8Bytes(expectedArg);
116+
const expectedHash = ethers.keccak256(expectedArgBytes);
117+
new Assertion(actualArg.hash, undefined, ssfi, true).to.equal(
118+
expectedHash,
119+
`The actual value was an indexed and hashed value of the event argument. The expected value provided to the assertion was hashed to produce ${expectedHash}. The actual hash and the expected hash did not match`
120+
);
121+
} else {
122+
new Assertion(actualArg, undefined, ssfi, true).equal(expectedArg);
123+
}
124+
}
125+
}
126+
}

0 commit comments

Comments
 (0)