{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE AllowAmbiguousTypes #-} -- {-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE TypeApplications #-} module Data.Units.Base.ConvertProp where import Data.Coerce import Data.Epsilon import Test.QuickCheck import Test.Hspec import Data.Units ------------------------------------ toFrom ------------------------------------ toFrom :: forall u a. (ConvertibleUnit u a) => a -> a toFrom a = coerce (toBaseUnit (fromBaseUnit @u (coerce a :: BaseUnitOf u a) :: u a) :: BaseUnitOf u a) toFromProp :: forall u a. ( ConvertibleUnit u a , Arbitrary a, Show a, Epsilon a ) => Property toFromProp = property (isApproxId (toFrom @u @a)) toFromSpec :: forall u a. ( ShowUnit u , ConvertibleUnit u a , Arbitrary a, Show a, Epsilon a ) => Spec toFromSpec = it ("toFrom " ++ showUnit @u) (toFromProp @u @a) ------------------------------------ fromTo ------------------------------------ fromToRoundtrip :: forall u v a. ( IsUnit u, IsUnit v , FromTo u v a, FromTo v u a ) => a -> a fromToRoundtrip a = coerce (fromTo (fromTo (coerce a :: u a) :: v a) :: u a) fromToProp :: forall u v a. ( ShowUnit u, ShowUnit v , FromTo u v a, FromTo v u a , Arbitrary a, Show a, Epsilon a ) => Property fromToProp = property $ isApproxId (fromToRoundtrip @u @v @a) fromToSpec :: forall u v a. ( ShowUnit u, ShowUnit v , FromTo u v a, FromTo v u a , Arbitrary a, Show a, Epsilon a ) => Spec fromToSpec = it ("From `" ++ showUnit @u ++ "` to `" ++ showUnit @v ++ "`") $ fromToProp @u @v @a fromToAssert :: forall a u v. ( Show (u a), Show (v a) , FromTo u v a , FromTo v u a , Arbitrary a, ShowUnit u, ShowUnit v, Show a, Epsilon a ) => u a -> v a -> Spec fromToAssert u v = it ("`" ++ prettyQuantity u ++ "` should be `" ++ prettyQuantity v ++ "`") $ aboutEqual (coerce (fromTo u :: v a) :: a) (coerce v :: a) && aboutEqual (coerce (fromTo v :: u a) :: a) (coerce u :: a) `shouldBe` True ----------------------------------- fromTo' ------------------------------------ fromToRoundtrip' :: forall u v a. ( FromTo' u v a, FromTo' v u a) => a -> a fromToRoundtrip' a = coerce (fromTo' (fromTo' (coerce a :: u a) :: v a) :: u a) fromToProp' :: forall u v a. ( ShowUnit u, ShowUnit v , FromTo' u v a, FromTo' v u a , Arbitrary a, Show a, Epsilon a ) => Property fromToProp' = property $ isApproxId (fromToRoundtrip' @u @v @a) fromToSpec' :: forall u v a. ( ShowUnit u, ShowUnit v , FromTo' u v a, FromTo' v u a , Arbitrary a, Show a, Epsilon a ) => Spec fromToSpec' = it ("From' `" ++ showUnit @u ++ "` to' `" ++ showUnit @v ++ "`") $ fromToProp' @u @v @a