use super::FieldResolver;
use std::collections::{HashMap, HashSet};
fn set(entries: &[&str]) -> HashSet<String> {
entries.iter().map(|s| (*s).to_string()).collect()
}
#[test]
fn accessor_strips_a_prefix_the_ir_recognizes_but_result_fields_omits() {
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&set(&["final_url"]),
&HashSet::new(),
&HashSet::new(),
)
.with_ir_fields(set(&["action_results"]), HashSet::new(), HashSet::new());
assert_eq!(
resolver.result_relative_path("interaction.action_results"),
"action_results",
"control: the shared answer strips the virtual label on the IR's word"
);
assert_eq!(
resolver.accessor("interaction.action_results", "python", "result"),
"result.action_results",
"the accessor must address the same place the shared answer names"
);
}
#[test]
fn accessor_strips_a_prefix_known_only_through_fields_array() {
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&set(&["final_url"]),
&set(&["action_results"]),
&HashSet::new(),
);
assert!(
resolver.is_array("interaction.action_results"),
"control: the classifier calls this a slice"
);
assert_eq!(
resolver.accessor("interaction.action_results", "go", "result"),
"result.ActionResults",
"a path the classifier calls a slice must be emitted as that slice, not as `result.Interaction...`"
);
}
#[test]
fn accessor_still_strips_a_prefix_result_fields_declares() {
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&set(&["action_results", "final_url"]),
&HashSet::new(),
&HashSet::new(),
);
assert_eq!(
resolver.accessor("interaction.action_results", "python", "result"),
"result.action_results"
);
}
#[test]
fn accessor_does_not_strip_a_real_nested_struct_field() {
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&set(&["metrics", "final_url"]),
&HashSet::new(),
&HashSet::new(),
);
assert_eq!(
resolver.result_relative_path("metrics.total_lines"),
"metrics.total_lines",
"control: `metrics` is a declared result field, so it is a real struct step"
);
assert_eq!(
resolver.accessor("metrics.total_lines", "python", "result"),
"result.metrics.total_lines"
);
}
#[test]
fn accessor_does_not_strip_when_result_fields_is_unconfigured() {
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&HashSet::new(),
&set(&["action_results"]),
&HashSet::new(),
);
assert_eq!(
resolver.accessor("interaction.action_results", "python", "result"),
"result.interaction.action_results",
"with no result_fields a virtual label is indistinguishable from a real nested field"
);
}
#[test]
fn accessor_keeps_a_prefix_whose_remainder_no_oracle_recognizes() {
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&set(&["final_url"]),
&HashSet::new(),
&HashSet::new(),
);
assert_eq!(
resolver.result_relative_path("interaction.unknown_thing"),
"interaction.unknown_thing",
"control: the shared answer declines to strip"
);
assert_eq!(
resolver.accessor("interaction.unknown_thing", "python", "result"),
"result.interaction.unknown_thing"
);
}
#[test]
fn rust_unwrap_binding_strips_the_same_prefix_the_accessor_does() {
let resolver = FieldResolver::new(
&HashMap::new(),
&set(&["action_results"]),
&set(&["final_url"]),
&HashSet::new(),
&HashSet::new(),
)
.with_ir_fields(set(&["action_results"]), HashSet::new(), HashSet::new());
let (binding, local) = resolver
.rust_unwrap_binding("interaction.action_results", "result")
.expect("the field is declared optional, so a binding is generated");
assert_eq!(local, "_action_results", "the local is named after the stripped path");
assert!(
binding.contains("result.action_results"),
"expected the stripped accessor in the binding, got: {binding}"
);
}
#[test]
fn accessor_renders_exactly_the_result_relative_path_for_every_shape() {
let mut aliases = HashMap::new();
aliases.insert("results".to_string(), "action_results".to_string());
let resolver = FieldResolver::new(
&aliases,
&HashSet::new(),
&set(&["metrics", "final_url"]),
&HashSet::new(),
&HashSet::new(),
)
.with_ir_fields(set(&["action_results"]), HashSet::new(), HashSet::new());
for field in [
"interaction.action_results",
"metrics.total_lines",
"interaction.unknown_thing",
"final_url",
"results",
] {
let expected = format!("result.{}", resolver.result_relative_path(field));
assert_eq!(
resolver.accessor(field, "python", "result"),
expected,
"accessor and result_relative_path disagree about where `{field}` lives"
);
}
}
#[test]
fn accessor_declines_to_strip_onto_a_field_the_ir_marks_binding_excluded() {
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&set(&["action_results", "final_url"]),
&HashSet::new(),
&HashSet::new(),
)
.with_ir_fields(HashSet::new(), set(&["action_results"]), HashSet::new());
assert_eq!(
resolver.result_relative_path("interaction.action_results"),
"interaction.action_results",
"control: the IR overrides the contradicting result_fields entry"
);
assert_eq!(
resolver.accessor("interaction.action_results", "python", "result"),
"result.interaction.action_results",
"the accessor must not keep a private answer for a config state the resolver rejects"
);
}