Added some more quickcheck tests
Getty Ritter
9 years ago
| 1 | 1 | {-# LANGUAGE OverloadedStrings #-} |
| 2 | {-# LANGUAGE ScopedTypeVariables #-} | |
| 2 | 3 | |
| 3 |
module |
|
| 4 | module Main where | |
| 4 | 5 | |
| 5 | import Data.SCargot ( SExprParser | |
| 6 | , SExprPrinter | |
| 7 | , mkParser | |
| 8 | , flatPrint | |
| 9 | , encodeOne | |
| 10 | , decodeOne | |
| 11 | , asRich | |
| 12 | , asWellFormed | |
| 13 | ) | |
| 14 | import Data.SCargot.Repr ( SExpr(..) | |
| 15 | , RichSExpr | |
| 16 | , fromRich | |
| 17 | , toRich | |
| 18 | , WellFormedSExpr(..) | |
| 19 | , fromWellFormed | |
| 20 | , toWellFormed | |
| 21 | ) | |
| 22 | import Test.QuickCheck | |
| 23 | import Test.QuickCheck.Arbitrary | |
| 24 | import Text.Parsec (char) | |
| 25 |
import |
|
| 6 | import Data.SCargot | |
| 7 | import Data.SCargot.Comments | |
| 8 | import Data.SCargot.Repr | |
| 9 | ||
| 10 | import Data.Monoid ((<>)) | |
| 11 | import Data.Text (Text) | |
| 12 | import qualified Data.Text as T | |
| 13 | import Test.QuickCheck | |
| 14 | import Test.QuickCheck.Arbitrary | |
| 15 | import Text.Parsec (char) | |
| 16 | import Text.Parsec.Text (Parser) | |
| 26 | 17 | |
| 27 | 18 | instance Arbitrary a => Arbitrary (SExpr a) where |
| 28 | 19 | arbitrary = sized $ \n -> |
| 54 | 45 | ] |
| 55 | 46 | ] |
| 56 | 47 | |
| 48 | data EncodedSExpr = EncodedSExpr | |
| 49 | { encoding :: Text | |
| 50 | , original :: SExpr () | |
| 51 | } deriving (Eq, Show) | |
| 52 | ||
| 53 | instance Arbitrary EncodedSExpr where | |
| 54 | arbitrary = do | |
| 55 | sexpr :: SExpr () <- arbitrary | |
| 56 | let chunks = T.words (encodeOne printer sexpr) | |
| 57 | whitespace <- sequence [ mkWs | _ <- chunks ] | |
| 58 | pure (EncodedSExpr { encoding = T.concat (zipWith (<>) chunks whitespace) | |
| 59 | , original = sexpr | |
| 60 | }) | |
| 61 | where mkWs = do | |
| 62 | n :: Int <- choose (1, 10) | |
| 63 | T.pack <$> sequence [ elements " \t\r\n" | |
| 64 | | _ <- [0..n] | |
| 65 | ] | |
| 66 | ||
| 57 | 67 | parser :: SExprParser () (SExpr ()) |
| 58 | 68 | parser = mkParser (() <$ char 'X') |
| 59 | 69 | |
| 60 | 70 | printer :: SExprPrinter () (SExpr ()) |
| 61 | 71 | printer = flatPrint (const "X") |
| 72 | ||
| 73 | prettyPrinter :: SExprPrinter () (SExpr ()) | |
| 74 | prettyPrinter = basicPrint (const "X") | |
| 75 | ||
| 62 | 76 | |
| 63 | 77 | richIso :: SExpr () -> Bool |
| 64 | 78 | richIso s = fromRich (toRich s) == s |
| 79 | 93 | encDec :: SExpr () -> Bool |
| 80 | 94 | encDec s = decodeOne parser (encodeOne printer s) == Right s |
| 81 | 95 | |
| 96 | encDecPretty :: SExpr () -> Bool | |
| 97 | encDecPretty s = decodeOne parser (encodeOne prettyPrinter s) == Right s | |
| 98 | ||
| 99 | decEnc :: EncodedSExpr -> Bool | |
| 100 | decEnc s = decodeOne parser (encoding s) == Right (original s) | |
| 101 | ||
| 102 | ||
| 82 | 103 | encDecRich :: RichSExpr () -> Bool |
| 83 | 104 | encDecRich s = decodeOne (asRich parser) (encodeOne printer (fromRich s)) |
| 84 | 105 | == Right s |
| 106 | ||
| 107 | encDecRichPretty :: RichSExpr () -> Bool | |
| 108 | encDecRichPretty s = decodeOne (asRich parser) | |
| 109 | (encodeOne prettyPrinter (fromRich s)) | |
| 110 | == Right s | |
| 111 | ||
| 112 | decEncRich :: EncodedSExpr -> Bool | |
| 113 | decEncRich s = decodeOne (asRich parser) (encoding s) == Right (toRich (original s)) | |
| 114 | ||
| 85 | 115 | |
| 86 | 116 | encDecWF :: WellFormedSExpr () -> Bool |
| 87 | 117 | encDecWF s = decodeOne (asWellFormed parser) (encodeOne printer (fromWellFormed s)) |
| 88 | 118 | == Right s |
| 89 | 119 | |
| 90 | reprQC :: IO () | |
| 91 | reprQC = do | |
| 120 | encDecWFPretty :: WellFormedSExpr () -> Bool | |
| 121 | encDecWFPretty s = | |
| 122 | decodeOne (asWellFormed parser) (encodeOne prettyPrinter (fromWellFormed s)) | |
| 123 | == Right s | |
| 124 | ||
| 125 | decEncWF :: EncodedSExpr -> Bool | |
| 126 | decEncWF s = decodeOne (asWellFormed parser) (encoding s) == toWellFormed (original s) | |
| 127 | ||
| 128 | ||
| 129 | insertComments :: Text -> Text -> Text -> Text | |
| 130 | insertComments lc rc sexpr = | |
| 131 | T.replace " " (" " <> lc <> "blahblahblah" <> rc <> " ") sexpr | |
| 132 | ||
| 133 | encDecLineComments :: SExpr () -> Bool | |
| 134 | encDecLineComments s = | |
| 135 | decodeOne (withLispComments parser) | |
| 136 | (insertComments ";" "\n" (encodeOne printer s)) == Right s | |
| 137 | ||
| 138 | encDecBlockComments :: SExpr () -> Bool | |
| 139 | encDecBlockComments s = | |
| 140 | decodeOne (withHaskellBlockComments parser) | |
| 141 | (insertComments "{-" "-}" (encodeOne printer s)) == Right s | |
| 142 | ||
| 143 | -- Sometimes we generate really huge test cases, which can take a really | |
| 144 | -- long time to process---especially when we're modifying the whitespace | |
| 145 | -- to produce weird anomalous S-expressions. So, we make the size parameter | |
| 146 | -- a bit smaller for good measure. | |
| 147 | reallyQuickCheck :: Testable prop => prop -> IO () | |
| 148 | reallyQuickCheck = quickCheckWith stdArgs { maxSize = 25 } | |
| 149 | ||
| 150 | main :: IO () | |
| 151 | main = do | |
| 92 | 152 | putStrLn "The SExpr <--> Rich translation should be isomorphic" |
| 93 | 153 | quickCheck richIso |
| 94 | 154 | quickCheck richIsoBk |
| 155 | ||
| 95 | 156 | putStrLn "The SExpr <--> WF translation should be near-isomorphic" |
| 96 | 157 | quickCheck wfIso |
| 97 | 158 | quickCheck wfIsoBk |
| 159 | ||
| 98 | 160 | putStrLn "This should be true when parsing, as well" |
| 99 | 161 | quickCheck encDec |
| 162 | reallyQuickCheck decEnc | |
| 100 | 163 | quickCheck encDecRich |
| 164 | reallyQuickCheck decEncRich | |
| 101 | 165 | quickCheck encDecWF |
| 166 | reallyQuickCheck decEncWF | |
| 167 | ||
| 168 | putStrLn "And it should be true if pretty-printed" | |
| 169 | reallyQuickCheck encDecPretty | |
| 170 | reallyQuickCheck encDecRichPretty | |
| 171 | reallyQuickCheck encDecWFPretty | |
| 172 | ||
| 173 | putStrLn "Comments should not affect parsing" | |
| 174 | reallyQuickCheck encDecLineComments | |
| 175 | reallyQuickCheck encDecBlockComments | |