packages feed

crem-0.1.0.0: spec/Crem/RiskManagerSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Crem.RiskManagerSpec where

import Crem.Example.RiskManager.Application
import Crem.Example.RiskManager.Domain
import Crem.Example.RiskManager.Projection (ReceivedData (..))
import Crem.StateMachineSpec (shouldOutput)
import "crem" Crem.StateMachine (run, runMultiple)
import "hspec" Test.Hspec (Spec, describe, it)

myUserData :: UserData
myUserData =
  UserData
    { name = "Marco"
    , surname = "Perone"
    , taxCode = "ABCDEF12T34J987H"
    }

notMyUserData :: UserData
notMyUserData =
  UserData
    { name = "Gigi"
    , surname = "Zucon"
    , taxCode = "ABCDEF12T34J987H"
    }

loanDetails :: LoanDetails
loanDetails =
  LoanDetails
    { amount = EuroCents 10000
    , instalments = InstalmentsNumber 10
    }

otherLoanDetails :: LoanDetails
otherLoanDetails =
  LoanDetails
    { amount = EuroCents 20000
    , instalments = InstalmentsNumber 5
    }

creditBureauData :: CreditBureauData
creditBureauData =
  CreditBureauData
    { missedPaymentDeadlines = MissedPaymentDeadlines 2
    , arrears = EuroCents 100000
    }

spec :: Spec
spec =
  describe "RiskManager" $ do
    describe "aggregate" $ do
      it "emits a registered event when a registration command is received" $ do
        run aggregate (RegisterUserData myUserData)
          `shouldOutput` [UserDataRegistered myUserData]

      it "emits two registered events when two registration commands are received" $ do
        runMultiple aggregate [RegisterUserData myUserData, RegisterUserData notMyUserData]
          `shouldOutput` [UserDataRegistered myUserData, UserDataRegistered notMyUserData]

      it "does not emit anything when a loan details command is received" $ do
        run aggregate (ProvideLoanDetails loanDetails)
          `shouldOutput` []

      it "emits a loan details event when a registration command and a loan detail command are received" $ do
        runMultiple aggregate [RegisterUserData myUserData, ProvideLoanDetails loanDetails]
          `shouldOutput` [UserDataRegistered myUserData, LoanDetailsProvided loanDetails]

    describe "policy" $ do
      it "emits a credit bureau command when a user registration event is received for a user named Marco" $ do
        run policy (UserDataRegistered myUserData)
          `shouldOutput` [ProvideCreditBureauData creditBureauData]

      it "emits no command when a user registration event is received for a user not named Marco" $ do
        run policy (UserDataRegistered notMyUserData)
          `shouldOutput` []

      it "emits two credit bureau command when two user registration events are received" $ do
        runMultiple policy [UserDataRegistered myUserData, UserDataRegistered myUserData]
          `shouldOutput` [ ProvideCreditBureauData creditBureauData
                         , ProvideCreditBureauData creditBureauData
                         ]

      it "emits one credit bureau command when two user registration events are received but only one for a user named Marco" $ do
        runMultiple policy [UserDataRegistered myUserData, UserDataRegistered notMyUserData]
          `shouldOutput` [ProvideCreditBureauData creditBureauData]

        runMultiple policy [UserDataRegistered notMyUserData, UserDataRegistered myUserData]
          `shouldOutput` [ProvideCreditBureauData creditBureauData]

      it "emits no command when two user registration events are received for a user not named Marco" $ do
        runMultiple policy [UserDataRegistered notMyUserData, UserDataRegistered notMyUserData]
          `shouldOutput` []

      it "emits no command when a loan details event is registered" $ do
        run policy (LoanDetailsProvided loanDetails)
          `shouldOutput` []

      it "emits no command when a credit bureau data is registered" $ do
        run policy (CreditBureauDataReceived creditBureauData)
          `shouldOutput` []

    describe "writeModel" $ do
      it "emits a registered event when a registration command is received" $ do
        run writeModel (RegisterUserData myUserData)
          `shouldOutput` [ UserDataRegistered myUserData
                         , CreditBureauDataReceived creditBureauData
                         ]

      it "emits two registered events when two registration command are received" $ do
        runMultiple writeModel [RegisterUserData myUserData, RegisterUserData myUserData]
          `shouldOutput` [ UserDataRegistered myUserData
                         , CreditBureauDataReceived creditBureauData
                         , UserDataRegistered myUserData
                         , CreditBureauDataReceived creditBureauData
                         ]

    describe "riskProjection" $ do
      it "registers one user when a registration event is received" $ do
        run projection (UserDataRegistered myUserData)
          `shouldOutput` ReceivedData
            { receivedUserData = Just myUserData
            , receivedLoanDetails = Nothing
            , receivedCreditBureauData = Nothing
            }

      it "updates the user data when two registration events are received" $ do
        runMultiple projection [UserDataRegistered myUserData, UserDataRegistered notMyUserData]
          `shouldOutput` ReceivedData
            { receivedUserData = Just notMyUserData
            , receivedLoanDetails = Nothing
            , receivedCreditBureauData = Nothing
            }

    describe "readModel" $ do
      it "registers one user when a registration event is received" $ do
        run readModel (UserDataRegistered myUserData)
          `shouldOutput` [ ReceivedData
                            { receivedUserData = Just myUserData
                            , receivedLoanDetails = Nothing
                            , receivedCreditBureauData = Nothing
                            }
                         ]

      it "registers two users when two registration events are received" $ do
        runMultiple readModel [UserDataRegistered myUserData, UserDataRegistered notMyUserData]
          `shouldOutput` [ ReceivedData
                            { receivedUserData = Just myUserData
                            , receivedLoanDetails = Nothing
                            , receivedCreditBureauData = Nothing
                            }
                         , ReceivedData
                            { receivedUserData = Just notMyUserData
                            , receivedLoanDetails = Nothing
                            , receivedCreditBureauData = Nothing
                            }
                         ]

    describe "whole" $ do
      it "registers one user when a registration command is received" $ do
        run whole (RegisterUserData myUserData)
          `shouldOutput` [ ReceivedData
                            { receivedUserData = Just myUserData
                            , receivedLoanDetails = Nothing
                            , receivedCreditBureauData = Nothing
                            }
                         , ReceivedData
                            { receivedUserData = Just myUserData
                            , receivedLoanDetails = Nothing
                            , receivedCreditBureauData = Just creditBureauData
                            }
                         ]

      it "registers two users when two registration commands are received" $ do
        runMultiple whole [RegisterUserData myUserData, RegisterUserData notMyUserData]
          `shouldOutput` [ ReceivedData
                            { receivedUserData = Just myUserData
                            , receivedLoanDetails = Nothing
                            , receivedCreditBureauData = Nothing
                            }
                         , ReceivedData
                            { receivedUserData = Just myUserData
                            , receivedLoanDetails = Nothing
                            , receivedCreditBureauData = Just creditBureauData
                            }
                         , ReceivedData
                            { receivedUserData = Just notMyUserData
                            , receivedLoanDetails = Nothing
                            , receivedCreditBureauData = Just creditBureauData
                            }
                         ]

    describe "riskApplication" $ do
      it "registers one user" $ do
        run riskApplication (RegisterUserData myUserData)
          `shouldOutput` ReceivedData
            { receivedUserData = Just myUserData
            , receivedLoanDetails = Nothing
            , receivedCreditBureauData = Just creditBureauData
            }

      it "updates the user data" $ do
        runMultiple riskApplication [RegisterUserData notMyUserData, RegisterUserData myUserData]
          `shouldOutput` ReceivedData
            { receivedUserData = Just myUserData
            , receivedLoanDetails = Nothing
            , receivedCreditBureauData = Just creditBureauData
            }

      it "collects the user data and the loan details" $ do
        runMultiple riskApplication [RegisterUserData myUserData, ProvideLoanDetails loanDetails]
          `shouldOutput` ReceivedData
            { receivedUserData = Just myUserData
            , receivedLoanDetails = Just loanDetails
            , receivedCreditBureauData = Just creditBureauData
            }

      it "updates the loan details" $ do
        runMultiple
          riskApplication
          [ RegisterUserData myUserData
          , ProvideLoanDetails loanDetails
          , ProvideLoanDetails otherLoanDetails
          ]
          `shouldOutput` ReceivedData
            { receivedUserData = Just myUserData
            , receivedLoanDetails = Just otherLoanDetails
            , receivedCreditBureauData = Just creditBureauData
            }