feat: update event names for OZ standards and test them

This commit is contained in:
Matt Condon
2017-12-04 13:42:55 +02:00
parent 5e55569db6
commit 677d05743c
4 changed files with 52 additions and 15 deletions

View File

@ -11,14 +11,16 @@ import './Roles.sol';
* See //contracts/examples/RBACExample.sol for an example of usage. * See //contracts/examples/RBACExample.sol for an example of usage.
* This RBAC method uses strings to key roles. It may be beneficial * This RBAC method uses strings to key roles. It may be beneficial
* for you to write your own implementation of this interface using Enums or similar. * for you to write your own implementation of this interface using Enums or similar.
* It's also recommended that you define constants in the contract, like ROLE_ADMIN below,
* to avoid typos.
*/ */
contract RBAC { contract RBAC {
using Roles for Roles.Role; using Roles for Roles.Role;
mapping (string => Roles.Role) private roles; mapping (string => Roles.Role) private roles;
event LogRoleAdded(address addr, string roleName); event RoleAdded(address addr, string roleName);
event LogRoleRemoved(address addr, string roleName); event RoleRemoved(address addr, string roleName);
/** /**
* A constant role name for indicating admins. * A constant role name for indicating admins.
@ -43,7 +45,7 @@ contract RBAC {
internal internal
{ {
roles[roleName].add(addr); roles[roleName].add(addr);
LogRoleAdded(addr, roleName); RoleAdded(addr, roleName);
} }
/** /**
@ -55,7 +57,7 @@ contract RBAC {
internal internal
{ {
roles[roleName].remove(addr); roles[roleName].remove(addr);
LogRoleRemoved(addr, roleName); RoleRemoved(addr, roleName);
} }
/** /**

View File

@ -1,17 +1,21 @@
const RBACMock = artifacts.require('./helpers/RBACMock.sol') const RBACMock = artifacts.require('./mocks/RBACMock.sol')
import expectThrow from './helpers/expectThrow' import expectThrow from './helpers/expectThrow'
import expectEvent from './helpers/expectEvent'
require('chai') require('chai')
.use(require('chai-as-promised')) .use(require('chai-as-promised'))
.should() .should()
const ROLE_ADVISOR = 'advisor';
contract('RBAC', function(accounts) { contract('RBAC', function(accounts) {
let mock let mock
const [ const [
admin, admin,
anyone, anyone,
futureAdvisor,
...advisors ...advisors
] = accounts ] = accounts
@ -60,9 +64,23 @@ contract('RBAC', function(accounts) {
.should.be.fulfilled .should.be.fulfilled
}) })
it('allows admins to #adminRemoveRole', async () => { it('allows admins to #adminRemoveRole', async () => {
await mock.adminRemoveRole(advisors[3], 'advisor', { from: admin }) await mock.adminRemoveRole(advisors[3], ROLE_ADVISOR, { from: admin })
.should.be.fulfilled .should.be.fulfilled
}) })
it('announces a RoleAdded event on addRole', async () => {
expectEvent.inTransaction(
mock.adminAddRole(futureAdvisor, ROLE_ADVISOR, { from: admin }),
'RoleAdded'
)
})
it('announces a RoleRemoved event on removeRole', async () => {
expectEvent.inTransaction(
mock.adminRemoveRole(futureAdvisor, ROLE_ADVISOR, { from: admin }),
'RoleRemoved'
)
})
}) })
context('in adversarial conditions', () => { context('in adversarial conditions', () => {

View File

@ -0,0 +1,16 @@
const assert = require('chai').assert;
const inLogs = async (logs, eventName) => {
const event = logs.find(e => e.event === eventName);
assert.exists(event);
};
const inTransaction = async (tx, eventName) => {
const { logs } = await tx;
return inLogs(logs, eventName);
};
module.exports = {
inLogs,
inTransaction,
};

View File

@ -5,11 +5,13 @@ import '../../contracts/ownership/rbac/RBAC.sol';
contract RBACMock is RBAC { contract RBACMock is RBAC {
string constant ROLE_ADVISOR = "advisor";
modifier onlyAdminOrAdvisor() modifier onlyAdminOrAdvisor()
{ {
require( require(
hasRole(msg.sender, "admin") || hasRole(msg.sender, ROLE_ADMIN) ||
hasRole(msg.sender, "advisor") hasRole(msg.sender, ROLE_ADVISOR)
); );
_; _;
} }
@ -17,23 +19,22 @@ contract RBACMock is RBAC {
function RBACMock(address[] _advisors) function RBACMock(address[] _advisors)
public public
{ {
addRole(msg.sender, "admin"); addRole(msg.sender, ROLE_ADVISOR);
addRole(msg.sender, "advisor");
for (uint256 i = 0; i < _advisors.length; i++) { for (uint256 i = 0; i < _advisors.length; i++) {
addRole(_advisors[i], "advisor"); addRole(_advisors[i], ROLE_ADVISOR);
} }
} }
function onlyAdminsCanDoThis() function onlyAdminsCanDoThis()
onlyRole("admin") onlyAdmin
view view
external external
{ {
} }
function onlyAdvisorsCanDoThis() function onlyAdvisorsCanDoThis()
onlyRole("advisor") onlyRole(ROLE_ADVISOR)
view view
external external
{ {
@ -60,9 +61,9 @@ contract RBACMock is RBAC {
{ {
// revert if the user isn't an advisor // revert if the user isn't an advisor
// (perhaps you want to soft-fail here instead?) // (perhaps you want to soft-fail here instead?)
checkRole(_addr, "advisor"); checkRole(_addr, ROLE_ADVISOR);
// remove the advisor's role // remove the advisor's role
removeRole(_addr, "advisor"); removeRole(_addr, ROLE_ADVISOR);
} }
} }