1//! The shelf of pictures. 2 3use ::log::info; 4use whiskers_ports::{PictureShelf, Put, SafePictureId, run_ready}; 5 6fn id(name: &str) -> SafePictureId { 7 SafePictureId::parse(name).expect("a picture name") 8} 9 10/// Runs every picture law. 11pub fn pictures<P: PictureShelf>(fresh: &impl Fn() -> P, restart: &impl Fn(P) -> P) { 12 info!("conformance: pictures"); 13 pictures_come_back_exactly_as_they_went_in(fresh()); 14 pictures_are_never_replaced(fresh()); 15 pictures_that_are_not_there_are_not_there(fresh()); 16 pictures_survive_a_restart(fresh, restart); 17 pictures_names_that_could_reach_a_path_cannot_be_written(); 18} 19 20pub fn pictures_come_back_exactly_as_they_went_in<P: PictureShelf>(p: P) { 21 let every_byte: Vec<u8> = (0..=255u8).collect(); 22 let a = id("0000000000000000-0000.jpg"); 23 assert!(!run_ready(p.has(&a)).unwrap()); 24 assert_eq!(run_ready(p.put(&a, &every_byte)).unwrap(), Put::Stored); 25 assert!(run_ready(p.has(&a)).unwrap()); 26 assert_eq!(run_ready(p.get(&a)).unwrap(), Some(every_byte)); 27 assert_eq!(run_ready(p.put(&id("empty.png"), &[])).unwrap(), Put::Stored); 28 assert_eq!(run_ready(p.get(&id("empty.png"))).unwrap(), Some(vec![]), "an empty picture is still a picture"); 29} 30 31pub fn pictures_are_never_replaced<P: PictureShelf>(p: P) { 32 let a = id("a.jpg"); 33 run_ready(p.put(&a, b"first")).unwrap(); 34 assert_eq!(run_ready(p.put(&a, b"second")).unwrap(), Put::AlreadyKept); 35 assert_eq!(run_ready(p.get(&a)).unwrap().as_deref(), Some(&b"first"[..]), "the name means the first picture"); 36} 37 38pub fn pictures_that_are_not_there_are_not_there<P: PictureShelf>(p: P) { 39 let a = id("a.jpg"); 40 assert!(!run_ready(p.has(&a)).unwrap()); 41 assert_eq!(run_ready(p.get(&a)).unwrap(), None); 42} 43 44pub fn pictures_survive_a_restart<P: PictureShelf>(fresh: &impl Fn() -> P, restart: &impl Fn(P) -> P) { 45 let p = fresh(); 46 run_ready(p.put(&id("a.jpg"), b"kept")).unwrap(); 47 let p = restart(p); 48 assert!(run_ready(p.has(&id("a.jpg"))).unwrap()); 49 assert_eq!(run_ready(p.get(&id("a.jpg"))).unwrap().as_deref(), Some(&b"kept"[..])); 50 assert_eq!(run_ready(p.put(&id("a.jpg"), b"again")).unwrap(), Put::AlreadyKept); 51} 52 53/// Not an adapter's law but the shelf's precondition: no adapter is ever handed one of these. 54pub fn pictures_names_that_could_reach_a_path_cannot_be_written() { 55 for bad in ["../x.jpg", "a/b.jpg", "/etc/passwd", ".hidden.jpg", "a..b.jpg", "noextension", "x.exe", "", &"a".repeat(65), "sp ace.jpg", "back\\slash.jpg"] { 56 assert!(SafePictureId::parse(bad).is_err(), "{bad:?} must not be a picture name"); 57 } 58 for good in ["0000000000000000-0000.jpg", "a.png", "A_b-c.webp", "x.gif", "y.img"] { 59 assert!(SafePictureId::parse(good).is_ok(), "{good:?}"); 60 } 61}