packages feed

hinterface-1.0.0: test/Foreign/Erlang/TermSpec.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedLists #-}

module Foreign.Erlang.TermSpec
  ( spec
  )
where

import           Data.Binary                    ( decode
                                                , encode
                                                )
import qualified Data.ByteString.Lazy          as B
import           Data.Word                      ( )
import           Data.List.NonEmpty             (NonEmpty(..))
import           Foreign.Erlang.Term
import           Test.Hspec
import           Test.QuickCheck
import           Data.Vector                    ( fromList )
-- import           Debug.Trace

traceShowIdBS :: B.ByteString -> B.ByteString
traceShowIdBS bs = bs
-- traceShowIdBS bs = traceShow (B.unpack bs) bs

spec :: HasCallStack => Spec
spec = do
  describe "Binary instances of arbitrary ExternalTerm" $
    it "decode . encode = id" $
    property $ \(t :: ExternalTerm) -> decode (traceShowIdBS (encode t)) === t
  describe "Binary instances of arbitrary Term" $
    it "decode . encode = id" $
    property $ \(MkExternalTerm t) -> decode (traceShowIdBS (encode t)) === t
  describe "Pid" $ do
    it "has a Binary instance such that decode is the inverse of encode" $
      property $ \(p :: Pid) ->
        fromTerm (decode (encode (toTerm p))) `shouldBe` Just p
    it "represents all valid Erlang pids" $
      property $ \x y z ->
        let p = pid "nodename" x y z
         in fromTerm (decode (encode (toTerm p))) `shouldBe` Just p
  describe "FromTerm/ToTerm" $ do
    it "converts '[Integer]' back and forth" $
      property $ \(xs :: [Integer]) -> fromTerms (toTerms xs) `shouldBe` Just xs
    it "converts 'Maybe Bool' back and forth" $
      property $ \(x :: Maybe Bool) -> fromTerm (toTerm x) `shouldBe` Just x
    it "converts 'Either a b' back and forth" $
      property $ \(x :: Either Integer Double) ->
        fromTerm (toTerm x) `shouldBe` Just x
    it "converts 'NonEmpty a' back and forth" $
      property $ \(h :: Integer) (t :: [Integer]) ->
        let xs = h :| t
         in fromTerm (toTerm xs) `shouldBe` Just xs
  describe "Integer" $
    it "has a Binary instance such that decode is the inverse of encode" $
    property $ \(i :: Integer) ->
      fromTerm (decode (encode (integer i))) `shouldBe` Just i
  describe "The largest smallBigIntegerExt Integer" $ do
    let i = 2 ^ (8 * 255) - 1
    it "has a Binary instance such that decode is the inverse of encode" $
      fromTerm (decode (encode (integer i))) `shouldBe` Just i
    it "is converted to a valid erlang binary" $
      B.unpack (encode (integer i)) `shouldBe`
      [ 110
      , 255
      , 0
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      , 255
      ]
  describe "The smallest largeBigIntegerExt Integer" $
    it "has a Binary instance such that decode is the inverse of encode" $
    let i = 2 ^ (8 * 255)
     in fromTerm (decode (encode (integer i))) `shouldBe` Just i
  describe "Term" $ do
    it "has a Binary instance such that decode is the inverse of encode" $
      property $ \(t :: Term) -> decode (encode t) `shouldBe` t
    it "has an IsString instance that makes atoms" $
      "testatom" `shouldBe` atom "testatom"
    describe "Pattern Synonyms" $ do
      it "Tuple3" $ do
        toTerm (Atom "test-atom", integer 1, integer 2) `shouldBe`
          Tuple3 "test-atom" (integer 1) (integer 2)
        (case toTerm (Atom "test-atom", integer 1, integer 2) of
           Tuple3 "test-atom" _ _ -> True
           _ -> False) `shouldBe`
          True
      it "List4" $ do
        List (fromList [integer 0, integer 1, integer 2]) Nil `shouldBe`
          toTerm (List3 (integer 0) (integer 1) (integer 2))
        (case List (fromList [integer 0, integer 1, integer 2]) Nil of
           List3 {} -> True
           _ -> False) `shouldBe`
          True
      it "Map2" $ do
        Map (fromList [MapEntry "k1" "v1", MapEntry "k2" "v2"]) `shouldBe`
          toTerm (Map2 ("k1" :=> "v1") ("k2" :=> "v2"))
        (case Map (fromList [MapEntry "k1" "v1", MapEntry "k2" "v2"]) of
           Map2 ("k1" :=> "v1") ("k2" :=> "v2") -> True
           _ -> False) `shouldBe`
          True
      it "has an IsList that generates lists" $
        ["a1", "a2"] `shouldBe` toTerm (List (fromList ["a1", "a2"]) Nil)