packages feed

ghcjs-base-0.2.0.0: test/Tests/Properties.hs

-- | QuickCheck properties for JSString, based on those from the text library.

{-# LANGUAGE BangPatterns, FlexibleInstances, OverloadedStrings,
             ScopedTypeVariables, TypeSynonymInstances #-}
{-# OPTIONS_GHC -fno-enable-rewrite-rules -fno-warn-missing-signatures #-}
module Tests.Properties
    (
      tests
    ) where

import Control.Applicative ((<$>), (<*>))
import Control.Arrow ((***), second)
import Data.Bits ((.&.))
import Data.Char (chr, isDigit, isHexDigit, isLower, isSpace, isUpper, ord)
-- import Data.Int (Int8, Int16, Int32, Int64)
import Data.Monoid (Monoid(..))
import Data.String (fromString)
-- import Data.Word (Word, Word8, Word16, Word32, Word64)
-- import Numeric (showEFloat, showFFloat, showGFloat, showHex)
import Prelude hiding (replicate)
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Test.QuickCheck hiding ((.&.))
import Test.QuickCheck.Monadic
import Test.QuickCheck.Property (Property(..))
import Test.Framework.Providers.HUnit (testCase)
import Test.HUnit ((@=?), Assertion)
import Text.Show.Functions ()
import qualified Control.Exception as Exception
import qualified Data.Bits as Bits (shiftL, shiftR)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.List as L
import Data.Word (Word, Word8, Word16, Word32, Word64)

import qualified System.IO as IO

import qualified Tests.SlowFunctions as Slow
import Tests.Properties.Numeric
import Tests.QuickCheckUtils
import Tests.Utils

import qualified Data.JSString as J
import qualified Data.JSString.Int as JI
import qualified Data.JSString.RealFloat as JR
import           Data.JSString.Internal.Search (indices)
import qualified Data.JSString.Internal.Fusion as S
import qualified Data.JSString.Internal.Fusion.Common as S

j_pack_unpack       = (J.unpack . J.pack) `eq` id
j_pack_unpack'      = (J.unpack' . J.pack) `eq` id
j_stream_unstream   = (S.unstream . S.stream) `eq` id
j_reverse_stream t  = (S.reverse . S.reverseStream) t == t
j_singleton c       = [c] == (J.unpack . J.singleton) c
j_singleton' c      = [c] == (J.unpack' . J.singleton) c

-- Insufficiently handled by quickcheck
packingAstralPlaneCharacter :: Assertion
packingAstralPlaneCharacter = J.unpack (J.pack "\120590") @=? "\120590"

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)
j_Eq s            = (s==)    `eq` ((J.pack s==) . J.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)
j_Ord s           = (compare s) `eq` (compare (J.pack s) . J.pack)
j_Read            = id       `eq` (J.unpack . read . show)
j_Show            = show     `eq` (show . J.pack)
j_mappend s       = mappend s`eqP` (unpackS . mappend (J.pack s))
j_mconcat         = unsquare $
                    mconcat `eq` (unpackS . mconcat . L.map J.pack)
j_mempty          = mempty == (unpackS (mempty :: J.JSString))
j_IsString        = fromString  `eqP` (J.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)
j_cons x          = (x:)     `eqP` (unpackS . J.cons x)
s_snoc x          = (++ [x]) `eqP` (unpackS . (flip S.snoc) x)
j_snoc x          = (++ [x]) `eqP` (unpackS . (flip J.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))
j_append s        = (s++)    `eqP` (unpackS . J.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)
j_uncons          = uncons   `eqP` (fmap (second unpackS) . J.uncons)
s_head            = head   `eqP` S.head
sf_head p         = (head . L.filter p) `eqP` (S.head . S.filter p)
j_head            = head   `eqP` J.head
s_last            = last   `eqP` S.last
sf_last p         = (last . L.filter p) `eqP` (S.last . S.filter p)
j_last            = last   `eqP` J.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)
j_tail            = tail   `eqP` (unpackS . J.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)
j_init            = init   `eqP` (unpackS . J.init)
s_null            = null   `eqP` S.null
sf_null p         = (null . L.filter p) `eqP` (S.null . S.filter p)
j_null            = null   `eqP` J.null
s_length          = length `eqP` S.length
sf_length p       = (length . L.filter p) `eqP` (S.length . S.filter p)
j_length          = length `eqP` J.length
j_compareLength t = (compare (J.length t)) `eq` J.compareLength t

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)
j_map f           = map f  `eqP` (unpackS . J.map f)
s_intercalate c   = unsquare $
                    L.intercalate c `eq`
                    (unpackS . S.intercalate (packS c) . map packS)
j_intercalate c   = unsquare $
                    L.intercalate c `eq`
                    (unpackS . J.intercalate (packS c) . map packS)
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)
j_intersperse c   = unsquare $
                    L.intersperse c `eqP` (unpackS . J.intersperse c)
j_transpose       = unsquare $
                    L.transpose `eq` (map unpackS . J.transpose . map packS)
j_reverse         = L.reverse `eqP` (unpackS . J.reverse)
-- s_reverse_short n = L.reverse `eqP` (unpackS . S.reverse . shorten n . S.stream)

j_replace s d     = (L.intercalate d . splitOn s) `eqP`
                    (unpackS . J.replace (J.pack s) (J.pack d))

splitOn :: (Show a, Eq a) => [a] -> [a] -> [[a]]
splitOn pat src0
    | l == 0    = error "splitOn: 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
j_toCaseFold_length t = J.length (J.toCaseFold t) >= J.length t
j_toLower_length t = J.length (J.toLower t) >= J.length t
j_toLower_lower t = p (J.toLower t) >= p t
    where p = J.length . J.filter isLower
j_toUpper_length t = J.length (J.toUpper t) >= J.length t
j_toUpper_upper t = p (J.toUpper t) >= p t
    where p = J.length . J.filter isUpper

justifyLeft k c xs  = xs ++ L.replicate (k - length xs) c
justifyRight m n xs = L.replicate (m - length xs) n ++ xs
center k c xs
    | len >= k  = xs
    | otherwise = L.replicate l c ++ xs ++ L.replicate r c
   where len = length xs
         d   = k - len
         r   = d `div` 2
         l   = d - r

s_justifyLeft k c = justifyLeft j c `eqP` (unpackS . S.justifyLeftI j c)
    where j = fromIntegral (k :: Word8)
s_justifyLeft_s k c = justifyLeft j c `eqP`
                      (unpackS . S.unstream . S.justifyLeftI j c)
    where j = fromIntegral (k :: Word8)
sf_justifyLeft p k c = (justifyLeft j c . L.filter p) `eqP`
                       (unpackS . S.justifyLeftI j c . S.filter p)
    where j = fromIntegral (k :: Word8)
j_justifyLeft k c = justifyLeft j c `eqP` (unpackS . J.justifyLeft j c)
    where j = fromIntegral (k :: Word8)
j_justifyRight k c = justifyRight j c `eqP` (unpackS . J.justifyRight j c)
    where j = fromIntegral (k :: Word8)

j_center k c = center j c `eqP` (unpackS . J.center j c)
    where j = fromIntegral (k :: Word8)

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
j_foldl f z       = L.foldl f z  `eqP` (J.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
j_foldl' f z      = L.foldl' f z `eqP` J.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)
j_foldl1 f        = L.foldl1 f   `eqP` J.foldl1 f
sf_foldl1' p f    = (L.foldl1' f . L.filter p) `eqP` (S.foldl1' f . S.filter p)
j_foldl1' f       = L.foldl1' f  `eqP` J.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
j_foldr f z       = L.foldr f z  `eqP` J.foldr f z
    where _types  = f :: Char -> Char -> Char
sf_foldr1 p f     = unsquare $
                    (L.foldr1 f . L.filter p) `eqP` (S.foldr1 f . S.filter p)
j_foldr1 f        = L.foldr1 f   `eqP` J.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))
j_concat          = unsquare $
                    L.concat `eq` (unpackS . J.concat . map packS)
sf_concatMap p f  = unsquare $ (L.concatMap f . L.filter p) `eqP`
                               (unpackS . S.concatMap (packS . f) . S.filter p)
j_concatMap f     = unsquare $
                    L.concatMap f `eqP` (unpackS . J.concatMap (packS . f))
sf_any q p        = (L.any p . L.filter q) `eqP` (S.any p . S.filter q)
j_any p           = L.any p       `eqP` J.any p
sf_all q p        = (L.all p . L.filter q) `eqP` (S.all p . S.filter q)
j_all p           = L.all p       `eqP` J.all p
sf_maximum p      = (L.maximum . L.filter p) `eqP` (S.maximum . S.filter p)
j_maximum         = L.maximum     `eqP` J.maximum
sf_minimum p      = (L.minimum . L.filter p) `eqP` (S.minimum . S.filter p)
j_minimum         = L.minimum     `eqP` J.minimum

sf_scanl p f z    = (L.scanl f z . L.filter p) `eqP`
                    (unpackS . S.scanl f z . S.filter p)
j_scanl f z       = L.scanl f z   `eqP` (unpackS . J.scanl f z)
j_scanl1 f        = L.scanl1 f    `eqP` (unpackS . J.scanl1 f)
j_scanr f z       = L.scanr f z   `eqP` (unpackS . J.scanr f z)
j_scanr1 f        = L.scanr1 f    `eqP` (unpackS . J.scanr1 f)

j_mapAccumL f z   = L.mapAccumL f z `eqP` (second unpackS . J.mapAccumL f z)
    where _types  = f :: Int -> Char -> (Int,Char)
j_mapAccumR f z   = L.mapAccumR f z `eqP` (second unpackS . J.mapAccumR f z)
    where _types  = f :: Int -> Char -> (Int,Char)

replicate n l = concat (L.replicate n l)

s_replicate n     = replicate m `eq`
                    (unpackS . S.replicateI (fromIntegral m) . packS)
    where m = fromIntegral (n :: Word8)
j_replicate n     = replicate m `eq` (unpackS . J.replicate m . packS)
    where m = fromIntegral (n :: Word8)

unf :: Int -> Char -> Maybe (Char, Char)
unf n c | fromEnum c * 100 > n = Nothing
        | otherwise            = Just (c, succ c)

j_unfoldr n       = L.unfoldr (unf m) `eq` (unpackS . J.unfoldr (unf m))
    where m = fromIntegral (n :: Word16)
j_unfoldrN n m    = (L.take i . L.unfoldr (unf j)) `eq`
                         (unpackS . J.unfoldrN i (unf j))
    where i = fromIntegral (n :: Word16)
          j = fromIntegral (m :: Word16)

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)
j_take n          = L.take n      `eqP` (unpackS . J.take n)
j_takeEnd n       = (L.reverse . L.take n . L.reverse) `eqP`
                    (unpackS . J.takeEnd 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)
j_drop n          = L.drop n      `eqP` (unpackS . J.drop n)
j_dropEnd n       = (L.reverse . L.drop n . L.reverse) `eqP`
                    (unpackS . J.dropEnd 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)
j_takeWhile p     = L.takeWhile p `eqP` (unpackS . J.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)
j_dropWhile p     = L.dropWhile p `eqP` (unpackS . J.dropWhile p)
j_dropWhileEnd p  = (L.reverse . L.dropWhile p . L.reverse) `eqP`
                    (unpackS . J.dropWhileEnd p)
j_dropAround p    = (L.dropWhile p . L.reverse . L.dropWhile p . L.reverse)
                    `eqP` (unpackS . J.dropAround p)
j_stripStart      = J.dropWhile isSpace `eq` J.stripStart
j_stripEnd        = J.dropWhileEnd isSpace `eq` J.stripEnd
j_strip           = J.dropAround isSpace `eq` J.strip
j_splitAt n       = L.splitAt n   `eqP` (unpack2 . J.splitAt n)
j_span p          = L.span p      `eqP` (unpack2 . J.span p)

j_breakOn_id s      = squid `eq` (uncurry J.append . J.breakOn s)
  where squid t | J.null s  = error "empty"
                | otherwise = t
j_breakOn_start (NotEmpty s) t =
    let (k,m) = J.breakOn s t
    in k `J.isPrefixOf` t && (J.null m || s `J.isPrefixOf` m)
j_breakOnEnd_end (NotEmpty s) t =
    let (m,k) = J.breakOnEnd s t
    in k `J.isSuffixOf` t && (J.null m || s `J.isSuffixOf` m)
j_break p       = L.break p     `eqP` (unpack2 . J.break p)
j_group           = L.group       `eqP` (map unpackS . J.group)
j_groupBy p       = L.groupBy p   `eqP` (map unpackS . J.groupBy p)
j_inits           = L.inits       `eqP` (map unpackS . J.inits)
j_tails           = L.tails       `eqP` (map unpackS . J.tails)
j_findAppendId = unsquare $ \(NotEmpty s) ts ->
    let t = J.intercalate s ts
    in all (==t) $ map (uncurry J.append) (J.breakOnAll s t)

j_findContains = unsquare $ \(NotEmpty s) ->
    all (J.isPrefixOf s . snd) . J.breakOnAll s . J.intercalate s
j_findContains' = unsquare $ \(NotEmpty s) ->
    all (J.isPrefixOf s . snd) . J.breakOnAll' s . J.intercalate s

j_findCount s     = (L.length . J.breakOnAll s) `eq` J.count s
j_findCount' s    = (L.length . J.breakOnAll' s) `eq` J.count s

j_splitOn_split s  = unsquare $
                     (J.splitOn s `eq` Slow.splitOn s) . J.intercalate s
j_splitOn'_split s  = unsquare $
                     (J.splitOn' s `eq` Slow.splitOn s) . J.intercalate s
j_splitOn_i (NotEmpty t)  = id `eq` (J.intercalate t . J.splitOn t)
j_splitOn'_i (NotEmpty t)  = id `eq` (J.intercalate t . J.splitOn' t)

j_split p       = split p `eqP` (map unpackS . J.split p)
j_split_count c = (L.length . J.split (==c)) `eq`
                  ((1+) . J.count (J.singleton c))
j_split_splitOn c = J.split (==c) `eq` J.splitOn (J.singleton c)
j_split_splitOn' c = J.split (==c) `eq` J.splitOn' (J.singleton c)

split :: (a -> Bool) -> [a] -> [[a]]
split _ [] =  [[]]
split p xs = loop xs
    where loop s | null s'   = [l]
                 | otherwise = l : loop (tail s')
              where (l, s') = break p s

j_chunksOf_same_lengths k = all ((==k) . J.length) . ini . J.chunksOf k
  where ini [] = []
        ini xs = init xs
j_chunksOf_same_lengths' k = all ((==k) . J.length) . ini . J.chunksOf' k
  where ini [] = []
        ini xs = init xs

j_chunksOf_length k t = len == J.length t || (k <= 0 && len == 0)
  where len = L.sum . L.map J.length $ J.chunksOf k t
j_chunksOf_length' k t = len == J.length t || (k <= 0 && len == 0)
  where len = L.sum . L.map J.length $ J.chunksOf' k t

j_lines           = L.lines       `eqP` (map unpackS . J.lines)
j_lines'          = L.lines       `eqP` (map unpackS . J.lines')

j_words           = L.words       `eqP` (map unpackS . J.words)
j_words'          = L.words       `eqP` (map unpackS . J.words')

j_unlines         = unsquare $
                    L.unlines `eq` (unpackS . J.unlines . map packS)
j_unwords         = unsquare $
                    L.unwords `eq` (unpackS . J.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)
j_isPrefixOf s    = L.isPrefixOf s`eqP` J.isPrefixOf (packS s)
j_isSuffixOf s    = L.isSuffixOf s`eqP` J.isSuffixOf (packS s)
j_isInfixOf s     = L.isInfixOf s `eqP` J.isInfixOf (packS s)

j_stripPrefix s      = (fmap packS . L.stripPrefix s) `eqP` J.stripPrefix (packS s)

stripSuffix p t = reverse `fmap` L.stripPrefix (reverse p) (reverse t)

j_stripSuffix s      = (fmap packS . stripSuffix s) `eqP` J.stripSuffix (packS s)

commonPrefixes a0@(_:_) b0@(_:_) = Just (go a0 b0 [])
    where go (a:as) (b:bs) ps
              | a == b = go as bs (a:ps)
          go as bs ps  = (reverse ps,as,bs)
commonPrefixes _ _ = Nothing

j_commonPrefixes a b (NonEmpty p)
    = commonPrefixes pa pb ==
      repack `fmap` J.commonPrefixes (packS pa) (packS pb)
  where repack (x,y,z) = (unpackS x,unpackS y,unpackS z)
        pa = p ++ a
        pb = p ++ b

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)
j_filter p        = L.filter p    `eqP` (unpackS . J.filter p)
sf_findBy q p     = (L.find p . L.filter q) `eqP` (S.findBy p . S.filter q)
j_find p          = L.find p      `eqP` J.find p
j_partition p     = L.partition p `eqP` (unpack2 . J.partition 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
j_index s         = forAll (choose (-l,l*2)) ((s L.!!) `eq` J.index (packS s))
    where l = L.length s

j_findIndex p     = L.findIndex p `eqP` J.findIndex p
j_count (NotEmpty t)  = (subtract 1 . L.length . J.splitOn t) `eq` J.count t
j_zip s           = L.zip s `eqP` J.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)
j_zipWith c s     = L.zipWith c s `eqP` (unpackS . J.zipWith c (packS s))

j_indices  (NotEmpty s) = Slow.indices s `eq` indices s
j_indices_occurs = unsquare $ \(NotEmpty t) ts ->
    let s = J.intercalate t ts
    in Slow.indices t s == indices t s

-- Reading.
{-
j_decimal (n::Int) s =
    J.signed J.decimal (J.pack (show n) `J.append` t) == Right (n,t)
    where t = J.dropWhile isDigit s
j_hexadecimal m s ox =
    J.hexadecimal (J.concat [p, J.pack (showHex n ""), t]) == Right (n,t)
    where t = J.dropWhile isHexDigit s
          p = if ox then "0x" else ""
          n = getPositive m :: Int

isFloaty c = c `elem` "+-.0123456789eE"

j_read_rational p tol (n::Double) s =
    case p (J.pack (show n) `J.append` t) of
      Left _err     -> False
      Right (n',t') -> t == t' && abs (n-n') <= tol
    where t = J.dropWhile isFloaty s

j_double = j_read_rational J.double 1e-13
j_rational = j_read_rational J.rational 1e-16
-}
-- Input and output.
{-
t_put_get = write_read T.unlines T.filter put get
  where put h = withRedirect h IO.stdout . T.putStr
        get h = withRedirect h IO.stdin T.getContents
tl_put_get = write_read TL.unlines TL.filter put get
  where put h = withRedirect h IO.stdout . TL.putStr
        get h = withRedirect h IO.stdin TL.getContents
t_write_read = write_read T.unlines T.filter T.hPutStr T.hGetContents
tl_write_read = write_read TL.unlines TL.filter TL.hPutStr TL.hGetContents

t_write_read_line e m b t = write_read head T.filter T.hPutStrLn
                            T.hGetLine e m b [t]
tl_write_read_line e m b t = write_read head TL.filter TL.hPutStrLn
                             TL.hGetLine e m b [t]
-}
-- Low-level.
{-
j_dropWord16 m t = dropWord16 m t `J.isSuffixOf` t
j_takeWord16 m t = takeWord16 m t `J.isPrefixOf` t
j_take_drop_16 m t = J.append (takeWord16 n t) (dropWord16 n t) == t
  where n = small m
j_use_from t = monadicIO $ assert . (==t) =<< run (useAsPtr t fromPtr)
-}
-- Regression tests.
s_filter_eq s = S.filter p t == S.streamList (filter p s)
    where p = (/= S.last t)
          t = S.streamList s

tests :: Test
tests =
  testGroup "Properties" [
    testGroup "creation/elimination" [
      testProperty "j_pack_unpack" j_pack_unpack,
      testProperty "j_pack_unpack'" j_pack_unpack',
      testCase "packing astral plane character" packingAstralPlaneCharacter,
      testProperty "j_stream_unstream" j_stream_unstream,
      testProperty "j_reverse_stream" j_reverse_stream,
      testProperty "j_singleton" j_singleton,
      testProperty "j_singleton'" j_singleton'
    ],

    testGroup "instances" [
      testProperty "s_Eq" s_Eq,
      testProperty "sf_Eq" sf_Eq,
      testProperty "j_Eq" j_Eq,
      testProperty "s_Ord" s_Ord,
      testProperty "sf_Ord" sf_Ord,
      testProperty "j_Ord" j_Ord,
      testProperty "j_Read" j_Read,
      testProperty "j_Show" j_Show,
      testProperty "j_mappend" j_mappend,
      testProperty "j_mconcat" j_mconcat,
      testProperty "j_mempty" j_mempty,
      testProperty "j_IsString" j_IsString
    ],

    testGroup "basics" [
      testProperty "s_cons" s_cons,
      testProperty "s_cons_s" s_cons_s,
      testProperty "sf_cons" sf_cons,
      testProperty "j_cons" j_cons,
      testProperty "s_snoc" s_snoc,
      testProperty "j_snoc" j_snoc,
      testProperty "s_append" s_append,
      testProperty "s_append_s" s_append_s,
      testProperty "sf_append" sf_append,
      testProperty "j_append" j_append,
      testProperty "s_uncons" s_uncons,
      testProperty "sf_uncons" sf_uncons,
      testProperty "j_uncons" j_uncons,
      testProperty "s_head" s_head,
      testProperty "sf_head" sf_head,
      testProperty "j_head" j_head,
      testProperty "s_last" s_last,
      testProperty "sf_last" sf_last,
      testProperty "j_last" j_last,
      testProperty "s_tail" s_tail,
      testProperty "s_tail_s" s_tail_s,
      testProperty "sf_tail" sf_tail,
      testProperty "j_tail" j_tail,
      testProperty "s_init" s_init,
      testProperty "s_init_s" s_init_s,
      testProperty "sf_init" sf_init,
      testProperty "j_init" j_init,
      testProperty "s_null" s_null,
      testProperty "sf_null" sf_null,
      testProperty "j_null" j_null,
      testProperty "s_length" s_length,
      testProperty "sf_length" sf_length,
--      testProperty "sl_length" sl_length,
      testProperty "j_length" j_length,
      testProperty "j_compareLength" j_compareLength
    ],

    testGroup "transformations" [
      testProperty "s_map" s_map,
      testProperty "s_map_s" s_map_s,
      testProperty "sf_map" sf_map,
      testProperty "j_map" j_map,
      testProperty "s_intercalate" s_intercalate,
      testProperty "j_intercalate" j_intercalate,
      testProperty "s_intersperse" s_intersperse,
      testProperty "s_intersperse_s" s_intersperse_s,
      testProperty "sf_intersperse" sf_intersperse,
      testProperty "j_intersperse" j_intersperse,
      testProperty "j_transpose" j_transpose,
      testProperty "j_reverse" j_reverse,
--      testProperty "s_reverse_short" s_reverse_short,
      testProperty "j_replace" j_replace,

      testGroup "case conversion" [
        testProperty "s_toCaseFold_length" s_toCaseFold_length,
        testProperty "sf_toCaseFold_length" sf_toCaseFold_length,
        testProperty "j_toCaseFold_length" j_toCaseFold_length,
        testProperty "j_toLower_length" j_toLower_length,
        testProperty "j_toLower_lower" j_toLower_lower,
        testProperty "j_toUpper_length" j_toUpper_length,
        testProperty "j_toUpper_upper" j_toUpper_upper
      ],

      testGroup "justification" [
        testProperty "s_justifyLeft" s_justifyLeft,
        testProperty "s_justifyLeft_s" s_justifyLeft_s,
        testProperty "sf_justifyLeft" sf_justifyLeft,
        testProperty "j_justifyLeft" j_justifyLeft,
        testProperty "j_justifyRight" j_justifyRight,
        testProperty "j_center" j_center
      ]
    ],

    testGroup "folds" [
      testProperty "sf_foldl" sf_foldl,
      testProperty "j_foldl" j_foldl,
      testProperty "sf_foldl'" sf_foldl',
      testProperty "j_foldl'" j_foldl',
      testProperty "sf_foldl1" sf_foldl1,
      testProperty "j_foldl1" j_foldl1,
      testProperty "j_foldl1'" j_foldl1',
      testProperty "sf_foldl1'" sf_foldl1',
      testProperty "sf_foldr" sf_foldr,
      testProperty "j_foldr" j_foldr,
      testProperty "sf_foldr1" sf_foldr1,
      testProperty "j_foldr1" j_foldr1,

      testGroup "special" [
        testProperty "s_concat_s" s_concat_s,
        testProperty "sf_concat" sf_concat,
        testProperty "j_concat" j_concat,
        testProperty "sf_concatMap" sf_concatMap,
        testProperty "j_concatMap" j_concatMap,
        testProperty "sf_any" sf_any,
        testProperty "j_any" j_any,
        testProperty "sf_all" sf_all,
        testProperty "j_all" j_all,
        testProperty "sf_maximum" sf_maximum,
        testProperty "j_maximum" j_maximum,
        testProperty "sf_minimum" sf_minimum,
        testProperty "j_minimum" j_minimum
      ]
    ],

    testGroup "construction" [
      testGroup "scans" [
        testProperty "sf_scanl" sf_scanl,
        testProperty "j_scanl" j_scanl,
        testProperty "j_scanl1" j_scanl1,
        testProperty "j_scanr" j_scanr,
        testProperty "j_scanr1" j_scanr1
      ],

      testGroup "mapAccum" [
        testProperty "j_mapAccumL" j_mapAccumL,
        testProperty "j_mapAccumR" j_mapAccumR
      ],

      testGroup "unfolds" [
        testProperty "s_replicate" s_replicate,
        testProperty "j_replicate" j_replicate,
        testProperty "j_unfoldr" j_unfoldr,
        testProperty "j_unfoldrN" j_unfoldrN
      ]
    ],

    testGroup "substrings" [
      testGroup "breaking" [
        testProperty "s_take" s_take,
        testProperty "s_take_s" s_take_s,
        testProperty "sf_take" sf_take,
        testProperty "j_take" j_take,
        testProperty "j_takeEnd" j_takeEnd,
        testProperty "s_drop" s_drop,
        testProperty "s_drop_s" s_drop_s,
        testProperty "sf_drop" sf_drop,
        testProperty "j_drop" j_drop,
        testProperty "j_dropEnd" j_dropEnd,
        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 "j_takeWhile" j_takeWhile,
        testProperty "sf_dropWhile" sf_dropWhile,
        testProperty "s_dropWhile" s_dropWhile,
        testProperty "s_dropWhile_s" s_dropWhile_s,
        testProperty "j_dropWhile" j_dropWhile,
        testProperty "j_dropWhileEnd" j_dropWhileEnd,
        testProperty "j_dropAround" j_dropAround,
        testProperty "j_stripStart" j_stripStart,
        testProperty "j_stripEnd" j_stripEnd,
        testProperty "j_strip" j_strip,
        testProperty "j_splitAt" j_splitAt,
        testProperty "j_span" j_span,
        testProperty "j_breakOn_id" j_breakOn_id,
        testProperty "j_breakOn_start" j_breakOn_start,
        testProperty "j_breakOnEnd_end" j_breakOnEnd_end,
        testProperty "j_break" j_break,
        testProperty "j_group" j_group,
        testProperty "j_groupBy" j_groupBy,
        testProperty "j_inits" j_inits,
        testProperty "j_tails" j_tails
      ],

      testGroup "breaking many" [
        testProperty "j_findAppendId" j_findAppendId,
        testProperty "j_findContains" j_findContains,
        testProperty "j_findContains'" j_findContains',
--        testProperty "sl_filterCount" sl_filterCount,
        testProperty "j_findCount" j_findCount,
        testProperty "j_findCount'" j_findCount',
        testProperty "j_splitOn_split" j_splitOn_split,
        testProperty "j_splitOn'_split" j_splitOn'_split,
        testProperty "j_splitOn_i" j_splitOn_i,
        testProperty "j_splitOn'_i" j_splitOn'_i,
        testProperty "j_split" j_split,
        testProperty "j_split_count" j_split_count,
        testProperty "j_split_splitOn" j_split_splitOn,
        testProperty "j_split_splitOn'" j_split_splitOn',
        testProperty "j_chunksOf_same_lengths" j_chunksOf_same_lengths,
        testProperty "j_chunksOf_same_lengths'" j_chunksOf_same_lengths',
        testProperty "j_chunksOf_length" j_chunksOf_length,
        testProperty "j_chunksOf_length'" j_chunksOf_length'
      ],

      testGroup "lines and words" [
        testProperty "j_lines" j_lines,
        testProperty "j_lines'" j_lines',
        testProperty "j_words" j_words,
        testProperty "j_words'" j_words',
        testProperty "j_unlines" j_unlines,
        testProperty "j_unwords" j_unwords
      ]
    ],

    testGroup "predicates" [
      testProperty "s_isPrefixOf" s_isPrefixOf,
      testProperty "sf_isPrefixOf" sf_isPrefixOf,
      testProperty "j_isPrefixOf" j_isPrefixOf,
      testProperty "j_isSuffixOf" j_isSuffixOf,
      testProperty "j_isInfixOf" j_isInfixOf,

      testGroup "view" [
        testProperty "j_stripPrefix" j_stripPrefix,
        testProperty "j_stripSuffix" j_stripSuffix,
        testProperty "j_commonPrefixes" j_commonPrefixes
      ]
    ],

    testGroup "searching" [
      testProperty "sf_elem" sf_elem,
      testProperty "sf_filter" sf_filter,
      testProperty "j_filter" j_filter,
      testProperty "sf_findBy" sf_findBy,
      testProperty "j_find" j_find,
      testProperty "j_partition" j_partition
    ],

    testGroup "indexing" [
      testProperty "sf_index" sf_index,
      testProperty "j_index" j_index,
      testProperty "j_findIndex" j_findIndex,
      testProperty "j_count" j_count,
      testProperty "j_indices" j_indices,
      testProperty "j_indices_occurs" j_indices_occurs
    ],

    testGroup "zips" [
      testProperty "j_zip" j_zip,
      testProperty "sf_zipWith" sf_zipWith,
      testProperty "j_zipWith" j_zipWith
    ],

    testGroup "numeric conversion" [
      testGroup "integral" [
        testProperty "j_decimal_integer"     j_decimal_integer,
        testProperty "j_decimal_int"         j_decimal_int,
        testProperty "j_decimal_int8"        j_decimal_int8,
        testProperty "j_decimal_int16"       j_decimal_int16,
        testProperty "j_decimal_int32"       j_decimal_int32,
        testProperty "j_decimal_int64"       j_decimal_int64,
        testProperty "j_decimal_word"        j_decimal_word,
        testProperty "j_decimal_word8"       j_decimal_word8,
        testProperty "j_decimal_word16"      j_decimal_word16,
        testProperty "j_decimal_word32"      j_decimal_word32,
        testProperty "j_decimal_word64"      j_decimal_word64,

        testProperty "j_decimal_integer_big" j_decimal_integer_big,
        testProperty "j_decimal_int_big"     j_decimal_int_big,
        testProperty "j_decimal_int64_big"   j_decimal_int64_big,
        testProperty "j_decimal_word_big"    j_decimal_word_big,
        testProperty "j_decimal_word64_big"  j_decimal_word64_big,

        testProperty "j_hexadecimal_integer" j_hexadecimal_integer,
        testProperty "j_hexadecimal_int"     j_hexadecimal_int,
        testProperty "j_hexadecimal_int8"    j_hexadecimal_int8,
        testProperty "j_hexadecimal_int16"   j_hexadecimal_int16,
        testProperty "j_hexadecimal_int32"   j_hexadecimal_int32,
        testProperty "j_hexadecimal_int64"   j_hexadecimal_int64,
        testProperty "j_hexadecimal_word"    j_hexadecimal_word,
        testProperty "j_hexadecimal_word8"   j_hexadecimal_word8,
        testProperty "j_hexadecimal_word16"  j_hexadecimal_word16,
        testProperty "j_hexadecimal_word32"  j_hexadecimal_word32,
        testProperty "j_hexadecimal_word64"  j_hexadecimal_word64
      ],
      testGroup "realfloat" [
        -- disabled due to rounding differences
        -- testProperty "j_realfloat_double"       j_realfloat_double,
        -- testProperty "j_formatRealFloat_double" j_formatRealFloat_double
      ]
    ],

    testGroup "regressions" [
      testProperty "s_filter_eq" s_filter_eq
    ]
  ]