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::registry::Registry;
11
12/// Parse + plan one oath.
13pub fn plan_oath(name: &str, source: &str, registry: &Registry) -> ExecutionPlan {
14    plan(&parse(name, source), registry)
15}
16
17/// The per-example display names: the innermost heading (or the body-derived
18/// name when there is no heading), de-duplicated with a `[n]` suffix — the rule
19/// the pytest/unittest adapters use, so header-bound rows share their binding
20/// sentence's name.
21pub fn example_names(plan: &ExecutionPlan) -> Vec<String> {
22    let mut seen: HashMap<String, usize> = HashMap::new();
23    plan.examples
24        .iter()
25        .map(|ex| {
26            let base = ex
27                .scope_stack
28                .last()
29                .cloned()
30                .unwrap_or_else(|| ex.name.clone());
31            let idx = *seen.get(&base).unwrap_or(&0);
32            seen.insert(base.clone(), idx + 1);
33            if idx == 0 {
34                base
35            } else {
36                format!("{base}[{idx}]")
37            }
38        })
39        .collect()
40}
41
42/// Run a single example by index. `context_factory` maps a step file to its
43/// fresh initial state.
44pub fn run_example(
45    plan: &ExecutionPlan,
46    context_factory: &dyn Fn(&str) -> Rc<dyn Any>,
47    index: usize,
48) -> Result<(), StepFailure> {
49    let ports = ExecutePorts {
50        reporter: Box::new(|_| {}),
51        create_context: Some(Box::new(|file: &str| context_factory(file))),
52        observer: None,
53    };
54    collect_examples(plan, &ports)[index].run()
55}