Skip to content

Commit

Permalink
ref: simplify scaffold entrypoint
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfertel committed Apr 14, 2024
1 parent 4c2002d commit 020c402
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 38 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ All notable changes to this project will be documented in this file.

### Features

- *(bulloak)* Make output more readable & succint
- *(bulloak)* Make output more readable & succinct
- Add ‘bulloak check —fix’


Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ You can use `bulloak scaffold` to generate a Solidity contract containing
modifiers and tests that match the spec described in `foo.tree`. The following
will be printed to `stdout`:

```terminal
$ bulloak scaffold foo.tree
```solidity
// $ bulloak scaffold foo.tree
pragma solidity 0.8.0;
contract FooTest {
Expand Down Expand Up @@ -151,7 +151,7 @@ running `bulloak check`, like so:
```text
warn: function "test_WhenFirstArgIsBiggerThanSecondArg" is missing in .sol
+ fix: run `bulloak check --fix tests/scaffold/basic.tree`
~~> tests/scaffold/basic.tree:5
--> tests/scaffold/basic.tree:5
warn: 1 check failed (run `bulloak check --fix <.tree files>` to apply 1 fix)
```
Expand All @@ -160,7 +160,7 @@ As you can see in the above message, `bulloak` can fix the issue automatically.
If we run the command with the `--stdout` flag, the output is:

```solidity
~~> tests/scaffold/basic.t.sol
--> tests/scaffold/basic.t.sol
pragma solidity 0.8.0;
contract HashPairTest {
Expand All @@ -176,7 +176,7 @@ contract HashPairTest {
// It should match the result of `keccak256(abi.encodePacked(b,a))`.
}
}
<~~
<--
success: 1 issue fixed.
```
Expand All @@ -202,7 +202,7 @@ The following rules are currently implemented:
the Solidity file.
- The order of every construct, as it would be generated by `bulloak scaffold`,
matches the spec order.
- Any valid Solidity construct is allowed and only construct that would be
- Any valid Solidity construct is allowed and only constructs that would be
generated by `bulloak scaffold` are checked. This means that any number of
extra functions, modifiers, etc. can be added to the file.

Expand Down
4 changes: 2 additions & 2 deletions src/check/violation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl fmt::Display for ViolationKind {
),
error::Error::Semantic(_) => write!(
f,
"at least one semantic error occured while parsing the tree"
"at least one semantic error occurred while parsing the tree"
),
}
} else {
Expand Down Expand Up @@ -374,7 +374,7 @@ pub(crate) fn fix_order(
// string `source`.
// b - Replace them with whitespace in `scratch`.
//
// Since we sorted in a previos step, they'll appear sorted in
// Since we sorted in a previous step, they'll appear sorted in
// the string. We do 4.b because we want to append the remaining
// functions after the sorted functions.
let mut scratch = ctx.src.clone();
Expand Down
86 changes: 57 additions & 29 deletions src/scaffold/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,52 +47,80 @@ impl Scaffold {

// For each input file, compile it and print it or write it
// to the filesystem.
let mut errors = Vec::with_capacity(self.files.len());
for file in &self.files {
let text = fs::read_to_string(file)?;
match scaffolder.scaffold(&text) {
Ok(emitted) => {
let emitted = fmt(&emitted).unwrap_or_else(|e| {
eprintln!("{}: {}", "WARN".yellow(), e);
let emitted = fmt(&emitted).unwrap_or_else(|err| {
eprintln!("{}: {}", "WARN".yellow(), err);
emitted
});

if self.write_files {
let mut output_path = file.clone();

// Get the path to the output file.
output_path.set_extension("t.sol");

// Don't overwrite files unless `--force-write` was passed.
if output_path.exists() && !self.force_write {
eprintln!(
"{}: Skipped emitting {:?}",
"warn".yellow(),
file.as_path().blue()
);
eprintln!(
" {} The corresponding `.t.sol` file already exists",
"=".blue()
);
continue;
}

if let Err(e) = fs::write(output_path, emitted) {
eprintln!("{}: {e}", "error".red());
};
} else {
if !self.write_files {
println!("{emitted}");
continue;
}

let file = self.to_test_file(file);
self.write_file(&emitted, &file);
}
Err(err) => {
eprintln!("{err}");
eprintln!("file: {}", file.display());
std::process::exit(1);
errors.push((file, err));
}
};
}

if !errors.is_empty() {
let error_count = errors.len();
for (file, err) in errors {
eprintln!("{err}");
eprintln!("file: {}", file.display());
}

eprintln!(
"\n{}: Could not scaffold {} files. Check the output above or run {}, which might prove helpful.",
"warn".yellow(),
error_count.yellow(),
"bulloak check".blue()
);

std::process::exit(1);
}

Ok(())
}

/// Gets the `t.sol` path equivalent of `file`.
fn to_test_file(&self, file: &PathBuf) -> PathBuf {
let mut file = file.clone();
file.set_extension("t.sol");
file
}

/// Writes the provided `text` to `file`.
///
/// If the file doesn't exist it will create it. If it exists,
/// and `--force-write` was not passed, it will skip writing to the file.
fn write_file(&self, text: &str, file: &PathBuf) {
// Don't overwrite files unless `--force-write` was passed.
if file.exists() && !self.force_write {
eprintln!(
"{}: Skipped emitting {:?}",
"warn".yellow(),
file.as_path().blue()
);
eprintln!(
" {} The corresponding `.t.sol` file already exists",
"=".blue()
);
return;
}

if let Err(err) = fs::write(file, text) {
eprintln!("{}: {err}", "error".red());
};
}
}

/// The overarching struct that generates Solidity
Expand Down
1 change: 1 addition & 0 deletions tests/scaffold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fn scaffolds_trees() {
"complex.tree",
"multiple_roots.tree",
"removes_invalid_title_chars.tree",
"hash_pair.tree",
];

for tree_name in trees {
Expand Down
40 changes: 40 additions & 0 deletions tests/scaffold/hash_pair.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;

contract Utils {
function test_HashPairShouldNeverRevert() external {
// It should never revert.
}

function test_HashPairWhenFirstArgIsSmallerThanSecondArg() external {
// It should match the result of `keccak256(abi.encodePacked(a,b))`.
}

function test_HashPairWhenFirstArgIsBiggerThanSecondArg() external {
// It should match the result of `keccak256(abi.encodePacked(b,a))`.
}

function test_MinShouldNeverRevert() external {
// It should never revert.
}

function test_MinWhenFirstArgIsSmallerThanSecondArg() external {
// It should match the value of `a`.
}

function test_MinWhenFirstArgIsBiggerThanSecondArg() external {
// It should match the value of `b`.
}

function test_MaxShouldNeverRevert() external {
// It should never revert.
}

function test_MaxWhenFirstArgIsSmallerThanSecondArg() external {
// It should match the value of `b`.
}

function test_MaxWhenFirstArgIsBiggerThanSecondArg() external {
// It should match the value of `a`.
}
}
22 changes: 22 additions & 0 deletions tests/scaffold/hash_pair.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Utils::hashPair
├── 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))`.


Utils::min
├── It should never revert.
├── When first arg is smaller than second arg
│ └── It should match the value of `a`.
└── When first arg is bigger than second arg
└── It should match the value of `b`.


Utils::max
├── It should never revert.
├── When first arg is smaller than second arg
│ └── It should match the value of `b`.
└── When first arg is bigger than second arg
└── It should match the value of `a`.

0 comments on commit 020c402

Please sign in to comment.