mirror of
https://github.com/composewell/streamly.git
synced 2024-09-11 11:37:22 +03:00
232 lines
10 KiB
Haskell
232 lines
10 KiB
Haskell
{-# OPTIONS_GHC -Wno-deprecations #-}
|
|
|
|
module Streamly.Test.Unicode.Parser
|
|
(main)
|
|
where
|
|
|
|
import Control.Monad.Identity (Identity(runIdentity))
|
|
import Debug.Trace (trace)
|
|
import Streamly.Internal.Data.Parser (ParseError (..), Parser)
|
|
import Streamly.Test.Common (chooseDouble)
|
|
import Test.Hspec.QuickCheck (prop)
|
|
import Test.QuickCheck
|
|
(forAll, Property, property)
|
|
import Test.QuickCheck.Monadic (monadicIO, assert, run)
|
|
|
|
import qualified Data.Scientific as Scientific
|
|
import qualified Streamly.Data.Stream as Stream
|
|
import qualified Streamly.Internal.Data.Stream as Stream (parseBreak)
|
|
import qualified Streamly.Unicode.Parser as Unicode
|
|
import qualified Streamly.Internal.Unicode.Parser as Parser
|
|
import qualified Test.Hspec as H
|
|
|
|
-- Scientific notation
|
|
scientificExpFP :: Property
|
|
scientificExpFP =
|
|
forAll (chooseDouble (-99.99e-12, 1234.4567e+234)) $ \ls ->
|
|
case runIdentity $ Stream.parse parser (Stream.fromList (show ls)) of
|
|
Right val -> val `H.shouldBe` read (show ls)
|
|
Left _ -> error "Parsing failed."
|
|
|
|
where
|
|
|
|
toScientific (c, m) = Scientific.scientific c m
|
|
parser = toScientific <$> Parser.number
|
|
|
|
-- Standard decimal notation.
|
|
scientificFixFP :: Property
|
|
scientificFixFP =
|
|
forAll (chooseDouble (-0.00099, 123445.67998)) $ \ls ->
|
|
case runIdentity $ Stream.parse parser (Stream.fromList (show ls)) of
|
|
Right val -> val `H.shouldBe` read (show ls)
|
|
Left _ -> error "Parsing failed."
|
|
|
|
where
|
|
|
|
toScientific (c, m) = Scientific.scientific c m
|
|
parser = toScientific <$> Parser.number
|
|
|
|
doubleExpFP :: Property
|
|
doubleExpFP =
|
|
forAll (chooseDouble (-99.99e-12, 1234.4567e+234)) $ \ls -> do
|
|
let sls = show ls
|
|
case runIdentity $ Stream.parse Parser.double (Stream.fromList sls) of
|
|
Right val -> if val == ls
|
|
then property (val == ls)
|
|
else trace
|
|
("Read = "++ show (read sls :: Double) ++ " Expected = " ++ sls ++ " Got = " ++ show val)
|
|
property (val == ls)
|
|
Left _ -> property False
|
|
|
|
-- Standard decimal notation.
|
|
doubleFixFP :: Property
|
|
doubleFixFP =
|
|
forAll (chooseDouble (-0.00099, 123445.67998)) $ \ls ->
|
|
case runIdentity $ Stream.parse Parser.double (Stream.fromList (show ls)) of
|
|
Right val -> if val == ls
|
|
then property (val == ls)
|
|
else trace
|
|
("Expected = " ++ show ls ++ " Got = " ++ show val)
|
|
property (val == ls)
|
|
Left _ -> property False
|
|
|
|
doubleParser :: String -> IO (Either ParseError Double)
|
|
doubleParser = Stream.parse Unicode.double . Stream.fromList
|
|
|
|
double :: String -> Double -> Property
|
|
double s d = monadicIO $ do
|
|
x <- run $ doubleParser s
|
|
case x of
|
|
Right val -> if val == d
|
|
then assert (val == d)
|
|
else trace ("Expected = " ++ show d ++ " Got = "++ show val) (assert (val == d))
|
|
Left (ParseError _) -> assert False
|
|
|
|
numberP :: Monad m => Parser Char m Double
|
|
numberP = uncurry Parser.mkDouble <$> Parser.number
|
|
|
|
numberParser :: String -> IO (Either ParseError Double)
|
|
numberParser = Stream.parse numberP . Stream.fromList
|
|
|
|
number :: String -> Double -> Property
|
|
number s d = monadicIO $ do
|
|
x <- run $ numberParser s
|
|
case x of
|
|
Right val -> if val == d
|
|
then assert (val == d)
|
|
else trace ("Expected = " ++ show d ++ " Got = "++ show val) (assert (val == d))
|
|
Left (ParseError _) -> assert False
|
|
|
|
doubleErr :: (String -> IO (Either ParseError Double)) -> String -> String -> Property
|
|
doubleErr f s msg = monadicIO $ do
|
|
x <- run $ f s
|
|
case x of
|
|
Right _ -> assert False
|
|
Left (ParseError err) -> if err == msg
|
|
then assert (err == msg)
|
|
else trace err (assert (err == msg))
|
|
|
|
remainingStreamDouble :: String -> [String]
|
|
remainingStreamDouble x =
|
|
let f = Stream.parseBreak Unicode.double . Stream.fromList
|
|
in concatMap (Stream.toList . snd) (f x)
|
|
|
|
remainingStreamNumber :: String -> [String]
|
|
remainingStreamNumber x =
|
|
let f = Stream.parseBreak numberP . Stream.fromList
|
|
in concatMap (Stream.toList . snd) (f x)
|
|
|
|
afterParse :: (String -> [String]) -> String -> String -> Property
|
|
afterParse f si so = monadicIO $ do
|
|
let x = f si
|
|
in assert (x == [so])
|
|
|
|
testParser :: String -> (String -> Double -> Property) -> H.SpecWith ()
|
|
testParser desc f = do
|
|
-- XXX We can combine the parser tests and remaining stream tests in the
|
|
-- same test.
|
|
H.describe ("Unicode Parser " ++ desc) $ do
|
|
prop "double \"00.00\"" $ f "00.00" 0.0
|
|
prop "double \"00.00e00\"" $ f "00.00e00" 0.0
|
|
prop "double \"4\" 4.0" $ f "4" 4.0
|
|
prop "double \"00.3\" 0.3" $ f "00.3" 0.3
|
|
prop "double \"0.003\" 3.0e-3" $ f "0.003" 3.0e-3
|
|
prop "double \"44.56.67\" 44.56" $ f "44.56.67" 44.56
|
|
prop "double \"0.0.00\" 0.0" $ f "0.0.00" 0.0
|
|
prop "double \"44.56-78\" 44.56" $ f "44.56-78" 44.56
|
|
prop "double \"44-\" 44.0" $ f "44-" 44.0
|
|
prop "double \"44-56\" 44.0" $ f "44-56" 44.0
|
|
prop "double \"44+\" 44.0" $ f "44+" 44.0
|
|
prop "double \"44+56\" 44.0" $ f "44+56" 44.0
|
|
prop "double \"44u\" 44.0" $ f "44u" 44.0
|
|
prop "double \"+123.345\" 123.345" $ f "+123.345" 123.345
|
|
prop "double \"-123.345\" (-123.345)" $ f "-123.345" (-123.345)
|
|
prop "double \"1e\"" $ f "1e" 1.0
|
|
prop "double \"1e+\"" $ f "1e+" 1.0
|
|
prop "double \"1ex\"" $ f "1ex" 1.0
|
|
prop "double \"1e+x\"" $ f "1e+x" 1.0
|
|
prop "double \"1e+0\"" $ f "1e+0" 1.0
|
|
prop "double \"1e-0\"" $ f "1e-0" 1.0
|
|
prop "double \"1.0e-1\"" $ f "1.0e-1" 0.1
|
|
prop "double \"1.0e+1\"" $ f "1.0e+1" 10.0
|
|
prop "double \"1.0e1\"" $ f "1.0e1" 10.0
|
|
prop "double \"1.0e+309\"" $ f "1.0e+309" 1.0e309
|
|
prop "double \"1.0e-309\"" $ f "1.0e-309" 1.0e-309
|
|
prop "double \"1.0e1.\"" $ f "1.0e1." 10.0
|
|
prop "double \"1.0e1+\"" $ f "1.0e1+" 10.0
|
|
prop "double \"1.0e1-\"" $ f "1.0e1-" 10.0
|
|
prop "double \"1.0e1e\"" $ f "1.0e1e" 10.0
|
|
prop "double \"1.0E+1\"" $ f "1.0E+1" 10.0
|
|
prop "double \"9223372036854775806\"" $ f "9223372036854775806" 9.223372036854776e18
|
|
-- maxBound :: Int
|
|
prop "double \"9223372036854775807\"" $ f "9223372036854775807" 9.223372036854776e18
|
|
prop "double \"9223372036854775808\"" $ f "9223372036854775808" 9.223372036854776e18
|
|
|
|
testParseErr :: String -> (String -> IO (Either ParseError Double)) -> H.SpecWith ()
|
|
testParseErr desc f = do
|
|
H.describe ("Unicode Parser Error " ++ desc) $ do
|
|
prop "double \"\" Error"
|
|
$ doubleErr f "" "number: expecting sign or decimal digit, got end of input"
|
|
prop "double \"a\" Error"
|
|
$ doubleErr f "a" "number: expecting sign or decimal digit, got 'a'"
|
|
prop "double \".4\" Error"
|
|
$ doubleErr f ".4" "number: expecting sign or decimal digit, got '.'"
|
|
prop "double \".\" Error"
|
|
$ doubleErr f "." "number: expecting sign or decimal digit, got '.'"
|
|
prop "double \"..\" Error"
|
|
$ doubleErr f ".." "number: expecting sign or decimal digit, got '.'"
|
|
prop "double \"-\" Error"
|
|
$ doubleErr f "-" "number: expecting decimal digit, got end of input"
|
|
prop "double \"+\" Error"
|
|
$ doubleErr f "+" "number: expecting decimal digit, got end of input"
|
|
prop "double \"++\" Error"
|
|
$ doubleErr f "++" "number: expecting decimal digit, got '+'"
|
|
|
|
testLeftOver :: String -> (String -> [String]) -> H.SpecWith ()
|
|
testLeftOver desc f = do
|
|
H.describe ("Unicode Parser leftover " ++ desc) $ do
|
|
prop "afterParse \"4.\" \".\"" $ afterParse f "4." "."
|
|
prop "afterParse \"4..\" \"..\"" $ afterParse f "4.." ".."
|
|
prop "afterParse \"4-\" \"-\"" $ afterParse f "4-" "-"
|
|
prop "afterParse \"4--\" \"--\"" $ afterParse f "4--" "--"
|
|
prop "afterParse \"4.9abc\" \"abc\"" $ afterParse f "4.9abc" "abc"
|
|
prop "afterParse \"4.9ex\"" $ afterParse f "4.9ex" "ex"
|
|
prop "afterParse \"4.9e+x\"" $ afterParse f "4.9e+x" "e+x"
|
|
prop "afterParse \"4.9\" \"\"" $ afterParse f "4.9" ""
|
|
prop "afterParse \"+4.9\" \"\"" $ afterParse f "+4.9" ""
|
|
prop "afterParse \"-4.9\" \"\"" $ afterParse f "-4.9" ""
|
|
prop "afterParse \"4.9.\" \".\"" $ afterParse f "4.9." "."
|
|
prop "afterParse \"4.9..\" \"..\"" $ afterParse f "4.9.." ".."
|
|
prop "afterParse \"4.9...\" \"...\"" $ afterParse f "4.9..." "..."
|
|
prop "afterParse \"4.9+\" \"+\"" $ afterParse f "4.9+" "+"
|
|
prop "afterParse \"4.9++\" \"++\"" $ afterParse f "4.9++" "++"
|
|
prop "afterParse \"4.9+++\" \"+++\"" $ afterParse f "4.9+++" "+++"
|
|
prop "afterParse \"4.9-\" \"-\"" $ afterParse f "4.9-" "-"
|
|
prop "afterParse \"4.9--\" \"--\"" $ afterParse f "4.9--" "--"
|
|
prop "afterParse \"4.9---\" \"---\"" $ afterParse f "4.9---" "---"
|
|
prop "afterParse \"\" \"\"" $ afterParse f "" ""
|
|
prop "afterParse \".\" \".\"" $ afterParse f "." "."
|
|
prop "afterParse \"..\" \"..\"" $ afterParse f ".." ".."
|
|
prop "afterParse \"+\" \"+\"" $ afterParse f "+" "+"
|
|
prop "afterParse \"++\" \"++\"" $ afterParse f "++" "++"
|
|
|
|
moduleName :: String
|
|
moduleName = "Unicode.Parser"
|
|
|
|
main :: IO ()
|
|
main = do
|
|
H.hspec
|
|
$ H.describe moduleName $ do
|
|
testParser "double" double
|
|
testParser "number" number
|
|
testParseErr "double" doubleParser
|
|
testParseErr "number" numberParser
|
|
testLeftOver "double" remainingStreamDouble
|
|
testLeftOver "number" remainingStreamNumber
|
|
H.describe "Scientific parser property test" $ do
|
|
prop "Exponent format" scientificExpFP
|
|
prop "Decimal format" scientificFixFP
|
|
H.describe "double parser property test" $ do
|
|
prop "Exponent format" doubleExpFP
|
|
prop "Decimal format" doubleFixFP
|