SCargotQC.hs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. {-# LANGUAGE OverloadedStrings #-}
  2. {-# LANGUAGE ScopedTypeVariables #-}
  3. {-# OPTIONS_GHC -fno-warn-orphans #-}
  4. module Main where
  5. import Data.SCargot
  6. import Data.SCargot.Comments
  7. import Data.SCargot.Repr
  8. import Data.Monoid ((<>))
  9. import Data.Text (Text)
  10. import qualified Data.Text as T
  11. import Test.QuickCheck
  12. import Text.Parsec (char)
  13. instance Arbitrary a => Arbitrary (SExpr a) where
  14. arbitrary = sized $ \n ->
  15. if n <= 0
  16. then pure SNil
  17. else oneof [ SAtom <$> arbitrary
  18. , do
  19. k <- choose (0, n)
  20. elems <- sequence [ resize (n-k) arbitrary
  21. | _ <- [0..k]
  22. ]
  23. rest <- oneof [ SAtom <$> arbitrary
  24. , pure SNil
  25. ]
  26. pure (foldr SCons rest elems)
  27. ]
  28. instance Arbitrary a => Arbitrary (RichSExpr a) where
  29. arbitrary = toRich `fmap` arbitrary
  30. instance Arbitrary a => Arbitrary (WellFormedSExpr a) where
  31. arbitrary = sized $ \n ->
  32. oneof [ WFSAtom <$> arbitrary
  33. , do
  34. k <- choose (0, n)
  35. WFSList <$> sequence
  36. [ resize (n-k) arbitrary
  37. | _ <- [0..k]
  38. ]
  39. ]
  40. data EncodedSExpr = EncodedSExpr
  41. { encoding :: Text
  42. , original :: SExpr ()
  43. } deriving (Eq, Show)
  44. instance Arbitrary EncodedSExpr where
  45. arbitrary = do
  46. sexpr :: SExpr () <- arbitrary
  47. let chunks = T.words (encodeOne printer sexpr)
  48. whitespace <- sequence [ mkWs | _ <- chunks ]
  49. pure (EncodedSExpr { encoding = T.concat (zipWith (<>) chunks whitespace)
  50. , original = sexpr
  51. })
  52. where mkWs = do
  53. n :: Int <- choose (1, 10)
  54. T.pack <$> sequence [ elements " \t\r\n"
  55. | _ <- [0..n]
  56. ]
  57. parser :: SExprParser () (SExpr ())
  58. parser = mkParser (() <$ char 'X')
  59. printer :: SExprPrinter () (SExpr ())
  60. printer = flatPrint (const "X")
  61. prettyPrinter :: SExprPrinter () (SExpr ())
  62. prettyPrinter = basicPrint (const "X")
  63. widePrinter :: SExprPrinter () (SExpr ())
  64. widePrinter = unconstrainedPrint (const "X")
  65. richIso :: SExpr () -> Bool
  66. richIso s = fromRich (toRich s) == s
  67. richIsoBk :: RichSExpr () -> Bool
  68. richIsoBk s = toRich (fromRich s) == s
  69. wfIso :: SExpr () -> Bool
  70. wfIso s = case toWellFormed s of
  71. Left _ -> True
  72. Right y -> s == fromWellFormed y
  73. wfIsoBk :: WellFormedSExpr () -> Bool
  74. wfIsoBk s = toWellFormed (fromWellFormed s) == Right s
  75. encDec :: SExpr () -> Bool
  76. encDec s = decodeOne parser (encodeOne printer s) == Right s
  77. encDecPretty :: SExpr () -> Bool
  78. encDecPretty s = decodeOne parser (encodeOne prettyPrinter s) == Right s
  79. encDecWide :: SExpr () -> Bool
  80. encDecWide s = decodeOne parser (encodeOne widePrinter s) == Right s
  81. decEnc :: EncodedSExpr -> Bool
  82. decEnc s = decodeOne parser (encoding s) == Right (original s)
  83. encDecRich :: RichSExpr () -> Bool
  84. encDecRich s = decodeOne (asRich parser) (encodeOne printer (fromRich s))
  85. == Right s
  86. encDecRichPretty :: RichSExpr () -> Bool
  87. encDecRichPretty s = decodeOne (asRich parser)
  88. (encodeOne prettyPrinter (fromRich s))
  89. == Right s
  90. encDecRichWide :: RichSExpr () -> Bool
  91. encDecRichWide s =
  92. decodeOne (asRich parser)
  93. (encodeOne widePrinter (fromRich s))
  94. == Right s
  95. decEncRich :: EncodedSExpr -> Bool
  96. decEncRich s = decodeOne (asRich parser) (encoding s) == Right (toRich (original s))
  97. encDecWF :: WellFormedSExpr () -> Bool
  98. encDecWF s = decodeOne (asWellFormed parser) (encodeOne printer (fromWellFormed s))
  99. == Right s
  100. encDecWFPretty :: WellFormedSExpr () -> Bool
  101. encDecWFPretty s =
  102. decodeOne (asWellFormed parser) (encodeOne prettyPrinter (fromWellFormed s))
  103. == Right s
  104. encDecWFWide :: WellFormedSExpr () -> Bool
  105. encDecWFWide s =
  106. decodeOne (asWellFormed parser) (encodeOne widePrinter (fromWellFormed s))
  107. == Right s
  108. decEncWF :: EncodedSExpr -> Bool
  109. decEncWF s = decodeOne (asWellFormed parser) (encoding s) == toWellFormed (original s)
  110. insertComments :: Text -> Text -> Text -> Text
  111. insertComments lc rc sexpr =
  112. T.replace " " (" " <> lc <> "blahblahblah" <> rc <> " ") sexpr
  113. encDecLineComments :: SExpr () -> Bool
  114. encDecLineComments s =
  115. decodeOne (withLispComments parser)
  116. (insertComments ";" "\n" (encodeOne printer s)) == Right s
  117. encDecBlockComments :: SExpr () -> Bool
  118. encDecBlockComments s =
  119. decodeOne (withHaskellBlockComments parser)
  120. (insertComments "{-" "-}" (encodeOne printer s)) == Right s
  121. -- Sometimes we generate really huge test cases, which can take a really
  122. -- long time to process---especially when we're modifying the whitespace
  123. -- to produce weird anomalous S-expressions. So, we make the size parameter
  124. -- a bit smaller for good measure.
  125. reallyQuickCheck :: Testable prop => prop -> IO ()
  126. reallyQuickCheck = quickCheckWith stdArgs { maxSize = 25 }
  127. main :: IO ()
  128. main = do
  129. putStrLn "The SExpr <--> Rich translation should be isomorphic"
  130. quickCheck richIso
  131. quickCheck richIsoBk
  132. putStrLn "The SExpr <--> WF translation should be near-isomorphic"
  133. quickCheck wfIso
  134. quickCheck wfIsoBk
  135. putStrLn "This should be true when parsing, as well"
  136. quickCheck encDec
  137. reallyQuickCheck decEnc
  138. quickCheck encDecRich
  139. reallyQuickCheck decEncRich
  140. quickCheck encDecWF
  141. reallyQuickCheck decEncWF
  142. putStrLn "And it should be true if pretty-printed"
  143. reallyQuickCheck encDecPretty
  144. reallyQuickCheck encDecRichPretty
  145. reallyQuickCheck encDecWFPretty
  146. putStrLn "And it should be true if pretty-printed using the wide-format printer"
  147. reallyQuickCheck encDecWide
  148. reallyQuickCheck encDecRichWide
  149. reallyQuickCheck encDecWFWide
  150. putStrLn "Comments should not affect parsing"
  151. reallyQuickCheck encDecLineComments
  152. reallyQuickCheck encDecBlockComments