packages feed

primecount-0.1.0.0: test/Test/Math/NumberTheory/Prime/Count.hs

-- |
-- Copyright   : 2021 Preetham Gujjula
-- License     : BSD-3-Clause
-- Maintainer  : primecount-haskell@mail.preetham.io
-- Stability   : experimental
module Test.Math.NumberTheory.Prime.Count (tests) where

import Control.Exception (SomeException, catch, evaluate)
import Data.Int (Int64)
import Math.NumberTheory.Prime.Count
  ( nthPrime,
    nthPrimeMaxBound,
    primePhi,
    primePi,
    primePiMaxBound,
  )
import System.IO (stderr)
import System.IO.Silently (hSilence)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (testCase, (@?=))

tests :: TestTree
tests =
  testGroup
    "Math.NumberTheory.Prime.Count"
    [primePiTest, nthPrimeTest, primePhiTest]

throwsException :: a -> IO Bool
throwsException thunk =
  (hSilence [stderr] (evaluate thunk) >> pure False)
    `catch` (\(_ :: SomeException) -> pure True)

primePiTest :: TestTree
primePiTest =
  testGroup
    "primePi tests"
    [ testCase "works for negative inputs" $
        primePi (-1 :: Int) @?= 0,
      testCase "works for small inputs" $ do
        primePi (5 :: Int) @?= 3
        primePi (10 :: Int) @?= 4
        primePi (100 :: Int) @?= 25,
      testCase "throws error when input is too large" $
        let tooBig :: Integer
            tooBig = primePiMaxBound + 1
         in throwsException (primePi tooBig) >>= (@?= True)
    ]

nthPrimeTest :: TestTree
nthPrimeTest =
  testGroup
    "nthPrime"
    [ testCase "throws error for non-positive inputs" $ do
        throwsException (nthPrime (0 :: Int)) >>= (@?= True)
        throwsException (nthPrime ((-1) :: Int)) >>= (@?= True),
      testCase "works for small inputs" $ do
        nthPrime (1 :: Int) @?= 2
        nthPrime (5 :: Int) @?= 11
        nthPrime (25 :: Int) @?= 97,
      testCase "throws error when input is too large" $
        let tooBig :: Integer
            tooBig = nthPrimeMaxBound + 1
         in throwsException (nthPrime tooBig) >>= (@?= True)
    ]

primePhiTest :: TestTree
primePhiTest =
  testGroup
    "primePhi"
    [ testCase "is 0 if n is not positive" $ do
        primePhi (0 :: Int) undefined @?= 0
        primePhi ((-1) :: Int) undefined @?= 0,
      testCase "is n if a is not positive" $ do
        primePhi (10 :: Int) 0 @?= 10
        primePhi (10 :: Int) (-1) @?= 10,
      testCase "works for small inputs" $ do
        primePhi (1 :: Int) 2 @?= 1
        primePhi (10 :: Int) 2 @?= 3
        primePhi (10 :: Int) 3 @?= 2
        primePhi (10 :: Int) 4 @?= 1
        primePhi (10 :: Int) 5 @?= 1,
      testCase "throws error if n is too large" $ do
        throwsException (primePhi tooBig 2) >>= (@?= True)
        throwsException (primePhi tooBig 3) >>= (@?= True),
      testCase "works even if a is too large" $
        primePhi 10 tooBig @?= 1
    ]
  where
    tooBig :: Integer
    tooBig = toInteger (maxBound :: Int64) + 1