packages feed

fastmemo-0.1.0.0: test/Spec.hs

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -Wno-orphans #-}

import Control.Exception (ErrorCall (..), catch, evaluate)
import Data.Function.FastMemo
import Data.Functor (($>))
import Data.Int (Int16, Int32, Int64, Int8)
import Data.Proxy (Proxy (Proxy))
import Data.Ratio (Ratio)
import Data.Word (Word16, Word32, Word64, Word8)
import Examples (Color (Color), Tree (Leaf, Node), fibonacci)
import Numeric.Natural (Natural)
import Test.QuickCheck

prop_memoizesFib :: Property
prop_memoizesFib = forAllShrink (sized $ \size -> choose (0, size)) shrink $
  \i -> fibonacci (fromIntegral i) === allFibs !! i

allFibs :: [Natural]
allFibs = 0 : 1 : zipWith (+) allFibs (tail allFibs)

instance Arbitrary Natural where
  arbitrary = fromInteger . getNonNegative <$> arbitrary
  shrink = map (fromInteger . getNonNegative) . shrink . NonNegative . toInteger

instance Arbitrary (Proxy a) where
  arbitrary = return Proxy

prop_memoizesId :: (Eq a, Show a, Memoizable a) => a -> Property
prop_memoizesId = let m = memoize id in \x -> m x === x

prop_memoizeFixedLenFixesLen :: (Eq a, Show a, Memoizable a) => Int -> [a] -> Property
prop_memoizeFixedLenFixesLen n =
  let m = memoizeFixedLen n id
   in \xs ->
        if length xs < n
          then expectErrorCall (Just "List too short") (m xs)
          else m xs === take n xs

expectErrorCall :: Maybe String -> a -> Property
expectErrorCall expected x =
  ioProperty $
    (evaluate x $> property False)
      `catch` \(ErrorCall msg) -> return $ maybe (property True) (msg ===) expected

prop_boolMemoizesId :: Bool -> Property
prop_boolMemoizesId = prop_memoizesId

prop_charMemoizesId :: Char -> Property
prop_charMemoizesId = prop_memoizesId

prop_stringMemoizesId :: String -> Property
prop_stringMemoizesId = prop_memoizesId

prop_integerMemoizesId :: Integer -> Property
prop_integerMemoizesId = prop_memoizesId

prop_bigIntegerMemoizesId :: Property
prop_bigIntegerMemoizesId =
  forAllShrink
    (genBigBound >>= \b -> choose (- b, b))
    shrink
    prop_memoizesId

genBigBound :: Gen Integer
genBigBound = sized $ \n -> return $ 256 ^ n

prop_naturalMemoizesId :: Natural -> Property
prop_naturalMemoizesId = prop_memoizesId

prop_bigNaturalMemoizesId :: Property
prop_bigNaturalMemoizesId =
  forAllShrink
    (genBigBound >>= \b -> (fromInteger :: Integer -> Natural) <$> choose (0, b))
    shrink
    prop_memoizesId

prop_unitMemoizesId :: () -> Property
prop_unitMemoizesId = prop_memoizesId

prop_eitherMemoizesId ::
  (Eq a, Show a, Memoizable a, Eq b, Show b, Memoizable b) => Either a b -> Property
prop_eitherMemoizesId = prop_memoizesId

prop_pairMemoizesId :: (Eq a, Show a, Memoizable a, Eq b, Show b, Memoizable b) => (a, b) -> Property
prop_pairMemoizesId = prop_memoizesId

prop_tripletMemoizesId ::
  (Eq a, Show a, Memoizable a, Eq b, Show b, Memoizable b, Eq c, Show c, Memoizable c) =>
  (a, b, c) ->
  Property
prop_tripletMemoizesId = prop_memoizesId

prop_maybeMemoizesId :: (Eq a, Show a, Memoizable a) => Maybe a -> Property
prop_maybeMemoizesId = prop_memoizesId

prop_listMemoizesId :: (Eq a, Show a, Memoizable a) => [a] -> Property
prop_listMemoizesId = prop_memoizesId

prop_intMemoizesId :: Int -> Property
prop_intMemoizesId = prop_memoizesId

prop_largeIntMemoizesId :: Large Int -> Property
prop_largeIntMemoizesId (Large i) = prop_memoizesId i

prop_int8MemoizesId :: Int8 -> Property
prop_int8MemoizesId = prop_memoizesId

prop_int16MemoizesId :: Int16 -> Property
prop_int16MemoizesId = prop_memoizesId

prop_int32MemoizesId :: Int32 -> Property
prop_int32MemoizesId = prop_memoizesId

prop_int64MemoizesId :: Int64 -> Property
prop_int64MemoizesId = prop_memoizesId

prop_wordMemoizesId :: Word -> Property
prop_wordMemoizesId = prop_memoizesId

prop_largeWordMemoizesId :: Large Word -> Property
prop_largeWordMemoizesId (Large w) = prop_memoizesId w

prop_word8MemoizesId :: Word8 -> Property
prop_word8MemoizesId = prop_memoizesId

prop_word16MemoizesId :: Word16 -> Property
prop_word16MemoizesId = prop_memoizesId

prop_word32MemoizesId :: Word32 -> Property
prop_word32MemoizesId = prop_memoizesId

prop_word64MemoizesId :: Word64 -> Property
prop_word64MemoizesId = prop_memoizesId

prop_ratioMemoizesId :: (Integral a, Memoizable a, Show a) => Ratio a -> Property
prop_ratioMemoizesId = prop_memoizesId

deriving instance Eq Color

deriving instance Show Color

instance Arbitrary Color where
  arbitrary = Color <$> arbitrary <*> arbitrary <*> arbitrary
  shrink = genericShrink

prop_colorMemoizesId :: Color -> Property
prop_colorMemoizesId = prop_memoizesId

deriving instance Eq a => Eq (Tree a)

deriving instance Show a => Show (Tree a)

instance Arbitrary a => Arbitrary (Tree a) where
  arbitrary = sized $ \n -> do
    let h = (n - 1) `quot` 2
        h' = n - 1 - h
    frequency
      [ (1, Leaf <$> arbitrary),
        (max (n - 1) 0, Node <$> resize h arbitrary <*> resize h' arbitrary)
      ]
  shrink = genericShrink

prop_treeMemoizesId :: (Eq a, Show a, Memoizable a) => Tree a -> Property
prop_treeMemoizesId = prop_memoizesId

return []

main :: IO ()
main = do
  True <- $quickCheckAll
  return ()