A simple, fast, and easy-to-use Solidity test generator based on the Branching Tree Technique.
bash
cargo install bulloak
Say you have a foo.tree
file with the following contents:
text
FooTest
└── When stuff called
└── It should revert.
If you pass it to bulloak
like so, you will get the skeleton
of a test contract printed to stdout
:
``` $ bulloak foo.tree pragma solidity 0.8.0;
contract FooTest { modifier whenStuffCalled() { _; }
function testRevertWhenStuffCalled() external whenStuffCalled { // It should revert. } } ```
If you are working in a solidity project and you have
multiple trees you want to scaffold, you can use the -w
option.
$ bulloak -w ./**/*.tree
This will create solidity
files with the same name as the .tree
files with the result of scaffolding each tree.
If there exists a file with a title that matches the name at the
root node of the .tree
, then bulloak
will skip writing that file.
However, you may override this behaviour with the -f
flag. This
will write to the filesystem overwriting any files that exist.
$ bulloak -wf ./**/*.tree
Another feature of bulloak
is reporting errors in your input trees.
For example, say you have a buggy foo.tree
file, which is missing a
└
character. Running bulloak foo.tree
would report the error like this:
``
•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
bulloak error: unexpected
when` keyword
── when the id references a null stream ^^^^
--- (line 2, column 4) --- file: foo.tree ```
``` Usage: bulloak [OPTIONS] [FILES]...
Arguments: [FILES]... .tree files to process
Options:
-c
Whether to print it
branches as comments in the output code
-i write_files
is specified, use --force-write
to overwrite the output files
-s, --solidity-version
bulloak
scaffolds solidity test files based on .tree
specifications
that follow the Branching Tree Technique.
Currently, there is on-going discussion on how to handle different edge-cases to better empower the solidity community. This section is a description of the current implementation of the compiler.
when/given
branches of a tree.it
branches of a tree. Every action is a leaf node of the tree.Each tree
file should describe a function under test. Trees follow these rules:
bulloak
expects you to use ├
and └
characters to denote branches.when
, given
or it
.when
or given
, it is a condition.when
and given
are interchangeable.it
, it is an action.it
is the same as It
and IT
.Take the following solidity function:
solidity
function hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? hash(a, b) : hash(b, a);
}
A reasonable spec for the above function would be:
HashPairTest
├── It should never revert.
├── When first arg is smaller than second arg
│ └── It should match the result of `keccak256(abi.encodePacked(a,b))`.
└── When first arg is bigger than second arg
└── It should match the result of `keccak256(abi.encodePacked(b,a))`.
There is a top-level action which would generate a test to check the function invariant that it should never revert.
Then, we have the two possible preconditions: a < b
and a >= b
. Both branches end in an action that will make bulloak
generate the respective test.
Note the following things:
bulloak
also supports actions with sibling conditions, but this might get removed in a future version per this discussion.There are a few things to keep in mind about the scaffolded solidity test:
.tree
but with a .t.sol
extension. E.g. test.tree
would correspond to test.t.sol
..tree
file.Please refer to CONTRIBUTING.md.
This project is licensed under either of: