packages feed

roc-id-0.1.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
import Test.QuickCheck
import Test.QuickCheck.Arbitrary.Generic

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

instance Arbitrary Digit where
  arbitrary = genericArbitrary
  shrink = genericShrink

instance Arbitrary Gender where
  arbitrary = genericArbitrary
  shrink = genericShrink

instance Arbitrary Identity where
  arbitrary = genericArbitrary
  shrink = genericShrink

instance Arbitrary Location where
  arbitrary = genericArbitrary
  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