packages feed

unwitch-2.0.0: test/Test/Convert/FixedSpec.hs

module Test.Convert.FixedSpec (spec) where

import Test.Hspec
import Data.Fixed (Fixed, E2, E6)
import Data.Ratio (numerator)
import qualified Unwitch.Convert.Fixed as Fixed

spec :: Spec
spec = describe "Unwitch.Convert.Fixed" $ do

  describe "fromInteger" $ do
    it "converts integer to Fixed E2" $
      Fixed.fromInteger 42 `shouldBe` (42.0 :: Fixed E2)
    it "converts zero" $
      Fixed.fromInteger 0 `shouldBe` (0.0 :: Fixed E2)

  describe "toInteger" $ do
    it "succeeds for whole Fixed values" $
      Fixed.toInteger (42.0 :: Fixed E2) `shouldBe` Just 42
    it "fails for fractional Fixed values" $
      Fixed.toInteger (1.50 :: Fixed E2) `shouldBe` Nothing

  describe "toRational" $ do
    it "converts Fixed to exact Rational" $
      Fixed.toRational (1.50 :: Fixed E2) `shouldBe` (3 / 2)
    it "round-trips whole values through toInteger" $
      let f = 10.0 :: Fixed E2
      in Fixed.toInteger f `shouldBe` Just (numerator (Fixed.toRational f))

  describe "toFixed" $ do
    it "succeeds for compatible resolutions" $
      Fixed.toFixed (1.50 :: Fixed E2) `shouldBe` Just (1.500000 :: Fixed E6)
    it "fails for incompatible resolutions" $
      -- 0.01 as E2 is representable, but converting to E6 should also work
      -- However 1/3 cannot be represented in either, so let's test a value
      -- that exists in E6 but not in E2:
      -- 1.123 in E6 -> 1.12 in E2 loses precision
      Fixed.toFixed (1.123000 :: Fixed E6) `shouldBe` (Nothing :: Maybe (Fixed E2))

  describe "toDouble" $ do
    it "converts whole Fixed to Double" $
      Fixed.toDouble (42.0 :: Fixed E2) `shouldBe` 42.0
    it "converts fractional Fixed to Double" $
      Fixed.toDouble (1.50 :: Fixed E2) `shouldBe` 1.5
    it "converts zero" $
      Fixed.toDouble (0.0 :: Fixed E6) `shouldBe` 0.0