summaryrefslogtreecommitdiffstats
path: root/tests/server_core.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-29 18:22:40 +0100
committersalmonik <salmonik@tuta.io>2026-10-29 18:22:40 +0100
commitb5a52fc0312afdf5d5fbe53275dc88d6d881c2ff (patch)
treed12e3c7f6c23ae1698199d16ee763551edfd8c12 /tests/server_core.rs
parentv2.1.2: ignore ANSI when measuring board height (diff)
downloadzagan-bet-b5a52fc0312afdf5d5fbe53275dc88d6d881c2ff.tar.gz
zagan-bet-b5a52fc0312afdf5d5fbe53275dc88d6d881c2ff.zip
v2.2.0: add blackjack with reserved bets and hit/stand/double
Diffstat (limited to 'tests/server_core.rs')
-rw-r--r--tests/server_core.rs159
1 files changed, 159 insertions, 0 deletions
diff --git a/tests/server_core.rs b/tests/server_core.rs
index cf05102..3ad277a 100644
--- a/tests/server_core.rs
+++ b/tests/server_core.rs
@@ -1,6 +1,7 @@
1use std::path::PathBuf; 1use std::path::PathBuf;
2 2
3use rusqlite::Connection; 3use rusqlite::Connection;
4use zagan_bet::blackjack::BlackjackState;
4use zagan_bet::server::core::{ConnectionState, ServerCore}; 5use zagan_bet::server::core::{ConnectionState, ServerCore};
5use zagan_bet::server::database; 6use zagan_bet::server::database;
6use zagan_bet::server::games::registry::GameRegistry; 7use zagan_bet::server::games::registry::GameRegistry;
@@ -47,6 +48,31 @@ fn setup_roulette(name: &str, number: u8) -> (ServerCore, String) {
47 (ServerCore::with_registry(conn, registry, 4), path) 48 (ServerCore::with_registry(conn, registry, 4), path)
48} 49}
49 50
51fn setup_blackjack(name: &str, deck: &[&str]) -> (ServerCore, String) {
52 let path = PathBuf::from(env!("CARGO_TARGET_TMPDIR"))
53 .join(format!("server-core-{name}.db"))
54 .to_string_lossy()
55 .into_owned();
56 let _ = std::fs::remove_file(&path);
57
58 let conn = Connection::open(&path).unwrap();
59 database::init_db(&conn);
60
61 let deck = deck.iter().map(|card| card.to_string()).collect();
62 (
63 ServerCore::with_registry(conn, GameRegistry::with_defaults(), 4)
64 .with_blackjack_deck(deck),
65 path,
66 )
67}
68
69fn blackjack_state(response: &str) -> BlackjackState {
70 let raw = response
71 .strip_prefix("BLACKJACK_STATE ")
72 .expect("blackjack state response");
73 serde_json::from_str(raw).expect("valid blackjack state")
74}
75
50fn register(core: &mut ServerCore, state: &mut ConnectionState, user: &str) { 76fn register(core: &mut ServerCore, state: &mut ConnectionState, user: &str) {
51 assert_eq!( 77 assert_eq!(
52 core.handle_message(state, &format!("REGISTER {user} credential")), 78 core.handle_message(state, &format!("REGISTER {user} credential")),
@@ -337,3 +363,136 @@ fn unknown_games_are_rejected_before_a_session_is_created() {
337 ); 363 );
338 assert_eq!(core.session_count(), 0); 364 assert_eq!(core.session_count(), 0);
339} 365}
366
367#[test]
368fn blackjack_reserves_the_bet_and_settles_a_hit_hand() {
369 let (mut core, path) = setup_blackjack(
370 "blackjack-hit",
371 &["10S", "9D", "6H", "8C", "5D"],
372 );
373 let mut state = ConnectionState::default();
374 register(&mut core, &mut state, "alice");
375 login(&mut core, &mut state, "alice");
376
377 let response = core.handle_message(&mut state, "PLAY_START blackjack 10");
378 let current = blackjack_state(&response);
379
380 assert_eq!(current.phase, "player");
381 assert_eq!(current.player_total, 16);
382 assert_eq!(current.dealer, vec!["9D".to_string(), "?".to_string()]);
383 assert_eq!(current.balance, 990);
384 assert_eq!(current.actions, vec!["hit", "stand", "double"]);
385 assert_eq!(core.session_count(), 1);
386
387 let response = core.handle_message(
388 &mut state,
389 &format!("BLACKJACK_ACTION {} hit", current.session_id),
390 );
391 let done = blackjack_state(&response);
392
393 assert_eq!(done.phase, "done");
394 assert_eq!(done.result, "win");
395 assert_eq!(done.winnings, 20);
396 assert_eq!(done.balance, 1010);
397 assert_eq!(core.balance("alice"), Some(1010));
398 assert_eq!(core.play_count("alice"), 1);
399 assert_eq!(core.session_count(), 0);
400
401 let conn = Connection::open(&path).unwrap();
402 let (game_type, details): (String, String) = conn
403 .query_row(
404 "SELECT game_type, details FROM plays WHERE username = 'alice'",
405 [],
406 |row| Ok((row.get(0)?, row.get(1)?)),
407 )
408 .unwrap();
409 assert_eq!(game_type, "blackjack");
410 let details: BlackjackState = serde_json::from_str(&details).unwrap();
411 assert_eq!(details.result, "win");
412 assert_eq!(details.winnings, 20);
413}
414
415#[test]
416fn blackjack_double_reserves_an_extra_bet() {
417 let (mut core, _path) = setup_blackjack(
418 "blackjack-double",
419 &["5S", "9D", "5H", "8C", "10D"],
420 );
421 let mut state = ConnectionState::default();
422 register(&mut core, &mut state, "alice");
423 login(&mut core, &mut state, "alice");
424
425 let current = blackjack_state(&core.handle_message(&mut state, "PLAY_START blackjack 10"));
426 assert_eq!(current.balance, 990);
427
428 let done = blackjack_state(&core.handle_message(
429 &mut state,
430 &format!("BLACKJACK_ACTION {} double", current.session_id),
431 ));
432
433 assert_eq!(done.phase, "done");
434 assert_eq!(done.bet, 20);
435 assert_eq!(done.winnings, 40);
436 assert_eq!(done.balance, 1020);
437 assert_eq!(core.balance("alice"), Some(1020));
438 assert_eq!(core.play_count("alice"), 1);
439}
440
441#[test]
442fn blackjack_natural_settles_immediately() {
443 let (mut core, _path) =
444 setup_blackjack("blackjack-natural", &["AS", "9D", "KH", "8C"]);
445 let mut state = ConnectionState::default();
446 register(&mut core, &mut state, "alice");
447 login(&mut core, &mut state, "alice");
448
449 let done = blackjack_state(&core.handle_message(&mut state, "PLAY_START blackjack 10"));
450
451 assert_eq!(done.phase, "done");
452 assert_eq!(done.result, "blackjack");
453 assert_eq!(done.winnings, 25);
454 assert_eq!(done.balance, 1015);
455 assert_eq!(core.session_count(), 0);
456 assert_eq!(core.play_count("alice"), 1);
457}
458
459#[test]
460fn blackjack_cancel_refunds_the_reserved_bet() {
461 let (mut core, _path) =
462 setup_blackjack("blackjack-cancel", &["10S", "9D", "6H", "8C"]);
463 let mut state = ConnectionState::default();
464 register(&mut core, &mut state, "alice");
465 login(&mut core, &mut state, "alice");
466
467 let current = blackjack_state(&core.handle_message(&mut state, "PLAY_START blackjack 10"));
468 assert_eq!(current.balance, 990);
469
470 let cancelled = blackjack_state(&core.handle_message(
471 &mut state,
472 &format!("BLACKJACK_ACTION {} cancel", current.session_id),
473 ));
474
475 assert_eq!(cancelled.result, "cancelled");
476 assert_eq!(cancelled.balance, 1000);
477 assert_eq!(core.balance("alice"), Some(1000));
478 assert_eq!(core.play_count("alice"), 0);
479 assert_eq!(core.session_count(), 0);
480}
481
482#[test]
483fn blackjack_disconnect_refunds_the_reserved_bet() {
484 let (mut core, _path) =
485 setup_blackjack("blackjack-disconnect", &["10S", "9D", "6H", "8C"]);
486 let mut state = ConnectionState::default();
487 register(&mut core, &mut state, "alice");
488 login(&mut core, &mut state, "alice");
489
490 let current = blackjack_state(&core.handle_message(&mut state, "PLAY_START blackjack 10"));
491 assert_eq!(current.balance, 990);
492
493 core.disconnect(&state);
494
495 assert_eq!(core.balance("alice"), Some(1000));
496 assert_eq!(core.play_count("alice"), 0);
497 assert_eq!(core.session_count(), 0);
498}