{-# LANGUAGE CPP #-} module Tests.UTF8 ( testTree -- :: TestTree ) where import Control.DeepSeq import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL #if ! MIN_VERSION_base(4,11,0) import Data.Monoid #endif import qualified Data.Text.Encoding as T import Codec.CBOR.Decoding import Codec.CBOR.Read import Tests.Util import Test.Tasty import Test.Tasty.QuickCheck #if !MIN_VERSION_base(4,8,0) import Control.Applicative #endif -- | Wrapper for ByteString with Arbitrary instance that might produce a valid -- UTF-8 encoding of a string. newtype MaybeText = MaybeText BS.ByteString deriving Show instance Arbitrary MaybeText where arbitrary = MaybeText . BS.pack <$> arbitrary -- | Test that decoding of both valid and invalid CBOR strings produces output -- without exceptions hidden within. utf8DecodingTest :: MaybeText -> Property utf8DecodingTest (MaybeText bs) = case T.decodeUtf8' bs of Right _ -> collect "valid utf8" $ (and splitsOk) Left _ -> collect "invalid utf8" $ not (or splitsOk) where -- We test 2-splits to check all decoder paths. splitsOk = [ok $ deserialiseFromBytes decodeString v | v <- splits2 s] where ok (Right v) = deepseq v True ok (Left v) = deepseq v False s = mkLengthPrefix True (Length . fromIntegral $ BS.length bs) <> BSL.fromStrict bs ---------------------------------------- testTree :: TestTree testTree = localOption (QuickCheckTests 1000) . testGroup "UTF8" $ [testProperty "Decoding of UTF8 encoded Text works and properly handles decoding failures" utf8DecodingTest ]