//! Acceptance tests for `BfldFrameHeader` serialization (ADR-119 AC5/AC6). use wifi_densepose_bfld::frame::flags; use wifi_densepose_bfld::{BfldError, BfldFrameHeader, BFLD_HEADER_SIZE, BFLD_MAGIC}; fn sample_header() -> BfldFrameHeader { let mut h = BfldFrameHeader::empty(); h.flags = flags::HAS_CSI_DELTA | flags::PRIVACY_MODE; h.timestamp_ns = 0x0123_4567_89AB_CDEF; h.ap_hash = [0xAA; 16]; h.sta_hash = [0xBB; 16]; h.session_id = [0xCC; 16]; h.channel = 36; h.bandwidth_mhz = 80; h.rssi_dbm = -55; h.noise_floor_dbm = -95; h.n_subcarriers = 234; h.n_tx = 3; h.n_rx = 4; h.quantization = 1; h.privacy_class = 2; h.payload_len = 12_345; h.payload_crc32 = 0xDEAD_BEEF; h } #[test] fn header_roundtrip_preserves_all_fields() { let original = sample_header(); let bytes = original.to_le_bytes(); let parsed = BfldFrameHeader::from_le_bytes(&bytes).expect("parse must succeed"); assert_eq!({ parsed.magic }, BFLD_MAGIC); assert_eq!({ parsed.version }, 1); assert_eq!({ parsed.flags }, flags::HAS_CSI_DELTA | flags::PRIVACY_MODE); assert_eq!({ parsed.timestamp_ns }, 0x0123_4567_89AB_CDEF); assert_eq!(parsed.ap_hash, [0xAA; 16]); assert_eq!(parsed.sta_hash, [0xBB; 16]); assert_eq!(parsed.session_id, [0xCC; 16]); assert_eq!({ parsed.channel }, 36); assert_eq!({ parsed.bandwidth_mhz }, 80); assert_eq!({ parsed.rssi_dbm }, -55); assert_eq!({ parsed.noise_floor_dbm }, -95); assert_eq!({ parsed.n_subcarriers }, 234); assert_eq!(parsed.n_tx, 3); assert_eq!(parsed.n_rx, 4); assert_eq!(parsed.quantization, 1); assert_eq!(parsed.privacy_class, 2); assert_eq!({ parsed.payload_len }, 12_345); assert_eq!({ parsed.payload_crc32 }, 0xDEAD_BEEF); } #[test] fn header_serialization_is_deterministic() { let h = sample_header(); let a = h.to_le_bytes(); let b = h.to_le_bytes(); assert_eq!(a, b, "two serializations of the same header must be bit-identical"); } #[test] fn header_magic_is_at_offset_zero_little_endian() { let bytes = sample_header().to_le_bytes(); // BFLD_MAGIC = 0xBF1D_0001 → little-endian: 01 00 1D BF assert_eq!(&bytes[0..4], &[0x01, 0x00, 0x1D, 0xBF]); } #[test] fn parsing_rejects_invalid_magic() { let mut bytes = sample_header().to_le_bytes(); bytes[0] = 0xFF; // clobber magic match BfldFrameHeader::from_le_bytes(&bytes) { Err(BfldError::InvalidMagic(got)) => { assert_ne!(got, BFLD_MAGIC); } other => panic!("expected InvalidMagic, got {other:?}"), } } #[test] fn parsing_rejects_unsupported_version() { let mut bytes = sample_header().to_le_bytes(); bytes[4] = 99; // version field at offset 4 (LE u16) bytes[5] = 0; match BfldFrameHeader::from_le_bytes(&bytes) { Err(BfldError::UnsupportedVersion(v)) => assert_eq!(v, 99), other => panic!("expected UnsupportedVersion, got {other:?}"), } } #[test] fn wire_size_is_constant() { assert_eq!(sample_header().to_le_bytes().len(), BFLD_HEADER_SIZE); }