// Module 4: Interceptors and "trigger twice". Each test matches a heading in scenarios.md. use engine::harness::*; fn game_with_deck() -> Game { new_game(GameOpts { decks: Some([vec!["Test Filler".to_string(); 5], vec![]]), }) } fn damaged(target: Id, amount: i32) -> GameEvent { GameEvent::Damaged { target, amount } } fn triggered(source: Id, trigger: &str) -> GameEvent { GameEvent::Triggered { source, trigger: trigger.to_string(), } } fn spell_cast(card: &str) -> GameEvent { GameEvent::SpellCast { card: card.to_string(), } } #[test] fn test_04_baron_doubles() { let mut g = game_with_deck(); let b = g.summon("Baron Rivendare", 0); let h = g.summon("Loot Hoarder", 0); let golem = g.summon("Harvest Golem", 0); g.deal_damage(golem, 2); g.clear_log(); g.cast("Whirlwind", 0, None); let hand = g.hand(0); assert_eq!(hand.len(), 2); let (c1, c2) = (hand[0], hand[1]); let summoned: Vec = g .log() .into_iter() .filter_map(|e| match e { GameEvent::Summoned { id } => Some(id), _ => None, }) .collect(); assert_eq!(summoned.len(), 2); let (d1, d2) = (summoned[0], summoned[1]); assert_eq!( g.log(), vec![ spell_cast("Whirlwind"), damaged(b, 1), damaged(h, 1), damaged(golem, 1), GameEvent::Destroyed { id: h }, GameEvent::Destroyed { id: golem }, GameEvent::DeathPhase { round: 1 }, triggered(h, "deathrattle"), GameEvent::Drew { player: 0, id: c1 }, triggered(h, "deathrattle"), GameEvent::Drew { player: 0, id: c2 }, triggered(golem, "deathrattle"), GameEvent::Summoned { id: d1 }, triggered(golem, "deathrattle"), GameEvent::Summoned { id: d2 }, ] ); assert_eq!(g.name_of(d1), "Damaged Golem"); assert_eq!(g.name_of(d2), "Damaged Golem"); let board = g.board(0); assert_eq!(board.len(), 3); assert_eq!(board[0], b); let mut golems = vec![board[1], board[2]]; golems.sort(); let mut expected = vec![d1, d2]; expected.sort(); assert_eq!(golems, expected); assert_eq!(g.health(b), 6); } #[test] fn test_04_simultaneous_death_not_doubled() { let mut g = game_with_deck(); let b = g.summon("Baron Rivendare", 0); let h = g.summon("Loot Hoarder", 0); g.clear_log(); g.cast("Twisting Nether", 0, None); assert_eq!(g.hand(0).len(), 1); let hoarder_triggers = g .log() .into_iter() .filter(|e| *e == triggered(h, "deathrattle")) .count(); assert_eq!(hoarder_triggers, 1); assert_eq!(g.zone_of(b), Zone::Graveyard); assert_eq!(g.zone_of(h), Zone::Graveyard); } #[test] fn test_04_two_barons_do_not_stack() { let mut g = game_with_deck(); g.summon("Baron Rivendare", 0); g.summon("Baron Rivendare", 0); let h = g.summon("Loot Hoarder", 0); g.clear_log(); g.deal_damage(h, 1); let hand = g.hand(0); assert_eq!(hand.len(), 2); let (c1, c2) = (hand[0], hand[1]); assert_eq!( g.log(), vec![ damaged(h, 1), GameEvent::Destroyed { id: h }, GameEvent::DeathPhase { round: 1 }, triggered(h, "deathrattle"), GameEvent::Drew { player: 0, id: c1 }, triggered(h, "deathrattle"), GameEvent::Drew { player: 0, id: c2 }, ] ); } #[test] fn test_04_aura_timing_order() { let mut g = game_with_deck(); let h = g.summon("Loot Hoarder", 0); let b = g.summon("Baron Rivendare", 0); g.clear_log(); g.cast("Twisting Nether", 0, None); let hand = g.hand(0); assert_eq!(hand.len(), 1); let c = hand[0]; assert_eq!( g.log(), vec![ spell_cast("Twisting Nether"), GameEvent::Destroyed { id: h }, GameEvent::Destroyed { id: b }, GameEvent::DeathPhase { round: 1 }, triggered(h, "deathrattle"), GameEvent::Drew { player: 0, id: c }, ] ); } #[test] fn test_04_battlecry_on_play() { let mut g = game_with_deck(); let e = g.add_to_hand("Novice Engineer", 0); g.clear_log(); g.play(e); let hand = g.hand(0); assert_eq!(hand.len(), 1); let c = hand[0]; assert_eq!( g.log(), vec![ GameEvent::Summoned { id: e }, triggered(e, "battlecry"), GameEvent::Drew { player: 0, id: c }, ] ); assert_eq!(g.zone_of(e), Zone::Board); assert_eq!(g.board(0), vec![e]); }