1091 lines
31 KiB
Haskell
1091 lines
31 KiB
Haskell
{-
|
|
|
|
mtlstats
|
|
Copyright (C) Rhéal Lamothe
|
|
<rheal.lamothe@gmail.com>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or (at
|
|
your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
-}
|
|
|
|
{-# LANGUAGE FlexibleInstances, OverloadedStrings, RankNTypes #-}
|
|
|
|
module TypesSpec
|
|
( Comparable (..)
|
|
, spec
|
|
, makePlayer
|
|
, makeGoalie
|
|
, makePlayerStats
|
|
, makeGoalieStats
|
|
) where
|
|
|
|
import Control.Monad (replicateM)
|
|
import Data.Aeson (FromJSON, ToJSON, decode, encode, toJSON)
|
|
import Data.Aeson.Types (Value (Object))
|
|
import qualified Data.Map.Lazy as M
|
|
import qualified Data.HashMap.Strict as HM
|
|
import Data.Ratio ((%))
|
|
import Lens.Micro (Lens', (&), (^.), (.~), (?~))
|
|
import System.Random (randomIO, randomRIO)
|
|
import Test.Hspec (Spec, context, describe, it, shouldBe)
|
|
|
|
import Mtlstats.Config
|
|
import Mtlstats.Types
|
|
|
|
import qualified Types.MenuSpec as Menu
|
|
|
|
class Comparable a where
|
|
compareTest :: a -> a -> Spec
|
|
|
|
spec :: Spec
|
|
spec = describe "Mtlstats.Types" $ do
|
|
playerSpec
|
|
goalieSpec
|
|
gameStatsSpec
|
|
databaseSpec
|
|
gameStateLSpec
|
|
createPlayerStateLSpec
|
|
createGoalieStateLSpec
|
|
editPlayerStateLSpec
|
|
editGoalieStateLSpec
|
|
editStandingsModeLSpec
|
|
esmSubModeLSpec
|
|
teamScoreSpec
|
|
otherScoreSpec
|
|
homeTeamSpec
|
|
awayTeamSpec
|
|
gameWonSpec
|
|
gameLostSpec
|
|
gameTiedSpec
|
|
unaccountedPointsSpec
|
|
gmsGamesSpec
|
|
gmsPointsSpec
|
|
addGameStatsSpec
|
|
playerSearchSpec
|
|
activePlayerSearchSpec
|
|
playerSearchExactSpec
|
|
modifyPlayerSpec
|
|
playerSummarySpec
|
|
playerIsActiveSpec
|
|
psPointsSpec
|
|
addPlayerStatsSpec
|
|
goalieSearchSpec
|
|
activeGoalieSearchSpec
|
|
goalieSearchExactSpec
|
|
goalieSummarySpec
|
|
goalieIsActiveSpec
|
|
addGoalieStatsSpec
|
|
gsAverageSpec
|
|
Menu.spec
|
|
|
|
playerSpec :: Spec
|
|
playerSpec = describe "Player" $ jsonSpec player playerJSON
|
|
|
|
goalieSpec :: Spec
|
|
goalieSpec = describe "Goalie" $ jsonSpec goalie goalieJSON
|
|
|
|
gameStatsSpec :: Spec
|
|
gameStatsSpec = describe "GameStats" $
|
|
jsonSpec (gameStats 1) (gameStatsJSON 1)
|
|
|
|
databaseSpec :: Spec
|
|
databaseSpec = describe "Database" $ jsonSpec db dbJSON
|
|
|
|
gameStateLSpec :: Spec
|
|
gameStateLSpec = describe "gameStateL" $ lensSpec gameStateL
|
|
-- getters
|
|
[ ( "missing state", MainMenu, newGameState )
|
|
, ( "home game", NewGame $ gs HomeGame, gs HomeGame )
|
|
, ( "away game", NewGame $ gs AwayGame, gs AwayGame )
|
|
]
|
|
-- setters
|
|
[ ( "set home", MainMenu, gs HomeGame )
|
|
, ( "home to away", NewGame $ gs HomeGame, gs AwayGame )
|
|
, ( "away to home", NewGame $ gs AwayGame, gs HomeGame )
|
|
, ( "clear home", NewGame $ gs HomeGame, newGameState )
|
|
, ( "clear away", NewGame $ gs AwayGame, newGameState )
|
|
]
|
|
where gs t = newGameState & gameType ?~ t
|
|
|
|
createPlayerStateLSpec :: Spec
|
|
createPlayerStateLSpec = describe "createPlayerStateL" $
|
|
lensSpec createPlayerStateL
|
|
-- getters
|
|
[ ( "missing state", MainMenu, newCreatePlayerState )
|
|
, ( "with state", CreatePlayer cps1, cps1 )
|
|
]
|
|
-- setters
|
|
[ ( "missing state", MainMenu, cps1 )
|
|
, ( "change state", CreatePlayer cps1, cps2 )
|
|
, ( "clear state", CreatePlayer cps1, newCreatePlayerState )
|
|
]
|
|
where
|
|
cps1 = newCreatePlayerState
|
|
& cpsNumber ?~ 1
|
|
& cpsName .~ "Joe"
|
|
& cpsPosition .~ "centre"
|
|
cps2 = newCreatePlayerState
|
|
& cpsNumber ?~ 2
|
|
& cpsName .~ "Bob"
|
|
& cpsPosition .~ "defense"
|
|
|
|
createGoalieStateLSpec :: Spec
|
|
createGoalieStateLSpec = describe "createGoalieStateL" $
|
|
lensSpec createGoalieStateL
|
|
-- getters
|
|
[ ( "missing state", MainMenu, newCreateGoalieState )
|
|
, ( "with state", CreateGoalie cgs1, cgs1 )
|
|
]
|
|
-- setters
|
|
[ ( "set state", MainMenu, cgs1 )
|
|
, ( "change state", CreateGoalie cgs1, cgs2 )
|
|
, ( "clear state", CreateGoalie cgs1, newCreateGoalieState )
|
|
]
|
|
where
|
|
cgs1 = newCreateGoalieState
|
|
& cgsNumber ?~ 1
|
|
& cgsName .~ "Joe"
|
|
cgs2 = newCreateGoalieState
|
|
& cgsNumber ?~ 2
|
|
& cgsName .~ "Bob"
|
|
|
|
editPlayerStateLSpec :: Spec
|
|
editPlayerStateLSpec = describe "editPlayerStateL" $
|
|
lensSpec editPlayerStateL
|
|
-- getters
|
|
[ ( "missing state", MainMenu, newEditPlayerState )
|
|
, ( "withState", EditPlayer eps1, eps1 )
|
|
]
|
|
-- setters
|
|
[ ( "set state", MainMenu, eps1 )
|
|
, ( "change state", EditPlayer eps1, eps2 )
|
|
, ( "clear state", EditPlayer eps1, newEditPlayerState )
|
|
]
|
|
where
|
|
eps1 = newEditPlayerState
|
|
& epsSelectedPlayer ?~ 1
|
|
eps2 = newEditPlayerState
|
|
& epsSelectedPlayer ?~ 2
|
|
|
|
editGoalieStateLSpec :: Spec
|
|
editGoalieStateLSpec = describe "editGoalieStateL" $
|
|
lensSpec editGoalieStateL
|
|
-- getters
|
|
[ ( "missing state", MainMenu, newEditGoalieState )
|
|
, ( "with state", EditGoalie egs1, egs1 )
|
|
]
|
|
-- setters
|
|
[ ( "set state", MainMenu, egs1 )
|
|
, ( "change state", EditGoalie egs1, egs2 )
|
|
, ( "clear state", EditGoalie egs1, newEditGoalieState )
|
|
]
|
|
where
|
|
egs1 = newEditGoalieState
|
|
& egsSelectedGoalie ?~ 1
|
|
egs2 = newEditGoalieState
|
|
& egsSelectedGoalie ?~ 2
|
|
|
|
editStandingsModeLSpec :: Spec
|
|
editStandingsModeLSpec = describe "editStandingsModeL" $
|
|
lensSpec editStandingsModeL
|
|
-- getters
|
|
[ ( "missing mode", MainMenu, menu )
|
|
, ( "with mode", EditStandings home, home )
|
|
]
|
|
-- setters
|
|
[ ( "set mode", MainMenu, home )
|
|
, ( "change mode", EditStandings home, away )
|
|
]
|
|
where
|
|
menu = ESMMenu
|
|
home = ESMHome ESMSubMenu
|
|
away = ESMAway ESMSubMenu
|
|
|
|
esmSubModeLSpec :: Spec
|
|
esmSubModeLSpec = describe "esmSubModeL" $ do
|
|
|
|
context "getters" $ mapM_
|
|
(\(label, mode, expected) -> context label $
|
|
it ("should be " ++ show expected) $
|
|
mode^.esmSubModeL `shouldBe` expected)
|
|
|
|
-- label, mode, expected
|
|
[ ( "no state", ESMMenu, ESMSubMenu )
|
|
, ( "with state", ESMHome ESMEditWins, ESMEditWins )
|
|
]
|
|
|
|
context "setters" $ mapM_
|
|
(\(label, mode, expected) -> context label $
|
|
it ("should be " ++ show expected) $ let
|
|
mode' = mode & esmSubModeL .~ ESMEditWins
|
|
in mode' `shouldBe` expected)
|
|
|
|
-- label, mode, expected
|
|
[ ( "no state", ESMMenu, ESMMenu )
|
|
, ( "home mode", ESMHome ESMSubMenu, ESMHome ESMEditWins )
|
|
, ( "away mode", ESMAway ESMSubMenu, ESMAway ESMEditWins )
|
|
]
|
|
|
|
teamScoreSpec :: Spec
|
|
teamScoreSpec = describe "teamScore" $ do
|
|
let
|
|
s t = newGameState
|
|
& gameType ?~ t
|
|
& homeScore ?~ 1
|
|
& awayScore ?~ 2
|
|
|
|
context "unknown game type" $
|
|
it "should return Nothing" $
|
|
teamScore newGameState `shouldBe` Nothing
|
|
|
|
context "HomeGame" $
|
|
it "should return 1" $
|
|
teamScore (s HomeGame) `shouldBe` Just 1
|
|
|
|
context "AwayGame" $
|
|
it "should return 2" $
|
|
teamScore (s AwayGame) `shouldBe` Just 2
|
|
|
|
otherScoreSpec :: Spec
|
|
otherScoreSpec = describe "otherScore" $ do
|
|
let
|
|
s t = newGameState
|
|
& gameType ?~ t
|
|
& homeScore ?~ 1
|
|
& awayScore ?~ 2
|
|
|
|
context "unknown game type" $
|
|
it "should return Nothing" $
|
|
otherScore newGameState `shouldBe` Nothing
|
|
|
|
context "HomeGame" $
|
|
it "should return 2" $
|
|
otherScore (s HomeGame) `shouldBe` Just 2
|
|
|
|
context "AwayGame" $
|
|
it "should return 1" $
|
|
otherScore (s AwayGame) `shouldBe` Just 1
|
|
|
|
jsonSpec
|
|
:: (Eq a, Show a, FromJSON a, ToJSON a)
|
|
=> a
|
|
-> Value
|
|
-> Spec
|
|
jsonSpec x j = do
|
|
|
|
describe "decode" $
|
|
it "should decode" $
|
|
decode (encode j) `shouldBe` Just x
|
|
|
|
describe "toJSON" $
|
|
it "should encode" $
|
|
decode (encode $ toJSON x) `shouldBe` Just x
|
|
|
|
describe "toEncoding" $
|
|
it "should encode" $
|
|
decode (encode x) `shouldBe` Just x
|
|
|
|
lensSpec
|
|
:: Comparable a
|
|
=> Lens' s a
|
|
-> [(String, s, a)]
|
|
-> [(String, s, a)]
|
|
-> Spec
|
|
lensSpec lens getters setters = do
|
|
|
|
context "getters" $ mapM_
|
|
(\(label, s, x) -> context label $
|
|
compareTest (s^.lens) x)
|
|
getters
|
|
|
|
context "setters" $ mapM_
|
|
(\(label, s, x) -> context label $ let
|
|
s' = s & lens .~ x
|
|
in compareTest (s'^.lens) x)
|
|
setters
|
|
|
|
player :: Player
|
|
player = newPlayer 1 "Joe" "centre"
|
|
& pRookie .~ False
|
|
& pYtd .~ playerStats 1
|
|
& pLifetime .~ playerStats 2
|
|
|
|
playerJSON :: Value
|
|
playerJSON = Object $ HM.fromList
|
|
[ ( "number", toJSON (1 :: Int) )
|
|
, ( "name", toJSON ("Joe" :: String) )
|
|
, ( "position", toJSON ("centre" :: String) )
|
|
, ( "rookie", toJSON False )
|
|
, ( "active", toJSON True )
|
|
, ( "ytd", playerStatsJSON 1 )
|
|
, ( "lifetime", playerStatsJSON 2 )
|
|
]
|
|
|
|
playerStats :: Int -> PlayerStats
|
|
playerStats n = newPlayerStats
|
|
& psGoals .~ n
|
|
& psAssists .~ n + 1
|
|
& psPMin .~ n + 2
|
|
|
|
playerStatsJSON :: Int -> Value
|
|
playerStatsJSON n = Object $ HM.fromList
|
|
[ ( "goals", toJSON n )
|
|
, ( "assists", toJSON $ n + 1 )
|
|
, ( "penalty_mins", toJSON $ n + 2 )
|
|
]
|
|
|
|
goalie :: Goalie
|
|
goalie = newGoalie 1 "Joe"
|
|
& gRookie .~ False
|
|
& gYtd .~ goalieStats 1
|
|
& gLifetime .~ goalieStats 2
|
|
|
|
goalieJSON :: Value
|
|
goalieJSON = Object $ HM.fromList
|
|
[ ( "number", toJSON (1 :: Int) )
|
|
, ( "name", toJSON ("Joe" :: String ) )
|
|
, ( "rookie", toJSON False )
|
|
, ( "active", toJSON True )
|
|
, ( "ytd", goalieStatsJSON 1 )
|
|
, ( "lifetime", goalieStatsJSON 2 )
|
|
]
|
|
|
|
goalieStats :: Int -> GoalieStats
|
|
goalieStats n = newGoalieStats
|
|
& gsGames .~ n
|
|
& gsMinsPlayed .~ n + 1
|
|
& gsGoalsAllowed .~ n + 2
|
|
& gsShutouts .~ n + 3
|
|
& gsWins .~ n + 4
|
|
& gsLosses .~ n + 5
|
|
& gsTies .~ n + 6
|
|
|
|
goalieStatsJSON :: Int -> Value
|
|
goalieStatsJSON n = Object $ HM.fromList
|
|
[ ( "games", toJSON n )
|
|
, ( "mins_played", toJSON $ n + 1 )
|
|
, ( "goals_allowed", toJSON $ n + 2 )
|
|
, ( "shutouts", toJSON $ n + 3 )
|
|
, ( "wins", toJSON $ n + 4 )
|
|
, ( "losses", toJSON $ n + 5 )
|
|
, ( "ties", toJSON $ n + 6 )
|
|
]
|
|
|
|
gameStats :: Int -> GameStats
|
|
gameStats n = GameStats
|
|
{ _gmsWins = n
|
|
, _gmsLosses = n + 1
|
|
, _gmsOvertime = n + 2
|
|
, _gmsGoalsFor = n + 3
|
|
, _gmsGoalsAgainst = n + 4
|
|
}
|
|
|
|
gameStatsJSON :: Int -> Value
|
|
gameStatsJSON n = Object $ HM.fromList
|
|
[ ( "wins", toJSON n )
|
|
, ( "losses", toJSON $ n + 1 )
|
|
, ( "overtime", toJSON $ n + 2 )
|
|
, ( "goals_for", toJSON $ n + 3 )
|
|
, ( "goals_against", toJSON $ n + 4 )
|
|
]
|
|
|
|
db :: Database
|
|
db = newDatabase
|
|
& dbPlayers .~ [player]
|
|
& dbGoalies .~ [goalie]
|
|
& dbGames .~ 1
|
|
& dbHomeGameStats .~ gameStats 1
|
|
& dbAwayGameStats .~ gameStats 2
|
|
|
|
dbJSON :: Value
|
|
dbJSON = Object $ HM.fromList
|
|
[ ( "players", toJSON [playerJSON] )
|
|
, ( "goalies", toJSON [goalieJSON] )
|
|
, ( "games", toJSON (1 :: Int) )
|
|
, ( "home_game_stats", gameStatsJSON 1 )
|
|
, ( "away_game_stats", gameStatsJSON 2 )
|
|
]
|
|
|
|
homeTeamSpec :: Spec
|
|
homeTeamSpec = describe "homeTeam" $ do
|
|
let
|
|
gs gt = newGameState
|
|
& gameType .~ gt
|
|
& otherTeam .~ "foo"
|
|
|
|
context "unknown game type" $
|
|
it "should return an empty string" $
|
|
homeTeam (gs Nothing) `shouldBe` ""
|
|
|
|
context "home game" $
|
|
it ("should return " ++ show myTeam) $
|
|
homeTeam (gs $ Just HomeGame) `shouldBe` myTeam
|
|
|
|
context "away game" $
|
|
it "should return \"foo\"" $
|
|
homeTeam (gs $ Just AwayGame) `shouldBe` "foo"
|
|
|
|
awayTeamSpec :: Spec
|
|
awayTeamSpec = describe "awayTeam" $ do
|
|
let
|
|
gs gt = newGameState
|
|
& gameType .~ gt
|
|
& otherTeam .~ "foo"
|
|
|
|
context "unknown game type" $
|
|
it "should return an empty string" $
|
|
awayTeam (gs Nothing) `shouldBe` ""
|
|
|
|
context "home game" $
|
|
it "should return \"foo\"" $
|
|
awayTeam (gs $ Just HomeGame) `shouldBe` "foo"
|
|
|
|
context "away game" $
|
|
it ("should return " ++ show myTeam) $
|
|
awayTeam (gs $ Just AwayGame) `shouldBe` myTeam
|
|
|
|
gameWonSpec :: Spec
|
|
gameWonSpec = describe "gameWon" $ mapM_
|
|
(\(t, h, a, expected) -> let
|
|
desc = "game type: " ++ show t ++
|
|
", home score: " ++ show h ++
|
|
", away score: " ++ show a
|
|
gs = newGameState
|
|
& gameType .~ t
|
|
& homeScore .~ h
|
|
& awayScore .~ a
|
|
in context desc $
|
|
it ("should be " ++ show expected) $
|
|
gameWon gs `shouldBe` expected)
|
|
-- gameType, homeScore, awayScore, expected
|
|
[ ( Just HomeGame, Just 1, Just 1, Just False )
|
|
, ( Just HomeGame, Just 1, Just 2, Just False )
|
|
, ( Just HomeGame, Just 2, Just 1, Just True )
|
|
, ( Just AwayGame, Just 1, Just 1, Just False )
|
|
, ( Just AwayGame, Just 1, Just 2, Just True )
|
|
, ( Just AwayGame, Just 2, Just 1, Just False )
|
|
, ( Nothing, Just 1, Just 2, Nothing )
|
|
, ( Just HomeGame, Nothing, Just 1, Nothing )
|
|
, ( Just AwayGame, Nothing, Just 1, Nothing )
|
|
, ( Just HomeGame, Just 1, Nothing, Nothing )
|
|
, ( Just AwayGame, Just 1, Nothing, Nothing )
|
|
, ( Nothing, Nothing, Nothing, Nothing )
|
|
]
|
|
|
|
gameLostSpec :: Spec
|
|
gameLostSpec = describe "gameLost" $ mapM_
|
|
(\(t, h, a, ot, expected) -> let
|
|
desc = "game type: " ++ show t ++
|
|
", home score: " ++ show h ++
|
|
", away score: " ++ show a ++
|
|
", overtimr flag: " ++ show ot
|
|
gs = newGameState
|
|
& gameType .~ t
|
|
& homeScore .~ h
|
|
& awayScore .~ a
|
|
& overtimeFlag .~ ot
|
|
in context desc $
|
|
it ("should be " ++ show expected) $
|
|
gameLost gs `shouldBe` expected)
|
|
-- gameType, homeScore, awayScore, overtimeFlag, expected
|
|
[ ( Just HomeGame, Just 1, Just 1, Just False, Just False )
|
|
, ( Just HomeGame, Just 1, Just 2, Just False, Just True )
|
|
, ( Just HomeGame, Just 1, Just 2, Just True, Just False )
|
|
, ( Just HomeGame, Just 2, Just 1, Just False, Just False )
|
|
, ( Just AwayGame, Just 1, Just 1, Just False, Just False )
|
|
, ( Just AwayGame, Just 1, Just 2, Just False, Just False )
|
|
, ( Just AwayGame, Just 2, Just 1, Just False, Just True )
|
|
, ( Just AwayGame, Just 2, Just 1, Just True, Just False )
|
|
, ( Nothing, Just 1, Just 2, Just False, Nothing )
|
|
, ( Just HomeGame, Nothing, Just 1, Just False, Nothing )
|
|
, ( Just AwayGame, Nothing, Just 1, Just False, Nothing )
|
|
, ( Just HomeGame, Just 1, Nothing, Just False, Nothing )
|
|
, ( Just AwayGame, Just 1, Nothing, Just False, Nothing )
|
|
, ( Just HomeGame, Just 1, Just 2, Nothing, Nothing )
|
|
, ( Just AwayGame, Just 1, Just 2, Nothing, Nothing )
|
|
, ( Nothing, Nothing, Nothing, Just False, Nothing )
|
|
]
|
|
|
|
gameTiedSpec :: Spec
|
|
gameTiedSpec = describe "gameTied" $ mapM_
|
|
(\(home, away, expected) -> let
|
|
desc = "home score: " ++ show home ++
|
|
", away score: " ++ show away
|
|
gs = newGameState
|
|
& homeScore .~ home
|
|
& awayScore .~ away
|
|
in context desc $
|
|
it ("should be " ++ show expected) $
|
|
gameTied gs `shouldBe` expected)
|
|
[ ( Nothing, Nothing, Nothing )
|
|
, ( Nothing, Just 1, Nothing )
|
|
, ( Just 1, Nothing, Nothing )
|
|
, ( Just 1, Just 1, Just True )
|
|
, ( Just 1, Just 2, Just False )
|
|
]
|
|
|
|
unaccountedPointsSpec :: Spec
|
|
unaccountedPointsSpec = describe "unaccounted points" $ do
|
|
context "no data" $
|
|
it "should return Nothing" $
|
|
unaccountedPoints newGameState `shouldBe` Nothing
|
|
|
|
context "unaccounted points" $
|
|
it "should return True" $ let
|
|
gs = newGameState
|
|
& gameType ?~ HomeGame
|
|
& homeScore ?~ 1
|
|
in unaccountedPoints gs `shouldBe` Just True
|
|
|
|
context "all points accounted" $
|
|
it "should return False" $ let
|
|
gs = newGameState
|
|
& gameType ?~ HomeGame
|
|
& homeScore ?~ 1
|
|
& pointsAccounted .~ 1
|
|
in unaccountedPoints gs `shouldBe` Just False
|
|
|
|
context "more points accounted" $
|
|
it "should return True" $ let
|
|
gs = newGameState
|
|
& gameType ?~ HomeGame
|
|
& homeScore ?~ 1
|
|
& pointsAccounted .~ 2
|
|
in unaccountedPoints gs `shouldBe` Just False
|
|
|
|
gmsGamesSpec :: Spec
|
|
gmsGamesSpec = describe "gmsGames" $ mapM_
|
|
(\(w, l, ot, expected) -> let
|
|
desc = "wins: " ++ show w ++
|
|
", losses: " ++ show l ++
|
|
", overtime: " ++ show ot
|
|
gs = newGameStats
|
|
& gmsWins .~ w
|
|
& gmsLosses .~ l
|
|
& gmsOvertime .~ ot
|
|
in context desc $
|
|
it ("should be " ++ show expected) $
|
|
gmsGames gs `shouldBe` expected)
|
|
-- wins, losses, overtime, expected
|
|
[ ( 0, 0, 0, 0 )
|
|
, ( 1, 0, 0, 1 )
|
|
, ( 0, 1, 0, 1 )
|
|
, ( 0, 0, 1, 1 )
|
|
, ( 1, 1, 1, 3 )
|
|
, ( 2, 3, 5, 10 )
|
|
]
|
|
|
|
gmsPointsSpec :: Spec
|
|
gmsPointsSpec = describe "gmsPoints" $ mapM_
|
|
(\(w, l, ot, expected) -> let
|
|
gs
|
|
= newGameStats
|
|
& gmsWins .~ w
|
|
& gmsLosses .~ l
|
|
& gmsOvertime .~ ot
|
|
in context (show gs) $
|
|
it ("should be " ++ show expected) $
|
|
gmsPoints gs `shouldBe` expected)
|
|
-- wins, losses, overtime, expected
|
|
[ ( 0, 0, 0, 0 )
|
|
, ( 1, 0, 0, 2 )
|
|
, ( 0, 1, 0, 0 )
|
|
, ( 0, 1, 1, 1 )
|
|
, ( 1, 1, 1, 3 )
|
|
, ( 2, 4, 3, 7 )
|
|
]
|
|
|
|
addGameStatsSpec :: Spec
|
|
addGameStatsSpec = describe "addGameStats" $
|
|
it "should add the values" $ let
|
|
|
|
s1 = GameStats
|
|
{ _gmsWins = 1
|
|
, _gmsLosses = 2
|
|
, _gmsOvertime = 3
|
|
, _gmsGoalsFor = 4
|
|
, _gmsGoalsAgainst = 5
|
|
}
|
|
|
|
s2 = GameStats
|
|
{ _gmsWins = 6
|
|
, _gmsLosses = 7
|
|
, _gmsOvertime = 8
|
|
, _gmsGoalsFor = 9
|
|
, _gmsGoalsAgainst = 10
|
|
}
|
|
|
|
expected = GameStats
|
|
{ _gmsWins = 7
|
|
, _gmsLosses = 9
|
|
, _gmsOvertime = 11
|
|
, _gmsGoalsFor = 13
|
|
, _gmsGoalsAgainst = 15
|
|
}
|
|
|
|
in addGameStats s1 s2 `shouldBe` expected
|
|
|
|
playerSearchSpec :: Spec
|
|
playerSearchSpec = describe "playerSearch" $ mapM_
|
|
(\(sStr, expected) -> context sStr $
|
|
it ("should return " ++ show expected) $ let
|
|
ps = [joe, bob, steve]
|
|
in playerSearch sStr ps `shouldBe` expected)
|
|
-- search, result
|
|
[ ( "joe", [(0, joe)] )
|
|
, ( "o", [(0, joe), (1, bob)] )
|
|
, ( "e", [(0, joe), (2, steve)] )
|
|
, ( "x", [] )
|
|
]
|
|
|
|
activePlayerSearchSpec :: Spec
|
|
activePlayerSearchSpec = describe "activePlayerSearch" $ mapM_
|
|
(\(sStr, expected) -> context sStr $
|
|
it ("should return " ++ show expected) $ let
|
|
ps = [joe, bob, steve & pActive .~ False]
|
|
in activePlayerSearch sStr ps `shouldBe` expected)
|
|
-- search, result
|
|
[ ( "joe", [(0, joe)] )
|
|
, ( "o", [(0, joe), (1, bob)] )
|
|
, ( "e", [(0, joe)] )
|
|
, ( "x", [] )
|
|
]
|
|
|
|
playerSearchExactSpec :: Spec
|
|
playerSearchExactSpec = describe "playerSearchExact" $ mapM_
|
|
(\(sStr, expected) -> context sStr $
|
|
it ("should be " ++ show expected) $ let
|
|
ps = [joe, bob, steve]
|
|
in playerSearchExact sStr ps `shouldBe` expected)
|
|
-- search, result
|
|
[ ( "Joe", Just (0, joe) )
|
|
, ( "Bob", Just (1, bob) )
|
|
, ( "Steve", Just (2, steve) )
|
|
, ( "Sam", Nothing )
|
|
, ( "", Nothing )
|
|
]
|
|
|
|
modifyPlayerSpec :: Spec
|
|
modifyPlayerSpec = describe "modifyPlayer" $ mapM_
|
|
(\(name, j, b, s) -> let
|
|
modifier = pLifetime.psGoals .~ 1
|
|
players = modifyPlayer modifier name [joe, bob, steve]
|
|
in context ("modify " ++ name) $ do
|
|
|
|
context "Joe's lifetime goals" $
|
|
it ("should be " ++ show j) $
|
|
head players^.pLifetime.psGoals `shouldBe` j
|
|
|
|
context "Bob's lifetime goals" $
|
|
it ("should be " ++ show b) $
|
|
(players !! 1)^.pLifetime.psGoals `shouldBe` b
|
|
|
|
context "Steve's lifetime goals" $
|
|
it ("should be " ++ show s) $
|
|
last players^.pLifetime.psGoals `shouldBe` s)
|
|
-- player name, Joe's goals, Bob's goals, Steve's goals
|
|
[ ( "Joe", 1, 0, 0 )
|
|
, ( "Bob", 0, 1, 0 )
|
|
, ( "Steve", 0, 0, 1 )
|
|
, ( "Sam", 0, 0, 0 )
|
|
]
|
|
|
|
playerSummarySpec :: Spec
|
|
playerSummarySpec = describe "playerSummary" $
|
|
it "should be \"Joe (2) center\"" $
|
|
playerSummary joe `shouldBe` "Joe (2) center"
|
|
|
|
playerIsActiveSpec :: Spec
|
|
playerIsActiveSpec = describe "playerIsActive" $ do
|
|
let
|
|
pStats = newPlayerStats
|
|
& psGoals .~ 10
|
|
& psAssists .~ 11
|
|
& psPMin .~ 12
|
|
p = newPlayer 1 "Joe" "centre" & pLifetime .~ pStats
|
|
|
|
mapM_
|
|
(\(label, p', expected) -> context label $
|
|
it ("should be " ++ show expected) $
|
|
playerIsActive p' `shouldBe` expected)
|
|
-- label, player, expected
|
|
[ ( "not active", p, False )
|
|
, ( "has goal", p & pYtd.psGoals .~ 1, True )
|
|
, ( "has assist", p & pYtd.psAssists .~ 1, True )
|
|
, ( "has penalty minute", p & pYtd.psPMin .~ 1, True )
|
|
]
|
|
|
|
psPointsSpec :: Spec
|
|
psPointsSpec = describe "psPoints" $ mapM_
|
|
(\(goals, assists, points) -> let
|
|
desc = "goals: " ++ show goals ++
|
|
", assists: " ++ show assists
|
|
stats = newPlayerStats &
|
|
psGoals .~ goals &
|
|
psAssists .~ assists
|
|
in context desc $
|
|
it ("should be " ++ show points) $
|
|
psPoints stats `shouldBe` points)
|
|
-- goals, assists, points
|
|
[ ( 0, 0, 0 )
|
|
, ( 1, 0, 1 )
|
|
, ( 0, 1, 1 )
|
|
, ( 2, 3, 5 )
|
|
]
|
|
|
|
addPlayerStatsSpec :: Spec
|
|
addPlayerStatsSpec = describe "addPlayerStats" $ do
|
|
let
|
|
s1
|
|
= newPlayerStats
|
|
& psGoals .~ 1
|
|
& psAssists .~ 2
|
|
& psPMin .~ 3
|
|
s2
|
|
= newPlayerStats
|
|
& psGoals .~ 4
|
|
& psAssists .~ 5
|
|
& psPMin .~ 6
|
|
s3 = addPlayerStats s1 s2
|
|
|
|
describe "psGoals" $
|
|
it "should be 5" $
|
|
s3^.psGoals `shouldBe` 5
|
|
|
|
describe "psAssists" $
|
|
it "should be 7" $
|
|
s3^.psAssists `shouldBe` 7
|
|
|
|
describe "psPMin" $
|
|
it "should be 9" $
|
|
s3^.psPMin `shouldBe` 9
|
|
|
|
goalieSearchSpec :: Spec
|
|
goalieSearchSpec = describe "goalieSearch" $ do
|
|
let
|
|
goalies =
|
|
[ newGoalie 2 "Joe"
|
|
, newGoalie 3 "Bob"
|
|
, newGoalie 5 "Steve"
|
|
]
|
|
result n = (n, goalies!!n)
|
|
|
|
context "partial match" $
|
|
it "should return Joe and Steve" $
|
|
goalieSearch "e" goalies `shouldBe` [result 0, result 2]
|
|
|
|
context "no match" $
|
|
it "should return an empty list" $
|
|
goalieSearch "x" goalies `shouldBe` []
|
|
|
|
context "exact match" $
|
|
it "should return Bob" $
|
|
goalieSearch "bob" goalies `shouldBe` [result 1]
|
|
|
|
activeGoalieSearchSpec :: Spec
|
|
activeGoalieSearchSpec = describe "activeGoalieSearch" $ do
|
|
let
|
|
goalies =
|
|
[ newGoalie 2 "Joe"
|
|
, newGoalie 3 "Bob"
|
|
, newGoalie 5 "Steve" & gActive .~ False
|
|
]
|
|
result n = (n, goalies!!n)
|
|
|
|
context "partial match" $
|
|
it "should return Joe" $
|
|
activeGoalieSearch "e" goalies `shouldBe` [result 0]
|
|
|
|
context "no match" $
|
|
it "should return an empty list" $
|
|
activeGoalieSearch "x" goalies `shouldBe` []
|
|
|
|
context "exact match" $
|
|
it "should return Bob" $
|
|
activeGoalieSearch "bob" goalies `shouldBe` [result 1]
|
|
|
|
goalieSearchExactSpec :: Spec
|
|
goalieSearchExactSpec = describe "goalieSearchExact" $ do
|
|
let
|
|
goalies =
|
|
[ newGoalie 2 "Joe"
|
|
, newGoalie 3 "Bob"
|
|
, newGoalie 5 "Steve"
|
|
]
|
|
result n = (n, goalies!!n)
|
|
|
|
mapM_
|
|
(\(name, num) -> context name $
|
|
it ("should return " ++ name) $
|
|
goalieSearchExact name goalies `shouldBe` Just (result num))
|
|
-- name, num
|
|
[ ( "Joe", 0 )
|
|
, ( "Bob", 1 )
|
|
, ( "Steve", 2 )
|
|
]
|
|
|
|
context "Greg" $
|
|
it "should return Nothing" $
|
|
goalieSearchExact "Greg" goalies `shouldBe` Nothing
|
|
|
|
goalieSummarySpec :: Spec
|
|
goalieSummarySpec = describe "goalieSummary" $
|
|
it "should provide a summary string" $
|
|
goalieSummary (newGoalie 2 "Joe") `shouldBe` "Joe (2)"
|
|
|
|
goalieIsActiveSpec :: Spec
|
|
goalieIsActiveSpec = describe "goalieIsActive" $ mapM_
|
|
(\(label, input, expected) -> context label $
|
|
it ("should be " ++ show expected) $
|
|
goalieIsActive input `shouldBe` expected)
|
|
|
|
-- label, input, expected
|
|
[ ( "inactive", inactive, False )
|
|
, ( "active", active, True )
|
|
]
|
|
|
|
where
|
|
inactive = newGoalie 1 "Joe"
|
|
& gLifetime.gsMinsPlayed .~ 1
|
|
|
|
active = inactive
|
|
& gYtd.gsMinsPlayed .~ 1
|
|
|
|
addGoalieStatsSpec :: Spec
|
|
addGoalieStatsSpec = describe "addGoalieStats" $ let
|
|
g1 = GoalieStats
|
|
{ _gsGames = 1
|
|
, _gsMinsPlayed = 2
|
|
, _gsGoalsAllowed = 3
|
|
, _gsShutouts = 4
|
|
, _gsWins = 5
|
|
, _gsLosses = 6
|
|
, _gsTies = 7
|
|
}
|
|
|
|
g2 = GoalieStats
|
|
{ _gsGames = 8
|
|
, _gsMinsPlayed = 9
|
|
, _gsGoalsAllowed = 10
|
|
, _gsShutouts = 11
|
|
, _gsWins = 12
|
|
, _gsLosses = 13
|
|
, _gsTies = 14
|
|
}
|
|
|
|
expected = GoalieStats
|
|
{ _gsGames = 9
|
|
, _gsMinsPlayed = 11
|
|
, _gsGoalsAllowed = 13
|
|
, _gsShutouts = 15
|
|
, _gsWins = 17
|
|
, _gsLosses = 19
|
|
, _gsTies = 21
|
|
}
|
|
|
|
actual = g1 `addGoalieStats` g2
|
|
|
|
in it ("should be " ++ show expected) $
|
|
actual `shouldBe` expected
|
|
|
|
gsAverageSpec :: Spec
|
|
gsAverageSpec = describe "gsAverage" $ mapM_
|
|
(\(label, stats, expected) -> context label $
|
|
it ("should be " ++ show expected) $
|
|
gsAverage stats `shouldBe` expected)
|
|
|
|
-- label, stats, expected
|
|
[ ( "with minutes", gs, 3 % 2 )
|
|
, ( "no minutes", newGoalieStats , 0 )
|
|
]
|
|
|
|
where
|
|
gs = newGoalieStats
|
|
& gsMinsPlayed .~ 2 * gameLength
|
|
& gsGoalsAllowed .~ 3
|
|
|
|
joe :: Player
|
|
joe = newPlayer 2 "Joe" "center"
|
|
|
|
bob :: Player
|
|
bob = newPlayer 3 "Bob" "defense"
|
|
|
|
steve :: Player
|
|
steve = newPlayer 5 "Steve" "forward"
|
|
|
|
-- | Creates a 'Player'
|
|
makePlayer :: IO Player
|
|
makePlayer = Player
|
|
<$> makeNum
|
|
<*> makeName
|
|
<*> makeName
|
|
<*> makeBool
|
|
<*> makeBool
|
|
<*> makePlayerStats
|
|
<*> makePlayerStats
|
|
|
|
-- | Creates a 'Goalie'
|
|
makeGoalie :: IO Goalie
|
|
makeGoalie = Goalie
|
|
<$> makeNum
|
|
<*> makeName
|
|
<*> makeBool
|
|
<*> makeBool
|
|
<*> makeGoalieStats
|
|
<*> makeGoalieStats
|
|
|
|
-- | Creates a 'PlayerStats' value
|
|
makePlayerStats :: IO PlayerStats
|
|
makePlayerStats = PlayerStats
|
|
<$> makeNum
|
|
<*> makeNum
|
|
<*> makeNum
|
|
|
|
-- | Creates a 'GoalieStats' value
|
|
makeGoalieStats :: IO GoalieStats
|
|
makeGoalieStats = GoalieStats
|
|
<$> makeNum
|
|
<*> makeNum
|
|
<*> makeNum
|
|
<*> makeNum
|
|
<*> makeNum
|
|
<*> makeNum
|
|
<*> makeNum
|
|
|
|
makeNum :: IO Int
|
|
makeNum = randomRIO (1, 10)
|
|
|
|
makeBool :: IO Bool
|
|
makeBool = randomIO
|
|
|
|
makeName :: IO String
|
|
makeName = replicateM 10 $ randomRIO ('A', 'Z')
|
|
|
|
instance Comparable GoalieStats where
|
|
compareTest actual expected = mapM_
|
|
(\(name, lens) -> describe name $
|
|
it ("should be " ++ show (expected^.lens)) $
|
|
actual^.lens `shouldBe` expected^.lens)
|
|
-- name, lens
|
|
[ ( "gsGames", gsGames )
|
|
, ( "gsMinsPlayed", gsMinsPlayed )
|
|
, ( "gsGoalsAllowed", gsGoalsAllowed )
|
|
, ( "gsWins", gsWins )
|
|
, ( "gsLosses", gsLosses )
|
|
, ( "gsTies", gsTies )
|
|
]
|
|
|
|
instance Comparable GameState where
|
|
compareTest actual expected =
|
|
it ("should be " ++ show expected) $
|
|
actual `shouldBe` expected
|
|
|
|
instance Comparable CreatePlayerState where
|
|
compareTest actual expected = do
|
|
|
|
describe "cpsNumber" $
|
|
it ("should be " ++ show (expected^.cpsNumber)) $
|
|
actual^.cpsNumber `shouldBe` expected^.cpsNumber
|
|
|
|
describe "cpsName" $
|
|
it ("should be " ++ expected^.cpsName) $
|
|
actual^.cpsName `shouldBe` expected^.cpsName
|
|
|
|
describe "cpsPosition" $
|
|
it ("should be " ++ expected^.cpsPosition) $
|
|
actual^.cpsPosition `shouldBe` expected^.cpsPosition
|
|
|
|
instance Comparable EditPlayerState where
|
|
compareTest actual expected = do
|
|
|
|
describe "epsSelectedPlayer" $
|
|
it ("should be " ++ show (expected^.epsSelectedPlayer)) $
|
|
actual^.epsSelectedPlayer `shouldBe` expected^.epsSelectedPlayer
|
|
|
|
describe "epsMode" $
|
|
it ("should be " ++ show (expected^.epsMode)) $
|
|
actual^.epsMode `shouldBe` expected^.epsMode
|
|
|
|
instance Comparable EditGoalieState where
|
|
compareTest actual expected = do
|
|
|
|
describe "egsSelectedGoalie" $
|
|
it ("should be " ++ show (expected^.egsSelectedGoalie)) $
|
|
actual^.egsSelectedGoalie `shouldBe` expected^.egsSelectedGoalie
|
|
|
|
describe "egsMode" $
|
|
it ("should be " ++ show (expected^.egsMode)) $
|
|
actual^.egsMode `shouldBe` expected^.egsMode
|
|
|
|
instance Comparable CreateGoalieState where
|
|
compareTest actual expected = do
|
|
|
|
describe "cgsNuber" $
|
|
it("should be " ++ show (expected^.cgsNumber)) $
|
|
actual^.cgsNumber `shouldBe` expected^.cgsNumber
|
|
|
|
describe "cgsName" $
|
|
it ("should be " ++ expected^.cgsName) $
|
|
actual^.cgsName `shouldBe` expected^.cgsName
|
|
|
|
instance Comparable EditStandingsMode where
|
|
compareTest actual expected =
|
|
it ("should be " ++ show expected) $
|
|
actual `shouldBe` expected
|
|
|
|
instance Comparable Goalie where
|
|
compareTest actual expected = do
|
|
|
|
describe "gNumber" $
|
|
it ("should be " ++ show (expected^.gNumber)) $
|
|
actual^.gNumber `shouldBe` expected^.gNumber
|
|
|
|
describe "gName" $
|
|
it ("should be " ++ show (expected^.gName)) $
|
|
actual^.gName `shouldBe` expected^.gName
|
|
|
|
describe "gRookie" $
|
|
it ("should be " ++ show (expected^.gRookie)) $
|
|
actual^.gRookie `shouldBe` expected^.gRookie
|
|
|
|
describe "gActive" $
|
|
it ("should be " ++ show (expected^.gActive)) $
|
|
actual^.gActive `shouldBe` expected^.gActive
|
|
|
|
describe "gYtd" $
|
|
(actual^.gYtd) `compareTest` (expected^.gYtd)
|
|
|
|
describe "gLifetime" $
|
|
(actual^.gLifetime) `compareTest` (expected^.gLifetime)
|
|
|
|
instance Comparable (M.Map Int GoalieStats) where
|
|
compareTest actual expected = do
|
|
|
|
let
|
|
aList = M.toList actual
|
|
eList = M.toList expected
|
|
|
|
it "should have the correct number of elements" $
|
|
length aList `shouldBe` length eList
|
|
|
|
mapM_
|
|
(\(n, (ka, va), (ke, ve)) -> context ("element " ++ show n) $ do
|
|
|
|
context "key" $
|
|
it ("should be " ++ show ke) $
|
|
ka `shouldBe` ke
|
|
|
|
context "value" $ va `compareTest` ve)
|
|
(zip3 ([0..] :: [Int]) aList eList)
|