forked from foundry-rs/foundry
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExpectEmit.t.sol
More file actions
462 lines (384 loc) · 14.7 KB
/
Copy pathExpectEmit.t.sol
File metadata and controls
462 lines (384 loc) · 14.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.18;
import "ds-test/test.sol";
import "cheats/Vm.sol";
contract Emitter {
uint256 public thing;
event Something(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, uint256 data);
event A(uint256 indexed topic1);
event B(uint256 indexed topic1);
event C(uint256 indexed topic1);
event D(uint256 indexed topic1);
event E(uint256 indexed topic1);
/// This event has 0 indexed topics, but the one in our tests
/// has exactly one indexed topic. Even though both of these
/// events have the same topic 0, they are different and should
/// be non-comparable.
///
/// Ref: issue #760
event SomethingElse(uint256 data);
event SomethingNonIndexed(uint256 data);
function emitEvent(uint256 topic1, uint256 topic2, uint256 topic3, uint256 data) public {
emit Something(topic1, topic2, topic3, data);
}
function emitNEvents(uint256 topic1, uint256 topic2, uint256 topic3, uint256 data, uint256 n) public {
for (uint256 i = 0; i < n; i++) {
emit Something(topic1, topic2, topic3, data);
}
}
function emitMultiple(
uint256[2] memory topic1,
uint256[2] memory topic2,
uint256[2] memory topic3,
uint256[2] memory data
) public {
emit Something(topic1[0], topic2[0], topic3[0], data[0]);
emit Something(topic1[1], topic2[1], topic3[1], data[1]);
}
function emitAndNest() public {
emit Something(1, 2, 3, 4);
emitNested(Emitter(address(this)), 1, 2, 3, 4);
}
function emitOutOfExactOrder() public {
emit SomethingNonIndexed(1);
emit Something(1, 2, 3, 4);
emit Something(1, 2, 3, 4);
emit Something(1, 2, 3, 4);
}
function emitNested(Emitter inner, uint256 topic1, uint256 topic2, uint256 topic3, uint256 data) public {
inner.emitEvent(topic1, topic2, topic3, data);
}
function getVar() public view returns (uint256) {
return 1;
}
/// Used to test matching of consecutive different events,
/// even if they're not emitted right after the other.
function emitWindow() public {
emit A(1);
emit B(2);
emit C(3);
emit D(4);
emit E(5);
}
function emitNestedWindow() public {
emit A(1);
emit C(3);
emit E(5);
this.emitWindow();
}
// Used to test matching of consecutive different events
// split across subtree calls.
function emitSplitWindow() public {
this.emitWindow();
this.emitWindow();
}
function emitWindowAndOnTest(ExpectEmitTest t) public {
this.emitWindow();
t.emitLocal();
}
/// Ref: issue #1214
function doesNothing() public pure {}
function changeThing(uint256 num) public {
thing = num;
}
/// Ref: issue #760
function emitSomethingElse(uint256 data) public {
emit SomethingElse(data);
}
}
/// Emulates `Emitter` in #760
contract LowLevelCaller {
function f() external {
address(this).call(abi.encodeWithSignature("g()"));
}
function g() public {}
}
contract ExpectEmitTest is DSTest {
Vm constant vm = Vm(HEVM_ADDRESS);
Emitter emitter;
event Something(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, uint256 data);
event SomethingElse(uint256 indexed topic1);
event SomethingNonIndexed(uint256 data);
event A(uint256 indexed topic1);
event B(uint256 indexed topic1);
event C(uint256 indexed topic1);
event D(uint256 indexed topic1);
event E(uint256 indexed topic1);
function setUp() public {
emitter = new Emitter();
}
function emitLocal() public {
emit A(1);
}
/// The topics that are not checked are altered to be incorrect
/// compared to the reference.
function testExpectEmit(
bool checkTopic1,
bool checkTopic2,
bool checkTopic3,
bool checkData,
uint128 topic1,
uint128 topic2,
uint128 topic3,
uint128 data
) public {
uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) : uint256(topic1) + 1;
uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) : uint256(topic2) + 1;
uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) : uint256(topic3) + 1;
uint256 transformedData = checkData ? uint256(data) : uint256(data) + 1;
vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);
emit Something(topic1, topic2, topic3, data);
emitter.emitEvent(transformedTopic1, transformedTopic2, transformedTopic3, transformedData);
}
/// The topics that are checked are altered to be incorrect
/// compared to the reference.
function testExpectEmitNested(
bool checkTopic1,
bool checkTopic2,
bool checkTopic3,
bool checkData,
uint128 topic1,
uint128 topic2,
uint128 topic3,
uint128 data
) public {
Emitter inner = new Emitter();
uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) : uint256(topic1) + 1;
uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) : uint256(topic2) + 1;
uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) : uint256(topic3) + 1;
uint256 transformedData = checkData ? uint256(data) : uint256(data) + 1;
vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);
emit Something(topic1, topic2, topic3, data);
emitter.emitNested(inner, transformedTopic1, transformedTopic2, transformedTopic3, transformedData);
}
function testExpectEmitMultiple() public {
vm.expectEmit();
emit Something(1, 2, 3, 4);
vm.expectEmit();
emit Something(5, 6, 7, 8);
emitter.emitMultiple(
[uint256(1), uint256(5)], [uint256(2), uint256(6)], [uint256(3), uint256(7)], [uint256(4), uint256(8)]
);
}
function testExpectedEmitMultipleNested() public {
vm.expectEmit();
emit Something(1, 2, 3, 4);
vm.expectEmit();
emit Something(1, 2, 3, 4);
emitter.emitAndNest();
}
function testExpectEmitMultipleWithArgs() public {
vm.expectEmit(true, true, true, true);
emit Something(1, 2, 3, 4);
vm.expectEmit(true, true, true, true);
emit Something(5, 6, 7, 8);
emitter.emitMultiple(
[uint256(1), uint256(5)], [uint256(2), uint256(6)], [uint256(3), uint256(7)], [uint256(4), uint256(8)]
);
}
function testExpectEmitCanMatchWithoutExactOrder() public {
vm.expectEmit(true, true, true, true);
emit Something(1, 2, 3, 4);
vm.expectEmit(true, true, true, true);
emit Something(1, 2, 3, 4);
emitter.emitOutOfExactOrder();
}
function testExpectEmitCanMatchWithoutExactOrder2() public {
vm.expectEmit(true, true, true, true);
emit SomethingNonIndexed(1);
vm.expectEmit(true, true, true, true);
emit Something(1, 2, 3, 4);
emitter.emitOutOfExactOrder();
}
function testExpectEmitAddress() public {
vm.expectEmit(address(emitter));
emit Something(1, 2, 3, 4);
emitter.emitEvent(1, 2, 3, 4);
}
function testExpectEmitAddressWithArgs() public {
vm.expectEmit(true, true, true, true, address(emitter));
emit Something(1, 2, 3, 4);
emitter.emitEvent(1, 2, 3, 4);
}
function testCanDoStaticCall() public {
vm.expectEmit(true, true, true, true);
emit Something(emitter.getVar(), 2, 3, 4);
emitter.emitEvent(1, 2, 3, 4);
}
/// Tests for additive behavior.
// As long as we match the event we want in order, it doesn't matter which events are emitted afterwards.
function testAdditiveBehavior() public {
vm.expectEmit(true, true, true, true, address(emitter));
emit Something(1, 2, 3, 4);
emitter.emitMultiple(
[uint256(1), uint256(5)], [uint256(2), uint256(6)], [uint256(3), uint256(7)], [uint256(4), uint256(8)]
);
}
/// emitWindow() emits events A, B, C, D, E.
/// We should be able to match [A, B, C, D, E] in the correct order.
function testCanMatchConsecutiveEvents() public {
vm.expectEmit(true, false, false, true);
emit A(1);
vm.expectEmit(true, false, false, true);
emit B(2);
vm.expectEmit(true, false, false, true);
emit C(3);
vm.expectEmit(true, false, false, true);
emit D(4);
vm.expectEmit(true, false, false, true);
emit E(5);
emitter.emitWindow();
}
/// emitWindow() emits events A, B, C, D, E.
/// We should be able to match [A, C, E], as they're in the right order,
/// even if they're not consecutive.
function testCanMatchConsecutiveEventsSkipped() public {
vm.expectEmit(true, false, false, true);
emit A(1);
vm.expectEmit(true, false, false, true);
emit C(3);
vm.expectEmit(true, false, false, true);
emit E(5);
emitter.emitWindow();
}
/// emitWindow() emits events A, B, C, D, E.
/// We should be able to match [C, E], as they're in the right order,
/// even if they're not consecutive.
function testCanMatchConsecutiveEventsSkipped2() public {
vm.expectEmit(true, false, false, true);
emit C(3);
vm.expectEmit(true, false, false, true);
emit E(5);
emitter.emitWindow();
}
/// emitWindow() emits events A, B, C, D, E.
/// We should be able to match [C], as it's contained in the events emitted,
/// even if we don't match the previous or following ones.
function testCanMatchSingleEventFromConsecutive() public {
vm.expectEmit(true, false, false, true);
emit C(3);
emitter.emitWindow();
}
/// emitWindowNested() emits events A, C, E, A, B, C, D, E, the last 5 on an external call.
/// We should be able to match the whole event sequence in order no matter if the events
/// were emitted deeper into the call tree.
function testCanMatchConsecutiveNestedEvents() public {
vm.expectEmit(true, false, false, true);
emit A(1);
vm.expectEmit(true, false, false, true);
emit C(3);
vm.expectEmit(true, false, false, true);
emit E(5);
vm.expectEmit(true, false, false, true);
emit A(1);
vm.expectEmit(true, false, false, true);
emit B(2);
vm.expectEmit(true, false, false, true);
emit C(3);
vm.expectEmit(true, false, false, true);
emit D(4);
vm.expectEmit(true, false, false, true);
emit E(5);
emitter.emitNestedWindow();
}
/// emitSplitWindow() emits events [[A, B, C, D, E], [A, B, C, D, E]]. Essentially, in an external call,
/// it emits the sequence of events twice at the same depth.
/// We should be able to match [A, A, B, C, D, E] as it's all in the next call, no matter
/// if they're emitted on subcalls at the same depth (but with correct ordering).
function testCanMatchConsecutiveSubtreeEvents() public {
vm.expectEmit(true, false, false, true);
emit A(1);
vm.expectEmit(true, false, false, true);
emit A(1);
vm.expectEmit(true, false, false, true);
emit B(2);
vm.expectEmit(true, false, false, true);
emit C(3);
vm.expectEmit(true, false, false, true);
emit D(4);
vm.expectEmit(true, false, false, true);
emit E(5);
emitter.emitSplitWindow();
}
/// emitWindowNested() emits events A, C, E, A, B, C, D, E, the last 5 on an external call.
/// We should be able to match [A, C, E, A, C, E] in that order, as these are emitted twice.
function testCanMatchRepeatedEvents() public {
vm.expectEmit(true, false, false, true);
emit A(1);
vm.expectEmit(true, false, false, true);
emit C(3);
vm.expectEmit(true, false, false, true);
emit E(5);
vm.expectEmit(true, false, false, true);
emit A(1);
vm.expectEmit(true, false, false, true);
emit C(3);
vm.expectEmit(true, false, false, true);
emit E(5);
emitter.emitNestedWindow();
}
/// emitWindowAndOnTest emits [[A, B, C, D, E], [A]]. The interesting bit is that the
/// second call that emits [A] is on this same contract. We should still be able to match
/// [A, A] as the call made to this contract is still external.
function testEmitWindowAndOnTest() public {
vm.expectEmit(true, false, false, true);
emit A(1);
vm.expectEmit(true, false, false, true);
emit A(1);
emitter.emitWindowAndOnTest(this);
}
/// This test will fail if we check that all expected logs were emitted
/// after every call from the same depth as the call that invoked the cheatcode.
///
/// Expected emits should only be checked when the call from which the cheatcode
/// was invoked ends.
///
/// Ref: issue #1214
/// NOTE: This is now invalid behavior.
// function testExpectEmitIsCheckedWhenCurrentCallTerminates() public {
// vm.expectEmit(true, true, true, true);
// emitter.doesNothing();
// emit Something(1, 2, 3, 4);
// // This should fail since `SomethingElse` in the test
// // and in the `Emitter` contract have differing
// // amounts of indexed topics.
// emitter.emitEvent(1, 2, 3, 4);
// }
}
contract ExpectEmitCountTest is DSTest {
Vm constant vm = Vm(HEVM_ADDRESS);
Emitter emitter;
event Something(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, uint256 data);
function setUp() public {
emitter = new Emitter();
}
function testCountNoEmit() public {
vm.expectEmit(0);
emit Something(1, 2, 3, 4);
emitter.doesNothing();
}
function testCountNEmits() public {
uint64 count = 2;
vm.expectEmit(count);
emit Something(1, 2, 3, 4);
emitter.emitNEvents(1, 2, 3, 4, count);
}
function testCountMoreEmits() public {
uint64 count = 2;
vm.expectEmit(count);
emit Something(1, 2, 3, 4);
emitter.emitNEvents(1, 2, 3, 4, count + 1);
}
/// Test zero emits from a specific address (emitter).
function testCountNoEmitFromAddress() public {
vm.expectEmit(address(emitter), 0);
emit Something(1, 2, 3, 4);
emitter.doesNothing();
}
function testCountEmitsFromAddress() public {
uint64 count = 2;
vm.expectEmit(address(emitter), count);
emit Something(1, 2, 3, 4);
emitter.emitNEvents(1, 2, 3, 4, count);
}
}