packages feed

dojang-0.1.0: test/Dojang/Types/MonikerNameSpec.hs

{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}

module Dojang.Types.MonikerNameSpec (spec) where

import Dojang.Types.Gen
  ( emptyMonikerNameText
  , invalidMonikerNameText
  , monikerName
  , monikerNameError
  , monikerNameText
  , monikerNameTextHavingInvalidCharacterWithIndex
  , monikerNameTextStartingWithNonLetter
  , monikerNameWithCIText
  )
import Dojang.Types.MonikerName
  ( MonikerNameError (Empty, HavingInvalidCharacter, StartingWithNonLetter)
  , parseMonikerName
  )

import Data.CaseInsensitive (foldCase, mk)
import Data.Either (isLeft)
import Data.Hashable (Hashable (hashWithSalt))
import Test.Hspec (Spec, describe, specify)
import Test.Hspec.Expectations.Pretty (shouldBe)
import Test.Hspec.Hedgehog
  ( assert
  , forAll
  , hedgehog
  , (===)
  )


spec :: Spec
spec = do
  describe "parseMonikerName" $ do
    specify "examples" $ do
      let Right a = parseMonikerName "foo-bar"
      a.name `shouldBe` "foo-bar"
      let Right b = parseMonikerName "甲乙_丙丁"
      b.name `shouldBe` "甲乙_丙丁"
      parseMonikerName "" `shouldBe` Left Empty
      parseMonikerName "1" `shouldBe` Left StartingWithNonLetter
      parseMonikerName "*" `shouldBe` Left StartingWithNonLetter
      parseMonikerName "$foo" `shouldBe` Left StartingWithNonLetter
      parseMonikerName "foo\tbar" `shouldBe` Left (HavingInvalidCharacter 3)

    specify "properties" $ hedgehog $ do
      forAll monikerNameText >>= \name ->
        let Right parsed = parseMonikerName name
        in parsed.name === mk name
      forAll invalidMonikerNameText >>= \name ->
        assert $ isLeft $ parseMonikerName name
      forAll emptyMonikerNameText >>= \name ->
        parseMonikerName name === Left Empty
      forAll monikerNameTextStartingWithNonLetter >>= \name ->
        parseMonikerName name === Left StartingWithNonLetter
      forAll monikerNameTextHavingInvalidCharacterWithIndex >>= \(name, idx) ->
        parseMonikerName name === Left (HavingInvalidCharacter idx)

  describe "MonikerName" $ do
    specify "Eq" $ hedgehog $ do
      name <- forAll monikerName
      name' <- forAll monikerName
      (name == name') === (foldCase name.name == foldCase name'.name)
      (name /= name') === (foldCase name.name /= foldCase name'.name)

    specify "Ord" $ hedgehog $ do
      name <- forAll monikerName
      name' <- forAll monikerName
      let foldedName = foldCase name.name
      let foldedName' = foldCase name'.name
      name `compare` name' === foldedName `compare` foldedName'
      (name < name') === (foldedName < foldedName')
      (name <= name') === (foldedName <= foldedName')
      (name > name') === (foldedName > foldedName')
      (name >= name') === (foldedName >= foldedName')
      (min name name').name === min foldedName foldedName'
      (max name name').name === max foldedName foldedName'

    specify "Hashable" $ hedgehog $ do
      (name, nameText) <- forAll monikerNameWithCIText
      hashWithSalt 0 name === hashWithSalt 0 (foldCase nameText)

    specify "HasField \"name\"" $ hedgehog $ do
      (name, nameText) <- forAll monikerNameWithCIText
      name.name === nameText

    specify "Show" $ hedgehog $ do
      (name, nameText) <- forAll monikerNameWithCIText
      show name === "MonikerName " ++ show nameText
      shows name "" === "MonikerName " ++ shows nameText ""
      showList [name] "" === "[MonikerName " ++ show nameText ++ "]"

  describe "MonikerNameError" $ do
    specify "Eq" $ hedgehog $ do
      e <- forAll monikerNameError
      e' <- forAll monikerNameError
      (e == e') === (show e == show e')
      (e /= e') === (show e /= show e')

    specify "Show" $ hedgehog $ do
      e <- forAll monikerNameError
      read (show e) === e
      read (shows e "") === e
      read (showList [e] "") === [e]