1//! The outbound ports, as far as they can be held to a contract without calling anything: what they 2//! do when they have nothing to call with. (What a real vendor says back is the adapter's own test.) 3 4use ::log::info; 5use whiskers_core::{Age, Direction}; 6use whiskers_ports::{Clock, Judge, JudgeError, SecretName, SpeakError, SpeechLine, Voice, run_ready}; 7 8/// A judge with no credentials never says `Allow` and never pretends to have decided. 9pub fn judge_without_credentials<J: Judge>(j: &J) { 10 info!("conformance: judge without credentials"); 11 let age = Age::new(6).unwrap(); 12 for direction in [Direction::FromChild, Direction::ToChild] { 13 assert_eq!(run_ready(j.check(direction, age, "hello")), Err(JudgeError::NotConfigured(SecretName::JevKey)), "no key is not an allow"); 14 } 15 let shortlist = ["a".to_owned(), "b".to_owned()]; 16 assert_eq!(run_ready(j.rerank("hello", &shortlist)), Err(JudgeError::NotConfigured(SecretName::JevKey))); 17 // "none fits" is an answer; with no key nothing was asked, so it is an error and never a `None`. 18 let options = [whiskers_core::IconId::new("cat").unwrap(), whiskers_core::IconId::new("dog").unwrap()]; 19 assert_eq!(run_ready(j.choose_icon("hello", &options)), Err(JudgeError::NotConfigured(SecretName::JevKey)), "no key is not 'none fits'"); 20} 21 22/// A voice with no credentials says so and does not try. 23pub fn voice_without_credentials<V: Voice>(v: &V) { 24 info!("conformance: voice without credentials"); 25 assert!(!run_ready(v.configured())); 26 let line = SpeechLine::new("hello there".into()).unwrap(); 27 assert_eq!(run_ready(v.speak(&line)), Err(SpeakError::NotConfigured)); 28 assert_eq!(run_ready(v.speak_timed(&line)), Err(SpeakError::NotConfigured)); 29} 30 31/// A clock reads a plausible time and does not run backwards. 32pub fn clock<C: Clock>(c: &C) { 33 let (a, b) = (c.now(), c.now()); 34 assert!(a.get() > 1_600_000_000_000, "milliseconds since the epoch, after 2020: {}", a.get()); 35 assert!(b >= a, "time does not run backwards"); 36}