quickcheck-text (empty) → 0.1.0.0
raw patch · 7 files changed
+230/−0 lines, 7 filesdep +QuickCheckdep +basedep +binarysetup-changed
Dependencies added: QuickCheck, base, binary, bytestring, quickcheck-text, text
Files
- LICENSE +20/−0
- README.md +7/−0
- Setup.hs +2/−0
- quickcheck-text.cabal +47/−0
- src/Data/Text/Arbitrary.hs +11/−0
- src/Test/QuickCheck/Utf8.hs +94/−0
- test/properties.hs +49/−0
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015 Sharif Olorin++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,7 @@+# quickcheck-text++The usual Arbitrary instance for Text (in+[quickcheck-instances](https://hackage.haskell.org/package/quickcheck-instances))+only has single-byte instances and so isn't an ideal representation of+a valid UTF-8 character. This package has generators for one-, two-+and three-byte UTF-8 characters (all that are currently in use).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ quickcheck-text.cabal view
@@ -0,0 +1,47 @@+name: quickcheck-text+version: 0.1.0.0+synopsis: Alternative arbitrary instance for Text+description: The usual Arbitrary instance for Text+ (in+ <https://hackage.haskell.org/package/quickcheck-instances quickcheck-instances>) + only has single-byte+ instances and so isn't an ideal representation of a valid UTF-8+ character. This package has generators for one-, two- and three-byte+ UTF-8 characters (all that are currently in use).+license: MIT+license-file: LICENSE+author: Sharif Olorin+maintainer: sio@tesser.org+copyright: 2015 Sharif Olorin+category: Text+build-type: Simple+cabal-version: >=1.10+extra-source-files: README.md++source-repository head+ type: git+ location: git@github.com:olorin/quickcheck-instances.git++library+ exposed-modules: Test.QuickCheck.Utf8+ Data.Text.Arbitrary+ build-depends: base >=4.7 && <5+ , QuickCheck+ , binary+ , bytestring+ , text+ hs-source-dirs: src+ default-language: Haskell2010+ ghc-options: -Wall++test-suite properties+ hs-source-dirs: test+ main-is: properties.hs+ type: exitcode-stdio-1.0+ default-language: Haskell2010+ ghc-options: -Wall+ build-depends: base >=4.7 && <5+ , QuickCheck+ , bytestring+ , quickcheck-text+ , text
+ src/Data/Text/Arbitrary.hs view
@@ -0,0 +1,11 @@+module Data.Text.Arbitrary(+ Text()+) where++import Data.Text++import Test.QuickCheck+import Test.QuickCheck.Utf8++instance Arbitrary Text where+ arbitrary = genValidUtf8
+ src/Test/QuickCheck/Utf8.hs view
@@ -0,0 +1,94 @@+module Test.QuickCheck.Utf8(+ genValidUtf8+ , utf8BS+ , genValidUtf81+ , utf8BS1+ -- * Generators for single characters+ , oneByte+ , twoByte+ , threeByte+) where++import Control.Monad++import Data.Binary.Builder+import Data.Binary.Get++import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BL+import Data.Char+import Data.Text (Text)+import qualified Data.Text as T+import Data.Text.Encoding+import Data.Text.Internal.Encoding.Utf8+import Data.Word++import Test.QuickCheck++-- |+-- Generate a possibly-empty valid UTF-8 'Text' value.+genValidUtf8 :: Gen Text+genValidUtf8 = fmap decodeUtf8 utf8BS++-- |+-- Generate a possibly-empty sequence of bytes which represent a valid+-- UTF-8 code point.+utf8BS :: Gen ByteString+utf8BS = fmap BS.concat $ elements symbolTypes >>= listOf++-- |+-- Like 'genValidUtf8', but does not allow empty 'Text' values.+genValidUtf81 :: Gen Text+genValidUtf81 = fmap decodeUtf8 utf8BS1++-- |+-- Like 'utf8BS', but does not allow empty 'ByteString's.+utf8BS1 :: Gen ByteString+utf8BS1 = fmap BS.concat $ elements symbolTypes >>= listOf1++symbolTypes :: [Gen ByteString]+symbolTypes = [ oneByte+ , twoByte+ , threeByte+ ]++inRange :: Int -> Int -> Gen Word8+inRange lo hi = fmap fromIntegral $ elements [lo..hi]++-- | Single-byte UTF-8 (i.e., a standard ASCII byte with a cleared MSB).+oneByte :: Gen ByteString+oneByte = fmap (BS.pack . return) $+ inRange 0 127 -- 0bbbbbbb++twoByte :: Gen ByteString+twoByte = do+ b1 <- inRange 0xC2 0xDF -- 110bbbbb+ b2 <- nonInitial+ return . buildUtf $ putBytes2 b1 b2++threeByte :: Gen ByteString+threeByte = do+ (b1, b2) <- oneof [b3_1, b3_2, b3_3, b3_4]+ b3 <- nonInitial+ return . buildUtf $ putBytes3 b1 b2 b3+ where+ b3_1 = (,) `fmap` return 0xE0 `ap` inRange 0xA0 0xBF++ b3_2 = (,) `fmap` inRange 0xE1 0xEC `ap` nonInitial++ b3_3 = (,) `fmap` return 0xED `ap` inRange 0x80 0x9F++ b3_4 = (,) `fmap` inRange 0xEE 0xEF `ap` nonInitial++buildUtf :: Builder -> ByteString +buildUtf = BS.concat . BL.toChunks . toLazyByteString++putBytes2 :: Word8 -> Word8 -> Builder+putBytes2 b1 b2 = putCharUtf8 $ chr2 b1 b2++putBytes3 :: Word8 -> Word8 -> Word8 -> Builder+putBytes3 b1 b2 b3 = putCharUtf8 $ chr3 b1 b2 b3++nonInitial :: Gen Word8+nonInitial = inRange 0x80 0xBF
+ test/properties.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE TemplateHaskell #-}++module Main where++import Control.Monad++import Data.Bits+import qualified Data.ByteString as BS+import Data.Text.Encoding++import System.Exit++import Test.QuickCheck+import Test.QuickCheck.Utf8++prop_decodes_without_exception :: Property+prop_decodes_without_exception = forAll utf8BS $ \bs ->+ decodeUtf8 bs === decodeUtf8 bs++prop_oneByte_lsb :: Property+prop_oneByte_lsb = forAll oneByte $ \bs ->+ let b = head $ BS.unpack bs+ in testBit b 7 === False++prop_oneByte_range :: Property+prop_oneByte_range = forAll oneByte $ \bs ->+ let s = sum $ fmap fromIntegral $ BS.unpack bs+ in (s >= 0 && s <= 127)++prop_twoByte_range :: Property+prop_twoByte_range = forAll twoByte $ \bs ->+ let s = sum $ fmap fromIntegral $ BS.unpack bs+ in (s >= 320 && s <= 65439)++prop_threeByte_range :: Property+prop_threeByte_range = forAll threeByte $ \bs ->+ let s = sum $ fmap fromIntegral $ BS.unpack bs+ in (s >= 480 && s <= 16777071)++prop_validUtf81 :: Property+prop_validUtf81 = forAll utf8BS1 $ \bs ->+ BS.length bs >= 1++return []+props :: IO Bool+props = $quickCheckAll++main :: IO ()+main = props >>= flip when exitFailure . not