sasha-0: tests/sasha-tests.hs
{-# LANGUAGE CPP #-}
module Main (main) where
import Data.Either (isRight)
import System.Environment (getArgs, withArgs)
import Test.Tasty (defaultMain, testGroup)
import Test.Tasty.HUnit (testCase, (@?=))
import Test.Tasty.QuickCheck (label, testProperty, (===))
import qualified Data.Aeson as A
import qualified Data.ByteString as BS
import qualified Data.Text.Encoding as TE
import qualified Test.Tasty.Bench as B
import Sasha.Example.Alex
import Sasha.Example.Sasha
import Sasha.Example.SaTTH
import Sasha.Example.Token
main :: IO ()
main = do
input <- BS.readFile "example.json"
args <- getArgs
case args of
"bench" : args' -> withArgs args' $ B.defaultMain
[ B.bgroup "json"
[ B.bench "sasha" $ B.nf (tokens sashaToken) input
, B.bench "alex" $ B.nf (tokens alexToken) input
, B.bench "satth" $ B.nf (tokens satthToken) input
, B.bench "aeson" $ B.nf (A.decodeStrict @A.Value) input
]
, B.bgroup "utf8"
[ B.bench "sasha" $ B.whnf (accepts sashaToken) input
, B.bench "satth" $ B.whnf (accepts satthToken) input
#if MIN_VERSION_bytestring(0,11,2)
, B.bench "bytestring" $ B.whnf BS.isValidUtf8 input
#endif
]
]
_ -> defaultMain $ testGroup "sasha-json"
[ testGroup "json"
[ testCase "sasha" $ tokens sashaToken input @?= expectedJson
, testCase "satth" $ tokens satthToken input @?= expectedJson
, testCase "alex" $ tokens alexToken input @?= expectedJson
]
, testGroup "utf8"
[ testProperty "sasha" $ \w8s ->
let bs = BS.pack w8s
isValid = isRight (TE.decodeUtf8' bs)
in label (show isValid) $ accepts sashaUtf8 bs === isValid
, testProperty "sasha" $ \w8s ->
let bs = BS.pack w8s
isValid = isRight (TE.decodeUtf8' bs)
in label (show isValid) $ accepts satthUtf8 bs === isValid
]
]
tokens
:: (BS.ByteString -> Maybe (Tk, BS.ByteString, BS.ByteString)) -- ^ single token scanner
-> BS.ByteString -- ^ input
-> [(Tk, BS.ByteString)] -- ^ result list of tokens
tokens scan = go
where
go !bs
| BS.null bs = []
| otherwise = case scan bs of
Nothing -> [(TkErr, bs)]
Just (tk, pfx, sfx) -> (tk, pfx) : go sfx
{-# INLINE tokens #-}
accepts
:: (BS.ByteString -> Maybe (a, b, BS.ByteString)) -- ^ single token scanner
-> BS.ByteString -- ^ input
-> Bool
accepts scan = go
where
go !bs
| BS.null bs = True
| otherwise = case scan bs of
Nothing -> False
Just (_, _, sfx) -> go sfx
{-# INLINE accepts #-}
expectedJson :: [(Tk, BS.ByteString)]
expectedJson =
[ TkBraceOpen := "{"
, TkSpace := "\n "
, TkString := "\"literals\""
, TkColon := ":"
, TkSpace := " "
, TkBracketOpen := "["
, TkTrue := "true"
, TkComma := ","
, TkSpace := " "
, TkFalse := "false"
, TkComma := ","
, TkSpace := " "
, TkNull := "null"
, TkBracketClose := "]"
, TkComma := ","
, TkSpace := "\n "
, TkString := "\"numbers\""
, TkColon := ":"
, TkSpace := " "
, TkBracketOpen := "["
, TkNumber := "0"
, TkComma := ","
, TkSpace := " "
, TkNumber := "123"
, TkBracketClose := "]"
, TkSpace := "\n"
, TkBraceClose := "}"
, TkSpace := "\n"
]