Merge pull request #40 from JoinColony/feature/contract-directories2

Cover nested contracts
uport
area 8 years ago committed by GitHub
commit 6982d5f34a
  1. 9
      coverageMap.js
  2. 15
      package.json
  3. 20
      runCoveredTests.js
  4. 18
      test/if.js
  5. 9
      test/loops.js
  6. 11
      test/statements.js

@ -70,23 +70,22 @@ module.exports = class CoverageMap {
const event = JSON.parse(events[idx]); const event = JSON.parse(events[idx]);
if (event.topics.indexOf(lineTopic) >= 0) { if (event.topics.indexOf(lineTopic) >= 0) {
const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', '')); const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = path.resolve(pathPrefix + path.basename(data[0])); const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].l[data[1].toNumber()] += 1; this.coverage[canonicalContractPath].l[data[1].toNumber()] += 1;
} else if (event.topics.indexOf(functionTopic) >= 0) { } else if (event.topics.indexOf(functionTopic) >= 0) {
const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', '')); const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = path.resolve(pathPrefix + path.basename(data[0])); const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].f[data[1].toNumber()] += 1; this.coverage[canonicalContractPath].f[data[1].toNumber()] += 1;
} else if (event.topics.indexOf(branchTopic) >= 0) { } else if (event.topics.indexOf(branchTopic) >= 0) {
const data = SolidityCoder.decodeParams(['string', 'uint256', 'uint256'], event.data.replace('0x', '')); const data = SolidityCoder.decodeParams(['string', 'uint256', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = path.resolve(pathPrefix + path.basename(data[0])); const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].b[data[1].toNumber()][data[2].toNumber()] += 1; this.coverage[canonicalContractPath].b[data[1].toNumber()][data[2].toNumber()] += 1;
} else if (event.topics.indexOf(statementTopic) >= 0) { } else if (event.topics.indexOf(statementTopic) >= 0) {
const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', '')); const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = path.resolve(pathPrefix + path.basename(data[0])); const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].s[data[1].toNumber()] += 1; this.coverage[canonicalContractPath].s[data[1].toNumber()] += 1;
} }
} }
return Object.assign({}, this.coverage); return Object.assign({}, this.coverage);
} }
}; };

@ -7,24 +7,25 @@
"test": "test" "test": "test"
}, },
"scripts": { "scripts": {
"test": "mocha --timeout 15000" "test": "mocha --timeout 30000"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"ethereumjs-testrpc": "^3.0.3", "ethereumjs-testrpc": "https://github.com/ethereumjs/testrpc.git#5ba3c45b2ca306ab589f4a4c649d9afc39042680",
"istanbul": "^0.4.5", "istanbul": "^0.4.5",
"mkdirp": "^0.5.1",
"shelljs": "^0.7.4", "shelljs": "^0.7.4",
"sol-explore": "^1.6.2", "sol-explore": "^1.6.2",
"solidity-parser": "^0.2.0" "solidity-parser": "^0.2.0"
}, },
"devDependencies": { "devDependencies": {
"crypto-js": "^3.1.9-1", "crypto-js": "^3.1.9-1",
"ethereumjs-account": "^2.0.4", "ethereumjs-account": "~2.0.4",
"ethereumjs-tx": "^1.2.2", "ethereumjs-tx": "1.1.2",
"ethereumjs-util": "^5.0.1", "ethereumjs-util": "~4.5.0",
"merkle-patricia-tree": "^2.1.2", "merkle-patricia-tree": "~2.1.2",
"mocha": "^3.1.0", "mocha": "^3.1.0",
"solc": "^0.4.6" "solc": "0.4.6"
} }
} }

@ -8,6 +8,7 @@ var path = require('path');
var getInstrumentedVersion = require('./instrumentSolidity.js'); var getInstrumentedVersion = require('./instrumentSolidity.js');
var CoverageMap = require('./coverageMap.js'); var CoverageMap = require('./coverageMap.js');
var coverage = new CoverageMap(); var coverage = new CoverageMap();
var mkdirp = require('mkdirp');
var childprocess = require('child_process'); var childprocess = require('child_process');
@ -17,7 +18,7 @@ if (!shell.test('-e','./node_modules/ethereumjs-vm/lib/opFns.js.orig')){
shell.exec('patch -b ./node_modules/ethereumjs-vm/lib/opFns.js ./hookIntoEvents.patch') shell.exec('patch -b ./node_modules/ethereumjs-vm/lib/opFns.js ./hookIntoEvents.patch')
} }
//Run the modified testrpc with large block limit //Run the modified testrpc with large block limit
var testrpcProcess = childprocess.exec('./node_modules/ethereumjs-testrpc/bin/testrpc --gasLimit 0xfffffffffff') var testrpcProcess = childprocess.exec('./node_modules/ethereumjs-testrpc/bin/testrpc --gasLimit 0xfffffffffffff --gasPrice 0x1')
if (shell.test('-d','../originalContracts')){ if (shell.test('-d','../originalContracts')){
console.log("There is already an 'originalContracts' directory in your truffle directory.\nThis is probably due to a previous solcover failure.\nPlease make sure the ./contracts/ directory contains your contracts (perhaps by copying them from originalContracts), and then delete the originalContracts directory.") console.log("There is already an 'originalContracts' directory in your truffle directory.\nThis is probably due to a previous solcover failure.\nPlease make sure the ./contracts/ directory contains your contracts (perhaps by copying them from originalContracts), and then delete the originalContracts directory.")
@ -27,21 +28,22 @@ if (shell.test('-d','../originalContracts')){
shell.mv('./../contracts/', './../originalContracts/'); shell.mv('./../contracts/', './../originalContracts/');
shell.mkdir('./../contracts/'); shell.mkdir('./../contracts/');
//For each contract in originalContracts, get the instrumented version //For each contract in originalContracts, get the instrumented version
shell.ls('./../originalContracts/*.sol').forEach(function(file) { shell.ls('./../originalContracts/**/*.sol').forEach(function(file) {
if (file !== 'originalContracts/Migrations.sol') { if (file !== 'originalContracts/Migrations.sol') {
console.log("instrumenting ", file); var canonicalContractPath = path.resolve(file);
var contract = fs.readFileSync("./" + file).toString();
var fileName = path.basename(file); console.log("instrumenting ", canonicalContractPath);
var instrumentedContractInfo = getInstrumentedVersion(contract, fileName, true); var contract = fs.readFileSync(canonicalContractPath).toString();
fs.writeFileSync('./../contracts/' + path.basename(file), instrumentedContractInfo.contract); var instrumentedContractInfo = getInstrumentedVersion(contract, canonicalContractPath, true);
var canonicalContractPath = path.resolve('./../originalContracts/' + path.basename(file)); mkdirp.sync(path.dirname(canonicalContractPath.replace('originalContracts', 'contracts')));
fs.writeFileSync(canonicalContractPath.replace('originalContracts','contracts'), instrumentedContractInfo.contract);
coverage.addContract(instrumentedContractInfo, canonicalContractPath); coverage.addContract(instrumentedContractInfo, canonicalContractPath);
} }
}); });
shell.cp("./../originalContracts/Migrations.sol", "./../contracts/Migrations.sol"); shell.cp("./../originalContracts/Migrations.sol", "./../contracts/Migrations.sol");
shell.rm('./allFiredEvents'); //Delete previous results shell.rm('./allFiredEvents'); //Delete previous results
shell.exec('truffle test --network coverage'); shell.exec('truffle test --network test');
events = fs.readFileSync('./allFiredEvents').toString().split('\n') events = fs.readFileSync('./allFiredEvents').toString().split('\n')
events.pop(); events.pop();

@ -8,13 +8,12 @@ const assert = require('assert');
describe('if, else, and else if statements', function(){ describe('if, else, and else if statements', function(){
const fileName = 'test.sol';
const filePath = path.resolve('./test.sol'); const filePath = path.resolve('./test.sol');
const pathPrefix = './'; const pathPrefix = './';
it('should cover an if statement with a bracketed consequent', (done) => { it('should cover an if statement with a bracketed consequent', (done) => {
const contract = util.getCode('if/if-with-brackets.sol'); const contract = util.getCode('if/if-with-brackets.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
@ -32,7 +31,7 @@ describe('if, else, and else if statements', function(){
// Runs: a(1) => if (x == 1) x = 2; // Runs: a(1) => if (x == 1) x = 2;
it('should cover an unbracketed if consequent (single line)',function(done){ it('should cover an unbracketed if consequent (single line)',function(done){
const contract = util.getCode('if/if-no-brackets.sol'); const contract = util.getCode('if/if-no-brackets.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
@ -49,7 +48,7 @@ describe('if, else, and else if statements', function(){
it('should cover an if statement with multiline bracketed consequent', (done) => { it('should cover an if statement with multiline bracketed consequent', (done) => {
const contract = util.getCode('if/if-with-brackets-multiline.sol'); const contract = util.getCode('if/if-with-brackets-multiline.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
@ -67,7 +66,7 @@ describe('if, else, and else if statements', function(){
// Runs: a(1) => if (x == 1)\n x = 3; // Runs: a(1) => if (x == 1)\n x = 3;
it('should cover an unbracketed if consequent (multi-line)', function(done){ it('should cover an unbracketed if consequent (multi-line)', function(done){
const contract = util.getCode('if/if-no-brackets-multiline.sol'); const contract = util.getCode('if/if-no-brackets-multiline.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
// Same results as previous test // Same results as previous test
@ -83,7 +82,7 @@ describe('if, else, and else if statements', function(){
it('should cover a simple if statement with a failing condition', (done) => { it('should cover a simple if statement with a failing condition', (done) => {
const contract = util.getCode('if/if-with-brackets.sol'); const contract = util.getCode('if/if-with-brackets.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
@ -101,7 +100,7 @@ describe('if, else, and else if statements', function(){
// Runs: a(2) => if (x == 1){\n throw;\n }else{\n x = 5; \n} // Runs: a(2) => if (x == 1){\n throw;\n }else{\n x = 5; \n}
it('should cover an if statement with a bracketed alternate', (done) => { it('should cover an if statement with a bracketed alternate', (done) => {
const contract = util.getCode('if/else-with-brackets.sol'); const contract = util.getCode('if/else-with-brackets.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
@ -117,7 +116,7 @@ describe('if, else, and else if statements', function(){
it('should cover an if statement with an unbracketed alternate',function(done){ it('should cover an if statement with an unbracketed alternate',function(done){
const contract = util.getCode('if/else-without-brackets.sol'); const contract = util.getCode('if/else-without-brackets.sol');
const info = getInstrumentedVersion(contract, "test.sol", true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
@ -133,7 +132,7 @@ describe('if, else, and else if statements', function(){
it('should cover nested if statements with missing else statements',function(done){ it('should cover nested if statements with missing else statements',function(done){
const contract = util.getCode('if/nested-if-missing-else.sol'); const contract = util.getCode('if/nested-if-missing-else.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
vm.execute(info.contract, 'a', [2, 3, 3]).then(events => { vm.execute(info.contract, 'a', [2, 3, 3]).then(events => {
@ -145,4 +144,5 @@ describe('if, else, and else if statements', function(){
done(); done();
}).catch(done) }).catch(done)
}) })
}) })

@ -8,13 +8,12 @@ const assert = require('assert');
describe('for and while statements', function(){ describe('for and while statements', function(){
const fileName = 'test.sol';
const filePath = path.resolve('./test.sol'); const filePath = path.resolve('./test.sol');
const pathPrefix = './'; const pathPrefix = './';
it('should cover a for statement with a bracketed body (multiline)', (done) => { it('should cover a for statement with a bracketed body (multiline)', (done) => {
const contract = util.getCode('loops/for-with-brackets.sol'); const contract = util.getCode('loops/for-with-brackets.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
@ -31,7 +30,7 @@ describe('for and while statements', function(){
it('should cover a for statement with an unbracketed body', (done) => { it('should cover a for statement with an unbracketed body', (done) => {
const contract = util.getCode('loops/for-no-brackets.sol'); const contract = util.getCode('loops/for-no-brackets.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
@ -48,7 +47,7 @@ describe('for and while statements', function(){
it('should cover a while statement with an bracketed body (multiline)', (done) => { it('should cover a while statement with an bracketed body (multiline)', (done) => {
const contract = util.getCode('loops/while-with-brackets.sol'); const contract = util.getCode('loops/while-with-brackets.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);
@ -65,7 +64,7 @@ describe('for and while statements', function(){
it('should cover a while statement with an unbracketed body (multiline)', (done) => { it('should cover a while statement with an unbracketed body (multiline)', (done) => {
const contract = util.getCode('loops/while-no-brackets.sol'); const contract = util.getCode('loops/while-no-brackets.sol');
const info = getInstrumentedVersion(contract, fileName, true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);

@ -12,41 +12,40 @@ const assert = require('assert');
* and passing the error to mocha. * and passing the error to mocha.
*/ */
describe('generic statements', function(){ describe('generic statements', function(){
const fileName = 'test.sol';
const filePath = path.resolve('./test.sol'); const filePath = path.resolve('./test.sol');
const pathPrefix = './'; const pathPrefix = './';
it('should compile after instrumenting a single statement (first line of function)', function(){ it('should compile after instrumenting a single statement (first line of function)', function(){
var contract = util.getCode('statements/single.sol'); var contract = util.getCode('statements/single.sol');
var info = getInstrumentedVersion(contract, "test.sol", true); var info = getInstrumentedVersion(contract, filePath, true);
var output = solc.compile(info.contract, 1); var output = solc.compile(info.contract, 1);
util.report(output.errors); util.report(output.errors);
}) })
it('should compile after instrumenting multiple statements', function(){ it('should compile after instrumenting multiple statements', function(){
var contract = util.getCode('statements/multiple.sol'); var contract = util.getCode('statements/multiple.sol');
var info = getInstrumentedVersion(contract, "test.sol", true); var info = getInstrumentedVersion(contract, filePath, true);
var output = solc.compile(info.contract, 1); var output = solc.compile(info.contract, 1);
util.report(output.errors); util.report(output.errors);
}) })
it('should compile after instrumenting a statement that is a function argument (single line)', function(){ it('should compile after instrumenting a statement that is a function argument (single line)', function(){
var contract = util.getCode('statements/fn-argument.sol'); var contract = util.getCode('statements/fn-argument.sol');
var info = getInstrumentedVersion(contract, "test.sol", true); var info = getInstrumentedVersion(contract, filePath, true);
var output = solc.compile(info.contract, 1); var output = solc.compile(info.contract, 1);
util.report(output.errors); util.report(output.errors);
}) })
it('should compile after instrumenting a statement that is a function argument (multi-line)', function(){ it('should compile after instrumenting a statement that is a function argument (multi-line)', function(){
var contract = util.getCode('statements/fn-argument-multiline.sol'); var contract = util.getCode('statements/fn-argument-multiline.sol');
var info = getInstrumentedVersion(contract, "test.sol", true); var info = getInstrumentedVersion(contract, filePath, true);
var output = solc.compile(info.contract, 1); var output = solc.compile(info.contract, 1);
util.report(output.errors); util.report(output.errors);
}) })
it('should cover a statement following a close brace', (done) => { it('should cover a statement following a close brace', (done) => {
const contract = util.getCode('statements/post-close-brace.sol'); const contract = util.getCode('statements/post-close-brace.sol');
const info = getInstrumentedVersion(contract, "test.sol", true); const info = getInstrumentedVersion(contract, filePath, true);
const coverage = new CoverageMap(); const coverage = new CoverageMap();
coverage.addContract(info, filePath); coverage.addContract(info, filePath);

Loading…
Cancel
Save