mirror of https://github.com/embarklabs/embark.git
add embark solidity tests package (not ready yet)
This commit is contained in:
parent
a8e71e3528
commit
5736dc9498
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"name": "embark-solidity-tests",
|
||||||
|
"version": "5.0.0",
|
||||||
|
"description": "Plugin to run Embark solidity tests",
|
||||||
|
"main": "dist/lib/index.js",
|
||||||
|
"repository": {
|
||||||
|
"directory": "packages/embark-solidity-tests",
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/embark-framework/embark/"
|
||||||
|
},
|
||||||
|
"author": "Iuri Matias <iuri.matias@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": "https://github.com/embark-framework/embark/issues",
|
||||||
|
"keywords": [
|
||||||
|
"blockchain",
|
||||||
|
"dapps",
|
||||||
|
"ethereum",
|
||||||
|
"ipfs",
|
||||||
|
"serverless",
|
||||||
|
"solc",
|
||||||
|
"solidity"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "cross-env BABEL_ENV=node babel src --extensions \".js\" --out-dir dist --root-mode upward --source-maps",
|
||||||
|
"ci": "npm run qa",
|
||||||
|
"clean": "npm run reset",
|
||||||
|
"lint": "npm-run-all lint:*",
|
||||||
|
"lint:js": "eslint src/",
|
||||||
|
"// lint:ts": "tslint -c tslint.json \"src/**/*.ts\"",
|
||||||
|
"package": "npm pack",
|
||||||
|
"// qa": "npm-run-all lint typecheck build package",
|
||||||
|
"qa": "npm-run-all lint build package",
|
||||||
|
"reset": "npx rimraf dist embark-*.tgz package",
|
||||||
|
"start": "npm run watch",
|
||||||
|
"// typecheck": "tsc",
|
||||||
|
"watch": "run-p watch:*",
|
||||||
|
"watch:build": "npm run build -- --verbose --watch",
|
||||||
|
"// watch:typecheck": "npm run typecheck -- --preserveWatchOutput --watch",
|
||||||
|
"test": "mocha dist/test/**/*.js"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": "../../.eslintrc.json"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "7.2.3",
|
||||||
|
"@babel/core": "7.2.2",
|
||||||
|
"@types/async": "2.0.50",
|
||||||
|
"cross-env": "5.2.0",
|
||||||
|
"eslint": "5.7.0",
|
||||||
|
"mocha": "6.2.0",
|
||||||
|
"npm-run-all": "4.1.5",
|
||||||
|
"rimraf": "2.6.3",
|
||||||
|
"tslint": "5.16.0",
|
||||||
|
"typescript": "3.4.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.12.0 <12.0.0",
|
||||||
|
"npm": ">=6.4.1",
|
||||||
|
"yarn": ">=1.12.3"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
const async = require("async");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const {
|
||||||
|
File,
|
||||||
|
Types
|
||||||
|
} = require("embark-utils");
|
||||||
|
|
||||||
|
const SOLIDITY_TEST_MATCH = /^.+_test\.sol$/i;
|
||||||
|
const PRAGMA_MATCH = /^pragma solidity (.*);$/mi;
|
||||||
|
const LIBRARY_NAME_MATCH = /remix_tests\.sol/i;
|
||||||
|
const IMPORT_REMIX_TESTS_STMT = `
|
||||||
|
// - INJECTED BY EMBARK -
|
||||||
|
import "remix_tests.sol";
|
||||||
|
// ----------------------
|
||||||
|
`;
|
||||||
|
|
||||||
|
class SolidityTestRunner {
|
||||||
|
constructor(embark, _options) {
|
||||||
|
this.embark = embark;
|
||||||
|
this.events = embark.events;
|
||||||
|
|
||||||
|
this.files = new Set();
|
||||||
|
|
||||||
|
this.events.request("tests:runner:register",
|
||||||
|
"Solidity",
|
||||||
|
this.match.bind(this),
|
||||||
|
this.addFile.bind(this),
|
||||||
|
this.run.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
addFile(path) {
|
||||||
|
if (!this.match(path)) {
|
||||||
|
throw new Error(`invalid Solidity test path: ${path}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.files.add(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
match(path) {
|
||||||
|
return SOLIDITY_TEST_MATCH.test(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
const {events} = this;
|
||||||
|
|
||||||
|
let web3;
|
||||||
|
let contractFiles = [];
|
||||||
|
let compiledContracts = [];
|
||||||
|
|
||||||
|
this.files.forEach(f => {
|
||||||
|
const resolver = (cb) => {
|
||||||
|
fs.readFile(file, (err, data) => { cb(data.toString()); });
|
||||||
|
};
|
||||||
|
|
||||||
|
const file = new File({
|
||||||
|
path: f,
|
||||||
|
originalPath: f,
|
||||||
|
type: Types.dappFile,
|
||||||
|
resolver
|
||||||
|
});
|
||||||
|
|
||||||
|
contractFiles.add(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
(next) => {
|
||||||
|
events.request("compiler:contracts:compile", contractFiles, next);
|
||||||
|
},
|
||||||
|
(cc, next) => {
|
||||||
|
events.request("contracts:build", {}, cc, next);
|
||||||
|
},
|
||||||
|
(contractsList, contractsDeps, next) => {
|
||||||
|
events.request("deployment:contracts:deploy", contractsList, contractDeps, next);
|
||||||
|
},
|
||||||
|
(next) => {
|
||||||
|
events.request("blockchain:client:provider", "ethereum", next);
|
||||||
|
},
|
||||||
|
(bcProvider, next) => {
|
||||||
|
web3 = new Web3(bcProvider);
|
||||||
|
},
|
||||||
|
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare(contents) {
|
||||||
|
if (LIBRARY_NAME_MATCH.test(contents)) {
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = contents.search(PRAGMA_MATCH);
|
||||||
|
const offset = contents.indexOf("\n", start);
|
||||||
|
|
||||||
|
// Here we offset the offset + 1 so that it doesn't double newline.
|
||||||
|
return contents.slice(0, offset) + IMPORT_REMIX_TESTS_STMT + contents.slice(offset + 1, contents.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SolidityTestRunner;
|
|
@ -0,0 +1,115 @@
|
||||||
|
/* globals beforeEach, describe, it */
|
||||||
|
const assert = require("assert").strict;
|
||||||
|
const sinon = require("sinon");
|
||||||
|
|
||||||
|
const SolidityTestRunner = require("../lib");
|
||||||
|
|
||||||
|
const validFiles = [
|
||||||
|
"SOME_UPPERCASE_TEST.sol",
|
||||||
|
"other_uppercase_test.SOL",
|
||||||
|
"some_file_test.sol",
|
||||||
|
"file_with/path_test.sol",
|
||||||
|
"c:\projects\cool-dapp\test\escrow_test.sol"
|
||||||
|
];
|
||||||
|
|
||||||
|
const invalidFiles = [
|
||||||
|
"escrow.sol",
|
||||||
|
"tricky.sol.js",
|
||||||
|
"somesol.js",
|
||||||
|
"c:\projects\cool-dapp\file.sol\test_file.md"
|
||||||
|
];
|
||||||
|
|
||||||
|
const cleanCode = (code) => {
|
||||||
|
return code
|
||||||
|
.trim()
|
||||||
|
.split("\n")
|
||||||
|
.map(l => l.replace(/^\s+/, ''))
|
||||||
|
.join("\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("SolidityTestRunner", () => {
|
||||||
|
let embark;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const events = { request: sinon.spy() };
|
||||||
|
embark = { events: events };
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("constructor", () => {
|
||||||
|
it("registers the runner", () => {
|
||||||
|
const _ = new SolidityTestRunner(embark);
|
||||||
|
assert(embark.events.request.called);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("methods", () => {
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
beforeEach(() => { instance = new SolidityTestRunner(embark); });
|
||||||
|
|
||||||
|
describe("match", () => {
|
||||||
|
it("matches .sol files", () => {
|
||||||
|
validFiles.forEach(f => {
|
||||||
|
assert(instance.match(f), `didn't match ${f} when it should`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't match non .sol files", () => {
|
||||||
|
invalidFiles.forEach(f => {
|
||||||
|
assert(!instance.match(f), `matched ${f} when it shouldn't`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("prepare", () => {
|
||||||
|
it("doesn't mutate code with the import statement", () => {
|
||||||
|
const code = cleanCode(`
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
import "remix_tests.sol";
|
||||||
|
import "escrow.sol";
|
||||||
|
contract Foo {}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const modified = instance.prepare(code);
|
||||||
|
assert.equal(code, modified);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("mutates code without the import statement", () => {
|
||||||
|
const code = cleanCode(`
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
import "escrow.sol";
|
||||||
|
contract Foo {}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const wanted = cleanCode(`
|
||||||
|
pragma solidity ^0.4.24;
|
||||||
|
// - INJECTED BY EMBARK -
|
||||||
|
import "remix_tests.sol";
|
||||||
|
// ----------------------
|
||||||
|
import "escrow.sol";
|
||||||
|
contract Foo {}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const modified = instance.prepare(code);
|
||||||
|
assert.equal(wanted, modified);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("addFile", () => {
|
||||||
|
it("throws an exception with invalid files", () => {
|
||||||
|
invalidFiles.forEach(f => {
|
||||||
|
assert.throws(() => { instance.addFile(f); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("remembers files that are added", () => {
|
||||||
|
validFiles.forEach(f => instance.addFile(f));
|
||||||
|
assert.deepEqual(instance.files, new Set(validFiles));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("run", () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -21,12 +21,16 @@ class TestRunner {
|
||||||
this.events = embark.events;
|
this.events = embark.events;
|
||||||
this.fs = embark.fs;
|
this.fs = embark.fs;
|
||||||
this.ipc = options.ipc;
|
this.ipc = options.ipc;
|
||||||
this.runResults = [];
|
this.runners = {};
|
||||||
this.gasLimit = options.coverage ? COVERAGE_GAS_LIMIT : GAS_LIMIT;
|
this.gasLimit = options.coverage ? COVERAGE_GAS_LIMIT : GAS_LIMIT;
|
||||||
|
|
||||||
this.events.setCommandHandler('tests:run', (options, callback) => {
|
this.events.setCommandHandler('tests:run', (options, callback) => {
|
||||||
this.run(options, callback);
|
this.run(options, callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.events.setCommandHandler('tests:runner:register', (name, glob, addFn, runFn) => {
|
||||||
|
this.runners[name] = {glob, addFn, runFn};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
run(options, cb) {
|
run(options, cb) {
|
||||||
|
@ -45,6 +49,7 @@ class TestRunner {
|
||||||
self.getFilesFromDir(testPath, next);
|
self.getFilesFromDir(testPath, next);
|
||||||
},
|
},
|
||||||
(files, next) => { // group files by types
|
(files, next) => { // group files by types
|
||||||
|
// TODO: figure out what files belong where
|
||||||
const types = { jsFiles: ".js", solidityFiles: "_test.sol" };
|
const types = { jsFiles: ".js", solidityFiles: "_test.sol" };
|
||||||
const groups = Object.entries(types).reduce((acc, [type, ext]) => {
|
const groups = Object.entries(types).reduce((acc, [type, ext]) => {
|
||||||
acc[type] = files.filter(f => f.endsWith(ext));
|
acc[type] = files.filter(f => f.endsWith(ext));
|
||||||
|
@ -168,7 +173,8 @@ class TestRunner {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
], (_err) => {
|
], (_err) => {
|
||||||
acctCb(accounts);
|
console.log('=====================> finished config');
|
||||||
|
acctCb(null, accounts);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -200,6 +206,7 @@ class TestRunner {
|
||||||
},
|
},
|
||||||
(cf, next) => { // compile contracts
|
(cf, next) => { // compile contracts
|
||||||
console.log('compiling contracts');
|
console.log('compiling contracts');
|
||||||
|
console.dir(cf);
|
||||||
events.request("compiler:contracts:compile", cf, next);
|
events.request("compiler:contracts:compile", cf, next);
|
||||||
},
|
},
|
||||||
(cc, next) => { // override require
|
(cc, next) => { // override require
|
||||||
|
|
Loading…
Reference in New Issue