Reorganize the repo structure (#2503)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
This commit is contained in:
13
test/utils/introspection/ERC165.test.js
Normal file
13
test/utils/introspection/ERC165.test.js
Normal file
@ -0,0 +1,13 @@
|
||||
const { shouldSupportInterfaces } = require('./SupportsInterface.behavior');
|
||||
|
||||
const ERC165Mock = artifacts.require('ERC165Mock');
|
||||
|
||||
contract('ERC165', function (accounts) {
|
||||
beforeEach(async function () {
|
||||
this.mock = await ERC165Mock.new();
|
||||
});
|
||||
|
||||
shouldSupportInterfaces([
|
||||
'ERC165',
|
||||
]);
|
||||
});
|
||||
218
test/utils/introspection/ERC165Checker.test.js
Normal file
218
test/utils/introspection/ERC165Checker.test.js
Normal file
@ -0,0 +1,218 @@
|
||||
require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const ERC165CheckerMock = artifacts.require('ERC165CheckerMock');
|
||||
const ERC165MissingData = artifacts.require('ERC165MissingData');
|
||||
const ERC165NotSupported = artifacts.require('ERC165NotSupported');
|
||||
const ERC165InterfacesSupported = artifacts.require('ERC165InterfacesSupported');
|
||||
|
||||
const DUMMY_ID = '0xdeadbeef';
|
||||
const DUMMY_ID_2 = '0xcafebabe';
|
||||
const DUMMY_ID_3 = '0xdecafbad';
|
||||
const DUMMY_UNSUPPORTED_ID = '0xbaddcafe';
|
||||
const DUMMY_UNSUPPORTED_ID_2 = '0xbaadcafe';
|
||||
const DUMMY_ACCOUNT = '0x1111111111111111111111111111111111111111';
|
||||
|
||||
contract('ERC165Checker', function (accounts) {
|
||||
beforeEach(async function () {
|
||||
this.mock = await ERC165CheckerMock.new();
|
||||
});
|
||||
|
||||
context('ERC165 missing return data', function () {
|
||||
beforeEach(async function () {
|
||||
this.target = await ERC165MissingData.new();
|
||||
});
|
||||
|
||||
it('does not support ERC165', async function () {
|
||||
const supported = await this.mock.supportsERC165(this.target.address);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsInterface', async function () {
|
||||
const supported = await this.mock.supportsInterface(this.target.address, DUMMY_ID);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsAllInterfaces', async function () {
|
||||
const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via getSupportedInterfaces', async function () {
|
||||
const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported.length).to.equal(1);
|
||||
expect(supported[0]).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('ERC165 not supported', function () {
|
||||
beforeEach(async function () {
|
||||
this.target = await ERC165NotSupported.new();
|
||||
});
|
||||
|
||||
it('does not support ERC165', async function () {
|
||||
const supported = await this.mock.supportsERC165(this.target.address);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsInterface', async function () {
|
||||
const supported = await this.mock.supportsInterface(this.target.address, DUMMY_ID);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsAllInterfaces', async function () {
|
||||
const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via getSupportedInterfaces', async function () {
|
||||
const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported.length).to.equal(1);
|
||||
expect(supported[0]).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('ERC165 supported', function () {
|
||||
beforeEach(async function () {
|
||||
this.target = await ERC165InterfacesSupported.new([]);
|
||||
});
|
||||
|
||||
it('supports ERC165', async function () {
|
||||
const supported = await this.mock.supportsERC165(this.target.address);
|
||||
expect(supported).to.equal(true);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsInterface', async function () {
|
||||
const supported = await this.mock.supportsInterface(this.target.address, DUMMY_ID);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsAllInterfaces', async function () {
|
||||
const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via getSupportedInterfaces', async function () {
|
||||
const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported.length).to.equal(1);
|
||||
expect(supported[0]).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('ERC165 and single interface supported', function () {
|
||||
beforeEach(async function () {
|
||||
this.target = await ERC165InterfacesSupported.new([DUMMY_ID]);
|
||||
});
|
||||
|
||||
it('supports ERC165', async function () {
|
||||
const supported = await this.mock.supportsERC165(this.target.address);
|
||||
expect(supported).to.equal(true);
|
||||
});
|
||||
|
||||
it('supports mock interface via supportsInterface', async function () {
|
||||
const supported = await this.mock.supportsInterface(this.target.address, DUMMY_ID);
|
||||
expect(supported).to.equal(true);
|
||||
});
|
||||
|
||||
it('supports mock interface via supportsAllInterfaces', async function () {
|
||||
const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported).to.equal(true);
|
||||
});
|
||||
|
||||
it('supports mock interface via getSupportedInterfaces', async function () {
|
||||
const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
|
||||
expect(supported.length).to.equal(1);
|
||||
expect(supported[0]).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
context('ERC165 and many interfaces supported', function () {
|
||||
beforeEach(async function () {
|
||||
this.supportedInterfaces = [DUMMY_ID, DUMMY_ID_2, DUMMY_ID_3];
|
||||
this.target = await ERC165InterfacesSupported.new(this.supportedInterfaces);
|
||||
});
|
||||
|
||||
it('supports ERC165', async function () {
|
||||
const supported = await this.mock.supportsERC165(this.target.address);
|
||||
expect(supported).to.equal(true);
|
||||
});
|
||||
|
||||
it('supports each interfaceId via supportsInterface', async function () {
|
||||
for (const interfaceId of this.supportedInterfaces) {
|
||||
const supported = await this.mock.supportsInterface(this.target.address, interfaceId);
|
||||
expect(supported).to.equal(true);
|
||||
};
|
||||
});
|
||||
|
||||
it('supports all interfaceIds via supportsAllInterfaces', async function () {
|
||||
const supported = await this.mock.supportsAllInterfaces(this.target.address, this.supportedInterfaces);
|
||||
expect(supported).to.equal(true);
|
||||
});
|
||||
|
||||
it('supports none of the interfaces queried via supportsAllInterfaces', async function () {
|
||||
const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2];
|
||||
|
||||
const supported = await this.mock.supportsAllInterfaces(this.target.address, interfaceIdsToTest);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('supports not all of the interfaces queried via supportsAllInterfaces', async function () {
|
||||
const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID];
|
||||
|
||||
const supported = await this.mock.supportsAllInterfaces(this.target.address, interfaceIdsToTest);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('supports all interfaceIds via getSupportedInterfaces', async function () {
|
||||
const supported = await this.mock.getSupportedInterfaces(this.target.address, this.supportedInterfaces);
|
||||
expect(supported.length).to.equal(3);
|
||||
expect(supported[0]).to.equal(true);
|
||||
expect(supported[1]).to.equal(true);
|
||||
expect(supported[2]).to.equal(true);
|
||||
});
|
||||
|
||||
it('supports none of the interfaces queried via getSupportedInterfaces', async function () {
|
||||
const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2];
|
||||
|
||||
const supported = await this.mock.getSupportedInterfaces(this.target.address, interfaceIdsToTest);
|
||||
expect(supported.length).to.equal(2);
|
||||
expect(supported[0]).to.equal(false);
|
||||
expect(supported[1]).to.equal(false);
|
||||
});
|
||||
|
||||
it('supports not all of the interfaces queried via getSupportedInterfaces', async function () {
|
||||
const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID];
|
||||
|
||||
const supported = await this.mock.getSupportedInterfaces(this.target.address, interfaceIdsToTest);
|
||||
expect(supported.length).to.equal(4);
|
||||
expect(supported[0]).to.equal(true);
|
||||
expect(supported[1]).to.equal(true);
|
||||
expect(supported[2]).to.equal(true);
|
||||
expect(supported[3]).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('account address does not support ERC165', function () {
|
||||
it('does not support ERC165', async function () {
|
||||
const supported = await this.mock.supportsERC165(DUMMY_ACCOUNT);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsInterface', async function () {
|
||||
const supported = await this.mock.supportsInterface(DUMMY_ACCOUNT, DUMMY_ID);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via supportsAllInterfaces', async function () {
|
||||
const supported = await this.mock.supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]);
|
||||
expect(supported).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not support mock interface via getSupportedInterfaces', async function () {
|
||||
const supported = await this.mock.getSupportedInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]);
|
||||
expect(supported.length).to.equal(1);
|
||||
expect(supported[0]).to.equal(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
25
test/utils/introspection/ERC165Storage.test.js
Normal file
25
test/utils/introspection/ERC165Storage.test.js
Normal file
@ -0,0 +1,25 @@
|
||||
const { expectRevert } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { shouldSupportInterfaces } = require('./SupportsInterface.behavior');
|
||||
|
||||
const ERC165Mock = artifacts.require('ERC165StorageMock');
|
||||
|
||||
contract('ERC165Storage', function (accounts) {
|
||||
beforeEach(async function () {
|
||||
this.mock = await ERC165Mock.new();
|
||||
});
|
||||
|
||||
it('register interface', async function () {
|
||||
expect(await this.mock.supportsInterface('0x00000001')).to.be.equal(false);
|
||||
await this.mock.registerInterface('0x00000001');
|
||||
expect(await this.mock.supportsInterface('0x00000001')).to.be.equal(true);
|
||||
});
|
||||
|
||||
it('does not allow 0xffffffff', async function () {
|
||||
await expectRevert(this.mock.registerInterface('0xffffffff'), 'ERC165: invalid interface id');
|
||||
});
|
||||
|
||||
shouldSupportInterfaces([
|
||||
'ERC165',
|
||||
]);
|
||||
});
|
||||
66
test/utils/introspection/ERC1820Implementer.test.js
Normal file
66
test/utils/introspection/ERC1820Implementer.test.js
Normal file
@ -0,0 +1,66 @@
|
||||
const { expectRevert, singletons } = require('@openzeppelin/test-helpers');
|
||||
const { bufferToHex, keccakFromString } = require('ethereumjs-util');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const ERC1820ImplementerMock = artifacts.require('ERC1820ImplementerMock');
|
||||
|
||||
contract('ERC1820Implementer', function (accounts) {
|
||||
const [ registryFunder, implementee, other ] = accounts;
|
||||
|
||||
const ERC1820_ACCEPT_MAGIC = bufferToHex(keccakFromString('ERC1820_ACCEPT_MAGIC'));
|
||||
|
||||
beforeEach(async function () {
|
||||
this.implementer = await ERC1820ImplementerMock.new();
|
||||
this.registry = await singletons.ERC1820Registry(registryFunder);
|
||||
|
||||
this.interfaceA = bufferToHex(keccakFromString('interfaceA'));
|
||||
this.interfaceB = bufferToHex(keccakFromString('interfaceB'));
|
||||
});
|
||||
|
||||
context('with no registered interfaces', function () {
|
||||
it('returns false when interface implementation is queried', async function () {
|
||||
expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceA, implementee))
|
||||
.to.not.equal(ERC1820_ACCEPT_MAGIC);
|
||||
});
|
||||
|
||||
it('reverts when attempting to set as implementer in the registry', async function () {
|
||||
await expectRevert(
|
||||
this.registry.setInterfaceImplementer(
|
||||
implementee, this.interfaceA, this.implementer.address, { from: implementee },
|
||||
),
|
||||
'Does not implement the interface',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('with registered interfaces', function () {
|
||||
beforeEach(async function () {
|
||||
await this.implementer.registerInterfaceForAddress(this.interfaceA, implementee);
|
||||
});
|
||||
|
||||
it('returns true when interface implementation is queried', async function () {
|
||||
expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceA, implementee))
|
||||
.to.equal(ERC1820_ACCEPT_MAGIC);
|
||||
});
|
||||
|
||||
it('returns false when interface implementation for non-supported interfaces is queried', async function () {
|
||||
expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceB, implementee))
|
||||
.to.not.equal(ERC1820_ACCEPT_MAGIC);
|
||||
});
|
||||
|
||||
it('returns false when interface implementation for non-supported addresses is queried', async function () {
|
||||
expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceA, other))
|
||||
.to.not.equal(ERC1820_ACCEPT_MAGIC);
|
||||
});
|
||||
|
||||
it('can be set as an implementer for supported interfaces in the registry', async function () {
|
||||
await this.registry.setInterfaceImplementer(
|
||||
implementee, this.interfaceA, this.implementer.address, { from: implementee },
|
||||
);
|
||||
|
||||
expect(await this.registry.getInterfaceImplementer(implementee, this.interfaceA))
|
||||
.to.equal(this.implementer.address);
|
||||
});
|
||||
});
|
||||
});
|
||||
88
test/utils/introspection/SupportsInterface.behavior.js
Normal file
88
test/utils/introspection/SupportsInterface.behavior.js
Normal file
@ -0,0 +1,88 @@
|
||||
const { makeInterfaceId } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const INTERFACES = {
|
||||
ERC165: [
|
||||
'supportsInterface(bytes4)',
|
||||
],
|
||||
ERC721: [
|
||||
'balanceOf(address)',
|
||||
'ownerOf(uint256)',
|
||||
'approve(address,uint256)',
|
||||
'getApproved(uint256)',
|
||||
'setApprovalForAll(address,bool)',
|
||||
'isApprovedForAll(address,address)',
|
||||
'transferFrom(address,address,uint256)',
|
||||
'safeTransferFrom(address,address,uint256)',
|
||||
'safeTransferFrom(address,address,uint256,bytes)',
|
||||
],
|
||||
ERC721Enumerable: [
|
||||
'totalSupply()',
|
||||
'tokenOfOwnerByIndex(address,uint256)',
|
||||
'tokenByIndex(uint256)',
|
||||
],
|
||||
ERC721Metadata: [
|
||||
'name()',
|
||||
'symbol()',
|
||||
'tokenURI(uint256)',
|
||||
],
|
||||
ERC1155: [
|
||||
'balanceOf(address,uint256)',
|
||||
'balanceOfBatch(address[],uint256[])',
|
||||
'setApprovalForAll(address,bool)',
|
||||
'isApprovedForAll(address,address)',
|
||||
'safeTransferFrom(address,address,uint256,uint256,bytes)',
|
||||
'safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)',
|
||||
],
|
||||
ERC1155Receiver: [
|
||||
'onERC1155Received(address,address,uint256,uint256,bytes)',
|
||||
'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)',
|
||||
],
|
||||
};
|
||||
|
||||
const INTERFACE_IDS = {};
|
||||
const FN_SIGNATURES = {};
|
||||
for (const k of Object.getOwnPropertyNames(INTERFACES)) {
|
||||
INTERFACE_IDS[k] = makeInterfaceId.ERC165(INTERFACES[k]);
|
||||
for (const fnName of INTERFACES[k]) {
|
||||
// the interface id of a single function is equivalent to its function signature
|
||||
FN_SIGNATURES[fnName] = makeInterfaceId.ERC165([fnName]);
|
||||
}
|
||||
}
|
||||
|
||||
function shouldSupportInterfaces (interfaces = []) {
|
||||
describe('Contract interface', function () {
|
||||
beforeEach(function () {
|
||||
this.contractUnderTest = this.mock || this.token || this.holder;
|
||||
});
|
||||
|
||||
for (const k of interfaces) {
|
||||
const interfaceId = INTERFACE_IDS[k];
|
||||
describe(k, function () {
|
||||
describe('ERC165\'s supportsInterface(bytes4)', function () {
|
||||
it('uses less than 30k gas [skip-on-coverage]', async function () {
|
||||
expect(await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).to.be.lte(30000);
|
||||
});
|
||||
|
||||
it('claims support', async function () {
|
||||
expect(await this.contractUnderTest.supportsInterface(interfaceId)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
for (const fnName of INTERFACES[k]) {
|
||||
const fnSig = FN_SIGNATURES[fnName];
|
||||
describe(fnName, function () {
|
||||
it('has to be implemented', function () {
|
||||
expect(this.contractUnderTest.abi.filter(fn => fn.signature === fnSig).length).to.equal(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
shouldSupportInterfaces,
|
||||
};
|
||||
Reference in New Issue
Block a user