From 75108c855398d9c41e530ad857f839450f2550d0 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 20 Dec 2022 20:47:51 +0100 Subject: [PATCH] test infra --- src/build.rs | 31 ++++++++++++++++++++----- src/lib.rs | 53 +++++++++++++++++++++++++++++-------------- src/main.rs | 5 +++- src/processor/mod.rs | 14 ++++++++---- tests/helper.rs | 54 ++++++++++++++++++++++++++++++++++++++------ tests/minimize.rs | 24 ++++++++++++++++++++ 6 files changed, 145 insertions(+), 36 deletions(-) create mode 100644 tests/minimize.rs diff --git a/src/build.rs b/src/build.rs index b2ef770..d68f5e4 100644 --- a/src/build.rs +++ b/src/build.rs @@ -3,6 +3,7 @@ use rustfix::diagnostics::Diagnostic; use serde::Deserialize; use std::{ collections::HashSet, + ffi::OsStr, fmt::{Debug, Display}, path::PathBuf, process::Command, @@ -39,6 +40,7 @@ struct BuildInner { verify: Verify, env: Vec, allow_color: bool, + project_dir: Option, } #[derive(Debug)] @@ -78,10 +80,19 @@ impl Build { verify, env: options.env.clone(), allow_color: !options.no_color, + project_dir: options.project_dir.clone(), }), } } + fn cmd(&self, name: impl AsRef) -> Command { + let mut cmd = Command::new(name); + if let Some(path) = &self.inner.project_dir { + cmd.current_dir(path); + } + cmd + } + pub fn build(&self) -> Result { let inner = &self.inner; @@ -96,8 +107,12 @@ impl Build { let (is_ice, output) = match &inner.mode { BuildMode::Cargo { args } => { - let mut cmd = Command::new("cargo"); - cmd.args(["build", "--color=always"]); + let mut cmd = self.cmd("cargo"); + cmd.arg("build"); + + if inner.allow_color { + cmd.arg("--color=always"); + } for arg in args.iter().flatten() { cmd.arg(arg); @@ -118,7 +133,7 @@ impl Build { ) } BuildMode::Script(script_path) => { - let mut cmd = Command::new(script_path); + let mut cmd = self.cmd(script_path); for env in &inner.env { cmd.env(&env.key, &env.value); @@ -131,10 +146,14 @@ impl Build { (outputs.status.success(), output) } BuildMode::Rustc => { - let mut cmd = Command::new("rustc"); + let mut cmd = self.cmd("rustc"); cmd.args(["--edition", "2021"]); cmd.arg(&inner.input_path); + if inner.allow_color { + cmd.arg("--color=always"); + } + for env in &inner.env { cmd.env(&env.key, &env.value); } @@ -170,7 +189,7 @@ impl Build { let diags = match &inner.mode { BuildMode::Cargo { args } => { - let mut cmd = Command::new("cargo"); + let mut cmd = self.cmd("cargo"); cmd.args(["build", "--message-format=json"]); for arg in args.iter().flatten() { @@ -195,7 +214,7 @@ impl Build { .collect() } BuildMode::Rustc => { - let mut cmd = std::process::Command::new("rustc"); + let mut cmd = self.cmd("rustc"); cmd.args(["--edition", "2021", "--error-format=json"]); cmd.arg(&inner.input_path); diff --git a/src/lib.rs b/src/lib.rs index 75b87fb..e3de7cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,47 +13,52 @@ mod processor; mod expand; use anyhow::{Context, Result}; -use clap::Parser; use dylib_flag::RustFunction; use processor::Minimizer; use crate::processor::Processor; +// Export so that the user doesn't have to add clap themselves. +pub use clap::Parser; + #[derive(clap::Parser)] #[command(version, about, name = "cargo", bin_name = "cargo")] -enum Cargo { +pub enum Cargo { Minimize(Options), } #[derive(clap::Args, Debug)] pub struct Options { #[arg(short, long)] - script_path: Option, + pub script_path: Option, #[arg(long)] - cargo_args: Option, + pub cargo_args: Option, #[arg(long)] - no_color: bool, + pub no_color: bool, #[arg(long)] - rustc: bool, + pub rustc: bool, #[arg(long)] - no_verify: bool, + pub no_verify: bool, #[arg(long)] - verify_fn: Option, + pub verify_fn: Option, #[arg(long)] - env: Vec, + pub env: Vec, + + #[arg(long)] + pub project_dir: Option, #[arg(default_value = "src")] - path: PathBuf, + pub path: PathBuf, } #[derive(Debug, Clone)] -struct EnvVar { - key: String, - value: String, +pub struct EnvVar { + pub key: String, + pub value: String, } impl FromStr for EnvVar { @@ -72,12 +77,10 @@ impl FromStr for EnvVar { } } -pub fn minimize() -> Result<()> { - let Cargo::Minimize(options) = Cargo::parse(); - +pub fn minimize(options: Options) -> Result<()> { let build = build::Build::new(&options); - let mut minimizer = Minimizer::new_glob_dir(options, build); + let mut minimizer = Minimizer::new_glob_dir(options, build)?; minimizer.run_passes([ Box::::default() as Box, @@ -88,3 +91,19 @@ pub fn minimize() -> Result<()> { Ok(()) } + +impl Default for Options { + fn default() -> Self { + Self { + script_path: None, + cargo_args: None, + no_color: false, + rustc: false, + no_verify: false, + verify_fn: None, + env: Vec::new(), + project_dir: None, + path: PathBuf::from("/the/wrong/path/you/need/to/change/it"), + } + } +} diff --git a/src/main.rs b/src/main.rs index 9811520..031251a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,11 @@ use anyhow::Result; +use cargo_minimize::{Cargo, Parser}; use tracing::{error, info, Level}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry}; fn main() -> Result<()> { + let Cargo::Minimize(options) = Cargo::parse(); + let registry = Registry::default().with( EnvFilter::builder() .with_default_directive(Level::INFO.into()) @@ -18,7 +21,7 @@ fn main() -> Result<()> { registry.with(tree_layer).init(); - if let Err(err) = cargo_minimize::minimize() { + if let Err(err) = cargo_minimize::minimize(options) { error!("An error occured:\n{err}"); } diff --git a/src/processor/mod.rs b/src/processor/mod.rs index e73d6ee..ea8eee5 100644 --- a/src/processor/mod.rs +++ b/src/processor/mod.rs @@ -4,7 +4,7 @@ mod reaper; pub(crate) use self::files::SourceFile; use crate::{build::Build, processor::files::Changes, Options}; -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use owo_colors::OwoColorize; use std::{collections::HashSet, ffi::OsStr, fmt::Debug}; @@ -49,7 +49,7 @@ pub(crate) struct Minimizer { } impl Minimizer { - pub(crate) fn new_glob_dir(options: Options, build: Build) -> Self { + pub(crate) fn new_glob_dir(options: Options, build: Build) -> Result { let path = &options.path; let walk = walkdir::WalkDir::new(path); @@ -69,13 +69,17 @@ impl Minimizer { .inspect(|file| { info!("Collecting file: {}", file.path.display()); }) - .collect(); + .collect::>(); - Self { + if files.is_empty() { + bail!("Did not find any files for path {}", path.display()); + } + + Ok(Self { files, build, options, - } + }) } pub(crate) fn run_passes<'a>( diff --git a/tests/helper.rs b/tests/helper.rs index ff55fc2..aba0aba 100644 --- a/tests/helper.rs +++ b/tests/helper.rs @@ -1,11 +1,51 @@ -use anyhow::Result; +use std::process::Command; + +use anyhow::{bail, Result}; +use cargo_minimize::Options; + +fn canonicalize(code: &str) -> Result { + let ast = syn::parse_file(code)?; + Ok(prettyplease::unparse(&ast)) +} + +pub fn run_test(code: &str, minimizes_to: &str, options: impl FnOnce(&mut Options)) -> Result<()> { + let dir = tempfile::tempdir()?; + + let mut cargo = Command::new("cargo"); + cargo.args(["new", "project"]); + cargo.current_dir(dir.path()); + + let output = cargo.output()?; + if !output.status.success() { + bail!( + "Failed to create cargo project, {}", + String::from_utf8(output.stderr)? + ); + } + + let cargo_dir = dir.path().join("project"); + + let main_rs = cargo_dir.join("src/main.rs"); + + std::fs::write(&main_rs, code)?; + + let mut opts = Options::default(); + + let path = cargo_dir.join("src"); + + opts.project_dir = Some(cargo_dir); + opts.path = path; + options(&mut opts); + + cargo_minimize::minimize(opts)?; + + let minimized_main_rs = std::fs::read_to_string(main_rs)?; + + let actual = canonicalize(&minimized_main_rs)?; + let expectecd = canonicalize(minimizes_to)?; + + assert_eq!(actual, expectecd); -fn run_test(_: &str) -> Result<()> { - let _ = tempfile::tempdir()?; Ok(()) } -#[test] -fn smoke() { - run_test("").unwrap(); -} diff --git a/tests/minimize.rs b/tests/minimize.rs new file mode 100644 index 0000000..56ea273 --- /dev/null +++ b/tests/minimize.rs @@ -0,0 +1,24 @@ +mod helper; + +use anyhow::Result; + +use helper::run_test; + +#[test] +fn hello_world_no_verify() -> Result<()> { + run_test( + r##" + fn main() { + println!("Hello, world!"); + } + "##, + r##" + fn main() { + loop {} + } + "##, + |opts| { + opts.no_verify = true; + }, + ) +}