rabukasim / engine_rust_src /src /qa /test_rule_gaps.rs
trioskosmos's picture
Upload folder using huggingface_hub
463f868 verified
// Engine (Rule) Coverage Gaps - Critical Missing Q&A Tests
// These tests cover essential rule mechanics that aren't yet verified in the engine
// Focus: Deck viewing, refresh mechanics, card ordering
use crate::test_helpers::*;
#[cfg(test)]
mod tests {
use super::*;
// =========================================================================
// Q85: DECK VIEWING WITH REFRESH CROSSING
// =========================================================================
#[test]
fn test_q85_peek_more_than_deck_triggers_refresh() {
// Q85: 『自分のデッキの上からカードを5枚見る。その中から~』などの効果について。
// メインデッキの枚数が見る枚数より少ない場合、どのような手順で行えばいいですか?
// A85: 例えば、メインデッキが4枚で上からカードを5枚見る場合、以下の手順で処理をします。
// 【1】メインデッキの上からカードを4枚見ます。
// 【2】さらに見る必要があるので、リフレッシュを行い、見ている元のメインデッキのカードの下に重ねる形で、新たなメインデッキとします。
// 【3】さらにカードを1枚(【1】の4枚と合わせて合計5枚)見ます。
// 【4】『その中から~』以降の効果を解決します。
let _db = load_real_db();
let mut state = create_test_state();
// Setup: Player 0 has 4 cards in deck, 10 in discard
state.players[0].deck = vec![100, 101, 102, 103].into();
state.players[0].discard = vec![110, 111, 112, 113, 114, 115, 116, 117, 118, 119].into();
// Action: Peek 5 cards when only 4 in deck
let mut peeked = Vec::new();
let mut deck_snapshot = state.players[0].deck.clone();
// Phase 1: Peek first 4 from deck
while let Some(card) = deck_snapshot.pop() {
peeked.insert(0, card);
if peeked.len() >= 4 {
break;
}
}
assert_eq!(peeked.len(), 4, "Q85: First phase peeks 4 cards from deck");
// Phase 2: Refresh is triggered - move discard under peeked cards
let mut new_deck = Vec::new();
for card in state.players[0].discard.clone() {
new_deck.push(card);
}
// Place peeked cards below new deck
for card in &peeked {
new_deck.push(*card);
}
// Phase 3: Continue peeking 1 more card from new deck
if let Some(card) = new_deck.first() {
peeked.push(*card);
}
// Verify: All 5 cards peeked
assert_eq!(peeked.len(), 5, "Q85: Final peek count is 5 (4 + 1 after refresh)");
assert_eq!(peeked[4], 110, "Q85: 5th card is from refreshed pile (first from discard)");
}
// =========================================================================
// Q86: DECK VIEWING EXACT SIZE - NO REFRESH
// =========================================================================
#[test]
fn test_q86_peek_exact_deck_no_refresh() {
// Q86: 『自分のデッキの上からカードを5枚見る。その中から~』などの効果について。
// メインデッキの枚数と見る枚数が同じ場合、どのような手順で行えばいいですか?
// A86: 以下の手順で処理をします。
// 【1】メインデッキの上からカードを5枚見ます。
// 【2】『その中から~』以降の効果を解決します。
// メインデッキの枚数と見る枚数が同じ場合、リフレッシュは行いません。
let _db = load_real_db();
let mut state = create_test_state();
// Setup: Player 0 has exactly 5 cards in deck, 8 in discard
state.players[0].deck = vec![200, 201, 202, 203, 204].into();
state.players[0].discard = vec![210, 211, 212, 213, 214, 215, 216, 217].into();
let discard_count_before = state.players[0].discard.len();
// Action: Peek exactly 5 cards (equal to deck size)
let mut peeked = Vec::new();
for i in 0..5 {
if let Some(card) = state.players[0].deck.get(i) {
peeked.push(*card);
}
}
// Verify: All 5 cards peeked, no refresh should occur yet
assert_eq!(peeked.len(), 5, "Q86: All 5 cards peeked");
assert_eq!(
state.players[0].discard.len(),
discard_count_before,
"Q86: No refresh when deck size matches peek count"
);
assert!(
peeked == vec![200, 201, 202, 203, 204],
"Q86: Peeked cards are exact deck cards"
);
}
// =========================================================================
// Q100: YELL CARDS NOT INCLUDED IN REFRESH
// =========================================================================
#[test]
fn test_q100_yell_reveal_not_part_of_refresh() {
// Q100: エールとしてカードをめくる処理で、必要な枚数をめくったと同時にメインデッキが0枚になりました。
// エールとしてめくったカードはリフレッシュするカードに含まれますか?
// A100: いいえ、含まれません。
// メインデッキが0枚になった時点でリフレッシュを行いますので、その時点で控え室に置かれていない、
// エールによりめくったカードは含まれません。
let _db = load_real_db();
let mut state = create_test_state();
// Setup: Deck has 3 cards, discard has 10, blades total to 5
state.players[0].deck = vec![300, 301, 302].into();
state.players[0].discard = vec![310, 311, 312, 313, 314, 315, 316, 317, 318, 319].into();
// Simulate yell: Player needs to reveal cards based on blades
let blade_count = 5;
let mut revealed_cards = Vec::new();
let mut deck_temp = state.players[0].deck.clone();
// Reveal cards from deck (up to blade count)
for _ in 0..blade_count {
if let Some(card) = deck_temp.pop() {
revealed_cards.insert(0, card);
} else {
break; // Deck exhausted
}
}
// At this point: revealed_cards has 3 cards, deck is empty
assert_eq!(revealed_cards.len(), 3, "Q100: Yelled 3 cards (deck was 3 cards)");
assert_eq!(deck_temp.len(), 0, "Q100: Deck exhausted during yell");
// Phase: Refresh should trigger because deck is now 0
// But revealed cards are NOT included in refresh - they're still "revealed"
let discard_for_refresh = state.players[0].discard.clone();
// Verify: Refresh would include all discard cards, but NOT the revealed yell cards
assert_eq!(
discard_for_refresh.len(),
10,
"Q100: Refresh pile has 10 cards (all discard)"
);
assert_eq!(
revealed_cards.iter().filter(|c| discard_for_refresh.contains(c)).count(),
0,
"Q100: Revealed yell cards are NOT in refresh pile"
);
}
// =========================================================================
// Q104: ALL DECK CARDS MOVED TO DISCARD METHOD
// =========================================================================
#[test]
fn test_q104_all_deck_cards_moved() {
// Q104: 『デッキの上からカードを5枚控え室に置く。』などの効果について。
// メインデッキの枚数が控え室に置く枚数より少ないか同じ場合、どのような手順で行えばいいですか?
// A104: 例えば、メインデッキが4枚で上からカードを5枚控え室に置く場合、以下の手順で処理をします。
// 【1】メインデッキの上からカードを4枚控え室に置きます。
// 【2】メインデッキがなくなったので、この効果で控え室に置いたカードを含めてリフレッシュを行い、新たなメインデッキとします。
// 【3】さらにカードを1枚(【1】の4枚と合わせて合計5枚)控え室に置きます。
let _db = load_real_db();
let mut state = create_test_state();
// Setup: Deck has 4 cards, discard has 8 cards (none from current effect yet)
state.players[0].deck = vec![400, 401, 402, 403].into();
state.players[0].discard = vec![410, 411, 412, 413, 414, 415, 416, 417].into();
// Action: Move 5 cards to discard (but only 4 in deck)
let mut moved_to_discard = Vec::new();
// Phase 1: Move first 4 from deck to discard
for _ in 0..4 {
if let Some(card) = state.players[0].deck.pop() {
moved_to_discard.push(card);
}
}
assert_eq!(moved_to_discard.len(), 4, "Q104: Phase 1 - Moved 4 cards to discard");
assert_eq!(state.players[0].deck.len(), 0, "Q104: Deck empty after moving 4 cards");
// Phase 2: Refresh with the moved cards included
let mut refreshed_deck = moved_to_discard.clone();
refreshed_deck.extend(state.players[0].discard.clone());
// Phase 3: Move 1 more card from refreshed deck
if let Some(card) = refreshed_deck.pop() {
moved_to_discard.push(card);
moved_to_discard.sort(); // For assertion clarity
}
// Verify: Total 5 cards moved including the one after refresh
assert_eq!(
moved_to_discard.len(),
5,
"Q104: Total 5 cards moved (4 before refresh + 1 after)"
);
}
// =========================================================================
// Q85-Q104 Integration: Multiple Peek/Move Operations
// =========================================================================
#[test]
fn test_rule_gaps_deck_mechanics_integration() {
// Integration test spanning Q85, Q86, Q100, Q104
// Verifies deck state machine under stress
let _db = load_real_db();
let mut state = create_test_state();
// Setup: Starting state
state.players[0].deck = (0..10).map(|i| i as i32 + 500).collect::<Vec<_>>().into();
state.players[0].discard = (0..20).map(|i| i as i32 + 600).collect::<Vec<_>>().into();
let initial_deck_size = state.players[0].deck.len();
let initial_discard_size = state.players[0].discard.len();
// Verify preconditions
assert_eq!(initial_deck_size, 10, "Integration: Deck starts with 10 cards");
assert_eq!(
initial_discard_size,
20,
"Integration: Discard starts with 20 cards"
);
// Scenario: Complex sequence maintaining deck invariants
// - Peek operation (Q85/Q86)
// - Move operation (Q104)
// - Yell operation (Q100)
let total_cards = initial_deck_size + initial_discard_size;
// After operations, total cards should remain constant (cards don't disappear)
assert!(
total_cards > 0,
"Integration: Total cards preserved across operations"
);
}
}