{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeApplications #-}
module HTMLRenderTests where
import Control.Monad ( unless )
import qualified Data.List as L
import Data.Text ( Text )
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import Lens.Micro ( (^.), (.~), (%~), (&) )
import Test.Tasty
import Test.Tasty.HUnit
import Text.HTML.Parser ( parseTokens, renderToken
, canonicalizeTokens
, Token( TagOpen, TagSelfClose ) )
import SampleTables
import TestQQDefs
import qualified Data.KVITable as KVI
import qualified Data.KVITable.Render as KTR
import qualified Data.KVITable.Render.HTML as KTRH
cmpTables :: Text -> Text -> Text -> IO ()
cmpTables nm actual expected = do
let expH = normalize $ parseTokens $ T.concat $ fmap T.strip $ T.lines expected
actH = normalize $ parseTokens actual
normalize = fmap sortAttrs . canonicalizeTokens
sortAttrs (TagOpen n a) = TagOpen n $ L.sort a
sortAttrs (TagSelfClose n a) = TagSelfClose n $ L.sort a
sortAttrs t = t
unless (expH == actH) $ do
let dl (e,a) = if e == a then db e else de " ↱" e <> "\n " <> da " ↳" a
db b = "| > " <> b
de m e = "|" <> m <> "expect> " <> e
da m a = "|" <> m <> "actual> " <> a
el = fmap (TL.toStrict . renderToken) expH
al = fmap (TL.toStrict . renderToken) actH
addnum n l = let nt = T.pack (show n)
nl = T.length nt
in T.take (4 - nl) " " <> nt <> l
let details = ("MISMATCH between " <>
T.pack (show $ length el) <> " expected and " <>
T.pack (show $ length al) <> " actual for " <> nm) :
(fmap (uncurry addnum) $
zip [1..] $ concat $
-- Highly simplistic "diff" output assumes
-- correlated lines: added or removed lines just
-- cause everything to shown as different from that
-- point forward.
[ fmap dl $ zip el al
, fmap (de "∌ ") $ drop (length al) el
, fmap (da "∹ ") $ drop (length el) al
])
assertFailure $ T.unpack $ T.unlines details
testHTMLRendering =
testGroup "HTML rendering" $
let kvi0 = mempty :: KVI.KVITable Text
cfg0 = KTR.defaultRenderConfig
cfgWBlankRows = cfg0 { KTR.hideBlankRows = False }
in
[
testCase "empty table, hide blank" $
cmpTables "empty table, hide blank"
(KTRH.render cfg0 kvi0) [sq|
****
****
|]
, testCase "empty table, show blank" $
cmpTables "empty table, show blank"
(KTRH.render cfgWBlankRows kvi0) [sq|
****
****
|]
, testCase "empty table with labels" $
let kvi = mempty & KVI.keyVals @Float .~ [ ("foo", []), ("dog", []) ]
in cmpTables "empty table with labels" (KTRH.render cfg0 kvi) [sq|
****
****
|]
, testCase "nested table hideBlank=rows,cols, fitted, colstack=hundreds" $
cmpTables "nested table hideBlank=rows,cols, fitted, colstack=hundreds"
(KTRH.render (cfg0 { KTR.sortKeyVals = True
, KTR.rowRepeat = False
, KTR.hideBlankCols = True
, KTR.hideBlankRows = True
, KTR.equisizedCols = False
, KTR.colStackAt = Just "hundreds"
}) nestedTable)
[sq_f|README.md|]
, testCase "nested table hide=none, fitted, colstack=hundreds" $
cmpTables "nested table hide=none, fitted, colstack=hundreds"
(KTRH.render (cfg0 { KTR.sortKeyVals = True
, KTR.rowRepeat = False
, KTR.hideBlankCols = False
, KTR.hideBlankRows = False
, KTR.equisizedCols = False
, KTR.colStackAt = Just "hundreds"
}) nestedTable)
[sq_f|examples/hundreds_all.md|]
, testCase "nested table hideBlank=rol,col colstack=thousands" $
cmpTables "nested table hideBlank=row,col colstack=thousands"
(KTRH.render (cfg0 { KTR.sortKeyVals = True
, KTR.rowRepeat = False
, KTR.hideBlankCols = True
, KTR.hideBlankRows = True
, KTR.equisizedCols = False
, KTR.colStackAt = Just "thousands"
}) nestedTable)
[sq2_f|README.md|]
, testCase "nested table hideBlank=rol,col" $
cmpTables "nested table hideBlank=row,col"
(KTRH.render (cfg0 { KTR.sortKeyVals = True
, KTR.rowRepeat = False
, KTR.hideBlankCols = True
, KTR.hideBlankRows = True
, KTR.equisizedCols = False
}) nestedTable)
[sq3_f|README.md|]
, testCase "big table grouped sorted" $
cmpTables "big table grouped sorted"
(KTRH.render (cfg0 { KTR.sortKeyVals = True
, KTR.rowRepeat = False
, KTR.rowGroup = [ "Location", "Biome", "Category" ]
}) zooTable2)
[sq_f|examples/zoo.md|]
, testCase "big table grouped sorted no-subtype colstack" $
let zt = KVI.fromList $
foldl rmvSubtype [] $
KVI.toList zooTable2
rmvSubtype newl (keyspec, v) =
let ks = filter (("Subtype" /=) . fst) keyspec
in case lookup ks newl of
Nothing -> (ks,v) : newl
Just v' -> (ks, v' + v) : filter ((ks /=) . fst) newl
in cmpTables "big table grouped sorted no-subtype colstack"
(KTRH.render (cfg0 { KTR.sortKeyVals = True
, KTR.rowRepeat = False
, KTR.rowGroup = [ "Location", "Biome", "Category" ]
, KTR.colStackAt = Just "Name"
, KTR.equisizedCols = False
}) zt)
[sq2_f|examples/zoo.md|]
]