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.fs = embark.fs;
|
||||
this.ipc = options.ipc;
|
||||
this.runResults = [];
|
||||
this.runners = {};
|
||||
this.gasLimit = options.coverage ? COVERAGE_GAS_LIMIT : GAS_LIMIT;
|
||||
|
||||
this.events.setCommandHandler('tests: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) {
|
||||
|
@ -45,6 +49,7 @@ class TestRunner {
|
|||
self.getFilesFromDir(testPath, next);
|
||||
},
|
||||
(files, next) => { // group files by types
|
||||
// TODO: figure out what files belong where
|
||||
const types = { jsFiles: ".js", solidityFiles: "_test.sol" };
|
||||
const groups = Object.entries(types).reduce((acc, [type, ext]) => {
|
||||
acc[type] = files.filter(f => f.endsWith(ext));
|
||||
|
@ -168,7 +173,8 @@ class TestRunner {
|
|||
next();
|
||||
}
|
||||
], (_err) => {
|
||||
acctCb(accounts);
|
||||
console.log('=====================> finished config');
|
||||
acctCb(null, accounts);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -200,6 +206,7 @@ class TestRunner {
|
|||
},
|
||||
(cf, next) => { // compile contracts
|
||||
console.log('compiling contracts');
|
||||
console.dir(cf);
|
||||
events.request("compiler:contracts:compile", cf, next);
|
||||
},
|
||||
(cc, next) => { // override require
|
||||
|
|
Loading…
Reference in New Issue