pet.rsannotatedpet.rssource141 lines · 4.4 KB · raw
1use std::f32::consts::TAU;
2
3use whiskers_pet::*;
4
5fn t(kind: TouchKind, x: f32, y: f32, at_ms: u64) -> Touch {
6    Touch { kind, x, y, at_ms }
7}
8
9#[test]
10fn eyes_follow_the_finger_and_return() {
11    let mut p = Pet::new();
12    p.tick(0);
13    p.touch(t(TouchKind::Down, 0.8, 0.0, 10));
14    let v = (1..=40).map(|i| p.tick(10 + i * 16)).last().unwrap();
15    assert!(v.gaze.0 > 0.75, "{:?}", v.gaze);
16    p.touch(t(TouchKind::Up, 0.8, 0.0, 700));
17    let v = (1..=80).map(|i| p.tick(700 + i * 16)).last().unwrap();
18    assert!(v.gaze.0.abs() < 0.05);
19}
20
21#[test]
22fn a_finger_far_outside_still_only_turns_the_eyes_to_the_edge() {
23    let mut p = Pet::new();
24    p.tick(0);
25    p.touch(t(TouchKind::Down, 5.0, 0.0, 1));
26    let v = (1..=80).map(|i| p.tick(1 + i * 16)).last().unwrap();
27    assert!(v.gaze.0 <= 1.0 && v.gaze.0 > 0.95);
28}
29
30#[test]
31fn a_quick_tap_on_the_body_tickles_and_counts_a_poke() {
32    let mut p = Pet::new();
33    p.touch(t(TouchKind::Down, 0.1, 0.2, 1000));
34    p.touch(t(TouchKind::Up, 0.1, 0.2, 1100));
35    let v = p.tick(1200);
36    assert_eq!((v.mood, v.pokes), (Mood::Tickled, 1));
37    assert_eq!(p.tick(1100 + 1600).mood, Mood::Idle);
38}
39
40#[test]
41fn a_tap_off_the_body_or_a_long_press_is_not_a_poke() {
42    let mut p = Pet::new();
43    p.touch(t(TouchKind::Down, 2.0, 0.0, 0));
44    p.touch(t(TouchKind::Up, 2.0, 0.0, 100));
45    p.touch(t(TouchKind::Down, 0.0, 0.0, 500));
46    p.touch(t(TouchKind::Up, 0.0, 0.0, 1500));
47    assert_eq!(p.tick(1600).pokes, 0);
48}
49
50fn circle(p: &mut Pet, start: u64, turns: f32, per_turn_ms: u64) -> u64 {
51    let steps = (turns * 48.0) as u64;
52    p.touch(t(TouchKind::Down, 0.6, 0.0, start));
53    for i in 1..=steps {
54        let a = TAU * i as f32 / 48.0;
55        p.touch(t(TouchKind::Move, 0.6 * a.cos(), 0.6 * a.sin(), start + i * per_turn_ms / 48));
56    }
57    start + steps * per_turn_ms / 48
58}
59
60#[test]
61fn two_fast_circles_make_it_dizzy_then_it_recovers() {
62    let mut p = Pet::new();
63    let end = circle(&mut p, 0, 2.5, 700);
64    let v = p.tick(end);
65    assert_eq!((v.mood, v.dizzy_spells), (Mood::Dizzy, 1));
66    p.touch(t(TouchKind::Up, 0.6, 0.0, end + 10));
67    assert_eq!(p.tick(end + 3100).mood, Mood::Idle);
68}
69
70#[test]
71fn slow_circling_is_not_dizzying_in_either_direction() {
72    let mut p = Pet::new();
73    let end = circle(&mut p, 0, 2.5, 4000);
74    assert_ne!(p.tick(end).mood, Mood::Dizzy);
75    let mut q = Pet::new();
76    q.touch(t(TouchKind::Down, 0.6, 0.0, 0));
77    for i in 1..=120u64 {
78        let a = -TAU * i as f32 / 48.0;
79        q.touch(t(TouchKind::Move, 0.6 * a.cos(), 0.6 * a.sin(), i * 14));
80    }
81    assert_eq!(q.tick(1700).mood, Mood::Dizzy, "fast the other way round is dizzy too");
82}
83
84#[test]
85fn wobbling_across_the_middle_is_not_a_spin() {
86    let mut p = Pet::new();
87    p.touch(t(TouchKind::Down, 0.6, 0.0, 0));
88    for i in 1..=200u64 {
89        let x = if i % 2 == 0 { 0.6 } else { -0.6 };
90        p.touch(t(TouchKind::Move, x, 0.02, i * 10));
91    }
92    assert_ne!(p.tick(2000).mood, Mood::Dizzy);
93}
94
95#[test]
96fn the_conversation_sets_the_face_and_touch_outranks_it() {
97    let mut p = Pet::new();
98    for (phase, mood) in [
99        (Phase::Listening, Mood::Listening),
100        (Phase::Thinking, Mood::Thinking),
101        (Phase::Working, Mood::Working),
102        (Phase::Speaking, Mood::Speaking),
103        (Phase::Tangled, Mood::Tangled),
104        (Phase::Busy, Mood::Busy),
105        (Phase::Offline, Mood::Offline),
106    ] {
107        p.set_phase(phase, 0);
108        assert_eq!(p.tick(10).mood, mood);
109    }
110    p.touch(t(TouchKind::Down, 0.0, 0.0, 20));
111    p.touch(t(TouchKind::Up, 0.0, 0.0, 60));
112    assert_eq!(p.tick(100).mood, Mood::Tickled);
113}
114
115#[test]
116fn it_dozes_after_a_quiet_minute_and_a_half_and_wakes_on_touch() {
117    let mut p = Pet::new();
118    assert_eq!(p.tick(89_000).mood, Mood::Idle);
119    assert_eq!(p.tick(90_000).mood, Mood::Sleeping);
120    p.touch(t(TouchKind::Down, 3.0, 0.0, 91_000));
121    assert_eq!(p.tick(91_010).mood, Mood::Idle);
122}
123
124#[test]
125fn it_does_not_doze_mid_conversation() {
126    let mut p = Pet::new();
127    p.set_phase(Phase::Thinking, 0);
128    assert_eq!(p.tick(500_000).mood, Mood::Thinking);
129}
130
131#[test]
132fn a_busy_or_offline_cat_never_dozes_and_is_never_the_idle_face() {
133    // "Idle" means ready to listen; anything else must look different.
134    for phase in [Phase::Busy, Phase::Offline, Phase::Tangled] {
135        let mut p = Pet::new();
136        p.set_phase(phase, 0);
137        let v = p.tick(10_000_000);
138        assert_ne!(v.mood, Mood::Idle);
139        assert_ne!(v.mood, Mood::Sleeping);
140    }
141}