use super::*;

#[test]
fn parses_placed_structure_record_triplet_probe_from_dual_name_rows() {
    let mut bytes = vec![0u8; 0x400];
    let metadata_tag_offset = 0x40usize;
    let records_tag_offset = 0x140usize;
    let close_tag_offset = 0x260usize;
    bytes[metadata_tag_offset..metadata_tag_offset + 4]
        .copy_from_slice(&0x000036b1u32.to_le_bytes());
    bytes[records_tag_offset..records_tag_offset + 4].copy_from_slice(&0x000036b2u32.to_le_bytes());
    bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000036b3u32.to_le_bytes());
    let mut cursor = records_tag_offset + 4;
    for (primary, secondary, lane0, lane1, lane2, lane3, lane4) in [
        (
            "StationA",
            "StationSetA",
            43111.92f32,
            1385.5f32,
            34581.95f32,
            0.0f32,
            5.9760494f32,
        ),
        (
            "StationB",
            "StationSetB",
            44000.0f32,
            1200.0f32,
            33000.0f32,
            0.0f32,
            4.5f32,
        ),
    ] {
        bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
        bytes[cursor + 4] = primary.len() as u8;
        bytes[cursor + 5..cursor + 5 + primary.len()].copy_from_slice(primary.as_bytes());
        let second_len_offset = cursor + 5 + primary.len();
        bytes[second_len_offset] = secondary.len() as u8;
        bytes[second_len_offset + 1..second_len_offset + 1 + secondary.len()]
            .copy_from_slice(secondary.as_bytes());
        cursor += 0x19;
        bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_POLICY_TAG.to_le_bytes());
        bytes[cursor + 4..cursor + 8].copy_from_slice(&lane0.to_bits().to_le_bytes());
        bytes[cursor + 8..cursor + 12].copy_from_slice(&lane1.to_bits().to_le_bytes());
        bytes[cursor + 12..cursor + 16].copy_from_slice(&lane2.to_bits().to_le_bytes());
        bytes[cursor + 16..cursor + 20].copy_from_slice(&lane3.to_bits().to_le_bytes());
        bytes[cursor + 20..cursor + 24].copy_from_slice(&lane4.to_bits().to_le_bytes());
        bytes[cursor + 28..cursor + 30].copy_from_slice(&0x0101u16.to_le_bytes());
        cursor += 0x1e;
        bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_PROFILE_TAG.to_le_bytes());
        bytes[cursor + 4..cursor + 8].copy_from_slice(&0x5dc1u32.to_le_bytes());
        let mut payload_cursor = cursor + 8;
        bytes[payload_cursor] = primary.len() as u8;
        bytes[payload_cursor + 1..payload_cursor + 1 + primary.len()]
            .copy_from_slice(primary.as_bytes());
        payload_cursor += 1 + primary.len();
        bytes[payload_cursor] = 0;
        payload_cursor += 1;
        bytes[payload_cursor] = secondary.len() as u8;
        bytes[payload_cursor + 1..payload_cursor + 1 + secondary.len()]
            .copy_from_slice(secondary.as_bytes());
        payload_cursor += 1 + secondary.len();
        bytes[payload_cursor] = 0;
        payload_cursor += 1;
        bytes[payload_cursor..payload_cursor + 4].copy_from_slice(&0x0e373500u32.to_le_bytes());
        bytes[payload_cursor + 4..payload_cursor + 8].copy_from_slice(&(-1i32).to_le_bytes());
        bytes[payload_cursor + 8..payload_cursor + 12].copy_from_slice(&0x5dc2u32.to_le_bytes());
        cursor += 0x18 + primary.len() + secondary.len();
    }

    let header_probe = SmpSaveTaggedCollectionHeaderProbe {
        profile_family: "rt3-105-save-container-v1".to_string(),
        source_kind: "save-placed-structure-tagged-header-counts".to_string(),
        semantic_family: "scenario-save-placed-structure-header-counts".to_string(),
        metadata_tag_offset,
        records_tag_offset,
        close_tag_offset,
        direct_collection_flag: 0,
        direct_collection_flag_hex: "0x00000000".to_string(),
        direct_record_stride: 0x06,
        direct_record_stride_hex: "0x00000006".to_string(),
        live_id_bound: 3,
        live_id_bound_hex: "0x00000003".to_string(),
        live_record_count: 2,
        live_record_count_hex: "0x00000002".to_string(),
        header_words: vec![0, 6, 0x0a, 0x14, 3, 2],
        header_hex_words: vec![],
        evidence: vec![],
    };
    let triplet_probe =
        parse_save_placed_structure_record_triplet_probe(&bytes, Some(&header_probe))
            .expect("placed-structure triplet probe should parse");

    assert_eq!(triplet_probe.record_count, 2);
    assert_eq!(triplet_probe.entries[0].primary_name, "StationA");
    assert_eq!(triplet_probe.entries[0].secondary_name, "StationSetA");
    assert_eq!(triplet_probe.entries[0].policy_chunk_len, 0x1a);
    assert_eq!(triplet_probe.entries[0].policy_f32_lane_4, 5.9760494);
    assert_eq!(triplet_probe.entries[0].policy_trailing_word, 0x0101);
    assert_eq!(
        triplet_probe.entries[0].profile_open_marker_hex,
        "0x00005dc1"
    );
    assert_eq!(
        triplet_probe.entries[0].profile_repeated_primary_name,
        "StationA"
    );
    assert_eq!(
        triplet_probe.entries[0].profile_repeated_secondary_name,
        "StationSetA"
    );
    assert_eq!(
        triplet_probe.entries[0].profile_footer_relative_offset_hex,
        "0x1b"
    );
    assert_eq!(triplet_probe.entries[0].profile_pre_footer_padding_len, 1);
    assert_eq!(
        triplet_probe.entries[0].profile_pre_footer_padding_hex_bytes,
        vec!["0x00".to_string()]
    );
    assert_eq!(triplet_probe.entries[0].profile_companion_byte_u8, Some(0));
    assert_eq!(
        triplet_probe.entries[0]
            .profile_companion_byte_hex
            .as_deref(),
        Some("0x00")
    );
    assert_eq!(
        triplet_probe.entries[0].profile_payload_dword_hex,
        "0x0e373500"
    );
    assert_eq!(triplet_probe.entries[0].profile_sentinel_i32, -1);
    assert_eq!(triplet_probe.entries[0].profile_status_kind, "unset");
    assert_eq!(triplet_probe.entries[0].farm_growth_stage_index, None);
    assert_eq!(
        triplet_probe.entries[0].profile_close_marker_hex,
        "0x00005dc2"
    );
    assert_eq!(triplet_probe.entries[1].primary_name, "StationB");
    assert_eq!(triplet_probe.entries[1].secondary_name, "StationSetB");
    assert_eq!(triplet_probe.entries[1].policy_f32_lane_1, 1200.0);
}

#[test]
fn derives_placed_structure_farm_growth_stage_from_nonnegative_status() {
    assert_eq!(
        derive_save_placed_structure_profile_status("FarmCorn", "FarmSet", 4),
        ("farm_growth_stage_bucket", Some(4))
    );
    assert_eq!(
        derive_save_placed_structure_profile_status("StationA", "StationSetA", -1),
        ("unset", None)
    );
    assert_eq!(
        derive_save_placed_structure_profile_status("StationA", "StationSetA", 4),
        ("opaque_nondefault", None)
    );
}

#[test]
fn parses_placed_structure_dynamic_side_buffer_probe_from_embedded_name_row() {
    let mut bytes = vec![0u8; 0x400];
    let metadata_tag_offset = 0x40usize;
    let records_tag_offset = 0x140usize;
    let close_tag_offset = 0x220usize;
    bytes[metadata_tag_offset..metadata_tag_offset + 4]
        .copy_from_slice(&0x000038a5u32.to_le_bytes());
    bytes[records_tag_offset..records_tag_offset + 4].copy_from_slice(&0x000038a6u32.to_le_bytes());
    bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000038a7u32.to_le_bytes());
    let header_words = [
        0u32, 0x06, 1000, 500, 1000, 388, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    ];
    for (index, word) in header_words.into_iter().enumerate() {
        let offset = metadata_tag_offset + 4 + index * 4;
        bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
    }
    let payload_offset = records_tag_offset + 4;
    bytes[payload_offset..payload_offset + 4].copy_from_slice(&0x0005d368u32.to_le_bytes());
    bytes[payload_offset + 4..payload_offset + 6].copy_from_slice(&0x0001u16.to_le_bytes());
    bytes[payload_offset + 6] = 0xff;
    let name_tag_offset = payload_offset + 7;
    bytes[name_tag_offset..name_tag_offset + 2]
        .copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
    let first_name = "TrackCapST_Cap.3dp";
    let second_name = "Infrastructure";
    bytes[name_tag_offset + 4] = first_name.len() as u8;
    bytes[name_tag_offset + 5..name_tag_offset + 5 + first_name.len()]
        .copy_from_slice(first_name.as_bytes());
    let second_len_offset = name_tag_offset + 5 + first_name.len();
    bytes[second_len_offset] = second_name.len() as u8;
    bytes[second_len_offset + 1..second_len_offset + 1 + second_name.len()]
        .copy_from_slice(second_name.as_bytes());

    let probe = parse_save_placed_structure_dynamic_side_buffer_probe(
        &bytes,
        Some("gms"),
        Some(&SmpContainerProfile {
            profile_family: "rt3-105-save-container-v1".to_string(),
            profile_evidence: vec![],
            is_known_profile: true,
        }),
    )
    .expect("placed-structure dynamic side-buffer probe should parse");

    assert_eq!(probe.direct_record_stride, 0x06);
    assert_eq!(probe.live_id_bound, 1000);
    assert_eq!(probe.live_record_count, 388);
    assert_eq!(probe.owner_shared_dword_hex, "0x0005d368");
    assert_eq!(probe.owner_shared_dword_relative_offset, 0);
    assert!(probe.owner_shared_dword_matches_first_compact_prefix_leading_dword);
    assert_eq!(probe.first_record_child_count_after_owner_shared, Some(1));
    assert_eq!(
        probe
            .first_record_saved_primary_child_byte_after_owner_shared_hex
            .as_deref(),
        Some("0xff")
    );
    assert_eq!(
        probe.first_record_first_name_tag_relative_offset_after_owner_shared,
        Some(3)
    );
    assert_eq!(probe.prefix_leading_dword_hex, "0x0005d368");
    assert_eq!(probe.prefix_trailing_word_hex, "0x0001");
    assert_eq!(probe.prefix_separator_byte_hex, "0xff");
    assert_eq!(probe.first_embedded_name_tag_relative_offset, 7);
    assert_eq!(probe.embedded_name_tag_count, 1);
    assert_eq!(probe.decoded_embedded_name_row_count, 1);
    assert_eq!(probe.decoded_embedded_name_row_with_tertiary_name_count, 0);
    assert_eq!(probe.unique_compact_prefix_pattern_count, 1);
    assert_eq!(
        probe.prefix_leading_dword_matching_embedded_profile_tag_count,
        0
    );
    assert_eq!(probe.unique_embedded_name_pair_count, 1);
    assert_eq!(
        probe.first_embedded_primary_name.as_deref(),
        Some("TrackCapST_Cap.3dp")
    );
    assert_eq!(
        probe.first_embedded_secondary_name.as_deref(),
        Some("Infrastructure")
    );
    assert_eq!(probe.first_embedded_tertiary_name.as_deref(), None);
    assert_eq!(probe.compact_prefix_pattern_summaries.len(), 1);
    assert_eq!(
        probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex,
        "0x0005d368"
    );
    assert_eq!(probe.compact_prefix_pattern_summaries[0].count, 1);
    assert_eq!(
        probe.compact_prefix_pattern_summaries[0].cap_like_primary_name_count,
        1
    );
    assert_eq!(
        probe.compact_prefix_pattern_summaries[0].section_like_primary_name_count,
        0
    );
    assert_eq!(probe.name_pair_summaries.len(), 1);
    assert_eq!(probe.name_pair_summaries[0].count, 1);
    assert_eq!(
        probe.name_pair_summaries[0].dominant_prefix_leading_dword_hex,
        "0x0005d368"
    );
    let payload_envelope_summary = probe
        .payload_envelope_summary
        .as_ref()
        .expect("payload envelope summary should be present");
    assert_eq!(
        payload_envelope_summary.row_count_with_policy_tag_before_next_name,
        0
    );
    assert_eq!(
        payload_envelope_summary.row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope,
        0
    );
    assert_eq!(
        payload_envelope_summary.row_count_missing_policy_tag_before_next_name,
        1
    );
}

#[test]
fn summarizes_placed_structure_dynamic_side_buffer_compact_prefix_patterns() {
    let mut bytes = vec![0u8; 0x600];
    let metadata_tag_offset = 0x40usize;
    let records_tag_offset = 0x140usize;
    let close_tag_offset = 0x320usize;
    bytes[metadata_tag_offset..metadata_tag_offset + 4]
        .copy_from_slice(&0x000038a5u32.to_le_bytes());
    bytes[records_tag_offset..records_tag_offset + 4].copy_from_slice(&0x000038a6u32.to_le_bytes());
    bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000038a7u32.to_le_bytes());
    let header_words = [
        0u32, 0x06, 1000, 500, 1000, 388, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    ];
    for (index, word) in header_words.into_iter().enumerate() {
        let offset = metadata_tag_offset + 4 + index * 4;
        bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
    }
    let mut cursor = records_tag_offset + 4;
    for (leading_dword, primary_name) in [
        (0x000055f3u32, "TunnelSTBrick_Section.3dp"),
        (0x000055f3u32, "TunnelSTBrick_Cap.3dp"),
        (0xff0000ffu32, "TunnelSTBrick_Cap.3dp"),
    ] {
        bytes[cursor..cursor + 4].copy_from_slice(&leading_dword.to_le_bytes());
        bytes[cursor + 4..cursor + 6].copy_from_slice(&0x0001u16.to_le_bytes());
        bytes[cursor + 6] = 0xff;
        let name_tag_offset = cursor + 7;
        bytes[name_tag_offset..name_tag_offset + 2]
            .copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
        let secondary_name = "Infrastructure";
        bytes[name_tag_offset + 4] = primary_name.len() as u8;
        bytes[name_tag_offset + 5..name_tag_offset + 5 + primary_name.len()]
            .copy_from_slice(primary_name.as_bytes());
        let second_len_offset = name_tag_offset + 5 + primary_name.len();
        bytes[second_len_offset] = secondary_name.len() as u8;
        bytes[second_len_offset + 1..second_len_offset + 1 + secondary_name.len()]
            .copy_from_slice(secondary_name.as_bytes());
        cursor = second_len_offset + 1 + secondary_name.len();
    }

    let probe = parse_save_placed_structure_dynamic_side_buffer_probe(
        &bytes,
        Some("gms"),
        Some(&SmpContainerProfile {
            profile_family: "rt3-105-save-container-v1".to_string(),
            profile_evidence: vec![],
            is_known_profile: true,
        }),
    )
    .expect("placed-structure dynamic side-buffer probe should parse");

    assert_eq!(probe.embedded_name_tag_count, 3);
    assert_eq!(probe.decoded_embedded_name_row_count, 3);
    assert_eq!(probe.decoded_embedded_name_row_with_tertiary_name_count, 0);
    assert_eq!(probe.unique_compact_prefix_pattern_count, 2);
    assert_eq!(
        probe.prefix_leading_dword_matching_embedded_profile_tag_count,
        2
    );
    assert_eq!(probe.unique_embedded_name_pair_count, 2);
    assert_eq!(probe.compact_prefix_pattern_summaries.len(), 2);
    assert_eq!(
        probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex,
        "0x000055f3"
    );
    assert_eq!(probe.compact_prefix_pattern_summaries[0].count, 2);
    assert_eq!(
        probe.compact_prefix_pattern_summaries[0].section_like_primary_name_count,
        1
    );
    assert_eq!(
        probe.compact_prefix_pattern_summaries[0].cap_like_primary_name_count,
        1
    );
    assert!(
        probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_matches_embedded_profile_tag
    );
    assert_eq!(
        probe.compact_prefix_pattern_summaries[1].prefix_leading_dword_hex,
        "0xff0000ff"
    );
    assert_eq!(probe.compact_prefix_pattern_summaries[1].count, 1);
    assert_eq!(probe.name_pair_summaries.len(), 2);
    assert_eq!(probe.name_pair_summaries[0].count, 2);
    assert_eq!(
        probe.name_pair_summaries[0].dominant_prefix_leading_dword_hex,
        "0x000055f3"
    );
    assert_eq!(probe.name_pair_summaries[1].count, 1);
    let payload_envelope_summary = probe
        .payload_envelope_summary
        .as_ref()
        .expect("payload envelope summary should be present");
    assert_eq!(
        payload_envelope_summary.row_count_with_policy_tag_before_next_name,
        0
    );
    assert_eq!(
        payload_envelope_summary.row_count_missing_policy_tag_before_next_name,
        3
    );
}

#[test]
fn parses_save_len_prefixed_ascii_name_triplet_with_optional_third_name() {
    let bytes = [
        5u8, b'F', b'i', b'r', b's', b't', 0, 6, b'S', b'e', b'c', b'o', b'n', b'd', 0, 5, b'T',
        b'h', b'i', b'r', b'd',
    ];
    let parsed = parse_save_len_prefixed_ascii_name_triplet(&bytes)
        .expect("triplet parser should decode three len-prefixed ascii names");
    assert_eq!(parsed.0, "First");
    assert_eq!(parsed.1, "Second");
    assert_eq!(parsed.2.as_deref(), Some("Third"));
}

#[test]
fn parses_save_len_prefixed_ascii_name_triplet_with_extended_length_prefix() {
    let mut bytes = Vec::new();
    bytes.extend_from_slice(&[0x80, 0x03, b'A', b'B', b'C']);
    bytes.extend_from_slice(&[0, 1, b'X']);
    let parsed = parse_save_len_prefixed_ascii_name_triplet(&bytes)
        .expect("triplet parser should decode extended-length prefix");
    assert_eq!(parsed.0, "ABC");
    assert_eq!(parsed.1, "X");
    assert_eq!(parsed.2, None);
}

#[test]
fn parses_save_len_prefixed_ascii_name_triplet_with_consumed_len() {
    let bytes = [
        5u8, b'F', b'i', b'r', b's', b't', 0, 6, b'S', b'e', b'c', b'o', b'n', b'd', 0, 5, b'T',
        b'h', b'i', b'r', b'd', 0xff,
    ];
    let (parsed, consumed_len) =
        parse_save_len_prefixed_ascii_name_triplet_and_consumed_len(&bytes)
            .expect("triplet parser should decode consumed len");
    assert_eq!(parsed.0, "First");
    assert_eq!(parsed.1, "Second");
    assert_eq!(parsed.2.as_deref(), Some("Third"));
    assert_eq!(consumed_len, 21);
}

#[test]
fn aligns_placed_structure_dynamic_side_buffer_name_pairs_with_triplets() {
    let side_buffer = SmpSavePlacedStructureDynamicSideBufferProbe {
        profile_family: "rt3-105-save-container-v1".to_string(),
        source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(),
        semantic_family: "scenario-save-placed-structure-dynamic-side-buffer-records".to_string(),
        metadata_tag_offset: 0,
        records_tag_offset: 0,
        close_tag_offset: 0,
        records_span_len: 0,
        direct_record_stride: 6,
        direct_record_stride_hex: "0x00000006".to_string(),
        live_id_bound: 1000,
        live_id_bound_hex: "0x000003e8".to_string(),
        live_record_count: 10,
        live_record_count_hex: "0x0000000a".to_string(),
        owner_shared_dword: 0,
        owner_shared_dword_hex: "0x00000000".to_string(),
        owner_shared_dword_relative_offset: 0,
        owner_shared_dword_matches_first_compact_prefix_leading_dword: true,
        first_record_child_count_after_owner_shared: None,
        first_record_child_count_after_owner_shared_hex: None,
        first_record_saved_primary_child_byte_after_owner_shared: None,
        first_record_saved_primary_child_byte_after_owner_shared_hex: None,
        first_record_first_name_tag_relative_offset_after_owner_shared: None,
        prefix_leading_dword: 0,
        prefix_leading_dword_hex: "0x00000000".to_string(),
        prefix_trailing_word: 1,
        prefix_trailing_word_hex: "0x0001".to_string(),
        prefix_separator_byte: 0xff,
        prefix_separator_byte_hex: "0xff".to_string(),
        first_embedded_name_tag_relative_offset: 7,
        embedded_name_tag_count: 3,
        decoded_embedded_name_row_count: 3,
        decoded_embedded_name_row_with_tertiary_name_count: 0,
        unique_compact_prefix_pattern_count: 2,
        prefix_leading_dword_matching_embedded_profile_tag_count: 2,
        unique_embedded_name_pair_count: 2,
        first_embedded_primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
        first_embedded_secondary_name: Some("Infrastructure".to_string()),
        first_embedded_tertiary_name: None,
        embedded_name_row_samples: vec![],
        compact_prefix_pattern_summaries: vec![],
        name_pair_summaries: vec![
            SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
                primary_name: "TunnelSTBrick_Section.3dp".to_string(),
                secondary_name: "Infrastructure".to_string(),
                count: 2,
                first_name_tag_relative_offset: 7,
                unique_compact_prefix_pattern_count: 1,
                dominant_prefix_leading_dword: 0x55f3,
                dominant_prefix_leading_dword_hex: "0x000055f3".to_string(),
                dominant_prefix_trailing_word: 1,
                dominant_prefix_trailing_word_hex: "0x0001".to_string(),
                dominant_prefix_separator_byte: 0xff,
                dominant_prefix_separator_byte_hex: "0xff".to_string(),
                dominant_prefix_count: 2,
            },
            SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
                primary_name: "BridgeSTWood_Section.3dp".to_string(),
                secondary_name: "Infrastructure".to_string(),
                count: 1,
                first_name_tag_relative_offset: 27,
                unique_compact_prefix_pattern_count: 1,
                dominant_prefix_leading_dword: 0xff000000,
                dominant_prefix_leading_dword_hex: "0xff000000".to_string(),
                dominant_prefix_trailing_word: 1,
                dominant_prefix_trailing_word_hex: "0x0001".to_string(),
                dominant_prefix_separator_byte: 0xff,
                dominant_prefix_separator_byte_hex: "0xff".to_string(),
                dominant_prefix_count: 1,
            },
        ],
        payload_envelope_summary: None,
        live_entry_prelude_summary: None,
        evidence: vec![],
    };
    let triplets = SmpSavePlacedStructureRecordTripletProbe {
        profile_family: "rt3-105-save-container-v1".to_string(),
        source_kind: "save-placed-structure-record-triplets".to_string(),
        semantic_family: "scenario-save-placed-structure-record-triplets".to_string(),
        records_tag_offset: 0,
        close_tag_offset: 0,
        record_count: 2,
        entries: vec![
            SmpSavePlacedStructureRecordTripletEntryProbe {
                record_index: 0,
                primary_name: "TunnelSTBrick_Section.3dp".to_string(),
                secondary_name: "Infrastructure".to_string(),
                name_tag_relative_offset: 0,
                policy_tag_relative_offset: 0,
                profile_tag_relative_offset: 0,
                policy_chunk_len: 0,
                profile_chunk_len: 0,
                policy_f32_lane_0: 0.0,
                policy_f32_lane_1: 0.0,
                policy_f32_lane_2: 0.0,
                policy_f32_lane_3: 0.0,
                policy_f32_lane_4: 0.0,
                policy_reserved_dword: 0,
                policy_trailing_word: 0,
                policy_trailing_word_hex: "0x0000".to_string(),
                profile_open_marker: 0,
                profile_open_marker_hex: "0x00000000".to_string(),
                profile_repeated_primary_name: "TunnelSTBrick_Section.3dp".to_string(),
                profile_repeated_secondary_name: "Infrastructure".to_string(),
                profile_footer_relative_offset: 0,
                profile_footer_relative_offset_hex: "0x0".to_string(),
                profile_pre_footer_padding_len: 0,
                profile_pre_footer_padding_hex_bytes: Vec::new(),
                profile_companion_byte_u8: None,
                profile_companion_byte_hex: None,
                profile_payload_dword: 0,
                profile_payload_dword_hex: "0x00000000".to_string(),
                profile_sentinel_i32: -1,
                profile_status_kind: "unset".to_string(),
                farm_growth_stage_index: None,
                profile_close_marker: 0,
                profile_close_marker_hex: "0x00000000".to_string(),
            },
            SmpSavePlacedStructureRecordTripletEntryProbe {
                record_index: 1,
                primary_name: "TrackCapST_Cap.3dp".to_string(),
                secondary_name: "Infrastructure".to_string(),
                name_tag_relative_offset: 0,
                policy_tag_relative_offset: 0,
                profile_tag_relative_offset: 0,
                policy_chunk_len: 0,
                profile_chunk_len: 0,
                policy_f32_lane_0: 0.0,
                policy_f32_lane_1: 0.0,
                policy_f32_lane_2: 0.0,
                policy_f32_lane_3: 0.0,
                policy_f32_lane_4: 0.0,
                policy_reserved_dword: 0,
                policy_trailing_word: 0,
                policy_trailing_word_hex: "0x0000".to_string(),
                profile_open_marker: 0,
                profile_open_marker_hex: "0x00000000".to_string(),
                profile_repeated_primary_name: "TrackCapST_Cap.3dp".to_string(),
                profile_repeated_secondary_name: "Infrastructure".to_string(),
                profile_footer_relative_offset: 0,
                profile_footer_relative_offset_hex: "0x0".to_string(),
                profile_pre_footer_padding_len: 0,
                profile_pre_footer_padding_hex_bytes: Vec::new(),
                profile_companion_byte_u8: None,
                profile_companion_byte_hex: None,
                profile_payload_dword: 0,
                profile_payload_dword_hex: "0x00000000".to_string(),
                profile_sentinel_i32: -1,
                profile_status_kind: "unset".to_string(),
                farm_growth_stage_index: None,
                profile_close_marker: 0,
                profile_close_marker_hex: "0x00000000".to_string(),
            },
        ],
        evidence: vec![],
    };

    let alignment =
        summarize_placed_structure_dynamic_side_buffer_alignment(&side_buffer, &triplets);

    assert_eq!(alignment.unique_side_buffer_name_pair_count, 2);
    assert_eq!(alignment.unique_triplet_name_pair_count, 2);
    assert_eq!(alignment.overlapping_name_pair_count, 1);
    assert_eq!(
        alignment.side_buffer_rows_with_matching_triplet_name_pair_count,
        2
    );
    assert_eq!(
        alignment.side_buffer_rows_without_matching_triplet_name_pair_count,
        1
    );
    assert_eq!(
        alignment.triplet_name_pairs_without_side_buffer_match_count,
        1
    );
    assert_eq!(alignment.matched_name_pair_samples.len(), 1);
    assert_eq!(alignment.unmatched_side_buffer_name_pair_samples.len(), 1);
}

#[test]
fn parses_placed_structure_tagged_collection_header_probe_from_exact_u32_tags() {
    let mut bytes = vec![0u8; 0x400];
    let metadata_tag_offset = 0x40usize;
    let records_tag_offset = 0x140usize;
    let close_tag_offset = 0x180usize;
    bytes[metadata_tag_offset..metadata_tag_offset + 4]
        .copy_from_slice(&0x000036b1u32.to_le_bytes());
    bytes[records_tag_offset..records_tag_offset + 4].copy_from_slice(&0x000036b2u32.to_le_bytes());
    bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000036b3u32.to_le_bytes());
    let header_words = [
        0u32, 0x06, 0x0a, 0x14, 0x7ee, 0x7ea, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    ];
    for (index, word) in header_words.into_iter().enumerate() {
        let offset = metadata_tag_offset + 4 + index * 4;
        bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
    }

    let probe = parse_save_placed_structure_collection_header_probe(
        &bytes,
        Some("gms"),
        Some(&SmpContainerProfile {
            profile_family: "rt3-105-save-container-v1".to_string(),
            profile_evidence: vec![],
            is_known_profile: true,
        }),
    )
    .expect("placed structure header probe should parse");

    assert_eq!(probe.metadata_tag_offset, metadata_tag_offset);
    assert_eq!(probe.records_tag_offset, records_tag_offset);
    assert_eq!(probe.close_tag_offset, close_tag_offset);
    assert_eq!(probe.direct_collection_flag, 0);
    assert_eq!(probe.direct_record_stride, 0x06);
    assert_eq!(probe.live_id_bound, 0x7ee);
    assert_eq!(probe.live_record_count, 0x7ea);
}

#[test]
fn scans_unclassified_tagged_collection_header_probe_from_adjacent_low_tags() {
    let mut bytes = vec![0u8; 0x400];
    let metadata_tag_offset = 0x40usize;
    let records_tag_offset = 0x140usize;
    let close_tag_offset = 0x1c0usize;
    bytes[metadata_tag_offset..metadata_tag_offset + 4]
        .copy_from_slice(&0x00007001u32.to_le_bytes());
    bytes[records_tag_offset..records_tag_offset + 4].copy_from_slice(&0x00007002u32.to_le_bytes());
    bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x00007003u32.to_le_bytes());
    let header_words = [
        0u32, 0x12, 0x0a, 0x14, 0x90, 0x78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    ];
    for (index, word) in header_words.into_iter().enumerate() {
        let offset = metadata_tag_offset + 4 + index * 4;
        bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
    }

    let probes = scan_save_unclassified_tagged_collection_header_probes(
        &bytes,
        Some("gms"),
        Some(&SmpContainerProfile {
            profile_family: "rt3-105-save-container-v1".to_string(),
            profile_evidence: vec![],
            is_known_profile: true,
        }),
    );

    let probe = probes
        .iter()
        .find(|probe| probe.metadata_tag == 0x7001)
        .expect("should include synthetic unclassified tag family");
    assert_eq!(probe.records_tag, 0x7002);
    assert_eq!(probe.close_tag, 0x7003);
    assert_eq!(probe.direct_record_stride, 0x12);
    assert_eq!(probe.live_id_bound, 0x90);
    assert_eq!(probe.live_record_count, 0x78);
    assert_eq!(
        probe.records_span_len,
        close_tag_offset - (records_tag_offset + 4)
    );
}
