Skip to content

Commit

Permalink
feat/Added CLI option to initialize fuzz tests or poc tests only (#124)
Browse files Browse the repository at this point in the history
* ✨ Init Template

* Init template updates

* 🐛 Build command to execute only if trdelnik is initialized

* 🐛 fixes
  • Loading branch information
lukacan committed Feb 23, 2024
1 parent 16b253d commit f3741ee
Show file tree
Hide file tree
Showing 12 changed files with 394 additions and 253 deletions.
2 changes: 1 addition & 1 deletion crates/cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod explorer;
pub use explorer::{explorer, ExplorerCommand};

mod init;
pub use init::init;
pub use init::{init, TestsType};

mod clean;
pub use clean::clean;
29 changes: 22 additions & 7 deletions crates/cli/src/command/build.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
use anyhow::Error;
use anyhow::{bail, Error};
use fehler::throws;
use trdelnik_client::*;

use crate::_discover;

use super::fuzz::TRDELNIK_TOML;

#[throws]
pub async fn build(root: String) {
let commander = Commander::with_root(root);
commander.create_program_client_crate().await?;
commander.build_programs().await?;
commander.generate_program_client_deps().await?;
commander.generate_program_client_lib_rs(None).await?;
pub async fn build(root: Option<String>) {
// if the root is present from the command line we will use it
// if the root is not present we will look for the Cargo.toml file
// Trdelnik does not have to be already defined to actually create/build
// program client
let root = match root {
Some(r) => r,
_ => {
if let Some(r) = _discover(TRDELNIK_TOML)? {
r
} else {
bail!("It does not seem that Trdelnik is initialized because the Trdelnik.toml file was not found in any parent directory!");
}
}
};
let mut generator: TestGenerator = TestGenerator::new_with_root(root);
generator.build().await?;
}
39 changes: 9 additions & 30 deletions crates/cli/src/command/fuzz.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use anyhow::{bail, Context, Error, Result};
use anyhow::{bail, Error};

use clap::Subcommand;
use fehler::throws;
use trdelnik_client::{Commander, TestGenerator};

use crate::_discover;

pub const TRDELNIK_TOML: &str = "Trdelnik.toml";

#[derive(Subcommand)]
#[allow(non_camel_case_types)]
pub enum FuzzCommand {
Expand Down Expand Up @@ -31,7 +35,7 @@ pub async fn fuzz(root: Option<String>, subcmd: FuzzCommand) {
let root = match root {
Some(r) => r,
_ => {
let root = _discover()?;
let root = _discover(TRDELNIK_TOML)?;
if let Some(r) = root {
r
} else {
Expand Down Expand Up @@ -61,35 +65,10 @@ pub async fn fuzz(root: Option<String>, subcmd: FuzzCommand) {
}

FuzzCommand::Add => {
let generator = TestGenerator::new();
// generate generator with root so that we do not need to again
// look for root within the generator
let mut generator = TestGenerator::new_with_root(root);
generator.add_new_fuzz_test().await?;
}
};
}

// Climbs each parent directory until we find Trdelnik.toml.
fn _discover() -> Result<Option<String>> {
let _cwd = std::env::current_dir()?;
let mut cwd_opt = Some(_cwd.as_path());

while let Some(cwd) = cwd_opt {
for f in std::fs::read_dir(cwd)
.with_context(|| format!("Error reading the directory with path: {}", cwd.display()))?
{
let p = f
.with_context(|| {
format!("Error reading the directory with path: {}", cwd.display())
})?
.path();
if let Some(filename) = p.file_name() {
if filename.to_str() == Some("Trdelnik.toml") {
return Ok(Some(cwd.to_string_lossy().to_string()));
}
}
}

cwd_opt = cwd.parent();
}

Ok(None)
}
38 changes: 34 additions & 4 deletions crates/cli/src/command/init.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
use anyhow::Error;
use anyhow::{bail, Error};
use clap::ValueEnum;
use fehler::throws;
use trdelnik_client::TestGenerator;

use crate::_discover;

pub const ANCHOR_TOML: &str = "Anchor.toml";

#[derive(ValueEnum, Clone)]
pub enum TestsType {
Both,
Fuzz,
Poc,
}

#[throws]
pub async fn init(skip_fuzzer: bool) {
let generator = TestGenerator::new();
generator.generate(skip_fuzzer).await?;
pub async fn init(tests_type: TestsType) {
// look for Anchor.toml
let root = if let Some(r) = _discover(ANCHOR_TOML)? {
r
} else {
bail!("It does not seem that Anchor is initialized because the Anchor.toml file was not found in any parent directory!");
};

let mut generator: TestGenerator = TestGenerator::new_with_root(root);

match tests_type {
TestsType::Poc => {
generator.generate_poc().await?;
}
TestsType::Both => {
generator.generate_both().await?;
}
TestsType::Fuzz => {
generator.generate_fuzz().await?;
}
};
}
20 changes: 18 additions & 2 deletions crates/cli/src/command/test.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
use anyhow::Error;
use anyhow::{bail, Error};
use fehler::throws;
use trdelnik_client::*;

use crate::_discover;

use super::fuzz::TRDELNIK_TOML;

#[throws]
pub async fn test(root: String) {
pub async fn test(root: Option<String>) {
// if the root is present from the command line we will use it
// if the root is not present we will look for the Trdelnik.toml file
let root = match root {
Some(r) => r,
_ => {
if let Some(r) = _discover(TRDELNIK_TOML)? {
r
} else {
bail!("It does not seem that Trdelnik is initialized because the Cargo.toml file was not found in any parent directory!");
}
}
};
let commander = Commander::with_root(root);
commander.run_tests().await?;
}
47 changes: 38 additions & 9 deletions crates/cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use anyhow::Error;
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use command::TestsType;
use fehler::throws;

// subcommand functions to call and nested subcommands
Expand All @@ -19,11 +21,11 @@ struct Cli {

#[derive(Subcommand)]
enum Command {
/// Create a `program_client` crate
/// Create or update a `program_client` crate
Build {
/// Anchor project root
#[clap(short, long, default_value = "./")]
root: String,
#[clap(short, long)]
root: Option<String>,
},
/// Get information about a keypair
KeyPair {
Expand All @@ -33,8 +35,8 @@ enum Command {
/// Run program Integration tests
Test {
/// Anchor project root
#[clap(short, long, default_value = "./")]
root: String,
#[clap(short, long)]
root: Option<String>,
},
/// Run and debug Fuzz tests
Fuzz {
Expand All @@ -53,9 +55,9 @@ enum Command {
},
/// Initialize test environment
Init {
/// Flag to skip generating template for fuzzing and activating the fuzzing feature.
#[arg(short, long)]
skip_fuzzer: bool,
/// Specifies the types of tests for which the frameworks should be initialized.
#[clap(default_value = "both")]
tests_type: TestsType,
},
/// Removes target contents except for KeyPair and removes hfuzz_target folder
Clean,
Expand All @@ -72,7 +74,34 @@ pub async fn start() {
Command::Fuzz { root, subcmd } => command::fuzz(root, subcmd).await?,
Command::Localnet => command::localnet().await?,
Command::Explorer { subcmd } => command::explorer(subcmd).await?,
Command::Init { skip_fuzzer } => command::init(skip_fuzzer).await?,
Command::Init { tests_type } => command::init(tests_type).await?,
Command::Clean => command::clean().await?,
}
}

// Climbs each parent directory until we find target.
fn _discover(target: &str) -> Result<Option<String>> {
let _cwd = std::env::current_dir()?;
let mut cwd_opt = Some(_cwd.as_path());

while let Some(cwd) = cwd_opt {
for f in std::fs::read_dir(cwd)
.with_context(|| format!("Error reading the directory with path: {}", cwd.display()))?
{
let p = f
.with_context(|| {
format!("Error reading the directory with path: {}", cwd.display())
})?
.path();
if let Some(filename) = p.file_name() {
if filename.to_str() == Some(target) {
return Ok(Some(cwd.to_string_lossy().to_string()));
}
}
}

cwd_opt = cwd.parent();
}

Ok(None)
}
Loading

0 comments on commit f3741ee

Please sign in to comment.