packages feed

sdp-quickcheck-0.2: src/Test/SDP/Gen.hs

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}

{- |
    Module      :  Test.SDP.Gen
    Copyright   :  (c) Andrey Mulik 2019
    License     :  BSD-style
    Maintainer  :  work.a.mulik@gmail.com
    Portability :  non-portable (requires non-portable modules)
    
    @Test.SDP.Gen@ provides newtypes for QuickCheck.
-}
module Test.SDP.Gen
(
  -- * Common newtypes for QuickCheck
  Short (..), Medium (..), Long (..),
  
  -- ** Related functions
  linearLargeA, linearA, orderA
)
where

import Prelude ()
import SDP.SafePrelude
import SDP.Linear

import Test.QuickCheck

import Data.Coerce

default ()

--------------------------------------------------------------------------------

{- |
  Short is newtype of short data structures [0, 100) in QuickCheck properties.
  
  Short is the equivalent of the standard Arbitrary definition:
  @arbitrary = fromList \<$\> arbitrary@.
-}
newtype Short a = Short a deriving ( Eq, Ord, Read, Show )

{- |
  Medium is newtype of medium data structures in QuickCheck properties. The
  Arbitrary Medium instance must create a random-sized structure from the range
  [100, 1024).
  
  Medium is useful in testing as a compromise between speed and reliability:
  structures are too short for stress tests, but still human readable and enough
  fast for auto-testing.
-}
newtype Medium a = Medium a deriving ( Eq, Ord, Read, Show )

{- |
  Long is newtype of large data structures (>= 1024) in QuickCheck properties.
  Since Large can generate really huge numbers, the maximum length is limited by
  16384 - [1024, 16384).
  
  Long is primarily intended for benchmarks, although a large range of lengths
  makes them not very convenient for a pure comparison of several algorithms
  (but for this can be used vector[Of] and generate). Long works well with
  Unrolled and ByteList, since only the shortest of the allowed structures may
  fit in one standard chunk (1024 elements).
-}
newtype Long a = Long a deriving ( Eq, Ord, Read, Show )

--------------------------------------------------------------------------------

instance (Linear l e, Arbitrary e) => Arbitrary (Short l)
  where
    arbitrary = arbitrary >>= \ n -> (Short . fromList) <$> vector n

instance (Linear l e, Arbitrary e) => Arbitrary (Medium l)
  where
    arbitrary = arbitrary >>= \ (Large n) -> (Medium . fromList) <$> vector (100 + n `mod` 914)

instance (Linear l e, Arbitrary e) => Arbitrary (Long l)
  where
    arbitrary = arbitrary >>= \ (Large n) -> (Long . fromList) <$> vector (1024 + n `mod` 15360)

--------------------------------------------------------------------------------

-- | 'linearA' is overloaded 'vector'.
linearA :: (Linear l e, Arbitrary e) => Int -> Gen l
linearA =  fmap fromList . vector

-- | 'linearLargeA' is version of 'linearA', which generates 'Large' 'Int's.
linearLargeA :: (Linear l Int) => Int -> Gen l
linearLargeA =
  let fromLarge = coerce :: [Large Int] -> [Int]
  in  fmap (fromList . fromLarge) . vector

{- |
  'orderA' returns a simple comparator that can be used to test the behavior of
  higher-order functions (for example, when comparing the results of @takeWhile@
  for different structures).
-}
orderA :: (Ord e) => Gen (e -> e -> Bool)
orderA =  elements [(>), (<), (>=), (<=), (==), (/=)]