{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ScopedTypeVariables #-} import Data.AEq import Data.Fixed import Data.Maybe import Geom2d.Point import Geom2d.Rotation import Linear.V2 (V2(..)) import Test.QuickCheck hiding (scale) import Test.Utils mkpropPoint :: forall a p. (Arbitrary (p a), Point p, Eq a) => p a -> Bool mkpropPoint p = and [ prop_identity ] where prop_identity = x p == x idPoint && y p == y idPoint idPoint :: p a idPoint = fromCoords (x p) (y p) mkpropNum :: (Arbitrary a, Num a) => (a -> a -> Bool) -> a -> Bool mkpropNum isEqual x = x `isEqual` (signum x * abs x) mkpropFunctor :: (Arbitrary (f a), Eq (f a), Functor f) => f a -> Bool mkpropFunctor x = fmap id x == x mkpropScale :: (Arbitrary (p a), Scale p, Floating a, Point p) => (a -> a -> Bool) -> p a -> a -> Bool mkpropScale comparison p a = (magnitude p * abs a) `comparison` magnitude (a `scale` p) mkpropNormalize :: (Arbitrary (p a), Point p, Scale p, Floating a, AEq a , Num a) => p a -> Bool mkpropNormalize v = maybe (magnitude v ~== 0) ( (~== 1).magnitude ) ( normalize v) prop_scaleTo :: Point' Float -> Float -> Bool prop_scaleTo vector x = fromMaybe (magnitude vector == 0) $ do scaledVector <- scaleTo x vector return (magnitude scaledVector ~== abs x) prop_point_point' :: Point' Integer -> Bool prop_point_point' = mkpropPoint prop_point_v2 :: V2 Integer -> Bool prop_point_v2 = mkpropPoint prop_num_point' :: Point' Float -> Bool prop_num_point' = mkpropNum (~==) prop_functor_point' :: Point' Integer -> Bool prop_functor_point' = mkpropFunctor prop_point'_magnitude :: Point' Float -> Bool prop_point'_magnitude p = sqrt ( x p ^ 2 + y p ^ 2 ) ~== magnitude p prop_triarea :: Float -> Float -> Bool prop_triarea a b = triArea triangle ~== abs ((a * b) / 2) where triangle :: Triangle (Point' Float) triangle = ( fromCoords 0 0 , fromCoords a 0 , fromCoords 0 b ) prop_point_scale :: Point' Float -> Float -> Bool prop_point_scale = mkpropScale (~==) prop_point_normalize :: Point' Float -> Bool prop_point_normalize = mkpropNormalize prop_point_normalize_v2 :: V2 Float -> Bool prop_point_normalize_v2 = mkpropNormalize prop_pointInTriangle :: Bool prop_pointInTriangle = pointInTriangle tri p where tri = ( fromCoords (-1) (-1) , fromCoords 1 (-1) , fromCoords 0 1 ) p :: Point' Float p = fromCoords 0 0 prop_pointInTriangle_onVert :: Bool prop_pointInTriangle_onVert = pointInTriangle tri p where p = fromCoords 0 0 tri :: Triangle (Point' Float) tri = (p, fromCoords 1 1, fromCoords 1 (-1)) prop_angle_zero :: Bool prop_angle_zero = angle (fromCoords 1 0 :: Point' Float) == Just 0 prop_point_show_read :: Point' Float -> Bool prop_point_show_read p = p == (read.show) p prop_point_add :: Point' Float -> Point' Float -> Bool prop_point_add p q = x (p + q) == x p + x q && y (p + q) == y p + y q prop_point_negate :: Point' Float -> Bool prop_point_negate p = x (negate p) == negate (x p) && y (negate p) == negate (y p) prop_triangle_invalid :: Bool prop_triangle_invalid = let tri :: Triangle (Point' Float) tri = ( fromCoords 0 0 , fromCoords 1 1 , fromCoords 1 1 ) in not (pointInTriangle tri (fromCoords 0 0)) prop_rotation_point_linear :: Point' Float -> Bool prop_rotation_point_linear x = fromMaybe True ( (~==) <$> angle (r `rotate` x) <*> ((subtract pi).((`mod'` (2*pi)).(+pi).(+r)) <$> angle x) ) where r = 1.2 prop_rotation_point_bounds :: Point' Float -> Bool prop_rotation_point_bounds x = fromMaybe True ( fmap (\a -> a >= (- pi) && a <= pi) (angle x) ) return [] runTests = $quickCheckAll main :: IO () main = do putStrLn "Test Point" runTests >>= doExit