packages feed

pez-0.0.1: Tests.hs

{-# LANGUAGE DeriveDataTypeable, TemplateHaskell, ViewPatterns #-}
module Main
    where

import Test.QuickCheck
import Data.Typeable.Zipper
import Data.Record.Label.Prelude

{-
 - These tests are vital, since with all the dynamic magic we're using, a
 - function that compiles could very well not actually work
 -}

-- a linear, mutually recursive type:
data Tick = Tick { _tock :: Tock }
          | Gong 
          deriving (Typeable, Eq, Show)

data Tock = LoudTock { _tick :: Tick }
          | SoftTock { _tick :: Tick }
          deriving (Typeable, Eq, Show)

newtype TickTock = TT { _tickTocks :: Tick }
                   deriving (Typeable, Eq, Show)

$(mkLabelsNoTypes [''TickTock, ''Tock, ''Tick])

instance Arbitrary TickTock where
    arbitrary = fmap TT arbTick where
        arbTick = do
            n <- choose (1,2) :: Gen Int
            case n of
                 1 -> fmap Tick arbTock
                 2 -> return Gong

        arbTock = do
            to <- elements [LoudTock, SoftTock]
            ti <- arbTick
            return $ to ti


{-
-- a simple binary tree:
data Tree a = Branch (Tree a) (Tree a) 
            | Leaf a
            deriving (Typeable, Eq)
-}

-- we also test on simple lists 

 -- Don't know the appropriate way to run batch job:
main = sequence_
        [ quickCheck prop_simple_creation
        , quickCheck prop_simple_recursive_movement
        , quickCheck prop_mutual_saving
        , quickCheck prop_simple_moveUp_past_top
        , quickCheck prop_moveUpSaving
        ]

prop_simple_creation :: [Char] -> Bool
prop_simple_creation a = 
    let z = zipper a
        f = viewf z                           
        a' = close z                          
     in a == f && a == a'

prop_simple_recursive_movement i =
    let i' = abs i `mod` 50 :: Int
        l = replicate i' () 
         -- test simple descending
        descend 0 z | null $ viewf z = maybe False atTop $  ascend i' z
                    | otherwise = False
        descend n z = descend (n-1) (moveTo lTail z)

         -- test ascending by two and one:
        ascend 0 z = return z
        ascend 1 z = moveUp 1 z
        ascend n z = moveUp 2 z >>= ascend (n-2)
     in descend i' $ zipper l


prop_mutual_saving :: TickTock -> Bool
prop_mutual_saving tt = checkSaving $ descend $ moveTo tickTocks $ zipper tt
    where descend z@(viewf -> Gong) = z
          descend z = descendTock $ moveTo tock z
          descendTock = descend . moveTo tick
          checkSaving z = 
              let (p,a) = closeSaving z
                  z' = restore p a
                  lns = savedLens p
               -- closed zipper is equal to original, 
               in a == tt && 
               -- restoring brings us back to the end
                  viewf z' == Gong && 
               -- lens rebuilt from SavedPath is equivalent
                  getL lns tt == Gong &&
               -- moving to rebuilt lens and moving up gets us back to top:
                  (maybe False ((==tt) . viewf) $ 
                      moveUp 1 $ moveTo lns $ zipper tt)

-- check moveUpSaving & Nothing returned from failed cast:
prop_moveUpSaving :: ((),((),(Int,Int))) -> Bool
prop_moveUpSaving = 
   check . moveTo lSnd . moveTo lSnd . moveTo lSnd . zipper 
       where check z = maybe False id $ do
                 (z', p') <- moveUpSaving 2 z
                 let n = viewf z 
                     -- otherwise type is ambiguous:
                     typeofz' = z' :: Zipper ((),((),(Int,Int))) ((),(Int,Int))
                     n' = viewf $ moveTo p' z'
                 -- we successfully moved up and back down again?:
                 return $ n == n'



-- test moveUp past top of Zipper, 
prop_simple_moveUp_past_top :: [Int] -> Bool
prop_simple_moveUp_past_top = check . moveUp 2 . moveTo lTail . zipper where
    -- this sig required else type ambiguous:
    check :: Maybe (Zipper1 [Int]) -> Bool
    check = maybe True (const False)