packages feed

naqsha-0.1.0.0: tests/Naqsha/PositionSpec.hs

{-# LANGUAGE ScopedTypeVariables #-}
module Naqsha.PositionSpec where
import Data.Monoid
import Data.Fixed
import Test.QuickCheck
import Test.Hspec
import Test.Hspec.QuickCheck

import Naqsha.Position
import Naqsha.Geometry.Angle
import Naqsha.Arbitrary ()

inRange :: Testable prop
        => (Angle, Angle) -- ^ Range
        -> String         -- ^ description
        -> ((Angle,Angle) -> prop)
        -> Spec
inRange (mi,mx) descr prop_test = it msg $ forAll pair prop_test
  where pair  = (,) <$> gen <*> gen
        msg   = "in range " ++ show (toNano mi,toNano mx) ++ ": " ++ descr
        gen   =  toEnum <$> choose (fromEnum mi, fromEnum mx)

        toNano :: Angle -> Nano
        toNano = toDegree

isIncreasing :: (Angle, Angle) -> Bool
isIncreasing (x , y)
  | x == y    = xA == yA
  | x <  y    = xA <  yA
  | otherwise = xA >  yA
  where xA = lat x
        yA = lat y


isDecreasing :: (Angle, Angle) -> Bool
isDecreasing (x, y)
  | x == y    = xA == yA
  | x >  y    = xA <  yA
  | otherwise = xA >  yA
  where xA  = lat x
        yA  = lat y

shouldBeBounded :: (Arbitrary a, Ord a, Show a, Bounded a) => a -> Spec
shouldBeBounded a = prop msg $ \ x -> x >= mi && x <= mx
  where msg = unwords [ "should lie between"
                      , show mi
                      , "and"
                      , show mx
                      ]
        mi   = minBound `asTypeOf` a
        mx   = maxBound `asTypeOf` a


spec :: Spec
spec = do

  describe "latitudes" $ do

    inRange (degree (-90),  degree 90)    "increases monotonically" isIncreasing
    inRange (degree 90 ,  maxBound)     "decreases monotonically"   isDecreasing
    inRange (minBound , degree (-90)) "decreases monotonically"     isDecreasing

    shouldBeBounded (undefined :: Latitude)

  describe "longitudes" $ do

    prop "should have a period of 360 deg" $
      \ (x :: Longitude) -> x <> lon (degree 360) `shouldBe` x

    shouldBeBounded (undefined ::Longitude)