{-# LANGUAGE ExistentialQuantification, OverloadedStrings #-}
module Main where
import qualified Data.ByteString as ByteString
import Data.ByteString (ByteString)
import Data.Functor.Identity (Identity)
import Data.List (isSuffixOf)
import Data.Maybe (mapMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import Numeric (showHex)
import System.Directory (doesDirectoryExist, listDirectory)
import System.FilePath.Posix (combine)
import qualified Text.ParserCombinators.Incremental as Incremental
import Text.ParserCombinators.Incremental.LeftBiasedLocal (Parser)
import qualified Data.Attoparsec.ByteString as Atto
import Test.Tasty (TestTree, defaultMain, testGroup)
import Test.Tasty.HUnit (assertFailure, assertEqual, testCase)
import Construct
import qualified MBR
import qualified TAR
import qualified URI
import qualified WMF
data TestFormat = forall f. TestFormat (Format (Parser ByteString) Maybe ByteString (f Identity))
| forall f. LineFormat (Format (Parser Text) Maybe Text (f Identity))
| forall f. AttoFormat (Format Atto.Parser Maybe ByteString (f Identity))
main = exampleTree "" "test/examples" >>= defaultMain . testGroup "examples"
exampleTree :: FilePath -> FilePath -> IO [TestTree]
exampleTree ancestry path =
do let fullPath = combine ancestry path
isDir <- doesDirectoryExist fullPath
if isDir
then (:[]) . testGroup path . concat <$> (listDirectory fullPath >>= mapM (exampleTree fullPath))
else do blob <- ByteString.readFile fullPath
let format
| ".mbr" `isSuffixOf` path = TestFormat MBR.format
| ".tar" `isSuffixOf` path = AttoFormat TAR.archive
| ".uris" `isSuffixOf` path = LineFormat URI.uriReference
| ".wmf" `isSuffixOf` path = TestFormat WMF.fileFormat
textLines = Text.lines (decodeUtf8 blob)
roundTrip f t
| Text.null t = Just t
| [(structure, remainder)] <- Incremental.completeResults (Incremental.feedEof $
Incremental.feed t $ parse f),
Text.null remainder = serialize f structure
| otherwise = Nothing
Just blob'
| TestFormat f <- format,
[(structure, remainder)] <- Incremental.completeResults (Incremental.feedEof $
Incremental.feed blob $ parse f) =
(<> remainder) <$> serialize f structure
| LineFormat f <- format = Just (encodeUtf8 $ mconcat $ mapMaybe (roundTrip f) textLines)
| AttoFormat f <- format,
Atto.Done remainder structure <- Atto.parse (parse f) blob =
(<> remainder) <$> serialize f structure
| AttoFormat f <- format, Atto.Partial i <- Atto.parse (parse f) blob,
Atto.Done remainder structure <- i mempty =
(<> remainder) <$> serialize f structure
return . (:[]) . testCase path $ assertEqual "round-trip" (hex blob) (hex blob')
hex :: ByteString -> String
hex = ByteString.foldr (pad . flip showHex "") ""
where pad [x] s = ['0', x] ++ s
pad [x, y] s = [x, y] ++ s