packages feed

roc-id-0.2.0.0: test/Spec.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}

{-# LANGUAGE ScopedTypeVariables #-}

module Main where

import ROC.ID
import ROC.ID.Digit
import ROC.ID.Gender
import ROC.ID.Location
import ROC.ID.Serial

import Data.Char
    ( intToDigit )
import Test.Hspec
    ( describe, hspec, it, shouldBe )
import Test.QuickCheck
    ( Arbitrary (..)
    , NonEmptyList (..)
    , applyArbitrary3
    , arbitraryBoundedEnum
    , genericShrink
    , property
    )

import qualified Data.Text as T
import qualified Data.Vector.Sized as V

instance Arbitrary Digit where
  arbitrary = arbitraryBoundedEnum
  shrink = genericShrink

instance Arbitrary Gender where
  arbitrary = arbitraryBoundedEnum
  shrink = genericShrink

instance Arbitrary Identity where
  arbitrary = applyArbitrary3 Identity
  shrink = genericShrink

instance Arbitrary Location where
  arbitrary = arbitraryBoundedEnum
  shrink = genericShrink

instance Arbitrary Serial where
  arbitrary = Serial . V.fromTuple <$> arbitrary
  shrink (Serial v) = Serial <$> traverse shrink v

main :: IO ()
main = hspec $

  describe "parseIdentity" $ do

    it "successfully parses valid identification numbers" $
      property $ \(i :: Identity) ->
        parseIdentity (T.pack $ show i) `shouldBe` Right i

    it "does not parse identification numbers that are too short" $
      property $ \(i :: Identity) n -> do
        let newLength = n `mod` 10
        let invalidIdentity = T.pack $ take newLength $ show i
        parseIdentity invalidIdentity `shouldBe` Left InvalidLength

    it "does not parse identification numbers that are too long" $
      property $ \(i :: Identity) (NonEmpty s) -> do
        let invalidIdentity = T.pack $ show i <> s
        parseIdentity invalidIdentity `shouldBe` Left InvalidLength

    it "does not parse identification numbers with invalid gender codes" $
      property $ \(i :: Identity) (c :: Int) -> do
        let invalidGenderCode = intToDigit $ ((c `mod` 8) + 3) `mod` 10
        let invalidIdentity = T.pack $
              take 1 (show i) <> [invalidGenderCode] <> drop 2 (show i)
        parseIdentity invalidIdentity `shouldBe` Left InvalidGender

    it "does not parse identification numbers with invalid location codes" $
      property $ \(i :: Identity) (c :: Int) -> do
        let invalidLocationCode = intToDigit $ c `mod` 10
        let invalidIdentity = T.pack $ invalidLocationCode : drop 1 (show i)
        parseIdentity invalidIdentity `shouldBe` Left InvalidLocation

    it "does not parse identification numbers with invalid checksums" $
      property $ \(i :: Identity) (c :: Int) -> do
        let invalidChecksum = intToDigit $
              ((c `mod` 9) + fromEnum (identityChecksum i) + 1) `mod` 10
        let invalidIdentity = T.pack $ take 9 (show i) <> [invalidChecksum]
        parseIdentity invalidIdentity `shouldBe` Left InvalidChecksum