diff --git a/src/main.rs b/src/main.rs index d026aded..33490cfb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use function_runner::{BytesContainer, BytesContainerType, Codec}; +use serde::Serialize; use wasmtime::Module; use std::{ @@ -69,6 +70,10 @@ struct Opts { /// In batch mode, continue processing on individual input errors (default: false) #[clap(long)] batch_continue_on_error: bool, + + /// In batch mode, emit the full FunctionRunResult for each input (default: minimal output) + #[clap(long)] + batch_full_output: bool, } impl Opts { @@ -213,6 +218,29 @@ fn run_single_mode( } } +#[derive(Serialize)] +struct MinimalBatchRunResult<'a> { + success: bool, + instructions: u64, + memory_usage: u64, + logs: &'a str, + output: &'a BytesContainer, +} + +impl<'a> From<&'a function_runner::function_run_result::FunctionRunResult> + for MinimalBatchRunResult<'a> +{ + fn from(result: &'a function_runner::function_run_result::FunctionRunResult) -> Self { + Self { + success: result.success, + instructions: result.instructions, + memory_usage: result.memory_usage, + logs: &result.logs, + output: &result.output, + } + } +} + fn run_batch_mode( opts: &Opts, engine: &wasmtime::Engine, @@ -338,8 +366,12 @@ fn run_batch_mode( } // Use compact JSON (not pretty-printed) for JSONL format - let compact_json = serde_json::to_string(&function_result) - .unwrap_or_else(|error| error.to_string()); + let compact_json = if opts.batch_full_output { + serde_json::to_string(&function_result) + } else { + serde_json::to_string(&MinimalBatchRunResult::from(&function_result)) + } + .unwrap_or_else(|error| error.to_string()); println!("{}", compact_json); if !function_succeeded && !opts.batch_continue_on_error { diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index e58de3bf..fb636847 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -88,6 +88,11 @@ mod tests { assert_eq!(results[0]["success"], true); assert_eq!(results[1]["success"], false); assert_eq!(results[2]["success"], true); + assert_eq!(results[0]["output"], json!({"exit": 0})); + assert!(results[0].get("instructions").is_some()); + assert!(results[0].get("input").is_none()); + assert!(results[0].get("name").is_none()); + assert!(results[0].get("size").is_none()); assert_eq!( String::from_utf8(output.stderr)?, @@ -97,6 +102,36 @@ mod tests { Ok(()) } + #[test] + fn batch_full_output_includes_input_and_function_metadata() -> Result<()> { + let mut cmd = Command::new(cargo_bin!()); + let input_file = temp_batch_input("{\"code\":0}\n")?; + + cmd.args(["--function", "tests/fixtures/build/exit_code.wasm"]) + .arg("--batch") + .arg("--batch-full-output") + .arg("--input") + .arg(input_file.as_os_str()); + + let output = cmd.output()?; + + assert!(output.status.success()); + + let stdout = String::from_utf8(output.stdout)?; + let results = stdout + .lines() + .map(serde_json::from_str::) + .collect::, _>>()?; + assert_eq!(results.len(), 1); + assert_eq!(results[0]["success"], true); + assert_eq!(results[0]["input"], json!({"code": 0})); + assert_eq!(results[0]["output"], json!({"exit": 0})); + assert_eq!(results[0]["name"], "exit_code.wasm"); + assert!(results[0].get("size").is_some()); + + Ok(()) + } + #[test] fn batch_stops_on_function_failure_by_default() -> Result<()> { let mut cmd = Command::new(cargo_bin!());