packages feed

dovin-0.1.0.0: test/Spec.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}

module Spec where

import TestPrelude

test_Test = testGroup "Actions"
  [ testGroup "cast"
    [ prove "casts from hand to stack" $ do
        withLocation (Active, Hand) $ addCreature (1, 1) "Zombie"
        addMana "B"
        castFromLocation (Active, Hand) "B" "Zombie"
        validate "Zombie" $ matchLocation (Active, Stack)
        validateBoardEquals (manaPoolFor Active) mempty
    , prove "can cast as opponent" $ do
        as Opponent $ do
          withLocation (Opponent, Hand) $ addCreature (1, 1) "Zombie"
          addMana "B"
          castFromLocation (Opponent, Hand) "B" "Zombie"
          validate "Zombie" $ matchLocation (Opponent, Stack)
          validateBoardEquals (manaPoolFor Opponent) mempty
    , refute
        "requires card to be in hand"
        "Zombie does not match requirements: in location (Active,Hand)" $ do
          withLocation (Active, Play) $ addCreature (1, 1) "Zombie"
          cast "" "Zombie"
    ]
  , testGroup "castFromLocation"
    [ prove "places card on top of stack, spending mana" $ do
        withLocation (Active, Graveyard) $ addCreature (1, 1) "Zombie"
        addMana "B"
        castFromLocation (Active, Graveyard) "B" "Zombie"
        validate "Zombie" $ matchLocation (Active, Stack)
        validateBoardEquals (manaPoolFor Active) mempty

    , refute
        "requires mana be available"
        "Mana pool () does not contain (B)" $ do
          withLocation (Active, Hand) $ addCreature (1, 1) "Zombie"
          castFromLocation (Active, Hand) "B" "Zombie"

    , prove "can cast non-instant in second main" $ do
        withLocation (Active, Hand) $ addSorcery "Lava Spike"
        transitionTo SecondMain
        castFromLocation (Active, Hand) "" "Lava Spike"

    , refute
        "requires main phase for non-instant"
        "not in a main phase" $ do
          withLocation (Active, Hand) $ addSorcery "Lava Spike"
          transitionTo BeginCombat
          castFromLocation (Active, Hand) "" "Lava Spike"

    , refute
        "requires stack to be empty for non-instant"
        "stack is not empty" $ do
          withLocation (Active, Hand) $ addInstant "Shock"
          withLocation (Active, Hand) $ addSorcery "Lava Spike"

          castFromLocation (Active, Hand) "" "Shock"
          castFromLocation (Active, Hand) "" "Lava Spike"

    , prove "increases storm count if instant" $ do
        withLocation (Active, Hand) $ addInstant "Shock"
        castFromLocation (Active, Hand) "" "Shock"
        validateBoardEquals (counters . at "storm" . non 0) 1

    , prove "increases storm count if sorcery" $ do
        withLocation (Active, Hand) $ addSorcery "Lava Spike"
        castFromLocation (Active, Hand) "" "Lava Spike"

    , prove "does not increase storm count otherwise" $ do
        withLocation (Active, Hand) $ addArtifact "Mox Amber"
        castFromLocation (Active, Hand) "" "Mox Amber"
        validateBoardEquals (counters . at "storm" . non 0) 0
    ]
  , testGroup "spendMana"
    [ prove "removes colored mana from pool" $ do
        addMana "BBRRRWW"
        spendMana "RB"
        validateBoardEquals (manaPoolFor Active) "BRRWW"
    , prove "removes colorless mana from pool" $ do
        addMana "RWB"
        spendMana "3"
        validateBoardEquals (manaPoolFor Active) mempty
    , prove "removes multiple digits for colorless mana from pool" $ do
        addMana "9"
        addMana "9"
        spendMana "15"
        validateBoardEquals (manaPoolFor Active) "XXX"
    , prove "removes colored mana before colorless" $ do
        addMana "RWB"
        spendMana "1R"
        validateBoardEquals (manaPoolFor Active) "W"
    , refute
        "requires sufficient mana (colorless)"
        "Mana pool () does not contain (X)" $ do
          spendMana "1"
    , refute
        "requires sufficient mana (colored)"
        "Mana pool () does not contain (X)" $ do
          addMana "R"
          spendMana "2"
    , refute
        "requires right color mana"
        "Mana pool (R) does not contain (W)" $ do
          addMana "R"
          spendMana "W"
    ]
  , testGroup "addMana"
    [ prove "adds mana to pool" $ do
        addMana "2RG"
        validateBoardEquals (manaPool . at Active . _Just) "GRXX"
    , prove "adds mana with multiple digits to pool" $ do
        addMana "10"
        validateBoardEquals (manaPool . at Active . _Just) (replicate 10 'X')
    ]
  , testGroup "tap"
    [ prove "taps card in play" $ do
        withLocation (Active, Play) $ addLand "Forest"
        tap "Forest"

        validate "Forest" $ matchAttribute tapped
    , prove "taps card in opponent's play" $ do
        withLocation (Active, Play) $ addLand "Forest"
        tap "Forest"

        validate "Forest" $ matchAttribute tapped
    , refute
        "requires card exists"
        "Card does not exist: Forest" $ do
          tap "Forest"
    , refute
        "requires untapped"
        "not has attribute tapped" $ do
          withAttribute tapped $ withLocation (Active, Play) $ addLand "Forest"
          tap "Forest"
    , refute
        "requires in play"
        "in play" $ do
          withLocation (Active, Graveyard) $ addLand "Forest"
          tap "Forest"
    ]
  , testGroup "tapForMana"
    [ prove "taps card and adds mana to pool" $ do
        withLocation (Active, Play) $ addLand "Forest"
        tapForMana "G" "Forest"

        validate "Forest" $ matchAttribute tapped
        validateBoardEquals (manaPoolFor Active) "G"
    ]
  , testGroup "transitionTo"
    [ prove "moves to new state" $ do
        transitionTo BeginCombat
        validatePhase BeginCombat
    , prove "empties mana pool" $ do
        addMana "B"
        transitionTo BeginCombat
        validateBoardEquals manaPool mempty
    , refute
        "requires later phase"
        "FirstMain does not occur after BeginCombat" $ do
          transitionTo BeginCombat
          transitionTo FirstMain
    ]
  , testGroup "transitionToForced"
    [ prove "can transition backwards" $ do
        transitionTo BeginCombat
        transitionToForced FirstMain
        validatePhase FirstMain
    ]
  , testGroup "untap"
    [ prove "untaps card in play" $ do
        withLocation (Active, Play) $ withAttribute tapped $  addLand "Forest"
        untap "Forest"

        validate "Forest" $ missingAttribute tapped
    , prove "untaps card in opponent's play" $ do
        withLocation (Opponent, Play) $ withAttribute tapped $ addLand "Forest"
        untap "Forest"

        validate "Forest" $ missingAttribute tapped
    , refute
        "requires card exists"
        "Card does not exist: Forest" $ do
          untap "Forest"
    , refute
        "requires tapped"
        "has attribute tapped" $ do
          withLocation (Active, Play) $ addLand "Forest"
          untap "Forest"
    , refute
        "requires in play"
        "in play" $ do
          withLocation (Active, Graveyard) $ addLand "Forest"
          untap "Forest"
    ]
  , testGroup "splice"
    [ prove "splices on to an arcane spell" $ do
        withLocation (Active, Hand) $ do
          addInstant "Glacial Ray"
          withAttribute arcane $ addInstant "Lava Spike"

        addMana "RRR"
        cast "R" "Lava Spike"
        splice "Lava Spike" "1R" "Glacial Ray"
        resolveTop

        validate "Glacial Ray" $ matchLocation (Active, Hand)
        validateBoardEquals stack mempty
        validateBoardEquals (manaPoolFor Active) mempty
    , prove "can splice as opponent" $ do
        withLocation (Opponent, Hand) $ do
          addInstant "Glacial Ray"
          withAttribute arcane $ addInstant "Lava Spike"

        as Opponent $ do
          addMana "RRR"
          cast "R" "Lava Spike"
          splice "Lava Spike" "1R" "Glacial Ray"
          resolveTop

          validate "Glacial Ray" $ matchLocation (Opponent, Hand)
          validateBoardEquals stack mempty
          validateBoardEquals (manaPoolFor Opponent) mempty
    , refute
      "requires arcane"
      "has attribute arcane" $ do
        withLocation (Active, Hand) $ do
          addInstant "Glacial Ray"
          addInstant "Lava Spike"

        cast "" "Lava Spike"
        splice "Lava Spike" "" "Glacial Ray"
    , refute
      "requires spliced spell on stack"
      "Lava Spike not on stack" $ do
        withLocation (Active, Hand) $ do
          addInstant "Glacial Ray"
          withAttribute arcane $ addInstant "Lava Spike"

        splice "Lava Spike" "" "Glacial Ray"
    , refute
      "requires spell in hand"
      "Glacial Ray not in hand" $ do
        withLocation (Active, Graveyard) $
          addInstant "Glacial Ray"
        withLocation (Active, Hand) $
          withAttribute arcane $ addInstant "Lava Spike"

        cast "" "Lava Spike"
        splice "Lava Spike" "" "Glacial Ray"
    ]
  , testGroup "attackWith"
    [ prove "attacks with listed creatures" $ do
        withLocation (Active, Play) $ do
          addCreature (1, 1) "Bat 1"
          addCreature (1, 1) "Bat 2"
          addCreature (1, 1) "Bat 3"

        attackWith ["Bat 1", "Bat 2"]

        validatePhase DeclareAttackers
        validate "Bat 1" $ matchAttributes [attacking, tapped]
        validate "Bat 2" $ matchAttributes [attacking, tapped]
        validate "Bat 3" $ missingAttribute attacking
        validate "Bat 3" $ missingAttribute tapped
    , prove "does not tap vigilant attackers" $ do
        withLocation (Active, Play) $ do
          withAttribute vigilance $ addCreature (1, 1) "Bat"

        attackWith ["Bat"]
        validate "Bat" $ matchAttribute attacking
        validate "Bat" $ missingAttribute tapped
    , refute
        "prevents summoned creatures from attacking"
        "does not have summoning sickness" $ do
          withLocation (Active, Play) $ do
            withAttributes [summoned] $ addCreature (1, 1) "Bat"

          attackWith ["Bat"]
    , prove "allows hasty creatures to attack" $ do
        withLocation (Active, Play) $ do
          withAttributes [haste, summoned] $ addCreature (1, 1) "Bat"

        attackWith ["Bat"]
        validate "Bat" $ matchAttributes [attacking, tapped]
    ]
  ]