sv-1.3: test/Data/Sv/EncodeTest.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Data.Sv.EncodeTest (test_Encode) where
import Control.Lens (makeClassyPrisms)
import Data.Functor.Contravariant
import Data.Functor.Contravariant.Divisible
import Data.Semigroup ((<>))
import Data.Text (Text)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (testCase, (@?=))
import Data.Sv
import qualified Data.Sv.Encode as E
data IntOrString =
I Int | S String
deriving (Eq, Ord, Show)
makeClassyPrisms ''IntOrString
data IntAndString = IAS { getInt :: Int, getString :: String }
test_Encode :: TestTree
test_Encode =
testGroup "Encode" [
divisibleTests
, decidableTests
, encodeTests
, escapeTests
, encodeNamedTests
]
intAndString :: Encode IntAndString
intAndString = contramap getInt E.int <> contramap getString E.string
opts :: EncodeOptions
opts = defaultEncodeOptions
intOrString :: Encode IntOrString
intOrString = E.encodeOf _I E.int <> E.encodeOf _S E.string
i :: IntOrString
i = I 5
s :: IntOrString
s = S "hello"
decidableTests :: TestTree
decidableTests =
testGroup "decidable" [
testCase "encode an Int" $
encodeRow intOrString opts i @?= "5"
, testCase "encode a String" $
encodeRow intOrString opts s @?= "hello"
]
intEmptyAndString :: Encode IntAndString
intEmptyAndString = contramap getInt E.int <> E.empty <> contramap getString E.string
ias :: IntAndString
ias = IAS 10 "goodbye"
divisibleTests :: TestTree
divisibleTests =
testGroup "divisible" [
testCase "encode an IntAndString" $
encodeRow intAndString opts ias @?= "10,goodbye"
, testCase "encode an IntAndString with an empty between" $
encodeRow intEmptyAndString opts ias @?= "10,,goodbye"
]
encodeTests :: TestTree
encodeTests =
testCase "multiple lines" $
encode (divided intAndString intOrString) opts [(IAS 3 "book", I 4), (IAS 7 "film", S "ok")]
@?= "3,book,4\n7,film,ok"
escapeTests :: TestTree
escapeTests =
testGroup "escape" [
testCase "string" $
encodeRow E.string opts "hello \"test\" case" @?= "\"hello \"\"test\"\" case\""
, testCase "text" $
encodeRow E.text opts "this is also\"a test\"" @?= "\"this is also\"\"a test\"\"\""
, testCase "bytestring - strict" $
encodeRow E.byteString opts "\"test\"ing\" " @?= "\"\"\"test\"\"ing\"\" \""
, testCase "bytestring - lazy" $
encodeRow E.lazyByteString opts "\"" @?= "\"\"\"\""
]
data Three = Three {
int :: Int
, double :: Double
, text :: Text
} deriving (Eq, Ord, Show)
three :: NameEncode Three
three =
E.named "first" (contramap int E.int)
<> E.named "\"Second\"" (contramap double E.doubleFast)
<> E.named "third" (contramap text E.text)
myInt :: NameEncode Int
myInt = E.named "my int" E.int
encodeNamedTests :: TestTree
encodeNamedTests = testGroup "named" [
testCase "empty decoder" $
encodeNamed mempty opts [] @?= ""
, testCase "single column, zero rows" $
encodeNamed myInt opts [] @?= "my int"
, testCase "single column, one row" $
encodeNamed myInt opts [5] @?= "my int\n5"
, testCase "single column, many rows" $
encodeNamed myInt opts [1..5] @?= "my int\n1\n2\n3\n4\n5"
, testCase "multiple columns, zero rows" $
encodeNamed three opts [] @?= "first,\"\"\"Second\"\"\",third"
, testCase "multiple columns, one row" $
encodeNamed three opts [Three 1 2 "th\"ree"]
@?= "first,\"\"\"Second\"\"\",third\n1,2,\"th\"\"ree\""
, testCase "multiple columns, multiple rows" $
encodeNamed three opts [Three 1 2 "three", Three 4 5 "SIX"]
@?= "first,\"\"\"Second\"\"\",third\n1,2,three\n4,5,SIX"
]