packages feed

jespresso-0.9: test/UnitTest.hs

{-# LANGUAGE Rank2Types #-}

module Main where

import Test.Tasty
import Test.Tasty.Golden.Advanced
import System.Directory
import qualified System.FilePath as FP
import System.IO hiding (utf8)
import Text.Html.Consolidate
import Text.XML.HXT.Core
import Text.XML.HXT.Arrow.XmlState.RunIOStateArrow
import Text.XML.HXT.Arrow.WriteDocument
import Control.Arrow
import Control.Monad
import Data.Char
import Control.Monad.IO.Class

main = do allCases <- getDirectoryContents casesDir
          allExpects <- getDirectoryContents expectsDir
          let validCases = getValid allCases
          let validExpects = getValid allExpects
          defaultMain $ testGroup "Tests" $
            map genTest $ filter (`elem` validExpects) validCases
            where getValid = filter $ \x -> FP.takeExtension x == ".js"

casesDir = "test-data/cases"
expectsDir = "test-data/expects"

genTest :: FilePath -> TestTree
genTest testFileName =
  let caseFileName = casesDir `FP.combine` testFileName
      expectFileName = expectsDir `FP.combine` testFileName
      ns = initialConsState False Nothing []
      state  = initialState ns
      normalizedA :: String -> TArr XmlTree XmlTree
      normalizedA s = single $ parseHTML s Nothing >>> consolidateArr
      expectedA :: String -> TArr XmlTree XmlTree      
      expectedA   s = single $ parseHTML s Nothing
      runX :: forall r s. (String -> TArr XmlTree XmlTree) -> FilePath -> ValueGetter r String
      runX a f = liftIO $ do
          s <- readFile f
          let arr :: TArr XmlTree String
              arr = (a s) >>> writeDocumentToString [withOutputHTML, withOutputEncoding utf8]
          liftM head $ runXIOState state $ arr
      expectedValueAction = runX expectedA expectFileName
      testValueAction     = runX normalizedA  caseFileName
  in goldenTest testFileName expectedValueAction testValueAction verifyOutput (const $ return ())

verifyOutput :: String -> String -> IO (Maybe String)
verifyOutput expected actual = return $
  let fs = filter (not . isSpace)
      msg = "Failed to match expected output to normalized input:\n\
            \Expected:\n" ++ expected ++ "\n\nSaw:\n" ++ actual ++ "\n"
  in  if (fs expected == fs actual) then Nothing
                                    else Just msg