From 9cab5eeaf199abc5d6c7b6f9632b897bf3776d63 Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Thu, 20 Sep 2018 09:52:36 -0400 Subject: [PATCH 01/10] add ControllerState object to ControllerTestUtils.js --- test/minting/ControllerTestUtils.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/minting/ControllerTestUtils.js b/test/minting/ControllerTestUtils.js index d11520538..f6b710b5d 100644 --- a/test/minting/ControllerTestUtils.js +++ b/test/minting/ControllerTestUtils.js @@ -14,11 +14,16 @@ var setAccountDefault = AccountUtils.setAccountDefault; var checkState = AccountUtils.checkState; var getAccountState = AccountUtils.getAccountState; +var ControllerState(owner, controllers) { + this.owner = owner; + this.controllers = controllers; + this.checkState = checkControllerState; +} + // Default state of Controller when it is deployed -var controllerEmptyState = { - 'owner': Accounts.mintOwnerAccount, - 'controllers': setAccountDefault(Accounts, "0x0000000000000000000000000000000000000000") -}; +var controllerEmptyState = ControllerState( + Accounts.mintOwnerAccount, + setAccountDefault(Accounts, "0x0000000000000000000000000000000000000000")); // Checks the state of an array of controller contracts async function checkControllerState(controllers, customVars, ignoreExtraStateVariables) { From 7dc6d8f28fc614344663c94b54d4ffd4dae0f84d Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Thu, 20 Sep 2018 16:05:56 -0400 Subject: [PATCH 02/10] checkVariables takes as input either FiatTokenV1 or MintController --- test/AccountUtils.js | 27 ++++++++++--- test/TokenTestUtils.js | 33 ++++++++------- test/minting/ControllerTestUtils.js | 19 ++++----- test/minting/MintControllerTests.js | 62 +++++++++-------------------- test/minting/MintControllerUtils.js | 47 ++++++++++++---------- 5 files changed, 94 insertions(+), 94 deletions(-) diff --git a/test/AccountUtils.js b/test/AccountUtils.js index 1660839e3..f7a8bf950 100644 --- a/test/AccountUtils.js +++ b/test/AccountUtils.js @@ -60,7 +60,7 @@ function cloneState(state) { var clone = {}; for (var attr in state) { var attrValue = state[attr]; - if(isLiteral(attrValue)) { + if(typeof(attrValue) != 'object') { clone[attr] = state[attr]; } else { clone[attr] = cloneState(attrValue); @@ -143,15 +143,30 @@ function isLiteral(object) { // Turns a simple literal object into a printable string function logObject(object) { - var output = ''; + internal_logObject(object, 0); +} + +function internal_logObject(object, stackHeight){ + if(stackHeight > 2) return; + for (var property in object) { - if(isLiteral(object[property])) { - output += property + ':\n' + logObject(object[property]); + var value = object[property]; + if(typeof(value) == 'function') { + console.log("function " + property + "\n"); + } else if(Array.isArray(value)) { + console.log("array " + property); + logObject(value); + } else if(typeof(value) == 'object') { + if(value == null) console.log("object: " + null); + else if(value._isBigNumber) console.log("BigNum: " + value ); + else { + console.log("object " + property + ':\n'); + logObject(value); + } } else { - output += property + ': ' + object[property]+';\n '; + console.log("value " + property + ': ' + value+';\n '); } } - return output; } module.exports = { diff --git a/test/TokenTestUtils.js b/test/TokenTestUtils.js index 28a3ece28..cf9c632c5 100644 --- a/test/TokenTestUtils.js +++ b/test/TokenTestUtils.js @@ -315,23 +315,28 @@ async function checkVariables(_tokens, _customVars) { for (n = 0; n < numTokens; n++) { var token = _tokens[n]; var customVars = _customVars[n]; - let expectedState = buildExpectedState(token, customVars); - if (debugLogging) { - console.log(util.inspect(expectedState, { showHidden: false, depth: null })) - } - let actualState = await getActualState(token); - assertDiff.deepEqual(actualState, expectedState, "difference between expected and actual state"); + if(! Array.isArray(customVars)) { + await customVars.checkState(token); + } else { + let expectedState = buildExpectedState(token, customVars); + if (debugLogging) { + console.log(util.inspect(expectedState, { showHidden: false, depth: null })) + } - // Check that sum of individual balances equals totalSupply - var accounts = [Accounts.arbitraryAccount, Accounts.masterMinterAccount, Accounts.minterAccount, Accounts.pauserAccount, Accounts.blacklisterAccount, Accounts.tokenOwnerAccount, Accounts.upgraderAccount]; - var balanceSum = bigZero; - var x; - for (x = 0; x < accounts.length; x++) { - balanceSum = balanceSum.plus(new BigNumber(await token.balanceOf(accounts[x]))); + let actualState = await getActualState(token); + assertDiff.deepEqual(actualState, expectedState, "difference between expected and actual state"); + + // Check that sum of individual balances equals totalSupply + var accounts = [Accounts.arbitraryAccount, Accounts.masterMinterAccount, Accounts.minterAccount, Accounts.pauserAccount, Accounts.blacklisterAccount, Accounts.tokenOwnerAccount, Accounts.upgraderAccount]; + var balanceSum = bigZero; + var x; + for (x = 0; x < accounts.length; x++) { + balanceSum = balanceSum.plus(new BigNumber(await token.balanceOf(accounts[x]))); + } + var totalSupply = new BigNumber(await token.totalSupply()) + assert(balanceSum.isEqualTo(totalSupply)); } - var totalSupply = new BigNumber(await token.totalSupply()) - assert(balanceSum.isEqualTo(totalSupply)); } } diff --git a/test/minting/ControllerTestUtils.js b/test/minting/ControllerTestUtils.js index f6b710b5d..236dcefc9 100644 --- a/test/minting/ControllerTestUtils.js +++ b/test/minting/ControllerTestUtils.js @@ -14,20 +14,21 @@ var setAccountDefault = AccountUtils.setAccountDefault; var checkState = AccountUtils.checkState; var getAccountState = AccountUtils.getAccountState; -var ControllerState(owner, controllers) { +function ControllerState(owner, controllers) { this.owner = owner; this.controllers = controllers; this.checkState = checkControllerState; } // Default state of Controller when it is deployed -var controllerEmptyState = ControllerState( +var controllerEmptyState = new ControllerState( Accounts.mintOwnerAccount, - setAccountDefault(Accounts, "0x0000000000000000000000000000000000000000")); + setAccountDefault(Accounts, "0x0000000000000000000000000000000000000000") +); // Checks the state of an array of controller contracts -async function checkControllerState(controllers, customVars, ignoreExtraStateVariables) { - await checkState(controllers, customVars, controllerEmptyState, getActualControllerState, Accounts, ignoreExtraStateVariables); +async function checkControllerState(controller, customState) { + await checkState(controller, customState, controllerEmptyState, getActualControllerState, Accounts, true); } // Gets the actual state of the controller contract. @@ -45,12 +46,8 @@ async function getActualControllerState(controllerContract, accounts) { owner, controllerState, ) { - var actualState = { - 'owner': owner, - 'controllers': controllerState, - }; - return actualState; - }) + return new ControllerState(owner, controllerState); + }); } module.exports = { diff --git a/test/minting/MintControllerTests.js b/test/minting/MintControllerTests.js index fb03fad80..ab34d6299 100644 --- a/test/minting/MintControllerTests.js +++ b/test/minting/MintControllerTests.js @@ -8,6 +8,7 @@ var expectRevert = tokenUtils.expectRevert; var mintUtils = require('./MintControllerUtils.js'); var AccountUtils = require('./../AccountUtils.js'); var Accounts = AccountUtils.Accounts; +var MintControllerState = AccountUtils.MintControllerState; var initializeTokenWithProxyAndMintController = mintUtils.initializeTokenWithProxyAndMintController; var checkMintControllerState = mintUtils.checkMintControllerState; @@ -15,20 +16,17 @@ async function run_tests(newToken, accounts) { beforeEach('Make fresh token contract', async function () { rawToken = await newToken(); - var tokenConfig = await initializeTokenWithProxyAndMintController(rawToken); + tokenConfig = await initializeTokenWithProxyAndMintController(rawToken); token = tokenConfig.token; mintController = tokenConfig.mintController; + customState = tokenConfig.customState.clone(); }); it('should mint through mint controller', async function () { var amount = 5000; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); await mintController.configureMinter(amount, {from: Accounts.controller1Account}); - customState = { - 'minterManager': token.address, - 'controllers': {'controller1Account': Accounts.minterAccount } - } - await checkMintControllerState([mintController], [customState]); + customState.controllers['controller1Account'] = Accounts.minterAccount; await token.mint(Accounts.arbitraryAccount, amount, {from: Accounts.minterAccount}); customVars = [ @@ -37,15 +35,11 @@ async function run_tests(newToken, accounts) { { 'variable': 'balances.arbitraryAccount', 'expectedValue': new BigNumber(amount) }, { 'variable': 'totalSupply', 'expectedValue': new BigNumber(amount)} ]; - await checkVariables([token], [customVars]); + await checkVariables([token, mintController], [customVars, customState]); }); it('initial state', async function () { - customState = { - 'minterManager': token.address, - }; - - await checkMintControllerState([mintController], [customState]); + await checkVariables([mintController], [customState]); }); it('only owner configures controller', async function () { @@ -55,17 +49,11 @@ async function run_tests(newToken, accounts) { it('remove controller', async function () { var amount = 5000; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); - customState = { - 'minterManager': token.address, - 'controllers': {'controller1Account': Accounts.minterAccount } - } - await checkMintControllerState([mintController], [customState]); + customState.controllers['controller1Account'] = Accounts.minterAccount; + await checkVariables([mintController], [customState]); await mintController.removeController(Accounts.controller1Account, {from: Accounts.mintOwnerAccount}); - customState = { - 'minterManager': token.address - }; - await checkMintControllerState([mintController], [customState]); + await checkVariables([mintController], [tokenConfig.customState.clone()]); }); it('only owner can remove controller', async function () { @@ -74,6 +62,8 @@ async function run_tests(newToken, accounts) { it('sets token', async function () { await mintController.setMinterManager(mintController.address, {from: Accounts.mintOwnerAccount}); + customState.minterManager = mintController.address; + checkVariables([mintController], [customState]); }); it('only owner sets token', async function () { @@ -85,25 +75,20 @@ async function run_tests(newToken, accounts) { var amount = 500; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); await mintController.configureMinter(amount, {from: Accounts.controller1Account}); - customState = { - 'minterManager': token.address, - 'controllers': {'controller1Account': Accounts.minterAccount } - } - await checkMintControllerState([mintController], [customState]); + customState.controllers['controller1Account'] = Accounts.minterAccount; customVars = [ { 'variable': 'masterMinter', 'expectedValue': mintController.address }, { 'variable': 'isAccountMinter.minterAccount', 'expectedValue': true }, { 'variable': 'minterAllowance.minterAccount', 'expectedValue': new BigNumber(amount) }, ]; - await checkVariables([token], [customVars]); + await checkVariables([token, mintController], [customVars, customState]); // remove minter await mintController.removeMinter({from: Accounts.controller1Account}); - await checkMintControllerState([mintController], [customState]); customVars = [ { 'variable': 'masterMinter', 'expectedValue': mintController.address }, ]; - await checkVariables([token], [customVars]); + await checkVariables([token, mintController], [customVars, customState]); }); it('only controller removes a minter', async function () { @@ -119,27 +104,22 @@ async function run_tests(newToken, accounts) { var amount = 500; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); await mintController.configureMinter(amount, {from: Accounts.controller1Account}); - customState = { - 'minterManager': token.address, - 'controllers': {'controller1Account': Accounts.minterAccount } - } - await checkMintControllerState([mintController], [customState]); + customState.controllers['controller1Account'] = Accounts.minterAccount; customVars = [ { 'variable': 'masterMinter', 'expectedValue': mintController.address }, { 'variable': 'isAccountMinter.minterAccount', 'expectedValue': true }, { 'variable': 'minterAllowance.minterAccount', 'expectedValue': new BigNumber(amount) }, ]; - await checkVariables([token], [customVars]); + await checkVariables([token, mintController], [customVars, customState]); // increment minter allowance await mintController.incrementMinterAllowance(amount, {from: Accounts.controller1Account}); - await checkMintControllerState([mintController], [customState]); customVars = [ { 'variable': 'masterMinter', 'expectedValue': mintController.address }, { 'variable': 'isAccountMinter.minterAccount', 'expectedValue': true }, { 'variable': 'minterAllowance.minterAccount', 'expectedValue': new BigNumber(amount*2) }, ]; - await checkVariables([token], [customVars]); + await checkVariables([token, mintController], [customVars, customState]); }); it('only controller increments allowance', async function () { @@ -150,15 +130,11 @@ async function run_tests(newToken, accounts) { // configure controller but not minter var amount = 500; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); - customState = { - 'minterManager': token.address, - 'controllers': {'controller1Account': Accounts.minterAccount } - } - await checkMintControllerState([mintController], [customState]); + customState.controllers['controller1Account']= Accounts.minterAccount; customVars = [ { 'variable': 'masterMinter', 'expectedValue': mintController.address }, ]; - await checkVariables([token], [customVars]); + await checkVariables([token, mintController], [customVars, customState]); // increment minter allowance await expectRevert(mintController.incrementMinterAllowance(amount, {from: Accounts.controller1Account})); diff --git a/test/minting/MintControllerUtils.js b/test/minting/MintControllerUtils.js index 46188b4ef..228b10f24 100644 --- a/test/minting/MintControllerUtils.js +++ b/test/minting/MintControllerUtils.js @@ -13,30 +13,21 @@ var getAccountState = AccountUtils.getAccountState; var ControllerUtils = require('./ControllerTestUtils'); var checkControllerState = ControllerUtils.checkControllerState; - -// Deploys a FiatTokenV1 with a MintController contract as the masterMinter. -// Uses the same workflow we would do in production - first deploy FiatToken then set the masterMinter. -async function initializeTokenWithProxyAndMintController(rawToken) { - var tokenConfig = await initializeTokenWithProxy(rawToken); - var mintController = await MintController.new(tokenConfig.token.address, {from:Accounts.mintOwnerAccount}); - await tokenConfig.token.updateMasterMinter(mintController.address, {from:Accounts.tokenOwnerAccount}); - var tokenConfigWithMinter = { - proxy: tokenConfig.proxy, - token: tokenConfig.token, - mintController: mintController - }; - return tokenConfigWithMinter; +function MintControllerState(owner, controllers, minterManager) { + this.owner = owner; + this.controllers = controllers; + this.minterManager = minterManager; + this.checkState = async function(mintController) {await checkMintControllerState(mintController, this)}; + this.clone = function(){return new MintControllerState(this.owner, AccountUtils.cloneState(this.controllers), this.minterManager)}; } // Default state of MintController when it is deployed -var mintControllerEmptyState = { - 'minterManager' : bigZero, -}; +var mintControllerEmptyState = new MintControllerState(null, {}, bigZero); // Checks the state of the mintController contract -async function checkMintControllerState(mintControllers, customVars) { - await checkControllerState(mintControllers, customVars, true); - await checkState(mintControllers, customVars, mintControllerEmptyState, getActualMintControllerState, Accounts, true); +async function checkMintControllerState(mintController, customState) { + await checkControllerState(mintController, customState); + await checkState(mintController, customState, mintControllerEmptyState, getActualMintControllerState, Accounts, true); } @@ -48,7 +39,23 @@ async function getActualMintControllerState(mintController, accounts) { }; } +// Deploys a FiatTokenV1 with a MintController contract as the masterMinter. +// Uses the same workflow we would do in production - first deploy FiatToken then set the masterMinter. +async function initializeTokenWithProxyAndMintController(rawToken) { + var tokenConfig = await initializeTokenWithProxy(rawToken); + var mintController = await MintController.new(tokenConfig.token.address, {from:Accounts.mintOwnerAccount}); + await tokenConfig.token.updateMasterMinter(mintController.address, {from:Accounts.tokenOwnerAccount}); + var tokenConfigWithMinter = { + proxy: tokenConfig.proxy, + token: tokenConfig.token, + mintController: mintController, + customState: new MintControllerState(null, {}, tokenConfig.token.address) + }; + return tokenConfigWithMinter; +} + module.exports = { initializeTokenWithProxyAndMintController: initializeTokenWithProxyAndMintController, - checkMintControllerState: checkMintControllerState + checkMintControllerState: checkMintControllerState, + MintControllerState: MintControllerState } \ No newline at end of file From 0eb61a62b770d5ed15e69e7994ff5acc6acfb003 Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Thu, 20 Sep 2018 16:13:49 -0400 Subject: [PATCH 03/10] replaced literal objects with actual objects --- test/minting/ControllerTestUtils.js | 2 ++ test/minting/MintControllerUtils.js | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/minting/ControllerTestUtils.js b/test/minting/ControllerTestUtils.js index 236dcefc9..c1d745a17 100644 --- a/test/minting/ControllerTestUtils.js +++ b/test/minting/ControllerTestUtils.js @@ -18,6 +18,8 @@ function ControllerState(owner, controllers) { this.owner = owner; this.controllers = controllers; this.checkState = checkControllerState; + this.checkState = async function(controllerContract) {await checkControllerState(controllerContract, this)}; + this.clone = function(){return new ControllerState(this.owner, AccountUtils.cloneState(this.controllers))}; } // Default state of Controller when it is deployed diff --git a/test/minting/MintControllerUtils.js b/test/minting/MintControllerUtils.js index 228b10f24..d7f34aa68 100644 --- a/test/minting/MintControllerUtils.js +++ b/test/minting/MintControllerUtils.js @@ -34,9 +34,8 @@ async function checkMintControllerState(mintController, customState) { // Gets the actual state of the mintController contract. // Evaluates all mappings on the provided accounts. async function getActualMintControllerState(mintController, accounts) { - return { - 'minterManager': await mintController.minterManager.call() - }; + var minterManager = await mintController.minterManager.call(); + return new MintControllerState(null, {}, minterManager); } // Deploys a FiatTokenV1 with a MintController contract as the masterMinter. From fd3ded71196919205d34f624043b36fdd6b796d2 Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Wed, 26 Sep 2018 12:26:46 -0400 Subject: [PATCH 04/10] Using library funciton clone(), removing logObject, and creating checkMINTp0 function for unit tests --- package.json | 3 +- test/AccountUtils.js | 50 +------ test/TokenTestUtils.js | 48 ++++--- test/minting/ControllerTestUtils.js | 4 +- test/minting/MintControllerTests.js | 65 +++++----- test/minting/MintControllerUtils.js | 4 +- yarn.lock | 195 +++++++++++++++++++++------- 7 files changed, 222 insertions(+), 147 deletions(-) diff --git a/package.json b/package.json index 2c77626fe..77a2abc70 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "dependencies": { "assert-diff": "^1.2.6", "bignumber.js": "6.0.0", + "clone": "2.1.2", "ethereum-input-data-decoder": "0.0.12", "ethereumjs-abi": "^0.6.5", "ethereumjs-tx": "1.3.1", @@ -33,7 +34,7 @@ "ganache-cli": "6.1.0", "lodash": "^4.17.10", "mkdirp": "^0.5.1", - "npm": "^6.2.0", + "npm": "^6.4.1", "openzeppelin-solidity": "1.11.0", "path": "^0.12.7", "q": "^1.5.1", diff --git a/test/AccountUtils.js b/test/AccountUtils.js index f7a8bf950..2be04f3c2 100644 --- a/test/AccountUtils.js +++ b/test/AccountUtils.js @@ -3,6 +3,7 @@ var debugLogging = false; var assertDiff = require('assert-diff'); assertDiff.options.strict = true; +var clone = require('clone'); // named list of all accounts var Accounts = { @@ -54,26 +55,10 @@ function setAccountDefault(accounts, defaultValue) { return result; } -// Clones a state object -function cloneState(state) { - // for each item in customVars, set the item in expectedState - var clone = {}; - for (var attr in state) { - var attrValue = state[attr]; - if(typeof(attrValue) != 'object') { - clone[attr] = state[attr]; - } else { - clone[attr] = cloneState(attrValue); - } - } - return clone; -} - // return an expectedState that combines customState with the emptyState -// todo: after merge, integrate this with TokenTestUtils.js function buildExpectedPartialState(emptyState, customState, ignoreExtraCustomVars) { // for each item in customVars, set the item in expectedState - var expectedState = cloneState(emptyState); + var expectedState = clone(emptyState); for( var variableName in customState) { // do I ignore extra values @@ -102,7 +87,6 @@ function buildExpectedPartialState(emptyState, customState, ignoreExtraCustomVar // getActualState: async function(token, accounts) => state // accounts: list of accounts on which to evaluate mappings // ignoreExtraCustomVars: ignore _customVars names that are not in the emptyState -// todo: after merge, integrate this with TokenTestUtils.js async function checkState(_tokens, _customVars, emptyState, getActualState, accounts, ignoreExtraCustomVars) { // Iterate over array of tokens. var numTokens = _tokens.length; @@ -141,41 +125,11 @@ function isLiteral(object) { return true; } -// Turns a simple literal object into a printable string -function logObject(object) { - internal_logObject(object, 0); -} - -function internal_logObject(object, stackHeight){ - if(stackHeight > 2) return; - - for (var property in object) { - var value = object[property]; - if(typeof(value) == 'function') { - console.log("function " + property + "\n"); - } else if(Array.isArray(value)) { - console.log("array " + property); - logObject(value); - } else if(typeof(value) == 'object') { - if(value == null) console.log("object: " + null); - else if(value._isBigNumber) console.log("BigNum: " + value ); - else { - console.log("object " + property + ':\n'); - logObject(value); - } - } else { - console.log("value " + property + ': ' + value+';\n '); - } - } -} - module.exports = { Accounts: Accounts, AccountPrivateKeys: AccountPrivateKeys, setAccountDefault: setAccountDefault, - cloneState: cloneState, buildExpectedPartialState: buildExpectedPartialState, checkState: checkState, - logObject: logObject, getAccountState: getAccountState, } \ No newline at end of file diff --git a/test/TokenTestUtils.js b/test/TokenTestUtils.js index cf9c632c5..f9cd4fb67 100644 --- a/test/TokenTestUtils.js +++ b/test/TokenTestUtils.js @@ -316,30 +316,41 @@ async function checkVariables(_tokens, _customVars) { var token = _tokens[n]; var customVars = _customVars[n]; - if(! Array.isArray(customVars)) { - await customVars.checkState(token); - } else { - let expectedState = buildExpectedState(token, customVars); - if (debugLogging) { - console.log(util.inspect(expectedState, { showHidden: false, depth: null })) - } + let expectedState = buildExpectedState(token, customVars); + if (debugLogging) { + console.log(util.inspect(expectedState, { showHidden: false, depth: null })) + } - let actualState = await getActualState(token); - assertDiff.deepEqual(actualState, expectedState, "difference between expected and actual state"); + let actualState = await getActualState(token); + assertDiff.deepEqual(actualState, expectedState, "difference between expected and actual state"); - // Check that sum of individual balances equals totalSupply - var accounts = [Accounts.arbitraryAccount, Accounts.masterMinterAccount, Accounts.minterAccount, Accounts.pauserAccount, Accounts.blacklisterAccount, Accounts.tokenOwnerAccount, Accounts.upgraderAccount]; - var balanceSum = bigZero; - var x; - for (x = 0; x < accounts.length; x++) { - balanceSum = balanceSum.plus(new BigNumber(await token.balanceOf(accounts[x]))); - } - var totalSupply = new BigNumber(await token.totalSupply()) - assert(balanceSum.isEqualTo(totalSupply)); + // Check that sum of individual balances equals totalSupply + var accounts = [Accounts.arbitraryAccount, Accounts.masterMinterAccount, Accounts.minterAccount, Accounts.pauserAccount, Accounts.blacklisterAccount, Accounts.tokenOwnerAccount, Accounts.upgraderAccount]; + var balanceSum = bigZero; + var x; + for (x = 0; x < accounts.length; x++) { + balanceSum = balanceSum.plus(new BigNumber(await token.balanceOf(accounts[x]))); } + var totalSupply = new BigNumber(await token.totalSupply()) + assert(balanceSum.isEqualTo(totalSupply)); } } +// All MINT p0 tests will call this function. +// _contracts is an array of exactly two values: a FiatTokenV1 and a MintController +// _customVars is an array of exactly two values: the expected state of the FiatTokenV1 +// and the expected state of the MintController +async function checkMINTp0(_contracts, _customVars) { + assert.equal(_contracts.length, 2); + assert.equal(_customVars.length, 2); + + // the first is a FiatTokenV1 + await checkVariables([_contracts[0]], [_customVars[0]]); + + // the second is a MintController + await _customVars[1].checkState(_contracts[1]); +} + // build up actualState object to compare to expectedState object async function getActualState(token) { return Q.all([ @@ -930,6 +941,7 @@ module.exports = { checkAdminChangedEvent: checkAdminChangedEvent, buildExpectedState, checkVariables: checkVariables, + checkMINTp0: checkMINTp0, setMinter: setMinter, mint: mint, burn: burn, diff --git a/test/minting/ControllerTestUtils.js b/test/minting/ControllerTestUtils.js index c1d745a17..b06f7fcf8 100644 --- a/test/minting/ControllerTestUtils.js +++ b/test/minting/ControllerTestUtils.js @@ -1,5 +1,6 @@ var BigNumber = require('bignumber.js'); var Q = require('q'); +var clone = require('clone'); // set to true to enable verbose logging in the tests var debugLogging = false; @@ -19,7 +20,8 @@ function ControllerState(owner, controllers) { this.controllers = controllers; this.checkState = checkControllerState; this.checkState = async function(controllerContract) {await checkControllerState(controllerContract, this)}; - this.clone = function(){return new ControllerState(this.owner, AccountUtils.cloneState(this.controllers))}; +// this.clone = function(){return clone(this);}; + //this.clone = function(){return new ControllerState(this.owner, clone(this.controllers))}; } // Default state of Controller when it is deployed diff --git a/test/minting/MintControllerTests.js b/test/minting/MintControllerTests.js index ab34d6299..d7b278c4e 100644 --- a/test/minting/MintControllerTests.js +++ b/test/minting/MintControllerTests.js @@ -2,8 +2,11 @@ var MintController = artifacts.require('minting/MintController'); var BigNumber = require('bignumber.js'); var tokenUtils = require('./../TokenTestUtils'); -var checkVariables = tokenUtils.checkVariables; +var checkMINTp0 = tokenUtils.checkMINTp0; var expectRevert = tokenUtils.expectRevert; +var bigZero = tokenUtils.bigZero; + +var clone = require('clone'); var mintUtils = require('./MintControllerUtils.js'); var AccountUtils = require('./../AccountUtils.js'); @@ -19,27 +22,27 @@ async function run_tests(newToken, accounts) { tokenConfig = await initializeTokenWithProxyAndMintController(rawToken); token = tokenConfig.token; mintController = tokenConfig.mintController; - customState = tokenConfig.customState.clone(); + expectedMintControllerState = clone(tokenConfig.customState); + expectedTokenState = [{ 'variable': 'masterMinter', 'expectedValue': mintController.address }]; }); it('should mint through mint controller', async function () { var amount = 5000; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); await mintController.configureMinter(amount, {from: Accounts.controller1Account}); - customState.controllers['controller1Account'] = Accounts.minterAccount; + expectedMintControllerState.controllers['controller1Account'] = Accounts.minterAccount; await token.mint(Accounts.arbitraryAccount, amount, {from: Accounts.minterAccount}); - customVars = [ - { 'variable': 'masterMinter', 'expectedValue': mintController.address }, + expectedTokenState.push( { 'variable': 'isAccountMinter.minterAccount', 'expectedValue': true }, { 'variable': 'balances.arbitraryAccount', 'expectedValue': new BigNumber(amount) }, { 'variable': 'totalSupply', 'expectedValue': new BigNumber(amount)} - ]; - await checkVariables([token, mintController], [customVars, customState]); + ); + await checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); }); it('initial state', async function () { - await checkVariables([mintController], [customState]); + await checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); }); it('only owner configures controller', async function () { @@ -49,11 +52,12 @@ async function run_tests(newToken, accounts) { it('remove controller', async function () { var amount = 5000; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); - customState.controllers['controller1Account'] = Accounts.minterAccount; - await checkVariables([mintController], [customState]); + expectedMintControllerState.controllers['controller1Account'] = Accounts.minterAccount; + await checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); await mintController.removeController(Accounts.controller1Account, {from: Accounts.mintOwnerAccount}); - await checkVariables([mintController], [tokenConfig.customState.clone()]); + expectedMintControllerState.controllers['controller1Account'] = bigZero; + await checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); }); it('only owner can remove controller', async function () { @@ -62,8 +66,8 @@ async function run_tests(newToken, accounts) { it('sets token', async function () { await mintController.setMinterManager(mintController.address, {from: Accounts.mintOwnerAccount}); - customState.minterManager = mintController.address; - checkVariables([mintController], [customState]); + expectedMintControllerState.minterManager = mintController.address; + checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); }); it('only owner sets token', async function () { @@ -75,20 +79,19 @@ async function run_tests(newToken, accounts) { var amount = 500; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); await mintController.configureMinter(amount, {from: Accounts.controller1Account}); - customState.controllers['controller1Account'] = Accounts.minterAccount; - customVars = [ - { 'variable': 'masterMinter', 'expectedValue': mintController.address }, + expectedMintControllerState.controllers['controller1Account'] = Accounts.minterAccount; + expectedTokenState.push( { 'variable': 'isAccountMinter.minterAccount', 'expectedValue': true }, { 'variable': 'minterAllowance.minterAccount', 'expectedValue': new BigNumber(amount) }, - ]; - await checkVariables([token, mintController], [customVars, customState]); + ); + await checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); // remove minter await mintController.removeMinter({from: Accounts.controller1Account}); - customVars = [ + expectedTokenState = [ { 'variable': 'masterMinter', 'expectedValue': mintController.address }, ]; - await checkVariables([token, mintController], [customVars, customState]); + await checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); }); it('only controller removes a minter', async function () { @@ -104,22 +107,21 @@ async function run_tests(newToken, accounts) { var amount = 500; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); await mintController.configureMinter(amount, {from: Accounts.controller1Account}); - customState.controllers['controller1Account'] = Accounts.minterAccount; - customVars = [ - { 'variable': 'masterMinter', 'expectedValue': mintController.address }, + expectedMintControllerState.controllers['controller1Account'] = Accounts.minterAccount; + expectedTokenState.push( { 'variable': 'isAccountMinter.minterAccount', 'expectedValue': true }, { 'variable': 'minterAllowance.minterAccount', 'expectedValue': new BigNumber(amount) }, - ]; - await checkVariables([token, mintController], [customVars, customState]); + ); + await checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); // increment minter allowance await mintController.incrementMinterAllowance(amount, {from: Accounts.controller1Account}); - customVars = [ + expectedTokenState = [ { 'variable': 'masterMinter', 'expectedValue': mintController.address }, { 'variable': 'isAccountMinter.minterAccount', 'expectedValue': true }, { 'variable': 'minterAllowance.minterAccount', 'expectedValue': new BigNumber(amount*2) }, ]; - await checkVariables([token, mintController], [customVars, customState]); + await checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); }); it('only controller increments allowance', async function () { @@ -130,17 +132,12 @@ async function run_tests(newToken, accounts) { // configure controller but not minter var amount = 500; await mintController.configureController(Accounts.controller1Account, Accounts.minterAccount, {from: Accounts.mintOwnerAccount}); - customState.controllers['controller1Account']= Accounts.minterAccount; - customVars = [ - { 'variable': 'masterMinter', 'expectedValue': mintController.address }, - ]; - await checkVariables([token, mintController], [customVars, customState]); + expectedMintControllerState.controllers['controller1Account']= Accounts.minterAccount; + await checkMINTp0([token, mintController], [expectedTokenState, expectedMintControllerState]); // increment minter allowance await expectRevert(mintController.incrementMinterAllowance(amount, {from: Accounts.controller1Account})); }); - - } var testWrapper = require('./../TestWrapper'); diff --git a/test/minting/MintControllerUtils.js b/test/minting/MintControllerUtils.js index d7f34aa68..eca81121e 100644 --- a/test/minting/MintControllerUtils.js +++ b/test/minting/MintControllerUtils.js @@ -1,5 +1,6 @@ var BigNumber = require('bignumber.js'); var bigZero = new BigNumber(0); +var clone = require('clone'); var tokenUtils = require('./../TokenTestUtils'); var initializeTokenWithProxy = tokenUtils.initializeTokenWithProxy; @@ -18,7 +19,8 @@ function MintControllerState(owner, controllers, minterManager) { this.controllers = controllers; this.minterManager = minterManager; this.checkState = async function(mintController) {await checkMintControllerState(mintController, this)}; - this.clone = function(){return new MintControllerState(this.owner, AccountUtils.cloneState(this.controllers), this.minterManager)}; +// this.clone = function(){return clone(this);}; +// this.clone = function(){return new MintControllerState(this.owner, clone(this.controllers), this.minterManager)}; } // Default state of MintController when it is deployed diff --git a/yarn.lock b/yarn.lock index 8614b4960..b10c67eb3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,9 +23,9 @@ version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" -JSONStream@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.3.tgz#27b4b8fbbfeab4e71bcf551e7f27be8d952239bf" +JSONStream@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.4.tgz#615bb2adb0cd34c8f4c447b5f6512fa1d8f16a2e" dependencies: jsonparse "^1.2.0" through ">=2.2.7 <3" @@ -1329,6 +1329,25 @@ cacache@^11.0.1, cacache@^11.0.2: unique-filename "^1.1.0" y18n "^4.0.0" +cacache@^11.2.0: + version "11.2.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.2.0.tgz#617bdc0b02844af56310e411c0878941d5739965" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + figgy-pudding "^3.1.0" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.3" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.0" + unique-filename "^1.1.0" + y18n "^4.0.0" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -1482,6 +1501,10 @@ ci-info@^1.0.0: version "1.1.3" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" +ci-info@^1.4.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" + cidr-regex@^2.0.8: version "2.0.9" resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-2.0.9.tgz#9c17bb2b18e15af07f7d0c3b994b961d687ed1c9" @@ -1605,14 +1628,14 @@ clone-stats@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" +clone@2.1.2, clone@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + clone@^1.0.0, clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" -clone@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - clone@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" @@ -1912,7 +1935,7 @@ debug@3.1.0, debug@^3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" -debuglog@^1.0.1: +debuglog@*, debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -2779,6 +2802,10 @@ figgy-pudding@^3.0.0, figgy-pudding@^3.1.0, figgy-pudding@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.2.0.tgz#464626b73d7b0fc045a99753d191b0785957ff73" +figgy-pudding@^3.4.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + figures@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -3489,7 +3516,7 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0, hosted-git-info@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" @@ -3559,7 +3586,7 @@ iferr@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" -iferr@^1.0.0: +iferr@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/iferr/-/iferr-1.0.2.tgz#e9fde49a9da06dc4a4194c6c9ed6d08305037a6d" @@ -3592,7 +3619,7 @@ import-local@^1.0.0: pkg-dir "^2.0.0" resolve-cwd "^2.0.0" -imurmurhash@^0.1.4: +imurmurhash@*, imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -4327,9 +4354,9 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libcipm@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-2.0.1.tgz#2f4ebf8562e0fc6e46f415373674e4cf3ac4b9ba" +libcipm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-2.0.2.tgz#4f38c2b37acf2ec156936cef1cbf74636568fc7b" dependencies: bin-links "^1.1.2" bluebird "^3.5.1" @@ -4483,6 +4510,10 @@ lockfile@^1.0.4: dependencies: signal-exit "^3.0.2" +lodash._baseindexof@*: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -4490,10 +4521,28 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" +lodash._bindcallback@*: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._cacheindexof@*: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + +lodash._createcache@*: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + dependencies: + lodash._getnative "^3.0.0" + lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" +lodash._getnative@*, lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + lodash._root@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" @@ -4514,6 +4563,10 @@ lodash.isstring@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" +lodash.restparam@*: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + lodash.union@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" @@ -5002,7 +5055,7 @@ node-forge@^0.7.4: version "0.7.5" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" -node-gyp@^3.6.2, node-gyp@^3.7.0: +node-gyp@^3.6.2: version "3.7.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.7.0.tgz#789478e8f6c45e277aa014f3e28f958f286f9203" dependencies: @@ -5019,6 +5072,23 @@ node-gyp@^3.6.2, node-gyp@^3.7.0: tar "^2.0.0" which "1" +node-gyp@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + node-pre-gyp@^0.10.0: version "0.10.3" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" @@ -5111,6 +5181,19 @@ npm-lifecycle@^2.0.3: umask "^1.1.0" which "^1.3.0" +npm-lifecycle@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.1.0.tgz#1eda2eedb82db929e3a0c50341ab0aad140ed569" + dependencies: + byline "^5.0.0" + graceful-fs "^4.1.11" + node-gyp "^3.8.0" + resolve-from "^4.0.0" + slide "^1.1.6" + uid-number "0.0.6" + umask "^1.1.0" + which "^1.3.1" + npm-logical-tree@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz#44610141ca24664cad35d1e607176193fd8f5b88" @@ -5124,7 +5207,7 @@ npm-logical-tree@^1.2.1: semver "^5.5.0" validate-npm-package-name "^3.0.0" -npm-packlist@^1.1.10, npm-packlist@^1.1.6, npm-packlist@~1.1.10: +npm-packlist@^1.1.10, npm-packlist@^1.1.11, npm-packlist@^1.1.6: version "1.1.11" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" dependencies: @@ -5145,7 +5228,7 @@ npm-profile@^3.0.2: aproba "^1.1.2 || 2" make-fetch-happen "^2.5.0 || 3 || 4" -npm-registry-client@^8.5.1: +npm-registry-client@^8.6.0: version "8.6.0" resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-8.6.0.tgz#7f1529f91450732e89f8518e0f21459deea3e4c4" dependencies: @@ -5194,11 +5277,11 @@ npm-user-validate@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.0.tgz#8ceca0f5cea04d4e93519ef72d0557a75122e951" -npm@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/npm/-/npm-6.2.0.tgz#2cee4b52825a91f531cd324a3b0f6e105be40c16" +npm@^6.4.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/npm/-/npm-6.4.1.tgz#4f39f9337b557a28faed4a771d5c8802d6b4288b" dependencies: - JSONStream "^1.3.3" + JSONStream "^1.3.4" abbrev "~1.1.1" ansicolors "~0.3.2" ansistyles "~0.1.3" @@ -5207,9 +5290,10 @@ npm@^6.2.0: bin-links "^1.1.2" bluebird "~3.5.1" byte-size "^4.0.3" - cacache "^11.0.2" + cacache "^11.2.0" call-limit "~1.1.0" chownr "~1.0.1" + ci-info "^1.4.0" cli-columns "^3.1.2" cli-table3 "^0.5.0" cmd-shim "~2.0.2" @@ -5219,7 +5303,7 @@ npm@^6.2.0: detect-newline "^2.1.0" dezalgo "~1.0.3" editor "~1.0.0" - figgy-pudding "^3.1.0" + figgy-pudding "^3.4.1" find-npm-prefix "^1.0.2" fs-vacuum "~1.2.10" fs-write-stream-atomic "~1.0.10" @@ -5227,8 +5311,8 @@ npm@^6.2.0: glob "~7.1.2" graceful-fs "~4.1.11" has-unicode "~2.0.1" - hosted-git-info "^2.6.0" - iferr "^1.0.0" + hosted-git-info "^2.7.1" + iferr "^1.0.2" inflight "~1.0.6" inherits "~2.0.3" ini "^1.3.5" @@ -5236,7 +5320,7 @@ npm@^6.2.0: is-cidr "^2.0.6" json-parse-better-errors "^1.0.2" lazy-property "~1.0.0" - libcipm "^2.0.0" + libcipm "^2.0.2" libnpmhook "^4.0.1" libnpx "^10.2.0" lock-verify "^2.0.2" @@ -5251,23 +5335,23 @@ npm@^6.2.0: mississippi "^3.0.0" mkdirp "~0.5.1" move-concurrently "^1.0.1" - node-gyp "^3.7.0" + node-gyp "^3.8.0" nopt "~4.0.1" normalize-package-data "~2.4.0" npm-audit-report "^1.3.1" npm-cache-filename "~1.0.2" npm-install-checks "~3.0.0" - npm-lifecycle "^2.0.3" + npm-lifecycle "^2.1.0" npm-package-arg "^6.1.0" - npm-packlist "~1.1.10" + npm-packlist "^1.1.11" npm-pick-manifest "^2.1.0" npm-profile "^3.0.2" - npm-registry-client "^8.5.1" + npm-registry-client "^8.6.0" npm-registry-fetch "^1.1.0" npm-user-validate "~1.0.0" npmlog "~4.1.2" once "~1.4.0" - opener "~1.4.3" + opener "^1.5.0" osenv "^0.1.5" pacote "^8.1.6" path-is-inside "~1.0.2" @@ -5281,7 +5365,7 @@ npm@^6.2.0: read-package-json "^2.0.13" read-package-tree "^5.2.1" readable-stream "^2.3.6" - request "^2.81.0" + request "^2.88.0" retry "^0.12.0" rimraf "~2.6.2" safe-buffer "^5.1.2" @@ -5291,7 +5375,8 @@ npm@^6.2.0: sorted-object "~2.0.1" sorted-union-stream "~2.1.3" ssri "^6.0.0" - tar "^4.4.4" + stringify-package "^1.0.0" + tar "^4.4.6" text-table "~0.2.0" tiny-relative-date "^1.3.0" uid-number "0.0.6" @@ -5300,11 +5385,10 @@ npm@^6.2.0: unpipe "~1.0.0" update-notifier "^2.5.0" uuid "^3.3.2" - validate-npm-package-license "^3.0.3" + validate-npm-package-license "^3.0.4" validate-npm-package-name "~3.0.0" which "^1.3.1" worker-farm "^1.6.0" - wrappy "~1.0.2" write-file-atomic "^2.3.0" "npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.2, npmlog@~4.1.2: @@ -5408,9 +5492,9 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -opener@~1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" +opener@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" openurl@1.1.1: version "1.1.1" @@ -6065,7 +6149,7 @@ readable-stream@~1.0.15: isarray "0.0.1" string_decoder "~0.10.x" -readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: @@ -6233,7 +6317,7 @@ req-from@^1.0.1: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@^2.67.0: +request@^2.67.0, request@^2.87.0, request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" dependencies: @@ -6258,7 +6342,7 @@ request@^2.67.0: tunnel-agent "^0.6.0" uuid "^3.3.2" -request@^2.74.0, request@^2.81.0: +request@^2.74.0: version "2.87.0" resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" dependencies: @@ -7066,6 +7150,10 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +stringify-package@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.0.tgz#e02828089333d7d45cd8c287c30aa9a13375081b" + stringstream@~0.0.4: version "0.0.6" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" @@ -7177,7 +7265,7 @@ tar@^2.0.0: fstream "^1.0.2" inherits "2" -tar@^4, tar@^4.4.3, tar@^4.4.4: +tar@^4, tar@^4.4.3: version "4.4.4" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" dependencies: @@ -7189,6 +7277,18 @@ tar@^4, tar@^4.4.3, tar@^4.4.4: safe-buffer "^5.1.2" yallist "^3.0.2" +tar@^4.4.6: + version "4.4.6" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + temp@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" @@ -7532,13 +7632,20 @@ v8-compile-cache@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.0.tgz#526492e35fc616864284700b7043e01baee09f0a" -validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3: +validate-npm-package-license@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +validate-npm-package-license@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" @@ -7759,7 +7866,7 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" -wrappy@1, wrappy@~1.0.2: +wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" From 59ec401e96a9b747b3c0b37cdf7fd3e2ae3fa190 Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Fri, 28 Sep 2018 16:30:33 -0400 Subject: [PATCH 05/10] Adding spreadsheets --- ...ContractStateChanges - ABIHackingTests.csv | 18 ++++++ .../ContractStateChanges - EventTests.csv | 18 ++++++ ...ctStateChanges - ExtendedPositiveTests.csv | 37 +++++++++++++ .../ContractStateChanges - MiscTests.csv | 34 ++++++++++++ .../ContractStateChanges - NegativeTests.csv | 49 +++++++++++++++++ .../ContractStateChanges - PositiveTests.csv | 29 ++++++++++ ...tractStateChanges - ProxyNegativeTests.csv | 11 ++++ ...tractStateChanges - ProxyPositiveTests.csv | 15 +++++ ...actStateChanges - UnitTestCompleteness.csv | 36 ++++++++++++ .../MINTp0UnitTests - ABITests.csv | 3 + .../MINTp0UnitTests - ArgumentTests.csv | 20 +++++++ .../MINTp0UnitTests - BasicTests.csv | 55 +++++++++++++++++++ .../MINTp0UnitTests - EndToEndTests.csv | 20 +++++++ .../MINTp0UnitTests - EventTests.csv | 8 +++ 14 files changed, 353 insertions(+) create mode 100644 verification/Spreadsheets/ContractStateChanges - ABIHackingTests.csv create mode 100644 verification/Spreadsheets/ContractStateChanges - EventTests.csv create mode 100644 verification/Spreadsheets/ContractStateChanges - ExtendedPositiveTests.csv create mode 100644 verification/Spreadsheets/ContractStateChanges - MiscTests.csv create mode 100644 verification/Spreadsheets/ContractStateChanges - NegativeTests.csv create mode 100644 verification/Spreadsheets/ContractStateChanges - PositiveTests.csv create mode 100644 verification/Spreadsheets/ContractStateChanges - ProxyNegativeTests.csv create mode 100644 verification/Spreadsheets/ContractStateChanges - ProxyPositiveTests.csv create mode 100644 verification/Spreadsheets/ContractStateChanges - UnitTestCompleteness.csv create mode 100644 verification/Spreadsheets/MINTp0UnitTests - ABITests.csv create mode 100644 verification/Spreadsheets/MINTp0UnitTests - ArgumentTests.csv create mode 100644 verification/Spreadsheets/MINTp0UnitTests - BasicTests.csv create mode 100644 verification/Spreadsheets/MINTp0UnitTests - EndToEndTests.csv create mode 100644 verification/Spreadsheets/MINTp0UnitTests - EventTests.csv diff --git a/verification/Spreadsheets/ContractStateChanges - ABIHackingTests.csv b/verification/Spreadsheets/ContractStateChanges - ABIHackingTests.csv new file mode 100644 index 000000000..01b4a2bac --- /dev/null +++ b/verification/Spreadsheets/ContractStateChanges - ABIHackingTests.csv @@ -0,0 +1,18 @@ +File,Function,Code,Test +Proxy.sol,_delegate,abi056,abi056 Proxy _delegate is internal +Proxy.sol,_fallback,abi058,abi058 Proxy _fallback is internal +AdminUpgradeabilityProxy.sol,_setAdmin,abi053,abi053 AdminUpgradeabillityProxy _setAdmin is internal +UpgradeabilityProxy.sol,_setImplementation,abi050,abi050 Upgradeability implementation is internal +UpgradeabilityProxy.sol,_upgradeTo,abi028,abi028 UpgradeabilityProxy._upgradeTo is internal +AdminUpgradeabilityProxy.sol,_willFallback,abi057,abi057 Proxy _willFallback is internal +Proxy.sol,_willFallback,abi057,abi057 Proxy _willFallback is internal +AdminUpgradeabilityProxy.sol,AdminUpgradeabilityProxy,abi051,abi051 AdminUpgradeabillityProxy constructor is not a function +Blacklistable.sol,Blacklistable,abi040,abi040 Blacklistable constructor is not a function +FiatTokenV1.sol,FiatToken,abi041,abi041 FiatToken constructor is not a function +Ownable.sol,Ownable,abi042,abi042 Ownable constructor is not a function +Pausable.sol,Pausable,abi005,abi005 Pausable constructor is not a function +FiatTokenV1.sol,pause,abi004,abi004 FiatToken pause() is public +FiatTokenProxy.sol,Proxy,abi043,abi043 FiatTokenProxy constructor is not a function +Proxy.sol,Proxy,abi055,abi055 Proxy constructor is not a function +Ownable.sol,setOwner,abi025,abi025 setOwner is internal +UpgradeabilityProxy.sol,UpgradeabilityProxy,abi027,abi027 UpgradeabilityProxy constructor \ No newline at end of file diff --git a/verification/Spreadsheets/ContractStateChanges - EventTests.csv b/verification/Spreadsheets/ContractStateChanges - EventTests.csv new file mode 100644 index 000000000..484979fb4 --- /dev/null +++ b/verification/Spreadsheets/ContractStateChanges - EventTests.csv @@ -0,0 +1,18 @@ +Event(s),File,Function,Code,Test +MinterConfigured,FiatTokenV1,configureMinter,et000,et000 should check MinterConfigured event +"Mint, Transfer",FiatTokenV1,mint,et001,et001 should check Mint/Transfer events +"Burn, Transfer",FiatTokenV1,burn,et002 ,et002 should check Burn/Transfer events +MinterRemoved,FiatTokenV1,removeMinter,et003,et003 should check MinterRemoved event +MasterMinterChanged,FiatTokenV1,updateMasterMinter,et004,et004 should check MasterMinterChanged event +Blacklisted,Blacklistable,blacklist,et005,et005 should check Blacklisted event +UnBlacklisted,Blacklistable,unBlacklist,et006,et006 should check UnBlacklisted event +BlacklisterChanged,Blacklistable,updateBlacklister,et007,et007 should check BlacklisterChanged event +Upgraded,_upgradeTo,UpgradeabilityProxy,et008,et008 should check Upgraded event +AdminChanged,changeAdmin,AdminUpgradeabilityProxy,et009,et009 should check AdminChanged event +OwnershipTransferred,Ownable,transferOwnership,et010,et010 should check OwnershipTransferred event +Approval,FiatTokenV1,approve,et011,et011 should check Approval event +Pause,Pausable,pause,et012,et012 should check Pause event +Unpause,Pausable,unpause,et013,et013 should check Unpause event +PauserChanged,Pausable,updatePauser,et014,et014 should check PauserChanged event +Transfer,FiatTokenV1,transfer,et015,et015 should check Transfer event +Transfer,FiatTokenV1,transferFrom,et016,et016 should check Transfer event in transferFrom \ No newline at end of file diff --git a/verification/Spreadsheets/ContractStateChanges - ExtendedPositiveTests.csv b/verification/Spreadsheets/ContractStateChanges - ExtendedPositiveTests.csv new file mode 100644 index 000000000..15d17ee83 --- /dev/null +++ b/verification/Spreadsheets/ContractStateChanges - ExtendedPositiveTests.csv @@ -0,0 +1,37 @@ +variable type,visibility,variable name,Modification Function,Arguments,Result,Special Condition,Code,Test +mapping(address => bool),internal,blacklisted,blacklist,_account,blacklisted[_account] = true,blacklisted[_account] == true,ept024,ept024 should blacklist a blacklisted address +address,ifAdmin,implementation(),upgradeTo,newImplementation,"sstore(slot, newImplementation)",blacklisted[newImplementation] == true,ept023,ept023 should upgrade to blacklisted address +address,public,blacklister,updateBlacklister,_newBlacklister,blacklister = _newBlacklister,blacklisted[_newBlacklister] == true,ept027,ept027 should updateBlacklister to blacklisted address +address,public,masterMinter,updateMasterMinter,_newMasterMinter,masterMinter = _newMasterMinter,blacklisted[_newMasterMinter ] == true,ept026,ept026 should updateMasterMinter to blacklisted address +mapping(address => uint256),internal,minterAllowed,removeMinter,minter,minterAllowed[minter] = 0,blacklisted[masterMinter ] == true,ept033,ept033 should removeMinter when masterMinter is blacklisted +mapping(address => bool),internal,minters,removeMinter,minter,minters[minter] = false,blacklisted[masterMinter ] == true,ept033,ept033 should removeMinter when masterMinter is blacklisted +address,private,_owner,transferOwnership,newOwner,_owner = newOwner,blacklisted[newOwner] == true,ept029,ept029 should transferOwnership to blacklisted address +address,public,pauser,updatePauser,_newPauser,pauser = _newPauser,blacklisted[_newPauser] == true,ept028,ept028 should updatePauser to blacklisted address +mapping(address => uint256),internal,minterAllowed,configureMinter,"minter, minterAllowedAmount",minterAllowed[minter] = minterAllowedAmount,blacklisted[masterMinter] == true,ept030,ept030 should configureMinter when masterMinter is blacklisted +mapping(address => bool),internal,minters,configureMinter,"minter, minterAllowedAmount",minters[minter] = true ,blacklisted[masterMinter] == true,ept030,ept030 should configureMinter when masterMinter is blacklisted +mapping(address => uint256),internal,minterAllowed,configureMinter,"minter, minterAllowedAmount",minterAllowed[minter] = minterAllowedAmount,blacklisted[minter] == true,ept032,ept032 should configureMinter when minter is blacklisted +mapping(address => bool),internal,minters,configureMinter,"minter, minterAllowedAmount",minters[minter] = true ,blacklisted[minter] == true,ept032,ept032 should configureMinter when minter is blacklisted +mapping(address => uint256),internal,minterAllowed,removeMinter,minter,minterAllowed[minter] = 0,blacklisted[minter] == true,ept034,ept034 should removeMinter when minter is blacklisted +mapping(address => bool),internal,minters,removeMinter,minter,minters[minter] = false,blacklisted[minter] == true,ept034,ept034 should removeMinter when minter is blacklisted +address,ifAdmin,admin(),changeAdmin,newAdmin,"sstore(slot, newAdmin)",blacklisted[msg.sender] == true,ept013,ept013 should changeAdmin when msg.sender blacklisted +address,public,masterMinter,updateMasterMinter,_newMasterMinter,masterMinter = _newMasterMinter,blacklisted[msg.sender] == true,ept014,ept014 should updateMasterMinter when msg.sender blacklisted +address,public,blacklister,updateBlacklister,_newBlacklister,blacklister = _newBlacklister,blacklisted[msg.sender] == true,ept015,ept015 should updateBlacklister when msg.sender blacklisted +address,public,pauser,updatePauser,_newPauser,pauser = _newPauser,blacklisted[msg.sender] == true,ept016,ept016 should updatePauser when msg.sender blacklisted +address,private,_owner,transferOwnership,newOwner,_owner = newOwner,blacklisted[msg.sender] == true,ept017,ept017 should transferOwnership when msg.sender blacklisted +bool,public,paused,pause,NA,paused = true,blacklisted[msg.sender] == true,ept018,ept018 should pause when msg.sender blacklisted +bool,public,paused,unpause,NA,paused = false ,blacklisted[msg.sender] == true,ept019,ept019 should unpause when msg.sender blacklisted +mapping(address => bool),internal,blacklisted,blacklist,_account,blacklisted[_account] = true,blacklisted[msg.sender] == true,ept020,ept020 should blacklist when msg.sender blacklisted +mapping(address => bool),internal,blacklisted,unBlacklist,_account,blacklisted[_account] = false,blacklisted[msg.sender] == true,ept021,ept021 should unBlacklist when msg.sender blacklisted +address,ifAdmin,implementation(),upgradeTo,newImplementation,"sstore(slot, newImplementation)",blacklisted[msg.sender] == true,ept022,ept022 should upgrade when msg.sender blacklisted +address,ifAdmin,admin(),changeAdmin,newAdmin,"sstore(slot, newAdmin)",blacklisted[newAdmin] == true,ept025,ept025 should changeAdmin to blacklisted address +address,ifAdmin,admin(),changeAdmin,newAdmin,"sstore(slot, newAdmin)",paused == true,ept001,ept001 should changeAdmin while paused +address,public,masterMinter,updateMasterMinter,_newMasterMinter,masterMinter = _newMasterMinter,paused == true,ept002,ept002 should updateMasterMinter while paused +address,public,blacklister,updateBlacklister,_newBlacklister,blacklister = _newBlacklister,paused == true,ept003,ept003 should updateBlacklister while paused +address,public,pauser,updatePauser,_newPauser,pauser = _newPauser,paused == true,ept004,ept004 should updatePauser while paused +address,private,_owner,transferOwnership,newOwner,_owner = newOwner,paused == true,ept005,ept005 should transferOwnership while paused +mapping(address => uint256),internal,minterAllowed,removeMinter,minter,minterAllowed[minter] = 0,paused == true,ept006,ept006 should removeMinter while paused +mapping(address => bool),internal,minters,removeMinter,minter,minters[minter] = false,paused == true,ept006,ept006 should removeMinter while paused +address,ifAdmin,implementation(),upgradeTo,newImplementation,"sstore(slot, newImplementation)",paused == true,ept008,ept008 should upgrade while paused +mapping(address => bool),internal,blacklisted,unBlacklist,_account,blacklisted[_account]= false,paused == true,ept035,ept035 should unBlacklist while contract is paused +mapping(address => bool),internal,blacklisted,blacklist,_account,blacklisted[_account]= true,paused == true,ept036,ept036 should blacklist while contract is paused +bool,public,paused,pause,NA,paused = true ,paused == true,ept037,ept037 should pause while contract is paused \ No newline at end of file diff --git a/verification/Spreadsheets/ContractStateChanges - MiscTests.csv b/verification/Spreadsheets/ContractStateChanges - MiscTests.csv new file mode 100644 index 000000000..da25efe45 --- /dev/null +++ b/verification/Spreadsheets/ContractStateChanges - MiscTests.csv @@ -0,0 +1,34 @@ +Code,Test,Test Type +ms001,ms001 no payable function,No Payable Function +ms002,ms002 should transfer to self has correct final balance,Same Address +ms003,ms003 should transferFrom to self from approved account and have correct final balance,Same Address +ms004,ms004 should transferFrom to self from approved self and have correct final balance,Same Address +ms005,ms005 should mint to self with correct final balance,Same Address +ms006,ms006 should approve correct allowance for self,Same Address +ms007,ms007 should configureMinter for masterMinter,Same Address +ms009,ms009 should configure two minters,Multiple Minters +ms010,ms010 should configure two minters and each mint distinct amounts,Multiple Minters +ms011,"ms011 should configure two minters, each minting distinct amounts and then remove one minter",Multiple Minters +ms012,ms012 should configure two minters and adjust both allowances,Multiple Minters +ms013,"ms013 should configure two minters, one with zero allowance fails to mint",Multiple Minters +ms014,ms014 should configure two minters and fail to mint when paused,Multiple Minters +ms015,"ms015 should configure two minters, blacklist one and ensure it cannot mint, then unblacklist and ensure it can mint",Multiple Minters +ms016,"ms016 should configure two minters, each mints to themselves and then burns certain amount",Multiple Minters +ms018,ms018 should approve 0 token allowance with unchanged state,0 Input +ms019,ms019 should transferFrom 0 tokens with unchanged state ,0 Input +ms020,ms020 should transfer 0 tokens with unchanged state,0 Input +ms036,ms036 should get allowance for same address,Same Address +ms039 ,ms039 should return true on mint,Return Value +ms040 ,ms040 should return true on approve,Return Value +ms041 ,ms041 should return true on transferFrom,Return Value +ms042 ,ms042 should return true on transfer,Return Value +ms043 ,ms043 should return true on configureMinter,Return Value +ms044 ,ms044 should return true on removeMinter,Return Value +ms045,"ms045 initialized should be in slot 8, byte 21",Slot Storage +ms046,ms046 initialized should be 0 before initialization,Slot Storage +ms047 -p,ms047 configureMinter works on amount=2^256-1,2^256-1 Input +ms048 -p,ms048 mint works on amount=2^256-1,2^256-1 Input +ms049 -p,ms049 burn on works on amount=2^256-1,2^256-1 Input +ms050 -p,ms050 approve works on amount=2^256-1,2^256-1 Input +ms051 -p,ms051 transfer works on amount=2^256-1,2^256-1 Input +ms052 -p,ms052 transferFrom works on amount=2^256-1,2^256-1 Input \ No newline at end of file diff --git a/verification/Spreadsheets/ContractStateChanges - NegativeTests.csv b/verification/Spreadsheets/ContractStateChanges - NegativeTests.csv new file mode 100644 index 000000000..7c968283e --- /dev/null +++ b/verification/Spreadsheets/ContractStateChanges - NegativeTests.csv @@ -0,0 +1,49 @@ +Function,Restriction,Code,Test +approve,blacklisted[msg.sender] == false,nt009,nt009 should fail to approve when msg.sender is blacklisted +approve,blacklisted[_spender] == false,nt008,nt008 should fail to approve when spender is blacklisted +approve,paused == false,nt010,nt010 should fail to approve when contract is paused +blacklist,msg.sender == blacklister,nt042,nt042 should fail to blacklist when sender is not blacklister +burn,_amount > 0,nt056,nt056 should fail to burn when amount = 0 +burn,_amount >= 0,nt032,nt032 should fail to burn when amount is -1 +burn,balances[msg.sender] >= _amount,nt031,nt031 should fail to burn when balance is less than amount +burn,blacklisted[msg.sender] ==false,nt033,nt033 should fail to burn when sender is blacklisted +burn,minters[msg.sender] == true,nt035,nt035 should fail to burn when sender is not minter +burn,minters[msg.sender] == true,nt036,nt036 should fail to burn after removeMinter +burn,paused == false,nt034,nt034 should fail to burn when paused +configureMinter,msg.sender == masterMinter,nt026,nt026 should fail to configureMinter when sender is not masterMinter +configureMinter,paused == false,nt028,nt028 should fail to configureMinter when paused +initialize,_blacklister != address(0),nt062,nt062 initialize should fail when _blacklister is 0x0 +initialize,_masterMinter != address(0),nt060,nt060 initialize should fail when _masterMinter is 0x0 +initialize,_owner != address(0),nt063,nt063 initialize should fail when _owner is 0x0 +initialize,_pauser != address(0),nt061,nt061 initialize should fail when _pauser is 0x0 +mint,_amount > 0,nt055,nt055 should fail to mint when amount = 0 +mint,blacklisted[msg.sender] == false,nt003,nt003 should fail to mint when msg.sender is blacklisted +mint,blacklisted[_to] == false,nt004,nt004 should fail to mint when recipient is blacklisted +mint,minterAllowed[msg.sender] >= amount,nt005,nt005 should fail to mint when allowance of minter is less than amount +mint,minters[msg.sender] == true,nt002,nt002 should fail to mint when msg.sender is not a minter +mint,paused == false,nt001,nt001 should fail to mint when paused +mint,_to != address(0),nt006,nt006 should fail to mint to 0x0 address +pause,msg.sender == pauser,nt040,nt040 should fail to pause when sender is not pauser +removeMinter,msg.sender == masterMinter,nt029,nt029 should fail to removeMinter when sender is not masterMinter +transfer,_value <= balances[msg.sender],nt021,nt021 should fail to transfer an amount greater than balance +transfer,_to != address(0),nt020,nt020 should fail to transfer to 0x0 address +transfer,blacklisted[msg.sender] == false,nt023,nt023 should fail to transfer when sender is blacklisted +transfer,blacklisted[_to] == false,nt022,nt022 should fail to transfer to blacklisted recipient +transfer,paused == false,nt024,nt024 should fail to transfer when paused +transferFrom,_value <= balances[_from],nt013,nt013 should fail to transferFrom an amount greater than balance +transferFrom,_to != address(0),nt012,nt012 should fail to transferFrom to 0x0 address +transferFrom,_value <= allowed[_from][msg.sender],nt017,nt017 should fail to transferFrom an amount greater than allowed for msg.sender +transferFrom,blacklisted[_from] == false,nt016,nt016 should fail to transferFrom when from is blacklisted +transferFrom,blacklisted[msg.sender] == false,nt015,nt015 should fail to transferFrom from blacklisted msg.sender +transferFrom,blacklisted[_to] == false,nt014,nt014 should fail to transferFrom to blacklisted recipient +transferFrom,paused == false,nt018,nt018 should fail to transferFrom when paused +transferOwnership,newOwner != address(0),nt064,nt064 transferOwnership should fail on 0x0 +transferOwnership,msg.sender == _owner,nt054,nt054 should fail to transferOwnership when sender is not owner +unBlacklist,msg.sender == blacklister,nt043,nt043 should fail to unblacklist when sender is not blacklister +unpause,msg.sender == pauser,nt041,nt041 should fail to unpause when sender is not pauser +updateBlacklister,_newBlacklister != address(0),nt059,nt059 updateBlacklister should fail on 0x0 +updateBlacklister,msg.sender == _owner,nt048,nt048 should fail to updateBlacklister when sender is not owner +updateMasterMinter,_newMasterMinter != address(0),nt057,nt057 updateMasterMinter should fail on 0x0 +updateMasterMinter,msg.sender == _owner,nt049,nt049 should fail to updateMasterMinter when sender is not owner +updatePauser,_newPauser != address(0),nt058,nt058 updatePauser should fail on 0x0 +updatePauser,msg.sender == _owner,nt050,nt050 should fail to updatePauser when sender is not owner \ No newline at end of file diff --git a/verification/Spreadsheets/ContractStateChanges - PositiveTests.csv b/verification/Spreadsheets/ContractStateChanges - PositiveTests.csv new file mode 100644 index 000000000..26198138e --- /dev/null +++ b/verification/Spreadsheets/ContractStateChanges - PositiveTests.csv @@ -0,0 +1,29 @@ +type,visibility,variable name,Modification Function,Arguments,Result,Code,Test +mapping(address => mapping(address => uint256)),internal,allowed,approve,"_spender = spender, _value = value",allowed[msg.sender][spender] = value,pt020,pt020 should approve a spend and set allowed amount +mapping(address => mapping(address => uint256)),internal,allowed,transferFrom,"_from = from, _to = to, _value = value",allowed[from][spender] -= value,pt007,"pt007 should transferFrom, reducing sender balance by amount and increasing recipient balance by amount" +mapping(address => uint256),internal,balances,burn,_amount = amount,balances[msg.sender] -= amount,pt017,pt017 should burn amount of tokens and reduce balance and total supply by amount +mapping(address => uint256),internal,balances,mint," _to = to, _amount = amount",balances[to] += amount,pt012,"pt012 should mint the amount, increasing balance of recipient by amount, increasing total supply by amount, and decreasing minterAllowed by amount" +mapping(address => uint256),internal,balances,transfer,"_to = to, _value = value","balances[msg.sender] -= amount, balances[to] += amount",pt008,"pt008 should transfer, reducing sender balance by amount and increasing recipient balance by amount" +mapping(address => uint256),internal,balances,transferFrom,"_from = from, _to = to, _value = value","balances[from] -= amount, balances[to] += amount ",pt007,"pt007 should transferFrom, reducing sender balance by amount and increasing recipient balance by amount" +mapping(address => bool),internal,blacklisted,blacklist,_account = account,blacklisted[account] = true,pt019,pt019 should blacklist and set blacklisted to true +mapping(address => bool),internal,blacklisted,unBlacklist,_account = account,blacklisted[account] = false,pt018,"pt018 should blacklist and set blacklisted to true, then unblacklist and set blacklisted to false" +address,public,blacklister,initialize,_blacklister = blacklister,assign,pt000,pt000 should check that default variable values are correct +address,public,blacklister,updateBlacklister,_newBlacklister = newBlacklister,blacklister = _newBlacklister,pt005,pt005 should updateBlacklister +string,public,currency,initialize,_currency = currency,assign,pt000,pt000 should check that default variable values are correct +uint8,public,decimals,initialize,_decimals = decimals,assign,pt000 ,pt000 should check that default variable values are correct +address,public,masterMinter,initialize,_masterMinter = masterMinter,assign,pt000,pt000 should check that default variable values are correct +address,public,masterMinter,updateMasterMinter,_newMasterMinter,masterMinter = _newMasterMinter ,pt004,pt004 should updateMasterMinter +mapping(address => uint256),internal,minterAllowed,configureMinter,"_minter = minter, _minterAllowedAmount = minterAllowedAmount",minterAllowed[minter] = minterAllowedAmount,pt015,"pt015 should configureMinter, setting the minter to true and mintingAllowance to amount" +mapping(address => uint256),internal,minterAllowed,mint,"_to = to, _amount = amount",minterAllowed[msg.sender] -= amount,pt012,"pt012 should mint the amount, increasing balance of recipient by amount, increasing total supply by amount, and decreasing minterAllowed by amount" +mapping(address => uint256),internal,minterAllowed,removeMinter,_minter = minter,minterAllowed[minter] = 0,pt010,"pt010 should removeMinter, setting the minter to false and minterAllowed to 0" +mapping(address => bool),internal,minters,configureMinter,"_minter = minter, _minterAllowedAmount = minterAllowedAmount",minters[minter] = true,pt015,"pt015 should configureMinter, setting the minter to true and mintingAllowance to amount" +mapping(address => bool),internal,minters,removeMinter,_minter = minter,minters[minter] = false,pt010,"pt010 should removeMinter, setting the minter to false and minterAllowed to 0" +string,public,name,initialize,_name = name,assign,pt000,pt000 should check that default variable values are correct +address,private,owner,transferOwnership ,_newOwner = newOwner,_owner = newOwner,pt009,pt009 should set owner to _newOwner +bool,public,paused = false,pause,NA,paused = true,pt011,pt011 should pause and set paused to true +bool,public,paused = false,unpause,NA,paused = false,pt006,pt006 should unpause and set paused to false +address,public,pauser,initialize,_pauser = pauser,assign,pt000,pt000 should check that default variable values are correct +address,public,pauser,updatePauser,_newPauser = newPauser,pauser = _newPauser,pt003,pt003 should updatePauser +string,public,symbol,initialize,symbol = _symbol,assign,pt000,pt000 should check that default variable values are correct +uint256,internal,totalSupply_,burn,_amount = amount,totalSupply_ -= _amount,pt017,pt017 should burn amount of tokens and reduce balance and total supply by amount +uint256,internal,totalSupply_,mint," _to = to, _amount = amount",totalSupply_ += _amount,pt012,"pt012 should mint the amount, increasing balance of recipient by amount, increasing total supply by amount, and decreasing minterAllowed by amount" \ No newline at end of file diff --git a/verification/Spreadsheets/ContractStateChanges - ProxyNegativeTests.csv b/verification/Spreadsheets/ContractStateChanges - ProxyNegativeTests.csv new file mode 100644 index 000000000..2d44c582f --- /dev/null +++ b/verification/Spreadsheets/ContractStateChanges - ProxyNegativeTests.csv @@ -0,0 +1,11 @@ +Function,Restriction,Code,Test +changeAdmin,msg.sender == admin,nut002,nut002 should fail to switch adminAccount with non-adminAccount as caller +upgradeTo,newImplementation is realContract,nut003,nut003 should fail to upgradeTo to null contract address +upgradeToAndCall,newImplementation is realContract,nut004,nut004 should fail to upgradeToAndCall to null contract address +initialize,initialized == false,nut005,nut005 should fail to initialize contract twice +allowance,msg.sender != admin,nut006,nut006 should fail to call contract function with adminAccount +admin,msg.sender == admin,nut007,nut007 should fail to call proxy function with non-adminAccount +transfer,N/A,nut008,nut008 shoud fail to update proxy storage if state-changing function called directly in FiatToken +upgradeTo,msg.sender == admin,nut009,nut009 should fail to call upgradeTo with non-adminAccount +upgradeToAndCall,msg.sender == admin,nut010,nut010 should fail to call updateToAndCall with non-adminAccount +upgradeToAndCall,initialized == false,nut011,nut011 should fail to upgradeToAndCall with initialize (already set variables) \ No newline at end of file diff --git a/verification/Spreadsheets/ContractStateChanges - ProxyPositiveTests.csv b/verification/Spreadsheets/ContractStateChanges - ProxyPositiveTests.csv new file mode 100644 index 000000000..be31bfbfc --- /dev/null +++ b/verification/Spreadsheets/ContractStateChanges - ProxyPositiveTests.csv @@ -0,0 +1,15 @@ +Variable Name,Code,Test +_implementation,upt001,upt001 should upgradeTo new contract and preserve data field values +"_implementation, [new fields]",upt002,upt002 should upgradeToandCall to contract with new data fields set on initVX and ensure new fields are correct and old data is preserved +"_implementation, [new fields]",upt003,"upt003 should upgradeToAndCall to contract with new data fields set on initVX and new logic and ensure old data preserved,new logic works, and new fields correct" +_admin,upt004,upt004 should update proxy adminAccount with previous adminAccount +"_implementation, balances",upt005,upt005 should receive Transfer event on transfer when proxied after upgrade +pause,upt006,upt006 should upgrade while paused and upgraded contract should be paused as a result; then unpause should unpause contract +should not change state,upt007,upt007 should upgrade contract to original address +"initialization fields, _implementation",upt008,upt008 should deploy upgraded version of contract with new data fields and without previous deployment and ensure new fields correct +_admin,upt009,upt009 should check that admin is set correctly by proxy constructor +"initialization fields, _implementation",upt010,"upt010 should deploy upgraded version of contract with new data fields and logic without previous deployment and ensure new logic works, and new fields correct" +"_implementation, [new fields]",upt011,upt011 should upgradeToAndCall while paused and upgraded contract should be paused as a result +"_implementation, [new fields]",upt012,upt012 should upgradeToAndCall while upgrader is blacklisted +"_implementation, [new fields]",upt013,upt013 should upgradeToAndCall while new logic is blacklisted +_implementation,upt014,upt014 should upgradeTo while new logic is blacklisted \ No newline at end of file diff --git a/verification/Spreadsheets/ContractStateChanges - UnitTestCompleteness.csv b/verification/Spreadsheets/ContractStateChanges - UnitTestCompleteness.csv new file mode 100644 index 000000000..0e1a79236 --- /dev/null +++ b/verification/Spreadsheets/ContractStateChanges - UnitTestCompleteness.csv @@ -0,0 +1,36 @@ +File,Function,Modifier,Simple Test,ABI Test,Pausable,Code: paused=true,Blacklistable,blacklisted[msg.sender]=true,blacklisted[address]=true,Only 1 User,Wrong msg.sender +AdminUpgradeabilityProxy.sol,_setAdmin,internal,,abi053,,,,,,, +AdminUpgradeabilityProxy.sol,_willFallback,internal,,abi057,,,,,,, +Blacklistable.sol,blacklist,public,pt019,,no,ept036,no,ept020,ept024,blacklister,nt042 +Blacklistable.sol,unBlacklist,public,pt018,,no,ept035,no,ept021,,blacklister,nt043 +Blacklistable.sol,updateBlacklister,public,pt005,,no,ept003,no,ept015,ept027,owner,nt048 +Blacklistable.sol,isBlacklisted,view,,,,,,,,, +FiatTokenProxy.sol,changeAdmin,public,upt004,,no,ept001,no,ept013,ept025,upgrader,nut002 +FiatTokenProxy.sol,upgradeTo,public,upt001,,no,ept008,no,ept022,upt013,upgrader,nut009 +FiatTokenProxy.sol,upgradeToAndCall,public ,upt002,,no,upt010,no,upt011,upt012,upgrader,nut010 +FiatTokenV1.sol,initialize,public,upt002,,no,,no,,,, +FiatTokenV1.sol,removeMinter,public,pt010,,no,ept006,no,ept033,ept034,masterMinter,nt029 +FiatTokenV1.sol,updateMasterMinter,public,pt004,,no,ept002,no,ept014,ept026,masterMinter,nt049 +FiatTokenV1.sol,approve,public,pt020,,yes,nt010,yes,nt009,nt008,user, +FiatTokenV1.sol,burn,public,pt017,,yes,nt034,yes,nt033,,minter,"nt035, nt031" +FiatTokenV1.sol,configureMinter,public,pt015,,yes,nt028,no,ept030,ept032,masterMinter,nt026 +FiatTokenV1.sol,mint,public,pt012,,yes,nt001,yes,nt003,nt004,minter,"nt002, nt005" +FiatTokenV1.sol,transfer,public,pt008,,yes,nt024,yes,nt023,nt022,user,nt021 +FiatTokenV1.sol,transferFrom,public,pt007,,yes,nt018,yes,nt015,"nt014, nt016",user,nt017 +FiatTokenV1.sol,allowance,view,,,,,,,,, +FiatTokenV1.sol,blanceOf,view,,,,,,,,, +FiatTokenV1.sol,isMinter,view,,,,,,,,, +FiatTokenV1.sol,minterAllowance,view,,,,,,,,, +FiatTokenV1.sol,totalSupply,view,,,,,,,,, +Ownable.sol,transferOwnership,public,pt009,,no,ept005,no,ept017,ept029,owner,nt054 +Ownable.sol,owner,view,,,,,,,,, +Ownable.sol,setOwner,internal,,abi025,,,,,,, +Pausable.sol,pause,public,pt011,,no,ept037,no,ept018,,pauser,nt040 +Pausable.sol,unpause,public,pt006,,no,pt006,no,ept019,,pauser,nt041 +Pausable.sol,updatePauser,public,pt003,,no,ept004,no,ept016,ept028,owner,nt050 +Proxy.sol,_delegate,internal,,abi056,,,,,,, +Proxy.sol,_fallback,internal,,abi058,,,,,,, +Proxy.sol,_willFallback,internal,,abi057,,,,,,, +Proxy.sol,implementation,view,,,,,,,,, +UpgradeabilityProxy.sol,_setImplementation,internal,,abi050,,,,,,, +UpgradeabilityProxy.sol,_upgradeTo,internal,,abi028,,,,,,, \ No newline at end of file diff --git a/verification/Spreadsheets/MINTp0UnitTests - ABITests.csv b/verification/Spreadsheets/MINTp0UnitTests - ABITests.csv new file mode 100644 index 000000000..b0d83e76d --- /dev/null +++ b/verification/Spreadsheets/MINTp0UnitTests - ABITests.csv @@ -0,0 +1,3 @@ +File,Function,Code,Description +MintController.sol,internal_setMinterAllowance,abi100,abi100 internal_setMinterAllowance is internal +Ownable.sol,setOwner,abi101,abi101 setOwner is internal \ No newline at end of file diff --git a/verification/Spreadsheets/MINTp0UnitTests - ArgumentTests.csv b/verification/Spreadsheets/MINTp0UnitTests - ArgumentTests.csv new file mode 100644 index 000000000..94454ee90 --- /dev/null +++ b/verification/Spreadsheets/MINTp0UnitTests - ArgumentTests.csv @@ -0,0 +1,20 @@ +File,Function,Arguments,Code,Description +Ownable.sol,transferOwnership,newOwner == msg.sender,arg000,arg000 transferOwnership(msg.sender) works +Ownable.sol,transferOwnership,newOwner == 0,arg001,arg001 transferOwnership(0) works +Ownable.sol,transferOwnership,newOwner == owner,arg002,arg002 transferOwnership(owner) works +Controller.sol,configureController,newController == 0,arg003,"arg003 configureController(0, M) works" +Controller.sol,configureController,newController == msg.sender,arg004,"arg004 configureController(msg.sender, M) works" +Controller.sol,configureController,newController == newMinter,arg005,"arg005 configureController(M, M) works" +Controller.sol,configureController,newMinter == 0,arg006,"arg006 configureController(C, 0) works" +Controller.sol,removeController,newController == 0,arg007,arg007 removeController(0) works +MintController.sol,setMinterManager,newMinterManager = 0,arg008,arg008 setMinterManager(0) works +MintController.sol,setMinterManager,newMinterManager == minterManager,arg009,arg009 setMinterManager(oldMinterManager) works +MintController.sol,setMinterManager,newMinterManager == user,arg010,arg010 setMinterManager(user_account) works +MintController.sol,setMinterManager,newMinterManager == newToken,arg011,arg011 setMinterManager(newToken) works +MintController.sol,configureMinter,newAllowance == 0,arg012,arg012 configureMinter(0) sets allowance to 0 +MintController.sol,configureMinter,newAllowance == oldAllowance,arg013,arg013 configureMinter(oldAllowance) makes no changes +MintController.sol,configureMinter,newAllowance == 2^256-1,arg014,arg014 configureMinter(MAX) works +MintController.sol,incrementMinterAllowance,increment ==0,arg015,arg015 incrementMinterAllowance(0) makes no changes to allowance +MintController.sol,incrementMinterAllowance,increment == oldAllowance,arg016,arg016 incrementMinterAllowance(oldAllowance) doubles the allowance +MintController.sol,incrementMinterAllowance,increment == 2^256-1,arg017,arg017 incrementMinterAllowance(MAX) throws +MintController.sol,incrementMinterAllowance,increment + oldAllowance == 2^256 -1,arg018,arg018 incrementMinterAlllowance(BIG) throws \ No newline at end of file diff --git a/verification/Spreadsheets/MINTp0UnitTests - BasicTests.csv b/verification/Spreadsheets/MINTp0UnitTests - BasicTests.csv new file mode 100644 index 000000000..4a27a8473 --- /dev/null +++ b/verification/Spreadsheets/MINTp0UnitTests - BasicTests.csv @@ -0,0 +1,55 @@ +File,Function,Special Condition,Code,Description +Controller.sol,configureController,msg.sender == owner,bt004,bt004 configureController works when owner is msg.sender +Controller.sol,configureController,msg.sender != owner,bt005,bt005 configureController reverts when owner is not msg.sender +Controller.sol,configureController,controllers[C]=0,bt019,bt019 configureController works when controller[C]=0 +Controller.sol,configureController,controllers[C] != 0,bt020,bt020 configureController works when controller[C] != 0 +Controller.sol,configureController,controllers[C]=C,bt021,"bt021 configureController(C,C) works" +Controller.sol,configureController,controllers[C] == msg.sender,bt022,bt022 configureController works when setting controller[C]=msg.sender +Controller.sol,configureController,controllers[C] == newM,bt023,"bt023 configureController(C, newM) works when controller[C]=newM" +Controller.sol,constructor,controllers[ALL] = 0,bt016,bt016 Constructor sets all controllers to 0 +Controller.sol,removeController,msg.sender == owner,bt008,bt008 removeController works when owner is msg.sender +Controller.sol,removeController,msg.sender != owner,bt009,bt009 removeController reverts when owner is not msg.sender +Controller.sol,removeController,controllers[C]=0,bt017,bt017 removeController does not revert when controllers[C] is 0 +Controller.sol,removeController,controllers[C]=M,bt018,bt018 removeController removes an arbitrary controller +FiatTokenV1.sol,constructor,minterManager.isMinter[ALL] == false,bt045,bt045 constructor - minterManager.isMinter[ALL] is false +FiatTokenV1.sol,constructor,minterManager.minterAllowance[ALL] == 0,bt046,bt046 constructor - minterManager.minterAllowance[ALL] = 0 +MintController.sol,configureMinter,controllers[msg.sender]==0,bt012,bt012 configureMinter reverts when msg.sender is not a controller +MintController.sol,configureMinter,controllers[msg.sender]==M,bt013,bt013 configureMinter sents controllers[msg.sender] to M +MintController.sol,configureMinter,minterManager = 0,bt033,bt033 configureMinter reverts when minterManager is 0 +MintController.sol,configureMinter,minterManager != MinterManagerInterface,bt034,bt034 configureMinter reverts when minterManager is a user account +MintController.sol,configureMinter,minterManager == OK,bt035,bt035 configureMinter works when minterManager is ok +MintController.sol,configureMinter,minterManager.isMinter == false,bt039,"bt039 configureMinter(M, amt) works when minterManager.isMinter(M)=false" +MintController.sol,configureMinter,minterManager.isMinter == true,bt040,"bt040 configureMinter(M, amt) works when minterManager.isMinter(M)=true" +MintController.sol,configureMinter,minterManager.minterAllowance[M] == 0,bt050,"bt050 configureMinter(M,amt) works when minterAllowance=0" +MintController.sol,configureMinter,minterManager.minterAllowance[M] == X,bt051,"bt051 configureMinter(M,amt) works when minterAllowance>0" +MintController.sol,configureMinter,minterManager.minterAllowance[M] == BIG,bt052,"bt052 configureMinter(M,amt) works when amt+minterAllowance > 2^256" +MintController.sol,constructor,minterManager == init,bt024,bt024 Constructor sets minterManager +MintController.sol,incrementMinterAllowance,controllers[msg.sender]==0,bt014,bt014 incrementMinterAllowance reverts if msg.sender is not a controller +MintController.sol,incrementMinterAllowance,controllers[msg.sender]==M,bt015,bt015 incrementMinterAllowance sets controllers[msg.sender] to M +MintController.sol,incrementMinterAllowance,minterManager = 0,bt036,bt036 incrementMinterAllowance reverts when minterManager is 0 +MintController.sol,incrementMinterAllowance,minterManager != MinterManagerInterface,bt037,bt037 incrementMinterAllowance reverts when minterManager is a user account +MintController.sol,incrementMinterAllowance,minterManager == OK,bt038,bt038 incrementMinterAllowance works when minterManager is ok +MintController.sol,incrementMinterAllowance,minterManager.isMinter == false,bt043,"bt043 incrementMinterAllowance(M, amt) works when minterManager.isMinter(M)=false" +MintController.sol,incrementMinterAllowance,minterManager.isMinter == true,bt044,"bt044 incrementMinterAllowance(M, amt) works when minterManager.isMinter(M)=true" +MintController.sol,incrementMinterAllowance,minterManager.minterAllowance[M] == 0,bt047,"bt047 incrementMinterAllowance(M,amt) works when minterAllowance is 0" +MintController.sol,incrementMinterAllowance,minterManager.minterAllowance[M] == X,bt048,"bt048 incrementMinterAllowance(M, amt) works when minterAllowance > 0" +MintController.sol,incrementMinterAllowance,minterManager.minterAllowance[M] == BIG,bt049,"bt049 incrementMinterAllowance(M,amt) reverts when minterAllowance[M] + amt > 2^256" +MintController.sol,removeMinter,controllers[msg.sender]==0,bt010,bt010 removeMinter reverts when msg.sender is not a controller +MintController.sol,removeMinter,controllers[msg.sender]==M,bt011,bt011 removeMinter sets controllers[msg.sender] to 0 +MintController.sol,removeMinter,minterManager = 0,bt030,bt030 removeMinter reverts when minterManager is 0 +MintController.sol,removeMinter,minterManager != MinterManagerInterface,bt031,bt031 removeMinter reverts when minterManager is a user account +MintController.sol,removeMinter,minterManager == OK,bt032,bt032 removeMinter works when minterManager is ok +MintController.sol,removeMinter,minterManager.isMinter == false,bt041,bt041 removeMinter(M) works when minterManager.isMinter(M)=false +MintController.sol,removeMinter,minterManager.isMinter == true,bt042,bt042 removeMinter(M) works when minterManager.isMinter(M)=true +MintController.sol,removeMinter,minterManager.minterAllowance[M] == 0,bt053,bt053 removeMinter works when the minterAllowance is 0 +MintController.sol,removeMinter,minterManager.minterAllowance[M] == X,bt054,bt054 removeMinter works when the minterAllowance is not zero +MintController.sol,removeMinter,minterManager.minterAllowance[M] == BIG,bt055,bt055 removeMinter works when the minterAllowance is big +MintController.sol,setMinterManager,msg.sender == owner,bt006,bt006 setMinterManager works when owner is msg.sender +MintController.sol,setMinterManager,msg.sender != owner,bt007,bt007 setMinterManager reverts when owner is not msg.sender +MintController.sol,setMinterManager,minterManager == 0,bt025,bt025 setMinterManager(x) works when existing minterManager = 0 +MintController.sol,setMinterManager,minterManager != 0,bt026,bt026 setMinterManager(x) works when existing minterManager != 0 +MintController.sol,setMinterManager,minterManager == msg.sender,bt027,bt027 setMinterManager(x) works when x = msg.sender +MintController.sol,setMinterManager,minterManager == newMinterManager,bt028,bt028 setMinterManager(x) works when x = minterManager +Ownable.sol,constructor,msg.sender == owner,bt001,bt001 Constructor - owner is msg.sender +Ownable.sol,transferOwnership,msg.sender == owner,bt002,bt002 transferOwnership works when owner is msg.sender +Ownable.sol,transferOwnership,msg.sender != owner,bt003,bt003 transferOwnership reverts when owner is not msg.sender \ No newline at end of file diff --git a/verification/Spreadsheets/MINTp0UnitTests - EndToEndTests.csv b/verification/Spreadsheets/MINTp0UnitTests - EndToEndTests.csv new file mode 100644 index 000000000..e5211baa1 --- /dev/null +++ b/verification/Spreadsheets/MINTp0UnitTests - EndToEndTests.csv @@ -0,0 +1,20 @@ +File,Function 1,Function 2,Function 3,Code,Description +Ownable.sol,transferOwnership,configureController,,ete000,ete000 New owner can configure controllers +Ownable.sol,transferOwnership,removeController,,ete001,ete001 New owner can remove controllers +Controller.sol,configureController,configureMinter,,ete002,ete002 New controller can configure minter +Controller.sol,configureController,incrementMinterAllowance,,ete011,ete011 New controller can increment minter allowance +Controller.sol,configureController,removeMinter,,ete012,ete012 New controller can remove minter +Controller.sol,configureController,configureController,configureMinter,ete003,ete003 Configure two controllers for the same minter and make sure they can both configureMinter +Controller.sol,configureController,configureMinter,removeMinter,ete004,"ete004 Configure two controllers for the same minter, one adds a minter and the other removes it" +Controller.sol,configureController,configureMinter,removeMinter,ete005,ete005 Configure two controllers for different minters and make sure 2nd cant remove +Controller.sol,configureController,configureMinter,configureMinter,ete006,ete006 Configure two controllers for different minters and make sure 2nd cant configure +Controller.sol,removeController,configureMinter,,ete007,ete007 Remove a controller and make sure it can't modify minter +MintController.sol,setMinterManager,configureMinter,,ete008,ete008 Change minter manager and make sure existing controllers still can configure their minters +MintController.sol,setMinterManager,removeMinter,,ete009,ete009 Change minter manager and make sure existing controllers still can remove their minters +MintController.sol,setMinterManager,incrementMinterAllowance,,ete010,ete010 Change minter manager and make sure existing controllers can increment allowances +MintController.sol,setMinterManager,configureMinter,setMinterManager,ete013,"ete013 Change minter manager, configure a minter, then change back and make sure changes DID NOT propogate" +MintController.sol,removeMinter,incrementMinterAllowance,,ete014,ete014 Remove a minter and then try to increment its allowance reverts +MintController.sol,configureMinter,mint,,ete015,ete015 Configure a minter and make sure it can mint +MintController.sol,configureMinter,burn,,ete017,ete017 Configure a minter and make sure it can burn +MintController.sol,removeMinter,mint,,ete016,ete016 Remove a minter and make sure it cannot mint +MintController.sol,removeMinter,burn,,ete018,ete018 Remove a minter and make sure it cannot burn \ No newline at end of file diff --git a/verification/Spreadsheets/MINTp0UnitTests - EventTests.csv b/verification/Spreadsheets/MINTp0UnitTests - EventTests.csv new file mode 100644 index 000000000..da5473939 --- /dev/null +++ b/verification/Spreadsheets/MINTp0UnitTests - EventTests.csv @@ -0,0 +1,8 @@ +File,Function,Event,Code,Description +Ownable.sol,transferOwnership,OwnershipTransferred,et100,et100 transferOwnership emits OwnershipTransferred event +Controller.sol,configureController,ControllerConfigured,et101,et101 configureController emits ControllerConfigured event +Controller.sol,removeController,ControllerRemoved,et102,et102 removeController emits ControllerRemoved event +MintController,setMinterManager,MinterManagerSet,et103,et103 setMinterManager emits MinterManagerSet event +MintController,removeMinter,MinterRemoved,et104,et104 removeMinter emits MinterRemoved event +MintController,configureMinter,MinterConfigured,et105,et105 configureMinter emits MinterConfigured event +MintController,incrementMinterAllowance,MinterAllowanceIncremented,et106,et106 incrementMinterAllowance emits MinterAllowanceConfigured event \ No newline at end of file From 620df426efe2b4baec2990ce570e5b1fdcbb1cd5 Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Fri, 28 Sep 2018 16:44:43 -0400 Subject: [PATCH 06/10] Adding parse-csv package --- package.json | 4 +++- yarn.lock | 36 +++++++----------------------------- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index 6a4648069..f68c93e66 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "assert-diff": "^1.2.6", "bignumber.js": "6.0.0", "clone": "2.1.2", + "csv-parse": "^3.0.0", "ethereum-input-data-decoder": "0.0.12", "ethereumjs-abi": "^0.6.5", "ethereumjs-tx": "1.3.1", @@ -40,7 +41,8 @@ "q": "^1.5.1", "truffle-hdwallet-provider": "^0.0.6", "yarn": "^1.10.1", - "zos-lib": "1.3.0" + "zos-lib": "1.3.0", + "csv-parse": "3.0.0" }, "devDependencies": { "chai": "^4.1.2", diff --git a/yarn.lock b/yarn.lock index a32bbd82b..4d9c8440b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1891,6 +1891,10 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" +csv-parse@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-3.0.0.tgz#2d592cf4bf7f3b1606900812df298a5bcc9f66e5" + cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -1935,7 +1939,7 @@ debug@3.1.0, debug@^3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" -debuglog@*, debuglog@^1.0.1: +debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -3619,7 +3623,7 @@ import-local@^1.0.0: pkg-dir "^2.0.0" resolve-cwd "^2.0.0" -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -4510,10 +4514,6 @@ lockfile@^1.0.4: dependencies: signal-exit "^3.0.2" -lodash._baseindexof@*: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -4521,28 +4521,10 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@*: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - -lodash._cacheindexof@*: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - -lodash._createcache@*: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - dependencies: - lodash._getnative "^3.0.0" - lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" -lodash._getnative@*, lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - lodash._root@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" @@ -4563,10 +4545,6 @@ lodash.isstring@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" -lodash.restparam@*: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - lodash.union@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" @@ -6149,7 +6127,7 @@ readable-stream@~1.0.15: isarray "0.0.1" string_decoder "~0.10.x" -readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: From 60101f305498037652e88cee830f5f9b746d9445 Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Wed, 3 Oct 2018 21:04:35 -0400 Subject: [PATCH 07/10] basic functionality working with *csv spreadsheets --- package.json | 5 +- truffle.js | 4 +- ...actStateChanges - UnitTestCompleteness.csv | 0 verification/GoogleSheets/index.js | 255 ------------------ verification/spreadsheet_parser.js | 126 +++++++++ verification/verification_reporter.js | 66 ++--- 6 files changed, 165 insertions(+), 291 deletions(-) rename verification/{Spreadsheets => }/ContractStateChanges - UnitTestCompleteness.csv (100%) delete mode 100644 verification/GoogleSheets/index.js create mode 100644 verification/spreadsheet_parser.js diff --git a/package.json b/package.json index f68c93e66..33ac07789 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "assert-diff": "^1.2.6", "bignumber.js": "6.0.0", "clone": "2.1.2", - "csv-parse": "^3.0.0", + "csv-parse": "3.0.0", "ethereum-input-data-decoder": "0.0.12", "ethereumjs-abi": "^0.6.5", "ethereumjs-tx": "1.3.1", @@ -41,8 +41,7 @@ "q": "^1.5.1", "truffle-hdwallet-provider": "^0.0.6", "yarn": "^1.10.1", - "zos-lib": "1.3.0", - "csv-parse": "3.0.0" + "zos-lib": "1.3.0" }, "devDependencies": { "chai": "^4.1.2", diff --git a/truffle.js b/truffle.js index 061c042d8..6191b721b 100644 --- a/truffle.js +++ b/truffle.js @@ -46,7 +46,7 @@ module.exports = { * To disable the spreadsheet verification tool ensure that * the reporter is set to 'Spec' by commenting/uncommenting the lines below. */ - reporter: 'Spec', - //reporter: './verification/verification_reporter.js', + // reporter: 'Spec', + reporter: "/Users/mirabelenkiy/Documents/Dev/centre-tokens/verification/verification_reporter.js", }, }; diff --git a/verification/Spreadsheets/ContractStateChanges - UnitTestCompleteness.csv b/verification/ContractStateChanges - UnitTestCompleteness.csv similarity index 100% rename from verification/Spreadsheets/ContractStateChanges - UnitTestCompleteness.csv rename to verification/ContractStateChanges - UnitTestCompleteness.csv diff --git a/verification/GoogleSheets/index.js b/verification/GoogleSheets/index.js deleted file mode 100644 index c6c8ad3dd..000000000 --- a/verification/GoogleSheets/index.js +++ /dev/null @@ -1,255 +0,0 @@ -const fs = require('fs'); -const readline = require('readline'); -const {google} = require('googleapis'); - -const SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']; -const CREDENTIALS_PATH = __dirname + '/credentials.json'; -const TOKEN_PATH = __dirname + '/token.json'; - -var indent = ' '; - - -/** -* Authorize access to GoogleSheets API and load spreadsheet data. -*/ -function load() { - return new Promise((resolve, reject) => { - // Load client secrets from a local file. - fs.readFile(CREDENTIALS_PATH, async (err, content) => { - if (err) { - reject('Error loading credentials file:' + err); - } - // If no error loading client secrets, authorize and run getTests(). - var res = await authorize(JSON.parse(content), getTests).catch((err) => { - reject(err); - }); - resolve(res); - }); - }); -} - - -/** - * Create an OAuth2 client with the given credentials, and then execute the - * given callback function. - * @param {Object} credentials The authorization client credentials. - * @param {function} callback The callback to call with the authorized client. - */ -function authorize(credentials, callback) { - const {client_secret, client_id, redirect_uris} = credentials.installed; - const oAuth2Client = new google.auth.OAuth2( - client_id, client_secret, redirect_uris[0]); - - return new Promise((resolve, reject) => { - // Check if we have previously stored an OAuth token. - fs.readFile(TOKEN_PATH, async (err, token) => { - // If we have not previously stored an OAuth token, get a new one and - // call getTests(). - if (err) { - var res = await getNewToken(oAuth2Client, callback).catch((err) => { - reject(err); - }); - } else { - // If we have previously stored an OAuth token, call getTests(). - oAuth2Client.setCredentials(JSON.parse(token)); - var res = await callback(oAuth2Client).catch((err) => { - reject(err); - }); - } - resolve(res); - }); - }); -} - - -/** - * Get and store new token after prompting for user authorization, and then - * execute the given callback with the authorized OAuth2 client. - * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for. - * @param {getEventsCallback} callback The callback for the authorized client. - */ -function getNewToken(oAuth2Client, callback) { - const authUrl = oAuth2Client.generateAuthUrl({ - access_type: 'offline', - scope: SCOPES, - }); - console.log('Authorize this app by visiting this url:', authUrl); - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - - return new Promise((resolve, reject) => { - rl.question('Enter the code from that page here: ', (code) => { - rl.close(); - oAuth2Client.getToken(code, async (err, token) => { - if (err) { - reject(await callback(err)); - } - oAuth2Client.setCredentials(token); - // Store the token to disk for later program executions - fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => { - if (err) { - console.error(err); - } - console.log('Token stored to', TOKEN_PATH); - }); - var res = await callback(oAuth2Client).catch((err) => { - reject(err); - }); - resolve(res); - }); - }); - }); -} - - -/** -* Gets the tests to verify from the GoogleSheets spreadsheet. -* @see https://docs.google.com/spreadsheets/d/1zP1_q8XbLH8YrWMJ0Od80PKleklUnvBAX96wypJaVTU/edit?usp=sharing -* @param {google.auth.OAuth2} auth The authenticated Google OAuth client. -*/ -function getTests(auth) { - const sheets = google.sheets({version: 'v4', auth}); - - return new Promise((resolve, reject) => { - sheets.spreadsheets.get({ - spreadsheetId: '1zP1_q8XbLH8YrWMJ0Od80PKleklUnvBAX96wypJaVTU', - includeGridData: true, - }, (err, res) => { - if (err) { - reject('The GoogleSheets API returned an error: ' + err); - } - var tests = {}; - let tabs = res.data.sheets; - if (tabs.length) { - tabs.map((tab) => { - let tab_name = tab.properties.title; - if (tab_name == 'UnitTestCompleteness') { - load_UnitTestCompleteness(tests, tab); - return; - } - let rows = tab.data[0].rowData; - let top_row = rows.shift().values; - let col = getCol(top_row); - if (typeof col == 'undefined') { - console.log('\nNo code column found in tab "' - + tab_name + '". Skipping.\n'); - return; - } - rows.map((rowData) => { - let row = rowData.values; - if (row) { - processRow(row, tab_name, tests, col); - } - }); - }); - } else { - reject('No GoogleSheets data found.'); - } - resolve(tests); - }); - }); -} - - -/** -* Helper function that gets the test code and test description from a row in a -* given speadsheet tab and adds them to the tests object returned by getTests(). -* @param {Array} row The row of the spreadsheet to processs. -* @param {String} tab_name The name of the spreadsheet tab currently loading. -* @param {Object} tests Contains all the spreadsheet test data to verify. -* @param {Int} col The index of the test code column of the spreadsheet tab. -*/ -function processRow(row, tab_name, tests, col) { - let code_cell = row[col]; - let desc_cell = row[col+1]; - if (code_cell && desc_cell) { - let test_code = code_cell.formattedValue; - let test_desc = desc_cell.formattedValue; - if (test_code && test_desc) { - let pending = test_code.match(/ -p/); - if (pending) { - test_code = test_code.replace(pending[0], ''); - } - categorize_test( - tests, - test_code.trim(), - test_desc.trim(), - tab_name.trim(), - pending - ); - } - } -} - - -/** -* Helper function that gets all test codes included in tab UnitTestCompleteness. -* @param {Object} tab The UnitTestCompleteness tab object. -* @param {Object} tests Contains all the spreadsheet test data to verify. -*/ -function load_UnitTestCompleteness(tests, tab) { - tests.completeness = {}; - let rows = tab.data[0].rowData; - rows.map((row) => { - row = row.values; - row.map((cell) => { - cell = cell.formattedValue; - if (cell) { - let codes = cell.match(/([a-z]{2,})([0-9]+)/g); - if (codes != null) { - codes.map((code) => { - if (!tests.completeness[code]) { - tests.completeness[code] = true; - } - }); - } - } - }); - }); -} - - -/** -* Helper function that adds a test code and description to the tests object -* returned by getTests(). -* @param {Object} tests Contains all the spreadsheet test data to verify. -* @param {String} code The test code to add to tests. -* @param {String} desc The test description to add to tests. -* @param {String} tab The name of the spreadsheet tab currently loading. -* @param {Array?} pending [' -p'] if test is pending, 'undefined' otherwise. -*/ -function categorize_test(tests, code, desc, tab, pending) { - if (pending) { - tab = 'pending'; - } - if (!tests[tab]) { - tests[tab] = {}; - } - let tab_tests = tests[tab]; - tab_tests[code] = desc.replace(code, ''); - tests[tab] = tab_tests; -} - - -/** -* Helper function that finds the 'Code' or 'code' column in a spreadsheet tab. -* @param {Array} top_row An array containing all the cells along the top row of -* the spreadsheet tab. Should contain column headers. -*/ -function getCol(top_row) { - var col; - for (let i = 0; i < top_row.length; i++) { - let cell = top_row[i]; - let label = cell.formattedValue; - if(label == 'code' || label == 'Code') { - col = i; - } - } - return col; -} - -module.exports = { - load: load, -} diff --git a/verification/spreadsheet_parser.js b/verification/spreadsheet_parser.js new file mode 100644 index 000000000..084354cf6 --- /dev/null +++ b/verification/spreadsheet_parser.js @@ -0,0 +1,126 @@ +var fs = require('fs'); +var parse = require('csv-parse/lib/sync'); +var SPREADSHEETS_DIR = '/Users/mirabelenkiy/Documents/Dev/centre-tokens/verification/Spreadsheets' + +function UnitTest(code, description, pending){ + this.code = code; + this.description = description; + this.pending = pending; +} + +/* + UnitTestDirectory is a literal object. + Keys - names of unit test files + Values - a UnitTestSet + + UnitTestSet is a literal object + Keys - codes associated with unit tests + Values - an instance of a UnitTest object +* + + +/** +* Reads all files in Spreadsheets directory and returns an oject with their contents +* Returns a UnitTestDirectory object +* TODO: handle errors, null objects, UnitTestCompleteness +*/ +function load() { + var unitTestDirectory = {}; + + // get names of all files in SPREADSHEETS_DIR + var files = fs.readdirSync(SPREADSHEETS_DIR, (err, data) => { + if(err){ + console.log("error reading " + SPREADSHEETS_DIR + " " + err); + return null; + } + return data; + }); + // process each file into a unitTestSet, then add the + // unitTestSet to unitTestDirectory + files.forEach(file => { + console.log('reading ' + file); + var csvFileContents = fs.readFileSync(SPREADSHEETS_DIR + "/" + file, "utf8"); + if(csvFileContents != null) { + var unitTestSet = {}; + var spreadsheet = parse(csvFileContents, {columns: true}); + spreadsheet.forEach(row => { + var unitTest = parseRow(row); + unitTestSet[unitTest.code] = unitTest; + }); + var unittestfilename = getUnitTestFileName(file); + unitTestDirectory[unittestfilename] = unitTestSet; + } + }); + + // return array of unitTestDirectory objects + return unitTestDirectory; +} + +// +// spreadsheet: UnitTestDirectory +function isPending(spreadsheet, filename, code) { + if((filename in spreadsheet ) && (code in spreadsheet[filename])) + { + return spreadsheet[filename][code].pending; + } + return false; +} + +// Transforms a row in spreadsheet into a UnitTest object +// row: a literal object. One of the keys must be 'code/Code' and another 'description/Description' +// Returns a UnitTest object or null if cannot find appropriate keys. +function parseRow(row) { + var test_code = ""; + var testCodeKey = ""; + var pending = false; + var description = ""; + for(var columnName in row) { + if(columnName == 'code' || columnName == 'Code') { + test_code = row[columnName]; + testCodeKey = columnName; + pending = test_code.match(/ -p/); + if (pending) { + test_code = test_code.replace(pending[0], ''); + pending = true; + } else { + pending = false; + } + } + } + var descriptionKey = getDescriptionKey(row, testCodeKey); + description = row[descriptionKey]; + if(test_code == '' || description == '') return null; + return new UnitTest(test_code, description, pending); +} + +function getDescriptionKey(row, testCodeKey) { + // get the index of the testCodeKey + var testCodeKeyIndex = 0; + for(var i=0; i { - console.log(err); - }); - spreadsheet_clone = JSON.parse(JSON.stringify(spreadsheet)); + spreadsheet = sheets.load(); }); // Runs at the beginning of each contract block execution. @@ -59,6 +55,7 @@ function verification_reporter (runner) { }); // Runs at the end of every test. + // TODO: upgraded tests "missing" because deleted from spreadsheet after first run runner.on('test end', function (test) { // If contract block title is marked 'Legacy', // we skip verification. (See README.verification) @@ -95,40 +92,46 @@ function verification_reporter (runner) { + indent + '(See README.verification)')); return; } - var test_ran = test.title.replace(id, ''); + var test_ran = test.title; +// var test_ran = test.title.replace(id, ''); // Check if test is in UnitTestCompleteness tab and "cross-off" if it is. + /* TODO: implement UnitTestCompleteness spreadsheet processing if (!_.isEmpty(spreadsheet.completeness)) { if (spreadsheet.completeness[id]) { delete spreadsheet.completeness[id]; } } - - // If test is marked pending in spreadsheet, record for later output. - if (spreadsheet.pending && (spreadsheet.pending[id] == test_ran)) { - console.log(indent + green_x + color('bright pass', ' pending')); - pending[id] = test_ran; - } else { +*/ // Verify test is in spreadsheet. if (spreadsheet[file]) { - let spreadsheet_test = spreadsheet[file][id] || spreadsheet_clone[file][id]; + let spreadsheet_test = spreadsheet[file][id]; if (spreadsheet_test) { - // Verify test descriptions match. - if (spreadsheet_test == test_ran) { + + // If test is marked pending in spreadsheet, record for later output. + if(spreadsheet_test.pending) { + console.log(indent + green_x + color('bright pass', ' pending')); + pending[id] = test_ran; + + // If test descriptions match, mark green. + } else if (spreadsheet_test.description == test_ran) { console.log(indent + green_x); + + // If test is in spreadsheet, but descriptions don't match. } else { - // If test is in spreadsheet, but descriptions don't match. console.log(indent + red_x + color('fail', ' test description inconsistent with spreadsheet for ' + id + ', ' + file)); + console.log("s: " + spreadsheet_test.description); + console.log("t: " + test_ran); // Print test description string diff. - let diff = getStringDiff(test_ran, spreadsheet_test); + let diff = getStringDiff(test_ran, spreadsheet_test.description); console.log(indent + diff); errs.push(red_x + color('fail', ' Test descriptions do not match for ' + id + ', ' + file) - + '\n' + indent + 'In spreadsheet: ' + spreadsheet_test + + '\n' + indent + 'In spreadsheet: ' + spreadsheet_test.description + '\n' + indent + 'In test file: ' + test_ran + '\n' + indent + 'Diff: ' + diff); } @@ -140,24 +143,23 @@ function verification_reporter (runner) { // If test is not in spreadsheet. console.log(indent + red_x + color('fail', ' ' - + id + ' missing from spreadsheet tab ' + file)); + + id + ' missing from spreadsheet file ' + file)); errs.push(red_x + color('fail', ' Test ' + id + ' missing from ' - + file + ' spreadsheet tab.')); + + file + ' spreadsheet file.')); } } else { - // If test file not found in spreadsheet tabs. + // If test file not found in directory. console.log(indent + red_x + color('fail', ' test file ' + file - + ' does not match a spreadsheet tab')); + + ' does not match a spreadsheet in the Spreadsheets directory')); errs.push(red_x + color('fail', ' Test file ' + file - + ' missing from spreadsheet. Possible solutions:\n' - + '1. Ensure test is listed in correct spreadsheet tab.\n' - + '2. Ensure the tab name is included in the contract block title.\n' + + ' missing from Spreadsheets directory. Possible solutions:\n' + + '1. Ensure test is listed in correct *.csv file.\n' + + '2. Ensure the *.csv file name is included in the contract block title.\n' + '(See README.verification)')); } - } }); // Runs at the end of test suite execution. Prints verification summary. @@ -170,11 +172,13 @@ function verification_reporter (runner) { + 'marked pending in the spreadsheet (delete -p flag once merged): '); console.log(pending); } + // TODO: fix pending // Do not report tests that are missing from test suite but marked pending. - delete spreadsheet.pending; + // delete spreadsheet.pending; // Print out any tests that are included in UnitTestCompleteness tab but // missing from the test suite. - if (!_.isEmpty(spreadsheet.completeness)) { + // TODO: fix completeness spreadshet + /* if (!_.isEmpty(spreadsheet.completeness)) { console.log('\n' + red_x + color('bright fail', ' UnitTestCompleteness tab includes tests that are not present in test suite:') + '\n' + Object.keys(spreadsheet.completeness).toString()); @@ -182,7 +186,7 @@ function verification_reporter (runner) { console.log(green_ok + color('bright pass', ' Test suite suite contains all tests in UnitTestCompleteness tab.')); } - delete spreadsheet.completeness; + delete spreadsheet.completeness;*/ // If all the tests in a tab are present, 'cross-off' tab by deleting. for(var file in spreadsheet) { if (_.isEmpty(spreadsheet[file])) { @@ -197,7 +201,7 @@ function verification_reporter (runner) { // If not all tests are 'crossed-off', print the tests remaining. console.log(color('bright fail', '\nTests missing from test suite (but included in spreadsheet):\n')); - console.log(spreadsheet); + console.log(spreadsheet); // TODO: test this line works } // Print all errors where executed tests did not match spreadsheet. if (errs.length) { From 43aaaf027e317ef0216e9953c65ab4bd78c78acb Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Thu, 4 Oct 2018 11:48:25 -0400 Subject: [PATCH 08/10] Added pending support, relative paths --- truffle.js | 2 +- ...ests.csv => FiatToken_ABIHackingTests.csv} | 0 ...ventTests.csv => FiatToken_EventTests.csv} | 0 ...sv => FiatToken_ExtendedPositiveTests.csv} | 0 ... MiscTests.csv => FiatToken_MiscTests.csv} | 0 ...eTests.csv => FiatToken_NegativeTests.csv} | 0 ...eTests.csv => FiatToken_PositiveTests.csv} | 0 ...s.csv => FiatToken_ProxyNegativeTests.csv} | 0 ...s.csv => FiatToken_ProxyPositiveTests.csv} | 0 ...s - ABITests.csv => MINTp0 - ABITests.csv} | 0 ...ntTests.csv => MINTp0 - ArgumentTests.csv} | 0 ...BasicTests.csv => MINTp0 - BasicTests.csv} | 0 ...ndTests.csv => MINTp0 - EndToEndTests.csv} | 0 ...EventTests.csv => MINTp0 - EventTests.csv} | 0 verification/spreadsheet_parser.js | 30 +++--- verification/verification_reporter.js | 93 ++++++++++--------- 16 files changed, 61 insertions(+), 64 deletions(-) rename verification/Spreadsheets/{ContractStateChanges - ABIHackingTests.csv => FiatToken_ABIHackingTests.csv} (100%) rename verification/Spreadsheets/{ContractStateChanges - EventTests.csv => FiatToken_EventTests.csv} (100%) rename verification/Spreadsheets/{ContractStateChanges - ExtendedPositiveTests.csv => FiatToken_ExtendedPositiveTests.csv} (100%) rename verification/Spreadsheets/{ContractStateChanges - MiscTests.csv => FiatToken_MiscTests.csv} (100%) rename verification/Spreadsheets/{ContractStateChanges - NegativeTests.csv => FiatToken_NegativeTests.csv} (100%) rename verification/Spreadsheets/{ContractStateChanges - PositiveTests.csv => FiatToken_PositiveTests.csv} (100%) rename verification/Spreadsheets/{ContractStateChanges - ProxyNegativeTests.csv => FiatToken_ProxyNegativeTests.csv} (100%) rename verification/Spreadsheets/{ContractStateChanges - ProxyPositiveTests.csv => FiatToken_ProxyPositiveTests.csv} (100%) rename verification/Spreadsheets/{MINTp0UnitTests - ABITests.csv => MINTp0 - ABITests.csv} (100%) rename verification/Spreadsheets/{MINTp0UnitTests - ArgumentTests.csv => MINTp0 - ArgumentTests.csv} (100%) rename verification/Spreadsheets/{MINTp0UnitTests - BasicTests.csv => MINTp0 - BasicTests.csv} (100%) rename verification/Spreadsheets/{MINTp0UnitTests - EndToEndTests.csv => MINTp0 - EndToEndTests.csv} (100%) rename verification/Spreadsheets/{MINTp0UnitTests - EventTests.csv => MINTp0 - EventTests.csv} (100%) diff --git a/truffle.js b/truffle.js index 6191b721b..f0aa71a44 100644 --- a/truffle.js +++ b/truffle.js @@ -47,6 +47,6 @@ module.exports = { * the reporter is set to 'Spec' by commenting/uncommenting the lines below. */ // reporter: 'Spec', - reporter: "/Users/mirabelenkiy/Documents/Dev/centre-tokens/verification/verification_reporter.js", + reporter: "verification/verification_reporter.js", }, }; diff --git a/verification/Spreadsheets/ContractStateChanges - ABIHackingTests.csv b/verification/Spreadsheets/FiatToken_ABIHackingTests.csv similarity index 100% rename from verification/Spreadsheets/ContractStateChanges - ABIHackingTests.csv rename to verification/Spreadsheets/FiatToken_ABIHackingTests.csv diff --git a/verification/Spreadsheets/ContractStateChanges - EventTests.csv b/verification/Spreadsheets/FiatToken_EventTests.csv similarity index 100% rename from verification/Spreadsheets/ContractStateChanges - EventTests.csv rename to verification/Spreadsheets/FiatToken_EventTests.csv diff --git a/verification/Spreadsheets/ContractStateChanges - ExtendedPositiveTests.csv b/verification/Spreadsheets/FiatToken_ExtendedPositiveTests.csv similarity index 100% rename from verification/Spreadsheets/ContractStateChanges - ExtendedPositiveTests.csv rename to verification/Spreadsheets/FiatToken_ExtendedPositiveTests.csv diff --git a/verification/Spreadsheets/ContractStateChanges - MiscTests.csv b/verification/Spreadsheets/FiatToken_MiscTests.csv similarity index 100% rename from verification/Spreadsheets/ContractStateChanges - MiscTests.csv rename to verification/Spreadsheets/FiatToken_MiscTests.csv diff --git a/verification/Spreadsheets/ContractStateChanges - NegativeTests.csv b/verification/Spreadsheets/FiatToken_NegativeTests.csv similarity index 100% rename from verification/Spreadsheets/ContractStateChanges - NegativeTests.csv rename to verification/Spreadsheets/FiatToken_NegativeTests.csv diff --git a/verification/Spreadsheets/ContractStateChanges - PositiveTests.csv b/verification/Spreadsheets/FiatToken_PositiveTests.csv similarity index 100% rename from verification/Spreadsheets/ContractStateChanges - PositiveTests.csv rename to verification/Spreadsheets/FiatToken_PositiveTests.csv diff --git a/verification/Spreadsheets/ContractStateChanges - ProxyNegativeTests.csv b/verification/Spreadsheets/FiatToken_ProxyNegativeTests.csv similarity index 100% rename from verification/Spreadsheets/ContractStateChanges - ProxyNegativeTests.csv rename to verification/Spreadsheets/FiatToken_ProxyNegativeTests.csv diff --git a/verification/Spreadsheets/ContractStateChanges - ProxyPositiveTests.csv b/verification/Spreadsheets/FiatToken_ProxyPositiveTests.csv similarity index 100% rename from verification/Spreadsheets/ContractStateChanges - ProxyPositiveTests.csv rename to verification/Spreadsheets/FiatToken_ProxyPositiveTests.csv diff --git a/verification/Spreadsheets/MINTp0UnitTests - ABITests.csv b/verification/Spreadsheets/MINTp0 - ABITests.csv similarity index 100% rename from verification/Spreadsheets/MINTp0UnitTests - ABITests.csv rename to verification/Spreadsheets/MINTp0 - ABITests.csv diff --git a/verification/Spreadsheets/MINTp0UnitTests - ArgumentTests.csv b/verification/Spreadsheets/MINTp0 - ArgumentTests.csv similarity index 100% rename from verification/Spreadsheets/MINTp0UnitTests - ArgumentTests.csv rename to verification/Spreadsheets/MINTp0 - ArgumentTests.csv diff --git a/verification/Spreadsheets/MINTp0UnitTests - BasicTests.csv b/verification/Spreadsheets/MINTp0 - BasicTests.csv similarity index 100% rename from verification/Spreadsheets/MINTp0UnitTests - BasicTests.csv rename to verification/Spreadsheets/MINTp0 - BasicTests.csv diff --git a/verification/Spreadsheets/MINTp0UnitTests - EndToEndTests.csv b/verification/Spreadsheets/MINTp0 - EndToEndTests.csv similarity index 100% rename from verification/Spreadsheets/MINTp0UnitTests - EndToEndTests.csv rename to verification/Spreadsheets/MINTp0 - EndToEndTests.csv diff --git a/verification/Spreadsheets/MINTp0UnitTests - EventTests.csv b/verification/Spreadsheets/MINTp0 - EventTests.csv similarity index 100% rename from verification/Spreadsheets/MINTp0UnitTests - EventTests.csv rename to verification/Spreadsheets/MINTp0 - EventTests.csv diff --git a/verification/spreadsheet_parser.js b/verification/spreadsheet_parser.js index 084354cf6..9996510d6 100644 --- a/verification/spreadsheet_parser.js +++ b/verification/spreadsheet_parser.js @@ -1,6 +1,7 @@ var fs = require('fs'); var parse = require('csv-parse/lib/sync'); -var SPREADSHEETS_DIR = '/Users/mirabelenkiy/Documents/Dev/centre-tokens/verification/Spreadsheets' +// NOTE: SPREADSHEETS_DIR must be relative to truffle.js +var SPREADSHEETS_DIR = './verification/Spreadsheets' function UnitTest(code, description, pending){ this.code = code; @@ -10,7 +11,7 @@ function UnitTest(code, description, pending){ /* UnitTestDirectory is a literal object. - Keys - names of unit test files + Keys - names of unit test suites Values - a UnitTestSet UnitTestSet is a literal object @@ -38,7 +39,6 @@ function load() { // process each file into a unitTestSet, then add the // unitTestSet to unitTestDirectory files.forEach(file => { - console.log('reading ' + file); var csvFileContents = fs.readFileSync(SPREADSHEETS_DIR + "/" + file, "utf8"); if(csvFileContents != null) { var unitTestSet = {}; @@ -47,7 +47,7 @@ function load() { var unitTest = parseRow(row); unitTestSet[unitTest.code] = unitTest; }); - var unittestfilename = getUnitTestFileName(file); + var unittestfilename = getTestSuiteTitle(file); unitTestDirectory[unittestfilename] = unitTestSet; } }); @@ -75,9 +75,9 @@ function parseRow(row) { var pending = false; var description = ""; for(var columnName in row) { - if(columnName == 'code' || columnName == 'Code') { - test_code = row[columnName]; - testCodeKey = columnName; + if(columnName.trim() == 'code' || columnName.trim() == 'Code') { + test_code = row[columnName].trim(); + testCodeKey = columnName.trim(); pending = test_code.match(/ -p/); if (pending) { test_code = test_code.replace(pending[0], ''); @@ -88,7 +88,7 @@ function parseRow(row) { } } var descriptionKey = getDescriptionKey(row, testCodeKey); - description = row[descriptionKey]; + description = row[descriptionKey].trim(); if(test_code == '' || description == '') return null; return new UnitTest(test_code, description, pending); } @@ -105,17 +105,11 @@ function getDescriptionKey(row, testCodeKey) { return Object.keys(row)[i];; } -// Returns the raw name of the unit test file associated with this csv file +// Returns the raw name of the unit test suite associated with this csv file // csvFileName: filename in the format `/path/to/file/spreadsheetname - unittestfilename.csv` -// returns unittestfilename -function getUnitTestFileName(csvFileName) { - var filenames = csvFileName.split(/ - /); - if(filenames.length != 2) { - console.log("failed to split " + csvFileName) - return ''; - } - var unitTestFileName = filenames[filenames.length - 1].replace(/\.csv/, "" ); - return unitTestFileName; +// returns 'spreadsheetname - unittestfilename' +function getTestSuiteTitle(csvFileName) { + return csvFileName.replace(/\.csv/, "" ); } diff --git a/verification/verification_reporter.js b/verification/verification_reporter.js index 7e3c3e2ec..4b9e5de13 100644 --- a/verification/verification_reporter.js +++ b/verification/verification_reporter.js @@ -1,3 +1,4 @@ +const util = require('util'); const mocha = require('mocha'); const spec_reporter = mocha.reporters.Spec; const base_reporter = mocha.reporters.Base; @@ -24,14 +25,18 @@ function verification_reporter (runner) { spec_reporter.call(this, runner); var spreadsheet; + var missingUnitTests; var errs = []; var pending = {}; + var executedTestSuites = {}; // Runs before tests are executed. Loads tests from spreadsheet. before('load_spreadsheet_tests', async function() { this.timeout(200000); console.log('Loading spreadsheet...\n'); - spreadsheet = sheets.load(); + // need two copies of spreadsheet because some unit tests run multiple times + spreadsheet = sheets.load(); // check if unit test is in spreadsheet at all + missingUnitTests = sheets.load(); // reporter will remove codes once they're found }); // Runs at the beginning of each contract block execution. @@ -55,7 +60,6 @@ function verification_reporter (runner) { }); // Runs at the end of every test. - // TODO: upgraded tests "missing" because deleted from spreadsheet after first run runner.on('test end', function (test) { // If contract block title is marked 'Legacy', // we skip verification. (See README.verification) @@ -72,16 +76,10 @@ function verification_reporter (runner) { } // Parse test title. - var file = test.parent.title.match(/[a-z]+Tests/gi); - if (file) { - file = file[0]; - } else { - console.log(indent + color('pass', - 'Error parsing test title.\n' - + indent + 'Confirm file name is formatted correctly and included in contract \n' - + indent + 'block title. (See README.verification)')); - return; - } + var fullSuiteName = test.parent.title.replace('Contract:','').trim(); + var suite = fullSuiteName.split(" ", 1)[0].trim(); + executedTestSuites[suite]=true; + var id = test.title.match(/([a-z]{2,})([0-9]+)/g); if (id) { id = id[0]; @@ -92,8 +90,7 @@ function verification_reporter (runner) { + indent + '(See README.verification)')); return; } - var test_ran = test.title; -// var test_ran = test.title.replace(id, ''); + var test_ran = test.title.trim(); // Check if test is in UnitTestCompleteness tab and "cross-off" if it is. /* TODO: implement UnitTestCompleteness spreadsheet processing @@ -104,14 +101,17 @@ function verification_reporter (runner) { } */ // Verify test is in spreadsheet. - if (spreadsheet[file]) { - let spreadsheet_test = spreadsheet[file][id]; + if (spreadsheet[suite]) { + let spreadsheet_test = spreadsheet[suite][id]; if (spreadsheet_test) { // If test is marked pending in spreadsheet, record for later output. if(spreadsheet_test.pending) { console.log(indent + green_x + color('bright pass', ' pending')); - pending[id] = test_ran; + if(! pending[suite]) { + pending[suite] = {}; + } + pending[suite][id] = test_ran; // If test descriptions match, mark green. } else if (spreadsheet_test.description == test_ran) { @@ -122,7 +122,7 @@ function verification_reporter (runner) { console.log(indent + red_x + color('fail', ' test description inconsistent with spreadsheet for ' - + id + ', ' + file)); + + id + ', ' + suite)); console.log("s: " + spreadsheet_test.description); console.log("t: " + test_ran); // Print test description string diff. @@ -130,31 +130,32 @@ function verification_reporter (runner) { console.log(indent + diff); errs.push(red_x + color('fail', ' Test descriptions do not match for ' - + id + ', ' + file) + + id + ', ' + suite) + '\n' + indent + 'In spreadsheet: ' + spreadsheet_test.description - + '\n' + indent + 'In test file: ' + test_ran + + '\n' + indent + 'In test suite: ' + test_ran + '\n' + indent + 'Diff: ' + diff); } // If test is included in spreadsheet, 'cross-off' by deleting. - if (spreadsheet[file][id]) { - delete spreadsheet[file][id]; + if (missingUnitTests[suite][id]) { + delete missingUnitTests[suite][id]; } } else { // If test is not in spreadsheet. console.log(indent + red_x + color('fail', ' ' - + id + ' missing from spreadsheet file ' + file)); + + id + ' missing from spreadsheet suite ' + suite)); errs.push(red_x + color('fail', ' Test ' + id + ' missing from ' - + file + ' spreadsheet file.')); + + suite + ' spreadsheet suite.')); + assert.equal(true, false); } } else { // If test file not found in directory. console.log(indent + red_x - + color('fail', ' test file ' + file + + color('fail', ' test suite ' + suite + ' does not match a spreadsheet in the Spreadsheets directory')); errs.push(red_x - + color('fail', ' Test file ' + file + + color('fail', ' Test suite ' + suite + ' missing from Spreadsheets directory. Possible solutions:\n' + '1. Ensure test is listed in correct *.csv file.\n' + '2. Ensure the *.csv file name is included in the contract block title.\n' @@ -170,11 +171,15 @@ function verification_reporter (runner) { console.log(color('bright pass', 'Pending Tests:')); console.log('The following tests are included in the test suite, but\n' + 'marked pending in the spreadsheet (delete -p flag once merged): '); - console.log(pending); + console.log(util.inspect(pending, { showHidden: false, depth: null })); } - // TODO: fix pending // Do not report tests that are missing from test suite but marked pending. - // delete spreadsheet.pending; + for(var pendingsuite in pending) { + for(var pendingID in pending[pendingsuite]) { + delete missingUnitTests[pendingsuite][pendingID]; + } + } + // Print out any tests that are included in UnitTestCompleteness tab but // missing from the test suite. // TODO: fix completeness spreadshet @@ -188,31 +193,29 @@ function verification_reporter (runner) { } delete spreadsheet.completeness;*/ // If all the tests in a tab are present, 'cross-off' tab by deleting. - for(var file in spreadsheet) { - if (_.isEmpty(spreadsheet[file])) { - delete spreadsheet[file]; + for(var testSuite in missingUnitTests) { + if (_.isEmpty(missingUnitTests[testSuite])) { + delete missingUnitTests[testSuite]; } } + + // Do not report missing unit tests for files that did not run + for(var testSuite in missingUnitTests){ + if(! _.has(executedTestSuites, testSuite)) { + console.log(color('fail', 'Did not run: ' + testSuite)); + delete missingUnitTests[testSuite]; + } + } + // If all tests are 'crossed-off', print success. - if (_.isEmpty(spreadsheet)) { + if (_.isEmpty(missingUnitTests)) { console.log('\n' + green_ok + color('bright pass', ' Test suite contains all tests in spreadsheet.')); } else { // If not all tests are 'crossed-off', print the tests remaining. console.log(color('bright fail', '\nTests missing from test suite (but included in spreadsheet):\n')); - console.log(spreadsheet); // TODO: test this line works - } - // Print all errors where executed tests did not match spreadsheet. - if (errs.length) { - console.log(color('bright fail', - '\nTests missing from spreadsheet (but included in test suite): ')); - errs.map((err) => { - console.log('\n' + err); - }); - } else { - console.log('\n' + green_ok + color('bright pass', - ' Spreadsheet contains all tests in test suite.')); + console.log(util.inspect(missingUnitTests, { showHidden: false, depth: null })); } }); } From 3895e5777daa8cb9e3d40bf5dcbb5a12939bfa48 Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Thu, 4 Oct 2018 11:56:56 -0400 Subject: [PATCH 09/10] updated README --- verification/README.verification.txt | 51 ++++++---------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/verification/README.verification.txt b/verification/README.verification.txt index 5a075ff42..fe4dd63e6 100644 --- a/verification/README.verification.txt +++ b/verification/README.verification.txt @@ -1,7 +1,7 @@ The spreadsheet verification tool requires certain naming and usage conventions to function correctly. -Test Codes: +Unit test codes: - Should follow the format of lowercase letters followed by a number with no spaces. (ex. pt001, ept016, misc0000, legacy2, fiat19) @@ -11,17 +11,15 @@ Test Codes: - Should be listed under the 'Code' column of each spreadsheet tab. -Test Titles: -- Should exactly match the test description assigned to the test in the - spreadsheet. +CSV files: +- All CSV files must be in the `verification/Spreadsheets` directory. -Spreadsheet Tabs: - -- Should have the same name as the test file they represent. - This name should be formatted BlankTests where Blank consists of uppercase - and/or lowercase letters and is followed without a space by the word 'Tests'. - (ex. PositiveTests, tokenTests, ABITests) +- Each unit test contract block is associated with a single *.csv file. + If the contract block title is 'FiatToken_EventTests' then it will be tested + against FiatToken_EventTests.csv. The verification tool will ignore all + text in the contract block title after a space. 'FiatToken_EventTests Upgraded' + will also be verified against FiatToken_EventTests.csv - Should include a column 'code' or 'Code' listing all unique test codes that correspond to tests expected in the test file. @@ -33,7 +31,7 @@ Spreadsheet Tabs: - Should keep the column headers in the top row. -UnitTestCompleteness tab: +UnitTestCompleteness CSV (unsupported): - The verification tool will print out any test codes that are featured in the UnitTestCompleteness tab but missing from the test suite. @@ -44,11 +42,7 @@ UnitTestCompleteness tab: Contract Block Titles: -- Should include the name of the test file they run, and this name should not - be immediately preceded by letters. - (ex. If the contract block runs the PositiveTests file, it should be named - 'FiatToken_PositiveTests', 'PositiveTestsupgraded', 'PositiveTests' etc., - but not 'upgradedPositiveTests'.) +- Must match the CSV file name that it is tested against (see CSV files above). - Should include the word 'Legacy' if they run tests that do not need to be recorded in the spreadsheet and can be ignored by the verification tool. @@ -74,29 +68,6 @@ Pending Tests: - To DISABLE the spreadsheet verification tool, go to the file truffle.js and comment out the following line: - reporter: './verification/verification_reporter.js', + reporter: 'verification/verification_reporter.js', Then, uncomment the line above it. //reporter: 'Spec', - -- To ENABLE the spreadsheet verification tool FOR THE FIRST TIME. - - 1) Ensure your browser is signed in to your Circle Google account and visit - https://developers.google.com/sheets/api/quickstart/nodejs . - - 2) Press the blue 'ENABLE THE GOOGLE SHEETS API' button. - - 3) Enter a project name (i.e. 'spreadsheet-verification') and product name - (i.e 'centre-tokens') and download the credentials.json file. - - 4) Move your credentials.json file into the verification/GoogleSheets folder. - - 5) Run 'npm run truffle-test'. You should be prompted to visit a URL and enter a code - that you find there into your terminal. This will create a token.json file - inside the GoogleSheets folder. Note, if a token.json file already exists in - this folder, you will encounter an error. - - From there, you should be good to go. This process only needs to be completed - the first time you use the tool. - - Note: Ensure that credentials.json and token.json are included in .gitignore - before committing. From 9f524bfa76a2a524a49a0e5dc2ec231372f1e1d8 Mon Sep 17 00:00:00 2001 From: mirathewhite Date: Thu, 4 Oct 2018 13:44:57 -0400 Subject: [PATCH 10/10] Added unit test completeness testing --- .../FiatToken - UnitTestCompleteness.csv} | 0 verification/spreadsheet_parser.js | 29 +++++++++++++++++-- verification/verification_reporter.js | 24 ++++++++------- 3 files changed, 40 insertions(+), 13 deletions(-) rename verification/{ContractStateChanges - UnitTestCompleteness.csv => Spreadsheets/FiatToken - UnitTestCompleteness.csv} (100%) diff --git a/verification/ContractStateChanges - UnitTestCompleteness.csv b/verification/Spreadsheets/FiatToken - UnitTestCompleteness.csv similarity index 100% rename from verification/ContractStateChanges - UnitTestCompleteness.csv rename to verification/Spreadsheets/FiatToken - UnitTestCompleteness.csv diff --git a/verification/spreadsheet_parser.js b/verification/spreadsheet_parser.js index 9996510d6..be5df1f4e 100644 --- a/verification/spreadsheet_parser.js +++ b/verification/spreadsheet_parser.js @@ -23,7 +23,7 @@ function UnitTest(code, description, pending){ /** * Reads all files in Spreadsheets directory and returns an oject with their contents * Returns a UnitTestDirectory object -* TODO: handle errors, null objects, UnitTestCompleteness +* TODO: handle errors, null objects */ function load() { var unitTestDirectory = {}; @@ -44,8 +44,13 @@ function load() { var unitTestSet = {}; var spreadsheet = parse(csvFileContents, {columns: true}); spreadsheet.forEach(row => { - var unitTest = parseRow(row); - unitTestSet[unitTest.code] = unitTest; + if(file.match("Completeness")){ + var unitTestArray = parseCompletenessRow(row); + unitTestArray.forEach(unitTest => {unitTestSet[unitTest.code] = unitTest}); + } else { + var unitTest = parseRow(row); + unitTestSet[unitTest.code] = unitTest; + } }); var unittestfilename = getTestSuiteTitle(file); unitTestDirectory[unittestfilename] = unitTestSet; @@ -66,6 +71,24 @@ function isPending(spreadsheet, filename, code) { return false; } +// Reads a row and tries to find one or more test codes inside the row +// Returns an array of UnitTest objects +function parseCompletenessRow(row){ + var unitTests = []; + var index =0; + for(var columnName in row) { + var rowValues = row[columnName].split(","); + for(var potentialCodeIndex in rowValues) { + var codes = rowValues[potentialCodeIndex].match(/([a-z]{2,4})([0-9]+)/g); + for(var codeIndex in codes) { + unitTests[index] = new UnitTest(codes[codeIndex], "", false); + ++index; + } + } + } + return unitTests; +} + // Transforms a row in spreadsheet into a UnitTest object // row: a literal object. One of the keys must be 'code/Code' and another 'description/Description' // Returns a UnitTest object or null if cannot find appropriate keys. diff --git a/verification/verification_reporter.js b/verification/verification_reporter.js index 4b9e5de13..b38cbe4cb 100644 --- a/verification/verification_reporter.js +++ b/verification/verification_reporter.js @@ -92,14 +92,18 @@ function verification_reporter (runner) { } var test_ran = test.title.trim(); - // Check if test is in UnitTestCompleteness tab and "cross-off" if it is. - /* TODO: implement UnitTestCompleteness spreadsheet processing - if (!_.isEmpty(spreadsheet.completeness)) { - if (spreadsheet.completeness[id]) { - delete spreadsheet.completeness[id]; - } + // check if test is in a "completeness" unit test sheet + // if it is, cross it off as found by deleting it + for(var completeness_suite in missingUnitTests) { + if(completeness_suite.match(/Completeness/)){ + if(missingUnitTests[completeness_suite][id]) { + console.log("complete: " + id); + delete missingUnitTests[completeness_suite][id]; + } + } } -*/ + + // Verify test is in spreadsheet. if (spreadsheet[suite]) { let spreadsheet_test = spreadsheet[suite][id]; @@ -201,7 +205,7 @@ function verification_reporter (runner) { // Do not report missing unit tests for files that did not run for(var testSuite in missingUnitTests){ - if(! _.has(executedTestSuites, testSuite)) { + if(! _.has(executedTestSuites, testSuite) && ! testSuite.match(/Completeness/)) { console.log(color('fail', 'Did not run: ' + testSuite)); delete missingUnitTests[testSuite]; } @@ -210,11 +214,11 @@ function verification_reporter (runner) { // If all tests are 'crossed-off', print success. if (_.isEmpty(missingUnitTests)) { console.log('\n' + green_ok + color('bright pass', - ' Test suite contains all tests in spreadsheet.')); + ' Test run contains all tests in spreadsheet.')); } else { // If not all tests are 'crossed-off', print the tests remaining. console.log(color('bright fail', - '\nTests missing from test suite (but included in spreadsheet):\n')); + '\nThe following tests were not executed (but are included in a spreadsheet):\n')); console.log(util.inspect(missingUnitTests, { showHidden: false, depth: null })); } });