/Lib/bsddb/test/test_dbtables.py

http://unladen-swallow.googlecode.com/ · Python · 405 lines · 308 code · 59 blank · 38 comment · 43 complexity · 88402054184fd61c395f6368f9ab3715 MD5 · raw file

  1. #!/usr/bin/env python
  2. #
  3. #-----------------------------------------------------------------------
  4. # A test suite for the table interface built on bsddb.db
  5. #-----------------------------------------------------------------------
  6. #
  7. # Copyright (C) 2000, 2001 by Autonomous Zone Industries
  8. # Copyright (C) 2002 Gregory P. Smith
  9. #
  10. # March 20, 2000
  11. #
  12. # License: This is free software. You may use this software for any
  13. # purpose including modification/redistribution, so long as
  14. # this header remains intact and that you do not claim any
  15. # rights of ownership or authorship of this software. This
  16. # software has been tested, but no warranty is expressed or
  17. # implied.
  18. #
  19. # -- Gregory P. Smith <greg@krypto.org>
  20. #
  21. # $Id: test_dbtables.py 66088 2008-08-31 14:00:51Z jesus.cea $
  22. import os, re
  23. try:
  24. import cPickle
  25. pickle = cPickle
  26. except ImportError:
  27. import pickle
  28. import unittest
  29. from test_all import db, dbtables, test_support, verbose, \
  30. get_new_environment_path, get_new_database_path
  31. #----------------------------------------------------------------------
  32. class TableDBTestCase(unittest.TestCase):
  33. db_name = 'test-table.db'
  34. def setUp(self):
  35. import sys
  36. if sys.version_info[0] >= 3 :
  37. from test_all import do_proxy_db_py3k
  38. self._flag_proxy_db_py3k = do_proxy_db_py3k(False)
  39. self.testHomeDir = get_new_environment_path()
  40. self.tdb = dbtables.bsdTableDB(
  41. filename='tabletest.db', dbhome=self.testHomeDir, create=1)
  42. def tearDown(self):
  43. self.tdb.close()
  44. import sys
  45. if sys.version_info[0] >= 3 :
  46. from test_all import do_proxy_db_py3k
  47. do_proxy_db_py3k(self._flag_proxy_db_py3k)
  48. test_support.rmtree(self.testHomeDir)
  49. def test01(self):
  50. tabname = "test01"
  51. colname = 'cool numbers'
  52. try:
  53. self.tdb.Drop(tabname)
  54. except dbtables.TableDBError:
  55. pass
  56. self.tdb.CreateTable(tabname, [colname])
  57. import sys
  58. if sys.version_info[0] < 3 :
  59. self.tdb.Insert(tabname, {colname: pickle.dumps(3.14159, 1)})
  60. else :
  61. self.tdb.Insert(tabname, {colname: pickle.dumps(3.14159,
  62. 1).decode("iso8859-1")}) # 8 bits
  63. if verbose:
  64. self.tdb._db_print()
  65. values = self.tdb.Select(
  66. tabname, [colname], conditions={colname: None})
  67. import sys
  68. if sys.version_info[0] < 3 :
  69. colval = pickle.loads(values[0][colname])
  70. else :
  71. colval = pickle.loads(bytes(values[0][colname], "iso8859-1"))
  72. self.assert_(colval > 3.141)
  73. self.assert_(colval < 3.142)
  74. def test02(self):
  75. tabname = "test02"
  76. col0 = 'coolness factor'
  77. col1 = 'but can it fly?'
  78. col2 = 'Species'
  79. import sys
  80. if sys.version_info[0] < 3 :
  81. testinfo = [
  82. {col0: pickle.dumps(8, 1), col1: 'no', col2: 'Penguin'},
  83. {col0: pickle.dumps(-1, 1), col1: 'no', col2: 'Turkey'},
  84. {col0: pickle.dumps(9, 1), col1: 'yes', col2: 'SR-71A Blackbird'}
  85. ]
  86. else :
  87. testinfo = [
  88. {col0: pickle.dumps(8, 1).decode("iso8859-1"),
  89. col1: 'no', col2: 'Penguin'},
  90. {col0: pickle.dumps(-1, 1).decode("iso8859-1"),
  91. col1: 'no', col2: 'Turkey'},
  92. {col0: pickle.dumps(9, 1).decode("iso8859-1"),
  93. col1: 'yes', col2: 'SR-71A Blackbird'}
  94. ]
  95. try:
  96. self.tdb.Drop(tabname)
  97. except dbtables.TableDBError:
  98. pass
  99. self.tdb.CreateTable(tabname, [col0, col1, col2])
  100. for row in testinfo :
  101. self.tdb.Insert(tabname, row)
  102. import sys
  103. if sys.version_info[0] < 3 :
  104. values = self.tdb.Select(tabname, [col2],
  105. conditions={col0: lambda x: pickle.loads(x) >= 8})
  106. else :
  107. values = self.tdb.Select(tabname, [col2],
  108. conditions={col0: lambda x:
  109. pickle.loads(bytes(x, "iso8859-1")) >= 8})
  110. self.assertEqual(len(values), 2)
  111. if values[0]['Species'] == 'Penguin' :
  112. self.assertEqual(values[1]['Species'], 'SR-71A Blackbird')
  113. elif values[0]['Species'] == 'SR-71A Blackbird' :
  114. self.assertEqual(values[1]['Species'], 'Penguin')
  115. else :
  116. if verbose:
  117. print "values= %r" % (values,)
  118. raise RuntimeError("Wrong values returned!")
  119. def test03(self):
  120. tabname = "test03"
  121. try:
  122. self.tdb.Drop(tabname)
  123. except dbtables.TableDBError:
  124. pass
  125. if verbose:
  126. print '...before CreateTable...'
  127. self.tdb._db_print()
  128. self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e'])
  129. if verbose:
  130. print '...after CreateTable...'
  131. self.tdb._db_print()
  132. self.tdb.Drop(tabname)
  133. if verbose:
  134. print '...after Drop...'
  135. self.tdb._db_print()
  136. self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e'])
  137. try:
  138. self.tdb.Insert(tabname,
  139. {'a': "",
  140. 'e': pickle.dumps([{4:5, 6:7}, 'foo'], 1),
  141. 'f': "Zero"})
  142. self.fail('Expected an exception')
  143. except dbtables.TableDBError:
  144. pass
  145. try:
  146. self.tdb.Select(tabname, [], conditions={'foo': '123'})
  147. self.fail('Expected an exception')
  148. except dbtables.TableDBError:
  149. pass
  150. self.tdb.Insert(tabname,
  151. {'a': '42',
  152. 'b': "bad",
  153. 'c': "meep",
  154. 'e': 'Fuzzy wuzzy was a bear'})
  155. self.tdb.Insert(tabname,
  156. {'a': '581750',
  157. 'b': "good",
  158. 'd': "bla",
  159. 'c': "black",
  160. 'e': 'fuzzy was here'})
  161. self.tdb.Insert(tabname,
  162. {'a': '800000',
  163. 'b': "good",
  164. 'd': "bla",
  165. 'c': "black",
  166. 'e': 'Fuzzy wuzzy is a bear'})
  167. if verbose:
  168. self.tdb._db_print()
  169. # this should return two rows
  170. values = self.tdb.Select(tabname, ['b', 'a', 'd'],
  171. conditions={'e': re.compile('wuzzy').search,
  172. 'a': re.compile('^[0-9]+$').match})
  173. self.assertEqual(len(values), 2)
  174. # now lets delete one of them and try again
  175. self.tdb.Delete(tabname, conditions={'b': dbtables.ExactCond('good')})
  176. values = self.tdb.Select(
  177. tabname, ['a', 'd', 'b'],
  178. conditions={'e': dbtables.PrefixCond('Fuzzy')})
  179. self.assertEqual(len(values), 1)
  180. self.assertEqual(values[0]['d'], None)
  181. values = self.tdb.Select(tabname, ['b'],
  182. conditions={'c': lambda c: c == 'meep'})
  183. self.assertEqual(len(values), 1)
  184. self.assertEqual(values[0]['b'], "bad")
  185. def test04_MultiCondSelect(self):
  186. tabname = "test04_MultiCondSelect"
  187. try:
  188. self.tdb.Drop(tabname)
  189. except dbtables.TableDBError:
  190. pass
  191. self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e'])
  192. try:
  193. self.tdb.Insert(tabname,
  194. {'a': "",
  195. 'e': pickle.dumps([{4:5, 6:7}, 'foo'], 1),
  196. 'f': "Zero"})
  197. self.fail('Expected an exception')
  198. except dbtables.TableDBError:
  199. pass
  200. self.tdb.Insert(tabname, {'a': "A", 'b': "B", 'c': "C", 'd': "D",
  201. 'e': "E"})
  202. self.tdb.Insert(tabname, {'a': "-A", 'b': "-B", 'c': "-C", 'd': "-D",
  203. 'e': "-E"})
  204. self.tdb.Insert(tabname, {'a': "A-", 'b': "B-", 'c': "C-", 'd': "D-",
  205. 'e': "E-"})
  206. if verbose:
  207. self.tdb._db_print()
  208. # This select should return 0 rows. it is designed to test
  209. # the bug identified and fixed in sourceforge bug # 590449
  210. # (Big Thanks to "Rob Tillotson (n9mtb)" for tracking this down
  211. # and supplying a fix!! This one caused many headaches to say
  212. # the least...)
  213. values = self.tdb.Select(tabname, ['b', 'a', 'd'],
  214. conditions={'e': dbtables.ExactCond('E'),
  215. 'a': dbtables.ExactCond('A'),
  216. 'd': dbtables.PrefixCond('-')
  217. } )
  218. self.assertEqual(len(values), 0, values)
  219. def test_CreateOrExtend(self):
  220. tabname = "test_CreateOrExtend"
  221. self.tdb.CreateOrExtendTable(
  222. tabname, ['name', 'taste', 'filling', 'alcohol content', 'price'])
  223. try:
  224. self.tdb.Insert(tabname,
  225. {'taste': 'crap',
  226. 'filling': 'no',
  227. 'is it Guinness?': 'no'})
  228. self.fail("Insert should've failed due to bad column name")
  229. except:
  230. pass
  231. self.tdb.CreateOrExtendTable(tabname,
  232. ['name', 'taste', 'is it Guinness?'])
  233. # these should both succeed as the table should contain the union of both sets of columns.
  234. self.tdb.Insert(tabname, {'taste': 'crap', 'filling': 'no',
  235. 'is it Guinness?': 'no'})
  236. self.tdb.Insert(tabname, {'taste': 'great', 'filling': 'yes',
  237. 'is it Guinness?': 'yes',
  238. 'name': 'Guinness'})
  239. def test_CondObjs(self):
  240. tabname = "test_CondObjs"
  241. self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e', 'p'])
  242. self.tdb.Insert(tabname, {'a': "the letter A",
  243. 'b': "the letter B",
  244. 'c': "is for cookie"})
  245. self.tdb.Insert(tabname, {'a': "is for aardvark",
  246. 'e': "the letter E",
  247. 'c': "is for cookie",
  248. 'd': "is for dog"})
  249. self.tdb.Insert(tabname, {'a': "the letter A",
  250. 'e': "the letter E",
  251. 'c': "is for cookie",
  252. 'p': "is for Python"})
  253. values = self.tdb.Select(
  254. tabname, ['p', 'e'],
  255. conditions={'e': dbtables.PrefixCond('the l')})
  256. self.assertEqual(len(values), 2, values)
  257. self.assertEqual(values[0]['e'], values[1]['e'], values)
  258. self.assertNotEqual(values[0]['p'], values[1]['p'], values)
  259. values = self.tdb.Select(
  260. tabname, ['d', 'a'],
  261. conditions={'a': dbtables.LikeCond('%aardvark%')})
  262. self.assertEqual(len(values), 1, values)
  263. self.assertEqual(values[0]['d'], "is for dog", values)
  264. self.assertEqual(values[0]['a'], "is for aardvark", values)
  265. values = self.tdb.Select(tabname, None,
  266. {'b': dbtables.Cond(),
  267. 'e':dbtables.LikeCond('%letter%'),
  268. 'a':dbtables.PrefixCond('is'),
  269. 'd':dbtables.ExactCond('is for dog'),
  270. 'c':dbtables.PrefixCond('is for'),
  271. 'p':lambda s: not s})
  272. self.assertEqual(len(values), 1, values)
  273. self.assertEqual(values[0]['d'], "is for dog", values)
  274. self.assertEqual(values[0]['a'], "is for aardvark", values)
  275. def test_Delete(self):
  276. tabname = "test_Delete"
  277. self.tdb.CreateTable(tabname, ['x', 'y', 'z'])
  278. # prior to 2001-05-09 there was a bug where Delete() would
  279. # fail if it encountered any rows that did not have values in
  280. # every column.
  281. # Hunted and Squashed by <Donwulff> (Jukka Santala - donwulff@nic.fi)
  282. self.tdb.Insert(tabname, {'x': 'X1', 'y':'Y1'})
  283. self.tdb.Insert(tabname, {'x': 'X2', 'y':'Y2', 'z': 'Z2'})
  284. self.tdb.Delete(tabname, conditions={'x': dbtables.PrefixCond('X')})
  285. values = self.tdb.Select(tabname, ['y'],
  286. conditions={'x': dbtables.PrefixCond('X')})
  287. self.assertEqual(len(values), 0)
  288. def test_Modify(self):
  289. tabname = "test_Modify"
  290. self.tdb.CreateTable(tabname, ['Name', 'Type', 'Access'])
  291. self.tdb.Insert(tabname, {'Name': 'Index to MP3 files.doc',
  292. 'Type': 'Word', 'Access': '8'})
  293. self.tdb.Insert(tabname, {'Name': 'Nifty.MP3', 'Access': '1'})
  294. self.tdb.Insert(tabname, {'Type': 'Unknown', 'Access': '0'})
  295. def set_type(type):
  296. if type == None:
  297. return 'MP3'
  298. return type
  299. def increment_access(count):
  300. return str(int(count)+1)
  301. def remove_value(value):
  302. return None
  303. self.tdb.Modify(tabname,
  304. conditions={'Access': dbtables.ExactCond('0')},
  305. mappings={'Access': remove_value})
  306. self.tdb.Modify(tabname,
  307. conditions={'Name': dbtables.LikeCond('%MP3%')},
  308. mappings={'Type': set_type})
  309. self.tdb.Modify(tabname,
  310. conditions={'Name': dbtables.LikeCond('%')},
  311. mappings={'Access': increment_access})
  312. try:
  313. self.tdb.Modify(tabname,
  314. conditions={'Name': dbtables.LikeCond('%')},
  315. mappings={'Access': 'What is your quest?'})
  316. except TypeError:
  317. # success, the string value in mappings isn't callable
  318. pass
  319. else:
  320. raise RuntimeError, "why was TypeError not raised for bad callable?"
  321. # Delete key in select conditions
  322. values = self.tdb.Select(
  323. tabname, None,
  324. conditions={'Type': dbtables.ExactCond('Unknown')})
  325. self.assertEqual(len(values), 1, values)
  326. self.assertEqual(values[0]['Name'], None, values)
  327. self.assertEqual(values[0]['Access'], None, values)
  328. # Modify value by select conditions
  329. values = self.tdb.Select(
  330. tabname, None,
  331. conditions={'Name': dbtables.ExactCond('Nifty.MP3')})
  332. self.assertEqual(len(values), 1, values)
  333. self.assertEqual(values[0]['Type'], "MP3", values)
  334. self.assertEqual(values[0]['Access'], "2", values)
  335. # Make sure change applied only to select conditions
  336. values = self.tdb.Select(
  337. tabname, None, conditions={'Name': dbtables.LikeCond('%doc%')})
  338. self.assertEqual(len(values), 1, values)
  339. self.assertEqual(values[0]['Type'], "Word", values)
  340. self.assertEqual(values[0]['Access'], "9", values)
  341. def test_suite():
  342. suite = unittest.TestSuite()
  343. suite.addTest(unittest.makeSuite(TableDBTestCase))
  344. return suite
  345. if __name__ == '__main__':
  346. unittest.main(defaultTest='test_suite')