Skip to content

Commit 96e5c08

Browse files
Amxxernestognw
andauthored
Deduplicate code in scripts/helpers and test/helpers/iterate (#4895)
Co-authored-by: ernestognw <[email protected]>
1 parent 4e7e6e5 commit 96e5c08

File tree

5 files changed

+43
-44
lines changed

5 files changed

+43
-44
lines changed

scripts/helpers.js

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,10 @@
1-
function chunk(array, size = 1) {
2-
return Array.range(Math.ceil(array.length / size)).map(i => array.slice(i * size, i * size + size));
3-
}
4-
5-
function range(start, stop = undefined, step = 1) {
6-
if (!stop) {
7-
stop = start;
8-
start = 0;
9-
}
10-
return start < stop ? Array.from({ length: Math.ceil((stop - start) / step) }, (_, i) => start + i * step) : [];
11-
}
12-
13-
function unique(array, op = x => x) {
14-
return array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i);
15-
}
16-
17-
function zip(...args) {
18-
return Array.from({ length: Math.max(...args.map(arg => arg.length)) }, (_, i) => args.map(arg => arg[i]));
19-
}
20-
21-
function capitalize(str) {
22-
return str.charAt(0).toUpperCase() + str.slice(1);
23-
}
1+
const iterate = require('../test/helpers/iterate');
242

253
module.exports = {
26-
chunk,
27-
range,
28-
unique,
29-
zip,
30-
capitalize,
4+
// Capitalize the first char of a string
5+
// Example: capitalize('uint256') → 'Uint256'
6+
capitalize: str => str.charAt(0).toUpperCase() + str.slice(1),
7+
8+
// Iterate tools for the test helpers
9+
...iterate,
3110
};

test/helpers/governance.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ class GovernorHelper {
175175
const statesCount = ethers.toBigInt(Object.keys(ProposalState).length);
176176
let result = 0n;
177177

178-
for (const state of unique(...proposalStates)) {
178+
for (const state of unique(proposalStates)) {
179179
if (state < 0n || state >= statesCount) {
180180
expect.fail(`ProposalState ${state} out of possible states (0...${statesCount}-1)`);
181181
} else {

test/helpers/iterate.js

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
1-
// Map values in an object
2-
const mapValues = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)]));
1+
module.exports = {
2+
// ================================================= Array helpers =================================================
33

4-
// Cartesian product of a list of arrays
5-
const product = (...arrays) => arrays.reduce((a, b) => a.flatMap(ai => b.map(bi => [...ai, bi])), [[]]);
6-
const unique = (...array) => array.filter((obj, i) => array.indexOf(obj) === i);
7-
const zip = (...args) =>
8-
Array.from({ length: Math.max(...args.map(array => array.length)) }, (_, i) => args.map(array => array[i]));
4+
// Cut an array into an array of sized-length arrays
5+
// Example: chunk([1,2,3,4,5,6,7,8], 3) → [[1,2,3],[4,5,6],[7,8]]
6+
chunk: (array, size = 1) =>
7+
Array.from({ length: Math.ceil(array.length / size) }, (_, i) => array.slice(i * size, i * size + size)),
98

10-
module.exports = {
11-
mapValues,
12-
product,
13-
unique,
14-
zip,
9+
// Cartesian cross product of an array of arrays
10+
// Example: product([1,2],[a,b,c],[true]) → [[1,a,true],[1,b,true],[1,c,true],[2,a,true],[2,b,true],[2,c,true]]
11+
product: (...arrays) => arrays.reduce((a, b) => a.flatMap(ai => b.map(bi => [...ai, bi])), [[]]),
12+
13+
// Range from start to end in increment
14+
// Example: range(17,42,7) → [17,24,31,38]
15+
range: (start, stop = undefined, step = 1) => {
16+
if (!stop) {
17+
stop = start;
18+
start = 0;
19+
}
20+
return start < stop ? Array.from({ length: Math.ceil((stop - start) / step) }, (_, i) => start + i * step) : [];
21+
},
22+
23+
// Unique elements, with an optional getter function
24+
// Example: unique([1,1,2,3,4,8,1,3,8,13,42]) → [1,2,3,4,8,13,42]
25+
unique: (array, op = x => x) => array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i),
26+
27+
// Zip arrays together. If some arrays are smaller, undefined is used as a filler.
28+
// Example: zip([1,2],[a,b,c],[true]) → [[1,a,true],[2,b,undefined],[undefined,c,undefined]]
29+
zip: (...args) => Array.from({ length: Math.max(...args.map(arg => arg.length)) }, (_, i) => args.map(arg => arg[i])),
30+
31+
// ================================================ Object helpers =================================================
32+
33+
// Create a new object by mapping the values through a function, keeping the keys
34+
// Example: mapValues({a:1,b:2,c:3}, x => x**2) → {a:1,b:4,c:9}
35+
mapValues: (obj, fn) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)])),
1536
};

test/utils/math/Math.test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
66
const { Rounding } = require('../../helpers/enums');
77
const { min, max, modExp } = require('../../helpers/math');
88
const { generators } = require('../../helpers/random');
9-
const { range } = require('../../../scripts/helpers');
10-
const { product } = require('../../helpers/iterate');
9+
const { product, range } = require('../../helpers/iterate');
1110

1211
const RoundingDown = [Rounding.Floor, Rounding.Trunc];
1312
const RoundingUp = [Rounding.Ceil, Rounding.Expand];

test/utils/math/SafeCast.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const { ethers } = require('hardhat');
22
const { expect } = require('chai');
33
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
44

5-
const { range } = require('../../../scripts/helpers');
5+
const { range } = require('../../helpers/iterate');
66

77
async function fixture() {
88
const mock = await ethers.deployContract('$SafeCast');

0 commit comments

Comments
 (0)