{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE CPP #-}
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
{-# LANGUAGE OverloadedLists #-} -- For the IsList test
#if __GLASGOW_HASKELL__ == 708
{-# LANGUAGE PatternSynonyms #-} -- For pattern synonym use only in GHC 7.8
#endif
#endif
--------------------------------------------------------------------------------
module Main (main) where
--------------------------------------------------------------------------------
import Prelude hiding (concat, foldr, head, map, replicate, tail)
import qualified Data.List as List
import Test.QuickCheck
import Test.QuickCheck.Instances ()
import Test.QuickCheck.Function
import Data.DList.NonEmpty
import OverloadedStrings (testOverloadedStrings)
import Data.Semigroup (Semigroup(..))
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NE
--------------------------------------------------------------------------------
eqWith :: (Eq b, Show b) => (a -> b) -> (a -> b) -> a -> Property
eqWith f g x = f x === g x
eqOn :: (Eq b, Show b) => (a -> Bool) -> (a -> b) -> (a -> b) -> a -> Property
eqOn c f g x = c x ==> f x === g x
--------------------------------------------------------------------------------
prop_model :: NonEmpty Int -> Property
prop_model = eqWith id (toNonEmpty . fromNonEmpty)
prop_singleton :: Int -> Property
prop_singleton = eqWith (:|[]) (toNonEmpty . singleton)
prop_cons :: Int -> NonEmpty Int -> Property
prop_cons c = eqWith (NE.cons c) (toNonEmpty . cons c . fromNonEmpty)
prop_snoc :: NonEmpty Int -> Int -> Property
prop_snoc xs c = xs <> (c :| []) === toNonEmpty (snoc (fromNonEmpty xs) c)
prop_append :: NonEmpty Int -> NonEmpty Int -> Property
prop_append xs ys = xs <> ys === toNonEmpty (fromNonEmpty xs `append` fromNonEmpty ys)
prop_concat1 :: NonEmpty (NonEmpty Int) -> Property
prop_concat1 = eqWith sconcat (toNonEmpty . concat1 . fmap fromNonEmpty)
-- The condition reduces the size of replications and thus the eval time.
prop_replicate :: Int -> Int -> Property
prop_replicate n =
eqOn (const (n < 100)) (rep n) (toNonEmpty . replicate n)
where
rep m x = x :| List.replicate (m - 1) x
prop_head :: NonEmpty Int -> Property
prop_head = eqWith NE.head (head . fromNonEmpty)
prop_tail :: NonEmpty Int -> Property
prop_tail = eqWith NE.tail (tail . fromNonEmpty)
prop_unfoldr :: Fun Int (Int, Maybe Int) -> Int -> Int -> Property
prop_unfoldr (Fun _ f) n =
eqOn (const (n >= 0)) (NE.take n . NE.unfoldr f) (NE.take n . toNonEmpty . unfoldr f)
prop_map :: Fun Int Int -> NonEmpty Int -> Property
prop_map (Fun _ f) = eqWith (fmap f) (toNonEmpty . map f . fromNonEmpty)
prop_map_fusion :: (Int -> Int) -> (a -> Int) -> NonEmpty a -> Property
prop_map_fusion f g =
eqWith (fmap f . fmap g) (toNonEmpty . map f . map g . fromNonEmpty)
prop_show_read :: [Int] -> Property
prop_show_read = eqWith id (read . show)
prop_read_show :: NonEmpty Int -> Property
prop_read_show x = eqWith id (show . f . read) $ "fromNonEmpty (" <> show x <> ")"
where
f :: NonEmptyDList Int -> NonEmptyDList Int
f = id
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
-- | Test that the IsList instance methods compile and work with simple lists
prop_IsList :: Property
prop_IsList = test_fromNonEmpty [1,2,3] .&&. test_toNonEmpty (fromNonEmpty [1,2,3])
where
test_fromNonEmpty, test_toNonEmpty :: NonEmptyDList Int -> Property
test_fromNonEmpty x = x === fromNonEmpty [1,2,3]
test_toNonEmpty [1,2,3] = property True
test_toNonEmpty _ = property False
prop_patterns :: NonEmpty Int -> Property
prop_patterns xs = case fromNonEmpty xs of
Cons y ys -> xs === (y:|ys)
_ -> property False
#endif
prop_Semigroup_append :: NonEmpty Int -> NonEmpty Int -> Property
prop_Semigroup_append xs ys = xs <> ys === toNonEmpty (fromNonEmpty xs <> fromNonEmpty ys)
prop_Semigroup_sconcat :: NonEmpty (NonEmpty Int) -> Property
prop_Semigroup_sconcat xs = sconcat xs === toNonEmpty (sconcat (fmap fromNonEmpty xs))
prop_Semigroup_stimes :: Int -> NonEmpty Int -> Property
prop_Semigroup_stimes n xs = n >=1 ==>
stimes n xs === toNonEmpty (stimes n (fromNonEmpty xs))
--------------------------------------------------------------------------------
props :: [(String, Property)]
props =
[ ("model", property prop_model)
, ("singleton", property prop_singleton)
, ("cons", property prop_cons)
, ("snoc", property prop_snoc)
, ("append", property prop_append)
, ("concat1", property prop_concat1)
, ("replicate", property prop_replicate)
, ("head", property prop_head)
, ("tail", property prop_tail)
, ("unfoldr", property prop_unfoldr)
, ("map", property prop_map)
, ("map fusion", property (prop_map_fusion (+1) (+1)))
, ("read . show", property prop_show_read)
, ("show . read", property prop_read_show)
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
, ("IsList", property prop_IsList)
, ("patterns", property prop_patterns)
#endif
, ("Semigroup <>", property prop_Semigroup_append)
, ("Semigroup sconcat", property prop_Semigroup_sconcat)
, ("Semigroup stimes", property prop_Semigroup_stimes)
]
--------------------------------------------------------------------------------
main :: IO ()
main = do
testOverloadedStrings
quickCheck $ conjoin $ fmap (uncurry label) props