Skip to main content

varar_runner/
run.rs

1//! Planning and running examples, plus the adapter display-name rule.
2
3use std::any::Any;
4use std::collections::HashMap;
5use std::rc::Rc;
6use varar_core::error::StepFailure;
7use varar_core::execute::{ExecutePorts, collect_examples};
8use varar_core::parse::parse;
9use varar_core::plan::{ExecutionPlan, plan};
10use varar_core::reference::OathWorkspace;
11use varar_core::registry::Registry;
12
13/// Plans one oath. `workspace` carries every other oath in the project plus the
14/// sections a reference block consumes (ADR 0016); it is required because an
15/// adapter that omitted it would run consumed sections as standalone examples,
16/// which is green and wrong.
17pub fn plan_oath(
18    name: &str,
19    source: &str,
20    registry: &Registry,
21    workspace: &OathWorkspace,
22) -> ExecutionPlan {
23    plan(&parse(name, source), registry, workspace)
24}
25
26/// The per-example display names: the innermost heading (or the body-derived
27/// name when there is no heading), de-duplicated with a `[n]` suffix — the rule
28/// the pytest/unittest adapters use, so header-bound rows share their binding
29/// sentence's name.
30pub fn example_names(plan: &ExecutionPlan) -> Vec<String> {
31    let mut seen: HashMap<String, usize> = HashMap::new();
32    plan.examples
33        .iter()
34        .map(|ex| {
35            let base = ex
36                .scope_stack
37                .last()
38                .cloned()
39                .unwrap_or_else(|| ex.name.clone());
40            let idx = *seen.get(&base).unwrap_or(&0);
41            seen.insert(base.clone(), idx + 1);
42            if idx == 0 {
43                base
44            } else {
45                format!("{base}[{idx}]")
46            }
47        })
48        .collect()
49}
50
51/// Run a single example by index. `context_factory` maps a step file to its
52/// fresh initial state.
53pub fn run_example(
54    plan: &ExecutionPlan,
55    context_factory: &dyn Fn(&str) -> Rc<dyn Any>,
56    index: usize,
57) -> Result<(), StepFailure> {
58    let ports = ExecutePorts {
59        reporter: Box::new(|_| {}),
60        create_context: Some(Box::new(|file: &str| context_factory(file))),
61        observer: None,
62    };
63    collect_examples(plan, &ports)[index].run()
64}