Browse Source

Deduplicate code in `scripts/helpers` and `test/helpers/iterate` (#4895)

Co-authored-by: ernestognw <ernestognw@gmail.com>
Hadrien Croubois 1 year ago
parent
commit
96e5c0830a

+ 7 - 28
scripts/helpers.js

@@ -1,31 +1,10 @@
-function chunk(array, size = 1) {
-  return Array.range(Math.ceil(array.length / size)).map(i => array.slice(i * size, i * size + size));
-}
-
-function range(start, stop = undefined, step = 1) {
-  if (!stop) {
-    stop = start;
-    start = 0;
-  }
-  return start < stop ? Array.from({ length: Math.ceil((stop - start) / step) }, (_, i) => start + i * step) : [];
-}
-
-function unique(array, op = x => x) {
-  return array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i);
-}
-
-function zip(...args) {
-  return Array.from({ length: Math.max(...args.map(arg => arg.length)) }, (_, i) => args.map(arg => arg[i]));
-}
-
-function capitalize(str) {
-  return str.charAt(0).toUpperCase() + str.slice(1);
-}
+const iterate = require('../test/helpers/iterate');
 
 
 module.exports = {
 module.exports = {
-  chunk,
-  range,
-  unique,
-  zip,
-  capitalize,
+  // Capitalize the first char of a string
+  // Example: capitalize('uint256') → 'Uint256'
+  capitalize: str => str.charAt(0).toUpperCase() + str.slice(1),
+
+  // Iterate tools for the test helpers
+  ...iterate,
 };
 };

+ 1 - 1
test/helpers/governance.js

@@ -175,7 +175,7 @@ class GovernorHelper {
     const statesCount = ethers.toBigInt(Object.keys(ProposalState).length);
     const statesCount = ethers.toBigInt(Object.keys(ProposalState).length);
     let result = 0n;
     let result = 0n;
 
 
-    for (const state of unique(...proposalStates)) {
+    for (const state of unique(proposalStates)) {
       if (state < 0n || state >= statesCount) {
       if (state < 0n || state >= statesCount) {
         expect.fail(`ProposalState ${state} out of possible states (0...${statesCount}-1)`);
         expect.fail(`ProposalState ${state} out of possible states (0...${statesCount}-1)`);
       } else {
       } else {

+ 33 - 12
test/helpers/iterate.js

@@ -1,15 +1,36 @@
-// Map values in an object
-const mapValues = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)]));
+module.exports = {
+  // ================================================= Array helpers =================================================
 
 
-// Cartesian product of a list of arrays
-const product = (...arrays) => arrays.reduce((a, b) => a.flatMap(ai => b.map(bi => [...ai, bi])), [[]]);
-const unique = (...array) => array.filter((obj, i) => array.indexOf(obj) === i);
-const zip = (...args) =>
-  Array.from({ length: Math.max(...args.map(array => array.length)) }, (_, i) => args.map(array => array[i]));
+  // Cut an array into an array of sized-length arrays
+  // Example: chunk([1,2,3,4,5,6,7,8], 3) → [[1,2,3],[4,5,6],[7,8]]
+  chunk: (array, size = 1) =>
+    Array.from({ length: Math.ceil(array.length / size) }, (_, i) => array.slice(i * size, i * size + size)),
 
 
-module.exports = {
-  mapValues,
-  product,
-  unique,
-  zip,
+  // Cartesian cross product of an array of arrays
+  // 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]]
+  product: (...arrays) => arrays.reduce((a, b) => a.flatMap(ai => b.map(bi => [...ai, bi])), [[]]),
+
+  // Range from start to end in increment
+  // Example: range(17,42,7) → [17,24,31,38]
+  range: (start, stop = undefined, step = 1) => {
+    if (!stop) {
+      stop = start;
+      start = 0;
+    }
+    return start < stop ? Array.from({ length: Math.ceil((stop - start) / step) }, (_, i) => start + i * step) : [];
+  },
+
+  // Unique elements, with an optional getter function
+  // Example: unique([1,1,2,3,4,8,1,3,8,13,42]) → [1,2,3,4,8,13,42]
+  unique: (array, op = x => x) => array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i),
+
+  // Zip arrays together. If some arrays are smaller, undefined is used as a filler.
+  // Example: zip([1,2],[a,b,c],[true]) → [[1,a,true],[2,b,undefined],[undefined,c,undefined]]
+  zip: (...args) => Array.from({ length: Math.max(...args.map(arg => arg.length)) }, (_, i) => args.map(arg => arg[i])),
+
+  // ================================================ Object helpers =================================================
+
+  // Create a new object by mapping the values through a function, keeping the keys
+  // Example: mapValues({a:1,b:2,c:3}, x => x**2) → {a:1,b:4,c:9}
+  mapValues: (obj, fn) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)])),
 };
 };

+ 1 - 2
test/utils/math/Math.test.js

@@ -6,8 +6,7 @@ const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
 const { Rounding } = require('../../helpers/enums');
 const { Rounding } = require('../../helpers/enums');
 const { min, max, modExp } = require('../../helpers/math');
 const { min, max, modExp } = require('../../helpers/math');
 const { generators } = require('../../helpers/random');
 const { generators } = require('../../helpers/random');
-const { range } = require('../../../scripts/helpers');
-const { product } = require('../../helpers/iterate');
+const { product, range } = require('../../helpers/iterate');
 
 
 const RoundingDown = [Rounding.Floor, Rounding.Trunc];
 const RoundingDown = [Rounding.Floor, Rounding.Trunc];
 const RoundingUp = [Rounding.Ceil, Rounding.Expand];
 const RoundingUp = [Rounding.Ceil, Rounding.Expand];

+ 1 - 1
test/utils/math/SafeCast.test.js

@@ -2,7 +2,7 @@ const { ethers } = require('hardhat');
 const { expect } = require('chai');
 const { expect } = require('chai');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
-const { range } = require('../../../scripts/helpers');
+const { range } = require('../../helpers/iterate');
 
 
 async function fixture() {
 async function fixture() {
   const mock = await ethers.deployContract('$SafeCast');
   const mock = await ethers.deployContract('$SafeCast');