packages feed

type-of-html-1.0.0.0: test/Main.hs

{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators    #-}
{-# LANGUAGE DataKinds        #-}

module Main where

import Html
import qualified Html.Attribute as A

import Data.Proxy
import Test.Hspec
import Test.QuickCheck

import Data.Text.Lazy.Encoding

import qualified Data.Text.Lazy as T

newtype Escaped = Escaped String deriving Show

instance Arbitrary Escaped where
  arbitrary = Escaped <$> arbitrary `suchThat` (\x -> all (`notElem` x) "<>&\"'")

main :: IO ()
main = hspec spec

spec :: Spec
spec = let allT a b c = b (renderString a, T.unpack $ renderText a, T.unpack . decodeUtf8 $ renderByteString a)
                          (c, c, c)

       in parallel $ do

  describe "render" $ do

    it "is id on strings without escaping chars" $ do

      property $ \(Escaped x) -> allT x (==) x

    it "handles single elements" $ do

      property $ \(Escaped x) -> allT (div_ x) (==) ("<div>" ++ x ++ "</div>")

    it "handles nested elements" $ do

      property $ \(Escaped x) -> allT (div_ (div_ x)) (==)
        ("<div><div>" ++ x ++ "</div></div>")

    it "handles parallel elements" $ do

      property $ \(Escaped x) (Escaped y) -> allT (div_ x # div_ y)
        (==)
        ("<div>" ++ x ++ "</div><div>" ++ y ++ "</div>")

    it "doesn't use closing tags for empty elements" $ do

      allT area_
        shouldBe
        "<area>"

      allT base_
        shouldBe
        "<base>"

      allT br_
        shouldBe
        "<br>"

      allT col_
        shouldBe
        "<col>"

      allT embed_
        shouldBe
        "<embed>"

      allT hr_
        shouldBe
        "<hr>"

      allT iframe_
        shouldBe
        "<iframe>"

      allT img_
        shouldBe
        "<img>"

      allT link_
        shouldBe
        "<link>"

      allT menuitem_
        shouldBe
        "<menuitem>"

      allT meta_
        shouldBe
        "<meta>"

      allT param_
        shouldBe
        "<param>"

      allT source_
        shouldBe
        "<source>"

      allT track_
        shouldBe
        "<track>"

      allT wbr_
        shouldBe
        "<wbr>"

    it "handles trailing text" $ do

      property $ \(Escaped x) (Escaped y) -> allT (td_ x # y)
        (==)
        ("<td>" ++ x ++ "</td>" ++ y)

    it "handles a single compile time text" $ do

      allT (Proxy :: Proxy "a")
        shouldBe
        "a"

    it "handles trailing compile time text" $ do

      allT (div_ "a" # (Proxy :: Proxy "b"))
        shouldBe
        "<div>a</div>b"

    it "handles nested compile time text" $ do

      allT (div_ (Proxy :: Proxy "a"))
        shouldBe
        "<div>a</div>"

    it "handles an empty list" $ do

      allT (tail [td_ "a"])
        shouldBe
        ""

    it "handles a list with a single element" $ do

      allT [td_ "a"]
        shouldBe
        "<td>a</td>"

    it "handles tags in a list with parallel elements" $ do

      allT [div_ "a" # i_ "b"]
        shouldBe
        "<div>a</div><i>b</i>"

    it "handles nested lists" $ do

      allT (div_ [div_ [div_ (4 :: Int)]])
        shouldBe
        "<div><div><div>4</div></div></div>"

    it "handles utf8 correctly" $ do

      allT (div_ "a ä € 𝄞")
        shouldBe
        "<div>a ä € 𝄞</div>"

      allT (img_A (A.id_ "a ä € 𝄞"))
        shouldBe
        "<img id=\"a ä € 𝄞\">"

    it "handles complex compile time documents" $ do

      allT (div_ () # i_ ())
        shouldBe
        "<div></div><i></i>"

      allT (div_ () # "a")
        shouldBe
        "<div></div>a"

      allT ("a" # i_ ())
        shouldBe
        "a<i></i>"

      allT (div_ () # i_ (Proxy @"a"))
        shouldBe
        "<div></div><i>a</i>"

      allT (div_ (Proxy @"a") # i_ ())
        shouldBe
        "<div>a</div><i></i>"

      allT (Proxy @"1" # "2")
        shouldBe
        "12"

      allT ("1" # Proxy @"2")
        shouldBe
        "12"

      allT (div_ () # td_ (Proxy @"1" # "2" # div_ () # i_A (A.id_ (Proxy @"3")) "4"))
        shouldBe
        "<div></div><td>12<div></div><i id=\"3\">4</i></td>"