2 # Simple tests for the ldb python bindings.
3 # Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org>
14 dir_prefix
= os
.path
.join(os
.environ
["SELFTEST_PREFIX"], "tmp")
17 return tempfile
.mktemp(dir=dir_prefix
)
19 class NoContextTests(unittest
.TestCase
):
21 def test_valid_attr_name(self
):
22 self
.assertTrue(ldb
.valid_attr_name("foo"))
23 self
.assertFalse(ldb
.valid_attr_name("24foo"))
25 def test_timestring(self
):
26 self
.assertEquals("19700101000000.0Z", ldb
.timestring(0))
27 self
.assertEquals("20071119191012.0Z", ldb
.timestring(1195499412))
29 def test_string_to_time(self
):
30 self
.assertEquals(0, ldb
.string_to_time("19700101000000.0Z"))
31 self
.assertEquals(1195499412, ldb
.string_to_time("20071119191012.0Z"))
34 class SimpleLdb(unittest
.TestCase
):
36 def test_connect(self
):
39 def test_connect_none(self
):
42 def test_connect_later(self
):
48 self
.assertTrue(repr(x
).startswith("<ldb connection"))
50 def test_set_create_perms(self
):
52 x
.set_create_perms(0600)
54 def test_set_modules_dir(self
):
56 x
.set_modules_dir("/tmp")
58 def test_modules_none(self
):
60 self
.assertEquals([], x
.modules())
62 def test_modules_tdb(self
):
63 x
= ldb
.Ldb(filename())
64 self
.assertEquals("[<ldb module 'tdb'>]", repr(x
.modules()))
66 def test_search(self
):
67 l
= ldb
.Ldb(filename())
68 self
.assertEquals(len(l
.search()), 1)
70 def test_search_controls(self
):
71 l
= ldb
.Ldb(filename())
72 self
.assertEquals(len(l
.search(controls
=["paged_results:0:5"])), 1)
74 def test_search_attrs(self
):
75 l
= ldb
.Ldb(filename())
76 self
.assertEquals(len(l
.search(ldb
.Dn(l
, ""), ldb
.SCOPE_SUBTREE
, "(dc=*)", ["dc"])), 0)
78 def test_search_string_dn(self
):
79 l
= ldb
.Ldb(filename())
80 self
.assertEquals(len(l
.search("", ldb
.SCOPE_SUBTREE
, "(dc=*)", ["dc"])), 0)
82 def test_search_attr_string(self
):
83 l
= ldb
.Ldb(filename())
84 self
.assertRaises(TypeError, l
.search
, attrs
="dc")
86 def test_opaque(self
):
87 l
= ldb
.Ldb(filename())
88 l
.set_opaque("my_opaque", l
)
89 self
.assertTrue(l
.get_opaque("my_opaque") is not None)
90 self
.assertEquals(None, l
.get_opaque("unknown"))
92 def test_search_scope_base(self
):
93 l
= ldb
.Ldb(filename())
94 self
.assertEquals(len(l
.search(ldb
.Dn(l
, "dc=foo1"),
95 ldb
.SCOPE_ONELEVEL
)), 0)
97 def test_delete(self
):
98 l
= ldb
.Ldb(filename())
99 self
.assertRaises(ldb
.LdbError
, lambda: l
.delete(ldb
.Dn(l
, "dc=foo2")))
101 def test_delete_w_unhandled_ctrl(self
):
102 l
= ldb
.Ldb(filename())
104 m
.dn
= ldb
.Dn(l
, "dc=foo1")
107 self
.assertRaises(ldb
.LdbError
, lambda: l
.delete(m
.dn
, ["search_options:1:2"]))
110 def test_contains(self
):
111 l
= ldb
.Ldb(filename())
112 self
.assertFalse(ldb
.Dn(l
, "dc=foo3") in l
)
113 l
= ldb
.Ldb(filename())
115 m
.dn
= ldb
.Dn(l
, "dc=foo3")
119 self
.assertTrue(ldb
.Dn(l
, "dc=foo3") in l
)
123 def test_get_config_basedn(self
):
124 l
= ldb
.Ldb(filename())
125 self
.assertEquals(None, l
.get_config_basedn())
127 def test_get_root_basedn(self
):
128 l
= ldb
.Ldb(filename())
129 self
.assertEquals(None, l
.get_root_basedn())
131 def test_get_schema_basedn(self
):
132 l
= ldb
.Ldb(filename())
133 self
.assertEquals(None, l
.get_schema_basedn())
135 def test_get_default_basedn(self
):
136 l
= ldb
.Ldb(filename())
137 self
.assertEquals(None, l
.get_default_basedn())
140 l
= ldb
.Ldb(filename())
142 m
.dn
= ldb
.Dn(l
, "dc=foo4")
144 self
.assertEquals(len(l
.search()), 1)
147 self
.assertEquals(len(l
.search()), 2)
149 l
.delete(ldb
.Dn(l
, "dc=foo4"))
151 def test_add_w_unhandled_ctrl(self
):
152 l
= ldb
.Ldb(filename())
154 m
.dn
= ldb
.Dn(l
, "dc=foo4")
156 self
.assertEquals(len(l
.search()), 1)
157 self
.assertRaises(ldb
.LdbError
, lambda: l
.add(m
,["search_options:1:2"]))
159 def test_add_dict(self
):
160 l
= ldb
.Ldb(filename())
161 m
= {"dn": ldb
.Dn(l
, "dc=foo5"),
163 self
.assertEquals(len(l
.search()), 1)
166 self
.assertEquals(len(l
.search()), 2)
168 l
.delete(ldb
.Dn(l
, "dc=foo5"))
170 def test_add_dict_string_dn(self
):
171 l
= ldb
.Ldb(filename())
172 m
= {"dn": "dc=foo6", "bla": "bla"}
173 self
.assertEquals(len(l
.search()), 1)
176 self
.assertEquals(len(l
.search()), 2)
178 l
.delete(ldb
.Dn(l
, "dc=foo6"))
180 def test_rename(self
):
181 l
= ldb
.Ldb(filename())
183 m
.dn
= ldb
.Dn(l
, "dc=foo7")
185 self
.assertEquals(len(l
.search()), 1)
188 l
.rename(ldb
.Dn(l
, "dc=foo7"), ldb
.Dn(l
, "dc=bar"))
189 self
.assertEquals(len(l
.search()), 2)
191 l
.delete(ldb
.Dn(l
, "dc=bar"))
193 def test_rename_string_dns(self
):
194 l
= ldb
.Ldb(filename())
196 m
.dn
= ldb
.Dn(l
, "dc=foo8")
198 self
.assertEquals(len(l
.search()), 1)
200 self
.assertEquals(len(l
.search()), 2)
202 l
.rename("dc=foo8", "dc=bar")
203 self
.assertEquals(len(l
.search()), 2)
205 l
.delete(ldb
.Dn(l
, "dc=bar"))
207 def test_modify_delete(self
):
208 l
= ldb
.Ldb(filename())
210 m
.dn
= ldb
.Dn(l
, "dc=modifydelete")
213 rm
= l
.search(m
.dn
)[0]
214 self
.assertEquals(["1234"], list(rm
["bla"]))
217 m
.dn
= ldb
.Dn(l
, "dc=modifydelete")
218 m
["bla"] = ldb
.MessageElement([], ldb
.FLAG_MOD_DELETE
, "bla")
219 self
.assertEquals(ldb
.FLAG_MOD_DELETE
, m
["bla"].flags())
221 rm
= l
.search(m
.dn
)[0]
222 self
.assertEquals(1, len(rm
))
223 rm
= l
.search(m
.dn
, attrs
=["bla"])
224 self
.assertEquals(0, len(rm
))
226 l
.delete(ldb
.Dn(l
, "dc=modifydelete"))
228 def test_modify_add(self
):
229 l
= ldb
.Ldb(filename())
231 m
.dn
= ldb
.Dn(l
, "dc=add")
236 m
.dn
= ldb
.Dn(l
, "dc=add")
237 m
["bla"] = ldb
.MessageElement(["456"], ldb
.FLAG_MOD_ADD
, "bla")
238 self
.assertEquals(ldb
.FLAG_MOD_ADD
, m
["bla"].flags())
240 rm
= l
.search(m
.dn
)[0]
241 self
.assertEquals(2, len(rm
))
242 self
.assertEquals(["1234", "456"], list(rm
["bla"]))
244 l
.delete(ldb
.Dn(l
, "dc=add"))
246 def test_modify_replace(self
):
247 l
= ldb
.Ldb(filename())
249 m
.dn
= ldb
.Dn(l
, "dc=modify2")
250 m
["bla"] = ["1234", "456"]
254 m
.dn
= ldb
.Dn(l
, "dc=modify2")
255 m
["bla"] = ldb
.MessageElement(["789"], ldb
.FLAG_MOD_REPLACE
, "bla")
256 self
.assertEquals(ldb
.FLAG_MOD_REPLACE
, m
["bla"].flags())
258 rm
= l
.search(m
.dn
)[0]
259 self
.assertEquals(2, len(rm
))
260 self
.assertEquals(["789"], list(rm
["bla"]))
261 rm
= l
.search(m
.dn
, attrs
=["bla"])[0]
262 self
.assertEquals(1, len(rm
))
264 l
.delete(ldb
.Dn(l
, "dc=modify2"))
266 def test_modify_flags_change(self
):
267 l
= ldb
.Ldb(filename())
269 m
.dn
= ldb
.Dn(l
, "dc=add")
274 m
.dn
= ldb
.Dn(l
, "dc=add")
275 m
["bla"] = ldb
.MessageElement(["456"], ldb
.FLAG_MOD_ADD
, "bla")
276 self
.assertEquals(ldb
.FLAG_MOD_ADD
, m
["bla"].flags())
278 rm
= l
.search(m
.dn
)[0]
279 self
.assertEquals(2, len(rm
))
280 self
.assertEquals(["1234", "456"], list(rm
["bla"]))
282 # Now create another modify, but switch the flags before we do it
283 m
["bla"] = ldb
.MessageElement(["456"], ldb
.FLAG_MOD_ADD
, "bla")
284 m
["bla"].set_flags(ldb
.FLAG_MOD_DELETE
)
286 rm
= l
.search(m
.dn
, attrs
=["bla"])[0]
287 self
.assertEquals(1, len(rm
))
288 self
.assertEquals(["1234"], list(rm
["bla"]))
290 l
.delete(ldb
.Dn(l
, "dc=add"))
292 def test_transaction_commit(self
):
293 l
= ldb
.Ldb(filename())
294 l
.transaction_start()
295 m
= ldb
.Message(ldb
.Dn(l
, "dc=foo9"))
298 l
.transaction_commit()
301 def test_transaction_cancel(self
):
302 l
= ldb
.Ldb(filename())
303 l
.transaction_start()
304 m
= ldb
.Message(ldb
.Dn(l
, "dc=foo10"))
307 l
.transaction_cancel()
308 self
.assertEquals(0, len(l
.search(ldb
.Dn(l
, "dc=foo10"))))
310 def test_set_debug(self
):
311 def my_report_fn(level
, text
):
313 l
= ldb
.Ldb(filename())
314 l
.set_debug(my_report_fn
)
316 def test_zero_byte_string(self
):
317 """Testing we do not get trapped in the \0 byte in a property string."""
318 l
= ldb
.Ldb(filename())
321 "objectclass" : "user",
322 "cN" : "LDAPtestUSER",
323 "givenname" : "ldap",
324 "displayname" : "foo\0bar",
326 res
= l
.search(expression
="(dn=dc=somedn)")
327 self
.assertEquals("foo\0bar", res
[0]["displayname"][0])
329 def test_no_crash_broken_expr(self
):
330 l
= ldb
.Ldb(filename())
331 self
.assertRaises(ldb
.LdbError
,lambda: l
.search("", ldb
.SCOPE_SUBTREE
, "&(dc=*)(dn=*)", ["dc"]))
334 class DnTests(unittest
.TestCase
):
337 self
.ldb
= ldb
.Ldb(filename())
339 def test_set_dn_invalid(self
):
343 self
.assertRaises(TypeError, assign
)
346 x
= ldb
.Dn(self
.ldb
, "dc=foo11,bar=bloe")
347 y
= ldb
.Dn(self
.ldb
, "dc=foo11,bar=bloe")
348 self
.assertEquals(x
, y
)
349 y
= ldb
.Dn(self
.ldb
, "dc=foo11,bar=blie")
350 self
.assertNotEquals(x
, y
)
353 x
= ldb
.Dn(self
.ldb
, "dc=foo12,bar=bloe")
354 self
.assertEquals(x
.__str
__(), "dc=foo12,bar=bloe")
357 x
= ldb
.Dn(self
.ldb
, "dc=foo13,bla=blie")
358 self
.assertEquals(x
.__repr
__(), "Dn('dc=foo13,bla=blie')")
360 def test_get_casefold(self
):
361 x
= ldb
.Dn(self
.ldb
, "dc=foo14,bar=bloe")
362 self
.assertEquals(x
.get_casefold(), "DC=FOO14,BAR=bloe")
364 def test_validate(self
):
365 x
= ldb
.Dn(self
.ldb
, "dc=foo15,bar=bloe")
366 self
.assertTrue(x
.validate())
368 def test_parent(self
):
369 x
= ldb
.Dn(self
.ldb
, "dc=foo16,bar=bloe")
370 self
.assertEquals("bar=bloe", x
.parent().__str
__())
372 def test_parent_nonexistant(self
):
373 x
= ldb
.Dn(self
.ldb
, "@BLA")
374 self
.assertEquals(None, x
.parent())
376 def test_is_valid(self
):
377 x
= ldb
.Dn(self
.ldb
, "dc=foo18,dc=bloe")
378 self
.assertTrue(x
.is_valid())
379 x
= ldb
.Dn(self
.ldb
, "")
380 self
.assertTrue(x
.is_valid())
382 def test_is_special(self
):
383 x
= ldb
.Dn(self
.ldb
, "dc=foo19,bar=bloe")
384 self
.assertFalse(x
.is_special())
385 x
= ldb
.Dn(self
.ldb
, "@FOOBAR")
386 self
.assertTrue(x
.is_special())
388 def test_check_special(self
):
389 x
= ldb
.Dn(self
.ldb
, "dc=foo20,bar=bloe")
390 self
.assertFalse(x
.check_special("FOOBAR"))
391 x
= ldb
.Dn(self
.ldb
, "@FOOBAR")
392 self
.assertTrue(x
.check_special("@FOOBAR"))
395 x
= ldb
.Dn(self
.ldb
, "dc=foo21,bar=bloe")
396 self
.assertEquals(2, len(x
))
397 x
= ldb
.Dn(self
.ldb
, "dc=foo21")
398 self
.assertEquals(1, len(x
))
400 def test_add_child(self
):
401 x
= ldb
.Dn(self
.ldb
, "dc=foo22,bar=bloe")
402 self
.assertTrue(x
.add_child(ldb
.Dn(self
.ldb
, "bla=bloe")))
403 self
.assertEquals("bla=bloe,dc=foo22,bar=bloe", x
.__str
__())
405 def test_add_base(self
):
406 x
= ldb
.Dn(self
.ldb
, "dc=foo23,bar=bloe")
407 base
= ldb
.Dn(self
.ldb
, "bla=bloe")
408 self
.assertTrue(x
.add_base(base
))
409 self
.assertEquals("dc=foo23,bar=bloe,bla=bloe", x
.__str
__())
412 x
= ldb
.Dn(self
.ldb
, "dc=foo24")
413 y
= ldb
.Dn(self
.ldb
, "bar=bla")
414 self
.assertEquals("dc=foo24,bar=bla", str(y
+ x
))
416 def test_parse_ldif(self
):
417 msgs
= self
.ldb
.parse_ldif("dn: foo=bar\n")
419 self
.assertEquals("foo=bar", str(msg
[1].dn
))
420 self
.assertTrue(isinstance(msg
[1], ldb
.Message
))
421 ldif
= self
.ldb
.write_ldif(msg
[1], ldb
.CHANGETYPE_NONE
)
422 self
.assertEquals("dn: foo=bar\n\n", ldif
)
424 def test_parse_ldif_more(self
):
425 msgs
= self
.ldb
.parse_ldif("dn: foo=bar\n\n\ndn: bar=bar")
427 self
.assertEquals("foo=bar", str(msg
[1].dn
))
429 self
.assertEquals("bar=bar", str(msg
[1].dn
))
431 def test_canonical_string(self
):
432 x
= ldb
.Dn(self
.ldb
, "dc=foo25,bar=bloe")
433 self
.assertEquals("/bloe/foo25", x
.canonical_str())
435 def test_canonical_ex_string(self
):
436 x
= ldb
.Dn(self
.ldb
, "dc=foo26,bar=bloe")
437 self
.assertEquals("/bloe\nfoo26", x
.canonical_ex_str())
440 class LdbMsgTests(unittest
.TestCase
):
443 self
.msg
= ldb
.Message()
445 def test_init_dn(self
):
446 self
.msg
= ldb
.Message(ldb
.Dn(ldb
.Ldb(), "dc=foo27"))
447 self
.assertEquals("dc=foo27", str(self
.msg
.dn
))
449 def test_iter_items(self
):
450 self
.assertEquals(0, len(self
.msg
.items()))
451 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "dc=foo28")
452 self
.assertEquals(1, len(self
.msg
.items()))
455 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "dc=foo29")
456 self
.msg
["dc"] = "foo"
457 self
.assertEquals("Message({'dn': Dn('dc=foo29'), 'dc': MessageElement(['foo'])})", repr(self
.msg
))
460 self
.assertEquals(0, len(self
.msg
))
462 def test_notpresent(self
):
463 self
.assertRaises(KeyError, lambda: self
.msg
["foo"])
469 self
.msg
.add(ldb
.MessageElement(["456"], ldb
.FLAG_MOD_ADD
, "bla"))
471 def test_elements_empty(self
):
472 self
.assertEquals([], self
.msg
.elements())
474 def test_elements(self
):
475 el
= ldb
.MessageElement(["456"], ldb
.FLAG_MOD_ADD
, "bla")
477 self
.assertEquals([el
], self
.msg
.elements())
479 def test_add_value(self
):
480 self
.assertEquals(0, len(self
.msg
))
481 self
.msg
["foo"] = ["foo"]
482 self
.assertEquals(1, len(self
.msg
))
484 def test_add_value_multiple(self
):
485 self
.assertEquals(0, len(self
.msg
))
486 self
.msg
["foo"] = ["foo", "bla"]
487 self
.assertEquals(1, len(self
.msg
))
488 self
.assertEquals(["foo", "bla"], list(self
.msg
["foo"]))
490 def test_set_value(self
):
491 self
.msg
["foo"] = ["fool"]
492 self
.assertEquals(["fool"], list(self
.msg
["foo"]))
493 self
.msg
["foo"] = ["bar"]
494 self
.assertEquals(["bar"], list(self
.msg
["foo"]))
497 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "@BASEINFO")
498 self
.msg
["foo"] = ["bla"]
499 self
.msg
["bar"] = ["bla"]
500 self
.assertEquals(["dn", "foo", "bar"], self
.msg
.keys())
503 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb(filename()), "@BASEINFO")
504 self
.assertEquals("@BASEINFO", self
.msg
.dn
.__str
__())
506 def test_get_dn(self
):
507 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "@BASEINFO")
508 self
.assertEquals("@BASEINFO", self
.msg
.get("dn").__str
__())
510 def test_get_invalid(self
):
511 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "@BASEINFO")
512 self
.assertRaises(TypeError, self
.msg
.get
, 42)
514 def test_get_other(self
):
515 self
.msg
["foo"] = ["bar"]
516 self
.assertEquals("bar", self
.msg
.get("foo")[0])
518 def test_get_unknown(self
):
519 self
.assertEquals(None, self
.msg
.get("lalalala"))
521 def test_msg_diff(self
):
523 msgs
= l
.parse_ldif("dn: foo=bar\nfoo: bar\nbaz: do\n\ndn: foo=bar\nfoo: bar\nbaz: dont\n")
524 msg1
= msgs
.next()[1]
525 msg2
= msgs
.next()[1]
526 msgdiff
= l
.msg_diff(msg1
, msg2
)
527 self
.assertEquals("foo=bar", msgdiff
.get("dn").__str
__())
528 self
.assertRaises(KeyError, lambda: msgdiff
["foo"])
529 self
.assertEquals(1, len(msgdiff
))
531 def test_equal_empty(self
):
534 self
.assertEquals(msg1
, msg2
)
536 def test_equal_simplel(self
):
537 db
= ldb
.Ldb("foo.tdb")
539 msg1
.dn
= ldb
.Dn(db
, "foo=bar")
541 msg2
.dn
= ldb
.Dn(db
, "foo=bar")
542 self
.assertEquals(msg1
, msg2
)
545 self
.assertEquals(msg1
, msg2
)
547 self
.assertNotEquals(msg1
, msg2
)
550 def test_from_dict(self
):
551 rec
= {"dn": "dc=fromdict",
552 "a1": ["a1-val1", "a1-val1"]}
554 # check different types of input Flags
555 for flags
in [ldb
.FLAG_MOD_ADD
, ldb
.FLAG_MOD_REPLACE
, ldb
.FLAG_MOD_DELETE
]:
556 m
= ldb
.Message
.from_dict(l
, rec
, flags
)
557 self
.assertEquals(rec
["a1"], list(m
["a1"]))
558 self
.assertEquals(flags
, m
["a1"].flags())
560 self
.assertRaises(TypeError, ldb
.Message
.from_dict
, dict(), rec
, ldb
.FLAG_MOD_REPLACE
)
561 self
.assertRaises(TypeError, ldb
.Message
.from_dict
, l
, list(), ldb
.FLAG_MOD_REPLACE
)
562 self
.assertRaises(ValueError, ldb
.Message
.from_dict
, l
, rec
, 0)
563 # Message.from_dict expects dictionary with 'dn'
564 err_rec
= {"a1": ["a1-val1", "a1-val1"]}
565 self
.assertRaises(TypeError, ldb
.Message
.from_dict
, l
, err_rec
, ldb
.FLAG_MOD_REPLACE
)
569 class MessageElementTests(unittest
.TestCase
):
571 def test_cmp_element(self
):
572 x
= ldb
.MessageElement(["foo"])
573 y
= ldb
.MessageElement(["foo"])
574 z
= ldb
.MessageElement(["bzr"])
575 self
.assertEquals(x
, y
)
576 self
.assertNotEquals(x
, z
)
578 def test_create_iterable(self
):
579 x
= ldb
.MessageElement(["foo"])
580 self
.assertEquals(["foo"], list(x
))
583 x
= ldb
.MessageElement(["foo"])
584 self
.assertEquals("MessageElement(['foo'])", repr(x
))
585 x
= ldb
.MessageElement(["foo", "bla"])
586 self
.assertEquals(2, len(x
))
587 self
.assertEquals("MessageElement(['foo','bla'])", repr(x
))
589 def test_get_item(self
):
590 x
= ldb
.MessageElement(["foo", "bar"])
591 self
.assertEquals("foo", x
[0])
592 self
.assertEquals("bar", x
[1])
593 self
.assertEquals("bar", x
[-1])
594 self
.assertRaises(IndexError, lambda: x
[45])
597 x
= ldb
.MessageElement(["foo", "bar"])
598 self
.assertEquals(2, len(x
))
601 x
= ldb
.MessageElement(["foo", "bar"])
602 y
= ldb
.MessageElement(["foo", "bar"])
603 self
.assertEquals(y
, x
)
604 x
= ldb
.MessageElement(["foo"])
605 self
.assertNotEquals(y
, x
)
606 y
= ldb
.MessageElement(["foo"])
607 self
.assertEquals(y
, x
)
610 class ModuleTests(unittest
.TestCase
):
612 def test_register_module(self
):
615 ldb
.register_module(ExampleModule
)
617 def test_use_module(self
):
622 def __init__(self
, ldb
, next
):
626 def search(self
, *args
, **kwargs
):
627 return self
.next
.search(*args
, **kwargs
)
630 ldb
.register_module(ExampleModule
)
631 if os
.path
.exists(name
):
634 l
.add({"dn": "@MODULES", "@LIST": "bla"})
635 self
.assertEquals([], ops
)
637 self
.assertEquals(["init"], ops
)
640 class VersionTests(unittest
.TestCase
):
642 def test_version(self
):
643 self
.assertTrue(isinstance(ldb
.__version
__, str))
646 if __name__
== '__main__':
648 unittest
.TestProgram()