fusible 0.11.3

Electronic linter: a fuse that blows to block firmware code generation
use std::cell::Cell;
use std::sync::Arc;

use super::mechanical::{meta_json, MechanicalCache};
use super::pipeline::revision;
use crate::commands::mechanical::MechanicalPreview;

fn sample() -> MechanicalPreview {
    MechanicalPreview {
        glb: vec![0x67, 0x6c, 0x54, 0x46],
        board_z: 5.0,
        board_thickness: 1.4,
        height: 18.4,
        wall: 2.0,
        size: [45.0, 159.0, 20.4],
    }
}

#[test]
fn revision_is_stable_hex_and_tracks_the_source() {
    let a = revision(r#"[{"type":"pcb_board"}]"#);
    assert_eq!(a, revision(r#"[{"type":"pcb_board"}]"#));
    assert_ne!(a, revision(r#"[{"type":"pcb_board","width":1}]"#));
    assert_eq!(a.len(), 16);
    assert!(a.chars().all(|c| c.is_ascii_hexdigit()));
}

#[test]
fn cache_generates_once_per_revision_including_errors() {
    let cache = MechanicalCache::default();
    let calls = Cell::new(0);
    let fail = |_: &str| {
        calls.set(calls.get() + 1);
        Err("boom".to_string())
    };
    assert!(cache.resolve_with(fail).is_none());
    cache.update(Some("[1]".into()), "r1".into());
    let (rev, first) = cache.resolve_with(fail).unwrap();
    assert_eq!((rev.as_str(), first), ("r1", Err("boom".to_string())));
    assert!(cache.resolve_with(fail).unwrap().1.is_err());
    assert_eq!(calls.get(), 1);
    cache.update(Some("[2]".into()), "r2".into());
    let (rev, second) = cache
        .resolve_with(|json| {
            assert_eq!(json, "[2]");
            Ok(Arc::new(sample()))
        })
        .unwrap();
    assert_eq!(rev, "r2");
    assert_eq!(second.unwrap().size, [45.0, 159.0, 20.4]);
}

#[test]
fn responses_carry_status_type_and_no_store() {
    let cache = MechanicalCache::default();
    let status = |glb: bool, ok: bool| {
        let response = cache.response(glb, |_| {
            if ok {
                Ok(Arc::new(sample()))
            } else {
                Err("x".into())
            }
        });
        let no_store = response
            .headers()
            .iter()
            .any(|h| h.field.equiv("Cache-Control") && h.value.as_str() == "no-store");
        assert!(no_store);
        response.status_code().0
    };
    assert_eq!(status(false, true), 503);
    assert_eq!(status(true, true), 503);
    cache.update(Some("[]".into()), "a".into());
    assert_eq!(status(true, false), 422);
    cache.update(Some("[]".into()), "b".into());
    assert_eq!(status(false, true), 200);
    assert_eq!(status(true, true), 200);
}

#[test]
fn meta_json_matches_the_contract() {
    let value: serde_json::Value = serde_json::from_str(&meta_json("abc", &sample())).unwrap();
    assert_eq!(
        value,
        serde_json::json!({
            "revision": "abc",
            "board_z": 5.0,
            "board_thickness": 1.4,
            "height": 18.4,
            "wall": 2.0,
            "size": [45.0, 159.0, 20.4],
        })
    );
}