11 KiB
Solidity-Coverage API
Solidity-coverage tracks which lines are hit as your tests run by instrumenting the contracts with special solidity statements and detecting their execution in a coverage-enabled EVM.
As such, the API spans the full set of tasks typically required to run a solidity test suite. The table below shows how its core methods relate to the stages of a test run:
Test Stage | API Method | Description |
---|---|---|
compilation | instrument |
A pre-compilation step: Rewrites contracts and generates an instrumentation data map. |
client launch | ganache |
A substitute step: Launches a ganache client with coverage collection enabled in its VM. As the client runs it will mark line/branch hits on the instrumentation data map. |
test | report |
A post-test step: Generates a coverage report from the data collected by the VM after tests complete. |
exit | finish |
A substitute step: Shuts client down |
Additional Resources:
-
the library includes file system utilities for managing the disposable set of contracts/artifacts which coverage must use in lieu of the 'real' (uninstrumented) contracts.
-
there are two complete coverage tool/plugin implementations (for Buidler and Truffle) which can be used as sources if you're building something similar.
Table of Contents
API
Example
const CoverageAPI = require("solidity-coverage/api");
const api = new CoverageAPI(options);
constructor
Creates a coverage API instance. Configurable.
Parameters
options
Object : API options
Option | Type | Default | Description |
---|---|---|---|
port | Number | 8555 | Port to launch client on |
silent | Boolean | false | Suppress logging output |
client | Object | require("ganache-core") |
JS Ethereum client |
providerOptions | Object | { } |
ganache-core options |
skipFiles | Array | [] |
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 |
instrument
Instruments a set of sources to prepare them for compilation.
⚠️ Important: Instrumented sources must be compiled with solc optimization OFF ⚠️
Parameters
contracts
Object[]: Array of solidity sources and their paths
Returns Object[] in the same format as the contracts
param, but with sources instrumented.
Example
const contracts = [{
source: "contract Simple { uint x = 5; }",
canonicalPath: "/Users/user/project/contracts/Simple.sol",
relativePath: "Simple.sol" // Optional, used for pretty printing.
},...]
const instrumented = api.instrument(contracts)
ganache
Enables coverage data collection on an in-process ganache server. By default, this method launches
the server, begins listening on the port specified in the config (or 8555 if unspecified), and
returns a url string. When autoLaunchServer
is false, method returns ganache.server
so you can control
the server.listen
invocation yourself.
Parameters
client
Object: (Optional) ganache moduleautoLaunchServer
Boolean: (Optional)
Returns Promise Address of server to connect to, or initialized, unlaunched server
Example
const client = require('ganache-cli');
const api = new CoverageAPI( { client: client } );
const address = await api.ganache();
> http://127.0.0.1:8555
// Alternatively...
const server = await api.ganache(client, false);
await pify(server.listen)(8545));
report
Generates coverage report using IstanbulJS
Parameters
istanbulFolder
String: (Optional) path to folder Istanbul will deposit coverage reports in.
Returns Promise
Example
await api.report('./coverage_4A3cd2b'); // Default folder name is 'coverage'
finish
Shuts down coverage-enabled ganache server instance
Returns Promise
Example
const client = require('ganache-cli');
await api.ganache(client); // Server listening...
await api.finish(); // Server shut down.
getInstrumentationData
Returns a copy of the hit map created during instrumentation. Useful if you'd like to delegate coverage collection to multiple processes.
Returns Object instrumentation data;
Example
const instrumented = api.instrument(contracts);
const data = api.getInstrumentationData();
save(data); // Pseudo-code
setInstrumentationData
Sets the hit map object generated during instrumentation. Useful if you'd like to collect or convert data to coverage for an instrumentation which was generated in a different process.
Example
const data = load(data); // Pseudo-code
api.setIntrumentationData(data);
// Client will collect data for the loaded map
const address = await api.ganache(client);
// Or to `report` instrumentation data which was collected in a different process.
const data = load(data); // Pseudo-code
api.setInstrumentationData(data);
api.report();
Utils
const utils = require('solidity-coverage/utils');
Many of the utils methods take a config
object param which
defines the absolute paths to your project root and contracts directory.
Example
const config = {
workingDir: process.cwd(),
contractsDir: path.join(process.cwd(), 'contracts'),
}
loadSolcoverJS
Loads .solcoverjs
. Users may specify options in a .solcover.js
config file which your
application needs to consume.
Parameters
config
Object: See config above
Returns Object Normalized coverage config
Example
const solcoverJS = utils.loadSolcoverJS(config);
const api = new CoverageAPI(solcoverJS);
assembleFiles
Loads contracts from the filesystem in a format that can be passed directly to the
api.instrument method. Filters by an optional skipFiles
parameter.
Parameters
config
Object: See config aboveskipFiles
String[]: (Optional) Array of files or folders to skip See API constructor
Returns Object with targets
and skipped
keys. These are Object arrays of contract sources
and paths.
Example
const {
targets,
skipped
} = utils.assembleFiles(config, ['Migrations.sol'])
const instrumented = api.instrument(targets);
getTempLocations
Returns a pair of canonically named temporary directory paths for contracts and artifacts. Instrumented assets can be compiled from and written to these so the unit tests can use them as sources.
Parameters
config
Object: See config above
Returns Object with two absolute paths to disposable folders, tempContractsDir
, tempArtifactsDir
.
These directories are named .coverage_contracts
and .coverage_artifacts
.
Example
const {
tempContractsDir,
tempArtifactsDir
} = utils.getTempLocations(config)
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir)
// Later, you can call `utils.finish` to delete these...
utils.finish(config, api)
setupTempFolders
Creates temporary directories to store instrumented contracts and their compilation artifacts in.
Parameters
config
Object: See config abovetempContractsDir
String: absolute path to temporary contracts directorytempArtifactsDir
String: absolute path to temporary artifacts directory
Example
const {
tempContractsDir,
tempArtifactsDir
} = utils.getTempLocations(config)
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir);
save
Writes an array of instrumented sources in the object format returned by api.instrument to a temporary directory.
Parameters
contracts
Object[]: array of contracts & paths generated by api.instrumentoriginalDir
String: absolute path to original contracts directorytempDir
String: absolute path to temp contracts directory (the destination of the save)
Example
const {
tempContractsDir,
tempArtifactsDir
} = utils.getTempLocations(config)
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir);
const instrumented = api.instrument(contracts);
utils.save(instrumented, config.contractsDir, tempContractsDir);
finish
Deletes temporary folders and shuts the ganache server down. Is tolerant - if folders or ganache server don't exist it will return silently.
Parameters
config
Object: See config aboveapi
Object: (Optional) coverage api instance whose ownfinish
method will be called
Returns Promise
Example
await utils.finish(config, api);