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"); |
||||||
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"; |
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