Add support for more types in Arrays.sol (#5568)
This commit is contained in:
@ -5,14 +5,19 @@ const generators = {
|
||||
bytes32: () => ethers.hexlify(ethers.randomBytes(32)),
|
||||
uint256: () => ethers.toBigInt(ethers.randomBytes(32)),
|
||||
int256: () => ethers.toBigInt(ethers.randomBytes(32)) + ethers.MinInt256,
|
||||
hexBytes: length => ethers.hexlify(ethers.randomBytes(length)),
|
||||
bytes: (length = 32) => ethers.hexlify(ethers.randomBytes(length)),
|
||||
string: () => ethers.uuidV4(ethers.randomBytes(32)),
|
||||
};
|
||||
|
||||
generators.address.zero = ethers.ZeroAddress;
|
||||
generators.bytes32.zero = ethers.ZeroHash;
|
||||
generators.uint256.zero = 0n;
|
||||
generators.int256.zero = 0n;
|
||||
generators.hexBytes.zero = '0x';
|
||||
generators.bytes.zero = '0x';
|
||||
generators.string.zero = '';
|
||||
|
||||
// alias hexBytes -> bytes
|
||||
generators.hexBytes = generators.bytes;
|
||||
|
||||
module.exports = {
|
||||
generators,
|
||||
|
||||
@ -119,61 +119,63 @@ describe('Arrays', function () {
|
||||
}
|
||||
});
|
||||
|
||||
for (const type of TYPES) {
|
||||
const elements = Array.from({ length: 10 }, generators[type]);
|
||||
for (const { name, isValueType } of TYPES) {
|
||||
const elements = Array.from({ length: 10 }, generators[name]);
|
||||
|
||||
describe(type, function () {
|
||||
describe(name, function () {
|
||||
const fixture = async () => {
|
||||
return { instance: await ethers.deployContract(`${capitalize(type)}ArraysMock`, [elements]) };
|
||||
return { instance: await ethers.deployContract(`${capitalize(name)}ArraysMock`, [elements]) };
|
||||
};
|
||||
|
||||
beforeEach(async function () {
|
||||
Object.assign(this, await loadFixture(fixture));
|
||||
});
|
||||
|
||||
describe('sort', function () {
|
||||
for (const length of [0, 1, 2, 8, 32, 128]) {
|
||||
describe(`${type}[] of length ${length}`, function () {
|
||||
beforeEach(async function () {
|
||||
this.array = Array.from({ length }, generators[type]);
|
||||
if (isValueType) {
|
||||
describe('sort', function () {
|
||||
for (const length of [0, 1, 2, 8, 32, 128]) {
|
||||
describe(`${name}[] of length ${length}`, function () {
|
||||
beforeEach(async function () {
|
||||
this.array = Array.from({ length }, generators[name]);
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
const expected = Array.from(this.array).sort(comparator);
|
||||
const reversed = Array.from(expected).reverse();
|
||||
expect(await this.instance.sort(this.array)).to.deep.equal(expected);
|
||||
expect(await this.instance.sortReverse(this.array)).to.deep.equal(reversed);
|
||||
});
|
||||
|
||||
it('sort array', async function () {
|
||||
// nothing to do here, beforeEach and afterEach already take care of everything.
|
||||
});
|
||||
|
||||
if (length > 1) {
|
||||
it('sort array for identical elements', async function () {
|
||||
// duplicate the first value to all elements
|
||||
this.array.fill(this.array.at(0));
|
||||
});
|
||||
|
||||
it('sort already sorted array', async function () {
|
||||
// pre-sort the elements
|
||||
this.array.sort(comparator);
|
||||
});
|
||||
|
||||
it('sort reversed array', async function () {
|
||||
// pre-sort in reverse order
|
||||
this.array.sort(comparator).reverse();
|
||||
});
|
||||
|
||||
it('sort almost sorted array', async function () {
|
||||
// pre-sort + rotate (move the last element to the front) for an almost sorted effect
|
||||
this.array.sort(comparator);
|
||||
this.array.unshift(this.array.pop());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
const expected = Array.from(this.array).sort(comparator);
|
||||
const reversed = Array.from(expected).reverse();
|
||||
expect(await this.instance.sort(this.array)).to.deep.equal(expected);
|
||||
expect(await this.instance.sortReverse(this.array)).to.deep.equal(reversed);
|
||||
});
|
||||
|
||||
it('sort array', async function () {
|
||||
// nothing to do here, beforeEach and afterEach already take care of everything.
|
||||
});
|
||||
|
||||
if (length > 1) {
|
||||
it('sort array for identical elements', async function () {
|
||||
// duplicate the first value to all elements
|
||||
this.array.fill(this.array.at(0));
|
||||
});
|
||||
|
||||
it('sort already sorted array', async function () {
|
||||
// pre-sort the elements
|
||||
this.array.sort(comparator);
|
||||
});
|
||||
|
||||
it('sort reversed array', async function () {
|
||||
// pre-sort in reverse order
|
||||
this.array.sort(comparator).reverse();
|
||||
});
|
||||
|
||||
it('sort almost sorted array', async function () {
|
||||
// pre-sort + rotate (move the last element to the front) for an almost sorted effect
|
||||
this.array.sort(comparator);
|
||||
this.array.unshift(this.array.pop());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('unsafeAccess', function () {
|
||||
describe('storage', function () {
|
||||
@ -197,7 +199,7 @@ describe('Arrays', function () {
|
||||
});
|
||||
|
||||
describe('memory', function () {
|
||||
const fragment = `$unsafeMemoryAccess(${type}[] arr, uint256 pos)`;
|
||||
const fragment = `$unsafeMemoryAccess(${name}[] arr, uint256 pos)`;
|
||||
|
||||
for (const i in elements) {
|
||||
it(`unsafeMemoryAccess within bounds #${i}`, async function () {
|
||||
@ -211,7 +213,9 @@ describe('Arrays', function () {
|
||||
|
||||
it('unsafeMemoryAccess loop around', async function () {
|
||||
for (let i = 251n; i < 256n; ++i) {
|
||||
expect(await this.mock[fragment](elements, 2n ** i - 1n)).to.equal(BigInt(elements.length));
|
||||
expect(await this.mock[fragment](elements, 2n ** i - 1n)).to.equal(
|
||||
isValueType ? BigInt(elements.length) : generators[name].zero,
|
||||
);
|
||||
expect(await this.mock[fragment](elements, 2n ** i + 0n)).to.equal(elements[0]);
|
||||
expect(await this.mock[fragment](elements, 2n ** i + 1n)).to.equal(elements[1]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user