Revision 8620f50e
b/lib/ht.py | ||
---|---|---|
25 | 25 |
|
26 | 26 |
from ganeti import compat |
27 | 27 |
from ganeti import utils |
28 |
from ganeti import constants |
|
28 | 29 |
|
29 | 30 |
|
30 | 31 |
_PAREN_RE = re.compile("^[a-zA-Z0-9_-]+$") |
... | ... | |
118 | 119 |
|
119 | 120 |
|
120 | 121 |
# Some basic types |
122 |
@WithDesc("Anything") |
|
123 |
def TAny(_): |
|
124 |
"""Accepts any value. |
|
125 |
|
|
126 |
""" |
|
127 |
return True |
|
128 |
|
|
129 |
|
|
121 | 130 |
@WithDesc("NotNone") |
122 | 131 |
def TNotNone(val): |
123 | 132 |
"""Checks if the given value is not None. |
... | ... | |
245 | 254 |
(Parens(fn), Parens(test)))(lambda val: test(fn(val))) |
246 | 255 |
|
247 | 256 |
|
257 |
def TRegex(pobj): |
|
258 |
"""Checks whether a string matches a specific regular expression. |
|
259 |
|
|
260 |
@param pobj: Compiled regular expression as returned by C{re.compile} |
|
261 |
|
|
262 |
""" |
|
263 |
desc = WithDesc("String matching regex \"%s\"" % |
|
264 |
pobj.pattern.encode("string_escape")) |
|
265 |
|
|
266 |
return desc(TAnd(TString, pobj.match)) |
|
267 |
|
|
268 |
|
|
248 | 269 |
# Type aliases |
249 | 270 |
|
250 | 271 |
#: a non-empty string |
... | ... | |
271 | 292 |
TPositiveFloat = \ |
272 | 293 |
TAnd(TFloat, WithDesc("EqualGreaterZero")(lambda v: v >= 0.0)) |
273 | 294 |
|
295 |
#: Job ID |
|
296 |
TJobId = TOr(TPositiveInt, |
|
297 |
TRegex(re.compile("^%s$" % constants.JOB_ID_TEMPLATE))) |
|
298 |
|
|
274 | 299 |
|
275 | 300 |
def TListOf(my_type): |
276 | 301 |
"""Checks if a given value is a list with all elements of the same type. |
... | ... | |
340 | 365 |
return desc(TAnd(TDict, |
341 | 366 |
compat.partial(_TStrictDictCheck, require_all, exclusive, |
342 | 367 |
items))) |
368 |
|
|
369 |
|
|
370 |
def TItems(items): |
|
371 |
"""Checks individual items of a container. |
|
372 |
|
|
373 |
If the verified value and the list of expected items differ in length, this |
|
374 |
check considers only as many items as are contained in the shorter list. Use |
|
375 |
L{TIsLength} to enforce a certain length. |
|
376 |
|
|
377 |
@type items: list |
|
378 |
@param items: List of checks |
|
379 |
|
|
380 |
""" |
|
381 |
assert items, "Need items" |
|
382 |
|
|
383 |
text = ["Item", "item"] |
|
384 |
desc = WithDesc(utils.CommaJoin("%s %s is %s" % |
|
385 |
(text[int(idx > 0)], idx, Parens(check)) |
|
386 |
for (idx, check) in enumerate(items))) |
|
387 |
|
|
388 |
return desc(lambda value: compat.all(check(i) |
|
389 |
for (check, i) in zip(items, value))) |
b/test/ganeti.ht_unittest.py | ||
---|---|---|
230 | 230 |
self.assertTrue(fn({"other": 11})) |
231 | 231 |
self.assertTrue(fn({"other": object()})) |
232 | 232 |
|
233 |
def testJobId(self): |
|
234 |
for i in [0, 1, 4395, 2347625220]: |
|
235 |
self.assertTrue(ht.TJobId(i)) |
|
236 |
self.assertTrue(ht.TJobId(str(i))) |
|
237 |
self.assertFalse(ht.TJobId(-(i + 1))) |
|
238 |
|
|
239 |
for i in ["", "-", ".", ",", "a", "99j", "job-123", "\t", " 83 ", |
|
240 |
None, [], {}, object()]: |
|
241 |
self.assertFalse(ht.TJobId(i)) |
|
242 |
|
|
243 |
def testItems(self): |
|
244 |
self.assertRaises(AssertionError, ht.TItems, []) |
|
245 |
|
|
246 |
fn = ht.TItems([ht.TString]) |
|
247 |
self.assertFalse(fn([0])) |
|
248 |
self.assertFalse(fn([None])) |
|
249 |
self.assertTrue(fn(["Hello"])) |
|
250 |
self.assertTrue(fn(["Hello", "World"])) |
|
251 |
self.assertTrue(fn(["Hello", 0, 1, 2, "anything"])) |
|
252 |
|
|
253 |
fn = ht.TItems([ht.TAny, ht.TInt, ht.TAny]) |
|
254 |
self.assertTrue(fn(["Hello", 0, []])) |
|
255 |
self.assertTrue(fn(["Hello", 893782])) |
|
256 |
self.assertTrue(fn([{}, -938210858947, None])) |
|
257 |
self.assertFalse(fn(["Hello", []])) |
|
258 |
|
|
233 | 259 |
|
234 | 260 |
if __name__ == "__main__": |
235 | 261 |
testutils.GanetiTestProgram() |
Also available in: Unified diff