{-| Module : Game.Werewolf.Test.Command.Choose Copyright : (c) Henry J. Wylde, 2016 License : BSD3 Maintainer : public@hjwylde.com -} {-# LANGUAGE OverloadedStrings #-} module Game.Werewolf.Test.Command.Choose ( -- * Tests allChooseCommandTests, ) where import Control.Lens hiding (elements, isn't) import Data.Maybe import Data.Text (Text) import qualified Data.Text as T import Game.Werewolf import Game.Werewolf.Command.Hunter as Hunter import Game.Werewolf.Command.Orphan as Orphan import Game.Werewolf.Command.Scapegoat as Scapegoat import Game.Werewolf.Command.WolfHound as WolfHound import Game.Werewolf.Test.Arbitrary import Game.Werewolf.Test.Util import Test.Tasty import Test.Tasty.QuickCheck allChooseCommandTests :: [TestTree] allChooseCommandTests = [ testProperty "hunter choose command errors when game is over" prop_hunterChooseCommandErrorsWhenGameIsOver , testProperty "hunter choose command errors when caller does not exist" prop_hunterChooseCommandErrorsWhenCallerDoesNotExist , testProperty "hunter choose command errors when any target does not exist" prop_hunterChooseCommandErrorsWhenTargetDoesNotExist , testProperty "hunter choose command errors when any target is dead" prop_hunterChooseCommandErrorsWhenTargetIsDead , testProperty "hunter choose command errors when not hunter's turn" prop_hunterChooseCommandErrorsWhenNotHuntersTurn , testProperty "hunter choose command errors when caller not hunter" prop_hunterChooseCommandErrorsWhenCallerNotHunter , testProperty "hunter choose command kills target" prop_hunterChooseCommandKillsTarget , testProperty "hunter choose command sets hunter retaliated" prop_hunterChooseCommandSetsHunterRetaliated , testProperty "orphan choose command errors when game is over" prop_orphanChooseCommandErrorsWhenGameIsOver , testProperty "orphan choose command errors when caller does not exist" prop_orphanChooseCommandErrorsWhenCallerDoesNotExist , testProperty "orphan choose command errors when target does not exist" prop_orphanChooseCommandErrorsWhenTargetDoesNotExist , testProperty "orphan choose command errors when caller is dead" prop_orphanChooseCommandErrorsWhenCallerIsDead , testProperty "orphan choose command errors when target is dead" prop_orphanChooseCommandErrorsWhenTargetIsDead , testProperty "orphan choose command errors when target is caller" prop_orphanChooseCommandErrorsWhenTargetIsCaller , testProperty "orphan choose command errors when not orphan's turn" prop_orphanChooseCommandErrorsWhenNotOrphansTurn , testProperty "orphan choose command errors when caller not orphan" prop_orphanChooseCommandErrorsWhenCallerNotOrphan , testProperty "orphan choose command sets role model" prop_orphanChooseCommandSetsRoleModel , testProperty "wolf-hound choose command errors when game is over" prop_wolfHoundChooseCommandErrorsWhenGameIsOver , testProperty "wolf-hound choose command errors when caller does not exist" prop_wolfHoundChooseCommandErrorsWhenCallerDoesNotExist , testProperty "wolf-hound choose command errors when caller is dead" prop_wolfHoundChooseCommandErrorsWhenCallerIsDead , testProperty "wolf-hound choose command errors when not wolf-hound's turn" prop_wolfHoundChooseCommandErrorsWhenNotWolfHoundsTurn , testProperty "wolf-hound choose command errors when caller not wolf-hound" prop_wolfHoundChooseCommandErrorsWhenCallerNotWolfHound , testProperty "wolf-hound choose command errors when allegiance does not exist" prop_wolfHoundChooseCommandErrorsWhenAllegianceDoesNotExist , testProperty "wolf-hound choose command sets allegiance chosen" prop_wolfHoundChooseCommandSetsAllegianceChosen , testProperty "wolf-hound choose command sets allegiance" prop_wolfHoundChooseCommandSetsAllegiance , testProperty "scapegoat choose command errors when game is over" prop_scapegoatChooseCommandErrorsWhenGameIsOver , testProperty "scapegoat choose command errors when caller does not exist" prop_scapegoatChooseCommandErrorsWhenCallerDoesNotExist , testProperty "scapegoat choose command errors when any target does not exist" prop_scapegoatChooseCommandErrorsWhenAnyTargetDoesNotExist , testProperty "scapegoat choose command errors when any target is dead" prop_scapegoatChooseCommandErrorsWhenAnyTargetIsDead , testProperty "scapegoat choose command errors when not scapegoat's turn" prop_scapegoatChooseCommandErrorsWhenNotScapegoatsTurn , testProperty "scapegoat choose command errors when caller not scapegoat" prop_scapegoatChooseCommandErrorsWhenCallerNotScapegoat , testProperty "scapegoat choose command sets allowed voters" prop_scapegoatChooseCommandSetsAllowedVoters , testProperty "scapegoat choose command resets scapegoat blamed" prop_scapegoatChooseCommandResetsScapegoatBlamed ] prop_hunterChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property prop_hunterChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) = forAll (arbitraryHunterChooseCommand game) $ verbose_runCommandErrors game . getBlind prop_hunterChooseCommandErrorsWhenCallerDoesNotExist :: GameAtHuntersTurn -> Player -> Property prop_hunterChooseCommandErrorsWhenCallerDoesNotExist (GameAtHuntersTurn game) caller = forAll (arbitraryPlayer game) $ \target -> do let command = Hunter.chooseCommand (caller ^. name) (target ^. name) not (doesPlayerExist (caller ^. name) game) ==> verbose_runCommandErrors game command prop_hunterChooseCommandErrorsWhenTargetDoesNotExist :: GameAtHuntersTurn -> Player -> Property prop_hunterChooseCommandErrorsWhenTargetDoesNotExist (GameAtHuntersTurn game) target = do let hunter = game ^?! players . hunters let command = Hunter.chooseCommand (hunter ^. name) (target ^. name) not (doesPlayerExist (target ^. name) game) ==> verbose_runCommandErrors game command prop_hunterChooseCommandErrorsWhenTargetIsDead :: GameAtHuntersTurn -> Property prop_hunterChooseCommandErrorsWhenTargetIsDead (GameAtHuntersTurn game) = do let hunter = game ^?! players . hunters forAll (arbitraryPlayer game) $ \target -> do let game' = killPlayer (target ^. name) game let command = Hunter.chooseCommand (hunter ^. name) (target ^. name) verbose_runCommandErrors game' command prop_hunterChooseCommandErrorsWhenNotHuntersTurn :: Game -> Property prop_hunterChooseCommandErrorsWhenNotHuntersTurn game = hasn't (stage . _HuntersTurn1) game && hasn't (stage . _HuntersTurn2) game ==> forAll (arbitraryHunterChooseCommand game) $ verbose_runCommandErrors game . getBlind prop_hunterChooseCommandErrorsWhenCallerNotHunter :: GameAtHuntersTurn -> Property prop_hunterChooseCommandErrorsWhenCallerNotHunter (GameAtHuntersTurn game) = forAll (suchThat (arbitraryPlayer game) (isn't hunter)) $ \caller -> forAll (arbitraryPlayer game) $ \target -> do let command = Hunter.chooseCommand (caller ^. name) (target ^. name) verbose_runCommandErrors game command prop_hunterChooseCommandKillsTarget :: GameAtHuntersTurn -> Property prop_hunterChooseCommandKillsTarget (GameAtHuntersTurn game) = do let hunter = game ^?! players . hunters forAll (arbitraryPlayer game) $ \target -> do let command = Hunter.chooseCommand (hunter ^. name) (target ^. name) let game' = run_ (apply command) game is dead $ game' ^?! players . traverse . filteredBy name (target ^. name) prop_hunterChooseCommandSetsHunterRetaliated :: GameAtHuntersTurn -> Property prop_hunterChooseCommandSetsHunterRetaliated (GameAtHuntersTurn game) = do let hunter = game ^?! players . hunters forAll (arbitraryPlayer game) $ \target -> do let command = Hunter.chooseCommand (hunter ^. name) (target ^. name) let game' = run_ (apply command) game game' ^. hunterRetaliated prop_orphanChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property prop_orphanChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) = forAll (arbitraryOrphanChooseCommand game) $ verbose_runCommandErrors game . getBlind prop_orphanChooseCommandErrorsWhenCallerDoesNotExist :: GameAtOrphansTurn -> Player -> Property prop_orphanChooseCommandErrorsWhenCallerDoesNotExist (GameAtOrphansTurn game) caller = forAll (arbitraryPlayer game) $ \target -> do let command = Orphan.chooseCommand (caller ^. name) (target ^. name) not (doesPlayerExist (caller ^. name) game) ==> verbose_runCommandErrors game command prop_orphanChooseCommandErrorsWhenTargetDoesNotExist :: GameAtOrphansTurn -> Player -> Property prop_orphanChooseCommandErrorsWhenTargetDoesNotExist (GameAtOrphansTurn game) target = do let orphan = game ^?! players . orphans let command = Orphan.chooseCommand (orphan ^. name) (target ^. name) not (doesPlayerExist (target ^. name) game) ==> verbose_runCommandErrors game command prop_orphanChooseCommandErrorsWhenCallerIsDead :: GameAtOrphansTurn -> Property prop_orphanChooseCommandErrorsWhenCallerIsDead (GameAtOrphansTurn game) = do let orphan = game ^?! players . orphans let game' = killPlayer (orphan ^. name) game forAll (arbitraryPlayer game') $ \target -> do let command = Orphan.chooseCommand (orphan ^. name) (target ^. name) verbose_runCommandErrors game' command prop_orphanChooseCommandErrorsWhenTargetIsDead :: GameAtOrphansTurn -> Property prop_orphanChooseCommandErrorsWhenTargetIsDead (GameAtOrphansTurn game) = do let orphan = game ^?! players . orphans forAll (arbitraryPlayer game) $ \target -> do let game' = killPlayer (target ^. name) game let command = Orphan.chooseCommand (orphan ^. name) (target ^. name) verbose_runCommandErrors game' command prop_orphanChooseCommandErrorsWhenTargetIsCaller :: GameAtOrphansTurn -> Property prop_orphanChooseCommandErrorsWhenTargetIsCaller (GameAtOrphansTurn game) = do let orphan = game ^?! players . orphans let command = Orphan.chooseCommand (orphan ^. name) (orphan ^. name) verbose_runCommandErrors game command prop_orphanChooseCommandErrorsWhenNotOrphansTurn :: Game -> Property prop_orphanChooseCommandErrorsWhenNotOrphansTurn game = hasn't (stage . _OrphansTurn) game ==> forAll (arbitraryOrphanChooseCommand game) $ verbose_runCommandErrors game . getBlind prop_orphanChooseCommandErrorsWhenCallerNotOrphan :: GameAtOrphansTurn -> Property prop_orphanChooseCommandErrorsWhenCallerNotOrphan (GameAtOrphansTurn game) = forAll (suchThat (arbitraryPlayer game) (isn't orphan)) $ \caller -> forAll (arbitraryPlayer game) $ \target -> do let command = Orphan.chooseCommand (caller ^. name) (target ^. name) verbose_runCommandErrors game command prop_orphanChooseCommandSetsRoleModel :: GameAtOrphansTurn -> Property prop_orphanChooseCommandSetsRoleModel (GameAtOrphansTurn game) = do let orphan = game ^?! players . orphans forAll (suchThat (arbitraryPlayer game) (orphan /=)) $ \target -> do let command = Orphan.chooseCommand (orphan ^. name) (target ^. name) let game' = run_ (apply command) game fromJust (game' ^. roleModel) === target ^. name prop_wolfHoundChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property prop_wolfHoundChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) = forAll (arbitraryWolfHoundChooseCommand game) $ verbose_runCommandErrors game . getBlind prop_wolfHoundChooseCommandErrorsWhenCallerDoesNotExist :: GameAtWolfHoundsTurn -> Player -> Allegiance -> Property prop_wolfHoundChooseCommandErrorsWhenCallerDoesNotExist (GameAtWolfHoundsTurn game) caller allegiance = do let command = WolfHound.chooseCommand (caller ^. name) (T.pack $ show allegiance) not (doesPlayerExist (caller ^. name) game) ==> verbose_runCommandErrors game command prop_wolfHoundChooseCommandErrorsWhenCallerIsDead :: GameAtWolfHoundsTurn -> Allegiance -> Property prop_wolfHoundChooseCommandErrorsWhenCallerIsDead (GameAtWolfHoundsTurn game) allegiance = do let wolfHound = game ^?! players . wolfHounds let game' = killPlayer (wolfHound ^. name) game let command = WolfHound.chooseCommand (wolfHound ^. name) (T.pack $ show allegiance) verbose_runCommandErrors game' command prop_wolfHoundChooseCommandErrorsWhenNotWolfHoundsTurn :: Game -> Property prop_wolfHoundChooseCommandErrorsWhenNotWolfHoundsTurn game = hasn't (stage . _WolfHoundsTurn) game ==> forAll (arbitraryWolfHoundChooseCommand game) $ verbose_runCommandErrors game . getBlind prop_wolfHoundChooseCommandErrorsWhenCallerNotWolfHound :: GameAtWolfHoundsTurn -> Allegiance -> Property prop_wolfHoundChooseCommandErrorsWhenCallerNotWolfHound (GameAtWolfHoundsTurn game) allegiance = forAll (suchThat (arbitraryPlayer game) (isn't wolfHound)) $ \caller -> do let command = WolfHound.chooseCommand (caller ^. name) (T.pack $ show allegiance) verbose_runCommandErrors game command prop_wolfHoundChooseCommandErrorsWhenAllegianceDoesNotExist :: GameAtWolfHoundsTurn -> Text -> Property prop_wolfHoundChooseCommandErrorsWhenAllegianceDoesNotExist (GameAtWolfHoundsTurn game) allegiance = do let wolfHound = game ^?! players . wolfHounds let command = WolfHound.chooseCommand (wolfHound ^. name) allegiance allegiance `notElem` ["Villagers", "Werewolves"] ==> verbose_runCommandErrors game command prop_wolfHoundChooseCommandSetsAllegianceChosen :: GameAtWolfHoundsTurn -> Property prop_wolfHoundChooseCommandSetsAllegianceChosen (GameAtWolfHoundsTurn game) = forAll (arbitraryWolfHoundChooseCommand game) $ \(Blind command) -> do let game' = run_ (apply command) game game' ^. allegianceChosen prop_wolfHoundChooseCommandSetsAllegiance :: GameAtWolfHoundsTurn -> Property prop_wolfHoundChooseCommandSetsAllegiance (GameAtWolfHoundsTurn game) = do let wolfHoundsName = game ^?! players . wolfHounds . name forAll (elements [Villagers, Werewolves]) $ \allegiance' -> do let command = WolfHound.chooseCommand wolfHoundsName (T.pack $ show allegiance') let game' = run_ (apply command) game game' ^?! players . wolfHounds . role . allegiance === allegiance' prop_scapegoatChooseCommandErrorsWhenGameIsOver :: GameAtGameOver -> Property prop_scapegoatChooseCommandErrorsWhenGameIsOver (GameAtGameOver game) = forAll (arbitraryScapegoatChooseCommand game) $ verbose_runCommandErrors game . getBlind prop_scapegoatChooseCommandErrorsWhenCallerDoesNotExist :: GameAtScapegoatsTurn -> Player -> Property prop_scapegoatChooseCommandErrorsWhenCallerDoesNotExist (GameAtScapegoatsTurn game) caller = forAll (NonEmpty <$> sublistOf (game ^.. players . traverse . alive)) $ \(NonEmpty targets) -> do let command = Scapegoat.chooseCommand (caller ^. name) (targets ^.. names) not (doesPlayerExist (caller ^. name) game) ==> verbose_runCommandErrors game command prop_scapegoatChooseCommandErrorsWhenAnyTargetDoesNotExist :: GameAtScapegoatsTurn -> Player -> Property prop_scapegoatChooseCommandErrorsWhenAnyTargetDoesNotExist (GameAtScapegoatsTurn game) target = do let scapegoat = game ^?! players . scapegoats let command = Scapegoat.chooseCommand (scapegoat ^. name) [target ^. name] not (doesPlayerExist (target ^. name) game) ==> verbose_runCommandErrors game command prop_scapegoatChooseCommandErrorsWhenAnyTargetIsDead :: GameAtScapegoatsTurn -> Property prop_scapegoatChooseCommandErrorsWhenAnyTargetIsDead (GameAtScapegoatsTurn game) = do let scapegoat = game ^?! players . scapegoats forAll (NonEmpty <$> sublistOf (game ^.. players . traverse . alive)) $ \(NonEmpty targets) -> forAll (elements targets) $ \target -> do let game' = killPlayer (target ^. name) game let command = Scapegoat.chooseCommand (scapegoat ^. name) (targets ^.. names) verbose_runCommandErrors game' command prop_scapegoatChooseCommandErrorsWhenNotScapegoatsTurn :: Game -> Property prop_scapegoatChooseCommandErrorsWhenNotScapegoatsTurn game = hasn't (stage . _ScapegoatsTurn) game ==> forAll (arbitraryScapegoatChooseCommand game) $ verbose_runCommandErrors game . getBlind prop_scapegoatChooseCommandErrorsWhenCallerNotScapegoat :: GameAtScapegoatsTurn -> Property prop_scapegoatChooseCommandErrorsWhenCallerNotScapegoat (GameAtScapegoatsTurn game) = forAll (suchThat (arbitraryPlayer game) (isn't scapegoat)) $ \caller -> forAll (NonEmpty <$> sublistOf (game ^.. players . traverse . alive)) $ \(NonEmpty targets) -> do let command = Scapegoat.chooseCommand (caller ^. name) (targets ^.. names) verbose_runCommandErrors game command prop_scapegoatChooseCommandSetsAllowedVoters :: GameAtScapegoatsTurn -> Property prop_scapegoatChooseCommandSetsAllowedVoters (GameAtScapegoatsTurn game) = do let scapegoat = game ^?! players . scapegoats forAll (NonEmpty <$> sublistOf (game ^.. players . traverse . alive)) $ \(NonEmpty targets) -> do let command = Scapegoat.chooseCommand (scapegoat ^. name) (targets ^.. names) let game' = run_ (apply command) game game' ^. allowedVoters === targets ^.. names prop_scapegoatChooseCommandResetsScapegoatBlamed :: GameAtScapegoatsTurn -> Property prop_scapegoatChooseCommandResetsScapegoatBlamed (GameAtScapegoatsTurn game) = do forAll (arbitraryScapegoatChooseCommand game) $ \(Blind command) -> not $ run_ (apply command) game ^. scapegoatBlamed