@@ -1,10 +1,10 @@
1-- | General quicktest properties for the text library
1-- | General quicktest properties for the text library
3−{-# LANGUAGE BangPatterns, FlexibleInstances, OverloadedStrings,
3+{-# LANGUAGE BangPatterns, CPP, FlexibleInstances, OverloadedStrings,
4− ScopedTypeVariables, TypeSynonymInstances, CPP #-}
4+ ScopedTypeVariables, TypeSynonymInstances #-}
5{-# OPTIONS_GHC -fno-enable-rewrite-rules #-}
5{-# OPTIONS_GHC -fno-enable-rewrite-rules #-}
6{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
6{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
7−module Data.Text.Tests.Properties
7+module Tests.Properties
@@ -16,6 +16,7 @@ import Text.Show.Functions ()
16import Control.Arrow ((***), second)
16import Control.Arrow ((***), second)
17import Control.Exception (catch)
17import Control.Exception (catch)
18import Data.Char (chr, isDigit, isHexDigit, isLower, isSpace, isUpper, ord)
18import Data.Char (chr, isDigit, isHexDigit, isLower, isSpace, isUpper, ord)
19+import Data.Int (Int8, Int16, Int32, Int64)
19import Data.Monoid (Monoid(..))
20import Data.Monoid (Monoid(..))
20import Data.String (fromString)
21import Data.String (fromString)
21import Data.Text.Encoding.Error
22import Data.Text.Encoding.Error
@@ -24,13 +25,13 @@ import Data.Text.Fusion.Size
24import Data.Text.Lazy.Read as TL
25import Data.Text.Lazy.Read as TL
25import Data.Text.Read as T
26import Data.Text.Read as T
26import Data.Text.Search (indices)
27import Data.Text.Search (indices)
27−import Data.Word (Word8, Word16, Word32)
28+import Data.Word (Word, Word8, Word16, Word32, Word64)
28import Numeric (showHex)
29import Numeric (showHex)
29−import Prelude hiding (catch, replicate)
30import Test.Framework (Test, testGroup)
30import Test.Framework (Test, testGroup)
31import Test.Framework.Providers.QuickCheck2 (testProperty)
31import Test.Framework.Providers.QuickCheck2 (testProperty)
32import qualified Data.Bits as Bits (shiftL, shiftR)
32import qualified Data.Bits as Bits (shiftL, shiftR)
33import qualified Data.ByteString as B
33import qualified Data.ByteString as B
34+import qualified Data.ByteString.Lazy as BL
34import qualified Data.List as L
35import qualified Data.List as L
35import qualified Data.Text as T
36import qualified Data.Text as T
36import qualified Data.Text.Encoding as E
37import qualified Data.Text.Encoding as E
@@ -39,6 +40,8 @@ import qualified Data.Text.Fusion.Common as S
39import qualified Data.Text.IO as T
40import qualified Data.Text.IO as T
40import qualified Data.Text.Lazy as TL
41import qualified Data.Text.Lazy as TL
41import qualified Data.Text.Lazy.Builder as TB
42import qualified Data.Text.Lazy.Builder as TB
43+import qualified Data.Text.Lazy.Builder.Int as TB
44+import qualified Data.Text.Lazy.Builder.RealFloat as TB
42import qualified Data.Text.Lazy.Encoding as EL
45import qualified Data.Text.Lazy.Encoding as EL
43import qualified Data.Text.Lazy.Fusion as SL
46import qualified Data.Text.Lazy.Fusion as SL
44import qualified Data.Text.Lazy.IO as TL
47import qualified Data.Text.Lazy.IO as TL
@@ -46,9 +49,15 @@ import qualified Data.Text.Lazy.Search as S (indices)
46import qualified Data.Text.UnsafeShift as U
49import qualified Data.Text.UnsafeShift as U
47import qualified System.IO as IO
50import qualified System.IO as IO
49−import Data.Text.Tests.QuickCheckUtils
52+import Tests.QuickCheckUtils
50−import Data.Text.Tests.Utils
53+import Tests.Utils
51−import qualified Data.Text.Tests.SlowFunctions as Slow
54+import qualified Tests.SlowFunctions as Slow
56+#if MIN_VERSION_base(4,6,0)
57+import Prelude hiding (replicate)
59+import Prelude hiding (catch, replicate)
53t_pack_unpack = (T.unpack . T.pack) `eq` id
62t_pack_unpack = (T.unpack . T.pack) `eq` id
54tl_pack_unpack = (TL.unpack . TL.pack) `eq` id
63tl_pack_unpack = (TL.unpack . TL.pack) `eq` id
@@ -62,10 +71,20 @@ tl_unstreamChunks x = f 11 x == f 1000 x
62tl_chunk_unchunk = (TL.fromChunks . TL.toChunks) `eq` id
71tl_chunk_unchunk = (TL.fromChunks . TL.toChunks) `eq` id
63tl_from_to_strict = (TL.fromStrict . TL.toStrict) `eq` id
72tl_from_to_strict = (TL.fromStrict . TL.toStrict) `eq` id
74+-- Note: this silently truncates code-points > 255 to 8-bit due to 'B.pack'
75+encodeL1 :: T.Text -> B.ByteString
76+encodeL1 = B.pack . map (fromIntegral . fromEnum) . T.unpack
77+encodeLazyL1 :: TL.Text -> BL.ByteString
78+encodeLazyL1 = BL.fromChunks . map encodeL1 . TL.toChunks
65t_ascii t = E.decodeASCII (E.encodeUtf8 a) == a
80t_ascii t = E.decodeASCII (E.encodeUtf8 a) == a
66 where a = T.map (\c -> chr (ord c `mod` 128)) t
81 where a = T.map (\c -> chr (ord c `mod` 128)) t
67tl_ascii t = EL.decodeASCII (EL.encodeUtf8 a) == a
82tl_ascii t = EL.decodeASCII (EL.encodeUtf8 a) == a
68 where a = TL.map (\c -> chr (ord c `mod` 128)) t
83 where a = TL.map (\c -> chr (ord c `mod` 128)) t
84+t_latin1 t = E.decodeLatin1 (encodeL1 a) == a
85+ where a = T.map (\c -> chr (ord c `mod` 256)) t
86+tl_latin1 t = EL.decodeLatin1 (encodeLazyL1 a) == a
87+ where a = TL.map (\c -> chr (ord c `mod` 256)) t
69t_utf8 = forAll genUnicode $ (E.decodeUtf8 . E.encodeUtf8) `eq` id
88t_utf8 = forAll genUnicode $ (E.decodeUtf8 . E.encodeUtf8) `eq` id
70t_utf8' = forAll genUnicode $ (E.decodeUtf8' . E.encodeUtf8) `eq` (id . Right)
89t_utf8' = forAll genUnicode $ (E.decodeUtf8' . E.encodeUtf8) `eq` (id . Right)
71tl_utf8 = forAll genUnicode $ (EL.decodeUtf8 . EL.encodeUtf8) `eq` id
90tl_utf8 = forAll genUnicode $ (EL.decodeUtf8 . EL.encodeUtf8) `eq` id
@@ -79,6 +98,18 @@ tl_utf32LE = forAll genUnicode $ (EL.decodeUtf32LE . EL.encodeUtf32LE) `eq` id
79t_utf32BE = forAll genUnicode $ (E.decodeUtf32BE . E.encodeUtf32BE) `eq` id
98t_utf32BE = forAll genUnicode $ (E.decodeUtf32BE . E.encodeUtf32BE) `eq` id
80tl_utf32BE = forAll genUnicode $ (EL.decodeUtf32BE . EL.encodeUtf32BE) `eq` id
99tl_utf32BE = forAll genUnicode $ (EL.decodeUtf32BE . EL.encodeUtf32BE) `eq` id
102+ Positive n <- arbitrary
103+ forAll genUnicode $ recode n `eq` id
104+ where recode n = T.concat . feedChunksOf n E.streamDecodeUtf8 . E.encodeUtf8
105+ feedChunksOf :: Int -> (B.ByteString -> E.Decoding) -> B.ByteString
109+ | otherwise = let (a,b) = B.splitAt n bs
111+ in t : feedChunksOf n f' b
82-- This is a poor attempt to ensure that the error handling paths on
113-- This is a poor attempt to ensure that the error handling paths on
83-- decode are exercised in some way. Proper testing would be rather
114-- decode are exercised in some way. Proper testing would be rather
84-- more involved.
115-- more involved.
@@ -610,17 +641,55 @@ shiftR_Word32 = shiftR :: Word32 -> Property
611-- Builder.
642-- Builder.
613−t_builderSingleton = id `eqP`
644+tb_singleton = id `eqP`
614− (unpackS . TB.toLazyText . mconcat . map TB.singleton)
645+ (unpackS . TB.toLazyText . mconcat . map TB.singleton)
615−t_builderFromText = L.concat `eq` (unpackS . TB.toLazyText . mconcat .
646+tb_fromText = L.concat `eq` (unpackS . TB.toLazyText . mconcat .
616 map (TB.fromText . packS))
647 map (TB.fromText . packS))
617−t_builderAssociative s1 s2 s3 =
648+tb_associative s1 s2 s3 =
618 TB.toLazyText (b1 `mappend` (b2 `mappend` b3)) ==
649 TB.toLazyText (b1 `mappend` (b2 `mappend` b3)) ==
619 TB.toLazyText ((b1 `mappend` b2) `mappend` b3)
650 TB.toLazyText ((b1 `mappend` b2) `mappend` b3)
620 where b1 = TB.fromText (packS s1)
651 where b1 = TB.fromText (packS s1)
621 b2 = TB.fromText (packS s2)
652 b2 = TB.fromText (packS s2)
622 b3 = TB.fromText (packS s3)
653 b3 = TB.fromText (packS s3)
655+-- Numeric builder stuff.
657+tb_decimal :: (Integral a, Show a) => a -> Bool
658+tb_decimal = (TB.toLazyText . TB.decimal) `eq` (TL.pack . show)
660+tb_decimal_integer (a::Integer) = tb_decimal a
661+tb_decimal_int (a::Int) = tb_decimal a
662+tb_decimal_int8 (a::Int8) = tb_decimal a
663+tb_decimal_int16 (a::Int16) = tb_decimal a
664+tb_decimal_int32 (a::Int32) = tb_decimal a
665+tb_decimal_int64 (a::Int64) = tb_decimal a
666+tb_decimal_word (a::Word) = tb_decimal a
667+tb_decimal_word8 (a::Word8) = tb_decimal a
668+tb_decimal_word16 (a::Word16) = tb_decimal a
669+tb_decimal_word32 (a::Word32) = tb_decimal a
670+tb_decimal_word64 (a::Word64) = tb_decimal a
672+tb_hex :: (Integral a, Show a) => a -> Bool
673+tb_hex = (TB.toLazyText . TB.hexadecimal) `eq` (TL.pack . flip showHex "")
675+tb_hexadecimal_integer (a::Integer) = tb_hex a
676+tb_hexadecimal_int (a::Int) = tb_hex a
677+tb_hexadecimal_int8 (a::Int8) = tb_hex a
678+tb_hexadecimal_int16 (a::Int16) = tb_hex a
679+tb_hexadecimal_int32 (a::Int32) = tb_hex a
680+tb_hexadecimal_int64 (a::Int64) = tb_hex a
681+tb_hexadecimal_word (a::Word) = tb_hex a
682+tb_hexadecimal_word8 (a::Word8) = tb_hex a
683+tb_hexadecimal_word16 (a::Word16) = tb_hex a
684+tb_hexadecimal_word32 (a::Word32) = tb_hex a
685+tb_hexadecimal_word64 (a::Word64) = tb_hex a
687+tb_realfloat :: (RealFloat a, Show a) => a -> Bool
688+tb_realfloat = (TB.toLazyText . TB.realFloat) `eq` (TL.pack . show)
690+tb_realfloat_float (a::Float) = tb_realfloat a
691+tb_realfloat_double (a::Double) = tb_realfloat a
624-- Reading.
693-- Reading.
626t_decimal (n::Int) s =
695t_decimal (n::Int) s =
@@ -681,6 +750,8 @@ t_take_drop_16 m t = T.append (takeWord16 n t) (dropWord16 n t) == t
681 where n = small m
750 where n = small m
682t_use_from t = monadicIO $ assert . (==t) =<< run (useAsPtr t fromPtr)
751t_use_from t = monadicIO $ assert . (==t) =<< run (useAsPtr t fromPtr)
753+t_copy t = T.copy t == t
684-- Regression tests.
755-- Regression tests.
685s_filter_eq s = S.filter p t == S.streamList (filter p s)
756s_filter_eq s = S.filter p t == S.streamList (filter p s)
686 where p = (/= S.last t)
757 where p = (/= S.last t)
@@ -691,7 +762,7 @@ s_filter_eq s = S.filter p t == S.streamList (filter p s)
691-- themselves.
762-- themselves.
692shorten :: Int -> S.Stream a -> S.Stream a
763shorten :: Int -> S.Stream a -> S.Stream a
693shorten n t@(S.Stream arr off len)
764shorten n t@(S.Stream arr off len)
694− | n > 0 = S.Stream arr off (smaller (exactSize n) len)
765+ | n > 0 = S.Stream arr off (smaller (exactSize n) len)
695 | otherwise = t
766 | otherwise = t
697tests :: Test
768tests :: Test
@@ -713,8 +784,11 @@ tests =
713 testGroup "transcoding" [
784 testGroup "transcoding" [
714 testProperty "t_ascii" t_ascii,
785 testProperty "t_ascii" t_ascii,
715 testProperty "tl_ascii" tl_ascii,
786 testProperty "tl_ascii" tl_ascii,
787+ testProperty "t_latin1" t_latin1,
788+ testProperty "tl_latin1" tl_latin1,
716 testProperty "t_utf8" t_utf8,
789 testProperty "t_utf8" t_utf8,
717 testProperty "t_utf8'" t_utf8',
790 testProperty "t_utf8'" t_utf8',
791+ testProperty "t_utf8_incr" t_utf8_incr,
718 testProperty "tl_utf8" tl_utf8,
792 testProperty "tl_utf8" tl_utf8,
719 testProperty "tl_utf8'" tl_utf8',
793 testProperty "tl_utf8'" tl_utf8',
720 testProperty "t_utf16LE" t_utf16LE,
794 testProperty "t_utf16LE" t_utf16LE,
@@ -1080,9 +1154,39 @@ tests =
1082 testGroup "builder" [
1156 testGroup "builder" [
1083− testProperty "t_builderSingleton" t_builderSingleton,
1157+ testProperty "tb_associative" tb_associative,
1084− testProperty "t_builderFromText" t_builderFromText,
1158+ testGroup "decimal" [
1085− testProperty "t_builderAssociative" t_builderAssociative
1159+ testProperty "tb_decimal_int" tb_decimal_int,
1160+ testProperty "tb_decimal_int8" tb_decimal_int8,
1161+ testProperty "tb_decimal_int16" tb_decimal_int16,
1162+ testProperty "tb_decimal_int32" tb_decimal_int32,
1163+ testProperty "tb_decimal_int64" tb_decimal_int64,
1164+ testProperty "tb_decimal_integer" tb_decimal_integer,
1165+ testProperty "tb_decimal_word" tb_decimal_word,
1166+ testProperty "tb_decimal_word8" tb_decimal_word8,
1167+ testProperty "tb_decimal_word16" tb_decimal_word16,
1168+ testProperty "tb_decimal_word32" tb_decimal_word32,
1169+ testProperty "tb_decimal_word64" tb_decimal_word64
1171+ testGroup "hexadecimal" [
1172+ testProperty "tb_hexadecimal_int" tb_hexadecimal_int,
1173+ testProperty "tb_hexadecimal_int8" tb_hexadecimal_int8,
1174+ testProperty "tb_hexadecimal_int16" tb_hexadecimal_int16,
1175+ testProperty "tb_hexadecimal_int32" tb_hexadecimal_int32,
1176+ testProperty "tb_hexadecimal_int64" tb_hexadecimal_int64,
1177+ testProperty "tb_hexadecimal_integer" tb_hexadecimal_integer,
1178+ testProperty "tb_hexadecimal_word" tb_hexadecimal_word,
1179+ testProperty "tb_hexadecimal_word8" tb_hexadecimal_word8,
1180+ testProperty "tb_hexadecimal_word16" tb_hexadecimal_word16,
1181+ testProperty "tb_hexadecimal_word32" tb_hexadecimal_word32,
1182+ testProperty "tb_hexadecimal_word64" tb_hexadecimal_word64
1184+ testGroup "realfloat" [
1185+ testProperty "tb_realfloat_double" tb_realfloat_double,
1186+ testProperty "tb_realfloat_float" tb_realfloat_float
1188+ testProperty "tb_fromText" tb_fromText,
1189+ testProperty "tb_singleton" tb_singleton
1088 testGroup "read" [
1192 testGroup "read" [
@@ -1113,6 +1217,7 @@ tests =
1113 testProperty "t_dropWord16" t_dropWord16,
1217 testProperty "t_dropWord16" t_dropWord16,
1114 testProperty "t_takeWord16" t_takeWord16,
1218 testProperty "t_takeWord16" t_takeWord16,
1115 testProperty "t_take_drop_16" t_take_drop_16,
1219 testProperty "t_take_drop_16" t_take_drop_16,
1116− testProperty "t_use_from" t_use_from
1220+ testProperty "t_use_from" t_use_from,
1221+ testProperty "t_copy" t_copy