{-# 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| ****
Value
**** |] , testCase "empty table, show blank" $ cmpTables "empty table, show blank" (KTRH.render cfgWBlankRows kvi0) [sq| ****
Value
**** |] , testCase "empty table with labels" $ let kvi = mempty & KVI.keyVals @Float .~ [ ("foo", []), ("dog", []) ] in cmpTables "empty table with labels" (KTRH.render cfg0 kvi) [sq| ****
foo dog Value
**** |] , 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|] ]