gps-0.8.2: Test/GpsTest.hs
import Data.GPS
import Data.Time
import Data.List
import Data.Ord
import Data.Fixed
import Test.QuickCheck
import Test.Framework (Test, defaultMain, testGroup)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Text.XML.XSD.DateTime
import Control.Applicative
import Control.Monad
instance Arbitrary LatitudeType where
arbitrary = liftM (latitudeType . flip mod' 180) arbitrary
instance Arbitrary LongitudeType where
arbitrary = liftM (longitudeType . flip mod' 180) arbitrary
instance Arbitrary DateTime where
arbitrary = liftM fromUTCTime arbitrary
instance Arbitrary UTCTime where
arbitrary = UTCTime <$> arbitrary <*> liftM (secondsToDiffTime . abs) (arbitrary :: Gen Integer)
instance Arbitrary Day where
arbitrary = fromGregorian <$> liftM ((+ 1000) . (`mod` 1100) .abs) arbitrary <*> liftM abs arbitrary <*> liftM abs arbitrary
instance Arbitrary NominalDiffTime where
arbitrary = liftM fromIntegral (arbitrary :: Gen Int)
instance Arbitrary WptType where
arbitrary =
wptType <$> arbitrary -- Lat
<*> arbitrary -- Lon
<*> arbitrary -- Time
<*> arbitrary -- elevation
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return [] -- LinkType
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
<*> return Nothing
newtype Trl = Trl [WptType]
deriving (Show)
instance Arbitrary Trl where
arbitrary = do
b <- arbitrary :: Gen [Int]
u_ts_d <- mapM (\i -> (,,) <$> arbitrary <*> replicateM i arbitrary <*> arbitrary) b :: Gen [(UTCTime, [WptType],NominalDiffTime)]
let u_ts_d' = sortBy (comparing (\(a,_,_) -> a)) u_ts_d
xs = concat [zipWith (setTime' . fromUTCTime) (iterate (addUTCTime d) u) x | (u,x,d) <- u_ts_d']
return $ Trl xs
approxEq :: WptType -> WptType -> Bool
approxEq a b = distance a b <= 0.2 -- error of 13cm has been observed due to floating point issues when using add vector.
pSaneDistance :: WptType -> WptType -> Bool
pSaneDistance a b = distance a b <= circumferenceOfEarth / 2
pTriangleTheorem :: WptType -> WptType -> WptType -> Bool
pTriangleTheorem a b c =
distance a b + distance b c >= distance a c -- Traditional flat-surface geometry
|| distance a b + distance b c + distance c a == 2 * pi * radiusOfEarth
pAddVector_DistanceHeading_ident :: WptType -> WptType -> Bool
pAddVector_DistanceHeading_ident a b =
let v = (distance a b, heading a b)
c = addVector v a
in (distance c b) <= 0.01 * (distance a b)
pConvexHull_Has_Extreme_Points :: Trl -> Bool
pConvexHull_Has_Extreme_Points (Trl ts) =
let ch = convexHull ts
ts' = sortBy (comparing lat) ts
northMost = last ts'
southMost = head ts'
in length ts < 3 || (northMost `elem` ch && southMost `elem` ch)
pConvexHull_Bezier_Const :: Trl -> Double -> Bool
pConvexHull_Bezier_Const (Trl ts) n =
let ts' = take 10 ts
ch = convexHull ts'
n' = abs (n `mod'` 1)
bp = bezierPoint ts' n'
ch' = convexHull (bp:ts')
in length ts < 3 || ch == ch'
tests :: [Test]
tests =
[
testGroup "Coordinate Computations"
[ testProperty "approxEq_id" (\x -> approxEq x x)
, testProperty "saneDistance" pSaneDistance
, testProperty "TriangleTheorem" pTriangleTheorem
, testProperty "Vector identity" pAddVector_DistanceHeading_ident
]
, testGroup "Trail Computations"
[ testProperty "Hull has extreme points" pConvexHull_Has_Extreme_Points
, testProperty "HullContainsBezier" pConvexHull_Bezier_Const]
]
----------------------------------------------------------
------------- * HARNESS * --------------------------------
----------------------------------------------------------
main :: IO ()
main = defaultMain tests