1use super::*; 2 3fn known(facts: &[(Fact, Value)]) -> Known { 4 let mut known = Known::default(); 5 for (fact, value) in facts { 6 known.learn(*fact, *value); 7 } 8 known 9} 10 11const NOUL: Fact = Fact::Reads(Kind::Noul); 12const CHOICE: Fact = Fact::Reads(Kind::Choice); 13const SCORE: Fact = Fact::Reads(Kind::Score); 14const CHANCE: Fact = Fact::Reads(Kind::Chance);
What Jev's one request teaches, with reads the readings that hold.
17fn facts(answerable: bool, several: bool, reads: &[Fact], scale: bool, fit: bool) -> Known { 18 let mut known = known(&[ 19 (Fact::Answerable, Value::Bool(answerable)), 20 (Fact::Several, Value::Bool(several)), 21 (Fact::Scale, Value::Bool(scale)), 22 (Fact::Yes, Value::Given), 23 (Fact::Degree, Value::Given), 24 (Fact::Chance, Value::Given), 25 (Fact::Fit, Value::Bool(fit)), 26 (Fact::Whole, YES), 27 ]); 28 for kind in [NOUL, CHOICE, SCORE, CHANCE] { 29 known.learn(kind, Value::Bool(reads.contains(&kind))); 30 } 31 known 32}
34#[test] 35fn with_nothing_known_every_jev_fact_is_asked_for_at_once() { 36 let next = Network::lmjtfy().next(&Known::default()); 37 assert_eq!(next, Next::Ask(vec![Fact::Answerable, Fact::Several, NOUL, CHOICE, SCORE, CHANCE, Fact::Scale, Fact::Yes, Fact::Degree, Fact::Chance, Fact::Fit, Fact::Whole])); 38} 39 40#[test] 41fn what_jev_cannot_judge_ends_there() { 42 let all = facts(false, true, &[CHOICE], false, true); 43 assert_eq!(Network::lmjtfy().next(&all), Next::End(End::NotAQuestion)); 44} 45 46#[test] 47fn one_yes_or_no_question_is_answered_without_the_llm() { 48 let network = Network::lmjtfy(); 49 let all = facts(true, false, &[NOUL], false, true); 50 assert_eq!(network.next(&all), Next::Done); 51 assert_eq!(network.shows(&all), [Fact::Yes]); 52 assert!(network.wants(&all).is_empty()); 53} 54 55#[test] 56fn a_how_much_question_is_graded_unless_it_needs_its_own_scale() { 57 let network = Network::lmjtfy(); 58 let general = facts(true, false, &[SCORE], false, true); 59 assert_eq!(network.next(&general), Next::Done); 60 assert_eq!(network.shows(&general), [Fact::Degree]); 61 62 let bespoke = facts(true, false, &[SCORE], true, true); 63 assert_eq!(network.next(&bespoke), Next::Do(Effect::Draft(Want::Scale))); 64 assert!(network.shows(&bespoke).is_empty()); 65 assert_eq!(network.wants(&bespoke), [Want::Scale]); 66} 67 68#[test] 69fn a_how_likely_question_is_answered_with_jevs_own_probability_and_no_llm() { 70 let network = Network::lmjtfy(); 71 let odds = facts(true, false, &[CHANCE], true, true); 72 assert_eq!(network.next(&odds), Next::Done); 73 assert_eq!(network.shows(&odds), [Fact::Chance]); 74 assert!(network.wants(&odds).is_empty()); 75} 76 77#[test] 78fn a_pick_or_several_questions_go_to_the_llm() { 79 let network = Network::lmjtfy(); 80 assert_eq!(network.next(&facts(true, false, &[CHOICE], false, true)), Next::Do(Effect::Draft(Want::Options))); 81 for reads in [NOUL, CHOICE, SCORE, CHANCE] { 82 let several = facts(true, true, &[reads], false, true); 83 assert_eq!(network.next(&several), Next::Do(Effect::Draft(Want::Split)), "{reads:?}"); 84 // Nothing is answered directly when it is several questions. 85 assert!(network.shows(&several).is_empty()); 86 } 87} 88 89#[test] 90fn when_jev_is_split_both_readings_are_answered() { 91 let network = Network::lmjtfy(); 92 // A yes-or-no and a pick: the yes-or-no is in hand, the pick is drafted. 93 let split = facts(true, false, &[NOUL, CHOICE], false, true); 94 assert_eq!(network.shows(&split), [Fact::Yes]); 95 assert_eq!(network.next(&split), Next::Do(Effect::Draft(Want::Options))); 96 // A yes-or-no and a how-much: both are in hand, and no LLM is asked. 97 let free = facts(true, false, &[NOUL, SCORE], false, true); 98 assert_eq!(network.shows(&free), [Fact::Yes, Fact::Degree]); 99 assert_eq!(network.next(&free), Next::Done); 100 // A pick and a how-much that needs its scale: one call writes both. 101 let both = facts(true, false, &[CHOICE, SCORE], true, true); 102 assert_eq!(network.wants(&both), [Want::Options, Want::Scale]); 103} 104 105#[test] 106fn drafts_are_judged_and_then_the_query_is_done() { 107 let network = Network::lmjtfy(); 108 let mut all = facts(true, false, &[CHOICE], false, true); 109 all.learn(Fact::Drafted, YES); 110 assert_eq!(network.next(&all), Next::Do(Effect::Judge)); 111 all.learn(Fact::Judged, YES); 112 assert_eq!(network.next(&all), Next::Done); 113 assert_eq!(network.shows(&all), [Fact::Judged]); 114 all.learn(Fact::Judged, NO); 115 assert_eq!(network.next(&all), Next::Done); 116 assert!(network.shows(&all).is_empty()); 117 all.learn(Fact::Drafted, NO); 118 assert_eq!(network.next(&all), Next::Done); 119} 120 121#[test] 122fn every_way_the_jev_facts_can_fall_ends_or_does_something() { 123 let network = Network::lmjtfy(); 124 let readings: [&[Fact]; 9] = [ 125 &[NOUL], 126 &[CHOICE], 127 &[SCORE], 128 &[CHANCE], 129 &[NOUL, CHOICE], 130 &[NOUL, SCORE], 131 &[CHOICE, SCORE], 132 &[NOUL, CHANCE], 133 &[SCORE, CHANCE], 134 ]; 135 for answerable in [true, false] { 136 for several in [true, false] { 137 for reads in readings { 138 for scale in [true, false] { 139 let all = facts(answerable, several, reads, scale, true); 140 let next = network.next(&all); 141 assert!(!matches!(next, Next::Ask(_)), "{all:?}"); 142 // An answerable question is either answered already or on its way to the LLM. 143 if answerable { 144 assert!(matches!(next, Next::Do(_)) || !network.shows(&all).is_empty(), "{all:?}"); 145 } 146 } 147 } 148 } 149 } 150} 151 152#[test] 153fn only_a_fit_question_jev_could_answer_is_listed() { 154 let network = Network::lmjtfy(); 155 assert!(network.notes(&known(&[(Fact::Answerable, YES), (Fact::Fit, YES)]), Note::List)); 156 assert!(!network.notes(&known(&[(Fact::Answerable, YES), (Fact::Fit, NO)]), Note::List)); 157 assert!(!network.notes(&known(&[(Fact::Answerable, NO), (Fact::Fit, YES)]), Note::List)); 158 assert!(!network.notes(&known(&[(Fact::Answerable, YES)]), Note::List)); 159} 160 161#[test] 162fn half_a_question_is_noted_and_still_answered() { 163 let network = Network::lmjtfy(); 164 let whole = facts(true, false, &[NOUL], false, true); 165 assert!(!network.notes(&whole, Note::Unfinished)); 166 // One that stops part way is said to, and what happens to it is the same. 167 let mut half = whole.clone(); 168 half.learn(Fact::Whole, NO); 169 assert!(network.notes(&half, Note::Unfinished)); 170 assert_eq!((network.next(&half), network.shows(&half)), (network.next(&whole), network.shows(&whole))); 171 // Until Jev has said, it is not called unfinished. 172 half.forget(Fact::Whole); 173 assert!(!network.notes(&half, Note::Unfinished)); 174 assert_eq!(network.next(&half), Next::Ask(vec![Fact::Whole])); 175} 176 177#[test] 178fn a_note_never_decides_a_step() { 179 let network = Network::lmjtfy(); 180 let all = facts(true, false, &[NOUL, CHOICE], false, true); 181 let (by, next) = network.decide(&all); 182 assert_eq!(next, Next::Do(Effect::Draft(Want::Options))); 183 assert_eq!(network.terminals[by.unwrap()].name, "draft options"); 184 assert_eq!(network.decide(&Known::default()).0, None); 185} 186 187#[test] 188fn rules_share_the_tests_they_have_in_common() { 189 let network = Network::lmjtfy(); 190 let tests: usize = RULES.iter().map(|rule| rule.when.len()).sum(); 191 assert_eq!(tests, 28); 192 // "one answerable question" is five rules' first two tests, and two joins. 193 let one = network.joins.iter().filter(|join| join.depth == 2 && network.alphas[join.alpha] == ONE[1]).count(); 194 assert_eq!(one, 1); 195 assert_eq!(network.terminals.len(), RULES.len()); 196 assert!(network.joins.len() < tests); 197} 198 199#[test] 200fn a_failed_test_fails_everything_after_it_and_nothing_before() { 201 let network = Network::lmjtfy(); 202 let some = known(&[(Fact::Answerable, YES), (Fact::Several, NO), (NOUL, NO)]); 203 let direct = network.terminals.iter().find(|terminal| terminal.name == "answer yes or no").unwrap(); 204 assert_eq!(network.join(direct.join, &some), State::Fails); 205 let options = network.terminals.iter().find(|terminal| terminal.name == "draft options").unwrap(); 206 assert_eq!(network.join(options.join, &some), State::Waits); 207 let one = network.joins[options.join].left.unwrap(); 208 assert_eq!(network.join(one, &some), State::Holds); 209} 210 211#[test] 212fn only_what_a_holding_rule_stands_on_is_used() { 213 let network = Network::lmjtfy(); 214 let all = facts(true, false, &[CHOICE], false, false); 215 let (_, alphas) = network.used(&all); 216 let used: Vec<Test> = network.alphas.iter().zip(&alphas).filter(|(_, used)| **used).map(|(test, _)| *test).collect(); 217 assert_eq!(used, [Test::Is(Fact::Answerable, YES), Test::Is(Fact::Several, NO), Test::Is(CHOICE, YES)]); 218}