diff --git a/src/cli.rs b/src/cli.rs index 6926084..0e08daf 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -216,7 +216,7 @@ Hint: Try using `--pairs {name}_calls_rustc` or `--pairs rustc_calls_{name}`. let filter_layer = EnvFilter::try_from_default_env() .or_else(|_| EnvFilter::try_new("info")) - .unwrap(); + .expect("failed to initialize logger"); let logger = crate::log::MapLogger::new(); tracing_subscriber::registry() diff --git a/src/error.rs b/src/error.rs index a468730..28ac108 100644 --- a/src/error.rs +++ b/src/error.rs @@ -61,8 +61,8 @@ pub enum BuildError { #[error("io error\n{0}")] Io(#[from] std::io::Error), #[error("rust compile error \n{} \n{}", - std::str::from_utf8(&.0.stdout).unwrap(), - std::str::from_utf8(&.0.stderr).unwrap())] + String::from_utf8_lossy(&.0.stdout), + String::from_utf8_lossy(&.0.stderr))] RustCompile(std::process::Output), #[error("c compile error\n{0}")] CCompile(#[from] cc::Error), @@ -125,8 +125,8 @@ pub enum LinkError { #[error("io error\n{0}")] Io(#[from] std::io::Error), #[error("rust link error \n{} \n{}", - std::str::from_utf8(&.0.stdout).unwrap(), - std::str::from_utf8(&.0.stderr).unwrap())] + String::from_utf8_lossy(&.0.stdout), + String::from_utf8_lossy(&.0.stderr))] RustLink(std::process::Output), } diff --git a/src/fivemat.rs b/src/fivemat.rs index a4936fa..660cf12 100644 --- a/src/fivemat.rs +++ b/src/fivemat.rs @@ -17,6 +17,27 @@ pub struct Fivemat<'a> { out: &'a mut dyn Write, } +pub struct FivematIndent<'a, 'b> { + inner: &'b mut Fivemat<'a>, + count: usize, +} +impl Drop for FivematIndent<'_, '_> { + fn drop(&mut self) { + self.inner.sub_indent(self.count); + } +} +impl<'a, 'b> std::ops::Deref for FivematIndent<'a, 'b> { + type Target = Fivemat<'a>; + fn deref(&self) -> &Fivemat<'a> { + self.inner + } +} +impl<'a, 'b> std::ops::DerefMut for FivematIndent<'a, 'b> { + fn deref_mut(&mut self) -> &mut Fivemat<'a> { + self.inner + } +} + impl<'a> Fivemat<'a> { pub fn new(out: &'a mut dyn Write, indent_text: impl Into) -> Self { Fivemat { @@ -26,6 +47,14 @@ impl<'a> Fivemat<'a> { out, } } + pub fn indent<'b>(&'b mut self) -> FivematIndent<'a, 'b> { + self.indent_many(1) + } + pub fn indent_many<'b>(&'b mut self, count: usize) -> FivematIndent<'a, 'b> { + self.add_indent(count); + FivematIndent { inner: self, count } + } + pub fn add_indent(&mut self, count: usize) { self.indent += count; } diff --git a/src/harness/check.rs b/src/harness/check.rs index e5be8f1..38cf7f5 100644 --- a/src/harness/check.rs +++ b/src/harness/check.rs @@ -134,8 +134,8 @@ impl TestHarness { let caller_tag = load_tag(caller_val); let callee_tag = load_tag(callee_val); - if caller_tag != expected_tag || callee_tag != expected_tag { - let expected = tagged_variant_name(tagged_ty, expected_tag); + if caller_tag != Some(expected_tag) || callee_tag != Some(expected_tag) { + let expected = tagged_variant_name(tagged_ty, Some(expected_tag)); let caller = tagged_variant_name(tagged_ty, caller_tag); let callee = tagged_variant_name(tagged_ty, callee_tag); return Err(tag_error(types, &expected_val, expected, caller, callee)); @@ -145,8 +145,8 @@ impl TestHarness { let caller_tag = load_tag(caller_val); let callee_tag = load_tag(callee_val); - if caller_tag != expected_tag || callee_tag != expected_tag { - let expected = enum_variant_name(enum_ty, expected_tag); + if caller_tag != Some(expected_tag) || callee_tag != Some(expected_tag) { + let expected = enum_variant_name(enum_ty, Some(expected_tag)); let caller = enum_variant_name(enum_ty, caller_tag); let callee = enum_variant_name(enum_ty, callee_tag); return Err(tag_error(types, &expected_val, expected, caller, callee)); @@ -156,8 +156,8 @@ impl TestHarness { let caller_tag = load_tag(caller_val); let callee_tag = load_tag(callee_val); - if caller_tag != expected_tag || callee_tag != expected_tag { - let expected = bool_variant_name(expected_tag, expected_tag); + if caller_tag != Some(expected_tag) || callee_tag != Some(expected_tag) { + let expected = bool_variant_name(expected_tag, Some(expected_tag)); let caller = bool_variant_name(expected_tag, caller_tag); let callee = bool_variant_name(expected_tag, callee_tag); return Err(tag_error(types, &expected_val, expected, caller, callee)); @@ -189,11 +189,16 @@ impl TestHarness { } } -fn load_tag(val: &ValBuffer) -> usize { - u32::from_ne_bytes(<[u8; 4]>::try_from(&val.bytes[..4]).unwrap()) as usize +fn load_tag(val: &ValBuffer) -> Option { + let buf = val.bytes.get(..4)?; + let bytes = <[u8; 4]>::try_from(buf).ok()?; + Some(u32::from_ne_bytes(bytes) as usize) } -fn tagged_variant_name(tagged_ty: &kdl_script::types::TaggedTy, tag: usize) -> String { +fn tagged_variant_name(tagged_ty: &kdl_script::types::TaggedTy, tag: Option) -> String { + let Some(tag) = tag else { + return "".to_owned(); + }; let tagged_name = &tagged_ty.name; let variant_name = tagged_ty .variants @@ -203,7 +208,10 @@ fn tagged_variant_name(tagged_ty: &kdl_script::types::TaggedTy, tag: usize) -> S format!("{tagged_name}::{variant_name}") } -fn enum_variant_name(enum_ty: &kdl_script::types::EnumTy, tag: usize) -> String { +fn enum_variant_name(enum_ty: &kdl_script::types::EnumTy, tag: Option) -> String { + let Some(tag) = tag else { + return "".to_owned(); + }; let enum_name = &enum_ty.name; let variant_name = enum_ty .variants @@ -213,7 +221,10 @@ fn enum_variant_name(enum_ty: &kdl_script::types::EnumTy, tag: usize) -> String format!("{enum_name}::{variant_name}") } -fn bool_variant_name(expected_tag: usize, tag: usize) -> String { +fn bool_variant_name(expected_tag: usize, tag: Option) -> String { + let Some(tag) = tag else { + return "".to_owned(); + }; // Because we're using the tag variant machinery, this code is a bit weird, // because we essentially get passed Option for `tag`, where we get // None when the wrong path is taken. diff --git a/src/harness/read/procgen.rs b/src/harness/read/procgen.rs index 5be07f9..90e668b 100644 --- a/src/harness/read/procgen.rs +++ b/src/harness/read/procgen.rs @@ -1,6 +1,6 @@ pub fn procgen_test_for_ty_string(ty_name: &str, ty_def: Option<&str>) -> String { let mut test_body = String::new(); - procgen_test_for_ty_impl(&mut test_body, ty_name, ty_def).unwrap(); + procgen_test_for_ty_impl(&mut test_body, ty_name, ty_def).expect("failed to format procgen!?"); test_body } diff --git a/src/harness/run.rs b/src/harness/run.rs index 0d8e4f9..f0e8cc8 100644 --- a/src/harness/run.rs +++ b/src/harness/run.rs @@ -118,7 +118,10 @@ fn run_dynamic_test(test_dylib: &LinkOutput, _full_test_name: &str) -> Result Self { Self::default() } + /* pub fn clear(&self) { - let mut log = self.state.lock().unwrap(); + let mut log = self.state.lock().ok()?; let ids = log.sub_spans.keys().cloned().collect::>(); for id in ids { - let span = log.sub_spans.get_mut(&id).unwrap(); + let span = log.sub_spans.get_mut(&id)?; if !span.destroyed { span.events.clear(); continue; @@ -85,23 +86,25 @@ impl MapLogger { } log.root_span.events.clear(); log.cur_string = None; + Some(()) } - - fn print_span_if_test(&self, span_id: &Id) { + */ + fn print_span_if_test(&self, span_id: &Id) -> Result<(), std::fmt::Error> { let span = { let log = self.state.lock().unwrap(); let Some(span) = log.live_spans.get(span_id) else { - return; + return Ok(()); }; if !log.test_spans.contains(span) { - return; + return Ok(()); } *span }; - eprintln!("{}", self.string_for_span(span)); + eprintln!("{}", self.string_for_span(span)?); + Ok(()) } - pub fn string_for_span(&self, span: SpanId) -> Arc { + pub fn string_for_span(&self, span: SpanId) -> Result, std::fmt::Error> { self.string_query(Query::Span(span)) } /* @@ -151,29 +154,29 @@ impl MapLogger { } } */ - fn string_query(&self, query: Query) -> Arc { + fn string_query(&self, query: Query) -> Result, std::fmt::Error> { use std::fmt::Write; - fn print_indent(output: &mut String, depth: usize) { - write!(output, "{:indent$}", "", indent = depth * 4).unwrap(); + fn print_indent(output: &mut String, depth: usize) -> Result<(), std::fmt::Error> { + write!(output, "{:indent$}", "", indent = depth * 4) } fn print_span_recursive( f: &mut Fivemat, sub_spans: &LinkedHashMap, span: &SpanEntry, range: Option>, - ) { + ) -> Result<(), std::fmt::Error> { if !span.name.is_empty() { let style = Style::new().blue(); - write!(f, "{}", style.apply_to(&span.name)).unwrap(); + write!(f, "{}", style.apply_to(&span.name))?; for (key, val) in &span.fields { if key == "id" { - write!(f, " {}", style.apply_to(val)).unwrap(); + write!(f, " {}", style.apply_to(val))?; } else { - write!(f, "{key}: {val}").unwrap(); + write!(f, "{key}: {val}")?; } } - writeln!(f).unwrap(); + writeln!(f)?; } let event_range = if let Some(range) = range { @@ -181,26 +184,26 @@ impl MapLogger { } else { &span.events[..] }; - f.add_indent(1); + let mut f = f.indent(); for event in event_range { match event { EventEntry::Message(event) => { if event.fields.contains_key("message") { - print_event(f, event); + print_event(&mut f, event)?; } } EventEntry::Span(sub_span) => { - print_span_recursive(f, sub_spans, &sub_spans[sub_span], None); + print_span_recursive(&mut f, sub_spans, &sub_spans[sub_span], None)?; } } } - f.sub_indent(1); + Ok(()) } let mut log = self.state.lock().unwrap(); if Some(query) == log.last_query { if let Some(string) = &log.cur_string { - return string.clone(); + return Ok(string.clone()); } } log.last_query = Some(query); @@ -213,22 +216,23 @@ impl MapLogger { Query::Span(span_id) => (&log.sub_spans[&span_id], None), }; - print_span_recursive(&mut f, &log.sub_spans, span_to_print, range); + print_span_recursive(&mut f, &log.sub_spans, span_to_print, range)?; let result = Arc::new(output_buf); log.cur_string = Some(result.clone()); - result + Ok(result) } } -fn immediate_event(event: &MessageEntry) { +fn immediate_event(event: &MessageEntry) -> std::fmt::Result { let mut output = String::new(); let mut f = Fivemat::new(&mut output, INDENT); - print_event(&mut f, event); + print_event(&mut f, event)?; eprintln!("{}", output); + Ok(()) } -fn print_event(f: &mut Fivemat, event: &MessageEntry) { +fn print_event(f: &mut Fivemat, event: &MessageEntry) -> Result<(), std::fmt::Error> { use std::fmt::Write; if let Some(message) = event.fields.get("message") { let style = match event.level { @@ -238,9 +242,10 @@ fn print_event(f: &mut Fivemat, event: &MessageEntry) { Level::DEBUG => Style::new().blue(), Level::TRACE => Style::new().green(), }; - // writeln!(output, "[{:5}] {}", event.level, message).unwrap(); - writeln!(f, "{}", style.apply_to(message)).unwrap(); + // writeln!(output, "[{:5}] {}", event.level, message)?; + writeln!(f, "{}", style.apply_to(message))?; } + Ok(()) } impl Layer for MapLogger @@ -277,7 +282,7 @@ where target: target.to_owned(), }; if is_root { - immediate_event(&event); + immediate_event(&event).ok(); } cur_span.events.push(EventEntry::Message(event)); } @@ -332,7 +337,7 @@ where fn on_close(&self, id: Id, _ctx: tracing_subscriber::layer::Context<'_, S>) { // Mark the span as GC-able and remove it from the live mappings, // as tracing may now recycle the id for future spans! - self.print_span_if_test(&id); + self.print_span_if_test(&id).ok(); let mut log = self.state.lock().unwrap(); let Some(&span_id) = log.live_spans.get(&id) else { // Skipped span, ignore diff --git a/src/main.rs b/src/main.rs index f7fe651..e0e7849 100644 --- a/src/main.rs +++ b/src/main.rs @@ -215,9 +215,9 @@ fn main() -> Result<(), Box> { let mut output = std::io::stdout(); match cfg.output_format { - OutputFormat::Human => full_report.print_human(&harness, &mut output).unwrap(), - OutputFormat::Json => full_report.print_json(&harness, &mut output).unwrap(), - OutputFormat::RustcJson => full_report.print_rustc_json(&harness, &mut output).unwrap(), + OutputFormat::Human => full_report.print_human(&harness, &mut output)?, + OutputFormat::Json => full_report.print_json(&harness, &mut output)?, + OutputFormat::RustcJson => full_report.print_rustc_json(&harness, &mut output)?, } if full_report.failed() { diff --git a/src/report.rs b/src/report.rs index f82d067..958ab43 100644 --- a/src/report.rs +++ b/src/report.rs @@ -349,40 +349,16 @@ impl FullReport { write!(f, "{}", red.apply_to("failed"))?; if test.results.ran_to < TestRunMode::Check { let (msg, err) = match &test.results.ran_to { - TestRunMode::Generate => ( - "generate source code", - format!( - "{}", - test.results - .source - .as_ref() - .unwrap() - .as_ref() - .err() - .unwrap() - ), - ), - TestRunMode::Build => ( - "compile source code", - format!( - "{}", - test.results.build.as_ref().unwrap().as_ref().err().unwrap() - ), - ), - TestRunMode::Link => ( - "link both sides together", - format!( - "{}", - test.results.link.as_ref().unwrap().as_ref().err().unwrap() - ), - ), - TestRunMode::Run => ( - "run the program", - format!( - "{}", - test.results.run.as_ref().unwrap().as_ref().err().unwrap() - ), - ), + TestRunMode::Generate => { + ("generate source code", format_err(&test.results.source)) + } + TestRunMode::Build => { + ("compile source code", format_err(&test.results.build)) + } + TestRunMode::Link => { + ("link both sides together", format_err(&test.results.link)) + } + TestRunMode::Run => ("run the program", format_err(&test.results.run)), TestRunMode::Skip | TestRunMode::Check => ("", String::new()), }; write!(f, "{}", red.apply_to(" to "))?; @@ -412,7 +388,9 @@ impl FullReport { writeln!(f)?; continue; } - let check_result = test.results.check.as_ref().unwrap(); + let Some(check_result) = &test.results.check else { + continue; + }; let sub_results = &check_result.subtest_checks; let num_passed = sub_results.iter().filter(|r| r.is_ok()).count(); @@ -537,3 +515,13 @@ impl FullReport { self.summary.num_failed > 0 } } + +fn format_err(maybe_res: &Option>) -> String { + let Some(res) = maybe_res else { + return String::new(); + }; + let Some(res) = res.as_ref().err() else { + return String::new(); + }; + format!("{res}") +} diff --git a/src/toolchains/c.rs b/src/toolchains/c.rs index 53cb377..61e31c1 100644 --- a/src/toolchains/c.rs +++ b/src/toolchains/c.rs @@ -322,13 +322,6 @@ impl CcToolchain { out_dir: &Utf8Path, lib_name: &str, ) -> Result { - /* - let out_sub = src_path.parent().unwrap(); - let ensure_out = out_dir.join(out_sub); - std::fs::create_dir_all(ensure_out).unwrap(); - info!("out: {}", out_dir); - info!("lib: {}", lib_name); - */ let mut build = cc::Build::new(); for flag in self.extra_flags() { build.flag(flag); @@ -366,15 +359,13 @@ impl CcToolchain { .arg(&obj_path) .arg("-c") .arg(src_path) - .status() - .unwrap(); + .status()?; Command::new("ar") .arg("cq") .arg(&lib_path) .arg(&obj_path) - .status() - .unwrap(); - Command::new("ar").arg("s").arg(&lib_path).status().unwrap(); + .status()?; + Command::new("ar").arg("s").arg(&lib_path).status()?; Ok(String::from(lib_name)) } @@ -397,15 +388,13 @@ impl CcToolchain { .arg(&obj_path) .arg("-c") .arg(src_path) - .status() - .unwrap(); + .status()?; Command::new("ar") .arg("cq") .arg(&lib_path) .arg(&obj_path) - .status() - .unwrap(); - Command::new("ar").arg("s").arg(&lib_path).status().unwrap(); + .status()?; + Command::new("ar").arg("s").arg(&lib_path).status()?; Ok(String::from(lib_name)) }