tests.rsannotatedtests.rssource175 lines · 5.9 KB · raw

The drawing of a small domain of its own, a change to be reviewed. lmjtfy holds the drawing of its network to the picture it served before the drawing moved here.

5use rete::{Domain, Known, Network, Rule, Test, Then};
7use super::*;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10struct Change;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
13enum F {
14    Code,
15    Tests,
16    Reviewed,
17}
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20struct Review;
21
22impl Domain for Change {
23    type Fact = F;
24    type Value = bool;
25    type Effect = Review;
26    type End = ();
27    type Note = ();
28
29    fn facts() -> &'static [F] {
30        &[F::Code, F::Tests, F::Reviewed]
31    }
32    fn fact_name(fact: F) -> &'static str {
33        match fact {
34            F::Code => "touches code",
35            F::Tests => "touches tests",
36            F::Reviewed => "reviewed",
37        }
38    }
39    fn values(_: F) -> &'static [bool] {
40        &[true, false]
41    }
42    fn value_name(value: bool) -> &'static str {
43        if value { "yes" } else { "no" }
44    }
45    fn asked_for(fact: F) -> bool {
46        fact != F::Reviewed
47    }
48    fn teaches(_: Review) -> F {
49        F::Reviewed
50    }
51    fn effect_name(_: Review) -> String {
52        "review".to_owned()
53    }
54    fn end_name(_: ()) -> String {
55        String::new()
56    }
57    fn note_name(_: ()) -> String {
58        String::new()
59    }
60}
61
62const RULES: &[Rule<'static, Change>] = &[
63    Rule {
64        name: "tests missing",
65        when: &[Test::Is(F::Code, true), Test::Is(F::Tests, false)],
66        then: Then::Note(()),
67    },
68    Rule { name: "look at it", when: &[Test::Is(F::Code, true), Test::Is(F::Tests, true)], then: Then::Do(Review) },
69    Rule { name: "approved", when: &[Test::Is(F::Reviewed, true)], then: Then::Note(()) },
70];
71
72fn legend() -> Legend<Change> {
73    Legend {
74        frames: vec![("source · 2 questions".to_owned(), vec![F::Code, F::Tests]), ("review · 1 call".to_owned(), vec![F::Reviewed])],
75        then: |then| match then {
76            Then::Do(_) => "ask a reviewer".to_owned(),
77            _ => "say so".to_owned(),
78        },
79    }
80}
81
82fn none(_: F) -> Option<String> {
83    None
84}
85
86fn unlinked(_: Clicked<Change>) -> Option<String> {
87    None
88}
89
90#[test]
91fn nothing_known_draws_every_node_waiting() {
92    let network = Network::compile(RULES);
93    let svg = rete(&network, &Known::default(), &[], &legend(), none, unlinked).into_string();
94    assert_eq!(svg.matches(r#"<g class="alpha waits">"#).count(), network.alphas.len());
95    assert_eq!(svg.matches(r#"<g class="rule waits">"#).count(), 3);
96    assert_eq!(svg.matches(r#"<g class="fact waits">"#).count(), 3);
97    assert_eq!(svg.matches(r#"<g class="frame">"#).count(), 2);
98    assert!(svg.contains("source · 2 questions") && svg.contains("tests missing → say so"));
99    assert!(!svg.contains("holds") && !svg.contains("spare") && !svg.contains("fired"));
100}
101
102#[test]
103fn a_rule_that_holds_is_lit_and_what_it_did_not_need_is_outlined() {
104    let network = Network::compile(RULES);
105    let mut known = Known::default();
106    known.learn(F::Code, true);
107    known.learn(F::Tests, false);
108    let svg = rete(&network, &known, &[], &legend(), none, unlinked).into_string();
109    assert_eq!(svg.matches(r#"<g class="rule holds">"#).count(), 1);
110    assert_eq!(svg.matches(r#"<g class="fact holds">"#).count(), 2);
111    // "look at it" fails, and its test on `touches tests` is the failed alpha.
112    assert!(svg.contains(r#"<g class="alpha fails">"#));
113}
114
115#[test]
116fn the_rules_that_decided_are_numbered() {
117    let network = Network::compile(RULES);
118    let mut known = Known::default();
119    known.learn(F::Code, true);
120    known.learn(F::Tests, true);
121    let (by, _) = network.decide(&known);
122    let fired: Vec<usize> = by.into_iter().collect();
123    let svg = rete(&network, &known, &fired, &legend(), none, unlinked).into_string();
124    assert_eq!(sequence(&network, &fired), "1 look at it");
125    assert_eq!(svg.matches(r#" fired">"#).count(), 1);
126    assert!(svg.contains(r#"<text class="nth""#));
127}
128
129#[test]
130fn facts_and_tests_are_links_when_they_are_given_one() {
131    let network = Network::compile(RULES);
132    let link = |clicked: Clicked<Change>| {
133        Some(match clicked {
134            Clicked::Fact(fact) => format!("/fact?{}", Change::fact_name(fact)),
135            Clicked::Test(test) => format!("/test?{}", Change::fact_name(test.fact())),
136        })
137    };
138    let svg = rete(&network, &Known::default(), &[], &legend(), none, link).into_string();
139    assert_eq!(svg.matches(r#"<a href="/test?"#).count(), network.alphas.len());
140    assert_eq!(svg.matches(r#"<a href="/fact?"#).count(), 3);
141}
142
143#[test]
144fn a_fact_shows_what_the_host_says_when_there_is_something() {
145    let mut known = Known::default();
146    known.learn(F::Code, true);
147    known.learn(F::Tests, true);
148    let shown = |fact: F| (fact == F::Code).then(|| "0.97".to_owned());
149    let svg = rete(&Network::compile(RULES), &known, &[], &legend(), shown, unlinked).into_string();
150    assert!(svg.contains(">0.97</text>"));
151    assert!(svg.contains(">yes</text>"), "a fact without one shows its value's name");
152}
153
154#[test]
155fn every_rule_with_an_effect_has_a_line_back_to_the_fact_it_teaches() {
156    let svg = rete(&Network::compile(RULES), &Known::default(), &[], &legend(), none, unlinked).into_string();
157    assert_eq!(svg.matches(r#"<g class="back "#).count(), 1);
158}
159
160#[test]
161fn the_picture_stands_alone_as_an_svg_file_with_its_styles() {
162    let svg = standalone(&Network::compile(RULES), &legend(), "g.holds rect { fill: pink; }");
163    assert!(svg.starts_with(r#"<svg xmlns="http://www.w3.org/2000/svg" "#), "{}", &svg[..60]);
164    assert!(svg.ends_with("</svg>"));
165    assert!(svg.contains("<style>g.holds rect { fill: pink; }</style>"));
166    assert!(!svg.contains("<a "), "nothing in it links");
167}
168
169#[test]
170fn no_two_nodes_in_a_column_share_a_place() {
171    let mut taken = BTreeSet::new();
172    assert_eq!(place(&mut taken, 20), 20);
173    assert_eq!(place(&mut taken, 20), 34);
174    assert_eq!(place(&mut taken, 20), 48);
175}