{-# LANGUAGE OverloadedStrings #-} module FicsMessageParserSpec (spec) where import Test.Hspec import Macbeth.Fics.Api.Api import Macbeth.Fics.Api.Challenge import qualified Macbeth.Fics.Api.Rating as R import Macbeth.Fics.FicsMessage import Macbeth.Fics.Api.Game import Macbeth.Fics.Api.Seek import Macbeth.Fics.Api.Move import Macbeth.Fics.Api.PendingOffer import qualified Macbeth.Fics.Api.Player as P import Macbeth.Fics.Parsers.FicsMessageParser import Macbeth.Fics.Parsers.MoveParser hiding (move) import Macbeth.Fics.Parsers.PositionParser import Data.Attoparsec.ByteString.Char8 hiding (Fail, Result, D) import qualified Data.ByteString.Char8 as BS data Result = Pass | Fail String deriving (Eq) spec :: Spec spec = describe "Parser test" $ do it "user not logged in after observe" $ parseFicsMessage "\NAK6\SYN80\SYNDharmadhikari is not logged in.\n\ETB\n" `shouldBe` (Right $ UserNotLoggedIn "Dharmadhikari") it "command message parser" $ commandMessageParserTest `shouldBe` True it "seek msg parser" $ seekMsgParserTest `shouldBe` True it "move parser" $ moveParserTest `shouldBe` True it "position parser" $ positionTest `shouldBe` True it "ping" $ parseFicsMessage ":min/avg/max/mdev = 131.497/132.073/132.718/0.460 ms\n" `shouldBe` Right (Ping 131 132 133) it "pending from" $ parseFicsMessage " 28 w=Schoon t=match p=Schoon ( 999) GuestNXQS (----) unrated blitz 5 0\n" `shouldBe ` Right (Pending $ PendingOffer From 28 (P.UserHandle "Schoon" []) "match" "Schoon ( 999) GuestNXQS (----) unrated blitz 5 0") it "pendingTo" $ parseFicsMessage "\NAK4\SYN73\SYNIssuing: GuestFTYL (----) GuestCVXP (----) unrated blitz 5 0.\n\n 3 w=GuestCVXP t=match p=GuestFTYL (----) GuestCVXP (----) unrated blitz 5 0\n\ETB\n" `shouldBe` Right (Pending $ PendingOffer To 3 (P.UserHandle "GuestCVXP" []) "match" "GuestFTYL (----) GuestCVXP (----) unrated blitz 5 0") it "pending removed" $ parseFicsMessage " 28\n" `shouldBe` Right (PendingRemoved 28) it "pending removed, after withdraw" $ parseFicsMessage "\NAK4\SYN147\SYNYou withdraw the match offer to GuestFZHQ.\n\n 1\n\ETB\n" `shouldBe` Right (PendingRemoved 1) commandMessageParserTest :: Bool commandMessageParserTest = all (== Pass) $ fmap compareCmdMsg commandMessageParserTestData commandMessageParserTestData :: [(FicsMessage, String)] commandMessageParserTestData = [ (DrawRequest, "GuestDWXY offers you a draw.") , (NoSuchGame, "\NAK5\SYN80\SYNThere is no such game.\n\ETB") , (MatchRequested $ Challenge "GuestYWYK" R.Unrated "GuestMGSD" R.Unrated "unrated blitz 2 12", "Challenge: GuestYWYK (----) GuestMGSD (----) unrated blitz 2 12.") , (GuestLogin "FOOBAR", "Press return to enter the server as \"FOOBAR\":") , (GameCreation 484, "{Game 484 (GuestYLCL vs. GuestBYPB) Creating unrated blitz match.}\n") , (AbortRequest "GuestSPLL", "GuestSPLL would like to abort the game; type \"abort\" to accept.") , (TakebackRequest "GuestTYLF" 2, "GuestTYLF would like to take back 2 half move(s).") , (GameResult 82 "Game aborted by mutual agreement" Aborted, "\NAK5\SYN11\SYNYou accept the abort request from GuestSPLL.\n\n{Game 82 (GuestTKHJ vs. GuestSPLL) Game aborted by mutual agreement} *\n\ETB") , (GameResult 112 "Game aborted on move 1" Aborted, "\NAK4\SYN10\SYNThe game has been aborted on move one.\n\n{Game 112 (GuestSPLL vs. GuestTKHJ) Game aborted on move 1} *\n\ETB") , (GameResult 383 "Game aborted by mutual agreement" Aborted, "\NAK5\SYN10\SYN\n{Game 383 (GuestRVNY vs. GuestZTNM) Game aborted by mutual agreement} *\n\ETB") , (GameResult 112 "Game aborted on move 1" Aborted, "{Game 112 (GuestSPLL vs. GuestTKHJ) Game aborted on move 1} *") , (GameResult 297 "Game aborted by mutual agreement" Aborted, "{Game 297 (GuestSPLL vs. GuestTKHJ) Game aborted by mutual agreement} *") , (GameResult 10 "Kratt forfeits on time" WhiteWins, "{Game 10 (GidonC vs. Kratt) Kratt forfeits on time} 1-0\n") , (GameResult 368 "CalicoCat resigns" WhiteWins, "{Game 368 (ALTOTAS vs. CalicoCat) CalicoCat resigns} 1-0") , (GameResult 406 "GuestQLHT resigns" BlackWins, "\n{Game 406 (GuestQLHT vs. GuestVYVJ) GuestQLHT resigns} 0-1\n\nNo ratings adjustment done.") , (GameResult 181 "Danimateit forfeits on time" BlackWins, "{Game 181 (Danimateit vs. WhatKnight) Danimateit forfeits on time} 0-1") , (GameResult 196 "Game drawn by mutual agreement" Draw, "\NAK4\SYN34\SYN\n{Game 196 (GuestCWVD vs. GuestDWTL) Game drawn by mutual agreement} 1/2-1/2\n\nNo ratings adjustment done.\n\ETB") , (GameResult 202 "Game drawn by mutual agreement" Draw, "\NAK5\SYN11\SYNYou accept the draw request from GuestNMNG.\n\n{Game 202 (GuestDKZD vs. GuestNMNG) Game drawn by mutual agreement} 1/2-1/2\n\nNo ratings adjustment done.\n\ETB") , (MatchUserNotLoggedIn "GuestLHDG", "\NAK4\SYN73\SYNGuestLHDG is not logged in.\n\ETB") , (PieceHolding 455 [Pawn,Rook,Knight] [Bishop,Queen], " game 455 white [PRN] black [BQ]") , (PieceHolding 182 [Pawn,Pawn,Bishop] [Pawn,Queen,Queen], " game 182 white [PPB] black [PQQ] <- BQ\n") , (SeekNotAvailable, "\NAK4\SYN158\SYNThat seek is not available.\n\ETB") , (MatchRequested $ Challenge "Schoon" (R.Rating 997 R.None) "GuestPCFH" R.Unrated "unrated blitz 5 0", "Challenge: Schoon ( 997) GuestPCFH (----) unrated blitz 5 0.\n\r\aYou can \"accept\" or \"decline\", or propose different parameters.") , (PromotionPiece Knight, "\NAK5\SYN92\SYNPromotion piece set to KNIGHT.\n\ETB\n") , (PromotionPiece Queen, "\NAK5\SYN92\SYNPromotion piece set to QUEEN.\n\ETB\n") , (PromotionPiece Bishop, "\NAK5\SYN92\SYNPromotion piece set to BISHOP.\n\ETB\n") , (PromotionPiece Rook, "\NAK5\SYN92\SYNPromotion piece set to ROOK.\n\ETB\n") , (PromotionPiece King, "\NAK5\SYN92\SYNPromotion piece set to KING.\n\ETB\n") -- Suicide ] defaultMove = Move "-------- -------- -------- -------- -------- -------- -------- --------" [] White Nothing [WhiteShort,WhiteLong,BlackShort,BlackLong] 0 18 "nameWhite" "nameBlack" OponentsMove 3 0 39 39 180 180 1 Nothing "(0:00)" Nothing defaultMoveStr = "<12> -------- -------- -------- -------- -------- -------- -------- -------- W -1 1 1 1 1 0 18 nameWhite nameBlack -1 3 0 39 39 180 180 1 none (0:00) none 1 0 0\n" seekMsgParserTest :: Bool seekMsgParserTest = all (== Pass) $ fmap compareCmdMsg seekMsgParserTestData seekMsgParserTestData :: [(FicsMessage, String)] seekMsgParserTestData = [ (ClearSeek, "") , (RemoveSeeks [59, 3, 11], " 59 3 11") , (NewSeek $ Seek 7 "GuestNMZJ" [Unregistered] (R.Rating 0 R.Provisional) 15 5 False Standard (Just White) (0,9999), " 7 w=GuestNMZJ ti=01 rt=0P t=15 i=5 r=u tp=standard c=W rr=0-9999 a=t f=t") , (NewSeek $ Seek 16 "CatNail" [Computer] (R.Rating 1997 R.None) 3 0 False Suicide Nothing (0,9999), " 16 w=CatNail ti=02 rt=1997 t=3 i=0 r=u tp=suicide c=? rr=0-9999 a=f f=f") , (NewSeek $ Seek 56 "GuestCXDH" [Unregistered] (R.Rating 0 R.Provisional) 7 0 False Wild (Just White) (0,9999), " 56 w=GuestCXDH ti=01 rt=0P t=7 i=0 r=u tp=wild/4 c=W rr=0-9999 a=t f=f") ] positionTest :: Bool positionTest = all (== Pass) $ fmap comparePosition positionTestData positionTestData :: [(Position, String)] positionTestData = [ ([], "-------- -------- -------- -------- -------- -------- -------- --------") , ([ (Square A Eight, Piece Rook White) , (Square B Seven, Piece Knight White) , (Square C Six, Piece Bishop White) , (Square D Five, Piece Queen White) , (Square E Four, Piece King White) , (Square F Three, Piece Pawn White) , (Square G Two, Piece Rook Black) , (Square H One, Piece King Black)], "R------- -N------ --B----- ---Q---- ----K--- -----P-- ------r- -------k") ] moveParserTest :: Bool moveParserTest = all (== Pass) $ fmap withParser moveParserTestData moveParserTestData :: [(Parser (Maybe MoveDetailed), String, Maybe MoveDetailed)] moveParserTestData = [ (verboseMove', "P/c7-c5", Just $ Simple (Square C Seven) (Square C Five)) , (verboseMove', "P/f2-f1=R", Just $ Simple (Square F Two) (Square F One)) , (verboseMove', "o-o", Just CastleShort) , (verboseMove', "o-o-o", Just CastleLong) , (verboseMove', "B/@@-g6", Just $ Drop $ Square G Six) ] {- parseGamesListTest :: Result parseGamesListTest = case parseFicsMessage $ BS.pack games of Left txt -> Fail txt Right (Games games) -> if length games == 584 then Pass else Fail $ show $ length games where games = unsafePerformIO $ readFile "./test/Games.txt" -} withParser :: (Show a, Eq a) => (Parser a, String, a) -> Result withParser (parser, str, x) = case parseOnly parser (BS.pack str) of Left txt -> Fail txt Right x' -> if x' == x then Pass else Fail $ show x ++ " <<==>> " ++ show x' comparePosition :: (Position, String) -> Result comparePosition (pos, str) = let pos' = parsePosition str in if pos' == pos then Pass else Fail $ show pos ++ " <<-->> " ++ show pos' compareCmdMsg :: (FicsMessage, String) -> Result compareCmdMsg (cmd, str) = case parseFicsMessage $ BS.pack str of Left txt -> Fail txt Right cmd' -> if cmd' == cmd then Pass else Fail $ show cmd ++ " <<-->> " ++ show cmd'