Skip to main content

lean_ctx/core/buddy/
mod.rs

1mod format;
2mod rpg;
3mod sprite;
4mod types;
5
6pub use format::{format_buddy_block, format_buddy_block_at, format_buddy_full};
7pub use sprite::render_sprite;
8pub use types::{BuddyState, BuddyStats, CreatureTraits, Mood, Rarity, Species};
9
10#[cfg(test)]
11mod tests {
12    use super::*;
13    use std::collections::HashMap;
14
15    #[test]
16    fn species_from_cargo_commands() {
17        let mut cmds = HashMap::new();
18        cmds.insert(
19            "cargo build".to_string(),
20            super::super::stats::CommandStats {
21                count: 50,
22                input_tokens: 1000,
23                output_tokens: 500,
24            },
25        );
26        assert_eq!(Species::from_commands(&cmds), Species::Crab);
27    }
28
29    #[test]
30    fn species_mixed_is_dragon() {
31        let mut cmds = HashMap::new();
32        cmds.insert(
33            "cargo build".to_string(),
34            super::super::stats::CommandStats {
35                count: 10,
36                input_tokens: 0,
37                output_tokens: 0,
38            },
39        );
40        cmds.insert(
41            "npm install".to_string(),
42            super::super::stats::CommandStats {
43                count: 10,
44                input_tokens: 0,
45                output_tokens: 0,
46            },
47        );
48        cmds.insert(
49            "python app.py".to_string(),
50            super::super::stats::CommandStats {
51                count: 10,
52                input_tokens: 0,
53                output_tokens: 0,
54            },
55        );
56        assert_eq!(Species::from_commands(&cmds), Species::Dragon);
57    }
58
59    #[test]
60    fn species_empty_is_egg() {
61        let cmds = HashMap::new();
62        assert_eq!(Species::from_commands(&cmds), Species::Egg);
63    }
64
65    #[test]
66    fn rarity_levels() {
67        assert_eq!(Rarity::from_tokens_saved(0), Rarity::Egg);
68        assert_eq!(Rarity::from_tokens_saved(5_000), Rarity::Egg);
69        assert_eq!(Rarity::from_tokens_saved(50_000), Rarity::Common);
70        assert_eq!(Rarity::from_tokens_saved(500_000), Rarity::Uncommon);
71        assert_eq!(Rarity::from_tokens_saved(5_000_000), Rarity::Rare);
72        assert_eq!(Rarity::from_tokens_saved(50_000_000), Rarity::Epic);
73        assert_eq!(Rarity::from_tokens_saved(500_000_000), Rarity::Legendary);
74    }
75
76    #[test]
77    fn name_is_deterministic() {
78        let s = types::user_seed();
79        let n1 = rpg::generate_name(s);
80        let n2 = rpg::generate_name(s);
81        assert_eq!(n1, n2);
82    }
83
84    #[test]
85    fn format_compact_values() {
86        assert_eq!(rpg::format_compact(500), "500");
87        assert_eq!(rpg::format_compact(1_500), "1.5K");
88        assert_eq!(rpg::format_compact(2_500_000), "2.5M");
89        assert_eq!(rpg::format_compact(3_000_000_000), "3.0B");
90    }
91
92    #[test]
93    fn procedural_sprite_returns_7_lines() {
94        for seed in [0u64, 1, 42, 999, 12345, 69_119_999, u64::MAX] {
95            let traits = CreatureTraits::from_seed(seed);
96            for mood in &[
97                Mood::Ecstatic,
98                Mood::Happy,
99                Mood::Content,
100                Mood::Worried,
101                Mood::Sleeping,
102            ] {
103                let sp = render_sprite(&traits, mood);
104                assert_eq!(sp.len(), 7, "sprite for seed={seed}, mood={mood:?}");
105            }
106        }
107    }
108
109    #[test]
110    fn creature_traits_are_deterministic() {
111        let t1 = CreatureTraits::from_seed(42);
112        let t2 = CreatureTraits::from_seed(42);
113        assert_eq!(t1.head, t2.head);
114        assert_eq!(t1.eyes, t2.eyes);
115        assert_eq!(t1.mouth, t2.mouth);
116        assert_eq!(t1.ears, t2.ears);
117        assert_eq!(t1.body, t2.body);
118        assert_eq!(t1.legs, t2.legs);
119        assert_eq!(t1.tail, t2.tail);
120        assert_eq!(t1.markings, t2.markings);
121    }
122
123    #[test]
124    fn different_seeds_produce_different_traits() {
125        let t1 = CreatureTraits::from_seed(1);
126        let t2 = CreatureTraits::from_seed(9999);
127        let same = t1.head == t2.head
128            && t1.eyes == t2.eyes
129            && t1.mouth == t2.mouth
130            && t1.ears == t2.ears
131            && t1.body == t2.body
132            && t1.legs == t2.legs
133            && t1.tail == t2.tail
134            && t1.markings == t2.markings;
135        assert!(
136            !same,
137            "seeds 1 and 9999 should differ in at least one trait"
138        );
139    }
140
141    #[test]
142    fn total_combinations_is_69m() {
143        assert_eq!(12u64 * 10 * 10 * 12 * 10 * 10 * 8 * 6, 69_120_000);
144    }
145
146    #[test]
147    fn xp_next_level_increases() {
148        let lv1 = (1u64 + 1) * (1 + 1) * 50;
149        let lv10 = (10u64 + 1) * (10 + 1) * 50;
150        assert!(lv10 > lv1);
151    }
152}