//! Validates the `examples/bfld_minimal.rs` operator-quickstart contract. //! The example file embeds via include_str! for documentation-drift checks, //! then a separate test re-executes the same end-to-end flow inline so we //! get a CI-runnable proof that the operator workflow produces valid JSON. #![cfg(feature = "std")] use wifi_densepose_bfld::{ BfldConfig, BfldPipeline, IdentityEmbedding, SensingInputs, SignatureHasher, EMBEDDING_DIM, SITE_SALT_LEN, }; const MINIMAL_EXAMPLE: &str = include_str!("../examples/bfld_minimal.rs"); #[test] fn minimal_example_documents_the_operator_quickstart_flow() { // The example must call out the canonical operator-facing types so // anyone reading it sees the right entry points. assert!(MINIMAL_EXAMPLE.contains("BfldPipeline")); assert!(MINIMAL_EXAMPLE.contains("SignatureHasher")); assert!(MINIMAL_EXAMPLE.contains("SensingInputs")); assert!(MINIMAL_EXAMPLE.contains("IdentityEmbedding")); assert!(MINIMAL_EXAMPLE.contains("BfldConfig")); assert!( MINIMAL_EXAMPLE.contains(".process("), "example must invoke pipeline.process(...) — method-chain style OK", ); assert!(MINIMAL_EXAMPLE.contains("to_json")); } #[test] fn minimal_example_carries_run_instructions_in_doc_comments() { assert!( MINIMAL_EXAMPLE.contains("cargo run -p wifi-densepose-bfld --example bfld_minimal"), "example must document its own run command", ); } #[test] fn minimal_example_flow_produces_valid_json_with_documented_fields() { // Re-execute the same logic the example does so CI proves the flow // works end-to-end without needing `cargo run --example`. let site_salt: [u8; SITE_SALT_LEN] = [0xAB; SITE_SALT_LEN]; let mut pipeline = BfldPipeline::new( BfldConfig::new("seed-example") .with_signature_hasher(SignatureHasher::new(site_salt)), ); let inputs = SensingInputs { timestamp_ns: 1_700_000_000_000_000_000, presence: true, motion: 0.42, person_count: 1, sensing_confidence: 0.91, sep: 0.2, stab: 0.2, consist: 0.2, risk_conf: 0.2, rf_signature_hash: None, }; let mut emb_values = [0.0f32; EMBEDDING_DIM]; for (i, v) in emb_values.iter_mut().enumerate() { *v = (i as f32) * 0.0073; } let embedding = IdentityEmbedding::from_raw(emb_values); let event = pipeline .process(inputs, Some(embedding)) .expect("low-risk emit must succeed"); let json = event.to_json().expect("JSON serialization must succeed"); // The published JSON should carry every documented anonymous-class field. for needle in [ "\"type\":\"bfld_update\"", "\"node_id\":\"seed-example\"", "\"presence\":true", "\"motion\":", "\"person_count\":1", "\"confidence\":", "\"privacy_class\":\"anonymous\"", "\"identity_risk_score\":", "\"rf_signature_hash\":\"blake3:", ] { assert!( json.contains(needle), "example JSON missing expected snippet `{needle}`\nfull JSON: {json}", ); } } #[test] fn example_returns_box_dyn_error_for_main_signature() { // `main() -> Result<(), Box>` is the standard // Rust-example pattern. Confirm the file uses it so future copy-paste // doesn't drop error propagation. assert!( MINIMAL_EXAMPLE.contains("fn main() -> Result<(), Box>"), ); }