Migrate `AccessControl` tests (#4694)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
pull/4707/head
Ernesto García 1 year ago committed by GitHub
parent 7c8b7a2728
commit 2ec2ed9695
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 860
      test/access/AccessControl.behavior.js
  2. 17
      test/access/AccessControl.test.js
  3. 30
      test/access/extensions/AccessControlDefaultAdminRules.test.js
  4. 19
      test/access/extensions/AccessControlEnumerable.test.js
  5. 13
      test/helpers/time.js
  6. 49
      test/utils/introspection/SupportsInterface.behavior.js

File diff suppressed because it is too large Load Diff

@ -1,12 +1,19 @@
const { ethers } = require('hardhat');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js'); const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js');
const AccessControl = artifacts.require('$AccessControl'); async function fixture() {
const [defaultAdmin, ...accounts] = await ethers.getSigners();
const mock = await ethers.deployContract('$AccessControl');
await mock.$_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
return { mock, defaultAdmin, accounts };
}
contract('AccessControl', function (accounts) { describe('AccessControl', function () {
beforeEach(async function () { beforeEach(async function () {
this.accessControl = await AccessControl.new({ from: accounts[0] }); Object.assign(this, await loadFixture(fixture));
await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]);
}); });
shouldBehaveLikeAccessControl(...accounts); shouldBehaveLikeAccessControl();
}); });

@ -1,26 +1,30 @@
const { time, constants, expectRevert } = require('@openzeppelin/test-helpers'); const { ethers } = require('hardhat');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { bigint: time } = require('../../helpers/time');
const { const {
shouldBehaveLikeAccessControl, shouldBehaveLikeAccessControl,
shouldBehaveLikeAccessControlDefaultAdminRules, shouldBehaveLikeAccessControlDefaultAdminRules,
} = require('../AccessControl.behavior.js'); } = require('../AccessControl.behavior.js');
const AccessControlDefaultAdminRules = artifacts.require('$AccessControlDefaultAdminRules'); async function fixture() {
const delay = time.duration.hours(10);
contract('AccessControlDefaultAdminRules', function (accounts) { const [defaultAdmin, ...accounts] = await ethers.getSigners();
const delay = web3.utils.toBN(time.duration.hours(10)); const mock = await ethers.deployContract('$AccessControlDefaultAdminRules', [delay, defaultAdmin]);
return { mock, defaultAdmin, delay, accounts };
}
describe('AccessControlDefaultAdminRules', function () {
beforeEach(async function () { beforeEach(async function () {
this.accessControl = await AccessControlDefaultAdminRules.new(delay, accounts[0], { from: accounts[0] }); Object.assign(this, await loadFixture(fixture));
}); });
it('initial admin not zero', async function () { it('initial admin not zero', async function () {
await expectRevert( await expect(ethers.deployContract('$AccessControlDefaultAdminRules', [this.delay, ethers.ZeroAddress]))
AccessControlDefaultAdminRules.new(delay, constants.ZERO_ADDRESS), .to.be.revertedWithCustomError(this.mock, 'AccessControlInvalidDefaultAdmin')
'AccessControlInvalidDefaultAdmin', .withArgs(ethers.ZeroAddress);
[constants.ZERO_ADDRESS],
);
}); });
shouldBehaveLikeAccessControl(...accounts); shouldBehaveLikeAccessControl();
shouldBehaveLikeAccessControlDefaultAdminRules(delay, ...accounts); shouldBehaveLikeAccessControlDefaultAdminRules();
}); });

@ -1,17 +1,24 @@
const { ethers } = require('hardhat');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const { const {
DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_ROLE,
shouldBehaveLikeAccessControl, shouldBehaveLikeAccessControl,
shouldBehaveLikeAccessControlEnumerable, shouldBehaveLikeAccessControlEnumerable,
} = require('../AccessControl.behavior.js'); } = require('../AccessControl.behavior.js');
const AccessControlEnumerable = artifacts.require('$AccessControlEnumerable'); async function fixture() {
const [defaultAdmin, ...accounts] = await ethers.getSigners();
const mock = await ethers.deployContract('$AccessControlEnumerable');
await mock.$_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
return { mock, defaultAdmin, accounts };
}
contract('AccessControlEnumerable', function (accounts) { describe('AccessControlEnumerable', function () {
beforeEach(async function () { beforeEach(async function () {
this.accessControl = await AccessControlEnumerable.new({ from: accounts[0] }); Object.assign(this, await loadFixture(fixture));
await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]);
}); });
shouldBehaveLikeAccessControl(...accounts); shouldBehaveLikeAccessControl();
shouldBehaveLikeAccessControlEnumerable(...accounts); shouldBehaveLikeAccessControlEnumerable();
}); });

@ -1,5 +1,7 @@
const { time, mineUpTo } = require('@nomicfoundation/hardhat-network-helpers'); const { time, mineUpTo } = require('@nomicfoundation/hardhat-network-helpers');
const mapObject = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, fn(value)]));
module.exports = { module.exports = {
clock: { clock: {
blocknumber: () => time.latestBlock(), blocknumber: () => time.latestBlock(),
@ -13,6 +15,15 @@ module.exports = {
}, },
forward: { forward: {
blocknumber: mineUpTo, blocknumber: mineUpTo,
timestamp: time.increaseTo, timestamp: (to, mine = true) => (mine ? time.increaseTo(to) : time.setNextBlockTimestamp(to)),
}, },
duration: time.duration,
};
// TODO: deprecate the old version in favor of this one
module.exports.bigint = {
clock: mapObject(module.exports.clock, fn => () => fn().then(BigInt)),
clockFromReceipt: mapObject(module.exports.clockFromReceipt, fn => receipt => fn(receipt).then(BigInt)),
forward: module.exports.forward,
duration: mapObject(module.exports.duration, fn => n => BigInt(fn(n))),
}; };

@ -1,9 +1,9 @@
const { makeInterfaceId } = require('@openzeppelin/test-helpers'); const { ethers } = require('ethers');
const { expect } = require('chai'); const { expect } = require('chai');
const { selector } = require('../../helpers/methods');
const INVALID_ID = '0xffffffff'; const INVALID_ID = '0xffffffff';
const INTERFACES = { const SIGNATURES = {
ERC165: ['supportsInterface(bytes4)'], ERC165: ['supportsInterface(bytes4)'],
ERC721: [ ERC721: [
'balanceOf(address)', 'balanceOf(address)',
@ -81,27 +81,27 @@ const INTERFACES = {
ERC2981: ['royaltyInfo(uint256,uint256)'], ERC2981: ['royaltyInfo(uint256,uint256)'],
}; };
const INTERFACE_IDS = {}; const INTERFACE_IDS = Object.fromEntries(
const FN_SIGNATURES = {}; Object.entries(SIGNATURES).map(([name, signatures]) => [
for (const k of Object.getOwnPropertyNames(INTERFACES)) { name,
INTERFACE_IDS[k] = makeInterfaceId.ERC165(INTERFACES[k]); ethers.toBeHex(
for (const fnName of INTERFACES[k]) { signatures.reduce((id, fnSig) => id ^ BigInt(selector(fnSig)), 0n),
// the interface id of a single function is equivalent to its function signature 4,
FN_SIGNATURES[fnName] = makeInterfaceId.ERC165([fnName]); ),
} ]),
} );
function shouldSupportInterfaces(interfaces = []) { function shouldSupportInterfaces(interfaces = []) {
describe('ERC165', function () { describe('ERC165', function () {
beforeEach(function () { beforeEach(function () {
this.contractUnderTest = this.mock || this.token || this.holder || this.accessControl; this.contractUnderTest = this.mock || this.token || this.holder;
}); });
describe('when the interfaceId is supported', function () { describe('when the interfaceId is supported', function () {
it('uses less than 30k gas', async function () { it('uses less than 30k gas', async function () {
for (const k of interfaces) { for (const k of interfaces) {
const interfaceId = INTERFACE_IDS[k] ?? k; const interface = INTERFACE_IDS[k] ?? k;
expect(await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).to.be.lte(30000); expect(await this.contractUnderTest.supportsInterface.estimateGas(interface)).to.be.lte(30000);
} }
}); });
@ -126,13 +126,18 @@ function shouldSupportInterfaces(interfaces = []) {
it('all interface functions are in ABI', async function () { it('all interface functions are in ABI', async function () {
for (const k of interfaces) { for (const k of interfaces) {
// skip interfaces for which we don't have a function list // skip interfaces for which we don't have a function list
if (INTERFACES[k] === undefined) continue; if (SIGNATURES[k] === undefined) continue;
for (const fnName of INTERFACES[k]) { for (const fnSig of SIGNATURES[k]) {
const fnSig = FN_SIGNATURES[fnName]; // TODO: Remove Truffle case when ethersjs migration is done
expect(this.contractUnderTest.abi.filter(fn => fn.signature === fnSig).length).to.equal( if (this.contractUnderTest.abi) {
1, const fnSelector = selector(fnSig);
`did not find ${fnName}`, return expect(this.contractUnderTest.abi.filter(fn => fn.signature === fnSelector).length).to.equal(
); 1,
`did not find ${fnSig}`,
);
}
expect(!!this.contractUnderTest.interface.getFunction(fnSig), `did not find ${fnSig}`).to.be.true;
} }
} }
}); });

Loading…
Cancel
Save