diff --git a/Makefile.am b/Makefile.am index b5166412f170b3022a083c53b65b868f7301d32e..8b3e539c90d929ce67de164aa946453249ea1326 100644 --- a/Makefile.am +++ b/Makefile.am @@ -438,6 +438,7 @@ HS_LIB_SRCS = \ htools/Ganeti/THH.hs HS_TEST_SRCS = \ + htest/Test/Ganeti/BasicTypes.hs \ htest/Test/Ganeti/Confd/Utils.hs \ htest/Test/Ganeti/HTools/CLI.hs \ htest/Test/Ganeti/HTools/Cluster.hs \ diff --git a/htest/Test/Ganeti/BasicTypes.hs b/htest/Test/Ganeti/BasicTypes.hs new file mode 100644 index 0000000000000000000000000000000000000000..eacdfbabccf54c57e948da4945a63e60e741e432 --- /dev/null +++ b/htest/Test/Ganeti/BasicTypes.hs @@ -0,0 +1,143 @@ +{-# LANGUAGE TemplateHaskell #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} + +{-| Unittests for ganeti-htools. + +-} + +{- + +Copyright (C) 2009, 2010, 2011, 2012 Google Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. + +-} + +module Test.Ganeti.BasicTypes (testBasicTypes) where + +import Test.QuickCheck hiding (Result) +import Test.QuickCheck.Function + +import Control.Applicative +import Control.Monad + +import Test.Ganeti.TestHelper +import Test.Ganeti.TestCommon + +import Ganeti.BasicTypes + +-- Since we actually want to test these, don't tell us not to use them :) + +{-# ANN module "HLint: ignore Functor law" #-} +{-# ANN module "HLint: ignore Monad law, left identity" #-} +{-# ANN module "HLint: ignore Monad law, right identity" #-} +{-# ANN module "HLint: ignore Use >=>" #-} + +-- * Arbitrary instances + +instance (Arbitrary a) => Arbitrary (Result a) where + arbitrary = oneof [ Bad <$> arbitrary + , Ok <$> arbitrary + ] + +-- * Test cases + +-- | Tests the functor identity law (fmap id == id). +prop_functor_id :: Result Int -> Property +prop_functor_id ri = + fmap id ri ==? ri + +-- | Tests the functor composition law (fmap (f . g) == fmap f . fmap g). +prop_functor_composition :: Result Int + -> Fun Int Int -> Fun Int Int -> Property +prop_functor_composition ri (Fun _ f) (Fun _ g) = + fmap (f . g) ri ==? (fmap f . fmap g) ri + +-- | Tests the applicative identity law (pure id <*> v = v). +prop_applicative_identity :: Result Int -> Property +prop_applicative_identity v = + pure id <*> v ==? v + +-- | Tests the applicative composition law (pure (.) <*> u <*> v <*> w +-- = u <*> (v <*> w)). +prop_applicative_composition :: (Result (Fun Int Int)) + -> (Result (Fun Int Int)) + -> Result Int + -> Property +prop_applicative_composition u v w = + let u' = fmap apply u + v' = fmap apply v + in pure (.) <*> u' <*> v' <*> w ==? u' <*> (v' <*> w) + +-- | Tests the applicative homomorphism law (pure f <*> pure x = pure (f x)). +prop_applicative_homomorphism :: Fun Int Int -> Int -> Property +prop_applicative_homomorphism (Fun _ f) x = + ((pure f <*> pure x)::Result Int) ==? + (pure (f x)) + +-- | Tests the applicative interchange law (u <*> pure y = pure ($ y) <*> u). +prop_applicative_interchange :: Result (Fun Int Int) + -> Int -> Property +prop_applicative_interchange f y = + let u = fmap apply f -- need to extract the actual function from Fun + in u <*> pure y ==? pure ($ y) <*> u + +-- | Tests the applicative\/functor correspondence (fmap f x = pure f <*> x). +prop_applicative_functor :: Fun Int Int -> Result Int -> Property +prop_applicative_functor (Fun _ f) x = + fmap f x ==? pure f <*> x + +-- | Tests the applicative\/monad correspondence (pure = return and +-- (<*>) = ap). +prop_applicative_monad :: Int -> Result (Fun Int Int) -> Property +prop_applicative_monad v f = + let v' = pure v :: Result Int + f' = fmap apply f -- need to extract the actual function from Fun + in v' ==? return v .&&. (f' <*> v') ==? f' `ap` v' + +-- | Tests the monad laws (return a >>= k == k a, m >>= return == m, m +-- >>= (\x -> k x >>= h) == (m >>= k) >>= h). +prop_monad_laws :: Int -> Result Int + -> Fun Int (Result Int) + -> Fun Int (Result Int) + -> Property +prop_monad_laws a m (Fun _ k) (Fun _ h) = + printTestCase "return a >>= k == k a" ((return a >>= k) ==? k a) .&&. + printTestCase "m >>= return == m" ((m >>= return) ==? m) .&&. + printTestCase "m >>= (\\x -> k x >>= h) == (m >>= k) >>= h)" + ((m >>= (\x -> k x >>= h)) ==? ((m >>= k) >>= h)) + +-- | Tests the monad plus laws ( mzero >>= f = mzero, v >> mzero = mzero). +prop_monadplus_mzero :: Result Int -> Fun Int (Result Int) -> Property +prop_monadplus_mzero v (Fun _ f) = + printTestCase "mzero >>= f = mzero" ((mzero >>= f) ==? mzero) .&&. + -- FIXME: since we have "many" mzeros, we can't test for equality, + -- just that we got back a 'Bad' value; I'm not sure if this means + -- our MonadPlus instance is not sound or not... + printTestCase "v >> mzero = mzero" (isBad (v >> mzero)) + +testSuite "BasicTypes" + [ 'prop_functor_id + , 'prop_functor_composition + , 'prop_applicative_identity + , 'prop_applicative_composition + , 'prop_applicative_homomorphism + , 'prop_applicative_interchange + , 'prop_applicative_functor + , 'prop_applicative_monad + , 'prop_monad_laws + , 'prop_monadplus_mzero + ] diff --git a/htest/test.hs b/htest/test.hs index cb0f2c82edfad54d90b68da45e76be9e35bb2753..899db7ed8066280550a5a5c77f0ea9199822fa25 100644 --- a/htest/test.hs +++ b/htest/test.hs @@ -30,6 +30,7 @@ import Test.Framework import System.Environment (getArgs) import Test.Ganeti.TestImports () +import Test.Ganeti.BasicTypes import Test.Ganeti.Confd.Utils import Test.Ganeti.HTools.CLI import Test.Ganeti.HTools.Cluster @@ -73,7 +74,8 @@ slow = fast -- | All our defined tests. allTests :: [(Bool, (String, [Test]))] allTests = - [ (True, testConfd_Utils) + [ (True, testBasicTypes) + , (True, testConfd_Utils) , (True, testHTools_CLI) , (True, testHTools_Container) , (True, testHTools_Instance)