content: -- |
  -- Module:      Math.NumberTheory.Primes.SieveTests
  -- Copyright:   (c) 2016-2018 Andrew Lelechenko
  -- Licence:     MIT
  -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>
  --
  -- Tests for Math.NumberTheory.Primes.Sieve
  --
  
  {-# LANGUAGE FlexibleContexts    #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  
  {-# OPTIONS_GHC -fno-warn-type-defaults #-}
  
  module Math.NumberTheory.Primes.SieveTests
    ( testSuite
    ) where
  
  import Prelude hiding (words)
  
  import Test.Tasty
  import Test.Tasty.HUnit
  
  import Data.Bits
  import Data.Int
  import Data.Proxy (Proxy(..))
  import Data.Word
  import Numeric.Natural (Natural)
  
  import Math.NumberTheory.Primes (Prime, unPrime, primes, nextPrime, precPrime, UniqueFactorisation)
  import Math.NumberTheory.Primes.Testing
  import Math.NumberTheory.TestUtils
  
  lim1 :: Num a => a
  lim1 = 1000000
  
  lim2 :: Num a => a
  lim2 = 100000
  
  -- | Check that 'primes' matches 'isPrime'.
  primesProperty1 :: forall a. (Integral a, Show a) => Proxy a -> Assertion
  primesProperty1 _ = assertEqual "primes matches isPrime"
    (takeWhile (<= lim1) (map unPrime primes) :: [a])
    (filter (isPrime . toInteger) [1..lim1])
  
  primesProperty2 :: forall a. (Integral a, Bounded a, Show a) => Proxy a -> Assertion
  primesProperty2 _ = assertEqual "primes matches isPrime"
    (map unPrime primes :: [a])
    (filter (isPrime . toInteger) [1..maxBound])
  
  -- | Check that 'primeList' from 'primeSieve' matches truncated 'primes'.
  primeSieveProperty1 :: AnySign Integer -> Bool
  primeSieveProperty1 (AnySign highBound')
    =  [nextPrime 2 .. precPrime highBound]
    == takeWhile (\p -> unPrime p <= highBound) primes
    where
      highBound = max 2 (highBound' `rem` lim1)
  
  -- | Check that 'primeList' from 'psieveList' matches 'primes'.
  psieveListProperty1 :: forall a. (Integral a, Show a, Enum (Prime a), Bits a, UniqueFactorisation a) => Proxy a -> Assertion
  psieveListProperty1 _ = assertEqual "primes == primeList . psieveList"
    (take lim2 primes :: [Prime a])
    (take lim2 [nextPrime 1..])
  
  psieveListProperty2 :: forall a. (Integral a, Bounded a, Show a) => Proxy a -> Assertion
  psieveListProperty2 _ = assertEqual "primes == primeList . psieveList"
    (map unPrime primes :: [a])
    (filter (isPrime . toInteger) [0..maxBound])
  
  testSuite :: TestTree
  testSuite = testGroup "Sieve"
    [ testGroup "primes"
      [ testCase "Int"     (primesProperty1 (Proxy :: Proxy Int))
      , testCase "Word"    (primesProperty1 (Proxy :: Proxy Word))
      , testCase "Integer" (primesProperty1 (Proxy :: Proxy Integer))
      , testCase "Natural" (primesProperty1 (Proxy :: Proxy Natural))
  
      , testCase "Int8"    (primesProperty2 (Proxy :: Proxy Int8))
      , testCase "Int16"   (primesProperty2 (Proxy :: Proxy Int16))
      , testCase "Word8"   (primesProperty2 (Proxy :: Proxy Word8))
      , testCase "Word16"  (primesProperty2 (Proxy :: Proxy Word16))
      ]
    , testSmallAndQuick "primeSieve" primeSieveProperty1
    , testGroup "psieveList"
      [ testCase "Int"     (psieveListProperty1 (Proxy :: Proxy Int))
      , testCase "Word"    (psieveListProperty1 (Proxy :: Proxy Word))
      , testCase "Integer" (psieveListProperty1 (Proxy :: Proxy Integer))
      , testCase "Natural" (psieveListProperty1 (Proxy :: Proxy Natural))
  
      , testCase "Int8"    (psieveListProperty2 (Proxy :: Proxy Int8))
      , testCase "Int16"   (psieveListProperty2 (Proxy :: Proxy Int16))
      , testCase "Word8"   (psieveListProperty2 (Proxy :: Proxy Word8))
      , testCase "Word16"  (psieveListProperty2 (Proxy :: Proxy Word16))
      ]
    ]
  