laws.rsannotatedlaws.rssource81 lines · 4.3 KB · raw
1//! The real conformance laws of `whiskers-conformance`, one by one, against a running host's hubs.
2//!
3//! Each law is run on its own under `catch_unwind` so one failing law does not hide the rest, and the
4//! report names it. `fresh` makes a new household (an empty hub: a new Durable Object); `restart` runs the
5//! host's restart command, so a law about surviving a restart restarts the real process.
6
7use std::panic::{AssertUnwindSafe, catch_unwind};
8
9use whiskers_conformance::suite::hubs;
10use whiskers_core::{ChatState, Household, MemorySnapshot};
11
12use crate::host::Host;
13use crate::hub::{HttpHub, Named};
14use crate::ids::Households;
15
16pub struct Outcome {
17    pub law: &'static str,
18    pub failure: Option<String>,
19}
20
21fn message(panic: Box<dyn std::any::Any + Send>) -> String {
22    panic.downcast_ref::<String>().cloned().or_else(|| panic.downcast_ref::<&str>().map(|s| (*s).to_owned())).unwrap_or_else(|| "a panic".into())
23}
24
25/// Runs every law the host can be asked, returning each outcome.
26pub fn run_all(host: &Host, ids: &Households, restart: &dyn Fn()) -> Vec<Outcome> {
27    let mut out = Vec::new();
28    // A law that needs a restart when the host cannot be restarted is reported, not skipped silently.
29    let fresh = |_: ()| HttpHub::<MemorySnapshot>::new(host, &ids.next());
30    let fresh_m = || fresh(());
31    let fresh_h = || HttpHub::<Household>::new(host, &ids.next());
32    let fresh_c = || HttpHub::<ChatState>::new(host, &ids.next());
33    let again_m = |h: HttpHub<MemorySnapshot>| {
34        restart();
35        h
36    };
37    let again_h = |h: HttpHub<Household>| {
38        restart();
39        h
40    };
41    let again_c = |h: HttpHub<ChatState>| {
42        restart();
43        h
44    };
45
46    macro_rules! law {
47        ($name:literal, $body:expr) => {{
48            let r = catch_unwind(AssertUnwindSafe(|| $body));
49            out.push(Outcome { law: $name, failure: r.err().map(message) });
50        }};
51    }
52
53    law!("memory_takes_facts_and_numbers_them", hubs::memory_takes_facts_and_numbers_them(fresh_m()));
54    law!("memory_merge_twice_changes_nothing", hubs::memory_merge_twice_changes_nothing(fresh_m()));
55    law!("memory_merge_is_order_independent", hubs::memory_merge_is_order_independent(&fresh_m));
56    law!("memory_forgotten_wins_and_stays_forgotten", hubs::memory_forgotten_wins_and_stays_forgotten(&fresh_m));
57    law!("memory_ignores_facts_with_no_identity", hubs::memory_ignores_facts_with_no_identity(fresh_m()));
58    law!("memory_the_same_words_twice_are_one_fact", hubs::memory_the_same_words_twice_are_one_fact(fresh_m()));
59    law!("memory_an_embedding_computed_anywhere_serves_everywhere", hubs::memory_an_embedding_computed_anywhere_serves_everywhere(&fresh_m));
60    law!("memory_current_changes_nothing", hubs::memory_current_changes_nothing(fresh_m()));
61    law!("memory_a_hide_is_kept_and_the_later_write_wins", hubs::memory_a_hide_is_kept_and_the_later_write_wins(&fresh_m));
62    law!("memory_a_hidden_fact_is_not_a_forgotten_one", hubs::memory_a_hidden_fact_is_not_a_forgotten_one(&fresh_m));
63    law!("memory_a_picture_chosen_anywhere_serves_everywhere", hubs::memory_a_picture_chosen_anywhere_serves_everywhere(&fresh_m));
64    law!("memory_survives_a_restart", hubs::memory_survives_a_restart(&fresh_m, &again_m));
65
66    law!("household_takes_the_later_choice", hubs::household_takes_the_later_choice(&fresh_h));
67    law!("household_merge_twice_changes_nothing", hubs::household_merge_twice_changes_nothing(fresh_h()));
68    law!("household_merge_is_order_independent", hubs::household_merge_is_order_independent(&fresh_h));
69    law!("household_time_is_summed_across_devices_and_a_later_day_wins", hubs::household_time_is_summed_across_devices_and_a_later_day_wins(fresh_h()));
70    law!("household_survives_a_restart", hubs::household_survives_a_restart(&fresh_h, &again_h));
71
72    law!("chat_the_newer_copy_wins_whole", hubs::chat_the_newer_copy_wins_whole(fresh_c()));
73    law!("chat_merge_twice_changes_nothing", hubs::chat_merge_twice_changes_nothing(fresh_c()));
74    law!("chat_survives_a_restart", hubs::chat_survives_a_restart(&fresh_c, &again_c));
75    let _ = (<MemorySnapshot as Named>::NAME,);
76    out
77}
78
79/// The laws that cannot be run against a black box, and why.
80pub const NOT_RUNNABLE_OVER_HTTP: &[(&str, &str)] =
81    &[("chat_a_copy_that_cannot_be_kept_is_an_error_and_changes_nothing", "needs a switch that makes the host's storage refuse writes; there is none from outside")];