Migrate math tests to ethers.js v6 (#4769)
Co-authored-by: Ernesto García <ernestognw@gmail.com>pull/4778/head^2
parent
ef699fa6a2
commit
cffb2f1ddc
@ -1,16 +1,10 @@ |
||||
// Map values in an object
|
||||
const mapValues = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)])); |
||||
|
||||
// Array of number or bigint
|
||||
const max = (...values) => values.slice(1).reduce((x, y) => (x > y ? x : y), values[0]); |
||||
const min = (...values) => values.slice(1).reduce((x, y) => (x < y ? x : y), values[0]); |
||||
|
||||
// Cartesian product of a list of arrays
|
||||
const product = (...arrays) => arrays.reduce((a, b) => a.flatMap(ai => b.map(bi => [...ai, bi])), [[]]); |
||||
|
||||
module.exports = { |
||||
mapValues, |
||||
max, |
||||
min, |
||||
product, |
||||
}; |
||||
|
@ -1,12 +1,13 @@ |
||||
// Array of number or bigint
|
||||
const max = (...values) => values.slice(1).reduce((x, y) => (x > y ? x : y), values.at(0)); |
||||
const min = (...values) => values.slice(1).reduce((x, y) => (x < y ? x : y), values.at(0)); |
||||
const sum = (...values) => values.slice(1).reduce((x, y) => x + y, values.at(0)); |
||||
|
||||
module.exports = { |
||||
// sum of integer / bignumber
|
||||
sum: (...args) => args.reduce((acc, n) => acc + n, 0), |
||||
bigintSum: (...args) => args.reduce((acc, n) => acc + n, 0n), |
||||
BNsum: (...args) => args.reduce((acc, n) => acc.add(n), web3.utils.toBN(0)), |
||||
// min of integer / bignumber
|
||||
min: (...args) => args.slice(1).reduce((x, y) => (x < y ? x : y), args[0]), |
||||
BNmin: (...args) => args.slice(1).reduce((x, y) => (x.lt(y) ? x : y), args[0]), |
||||
// max of integer / bignumber
|
||||
max: (...args) => args.slice(1).reduce((x, y) => (x > y ? x : y), args[0]), |
||||
BNmax: (...args) => args.slice(1).reduce((x, y) => (x.gt(y) ? x : y), args[0]), |
||||
// re-export min, max & sum of integer / bignumber
|
||||
min, |
||||
max, |
||||
sum, |
||||
// deprecated: BN version of sum
|
||||
BNsum: (...args) => args.slice(1).reduce((x, y) => x.add(y), args.at(0)), |
||||
}; |
||||
|
@ -1,161 +1,148 @@ |
||||
const { BN } = require('@openzeppelin/test-helpers'); |
||||
const { ethers } = require('hardhat'); |
||||
const { expect } = require('chai'); |
||||
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); |
||||
const { range } = require('../../../scripts/helpers'); |
||||
const { expectRevertCustomError } = require('../../helpers/customError'); |
||||
|
||||
const SafeCast = artifacts.require('$SafeCast'); |
||||
async function fixture() { |
||||
const mock = await ethers.deployContract('$SafeCast'); |
||||
return { mock }; |
||||
} |
||||
|
||||
contract('SafeCast', async function () { |
||||
contract('SafeCast', function () { |
||||
beforeEach(async function () { |
||||
this.safeCast = await SafeCast.new(); |
||||
Object.assign(this, await loadFixture(fixture)); |
||||
}); |
||||
|
||||
function testToUint(bits) { |
||||
describe(`toUint${bits}`, () => { |
||||
const maxValue = new BN('2').pow(new BN(bits)).subn(1); |
||||
for (const bits of range(8, 256, 8).map(ethers.toBigInt)) { |
||||
const maxValue = 2n ** bits - 1n; |
||||
|
||||
describe(`toUint${bits}`, () => { |
||||
it('downcasts 0', async function () { |
||||
expect(await this.safeCast[`$toUint${bits}`](0)).to.be.bignumber.equal('0'); |
||||
expect(await this.mock[`$toUint${bits}`](0n)).is.equal(0n); |
||||
}); |
||||
|
||||
it('downcasts 1', async function () { |
||||
expect(await this.safeCast[`$toUint${bits}`](1)).to.be.bignumber.equal('1'); |
||||
expect(await this.mock[`$toUint${bits}`](1n)).is.equal(1n); |
||||
}); |
||||
|
||||
it(`downcasts 2^${bits} - 1 (${maxValue})`, async function () { |
||||
expect(await this.safeCast[`$toUint${bits}`](maxValue)).to.be.bignumber.equal(maxValue); |
||||
expect(await this.mock[`$toUint${bits}`](maxValue)).is.equal(maxValue); |
||||
}); |
||||
|
||||
it(`reverts when downcasting 2^${bits} (${maxValue.addn(1)})`, async function () { |
||||
await expectRevertCustomError( |
||||
this.safeCast[`$toUint${bits}`](maxValue.addn(1)), |
||||
`SafeCastOverflowedUintDowncast`, |
||||
[bits, maxValue.addn(1)], |
||||
); |
||||
it(`reverts when downcasting 2^${bits} (${maxValue + 1n})`, async function () { |
||||
await expect(this.mock[`$toUint${bits}`](maxValue + 1n)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') |
||||
.withArgs(bits, maxValue + 1n); |
||||
}); |
||||
|
||||
it(`reverts when downcasting 2^${bits} + 1 (${maxValue.addn(2)})`, async function () { |
||||
await expectRevertCustomError( |
||||
this.safeCast[`$toUint${bits}`](maxValue.addn(2)), |
||||
`SafeCastOverflowedUintDowncast`, |
||||
[bits, maxValue.addn(2)], |
||||
); |
||||
it(`reverts when downcasting 2^${bits} + 1 (${maxValue + 2n})`, async function () { |
||||
await expect(this.mock[`$toUint${bits}`](maxValue + 2n)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintDowncast') |
||||
.withArgs(bits, maxValue + 2n); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
range(8, 256, 8).forEach(bits => testToUint(bits)); |
||||
|
||||
describe('toUint256', () => { |
||||
const maxInt256 = new BN('2').pow(new BN(255)).subn(1); |
||||
const minInt256 = new BN('2').pow(new BN(255)).neg(); |
||||
|
||||
it('casts 0', async function () { |
||||
expect(await this.safeCast.$toUint256(0)).to.be.bignumber.equal('0'); |
||||
expect(await this.mock.$toUint256(0n)).is.equal(0n); |
||||
}); |
||||
|
||||
it('casts 1', async function () { |
||||
expect(await this.safeCast.$toUint256(1)).to.be.bignumber.equal('1'); |
||||
expect(await this.mock.$toUint256(1n)).is.equal(1n); |
||||
}); |
||||
|
||||
it(`casts INT256_MAX (${maxInt256})`, async function () { |
||||
expect(await this.safeCast.$toUint256(maxInt256)).to.be.bignumber.equal(maxInt256); |
||||
it(`casts INT256_MAX (${ethers.MaxInt256})`, async function () { |
||||
expect(await this.mock.$toUint256(ethers.MaxInt256)).is.equal(ethers.MaxInt256); |
||||
}); |
||||
|
||||
it('reverts when casting -1', async function () { |
||||
await expectRevertCustomError(this.safeCast.$toUint256(-1), `SafeCastOverflowedIntToUint`, [-1]); |
||||
await expect(this.mock.$toUint256(-1n)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntToUint') |
||||
.withArgs(-1n); |
||||
}); |
||||
|
||||
it(`reverts when casting INT256_MIN (${minInt256})`, async function () { |
||||
await expectRevertCustomError(this.safeCast.$toUint256(minInt256), `SafeCastOverflowedIntToUint`, [minInt256]); |
||||
it(`reverts when casting INT256_MIN (${ethers.MinInt256})`, async function () { |
||||
await expect(this.mock.$toUint256(ethers.MinInt256)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntToUint') |
||||
.withArgs(ethers.MinInt256); |
||||
}); |
||||
}); |
||||
|
||||
function testToInt(bits) { |
||||
describe(`toInt${bits}`, () => { |
||||
const minValue = new BN('-2').pow(new BN(bits - 1)); |
||||
const maxValue = new BN('2').pow(new BN(bits - 1)).subn(1); |
||||
for (const bits of range(8, 256, 8).map(ethers.toBigInt)) { |
||||
const minValue = -(2n ** (bits - 1n)); |
||||
const maxValue = 2n ** (bits - 1n) - 1n; |
||||
|
||||
describe(`toInt${bits}`, () => { |
||||
it('downcasts 0', async function () { |
||||
expect(await this.safeCast[`$toInt${bits}`](0)).to.be.bignumber.equal('0'); |
||||
expect(await this.mock[`$toInt${bits}`](0n)).is.equal(0n); |
||||
}); |
||||
|
||||
it('downcasts 1', async function () { |
||||
expect(await this.safeCast[`$toInt${bits}`](1)).to.be.bignumber.equal('1'); |
||||
expect(await this.mock[`$toInt${bits}`](1n)).is.equal(1n); |
||||
}); |
||||
|
||||
it('downcasts -1', async function () { |
||||
expect(await this.safeCast[`$toInt${bits}`](-1)).to.be.bignumber.equal('-1'); |
||||
expect(await this.mock[`$toInt${bits}`](-1n)).is.equal(-1n); |
||||
}); |
||||
|
||||
it(`downcasts -2^${bits - 1} (${minValue})`, async function () { |
||||
expect(await this.safeCast[`$toInt${bits}`](minValue)).to.be.bignumber.equal(minValue); |
||||
it(`downcasts -2^${bits - 1n} (${minValue})`, async function () { |
||||
expect(await this.mock[`$toInt${bits}`](minValue)).is.equal(minValue); |
||||
}); |
||||
|
||||
it(`downcasts 2^${bits - 1} - 1 (${maxValue})`, async function () { |
||||
expect(await this.safeCast[`$toInt${bits}`](maxValue)).to.be.bignumber.equal(maxValue); |
||||
it(`downcasts 2^${bits - 1n} - 1 (${maxValue})`, async function () { |
||||
expect(await this.mock[`$toInt${bits}`](maxValue)).is.equal(maxValue); |
||||
}); |
||||
|
||||
it(`reverts when downcasting -2^${bits - 1} - 1 (${minValue.subn(1)})`, async function () { |
||||
await expectRevertCustomError( |
||||
this.safeCast[`$toInt${bits}`](minValue.subn(1)), |
||||
`SafeCastOverflowedIntDowncast`, |
||||
[bits, minValue.subn(1)], |
||||
); |
||||
it(`reverts when downcasting -2^${bits - 1n} - 1 (${minValue - 1n})`, async function () { |
||||
await expect(this.mock[`$toInt${bits}`](minValue - 1n)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') |
||||
.withArgs(bits, minValue - 1n); |
||||
}); |
||||
|
||||
it(`reverts when downcasting -2^${bits - 1} - 2 (${minValue.subn(2)})`, async function () { |
||||
await expectRevertCustomError( |
||||
this.safeCast[`$toInt${bits}`](minValue.subn(2)), |
||||
`SafeCastOverflowedIntDowncast`, |
||||
[bits, minValue.subn(2)], |
||||
); |
||||
it(`reverts when downcasting -2^${bits - 1n} - 2 (${minValue - 2n})`, async function () { |
||||
await expect(this.mock[`$toInt${bits}`](minValue - 2n)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') |
||||
.withArgs(bits, minValue - 2n); |
||||
}); |
||||
|
||||
it(`reverts when downcasting 2^${bits - 1} (${maxValue.addn(1)})`, async function () { |
||||
await expectRevertCustomError( |
||||
this.safeCast[`$toInt${bits}`](maxValue.addn(1)), |
||||
`SafeCastOverflowedIntDowncast`, |
||||
[bits, maxValue.addn(1)], |
||||
); |
||||
it(`reverts when downcasting 2^${bits - 1n} (${maxValue + 1n})`, async function () { |
||||
await expect(this.mock[`$toInt${bits}`](maxValue + 1n)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') |
||||
.withArgs(bits, maxValue + 1n); |
||||
}); |
||||
|
||||
it(`reverts when downcasting 2^${bits - 1} + 1 (${maxValue.addn(2)})`, async function () { |
||||
await expectRevertCustomError( |
||||
this.safeCast[`$toInt${bits}`](maxValue.addn(2)), |
||||
`SafeCastOverflowedIntDowncast`, |
||||
[bits, maxValue.addn(2)], |
||||
); |
||||
it(`reverts when downcasting 2^${bits - 1n} + 1 (${maxValue + 2n})`, async function () { |
||||
await expect(this.mock[`$toInt${bits}`](maxValue + 2n)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedIntDowncast') |
||||
.withArgs(bits, maxValue + 2n); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
range(8, 256, 8).forEach(bits => testToInt(bits)); |
||||
|
||||
describe('toInt256', () => { |
||||
const maxUint256 = new BN('2').pow(new BN(256)).subn(1); |
||||
const maxInt256 = new BN('2').pow(new BN(255)).subn(1); |
||||
|
||||
it('casts 0', async function () { |
||||
expect(await this.safeCast.$toInt256(0)).to.be.bignumber.equal('0'); |
||||
expect(await this.mock.$toInt256(0)).is.equal(0n); |
||||
}); |
||||
|
||||
it('casts 1', async function () { |
||||
expect(await this.safeCast.$toInt256(1)).to.be.bignumber.equal('1'); |
||||
expect(await this.mock.$toInt256(1)).is.equal(1n); |
||||
}); |
||||
|
||||
it(`casts INT256_MAX (${maxInt256})`, async function () { |
||||
expect(await this.safeCast.$toInt256(maxInt256)).to.be.bignumber.equal(maxInt256); |
||||
it(`casts INT256_MAX (${ethers.MaxInt256})`, async function () { |
||||
expect(await this.mock.$toInt256(ethers.MaxInt256)).is.equal(ethers.MaxInt256); |
||||
}); |
||||
|
||||
it(`reverts when casting INT256_MAX + 1 (${maxInt256.addn(1)})`, async function () { |
||||
await expectRevertCustomError(this.safeCast.$toInt256(maxInt256.addn(1)), 'SafeCastOverflowedUintToInt', [ |
||||
maxInt256.addn(1), |
||||
]); |
||||
it(`reverts when casting INT256_MAX + 1 (${ethers.MaxInt256 + 1n})`, async function () { |
||||
await expect(this.mock.$toInt256(ethers.MaxInt256 + 1n)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintToInt') |
||||
.withArgs(ethers.MaxInt256 + 1n); |
||||
}); |
||||
|
||||
it(`reverts when casting UINT256_MAX (${maxUint256})`, async function () { |
||||
await expectRevertCustomError(this.safeCast.$toInt256(maxUint256), 'SafeCastOverflowedUintToInt', [maxUint256]); |
||||
it(`reverts when casting UINT256_MAX (${ethers.MaxUint256})`, async function () { |
||||
await expect(this.mock.$toInt256(ethers.MaxUint256)) |
||||
.to.be.revertedWithCustomError(this.mock, 'SafeCastOverflowedUintToInt') |
||||
.withArgs(ethers.MaxUint256); |
||||
}); |
||||
}); |
||||
}); |
||||
|
Loading…
Reference in new issue