Commit | Line | Data |
---|---|---|
920dae64 AT |
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@electricrain.com> | |
20 | # | |
21 | # $Id: test_dbtables.py,v 1.7 2004/02/12 17:35:08 doerwalter Exp $ | |
22 | ||
23 | import sys, os, re | |
24 | try: | |
25 | import cPickle | |
26 | pickle = cPickle | |
27 | except ImportError: | |
28 | import pickle | |
29 | ||
30 | import unittest | |
31 | from test_all import verbose | |
32 | ||
33 | try: | |
34 | # For Pythons w/distutils pybsddb | |
35 | from bsddb3 import db, dbtables | |
36 | except ImportError: | |
37 | # For Python 2.3 | |
38 | from bsddb import db, dbtables | |
39 | ||
40 | ||
41 | ||
42 | #---------------------------------------------------------------------- | |
43 | ||
44 | class TableDBTestCase(unittest.TestCase): | |
45 | db_home = 'db_home' | |
46 | db_name = 'test-table.db' | |
47 | ||
48 | def setUp(self): | |
49 | homeDir = os.path.join(os.path.dirname(sys.argv[0]), 'db_home') | |
50 | self.homeDir = homeDir | |
51 | try: os.mkdir(homeDir) | |
52 | except os.error: pass | |
53 | self.tdb = dbtables.bsdTableDB( | |
54 | filename='tabletest.db', dbhome=homeDir, create=1) | |
55 | ||
56 | def tearDown(self): | |
57 | self.tdb.close() | |
58 | import glob | |
59 | files = glob.glob(os.path.join(self.homeDir, '*')) | |
60 | for file in files: | |
61 | os.remove(file) | |
62 | ||
63 | def test01(self): | |
64 | tabname = "test01" | |
65 | colname = 'cool numbers' | |
66 | try: | |
67 | self.tdb.Drop(tabname) | |
68 | except dbtables.TableDBError: | |
69 | pass | |
70 | self.tdb.CreateTable(tabname, [colname]) | |
71 | self.tdb.Insert(tabname, {colname: pickle.dumps(3.14159, 1)}) | |
72 | ||
73 | if verbose: | |
74 | self.tdb._db_print() | |
75 | ||
76 | values = self.tdb.Select( | |
77 | tabname, [colname], conditions={colname: None}) | |
78 | ||
79 | colval = pickle.loads(values[0][colname]) | |
80 | assert(colval > 3.141 and colval < 3.142) | |
81 | ||
82 | ||
83 | def test02(self): | |
84 | tabname = "test02" | |
85 | col0 = 'coolness factor' | |
86 | col1 = 'but can it fly?' | |
87 | col2 = 'Species' | |
88 | testinfo = [ | |
89 | {col0: pickle.dumps(8, 1), col1: 'no', col2: 'Penguin'}, | |
90 | {col0: pickle.dumps(-1, 1), col1: 'no', col2: 'Turkey'}, | |
91 | {col0: pickle.dumps(9, 1), col1: 'yes', col2: 'SR-71A Blackbird'} | |
92 | ] | |
93 | ||
94 | try: | |
95 | self.tdb.Drop(tabname) | |
96 | except dbtables.TableDBError: | |
97 | pass | |
98 | self.tdb.CreateTable(tabname, [col0, col1, col2]) | |
99 | for row in testinfo : | |
100 | self.tdb.Insert(tabname, row) | |
101 | ||
102 | values = self.tdb.Select(tabname, [col2], | |
103 | conditions={col0: lambda x: pickle.loads(x) >= 8}) | |
104 | ||
105 | assert len(values) == 2 | |
106 | if values[0]['Species'] == 'Penguin' : | |
107 | assert values[1]['Species'] == 'SR-71A Blackbird' | |
108 | elif values[0]['Species'] == 'SR-71A Blackbird' : | |
109 | assert values[1]['Species'] == 'Penguin' | |
110 | else : | |
111 | if verbose: | |
112 | print "values= %r" % (values,) | |
113 | raise "Wrong values returned!" | |
114 | ||
115 | def test03(self): | |
116 | tabname = "test03" | |
117 | try: | |
118 | self.tdb.Drop(tabname) | |
119 | except dbtables.TableDBError: | |
120 | pass | |
121 | if verbose: | |
122 | print '...before CreateTable...' | |
123 | self.tdb._db_print() | |
124 | self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e']) | |
125 | if verbose: | |
126 | print '...after CreateTable...' | |
127 | self.tdb._db_print() | |
128 | self.tdb.Drop(tabname) | |
129 | if verbose: | |
130 | print '...after Drop...' | |
131 | self.tdb._db_print() | |
132 | self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e']) | |
133 | ||
134 | try: | |
135 | self.tdb.Insert(tabname, | |
136 | {'a': "", | |
137 | 'e': pickle.dumps([{4:5, 6:7}, 'foo'], 1), | |
138 | 'f': "Zero"}) | |
139 | assert 0 | |
140 | except dbtables.TableDBError: | |
141 | pass | |
142 | ||
143 | try: | |
144 | self.tdb.Select(tabname, [], conditions={'foo': '123'}) | |
145 | assert 0 | |
146 | except dbtables.TableDBError: | |
147 | pass | |
148 | ||
149 | self.tdb.Insert(tabname, | |
150 | {'a': '42', | |
151 | 'b': "bad", | |
152 | 'c': "meep", | |
153 | 'e': 'Fuzzy wuzzy was a bear'}) | |
154 | self.tdb.Insert(tabname, | |
155 | {'a': '581750', | |
156 | 'b': "good", | |
157 | 'd': "bla", | |
158 | 'c': "black", | |
159 | 'e': 'fuzzy was here'}) | |
160 | self.tdb.Insert(tabname, | |
161 | {'a': '800000', | |
162 | 'b': "good", | |
163 | 'd': "bla", | |
164 | 'c': "black", | |
165 | 'e': 'Fuzzy wuzzy is a bear'}) | |
166 | ||
167 | if verbose: | |
168 | self.tdb._db_print() | |
169 | ||
170 | # this should return two rows | |
171 | values = self.tdb.Select(tabname, ['b', 'a', 'd'], | |
172 | conditions={'e': re.compile('wuzzy').search, | |
173 | 'a': re.compile('^[0-9]+$').match}) | |
174 | assert len(values) == 2 | |
175 | ||
176 | # now lets delete one of them and try again | |
177 | self.tdb.Delete(tabname, conditions={'b': dbtables.ExactCond('good')}) | |
178 | values = self.tdb.Select( | |
179 | tabname, ['a', 'd', 'b'], | |
180 | conditions={'e': dbtables.PrefixCond('Fuzzy')}) | |
181 | assert len(values) == 1 | |
182 | assert values[0]['d'] == None | |
183 | ||
184 | values = self.tdb.Select(tabname, ['b'], | |
185 | conditions={'c': lambda c: c == 'meep'}) | |
186 | assert len(values) == 1 | |
187 | assert values[0]['b'] == "bad" | |
188 | ||
189 | ||
190 | def test04_MultiCondSelect(self): | |
191 | tabname = "test04_MultiCondSelect" | |
192 | try: | |
193 | self.tdb.Drop(tabname) | |
194 | except dbtables.TableDBError: | |
195 | pass | |
196 | self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e']) | |
197 | ||
198 | try: | |
199 | self.tdb.Insert(tabname, | |
200 | {'a': "", | |
201 | 'e': pickle.dumps([{4:5, 6:7}, 'foo'], 1), | |
202 | 'f': "Zero"}) | |
203 | assert 0 | |
204 | except dbtables.TableDBError: | |
205 | pass | |
206 | ||
207 | self.tdb.Insert(tabname, {'a': "A", 'b': "B", 'c': "C", 'd': "D", | |
208 | 'e': "E"}) | |
209 | self.tdb.Insert(tabname, {'a': "-A", 'b': "-B", 'c': "-C", 'd': "-D", | |
210 | 'e': "-E"}) | |
211 | self.tdb.Insert(tabname, {'a': "A-", 'b': "B-", 'c': "C-", 'd': "D-", | |
212 | 'e': "E-"}) | |
213 | ||
214 | if verbose: | |
215 | self.tdb._db_print() | |
216 | ||
217 | # This select should return 0 rows. it is designed to test | |
218 | # the bug identified and fixed in sourceforge bug # 590449 | |
219 | # (Big Thanks to "Rob Tillotson (n9mtb)" for tracking this down | |
220 | # and supplying a fix!! This one caused many headaches to say | |
221 | # the least...) | |
222 | values = self.tdb.Select(tabname, ['b', 'a', 'd'], | |
223 | conditions={'e': dbtables.ExactCond('E'), | |
224 | 'a': dbtables.ExactCond('A'), | |
225 | 'd': dbtables.PrefixCond('-') | |
226 | } ) | |
227 | assert len(values) == 0, values | |
228 | ||
229 | ||
230 | def test_CreateOrExtend(self): | |
231 | tabname = "test_CreateOrExtend" | |
232 | ||
233 | self.tdb.CreateOrExtendTable( | |
234 | tabname, ['name', 'taste', 'filling', 'alcohol content', 'price']) | |
235 | try: | |
236 | self.tdb.Insert(tabname, | |
237 | {'taste': 'crap', | |
238 | 'filling': 'no', | |
239 | 'is it Guinness?': 'no'}) | |
240 | assert 0, "Insert should've failed due to bad column name" | |
241 | except: | |
242 | pass | |
243 | self.tdb.CreateOrExtendTable(tabname, | |
244 | ['name', 'taste', 'is it Guinness?']) | |
245 | ||
246 | # these should both succeed as the table should contain the union of both sets of columns. | |
247 | self.tdb.Insert(tabname, {'taste': 'crap', 'filling': 'no', | |
248 | 'is it Guinness?': 'no'}) | |
249 | self.tdb.Insert(tabname, {'taste': 'great', 'filling': 'yes', | |
250 | 'is it Guinness?': 'yes', | |
251 | 'name': 'Guinness'}) | |
252 | ||
253 | ||
254 | def test_CondObjs(self): | |
255 | tabname = "test_CondObjs" | |
256 | ||
257 | self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e', 'p']) | |
258 | ||
259 | self.tdb.Insert(tabname, {'a': "the letter A", | |
260 | 'b': "the letter B", | |
261 | 'c': "is for cookie"}) | |
262 | self.tdb.Insert(tabname, {'a': "is for aardvark", | |
263 | 'e': "the letter E", | |
264 | 'c': "is for cookie", | |
265 | 'd': "is for dog"}) | |
266 | self.tdb.Insert(tabname, {'a': "the letter A", | |
267 | 'e': "the letter E", | |
268 | 'c': "is for cookie", | |
269 | 'p': "is for Python"}) | |
270 | ||
271 | values = self.tdb.Select( | |
272 | tabname, ['p', 'e'], | |
273 | conditions={'e': dbtables.PrefixCond('the l')}) | |
274 | assert len(values) == 2, values | |
275 | assert values[0]['e'] == values[1]['e'], values | |
276 | assert values[0]['p'] != values[1]['p'], values | |
277 | ||
278 | values = self.tdb.Select( | |
279 | tabname, ['d', 'a'], | |
280 | conditions={'a': dbtables.LikeCond('%aardvark%')}) | |
281 | assert len(values) == 1, values | |
282 | assert values[0]['d'] == "is for dog", values | |
283 | assert values[0]['a'] == "is for aardvark", values | |
284 | ||
285 | values = self.tdb.Select(tabname, None, | |
286 | {'b': dbtables.Cond(), | |
287 | 'e':dbtables.LikeCond('%letter%'), | |
288 | 'a':dbtables.PrefixCond('is'), | |
289 | 'd':dbtables.ExactCond('is for dog'), | |
290 | 'c':dbtables.PrefixCond('is for'), | |
291 | 'p':lambda s: not s}) | |
292 | assert len(values) == 1, values | |
293 | assert values[0]['d'] == "is for dog", values | |
294 | assert values[0]['a'] == "is for aardvark", values | |
295 | ||
296 | def test_Delete(self): | |
297 | tabname = "test_Delete" | |
298 | self.tdb.CreateTable(tabname, ['x', 'y', 'z']) | |
299 | ||
300 | # prior to 2001-05-09 there was a bug where Delete() would | |
301 | # fail if it encountered any rows that did not have values in | |
302 | # every column. | |
303 | # Hunted and Squashed by <Donwulff> (Jukka Santala - donwulff@nic.fi) | |
304 | self.tdb.Insert(tabname, {'x': 'X1', 'y':'Y1'}) | |
305 | self.tdb.Insert(tabname, {'x': 'X2', 'y':'Y2', 'z': 'Z2'}) | |
306 | ||
307 | self.tdb.Delete(tabname, conditions={'x': dbtables.PrefixCond('X')}) | |
308 | values = self.tdb.Select(tabname, ['y'], | |
309 | conditions={'x': dbtables.PrefixCond('X')}) | |
310 | assert len(values) == 0 | |
311 | ||
312 | def test_Modify(self): | |
313 | tabname = "test_Modify" | |
314 | self.tdb.CreateTable(tabname, ['Name', 'Type', 'Access']) | |
315 | ||
316 | self.tdb.Insert(tabname, {'Name': 'Index to MP3 files.doc', | |
317 | 'Type': 'Word', 'Access': '8'}) | |
318 | self.tdb.Insert(tabname, {'Name': 'Nifty.MP3', 'Access': '1'}) | |
319 | self.tdb.Insert(tabname, {'Type': 'Unknown', 'Access': '0'}) | |
320 | ||
321 | def set_type(type): | |
322 | if type == None: | |
323 | return 'MP3' | |
324 | return type | |
325 | ||
326 | def increment_access(count): | |
327 | return str(int(count)+1) | |
328 | ||
329 | def remove_value(value): | |
330 | return None | |
331 | ||
332 | self.tdb.Modify(tabname, | |
333 | conditions={'Access': dbtables.ExactCond('0')}, | |
334 | mappings={'Access': remove_value}) | |
335 | self.tdb.Modify(tabname, | |
336 | conditions={'Name': dbtables.LikeCond('%MP3%')}, | |
337 | mappings={'Type': set_type}) | |
338 | self.tdb.Modify(tabname, | |
339 | conditions={'Name': dbtables.LikeCond('%')}, | |
340 | mappings={'Access': increment_access}) | |
341 | ||
342 | # Delete key in select conditions | |
343 | values = self.tdb.Select( | |
344 | tabname, None, | |
345 | conditions={'Type': dbtables.ExactCond('Unknown')}) | |
346 | assert len(values) == 1, values | |
347 | assert values[0]['Name'] == None, values | |
348 | assert values[0]['Access'] == None, values | |
349 | ||
350 | # Modify value by select conditions | |
351 | values = self.tdb.Select( | |
352 | tabname, None, | |
353 | conditions={'Name': dbtables.ExactCond('Nifty.MP3')}) | |
354 | assert len(values) == 1, values | |
355 | assert values[0]['Type'] == "MP3", values | |
356 | assert values[0]['Access'] == "2", values | |
357 | ||
358 | # Make sure change applied only to select conditions | |
359 | values = self.tdb.Select( | |
360 | tabname, None, conditions={'Name': dbtables.LikeCond('%doc%')}) | |
361 | assert len(values) == 1, values | |
362 | assert values[0]['Type'] == "Word", values | |
363 | assert values[0]['Access'] == "9", values | |
364 | ||
365 | ||
366 | def test_suite(): | |
367 | suite = unittest.TestSuite() | |
368 | suite.addTest(unittest.makeSuite(TableDBTestCase)) | |
369 | return suite | |
370 | ||
371 | ||
372 | if __name__ == '__main__': | |
373 | unittest.main(defaultTest='test_suite') |