packages feed

eventium-core-0.2.1: tests/Eventium/CodecSpec.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TemplateHaskell #-}

module Eventium.CodecSpec (spec) where

import Data.Dynamic
import Data.Typeable (typeOf)
import Eventium.Codec
import Eventium.TH.SumTypeCodec
import Eventium.TypeEmbedding
import GHC.Generics
import Test.Hspec

data EventA = EventA deriving (Show, Eq)

data EventB = EventB deriving (Show, Eq)

data EventC = EventC deriving (Show, Eq)

data AllEvents
  = AllEventsEventA EventA
  | AllEventsEventB EventB
  | AllEventsEventC EventC
  deriving (Show, Eq, Generic)

instance EventSumType AllEvents

data MyEvents
  = MyEventsEventA EventA
  | MyEventsEventB EventB
  deriving (Show, Eq, Generic)

instance EventSumType MyEvents

mkSumTypeCodec "myEventsCodec" ''MyEvents ''AllEvents

-- Separate subset type for TypeEmbedding tests to avoid TH name clashes
-- (mkSumTypeCodec and mkSumTypeEmbedding generate the same helper
-- function names for the same type pair)
data SubsetEvents
  = SubsetEventsEventA EventA
  | SubsetEventsEventB EventB
  deriving (Show, Eq)

mkSumTypeEmbedding "subsetEventsEmbedding" ''SubsetEvents ''AllEvents

spec :: Spec
spec = do
  describe "EventSumType" $ do
    it "can serialize events without the constructor" $ do
      dynTypeRep (eventToDyn $ MyEventsEventA EventA) `shouldBe` typeOf EventA
      dynTypeRep (eventToDyn $ MyEventsEventA EventA) `shouldBe` dynTypeRep (eventToDyn $ AllEventsEventA EventA)

    it "can deserialize events with the constructor" $ do
      eventFromDyn (toDyn EventA) `shouldBe` Just (MyEventsEventA EventA)
      eventFromDyn (toDyn EventB) `shouldBe` Just (AllEventsEventB EventB)

      eventFromDyn (eventToDyn $ MyEventsEventA EventA) `shouldBe` Just (AllEventsEventA EventA)
      eventFromDyn (eventToDyn $ AllEventsEventB EventB) `shouldBe` Just (MyEventsEventB EventB)

  describe "mkSumTypeCodec" $ do
    it "can serialize events" $ do
      myEventsCodec.encode (MyEventsEventA EventA) `shouldBe` AllEventsEventA EventA
      myEventsCodec.encode (MyEventsEventB EventB) `shouldBe` AllEventsEventB EventB

    it "can deserialize events" $ do
      myEventsCodec.decode (AllEventsEventA EventA) `shouldBe` Just (MyEventsEventA EventA)
      myEventsCodec.decode (AllEventsEventB EventB) `shouldBe` Just (MyEventsEventB EventB)
      myEventsCodec.decode (AllEventsEventC EventC) `shouldBe` Nothing

  describe "mkSumTypeEmbedding" $ do
    it "can embed events" $ do
      subsetEventsEmbedding.embed (SubsetEventsEventA EventA) `shouldBe` AllEventsEventA EventA
      subsetEventsEmbedding.embed (SubsetEventsEventB EventB) `shouldBe` AllEventsEventB EventB

    it "can extract matching events" $ do
      subsetEventsEmbedding.extract (AllEventsEventA EventA) `shouldBe` Just (SubsetEventsEventA EventA)
      subsetEventsEmbedding.extract (AllEventsEventB EventB) `shouldBe` Just (SubsetEventsEventB EventB)

    it "returns Nothing for non-matching events" $ do
      subsetEventsEmbedding.extract (AllEventsEventC EventC) `shouldBe` Nothing