use super::*;
pub(super) const IF_DIRECTIVE_CHAIN: &str =
include_str!("../../../fixtures/preproc/preproc_chain_interrupt_if.cs");
const IFELSE_DIRECTIVE_CHAIN: &str =
include_str!("../../../fixtures/preproc/preproc_chain_interrupt_ifelse.cs");
const NESTED_IF_DIRECTIVE_CHAIN_CONTROL: &str =
include_str!("../../../fixtures/preproc/preproc_chain_interrupt_nested_control.cs");
const WHOLESTMT_DIRECTIVE_CONTROL: &str =
include_str!("../../../fixtures/preproc/preproc_chain_wholestmt_control.cs");
fn uses_member_refs(e: &Extraction) -> Vec<(&str, &str, usize)> {
e.refs
.iter()
.filter(|r| r.kind == "uses-member")
.map(|r| (r.name.as_str(), r.member.as_deref().unwrap_or(""), r.line))
.collect()
}
#[test]
fn preproc_if_arm_inside_a_chain_is_not_indexed_and_the_chain_continues() {
let e = extract_src(IF_DIRECTIVE_CHAIN);
let refs = uses_member_refs(&e);
assert!(!refs.iter().any(|(_, member, _)| *member == "Debug"));
assert!(!refs.iter().any(|(name, _, _)| *name == "WriteTo"));
assert_eq!(
refs,
vec![
("e", "Level", 9),
("Level", "Error", 9),
("Interval", "Day", 13),
("Level", "Information", 20),
("Level", "Information", 21),
]
);
}
#[test]
fn preproc_ifelse_group_drops_the_dead_arm_and_leaves_the_chain_tail_intact() {
let e = extract_src(IFELSE_DIRECTIVE_CHAIN);
let refs = uses_member_refs(&e);
assert!(!refs.iter().any(|(_, member, _)| *member == "Trace"));
assert!(!refs.iter().any(|(_, member, _)| *member == "Console"));
assert_eq!(refs, vec![("Level", "Information", 17)]);
}
#[test]
fn preproc_nested_if_in_if_leaves_the_whole_inner_group_absent() {
let e = extract_src(NESTED_IF_DIRECTIVE_CHAIN_CONTROL);
let refs = uses_member_refs(&e);
assert!(!refs.iter().any(|(_, member, _)| *member == "Trace"));
assert!(!refs.iter().any(|(_, member, _)| *member == "Debug"));
assert_eq!(refs, vec![("Level", "Information", 18)]);
}
#[test]
fn preproc_if_wrapping_a_whole_statement_removes_only_the_guarded_call() {
let e = extract_src(WHOLESTMT_DIRECTIVE_CONTROL);
let refs = uses_member_refs(&e);
assert_eq!(refs, vec![("registry", "Attach", 7)]);
}
const NAMESPACE_SELECTION_SRC: &str =
include_str!("../../../fixtures/preproc/preproc_namespace_selection.cs");
#[test]
fn preproc_namespace_selection_indexes_only_the_active_arm() {
let e = extract_src(NAMESPACE_SELECTION_SRC);
assert_eq!(e.defs.len(), 7);
let expected: Vec<(&str, &str, usize)> = vec![
("Fixtures.Preproc.Lattice.LatticeCompiler", "class", 9),
(
"Fixtures.Preproc.Lattice.LatticeCompiler+EmitMode",
"enum",
18,
),
(
"Fixtures.Preproc.Lattice.LatticeCompiler+EmitMode.Direct",
"enum-member",
20,
),
(
"Fixtures.Preproc.Lattice.LatticeCompiler+EmitMode.Delegated",
"enum-member",
21,
),
("Fixtures.Preproc.Lattice.LatticeEmitter", "class", 25),
("Fixtures.Preproc.Lattice.Closure", "class", 33),
("Fixtures.Preproc.Lattice.Expression", "class", 38),
];
for (id, kind, line) in &expected {
let d = find_def(&e, id).unwrap_or_else(|| panic!("def {id} present"));
assert_eq!(d.kind, *kind, "{id} kind");
assert_eq!(d.line, *line, "{id} line");
assert_eq!(d.namespace, "Fixtures.Preproc.Lattice", "{id} namespace");
}
assert!(e.defs.iter().all(|d| !d.id.contains("LightLattice")));
assert_eq!(e.usings.len(), 1);
match &e.usings[0] {
UsingRecord::Plain { text, global } => {
assert_eq!(text, "Fixtures.Preproc.Lattice.Expression");
assert!(!global);
}
UsingRecord::Alias { .. } => panic!("expected plain form"),
}
assert!(!e.refs.iter().any(|r| r.name.contains("LightLattice")
|| r.qualified
.as_deref()
.unwrap_or("")
.contains("LightLattice")));
}