testCollectionProperties :: forall collection
                          . ( Collection collection
                            , Typeable collection, Typeable (Element collection)
                            , Show (Element collection), Eq (Element collection)
                                                       , Ord (Element collection)
                            , Ord collection
                            )
                         => Proxy collection
                            -- ^ a proxy for the collection to test
                         -> Gen (Element collection)
                            -- ^ a generator to generate elements for the collection
                         -> Test
testCollectionProperties proxy genElement = Group "Collection"
    [ Property "null mempty" $ (null $ fromListP proxy []) === True
    , Property "null . getNonEmpty" $ withNonEmptyElements $ \els ->
          (null $ fromListP proxy $ getNonEmpty els) === False
    , Property "length" $ withElements $ \l -> (length $ fromListP proxy l) === length l
    , Property "elem" $ withListAndElement $ \(l,e) -> elem e (fromListP proxy l) === elem e l
    , Property "notElem" $ withListAndElement $ \(l,e) -> notElem e (fromListP proxy l) === notElem e l
    , Property "minimum" $ withNonEmptyElements $ \els -> minimum (fromListNonEmptyP proxy els) === minimum els
    , Property "maximum" $ withNonEmptyElements $ \els -> maximum (fromListNonEmptyP proxy els) === maximum els
    , Property "all" $ withListAndElement $ \(l, e) ->
        (all (/= e) (fromListP proxy l) === all (/= e) l) `propertyAnd`
        (all (== e) (fromListP proxy l) === all (== e) l)
    , Property "any" $ withListAndElement $ \(l, e) ->
        (any (/= e) (fromListP proxy l) === any (/= e) l) `propertyAnd`
        (any (== e) (fromListP proxy l) === any (== e) l)
    ]
  where
    withElements f = forAll (generateListOfElement genElement) f
    withListAndElement = forAll ((,) <$> generateListOfElement genElement <*> genElement)
    withNonEmptyElements f = forAll (generateNonEmptyListOfElement 80 genElement) f
testCollectionProperties :: forall collection
                          . ( Collection collection
                            , Typeable collection, Typeable (Element collection)
                            , Show (Element collection), Eq (Element collection)
                                                       , Ord (Element collection)
                            , Ord collection
                            )
                         => Proxy collection
                            -- ^ a proxy for the collection to test
                         -> Gen (Element collection)
                            -- ^ a generator to generate elements for the collection
                         -> Test
testCollectionProperties proxy genElement = Group "Collection"
    [ Property "null mempty" $ (null $ fromListP proxy []) === True
    , Property "null . getNonEmpty" $ withNonEmptyElements $ \els ->
          (null $ fromListP proxy $ getNonEmpty els) === False
    , Property "length" $ withElements $ \l -> (length $ fromListP proxy l) === length l
    , Property "elem" $ withListAndElement $ \(l,e) -> elem e (fromListP proxy l) === elem e l
    , Property "notElem" $ withListAndElement $ \(l,e) -> notElem e (fromListP proxy l) === notElem e l
    , Property "minimum" $ withNonEmptyElements $ \els -> minimum (fromListNonEmptyP proxy els) === minimum els
    , Property "maximum" $ withNonEmptyElements $ \els -> maximum (fromListNonEmptyP proxy els) === maximum els
    , Property "all" $ withListAndElement $ \(l, e) ->
        (all (/= e) (fromListP proxy l) === all (/= e) l) `propertyAnd`
        (all (== e) (fromListP proxy l) === all (== e) l)
    , Property "any" $ withListAndElement $ \(l, e) ->
        (any (/= e) (fromListP proxy l) === any (/= e) l) `propertyAnd`
        (any (== e) (fromListP proxy l) === any (== e) l)
    ]
  where
    withElements f = forAll (generateListOfElement genElement) f
    withListAndElement = forAll ((,) <$> generateListOfElement genElement <*> genElement)
    withNonEmptyElements f = forAll (generateNonEmptyListOfElement 80 genElement) f
testCollectionProperties proxy genElement = Group "Collection"
    [ Property "null mempty" $ (null $ fromListP proxy []) === True
    , Property "null . getNonEmpty" $ withNonEmptyElements $ \els ->
          (null $ fromListP proxy $ getNonEmpty els) === False
    , Property "length" $ withElements $ \l -> (length $ fromListP proxy l) === length l
    , Property "elem" $ withListAndElement $ \(l,e) -> elem e (fromListP proxy l) === elem e l
    , Property "notElem" $ withListAndElement $ \(l,e) -> notElem e (fromListP proxy l) === notElem e l
    , Property "minimum" $ withNonEmptyElements $ \els -> minimum (fromListNonEmptyP proxy els) === minimum els
    , Property "maximum" $ withNonEmptyElements $ \els -> maximum (fromListNonEmptyP proxy els) === maximum els
    , Property "all" $ withListAndElement $ \(l, e) ->
        (all (/= e) (fromListP proxy l) === all (/= e) l) `propertyAnd`
        (all (== e) (fromListP proxy l) === all (== e) l)
    , Property "any" $ withListAndElement $ \(l, e) ->
        (any (/= e) (fromListP proxy l) === any (/= e) l) `propertyAnd`
        (any (== e) (fromListP proxy l) === any (== e) l)
    ]
  where
    withElements f = forAll (generateListOfElement genElement) f
    withListAndElement = forAll ((,) <$> generateListOfElement genElement <*> genElement)
    withNonEmptyElements f = forAll (generateNonEmptyListOfElement 80 genElement) f