Skip to content

Commit

Permalink
test: unit tests for cairo-vm-cli (#964)
Browse files Browse the repository at this point in the history
This splits functionality into a `run` function that receives the
iterator of arguments, and `main` that simply calls it with
`std::env::args`.
Then, adds several test cases with `rstest`. It checks all combinations
of successful runs and a few of invalid arguments and missing files.
This should make the codecov path pipeline happier :)

NOTE: the dynamic layout is too slow, and it caused a panic
(subsequently fixed) as well. It is commented out from the tests until
optimized.
  • Loading branch information
Oppen authored Apr 17, 2023
1 parent 263712a commit 4ed5aea
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 6 deletions.
163 changes: 161 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions cairo-vm-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ mimalloc = { version = "0.1.29", default-features = false, optional = true }
nom = "7"
thiserror = { version = "1.0.32" }

[dev-dependencies]
assert_matches = "1.5.0"
rstest = "0.17.0"

[features]
default = ["with_mimalloc"]
with_mimalloc = ["cairo-vm/with_mimalloc", "mimalloc"]
111 changes: 108 additions & 3 deletions cairo-vm-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ fn validate_layout(value: &str) -> Result<(), String> {

#[derive(Debug, Error)]
enum Error {
#[error("Invalid arguments")]
CLI(#[from] clap::Error),
#[error("Failed to interact with the file system")]
IO(#[from] std::io::Error),
#[error("The cairo program execution failed")]
Expand Down Expand Up @@ -101,8 +103,15 @@ impl FileWriter {
}
}

fn main() -> Result<(), Error> {
let args = Args::parse();
fn run(args: impl Iterator<Item = String>) -> Result<(), Error> {
let args = Args::try_parse_from(args);
let args = match args {
Ok(args) => args,
Err(error) => {
eprintln!("{error}");
return Err(Error::CLI(error.into()));
}
};
let trace_enabled = args.trace_file.is_some();
let mut hint_executor = BuiltinHintProcessor::new_empty();
let cairo_run_config = cairo_run::CairoRunConfig {
Expand All @@ -120,7 +129,7 @@ fn main() -> Result<(), Error> {
match cairo_run::cairo_run(&program_content, &cairo_run_config, &mut hint_executor) {
Ok(runner) => runner,
Err(error) => {
println!("{error}");
eprintln!("{error}");
return Err(Error::Runner(error));
}
};
Expand Down Expand Up @@ -154,9 +163,105 @@ fn main() -> Result<(), Error> {
Ok(())
}

fn main() -> Result<(), Error> {
run(std::env::args())
}

#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
use rstest::rstest;

#[rstest]
#[case([].as_slice())]
#[case(["cairo-vm-cli"].as_slice())]
fn test_run_missing_mandatory_args(#[case] args: &[&str]) {
let args = args.into_iter().cloned().map(String::from);
assert_matches!(run(args), Err(Error::CLI(_)));
}

#[rstest]
#[case(["cairo-vm-cli", "--layout", "broken_layout", "../cairo_programs/fibonacci.json"].as_slice())]
fn test_run_invalid_args(#[case] args: &[&str]) {
let args = args.into_iter().cloned().map(String::from);
assert_matches!(run(args), Err(Error::CLI(_)));
}

#[rstest]
fn test_run_ok(
#[values(None,
Some("plain"),
Some("small"),
Some("dex"),
Some("starknet"),
Some("starknet_with_keccak"),
Some("recursive_large_output"),
Some("all_cairo"),
Some("all_solidity"),
//FIXME: dynamic layout leads to _very_ slow execution
//Some("dynamic"),
)]
layout: Option<&str>,
#[values(false, true)] memory_file: bool,
#[values(false, true)] mut trace_file: bool,
#[values(false, true)] proof_mode: bool,
#[values(false, true)] secure_run: bool,
#[values(false, true)] print_output: bool,
#[values(false, true)] entrypoint: bool,
) {
let mut args = vec!["cairo-vm-cli".to_string()];
if let Some(layout) = layout {
args.extend_from_slice(&["--layout".to_string(), layout.to_string()]);
}
if proof_mode {
trace_file = true;
args.extend_from_slice(&["--proof_mode".to_string()]);
}
if entrypoint {
args.extend_from_slice(&["--entrypoint".to_string(), "main".to_string()]);
}
if memory_file {
args.extend_from_slice(&["--memory_file".to_string(), "/dev/null".to_string()]);
}
if trace_file {
args.extend_from_slice(&["--trace_file".to_string(), "/dev/null".to_string()]);
}
if secure_run {
args.extend_from_slice(&["--secure_run".to_string(), "true".to_string()]);
}
if print_output {
args.extend_from_slice(&["--print_output".to_string()]);
}
args.push("../cairo_programs/proof_programs/fibonacci.json".to_string());
assert_matches!(run(args.into_iter()), Ok(_));
}

#[test]
fn test_run_missing_program() {
let args = ["cairo-vm-cli", "../missing/program.json"]
.into_iter()
.map(String::from);
assert_matches!(run(args), Err(Error::IO(_)));
}

#[rstest]
#[case("../cairo_programs/manually_compiled/invalid_even_length_hex.json")]
#[case("../cairo_programs/manually_compiled/invalid_memory.json")]
#[case("../cairo_programs/manually_compiled/invalid_odd_length_hex.json")]
#[case("../cairo_programs/manually_compiled/no_data_program.json")]
#[case("../cairo_programs/manually_compiled/no_main_program.json")]
fn test_run_bad_file(#[case] program: &str) {
let args = ["cairo-vm-cli", program].into_iter().map(String::from);
assert_matches!(run(args), Err(Error::Runner(_)));
}

//Since the functionality here is trivial, I just call the function
//to fool Codecov.
#[test]
fn test_main() {
assert!(main().is_err());
}

#[test]
fn test_valid_layouts() {
Expand Down
2 changes: 1 addition & 1 deletion src/vm/runners/cairo_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ impl CairoRunner {
}

let diluted_units = diluted_pool_instance.units_per_step as usize * vm.current_step;
let unused_diluted_units = diluted_units - used_units_by_builtins;
let unused_diluted_units = diluted_units.saturating_sub(used_units_by_builtins);

let diluted_usage_upper_bound = 1usize << diluted_pool_instance.n_bits;
if unused_diluted_units < diluted_usage_upper_bound {
Expand Down

0 comments on commit 4ed5aea

Please sign in to comment.