dbus-core-0.8.5: hs/Tests.hs
#line 64 "src/introduction.anansi"
#line 30 "src/introduction.anansi"
-- Copyright (C) 2009-2010 John Millikin <jmillikin@gmail.com>
--
-- 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 3 of the License, or
-- 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, see <http://www.gnu.org/licenses/>.
#line 65 "src/introduction.anansi"
#line 52 "src/introduction.anansi"
{-# LANGUAGE OverloadedStrings #-}
#line 66 "src/introduction.anansi"
module Main (tests, main) where
#line 159 "src/util.anansi"
import Test.QuickCheck
import qualified Test.Framework as F
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Control.Arrow ((&&&))
import Control.Monad (replicateM)
import qualified Data.Binary.Get as G
import Data.Char (isPrint)
import Data.String
import Data.List (intercalate, isInfixOf)
import Data.Maybe (fromJust, isJust, isNothing)
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import Data.Word (Word8, Word16, Word32, Word64)
import Data.Int (Int16, Int32, Int64)
import DBus.Address
import DBus.Message.Internal
import DBus.Types
import DBus.Wire.Internal
import DBus.Wire.Marshal
import DBus.Wire.Unmarshal
import qualified DBus.Introspection as I
#line 68 "src/introduction.anansi"
tests :: [F.Test]
tests = [ F.testGroup "dummy" []
#line 384 "src/types.anansi"
, F.testGroup "String"
[ testProperty "String -> strict Text"
$ funEq (fromVariant . toVariant) (Just . T.pack)
, testProperty "String <- strict Text"
$ funEq (fromVariant . toVariant) (Just . T.unpack)
, testProperty "String -> lazy Text"
$ funEq (fromVariant . toVariant) (Just . TL.pack)
, testProperty "String <- lazy Text"
$ funEq (fromVariant . toVariant) (Just . TL.unpack)
, testProperty "Strict Text -> lazy Text"
$ funEq (fromVariant . toVariant) (Just . TL.pack . T.unpack)
, testProperty "Strict Text <- lazy Text"
$ funEq (fromVariant . toVariant) (Just . T.pack . TL.unpack)
]
#line 736 "src/types.anansi"
, F.testGroup "Signature"
[ testProperty "Signature identity"
$ funEq (mkSignature . strSignature) Just
]
#line 806 "src/types.anansi"
, F.testGroup "ObjectPath"
[ testProperty "ObjectPath identity"
$ funEq (mkObjectPath . strObjectPath) Just
]
#line 942 "src/types.anansi"
, F.testGroup "Array"
[ testProperty "Array identity"
$ \x -> Just x == arrayFromItems (arrayType x) (arrayItems x)
, testProperty "Array homogeneity" prop_ArrayHomogeneous
]
#line 1071 "src/types.anansi"
, F.testGroup "Dictionary"
[ testProperty "Dictionary identity"
$ \x -> Just x == dictionaryFromItems
(dictionaryKeyType x)
(dictionaryValueType x)
(dictionaryItems x)
, testProperty "Dictionary homogeneity" prop_DictionaryHomogeneous
, testProperty "Dictionary must have atomic keys"
$ \vt -> forAll containerType $ \kt ->
isNothing (dictionaryFromItems kt vt [])
, testProperty "Dictionary <-> Array conversion"
$ funEq (arrayToDictionary . dictionaryToArray) Just
]
#line 1232 "src/types.anansi"
, F.testGroup "BusName"
[ testProperty "BusName identity"
$ funEq (mkBusName . strBusName) Just
]
#line 1279 "src/types.anansi"
, F.testGroup "InterfaceName"
[ testProperty "InterfaceName identity"
$ funEq (mkInterfaceName . strInterfaceName) Just
]
#line 1311 "src/types.anansi"
, F.testGroup "ErrorName"
[ testProperty "ErrorName identity"
$ funEq (mkErrorName . strErrorName) Just
]
#line 1354 "src/types.anansi"
, F.testGroup "MemberName"
[ testProperty "MemberName identity"
$ funEq (mkMemberName . strMemberName) Just
]
#line 1223 "src/wire.anansi"
, F.testGroup "Wire format"
[ testProperty "Marshal -> Ummarshal" prop_Unmarshal
, F.testGroup "Messages"
[ testProperty "Method calls" prop_WireMethodCall
, testProperty "Method returns" prop_WireMethodReturn
, testProperty "Errors" prop_WireError
, testProperty "Signals" prop_WireSignal
]
]
#line 177 "src/addresses.anansi"
, F.testGroup "Addresses"
[ testProperty "Address identity"
$ \x -> mkAddresses (strAddress x) == Just [x]
, testProperty "Multiple addresses"
$ \x y -> let
joined = TL.concat [strAddress x, ";", strAddress y]
in mkAddresses joined == Just [x, y]
, testProperty "Ignore trailing semicolon"
$ \x -> mkAddresses (TL.append (strAddress x) ";") == Just [x]
, testProperty "Ignore trailing comma"
$ \x -> let
hasParams = not . Map.null . addressParameters $ x
parsed = mkAddresses (TL.append (strAddress x) ",")
in hasParams ==> parsed == Just [x]
, F.testGroup "Valid addresses"
[ test "colon" $ isJust . mkAddresses $ ":"
, test "just scheme" $ isJust . mkAddresses $ "a:"
, test "param" $ isJust . mkAddresses $ "a:b=c"
, test "trailing semicolon" $ isJust . mkAddresses $ "a:;"
, test "two schemes" $ isJust . mkAddresses $ "a:;b:"
, test "trailing comma" $ isJust . mkAddresses $ "a:b=c,"
]
, F.testGroup "Invalid addresses"
[ test "empty" $ isNothing . mkAddresses $ ""
, test "no colon" $ isNothing . mkAddresses $ "a"
, test "no equals" $ isNothing . mkAddresses $ "a:b"
, test "no param" $ isNothing . mkAddresses $ "a:b="
, test "no param" $ isNothing . mkAddresses $ "a:,"
]
]
#line 507 "src/introspection.anansi"
, F.testGroup "Introspection"
[ testProperty "Generate -> Parse"
$ \x@(I.Object path _ _) -> let
xml = I.toXML x
Just xml' = xml
parsed = I.fromXML path xml'
in isJust xml ==> I.fromXML path xml' == Just x
]
#line 72 "src/introduction.anansi"
]
main :: IO ()
main = F.defaultMain tests
#line 106 "src/types.anansi"
instance Arbitrary Type where
arbitrary = oneof [atomicType, containerType]
atomicType :: Gen Type
atomicType = elements
[ DBusBoolean
, DBusByte
, DBusWord16
, DBusWord32
, DBusWord64
, DBusInt16
, DBusInt32
, DBusInt64
, DBusDouble
, DBusString
, DBusObjectPath
, DBusSignature
]
containerType :: Gen Type
containerType = do
c <- choose (0,3) :: Gen Int
case c of
0 -> fmap DBusArray arbitrary
1 -> do
kt <- atomicType
vt <- arbitrary
return $ DBusDictionary kt vt
2 -> fmap DBusStructure $ halfSized arbitrary
3 -> return DBusVariant
#line 272 "src/types.anansi"
instance Arbitrary Variant where
arbitrary = arbitrary >>= genVariant
genVariant :: Type -> Gen Variant
genVariant t = case t of
DBusBoolean -> fmap toVariant (arbitrary :: Gen Bool)
DBusByte -> fmap toVariant (arbitrary :: Gen Word8)
DBusWord16 -> fmap toVariant (arbitrary :: Gen Word16)
DBusWord32 -> fmap toVariant (arbitrary :: Gen Word32)
DBusWord64 -> fmap toVariant (arbitrary :: Gen Word64)
DBusInt16 -> fmap toVariant (arbitrary :: Gen Int16)
DBusInt32 -> fmap toVariant (arbitrary :: Gen Int32)
DBusInt64 -> fmap toVariant (arbitrary :: Gen Int64)
DBusDouble -> fmap toVariant (arbitrary :: Gen Double)
DBusString -> fmap toVariant (arbitrary :: Gen String)
DBusObjectPath -> fmap toVariant (arbitrary :: Gen ObjectPath)
DBusSignature -> fmap toVariant (arbitrary :: Gen Signature)
(DBusArray _) -> fmap toVariant (arbitrary :: Gen Array)
(DBusDictionary _ _) -> fmap toVariant (arbitrary :: Gen Dictionary)
(DBusStructure _) -> fmap toVariant (arbitrary :: Gen Structure)
DBusVariant -> fmap toVariant (arbitrary :: Gen Variant)
#line 731 "src/types.anansi"
instance Arbitrary Signature where
arbitrary = sizedText 255 $ fmap (TL.concat . map typeCode) arbitrary
#line 797 "src/types.anansi"
instance Arbitrary ObjectPath where
arbitrary = fmap (mkObjectPath_ . TL.pack) path' where
c = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ "_"
path = fmap (intercalate "/" . ([] :)) genElements
path' = frequency [(1, return "/"), (9, path)]
genElements = atLeast 1 (atLeast 1 (elements c))
#line 926 "src/types.anansi"
instance Arbitrary Array where
arbitrary = do
t <- atomicType
xs <- listOf $ genVariant t
return . fromJust $ arrayFromItems t xs
prop_ArrayHomogeneous vs = isJust array == homogeneousTypes where
array = arrayFromItems firstType vs
homogeneousTypes = all (== firstType) types
types = map variantType vs
firstType = if null types
then DBusByte
else head types
#line 1053 "src/types.anansi"
instance Arbitrary Dictionary where
arbitrary = do
kt <- atomicType
vt <- atomicType
ks <- listOf $ genVariant kt
vs <- vectorOf (length ks) $ genVariant vt
return . fromJust $ dictionaryFromItems kt vt $ zip ks vs
prop_DictionaryHomogeneous x = all correctType pairs where
pairs = dictionaryItems x
kType = dictionaryKeyType x
vType = dictionaryValueType x
correctType (k, v) = variantType k == kType &&
variantType v == vType
#line 1138 "src/types.anansi"
instance Arbitrary Structure where
arbitrary = fmap Structure $ halfSized arbitrary
#line 1212 "src/types.anansi"
instance Arbitrary BusName where
arbitrary = sizedText 255 (oneof [unique, wellKnown]) where
c = ['a'..'z'] ++ ['A'..'Z'] ++ "_-"
c' = c ++ ['0'..'9']
unique = do
elems' <- atLeast 2 $ elems c'
return . TL.pack $ ':' : intercalate "." elems'
wellKnown = do
elems' <- atLeast 2 $ elems c
return . TL.pack $ intercalate "." elems'
elems start = do
x <- elements start
xs <- atLeast 0 (elements c')
return (x:xs)
#line 1265 "src/types.anansi"
instance Arbitrary InterfaceName where
arbitrary = sizedText 255 genName where
c = ['a'..'z'] ++ ['A'..'Z'] ++ "_"
c' = c ++ ['0'..'9']
genName = fmap (TL.pack . intercalate ".") genElements
genElements = atLeast 2 genElement
genElement = do
x <- elements c
xs <- atLeast 0 (elements c')
return (x:xs)
#line 1306 "src/types.anansi"
instance Arbitrary ErrorName where
arbitrary = fmap (mkErrorName_ . strInterfaceName) arbitrary
#line 1342 "src/types.anansi"
instance Arbitrary MemberName where
arbitrary = sizedText 255 genName where
c = ['a'..'z'] ++ ['A'..'Z'] ++ "_"
c' = c ++ ['0'..'9']
genName = do
x <- elements c
xs <- atLeast 0 (elements c')
return . TL.pack $ (x:xs)
#line 73 "src/messages.anansi"
instance Arbitrary Flag where
arbitrary = elements [NoReplyExpected, NoAutoStart]
#line 131 "src/messages.anansi"
instance Arbitrary Serial where
arbitrary = fmap Serial arbitrary
#line 173 "src/messages.anansi"
instance Arbitrary MethodCall where
arbitrary = do
path <- arbitrary
member <- arbitrary
iface <- arbitrary
dest <- arbitrary
flags <- fmap Set.fromList arbitrary
Structure body <- arbitrary
return $ MethodCall path member iface dest flags body
#line 210 "src/messages.anansi"
instance Arbitrary MethodReturn where
arbitrary = do
serial <- arbitrary
dest <- arbitrary
Structure body <- arbitrary
return $ MethodReturn serial dest body
#line 261 "src/messages.anansi"
instance Arbitrary Error where
arbitrary = do
name <- arbitrary
serial <- arbitrary
dest <- arbitrary
Structure body <- arbitrary
return $ Error name serial dest body
#line 300 "src/messages.anansi"
instance Arbitrary Signal where
arbitrary = do
path <- arbitrary
member <- arbitrary
iface <- arbitrary
dest <- arbitrary
Structure body <- arbitrary
return $ Signal path member iface dest body
#line 58 "src/wire.anansi"
instance Arbitrary Endianness where
arbitrary = elements [LittleEndian, BigEndian]
#line 1188 "src/wire.anansi"
prop_Unmarshal :: Endianness -> Variant -> Property
prop_Unmarshal e x = valid ==> unmarshaled == Right [x] where
sig = mkSignature . typeCode . variantType $ x
Just sig' = sig
bytes = runMarshal (marshal x) e
Right bytes' = bytes
valid = isJust sig && isRight bytes
unmarshaled = runUnmarshal (unmarshal sig') e bytes'
prop_MarshalMessage e serial msg expected = valid ==> correct where
bytes = marshalMessage e serial msg
Right bytes' = bytes
getBytes = G.getLazyByteString . fromIntegral
unmarshaled = G.runGet (unmarshalMessage getBytes) bytes'
valid = isRight bytes
correct = unmarshaled == Right expected
prop_WireMethodCall e serial msg = prop_MarshalMessage e serial msg
$ ReceivedMethodCall serial Nothing msg
prop_WireMethodReturn e serial msg = prop_MarshalMessage e serial msg
$ ReceivedMethodReturn serial Nothing msg
prop_WireError e serial msg = prop_MarshalMessage e serial msg
$ ReceivedError serial Nothing msg
prop_WireSignal e serial msg = prop_MarshalMessage e serial msg
$ ReceivedSignal serial Nothing msg
#line 138 "src/addresses.anansi"
instance Arbitrary Address where
arbitrary = genAddress where
optional = ['0'..'9'] ++ ['a'..'z'] ++ ['A'..'Z'] ++ "-_/\\*."
methodChars = filter (flip notElem ":;") ['!'..'~']
keyChars = filter (flip notElem "=;,") ['!'..'~']
genMethod = atLeast 0 $ elements methodChars
genParam = do
key <- genKey
value <- genValue
return . concat $ [key, "=", value]
genKey = atLeast 1 $ elements keyChars
genValue = oneof [encodedValue, plainValue]
genHex = elements $ ['0'..'9'] ++ ['a'..'f'] ++ ['A'..'F']
encodedValue = do
x1 <- genHex
x2 <- genHex
return ['%', x1, x2]
plainValue = atLeast 1 $ elements optional
genParams = do
params <- atLeast 0 genParam
let params' = intercalate "," params
extraComma <- if null params
then return ""
else elements ["", ","]
return $ concat [params', extraComma]
genAddress = do
m <- genMethod
params <- genParams
extraSemicolon <- elements ["", ";"]
let addrStr = concat [m, ":", params, extraSemicolon]
let Just [addr] = mkAddresses $ TL.pack addrStr
return addr
#line 442 "src/introspection.anansi"
subObject :: ObjectPath -> Gen I.Object
subObject parentPath = sized $ \n -> resize (min n 4) $ do
let nonRoot = do
x <- arbitrary
case strObjectPath x of
"/" -> nonRoot
x' -> return x'
thisPath <- nonRoot
let path' = case strObjectPath parentPath of
"/" -> thisPath
x -> TL.append x thisPath
let path = mkObjectPath_ path'
ifaces <- arbitrary
children <- halfSized . listOf . subObject $ path
return $ I.Object path ifaces children
instance Arbitrary I.Object where
arbitrary = arbitrary >>= subObject
instance Arbitrary I.Interface where
arbitrary = do
name <- arbitrary
methods <- arbitrary
signals <- arbitrary
properties <- arbitrary
return $ I.Interface name methods signals properties
instance Arbitrary I.Method where
arbitrary = do
name <- arbitrary
inParams <- arbitrary
outParams <- arbitrary
return $ I.Method name inParams outParams
instance Arbitrary I.Signal where
arbitrary = do
name <- arbitrary
params <- arbitrary
return $ I.Signal name params
singleType :: Gen Signature
singleType = do
t <- arbitrary
case mkSignature $ typeCode t of
Just x -> return x
Nothing -> singleType
instance Arbitrary I.Parameter where
arbitrary = do
name <- listOf $ arbitrary `suchThat` isPrint
sig <- singleType
return $ I.Parameter (TL.pack name) sig
instance Arbitrary I.Property where
arbitrary = do
name <- listOf $ arbitrary `suchThat` isPrint
sig <- singleType
access <- elements
[[], [I.Read], [I.Write],
[I.Read, I.Write]]
return $ I.Property (TL.pack name) sig access
#line 187 "src/util.anansi"
halfSized :: Gen a -> Gen a
halfSized gen = sized $ \n -> if n > 0 then
resize (n `div` 2) gen
else gen
funEq :: Eq b => (a -> b) -> (a -> b) -> a -> Bool
funEq f g x = f x == g x
sizedText :: (IsString a, Arbitrary a) => Integer -> Gen TL.Text -> Gen a
sizedText maxSize gen = step where
step = do
s <- gen
if toInteger (TL.length s) > maxSize
then halfSized step
else return . fromString . TL.unpack $ s
atLeast :: Int -> Gen a -> Gen [a]
atLeast minSize g = sized $ \n -> do
count <- choose (minSize, max minSize n)
replicateM count g
isRight :: Either a b -> Bool
isRight = either (const False) (const True)
#line 216 "src/util.anansi"
test :: Testable a => F.TestName -> a -> F.Test
test name prop = F.plusTestOptions options (testProperty name prop) where
options = F.TestOptions Nothing (Just 1) Nothing Nothing
#line 225 "src/util.anansi"
instance Arbitrary Word8 where
arbitrary = arbitraryBoundedIntegral
shrink = shrinkIntegral
instance Arbitrary Word16 where
arbitrary = arbitraryBoundedIntegral
shrink = shrinkIntegral
instance Arbitrary Word32 where
arbitrary = arbitraryBoundedIntegral
shrink = shrinkIntegral
instance Arbitrary Word64 where
arbitrary = arbitraryBoundedIntegral
shrink = shrinkIntegral
instance Arbitrary Int16 where
arbitrary = arbitraryBoundedIntegral
shrink = shrinkIntegral
instance Arbitrary Int32 where
arbitrary = arbitraryBoundedIntegral
shrink = shrinkIntegral
instance Arbitrary Int64 where
arbitrary = arbitraryBoundedIntegral
shrink = shrinkIntegral
instance Arbitrary T.Text where
arbitrary = fmap T.pack arbitrary
instance Arbitrary TL.Text where
arbitrary = fmap TL.pack arbitrary