{- | Properties for testing that instances of the 'Functor' class perform correctly. This testing requires an 'Eq' instance, which not all 'Functor's actually have. It also requires a 'Show' instance, which is also uncommon. The 'Label1' wrapper may be useful in dealing with the 'Show' requirement. Tests are supplied both in regular \"unlabelled\" form, and also in a special \"labelled\" form, where function objects have 'Label's attached to them. Because of this, the function used for each test can be recorded in the test log, which can be quite helpful. -} module Test.AC.Class.Functor where import Test.AC.Test import Test.AC.Label -- * Unlabelled tests -- | Check that @'fmap' 'id' '==' 'id'@. p_map_id :: (Functor f, Eq (f x), Show (f x)) => f x -> Test p_map_id fx = title "fmap id == id" $ argument "fx" fx $ fmap id fx ?= fx -- | Check that @'fmap' (f '.' g) '==' 'fmap' 'f' '.' 'fmap' g@. p_map_compose :: (Functor f, Eq (f z), Show (f x), Show (f y), Show (f z)) => f x -> (x -> y) -> (y -> z) -> Test p_map_compose fx g f = title "fmap (f . g) == fmap f . fmap g" $ argument "fx" fx $ temporary "fmap g fx" (fmap g fx) $ temporary "fmap f (fmap g fx)" (fmap f (fmap g fx)) $ fmap (f . g) fx ?= fmap f (fmap g fx) {- | Given a list of /distinct/ 'Functor' values and functions, perform all tests on all combinations of inputs. (If the inputs are not distinct, some redundant tests will be performed.) The argument types are somewhat constrained to keep the type signature reasonably simple. -} p_Functor :: (Functor f, Eq (f x), Show (f x)) => [f x] -> [x -> x] -> Test p_Functor fxs fs = title "p_Functor" $ argument "fxs" fxs $ tests [ title "p_map_id" $ tests [ p_map_id fx | fx <- fxs ], title "p_map_compose" $ tests [ p_map_compose fx f2 f1 | fx <- fxs, f1 <- fs, f2 <- fs ] ] -- * Labelled tests -- | Check that @'fmap' (f '.' g) '==' 'fmap' 'f' '.' 'fmap' g@. p_map_compose_L :: (Functor f, Eq (f z), Show (f x), Show (f y), Show (f z)) => f x -> Label (x -> y) -> Label (y -> z) -> Test p_map_compose_L fx (Label lg g) (Label lf f) = title "fmap (f . g) == fmap f . fmap g" $ argument "fx" fx $ argument_ "f" lf $ argument_ "g" lg $ temporary "fmap g fx" (fmap g fx) $ temporary "fmap f (fmap g fx)" (fmap f (fmap g fx)) $ fmap (f . g) fx ?= fmap f (fmap g fx) {- | Given a list of /distinct/ 'Functor' values and functions, perform all tests on all combinations of inputs. (If the inputs are not distinct, some redundant tests will be performed.) The argument types are somewhat constrained to keep the function's type signature reasonably simple. -} p_Functor_L :: (Functor f, Eq (f x), Show (f x)) => [f x] -> [Label (x -> x)] -> Test p_Functor_L fxs fs = title "p_Functor_L" $ argument "fxs" fxs $ tests [ title "p_map_id" $ tests [ p_map_id fx | fx <- fxs ], title "p_map_compose_L" $ tests [ p_map_compose_L fx f2 f1 | fx <- fxs, f1 <- fs, f2 <- fs ] ]