packages feed

mmzk-env-0.2.0.0: test/RecordParserSpec.hs

module RecordParserSpec ( spec ) where

import Data.Coerce ( coerce )
import Data.Either ( isLeft )
import Data.Env.EnumParser
import Data.Env.RecordParser
import Data.Env.TypeParser
import Data.Map qualified as M
import GHC.Generics
import Test.Hspec

data Gender = Male | Female
  deriving (Show, Eq, Enum, Bounded)
  deriving TypeParser via (EnumParser Gender)

newtype Age = Age Int
  deriving (Show, Eq)

instance TypeParser Age where
  parseType :: String -> Either String Age
  parseType str = case parseType @Int str of
    Right a -> if a >= 0 && a <= 120 then Right $ Age a else Left "Age is not within range!"
    left    -> coerce left

data Person = Person
  { name   :: String
  , age    :: Age
  , gender :: Maybe Gender
  } deriving (Show, Eq, Generic)

spec :: Spec
spec = describe "parseRecord" do
  it "parses a valid record" do
    let env = M.fromList [("name", "Alice"), ("age", "30")]
    parseRecord @Person env `shouldBe` Right (Person "Alice" (Age 30) Nothing)
  it "allows extra fields" do
    let env = M.fromList [("name", "Alice"), ("age", "30"), ("extra", "value")]
    parseRecord @Person env `shouldBe` Right (Person "Alice" (Age 30) Nothing)
  it "parses optional fields" do
    let env = M.fromList [("name", "Alice"), ("age", "30"), ("gender", "Female")]
    parseRecord @Person env `shouldBe` Right (Person "Alice" (Age 30) (Just Female))
  it "fails to parse an invalid record" do
    let env = M.fromList [("name", "Alice"), ("age", "30"), ("gender", "Other")]
    parseRecord @Person env `shouldSatisfy` isLeft
  it "fails to parse an invalid age" do
    let env = M.fromList [("name", "Alice"), ("age", "150"), ("gender", "Female")]
    parseRecord @Person env `shouldSatisfy` isLeft
  it "fails to parse a missing field" do
    let env = M.fromList [("name", "Alice")]
    parseRecord @Person env `shouldSatisfy` isLeft