Skip to main content

varar_core/
failure.rs

1//! Converts a caught step failure into the structured [`ExampleFailure`] payload
2//! — port of `failure.ts` / `Failure.java`. The Java stack-trace-scraping
3//! machinery becomes a structural [`FailureLocation`] lookup by exact path match.
4
5use crate::error::{StepError, StepFailure};
6use crate::result::{CellFailure, ExampleFailure};
7
8/// A caught step failure → the `ExampleResult.failure` payload. `fallback_line`
9/// is used when `failure` carries no location matching `oath_path`.
10pub fn to_failure(failure: &StepFailure, oath_path: &str, fallback_line: i64) -> ExampleFailure {
11    let message = failure.error.message();
12
13    let cells = match &failure.error {
14        StepError::CellMismatch(cells) => {
15            let failing: Vec<CellFailure> = cells
16                .iter()
17                .filter(|c| !c.ok)
18                .map(|c| CellFailure::new(c.span.start_offset, c.span.end_offset, c.actual.clone()))
19                .collect();
20            (!failing.is_empty()).then_some(failing)
21        }
22        _ => None,
23    };
24
25    // The location's path is the oath, or — for a step a reference block
26    // spliced in (ADR 0016) — the document that step was written in. Either way
27    // its line and anchor are the precise ones; `doc_path` says which file they
28    // address.
29    let here = failure.location.as_ref();
30    let line = here.map_or(fallback_line, |l| l.line as i64);
31    let doc_path = here.filter(|l| l.path != oath_path).map(|l| l.path.clone());
32    // The executor recorded the anchor alongside the location, so this is the
33    // failing step's span (or the first mismatched cell's) — what a renderer
34    // underlines instead of the whole line. `None` when the failure carries no
35    // location at all, i.e. it never passed through a step.
36    let anchor = here.map(|l| l.anchor);
37
38    let stack = render_stack(failure);
39    ExampleFailure {
40        line,
41        message,
42        stack,
43        cells,
44        anchor,
45        doc_path,
46    }
47}
48
49/// Display-only rendering of the failure's location (the Java `stack` field is
50/// rendered from structural data, not scraped from it).
51fn render_stack(failure: &StepFailure) -> String {
52    match &failure.location {
53        Some(l) => {
54            format!("{}\n    at {} ({}:{})", failure.error.message(), l.label, l.path, l.line)
55        }
56        None => failure.error.message(),
57    }
58}