Skip to content
This repository has been archived by the owner on Feb 4, 2022. It is now read-only.

Commit

Permalink
uses an empty array to represent a null filter parameter (#228)
Browse files Browse the repository at this point in the history
* uses an empty array to represent a null filter parameter

* Removes unnecesary imports

* adds filters unit tests
  • Loading branch information
gordienoye authored Jan 6, 2022
1 parent fa276fa commit 5c646cd
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# OS-specific files
.DS_Store

# Files and directories created by pub
.packages
.pub/
Expand Down
1 change: 0 additions & 1 deletion lib/src/browser/credentials.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import 'dart:typed_data';
import 'package:js/js.dart';
import 'package:web3dart/web3dart.dart';

import '../../credentials.dart';
import '../../crypto.dart';

import 'dart_wrappers.dart';
Expand Down
1 change: 0 additions & 1 deletion lib/src/contracts/generated_contract.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'package:meta/meta.dart';

import '../../crypto.dart';
import '../../web3dart.dart';
import 'deployed_contract.dart';

/// Base classes for generated contracts.
///
Expand Down
4 changes: 3 additions & 1 deletion lib/src/core/filters.dart
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,9 @@ class _EventFilter extends _Filter<FilterEvent> {
encodedOptions['address'] = options.address?.hex;
}
if (options.topics != null) {
encodedOptions['topics'] = options.topics;
final topics = <dynamic>[];
options.topics?.forEach((e) => topics.add(e.isEmpty ? null : e));
encodedOptions['topics'] = topics;
}

return encodedOptions;
Expand Down
130 changes: 130 additions & 0 deletions test/core/event_filter_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import 'package:test/test.dart';
import 'package:web3dart/web3dart.dart';

import '../mock_client.dart';

void main() {
const alice =
'0x000000000000000000000000Dd611f2b2CaF539aC9e12CF84C09CB9bf81CA37F';
const bob =
'0x0000000000000000000000006c87E1a114C3379BEc929f6356c5263d62542C13';
const contract = '0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d';

final testCases = [
{
'name': 'one topic',
'input': [
[alice]
],
'expected': [
[alice]
]
},
{
'name': 'two topics one item',
'input': [
[alice, bob]
],
'expected': [
[alice, bob]
]
},
{
'name': 'two topics two items',
'input': [
[alice],
[bob]
],
'expected': [
[alice],
[bob]
]
},
{
'name': 'two topics first null',
'input': [
[],
[bob]
],
'expected': [
null,
[bob]
]
},
{
'name': 'three topics first null',
'input': [
[],
[alice],
[bob]
],
'expected': [
null,
[alice],
[bob]
]
},
{
'name': 'three topics second null',
'input': [
[alice],
[],
[bob]
],
'expected': [
[alice],
null,
[bob]
]
}
];

Future _runFilterTest(input, expected) async {
final client = MockClient(expectAsync2((method, params) {
expect(method, 'eth_getLogs');

// verify that the topics are sent to eth_getLogs in the correct format
final actual = ((params as List)[0])['topics'];
expect(actual, expected);

// return a valid response from eth_getLogs
return [
{'address': contract}
];
}));

final web3 = Web3Client('', client);
addTearDown(web3.dispose);

// Dart typing will not allow an empty list to be added so when an empty
// list is encountered, a list containing a single string is added and then
// the single string in that list is removed.
// The type is required to ensure `topics` is forced to List<List<String>>

// ignore: omit_local_variable_types
final List<List<String>> topics = [];
input.forEach((element) {
if (element.length == 0) {
topics.add(['dummy string element']);
topics.last.remove('dummy string element');
} else {
topics.add(element as List<String>);
}
});

final filter = FilterOptions(
fromBlock: const BlockNum.genesis(),
toBlock: const BlockNum.current(),
address: EthereumAddress.fromHex(contract),
topics: topics);

await web3.getLogs(filter);
}

// test each test case in the list of test cases
for (final testCase in testCases) {
test('filters test with ${testCase['name']}', () async {
await _runFilterTest(testCase['input'], testCase['expected']);
});
}
}
24 changes: 24 additions & 0 deletions test/mock_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,30 @@ class MockClient extends BaseClient {

MockClient(this.handler);

@override
Future<Response> post(Uri url,
{Map<String, String>? headers, Object? body, Encoding? encoding}) async {
if (body is! String) {
fail('Invalid request, expected string as request body');
}

final data = json.decode(body) as Map<String, dynamic>;
if (data['jsonrpc'] != '2.0') {
fail('Expected request to contain correct jsonrpc key');
}

final id = data['id'];
final method = data['method'] as String;
final params = data['params'];
final response = {
'body': body,
'id': id,
'result': handler(method, params)
};

return Response(json.encode(response), 200);
}

@override
Future<StreamedResponse> send(BaseRequest request) async {
final data = await _jsonUtf8.decoder.bind(request.finalize()).first;
Expand Down

0 comments on commit 5c646cd

Please sign in to comment.