1 {-# LANGUAGE TemplateHaskell #-}
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
4 {-| Unittests for ganeti-htools.
10 Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29 module Test.Ganeti.Query.Language
34 import Test.QuickCheck
36 import Control.Applicative
37 import Control.Arrow (second)
40 import Test.Ganeti.TestHelper
41 import Test.Ganeti.TestCommon
43 import Ganeti.Query.Language
45 -- | Custom 'Filter' generator (top-level), which enforces a
46 -- (sane) limit on the depth of the generated filters.
47 genFilter :: Gen (Filter FilterField)
48 genFilter = choose (0, 10) >>= genFilter'
50 -- | Custom generator for filters that correctly halves the state of
51 -- the generators at each recursive step, per the QuickCheck
52 -- documentation, in order not to run out of memory.
53 genFilter' :: Int -> Gen (Filter FilterField)
55 oneof [ pure EmptyFilter
56 , TrueFilter <$> getName
57 , EQFilter <$> getName <*> value
58 , LTFilter <$> getName <*> value
59 , GTFilter <$> getName <*> value
60 , LEFilter <$> getName <*> value
61 , GEFilter <$> getName <*> value
62 , RegexpFilter <$> getName <*> arbitrary
63 , ContainsFilter <$> getName <*> value
65 where value = oneof [ QuotedString <$> getName
66 , NumericValue <$> arbitrary
69 oneof [ AndFilter <$> vectorOf n'' (genFilter' n')
70 , OrFilter <$> vectorOf n'' (genFilter' n')
71 , NotFilter <$> genFilter' n'
73 where n' = n `div` 2 -- sub-filter generator size
74 n'' = max n' 2 -- but we don't want empty or 1-element lists,
75 -- so use this for and/or filter list length
77 $(genArbitrary ''ItemType)
79 instance Arbitrary FilterRegex where
80 arbitrary = getName >>= mkRegex -- a name should be a good regex
82 $(genArbitrary ''ResultStatus)
84 $(genArbitrary ''FieldType)
86 $(genArbitrary ''FieldDefinition)
88 -- | Generates an arbitrary JSValue. We do this via a function a not
89 -- via arbitrary instance since that would require us to define an
90 -- arbitrary for JSValue, which can be recursive, entering the usual
91 -- problems with that; so we only generate the base types, not the
92 -- recursive ones, and not 'JSNull', which we can't use in a
93 -- 'RSNormal' 'ResultEntry'.
94 genJSValue :: Gen JSValue
96 oneof [ JSBool <$> arbitrary
97 , JSRational <$> pure False <*> arbitrary
98 , JSString <$> (toJSString <$> arbitrary)
99 , (JSArray . map showJSON) <$> (arbitrary::Gen [Int])
100 , JSObject . toJSObject . map (second showJSON) <$>
101 (arbitrary::Gen [(String, Int)])
104 -- | Generates a 'ResultEntry' value.
105 genResultEntry :: Gen ResultEntry
109 RSNormal -> Just <$> genJSValue
111 return $ ResultEntry rs rv
113 $(genArbitrary ''QueryFieldsResult)
115 -- | Tests that serialisation/deserialisation of filters is
117 prop_filter_serialisation :: Property
118 prop_filter_serialisation = forAll genFilter testSerialisation
120 -- | Tests that filter regexes are serialised correctly.
121 prop_filterregex_instances :: FilterRegex -> Property
122 prop_filterregex_instances rex =
123 printTestCase "failed JSON encoding" (testSerialisation rex) .&&.
124 printTestCase "failed read/show instances" (read (show rex) ==? rex)
126 -- | Tests 'ResultStatus' serialisation.
127 prop_resultstatus_serialisation :: ResultStatus -> Property
128 prop_resultstatus_serialisation = testSerialisation
130 -- | Tests 'FieldType' serialisation.
131 prop_fieldtype_serialisation :: FieldType -> Property
132 prop_fieldtype_serialisation = testSerialisation
134 -- | Tests 'FieldDef' serialisation.
135 prop_fielddef_serialisation :: FieldDefinition -> Property
136 prop_fielddef_serialisation = testSerialisation
138 -- | Tests 'ResultEntry' serialisation. Needed especially as this is
139 -- done manually, and not via buildObject (different serialisation
141 prop_resultentry_serialisation :: Property
142 prop_resultentry_serialisation = forAll genResultEntry testSerialisation
144 -- | Tests 'FieldDef' serialisation. We use a made-up maximum limit of
145 -- 20 for the generator, since otherwise the lists become too long and
146 -- we don't care so much about list length but rather structure.
147 prop_fieldsresult_serialisation :: Property
148 prop_fieldsresult_serialisation =
149 forAll (resize 20 arbitrary::Gen QueryFieldsResult) testSerialisation
151 testSuite "Query/Language"
152 [ 'prop_filter_serialisation
153 , 'prop_filterregex_instances
154 , 'prop_resultstatus_serialisation
155 , 'prop_fieldtype_serialisation
156 , 'prop_fielddef_serialisation
157 , 'prop_resultentry_serialisation
158 , 'prop_fieldsresult_serialisation