Skip to content

Commit

Permalink
🌶 Support structs in events for withArgs matcher (#751)
Browse files Browse the repository at this point in the history
* Remove Chai AssertionError for emit withArgs(nestedStruct)

* Rename parametr

* Rename variables

* Change pragma solidity version

* Fix test name

* Add changeset

* Remove typo

* Fix alphanumeric keys

* Linting

* Update .changeset/silver-masks-compete.md

Co-authored-by: Przemyslaw Rzad <roopert7@gmail.com>
  • Loading branch information
jakvbs and rzadp committed Jul 8, 2022
1 parent 9d3a171 commit b9af4f0
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/silver-masks-compete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ethereum-waffle/chai": patch
---

Support structs in events for withArgs matcher
27 changes: 27 additions & 0 deletions waffle-chai/src/matchers/withArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ export function supportWithArgs(Assertion: Chai.AssertionStatic) {
[expectedArgs[index], utils.keccak256(expectedArgBytes)]
);
} else {
if (isStruct(actualArgs[index])) {
new Assertion(
convertStructToPlainObject(actualArgs[index])
).to.deep.equal(expectedArgs[index]);
return;
}
new Assertion(actualArgs[index]).equal(expectedArgs[index]);
}
}
Expand All @@ -68,6 +74,27 @@ export function supportWithArgs(Assertion: Chai.AssertionStatic) {
);
};

const isStruct = (arr: any[]) => {
if (!Array.isArray(arr)) return false;
const keys = Object.keys(arr);
const hasAlphaNumericKeys = keys.some((key) => key.match(/^[a-zA-Z0-9]*[a-zA-Z]+[a-zA-Z0-9]*$/));
const hasNumericKeys = keys.some((key) => key.match(/^\d+$/));
return hasAlphaNumericKeys && hasNumericKeys;
};

const convertStructToPlainObject = (struct: any[]): any => {
const keys = Object.keys(struct).filter((key: any) => isNaN(key));
return keys.reduce(
(acc: any, key: any) => ({
...acc,
[key]: isStruct(struct[key])
? convertStructToPlainObject(struct[key])
: struct[key]
}),
{}
);
};

Assertion.addMethod('withArgs', function (this: any, ...expectedArgs: any[]) {
if (!('txMatcher' in this) || !('callPromise' in this)) {
throw new Error('withArgs() must be used after emit() or revertedWith()');
Expand Down
50 changes: 47 additions & 3 deletions waffle-chai/test/contracts/Events.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
export const EVENTS_SOURCE = `
pragma solidity ^0.6.0;
pragma solidity ^0.8.0;
contract Events {
event One(uint value, string msg, bytes32 encoded);
event Two(uint indexed value, string msg);
event Index(string indexed msgHashed, string msg, bytes bmsg, bytes indexed bmsgHash, bytes32 indexed encoded);
event Arrays(uint256[3] value, bytes32[2] encoded);
event Struct(Task task);
event NestedStruct(Nested nested);
struct Task {
bytes32 hash;
uint value;
bytes32[2] encoded;
}
struct Nested {
bytes32 hash;
uint value;
Task task;
}
function emitOne() public {
emit One(1, "One", 0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123);
Expand Down Expand Up @@ -58,6 +72,32 @@ pragma solidity ^0.6.0;
function doNotEmit() pure public {
}
function emitStruct() public {
emit Struct(Task(
0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123,
1,
[
bytes32(0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123),
bytes32(0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162124)
]
));
}
function emitNestedStruct() public {
emit NestedStruct(Nested(
0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123,
1,
Task(
0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123,
1,
[
bytes32(0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162123),
bytes32(0x00cFBbaF7DDB3a1476767101c12a0162e241fbAD2a0162e2410cFBbaF7162124)
]
)
));
}
}
`;

Expand All @@ -66,6 +106,8 @@ export const EVENTS_ABI = [
'event Two(uint indexed value, string msg)',
'event Index(string indexed msgHashed, string msg, bytes bmsg, bytes indexed bmsgHash, bytes32 indexed encoded)',
'event Arrays(uint256[3] value, bytes32[2] encoded)',
'event Struct((bytes32 hash, uint value, bytes32[2] encoded) task)',
'event NestedStruct((bytes32 hash, uint value, (bytes32 hash, uint value, bytes32[2] encoded) task) nested)',
'function emitOne() public',
'function emitOneMultipleTimes() public',
'function emitTwo() public',
Expand All @@ -74,8 +116,10 @@ export const EVENTS_ABI = [
'function emitArrays() public',
'function doNotEmit() pure public',
'function emitNested() public',
'function _emitInternal() internal'
'function _emitInternal() internal',
'function emitStruct() public',
'function emitNestedStruct() public'
];

// eslint-disable-next-line max-len
export const EVENTS_BYTECODE = '608060405234801561001057600080fd5b50610862806100206000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063b2f998381161005b578063b2f99838146100b5578063baa4c5ef146100bf578063d5eacee0146100c9578063db6cdf68146100d357610088565b806334c101151461008d5780633f0e64ba1461009757806377f3094b146100a1578063a35a3a0d146100ab575b600080fd5b6100956100dd565b005b61009f610149565b005b6100a96101e6565b005b6100b36103e1565b005b6100bd6104e7565b005b6100c761069b565b005b6100d16106a5565b005b6100db61078d565b005b60027f726d8d77432fef0b8999b8e1f5ed6d11c42c0a861c61228b03e767ad3c43d0df6040518080602001828103825260038152602001807f54776f000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390a2565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a1565b7ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b6040518060400160405280600581526020017f54687265650000000000000000000000000000000000000000000000000000008152506040518082805190602001908083835b60208310610272578051825260208201915060208101905060208303925061024f565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060405180807f5468726565000000000000000000000000000000000000000000000000000000815250600501905060405180910390207f2c0160d31a12563decf7b38f40fd0fab153ae9c20f87643b7fb747e3f0e4c93f6040518060400160405280600581526020017f5468726565000000000000000000000000000000000000000000000000000000815250604051808060200180602001838103835260058152602001807f5468726565000000000000000000000000000000000000000000000000000000815250602001838103825284818151815260200191508051906020019080838360005b838110156103a4578082015181840152602081019050610389565b50505050905090810190601f1680156103d15780820380516001836020036101000a031916815260200191505b50935050505060405180910390a4565b7f35cf379c46b4950eedc35bc96d30e9fe7480e2422431c50ea5c4b211ee6b1b8d60405180606001604052806001815260200160028152602001600381525060405180604001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212460001b8152506040518083600360200280838360005b838110156104a4578082015181840152602081019050610489565b5050505090500182600260200280838360005b838110156104d25780820151818401526020810190506104b7565b505050509050019250505060405180910390a1565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a17f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a17f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60018060405180838152602001806020018360001b8152602001828103825260128152602001807f446966666572656e744b696e644f664f6e650000000000000000000000000000815250602001935050505060405180910390a1565b6106a361078f565b565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60018060405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a160027f726d8d77432fef0b8999b8e1f5ed6d11c42c0a861c61228b03e767ad3c43d0df6040518080602001828103825260038152602001807f54776f000000000000000000000000000000000000000000000000000000000081525060200191505060405180910390a2565b565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405180838152602001806020018360001b8152602001828103825260038152602001807f4f6e650000000000000000000000000000000000000000000000000000000000815250602001935050505060405180910390a156fea26469706673582212208a01fcb12fd6c96d5813c2d16a13edf495b5261a585830072215df30f387ceeb64736f6c63430006000033';
export const EVENTS_BYTECODE = '608060405234801561001057600080fd5b50610e3a806100206000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c8063b2f9983811610066578063b2f99838146100d5578063baa4c5ef146100df578063d5eacee0146100e9578063db6cdf68146100f3578063ec168af5146100fd5761009e565b806334c10115146100a35780633f0e64ba146100ad57806377f3094b146100b75780639c75eefb146100c1578063a35a3a0d146100cb575b600080fd5b6100ab610107565b005b6100b5610140565b005b6100bf61019b565b005b6100c961028b565b005b6100d3610359565b005b6100dd610409565b005b6100e76104f7565b005b6100f1610501565b005b6100fb610574565b005b610105610576565b005b60027f726d8d77432fef0b8999b8e1f5ed6d11c42c0a861c61228b03e767ad3c43d0df60405161013690610739565b60405180910390a2565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123604051610191929190610846565b60405180910390a1565b7ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b6040518060400160405280600581526020017f546872656500000000000000000000000000000000000000000000000000000081525060405161020191906108fc565b60405180910390206040516102159061096a565b60405180910390207f2c0160d31a12563decf7b38f40fd0fab153ae9c20f87643b7fb747e3f0e4c93f6040518060400160405280600581526020017f546872656500000000000000000000000000000000000000000000000000000081525060405161028191906109fd565b60405180910390a4565b7f88af697807fb5575334776b551b779d8a0b7114db2b5077d73bb6f608caa313c60405180606001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020016001815260200160405180604001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212460001b81525081525060405161034f9190610b2e565b60405180910390a1565b7f35cf379c46b4950eedc35bc96d30e9fe7480e2422431c50ea5c4b211ee6b1b8d60405180606001604052806001815260200160028152602001600381525060405180604001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212460001b8152506040516103ff929190610c47565b60405180910390a1565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360405161045a929190610846565b60405180910390a17f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf71621236040516104b3929190610846565b60405180910390a17f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c6001806040516104ed929190610ced565b60405180910390a1565b6104ff610681565b565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c600180604051610533929190610d29565b60405180910390a160027f726d8d77432fef0b8999b8e1f5ed6d11c42c0a861c61228b03e767ad3c43d0df60405161056a90610739565b60405180910390a2565b565b7f24ddd153a6146efa8103ad88564854b506eca37f3c52bdb18fdf3416dfa19d1360405180606001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020016001815260200160405180606001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020016001815260200160405180604001604052807ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212360001b81526020017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf716212460001b8152508152508152506040516106779190610de9565b60405180910390a1565b7f824e7918d5bcff68837d677d05258e17ec7b1bd7b488aa5e3bd2d5cbefa9e04c60017ecfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf71621236040516106d2929190610846565b60405180910390a1565b600082825260208201905092915050565b7f54776f0000000000000000000000000000000000000000000000000000000000600082015250565b60006107236003836106dc565b915061072e826106ed565b602082019050919050565b6000602082019050818103600083015261075281610716565b9050919050565b6000819050919050565b6000819050919050565b6000819050919050565b600061079261078d61078884610759565b61076d565b610763565b9050919050565b6107a281610777565b82525050565b7f4f6e650000000000000000000000000000000000000000000000000000000000600082015250565b60006107de6003836106dc565b91506107e9826107a8565b602082019050919050565b6000819050919050565b6000819050919050565b60008160001b9050919050565b600061083061082b610826846107f4565b610808565b6107fe565b9050919050565b61084081610815565b82525050565b600060608201905061085b6000830185610799565b818103602083015261086c816107d1565b905061087b6040830184610837565b9392505050565b600081519050919050565b600081905092915050565b60005b838110156108b657808201518184015260208101905061089b565b838111156108c5576000848401525b50505050565b60006108d682610882565b6108e0818561088d565b93506108f0818560208601610898565b80840191505092915050565b600061090882846108cb565b915081905092915050565b600081905092915050565b7f5468726565000000000000000000000000000000000000000000000000000000600082015250565b6000610954600583610913565b915061095f8261091e565b600582019050919050565b600061097582610947565b9150819050919050565b600061098c6005836106dc565b91506109978261091e565b602082019050919050565b600082825260208201905092915050565b6000601f19601f8301169050919050565b60006109cf82610882565b6109d981856109a2565b93506109e9818560208601610898565b6109f2816109b3565b840191505092915050565b60006040820190508181036000830152610a168161097f565b90508181036020830152610a2a81846109c4565b905092915050565b610a3b816107fe565b82525050565b610a4a81610763565b82525050565b600060029050919050565b600081905092915050565b6000819050919050565b6000610a7c8383610a32565b60208301905092915050565b6000602082019050919050565b610a9e81610a50565b610aa88184610a5b565b9250610ab382610a66565b8060005b83811015610ae4578151610acb8782610a70565b9650610ad683610a88565b925050600181019050610ab7565b505050505050565b608082016000820151610b026000850182610a32565b506020820151610b156020850182610a41565b506040820151610b286040850182610a95565b50505050565b6000608082019050610b436000830184610aec565b92915050565b600060039050919050565b600081905092915050565b6000819050919050565b6000610b758383610a41565b60208301905092915050565b6000602082019050919050565b610b9781610b49565b610ba18184610b54565b9250610bac82610b5f565b8060005b83811015610bdd578151610bc48782610b69565b9650610bcf83610b81565b925050600181019050610bb0565b505050505050565b600081905092915050565b610bf981610a50565b610c038184610be5565b9250610c0e82610a66565b8060005b83811015610c3f578151610c268782610a70565b9650610c3183610a88565b925050600181019050610c12565b505050505050565b600060a082019050610c5c6000830185610b8e565b610c696060830184610bf0565b9392505050565b7f446966666572656e744b696e644f664f6e650000000000000000000000000000600082015250565b6000610ca66012836106dc565b9150610cb182610c70565b602082019050919050565b6000610cd7610cd2610ccd84610759565b610808565b6107fe565b9050919050565b610ce781610cbc565b82525050565b6000606082019050610d026000830185610799565b8181036020830152610d1381610c99565b9050610d226040830184610cde565b9392505050565b6000606082019050610d3e6000830185610799565b8181036020830152610d4f816107d1565b9050610d5e6040830184610cde565b9392505050565b608082016000820151610d7b6000850182610a32565b506020820151610d8e6020850182610a41565b506040820151610da16040850182610a95565b50505050565b60c082016000820151610dbd6000850182610a32565b506020820151610dd06020850182610a41565b506040820151610de36040850182610d65565b50505050565b600060c082019050610dfe6000830184610da7565b9291505056fea2646970667358221220f8b514d0f235d497ef41cb23be8705ea2d1e301573a1be093b353512357b88c764736f6c634300080f0033';
51 changes: 51 additions & 0 deletions waffle-chai/test/matchers/eventsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,5 +467,56 @@ export const eventsTest = (provider: TestProvider) => {
.to.emit(events, 'One')
.and.not.to.emit(differentEvents, 'One');
});

it('Emit struct: success', async () => {
const struct = {
hash: '0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
value: BigNumber.from(1),
encoded: [
'0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
'0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162124'
]
};
await expect(events.emitStruct())
.to.emit(events, 'Struct')
.withArgs(struct);
});

it('Emit struct: fail', async () => {
await expect(
expect(events.emitStruct()).to.emit(events, 'One')
).to.be.eventually.rejectedWith(
AssertionError,
'Expected event "One" to be emitted, but it wasn\'t'
);
});

it('Emit nested struct: success', async () => {
const struct = {
hash: '0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
value: BigNumber.from(1),
encoded: [
'0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
'0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162124'
]
};
const nestedStruct = {
hash: '0x00cfbbaf7ddb3a1476767101c12a0162e241fbad2a0162e2410cfbbaf7162123',
value: BigNumber.from(1),
task: struct
};
await expect(events.emitNestedStruct())
.to.emit(events, 'NestedStruct')
.withArgs(nestedStruct);
});

it('Emit nested struct: fail', async () => {
await expect(
expect(events.emitNestedStruct()).to.emit(events, 'One')
).to.be.eventually.rejectedWith(
AssertionError,
'Expected event "One" to be emitted, but it wasn\'t'
);
});
});
};

0 comments on commit b9af4f0

Please sign in to comment.