summaryrefslogtreecommitdiffstats
path: root/tests/roulette.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/roulette.rs184
1 files changed, 184 insertions, 0 deletions
diff --git a/tests/roulette.rs b/tests/roulette.rs
new file mode 100644
index 0000000..6b99d17
--- /dev/null
+++ b/tests/roulette.rs
@@ -0,0 +1,184 @@
1use zagan_bet::roulette::{
2 color, is_black, is_even, is_odd, is_red, rtp, Bets, NumberBet, WHEEL,
3};
4use zagan_bet::server::games::roulette::RouletteGame;
5use zagan_bet::server::games::traits::Game;
6
7#[test]
8fn the_european_wheel_has_all_37_unique_pockets() {
9 let mut numbers = WHEEL.to_vec();
10 numbers.sort_unstable();
11 assert_eq!(numbers, (0..=36).collect::<Vec<_>>());
12 assert_eq!(color(0), "green");
13 assert_eq!(WHEEL.len(), 37);
14}
15
16#[test]
17fn colors_and_even_odd_are_correct() {
18 assert!(is_red(1));
19 assert!(is_black(2));
20 assert!(!is_red(0));
21 assert!(!is_black(0));
22 assert!(is_even(2));
23 assert!(is_odd(3));
24 assert!(!is_even(0));
25 assert!(!is_odd(0));
26 assert_eq!(color(17), "black");
27 assert_eq!(color(18), "red");
28}
29
30#[test]
31fn european_rtp_is_36_over_37() {
32 assert!((rtp() - 36.0 / 37.0).abs() < 1e-12);
33}
34
35#[test]
36fn bets_total_and_winning_number_payouts() {
37 let bets = Bets {
38 red: 10,
39 black: 10,
40 even: 10,
41 odd: 10,
42 numbers: vec![NumberBet {
43 number: 17,
44 amount: 5,
45 }],
46 };
47
48 assert_eq!(bets.total(), 45);
49 // 17 is black and odd: 10*2 + 10*2 + 5*36.
50 assert_eq!(bets.winnings(17), 220);
51 // 18 is red and even.
52 assert_eq!(bets.winnings(18), 40);
53}
54
55#[test]
56fn zero_loses_all_outside_bets_but_pays_a_straight_zero() {
57 let outside = Bets {
58 red: 10,
59 black: 10,
60 even: 10,
61 odd: 10,
62 numbers: vec![],
63 };
64 assert_eq!(outside.winnings(0), 0);
65
66 let straight = Bets {
67 red: 10,
68 black: 10,
69 even: 10,
70 odd: 10,
71 numbers: vec![NumberBet {
72 number: 0,
73 amount: 5,
74 }],
75 };
76 assert_eq!(straight.total(), 45);
77 assert_eq!(straight.winnings(0), 180);
78}
79
80#[test]
81fn bets_validate_empty_balance_and_invalid_numbers() {
82 assert!(Bets::default().validate(1000).is_err());
83
84 let too_big = Bets {
85 red: 2000,
86 ..Bets::default()
87 };
88 assert!(too_big.validate(1000).is_err());
89
90 let bad_number = Bets {
91 numbers: vec![NumberBet {
92 number: 37,
93 amount: 10,
94 }],
95 ..Bets::default()
96 };
97 assert!(bad_number.validate(1000).is_err());
98}
99
100#[test]
101fn the_server_settles_a_split_bet() {
102 let bets = Bets {
103 red: 10,
104 black: 10,
105 even: 10,
106 odd: 10,
107 numbers: vec![NumberBet {
108 number: 17,
109 amount: 5,
110 }],
111 };
112 let payload = serde_json::to_string(&bets).unwrap();
113 let game = RouletteGame::with_result(17);
114 let state = game.prepare_state("alice", bets.total());
115
116 let state = game.process_action(&state, "spin", &[&payload]).unwrap();
117 let result = game.calculate_result(&state).unwrap();
118
119 assert_eq!(result.winnings, 220);
120 assert_eq!(result.result_data.get("number").unwrap(), "17");
121 assert_eq!(result.result_data.get("color").unwrap(), "black");
122 assert_eq!(result.result_data.get("bets").unwrap(), &payload);
123}
124
125#[test]
126fn the_server_rejects_a_total_that_does_not_match_the_bets() {
127 let payload = serde_json::to_string(&Bets {
128 red: 10,
129 ..Bets::default()
130 })
131 .unwrap();
132 let game = RouletteGame::with_result(17);
133 let state = game.prepare_state("alice", 99);
134
135 assert!(game.process_action(&state, "spin", &[&payload]).is_err());
136}
137
138#[test]
139fn the_server_rejects_an_invalid_number() {
140 let payload = serde_json::to_string(&Bets {
141 numbers: vec![NumberBet {
142 number: 37,
143 amount: 10,
144 }],
145 ..Bets::default()
146 })
147 .unwrap();
148 let game = RouletteGame::with_result(17);
149 let state = game.prepare_state("alice", 10);
150
151 assert!(game.process_action(&state, "spin", &[&payload]).is_err());
152}
153
154#[test]
155fn parses_a_roulette_result() {
156 let bets = r#"{"red":10,"black":0,"even":10,"odd":0,"numbers":[{"number":17,"amount":10}]}"#;
157 let response = format!("ROULETTE_RESULT session-1 360 30 1330 17 black {bets}");
158 let result = zagan_bet::client::games::response::parse_roulette_response(&response).unwrap();
159
160 assert_eq!(result.session_id, "session-1");
161 assert_eq!(result.winnings, 360);
162 assert_eq!(result.bet_amount, 30);
163 assert_eq!(result.balance, 1330);
164 assert_eq!(result.number, 17);
165 assert_eq!(result.color, "black");
166 assert_eq!(result.bets, bets);
167}
168
169#[test]
170fn rejects_bad_roulette_results() {
171 use zagan_bet::client::games::response::parse_roulette_response;
172
173 let valid_bets = r#"{"red":10}"#;
174 assert!(parse_roulette_response(&format!(
175 "ROULETTE_RESULT s 1 1 1 37 green {valid_bets}"
176 ))
177 .is_err());
178 assert!(parse_roulette_response(&format!(
179 "ROULETTE_RESULT s 1 1 1 17 purple {valid_bets}"
180 ))
181 .is_err());
182 assert!(parse_roulette_response("ROULETTE_RESULT s 1 1 1 17 black nope").is_err());
183 assert!(parse_roulette_response("").is_err());
184}