{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- {{{ 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.Singletons.Prelude.List
import Data.Text (Text)
import Data.Text.Encoding
import Data.Time.Calendar
import Data.Time.LocalTime
import Data.Version
import Data.Vinyl.Core
import Data.Void
import Data.XML.Types
import qualified Language.Haskell.HLint as HLint (hlint)
import Lens.Simple
import System.IO
import System.Timeout
import Test.Tasty
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 = defaultMain $ testGroup "Tests"
[ unitTests
, properties
, hlint
]
unitTests :: TestTree
unitTests = testGroup "Unit tests"
[ skipHoursCase
, skipDaysCase
, rss1TextInputCase
, rss2TextInputCase
, rss1ImageCase
, rss2ImageCase
, categoryCase
, cloudCase
, guidCase
, enclosureCase
, sourceCase
, rss1ItemCase
, rss2ItemCase
, rss1ChannelItemsCase
, rss1DocumentCase
, rss2DocumentCase
, dublinCoreChannelCase
, dublinCoreItemCase
, contentItemCase
, syndicationChannelCase
, atomChannelCase
, multipleExtensionsCase
]
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 '[] -> Source Maybe Event)
rssItem
, roundtripProperty "DublinCore"
(renderRssChannelExtension :: RssChannelExtension DublinCoreModule -> Source Maybe Event)
(Just <$> parseRssChannelExtension)
, roundtripProperty "Syndication"
(renderRssChannelExtension :: RssChannelExtension SyndicationModule -> Source Maybe Event)
(Just <$> parseRssChannelExtension)
, roundtripProperty "Atom"
(renderRssChannelExtension :: RssChannelExtension AtomModule -> Source Maybe Event)
(Just <$> parseRssChannelExtension)
, roundtripProperty "Content"
(renderRssItemExtension :: RssItemExtension ContentModule -> Source Maybe Event)
(Just <$> parseRssItemExtension)
]
roundtripProperty :: Eq a => Arbitrary a => Show a
=> TestName -> (a -> Source Maybe Event) -> ConduitM 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 = [ "