use super::*;
const DUPLICATE_HEADER_HOST_SRC: &str = "
namespace Fixtures.Preproc
{
public static class WidgetCompiler
{
private static readonly int[] _pool = new int[8];
#if WIDGET_V2
private static int[] ComputeOffsets(IWidgetProvider items)
{
var count = items.WidgetCount;
#else
private static int[] ComputeOffsets(IReadOnlyList<Widget> items)
{
var count = items.Count;
#endif
if (count == 0)
return _pool;
return _pool;
}
private struct SlotInfo
{
public object Payload;
}
[System.Flags]
private enum SlotStatus : byte
{
Empty = 0,
Filled = 1,
}
}
}
";
#[test]
fn duplicate_header_keeps_nested_type_defs_at_their_real_scope() {
let e = extract_src(DUPLICATE_HEADER_HOST_SRC);
assert!(find_def(&e, "Fixtures.Preproc.WidgetCompiler").is_some());
let slot_info = find_def(&e, "Fixtures.Preproc.WidgetCompiler+SlotInfo")
.expect("SlotInfo kept, nested under its type");
assert_eq!(slot_info.kind, "struct");
assert_eq!(slot_info.namespace, "Fixtures.Preproc");
let slot_status =
find_def(&e, "Fixtures.Preproc.WidgetCompiler+SlotStatus").expect("SlotStatus kept");
assert_eq!(slot_status.kind, "enum");
assert!(find_def(&e, "Fixtures.Preproc.WidgetCompiler+SlotStatus.Empty").is_some());
assert!(find_def(&e, "Fixtures.Preproc.WidgetCompiler+SlotStatus.Filled").is_some());
assert!(!e
.refs
.iter()
.any(|r| r.kind == "uses-type" && r.name == "IWidgetProvider"));
assert!(!e
.refs
.iter()
.any(|r| r.member.as_deref() == Some("WidgetCount")));
assert!(e
.refs
.iter()
.any(|r| r.kind == "uses-type" && r.name == "IReadOnlyList"));
assert!(e
.refs
.iter()
.any(|r| r.kind == "uses-type" && r.name == "Widget"));
assert!(e
.refs
.iter()
.any(|r| r.kind == "uses-member" && r.member.as_deref() == Some("Count")));
}
#[test]
fn defs_and_refs_stay_in_ascending_line_order_when_an_if_group_is_blanked() {
let e = extract_src(DUPLICATE_HEADER_HOST_SRC);
let def_lines: Vec<usize> = e.defs.iter().map(|d| d.line).collect();
let mut sorted = def_lines.clone();
sorted.sort();
assert_eq!(
def_lines, sorted,
"defs must already be in ascending line order"
);
let ref_lines: Vec<usize> = e.refs.iter().map(|r| r.line).collect();
let mut sorted_refs = ref_lines.clone();
sorted_refs.sort();
assert_eq!(
ref_lines, sorted_refs,
"refs must already be in ascending line order"
);
}
#[test]
fn well_formed_file_is_unaffected() {
let e = extract_src(
"namespace Fixtures.Widgets { public class Gadget { public int Count; } public struct Handle {} }",
);
assert!(find_def(&e, "Fixtures.Widgets.Gadget").is_some());
assert!(find_def(&e, "Fixtures.Widgets.Handle").is_some());
}
pub(super) const DUPLICATE_HEADER_HOST_WITH_NESTED_EMITTER_SRC: &str = "
namespace Fixtures.Preproc
{
public static class WidgetCompiler
{
private static readonly int[] _pool = new int[8];
#if WIDGET_V2
private static int[] ComputeOffsets(IWidgetProvider items)
{
var count = items.WidgetCount;
#else
private static int[] ComputeOffsets(IReadOnlyList<Widget> items)
{
var count = items.Count;
#endif
if (count == 0)
return _pool;
return _pool;
}
private struct SlotInfo
{
public object Payload;
}
[System.Flags]
private enum SlotStatus : byte
{
Empty = 0,
Filled = 1,
}
private static class Emitter
{
#if WIDGET_V2
public static bool TryEmit(Widget expr, IWidgetProvider items, Sink sink)
{
var scaled = items.WidgetCount;
#else
public static bool TryEmit(Widget expr, IReadOnlyList<Widget> items, Sink sink)
{
var scaled = items.Count;
#endif
sink.Write(scaled);
return true;
}
}
}
}
";
#[test]
fn stacked_duplicate_headers_keep_both_wrapping_types_at_their_real_scope() {
let e = extract_src(DUPLICATE_HEADER_HOST_WITH_NESTED_EMITTER_SRC);
assert!(find_def(&e, "Fixtures.Preproc.WidgetCompiler").is_some());
let emitter = find_def(&e, "Fixtures.Preproc.WidgetCompiler+Emitter")
.expect("Emitter kept, nested under WidgetCompiler");
assert_eq!(emitter.kind, "class");
assert_eq!(emitter.namespace, "Fixtures.Preproc");
let slot_info = find_def(&e, "Fixtures.Preproc.WidgetCompiler+SlotInfo")
.expect("SlotInfo kept, nested under its type");
assert_eq!(slot_info.kind, "struct");
assert!(find_def(&e, "Fixtures.Preproc.WidgetCompiler+SlotStatus").is_some());
assert!(find_def(&e, "Fixtures.Preproc.WidgetCompiler+SlotStatus.Empty").is_some());
assert!(find_def(&e, "Fixtures.Preproc.WidgetCompiler+SlotStatus.Filled").is_some());
assert!(!e
.refs
.iter()
.any(|r| r.kind == "uses-type" && r.name == "IWidgetProvider"));
assert!(e
.refs
.iter()
.any(|r| r.kind == "uses-type" && r.name == "Sink"));
assert!(e.refs.iter().any(|r| r.kind == "uses-member"
&& r.name == "sink"
&& r.member.as_deref() == Some("Write")));
}