packages feed

shikensu-0.3.8: tests/Test/Contrib.hs

module Test.Contrib
    ( contribTests
    ) where

import Data.ByteString (ByteString)
import Data.Monoid ((<>))
import Flow
import System.FilePath
import Test.Helpers
import Test.Tasty
import Test.Tasty.HUnit

import qualified Data.Aeson.Types as Aeson (Value(..))
import qualified Data.ByteString as B (empty)
import qualified Data.ByteString.Char8 as BS (intercalate, pack)
import qualified Data.HashMap.Strict as HashMap (fromList, lookup)
import qualified Data.List as List (head, reverse)
import qualified Data.Text as Text (pack, unpack)
import qualified Data.Text.Encoding as Text (decodeUtf8, encodeUtf8)
import qualified Data.Text.IO as Text (readFile)
import qualified Shikensu
import qualified Shikensu.Contrib as Contrib
import qualified Shikensu.Contrib.IO as Contrib.IO


contribTests :: TestTree
contribTests = testGroup
    "Contrib tests"
    [ testClone
    , testExclude
    , testMetadata
    , testPermalink
    , testPrefixDirname
    , testRead
    , testRename
    , testRenameExt
    , testRenderContent
    , testSetContent
    , testTransformContent
    , testWrite
    ]



-- Test data


list :: String -> IO Shikensu.Dictionary
list thePattern =
    Shikensu.listRelative [thePattern] "."


example_md :: IO Shikensu.Dictionary
example_md =
    list $ joinPath [ "tests", "fixtures", "example.md" ]


renderer :: Shikensu.Definition -> Maybe ByteString
renderer def =
    let
        openingTag = BS.pack "<html>"
        closingTag = BS.pack "</html>"
    in
        def
            |> Shikensu.content
            |> fmap (\c -> BS.intercalate B.empty [openingTag, c, closingTag])


upstairs :: String
upstairs =
    addTrailingPathSeparator ".."



-- Tests


testClone :: TestTree
testClone =
    let
        dictionary = fmap (Contrib.clone "example.md" "cloned.md") example_md
        definition = fmap (List.reverse .> List.head) dictionary
    in
        testCase "Should `clone`"
        $ assertDef definition Shikensu.localPath "cloned.md"



testExclude :: TestTree
testExclude =
    let
        dictionary = fmap (Contrib.exclude "example.md") example_md
        dictLength = fmap length dictionary
    in
        testCase "Should `exclude`"
        $ assertEqm dictLength 0



testMetadata :: TestTree
testMetadata =
    let
        keyA        = Text.pack "title"
        valueA      = Aeson.String (Text.pack "Hello world!")

        keyB        = Text.pack "hello"
        valueB      = Aeson.String (Text.pack "Guardian.")

        keyC        = Text.pack "removed"
        valueC      = Aeson.String (Text.pack "Me.")

        keyBase     = Text.pack "basename"
        valueBase   = Aeson.String (Text.pack "example")

        -- 1. Insert C
        -- 2. Replace with A
        -- 3. Insert B
        dictionary = fmap
            ( id
                .> Contrib.insertMetadata   (HashMap.fromList [ (keyC, valueC) ])
                .> Contrib.replaceMetadata  (HashMap.fromList [ (keyA, valueA) ])
                .> Contrib.copyPropsToMetadata
                .> Contrib.insertMetadata   (HashMap.fromList [ (keyB, valueB) ])
            )
            example_md

        definition          = fmap (List.reverse .> List.head) dictionary

        lookupTitle     def = HashMap.lookup keyA (Shikensu.metadata def)
        lookupHello     def = HashMap.lookup keyB (Shikensu.metadata def)
        lookupRemoved   def = HashMap.lookup keyC (Shikensu.metadata def)
        lookupBasename  def = HashMap.lookup keyBase (Shikensu.metadata def)
    in
        testGroup
            "Metadata"
            [ testCase "Should no longer have `removed` key"
            $ assertDef definition lookupRemoved Nothing

            , testCase "Should have `hello` key"
            $ assertDef definition lookupHello (Just valueB)

            , testCase "Should have `title` key"
            $ assertDef definition lookupTitle (Just valueA)

            , testCase "Should have `basename` key"
            $ assertDef definition lookupBasename (Just valueBase)
            ]



testPermalink :: TestTree
testPermalink =
    let
        dictionary = fmap (Contrib.permalink "index") example_md
        definition = fmap List.head dictionary
    in
        testGroup
            "Permalink"
            [ testCase "Should have the correct `localPath`"
            $ assertDef definition Shikensu.localPath ("example" </> "index.md")

            , testCase "Should have the correct `parentPath`"
            $ assertDef definition Shikensu.parentPath (Just upstairs)

            , testCase "Should have the correct `pathToRoot`"
            $ assertDef definition Shikensu.pathToRoot upstairs
            ]



testPrefixDirname :: TestTree
testPrefixDirname =
    let
        thePrefix  = addTrailingPathSeparator "prefix"
        thePattern = "tests" </> "**" </> "example.md"

        dictionary = fmap (Contrib.prefixDirname thePrefix) (list thePattern)
        definition = fmap List.head dictionary
    in
        testGroup
            "PrefixDirname"
            [ testCase "Should have the correct `dirname`"
            $ assertDef definition Shikensu.dirname ("prefix" </> "fixtures")

            , testCase "Should have the correct `parentPath`"
            $ assertDef definition Shikensu.parentPath (Just upstairs)

            , testCase "Should have the correct `pathToRoot`"
            $ assertDef definition Shikensu.pathToRoot (upstairs <> upstairs)
            ]



testRead :: TestTree
testRead =
    let
        theResult  = Just (Text.pack "# Example\n")
        definition = fmap List.head (example_md >>= Contrib.IO.read)
    in
        testCase "Should `read`"
        $ assertDef definition (Shikensu.content .> fmap Text.decodeUtf8) theResult



testRename :: TestTree
testRename =
    let
        dictionary = fmap (Contrib.rename "example.md" "renamed.md") example_md
        definition = fmap List.head dictionary
    in
        testCase "Should `rename`"
        $ assertDef definition Shikensu.localPath "renamed.md"



testRenameExt :: TestTree
testRenameExt =
    let
        dictionary = fmap (Contrib.renameExt ".md" ".html") example_md
        definition = fmap List.head dictionary
    in
        testCase "Should `renameExt`"
        $ assertDef definition Shikensu.extname ".html"



testRenderContent :: TestTree
testRenderContent =
    let
        theResult  = Just (Text.pack "<html># Example\n</html>")
        dictionary = fmap (Contrib.renderContent renderer) (example_md >>= Contrib.IO.read)
        definition = fmap List.head dictionary
    in
        testCase "Should `renderContent`"
        $ assertDef definition (Shikensu.content .> fmap Text.decodeUtf8) theResult


testSetContent :: TestTree
testSetContent =
    let
        content    = Text.encodeUtf8 "<html># Example\n</html>"
        dictionary = fmap (Contrib.setContent content) (example_md >>= Contrib.IO.read)
        definition = fmap List.head dictionary
    in
        testCase "Should `setContent`"
        $ assertDef definition Shikensu.content (Just content)


testTransformContent :: TestTree
testTransformContent =
    let
        theResult  = Just (Text.pack "<html># Example\n</html>")
        dictionary = fmap (Contrib.transformContent renderer) (example_md >>= Contrib.IO.read)
        definition = fmap List.head dictionary
    in
        testCase "Should `transformContent`"
        $ assertDef definition (Shikensu.content .> fmap Text.decodeUtf8) theResult


testWrite :: TestTree
testWrite =
    let
        destination = "tests" </> "build" <> [ pathSeparator ]
        thePattern  = "tests" </> "**" </> "example.md"

        dictionary  = list thePattern
            >>= Contrib.IO.read
            >>= Contrib.IO.write destination

        definition = fmap List.head dictionary
    in
        testCase "Should `write`"
        $ fmap Shikensu.rootDirname definition
            >>= \r -> readFile (joinPath [ r, destination, "fixtures", "example.md" ])
            >>= \c -> assertEq "# Example\n" c