use super::*;
use crate::registry::TypeEntry;
#[test]
fn final_invariant_reports_unresolved_field_of_unresolved_struct() {
use crate::registry::{Registry, TypeKey};
let mut reg: Registry<()> =
crate::test_util::scanned_with(&["pub struct Outer { pub inner: ZKeyExpr }"]);
let outer = reg
.intern(
crate::registry::Direction::Input,
&syn::parse_quote!(Outer),
true,
)
.expect("fixture type");
reg.require_input(&outer);
let zke_key = TypeKey::parse("ZKeyExpr").expect("test type");
assert!(!reg.input_types[&zke_key].root, "the field is not a root");
let err = check_complete(®).expect_err("must surface unresolved");
let ResolveError::Unresolved { entries } = err;
let reported: std::collections::HashSet<String> =
entries.iter().map(|e| e.key.to_string()).collect();
assert!(
reported.contains("Outer"),
"expected `Outer` in report, got {:?}",
reported
);
assert!(
reported.contains("ZKeyExpr"),
"expected `ZKeyExpr` (transitively unresolved via Outer.inner) in report, got {:?}",
reported
);
}
#[test]
fn final_invariant_stops_at_resolved_nodes() {
use crate::registry::{Direction, Registry, TypeEntry};
let mut reg: Registry<()> = crate::test_util::scanned_with(&[
"pub struct Outer { pub inner: Inner }",
"pub struct Inner { pub unused: Unrelated }",
]);
let outer_ty: syn::Type = syn::parse_quote!(Outer);
let inner_ty: syn::Type = syn::parse_quote!(Inner);
let unrelated_ty: syn::Type = syn::parse_quote!(Unrelated);
reg.insert_crossing(Direction::Input, &outer_ty, true, None);
reg.insert_crossing(
Direction::Input,
&inner_ty,
false,
Some(TypeEntry {
destination: syn::parse_quote!(i64),
function: syn::parse_quote!(
fn __dummy() {}
),
pre_stages: vec![],
subs: vec![],
niches: crate::niches::Niches::empty(),
metadata: (),
}),
);
reg.insert_crossing(Direction::Input, &unrelated_ty, false, None);
let err = check_complete(®).expect_err("must surface Outer");
let ResolveError::Unresolved { entries } = err;
let reported: std::collections::HashSet<String> =
entries.iter().map(|e| e.key.to_string()).collect();
assert!(reported.contains("Outer"));
assert!(!reported.contains("Inner"));
assert!(
!reported.contains("Unrelated"),
"BFS must stop at resolved nodes, got report: {:?}",
reported
);
let _ = Direction::Input; }
#[test]
fn a_type_reachable_only_through_subs_must_still_resolve() {
use crate::registry::{Registry, TypeKey};
let mut reg: Registry<()> = Registry::empty();
let outer: syn::Type = syn::parse_quote!(Outer);
let mid: syn::Type = syn::parse_quote!(Mid);
reg.insert_crossing(
Direction::Input,
&outer,
true,
Some(TypeEntry {
destination: syn::parse_quote!(i64),
function: syn::parse_quote!(
fn __outer() {}
),
pre_stages: vec![],
subs: vec![TypeKey::from_type(&mid)],
niches: crate::niches::Niches::empty(),
metadata: (),
}),
);
reg.insert_crossing(Direction::Input, &mid, false, None);
let err = check_complete(®).expect_err("Mid must be reported");
let ResolveError::Unresolved { entries } = err;
let reported: std::collections::HashSet<String> =
entries.iter().map(|e| e.key.to_string()).collect();
assert_eq!(reported, ["Mid".to_string()].into_iter().collect());
}