use concinnity_cook::check::fault::Step as FaultStep;
use super::outline::Row;
use super::path::{Path, Step};
pub(crate) fn to_path(at: &[FaultStep]) -> Path {
at.iter()
.map(|step| match step {
FaultStep::Field(name) => Step::Field(name.clone()),
FaultStep::Index(i) => Step::Index(*i),
})
.collect()
}
pub(crate) fn row_of(rows: &[Row], path: &[Step]) -> Option<usize> {
(0..=path.len())
.rev()
.find_map(|n| rows.iter().position(|r| r.path == path[..n]))
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::super::outline;
use super::*;
fn steps(parts: &[&str]) -> Vec<FaultStep> {
parts
.iter()
.map(|s| match s.parse::<usize>() {
Ok(i) => FaultStep::Index(i),
Err(_) => FaultStep::Field(s.to_string()),
})
.collect()
}
fn at(parts: &[&str]) -> Path {
to_path(&steps(parts))
}
fn sample() -> Vec<Row> {
outline::rows(&json!({
"on": "tick",
"scope": ["Prop"],
"do": [
{"if": {"cond": {"bool": true}, "then": [{"hide": {"target": "self"}}]}},
{"save": {}},
],
}))
}
#[test]
fn an_addressed_value_resolves_to_its_own_row() {
let rows = sample();
let cond = row_of(&rows, &at(&["do", "0", "if", "cond"])).expect("the cond row");
assert_eq!(rows[cond].label, "cond");
let node = row_of(&rows, &at(&["do", "1"])).expect("the second node's row");
assert_eq!(rows[node].label, "save");
}
#[test]
fn an_unaddressed_value_settles_for_the_row_containing_it() {
let rows = outline::rows(&json!({"on": "start", "do": [{"teleport": {}}]}));
let node = row_of(&rows, &at(&["do", "0", "teleport"])).expect("the node's row");
assert_eq!(
rows[node].path,
vec![Step::Field("do".into()), Step::Index(0)]
);
}
#[test]
fn a_location_pointing_nowhere_at_all_falls_back_to_the_whole_asset() {
let rows = sample();
assert_eq!(row_of(&rows, &at(&["nonsense", "4"])), None);
assert_eq!(row_of(&[], &at(&["do", "0"])), None);
}
#[test]
fn hop_kinds_carry_across_unchanged() {
assert_eq!(
to_path(&steps(&["do", "2", "if"])),
vec![
Step::Field("do".into()),
Step::Index(2),
Step::Field("if".into()),
],
);
assert!(to_path(&[]).is_empty());
}
}