//! `BfldError` Display format pinning. Operators grep log lines for these //! strings; format drift between minor versions breaks monitoring queries. //! Each variant gets a test that asserts the documented substrings appear. #![cfg(feature = "std")] use wifi_densepose_bfld::BfldError; #[test] fn invalid_magic_displays_both_expected_and_actual_in_hex() { let err = BfldError::InvalidMagic(0xDEAD_BEEF); let s = err.to_string(); assert!(s.contains("invalid BFLD magic"), "got: {s}"); assert!(s.contains("0xBF1D0001"), "expected magic missing: {s}"); assert!(s.contains("0xDEADBEEF"), "actual magic missing: {s}"); } #[test] fn unsupported_version_displays_the_offending_version() { let err = BfldError::UnsupportedVersion(99); let s = err.to_string(); assert!(s.contains("unsupported BFLD version"), "got: {s}"); assert!(s.contains("99"), "version number missing: {s}"); } #[test] fn crc_mismatch_displays_both_values_in_hex() { let err = BfldError::Crc { expected: 0xCAFEBABE, actual: 0xDEADBEEF, }; let s = err.to_string(); assert!(s.contains("payload CRC mismatch"), "got: {s}"); assert!(s.contains("0xCAFEBABE"), "expected missing: {s}"); assert!(s.contains("0xDEADBEEF"), "actual missing: {s}"); } #[test] fn privacy_violation_displays_the_sink_reason() { let err = BfldError::PrivacyViolation { reason: "NetworkKind", }; let s = err.to_string(); assert!(s.contains("privacy violation"), "got: {s}"); assert!(s.contains("NetworkKind"), "reason missing: {s}"); } #[test] fn invalid_privacy_class_displays_the_offending_byte() { let err = BfldError::InvalidPrivacyClass(7); let s = err.to_string(); assert!(s.contains("invalid PrivacyClass byte"), "got: {s}"); assert!(s.contains("7"), "byte value missing: {s}"); } #[test] fn truncated_frame_displays_got_and_need_byte_counts() { let err = BfldError::TruncatedFrame { got: 50, need: 86 }; let s = err.to_string(); assert!(s.contains("truncated frame"), "got: {s}"); assert!(s.contains("50"), "got count missing: {s}"); assert!(s.contains("86"), "need count missing: {s}"); } #[test] fn malformed_section_displays_offset_and_reason() { let err = BfldError::MalformedSection { offset: 1234, reason: "section body runs past buffer end", }; let s = err.to_string(); assert!(s.contains("malformed payload section"), "got: {s}"); assert!(s.contains("1234"), "offset missing: {s}"); assert!(s.contains("buffer end"), "reason missing: {s}"); } #[test] fn invalid_demote_displays_both_from_and_to_class_bytes() { let err = BfldError::InvalidDemote { from: 2, to: 1 }; let s = err.to_string(); assert!(s.contains("invalid demote"), "got: {s}"); assert!(s.contains("from class 2"), "from missing: {s}"); assert!(s.contains("to class 1"), "to missing: {s}"); } // --- meta: error implements std::error::Error (for ? + dyn use) ------- #[test] fn bfld_error_implements_std_error_trait() { fn assert_error_trait() {} assert_error_trait::(); } #[test] fn bfld_error_is_debug_so_panic_unwrap_messages_carry_diagnostics() { let err = BfldError::Crc { expected: 0xAA, actual: 0xBB, }; let debug = format!("{err:?}"); assert!(debug.contains("Crc"), "Debug must show variant name: {debug}"); } // --- catch-all: every variant has a non-empty Display ----------------- #[test] fn every_variant_has_a_non_empty_display_string() { let cases: Vec = vec![ BfldError::InvalidMagic(0), BfldError::UnsupportedVersion(0), BfldError::Crc { expected: 0, actual: 0, }, BfldError::PrivacyViolation { reason: "X" }, BfldError::InvalidPrivacyClass(0), BfldError::TruncatedFrame { got: 0, need: 0 }, BfldError::MalformedSection { offset: 0, reason: "X", }, BfldError::InvalidDemote { from: 0, to: 0 }, ]; for err in cases { let s = err.to_string(); assert!(!s.is_empty(), "Display for {err:?} returned empty string"); assert!( s.len() >= 5, "Display for {err:?} suspiciously short: {s:?}", ); } }