testSequentialProperties :: forall collection
                          . ( Sequential collection
                            , Typeable collection, Typeable (Element collection)
                            , Eq collection, Eq (Element collection)
                            , Ord collection, Ord (Element collection)
                            , Show collection, Show (Element collection)
                            )
                         => Proxy collection
                         -> Gen (Element collection)
                         -> Test
testSequentialProperties proxy genElement = Group "Sequential"
    [ Property "take" $ withElements2 $ \(l, n) -> toList (take n $ fromListP proxy l) === (take n) l
    , Property "drop" $ withElements2 $ \(l, n) -> toList (drop n $ fromListP proxy l) === (drop n) l
    , Property "splitAt" $ withElements2 $ \(l, n) -> toList2 (splitAt n $ fromListP proxy l) === (splitAt n) l
    , Property "revTake" $ withElements2 $ \(l, n) -> toList (revTake n $ fromListP proxy l) === (revTake n) l
    , Property "revDrop" $ withElements2 $ \(l, n) -> toList (revDrop n $ fromListP proxy l) === (revDrop n) l
    , Property "revSplitAt" $ withElements2 $ \(l, n) -> toList2 (revSplitAt n $ fromListP proxy l) === (revSplitAt n) l
    , Property "break" $ withElements2E $ \(l, c) -> toList2 (break (== c) $ fromListP proxy l) === (break (== c)) l
    , Property "breakEnd" $ withElements2E $ \(l, c) -> toList2 (breakEnd (== c) $ fromListP proxy l) === (breakEnd (== c)) l
    , Property "breakElem" $ withElements2E $ \(l, c) -> toList2 (breakElem c $ fromListP proxy l) === (breakElem c) l
    , Property "span" $ withElements2E $ \(l, c) -> toList2 (span (== c) $ fromListP proxy l) === (span (== c)) l
    , Property "spanEnd" $ withElements2E $ \(l, c) -> toList2 (spanEnd (== c) $ fromListP proxy l) === (spanEnd (== c)) l
    , Property "filter" $ withElements2E $ \(l, c) -> toList (filter (== c) $ fromListP proxy l) === (filter (== c)) l
    , Property "partition" $ withElements2E $ \(l, c) -> toList2 (partition (== c) $ fromListP proxy l) === (partition (== c)) l
    , Property "snoc" $ withElements2E $ \(l, c) -> toList (snoc (fromListP proxy l) c) === (l <> [c])
    , Property "cons" $ withElements2E $ \(l, c) -> toList (cons c (fromListP proxy l)) === (c : l)
    , Property "unsnoc" $ withElements $ \l -> fmap toListFirst (unsnoc (fromListP proxy l)) === unsnoc l
    , Property "uncons" $ withElements $ \l -> fmap toListSecond (uncons (fromListP proxy l)) === uncons l
    , Property "head" $ withNonEmptyElements $ \els -> head (fromListNonEmptyP proxy els) === head els
    , Property "last" $ withNonEmptyElements $ \els -> last (fromListNonEmptyP proxy els) === last els
    , Property "tail" $ withNonEmptyElements $ \els -> toList (tail $ fromListNonEmptyP proxy els) === tail els
    , Property "init" $ withNonEmptyElements $ \els -> toList (init $ fromListNonEmptyP proxy els) === init els
    , Property "splitOn" $ withElements2E $ \(l, ch) ->
         fmap toList (splitOn (== ch) (fromListP proxy l)) === splitOn (== ch) l
    , testSplitOn proxy (const True) mempty
    , Property "intercalate c (splitOn (c ==) col) == col" $ withElements2E $ \(c, ch) ->
        intercalate [ch] (splitOn (== ch) c) === c
    , Property "intercalate c (splitOn (c ==) (col ++ [c]) == (col ++ [c])" $ withElements2E $ \(c, ch) ->
        intercalate [ch] (splitOn (== ch) $ snoc c ch) === (snoc c ch)
    , Property "intercalate c (splitOn (c ==) (col ++ [c,c]) == (col ++ [c,c])" $ withElements2E $ \(c, ch) ->
        intercalate [ch] (splitOn (== ch) $ snoc (snoc c ch) ch) === (snoc (snoc c ch) ch)
    , Property "intersperse" $ withElements2E $ \(l, c) ->
        toList (intersperse c (fromListP proxy l)) === intersperse c l
    , Property "intercalate" $ withElements2E $ \(l, c) ->
        let ls = Prelude.replicate 5 l
            cs = Prelude.replicate 5 c
        in toList (intercalate (fromListP proxy cs) (fromListP proxy <$> ls)) === intercalate cs ls
    , Property "sortBy" $ withElements $ \l ->
        (sortBy compare $ fromListP proxy l) === fromListP proxy (sortBy compare l)
    , Property "reverse" $ withElements $ \l ->
        (reverse $ fromListP proxy l) === fromListP proxy (reverse l)
    -- stress slicing
    , Property "take . take" $ withElements3 $ \(l, n1, n2) -> toList (take n2 $ take n1 $ fromListP proxy l) === (take n2 $ take n1 l)
    , Property "drop . take" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ take n1 $ fromListP proxy l) === (drop n2 $ take n1 l)
    , Property "drop . drop" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ drop n1 $ fromListP proxy l) === (drop n2 $ drop n1 l)
    , Property "drop . take" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ take n1 $ fromListP proxy l) === (drop n2 $ take n1 l)
    , Property "second take . splitAt" $ withElements3 $ \(l, n1, n2) ->
        (toList2 $ (second (take n1) . splitAt n2) $ fromListP proxy l) === (second (take n1) . splitAt n2) l
    , Property "splitAt == (take, drop)" $ withCollection2 $ \(col, n) ->
        splitAt n col === (take n col, drop n col)
    , Property "revSplitAt == (revTake, revDrop)" $ withCollection2 $ \(col, n) ->
        revSplitAt n col === (revTake n col, revDrop n col)
    , Group "isSuffixOf"
        [ Property "collection + sub" $ withElements2 $ \(l1, n) ->
            let c1 = fromListP proxy l1 in isSuffixOf (revTake n c1) c1 === isSuffixOf (revTake n l1) l1
        , Property "2 collections" $ with2Elements $ \(l1, l2) -> isSuffixOf (fromListP proxy l1) (fromListP proxy l2) === isSuffixOf l1 l2
        , Property "collection + empty" $ withElements $ \l1 ->
            isSuffixOf (fromListP proxy []) (fromListP proxy l1) === isSuffixOf [] l1
        ]
    , Group "isPrefixOf"
        [ Property "collection + sub" $ withElements2 $ \(l1, n) ->
            let c1 = fromListP proxy l1 in isPrefixOf (take n c1) c1 === isPrefixOf (take n l1) l1
        , Property "2 collections" $ with2Elements $ \(l1, l2) -> isPrefixOf (fromListP proxy l1) (fromListP proxy l2) === isPrefixOf l1 l2
        , Property "collection + empty" $ withElements $ \l1 ->
            isPrefixOf (fromListP proxy []) (fromListP proxy l1) === isPrefixOf [] l1
        ]
    , Group "isInfixOf"
        [ Property "b isInfixOf 'a b c'" $ with3Elements $ \(a, b, c) -> 
            isInfixOf (toCol b) (toCol a <> toCol b <> toCol c)
        , Property "the reverse is typically not an infix" $ withElements $ \a' ->
            let a = toCol a'; rev = reverse a in isInfixOf rev a === (a == rev)
        ]
    ]
{-
    , testProperty "imap" $ \(CharMap (LUString u) i) ->
        (imap (addChar i) (fromList u) :: String) `assertEq` fromList (Prelude.map (addChar i) u)
    ]
-}
  where
    toCol = fromListP proxy 
    toList2 (x,y) = (toList x, toList y)
    toListFirst (x,y) = (toList x, y)
    toListSecond (x,y) = (x, toList y)
    withElements f = forAll (generateListOfElement genElement) f
    with2Elements f = forAll ((,) <$> generateListOfElement genElement <*> generateListOfElement genElement) f
    with3Elements f = forAll ((,,) <$> generateListOfElement genElement <*> generateListOfElement genElement <*> generateListOfElement genElement) f
    withElements2 f = forAll ((,) <$> generateListOfElement genElement <*> arbitrary) f
    withElements3 f = forAll ((,,) <$> generateListOfElement genElement <*> arbitrary <*> arbitrary) f
    withElements2E f = forAll ((,) <$> generateListOfElement genElement <*> genElement) f
    withNonEmptyElements f = forAll (generateNonEmptyListOfElement 80 genElement) f
    withCollection2 f = forAll ((,) <$> (fromListP proxy <$> generateListOfElement genElement) <*> arbitrary) f

    testSplitOn :: ( Sequential a
                   , Show a, Show (Element a)
                   , Typeable a
                   , Eq (Element a)
                   , Eq a, Ord a, Ord (Item a), Show a
                   )
                => Proxy a -> (Element a -> Bool) -> a
                -> Test
    testSplitOn _ predicate col = Property "splitOn (const True) mempty == [mempty]" $
      (splitOn predicate col) === [col]
testSequentialProperties :: forall collection
                          . ( Sequential collection
                            , Typeable collection, Typeable (Element collection)
                            , Eq collection, Eq (Element collection)
                            , Ord collection, Ord (Element collection)
                            , Show collection, Show (Element collection)
                            )
                         => Proxy collection
                         -> Gen (Element collection)
                         -> Test
testSequentialProperties proxy genElement = Group "Sequential"
    [ Property "take" $ withElements2 $ \(l, n) -> toList (take n $ fromListP proxy l) === (take n) l
    , Property "drop" $ withElements2 $ \(l, n) -> toList (drop n $ fromListP proxy l) === (drop n) l
    , Property "splitAt" $ withElements2 $ \(l, n) -> toList2 (splitAt n $ fromListP proxy l) === (splitAt n) l
    , Property "revTake" $ withElements2 $ \(l, n) -> toList (revTake n $ fromListP proxy l) === (revTake n) l
    , Property "revDrop" $ withElements2 $ \(l, n) -> toList (revDrop n $ fromListP proxy l) === (revDrop n) l
    , Property "revSplitAt" $ withElements2 $ \(l, n) -> toList2 (revSplitAt n $ fromListP proxy l) === (revSplitAt n) l
    , Property "break" $ withElements2E $ \(l, c) -> toList2 (break (== c) $ fromListP proxy l) === (break (== c)) l
    , Property "breakEnd" $ withElements2E $ \(l, c) -> toList2 (breakEnd (== c) $ fromListP proxy l) === (breakEnd (== c)) l
    , Property "breakElem" $ withElements2E $ \(l, c) -> toList2 (breakElem c $ fromListP proxy l) === (breakElem c) l
    , Property "span" $ withElements2E $ \(l, c) -> toList2 (span (== c) $ fromListP proxy l) === (span (== c)) l
    , Property "spanEnd" $ withElements2E $ \(l, c) -> toList2 (spanEnd (== c) $ fromListP proxy l) === (spanEnd (== c)) l
    , Property "filter" $ withElements2E $ \(l, c) -> toList (filter (== c) $ fromListP proxy l) === (filter (== c)) l
    , Property "partition" $ withElements2E $ \(l, c) -> toList2 (partition (== c) $ fromListP proxy l) === (partition (== c)) l
    , Property "snoc" $ withElements2E $ \(l, c) -> toList (snoc (fromListP proxy l) c) === (l <> [c])
    , Property "cons" $ withElements2E $ \(l, c) -> toList (cons c (fromListP proxy l)) === (c : l)
    , Property "unsnoc" $ withElements $ \l -> fmap toListFirst (unsnoc (fromListP proxy l)) === unsnoc l
    , Property "uncons" $ withElements $ \l -> fmap toListSecond (uncons (fromListP proxy l)) === uncons l
    , Property "head" $ withNonEmptyElements $ \els -> head (fromListNonEmptyP proxy els) === head els
    , Property "last" $ withNonEmptyElements $ \els -> last (fromListNonEmptyP proxy els) === last els
    , Property "tail" $ withNonEmptyElements $ \els -> toList (tail $ fromListNonEmptyP proxy els) === tail els
    , Property "init" $ withNonEmptyElements $ \els -> toList (init $ fromListNonEmptyP proxy els) === init els
    , Property "splitOn" $ withElements2E $ \(l, ch) ->
         fmap toList (splitOn (== ch) (fromListP proxy l)) === splitOn (== ch) l
    , testSplitOn proxy (const True) mempty
    , Property "intercalate c (splitOn (c ==) col) == col" $ withElements2E $ \(c, ch) ->
        intercalate [ch] (splitOn (== ch) c) === c
    , Property "intercalate c (splitOn (c ==) (col ++ [c]) == (col ++ [c])" $ withElements2E $ \(c, ch) ->
        intercalate [ch] (splitOn (== ch) $ snoc c ch) === (snoc c ch)
    , Property "intercalate c (splitOn (c ==) (col ++ [c,c]) == (col ++ [c,c])" $ withElements2E $ \(c, ch) ->
        intercalate [ch] (splitOn (== ch) $ snoc (snoc c ch) ch) === (snoc (snoc c ch) ch)
    , Property "intersperse" $ withElements2E $ \(l, c) ->
        toList (intersperse c (fromListP proxy l)) === intersperse c l
    , Property "intercalate" $ withElements2E $ \(l, c) ->
        let ls = Prelude.replicate 5 l
            cs = Prelude.replicate 5 c
        in toList (intercalate (fromListP proxy cs) (fromListP proxy <$> ls)) === intercalate cs ls
    , Property "sortBy" $ withElements $ \l ->
        (sortBy compare $ fromListP proxy l) === fromListP proxy (sortBy compare l)
    , Property "reverse" $ withElements $ \l ->
        (reverse $ fromListP proxy l) === fromListP proxy (reverse l)
    -- stress slicing
    , Property "take . take" $ withElements3 $ \(l, n1, n2) -> toList (take n2 $ take n1 $ fromListP proxy l) === (take n2 $ take n1 l)
    , Property "drop . take" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ take n1 $ fromListP proxy l) === (drop n2 $ take n1 l)
    , Property "drop . drop" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ drop n1 $ fromListP proxy l) === (drop n2 $ drop n1 l)
    , Property "drop . take" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ take n1 $ fromListP proxy l) === (drop n2 $ take n1 l)
    , Property "second take . splitAt" $ withElements3 $ \(l, n1, n2) ->
        (toList2 $ (second (take n1) . splitAt n2) $ fromListP proxy l) === (second (take n1) . splitAt n2) l
    , Property "splitAt == (take, drop)" $ withCollection2 $ \(col, n) ->
        splitAt n col === (take n col, drop n col)
    , Property "revSplitAt == (revTake, revDrop)" $ withCollection2 $ \(col, n) ->
        revSplitAt n col === (revTake n col, revDrop n col)
    , Group "isSuffixOf"
        [ Property "collection + sub" $ withElements2 $ \(l1, n) ->
            let c1 = fromListP proxy l1 in isSuffixOf (revTake n c1) c1 === isSuffixOf (revTake n l1) l1
        , Property "2 collections" $ with2Elements $ \(l1, l2) -> isSuffixOf (fromListP proxy l1) (fromListP proxy l2) === isSuffixOf l1 l2
        , Property "collection + empty" $ withElements $ \l1 ->
            isSuffixOf (fromListP proxy []) (fromListP proxy l1) === isSuffixOf [] l1
        ]
    , Group "isPrefixOf"
        [ Property "collection + sub" $ withElements2 $ \(l1, n) ->
            let c1 = fromListP proxy l1 in isPrefixOf (take n c1) c1 === isPrefixOf (take n l1) l1
        , Property "2 collections" $ with2Elements $ \(l1, l2) -> isPrefixOf (fromListP proxy l1) (fromListP proxy l2) === isPrefixOf l1 l2
        , Property "collection + empty" $ withElements $ \l1 ->
            isPrefixOf (fromListP proxy []) (fromListP proxy l1) === isPrefixOf [] l1
        ]
    , Group "isInfixOf"
        [ Property "b isInfixOf 'a b c'" $ with3Elements $ \(a, b, c) -> 
            isInfixOf (toCol b) (toCol a <> toCol b <> toCol c)
        , Property "the reverse is typically not an infix" $ withElements $ \a' ->
            let a = toCol a'; rev = reverse a in isInfixOf rev a === (a == rev)
        ]
    ]
{-
    , testProperty "imap" $ \(CharMap (LUString u) i) ->
        (imap (addChar i) (fromList u) :: String) `assertEq` fromList (Prelude.map (addChar i) u)
    ]
-}
  where
    toCol = fromListP proxy 
    toList2 (x,y) = (toList x, toList y)
    toListFirst (x,y) = (toList x, y)
    toListSecond (x,y) = (x, toList y)
    withElements f = forAll (generateListOfElement genElement) f
    with2Elements f = forAll ((,) <$> generateListOfElement genElement <*> generateListOfElement genElement) f
    with3Elements f = forAll ((,,) <$> generateListOfElement genElement <*> generateListOfElement genElement <*> generateListOfElement genElement) f
    withElements2 f = forAll ((,) <$> generateListOfElement genElement <*> arbitrary) f
    withElements3 f = forAll ((,,) <$> generateListOfElement genElement <*> arbitrary <*> arbitrary) f
    withElements2E f = forAll ((,) <$> generateListOfElement genElement <*> genElement) f
    withNonEmptyElements f = forAll (generateNonEmptyListOfElement 80 genElement) f
    withCollection2 f = forAll ((,) <$> (fromListP proxy <$> generateListOfElement genElement) <*> arbitrary) f

    testSplitOn :: ( Sequential a
                   , Show a, Show (Element a)
                   , Typeable a
                   , Eq (Element a)
                   , Eq a, Ord a, Ord (Item a), Show a
                   )
                => Proxy a -> (Element a -> Bool) -> a
                -> Test
    testSplitOn _ predicate col = Property "splitOn (const True) mempty == [mempty]" $
      (splitOn predicate col) === [col]
testSequentialProperties proxy genElement = Group "Sequential"
    [ Property "take" $ withElements2 $ \(l, n) -> toList (take n $ fromListP proxy l) === (take n) l
    , Property "drop" $ withElements2 $ \(l, n) -> toList (drop n $ fromListP proxy l) === (drop n) l
    , Property "splitAt" $ withElements2 $ \(l, n) -> toList2 (splitAt n $ fromListP proxy l) === (splitAt n) l
    , Property "revTake" $ withElements2 $ \(l, n) -> toList (revTake n $ fromListP proxy l) === (revTake n) l
    , Property "revDrop" $ withElements2 $ \(l, n) -> toList (revDrop n $ fromListP proxy l) === (revDrop n) l
    , Property "revSplitAt" $ withElements2 $ \(l, n) -> toList2 (revSplitAt n $ fromListP proxy l) === (revSplitAt n) l
    , Property "break" $ withElements2E $ \(l, c) -> toList2 (break (== c) $ fromListP proxy l) === (break (== c)) l
    , Property "breakEnd" $ withElements2E $ \(l, c) -> toList2 (breakEnd (== c) $ fromListP proxy l) === (breakEnd (== c)) l
    , Property "breakElem" $ withElements2E $ \(l, c) -> toList2 (breakElem c $ fromListP proxy l) === (breakElem c) l
    , Property "span" $ withElements2E $ \(l, c) -> toList2 (span (== c) $ fromListP proxy l) === (span (== c)) l
    , Property "spanEnd" $ withElements2E $ \(l, c) -> toList2 (spanEnd (== c) $ fromListP proxy l) === (spanEnd (== c)) l
    , Property "filter" $ withElements2E $ \(l, c) -> toList (filter (== c) $ fromListP proxy l) === (filter (== c)) l
    , Property "partition" $ withElements2E $ \(l, c) -> toList2 (partition (== c) $ fromListP proxy l) === (partition (== c)) l
    , Property "snoc" $ withElements2E $ \(l, c) -> toList (snoc (fromListP proxy l) c) === (l <> [c])
    , Property "cons" $ withElements2E $ \(l, c) -> toList (cons c (fromListP proxy l)) === (c : l)
    , Property "unsnoc" $ withElements $ \l -> fmap toListFirst (unsnoc (fromListP proxy l)) === unsnoc l
    , Property "uncons" $ withElements $ \l -> fmap toListSecond (uncons (fromListP proxy l)) === uncons l
    , Property "head" $ withNonEmptyElements $ \els -> head (fromListNonEmptyP proxy els) === head els
    , Property "last" $ withNonEmptyElements $ \els -> last (fromListNonEmptyP proxy els) === last els
    , Property "tail" $ withNonEmptyElements $ \els -> toList (tail $ fromListNonEmptyP proxy els) === tail els
    , Property "init" $ withNonEmptyElements $ \els -> toList (init $ fromListNonEmptyP proxy els) === init els
    , Property "splitOn" $ withElements2E $ \(l, ch) ->
         fmap toList (splitOn (== ch) (fromListP proxy l)) === splitOn (== ch) l
    , testSplitOn proxy (const True) mempty
    , Property "intercalate c (splitOn (c ==) col) == col" $ withElements2E $ \(c, ch) ->
        intercalate [ch] (splitOn (== ch) c) === c
    , Property "intercalate c (splitOn (c ==) (col ++ [c]) == (col ++ [c])" $ withElements2E $ \(c, ch) ->
        intercalate [ch] (splitOn (== ch) $ snoc c ch) === (snoc c ch)
    , Property "intercalate c (splitOn (c ==) (col ++ [c,c]) == (col ++ [c,c])" $ withElements2E $ \(c, ch) ->
        intercalate [ch] (splitOn (== ch) $ snoc (snoc c ch) ch) === (snoc (snoc c ch) ch)
    , Property "intersperse" $ withElements2E $ \(l, c) ->
        toList (intersperse c (fromListP proxy l)) === intersperse c l
    , Property "intercalate" $ withElements2E $ \(l, c) ->
        let ls = Prelude.replicate 5 l
            cs = Prelude.replicate 5 c
        in toList (intercalate (fromListP proxy cs) (fromListP proxy <$> ls)) === intercalate cs ls
    , Property "sortBy" $ withElements $ \l ->
        (sortBy compare $ fromListP proxy l) === fromListP proxy (sortBy compare l)
    , Property "reverse" $ withElements $ \l ->
        (reverse $ fromListP proxy l) === fromListP proxy (reverse l)
    -- stress slicing
    , Property "take . take" $ withElements3 $ \(l, n1, n2) -> toList (take n2 $ take n1 $ fromListP proxy l) === (take n2 $ take n1 l)
    , Property "drop . take" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ take n1 $ fromListP proxy l) === (drop n2 $ take n1 l)
    , Property "drop . drop" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ drop n1 $ fromListP proxy l) === (drop n2 $ drop n1 l)
    , Property "drop . take" $ withElements3 $ \(l, n1, n2) -> toList (drop n2 $ take n1 $ fromListP proxy l) === (drop n2 $ take n1 l)
    , Property "second take . splitAt" $ withElements3 $ \(l, n1, n2) ->
        (toList2 $ (second (take n1) . splitAt n2) $ fromListP proxy l) === (second (take n1) . splitAt n2) l
    , Property "splitAt == (take, drop)" $ withCollection2 $ \(col, n) ->
        splitAt n col === (take n col, drop n col)
    , Property "revSplitAt == (revTake, revDrop)" $ withCollection2 $ \(col, n) ->
        revSplitAt n col === (revTake n col, revDrop n col)
    , Group "isSuffixOf"
        [ Property "collection + sub" $ withElements2 $ \(l1, n) ->
            let c1 = fromListP proxy l1 in isSuffixOf (revTake n c1) c1 === isSuffixOf (revTake n l1) l1
        , Property "2 collections" $ with2Elements $ \(l1, l2) -> isSuffixOf (fromListP proxy l1) (fromListP proxy l2) === isSuffixOf l1 l2
        , Property "collection + empty" $ withElements $ \l1 ->
            isSuffixOf (fromListP proxy []) (fromListP proxy l1) === isSuffixOf [] l1
        ]
    , Group "isPrefixOf"
        [ Property "collection + sub" $ withElements2 $ \(l1, n) ->
            let c1 = fromListP proxy l1 in isPrefixOf (take n c1) c1 === isPrefixOf (take n l1) l1
        , Property "2 collections" $ with2Elements $ \(l1, l2) -> isPrefixOf (fromListP proxy l1) (fromListP proxy l2) === isPrefixOf l1 l2
        , Property "collection + empty" $ withElements $ \l1 ->
            isPrefixOf (fromListP proxy []) (fromListP proxy l1) === isPrefixOf [] l1
        ]
    , Group "isInfixOf"
        [ Property "b isInfixOf 'a b c'" $ with3Elements $ \(a, b, c) -> 
            isInfixOf (toCol b) (toCol a <> toCol b <> toCol c)
        , Property "the reverse is typically not an infix" $ withElements $ \a' ->
            let a = toCol a'; rev = reverse a in isInfixOf rev a === (a == rev)
        ]
    ]
{-
    , testProperty "imap" $ \(CharMap (LUString u) i) ->
        (imap (addChar i) (fromList u) :: String) `assertEq` fromList (Prelude.map (addChar i) u)
    ]
-}
  where
    toCol = fromListP proxy 
    toList2 (x,y) = (toList x, toList y)
    toListFirst (x,y) = (toList x, y)
    toListSecond (x,y) = (x, toList y)
    withElements f = forAll (generateListOfElement genElement) f
    with2Elements f = forAll ((,) <$> generateListOfElement genElement <*> generateListOfElement genElement) f
    with3Elements f = forAll ((,,) <$> generateListOfElement genElement <*> generateListOfElement genElement <*> generateListOfElement genElement) f
    withElements2 f = forAll ((,) <$> generateListOfElement genElement <*> arbitrary) f
    withElements3 f = forAll ((,,) <$> generateListOfElement genElement <*> arbitrary <*> arbitrary) f
    withElements2E f = forAll ((,) <$> generateListOfElement genElement <*> genElement) f
    withNonEmptyElements f = forAll (generateNonEmptyListOfElement 80 genElement) f
    withCollection2 f = forAll ((,) <$> (fromListP proxy <$> generateListOfElement genElement) <*> arbitrary) f

    testSplitOn :: ( Sequential a
                   , Show a, Show (Element a)
                   , Typeable a
                   , Eq (Element a)
                   , Eq a, Ord a, Ord (Item a), Show a
                   )
                => Proxy a -> (Element a -> Bool) -> a
                -> Test
    testSplitOn _ predicate col = Property "splitOn (const True) mempty == [mempty]" $
      (splitOn predicate col) === [col]