unwitch 2.0.1 → 2.0.2
raw patch · 28 files changed
+137/−3 lines, 28 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Changelog.md +8/−0
- src/Unwitch/Constant.hs +1/−0
- src/Unwitch/Convert/ByteString.hs +1/−0
- src/Unwitch/Convert/Char.hs +1/−0
- src/Unwitch/Convert/Double.hs +1/−0
- src/Unwitch/Convert/Fixed.hs +1/−0
- src/Unwitch/Convert/Float.hs +1/−0
- src/Unwitch/Convert/Int.hs +1/−0
- src/Unwitch/Convert/Int16.hs +1/−0
- src/Unwitch/Convert/Int32.hs +1/−0
- src/Unwitch/Convert/Int64.hs +1/−0
- src/Unwitch/Convert/Int8.hs +1/−0
- src/Unwitch/Convert/Integer.hs +1/−0
- src/Unwitch/Convert/LazyByteString.hs +1/−0
- src/Unwitch/Convert/LazyText.hs +1/−0
- src/Unwitch/Convert/Natural.hs +1/−0
- src/Unwitch/Convert/Ratio.hs +1/−0
- src/Unwitch/Convert/ShortByteString.hs +1/−0
- src/Unwitch/Convert/Text.hs +1/−0
- src/Unwitch/Convert/Word.hs +1/−0
- src/Unwitch/Convert/Word16.hs +1/−0
- src/Unwitch/Convert/Word32.hs +1/−0
- src/Unwitch/Convert/Word64.hs +1/−0
- src/Unwitch/Convert/Word8.hs +1/−0
- src/Unwitch/Errors.hs +6/−2
- test/Spec.hs +18/−0
- test/Test/Convert/PropertySpec.hs +81/−0
- unwitch.cabal +1/−1
Changelog.md view
@@ -1,5 +1,13 @@ # Change log for unwitch project +## Version 2.0.2++ Wire up 9 missing test specs that existed but were not included in the test runner++ Add module-level haddock to all Convert modules, Errors, and Constant++ Add haddock to Overflows type and constructors++ Expand property tests with 20+ new properties covering Int/Word+ same-width conversions, Float/Double range checks, cross-sign+ narrowing, Ratio round-trips, and Fixed round-trips+ ## Version 2.0.1 + Add haddock section headers separating boxed and unboxed conversions + Each module with unboxed functions now has "Conversions" and
src/Unwitch/Constant.hs view
@@ -1,3 +1,4 @@+-- | Constants used for range-checking floating-point conversions. module Unwitch.Constant ( maxIntegralRepDouble , maxIntegralRepFloat
src/Unwitch/Convert/ByteString.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Data.ByteString.ByteString'. module Unwitch.Convert.ByteString ( toLazyByteString , toShortByteString
src/Unwitch/Convert/Char.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Char'. module Unwitch.Convert.Char ( -- * Conversions toInt
src/Unwitch/Convert/Double.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Double'. module Unwitch.Convert.Double ( toFloat , toFixed
src/Unwitch/Convert/Fixed.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Data.Fixed.Fixed'. module Unwitch.Convert.Fixed ( fromInteger , toInteger
src/Unwitch/Convert/Float.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Float'. module Unwitch.Convert.Float ( toDouble , toRational
src/Unwitch/Convert/Int.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Int'. module Unwitch.Convert.Int ( -- * Conversions toInt8
src/Unwitch/Convert/Int16.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Int16'. module Unwitch.Convert.Int16 ( -- * Conversions toInt8
src/Unwitch/Convert/Int32.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Int32'. module Unwitch.Convert.Int32 ( -- * Conversions toInt8
src/Unwitch/Convert/Int64.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Int64'. module Unwitch.Convert.Int64 ( -- * Conversions toInt8
src/Unwitch/Convert/Int8.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Int8'. module Unwitch.Convert.Int8 ( -- * Conversions toInt16
src/Unwitch/Convert/Integer.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Integer'. module Unwitch.Convert.Integer ( -- * Conversions toDouble
src/Unwitch/Convert/LazyByteString.hs view
@@ -1,3 +1,4 @@+-- | Conversions from lazy 'Data.ByteString.Lazy.ByteString'. module Unwitch.Convert.LazyByteString ( toByteString , toWord8s
src/Unwitch/Convert/LazyText.hs view
@@ -1,3 +1,4 @@+-- | Conversions from lazy 'Data.Text.Lazy.Text'. module Unwitch.Convert.LazyText ( toText , toString
src/Unwitch/Convert/Natural.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Natural'. module Unwitch.Convert.Natural ( -- * Conversions toWord8
src/Unwitch/Convert/Ratio.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Data.Ratio.Ratio'. module Unwitch.Convert.Ratio ( unwrapIfDenominatorOne , fromIntegralToRatio
src/Unwitch/Convert/ShortByteString.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Data.ByteString.Short.ShortByteString'. module Unwitch.Convert.ShortByteString ( toByteString , toWord8s
src/Unwitch/Convert/Text.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Data.Text.Text'. module Unwitch.Convert.Text ( toLazyText , toString
src/Unwitch/Convert/Word.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Word'. module Unwitch.Convert.Word ( -- * Conversions toWord8
src/Unwitch/Convert/Word16.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Word16'. module Unwitch.Convert.Word16 ( -- * Conversions toWord8
src/Unwitch/Convert/Word32.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Word32'. module Unwitch.Convert.Word32 ( -- * Conversions toWord8
src/Unwitch/Convert/Word64.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Word64'. module Unwitch.Convert.Word64 ( -- * Conversions toWord8
src/Unwitch/Convert/Word8.hs view
@@ -1,3 +1,4 @@+-- | Conversions from 'Word8'. module Unwitch.Convert.Word8 ( -- * Conversions toWord16
src/Unwitch/Errors.hs view
@@ -1,8 +1,12 @@+-- | Error types for fallible numeric conversions. module Unwitch.Errors ( Overflows(..) ) where -data Overflows = Overflow- | Underflow+-- | Indicates that a numeric conversion failed because the source+-- value is outside the representable range of the target type.+data Overflows+ = Overflow -- ^ The source value is above the target's upper bound.+ | Underflow -- ^ The source value is below the target's lower bound. deriving (Show, Eq)
test/Spec.hs view
@@ -16,6 +16,15 @@ import qualified Test.Convert.FloatSpec import qualified Test.Convert.DoubleSpec import qualified Test.Convert.PropertySpec+import qualified Test.Convert.CharSpec+import qualified Test.Convert.FixedSpec+import qualified Test.Convert.RatioSpec+import qualified Test.Convert.TextSpec+import qualified Test.Convert.LazyTextSpec+import qualified Test.Convert.ByteStringSpec+import qualified Test.Convert.LazyByteStringSpec+import qualified Test.Convert.ShortByteStringSpec+import qualified Test.Convert.UnboxedSpec main :: IO () main = hspec $ do@@ -33,4 +42,13 @@ Test.Convert.IntegerSpec.spec Test.Convert.FloatSpec.spec Test.Convert.DoubleSpec.spec+ Test.Convert.CharSpec.spec+ Test.Convert.FixedSpec.spec+ Test.Convert.RatioSpec.spec+ Test.Convert.TextSpec.spec+ Test.Convert.LazyTextSpec.spec+ Test.Convert.ByteStringSpec.spec+ Test.Convert.LazyByteStringSpec.spec+ Test.Convert.ShortByteStringSpec.spec+ Test.Convert.UnboxedSpec.spec Test.Convert.PropertySpec.spec
test/Test/Convert/PropertySpec.hs view
@@ -5,6 +5,8 @@ import Test.Hspec.QuickCheck (prop) import Data.Int import Data.Word+import Data.Fixed (Fixed, E6)+import Data.Ratio (Ratio) import qualified Unwitch.Convert.Int8 as Int8 import qualified Unwitch.Convert.Int16 as Int16 import qualified Unwitch.Convert.Int32 as Int32@@ -20,6 +22,8 @@ import qualified Unwitch.Convert.Char as Char import qualified Unwitch.Convert.Float as Float import qualified Unwitch.Convert.Double as Double+import qualified Unwitch.Convert.Ratio as Ratio+import qualified Unwitch.Convert.Fixed as Fixed import Numeric.Natural (Natural) spec :: Spec@@ -398,6 +402,25 @@ prop "Int64 -> Word64: Nothing iff x < 0" $ \(x :: Int64) -> (Int64.toWord64 x == Nothing) `shouldBe` (x < 0) + prop "Int -> Word: Nothing iff x < 0" $ \(x :: Int) ->+ (Int.toWord x == Nothing) `shouldBe` (x < 0)++ describe "Unsigned-to-signed same-width: exact failure condition" $ do+ prop "Word8 -> Int8: Nothing iff x > 127" $ \(x :: Word8) ->+ (Word8.toInt8 x == Nothing) `shouldBe` (x > 127)++ prop "Word16 -> Int16: Nothing iff x > 32767" $ \(x :: Word16) ->+ (Word16.toInt16 x == Nothing) `shouldBe` (x > 32767)++ prop "Word32 -> Int32: Nothing iff x > 2147483647" $ \(x :: Word32) ->+ (Word32.toInt32 x == Nothing) `shouldBe` (x > 2147483647)++ prop "Word64 -> Int64: Nothing iff x > fromIntegral (maxBound :: Int64)" $ \(x :: Word64) ->+ (Word64.toInt64 x == Nothing) `shouldBe` (x > fromIntegral (maxBound :: Int64))++ prop "Word -> Int: Nothing iff x > fromIntegral (maxBound :: Int)" $ \(x :: Word) ->+ (Word.toInt x == Nothing) `shouldBe` (x > fromIntegral (maxBound :: Int))+ describe "Cross-sign narrowing: exact failure condition" $ do prop "Int16 -> Word8: Nothing iff x < 0 || x > 255" $ \(x :: Int16) -> (Int16.toWord8 x == Nothing) `shouldBe` (x < 0 || x > 255)@@ -417,6 +440,54 @@ prop "Word64 -> Int32: Nothing iff x > 2147483647" $ \(x :: Word64) -> (Word64.toInt32 x == Nothing) `shouldBe` (x > 2147483647) + prop "Int -> Word8: Nothing iff x < 0 || x > 255" $ \(x :: Int) ->+ (Int.toWord8 x == Nothing) `shouldBe` (x < 0 || x > 255)++ prop "Int -> Word16: Nothing iff x < 0 || x > 65535" $ \(x :: Int) ->+ (Int.toWord16 x == Nothing) `shouldBe` (x < 0 || x > 65535)++ prop "Int -> Word32: Nothing iff x < 0 || x > 4294967295" $ \(x :: Int) ->+ (Int.toWord32 x == Nothing) `shouldBe` (x < 0 || x > 4294967295)++ prop "Word -> Int8: Nothing iff x > 127" $ \(x :: Word) ->+ (Word.toInt8 x == Nothing) `shouldBe` (x > 127)++ prop "Word -> Int16: Nothing iff x > 32767" $ \(x :: Word) ->+ (Word.toInt16 x == Nothing) `shouldBe` (x > 32767)++ prop "Word -> Int32: Nothing iff x > 2147483647" $ \(x :: Word) ->+ (Word.toInt32 x == Nothing) `shouldBe` (x > 2147483647)++ describe "Int/Word/Natural Float range check" $ do+ prop "Int -> Float: succeeds iff abs value <= maxRepFloat" $ \(x :: Int) ->+ let xi = fromIntegral x :: Integer+ in isRight (Int.toFloat x) `shouldBe`+ (xi >= -maxRepFloat && xi <= maxRepFloat)++ prop "Word -> Float: succeeds iff value <= maxRepFloat" $ \(x :: Word) ->+ isRight (Word.toFloat x) `shouldBe`+ (fromIntegral x <= (maxRepFloat :: Integer))++ prop "Natural -> Float: succeeds iff value <= maxRepFloat" $ \(w :: Word64) ->+ let x = fromIntegral w :: Natural+ in isRight (Natural.toFloat x) `shouldBe`+ (fromIntegral w <= (maxRepFloat :: Integer))++ describe "Int/Word/Natural Double range check" $ do+ prop "Int -> Double: succeeds iff abs value <= maxRepDouble" $ \(x :: Int) ->+ let xi = fromIntegral x :: Integer+ in isRight (Int.toDouble x) `shouldBe`+ (xi >= -maxRepDouble && xi <= maxRepDouble)++ prop "Word -> Double: succeeds iff value <= maxRepDouble" $ \(x :: Word) ->+ isRight (Word.toDouble x) `shouldBe`+ (fromIntegral x <= (maxRepDouble :: Integer))++ prop "Natural -> Double: succeeds iff value <= maxRepDouble" $ \(w :: Word64) ->+ let x = fromIntegral w :: Natural+ in isRight (Natural.toDouble x) `shouldBe`+ (fromIntegral w <= (maxRepDouble :: Integer))+ describe "Float/Double to integer: exact success condition" $ do prop "Float -> Integer: succeeds iff finite and whole" $ \(x :: Float) -> isRight (Float.toInteger x) `shouldBe` isWholeFloat x@@ -471,6 +542,16 @@ in if isNaN x then y `shouldSatisfy` isNaN else y `shouldBe` x++ describe "Ratio round-trip" $ do+ prop "Int8 -> Ratio Int8 -> Int8" $ \(x :: Int8) ->+ let r = Ratio.fromIntegralToRatio x :: Ratio Int8+ in Ratio.unwrapIfDenominatorOne r `shouldBe` Just x++ describe "Fixed round-trip" $ do+ prop "Integer -> Fixed E6 -> Integer for whole numbers" $ \(x :: Integer) ->+ let f = Fixed.fromInteger x :: Fixed E6+ in Fixed.toInteger f `shouldBe` Just x maxRepFloat :: Num a => a maxRepFloat = 16777215
unwitch.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0 name: unwitch-version: 2.0.1+version: 2.0.2 homepage: https://github.com/jappeace/unwitch#readme synopsis: converts between primitives description: