packages feed

willow-0.1.0.0: test/Test/Willow/Html5Lib/Encoding/Sniffer.hs

{-# LANGUAGE OverloadedStrings #-}

{-|
Description:    

Copyright:      (c) 2020 Samuel May
License:        MPL-2.0
Maintainer:     ag.eitilt@gmail.com

Stability:      experimental
Portability:    portable
-}
module Test.Willow.Html5Lib.Encoding.Sniffer
    ( tests
    ) where


import qualified Test.HUnit as U
import Test.HUnit ( (~?=), (~:) )

import System.FilePath ( (</>) )

import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BS.C
import qualified Data.Char as C
import qualified Data.Either as E
import qualified Data.Maybe as Y

import qualified Text.Read as R

import Web.Willow.Common.Encoding.Sniffer

import Test.Willow.Html5Lib.Common


testFile :: FilePath -> IO FilePath
testFile f = (</> f) <$> dataFile "encoding"


tests :: IO U.Test
tests = do
    ts <- mapM id
        [ test (Just 47) "tests1.dat"   -- More complex than the presniffer after that
        , test Nothing "tests2.dat"
        ]
    return $ "encoding" ~: U.TestList ts


test :: Maybe Word -> FilePath -> IO U.Test
test len p = ((~:) p . U.TestList . cut) <$> parse p
  where cut = case len of
            Just i -> take $ fromIntegral i
            Nothing -> id


parse :: FilePath -> IO [U.Test]
parse p = do
    ls <- testFile p >>= BS.readFile
    let ts = uncurry zip . E.partitionEithers . foldr gatherLines [] . fst . foldr categorizeLines ([], True) $ BS.C.lines ls
    return $ map (\(testData, enc) -> run testData ~?= parseEncoding enc) ts

categorizeLines :: BS.ByteString -> ([Either BS.ByteString BS.ByteString], Bool) -> ([Either BS.ByteString BS.ByteString], Bool)
categorizeLines "#data" (ls, _) = (ls, True)
categorizeLines "#encoding" (ls, _) = (ls, False)
categorizeLines l (ls, True) = (Right l : ls, True)
categorizeLines l (ls, False) = (Left l : ls, False)

gatherLines :: Either BS.ByteString BS.ByteString -> [Either BS.ByteString BS.ByteString] -> [Either BS.ByteString BS.ByteString]
gatherLines l [] = [l]
gatherLines (Left l) ((Left l'):ls) = Left (BS.concat [l, "\n", l']) : ls
gatherLines (Right l) ((Right l'):ls) = Right (BS.concat [l, "\n", l']) : ls
gatherLines l ls = l : ls

-- | Avoids relying on 'lookupEncoding', and so is able to test that at the
-- same time.
parseEncoding :: BS.ByteString -> Encoding
parseEncoding enc = Y.fromMaybe Windows1252 . R.readMaybe . foldr foldEncoding [] . map (map (toEnum . fromIntegral) . BS.unpack) $ BS.split 0x2D enc
  where foldEncoding s@(c:cs) ss@(d:_)
            | C.isDigit (last s) && C.isDigit d = s' ++ '_' : ss
            | otherwise = s' ++ ss
          where s' = C.toUpper c : map C.toLower cs
        foldEncoding [] ss = ss
        foldEncoding (c:cs) [] = C.toUpper c : map C.toLower cs


run :: BS.ByteString -> Encoding
run = confidenceEncoding . sniff emptySnifferEnvironment