{-# LANGUAGE BangPatterns, FlexibleInstances, OverloadedStrings, ScopedTypeVariables, TypeSynonymInstances #-} {-# OPTIONS_GHC -fno-enable-rewrite-rules #-} import Test.QuickCheck hiding (evaluate) import Text.Show.Functions () import qualified Data.Bits as Bits (shiftL, shiftR) import Data.Char (chr, isLower, isSpace, isUpper, ord) import Data.Monoid (Monoid(..)) import Data.String (fromString) import Debug.Trace (trace) import Control.Arrow ((***), second) import Data.Word (Word8, Word16, Word32) import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Encoding as E import Control.Exception (SomeException, evaluate, try) import qualified Data.Text.Fusion as S import qualified Data.Text.Fusion.Common as S import Data.Text.Fusion.Size import qualified Data.Text.Lazy.Encoding as EL import qualified Data.Text.Lazy.Fusion as SL import qualified Data.Text.UnsafeShift as U import qualified Data.List as L import Prelude hiding (replicate) import System.IO.Unsafe (unsafePerformIO) import Test.Framework (defaultMain, testGroup) import Test.Framework.Providers.QuickCheck (testProperty) import Data.Text.Search (indices) import qualified Data.Text.Lazy.Search as S (indices) import qualified SlowFunctions as Slow import QuickCheckUtils (NotEmpty(..), small) -- Ensure that two potentially bottom values (in the sense of crashing -- for some inputs, not looping infinitely) either both crash, or both -- give comparable results for some input. (=^=) :: (Eq a, Show a) => a -> a -> Bool {-# NOINLINE (=^=) #-} i =^= j = unsafePerformIO $ do x <- try (evaluate i) y <- try (evaluate j) case (x,y) of (Left (_ :: SomeException), Left (_ :: SomeException)) -> return True (Right a, Right b) -> return (a == b) e -> trace ("*** Divergence: " ++ show e) return False infix 4 =^= t_pack_unpack = (T.unpack . T.pack) `eq` id tl_pack_unpack = (TL.unpack . TL.pack) `eq` id t_stream_unstream = (S.unstream . S.stream) `eq` id tl_stream_unstream = (SL.unstream . SL.stream) `eq` id t_reverse_stream t = (S.reverse . S.reverseStream) t == t t_singleton c = [c] == (T.unpack . T.singleton) c tl_singleton c = [c] == (TL.unpack . TL.singleton) c tl_unstreamChunks x = f 11 x == f 1000 x where f n = SL.unstreamChunks n . S.streamList tl_chunk_unchunk = (TL.fromChunks . TL.toChunks) `eq` id t_ascii t = E.decodeASCII (E.encodeUtf8 a) == a where a = T.map (\c -> chr (ord c `mod` 128)) t t_utf8 = (E.decodeUtf8 . E.encodeUtf8) `eq` id tl_utf8 = (EL.decodeUtf8 . EL.encodeUtf8) `eq` id t_utf16LE = (E.decodeUtf16LE . E.encodeUtf16LE) `eq` id t_utf16BE = (E.decodeUtf16BE . E.encodeUtf16BE) `eq` id t_utf32LE = (E.decodeUtf32LE . E.encodeUtf32LE) `eq` id t_utf32BE = (E.decodeUtf32BE . E.encodeUtf32BE) `eq` id class Stringy s where packS :: String -> s unpackS :: s -> String splitAtS :: Int -> s -> (s,s) packSChunkSize :: Int -> String -> s packSChunkSize _ = packS instance Stringy String where packS = id unpackS = id splitAtS = splitAt instance Stringy (S.Stream Char) where packS = S.streamList unpackS = S.unstreamList splitAtS n s = (S.take n s, S.drop n s) instance Stringy T.Text where packS = T.pack unpackS = T.unpack splitAtS = T.splitAt instance Stringy TL.Text where packSChunkSize k = SL.unstreamChunks k . S.streamList packS = TL.pack unpackS = TL.unpack splitAtS = TL.splitAt . fromIntegral -- Do two functions give the same answer? eq :: (Eq a, Show a) => (t -> a) -> (t -> a) -> t -> Bool eq a b s = a s =^= b s -- What about with the RHS packed? eqP :: (Eq a, Show a, Stringy s) => (String -> a) -> (s -> a) -> String -> Word8 -> Bool eqP f g s w = eql "orig" (f s) (g t) && eql "mini" (f s) (g mini) && eql "head" (f sa) (g ta) && eql "tail" (f sb) (g tb) where t = packS s mini = packSChunkSize 10 s (sa,sb) = splitAt m s (ta,tb) = splitAtS m t l = length s m | l == 0 = n | otherwise = n `mod` l n = fromIntegral w eql d a b | a =^= b = True | otherwise = trace (d ++ ": " ++ show a ++ " /= " ++ show b) False -- For tests that have O(n^2) running times or input sizes, resize -- their inputs to the square root of the originals. unsquare :: (Arbitrary a, Show a, Testable b) => (a -> b) -> Property unsquare = forAll . sized $ \n -> resize (smallish n) arbitrary where smallish = round . (sqrt :: Double -> Double) . fromIntegral s_Eq s = (s==) `eq` ((S.streamList s==) . S.streamList) where _types = s :: String sf_Eq p s = ((L.filter p s==) . L.filter p) `eq` (((S.filter p $ S.streamList s)==) . S.filter p . S.streamList) t_Eq s = (s==) `eq` ((T.pack s==) . T.pack) tl_Eq s = (s==) `eq` ((TL.pack s==) . TL.pack) s_Ord s = (compare s) `eq` (compare (S.streamList s) . S.streamList) where _types = s :: String sf_Ord p s = ((compare $ L.filter p s) . L.filter p) `eq` (compare (S.filter p $ S.streamList s) . S.filter p . S.streamList) t_Ord s = (compare s) `eq` (compare (T.pack s) . T.pack) tl_Ord s = (compare s) `eq` (compare (TL.pack s) . TL.pack) t_Read = id `eq` (T.unpack . read . show) tl_Read = id `eq` (TL.unpack . read . show) t_Show = show `eq` (show . T.pack) tl_Show = show `eq` (show . TL.pack) t_mappend s = mappend s`eqP` (unpackS . mappend (T.pack s)) tl_mappend s = mappend s`eqP` (unpackS . mappend (TL.pack s)) t_mconcat = unsquare (mconcat `eq` (unpackS . mconcat . L.map T.pack)) tl_mconcat = unsquare (mconcat `eq` (unpackS . mconcat . L.map TL.pack)) t_IsString = fromString `eqP` (T.unpack . fromString) tl_IsString = fromString `eqP` (TL.unpack . fromString) s_cons x = (x:) `eqP` (unpackS . S.cons x) s_cons_s x = (x:) `eqP` (unpackS . S.unstream . S.cons x) sf_cons p x = ((x:) . L.filter p) `eqP` (unpackS . S.cons x . S.filter p) t_cons x = (x:) `eqP` (unpackS . T.cons x) tl_cons x = (x:) `eqP` (unpackS . TL.cons x) s_snoc x = (++ [x]) `eqP` (unpackS . (flip S.snoc) x) t_snoc x = (++ [x]) `eqP` (unpackS . (flip T.snoc) x) tl_snoc x = (++ [x]) `eqP` (unpackS . (flip TL.snoc) x) s_append s = (s++) `eqP` (unpackS . S.append (S.streamList s)) s_append_s s = (s++) `eqP` (unpackS . S.unstream . S.append (S.streamList s)) sf_append p s = (L.filter p s++) `eqP` (unpackS . S.append (S.filter p $ S.streamList s)) t_append s = (s++) `eqP` (unpackS . T.append (packS s)) uncons (x:xs) = Just (x,xs) uncons _ = Nothing s_uncons = uncons `eqP` (fmap (second unpackS) . S.uncons) sf_uncons p = (uncons . L.filter p) `eqP` (fmap (second unpackS) . S.uncons . S.filter p) t_uncons = uncons `eqP` (fmap (second unpackS) . T.uncons) tl_uncons = uncons `eqP` (fmap (second unpackS) . TL.uncons) s_head = head `eqP` S.head sf_head p = (head . L.filter p) `eqP` (S.head . S.filter p) t_head = head `eqP` T.head tl_head = head `eqP` TL.head s_last = last `eqP` S.last sf_last p = (last . L.filter p) `eqP` (S.last . S.filter p) t_last = last `eqP` T.last tl_last = last `eqP` TL.last s_tail = tail `eqP` (unpackS . S.tail) s_tail_s = tail `eqP` (unpackS . S.unstream . S.tail) sf_tail p = (tail . L.filter p) `eqP` (unpackS . S.tail . S.filter p) t_tail = tail `eqP` (unpackS . T.tail) tl_tail = tail `eqP` (unpackS . TL.tail) s_init = init `eqP` (unpackS . S.init) s_init_s = init `eqP` (unpackS . S.unstream . S.init) sf_init p = (init . L.filter p) `eqP` (unpackS . S.init . S.filter p) t_init = init `eqP` (unpackS . T.init) tl_init = init `eqP` (unpackS . TL.init) s_null = null `eqP` S.null sf_null p = (null . L.filter p) `eqP` (S.null . S.filter p) t_null = null `eqP` T.null tl_null = null `eqP` TL.null s_length = length `eqP` S.length sf_length p = (length . L.filter p) `eqP` (S.length . S.filter p) t_length = length `eqP` T.length tl_length = length `eqP` (fromIntegral . TL.length) s_map f = map f `eqP` (unpackS . S.map f) s_map_s f = map f `eqP` (unpackS . S.unstream . S.map f) sf_map p f = (map f . L.filter p) `eqP` (unpackS . S.map f . S.filter p) t_map f = map f `eqP` (unpackS . T.map f) tl_map f = map f `eqP` (unpackS . TL.map f) t_intercalate c = unsquare (L.intercalate c `eq` (unpackS . T.intercalate (packS c) . map packS)) tl_intercalate c = unsquare (L.intercalate c `eq` (unpackS . TL.intercalate (TL.pack c) . map TL.pack)) s_intersperse c = L.intersperse c `eqP` (unpackS . S.intersperse c) s_intersperse_s c = L.intersperse c `eqP` (unpackS . S.unstream . S.intersperse c) sf_intersperse p c= (L.intersperse c . L.filter p) `eqP` (unpackS . S.intersperse c . S.filter p) t_intersperse c = L.intersperse c `eqP` (unpackS . T.intersperse c) tl_intersperse c = L.intersperse c `eqP` (unpackS . TL.intersperse c) t_transpose = unsquare (L.transpose `eq` (map unpackS . T.transpose . map packS)) tl_transpose = unsquare (L.transpose `eq` (map unpackS . TL.transpose . map TL.pack)) t_reverse = L.reverse `eqP` (unpackS . T.reverse) tl_reverse = L.reverse `eqP` (unpackS . TL.reverse) t_reverse_short n = L.reverse `eqP` (unpackS . S.reverse . shorten n . S.stream) t_replace s d = (L.intercalate d . split s) `eqP` (unpackS . T.replace (T.pack s) (T.pack d)) tl_replace s d = (L.intercalate d . split s) `eqP` (unpackS . TL.replace (TL.pack s) (TL.pack d)) split :: (Eq a) => [a] -> [a] -> [[a]] split pat src0 | l == 0 = error "empty" | otherwise = go src0 where l = length pat go src = search 0 src where search _ [] = [src] search !n s@(_:s') | pat `L.isPrefixOf` s = take n src : go (drop l s) | otherwise = search (n+1) s' s_toCaseFold_length xs = S.length (S.toCaseFold s) >= length xs where s = S.streamList xs sf_toCaseFold_length p xs = (S.length . S.toCaseFold . S.filter p $ s) >= (length . L.filter p $ xs) where s = S.streamList xs t_toCaseFold_length t = T.length (T.toCaseFold t) >= T.length t tl_toCaseFold_length t = TL.length (TL.toCaseFold t) >= TL.length t t_toLower_length t = T.length (T.toLower t) >= T.length t t_toLower_lower t = p (T.toLower t) >= p t where p = T.length . T.filter isLower tl_toLower_lower t = p (TL.toLower t) >= p t where p = TL.length . TL.filter isLower t_toUpper_length t = T.length (T.toUpper t) >= T.length t t_toUpper_upper t = p (T.toUpper t) >= p t where p = T.length . T.filter isUpper tl_toUpper_upper t = p (TL.toUpper t) >= p t where p = TL.length . TL.filter isUpper justifyLeft k c s = s ++ L.replicate (k - length s) c justifyRight m n s = L.replicate (m - length s) n ++ s s_justifyLeft k c = justifyLeft k c `eqP` (unpackS . S.justifyLeftI k c) s_justifyLeft_s k c = justifyLeft k c `eqP` (unpackS . S.unstream . S.justifyLeftI k c) sf_justifyLeft p k c = (justifyLeft k c . L.filter p) `eqP` (unpackS . S.justifyLeftI k c . S.filter p) t_justifyLeft k c = justifyLeft k c `eqP` (unpackS . T.justifyLeft k c) tl_justifyLeft k c = justifyLeft k c `eqP` (unpackS . TL.justifyLeft (fromIntegral k) c) t_justifyRight k c = justifyRight k c `eqP` (unpackS . T.justifyRight k c) tl_justifyRight k c = justifyRight k c `eqP` (unpackS . TL.justifyRight (fromIntegral k) c) sf_foldl p f z = (L.foldl f z . L.filter p) `eqP` (S.foldl f z . S.filter p) where _types = f :: Char -> Char -> Char t_foldl f z = L.foldl f z `eqP` (T.foldl f z) where _types = f :: Char -> Char -> Char tl_foldl f z = L.foldl f z `eqP` (TL.foldl f z) where _types = f :: Char -> Char -> Char sf_foldl' p f z = (L.foldl' f z . L.filter p) `eqP` (S.foldl' f z . S.filter p) where _types = f :: Char -> Char -> Char t_foldl' f z = L.foldl' f z `eqP` T.foldl' f z where _types = f :: Char -> Char -> Char tl_foldl' f z = L.foldl' f z `eqP` TL.foldl' f z where _types = f :: Char -> Char -> Char sf_foldl1 p f = (L.foldl1 f . L.filter p) `eqP` (S.foldl1 f . S.filter p) t_foldl1 f = L.foldl1 f `eqP` T.foldl1 f tl_foldl1 f = L.foldl1 f `eqP` TL.foldl1 f sf_foldl1' p f = (L.foldl1' f . L.filter p) `eqP` (S.foldl1' f . S.filter p) t_foldl1' f = L.foldl1' f `eqP` T.foldl1' f tl_foldl1' f = L.foldl1' f `eqP` TL.foldl1' f sf_foldr p f z = (L.foldr f z . L.filter p) `eqP` (S.foldr f z . S.filter p) where _types = f :: Char -> Char -> Char t_foldr f z = L.foldr f z `eqP` T.foldr f z where _types = f :: Char -> Char -> Char tl_foldr f z = L.foldr f z `eqP` TL.foldr f z where _types = f :: Char -> Char -> Char sf_foldr1 p f = (L.foldr1 f . L.filter p) `eqP` (S.foldr1 f . S.filter p) t_foldr1 f = L.foldr1 f `eqP` T.foldr1 f tl_foldr1 f = L.foldr1 f `eqP` TL.foldr1 f s_concat_s = unsquare (L.concat `eq` (unpackS . S.unstream . S.concat . map packS)) sf_concat p = unsquare ((L.concat . map (L.filter p)) `eq` (unpackS . S.concat . map (S.filter p . packS))) t_concat = unsquare (L.concat `eq` (unpackS . T.concat . map packS)) tl_concat = unsquare (L.concat `eq` (unpackS . TL.concat . map TL.pack)) sf_concatMap p f = unsquare ((L.concatMap f . L.filter p) `eqP` (unpackS . S.concatMap (packS . f) . S.filter p)) t_concatMap f = unsquare (L.concatMap f `eqP` (unpackS . T.concatMap (packS . f))) tl_concatMap f = unsquare (L.concatMap f `eqP` (unpackS . TL.concatMap (TL.pack . f))) sf_any q p = (L.any p . L.filter q) `eqP` (S.any p . S.filter q) t_any p = L.any p `eqP` T.any p tl_any p = L.any p `eqP` TL.any p sf_all q p = (L.all p . L.filter q) `eqP` (S.all p . S.filter q) t_all p = L.all p `eqP` T.all p tl_all p = L.all p `eqP` TL.all p sf_maximum p = (L.maximum . L.filter p) `eqP` (S.maximum . S.filter p) t_maximum = L.maximum `eqP` T.maximum tl_maximum = L.maximum `eqP` TL.maximum sf_minimum p = (L.minimum . L.filter p) `eqP` (S.minimum . S.filter p) t_minimum = L.minimum `eqP` T.minimum tl_minimum = L.minimum `eqP` TL.minimum sf_scanl p f z = (L.scanl f z . L.filter p) `eqP` (unpackS . S.scanl f z . S.filter p) t_scanl f z = L.scanl f z `eqP` (unpackS . T.scanl f z) tl_scanl f z = L.scanl f z `eqP` (unpackS . TL.scanl f z) t_scanl1 f = L.scanl1 f `eqP` (unpackS . T.scanl1 f) tl_scanl1 f = L.scanl1 f `eqP` (unpackS . TL.scanl1 f) t_scanr f z = L.scanr f z `eqP` (unpackS . T.scanr f z) tl_scanr f z = L.scanr f z `eqP` (unpackS . TL.scanr f z) t_scanr1 f = L.scanr1 f `eqP` (unpackS . T.scanr1 f) tl_scanr1 f = L.scanr1 f `eqP` (unpackS . TL.scanr1 f) t_mapAccumL f z = unsquare (L.mapAccumL f z `eqP` (second unpackS . T.mapAccumL f z)) where _types = f :: Int -> Char -> (Int,Char) tl_mapAccumL f z = unsquare (L.mapAccumL f z `eqP` (second unpackS . TL.mapAccumL f z)) where _types = f :: Int -> Char -> (Int,Char) t_mapAccumR f z = unsquare (L.mapAccumR f z `eqP` (second unpackS . T.mapAccumR f z)) where _types = f :: Int -> Char -> (Int,Char) tl_mapAccumR f z = unsquare (L.mapAccumR f z `eqP` (second unpackS . TL.mapAccumR f z)) where _types = f :: Int -> Char -> (Int,Char) replicate n l = concat (L.replicate n l) t_replicate n = replicate n `eq` (unpackS . T.replicate n . packS) tl_replicate n = replicate n `eq` (unpackS . TL.replicate (fromIntegral n) . packS) unf :: Int -> Char -> Maybe (Char, Char) unf n c | fromEnum c * 100 > n = Nothing | otherwise = Just (c, succ c) t_unfoldr n = L.unfoldr (unf n) `eq` (unpackS . T.unfoldr (unf n)) tl_unfoldr n = L.unfoldr (unf n) `eq` (unpackS . TL.unfoldr (unf n)) t_unfoldrN n m = (L.take n . L.unfoldr (unf m)) `eq` (unpackS . T.unfoldrN n (unf m)) tl_unfoldrN n m = (L.take n . L.unfoldr (unf m)) `eq` (unpackS . TL.unfoldrN (fromIntegral n) (unf m)) unpack2 :: (Stringy s) => (s,s) -> (String,String) unpack2 = unpackS *** unpackS s_take n = L.take n `eqP` (unpackS . S.take n) s_take_s m = L.take n `eqP` (unpackS . S.unstream . S.take n) where n = small m sf_take p n = (L.take n . L.filter p) `eqP` (unpackS . S.take n . S.filter p) t_take n = L.take n `eqP` (unpackS . T.take n) tl_take n = L.take n `eqP` (unpackS . TL.take (fromIntegral n)) s_drop n = L.drop n `eqP` (unpackS . S.drop n) s_drop_s m = L.drop n `eqP` (unpackS . S.unstream . S.drop n) where n = small m sf_drop p n = (L.drop n . L.filter p) `eqP` (unpackS . S.drop n . S.filter p) t_drop n = L.drop n `eqP` (unpackS . T.drop n) tl_drop n = L.drop n `eqP` (unpackS . TL.drop (fromIntegral n)) s_take_drop m = (L.take n . L.drop n) `eqP` (unpackS . S.take n . S.drop n) where n = small m s_take_drop_s m = (L.take n . L.drop n) `eqP` (unpackS . S.unstream . S.take n . S.drop n) where n = small m s_takeWhile p = L.takeWhile p `eqP` (unpackS . S.takeWhile p) s_takeWhile_s p = L.takeWhile p `eqP` (unpackS . S.unstream . S.takeWhile p) sf_takeWhile q p = (L.takeWhile p . L.filter q) `eqP` (unpackS . S.takeWhile p . S.filter q) t_takeWhile p = L.takeWhile p `eqP` (unpackS . T.takeWhile p) tl_takeWhile p = L.takeWhile p `eqP` (unpackS . TL.takeWhile p) s_dropWhile p = L.dropWhile p `eqP` (unpackS . S.dropWhile p) s_dropWhile_s p = L.dropWhile p `eqP` (unpackS . S.unstream . S.dropWhile p) sf_dropWhile q p = (L.dropWhile p . L.filter q) `eqP` (unpackS . S.dropWhile p . S.filter q) t_dropWhile p = L.dropWhile p `eqP` (unpackS . T.dropWhile p) tl_dropWhile p = L.dropWhile p `eqP` (unpackS . S.dropWhile p) t_dropWhileEnd p = (L.reverse . L.dropWhile p . L.reverse) `eqP` (unpackS . T.dropWhileEnd p) tl_dropWhileEnd p = (L.reverse . L.dropWhile p . L.reverse) `eqP` (unpackS . TL.dropWhileEnd p) t_dropAround p = (L.dropWhile p . L.reverse . L.dropWhile p . L.reverse) `eqP` (unpackS . T.dropAround p) tl_dropAround p = (L.dropWhile p . L.reverse . L.dropWhile p . L.reverse) `eqP` (unpackS . TL.dropAround p) t_stripStart = T.dropWhile isSpace `eq` T.stripStart tl_stripStart = TL.dropWhile isSpace `eq` TL.stripStart t_stripEnd = T.dropWhileEnd isSpace `eq` T.stripEnd tl_stripEnd = TL.dropWhileEnd isSpace `eq` TL.stripEnd t_strip = T.dropAround isSpace `eq` T.strip tl_strip = TL.dropAround isSpace `eq` TL.strip t_splitAt n = L.splitAt n `eqP` (unpack2 . T.splitAt n) tl_splitAt n = L.splitAt n `eqP` (unpack2 . TL.splitAt (fromIntegral n)) t_spanBy p = L.span p `eqP` (unpack2 . T.spanBy p) tl_spanBy p = L.span p `eqP` (unpack2 . TL.spanBy p) t_break_id s = squid `eq` (uncurry T.append . T.break s) where squid t | T.null s = error "empty" | otherwise = t tl_break_id s = squid `eq` (uncurry TL.append . TL.break s) where squid t | TL.null s = error "empty" | otherwise = t t_break_start (NotEmpty s) t = let (_,m) = T.break s t in T.null m || s `T.isPrefixOf` m tl_break_start (NotEmpty s) t = let (_,m) = TL.break s t in TL.null m || s `TL.isPrefixOf` m t_breakBy p = L.break p `eqP` (unpack2 . T.breakBy p) tl_breakBy p = L.break p `eqP` (unpack2 . TL.breakBy p) t_group = L.group `eqP` (map unpackS . T.group) tl_group = L.group `eqP` (map unpackS . TL.group) t_groupBy p = L.groupBy p `eqP` (map unpackS . T.groupBy p) tl_groupBy p = L.groupBy p `eqP` (map unpackS . TL.groupBy p) t_inits = L.inits `eqP` (map unpackS . T.inits) tl_inits = L.inits `eqP` (map unpackS . TL.inits) t_tails = L.tails `eqP` (map unpackS . T.tails) tl_tails = L.tails `eqP` (map unpackS . TL.tails) t_findSplit s t = (T.split s `eq` splitty) u where splitty v = case T.find s v of (x,xs) -> x : L.map (T.drop (T.length s) . fst) xs u = T.concat [t,s,t] tl_findSplit s t = (TL.split s `eq` splitty) u where splitty v = case TL.find s v of (x,xs) -> x : L.map (TL.drop (TL.length s) . fst) xs u = TL.concat [t,s,t] t_split_split s = unsquare ((T.split s `eq` Slow.split s) . T.intercalate s) tl_split_split s = unsquare (((TL.split (chunkify s) . chunkify) `eq` (map chunkify . T.split s)) . T.intercalate s) t_split_i (NotEmpty t) = id `eq` (T.intercalate t . T.split t) tl_split_i (NotEmpty t) = id `eq` (TL.intercalate t . TL.split t) t_splitBy p = splitBy p `eqP` (map unpackS . T.splitBy p) t_splitBy_count c = (L.length . T.splitBy (==c)) `eq` ((1+) . T.count (T.singleton c)) t_splitBy_split c = T.splitBy (==c) `eq` T.split (T.singleton c) tl_splitBy p = splitBy p `eqP` (map unpackS . TL.splitBy p) splitBy :: (a -> Bool) -> [a] -> [[a]] splitBy _ [] = [[]] splitBy p xs = loop xs where loop s | null s' = [l] | otherwise = l : loop (tail s') where (l, s') = break p s t_chunksOf_same_lengths k = all ((==k) . T.length) . ini . T.chunksOf k where ini [] = [] ini xs = init xs t_chunksOf_length k t = len == T.length t || (k <= 0 && len == 0) where len = L.sum . L.map T.length $ T.chunksOf k t chunkify = TL.fromChunks . (:[]) tl_chunksOf k = T.chunksOf k `eq` (map (T.concat . TL.toChunks) . TL.chunksOf (fromIntegral k) . chunkify) t_lines = L.lines `eqP` (map unpackS . T.lines) tl_lines = L.lines `eqP` (map unpackS . TL.lines) {- t_lines' = lines' `eqP` (map unpackS . T.lines') where lines' "" = [] lines' s = let (l, s') = break eol s in l : case s' of [] -> [] ('\r':'\n':s'') -> lines' s'' (_:s'') -> lines' s'' eol c = c == '\r' || c == '\n' -} t_words = L.words `eqP` (map unpackS . T.words) tl_words = L.words `eqP` (map unpackS . TL.words) t_unlines = unsquare (L.unlines `eq` (unpackS . T.unlines . map packS)) tl_unlines = unsquare (L.unlines `eq` (unpackS . TL.unlines . map packS)) t_unwords = unsquare (L.unwords `eq` (unpackS . T.unwords . map packS)) tl_unwords = unsquare (L.unwords `eq` (unpackS . TL.unwords . map packS)) s_isPrefixOf s = L.isPrefixOf s `eqP` (S.isPrefixOf (S.stream $ packS s) . S.stream) sf_isPrefixOf p s = (L.isPrefixOf s . L.filter p) `eqP` (S.isPrefixOf (S.stream $ packS s) . S.filter p . S.stream) t_isPrefixOf s = L.isPrefixOf s`eqP` T.isPrefixOf (packS s) tl_isPrefixOf s = L.isPrefixOf s`eqP` TL.isPrefixOf (packS s) t_isSuffixOf s = L.isSuffixOf s`eqP` T.isSuffixOf (packS s) tl_isSuffixOf s = L.isSuffixOf s`eqP` TL.isSuffixOf (packS s) t_isInfixOf s = L.isInfixOf s `eqP` T.isInfixOf (packS s) tl_isInfixOf s = L.isInfixOf s `eqP` TL.isInfixOf (packS s) sf_elem p c = (L.elem c . L.filter p) `eqP` (S.elem c . S.filter p) sf_filter q p = (L.filter p . L.filter q) `eqP` (unpackS . S.filter p . S.filter q) t_filter p = L.filter p `eqP` (unpackS . T.filter p) tl_filter p = L.filter p `eqP` (unpackS . TL.filter p) sf_findBy q p = (L.find p . L.filter q) `eqP` (S.findBy p . S.filter q) t_findBy p = L.find p `eqP` T.findBy p tl_findBy p = L.find p `eqP` TL.findBy p t_partition p = L.partition p `eqP` (unpack2 . T.partitionBy p) tl_partition p = L.partition p `eqP` (unpack2 . TL.partitionBy p) sf_index p s = forAll (choose (-l,l*2)) ((L.filter p s L.!!) `eq` S.index (S.filter p $ packS s)) where l = L.length s t_index s = forAll (choose (-l,l*2)) ((s L.!!) `eq` T.index (packS s)) where l = L.length s tl_index s = forAll (choose (-l,l*2)) ((s L.!!) `eq` (TL.index (packS s) . fromIntegral)) where l = L.length s t_findIndex p = L.findIndex p `eqP` T.findIndex p t_count t = (subtract 1 . L.length . T.split t) `eq` T.count t tl_count t = (subtract 1 . L.genericLength . TL.split t) `eq` TL.count t t_zip s = L.zip s `eqP` T.zip (packS s) tl_zip s = L.zip s `eqP` TL.zip (packS s) sf_zipWith p c s = (L.zipWith c (L.filter p s) . L.filter p) `eqP` (unpackS . S.zipWith c (S.filter p $ packS s) . S.filter p) t_zipWith c s = L.zipWith c s `eqP` (unpackS . T.zipWith c (packS s)) tl_zipWith c s = L.zipWith c s `eqP` (unpackS . TL.zipWith c (packS s)) t_indices = unsquare (\s -> Slow.indices s `eq` indices s) tl_indices = unsquare (\s -> lazyIndices s `eq` S.indices s) where lazyIndices s t = map fromIntegral $ Slow.indices (conc s) (conc t) conc = T.concat . TL.toChunks t_indices_occurs t = unsquare (\ts -> let s = T.intercalate t ts in Slow.indices t s == indices t s) -- Bit shifts. shiftL w = forAll (choose (0,width-1)) $ \k -> Bits.shiftL w k == U.shiftL w k where width = round (log (fromIntegral m) / log 2 :: Double) (m,_) = (maxBound, m == w) shiftR w = forAll (choose (0,width-1)) $ \k -> Bits.shiftR w k == U.shiftR w k where width = round (log (fromIntegral m) / log 2 :: Double) (m,_) = (maxBound, m == w) shiftL_Int = shiftL :: Int -> Property shiftL_Word16 = shiftL :: Word16 -> Property shiftL_Word32 = shiftL :: Word32 -> Property shiftR_Int = shiftR :: Int -> Property shiftR_Word16 = shiftR :: Word16 -> Property shiftR_Word32 = shiftR :: Word32 -> Property -- Regression tests. s_filter_eq s = S.filter p t == S.streamList (filter p s) where p = (/= S.last t) t = S.streamList s -- Make a stream appear shorter than it really is, to ensure that -- functions that consume inaccurately sized streams behave -- themselves. shorten :: Int -> S.Stream a -> S.Stream a shorten n t@(S.Stream arr off len) | n > 0 = S.Stream arr off (smaller (exactSize n) len) | otherwise = t main = defaultMain tests tests = [ testGroup "creation/elimination" [ testProperty "t_pack_unpack" t_pack_unpack, testProperty "tl_pack_unpack" tl_pack_unpack, testProperty "t_stream_unstream" t_stream_unstream, testProperty "tl_stream_unstream" tl_stream_unstream, testProperty "t_reverse_stream" t_reverse_stream, testProperty "t_singleton" t_singleton, testProperty "tl_singleton" tl_singleton, testProperty "tl_unstreamChunks" tl_unstreamChunks, testProperty "tl_chunk_unchunk" tl_chunk_unchunk ], testGroup "transcoding" [ testProperty "t_ascii" t_ascii, testProperty "t_utf8" t_utf8, testProperty "tl_utf8" tl_utf8, testProperty "t_utf16LE" t_utf16LE, testProperty "t_utf16BE" t_utf16BE, testProperty "t_utf32LE" t_utf32LE, testProperty "t_utf32BE" t_utf32BE ], testGroup "instances" [ testProperty "s_Eq" s_Eq, testProperty "sf_Eq" sf_Eq, testProperty "t_Eq" t_Eq, testProperty "tl_Eq" tl_Eq, testProperty "s_Ord" s_Ord, testProperty "sf_Ord" sf_Ord, testProperty "t_Ord" t_Ord, testProperty "tl_Ord" tl_Ord, testProperty "t_Read" t_Read, testProperty "tl_Read" tl_Read, testProperty "t_Show" t_Show, testProperty "tl_Show" tl_Show, testProperty "t_mappend" t_mappend, testProperty "tl_mappend" tl_mappend, testProperty "t_mconcat" t_mconcat, testProperty "tl_mconcat" tl_mconcat, testProperty "t_IsString" t_IsString, testProperty "tl_IsString" tl_IsString ], testGroup "basics" [ testProperty "s_cons" s_cons, testProperty "s_cons_s" s_cons_s, testProperty "sf_cons" sf_cons, testProperty "t_cons" t_cons, testProperty "tl_cons" tl_cons, testProperty "s_snoc" s_snoc, testProperty "t_snoc" t_snoc, testProperty "tl_snoc" tl_snoc, testProperty "s_append" s_append, testProperty "s_append_s" s_append_s, testProperty "sf_append" sf_append, testProperty "t_append" t_append, testProperty "s_uncons" s_uncons, testProperty "sf_uncons" sf_uncons, testProperty "t_uncons" t_uncons, testProperty "tl_uncons" tl_uncons, testProperty "s_head" s_head, testProperty "sf_head" sf_head, testProperty "t_head" t_head, testProperty "tl_head" tl_head, testProperty "s_last" s_last, testProperty "sf_last" sf_last, testProperty "t_last" t_last, testProperty "tl_last" tl_last, testProperty "s_tail" s_tail, testProperty "s_tail_s" s_tail_s, testProperty "sf_tail" sf_tail, testProperty "t_tail" t_tail, testProperty "tl_tail" tl_tail, testProperty "s_init" s_init, testProperty "s_init_s" s_init_s, testProperty "sf_init" sf_init, testProperty "t_init" t_init, testProperty "tl_init" tl_init, testProperty "s_null" s_null, testProperty "sf_null" sf_null, testProperty "t_null" t_null, testProperty "tl_null" tl_null, testProperty "s_length" s_length, testProperty "sf_length" sf_length, testProperty "t_length" t_length, testProperty "tl_length" tl_length ], testGroup "transformations" [ testProperty "s_map" s_map, testProperty "s_map_s" s_map_s, testProperty "sf_map" sf_map, testProperty "t_map" t_map, testProperty "tl_map" tl_map, testProperty "t_intercalate" t_intercalate, testProperty "tl_intercalate" tl_intercalate, testProperty "s_intersperse" s_intersperse, testProperty "s_intersperse_s" s_intersperse_s, testProperty "sf_intersperse" sf_intersperse, testProperty "t_intersperse" t_intersperse, testProperty "tl_intersperse" tl_intersperse, testProperty "t_transpose" t_transpose, testProperty "tl_transpose" tl_transpose, testProperty "t_reverse" t_reverse, testProperty "tl_reverse" tl_reverse, testProperty "t_reverse_short" t_reverse_short, testProperty "t_replace" t_replace, testProperty "tl_replace" tl_replace, testGroup "case conversion" [ testProperty "s_toCaseFold_length" s_toCaseFold_length, testProperty "sf_toCaseFold_length" sf_toCaseFold_length, testProperty "t_toCaseFold_length" t_toCaseFold_length, testProperty "tl_toCaseFold_length" tl_toCaseFold_length, testProperty "t_toLower_length" t_toLower_length, testProperty "t_toLower_lower" t_toLower_lower, testProperty "tl_toLower_lower" tl_toLower_lower, testProperty "t_toUpper_length" t_toUpper_length, testProperty "t_toUpper_upper" t_toUpper_upper, testProperty "tl_toUpper_upper" tl_toUpper_upper ], testGroup "justification" [ testProperty "s_justifyLeft" s_justifyLeft, testProperty "s_justifyLeft_s" s_justifyLeft_s, testProperty "sf_justifyLeft" sf_justifyLeft, testProperty "t_justifyLeft" t_justifyLeft, testProperty "tl_justifyLeft" tl_justifyLeft, testProperty "t_justifyRight" t_justifyRight, testProperty "tl_justifyRight" tl_justifyRight ] ], testGroup "folds" [ testProperty "sf_foldl" sf_foldl, testProperty "t_foldl" t_foldl, testProperty "tl_foldl" tl_foldl, testProperty "sf_foldl'" sf_foldl', testProperty "t_foldl'" t_foldl', testProperty "tl_foldl'" tl_foldl', testProperty "sf_foldl1" sf_foldl1, testProperty "t_foldl1" t_foldl1, testProperty "tl_foldl1" tl_foldl1, testProperty "t_foldl1'" t_foldl1', testProperty "sf_foldl1'" sf_foldl1', testProperty "tl_foldl1'" tl_foldl1', testProperty "sf_foldr" sf_foldr, testProperty "t_foldr" t_foldr, testProperty "tl_foldr" tl_foldr, testProperty "sf_foldr1" sf_foldr1, testProperty "t_foldr1" t_foldr1, testProperty "tl_foldr1" tl_foldr1, testGroup "special" [ testProperty "s_concat_s" s_concat_s, testProperty "sf_concat" sf_concat, testProperty "t_concat" t_concat, testProperty "tl_concat" tl_concat, testProperty "sf_concatMap" sf_concatMap, testProperty "t_concatMap" t_concatMap, testProperty "tl_concatMap" tl_concatMap, testProperty "sf_any" sf_any, testProperty "t_any" t_any, testProperty "tl_any" tl_any, testProperty "sf_all" sf_all, testProperty "t_all" t_all, testProperty "tl_all" tl_all, testProperty "sf_maximum" sf_maximum, testProperty "t_maximum" t_maximum, testProperty "tl_maximum" tl_maximum, testProperty "sf_minimum" sf_minimum, testProperty "t_minimum" t_minimum, testProperty "tl_minimum" tl_minimum ] ], testGroup "construction" [ testGroup "scans" [ testProperty "sf_scanl" sf_scanl, testProperty "t_scanl" t_scanl, testProperty "tl_scanl" tl_scanl, testProperty "t_scanl1" t_scanl1, testProperty "tl_scanl1" tl_scanl1, testProperty "t_scanr" t_scanr, testProperty "tl_scanr" tl_scanr, testProperty "t_scanr1" t_scanr1, testProperty "tl_scanr1" tl_scanr1 ], testGroup "mapAccum" [ testProperty "t_mapAccumL" t_mapAccumL, testProperty "tl_mapAccumL" tl_mapAccumL, testProperty "t_mapAccumR" t_mapAccumR, testProperty "tl_mapAccumR" tl_mapAccumR ], testGroup "unfolds" [ testProperty "t_replicate" t_replicate, testProperty "tl_replicate" tl_replicate, testProperty "t_unfoldr" t_unfoldr, testProperty "tl_unfoldr" tl_unfoldr, testProperty "t_unfoldrN" t_unfoldrN, testProperty "tl_unfoldrN" tl_unfoldrN ] ], testGroup "substrings" [ testGroup "breaking" [ testProperty "s_take" s_take, testProperty "s_take_s" s_take_s, testProperty "sf_take" sf_take, testProperty "t_take" t_take, testProperty "tl_take" tl_take, testProperty "s_drop" s_drop, testProperty "s_drop_s" s_drop_s, testProperty "sf_drop" sf_drop, testProperty "t_drop" t_drop, testProperty "tl_drop" tl_drop, testProperty "s_take_drop" s_take_drop, testProperty "s_take_drop_s" s_take_drop_s, testProperty "s_takeWhile" s_takeWhile, testProperty "s_takeWhile_s" s_takeWhile_s, testProperty "sf_takeWhile" sf_takeWhile, testProperty "t_takeWhile" t_takeWhile, testProperty "tl_takeWhile" tl_takeWhile, testProperty "sf_dropWhile" sf_dropWhile, testProperty "s_dropWhile" s_dropWhile, testProperty "s_dropWhile_s" s_dropWhile_s, testProperty "t_dropWhile" t_dropWhile, testProperty "tl_dropWhile" tl_dropWhile, testProperty "t_dropWhileEnd" t_dropWhileEnd, testProperty "tl_dropWhileEnd" tl_dropWhileEnd, testProperty "t_dropAround" t_dropAround, testProperty "tl_dropAround" tl_dropAround, testProperty "t_stripStart" t_stripStart, testProperty "tl_stripStart" tl_stripStart, testProperty "t_stripEnd" t_stripEnd, testProperty "tl_stripEnd" tl_stripEnd, testProperty "t_strip" t_strip, testProperty "tl_strip" tl_strip, testProperty "t_splitAt" t_splitAt, testProperty "tl_splitAt" tl_splitAt, testProperty "t_spanBy" t_spanBy, testProperty "tl_spanBy" tl_spanBy, testProperty "t_break_id" t_break_id, testProperty "tl_break_id" tl_break_id, testProperty "t_break_start" t_break_start, testProperty "tl_break_start" tl_break_start, testProperty "t_breakBy" t_breakBy, testProperty "tl_breakBy" tl_breakBy, testProperty "t_group" t_group, testProperty "tl_group" tl_group, testProperty "t_groupBy" t_groupBy, testProperty "tl_groupBy" tl_groupBy, testProperty "t_inits" t_inits, testProperty "tl_inits" tl_inits, testProperty "t_tails" t_tails, testProperty "tl_tails" tl_tails ], testGroup "breaking many" [ testProperty "t_findSplit" t_findSplit, testProperty "tl_findSplit" tl_findSplit, testProperty "t_split_split" t_split_split, testProperty "tl_split_split" tl_split_split, testProperty "t_split_i" t_split_i, testProperty "tl_split_i" tl_split_i, testProperty "t_splitBy" t_splitBy, testProperty "t_splitBy_count" t_splitBy_count, testProperty "t_splitBy_split" t_splitBy_split, testProperty "tl_splitBy" tl_splitBy, testProperty "t_chunksOf_same_lengths" t_chunksOf_same_lengths, testProperty "t_chunksOf_length" t_chunksOf_length, testProperty "tl_chunksOf" tl_chunksOf ], testGroup "lines and words" [ testProperty "t_lines" t_lines, testProperty "tl_lines" tl_lines, --testProperty "t_lines'" t_lines', testProperty "t_words" t_words, testProperty "tl_words" tl_words, testProperty "t_unlines" t_unlines, testProperty "tl_unlines" tl_unlines, testProperty "t_unwords" t_unwords, testProperty "tl_unwords" tl_unwords ] ], testGroup "predicates" [ testProperty "s_isPrefixOf" s_isPrefixOf, testProperty "sf_isPrefixOf" sf_isPrefixOf, testProperty "t_isPrefixOf" t_isPrefixOf, testProperty "tl_isPrefixOf" tl_isPrefixOf, testProperty "t_isSuffixOf" t_isSuffixOf, testProperty "tl_isSuffixOf" tl_isSuffixOf, testProperty "t_isInfixOf" t_isInfixOf, testProperty "tl_isInfixOf" tl_isInfixOf ], testGroup "searching" [ testProperty "sf_elem" sf_elem, testProperty "sf_filter" sf_filter, testProperty "t_filter" t_filter, testProperty "tl_filter" tl_filter, testProperty "sf_findBy" sf_findBy, testProperty "t_findBy" t_findBy, testProperty "tl_findBy" tl_findBy, testProperty "t_partition" t_partition, testProperty "tl_partition" tl_partition ], testGroup "indexing" [ testProperty "sf_index" sf_index, testProperty "t_index" t_index, testProperty "tl_index" tl_index, testProperty "t_findIndex" t_findIndex, testProperty "t_count" t_count, testProperty "tl_count" tl_count, testProperty "t_indices" t_indices, testProperty "tl_indices" tl_indices, testProperty "t_indices_occurs" t_indices_occurs ], testGroup "zips" [ testProperty "t_zip" t_zip, testProperty "tl_zip" tl_zip, testProperty "sf_zipWith" sf_zipWith, testProperty "t_zipWith" t_zipWith, testProperty "tl_zipWith" tl_zipWith ], testGroup "regressions" [ testProperty "s_filter_eq" s_filter_eq ], testGroup "shifts" [ testProperty "shiftL_Int" shiftL_Int, testProperty "shiftL_Word16" shiftL_Word16, testProperty "shiftL_Word32" shiftL_Word32, testProperty "shiftR_Int" shiftR_Int, testProperty "shiftR_Word16" shiftR_Word16, testProperty "shiftR_Word32" shiftR_Word32 ] ]