Skip to content

Commit f052dda

Browse files
committed
test coverage for reader getEvents
1 parent dd7cd7f commit f052dda

File tree

1 file changed

+265
-0
lines changed

1 file changed

+265
-0
lines changed

tests/reader.spec.ts

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
import { expect } from 'chai';
2+
import { BigNumber } from '../src/utils/numerics';
3+
import Reader from '../src/contracts-api/Reader';
4+
import { Contracts } from '../src/contracts-api/Contracts';
5+
import {
6+
EncodedStrategy,
7+
TradeData,
8+
TradingFeeUpdate,
9+
} from '../src/common/types';
10+
11+
describe('Reader', () => {
12+
let reader: Reader;
13+
let mockContracts: Contracts;
14+
15+
const mockEncodedStrategy: EncodedStrategy = {
16+
id: BigNumber.from(1),
17+
token0: '0x123',
18+
token1: '0x456',
19+
order0: {
20+
y: BigNumber.from(100),
21+
z: BigNumber.from(200),
22+
A: BigNumber.from(300),
23+
B: BigNumber.from(400),
24+
},
25+
order1: {
26+
y: BigNumber.from(500),
27+
z: BigNumber.from(600),
28+
A: BigNumber.from(700),
29+
B: BigNumber.from(800),
30+
},
31+
};
32+
33+
const mockTradeData: TradeData = {
34+
trader: '0x789',
35+
sourceToken: '0x123',
36+
targetToken: '0x456',
37+
sourceAmount: '1000',
38+
targetAmount: '2000',
39+
tradingFeeAmount: '10',
40+
byTargetAmount: true,
41+
};
42+
43+
const mockTradingFeeUpdate: TradingFeeUpdate = ['0x123', '0x456', 100];
44+
45+
beforeEach(() => {
46+
// Create mock contracts with necessary methods
47+
mockContracts = {
48+
carbonController: {
49+
address: '0x123',
50+
interface: {
51+
parseLog: (log: { topics: string[]; data: string }) => {
52+
// Mock event parsing based on topics
53+
const eventType = log.topics[0];
54+
switch (eventType) {
55+
case '0x123': // StrategyCreated
56+
return {
57+
name: 'StrategyCreated',
58+
args: mockEncodedStrategy,
59+
};
60+
case '0x456': // TokensTraded
61+
return {
62+
name: 'TokensTraded',
63+
args: mockTradeData,
64+
};
65+
case '0x789': // TradingFeePPMUpdated
66+
return {
67+
name: 'TradingFeePPMUpdated',
68+
args: { newFeePPM: 100 },
69+
};
70+
case '0xabc': // PairTradingFeePPMUpdated
71+
return {
72+
name: 'PairTradingFeePPMUpdated',
73+
args: {
74+
token0: mockTradingFeeUpdate[0],
75+
token1: mockTradingFeeUpdate[1],
76+
newFeePPM: mockTradingFeeUpdate[2],
77+
},
78+
};
79+
default:
80+
return null;
81+
}
82+
},
83+
},
84+
},
85+
provider: {
86+
getLogs: async ({
87+
fromBlock,
88+
toBlock,
89+
}: {
90+
fromBlock: number;
91+
toBlock: number;
92+
}) => {
93+
// Mock logs based on block range
94+
const logs: {
95+
blockNumber: number;
96+
logIndex: number;
97+
topics: string[];
98+
data: string;
99+
blockHash: string;
100+
transactionIndex: number;
101+
removed: boolean;
102+
address: string;
103+
transactionHash: string;
104+
}[] = [];
105+
for (let block = fromBlock; block <= toBlock; block++) {
106+
// Add multiple events per block with different log indices
107+
logs.push(
108+
{
109+
blockNumber: block,
110+
logIndex: 0,
111+
topics: ['0x123'], // StrategyCreated
112+
data: '0x',
113+
blockHash: '0x123',
114+
transactionIndex: 0,
115+
removed: false,
116+
address: '0x123',
117+
transactionHash: '0x456',
118+
},
119+
{
120+
blockNumber: block,
121+
logIndex: 1,
122+
topics: ['0x456'], // TokensTraded
123+
data: '0x',
124+
blockHash: '0x123',
125+
transactionIndex: 1,
126+
removed: false,
127+
address: '0x123',
128+
transactionHash: '0x456',
129+
},
130+
{
131+
blockNumber: block,
132+
logIndex: 2,
133+
topics: ['0x789'], // TradingFeePPMUpdated
134+
data: '0x',
135+
blockHash: '0x123',
136+
transactionIndex: 2,
137+
removed: false,
138+
address: '0x123',
139+
transactionHash: '0x456',
140+
},
141+
{
142+
blockNumber: block,
143+
logIndex: 3,
144+
topics: ['0xabc'], // PairTradingFeePPMUpdated
145+
data: '0x',
146+
blockHash: '0x123',
147+
transactionIndex: 3,
148+
removed: false,
149+
address: '0x123',
150+
transactionHash: '0x456',
151+
}
152+
);
153+
}
154+
return logs;
155+
},
156+
},
157+
} as unknown as Contracts;
158+
159+
reader = new Reader(mockContracts);
160+
});
161+
162+
describe('getEvents', () => {
163+
it('should process events from a single chunk', async () => {
164+
const events = await reader.getEvents(1, 5, 10);
165+
expect(events).to.have.length(20); // 5 blocks * 4 events per block
166+
expect(events[0].blockNumber).to.equal(1);
167+
expect(events[events.length - 1].blockNumber).to.equal(5);
168+
});
169+
170+
it('should process events from multiple chunks', async () => {
171+
const events = await reader.getEvents(1, 15, 5); // 3 chunks of 5 blocks each
172+
expect(events).to.have.length(60); // 15 blocks * 4 events per block
173+
expect(events[0].blockNumber).to.equal(1);
174+
expect(events[events.length - 1].blockNumber).to.equal(15);
175+
});
176+
177+
it('should sort events by block number and log index', async () => {
178+
const events = await reader.getEvents(1, 3, 1); // 3 blocks, 1 block per chunk
179+
expect(events).to.have.length(12); // 3 blocks * 4 events per block
180+
181+
// Verify sorting
182+
for (let i = 1; i < events.length; i++) {
183+
const prev = events[i - 1];
184+
const curr = events[i];
185+
if (prev.blockNumber !== curr.blockNumber) {
186+
expect(curr.blockNumber).to.be.greaterThan(prev.blockNumber);
187+
} else {
188+
expect(curr.logIndex).to.be.greaterThan(prev.logIndex);
189+
}
190+
}
191+
});
192+
193+
it('should handle different event types correctly', async () => {
194+
const events = await reader.getEvents(1, 1, 1);
195+
expect(events).to.have.length(4); // 1 block * 4 events per block
196+
197+
// Verify event types and data
198+
expect(events[0].type).to.equal('StrategyCreated');
199+
expect(events[0].data).to.deep.equal(mockEncodedStrategy);
200+
201+
expect(events[1].type).to.equal('TokensTraded');
202+
expect(events[1].data).to.deep.equal(mockTradeData);
203+
204+
expect(events[2].type).to.equal('TradingFeePPMUpdated');
205+
expect(events[2].data).to.equal(100);
206+
207+
expect(events[3].type).to.equal('PairTradingFeePPMUpdated');
208+
expect(events[3].data).to.deep.equal(mockTradingFeeUpdate);
209+
});
210+
211+
it('should handle empty block ranges', async () => {
212+
const events = await reader.getEvents(5, 4, 1);
213+
expect(events).to.have.length(0);
214+
});
215+
216+
it('should handle invalid events gracefully', async () => {
217+
// Override the mock contracts to include invalid events
218+
mockContracts.provider.getLogs = async (_filter) => {
219+
return [
220+
{
221+
blockNumber: 1,
222+
logIndex: 0,
223+
topics: ['0xinvalid'], // Invalid event type
224+
data: '0x',
225+
blockHash: '0x123',
226+
transactionIndex: 0,
227+
removed: false,
228+
address: '0x123',
229+
transactionHash: '0x456',
230+
},
231+
{
232+
blockNumber: 1,
233+
logIndex: 1,
234+
topics: ['0x123'], // Valid event
235+
data: '0x',
236+
blockHash: '0x123',
237+
transactionIndex: 1,
238+
removed: false,
239+
address: '0x123',
240+
transactionHash: '0x456',
241+
},
242+
];
243+
};
244+
245+
const events = await reader.getEvents(1, 1, 1);
246+
expect(events).to.have.length(1);
247+
expect(events[0].type).to.equal('StrategyCreated');
248+
});
249+
250+
it('should handle provider errors gracefully', async () => {
251+
// Override the mock contracts to simulate provider error
252+
mockContracts.provider.getLogs = async () => {
253+
throw new Error('Provider error');
254+
};
255+
256+
try {
257+
await reader.getEvents(1, 5, 1);
258+
expect.fail('Should have thrown an error');
259+
} catch (error: unknown) {
260+
// @ts-expect-error - Error is of unknown type but we need to access message property
261+
expect(error.message).to.equal('Provider error');
262+
}
263+
});
264+
});
265+
});

0 commit comments

Comments
 (0)