packages feed

serokell-util-0.9.0: test/Test/Serokell/Data/Variant/VariantSpec.hs

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns        #-}

module Test.Serokell.Data.Variant.VariantSpec
       ( spec
       ) where

import Universum

import Data.Scientific (floatingOrInteger, fromFloatDigits)
import Test.Hspec (Spec, describe)
import Test.Hspec.QuickCheck (prop)
import Test.QuickCheck ((===))

import Serokell.Arbitrary (VariantNoBytes (..), VariantOnlyBytes (..))

import qualified Data.Aeson as A (decode, encode)
import qualified Data.HashMap.Lazy as HM (fromList)
import qualified Data.Vector as V (map)
import qualified Serokell.Data.Variant as S
import qualified Serokell.Util.Base64 as S

spec :: Spec
spec = describe "Variant" $
           describe "Identity Properties" $
               describe "JSON" $ do
                   prop "Variant (No VarBytes)" $
                       \(getVariant -> a) -> jsonFixer a === jsonMid a
                   prop "Variant (Only VarBytes)" $
                       \(getVarBytes -> a) -> a === bytesFun (jsonMid a)

jsonFixer :: S.Variant -> S.Variant
jsonFixer (S.VarMap m) = let ks = map toStr $ keys m
                             vs = map jsonFixer $ elems m
                             m' = HM.fromList $ zip ks vs
                         in S.VarMap m'
jsonFixer (S.VarList l) = S.VarList $ V.map jsonFixer l
jsonFixer v@(S.VarInt i) =
    if i < 0 then v
             else S.VarUInt $ fromIntegral i
jsonFixer (S.VarFloat f) =
    case floatingOrInteger $ fromFloatDigits f of
        Left float -> S.VarFloat float
        Right int -> if int < 0 then S.VarInt int
                                else S.VarUInt $ fromIntegral int
jsonFixer v = v

toStr :: S.Variant -> S.Variant
toStr = S.VarString . pretty

jsonMid :: S.Variant -> S.Variant
jsonMid = maybe err id . A.decode . A.encode
   where
     err = error "[VariantSpec] Failed JSON decoding"

bytesFun :: S.Variant -> S.Variant
bytesFun (S.VarString s) = S.VarBytes right
  where
     right = either error id $ S.decode s
bytesFun _ = error "[bytesFun:] called with Variant that was not VarBytes"