const assert = require('assert'); const fs = require('fs'); const path = require('path') const shell = require('shelljs'); const verify = require('../../util/verifiers') const mock = require('../../util/integration'); const plugin = require('../../../plugins/truffle.plugin'); // ======================= // CLI Options / Flags // ======================= describe('Truffle Plugin: command line options', function() { let truffleConfig; let solcoverConfig; beforeEach(() => { mock.clean(); mock.loggerOutput.val = ''; solcoverConfig = {}; truffleConfig = mock.getDefaultTruffleConfig(); verify.cleanInitialState(); }) afterEach(() => mock.clean()); it('--file test/', async function() { truffleConfig.file = path.join( truffleConfig.working_directory, 'test/specific_a.js' ); mock.installFullProject('test-files'); await plugin(truffleConfig); const expected = [ { file: mock.pathToContract(truffleConfig, 'ContractA.sol'), pct: 100 }, { file: mock.pathToContract(truffleConfig, 'ContractB.sol'), pct: 0, }, { file: mock.pathToContract(truffleConfig, 'ContractC.sol'), pct: 0, }, ]; verify.lineCoverage(expected); }); it('--file test/', async function() { truffleConfig.file = path.join( truffleConfig.working_directory, 'test/globby*' ); mock.installFullProject('test-files'); await plugin(truffleConfig); const expected = [ { file: mock.pathToContract(truffleConfig, 'ContractA.sol'), pct: 0, }, { file: mock.pathToContract(truffleConfig, 'ContractB.sol'), pct: 100, }, { file: mock.pathToContract(truffleConfig, 'ContractC.sol'), pct: 100, }, ]; verify.lineCoverage(expected); }); it('--file test/gl{o,b}*.js', async function() { truffleConfig.file = path.join( truffleConfig.working_directory, 'test/gl{o,b}*.js' ); mock.installFullProject('test-files'); await plugin(truffleConfig); const expected = [ { file: mock.pathToContract(truffleConfig, 'ContractA.sol'), pct: 0, }, { file: mock.pathToContract(truffleConfig, 'ContractB.sol'), pct: 100, }, { file: mock.pathToContract(truffleConfig, 'ContractC.sol'), pct: 100, }, ]; verify.lineCoverage(expected); }); it('--config ../.solcover.js', async function() { solcoverConfig = { silent: process.env.SILENT ? true : false, istanbulReporter: ['json-summary', 'text'] }; // Write solcoverjs to parent dir of sc_temp (where the test project is installed) fs.writeFileSync( '.solcover.js', `module.exports=${JSON.stringify(solcoverConfig)}` ); // This relative path has to be ./ prefixed (it's path.joined to truffle's working_directory) truffleConfig.solcoverjs = './../.solcover.js'; mock.install('Simple', 'simple.js'); await plugin(truffleConfig); // The relative solcoverjs uses the json-summary reporter const expected = [{ file: mock.pathToContract(truffleConfig, 'Simple.sol'), pct: 100 }]; verify.lineCoverage(expected); shell.rm('.solcover.js'); }); it('--help', async function(){ truffleConfig.help = "true"; truffleConfig.logger = mock.testLogger; mock.install('Simple', 'simple.js', solcoverConfig); await plugin(truffleConfig); assert( mock.loggerOutput.val.includes('Usage'), `Should output help with Usage instruction : ${mock.loggerOutput.val}` ); }) it('--version', async function(){ truffleConfig.version = "true"; truffleConfig.logger = mock.testLogger; mock.install('Simple', 'simple.js', solcoverConfig); await plugin(truffleConfig); assert( mock.loggerOutput.val.includes('truffle'), `Should output truffle version: ${mock.loggerOutput.val}` ); assert( mock.loggerOutput.val.includes('ganache-core'), `Should output ganache-core version: ${mock.loggerOutput.val}` ); assert( mock.loggerOutput.val.includes('solidity-coverage'), `Should output solidity-coverage version: ${mock.loggerOutput.val}` ); }) it('--useGlobalTruffle', async function(){ truffleConfig.useGlobalTruffle = true; truffleConfig.logger = mock.testLogger; mock.install('Simple', 'simple.js', solcoverConfig); await plugin(truffleConfig); assert( mock.loggerOutput.val.includes('global node_modules'), `Should notify it's using global truffle: ${mock.loggerOutput.val}` ); }); it('--temp', async function(){ truffleConfig.logger = mock.testLogger; truffleConfig.temp = 'special_location'; truffleConfig.verbose = true; mock.install('Simple', 'simple.js', solcoverConfig); await plugin(truffleConfig); assert( mock.loggerOutput.val.includes("/special_location/contracts"), `Should write artifacts to "special_location": ${mock.loggerOutput.val}` ); }); it('--network (network_id mismatch in configs)', async function(){ truffleConfig.logger = mock.testLogger; solcoverConfig = { providerOptions: { network_id: 5 }} truffleConfig.network = 'development'; truffleConfig.networks['development'].network_id = 7; mock.install('Simple', 'simple.js', solcoverConfig); await plugin(truffleConfig); assert( mock.loggerOutput.val.includes("'network_id' values"), `Should notify about network_id values: ${mock.loggerOutput.val}` ); }); it('--network (truffle config missing port)', async function(){ truffleConfig.logger = mock.testLogger; truffleConfig.network = 'development'; truffleConfig.networks['development'].port = undefined; mock.install('Simple', 'simple.js', solcoverConfig); await plugin(truffleConfig); assert( mock.loggerOutput.val.includes("No 'port' was declared"), `Should notify about missing port: ${mock.loggerOutput.val}` ); assert( mock.loggerOutput.val.includes("8555"), `Should have used default coverage port 8555: ${mock.loggerOutput.val}` ); }); it('--network (declared port mismatches)', async function(){ truffleConfig.logger = mock.testLogger; truffleConfig.network = 'development'; // 8545 solcoverConfig = { port: 8222 } mock.install('Simple', 'simple.js', solcoverConfig); await plugin(truffleConfig); assert( mock.loggerOutput.val.includes("The 'port' values"), `Should notify about mismatched port values: ${mock.loggerOutput.val}` ); assert( mock.loggerOutput.val.includes("8545"), `Should have used default coverage port 8545: ${mock.loggerOutput.val}` ); }); it('--matrix', async function(){ process.env.TRUFFLE_TEST = true; // Path to reporter differs btw HH and Truffle truffleConfig.matrix = true; mock.installFullProject('matrix'); await plugin(truffleConfig); // Integration test checks output path configurabililty const altMatrixPath = path.join(process.cwd(), mock.pathToTemp('./alternateTestMatrix.json')); const expMatrixPath = path.join(process.cwd(), mock.pathToTemp('./expectedTestMatrixHardhat.json')); const altMochaPath = path.join(process.cwd(), mock.pathToTemp('./alternateMochaOutput.json')); const expMochaPath = path.join(process.cwd(), mock.pathToTemp('./expectedMochaOutput.json')); const producedMatrix = require(altMatrixPath) const expectedMatrix = require(expMatrixPath); const producedMochaOutput = require(altMochaPath); const expectedMochaOutput = require(expMochaPath); assert.deepEqual(producedMatrix, expectedMatrix); assert.deepEqual(producedMochaOutput, expectedMochaOutput); process.env.TRUFFLE_TEST = false; }); it('--abi', async function(){ const expected = [ { "contractName": "Migrations", "humanReadableAbiList": [ "function last_completed_migration() view returns (uint256)", "function owner() view returns (address)", "function setCompleted(uint256) nonpayable", "function upgrade(address) nonpayable" ] }, { "contractName": "Simple", "humanReadableAbiList": [ "function getX() view returns (uint256)", "function test(uint256) nonpayable" ] } ]; truffleConfig.abi = true; mock.install('Simple', 'simple.js', solcoverConfig); await plugin(truffleConfig); const outputPath = path.join(process.cwd(), mock.pathToTemp('./humanReadableAbis.json')); const output = require(outputPath); assert.deepEqual(output, expected); }) });