packages feed

grid-7.8.6: test/Math/Geometry/Grid/SquareQC.hs

------------------------------------------------------------------------
-- |
-- Module      :  Math.Geometry.Grid.SquareQC
-- Copyright   :  (c) Amy de Buitléir 2012-2016
-- License     :  BSD-style
-- Maintainer  :  amy@nualeargais.ie
-- Stability   :  experimental
-- Portability :  portable
--
-- QuickCheck tests.
--
------------------------------------------------------------------------
{-# LANGUAGE FlexibleContexts, ExistentialQuantification,
    TypeFamilies #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Math.Geometry.Grid.SquareQC
  (
    test
  ) where

import Math.Geometry.Grid.SquareInternal 
import Math.Geometry.GridInternal 
import Math.Geometry.GridQC

import Prelude hiding (null)
import Test.Framework (Test, testGroup)
import Test.QuickCheck 
  (Gen, Arbitrary, arbitrary, sized, choose, elements,  Property, vectorOf)

instance Arbitrary SquareDirection where
  arbitrary =
    elements [North, South, East, West]

--
-- Unbounded grids with square tiles
--

data UnboundedSquareGridTD = 
  UnboundedSquareGridTD [(Int,Int)] ((Int,Int),(Int,Int)) SquareDirection
  deriving Show

instance TestData UnboundedSquareGridTD where
  type BaseGrid UnboundedSquareGridTD = UnboundedSquareGrid
  grid _ = UnboundedSquareGrid
  points (UnboundedSquareGridTD ps _ _) = ps
  twoClosePoints (UnboundedSquareGridTD _ qs _) = qs
  neighbourCountBounds _ = (4, 4)
  direction (UnboundedSquareGridTD _ _ d) = d

sizedUnboundedSquareGridTD :: Int -> Gen UnboundedSquareGridTD
sizedUnboundedSquareGridTD n = do
  k <- choose (0,n)
  ps <- vectorOf (k+2) arbitrary :: Gen [(Int,Int)]
  qs <- chooseClosePointsUnbounded
  d <- arbitrary
  return $ UnboundedSquareGridTD ps qs d

instance Arbitrary UnboundedSquareGridTD where
  arbitrary = sized sizedUnboundedSquareGridTD

unboundedSquareGridProperties :: [(String, UnboundedSquareGridTD -> Property)]
unboundedSquareGridProperties = gridProperties "UnboundedSquareGrid"

unboundedSquareGridTests :: [Test]
unboundedSquareGridTests = makeTests unboundedSquareGridProperties


--
-- Rectangular grids with square tiles
--

data RectSquareGridTD = 
  RectSquareGridTD RectSquareGrid [(Int,Int)] ((Int,Int),(Int,Int)) SquareDirection
  deriving Show

instance TestData RectSquareGridTD where
  type BaseGrid RectSquareGridTD = RectSquareGrid
  grid (RectSquareGridTD g _ _ _) = g
  points (RectSquareGridTD _ ps _ _) = ps
  twoClosePoints (RectSquareGridTD _ _ qs _) = qs
  neighbourCountBounds _ = (0, 4)
  direction (RectSquareGridTD _ _ _ d) = d

instance TestDataF RectSquareGridTD where
  maxDistance (RectSquareGridTD g _ _ _) = r + c - 2
    where (r, c) = size g
  expectedTileCount (RectSquareGridTD g _ _ _) = r*c
    where (r,c) = size g

instance TestDataB RectSquareGridTD where
  expectedBoundaryCount (RectSquareGridTD g _ _ _) = 
    (cartesianBoundaryCount . size) g

-- We want the number of tiles in a test grid to be O(n)
sizedRectSquareGridTD :: Int -> Gen RectSquareGridTD
sizedRectSquareGridTD n = do
  r <- choose (0,n)
  let c = n `div` (r+1)
  let g = rectSquareGrid r c
  ps <- chooseIndices g n
  qs <- chooseClosePoints g
  d <- arbitrary
  return $ RectSquareGridTD g ps qs d

instance Arbitrary RectSquareGridTD where
  arbitrary = sized sizedRectSquareGridTD

rectSquareGridProperties :: [(String, RectSquareGridTD -> Property)]
rectSquareGridProperties = gridProperties "RectSquareGrid"
  ++ finiteGridProperties "RectSquareGrid"
  ++ boundedGridProperties "RectSquareGrid"
  ++ boundedGridProperties2 "RectSquareGrid"

rectSquareGridTests :: [Test]
rectSquareGridTests = makeTests rectSquareGridProperties


--
-- Toroidal grids with square tiles
--

data TorSquareGridTD = 
  TorSquareGridTD TorSquareGrid [(Int,Int)] ((Int,Int),(Int,Int)) SquareDirection
  deriving Show

instance TestData TorSquareGridTD where
  type BaseGrid TorSquareGridTD = TorSquareGrid
  grid (TorSquareGridTD g _ _ _) = g
  points (TorSquareGridTD _ ps _ _) = ps 
  twoClosePoints (TorSquareGridTD _ _ qs _) = qs
  neighbourCountBounds _ = (0, 4)
  direction (TorSquareGridTD _ _ _ d) = d

instance TestDataF TorSquareGridTD where
  maxDistance (TorSquareGridTD g _ _ _) = (r+c) `div` 2
    where (r, c) = size g
  expectedTileCount (TorSquareGridTD g _ _ _) = r*c
    where (r,c) = size g

-- We want the number of tiles in a test grid to be O(n)
sizedTorSquareGridTD :: Int -> Gen TorSquareGridTD
sizedTorSquareGridTD n = do
  r <- choose (0,n)
  let c = n `div` (r+1)
  let g = torSquareGrid r c
  ps <- chooseIndices g n
  qs <- chooseClosePoints g
  d <- arbitrary
  return $ TorSquareGridTD g ps qs d

instance Arbitrary TorSquareGridTD where
  arbitrary = sized sizedTorSquareGridTD

torSquareGridProperties :: [(String, TorSquareGridTD -> Property)]
torSquareGridProperties = gridProperties "TorSquareGrid"
  ++ finiteGridProperties "TorSquareGrid"

torSquareGridTests :: [Test]
torSquareGridTests = makeTests torSquareGridProperties

--TODO replace these
--TODO replace these
--TODO replace these

--prop_UnboundedSquareGrid_num_min_paths_correct :: 
--  UnboundedSquareGrid -> Int -> Int -> Property
--prop_UnboundedSquareGrid_num_min_paths_correct g i j = nonNull g ==>
--  minPathCount g a b == M.choose (deltaX+deltaY) deltaX
--    where a = g `pointAt` i
--          b = g `pointAt` j
--          deltaX = abs $ fst b - fst a
--          deltaY = abs $ snd b - snd a

---- If the ordering produced by rectSquareGrid is ever changed, this
---- property may need to be changed too. It relies on the first and last 
---- elements being at opposite corners.
--prop_RectSquareGrid_distance_corner_to_corner :: RectSquareGrid -> Property
--prop_RectSquareGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> 
--  distance g a b == r + c - 2
--    where (r, c) = size g
--          ps = indices g
--          a = head ps
--          b = last ps

--prop_RectSquareGrid_num_min_paths_correct :: 
--  RectSquareGrid -> Int -> Int -> Property
--prop_RectSquareGrid_num_min_paths_correct g i j = nonNull g ==>
--  minPathCount g a b == M.choose (deltaX+deltaY) deltaX
--    where a = g `pointAt` i
--          b = g `pointAt` j
--          deltaX = abs $ fst b - fst a
--          deltaY = abs $ snd b - snd a

---- If the ordering produced by torSquareGrid is ever changed, this property
---- may need to be changed too.
--prop_TorSquareGrid_distance_corner_to_corner :: TorSquareGrid -> Property
--prop_TorSquareGrid_distance_corner_to_corner g = r > 0 && c > 0 ==> 
--  distance g a b == f
--    where (r, c) = size g
--          ps = indices g
--          a = head ps
--          b = last ps
--          f | r == 1 && c == 1 = 0 -- single-tile torus
--            | r == 1 || c == 1 = 1 -- a and b are the same
--            | otherwise      = 2


test :: Test
test = testGroup "Math.Geometry.Grid.SquareQC"
  (unboundedSquareGridTests ++ rectSquareGridTests ++ torSquareGridTests)