Merge pull request #73 from sc-forks/signing-test

Add testrpc-sc signing test and lint
pull/76/head
c-g-e-w-e-k-e- 7 years ago committed by GitHub
commit ebda87dd3c
  1. 2
      .eslintrc
  2. 1
      bin/exec.js
  3. 19
      lib/app.js
  4. 2
      lib/instrumenter.js
  5. 2
      lib/truffleConfig.js
  6. 17
      test/app.js
  7. 31
      test/cli/sign.js
  8. 4
      test/conditional.js
  9. 6
      test/statements.js
  10. 22
      test/util/mockTestCommand.js

@ -14,7 +14,7 @@
/* General */ /* General */
"consistent-return": [0], "consistent-return": [0],
"no-return-assign": [0], "no-return-assign": [0],
"complexity": ["error", 6], "complexity": ["error", 20],
"eol-last": [0], "eol-last": [0],
"eqeqeq": ["error", "smart"], "eqeqeq": ["error", "smart"],
"max-len": ["error", 150, 2], "max-len": ["error", 150, 2],

@ -2,6 +2,7 @@
const App = require('./../lib/app.js'); const App = require('./../lib/app.js');
const reqCwd = require('req-cwd'); const reqCwd = require('req-cwd');
const death = require('death'); const death = require('death');
const log = console.log; const log = console.log;
const config = reqCwd.silent('./.solcover.js') || {}; const config = reqCwd.silent('./.solcover.js') || {};

@ -20,12 +20,12 @@ class App {
// Options // Options
this.network = ''; // Default truffle network execution flag this.network = ''; // Default truffle network execution flag
this.silence = ''; // Default log level: configurable by --silence this.silence = ''; // Default log level passed to shell
this.log = console.log; this.log = console.log;
// Other // Other
this.testrpcProcess; // ref to testrpc server we need to close on exit this.testrpcProcess = null; // ref to testrpc server we need to close on exit
this.events; // ref to string loaded from 'allFiredEvents' this.events = null; // ref to string array loaded from 'allFiredEvents'
this.testsErrored = null; // flag set to non-null if truffle tests error this.testsErrored = null; // flag set to non-null if truffle tests error
this.coverage = new CoverageMap(); // initialize a coverage map this.coverage = new CoverageMap(); // initialize a coverage map
@ -51,7 +51,6 @@ class App {
* the coverage environment folder. Process exits(1) if try fails * the coverage environment folder. Process exits(1) if try fails
*/ */
generateCoverageEnvironment() { generateCoverageEnvironment() {
this.log('Generating coverage environment'); this.log('Generating coverage environment');
try { try {
@ -76,7 +75,7 @@ class App {
// No coverage network defaults to the dev network on port 8555, high gas / low price. // No coverage network defaults to the dev network on port 8555, high gas / low price.
} else { } else {
const trufflejs = defaultTruffleConfig(this.port, gasLimitHex, gasPriceHex) const trufflejs = defaultTruffleConfig(this.port, gasLimitHex, gasPriceHex);
fs.writeFileSync(`${this.coverageDir}/truffle.js`, trufflejs); fs.writeFileSync(`${this.coverageDir}/truffle.js`, trufflejs);
} }
} catch (err) { } catch (err) {
@ -94,7 +93,6 @@ class App {
* + Add instrumentation info to the coverage map * + Add instrumentation info to the coverage map
*/ */
instrumentTarget() { instrumentTarget() {
this.skipFiles = this.skipFiles.map(contract => `${this.coverageDir}/contracts/${contract}`); this.skipFiles = this.skipFiles.map(contract => `${this.coverageDir}/contracts/${contract}`);
this.skipFiles.push(`${this.coverageDir}/contracts/Migrations.sol`); this.skipFiles.push(`${this.coverageDir}/contracts/Migrations.sol`);
@ -128,7 +126,6 @@ class App {
*/ */
launchTestrpc() { launchTestrpc() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!this.norpc) { if (!this.norpc) {
const defaultRpcOptions = `--gasLimit ${gasLimitHex} --accounts ${this.accounts} --port ${this.port}`; const defaultRpcOptions = `--gasLimit ${gasLimitHex} --accounts ${this.accounts} --port ${this.port}`;
const options = this.testrpcOptions || defaultRpcOptions; const options = this.testrpcOptions || defaultRpcOptions;
@ -153,7 +150,7 @@ class App {
} else { } else {
return resolve(); return resolve();
} }
}) });
} }
/** /**
@ -163,9 +160,7 @@ class App {
* Also reads the 'allFiredEvents' log. * Also reads the 'allFiredEvents' log.
*/ */
runTestCommand() { runTestCommand() {
try { try {
const defaultCommand = `truffle test ${this.network} ${this.silence}`; const defaultCommand = `truffle test ${this.network} ${this.silence}`;
const command = this.testCommand || defaultCommand; const command = this.testCommand || defaultCommand;
this.log(`Running: ${command}\n(this can take a few seconds)...`); this.log(`Running: ${command}\n(this can take a few seconds)...`);
@ -197,7 +192,6 @@ class App {
* Generate coverage / write coverage report / run istanbul * Generate coverage / write coverage report / run istanbul
*/ */
generateReport() { generateReport() {
const collector = new istanbul.Collector(); const collector = new istanbul.Collector();
const reporter = new istanbul.Reporter(); const reporter = new istanbul.Reporter();
@ -220,9 +214,8 @@ class App {
} catch (err) { } catch (err) {
const msg = 'There was a problem generating the coverage map / running Istanbul.\n'; const msg = 'There was a problem generating the coverage map / running Istanbul.\n';
this.cleanUp(msg + err); this.cleanUp(msg + err);
} }
}) });
} }
// ------------------------------------------ Utils ---------------------------------------------- // ------------------------------------------ Utils ----------------------------------------------

@ -16,7 +16,7 @@ instrumenter.prePosition = function prePosition(expression){
expression.left.type === 'MemberExpression') { expression.left.type === 'MemberExpression') {
expression.start -= 2; expression.start -= 2;
} }
} };
instrumenter.instrumentAssignmentExpression = function instrumentAssignmentExpression(contract, expression) { instrumenter.instrumentAssignmentExpression = function instrumentAssignmentExpression(contract, expression) {
// The only time we instrument an assignment expression is if there's a conditional expression on // The only time we instrument an assignment expression is if there's a conditional expression on

@ -10,5 +10,5 @@ module.exports = function truffleConfig(port, gasLimit, gasPrice) {
gasPrice: ${gasPrice} gasPrice: ${gasPrice}
} }
} }
};` };`;
}; };

@ -27,9 +27,15 @@ describe('app', () => {
norpc: true, norpc: true,
}; };
before(() => { before(done => {
const command = `./node_modules/.bin/testrpc-sc --gasLimit 0xfffffffffff --port ${port}`; const command = `./node_modules/.bin/testrpc-sc --gasLimit 0xfffffffffff --port ${port}`;
testrpcProcess = childprocess.exec(command); testrpcProcess = childprocess.exec(command);
testrpcProcess.stdout.on('data', data => {
if (data.includes('Listening')) {
done();
}
});
}); });
afterEach(() => { afterEach(() => {
@ -198,6 +204,14 @@ describe('app', () => {
collectGarbage(); collectGarbage();
}); });
it('testrpc-sc signs and recovers messages correctly', () => {
// sign.js signs and recovers
mock.install('Simple.sol', 'sign.js', config);
shell.exec(script);
assert(shell.error() === null, 'script should not error');
collectGarbage();
});
it('tests require assets outside of test folder: should generate coverage, cleanup & exit(0)', () => { it('tests require assets outside of test folder: should generate coverage, cleanup & exit(0)', () => {
// Directory should be clean // Directory should be clean
assert(pathExists('./coverage') === false, 'should start without: coverage'); assert(pathExists('./coverage') === false, 'should start without: coverage');
@ -239,6 +253,7 @@ describe('app', () => {
collectGarbage(); collectGarbage();
}); });
it('contract uses inheritance: should generate coverage, cleanup & exit(0)', () => { it('contract uses inheritance: should generate coverage, cleanup & exit(0)', () => {
// Run against a contract that 'is' another contract // Run against a contract that 'is' another contract
assert(pathExists('./coverage') === false, 'should start without: coverage'); assert(pathExists('./coverage') === false, 'should start without: coverage');

@ -0,0 +1,31 @@
/* eslint-env node, mocha */
/* global artifacts, contract, assert */
const Web3 = require('web3');
const ethUtil = require('ethereumjs-util');
const provider = new Web3.providers.HttpProvider('http://localhost:8555'); // testrpc-sc
const web3 = new Web3(provider);
const Simple = artifacts.require('./Simple.sol');
contract('Simple', accounts => {
it('should set x to 5', () => {
let simple;
return Simple.deployed()
.then(instance => instance.test(5)) // We need this line to generate some coverage
.then(() => {
const message = 'Enclosed is my formal application for permanent residency in New Zealand';
const messageSha3 = web3.sha3(message);
const signature = web3.eth.sign(accounts[0], messageSha3);
const messageBuffer = new Buffer(messageSha3.replace('0x', ''), 'hex');
const messagePersonalHash = ethUtil.hashPersonalMessage(messageBuffer);
const sigParams = ethUtil.fromRpcSig(signature);
const publicKey = ethUtil.ecrecover(messagePersonalHash, sigParams.v, sigParams.r, sigParams.s);
const senderBuffer = ethUtil.pubToAddress(publicKey);
const sender = ethUtil.bufferToHex(senderBuffer);
assert.equal(sender, accounts[0]);
});
});
});

@ -168,13 +168,13 @@ describe('conditional statements', () => {
vm.execute(info.contract, 'a', []).then(events => { vm.execute(info.contract, 'a', []).then(events => {
const mapping = coverage.generate(events, pathPrefix); const mapping = coverage.generate(events, pathPrefix);
assert.deepEqual(mapping[filePath].l, { assert.deepEqual(mapping[filePath].l, {
'11': 1, '12': 1, 11: 1, 12: 1,
}); });
assert.deepEqual(mapping[filePath].b, { assert.deepEqual(mapping[filePath].b, {
1: [0, 1], 1: [0, 1],
}); });
assert.deepEqual(mapping[filePath].s, { assert.deepEqual(mapping[filePath].s, {
'1': 1, '2': 1, 1: 1, 2: 1,
}); });
assert.deepEqual(mapping[filePath].f, { assert.deepEqual(mapping[filePath].f, {
1: 1, 1: 1,

@ -109,14 +109,14 @@ describe('generic statements', () => {
vm.execute(info.contract, 'a', []).then(events => { vm.execute(info.contract, 'a', []).then(events => {
const mapping = coverage.generate(events, pathPrefix); const mapping = coverage.generate(events, pathPrefix);
assert.deepEqual(mapping[filePath].l, { assert.deepEqual(mapping[filePath].l, {
6: 1, 10: 1, 11: 1 6: 1, 10: 1, 11: 1,
}); });
assert.deepEqual(mapping[filePath].b, {}); assert.deepEqual(mapping[filePath].b, {});
assert.deepEqual(mapping[filePath].s, { assert.deepEqual(mapping[filePath].s, {
1: 1, 2: 1, 3: 1 1: 1, 2: 1, 3: 1,
}); });
assert.deepEqual(mapping[filePath].f, { assert.deepEqual(mapping[filePath].f, {
1: 1, 2: 1 1: 1, 2: 1,
}); });
done(); done();
}).catch(done); }).catch(done);

@ -1,22 +1,22 @@
#!/usr/bin/env node #!/usr/bin/env node
const fs = require('fs') const fs = require('fs');
const request = require('request') const request = require('request');
request({ request({
uri: 'http://localhost:8888', uri: 'http://localhost:8888',
body: { body: {
jsonrpc: "2.0", jsonrpc: '2.0',
method: "web3_clientVersion", method: 'web3_clientVersion',
params: [], params: [],
id: 0 id: 0,
}, },
json: true json: true,
}, (error, response, body) => { }, (error, response, body) => {
if (error) { if (error) {
console.error(error) console.error(error);
process.exit(1) process.exit(1);
} }
fs.writeFileSync('../allFiredEvents', 'foobar') fs.writeFileSync('../allFiredEvents', 'foobar');
process.exit(0) process.exit(0);
}) });

Loading…
Cancel
Save