{-# LANGUAGE ScopedTypeVariables #-} module Main (main) where import Data.Complex (Complex) import Data.Int (Int8, Int16, Int32, Int64) import Data.List.NonEmpty (NonEmpty) import Data.Proxy (Proxy (..)) import Data.Typeable (Typeable, typeRep) import Data.Word (Word8, Word16, Word32, Word64) import Numeric.Natural (Natural) import Test.QuickCheck (Arbitrary (..), Property, counterexample, label, (===), sized, chooseInt, vectorOf) import Test.QuickCheck.Instances () import Test.Tasty (defaultMain, testGroup, TestTree) import Test.Tasty.QuickCheck (testProperty) import qualified Data.List as L import Data.Discrimination import Utils main :: IO () main = defaultMain $ testGroup "discrimination" [ testGroup "examples" [ testGroup "nub" [ testProperty "List.nub" $ let prop :: [Word64] -> Property prop xs = L.nub xs === nub xs in prop , testProperty "ordNub" $ let prop :: [Word64] -> Property prop xs = ordNub xs === nub xs in prop , testProperty "hashNub" $ let prop :: [Word64] -> Property prop xs = hashNub xs === nub xs in prop ] , testGroup "sort" [ testProperty "List.sort" $ let prop :: [Word64] -> Property prop xs = L.sort xs === sort xs in prop , testProperty "introsort" $ -- for Word64 unstable sort works too let prop :: [Word64] -> Property prop xs = introsort xs === sort xs in prop , testProperty "mergesort" $ let prop :: [Word64] -> Property prop xs = mergesort xs === sort xs in prop ] ] , testGroup "Grouping" [ testGrouping (Proxy :: Proxy ()) , testGrouping (Proxy :: Proxy Int) , testGrouping (Proxy :: Proxy Int8) , testGrouping (Proxy :: Proxy Int16) , testGrouping (Proxy :: Proxy Int32) , testGrouping (Proxy :: Proxy Int64) , testGrouping (Proxy :: Proxy Word) , testGrouping (Proxy :: Proxy Word8) , testGrouping (Proxy :: Proxy Word16) , testGrouping (Proxy :: Proxy Word32) , testGrouping (Proxy :: Proxy Word64) , testGrouping (Proxy :: Proxy Bool) , testGrouping (Proxy :: Proxy Ordering) , testGrouping (Proxy :: Proxy (Word8,Word8)) , testGrouping (Proxy :: Proxy (Word8,Word8,Word8)) , testGrouping (Proxy :: Proxy (Word8,Word8,Word8,Word8)) , testGrouping (Proxy :: Proxy Rational) , testGrouping (Proxy :: Proxy (Complex Word8)) , testGrouping (Proxy :: Proxy (Maybe Word8)) , testGrouping (Proxy :: Proxy (Either Word8 Word8)) , testGrouping (Proxy :: Proxy Char) , testGrouping (Proxy :: Proxy String) , testGrouping (Proxy :: Proxy (NonEmpty Int)) , testGrouping (Proxy :: Proxy Natural) , testGrouping (Proxy :: Proxy Integer) , testGrouping' listToNatural , testGrouping' listToInteger ] , testGroup "Sorting" [ testSorting (Proxy :: Proxy ()) , testSorting (Proxy :: Proxy Int) , testSorting (Proxy :: Proxy Int8) , testSorting (Proxy :: Proxy Int16) , testSorting (Proxy :: Proxy Int32) , testSorting (Proxy :: Proxy Int64) , testSorting (Proxy :: Proxy Word) , testSorting (Proxy :: Proxy Word8) , testSorting (Proxy :: Proxy Word16) , testSorting (Proxy :: Proxy Word32) , testSorting (Proxy :: Proxy Word64) , testSorting (Proxy :: Proxy Bool) , testSorting (Proxy :: Proxy Ordering) , testSorting (Proxy :: Proxy (Word8,Word8)) , testSorting (Proxy :: Proxy (Word8,Word8,Word8)) , testSorting (Proxy :: Proxy (Word8,Word8,Word8,Word8)) , testSorting (Proxy :: Proxy (Maybe Word8)) , testSorting (Proxy :: Proxy (Either Word8 Word8)) , testSorting (Proxy :: Proxy Char) , testSorting (Proxy :: Proxy String) , testSorting (Proxy :: Proxy (NonEmpty Int)) , testSorting (Proxy :: Proxy Natural) , testSorting (Proxy :: Proxy Integer) , testSorting' listToNatural , testSorting' listToInteger ] ] listToNatural :: SmallList Word64 -> Natural listToNatural = L.foldl' (\x y -> x * 2 ^ (64 :: Int) + fromIntegral y) 0 . getSmallList listToInteger :: SmallList Int64 -> Integer listToInteger = L.foldl' (\x y -> x * 2 ^ (64 :: Int) + fromIntegral y) 0 . getSmallList newtype SmallList a = SmallList { getSmallList :: [a] } deriving (Eq, Show) instance Arbitrary a => Arbitrary (SmallList a) where arbitrary = sized $ \n -> do m <- chooseInt (0, min 10 n) SmallList <$> vectorOf m arbitrary shrink = fmap SmallList . shrink . getSmallList testGrouping :: forall a. (Grouping a, Typeable a, Arbitrary a, Eq a, Show a) => Proxy a -> TestTree testGrouping _ = testGrouping' (id :: a -> a) testGrouping' :: forall a b. (Grouping b, Typeable a, Typeable b, Arbitrary a, Eq b, Show a, Show b) => (a -> b) -> TestTree testGrouping' f = testGroup name [ testProperty "groupingEq" prop_eq , testProperty "nub" prop_nub ] where tra = typeRep (Proxy :: Proxy a) trb = typeRep (Proxy :: Proxy b) name = if tra == trb then show tra else show trb ++ " from " ++ show tra prop_eq :: a -> a -> Property prop_eq x' y' = counterexample (show (x,y)) $ label (show lhs) $ lhs === groupingEq x y where x = f x' y = f y' lhs = x == y prop_nub :: [a] -> Property prop_nub xs' = L.nub xs === nub xs where xs = take 100 (map f xs') testSorting :: forall a. (Sorting a, Typeable a, Arbitrary a, Ord a, Show a) => Proxy a -> TestTree testSorting _ = testSorting' (id :: a -> a) testSorting' :: forall a b. (Sorting b, Typeable a, Typeable b, Arbitrary a, Ord b, Show a, Show b) => (a -> b) -> TestTree testSorting' f = testGroup name [ testProperty "sortingCompare" prop_cmp , testProperty "sort" prop_sort ] where tra = typeRep (Proxy :: Proxy a) trb = typeRep (Proxy :: Proxy b) name = if tra == trb then show tra else show trb ++ " from " ++ show tra prop_cmp :: a -> a -> Property prop_cmp x' y' = counterexample (show (x,y)) $ label (show lhs) $ lhs === sortingCompare x y where x = f x' y = f y' lhs = compare x y prop_sort :: [a] -> Property prop_sort xs' = L.sort xs === sort xs where xs = map f xs'