{-# 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 }