{-# LANGUAGE OverloadedStrings #-} import Control.Applicative ((<$>), (<*>), Applicative) import qualified Data.ByteString.Lazy as L import Data.Conduit (($$), ($=), MonadThrow (..), runResourceT) import qualified Data.Conduit.List as CL import Data.Text (Text) import Test.Hspec import Text.XML.Stream.Parse (parseLBS, def) import Cloud.AWS.Lib.Parser.Unordered main :: IO () main = hspec $ do describe "xml parser" $ do it "parse normal xml" parseNormal it "parse xml which contains unordered elements" parseUnordered it "parse xml which contains empty list" parseEmptyList it "parse xml which does not contain itemSet tag" parseNotAppearItemSet it "cannot parse unexpected xml structure" notParseUnexpectedDataStructure it "ignore unexpected tag" ignoreUnexpectedTag it "parse top data set" parseTopDataSet describe "xml parser of maybe version" $ it "parse empty xml" parseEmpty describe "xml parser of conduit version" $ do it "parse normal xml" parseTopDataSetConduit it "parse empty itemSet" parseEmptyItemSetConduit data TestData = TestData { testDataId :: Int , testDataName :: Text , testDataDescription :: Maybe Text , testDataItemsSet :: [TestItem] } deriving (Eq, Show) data TestItem = TestItem { testItemId :: Int , testItemName :: Text , testItemDescription :: Maybe Text , testItemSubItem :: Maybe TestItem } deriving (Eq, Show) parseTestData :: (MonadThrow m, Applicative m) => SimpleXML -> m TestData parseTestData xml = TestData <$> xml .< "id" <*> xml .< "name" <*> xml .< "description" <*> getElements xml "itemSet" "item" parseTestItem parseTestItem :: (MonadThrow m, Applicative m) => SimpleXML -> m TestItem parseTestItem xml = TestItem <$> xml .< "id" <*> xml .< "name" <*> xml .< "description" <*> getElementM xml "subItem" parseTestItem parseNormal :: Expectation parseNormal = do d <- runResourceT $ parseLBS def input $$ xmlParser (\xml -> getElement xml "data" parseTestData) d `shouldBe` input' where input = L.concat [ "\n" , "" , " 1" , " test" , " this is test" , " " , " " , " 1" , " item1" , " this is item1" , " " , " 11" , " item1sub" , " " , " " , " " , " 2" , " item2" , " " , " " , "" ] input' = TestData { testDataId = 1 , testDataName = "test" , testDataDescription = Just "this is test" , testDataItemsSet = [ TestItem { testItemId = 1 , testItemName = "item1" , testItemDescription = Just "this is item1" , testItemSubItem = Just TestItem { testItemId = 11 , testItemName = "item1sub" , testItemDescription = Nothing , testItemSubItem = Nothing } } , TestItem { testItemId = 2 , testItemName = "item2" , testItemDescription = Nothing , testItemSubItem = Nothing } ] } parseUnordered :: Expectation parseUnordered = do d <- runResourceT $ parseLBS def input $$ xmlParser (\xml -> getElement xml "data" parseTestData) d `shouldBe` input' where input = L.concat [ "\n" , "" , " test" , " " , " " , " item1" , " 1" , " " , " item1sub" , " 11" , " " , " this is item1" , " " , " " , " item2" , " 2" , " " , " " , " this is test" , " 1" , "" ] input' = TestData { testDataId = 1 , testDataName = "test" , testDataDescription = Just "this is test" , testDataItemsSet = [ TestItem { testItemId = 1 , testItemName = "item1" , testItemDescription = Just "this is item1" , testItemSubItem = Just TestItem { testItemId = 11 , testItemName = "item1sub" , testItemDescription = Nothing , testItemSubItem = Nothing } } , TestItem { testItemId = 2 , testItemName = "item2" , testItemDescription = Nothing , testItemSubItem = Nothing } ] } parseEmpty :: Expectation parseEmpty = do d <- runResourceT $ parseLBS def input $$ xmlParserM (\xml -> getElement xml "data" parseTestData) d `shouldBe` input' where input = "\n" input' = Nothing parseEmptyList :: Expectation parseEmptyList = do d <- runResourceT $ parseLBS def input $$ xmlParser (\xml -> getElement xml "data" parseTestData) d `shouldBe` input' where input = L.concat [ "\n" , "" , " 1" , " test" , " this is test" , " " , " " , "" ] input' = TestData { testDataId = 1 , testDataName = "test" , testDataDescription = Just "this is test" , testDataItemsSet = [] } parseNotAppearItemSet :: Expectation parseNotAppearItemSet = do d <- runResourceT $ parseLBS def input $$ xmlParser (\xml -> getElement xml "data" parseTestData) d `shouldBe` input' where input = L.concat [ "\n" , "" , " 1" , " test" , "" ] input' = TestData { testDataId = 1 , testDataName = "test" , testDataDescription = Nothing , testDataItemsSet = [] } notParseUnexpectedDataStructure :: Expectation notParseUnexpectedDataStructure = runResourceT (parseLBS def input $$ xmlParser (\xml -> getElement xml "data" parseTestData)) `shouldThrow` errorCall "FromText error: no text name=name" where input = L.concat [ "\n" , "" , " 1" , " " , " foo" , " bar" , " " , "" ] ignoreUnexpectedTag :: Expectation ignoreUnexpectedTag = do d <- runResourceT $ parseLBS def input $$ xmlParser (\xml -> getElement xml "data" parseTestData) d `shouldBe` input' where input = L.concat [ "\n" , "" , " 1" , " tag" , " test" , " " , " tag" , " tag" , " " , " tag" , "" ] input' = TestData { testDataId = 1 , testDataName = "test" , testDataDescription = Nothing , testDataItemsSet = [] } parseTopDataSet :: Expectation parseTopDataSet = do d <- runResourceT $ parseLBS def input $$ xmlParser (\xml -> getElements xml "dataSet" "data" parseTestData) d `shouldBe` input' where input = L.concat [ "\n" , "" , " " , " 1" , " test1" , " " , " " , " this is test 1" , " " , " " , " 2" , " test2" , " " , "" ] input' = [ TestData { testDataId = 1 , testDataName = "test1" , testDataDescription = Just "this is test 1" , testDataItemsSet = [] } , TestData { testDataId = 2 , testDataName = "test2" , testDataDescription = Nothing , testDataItemsSet = [] } ] parseTopDataSetConduit :: Expectation parseTopDataSetConduit = do d <- runResourceT $ parseLBS def input $= xmlParserConduit "dataSet" (\xml -> getElement xml "data" parseTestData) $$ CL.consume d `shouldBe` input' where input = L.concat [ "\n" , "" , " " , " 1" , " test1" , " " , " " , " this is test 1" , " " , " " , " 2" , " test2" , " " , "" ] input' = [ TestData { testDataId = 1 , testDataName = "test1" , testDataDescription = Just "this is test 1" , testDataItemsSet = [] } , TestData { testDataId = 2 , testDataName = "test2" , testDataDescription = Nothing , testDataItemsSet = [] } ] parseEmptyItemSetConduit :: Expectation parseEmptyItemSetConduit = do d <- runResourceT $ parseLBS def input $= xmlParserConduit "dataSet" (\xml -> getElement xml "data" parseTestData) $$ CL.consume d `shouldBe` input' where input = L.concat [ "\n" , "" , "" ] input' = []