Added some more quickcheck tests
Getty Ritter
8 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 |