werewolf-0.4.3.0: test/src/Game/Werewolf/Test/Command.hs
{-|
Module : Game.Werewolf.Test.Command
Copyright : (c) Henry J. Wylde, 2015
License : BSD3
Maintainer : public@hjwylde.com
-}
{-# OPTIONS_HADDOCK hide, prune #-}
module Game.Werewolf.Test.Command (
-- * devourVoteCommand
prop_devourVoteCommandErrorsWhenGameIsOver, prop_devourVoteCommandErrorsWhenCallerDoesNotExist,
prop_devourVoteCommandErrorsWhenTargetDoesNotExist,
prop_devourVoteCommandErrorsWhenCallerIsDead, prop_devourVoteCommandErrorsWhenTargetIsDead,
prop_devourVoteCommandErrorsWhenNotWerewolvesTurn,
prop_devourVoteCommandErrorsWhenCallerNotWerewolf,
prop_devourVoteCommandErrorsWhenCallerHasVoted, prop_devourVoteCommandErrorsWhenTargetWerewolf,
prop_devourVoteCommandUpdatesVotes,
-- * healCommand
prop_healCommandErrorsWhenGameIsOver, prop_healCommandErrorsWhenCallerDoesNotExist,
prop_healCommandErrorsWhenCallerIsDead, prop_healCommandErrorsWhenNoTargetIsDevoured,
prop_healCommandErrorsWhenNotWitchsTurn, prop_healCommandErrorsWhenCallerHasHealed,
prop_healCommandErrorsWhenCallerNotWitch, prop_healCommandSetsHeal,
prop_healCommandSetsHealUsed,
-- * lynchVoteCommand
prop_lynchVoteCommandErrorsWhenGameIsOver, prop_lynchVoteCommandErrorsWhenCallerDoesNotExist,
prop_lynchVoteCommandErrorsWhenTargetDoesNotExist, prop_lynchVoteCommandErrorsWhenCallerIsDead,
prop_lynchVoteCommandErrorsWhenTargetIsDead, prop_lynchVoteCommandErrorsWhenNotVillagesTurn,
prop_lynchVoteCommandErrorsWhenCallerHasVoted, prop_lynchVoteCommandUpdatesVotes,
-- * passCommand
prop_passCommandErrorsWhenGameIsOver, prop_passCommandErrorsWhenCallerDoesNotExist,
prop_passCommandErrorsWhenCallerIsDead, prop_passCommandErrorsWhenNotWitchsTurn,
prop_passCommandUpdatesPasses,
-- * poisonCommand
prop_poisonCommandErrorsWhenGameIsOver, prop_poisonCommandErrorsWhenCallerDoesNotExist,
prop_poisonCommandErrorsWhenTargetDoesNotExist, prop_poisonCommandErrorsWhenCallerIsDead,
prop_poisonCommandErrorsWhenTargetIsDead, prop_poisonCommandErrorsWhenTargetIsDevoured,
prop_poisonCommandErrorsWhenNotWitchsTurn, prop_poisonCommandErrorsWhenCallerHasPoisoned,
prop_poisonCommandErrorsWhenCallerNotWitch, prop_poisonCommandSetsPoison,
prop_poisonCommandSetsPoisonUsed,
-- * protectCommand
prop_protectCommandErrorsWhenGameIsOver, prop_protectCommandErrorsWhenCallerDoesNotExist,
prop_protectCommandErrorsWhenTargetDoesNotExist, prop_protectCommandErrorsWhenCallerIsDead,
prop_protectCommandErrorsWhenTargetIsDead, prop_protectCommandErrorsWhenNotDefendersTurn,
prop_protectCommandErrorsWhenCallerNotDefender, prop_protectCommandErrorsWhenTargetIsCaller,
prop_protectCommandErrorsWhenTargetIsPriorProtect, prop_protectCommandSetsPriorProtect,
prop_protectCommandSetsProtect,
-- * quitCommand
prop_quitCommandErrorsWhenGameIsOver, prop_quitCommandErrorsWhenCallerDoesNotExist,
prop_quitCommandErrorsWhenCallerIsDead, prop_quitCommandKillsPlayer,
prop_quitCommandClearsHealWhenCallerIsWitch, prop_quitCommandClearsHealUsedWhenCallerIsWitch,
prop_quitCommandClearsPoisonWhenCallerIsWitch,
prop_quitCommandClearsPoisonUsedWhenCallerIsWitch,
prop_quitCommandClearsPriorProtectWhenCallerIsDefender,
prop_quitCommandClearsProtectWhenCallerIsDefender, prop_quitCommandClearsPlayersDevourVote,
prop_quitCommandClearsPlayersLynchVote,
-- * seeCommand
prop_seeCommandErrorsWhenGameIsOver, prop_seeCommandErrorsWhenCallerDoesNotExist,
prop_seeCommandErrorsWhenTargetDoesNotExist, prop_seeCommandErrorsWhenCallerIsDead,
prop_seeCommandErrorsWhenTargetIsDead, prop_seeCommandErrorsWhenNotSeersTurn,
prop_seeCommandErrorsWhenCallerNotSeer, prop_seeCommandSetsSee,
) where
import Control.Lens hiding (elements)
import Data.Either.Extra
import qualified Data.Map as Map
import Data.Maybe
import Game.Werewolf.Command
import Game.Werewolf.Engine (checkStage)
import Game.Werewolf.Game
import Game.Werewolf.Player
import Game.Werewolf.Test.Arbitrary
import Game.Werewolf.Test.Util
import Test.QuickCheck
prop_devourVoteCommandErrorsWhenGameIsOver :: Game -> Property
prop_devourVoteCommandErrorsWhenGameIsOver game =
forAll (arbitraryDevourVoteCommand game') $ verbose_runCommandErrors game'
where
game' = game { _stage = GameOver }
prop_devourVoteCommandErrorsWhenCallerDoesNotExist :: Game -> Player -> Property
prop_devourVoteCommandErrorsWhenCallerDoesNotExist game caller =
not (doesPlayerExist (caller ^. name) (game ^. players))
==> forAll (arbitraryPlayer game) $ \target ->
verbose_runCommandErrors game (devourVoteCommand (caller ^. name) (target ^. name))
prop_devourVoteCommandErrorsWhenTargetDoesNotExist :: Game -> Player -> Property
prop_devourVoteCommandErrorsWhenTargetDoesNotExist game target =
not (doesPlayerExist (target ^. name) (game ^. players))
==> forAll (arbitraryWerewolf game) $ \caller ->
verbose_runCommandErrors game (devourVoteCommand (caller ^. name) (target ^. name))
prop_devourVoteCommandErrorsWhenCallerIsDead :: Game -> Property
prop_devourVoteCommandErrorsWhenCallerIsDead game =
forAll (arbitraryWerewolf game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game caller
let command = devourVoteCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_devourVoteCommandErrorsWhenTargetIsDead :: Game -> Property
prop_devourVoteCommandErrorsWhenTargetIsDead game =
forAll (arbitraryWerewolf game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game target
let command = devourVoteCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_devourVoteCommandErrorsWhenNotWerewolvesTurn :: Game -> Property
prop_devourVoteCommandErrorsWhenNotWerewolvesTurn game =
not (isWerewolvesTurn game)
==> forAll (arbitraryDevourVoteCommand game) $ verbose_runCommandErrors game
prop_devourVoteCommandErrorsWhenCallerNotWerewolf :: Game -> Property
prop_devourVoteCommandErrorsWhenCallerNotWerewolf game =
forAll (suchThat (arbitraryPlayer game) (not . isWerewolf)) $ \caller ->
forAll (arbitraryPlayer game) $ \target ->
verbose_runCommandErrors game (devourVoteCommand (caller ^. name) (target ^. name))
prop_devourVoteCommandErrorsWhenCallerHasVoted :: Game -> Property
prop_devourVoteCommandErrorsWhenCallerHasVoted game =
forAll (arbitraryWerewolf game') $ \caller ->
forAll (suchThat (arbitraryPlayer game') (not . isWerewolf)) $ \target -> do
let command = devourVoteCommand (caller ^. name) (target ^. name)
let game'' = run_ (apply command) game'
verbose_runCommandErrors game'' command
where
game' = game { _stage = WerewolvesTurn }
prop_devourVoteCommandErrorsWhenTargetWerewolf :: Game -> Property
prop_devourVoteCommandErrorsWhenTargetWerewolf game =
forAll (suchThat (arbitraryPlayer game) isWerewolf) $ \target ->
forAll (arbitraryPlayer game) $ \caller ->
verbose_runCommandErrors game (devourVoteCommand (caller ^. name) (target ^. name))
prop_devourVoteCommandUpdatesVotes :: Game -> Property
prop_devourVoteCommandUpdatesVotes game =
forAll (arbitraryDevourVoteCommand game') $ \command -> do
let game'' = run_ (apply command) game'
Map.size (game'' ^. votes) == 1
where
game' = game { _stage = WerewolvesTurn }
prop_healCommandErrorsWhenGameIsOver :: Game -> Property
prop_healCommandErrorsWhenGameIsOver game =
forAll (arbitraryWitch game') $ \witch ->
verbose_runCommandErrors game' (healCommand $ witch ^. name)
where
game' = game { _stage = GameOver }
prop_healCommandErrorsWhenCallerDoesNotExist :: Game -> Player -> Property
prop_healCommandErrorsWhenCallerDoesNotExist game caller =
not (doesPlayerExist (caller ^. name) (game ^. players))
==> verbose_runCommandErrors game (healCommand (caller ^. name))
prop_healCommandErrorsWhenCallerIsDead :: Game -> Property
prop_healCommandErrorsWhenCallerIsDead game =
forAll (arbitraryPlayer game) $ \caller -> do
let game' = killPlayer game caller
let command = healCommand (caller ^. name)
verbose_runCommandErrors game' command
prop_healCommandErrorsWhenNoTargetIsDevoured :: Game -> Property
prop_healCommandErrorsWhenNoTargetIsDevoured game =
forAll (arbitraryWitch game) $ \witch ->
verbose_runCommandErrors game (healCommand $ witch ^. name)
prop_healCommandErrorsWhenNotWitchsTurn :: Game -> Property
prop_healCommandErrorsWhenNotWitchsTurn game =
not (isWitchsTurn game)
==> forAll (arbitraryWitch game) $ \witch ->
verbose_runCommandErrors game (healCommand $ witch ^. name)
prop_healCommandErrorsWhenCallerHasHealed :: Gen Property
prop_healCommandErrorsWhenCallerHasHealed = do
game <- arbitraryGameWithDevourEventForVillager
return $ forAll (arbitraryHealCommand game) $ \command -> do
let game' = run_ (apply command) game
verbose_runCommandErrors game' command
prop_healCommandErrorsWhenCallerNotWitch :: Game -> Property
prop_healCommandErrorsWhenCallerNotWitch game =
forAll (suchThat (arbitraryPlayer game) (not . isWitch)) $ \caller ->
verbose_runCommandErrors game (healCommand (caller ^. name))
prop_healCommandSetsHeal :: Gen Property
prop_healCommandSetsHeal = do
game <- arbitraryGameWithDevourEventForVillager
return $ forAll (arbitraryHealCommand game) $ \command ->
(run_ (apply command) game) ^. heal
prop_healCommandSetsHealUsed :: Gen Property
prop_healCommandSetsHealUsed = do
game <- arbitraryGameWithDevourEventForVillager
return $ forAll (arbitraryHealCommand game) $ \command ->
(run_ (apply command) game) ^. healUsed
prop_lynchVoteCommandErrorsWhenGameIsOver :: Game -> Property
prop_lynchVoteCommandErrorsWhenGameIsOver game =
forAll (arbitraryLynchVoteCommand game') $ verbose_runCommandErrors game'
where
game' = game { _stage = GameOver }
prop_lynchVoteCommandErrorsWhenCallerDoesNotExist :: Game -> Player -> Property
prop_lynchVoteCommandErrorsWhenCallerDoesNotExist game caller =
not (doesPlayerExist (caller ^. name) (game ^. players))
==> forAll (arbitraryPlayer game) $ \target ->
verbose_runCommandErrors game (lynchVoteCommand (caller ^. name) (target ^. name))
prop_lynchVoteCommandErrorsWhenTargetDoesNotExist :: Game -> Player -> Property
prop_lynchVoteCommandErrorsWhenTargetDoesNotExist game target =
not (doesPlayerExist (target ^. name) (game ^. players))
==> forAll (arbitraryPlayer game) $ \caller ->
verbose_runCommandErrors game (lynchVoteCommand (caller ^. name) (target ^. name))
prop_lynchVoteCommandErrorsWhenCallerIsDead :: Game -> Property
prop_lynchVoteCommandErrorsWhenCallerIsDead game =
forAll (arbitraryPlayer game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game caller
let command = lynchVoteCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_lynchVoteCommandErrorsWhenTargetIsDead :: Game -> Property
prop_lynchVoteCommandErrorsWhenTargetIsDead game =
forAll (arbitraryPlayer game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game target
let command = lynchVoteCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_lynchVoteCommandErrorsWhenNotVillagesTurn :: Game -> Property
prop_lynchVoteCommandErrorsWhenNotVillagesTurn game =
not (isVillagesTurn game)
==> forAll (arbitraryLynchVoteCommand game) $ verbose_runCommandErrors game
prop_lynchVoteCommandErrorsWhenCallerHasVoted :: Game -> Property
prop_lynchVoteCommandErrorsWhenCallerHasVoted game =
forAll (arbitraryPlayer game') $ \caller ->
forAll (arbitraryPlayer game') $ \target -> do
let command = lynchVoteCommand (caller ^. name) (target ^. name)
let game'' = run_ (apply command) game'
verbose_runCommandErrors game'' command
where
game' = game { _stage = VillagesTurn }
prop_lynchVoteCommandUpdatesVotes :: Game -> Property
prop_lynchVoteCommandUpdatesVotes game =
forAll (arbitraryLynchVoteCommand game') $ \command -> do
let game'' = run_ (apply command) game'
Map.size (game'' ^. votes) == 1
where
game' = game { _stage = VillagesTurn }
prop_passCommandErrorsWhenGameIsOver :: Game -> Property
prop_passCommandErrorsWhenGameIsOver game =
forAll (arbitraryPassCommand game') $ verbose_runCommandErrors game'
where
game' = game { _stage = GameOver }
prop_passCommandErrorsWhenCallerDoesNotExist :: Game -> Player -> Property
prop_passCommandErrorsWhenCallerDoesNotExist game caller =
not (doesPlayerExist (caller ^. name) (game ^. players))
==> verbose_runCommandErrors game (passCommand (caller ^. name))
prop_passCommandErrorsWhenCallerIsDead :: Game -> Property
prop_passCommandErrorsWhenCallerIsDead game =
forAll (arbitraryPlayer game) $ \caller -> do
let game' = killPlayer game caller
let command = passCommand (caller ^. name)
verbose_runCommandErrors game' command
prop_passCommandErrorsWhenNotWitchsTurn :: Game -> Property
prop_passCommandErrorsWhenNotWitchsTurn game =
not (isWitchsTurn game)
==> forAll (arbitraryPassCommand game) $ verbose_runCommandErrors game
prop_passCommandUpdatesPasses :: Game -> Property
prop_passCommandUpdatesPasses game =
forAll (arbitraryPassCommand game') $ \command -> do
let game'' = run_ (apply command) game'
length (game'' ^. passes) == 1
where
game' = game { _stage = WitchsTurn }
prop_poisonCommandErrorsWhenGameIsOver :: Game -> Property
prop_poisonCommandErrorsWhenGameIsOver game =
forAll (arbitraryPoisonCommand game') $ verbose_runCommandErrors game'
where
game' = game { _stage = GameOver }
prop_poisonCommandErrorsWhenCallerDoesNotExist :: Game -> Player -> Property
prop_poisonCommandErrorsWhenCallerDoesNotExist game caller =
not (doesPlayerExist (caller ^. name) (game ^. players))
==> forAll (arbitraryPlayer game) $ \target ->
verbose_runCommandErrors game (poisonCommand (caller ^. name) (target ^. name))
prop_poisonCommandErrorsWhenTargetDoesNotExist :: Game -> Player -> Property
prop_poisonCommandErrorsWhenTargetDoesNotExist game target =
not (doesPlayerExist (target ^. name) (game ^. players))
==> forAll (arbitraryPlayer game) $ \caller ->
verbose_runCommandErrors game (poisonCommand (caller ^. name) (target ^. name))
prop_poisonCommandErrorsWhenCallerIsDead :: Game -> Property
prop_poisonCommandErrorsWhenCallerIsDead game =
forAll (arbitraryPlayer game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game caller
let command = poisonCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_poisonCommandErrorsWhenTargetIsDead :: Game -> Property
prop_poisonCommandErrorsWhenTargetIsDead game =
forAll (arbitraryPlayer game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game target
let command = poisonCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_poisonCommandErrorsWhenTargetIsDevoured :: Game -> Property
prop_poisonCommandErrorsWhenTargetIsDevoured game =
forAll (runArbitraryCommands n game') $ \game'' ->
length (getVoteResult game'') == 1
==> forAll (arbitraryWitch game'') $ \caller ->
let game''' = run_ checkStage game''
votee = head (getVoteResult game'')
in verbose_runCommandErrors game''' (poisonCommand (caller ^. name) (votee ^. name))
where
game' = game { _stage = WerewolvesTurn }
n = length . filterWerewolves $ game' ^. players
prop_poisonCommandErrorsWhenNotWitchsTurn :: Game -> Property
prop_poisonCommandErrorsWhenNotWitchsTurn game =
not (isWitchsTurn game)
==> forAll (arbitraryPoisonCommand game) $ verbose_runCommandErrors game
prop_poisonCommandErrorsWhenCallerHasPoisoned :: Game -> Property
prop_poisonCommandErrorsWhenCallerHasPoisoned game =
forAll (arbitraryWitch game') $ \caller ->
forAll (arbitraryPlayer game') $ \target ->
let command = poisonCommand (caller ^. name) (target ^. name)
in verbose_runCommandErrors (run_ (apply command) game') command
where
game' = game { _stage = WitchsTurn }
prop_poisonCommandErrorsWhenCallerNotWitch :: Game -> Property
prop_poisonCommandErrorsWhenCallerNotWitch game =
forAll (suchThat (arbitraryPlayer game) (not . isWitch)) $ \caller ->
forAll (arbitraryPlayer game) $ \target ->
verbose_runCommandErrors game (poisonCommand (caller ^. name) (target ^. name))
prop_poisonCommandSetsPoison :: Game -> Property
prop_poisonCommandSetsPoison game =
forAll (arbitraryPoisonCommand game') $ \command ->
isJust (run_ (apply command) game' ^. poison)
where
game' = game { _stage = WitchsTurn }
prop_poisonCommandSetsPoisonUsed :: Game -> Property
prop_poisonCommandSetsPoisonUsed game =
forAll (arbitraryPoisonCommand game') $ \command ->
run_ (apply command) game' ^. poisonUsed
where
game' = game { _stage = WitchsTurn }
prop_protectCommandErrorsWhenGameIsOver :: Game -> Property
prop_protectCommandErrorsWhenGameIsOver game =
forAll (arbitraryProtectCommand game') $ verbose_runCommandErrors game'
where
game' = game { _stage = GameOver }
prop_protectCommandErrorsWhenCallerDoesNotExist :: Game -> Player -> Property
prop_protectCommandErrorsWhenCallerDoesNotExist game caller =
not (doesPlayerExist (caller ^. name) (game ^. players))
==> forAll (arbitraryPlayer game) $ \target -> do
let command = protectCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game command
prop_protectCommandErrorsWhenTargetDoesNotExist :: Game -> Player -> Property
prop_protectCommandErrorsWhenTargetDoesNotExist game target =
not (doesPlayerExist (target ^. name) (game ^. players))
==> forAll (arbitraryDefender game) $ \caller -> do
let command = protectCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game command
prop_protectCommandErrorsWhenCallerIsDead :: Game -> Property
prop_protectCommandErrorsWhenCallerIsDead game =
forAll (arbitraryDefender game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game caller
let command = protectCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_protectCommandErrorsWhenTargetIsDead :: Game -> Property
prop_protectCommandErrorsWhenTargetIsDead game =
forAll (arbitraryDefender game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game target
let command = protectCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_protectCommandErrorsWhenNotDefendersTurn :: Game -> Property
prop_protectCommandErrorsWhenNotDefendersTurn game =
not (isDefendersTurn game)
==> forAll (arbitraryProtectCommand game) $ verbose_runCommandErrors game
prop_protectCommandErrorsWhenCallerNotDefender :: Game -> Property
prop_protectCommandErrorsWhenCallerNotDefender game =
forAll (suchThat (arbitraryPlayer game) (not . isDefender)) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let command = protectCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game command
prop_protectCommandErrorsWhenTargetIsCaller :: Game -> Property
prop_protectCommandErrorsWhenTargetIsCaller game =
forAll (arbitraryDefender game) $ \caller -> do
let command = protectCommand (caller ^. name) (caller ^. name)
verbose_runCommandErrors game command
prop_protectCommandErrorsWhenTargetIsPriorProtect :: Gen Property
prop_protectCommandErrorsWhenTargetIsPriorProtect = do
game <- arbitraryGameWithProtect
let game' = game { _protect = Nothing }
return $ forAll (arbitraryDefender game') $ \caller -> do
let command = protectCommand (caller ^. name) (fromJust $ game' ^. priorProtect)
verbose_runCommandErrors game' command
prop_protectCommandSetsPriorProtect :: Game -> Property
prop_protectCommandSetsPriorProtect game =
forAll (arbitraryProtectCommand game') $ \command ->
isJust $ run_ (apply command) game' ^. priorProtect
where
game' = game { _stage = DefendersTurn }
prop_protectCommandSetsProtect :: Game -> Property
prop_protectCommandSetsProtect game =
forAll (arbitraryProtectCommand game') $ \command ->
isJust $ run_ (apply command) game' ^. protect
where
game' = game { _stage = DefendersTurn }
prop_quitCommandErrorsWhenGameIsOver :: Game -> Property
prop_quitCommandErrorsWhenGameIsOver game =
forAll (arbitraryQuitCommand game') $ verbose_runCommandErrors game'
where
game' = game { _stage = GameOver }
prop_quitCommandErrorsWhenCallerDoesNotExist :: Game -> Player -> Property
prop_quitCommandErrorsWhenCallerDoesNotExist game caller =
not (doesPlayerExist (caller ^. name) (game ^. players))
==> verbose_runCommandErrors game (quitCommand $ caller ^. name)
prop_quitCommandErrorsWhenCallerIsDead :: Game -> Property
prop_quitCommandErrorsWhenCallerIsDead game =
forAll (arbitraryPlayer game) $ \caller ->
verbose_runCommandErrors (killPlayer game caller) (quitCommand $ caller ^. name)
prop_quitCommandKillsPlayer :: Game -> Property
prop_quitCommandKillsPlayer game =
not (isGameOver game)
==> forAll (arbitraryQuitCommand game) $ \command ->
length (filterDead $ run_ (apply command) game ^. players) == 1
prop_quitCommandClearsHealWhenCallerIsWitch :: Game -> Property
prop_quitCommandClearsHealWhenCallerIsWitch game =
forAll (runArbitraryCommands n game') $ \game'' ->
length (getVoteResult game'') == 1
==> let target = head $ getVoteResult game''
in not (isWitch target)
==> forAll (arbitraryWitch game'') $ \caller ->
let command = healCommand (caller ^. name)
game''' = run_ (apply command) $ run_ checkStage game''
in not $ run_ (apply $ quitCommand (caller ^. name)) game''' ^. heal
where
game' = game { _stage = WerewolvesTurn }
n = length . filterWerewolves $ game' ^. players
prop_quitCommandClearsHealUsedWhenCallerIsWitch :: Game -> Property
prop_quitCommandClearsHealUsedWhenCallerIsWitch game =
forAll (runArbitraryCommands n game') $ \game'' ->
length (getVoteResult game'') == 1
==> let target = head $ getVoteResult game''
in not (isWitch target)
==> forAll (arbitraryWitch game'') $ \caller ->
let command = healCommand (caller ^. name)
game''' = run_ (apply command) $ run_ checkStage game''
in not $ run_ (apply $ quitCommand (caller ^. name)) game''' ^. healUsed
where
game' = game { _stage = WerewolvesTurn }
n = length . filterWerewolves $ game' ^. players
prop_quitCommandClearsPoisonWhenCallerIsWitch :: Game -> Property
prop_quitCommandClearsPoisonWhenCallerIsWitch game =
forAll (arbitraryWitch game') $ \caller ->
forAll (arbitraryPlayer game') $ \target ->
let game'' = run_ (apply $ poisonCommand (caller ^. name) (target ^. name)) game'
in isNothing $ run_ (apply $ quitCommand (caller ^. name)) game'' ^. poison
where
game' = game { _stage = WitchsTurn }
prop_quitCommandClearsPriorProtectWhenCallerIsDefender :: Game -> Property
prop_quitCommandClearsPriorProtectWhenCallerIsDefender game =
forAll (arbitraryDefender game') $ \caller ->
forAll (suchThat (arbitraryPlayer game') (not . isDefender)) $ \target -> do
let command = protectCommand (caller ^. name) (target ^. name)
let game'' = run_ (apply command) game'
isNothing $ run_ (apply $ quitCommand (caller ^. name)) game'' ^. priorProtect
where
game' = game { _stage = DefendersTurn }
prop_quitCommandClearsProtectWhenCallerIsDefender :: Game -> Property
prop_quitCommandClearsProtectWhenCallerIsDefender game =
forAll (arbitraryDefender game') $ \caller ->
forAll (suchThat (arbitraryPlayer game') (not . isDefender)) $ \target -> do
let command = protectCommand (caller ^. name) (target ^. name)
let game'' = run_ (apply command) game'
isNothing $ run_ (apply $ quitCommand (caller ^. name)) game'' ^. protect
where
game' = game { _stage = DefendersTurn }
prop_quitCommandClearsPoisonUsedWhenCallerIsWitch :: Game -> Property
prop_quitCommandClearsPoisonUsedWhenCallerIsWitch game =
forAll (arbitraryWitch game') $ \caller ->
forAll (arbitraryPlayer game') $ \target ->
let game'' = run_ (apply $ poisonCommand (caller ^. name) (target ^. name)) game'
in not $ run_ (apply $ quitCommand (caller ^. name)) game'' ^. poisonUsed
where
game' = game { _stage = WitchsTurn }
prop_quitCommandClearsPlayersDevourVote :: Game -> Property
prop_quitCommandClearsPlayersDevourVote game =
forAll (arbitraryWerewolf game') $ \caller ->
forAll (suchThat (arbitraryPlayer game') (not . isWerewolf)) $ \target ->
let game'' = run_ (apply $ devourVoteCommand (caller ^. name) (target ^. name)) game'
in Map.null $ run_ (apply $ quitCommand (caller ^. name)) game'' ^. votes
where
game' = game { _stage = WerewolvesTurn }
prop_quitCommandClearsPlayersLynchVote :: Game -> Property
prop_quitCommandClearsPlayersLynchVote game =
forAll (arbitraryPlayer game') $ \caller ->
forAll (arbitraryPlayer game') $ \target ->
let game'' = run_ (apply $ lynchVoteCommand (caller ^. name) (target ^. name)) game'
in Map.null $ run_ (apply $ quitCommand (caller ^. name)) game'' ^. votes
where
game' = game { _stage = VillagesTurn }
prop_seeCommandErrorsWhenGameIsOver :: Game -> Property
prop_seeCommandErrorsWhenGameIsOver game =
forAll (arbitrarySeeCommand game') $ verbose_runCommandErrors game'
where
game' = game { _stage = GameOver }
prop_seeCommandErrorsWhenCallerDoesNotExist :: Game -> Player -> Property
prop_seeCommandErrorsWhenCallerDoesNotExist game caller =
not (doesPlayerExist (caller ^. name) (game ^. players))
==> forAll (arbitraryPlayer game) $ \target -> do
let command = seeCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game command
prop_seeCommandErrorsWhenTargetDoesNotExist :: Game -> Player -> Property
prop_seeCommandErrorsWhenTargetDoesNotExist game target =
not (doesPlayerExist (target ^. name) (game ^. players))
==> forAll (arbitrarySeer game) $ \caller -> do
let command = seeCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game command
prop_seeCommandErrorsWhenCallerIsDead :: Game -> Property
prop_seeCommandErrorsWhenCallerIsDead game =
forAll (arbitrarySeer game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game caller
let command = seeCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_seeCommandErrorsWhenTargetIsDead :: Game -> Property
prop_seeCommandErrorsWhenTargetIsDead game =
forAll (arbitrarySeer game) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let game' = killPlayer game target
let command = seeCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game' command
prop_seeCommandErrorsWhenNotSeersTurn :: Game -> Property
prop_seeCommandErrorsWhenNotSeersTurn game =
not (isSeersTurn game)
==> forAll (arbitrarySeeCommand game) $ verbose_runCommandErrors game
prop_seeCommandErrorsWhenCallerNotSeer :: Game -> Property
prop_seeCommandErrorsWhenCallerNotSeer game =
forAll (suchThat (arbitraryPlayer game) (not . isSeer)) $ \caller ->
forAll (arbitraryPlayer game) $ \target -> do
let command = seeCommand (caller ^. name) (target ^. name)
verbose_runCommandErrors game command
prop_seeCommandSetsSee :: Game -> Property
prop_seeCommandSetsSee game =
forAll (arbitrarySeeCommand game') $ \command ->
isJust $ run_ (apply command) game' ^. see
where
game' = game { _stage = SeersTurn }
verbose_runCommandErrors :: Game -> Command -> Property
verbose_runCommandErrors game command = whenFail (mapM_ putStrLn [show game, show . fromRight $ run (apply command) game]) (isLeft $ run (apply command) game)