packages feed

persistent-audit-0.1.0.2: tests/Database/Persist/Audit/GeneratorSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Database.Persist.Audit.GeneratorSpec (main, spec) where

import           Control.Monad.IO.Class   (liftIO)
import           Data.Attoparsec.Text

import           Data.Text                              (Text)

import           Database.Persist.Audit.Generator
import           Database.Persist.Audit.Parser

import           Test.Hspec


{- The following data is used below
User
    ident Text
    password Text Maybe
    UniqueUser ident
    deriving Typeable
    deriving Generic
    deriving Eq
    deriving Show
    deriving Ord

Phone
    number Int
    user UserId

instance ToAudit User where
  type AuditResult User = UserAudit
  toAudit v k auditAction editedBy editedOn = UserAudit (userIdent v)
    (userPassword v)
    k auditAction editedBy editedOn

instance ToAudit Person where
  type AuditResult Person = PersonAudit
  toAudit v k auditAction editedBy editedOn = PersonAudit (personName v)
                                                          (personAge v)
                                                          k auditAction editedBy editedOn

-}

emptyModel :: Text
emptyModel = "Test json sql=testing\n"

emptyAuditModel :: Text
emptyAuditModel = "TestAudit json sql=testing\n  originalId TestId noreference\n  auditAction AuditAction\n  editedBy Text\n  editedOn UTCTime\n\n"

userModel :: Text
userModel = "User\n  ident Text\n  password Text Maybe\n UniqueUser ident\n  deriving Typeable\n deriving Generic\n  deriving Eq\n  deriving Show\n  deriving Ord"

userAuditModel :: Text
userAuditModel = "UserAudit\n  ident Text\n  password Text Maybe\n  deriving Typeable\n  deriving Generic\n  deriving Eq\n  deriving Show\n  deriving Ord\n  originalId UserId noreference\n  auditAction AuditAction\n  editedBy Text\n  editedOn UTCTime\n\n"

userToAuditInstance :: Text
userToAuditInstance = "instance ToAudit User where\n  type AuditResult User = UserAudit\n  toAudit v k auditAction editedBy editedOn = UserAudit\n    (userIdent v)\n    (userPassword v)\n    (k) auditAction editedBy editedOn\n\n"

userToAuditInstanceInt64 :: Text
userToAuditInstanceInt64 = "instance ToAudit User where\n  type AuditResult User = UserAudit\n  toAudit v k auditAction editedBy editedOn = UserAudit\n    (userIdent v)\n    (userPassword v)\n    (fromSqlKey k) auditAction editedBy editedOn\n\n"



phoneModel :: Text
phoneModel = "Phone\n  number Int\n  user UserId"

phoneAuditModel :: Text
phoneAuditModel = "PhoneAudit\n  number Int\n  user UserId noreference\n  originalId PhoneId noreference\n  auditAction AuditAction\n  editedBy Text\n  editedOn UTCTime\n\n"

phoneToAuditInstanceByteString :: Text
phoneToAuditInstanceByteString = "instance ToAudit Phone where\n  type AuditResult Phone = PhoneAudit\n  toAudit v k auditAction editedBy editedOn = PhoneAudit\n    (phoneNumber v)\n    (mongoKeyToByteString $ phoneUser v)\n    (mongoKeyToByteString k) auditAction editedBy editedOn\n\n"



phoneWithMaybeModel :: Text
phoneWithMaybeModel = "Phone\n  number Int\n  user UserId Maybe"

phoneWithMaybeToAuditInstanceByteString :: Text
phoneWithMaybeToAuditInstanceByteString = "instance ToAudit Phone where\n  type AuditResult Phone = PhoneAudit\n  toAudit v k auditAction editedBy editedOn = PhoneAudit\n    (phoneNumber v)\n    (mongoKeyToByteString <$> phoneUser v)\n    (mongoKeyToByteString k) auditAction editedBy editedOn\n\n"

-- userToAuditInstanceInt64 :: Text
-- userToAuditInstanceInt64 = "instance ToAudit User where\n  type AuditResult User = UserAudit\n  toAudit v k auditAction editedBy editedOn = UserAudit\n    (userIdent v)\n    (userPassword v)\n    (fromSqlKey k) auditAction editedBy editedOn\n\n"

phoneAuditByteStringModel :: Text
phoneAuditByteStringModel = "PhoneAudit\n  number Int\n  user ByteString -- UserId\n  originalId ByteString -- PhoneId\n  auditAction AuditAction\n  editedBy Text\n  editedOn UTCTime\n\n"

phoneAuditInt64Model :: Text
phoneAuditInt64Model = "PhoneAudit\n  number Int\n  user Int64 -- UserId\n  originalId Int64 -- PhoneId\n  auditAction AuditAction\n  editedBy Text\n  editedOn UTCTime\n\n"


addressModel :: Text
addressModel = "Address\n  address Text\n  phoneNumbers [Phone]"

addressAuditModel :: Text
addressAuditModel = "AddressAudit\n  address Text\n  phoneNumbers [Phone]\n  originalId AddressId noreference\n  auditAction AuditAction\n  editedBy Text\n  editedOn UTCTime\n\n"


spec :: Spec
spec = do
  describe "Audit Model generator" $ do
    it "should generate an audit model from a model" $ do
      let parseResult = parseOnly parseEntities emptyModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          let generatedAuditModels = generateAuditModels defaultSettings es
          generatedAuditModels  `shouldBe` emptyAuditModel

    it "should generate an audit model for another model" $ do
      let parseResult = parseOnly parseEntities userModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          let generatedAuditModels = generateAuditModels defaultSettings es
          generatedAuditModels `shouldBe` userAuditModel

    it "should add noreference tag to foreign refereces" $ do
      let parseResult = parseOnly parseEntities phoneModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          let generatedAuditModels = generateAuditModels defaultSettings es
          generatedAuditModels `shouldBe` phoneAuditModel

    it "should generate fields that are list types" $ do
      let parseResult = parseOnly parseEntities addressModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          liftIO $ print es
          let generatedAuditModels = generateAuditModels defaultSettings es
          generatedAuditModels `shouldBe` addressAuditModel

    it "should generate foreign references as ByteString if the MongoKeyInSQL setting is used" $ do
      let parseResult = parseOnly parseEntities phoneModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          let generatedAuditModels = generateAuditModels (defaultSettings {foreignKeyType = MongoKeyInSQL}) es
          generatedAuditModels `shouldBe` phoneAuditByteStringModel

    it "should generate foreign references as Int64 if the SQLKeyInMongo setting is used" $ do
      let parseResult = parseOnly parseEntities phoneModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          let generatedAuditModels = generateAuditModels (defaultSettings {foreignKeyType = SQLKeyInMongo}) es
          generatedAuditModels `shouldBe` phoneAuditInt64Model



  describe "ToAudit instance generator" $ do
    it "should generate an instance from a model" $ do
      let parseResult = parseOnly parseEntities userModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          let generatedAuditInstances = generateToAuditInstances defaultSettings es
          generatedAuditInstances `shouldBe` userToAuditInstance

    it "should generate an instance from a model foreign references as ByteString when the MongoKeyInSQL setting is used" $ do
      let parseResult = parseOnly parseEntities phoneModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          let generatedAuditInstances = generateToAuditInstances (defaultSettings {foreignKeyType = MongoKeyInSQL}) es
          generatedAuditInstances `shouldBe` phoneToAuditInstanceByteString

    it "should generate an instance from a model maybe foreign references as fmap ByteString when the MongoKeyInSQL setting is used" $ do
      let parseResult = parseOnly parseEntities phoneWithMaybeModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          let generatedAuditInstances = generateToAuditInstances (defaultSettings {foreignKeyType = MongoKeyInSQL}) es
          generatedAuditInstances `shouldBe` phoneWithMaybeToAuditInstanceByteString

    it "should generate an instance from a model with foreign references as Int64 when the SQLKeyInMongo setting is used" $ do
      let parseResult = parseOnly parseEntities userModel
      case parseResult of
        Left _ -> False `shouldBe` True
        Right es -> do
          let generatedAuditInstances = generateToAuditInstances (defaultSettings {foreignKeyType = SQLKeyInMongo}) es
          liftIO $ print parseResult
          generatedAuditInstances `shouldBe` userToAuditInstanceInt64


main :: IO ()
main = hspec spec