aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeonid Logvinov <logvinov.leon@gmail.com>2018-03-15 22:42:48 +0800
committerLeonid Logvinov <logvinov.leon@gmail.com>2018-03-15 23:19:01 +0800
commitf6c01520ae75d173937f0847ac45e636b06f4146 (patch)
tree6c16d0a8050bf470fd9a7e93c88b8f840b35b604
parent40ebb533b324bf7dd454243fcb1ee092ab85f7eb (diff)
downloaddexon-sol-tools-f6c01520ae75d173937f0847ac45e636b06f4146.tar
dexon-sol-tools-f6c01520ae75d173937f0847ac45e636b06f4146.tar.gz
dexon-sol-tools-f6c01520ae75d173937f0847ac45e636b06f4146.tar.bz2
dexon-sol-tools-f6c01520ae75d173937f0847ac45e636b06f4146.tar.lz
dexon-sol-tools-f6c01520ae75d173937f0847ac45e636b06f4146.tar.xz
dexon-sol-tools-f6c01520ae75d173937f0847ac45e636b06f4146.tar.zst
dexon-sol-tools-f6c01520ae75d173937f0847ac45e636b06f4146.zip
Add tests for sol-cov
-rw-r--r--.circleci/config.yml7
-rw-r--r--packages/sol-cov/coverage/.gitkeep0
-rw-r--r--packages/sol-cov/package.json18
-rw-r--r--packages/sol-cov/src/ast_visitor.ts4
-rw-r--r--packages/sol-cov/src/collect_coverage_entries.ts2
-rw-r--r--packages/sol-cov/src/coverage_manager.ts2
-rw-r--r--packages/sol-cov/src/globals.d.ts3
-rw-r--r--packages/sol-cov/src/source_maps.ts11
-rw-r--r--packages/sol-cov/test/collect_contracts_data_test.ts30
-rw-r--r--packages/sol-cov/test/collect_coverage_entries_test.ts64
-rw-r--r--packages/sol-cov/test/fixtures/artifacts/SimpleStorage.json64
-rw-r--r--packages/sol-cov/test/fixtures/artifacts/Simplest.json20
-rw-r--r--packages/sol-cov/test/fixtures/contracts/SimpleStorage.sol9
-rw-r--r--packages/sol-cov/test/fixtures/contracts/Simplest.sol2
-rw-r--r--packages/sol-cov/test/instructions_test.ts22
-rw-r--r--packages/sol-cov/test/source_maps_test.ts71
-rw-r--r--packages/sol-cov/test/utils_test.ts53
-rw-r--r--packages/sol-cov/tsconfig.json2
18 files changed, 370 insertions, 14 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 3b1f55656..31a58a963 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -111,6 +111,10 @@ jobs:
key: coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/subproviders/coverage/lcov.info
+ - save_cache:
+ key: coverage-sol-cov-{{ .Environment.CIRCLE_SHA1 }}
+ paths:
+ - ~/repo/packages/sol-cov/coverage/lcov.info
lint:
working_directory: ~/repo
docker:
@@ -157,6 +161,9 @@ jobs:
- coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
+ - coverage-sol-cov-{{ .Environment.CIRCLE_SHA1 }}
+ - restore_cache:
+ keys:
- coverage-deployer-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
diff --git a/packages/sol-cov/coverage/.gitkeep b/packages/sol-cov/coverage/.gitkeep
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/packages/sol-cov/coverage/.gitkeep
diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json
index 84e58f8d8..f3de566c1 100644
--- a/packages/sol-cov/package.json
+++ b/packages/sol-cov/package.json
@@ -2,13 +2,18 @@
"name": "@0xproject/sol-cov",
"version": "0.0.1",
"description": "Generate coverage reports for Solidity code",
- "main": "lib/index.js",
- "types": "lib/index.d.ts",
+ "main": "lib/src/index.js",
+ "types": "lib/src/index.d.ts",
"scripts": {
"build:watch": "tsc -w",
"lint": "tslint --project . 'src/**/*.ts'",
+ "test": "run-s clean build run_mocha",
+ "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
+ "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
+ "test:circleci": "yarn test:coverage",
+ "run_mocha": "mocha lib/test/**/*_test.js",
"clean": "shx rm -rf lib scripts",
- "build": "tsc && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts"
+ "build": "copyfiles 'test/fixtures/**/*' ./lib && tsc && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts"
},
"repository": {
"type": "git",
@@ -37,7 +42,14 @@
"@0xproject/tslint-config": "^0.4.9",
"@types/istanbul": "^0.4.29",
"@types/node": "^8.0.53",
+ "@types/mocha": "^2.2.42",
+ "sinon": "^4.0.0",
"copyfiles": "^1.2.0",
+ "nyc": "^11.0.1",
+ "chai": "^4.0.1",
+ "dirty-chai": "^2.0.1",
+ "chai-typescript-typings": "^0.0.4",
+ "mocha": "^4.0.1",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.8.0",
diff --git a/packages/sol-cov/src/ast_visitor.ts b/packages/sol-cov/src/ast_visitor.ts
index 66190afec..88309d3eb 100644
--- a/packages/sol-cov/src/ast_visitor.ts
+++ b/packages/sol-cov/src/ast_visitor.ts
@@ -113,8 +113,8 @@ export class ASTVisitor {
this._statementMap[this._entryId++] = this._getExpressionRange(ast);
}
private _getExpressionRange(ast: Parser.ASTNode): SingleFileSourceRange {
- const start = this._locationByOffset[ast.range[0] - 1];
- const end = this._locationByOffset[ast.range[1]];
+ const start = this._locationByOffset[ast.range[0]];
+ const end = this._locationByOffset[ast.range[1] + 1];
const range = {
start,
end,
diff --git a/packages/sol-cov/src/collect_coverage_entries.ts b/packages/sol-cov/src/collect_coverage_entries.ts
index 6da81fbfc..97218616c 100644
--- a/packages/sol-cov/src/collect_coverage_entries.ts
+++ b/packages/sol-cov/src/collect_coverage_entries.ts
@@ -10,7 +10,7 @@ import { getLocationByOffset } from './source_maps';
// Parsing source code for each transaction/code is slow and therefore we cache it
const coverageEntriesBySourceHash: { [sourceHash: string]: CoverageEntriesDescription } = {};
-export const collectCoverageEntries = (contractSource: string, fileName: string) => {
+export const collectCoverageEntries = (contractSource: string) => {
const sourceHash = ethUtil.sha3(contractSource).toString('hex');
if (_.isUndefined(coverageEntriesBySourceHash[sourceHash])) {
const ast = parser.parse(contractSource, { range: true });
diff --git a/packages/sol-cov/src/coverage_manager.ts b/packages/sol-cov/src/coverage_manager.ts
index b1ba8b22b..230ccc3c9 100644
--- a/packages/sol-cov/src/coverage_manager.ts
+++ b/packages/sol-cov/src/coverage_manager.ts
@@ -39,7 +39,7 @@ export class CoverageManager {
fileIndex: number,
): Coverage {
const fileName = contractData.sources[fileIndex];
- const coverageEntriesDescription = collectCoverageEntries(contractData.sourceCodes[fileIndex], fileName);
+ const coverageEntriesDescription = collectCoverageEntries(contractData.sourceCodes[fileIndex]);
let sourceRanges = _.map(coveredPcs, coveredPc => pcToSourceRange[coveredPc]);
sourceRanges = _.compact(sourceRanges); // Some PC's don't map to a source range and we just ignore them.
// By default lodash does a shallow object comparasion. We JSON.stringify them and compare as strings.
diff --git a/packages/sol-cov/src/globals.d.ts b/packages/sol-cov/src/globals.d.ts
index 3e457f0b5..0ee0f394c 100644
--- a/packages/sol-cov/src/globals.d.ts
+++ b/packages/sol-cov/src/globals.d.ts
@@ -1,5 +1,6 @@
-// tslint:disable:completed-docs
+declare module 'dirty-chai';
+// tslint:disable:completed-docs
declare module '*.json' {
const json: any;
/* tslint:disable */
diff --git a/packages/sol-cov/src/source_maps.ts b/packages/sol-cov/src/source_maps.ts
index 9b3ea9e24..694171442 100644
--- a/packages/sol-cov/src/source_maps.ts
+++ b/packages/sol-cov/src/source_maps.ts
@@ -12,12 +12,12 @@ export interface SourceLocation {
}
export function getLocationByOffset(str: string): LocationByOffset {
- const locationByOffset: LocationByOffset = {};
+ const locationByOffset: LocationByOffset = { 0: { line: 1, column: 0 } };
let currentOffset = 0;
for (const char of str.split('')) {
- const location = locationByOffset[currentOffset - 1] || { line: 1, column: 0 };
+ const location = locationByOffset[currentOffset];
const isNewline = char === '\n';
- locationByOffset[currentOffset] = {
+ locationByOffset[currentOffset + 1] = {
line: location.line + (isNewline ? 1 : 0),
column: isNewline ? 0 : location.column + 1,
};
@@ -59,9 +59,8 @@ export function parseSourceMap(
if (parsedEntry.fileIndex !== -1) {
const sourceRange = {
location: {
- start: locationByOffsetByFileIndex[parsedEntry.fileIndex][parsedEntry.offset - 1],
- end:
- locationByOffsetByFileIndex[parsedEntry.fileIndex][parsedEntry.offset + parsedEntry.length - 1],
+ start: locationByOffsetByFileIndex[parsedEntry.fileIndex][parsedEntry.offset],
+ end: locationByOffsetByFileIndex[parsedEntry.fileIndex][parsedEntry.offset + parsedEntry.length],
},
fileName: sources[parsedEntry.fileIndex],
};
diff --git a/packages/sol-cov/test/collect_contracts_data_test.ts b/packages/sol-cov/test/collect_contracts_data_test.ts
new file mode 100644
index 000000000..e793085e3
--- /dev/null
+++ b/packages/sol-cov/test/collect_contracts_data_test.ts
@@ -0,0 +1,30 @@
+import * as chai from 'chai';
+import * as _ from 'lodash';
+import 'mocha';
+import * as path from 'path';
+
+import { collectContractsData } from '../src/collect_contract_data';
+
+const expect = chai.expect;
+
+describe('Collect contracts data', () => {
+ describe('#collectContractsData', () => {
+ it('correctly collects contracts data', () => {
+ const artifactsPath = path.resolve(__dirname, 'fixtures/artifacts');
+ const sourcesPath = path.resolve(__dirname, 'fixtures/contracts');
+ const networkId = 50;
+ const contractsData = collectContractsData(artifactsPath, sourcesPath, networkId);
+ _.forEach(contractsData, contractData => {
+ expect(contractData).to.have.keys([
+ 'baseName',
+ 'sourceCodes',
+ 'sources',
+ 'sourceMap',
+ 'sourceMapRuntime',
+ 'bytecode',
+ 'runtimeBytecode',
+ ]);
+ });
+ });
+ });
+});
diff --git a/packages/sol-cov/test/collect_coverage_entries_test.ts b/packages/sol-cov/test/collect_coverage_entries_test.ts
new file mode 100644
index 000000000..84451686f
--- /dev/null
+++ b/packages/sol-cov/test/collect_coverage_entries_test.ts
@@ -0,0 +1,64 @@
+import * as chai from 'chai';
+import * as fs from 'fs';
+import * as _ from 'lodash';
+import 'mocha';
+import * as path from 'path';
+
+import { collectCoverageEntries } from '../src/collect_coverage_entries';
+import { SingleFileSourceRange } from '../src/types';
+
+const expect = chai.expect;
+
+const getRange = (sourceCode: string, range: SingleFileSourceRange) => {
+ const lines = sourceCode.split('\n').slice(range.start.line - 1, range.end.line);
+ lines[lines.length - 1] = lines[lines.length - 1].slice(0, range.end.column);
+ lines[0] = lines[0].slice(range.start.column);
+ return lines.join('\n');
+};
+
+describe('Collect coverage entries', () => {
+ describe('#collectCoverageEntries', () => {
+ it('correctly collects coverage entries for Simplest contract', () => {
+ const simplestContractBaseName = 'Simplest.sol';
+ const simplestContractFileName = path.resolve(__dirname, 'fixtures/contracts', simplestContractBaseName);
+ const simplestContract = fs.readFileSync(simplestContractFileName).toString();
+ const coverageEntries = collectCoverageEntries(simplestContract);
+ expect(coverageEntries.fnMap).to.be.deep.equal({});
+ expect(coverageEntries.branchMap).to.be.deep.equal({});
+ expect(coverageEntries.statementMap).to.be.deep.equal({});
+ expect(coverageEntries.modifiersStatementIds).to.be.deep.equal([]);
+ });
+ it('correctly collects coverage entries for SimpleStorage contract', () => {
+ const simpleStorageContractBaseName = 'SimpleStorage.sol';
+ const simpleStorageContractFileName = path.resolve(
+ __dirname,
+ 'fixtures/contracts',
+ simpleStorageContractBaseName,
+ );
+ const simpleStorageContract = fs.readFileSync(simpleStorageContractFileName).toString();
+ const coverageEntries = collectCoverageEntries(simpleStorageContract);
+ const fnIds = _.keys(coverageEntries.fnMap);
+ expect(coverageEntries.fnMap[fnIds[0]].name).to.be.equal('set');
+ expect(coverageEntries.fnMap[fnIds[0]].line).to.be.equal(3);
+ const setFunction = `function set(uint x) {
+ storedData = x;
+ }`;
+ expect(getRange(simpleStorageContract, coverageEntries.fnMap[fnIds[0]].loc)).to.be.equal(setFunction);
+ expect(coverageEntries.fnMap[fnIds[1]].name).to.be.equal('get');
+ expect(coverageEntries.fnMap[fnIds[1]].line).to.be.equal(6);
+ const getFunction = `function get() constant returns (uint retVal) {
+ return storedData;
+ }`;
+ expect(getRange(simpleStorageContract, coverageEntries.fnMap[fnIds[1]].loc)).to.be.equal(getFunction);
+ expect(coverageEntries.branchMap).to.be.deep.equal({});
+ const statementIds = _.keys(coverageEntries.statementMap);
+ expect(getRange(simpleStorageContract, coverageEntries.statementMap[statementIds[1]])).to.be.equal(
+ 'storedData = x',
+ );
+ expect(getRange(simpleStorageContract, coverageEntries.statementMap[statementIds[3]])).to.be.equal(
+ 'return storedData;',
+ );
+ expect(coverageEntries.modifiersStatementIds).to.be.deep.equal([]);
+ });
+ });
+});
diff --git a/packages/sol-cov/test/fixtures/artifacts/SimpleStorage.json b/packages/sol-cov/test/fixtures/artifacts/SimpleStorage.json
new file mode 100644
index 000000000..416170ef2
--- /dev/null
+++ b/packages/sol-cov/test/fixtures/artifacts/SimpleStorage.json
@@ -0,0 +1,64 @@
+{
+ "contract_name": "SimpleStorage",
+ "networks": {
+ "50": {
+ "solc_version": "0.4.21",
+ "keccak256": "0x18dc5b5a0e813c17e49936d2f2f7c07c51f050c09ba5e7206f17c855f23f4b6a",
+ "source_tree_hash": "0x18dc5b5a0e813c17e49936d2f2f7c07c51f050c09ba5e7206f17c855f23f4b6a",
+ "optimizer_enabled": 0,
+ "abi": [
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "storedData",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "x",
+ "type": "uint256"
+ }
+ ],
+ "name": "set",
+ "outputs": [],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "get",
+ "outputs": [
+ {
+ "name": "retVal",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ }
+ ],
+ "bytecode":
+ "0x6060604052341561000f57600080fd5b6101098061001e6000396000f3006060604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605857806360fe47b114607e5780636d4ce63c14609e575b600080fd5b3415606257600080fd5b606860c4565b6040518082815260200191505060405180910390f35b3415608857600080fd5b609c600480803590602001909190505060ca565b005b341560a857600080fd5b60ae60d4565b6040518082815260200191505060405180910390f35b60005481565b8060008190555050565b600080549050905600a165627a7a723058207f743855fd0c71699620424a21a257cd197ed05032d6768eb9b874e4898f44c60029",
+ "runtime_bytecode":
+ "0x6060604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605857806360fe47b114607e5780636d4ce63c14609e575b600080fd5b3415606257600080fd5b606860c4565b6040518082815260200191505060405180910390f35b3415608857600080fd5b609c600480803590602001909190505060ca565b005b341560a857600080fd5b60ae60d4565b6040518082815260200191505060405180910390f35b60005481565b8060008190555050565b600080549050905600a165627a7a723058207f743855fd0c71699620424a21a257cd197ed05032d6768eb9b874e4898f44c60029",
+ "updated_at": 1521118350895,
+ "source_map": "26:196:0:-;;;;;;;;;;;;;;;;;",
+ "source_map_runtime":
+ "26:196:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83:52;;;;;;;;;;;;;;;;;;;;;;;;;;140:80;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55:22;;;;:::o;83:52::-;127:1;114:10;:14;;;;83:52;:::o;140:80::-;173:11;203:10;;196:17;;140:80;:::o",
+ "sources": ["SimpleStorage.sol"]
+ }
+ }
+}
diff --git a/packages/sol-cov/test/fixtures/artifacts/Simplest.json b/packages/sol-cov/test/fixtures/artifacts/Simplest.json
new file mode 100644
index 000000000..8de60e481
--- /dev/null
+++ b/packages/sol-cov/test/fixtures/artifacts/Simplest.json
@@ -0,0 +1,20 @@
+{
+ "contract_name": "Simplest",
+ "networks": {
+ "50": {
+ "solc_version": "0.4.21",
+ "keccak256": "0x8e7d62e19c7c7b8bf9a4a43749e111605950cc877574fb9640a1a07d1c3749f9",
+ "source_tree_hash": "0x8e7d62e19c7c7b8bf9a4a43749e111605950cc877574fb9640a1a07d1c3749f9",
+ "optimizer_enabled": 0,
+ "abi": [],
+ "bytecode":
+ "0x60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a7230582097cfe05b4d18d6ffb3a8d8fab0570cf09640d3131b9677ddb9be4e9fbcb65f010029",
+ "runtime_bytecode":
+ "0x6060604052600080fd00a165627a7a7230582097cfe05b4d18d6ffb3a8d8fab0570cf09640d3131b9677ddb9be4e9fbcb65f010029",
+ "updated_at": 1521118525393,
+ "source_map": "26:21:0:-;;;;;;;;;;;;;;;;;",
+ "source_map_runtime": "26:21:0:-;;;;;",
+ "sources": ["Simplest.sol"]
+ }
+ }
+}
diff --git a/packages/sol-cov/test/fixtures/contracts/SimpleStorage.sol b/packages/sol-cov/test/fixtures/contracts/SimpleStorage.sol
new file mode 100644
index 000000000..178a52318
--- /dev/null
+++ b/packages/sol-cov/test/fixtures/contracts/SimpleStorage.sol
@@ -0,0 +1,9 @@
+contract SimpleStorage {
+ uint public storedData;
+ function set(uint x) {
+ storedData = x;
+ }
+ function get() constant returns (uint retVal) {
+ return storedData;
+ }
+}
diff --git a/packages/sol-cov/test/fixtures/contracts/Simplest.sol b/packages/sol-cov/test/fixtures/contracts/Simplest.sol
new file mode 100644
index 000000000..d71016e07
--- /dev/null
+++ b/packages/sol-cov/test/fixtures/contracts/Simplest.sol
@@ -0,0 +1,2 @@
+contract Simplest {
+}
diff --git a/packages/sol-cov/test/instructions_test.ts b/packages/sol-cov/test/instructions_test.ts
new file mode 100644
index 000000000..f64ec11ed
--- /dev/null
+++ b/packages/sol-cov/test/instructions_test.ts
@@ -0,0 +1,22 @@
+import * as chai from 'chai';
+import * as fs from 'fs';
+import 'mocha';
+import * as path from 'path';
+
+import { getPcToInstructionIndexMapping } from '../src/instructions';
+
+const expect = chai.expect;
+
+describe('instructions', () => {
+ describe('#getPcToInstructionIndexMapping', () => {
+ it('correctly maps pcs to instruction indexed', () => {
+ const PUSH1 = 0x60;
+ const PUSH2 = 0x61;
+ const TIMESTAMP = 0x42;
+ const bytecode = new Uint8Array([PUSH1, 42, PUSH2, 1, 2, TIMESTAMP]);
+ const pcToInstruction = getPcToInstructionIndexMapping(bytecode);
+ const expectedPcToInstruction = { '0': 0, '2': 1, '5': 2 };
+ expect(pcToInstruction).to.be.deep.equal(expectedPcToInstruction);
+ });
+ });
+});
diff --git a/packages/sol-cov/test/source_maps_test.ts b/packages/sol-cov/test/source_maps_test.ts
new file mode 100644
index 000000000..5820bedd7
--- /dev/null
+++ b/packages/sol-cov/test/source_maps_test.ts
@@ -0,0 +1,71 @@
+import * as chai from 'chai';
+import * as fs from 'fs';
+import * as _ from 'lodash';
+import 'mocha';
+import * as path from 'path';
+
+import { getLocationByOffset, parseSourceMap } from '../src/source_maps';
+
+const expect = chai.expect;
+
+const simplestContractBaseName = 'Simplest.sol';
+const simplestContractFileName = path.resolve(__dirname, 'fixtures/contracts', simplestContractBaseName);
+const simplestContract = fs.readFileSync(simplestContractFileName).toString();
+
+describe('source maps', () => {
+ describe('#getLocationByOffset', () => {
+ it('correctly computes location by offset', () => {
+ const locationByOffset = getLocationByOffset(simplestContract);
+ const expectedLocationByOffset = {
+ '0': { line: 1, column: 0 },
+ '1': { line: 1, column: 1 },
+ '2': { line: 1, column: 2 },
+ '3': { line: 1, column: 3 },
+ '4': { line: 1, column: 4 },
+ '5': { line: 1, column: 5 },
+ '6': { line: 1, column: 6 },
+ '7': { line: 1, column: 7 },
+ '8': { line: 1, column: 8 },
+ '9': { line: 1, column: 9 },
+ '10': { line: 1, column: 10 },
+ '11': { line: 1, column: 11 },
+ '12': { line: 1, column: 12 },
+ '13': { line: 1, column: 13 },
+ '14': { line: 1, column: 14 },
+ '15': { line: 1, column: 15 },
+ '16': { line: 1, column: 16 },
+ '17': { line: 1, column: 17 },
+ '18': { line: 1, column: 18 },
+ '19': { line: 1, column: 19 },
+ '20': { line: 2, column: 0 },
+ '21': { line: 2, column: 1 },
+ '22': { line: 3, column: 0 },
+ };
+ expect(locationByOffset).to.be.deep.equal(expectedLocationByOffset);
+ });
+ });
+ describe('#parseSourceMap', () => {
+ it('correctly parses the source map', () => {
+ // This is the source map and bytecode for an empty contract like Example.sol
+ const srcMap = '0:21:0:-;;;;;;;;;;;;;;;;;';
+ const bytecodeHex =
+ '60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a72305820377cdef690e46589f40efeef14d8ef73504af059fb3fd46f1da3cd2fc52ef7890029';
+ const sources = [simplestContractBaseName];
+ const pcToSourceRange = parseSourceMap([simplestContract], srcMap, bytecodeHex, sources);
+ const expectedSourceRange = {
+ location: {
+ start: { line: 1, column: 0 },
+ end: { line: 2, column: 1 },
+ },
+ fileName: simplestContractBaseName,
+ };
+ _.forEach(pcToSourceRange, sourceRange => {
+ // Solidity source maps are too short and we map some instructions to undefined
+ // Source: https://github.com/ethereum/solidity/issues/3741
+ if (!_.isUndefined(sourceRange)) {
+ expect(sourceRange).to.be.deep.equal(expectedSourceRange);
+ }
+ });
+ });
+ });
+});
diff --git a/packages/sol-cov/test/utils_test.ts b/packages/sol-cov/test/utils_test.ts
new file mode 100644
index 000000000..6fc8fcfe1
--- /dev/null
+++ b/packages/sol-cov/test/utils_test.ts
@@ -0,0 +1,53 @@
+import * as chai from 'chai';
+import * as dirtyChai from 'dirty-chai';
+import 'mocha';
+
+import { utils } from '../src/utils';
+
+chai.use(dirtyChai);
+const expect = chai.expect;
+
+describe('utils', () => {
+ describe('#compareLineColumn', () => {
+ it('correctly compares LineColumns', () => {
+ expect(utils.compareLineColumn({ line: 1, column: 3 }, { line: 1, column: 4 })).to.be.lessThan(0);
+ expect(utils.compareLineColumn({ line: 1, column: 4 }, { line: 1, column: 3 })).to.be.greaterThan(0);
+ expect(utils.compareLineColumn({ line: 1, column: 3 }, { line: 1, column: 3 })).to.be.equal(0);
+ expect(utils.compareLineColumn({ line: 0, column: 2 }, { line: 1, column: 0 })).to.be.lessThan(0);
+ expect(utils.compareLineColumn({ line: 1, column: 0 }, { line: 0, column: 2 })).to.be.greaterThan(0);
+ });
+ });
+
+ describe('#isRangeInside', () => {
+ it('returns true if inside', () => {
+ expect(
+ utils.isRangeInside(
+ { start: { line: 1, column: 3 }, end: { line: 1, column: 4 } },
+ { start: { line: 1, column: 2 }, end: { line: 1, column: 5 } },
+ ),
+ ).to.be.true();
+ });
+ it('returns true if the same', () => {
+ expect(
+ utils.isRangeInside(
+ { start: { line: 1, column: 3 }, end: { line: 1, column: 4 } },
+ { start: { line: 1, column: 3 }, end: { line: 1, column: 4 } },
+ ),
+ ).to.be.true();
+ });
+ it('returns false if not inside', () => {
+ expect(
+ utils.isRangeInside(
+ { start: { line: 1, column: 3 }, end: { line: 1, column: 4 } },
+ { start: { line: 1, column: 4 }, end: { line: 1, column: 4 } },
+ ),
+ ).to.be.false();
+ expect(
+ utils.isRangeInside(
+ { start: { line: 1, column: 3 }, end: { line: 1, column: 4 } },
+ { start: { line: 1, column: 4 }, end: { line: 1, column: 5 } },
+ ),
+ ).to.be.false();
+ });
+ });
+});
diff --git a/packages/sol-cov/tsconfig.json b/packages/sol-cov/tsconfig.json
index bdf315d59..44e43719b 100644
--- a/packages/sol-cov/tsconfig.json
+++ b/packages/sol-cov/tsconfig.json
@@ -5,8 +5,10 @@
},
"include": [
"./src/**/*",
+ "./test/**/*",
"../../node_modules/types-bn/index.d.ts",
"../../node_modules/web3-typescript-typings/index.d.ts",
+ "../../node_modules/chai-typescript-typings/index.d.ts",
"../../node_modules/types-ethereumjs-util/index.d.ts"
]
}