The shelf of pictures.

3use ::log::info;
4use whiskers_ports::{PictureShelf, Put, SafePictureId, run_ready};
6fn id(name: &str) -> SafePictureId {
7    SafePictureId::parse(name).expect("a picture name")
8}

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}
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}

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}