commit
0bf470ac0a
@ -1,133 +0,0 @@ |
||||
[![Gitter chat](https://badges.gitter.im/sc-forks/solidity-coverage.svg)][18] |
||||
![npm (tag)](https://img.shields.io/npm/v/solidity-coverage/latest) |
||||
[![CircleCI](https://circleci.com/gh/sc-forks/solidity-coverage.svg?style=svg)][20] |
||||
[![codecov](https://codecov.io/gh/sc-forks/solidity-coverage/branch/beta/graph/badge.svg)][21] |
||||
[![buidler](https://buidler.dev/buidler-plugin-badge.svg?1)][26] |
||||
|
||||
# solidity-coverage |
||||
|
||||
Solidity code coverage plugin for [buidler](http://getbuidler.com). |
||||
|
||||
## What |
||||
|
||||
![coverage example][22] |
||||
|
||||
+ For more details about how it works and potential limitations, see [the accompanying article][16]. |
||||
+ `solidity-coverage` is also [JoinColony/solcover][17] |
||||
|
||||
|
||||
## Installation |
||||
|
||||
```bash |
||||
$ npm install --save-dev solidity-coverage |
||||
``` |
||||
|
||||
And add the following to your `buidler.config.js`: |
||||
|
||||
```js |
||||
usePlugin("solidity-coverage"); |
||||
|
||||
module.exports = { |
||||
networks: { |
||||
coverage: { |
||||
url: 'http://localhost:8555' |
||||
} |
||||
}, |
||||
} |
||||
``` |
||||
|
||||
## Tasks |
||||
|
||||
This plugin implements a `coverage` task |
||||
|
||||
```bash |
||||
npx buidler coverage --network coverage [options] |
||||
``` |
||||
|
||||
| Option <img width=200/> | Example <img width=750/>| Description <img width=1000/> | |
||||
|--------------|------------------------------------|--------------------------------| |
||||
| testfiles | `--testfiles "test/registry/*.ts"` | Test file(s) to run. (Globs must be enclosed by quotes.)| |
||||
| solcoverjs | `--solcoverjs ./../.solcover.js` | Relative path from working directory to config. Useful for monorepo packages that share settings. (Path must be "./" prefixed) | |
||||
| network | `--network development` | Use network settings defined in the Buidler config | |
||||
|
||||
|
||||
## Configuration |
||||
|
||||
Options can be specified in a `.solcover.js` config file located in the root directory of your project. |
||||
|
||||
**Project Examples:** |
||||
|
||||
+ Simple: [buidler-metacoin][29] |
||||
+ More complex: [MolochDao/moloch][30] |
||||
|
||||
**Config Example:** |
||||
```javascript |
||||
module.exports = { |
||||
skipFiles: ['Routers/EtherRouter.sol'] |
||||
}; |
||||
``` |
||||
|
||||
| Option <img width=200/>| Type <img width=200/> | Default <img width=1300/> | Description <img width=800/> | |
||||
| ------ | ---- | ------- | ----------- | |
||||
| silent | *Boolean* | false | Suppress logging output | |
||||
| client | *Object* | `require("ganache-core")` | Useful if you need a specific ganache version. | |
||||
| providerOptions | *Object* | `{ }` | [ganache-core options][1] | |
||||
| skipFiles | *Array* | `['Migrations.sol']` | Array of contracts or folders (with paths expressed relative to the `contracts` directory) that should be skipped when doing instrumentation. | |
||||
| istanbulFolder | *String* | `./coverage` | Folder location for Istanbul coverage reports. | |
||||
| istanbulReporter | *Array* | `['html', 'lcov', 'text', 'json']` | [Istanbul coverage reporters][2] | |
||||
| mocha | *Object* | `{ }` | [Mocha options][3] to merge into existing mocha config. `grep` and `invert` are useful for skipping certain tests under coverage using tags in the test descriptions.| |
||||
| onServerReady[<sup>*</sup>][14] | *Function* | | Hook run *after* server is launched, *before* the tests execute. Useful if you need to use the Oraclize bridge or have setup scripts which rely on the server's availability. [More...][23] | |
||||
| onCompileComplete[<sup>*</sup>][14] | *Function* | | Hook run *after* compilation completes, *before* tests are run. Useful if you have secondary compilation steps or need to modify built artifacts. [More...][23]| |
||||
| onTestsComplete[<sup>*</sup>][14] | *Function* | | Hook run *after* the tests complete, *before* Istanbul reports are generated. [More...][23]| |
||||
| onIstanbulComplete[<sup>*</sup>][14] | *Function* | | Hook run *after* the Istanbul reports are generated, *before* the ganache server is shut down. Useful if you need to clean resources up. [More...][23]| |
||||
|
||||
[<sup>*</sup> Advanced use][14] |
||||
|
||||
## Usage |
||||
|
||||
+ Coverage runs tests a little more slowly. |
||||
+ Coverage launches its own in-process ganache server. |
||||
+ You can set [ganache options][1] using the `providerOptions` key in your `.solcover.js` [config][15]. |
||||
+ Coverage [distorts gas consumption][13]. Tests that check exact gas consumption should be [skipped][24]. |
||||
+ :warning: Contracts are compiled **without optimization**. Please report unexpected compilation faults to [issue 417][25] |
||||
|
||||
## Documentation |
||||
|
||||
More documentation, including FAQ and information about solidity-coverage's API [is available here][28]. |
||||
|
||||
|
||||
[1]: https://github.com/trufflesuite/ganache-core#options |
||||
[2]: https://istanbul.js.org/docs/advanced/alternative-reporters/ |
||||
[3]: https://mochajs.org/api/mocha |
||||
[4]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/faq.md#running-out-of-gas |
||||
[5]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/faq.md#running-out-of-memory |
||||
[6]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/faq.md#running-out-of-time |
||||
[7]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/faq.md#continuous-integration |
||||
[8]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/faq.md#notes-on-branch-coverage |
||||
[9]: https://sc-forks.github.io/metacoin/ |
||||
[10]: https://coveralls.io/github/OpenZeppelin/openzeppelin-solidity?branch=master |
||||
[11]: https://github.com/sc-forks/solidity-coverage/tree/master/test/units |
||||
[12]: https://github.com/sc-forks/solidity-coverage/issues |
||||
[13]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/faq.md#notes-on-gas-distortion |
||||
[14]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/advanced.md |
||||
[15]: #config-options |
||||
[16]: https://blog.colony.io/code-coverage-for-solidity-eecfa88668c2 |
||||
[17]: https://github.com/JoinColony/solcover |
||||
[18]: https://gitter.im/sc-forks/solidity-coverage?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge |
||||
[19]: https://badge.fury.io/js/solidity-coverage |
||||
[20]: https://circleci.com/gh/sc-forks/solidity-coverage |
||||
[21]: https://codecov.io/gh/sc-forks/solidity-coverage |
||||
[22]: https://cdn-images-1.medium.com/max/800/1*uum8t-31bUaa6dTRVVhj6w.png |
||||
[23]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/advanced.md#workflow-hooks |
||||
[24]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/advanced.md#skipping-tests |
||||
[25]: https://github.com/sc-forks/solidity-coverage/issues/417 |
||||
[26]: https://buidler.dev/ |
||||
[27]: https://www.trufflesuite.com/docs |
||||
[28]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/api.md |
||||
[29]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/upgrade.md#upgrading-from-06x-to-070 |
||||
[30]: https://github.com/sc-forks/solidity-coverage/tree/0.6.x-final#solidity-coverage |
||||
[31]: https://github.com/sc-forks/solidity-coverage/releases/tag/v0.7.0 |
||||
[32]: https://github.com/sc-forks/buidler-e2e/tree/coverage |
||||
[33]: https://github.com/sc-forks/moloch |
||||
[34]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/advanced.md#reducing-the-instrumentation-footprint |
||||
|
@ -0,0 +1,421 @@ |
||||
### Test Matrix Example |
||||
|
||||
An example of output written to the file `./testMatrix.json` when coverage |
||||
is run with the `--matrix` cli flag. (Source project: [sc-forks/hardhat-e2e][1]) |
||||
|
||||
[1]: https://github.com/sc-forks/hardhat-e2e |
||||
|
||||
|
||||
```js |
||||
// Paths are relative to the project root directory |
||||
{ |
||||
// Solidity file name |
||||
"contracts/EtherRouter/EtherRouter.sol": { |
||||
|
||||
// Line number |
||||
"23": [ |
||||
{ |
||||
// Grep-able mocha test title |
||||
"title": "Resolves methods routed through an EtherRouter proxy", |
||||
|
||||
// Selectable mocha test file |
||||
"file": "test/etherrouter.js" |
||||
} |
||||
], |
||||
"42": [ |
||||
{ |
||||
"title": "Resolves methods routed through an EtherRouter proxy", |
||||
"file": "test/etherrouter.js" |
||||
} |
||||
], |
||||
"45": [ |
||||
{ |
||||
"title": "Resolves methods routed through an EtherRouter proxy", |
||||
"file": "test/etherrouter.js" |
||||
} |
||||
], |
||||
"61": [ |
||||
{ |
||||
"title": "Resolves methods routed through an EtherRouter proxy", |
||||
"file": "test/etherrouter.js" |
||||
} |
||||
] |
||||
}, |
||||
"contracts/EtherRouter/Factory.sol": { |
||||
"19": [ |
||||
{ |
||||
"title": "Resolves methods routed through an EtherRouter proxy", |
||||
"file": "test/etherrouter.js" |
||||
} |
||||
] |
||||
}, |
||||
"contracts/EtherRouter/Resolver.sol": { |
||||
"22": [ |
||||
{ |
||||
"title": "Resolves methods routed through an EtherRouter proxy", |
||||
"file": "test/etherrouter.js" |
||||
} |
||||
], |
||||
"26": [ |
||||
{ |
||||
"title": "Resolves methods routed through an EtherRouter proxy", |
||||
"file": "test/etherrouter.js" |
||||
} |
||||
], |
||||
"30": [ |
||||
{ |
||||
"title": "Resolves methods routed through an EtherRouter proxy", |
||||
"file": "test/etherrouter.js" |
||||
} |
||||
] |
||||
}, |
||||
"contracts/MetaCoin.sol": { |
||||
"16": [ |
||||
{ |
||||
"title": "should put 10000 MetaCoin in the first account", |
||||
"file": "test/metacoin.js" |
||||
}, |
||||
{ |
||||
"title": "should call a function that depends on a linked library", |
||||
"file": "test/metacoin.js" |
||||
}, |
||||
{ |
||||
"title": "should send coin correctly", |
||||
"file": "test/metacoin.js" |
||||
}, |
||||
{ |
||||
"title": "a and b", |
||||
"file": "test/multicontract.js" |
||||
} |
||||
], |
||||
"20": [ |
||||
{ |
||||
"title": "should send coin correctly", |
||||
"file": "test/metacoin.js" |
||||
} |
||||
], |
||||
"21": [ |
||||
{ |
||||
"title": "should send coin correctly", |
||||
"file": "test/metacoin.js" |
||||
} |
||||
], |
||||
"22": [ |
||||
{ |
||||
"title": "should send coin correctly", |
||||
"file": "test/metacoin.js" |
||||
} |
||||
], |
||||
"23": [ |
||||
{ |
||||
"title": "should send coin correctly", |
||||
"file": "test/metacoin.js" |
||||
} |
||||
], |
||||
"24": [ |
||||
{ |
||||
"title": "should send coin correctly", |
||||
"file": "test/metacoin.js" |
||||
} |
||||
], |
||||
"28": [ |
||||
{ |
||||
"title": "should call a function that depends on a linked library", |
||||
"file": "test/metacoin.js" |
||||
} |
||||
], |
||||
"32": [ |
||||
{ |
||||
"title": "should put 10000 MetaCoin in the first account", |
||||
"file": "test/metacoin.js" |
||||
}, |
||||
{ |
||||
"title": "should call a function that depends on a linked library", |
||||
"file": "test/metacoin.js" |
||||
}, |
||||
{ |
||||
"title": "should send coin correctly", |
||||
"file": "test/metacoin.js" |
||||
} |
||||
] |
||||
}, |
||||
"contracts/ConvertLib.sol": { |
||||
"6": [ |
||||
{ |
||||
"title": "should call a function that depends on a linked library", |
||||
"file": "test/metacoin.js" |
||||
} |
||||
] |
||||
}, |
||||
"contracts/MultiContractFile.sol": { |
||||
"7": [ |
||||
{ |
||||
"title": "a and b", |
||||
"file": "test/multicontract.js" |
||||
}, |
||||
{ |
||||
"title": "methods that call methods in other contracts", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"15": [ |
||||
{ |
||||
"title": "a and b", |
||||
"file": "test/multicontract.js" |
||||
} |
||||
] |
||||
}, |
||||
"contracts/VariableConstructor.sol": { |
||||
"8": [ |
||||
{ |
||||
"title": "should should initialize with a short string", |
||||
"file": "test/variableconstructor.js" |
||||
}, |
||||
{ |
||||
"title": "should should initialize with a medium length string", |
||||
"file": "test/variableconstructor.js" |
||||
}, |
||||
{ |
||||
"title": "should should initialize with a long string", |
||||
"file": "test/variableconstructor.js" |
||||
}, |
||||
{ |
||||
"title": "should should initialize with a random length string", |
||||
"file": "test/variableconstructor.js" |
||||
} |
||||
] |
||||
}, |
||||
"contracts/VariableCosts.sol": { |
||||
"13": [ |
||||
{ |
||||
"title": "should should initialize with a short string", |
||||
"file": "test/variableconstructor.js" |
||||
}, |
||||
{ |
||||
"title": "should should initialize with a medium length string", |
||||
"file": "test/variableconstructor.js" |
||||
}, |
||||
{ |
||||
"title": "should should initialize with a long string", |
||||
"file": "test/variableconstructor.js" |
||||
}, |
||||
{ |
||||
"title": "should should initialize with a random length string", |
||||
"file": "test/variableconstructor.js" |
||||
}, |
||||
{ |
||||
"title": "should add one", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add three", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add even 5!", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should delete one", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should delete three", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should delete five", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add five and delete one", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should set a random length string", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "methods that do not throw", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "methods that throw", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "methods that call methods in other contracts", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should allow contracts to have identically named methods", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"29": [ |
||||
{ |
||||
"title": "should add one", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add three", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add even 5!", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add five and delete one", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"30": [ |
||||
{ |
||||
"title": "should add one", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add three", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add even 5!", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add five and delete one", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"34": [ |
||||
{ |
||||
"title": "should delete one", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should delete three", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should delete five", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add five and delete one", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"35": [ |
||||
{ |
||||
"title": "should delete one", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should delete three", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should delete five", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should add five and delete one", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"43": [ |
||||
{ |
||||
"title": "should set a random length string", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"47": [ |
||||
{ |
||||
"title": "methods that do not throw", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "methods that throw", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"48": [ |
||||
{ |
||||
"title": "methods that do not throw", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"52": [ |
||||
{ |
||||
"title": "methods that call methods in other contracts", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"53": [ |
||||
{ |
||||
"title": "methods that call methods in other contracts", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
], |
||||
"54": [ |
||||
{ |
||||
"title": "methods that call methods in other contracts", |
||||
"file": "test/variablecosts.js" |
||||
} |
||||
] |
||||
}, |
||||
"contracts/Wallets/Wallet.sol": { |
||||
"8": [ |
||||
{ |
||||
"title": "should allow contracts to have identically named methods", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should should allow transfers and sends", |
||||
"file": "test/wallet.js" |
||||
} |
||||
], |
||||
"12": [ |
||||
{ |
||||
"title": "should allow contracts to have identically named methods", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should should allow transfers and sends", |
||||
"file": "test/wallet.js" |
||||
} |
||||
], |
||||
"17": [ |
||||
{ |
||||
"title": "should allow contracts to have identically named methods", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should should allow transfers and sends", |
||||
"file": "test/wallet.js" |
||||
} |
||||
], |
||||
"22": [ |
||||
{ |
||||
"title": "should allow contracts to have identically named methods", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should should allow transfers and sends", |
||||
"file": "test/wallet.js" |
||||
} |
||||
], |
||||
"23": [ |
||||
{ |
||||
"title": "should allow contracts to have identically named methods", |
||||
"file": "test/variablecosts.js" |
||||
}, |
||||
{ |
||||
"title": "should should allow transfers and sends", |
||||
"file": "test/wallet.js" |
||||
} |
||||
] |
||||
} |
||||
} |
||||
``` |
@ -0,0 +1,99 @@ |
||||
const ethersABI = require("@ethersproject/abi"); |
||||
const difflib = require('difflib'); |
||||
|
||||
class AbiUtils { |
||||
|
||||
diff(orig={}, cur={}){ |
||||
let plus = 0; |
||||
let minus = 0; |
||||
|
||||
const unifiedDiff = difflib.unifiedDiff( |
||||
orig.humanReadableAbiList, |
||||
cur.humanReadableAbiList, |
||||
{ |
||||
fromfile: orig.contractName, |
||||
tofile: cur.contractName, |
||||
fromfiledate: `sha: ${orig.sha}`, |
||||
tofiledate: `sha: ${cur.sha}`, |
||||
lineterm: '' |
||||
} |
||||
); |
||||
|
||||
// Count changes (unified diff always has a plus & minus in header);
|
||||
if (unifiedDiff.length){ |
||||
plus = -1; |
||||
minus = -1; |
||||
} |
||||
|
||||
unifiedDiff.forEach(line => { |
||||
if (line[0] === `+`) plus++; |
||||
if (line[0] === `-`) minus++; |
||||
}) |
||||
|
||||
return { |
||||
plus, |
||||
minus, |
||||
unifiedDiff |
||||
} |
||||
} |
||||
|
||||
toHumanReadableFunctions(contract){ |
||||
const human = []; |
||||
const ethersOutput = new ethersABI.Interface(contract.abi).functions; |
||||
const signatures = Object.keys(ethersOutput); |
||||
|
||||
for (const sig of signatures){ |
||||
const method = ethersOutput[sig]; |
||||
let returns = ''; |
||||
|
||||
method.outputs.forEach(output => { |
||||
(returns.length) |
||||
? returns += `, ${output.type}` |
||||
: returns += output.type; |
||||
}); |
||||
|
||||
let readable = `${method.type} ${sig} ${method.stateMutability}`; |
||||
|
||||
if (returns.length){ |
||||
readable += ` returns (${returns})` |
||||
} |
||||
|
||||
human.push(readable); |
||||
} |
||||
|
||||
return human; |
||||
} |
||||
|
||||
toHumanReadableEvents(contract){ |
||||
const human = []; |
||||
const ethersOutput = new ethersABI.Interface(contract.abi).events; |
||||
const signatures = Object.keys(ethersOutput); |
||||
|
||||
for (const sig of signatures){ |
||||
const method = ethersOutput[sig]; |
||||
const readable = `${ethersOutput[sig].type} ${sig}`; |
||||
human.push(readable); |
||||
} |
||||
|
||||
return human; |
||||
} |
||||
|
||||
generateHumanReadableAbiList(_artifacts, sha){ |
||||
const list = []; |
||||
if (_artifacts.length){ |
||||
for (const item of _artifacts){ |
||||
const fns = this.toHumanReadableFunctions(item); |
||||
const evts = this.toHumanReadableEvents(item); |
||||
const all = fns.concat(evts); |
||||
list.push({ |
||||
contractName: item.contractName, |
||||
sha: sha, |
||||
humanReadableAbiList: all |
||||
}) |
||||
} |
||||
} |
||||
return list; |
||||
} |
||||
} |
||||
|
||||
module.exports = AbiUtils; |
@ -1,185 +0,0 @@ |
||||
/* eslint-env node, mocha */ |
||||
|
||||
/*const path = require('path'); |
||||
const getInstrumentedVersion = require('./../lib/instrumentSolidity.js'); |
||||
const util = require('./util/util.js'); |
||||
const CoverageMap = require('./../lib/coverageMap'); |
||||
const vm = require('./util/vm'); |
||||
const assert = require('assert'); |
||||
|
||||
describe.skip('conditional statements', () => { |
||||
const filePath = path.resolve('./test.sol'); |
||||
const pathPrefix = './'; |
||||
|
||||
it('should cover a conditional that reaches the consequent (same-line)', done => { |
||||
const contract = util.getCode('conditional/sameline-consequent.sol'); |
||||
const info = getInstrumentedVersion(contract, filePath); |
||||
const coverage = new CoverageMap(); |
||||
coverage.addContract(info, filePath); |
||||
|
||||
vm.execute(info.contract, 'a', []).then(events => { |
||||
const mapping = coverage.generate(events, pathPrefix); |
||||
assert.deepEqual(mapping[filePath].l, { |
||||
5: 1, 6: 1, 7: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].b, { |
||||
1: [1, 0], |
||||
}); |
||||
assert.deepEqual(mapping[filePath].s, { |
||||
1: 1, 2: 1, 3: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].f, { |
||||
1: 1, |
||||
}); |
||||
done(); |
||||
}).catch(done); |
||||
}); |
||||
|
||||
it('should cover a conditional that reaches the alternate (same-line)', done => { |
||||
const contract = util.getCode('conditional/sameline-alternate.sol'); |
||||
const info = getInstrumentedVersion(contract, filePath); |
||||
const coverage = new CoverageMap(); |
||||
coverage.addContract(info, filePath); |
||||
|
||||
vm.execute(info.contract, 'a', []).then(events => { |
||||
const mapping = coverage.generate(events, pathPrefix); |
||||
assert.deepEqual(mapping[filePath].l, { |
||||
5: 1, 6: 1, 7: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].b, { |
||||
1: [0, 1], |
||||
}); |
||||
assert.deepEqual(mapping[filePath].s, { |
||||
1: 1, 2: 1, 3: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].f, { |
||||
1: 1, |
||||
}); |
||||
done(); |
||||
}).catch(done); |
||||
}); |
||||
|
||||
it('should cover a conditional that reaches the consequent (multi-line)', done => { |
||||
const contract = util.getCode('conditional/multiline-consequent.sol'); |
||||
const info = getInstrumentedVersion(contract, filePath); |
||||
const coverage = new CoverageMap(); |
||||
coverage.addContract(info, filePath); |
||||
|
||||
vm.execute(info.contract, 'a', []).then(events => { |
||||
const mapping = coverage.generate(events, pathPrefix); |
||||
assert.deepEqual(mapping[filePath].l, { |
||||
5: 1, 6: 1, 7: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].b, { |
||||
1: [1, 0], |
||||
}); |
||||
assert.deepEqual(mapping[filePath].s, { |
||||
1: 1, 2: 1, 3: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].f, { |
||||
1: 1, |
||||
}); |
||||
done(); |
||||
}).catch(done); |
||||
}); |
||||
|
||||
it('should cover a conditional that reaches the alternate (multi-line)', done => { |
||||
const contract = util.getCode('conditional/multiline-alternate.sol'); |
||||
const info = getInstrumentedVersion(contract, filePath); |
||||
const coverage = new CoverageMap(); |
||||
coverage.addContract(info, filePath); |
||||
|
||||
vm.execute(info.contract, 'a', []).then(events => { |
||||
const mapping = coverage.generate(events, pathPrefix); |
||||
assert.deepEqual(mapping[filePath].l, { |
||||
5: 1, 6: 1, 7: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].b, { |
||||
1: [0, 1], |
||||
}); |
||||
assert.deepEqual(mapping[filePath].s, { |
||||
1: 1, 2: 1, 3: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].f, { |
||||
1: 1, |
||||
}); |
||||
done(); |
||||
}).catch(done); |
||||
}); |
||||
|
||||
it('should cover a DeclarativeExpression assignment by conditional that reaches the alternate', done => { |
||||
const contract = util.getCode('conditional/declarative-exp-assignment-alternate.sol'); |
||||
const info = getInstrumentedVersion(contract, filePath); |
||||
const coverage = new CoverageMap(); |
||||
coverage.addContract(info, filePath); |
||||
|
||||
// Runs bool z = (x) ? false : true;
|
||||
vm.execute(info.contract, 'a', []).then(events => { |
||||
const mapping = coverage.generate(events, pathPrefix); |
||||
assert.deepEqual(mapping[filePath].l, { |
||||
5: 1, 6: 1, 7: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].b, { |
||||
1: [0, 1], |
||||
}); |
||||
assert.deepEqual(mapping[filePath].s, { |
||||
1: 1, 2: 1, 3: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].f, { |
||||
1: 1, |
||||
}); |
||||
done(); |
||||
}).catch(done); |
||||
}); |
||||
|
||||
it('should cover an Identifier assignment by conditional that reaches the alternate', done => { |
||||
const contract = util.getCode('conditional/identifier-assignment-alternate.sol'); |
||||
const info = getInstrumentedVersion(contract, filePath); |
||||
const coverage = new CoverageMap(); |
||||
coverage.addContract(info, filePath); |
||||
|
||||
// Runs z = (x) ? false : true;
|
||||
vm.execute(info.contract, 'a', []).then(events => { |
||||
const mapping = coverage.generate(events, pathPrefix); |
||||
assert.deepEqual(mapping[filePath].l, { |
||||
5: 1, 6: 1, 7: 1, 8: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].b, { |
||||
1: [0, 1], |
||||
}); |
||||
assert.deepEqual(mapping[filePath].s, { |
||||
1: 1, 2: 1, 3: 1, 4: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].f, { |
||||
1: 1, |
||||
}); |
||||
done(); |
||||
}).catch(done); |
||||
}); |
||||
|
||||
it('should cover an assignment to a member expression (reaches the alternate)', done => { |
||||
const contract = util.getCode('conditional/mapping-assignment.sol'); |
||||
const info = getInstrumentedVersion(contract, filePath); |
||||
const coverage = new CoverageMap(); |
||||
coverage.addContract(info, filePath); |
||||
|
||||
vm.execute(info.contract, 'a', []).then(events => { |
||||
const mapping = coverage.generate(events, pathPrefix); |
||||
assert.deepEqual(mapping[filePath].l, { |
||||
11: 1, 12: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].b, { |
||||
1: [0, 1], |
||||
}); |
||||
assert.deepEqual(mapping[filePath].s, { |
||||
1: 1, 2: 1, |
||||
}); |
||||
assert.deepEqual(mapping[filePath].f, { |
||||
1: 1, |
||||
}); |
||||
done(); |
||||
}).catch(done); |
||||
}); |
||||
|
||||
}); |
||||
*/ |
@ -1,121 +0,0 @@ |
||||
/** |
||||
* This is logic to instrument ternary conditional assignment statements. Preserving |
||||
* here for the time being, because instrumentation of these became impossible in |
||||
* solc >= 0.5.0 |
||||
*/ |
||||
|
||||
function instrumentAssignmentExpression(contract, expression) { |
||||
|
||||
// This is suspended for 0.5.0 which tries to accomodate the new `emit` keyword.
|
||||
// Solc is not allowing us to use the construction `emit SomeEvent()` within the parens :/
|
||||
return; |
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
// The only time we instrument an assignment expression is if there's a conditional expression on
|
||||
// the right
|
||||
/*if (expression.right.type === 'ConditionalExpression') { |
||||
if (expression.left.type === 'DeclarativeExpression' || expression.left.type === 'Identifier') { |
||||
// Then we need to go from bytes32 varname = (conditional expression)
|
||||
// to bytes32 varname; (,varname) = (conditional expression)
|
||||
createOrAppendInjectionPoint(contract, expression.left.range[1], { |
||||
type: 'literal', string: '; (,' + expression.left.name + ')', |
||||
}); |
||||
instrumenter.instrumentConditionalExpression(contract, expression.right); |
||||
} else if (expression.left.type === 'MemberExpression') { |
||||
createOrAppendInjectionPoint(contract, expression.left.range[0], { |
||||
type: 'literal', string: '(,', |
||||
}); |
||||
createOrAppendInjectionPoint(contract, expression.left.range[1], { |
||||
type: 'literal', string: ')', |
||||
}); |
||||
instrumenter.instrumentConditionalExpression(contract, expression.right); |
||||
} else { |
||||
const err = 'Error instrumenting assignment expression @ solidity-coverage/lib/instrumenter.js'; |
||||
console.log(err, contract, expression.left); |
||||
process.exit(); |
||||
} |
||||
}*/ |
||||
}; |
||||
|
||||
function instrumentConditionalExpression(contract, expression) { |
||||
// ----------------------------------------------------------------------------------------------
|
||||
// This is suspended for 0.5.0 which tries to accomodate the new `emit` keyword.
|
||||
// Solc is not allowing us to use the construction `emit SomeEvent()` within the parens :/
|
||||
// Very sad, this is the coolest thing in here.
|
||||
return; |
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
/*contract.branchId += 1; |
||||
|
||||
const startline = (contract.instrumented.slice(0, expression.range[0]).match(/\n/g) || []).length + 1; |
||||
const startcol = expression.range[0] - contract.instrumented.slice(0, expression.range[0]).lastIndexOf('\n') - 1; |
||||
const consequentStartCol = startcol + (contract, expression.trueBody.range[0] - expression.range[0]); |
||||
const consequentEndCol = consequentStartCol + (contract, expression.trueBody.range[1] - expression.trueBody.range[0]); |
||||
const alternateStartCol = startcol + (contract, expression.falseBody.range[0] - expression.range[0]); |
||||
const alternateEndCol = alternateStartCol + (contract, expression.falseBody.range[1] - expression.falseBody.range[0]); |
||||
// NB locations for conditional branches in istanbul are length 1 and associated with the : and ?.
|
||||
contract.branchMap[contract.branchId] = { |
||||
line: startline, |
||||
type: 'cond-expr', |
||||
locations: [{ |
||||
start: { |
||||
line: startline, column: consequentStartCol, |
||||
}, |
||||
end: { |
||||
line: startline, column: consequentEndCol, |
||||
}, |
||||
}, { |
||||
start: { |
||||
line: startline, column: alternateStartCol, |
||||
}, |
||||
end: { |
||||
line: startline, column: alternateEndCol, |
||||
}, |
||||
}], |
||||
}; |
||||
// Right, this could be being used just by itself or as an assignment. In the case of the latter, because
|
||||
// the comma operator doesn't exist, we're going to have to get funky.
|
||||
// if we're on a line by ourselves, this is easier
|
||||
//
|
||||
// Now if we've got to wrap the expression it's being set equal to, do that...
|
||||
|
||||
|
||||
// Wrap the consequent
|
||||
createOrAppendInjectionPoint(contract, expression.trueBody.range[0], { |
||||
type: 'openParen', |
||||
}); |
||||
createOrAppendInjectionPoint(contract, expression.trueBody.range[0], { |
||||
type: 'callBranchEvent', comma: true, branchId: contract.branchId, locationIdx: 0, |
||||
}); |
||||
createOrAppendInjectionPoint(contract, expression.trueBody.range[1], { |
||||
type: 'closeParen', |
||||
}); |
||||
|
||||
// Wrap the alternate
|
||||
createOrAppendInjectionPoint(contract, expression.falseBody.range[0], { |
||||
type: 'openParen', |
||||
}); |
||||
createOrAppendInjectionPoint(contract, expression.falseBody.range[0], { |
||||
type: 'callBranchEvent', comma: true, branchId: contract.branchId, locationIdx: 1, |
||||
}); |
||||
createOrAppendInjectionPoint(contract, expression.falseBody.range[1], { |
||||
type: 'closeParen', |
||||
});*/ |
||||
}; |
||||
|
||||
// Paren / Literal injectors
|
||||
/* |
||||
|
||||
injector.openParen = function injectOpenParen(contract, fileName, injectionPoint, injection) { |
||||
contract.instrumented = contract.instrumented.slice(0, injectionPoint) + '(' + contract.instrumented.slice(injectionPoint); |
||||
}; |
||||
|
||||
injector.closeParen = function injectCloseParen(contract, fileName, injectionPoint, injection) { |
||||
contract.instrumented = contract.instrumented.slice(0, injectionPoint) + ')' + contract.instrumented.slice(injectionPoint); |
||||
}; |
||||
|
||||
injector.literal = function injectLiteral(contract, fileName, injectionPoint, injection) { |
||||
contract.instrumented = contract.instrumented.slice(0, injectionPoint) + injection.string + contract.instrumented.slice(injectionPoint); |
||||
}; |
||||
|
||||
*/ |
@ -1,148 +0,0 @@ |
||||
const API = require('./../lib/api'); |
||||
const utils = require('./resources/plugin.utils'); |
||||
const buidlerUtils = require('./resources/nomiclabs.utils'); |
||||
const PluginUI = require('./resources/nomiclabs.ui'); |
||||
|
||||
const pkg = require('./../package.json'); |
||||
const death = require('death'); |
||||
const path = require('path'); |
||||
|
||||
const { task, types } = require("@nomiclabs/buidler/config"); |
||||
const { ensurePluginLoadedWithUsePlugin } = require("@nomiclabs/buidler/plugins"); |
||||
|
||||
const { |
||||
TASK_TEST, |
||||
TASK_COMPILE, |
||||
TASK_COMPILE_GET_COMPILER_INPUT |
||||
} = require("@nomiclabs/buidler/builtin-tasks/task-names"); |
||||
|
||||
ensurePluginLoadedWithUsePlugin(); |
||||
|
||||
function plugin() { |
||||
|
||||
// UI for the task flags...
|
||||
const ui = new PluginUI(); |
||||
|
||||
// Unset useLiteralContent due to solc metadata size restriction
|
||||
task(TASK_COMPILE_GET_COMPILER_INPUT).setAction(async (_, __, runSuper) => { |
||||
const input = await runSuper(); |
||||
input.settings.metadata.useLiteralContent = false; |
||||
return input; |
||||
}) |
||||
|
||||
task("coverage", "Generates a code coverage report for tests") |
||||
|
||||
.addOptionalParam("testfiles", ui.flags.file, "", types.string) |
||||
.addOptionalParam("solcoverjs", ui.flags.solcoverjs, "", types.string) |
||||
.addOptionalParam('temp', ui.flags.temp, "", types.string) |
||||
|
||||
.setAction(async function(args, env){ |
||||
let error; |
||||
let ui; |
||||
let api; |
||||
let config; |
||||
|
||||
try { |
||||
death(buidlerUtils.finish.bind(null, config, api)); // Catch interrupt signals
|
||||
|
||||
config = buidlerUtils.normalizeConfig(env.config, args); |
||||
ui = new PluginUI(config.logger.log); |
||||
api = new API(utils.loadSolcoverJS(config)); |
||||
|
||||
// ==============
|
||||
// Server launch
|
||||
// ==============
|
||||
const network = buidlerUtils.setupBuidlerNetwork(env, api, ui); |
||||
|
||||
const client = api.client || require('ganache-cli'); |
||||
const address = await api.ganache(client); |
||||
const accountsRequest = await utils.getAccountsGanache(api.server.provider); |
||||
const nodeInfoRequest = await utils.getNodeInfoGanache(api.server.provider); |
||||
const ganacheVersion = nodeInfoRequest.result.split('/')[1]; |
||||
|
||||
// Set default account
|
||||
network.from = accountsRequest.result[0]; |
||||
|
||||
// Version Info
|
||||
ui.report('versions', [ |
||||
ganacheVersion, |
||||
pkg.version |
||||
]); |
||||
|
||||
ui.report('ganache-network', [ |
||||
env.network.name, |
||||
api.port |
||||
]); |
||||
|
||||
// Run post-launch server hook;
|
||||
await api.onServerReady(config); |
||||
|
||||
// ================
|
||||
// Instrumentation
|
||||
// ================
|
||||
|
||||
const skipFiles = api.skipFiles || []; |
||||
|
||||
let { |
||||
targets, |
||||
skipped |
||||
} = utils.assembleFiles(config, skipFiles); |
||||
|
||||
targets = api.instrument(targets); |
||||
utils.reportSkipped(config, skipped); |
||||
|
||||
// ==============
|
||||
// Compilation
|
||||
// ==============
|
||||
config.temp = args.temp; |
||||
|
||||
const { |
||||
tempArtifactsDir, |
||||
tempContractsDir |
||||
} = utils.getTempLocations(config); |
||||
|
||||
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir) |
||||
utils.save(targets, config.paths.sources, tempContractsDir); |
||||
utils.save(skipped, config.paths.sources, tempContractsDir); |
||||
|
||||
config.paths.sources = tempContractsDir; |
||||
config.paths.artifacts = tempArtifactsDir; |
||||
config.paths.cache = buidlerUtils.tempCacheDir(config); |
||||
config.solc.optimizer.enabled = false; |
||||
|
||||
await env.run(TASK_COMPILE); |
||||
|
||||
await api.onCompileComplete(config); |
||||
|
||||
// ======
|
||||
// Tests
|
||||
// ======
|
||||
const testfiles = args.testfiles |
||||
? buidlerUtils.getTestFilePaths(args.testfiles) |
||||
: []; |
||||
|
||||
try { |
||||
await env.run(TASK_TEST, {testFiles: testfiles}) |
||||
} catch (e) { |
||||
error = e; |
||||
} |
||||
await api.onTestsComplete(config); |
||||
|
||||
// ========
|
||||
// Istanbul
|
||||
// ========
|
||||
await api.report(); |
||||
await api.onIstanbulComplete(config); |
||||
|
||||
} catch(e) { |
||||
error = e; |
||||
} |
||||
|
||||
await buidlerUtils.finish(config, api); |
||||
|
||||
if (error !== undefined ) throw error; |
||||
if (process.exitCode > 0) throw new Error(ui.generate('tests-fail', [process.exitCode])); |
||||
}) |
||||
} |
||||
|
||||
module.exports = plugin; |
@ -1,6 +1 @@ |
||||
if (global && global.__hardhatContext){ |
||||
require("./hardhat.plugin"); |
||||
return; |
||||
} |
||||
|
||||
module.exports = require('./buidler.plugin') |
||||
|
@ -0,0 +1,145 @@ |
||||
const mocha = require("mocha"); |
||||
const inherits = require("util").inherits; |
||||
const Spec = mocha.reporters.Spec; |
||||
const path = require('path'); |
||||
|
||||
/** |
||||
* This file adapted from mocha's stats-collector |
||||
* https://github.com/mochajs/mocha/blob/54475eb4ca35a2c9044a1b8c59a60f09c73e6c01/lib/stats-collector.js#L1-L83
|
||||
*/ |
||||
const Date = global.Date; |
||||
|
||||
/** |
||||
* Provides stats such as test duration, number of tests passed / failed etc., by |
||||
* listening for events emitted by `runner`. |
||||
*/ |
||||
function mochaStats(runner) { |
||||
const stats = { |
||||
suites: 0, |
||||
tests: 0, |
||||
passes: 0, |
||||
pending: 0, |
||||
failures: 0 |
||||
}; |
||||
|
||||
if (!runner) throw new Error("Missing runner argument"); |
||||
|
||||
runner.stats = stats; |
||||
|
||||
runner.on("pass", () => stats.passes++); |
||||
runner.on("fail", () => stats.failures++); |
||||
runner.on("pending", () => stats.pending++); |
||||
runner.on("test end", () => stats.tests++); |
||||
|
||||
runner.once("start", () => (stats.start = new Date())); |
||||
|
||||
runner.once("end", function() { |
||||
stats.end = new Date(); |
||||
stats.duration = stats.end - stats.start; |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Based on the Mocha 'Spec' reporter. |
||||
* |
||||
* Watches an Ethereum test suite run and collects data about which tests hit |
||||
* which lines of code. This "test matrix" can be used as an input to fault localization tools |
||||
* like: https://github.com/JoranHonig/tarantula
|
||||
* |
||||
* Mocha's JSON reporter output is also generated and saved to a separate file |
||||
* |
||||
* @param {Object} runner mocha's runner |
||||
* @param {Object} options reporter.options (see README example usage) |
||||
*/ |
||||
function Matrix(runner, options) { |
||||
// Spec reporter
|
||||
Spec.call(this, runner, options); |
||||
|
||||
const self = this; |
||||
const tests = []; |
||||
const failures = []; |
||||
const passes = []; |
||||
|
||||
// Initialize stats for Mocha 6+ epilogue
|
||||
if (!runner.stats) { |
||||
mochaStats(runner); |
||||
this.stats = runner.stats; |
||||
} |
||||
|
||||
runner.on("test end", (info) => { |
||||
options.reporterOptions.collectTestMatrixData(info); |
||||
tests.push(info); |
||||
}); |
||||
|
||||
runner.on('pass', function(info) { |
||||
passes.push(info) |
||||
}) |
||||
runner.on('fail', function(info) { |
||||
failures.push(info) |
||||
}); |
||||
|
||||
runner.once('end', function() { |
||||
delete self.stats.start; |
||||
delete self.stats.end; |
||||
delete self.stats.duration; |
||||
|
||||
var obj = { |
||||
stats: self.stats, |
||||
tests: tests.map(clean), |
||||
failures: failures.map(clean), |
||||
passes: passes.map(clean) |
||||
}; |
||||
runner.testResults = obj; |
||||
options.reporterOptions.saveMochaJsonOutput(obj) |
||||
}); |
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
// Mocha JSON Reporter Utils
|
||||
// Code taken from:
|
||||
// https://mochajs.org/api/reporters_json.js.html
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
function clean(info) { |
||||
var err = info.err || {}; |
||||
if (err instanceof Error) { |
||||
err = errorJSON(err); |
||||
} |
||||
return { |
||||
title: info.title, |
||||
fullTitle: info.fullTitle(), |
||||
file: path.relative(options.reporterOptions.cwd, info.file), |
||||
currentRetry: info.currentRetry(), |
||||
err: cleanCycles(err) |
||||
}; |
||||
} |
||||
|
||||
function cleanCycles(obj) { |
||||
var cache = []; |
||||
return JSON.parse( |
||||
JSON.stringify(obj, function(key, value) { |
||||
if (typeof value === 'object' && value !== null) { |
||||
if (cache.indexOf(value) !== -1) { |
||||
// Instead of going in a circle, we'll print [object Object]
|
||||
return '' + value; |
||||
} |
||||
cache.push(value); |
||||
} |
||||
return value; |
||||
}) |
||||
); |
||||
} |
||||
|
||||
function errorJSON(err) { |
||||
var res = {}; |
||||
Object.getOwnPropertyNames(err).forEach(function(key) { |
||||
res[key] = err[key]; |
||||
}, err); |
||||
return res; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Inherit from `Base.prototype`. |
||||
*/ |
||||
inherits(Matrix, Spec); |
||||
|
||||
module.exports = Matrix; |
@ -1,23 +0,0 @@ |
||||
pragma solidity >=0.4.21 <0.6.0; |
||||
|
||||
contract Migrations { |
||||
address public owner; |
||||
uint public last_completed_migration; |
||||
|
||||
constructor() public { |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
modifier restricted() { |
||||
if (msg.sender == owner) _; |
||||
} |
||||
|
||||
function setCompleted(uint completed) public restricted { |
||||
last_completed_migration = completed; |
||||
} |
||||
|
||||
function upgrade(address new_address) public restricted { |
||||
Migrations upgraded = Migrations(new_address); |
||||
upgraded.setCompleted(last_completed_migration); |
||||
} |
||||
} |
@ -1,3 +1,3 @@ |
||||
pragma solidity >=0.4.21 <0.6.0; |
||||
pragma solidity >=0.4.21 <0.8.0; |
||||
|
||||
import "package/AnotherImport.sol"; |
||||
|
@ -1,5 +0,0 @@ |
||||
const Migrations = artifacts.require("Migrations"); |
||||
|
||||
module.exports = function(deployer) { |
||||
deployer.deploy(Migrations); |
||||
}; |
2
test/integration/projects/import-paths/node_modules/package/NodeModulesImport.sol
generated
vendored
2
test/integration/projects/import-paths/node_modules/package/NodeModulesImport.sol
generated
vendored
@ -0,0 +1,17 @@ |
||||
// Testing hooks
|
||||
const fn = (msg, config) => config.logger.log(msg); |
||||
const reporterPath = (process.env.TRUFFLE_TEST) |
||||
? "./plugins/resources/matrix.js" |
||||
: "../plugins/resources/matrix.js"; |
||||
|
||||
module.exports = { |
||||
// This is loaded directly from `./plugins` during unit tests. The default val is
|
||||
// "solidity-coverage/plugins/resources/matrix.js"
|
||||
matrixReporterPath: reporterPath, |
||||
matrixOutputPath: "alternateTestMatrix.json", |
||||
mochaJsonOutputPath: "alternateMochaOutput.json", |
||||
|
||||
skipFiles: ['Migrations.sol'], |
||||
silent: process.env.SILENT ? true : false, |
||||
istanbulReporter: ['json-summary', 'text'], |
||||
} |
@ -0,0 +1,21 @@ |
||||
pragma solidity ^0.7.0; |
||||
|
||||
|
||||
contract MatrixA { |
||||
uint x; |
||||
constructor() public { |
||||
} |
||||
|
||||
function sendFn() public { |
||||
x = 5; |
||||
} |
||||
|
||||
function callFn() public pure returns (uint){ |
||||
uint y = 5; |
||||
return y; |
||||
} |
||||
|
||||
function unhit() public { |
||||
uint z = 7; |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
pragma solidity ^0.7.0; |
||||
|
||||
|
||||
contract MatrixB { |
||||
uint x; |
||||
constructor() public { |
||||
} |
||||
|
||||
function sendFn() public { |
||||
x = 5; |
||||
} |
||||
|
||||
function callFn() public pure returns (uint){ |
||||
uint y = 5; |
||||
return y; |
||||
} |
||||
} |
@ -0,0 +1,99 @@ |
||||
{ |
||||
"stats": { |
||||
"suites": 2, |
||||
"tests": 6, |
||||
"passes": 6, |
||||
"pending": 0, |
||||
"failures": 0 |
||||
}, |
||||
"tests": [ |
||||
{ |
||||
"title": "sends to A", |
||||
"fullTitle": "Contract: Matrix A and B sends to A", |
||||
"file": "test/matrix_a_b.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "sends to A", |
||||
"fullTitle": "Contract: Matrix A and B sends to A", |
||||
"file": "test/matrix_a_b.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "calls B", |
||||
"fullTitle": "Contract: Matrix A and B calls B", |
||||
"file": "test/matrix_a_b.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "sends to B", |
||||
"fullTitle": "Contract: Matrix A and B sends to B", |
||||
"file": "test/matrix_a_b.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "sends", |
||||
"fullTitle": "Contract: MatrixA sends", |
||||
"file": "test/matrix_a.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "calls", |
||||
"fullTitle": "Contract: MatrixA calls", |
||||
"file": "test/matrix_a.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
} |
||||
], |
||||
"failures": [], |
||||
"passes": [ |
||||
{ |
||||
"title": "sends to A", |
||||
"fullTitle": "Contract: Matrix A and B sends to A", |
||||
"file": "test/matrix_a_b.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "sends to A", |
||||
"fullTitle": "Contract: Matrix A and B sends to A", |
||||
"file": "test/matrix_a_b.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "calls B", |
||||
"fullTitle": "Contract: Matrix A and B calls B", |
||||
"file": "test/matrix_a_b.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "sends to B", |
||||
"fullTitle": "Contract: Matrix A and B sends to B", |
||||
"file": "test/matrix_a_b.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "sends", |
||||
"fullTitle": "Contract: MatrixA sends", |
||||
"file": "test/matrix_a.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
}, |
||||
{ |
||||
"title": "calls", |
||||
"fullTitle": "Contract: MatrixA calls", |
||||
"file": "test/matrix_a.js", |
||||
"currentRetry": 0, |
||||
"err": {} |
||||
} |
||||
] |
||||
} |
||||
|
@ -0,0 +1,48 @@ |
||||
{ |
||||
"contracts/MatrixA.sol": { |
||||
"10": [ |
||||
{ |
||||
"title": "sends to A", |
||||
"file": "test/matrix_a_b.js" |
||||
}, |
||||
{ |
||||
"title": "sends", |
||||
"file": "test/matrix_a.js" |
||||
} |
||||
], |
||||
"14": [ |
||||
{ |
||||
"title": "calls", |
||||
"file": "test/matrix_a.js" |
||||
} |
||||
], |
||||
"15": [ |
||||
{ |
||||
"title": "calls", |
||||
"file": "test/matrix_a.js" |
||||
} |
||||
], |
||||
"19": [] |
||||
}, |
||||
"contracts/MatrixB.sol": { |
||||
"10": [ |
||||
{ |
||||
"title": "sends to B", |
||||
"file": "test/matrix_a_b.js" |
||||
} |
||||
], |
||||
"14": [ |
||||
{ |
||||
"title": "calls B", |
||||
"file": "test/matrix_a_b.js" |
||||
} |
||||
], |
||||
"15": [ |
||||
{ |
||||
"title": "calls B", |
||||
"file": "test/matrix_a_b.js" |
||||
} |
||||
] |
||||
} |
||||
} |
||||
|
@ -0,0 +1,46 @@ |
||||
{ |
||||
"contracts/MatrixA.sol": { |
||||
"10": [ |
||||
{ |
||||
"title": "sends", |
||||
"file": "test/matrix_a.js" |
||||
}, |
||||
{ |
||||
"title": "sends to A", |
||||
"file": "test/matrix_a_b.js" |
||||
} |
||||
], |
||||
"14": [ |
||||
{ |
||||
"title": "calls", |
||||
"file": "test/matrix_a.js" |
||||
} |
||||
], |
||||
"15": [ |
||||
{ |
||||
"title": "calls", |
||||
"file": "test/matrix_a.js" |
||||
} |
||||
] |
||||
}, |
||||
"contracts/MatrixB.sol": { |
||||
"10": [ |
||||
{ |
||||
"title": "sends to B", |
||||
"file": "test/matrix_a_b.js" |
||||
} |
||||
], |
||||
"14": [ |
||||
{ |
||||
"title": "calls B", |
||||
"file": "test/matrix_a_b.js" |
||||
} |
||||
], |
||||
"15": [ |
||||
{ |
||||
"title": "calls B", |
||||
"file": "test/matrix_a_b.js" |
||||
} |
||||
] |
||||
} |
||||
} |
@ -0,0 +1,9 @@ |
||||
require("@nomiclabs/hardhat-truffle5"); |
||||
require(__dirname + "/../plugins/nomiclabs.plugin"); |
||||
|
||||
module.exports={ |
||||
solidity: { |
||||
version: "0.7.3" |
||||
}, |
||||
logger: process.env.SILENT ? { log: () => {} } : console, |
||||
}; |
@ -0,0 +1,15 @@ |
||||
const MatrixA = artifacts.require("MatrixA"); |
||||
|
||||
contract("MatrixA", function(accounts) { |
||||
let instance; |
||||
|
||||
before(async () => instance = await MatrixA.new()) |
||||
|
||||
it('sends', async function(){ |
||||
await instance.sendFn(); |
||||
}); |
||||
|
||||
it('calls', async function(){ |
||||
await instance.callFn(); |
||||
}) |
||||
}); |
@ -0,0 +1,30 @@ |
||||
const MatrixA = artifacts.require("MatrixA"); |
||||
const MatrixB = artifacts.require("MatrixB"); |
||||
|
||||
contract("Matrix A and B", function(accounts) { |
||||
let instanceA; |
||||
let instanceB; |
||||
|
||||
before(async () => { |
||||
instanceA = await MatrixA.new(); |
||||
instanceB = await MatrixB.new(); |
||||
}) |
||||
|
||||
it('sends to A', async function(){ |
||||
await instanceA.sendFn(); |
||||
}); |
||||
|
||||
// Duplicate test title and file should *not* be duplicated in the output
|
||||
it('sends to A', async function(){ |
||||
await instanceA.sendFn(); |
||||
}) |
||||
|
||||
it('calls B', async function(){ |
||||
await instanceB.callFn(); |
||||
}) |
||||
|
||||
it('sends to B', async function(){ |
||||
await instanceB.sendFn(); |
||||
}); |
||||
|
||||
}); |
@ -0,0 +1,10 @@ |
||||
module.exports = { |
||||
networks: {}, |
||||
mocha: {}, |
||||
compilers: { |
||||
solc: { |
||||
version: "0.7.3" |
||||
} |
||||
}, |
||||
logger: process.env.SILENT ? { log: () => {} } : console, |
||||
} |
@ -0,0 +1,8 @@ |
||||
// Testing hooks
|
||||
const fn = (msg, config) => config.logger.log(msg); |
||||
|
||||
module.exports = { |
||||
skipFiles: ['Migrations.sol'], |
||||
silent: process.env.SILENT ? true : false, |
||||
istanbulReporter: ['json-summary', 'text'], |
||||
} |
@ -0,0 +1,45 @@ |
||||
pragma solidity ^0.6.0; |
||||
|
||||
import "./ModifiersB.sol"; |
||||
|
||||
/** |
||||
* New syntaxes in solc 0.6.x |
||||
*/ |
||||
contract ModifiersA is ModifiersB { |
||||
uint counter; |
||||
bool flag = true; |
||||
|
||||
modifier flippable { |
||||
require(flag); |
||||
_; |
||||
} |
||||
|
||||
modifier overridden() override { |
||||
require(true); |
||||
_; |
||||
} |
||||
|
||||
function flip() public { |
||||
flag = !flag; |
||||
} |
||||
|
||||
function simpleSet(uint i) |
||||
public |
||||
override(ModifiersB) |
||||
{ |
||||
counter = counter + i; |
||||
} |
||||
|
||||
function simpleView(uint i) |
||||
view |
||||
overridden |
||||
external |
||||
returns (uint, bool) |
||||
{ |
||||
return (counter + i, true); |
||||
} |
||||
|
||||
function simpleSetFlip(uint i) flippable public { |
||||
counter = counter + i; |
||||
} |
||||
} |
@ -0,0 +1,19 @@ |
||||
pragma solidity ^0.6.0; |
||||
|
||||
|
||||
contract ModifiersB { |
||||
uint value; |
||||
uint b; |
||||
|
||||
constructor() public { |
||||
} |
||||
|
||||
modifier overridden() virtual { |
||||
require(true); |
||||
_; |
||||
} |
||||
|
||||
function simpleSet(uint i) public virtual { |
||||
value = 5; |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
pragma solidity ^0.6.0; |
||||
|
||||
import "./ModifiersB.sol"; |
||||
|
||||
/** |
||||
* New syntaxes in solc 0.6.x |
||||
*/ |
||||
contract ModifiersC { |
||||
uint counter; |
||||
address owner; |
||||
bool flag = true; |
||||
|
||||
constructor() public { |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
modifier flippable { |
||||
require(flag); |
||||
_; |
||||
} |
||||
|
||||
function flip() public { |
||||
flag = !flag; |
||||
} |
||||
|
||||
function simpleSetFlip(uint i) flippable public { |
||||
counter = counter + i; |
||||
} |
||||
|
||||
modifier onlyOwner { |
||||
require(msg.sender == owner); |
||||
_; |
||||
} |
||||
|
||||
function set(uint i) |
||||
onlyOwner |
||||
public |
||||
payable |
||||
virtual |
||||
{ |
||||
counter = counter + i; |
||||
} |
||||
} |
@ -0,0 +1,9 @@ |
||||
require("@nomiclabs/hardhat-truffle5"); |
||||
require(__dirname + "/../plugins/nomiclabs.plugin"); |
||||
|
||||
module.exports = { |
||||
solidity: { |
||||
version: "0.6.7" |
||||
}, |
||||
logger: process.env.SILENT ? { log: () => {} } : console, |
||||
}; |
@ -0,0 +1,40 @@ |
||||
const ModifiersA = artifacts.require("ModifiersA"); |
||||
const ModifiersC = artifacts.require("ModifiersC"); |
||||
|
||||
contract("Modifiers", function(accounts) { |
||||
let instance; |
||||
|
||||
before(async () => { |
||||
A = await ModifiersA.new(); |
||||
C = await ModifiersC.new(); |
||||
}) |
||||
|
||||
it('simpleSet (overridden method)', async function(){ |
||||
await A.simpleSet(5); |
||||
}); |
||||
|
||||
it('simpleView (overridden modifier)', async function(){ |
||||
await A.simpleView(5); |
||||
}); |
||||
|
||||
it('simpleSetFlip (both branches)', async function(){ |
||||
await A.simpleSetFlip(5); |
||||
await A.flip(); |
||||
|
||||
try { |
||||
await A.simpleSetFlip(5); |
||||
} catch (e) { |
||||
/* ignore */ |
||||
} |
||||
}); |
||||
|
||||
it('simpleSetFlip (false branch + other file)', async function(){ |
||||
await C.flip(); |
||||
|
||||
try { |
||||
await C.simpleSetFlip(5); |
||||
} catch (e) { |
||||
/* ignore */ |
||||
} |
||||
}); |
||||
}); |
@ -0,0 +1,9 @@ |
||||
module.exports = { |
||||
networks: {}, |
||||
mocha: {}, |
||||
compilers: { |
||||
solc: { |
||||
version: "0.6.2" |
||||
} |
||||
} |
||||
} |
@ -1,23 +0,0 @@ |
||||
pragma solidity >=0.4.21 <0.6.0; |
||||
|
||||
contract Migrations { |
||||
address public owner; |
||||
uint public last_completed_migration; |
||||
|
||||
constructor() public { |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
modifier restricted() { |
||||
if (msg.sender == owner) _; |
||||
} |
||||
|
||||
function setCompleted(uint completed) public restricted { |
||||
last_completed_migration = completed; |
||||
} |
||||
|
||||
function upgrade(address new_address) public restricted { |
||||
Migrations upgraded = Migrations(new_address); |
||||
upgraded.setCompleted(last_completed_migration); |
||||
} |
||||
} |
@ -1,23 +0,0 @@ |
||||
pragma solidity >=0.4.21 <0.6.0; |
||||
|
||||
contract Migrations { |
||||
address public owner; |
||||
uint public last_completed_migration; |
||||
|
||||
constructor() public { |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
modifier restricted() { |
||||
if (msg.sender == owner) _; |
||||
} |
||||
|
||||
function setCompleted(uint completed) public restricted { |
||||
last_completed_migration = completed; |
||||
} |
||||
|
||||
function upgrade(address new_address) public restricted { |
||||
Migrations upgraded = Migrations(new_address); |
||||
upgraded.setCompleted(last_completed_migration); |
||||
} |
||||
} |
@ -1,5 +0,0 @@ |
||||
const Migrations = artifacts.require("Migrations"); |
||||
|
||||
module.exports = function(deployer) { |
||||
deployer.deploy(Migrations); |
||||
}; |
@ -0,0 +1,8 @@ |
||||
// Testing hooks
|
||||
const fn = (msg, config) => config.logger.log(msg); |
||||
|
||||
module.exports = { |
||||
skipFiles: ['Migrations.sol'], |
||||
silent: process.env.SILENT ? true : false, |
||||
istanbulReporter: ['json-summary', 'text', 'html'], |
||||
} |
@ -0,0 +1,46 @@ |
||||
pragma solidity ^0.7.0; |
||||
|
||||
|
||||
contract Contract_OR { |
||||
|
||||
function _if(uint i) public pure { |
||||
if (i == 0 || i > 5){ |
||||
/* ignore */ |
||||
} |
||||
} |
||||
|
||||
function _if_and(uint i) public pure { |
||||
if (i != 0 && (i < 2 || i > 5)){ |
||||
/* ignore */ |
||||
} |
||||
} |
||||
|
||||
function _return(uint i) public pure returns (bool){ |
||||
return (i != 0 && i != 1 ) || |
||||
((i + 1) == 2); |
||||
} |
||||
|
||||
function _while(uint i) public pure returns (bool){ |
||||
uint counter; |
||||
while( (i == 1 || i == 2) && counter < 2 ){ |
||||
counter++; |
||||
} |
||||
} |
||||
|
||||
function _require(uint x) public { |
||||
require(x == 1 || x == 2); |
||||
} |
||||
|
||||
function _require_multi_line(uint x) public { |
||||
require( |
||||
(x == 1 || x == 2) || |
||||
x == 3 |
||||
); |
||||
} |
||||
|
||||
function _if_neither(uint i) public { |
||||
if (i == 1 || i == 2){ |
||||
/* ignore */ |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
pragma solidity ^0.7.0; |
||||
|
||||
|
||||
contract Contract_ternary { |
||||
|
||||
// Sameline consequent |
||||
function a() public { |
||||
bool x = true; |
||||
bool y = true; |
||||
x && y ? y = false : y = false; |
||||
} |
||||
|
||||
// Multiline consequent |
||||
function b() public { |
||||
bool x = false; |
||||
bool y = false; |
||||
(x) |
||||
? y = false |
||||
: y = false; |
||||
} |
||||
|
||||
// Sameline w/ logicalOR |
||||
function c() public { |
||||
bool x = false; |
||||
bool y = true; |
||||
(x || y) ? y = false : y = false; |
||||
} |
||||
|
||||
// Multiline w/ logicalOR |
||||
function d() public { |
||||
bool x = false; |
||||
bool y = true; |
||||
(x || y) |
||||
? y = false |
||||
: y = false; |
||||
} |
||||
|
||||
// Sameline alternate |
||||
function e() public { |
||||
bool x = false; |
||||
bool y = false; |
||||
(x) ? y = false : y = false; |
||||
} |
||||
|
||||
// Multiline w/ logicalOR (both false) |
||||
function f() public { |
||||
bool x = false; |
||||
bool y = false; |
||||
(x || y) |
||||
? y = false |
||||
: y = false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,9 @@ |
||||
require("@nomiclabs/hardhat-truffle5"); |
||||
require(__dirname + "/../plugins/nomiclabs.plugin"); |
||||
|
||||
module.exports = { |
||||
solidity: { |
||||
version: "0.7.3" |
||||
}, |
||||
logger: process.env.SILENT ? { log: () => {} } : console, |
||||
}; |
@ -0,0 +1,37 @@ |
||||
const Contract_OR = artifacts.require("Contract_OR"); |
||||
|
||||
contract("contract_or", function(accounts) { |
||||
let instance; |
||||
|
||||
before(async () => instance = await Contract_OR.new()) |
||||
|
||||
it('_if', async function(){ |
||||
await instance._if(0); |
||||
await instance._if(7); |
||||
}); |
||||
|
||||
it('_if_and', async function(){ |
||||
await instance._if_and(1); |
||||
}); |
||||
|
||||
it('_return', async function(){ |
||||
await instance._return(4); |
||||
}); |
||||
|
||||
it('_while', async function(){ |
||||
await instance._while(1); |
||||
}); |
||||
|
||||
it('_require', async function(){ |
||||
await instance._require(2); |
||||
}) |
||||
|
||||
it('_require_multi_line', async function(){ |
||||
await instance._require_multi_line(1); |
||||
await instance._require_multi_line(3); |
||||
}) |
||||
|
||||
it('_if_neither', async function(){ |
||||
await instance._if_neither(3); |
||||
}) |
||||
}); |
@ -0,0 +1,16 @@ |
||||
const Contract_ternary = artifacts.require("Contract_ternary"); |
||||
|
||||
contract("contract_ternary", function(accounts) { |
||||
let instance; |
||||
|
||||
before(async () => instance = await Contract_ternary.new()) |
||||
|
||||
it('misc ternary conditionals', async function(){ |
||||
await instance.a(); |
||||
await instance.b(); |
||||
await instance.c(); |
||||
await instance.d(); |
||||
await instance.e(); |
||||
await instance.f(); |
||||
}); |
||||
}); |
@ -0,0 +1,7 @@ |
||||
module.exports = { |
||||
networks: {}, |
||||
mocha: {}, |
||||
compilers: { |
||||
solc: {} |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue