packages feed

hedn-0.1.5.2: tests/Main.hs

{-# LANGUAGE OverloadedStrings, ExistentialQuantification #-}

module Main where

import Test.HUnit
import Control.Monad (when)
import System.Exit (exitFailure)

import qualified Data.ByteString.Lazy.Char8 as BSL
import qualified Data.ByteString.Char8 as BS
import qualified Data.Text.Lazy as TL
import qualified Data.Text as T

import qualified Data.Vector as V
import qualified Data.Set as S
import qualified Data.Map as M

import Data.EDN (ToEDN, toEDN, fromEDN, Result(..))
import Data.EDN.Types as E
import Data.EDN.Parser (decode)
import Data.EDN.Encode (encode)

main :: IO ()
main = do
    (Counts _ _ e f) <- runTestTT tests
    when (e > 0 || f > 0) $ exitFailure

tests :: Test
tests = TestList [ TestLabel "BSL -> TV decoder" $ TestList $ map makeDecodeCase decodeCases
                 , TestLabel "TV -> BSL encoder" $ TestList $ map makeEncodeCase encodeCases
                 , TestLabel "decoder fail" (TestCase (assertEqual "bad unicode" Nothing (decode "№")))
                 , TestLabel "ToEDN conversion" $ TestList $ map makeToEDNcase toEDNcases
                 , TestLabel "'Tagged a' conversion" $ TestList taggedConversion
                 ]

makeDecodeCase :: (BSL.ByteString, E.TaggedValue) -> Test
makeDecodeCase (i, o) = TestCase (assertEqual (BSL.unpack i) (Just o) (decode i))

makeEncodeCase :: (E.TaggedValue, BSL.ByteString) -> Test
makeEncodeCase (i, o) = TestCase (assertEqual (BSL.unpack o) o (encode i))

decodeCases :: [(BSL.ByteString, E.TaggedValue)]
decodeCases = [ ("nil", E.nil)

              , ("true", E.true)
              , ("false", E.false)

              , ("\"a nice string\"", "a nice string")
              , ("\"split\\second \\t\\rai\\n\"", "split\\second \t\rai\n")
              , ("\"test \\\"sausage\\\" shmest\"", "test \"sausage\" shmest")
              , ("\"\"", "")

              , ("\\c", E.char 'c')
              , ("\\\\", E.char '\\')
              , ("\\newline", E.char '\n')
              , ("\\space", E.char ' ')
              , ("\\tab", E.char '\t')

              , ("justasymbol", E.symbol "justasymbol")
              , ("with#stuff:inside", E.symbol "with#stuff:inside")
              , ("my-namespace/foo", E.symbolNS "my-namespace" "foo")
              , ("/", E.symbol "/")

              , (":fred", E.keyword "fred")
              , (":my/fred", E.keyword "my/fred")

              , ("42", E.integer 42)
              , ("-1", E.integer (-1))

              , ("100.50", E.floating 100.5)
              , ("-3.14", E.floating (-3.14))
               -- ...and many other strange stuff...

              , ("(a b 42)", sampleList)
              , ("()", E.notag $ E.makeList [])

              , ("[a b 42]", sampleVec)
              , ("[]", E.notag $ E.makeVec [])

              , ("{:a 1, \"foo\" :bar, [1 2 3] four}", sampleMap)
              , ("{}", E.notag $ E.makeMap [])

              , ("#{a b [1 2 3]}", sampleSet)
              , ("#{}", E.notag $ E.makeSet [])

              , ("[a b #_foo 42]", sampleDiscard)
              , ("(1 2 ;more to go!\n 3 4)", sampleComment)

              , ("#myapp/Person {:first \"Fred\" :last \"Mertz\"}", E.tag "myapp" "Person" sampleTaggedMap)
              , ("{:first \"Fred\" :last \"Mertz\"}", E.notag sampleTaggedMap)
              ]

encodeCases :: [(E.TaggedValue, BSL.ByteString)]
encodeCases = [ (E.nil, "nil")

              , (E.true, "true")
              , (E.false, "false")

              , (E.string "a nice string", "\"a nice string\"")
              , ("overloaded", "\"overloaded\"")
              , ("escape \rou\te \\ \"\north\"", "\"escape \\rou\\te \\\\ \\\"\\north\\\"\"")

              , (E.char 'c', "\\c")
              , (E.char '\\', "\\\\")
              , (E.char '\n', "\\newline")
              , (E.char '\r', "\\return")
              , (E.char '\t', "\\tab")
              , (E.char ' ', "\\space")

              , (E.symbol "justasymbol", "justasymbol")
              , (E.symbol "with#stuff:inside", "with#stuff:inside")
              , (E.symbolNS "whatever" "whenever", "whatever/whenever")
              , (E.symbol "/", "/")

              , (E.keyword "fred", ":fred")
              , (E.keyword "my/fred", ":my/fred")
              , (E.notag ":overloaded", ":overloaded") -- IsString kw transform only for untagged values

              , (E.integer 42, "42")
              , (E.integer (-1), "-1")

              , (E.floating 100.50, "100.5")
              , (E.floating (-3.14), "-3.14")

              , (sampleList, "(a b 42)")
              , (E.notag $ E.makeList [], "()")

              , (sampleVec, "[a b 42]")
              , (E.notag $ E.makeVec [], "[]")

              , (sampleMap, "{\"foo\" :bar :a 1 [1 2 3] four}") -- Order not guaranteed
              , (E.notag $ E.makeMap [], "{}")

              , (E.tag "myapp" "Person" sampleTaggedMap, "#myapp/Person {:first \"Fred\" :last \"Mertz\"}")
              ]

sampleList :: E.TaggedValue
sampleList = E.notag $ E.makeList [E.symbol "a", E.symbol "b", E.integer 42]

sampleVec :: E.TaggedValue
sampleVec = E.notag $ E.makeVec [E.symbol "a", E.symbol "b", E.integer 42]

sampleMap :: E.TaggedValue
sampleMap = E.notag $ E.makeMap [ (":a",                                              E.integer 1)
                                , ("foo",                                             E.keyword "bar")
                                , (E.makeVec [E.integer 1, E.integer 2, E.integer 3], E.symbol "four")
                                ]

sampleSet :: E.TaggedValue
sampleSet = E.notag $ E.makeSet [ E.symbol "a"
                                , E.symbol "b"
                                , E.notag $ E.makeVec [E.integer 1, E.integer 2, E.integer 3]
                                ]

sampleDiscard :: E.TaggedValue
sampleDiscard = E.notag $ E.makeVec [E.symbol "a", E.symbol "b", E.integer 42]

sampleComment :: E.TaggedValue
sampleComment = E.notag $ E.makeList [E.integer 1, E.integer 2, E.integer 3, E.integer 4]

sampleTaggedMap :: E.Value
sampleTaggedMap = E.makeMap [ "first" .= "Fred", "last" .= "Mertz" ]

data ToEDNCase = forall a. ToEDN a => ToEDNCase !a !E.TaggedValue

makeToEDNcase :: ToEDNCase -> Test
makeToEDNcase (ToEDNCase i o) = TestCase (assertEqual (show o) o (toEDN i))

toEDNcases :: [ToEDNCase]
toEDNcases = [ ToEDNCase (Nothing :: Maybe Bool) E.nil

             , ToEDNCase (Left "hi" :: Either String ()) $ E.tag "either" "left" "hi"
             , ToEDNCase (Right "z" :: Either () String) $ E.tag "either" "right" "z"

             , ToEDNCase True E.true
             , ToEDNCase False E.false

             , ToEDNCase ("test" :: String) (E.string "test")
             , ToEDNCase ("test" :: BSL.ByteString) "test"
             , ToEDNCase ("test" :: BS.ByteString) "test"
             , ToEDNCase ("test" :: TL.Text) "test"
             , ToEDNCase ("test" :: T.Text) "test"

             , ToEDNCase 'c' $ E.char 'c'
             , ToEDNCase '\n' $ E.char '\n'
             , ToEDNCase '\\' $ E.char '\\'

             , ToEDNCase (3.14 :: Double) $ E.floating 3.14
             , ToEDNCase (42 :: Integer) $ E.integer 42

             , ToEDNCase () (E.notag $ E.makeList [])
             , ToEDNCase ([] :: [()]) (E.notag $ E.makeList [])
             , ToEDNCase (["yo", "wassup"] :: [String]) (E.notag $ E.makeList ["yo", "wassup"])
             , ToEDNCase [E.string "i", "am", E.symbolNS "boxed" "container"] (E.notag $ E.makeList [E.string "i", "am", E.symbolNS "boxed" "container"])

             , ToEDNCase (V.fromList ['o', 'm', 'g']) (E.notag $ E.makeVec [E.char 'o', E.char 'm', E.char 'g'])

             , ToEDNCase (S.fromList ['o', 'm', 'g']) (E.notag $ E.makeSet [E.char 'o', E.char 'm', E.char 'g'])

             , ToEDNCase (M.fromList [("test", "shmest"), ("foo", "bar")] :: M.Map String String) (E.notag $ E.makeMap [("test", "shmest"), ("foo", "bar")])
             , ToEDNCase (M.fromList [(":test", "shmest"), (":foo", "bar")] :: EDNMap) (E.notag $ E.makeMap ["test" .= "shmest", "foo" .= "bar"])
             ]


taggedConversion :: [Test]
taggedConversion = [ TestCase (assertEqual "toEDN tagged" (E.tag "wo" "ot" (E.Boolean False)) (toEDN $ E.tag "wo" "ot" False))
                   , TestCase (assertEqual "toEDN notag" E.false (toEDN $ E.notag False))
                   , TestCase (assertEqual "fromEDN tagged" (Success $ E.tag "wo" "ot" False) (fromEDN $ E.tag "wo" "ot" (E.Boolean False)))
                   , TestCase (assertEqual "fromEDN notag" (Success $ E.notag False) (fromEDN $ E.false))
                   ]