point-octree-0.5.5.3: tests/PropTests/OctreeTests/Internal.hs
{- |
Module : PropTests.OctreeTests.Internal
Copyright : Copyright (c) 2016 Michal J. Gajda
License : BSD3
Maintainer : Michael Litchard
Stability : experimental
Portability: not portable
This module provides tests for internal helper functions:
-}
{-# LANGUAGE ScopedTypeVariables #-}
module PropTests.OctreeTests.Internal
( prop_depth
, prop_cmp1
, prop_cmp2
, prop_stepDescription
, prop_octantDistanceNoGreaterThanInterpointDistance0
, prop_octantDistanceNoGreaterThanInterpointDistance
, prop_octantDistanceNoGreaterThanInterpointDistanceZero
, prop_octantDistanceNoGreaterThanCentroidDistance
, prop_pickClosest
) where
import Prelude hiding(lookup)
import Data.List(sort, sortBy)
import Control.Arrow(second)
import Data.Octree.Internal
import Data.Octree() -- test that interface module is not broken
import PropTests.Common
-- for easier testing
origin :: Vector3
origin = 0
prop_depth [] = True -- fudging , what is true fix?
prop_depth a =
(depth oct <= ((+1) . ceiling $ expectedDepth)) &&
(depth oct >= ((\a -> a-1) . floor $ expectedDepth))
where
expectedDepth =
(logBase 8 :: Double -> Double) . fromIntegral . length $ a
oct :: Octree Int = fromList a
prop_cmp1 a b = cmp a b == joinStep (dx >= 0, dy >= 0, dz >= 0)
where Vector3 dx dy dz = a - b
prop_cmp2 a = cmp a origin == joinStep (dx >= 0, dy >= 0, dz >= 0)
where Vector3 dx dy dz = a
prop_stepDescription a b =
splitStep (cmp a b) == (v3x a >= v3x b, v3y a >= v3y b, v3z a >= v3z b)
prop_octantDistanceNoGreaterThanInterpointDistance0 ptA ptB = triangleInequality
where
triangleInequality = octantDistance' aptA (cmp ptB origin) <= dist aptA ptB
aptA = abs ptA
prop_octantDistanceNoGreaterThanInterpointDistance ptA ptB vp =
triangleInequality
where
triangleInequality = octantDistance (ptA - vp) (cmp ptB vp) <= dist ptA ptB
sameOctant = cmp ptA vp == cmp ptB vp
prop_octantDistanceNoGreaterThanInterpointDistanceZero ptA ptB =
triangleInequality
where
triangleInequality = octantDistance ptA (cmp ptB origin) <= dist ptA ptB
sameOctant = cmp ptA origin == cmp ptB origin
prop_octantDistanceNoGreaterThanInterpointDistanceZero0 ptA ptB =
triangleInequality
where
triangleInequality = octantDistance aptA (cmp ptB origin) <= dist aptA ptB
sameOctant = cmp aptA origin == cmp ptB origin
aptA = abs ptA
prop_octantDistanceNoGreaterThanCentroidDistance pt vp = all testFun allOctants
where testFun odir = octantDistance (pt - vp) odir <= dist pt vp
prop_splitByPrime splitPt pt =
(unLeaf . octreeStep ot . cmp pt $ splitPt) == [arg]
where
ot = splitBy' Leaf splitPt [arg]
arg = (pt, dist pt splitPt)
prop_pickClosest :: (Eq a) => [(Vector3, a)] -> Vector3 -> Bool
prop_pickClosest l pt = pickClosest pt l == naiveNearest pt l
-- | These are tests for exposed functions:
prop_lookup l = all isIn l
where
ot = fromList l
isIn x = lookup ot (fst x) == Just x
prop_fromToList l = sort l == (sort . toList . fromList $ l)
prop_insertionPreserved l =
sort l == (sort . toList . foldr insert (Leaf []) $ l)
prop_nearest l pt = nearest (fromList l) pt == naiveNearest pt l
prop_naiveWithinRange r l pt =
naiveWithinRange r pt l == testPoints
where
testPoints =
sort . map fst . (\o -> withinRange o r pt) . fromList . tuplify pt $ l
tuplify pt = map (\a -> (a, dist pt a))
compareDistance pt (a,_) (b,_) = compare (dist pt a) (dist pt b)
naiveNearest pt [] = Nothing
naiveNearest pt l = Just $ head byDist
where byDist = sortBy (compareDistance pt) l
naiveWithinRange r pt = sort . filter withinRange
where withinRange p = dist pt p <= r
-- unfortunately there is no Arbitrary for (a -> b)
-- since generic properties are quite common, I wonder how to force Quickcheck to default something reasonable?
prop_fmap1,prop_fmap2 :: [(Vector3, Int)] -> Bool
prop_fmap1 = genericPropertyFmap (+1)
prop_fmap2 = genericPropertyFmap (*2)
prop_fmap3 = genericPropertyFmap (show :: Int -> String)
genericPropertyFmap f l =
(sort . map (Control.Arrow.second f) $ l) == testFmap
where testFmap = sort . toList . fmap f . fromList $ l
prop_depth_empty = depth (Leaf []) == 0
prop_depth_upper_bound l =
depth ot <= max 0 (ceiling . logBase 2 . realToFrac $ size) -- worst splitting ratio possible when we take midpoint (and inputs are colinear)
where
ot = fromList l
size = length l
prop_size l = size (fromList l) == length l