{-# LANGUAGE OverloadedStrings #-}
import Control.Monad
import Control.Monad.IO.Class
import Data.ByteString.Lazy.Char8 ({- IsString -})
import Data.Char (ord, chr)
import Data.String
import Data.Text (toLower)
import Data.XML.Types
import Test.HUnit hiding (Test)
import Test.Hspec
import Test.Hspec.HUnit
import Text.XML.Enumerator.Combinators.General
import Text.XML.Enumerator.Combinators.Tags
import Text.XML.Enumerator.Parse (decodeEntities)
import qualified Control.Exception as C
import qualified Data.ByteString.Lazy as L
import qualified Data.Map as Map
import qualified Text.XML.Enumerator.Parse as P
main :: IO ()
main = hspec $ describe "XML combinators"
[ it "has working chooseSplit" testChooseSplit
, it "has working permute" testPermute
, it "has working permuteFallback" testPermuteFallback
, it "has working tags" testTags
, it "has working tagsPermute" testTagsPermute
, it "has working tagsPermuteRepetition" testTagsPermuteRepetition
]
testChooseSplit = P.parseLBS_ input decodeEntities $ do
P.force "need hello" $ P.tagNoAttr "hello" $ do
x <- chooseSplit (\t-> P.tagNoAttr t (return t)) ["a", "b", "c"]
liftIO $ x @?= Just ("b",["a","c"])
where
input = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
]
testPermute
= do
let frame input = P.parseLBS_ input decodeEntities $ do
P.force "need hello" $ P.tagNoAttr "hello" $
permute (\t -> P.tagNoAttr t (return t)) ["a", "b"]
frame input1 >>= \result1 -> result1 @?= Just ["a", "b"]
frame input2 >>= \result2 -> result2 @?= Just ["b", "a"]
frame input3 >>= \result3 -> result3 @?= Nothing
C.try (frame input4) >>= \result4 -> case result4 of
Left (P.XmlException {
P.xmlBadInput = Just (EventBeginElement
Name {
nameLocalName = "c"
, nameNamespace = Nothing
, namePrefix = Nothing
}
_)
}) -> return () -- right type of error
Left _ -> assertFailure "wrong error"
Right _ -> assertFailure "erroneous document requires an error"
where
input1 = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
, ""
]
input2 = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
, ""
]
input3 = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
]
input4 = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
, ""
]
testPermuteFallback
= do
let frame input = P.parseLBS_ input decodeEntities $ do
P.force "need hello" $ P.tagNoAttr "hello" $
permuteFallback (fmap return `fmap` P.contentMaybe)
(\t -> P.tagNoAttr t (return $ nameLocalName t))
["a", "b"]
frame input1 >>= \result1 -> result1 @?= Just ["a", "t", "b"]
frame input2 >>= \result2 -> result2 @?= Just ["t", "b", "a"]
frame input3 >>= \result3 -> result3 @?= Nothing
C.try (frame input4) >>= \result4 -> case result4 of
Left (P.XmlException {
P.xmlBadInput = Just (EventBeginElement
Name {
nameLocalName = "c"
, nameNamespace = Nothing
, namePrefix = Nothing
}
_)
}) -> return () -- right type of error
Left _ -> assertFailure "wrong error"
Right _ -> assertFailure "erroneous document requires an error"
where
input1 = L.concat
[ "\n"
, "\n"
, ""
, ""
, "t"
, ""
, ""
]
input2 = L.concat
[ "\n"
, "\n"
, ""
, "t"
, ""
, ""
, ""
]
input3 = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
]
input4 = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
, ""
]
testTags = P.parseLBS_ input decodeEntities $ do
P.force "need hello" $ P.tagNoAttr "hello" $ do
x <- tags (\state name -> do
let n = nameLocalName name
guard (n == fromString [chr $ ord 'a' + state])
Just (return (), \_ -> return $ Just (state + 1, Just n)))
(const $ return Nothing)
0
liftIO $ x @?= (5, ["a", "b", "c", "d", "e"])
where
input = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
, ""
, ""
, ""
, ""
]
testTagsPermute = P.parseLBS_ input decodeEntities $ do
P.force "need hello" $ P.tagNoAttr "hello" $ do
let p c = (return (), \_ -> return (Just c))
x <- tagsPermute (toLower . nameLocalName)
(Map.fromList $ map (\c -> (c, p c))
["a", "b", "c", "d", "e"])
(return Nothing)
liftIO $ x @?= Just ["d", "b", "e", "a", "c"]
where
input = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
, ""
, ""
, ""
, ""
]
testTagsPermuteRepetition = P.parseLBS_ input decodeEntities $ do
P.force "need hello" $ P.tagNoAttr "hello" $ do
let p r c = (r, return (), \_ -> return (Just ()))
x <- tagsPermuteRepetition (toLower . nameLocalName)
(Map.fromList $ map (\c -> (c, p repeatOnce c)) ["a", "b", "c", "d", "e"] ++
map (\c -> (c, p repeatMany c)) ["r"])
(return Nothing)
liftIO $ fmap (map fst) x @?= Just ["d", "r", "b", "e", "r", "a", "c"]
where
input = L.concat
[ "\n"
, "\n"
, ""
, ""
, ""
, ""
, ""
, ""
, ""
, ""
, ""
]