Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 4 additions & 20 deletions dist/truffle.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function plugin(truffleConfig){
coverageConfig = req.silent(coverageConfigPath) || {};

coverageConfig.cwd = truffleConfig.working_directory;
coverageConfig.contractsDir = truffleConfig.contracts_directory;
coverageConfig.originalContractsDir = truffleConfig.contracts_directory;

app = new App(coverageConfig);

Expand All @@ -66,8 +66,8 @@ async function plugin(truffleConfig){
app.instrument();

// Ask truffle to use temp folders
truffleConfig.contracts_directory = paths.contracts(app);
truffleConfig.build_directory = paths.build(app);
truffleConfig.contracts_directory = app.contractsDir;
truffleConfig.build_directory = app.artifactsDir;
truffleConfig.contracts_build_directory = paths.artifacts(truffleConfig, app);

// Additional config
Expand Down Expand Up @@ -142,27 +142,11 @@ function loadTruffleLibrary(){
* @type {Object}
*/
const paths = {
// "contracts_directory":
contracts: (app) => {
return path.join(
app.coverageDir,
app.contractsDirName
)
},

// "build_directory":
build: (app) => {
return path.join(
app.coverageDir,
app.artifactsDirName
)
},

// "contracts_build_directory":
artifacts: (truffle, app) => {
return path.join(
app.coverageDir,
app.artifactsDirName,
app.artifactsDir,
path.basename(truffle.contracts_build_directory)
)
}
Expand Down
48 changes: 28 additions & 20 deletions lib/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ class App {
this.testsErrored = false;

this.cwd = config.cwd;
this.tempFolderName = '.coverageEnv';
this.contractsDir = config.contractsDir
this.coverageDir = path.join(this.cwd, this.tempFolderName);
this.contractsDirName = 'contracts';
this.artifactsDirName = 'artifacts';
this.contractsDirName = '.coverage_contracts';
this.artifactsDirName = '.coverage_artifacts';
this.contractsDir = path.join(this.cwd, this.contractsDirName);
this.artifactsDir = path.join(this.cwd, this.artifactsDirName);

this.originalContractsDir = config.originalContractsDir

this.client = config.provider;
this.providerOptions = config.providerOptions || {};
Expand Down Expand Up @@ -55,7 +56,7 @@ class App {
this.registerSkippedItems();
this.generateEnvelope();

const target = `${this.coverageDir}/**/*.sol`;
const target = `${this.contractsDir}/**/*.sol`;

shell.ls(target).forEach(file => {
currentFile = file;
Expand All @@ -66,10 +67,11 @@ class App {
// Remember the real path
const contractPath = this.platformNeutralPath(file);
const canonicalPath = path.join(
this.cwd,
contractPath.split(`/${this.tempFolderName}`)[1]
this.originalContractsDir,
contractPath.split(`/${this.contractsDirName}`)[1]
);


// Instrument contract, save, add to coverage map
const contract = this.loadContract(contractPath);
const instrumented = this.instrumenter.instrument(contract, canonicalPath);
Expand Down Expand Up @@ -115,7 +117,7 @@ class App {

return new Promise((resolve, reject) => {
try {
this.coverage.generate(this.instrumenter.instrumentationData, this.contractsDir);
this.coverage.generate(this.instrumenter.instrumentationData, this.originalContractsDir);
const relativeMapping = this.makeKeysRelative(this.coverage.data, this.cwd);
this.saveCoverage(relativeMapping);

Expand Down Expand Up @@ -147,7 +149,8 @@ class App {
const self = this;
this.log('Cleaning up...');
shell.config.silent = true;
shell.rm('-Rf', this.coverageDir);
shell.rm('-Rf', this.contractsDir);
shell.rm('-Rf', this.artifactsDir);

if (this.provider && this.provider.close){
this.log('Shutting down ganache-core')
Expand All @@ -168,26 +171,31 @@ class App {
}

saveCoverage(data){
fs.writeFileSync('./coverage.json', JSON.stringify(data));
const covPath = path.join(this.cwd, "coverage.json");
fs.writeFileSync(covPath, JSON.stringify(data));
}

// ======
// Launch
// ======
sanityCheckContext(contractsDir){
if (!shell.test('-e', this.contractsDir)){
sanityCheckContext(){
if (!shell.test('-e', this.originalContractsDir)){
this.cleanUp("Couldn't find a 'contracts' folder to instrument.");
}

if (shell.test('-e', path.join(this.cwd, this.coverageDir))){
shell.rm('-Rf', this.coverageDir);
if (shell.test('-e', path.join(this.cwd, this.contractsDir))){
shell.rm('-Rf', this.contractsDir);
}

if (shell.test('-e', path.join(this.cwd, this.artifactsDir))){
shell.rm('-Rf', this.artifactsDir);
}
}

generateEnvelope(){
shell.mkdir(this.coverageDir);
shell.mkdir(path.join(this.coverageDir, this.artifactsDirName))
shell.cp('-Rf', this.contractsDir, this.coverageDir)
shell.mkdir(this.contractsDir);
shell.mkdir(this.artifactsDir);
shell.cp('-Rf', `${this.originalContractsDir}/*`, this.contractsDir);
}

// =====
Expand Down Expand Up @@ -226,7 +234,7 @@ class App {
*/
inSkippedFolder(file){
let shouldSkip;
const root = `${this.coverageDir}/${this.contractsDirName}`;
const root = `${this.contractsDir}`;
this.skippedFolders.forEach(folderToSkip => {
folderToSkip = `${root}/${folderToSkip}`;
if (file.indexOf(folderToSkip) === 0)
Expand All @@ -239,7 +247,7 @@ class App {
* Parses the skipFiles option (which also accepts folders)
*/
registerSkippedItems(){
const root = `${this.coverageDir}/${this.contractsDirName}`;
const root = `${this.contractsDir}`;
this.skippedFolders = this.skipFiles.filter(item => path.extname(item) !== '.sol')
this.skipFiles = this.skipFiles.map(contract => `${root}/${contract}`);
this.skipFiles.push(`${root}/Migrations.sol`);
Expand Down
44 changes: 24 additions & 20 deletions test/units/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const fs = require('fs');
const shell = require('shelljs');
const mock = require('../util/integration.truffle');
const plugin = require('../../dist/truffle.plugin');
const path = require('path')
const util = require('util')
const opts = { compact: false, depth: 5, breakLength: 80 };

Expand All @@ -16,18 +17,21 @@ function assertCleanInitialState(){
assert(pathExists('./coverage.json') === false, 'should start without: coverage.json');
}

function assertCoverageGenerated(){
function assertCoverageGenerate(truffleConfig){
const jsonPath = path.join(truffleConfig.working_directory, "coverage.json");
assert(pathExists('./coverage') === true, 'should gen coverage folder');
assert(pathExists('./coverage.json') === true, 'should gen coverage.json');
assert(pathExists(jsonPath) === true, 'should gen coverage.json');
}

function assertCoverageNotGenerated(){
function assertCoverageNotGenerated(truffleConfig){
const jsonPath = path.join(truffleConfig.working_directory, "coverage.json");
assert(pathExists('./coverage') !== true, 'should NOT gen coverage folder');
assert(pathExists('./coverage.json') !== true, 'should NOT gen coverage.json');
assert(pathExists(jsonPath) !== true, 'should NOT gen coverage.json');
}

function getOutput(){
return JSON.parse(fs.readFileSync('./coverage.json', 'utf8'));
function getOutput(truffleConfig){
const jsonPath = path.join(truffleConfig.working_directory, "coverage.json");
return JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
}

// ========
Expand All @@ -54,9 +58,9 @@ describe('app', function() {
mock.install('Simple', 'simple.js', solcoverConfig);
await plugin(truffleConfig);

assertCoverageGenerated();
assertCoverageGenerate(truffleConfig);

const output = getOutput();
const output = getOutput(truffleConfig);
const path = Object.keys(output)[0];

assert(output[path].fnMap['1'].name === 'test', 'coverage.json missing "test"');
Expand Down Expand Up @@ -92,7 +96,7 @@ describe('app', function() {
await plugin(truffleConfig);
});

it.skip('project with node_modules packages and relative path solidity imports', async function() {
it('project with node_modules packages and relative path solidity imports', async function() {
assertCleanInitialState();
mock.installFullProject('import-paths');
await plugin(truffleConfig);
Expand All @@ -105,9 +109,9 @@ describe('app', function() {
mock.install('OnlyCall', 'only-call.js', solcoverConfig);
await plugin(truffleConfig);

assertCoverageGenerated();
assertCoverageGenerate(truffleConfig);

const output = getOutput();
const output = getOutput(truffleConfig);
const path = Object.keys(output)[0];
assert(output[path].fnMap['1'].name === 'addTwo', 'cov should map "addTwo"');
});
Expand All @@ -118,9 +122,9 @@ describe('app', function() {
mock.install('Wallet', 'wallet.js', solcoverConfig);
await plugin(truffleConfig);

assertCoverageGenerated();
assertCoverageGenerate(truffleConfig);

const output = getOutput();
const output = getOutput(truffleConfig);
const path = Object.keys(output)[0];
assert(output[path].fnMap['1'].name === 'transferPayment', 'cov should map "transferPayment"');
});
Expand All @@ -133,9 +137,9 @@ describe('app', function() {
mock.installDouble(['Proxy', 'Owned'], 'inheritance.js', solcoverConfig);
await plugin(truffleConfig);

assertCoverageGenerated();
assertCoverageGenerate(truffleConfig);

const output = getOutput();
const output = getOutput(truffleConfig);
const firstKey = Object.keys(output)[0];
assert(Object.keys(output).length === 1, 'Wrong # of contracts covered');
assert(firstKey.substr(firstKey.length - 9) === 'Proxy.sol', 'Wrong contract covered');
Expand All @@ -147,9 +151,9 @@ describe('app', function() {
mock.installDouble(['Proxy', 'Owned'], 'inheritance.js', solcoverConfig);
await plugin(truffleConfig);

assertCoverageGenerated();
assertCoverageGenerate(truffleConfig);

const output = getOutput();
const output = getOutput(truffleConfig);
const ownedPath = Object.keys(output)[0];
const proxyPath = Object.keys(output)[1];
assert(output[ownedPath].fnMap['1'].name === 'constructor', '"constructor" not covered');
Expand All @@ -169,9 +173,9 @@ describe('app', function() {
assert(err.message.includes('failed under coverage'));
}

assertCoverageGenerated();
assertCoverageGenerate(truffleConfig);

const output = getOutput();
const output = getOutput(truffleConfig);
const path = Object.keys(output)[0];

assert(output[path].fnMap['1'].name === 'test', 'cov missing "test"');
Expand Down Expand Up @@ -210,7 +214,7 @@ describe('app', function() {
assert(err.message.includes('Compilation failed'));
}

assertCoverageNotGenerated();
assertCoverageNotGenerated(truffleConfig);
});

});