{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
-- {{{ Imports
import Text.RSS.Conduit.Parse as Parser
import Text.RSS.Conduit.Render as Renderer
import Text.RSS.Extensions
import Text.RSS.Extensions.Atom
import Text.RSS.Extensions.Content
import Text.RSS.Extensions.DublinCore
import Text.RSS.Extensions.Syndication
import Text.RSS.Lens
import Text.RSS.Types
import Text.RSS1.Conduit.Parse as Parser
import Arbitrary
import Blaze.ByteString.Builder (toByteString)
import Conduit
import Control.Exception.Safe as Exception
import Control.Monad
import Control.Monad.Trans.Resource
import Data.Char
import Data.Conduit
import Data.Conduit.List
import Data.Default
import Data.Maybe
import Data.Singletons.Prelude.List
import Data.String
import Data.Text (Text)
import Data.Text.Encoding
import qualified Data.Text.Lazy.Encoding as Lazy
import Data.Time.Calendar
import Data.Time.LocalTime
import Data.Version
import Data.Vinyl.Core
import Data.Void
import Data.XML.Types
import Lens.Simple
import System.FilePath
import System.IO
import System.Timeout
import Test.Tasty
import Test.Tasty.Golden (findByExtension, goldenVsString)
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
import Text.Atom.Conduit.Parse
import Text.Atom.Types
import Text.XML.Stream.Parse as XML hiding (choose)
import Text.XML.Stream.Render
import URI.ByteString
import URI.ByteString.QQ
-- }}}
main :: IO ()
main = do
goldenTests <- genGoldenTests
defaultMain $ testGroup "Tests"
[ unitTests
, goldenTests
, properties
]
unitTests :: TestTree
unitTests = testGroup "Unit tests"
[ skipHoursCase
, skipDaysCase
, rss1TextInputCase
, rss2TextInputCase
, rss1ImageCase
, rss2ImageCase
, categoryCase
, cloudCase
, guidCase
, enclosureCase
, sourceCase
, rss1ItemCase
, rss2ItemCase1
, rss2ItemCase2
, rss1ChannelItemsCase
, rss1DocumentCase
, dublinCoreChannelCase
, dublinCoreItemCase
, contentItemCase
, syndicationChannelCase
, atomChannelCase
, multipleExtensionsCase
]
genGoldenTests :: IO TestTree
genGoldenTests = do
xmlFiles <- findByExtension [".xml"] "."
return $ testGroup "RSS golden tests" $ do
xmlFile <- xmlFiles
let goldenFile = addExtension xmlFile ".golden"
f file = fmap (Lazy.encodeUtf8 . fromString . show) $ runResourceT $ runConduit $ sourceFile file .| Conduit.decodeUtf8C .| XML.parseText' def .| parser
parser = rssDocument :: MonadThrow m => ConduitM Event o m (Maybe (RssDocument '[]))
return $ goldenVsString xmlFile goldenFile $ f xmlFile
properties :: TestTree
properties = testGroup "Properties"
[ roundtripProperty "RssTextInput" renderRssTextInput rssTextInput
, roundtripProperty "RssImage" renderRssImage rssImage
, roundtripProperty "RssCategory" renderRssCategory rssCategory
, roundtripProperty "RssEnclosure" renderRssEnclosure rssEnclosure
, roundtripProperty "RssSource" renderRssSource rssSource
, roundtripProperty "RssGuid" renderRssGuid rssGuid
, roundtripProperty "RssItem"
(renderRssItem :: RssItem '[] -> ConduitT () Event Maybe ())
rssItem
, roundtripProperty "DublinCore"
(renderRssChannelExtension @DublinCoreModule)
(Just <$> parseRssChannelExtension)
, roundtripProperty "Syndication"
(renderRssChannelExtension @SyndicationModule)
(Just <$> parseRssChannelExtension)
, roundtripProperty "Atom"
(renderRssChannelExtension @AtomModule)
(Just <$> parseRssChannelExtension)
, roundtripProperty "Content"
(renderRssItemExtension @ContentModule)
(Just <$> parseRssItemExtension)
]
roundtripProperty :: Eq a => Arbitrary a => Show a
=> TestName -> (a -> ConduitT () Event Maybe ()) -> ConduitT Event Void Maybe (Maybe a) -> TestTree
roundtripProperty name render parse = testProperty ("parse . render = id (" <> name <> ")") $ do
input <- arbitrary
let intermediate = fmap (decodeUtf8 . toByteString) $ runConduit $ render input .| renderBuilder def .| foldC
output = join $ runConduit $ render input .| parse
return $ counterexample (show input <> " | " <> show intermediate <> " | " <> show output) $ Just input == output
skipHoursCase :: TestTree
skipHoursCase = testCase "
What a beautiful day!
" :& AtomItem (Just link) :& RNil) where input = [ "