aboutsummaryrefslogtreecommitdiff
path: root/bbcode/test/Text/BBCode/LexerSpec.hs
diff options
context:
space:
mode:
Diffstat (limited to 'bbcode/test/Text/BBCode/LexerSpec.hs')
-rw-r--r--bbcode/test/Text/BBCode/LexerSpec.hs68
1 files changed, 68 insertions, 0 deletions
diff --git a/bbcode/test/Text/BBCode/LexerSpec.hs b/bbcode/test/Text/BBCode/LexerSpec.hs
new file mode 100644
index 0000000..8b95874
--- /dev/null
+++ b/bbcode/test/Text/BBCode/LexerSpec.hs
@@ -0,0 +1,68 @@
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE FlexibleInstances #-}
3
4module Text.BBCode.LexerSpec (spec) where
5
6import Test.Hspec
7import Test.Hspec.QuickCheck (prop)
8import Test.QuickCheck (Property, Discard(..), property)
9import Text.BBCode.Lexer
10
11import Data.Text (Text)
12import qualified Data.Text as T (singleton, replace, last, null)
13
14import Data.Monoid ((<>), mconcat, Endo(..))
15
16import Data.Attoparsec.Text (parseOnly, endOfInput)
17
18import Control.Applicative
19import Control.Monad (zipWithM_)
20
21coToken :: BBToken -> Text
22-- ^ Inverse of `token`
23coToken (BBOpen t) = "[" <> escape [']'] t <> "]"
24coToken (BBClose t) = "[/" <> escape [']'] t <> "]"
25coToken (BBStr t) = escape ['['] t
26
27escape :: [Char] -> Text -> Text
28-- ^ Inverse of `escapedText`
29escape xs = endos [ T.replace c' ("\\" <> c') . T.replace ("\\" <> c') ("\\\\" <> c') | c <- xs, let c' = T.singleton c ] . escapeLast
30 where
31 endos = appEndo . mconcat . map Endo
32 escapeLast t
33 | T.null t = ""
34 | T.last t == '\\' = t <> "\\"
35 | otherwise = t
36
37tokenize :: Text -> Either String [BBToken]
38-- ^ Run 'many token' against input
39tokenize = parseOnly (many token <* endOfInput)
40
41spec :: Spec
42spec = do
43 prop "prop_token" prop_token
44 zipWithM_ example [1..] examples
45 where
46 example n (s, ts) = let str = "Example " <> show n
47 in specify str $ (tokenize s == Right ts)
48
49prop_token :: Text -> Property
50-- ^ prop> (mconcat . map coToken) <$> tokenize x == Right x
51--
52-- Where 'x' is restricted such that `tokenize` succeeds
53prop_token x = discardLeft (((== x) . mconcat . map coToken) <$> tokenize x)
54 where
55 discardLeft = either (const $ property Discard) property
56
57examples :: [(Text, [BBToken])]
58examples = [ ("[t]test[/t]"
59 , [BBOpen "t", BBStr "test", BBClose "t"])
60 , ("[t]te\\st[/t]"
61 , [BBOpen "t", BBStr "te\\st", BBClose "t"])
62 , ("[t]te\\[st[/t]"
63 , [BBOpen "t", BBStr "te[st", BBClose "t"])
64 , ("[\\t]test[/t]"
65 , [BBOpen "\\t", BBStr "test", BBClose "t"])
66 , ("[t]test[/t\\]]"
67 , [BBOpen "t", BBStr "test", BBClose "t]"])
68 ]