summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/slots.rs92
1 files changed, 92 insertions, 0 deletions
diff --git a/tests/slots.rs b/tests/slots.rs
new file mode 100644
index 0000000..c50f425
--- /dev/null
+++ b/tests/slots.rs
@@ -0,0 +1,92 @@
1//! Regression tests for the server-side slots game logic.
2
3use zagan_bet::server_game_traits::{Game, GamePhase};
4use zagan_bet::server_slots::SlotsGame;
5
6fn make_game() -> SlotsGame {
7 SlotsGame::new()
8}
9
10/// Three of a kind pays the three-of-a-kind multiplier.
11#[test]
12fn three_of_a_kind_pays() {
13 let game = make_game();
14 // CCC = 5x
15 assert_eq!(game.calculate_payout(&['C', 'C', 'C'], 100), 500);
16 // SSS = 100x
17 assert_eq!(game.calculate_payout(&['S', 'S', 'S'], 10), 1000);
18}
19
20/// Two adjacent matching symbols pays the two-of-a-kind multiplier.
21#[test]
22fn two_adjacent_pays() {
23 let game = make_game();
24 // CC? = 2x
25 assert_eq!(game.calculate_payout(&['C', 'C', 'D'], 100), 200);
26 // ?LL = 3x
27 assert_eq!(game.calculate_payout(&['D', 'L', 'L'], 50), 150);
28}
29
30/// Non-adjacent matching symbols (e.g. [C,D,C]) must also pay.
31/// This was a bug: the old code only checked pairs (0,1) and (1,2).
32#[test]
33fn two_non_adjacent_pays() {
34 let game = make_game();
35 // C,D,C — two cherries at positions 0 and 2
36 assert_eq!(game.calculate_payout(&['C', 'D', 'C'], 100), 200);
37 // S,X,S — two sevens at positions 0 and 2
38 assert_eq!(game.calculate_payout(&['S', 'L', 'S'], 10), 200);
39 // L,O,L
40 assert_eq!(game.calculate_payout(&['L', 'O', 'L'], 50), 150);
41}
42
43/// No matching symbols returns 0.
44#[test]
45fn no_match_returns_zero() {
46 let game = make_game();
47 assert_eq!(game.calculate_payout(&['C', 'L', 'O'], 100), 0);
48 assert_eq!(game.calculate_payout(&['G', 'D', 'S'], 50), 0);
49}
50
51/// process_action produces a finished state with correct reels and win_type.
52#[test]
53fn process_action_spin_sets_finished() {
54 let game = make_game();
55 let state = game.prepare_state("alice", 100);
56 assert_eq!(state.phase, GamePhase::WaitingToStart);
57
58 // Manually set reels by going through process_action.
59 // Since spin is random, we test the state machine rather than the outcome.
60 let result = game.process_action(&state, "spin", &[]);
61 assert!(result.is_ok());
62 let new_state = result.unwrap();
63 assert_eq!(new_state.phase, GamePhase::Finished);
64 assert!(new_state.data.contains_key("reels"));
65 assert!(new_state.data.contains_key("win_type"));
66}
67
68/// calculate_result on a finished state returns valid GameResult.
69#[test]
70fn calculate_result_on_finished_state() {
71 let game = make_game();
72 let mut state = game.prepare_state("alice", 100);
73 state.phase = GamePhase::Finished;
74 state
75 .data
76 .insert("reels".to_string(), "CCD".to_string());
77 state
78 .data
79 .insert("win_type".to_string(), "two".to_string());
80
81 let result = game.calculate_result(&state).unwrap();
82 assert_eq!(result.bet_amount, 100);
83 assert_eq!(result.winnings, 200); // CC = 2x
84}
85
86/// calculate_result on a non-finished state returns an error.
87#[test]
88fn calculate_result_on_unfinished_state() {
89 let game = make_game();
90 let state = game.prepare_state("alice", 100);
91 assert!(game.calculate_result(&state).is_err());
92}