SCargotQC.hs 5.9 KB

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