blob: df531d64e4889d87795eafa3ecd43de4d5c57fec [file] [log] [blame]
Guido van Rossum2f1064c2001-01-18 16:46:52 +00001"""Test script for the dumbdbm module
2 Original by Roger E. Masse
3"""
4
Guido van Rossum6252e102007-05-23 20:51:02 +00005import io
Benjamin Petersone3083d32014-04-26 16:56:52 -04006import operator
Guido van Rossum2f1064c2001-01-18 16:46:52 +00007import os
Serhiy Storchaka028ace12016-12-07 10:56:39 +02008import stat
Barry Warsaw3ca656f2001-11-13 20:16:52 +00009import unittest
Serhiy Storchaka0122ae92016-07-06 12:21:58 +030010import warnings
Georg Brandl0a7ac7d2008-05-26 10:29:35 +000011import dbm.dumb as dumbdbm
Benjamin Petersonee8712c2008-05-20 21:35:26 +000012from test import support
Benjamin Petersone3083d32014-04-26 16:56:52 -040013from functools import partial
Guido van Rossum2f1064c2001-01-18 16:46:52 +000014
Benjamin Petersonee8712c2008-05-20 21:35:26 +000015_fname = support.TESTFN
Tim Petersd9fbf352002-01-30 07:32:53 +000016
17def _delete_files():
18 for ext in [".dir", ".dat", ".bak"]:
19 try:
20 os.unlink(_fname + ext)
21 except OSError:
22 pass
23
Barry Warsaw3ca656f2001-11-13 20:16:52 +000024class DumbDBMTestCase(unittest.TestCase):
Brett Cannon58425d32008-11-21 00:17:53 +000025 _dict = {b'0': b'',
26 b'a': b'Python:',
27 b'b': b'Programming',
28 b'c': b'the',
29 b'd': b'way',
30 b'f': b'Guido',
31 b'g': b'intended',
32 '\u00fc'.encode('utf-8') : b'!',
Barry Warsaw3ca656f2001-11-13 20:16:52 +000033 }
34
Barry Warsaw3ca656f2001-11-13 20:16:52 +000035 def test_dumbdbm_creation(self):
Tim Petersd9fbf352002-01-30 07:32:53 +000036 f = dumbdbm.open(_fname, 'c')
Brett Cannonc1b22a02007-02-22 05:04:32 +000037 self.assertEqual(list(f.keys()), [])
Barry Warsaw3ca656f2001-11-13 20:16:52 +000038 for key in self._dict:
Brett Cannon58425d32008-11-21 00:17:53 +000039 f[key] = self._dict[key]
Barry Warsaw3ca656f2001-11-13 20:16:52 +000040 self.read_helper(f)
41 f.close()
42
Serhiy Storchaka43767632013-11-03 21:31:38 +020043 @unittest.skipUnless(hasattr(os, 'umask'), 'test needs os.umask()')
44 @unittest.skipUnless(hasattr(os, 'chmod'), 'test needs os.chmod()')
Thomas Wouters902d6eb2007-01-09 23:18:33 +000045 def test_dumbdbm_creation_mode(self):
Thomas Wouters902d6eb2007-01-09 23:18:33 +000046 try:
Guido van Rossumcd16bf62007-06-13 18:07:49 +000047 old_umask = os.umask(0o002)
48 f = dumbdbm.open(_fname, 'c', 0o637)
Thomas Wouters902d6eb2007-01-09 23:18:33 +000049 f.close()
50 finally:
51 os.umask(old_umask)
Thomas Wouters9fe394c2007-02-05 01:24:16 +000052
Guido van Rossumcd16bf62007-06-13 18:07:49 +000053 expected_mode = 0o635
Thomas Woutersb2137042007-02-01 18:02:27 +000054 if os.name != 'posix':
55 # Windows only supports setting the read-only attribute.
56 # This shouldn't fail, but doesn't work like Unix either.
Guido van Rossumcd16bf62007-06-13 18:07:49 +000057 expected_mode = 0o666
Thomas Woutersb2137042007-02-01 18:02:27 +000058
Thomas Wouters902d6eb2007-01-09 23:18:33 +000059 import stat
60 st = os.stat(_fname + '.dat')
Thomas Woutersb2137042007-02-01 18:02:27 +000061 self.assertEqual(stat.S_IMODE(st.st_mode), expected_mode)
Thomas Wouters902d6eb2007-01-09 23:18:33 +000062 st = os.stat(_fname + '.dir')
Thomas Woutersb2137042007-02-01 18:02:27 +000063 self.assertEqual(stat.S_IMODE(st.st_mode), expected_mode)
Thomas Wouters9fe394c2007-02-05 01:24:16 +000064
Tim Peters7a6c7332003-07-13 17:21:10 +000065 def test_close_twice(self):
66 f = dumbdbm.open(_fname)
Martin v. Löwise6568692007-08-07 05:37:39 +000067 f[b'a'] = b'b'
68 self.assertEqual(f[b'a'], b'b')
Tim Peters7a6c7332003-07-13 17:21:10 +000069 f.close()
70 f.close()
71
Barry Warsaw3ca656f2001-11-13 20:16:52 +000072 def test_dumbdbm_modification(self):
Skip Montanaroc08fe822002-03-17 23:03:42 +000073 self.init_db()
Tim Petersd9fbf352002-01-30 07:32:53 +000074 f = dumbdbm.open(_fname, 'w')
Brett Cannon58425d32008-11-21 00:17:53 +000075 self._dict[b'g'] = f[b'g'] = b"indented"
Barry Warsaw3ca656f2001-11-13 20:16:52 +000076 self.read_helper(f)
77 f.close()
78
79 def test_dumbdbm_read(self):
Skip Montanaroc08fe822002-03-17 23:03:42 +000080 self.init_db()
Tim Petersd9fbf352002-01-30 07:32:53 +000081 f = dumbdbm.open(_fname, 'r')
Barry Warsaw3ca656f2001-11-13 20:16:52 +000082 self.read_helper(f)
Serhiy Storchaka0122ae92016-07-06 12:21:58 +030083 with self.assertWarnsRegex(DeprecationWarning,
84 'The database is opened for reading only'):
85 f[b'g'] = b'x'
86 with self.assertWarnsRegex(DeprecationWarning,
87 'The database is opened for reading only'):
88 del f[b'a']
Barry Warsaw3ca656f2001-11-13 20:16:52 +000089 f.close()
90
91 def test_dumbdbm_keys(self):
Skip Montanaroc08fe822002-03-17 23:03:42 +000092 self.init_db()
Tim Petersd9fbf352002-01-30 07:32:53 +000093 f = dumbdbm.open(_fname)
Barry Warsaw3ca656f2001-11-13 20:16:52 +000094 keys = self.keys_helper(f)
95 f.close()
96
Gregory P. Smith178fefb2007-08-24 21:59:45 +000097 def test_write_contains(self):
98 f = dumbdbm.open(_fname)
99 f[b'1'] = b'hello'
Benjamin Peterson577473f2010-01-19 00:09:57 +0000100 self.assertIn(b'1', f)
Gregory P. Smith178fefb2007-08-24 21:59:45 +0000101 f.close()
102
Skip Montanaroc08fe822002-03-17 23:03:42 +0000103 def test_write_write_read(self):
104 # test for bug #482460
105 f = dumbdbm.open(_fname)
Martin v. Löwise6568692007-08-07 05:37:39 +0000106 f[b'1'] = b'hello'
107 f[b'1'] = b'hello2'
Skip Montanaroc08fe822002-03-17 23:03:42 +0000108 f.close()
109 f = dumbdbm.open(_fname)
Guido van Rossum7b4beea2007-08-28 00:09:54 +0000110 self.assertEqual(f[b'1'], b'hello2')
Skip Montanaroc08fe822002-03-17 23:03:42 +0000111 f.close()
112
Brett Cannon58425d32008-11-21 00:17:53 +0000113 def test_str_read(self):
114 self.init_db()
115 f = dumbdbm.open(_fname, 'r')
116 self.assertEqual(f['\u00fc'], self._dict['\u00fc'.encode('utf-8')])
117
118 def test_str_write_contains(self):
119 self.init_db()
120 f = dumbdbm.open(_fname)
121 f['\u00fc'] = b'!'
Brett Cannon7317c1e2008-11-25 19:19:17 +0000122 f['1'] = 'a'
Brett Cannon58425d32008-11-21 00:17:53 +0000123 f.close()
124 f = dumbdbm.open(_fname, 'r')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000125 self.assertIn('\u00fc', f)
Brett Cannon58425d32008-11-21 00:17:53 +0000126 self.assertEqual(f['\u00fc'.encode('utf-8')],
127 self._dict['\u00fc'.encode('utf-8')])
Brett Cannon7317c1e2008-11-25 19:19:17 +0000128 self.assertEqual(f[b'1'], b'a')
Brett Cannon58425d32008-11-21 00:17:53 +0000129
Andrew M. Kuchlingecdad852005-06-07 19:36:10 +0000130 def test_line_endings(self):
131 # test for bug #1172763: dumbdbm would die if the line endings
132 # weren't what was expected.
133 f = dumbdbm.open(_fname)
Martin v. Löwise6568692007-08-07 05:37:39 +0000134 f[b'1'] = b'hello'
135 f[b'2'] = b'hello2'
Andrew M. Kuchlingecdad852005-06-07 19:36:10 +0000136 f.close()
137
Christian Heimes9289bfc2007-10-31 19:40:17 +0000138 # Mangle the file by changing the line separator to Windows or Unix
Brett Cannonc0eee312010-10-29 22:49:14 +0000139 with io.open(_fname + '.dir', 'rb') as file:
140 data = file.read()
Guido van Rossum98297ee2007-11-06 21:34:58 +0000141 if os.linesep == '\n':
Christian Heimes9289bfc2007-10-31 19:40:17 +0000142 data = data.replace(b'\n', b'\r\n')
143 else:
144 data = data.replace(b'\r\n', b'\n')
Brett Cannonc0eee312010-10-29 22:49:14 +0000145 with io.open(_fname + '.dir', 'wb') as file:
146 file.write(data)
Anthony Baxter95a2a4e2005-06-08 04:35:50 +0000147
Andrew M. Kuchlingecdad852005-06-07 19:36:10 +0000148 f = dumbdbm.open(_fname)
Martin v. Löwise6568692007-08-07 05:37:39 +0000149 self.assertEqual(f[b'1'], b'hello')
150 self.assertEqual(f[b'2'], b'hello2')
Anthony Baxter95a2a4e2005-06-08 04:35:50 +0000151
152
Barry Warsaw3ca656f2001-11-13 20:16:52 +0000153 def read_helper(self, f):
154 keys = self.keys_helper(f)
155 for key in self._dict:
Brett Cannon58425d32008-11-21 00:17:53 +0000156 self.assertEqual(self._dict[key], f[key])
Tim Peters88768482001-11-13 21:51:26 +0000157
Skip Montanaroc08fe822002-03-17 23:03:42 +0000158 def init_db(self):
Serhiy Storchaka0122ae92016-07-06 12:21:58 +0300159 f = dumbdbm.open(_fname, 'n')
Skip Montanaroc08fe822002-03-17 23:03:42 +0000160 for k in self._dict:
Brett Cannon58425d32008-11-21 00:17:53 +0000161 f[k] = self._dict[k]
Skip Montanaroc08fe822002-03-17 23:03:42 +0000162 f.close()
163
Barry Warsaw3ca656f2001-11-13 20:16:52 +0000164 def keys_helper(self, f):
Brett Cannon58425d32008-11-21 00:17:53 +0000165 keys = sorted(f.keys())
Brett Cannonc1b22a02007-02-22 05:04:32 +0000166 dkeys = sorted(self._dict.keys())
Skip Montanaroc08fe822002-03-17 23:03:42 +0000167 self.assertEqual(keys, dkeys)
Barry Warsaw3ca656f2001-11-13 20:16:52 +0000168 return keys
169
Tim Peters663d1b62003-07-11 04:09:09 +0000170 # Perform randomized operations. This doesn't make assumptions about
171 # what *might* fail.
172 def test_random(self):
173 import random
174 d = {} # mirror the database
175 for dummy in range(5):
176 f = dumbdbm.open(_fname)
177 for dummy in range(100):
178 k = random.choice('abcdefghijklm')
179 if random.random() < 0.2:
180 if k in d:
181 del d[k]
Brett Cannon58425d32008-11-21 00:17:53 +0000182 del f[k]
Tim Peters663d1b62003-07-11 04:09:09 +0000183 else:
Guido van Rossum6252e102007-05-23 20:51:02 +0000184 v = random.choice((b'a', b'b', b'c')) * random.randrange(10000)
Tim Peters663d1b62003-07-11 04:09:09 +0000185 d[k] = v
Brett Cannon58425d32008-11-21 00:17:53 +0000186 f[k] = v
187 self.assertEqual(f[k], v)
Tim Peters663d1b62003-07-11 04:09:09 +0000188 f.close()
189
190 f = dumbdbm.open(_fname)
Guido van Rossum7b4beea2007-08-28 00:09:54 +0000191 expected = sorted((k.encode("latin-1"), v) for k, v in d.items())
Brett Cannonc1b22a02007-02-22 05:04:32 +0000192 got = sorted(f.items())
Tim Peters663d1b62003-07-11 04:09:09 +0000193 self.assertEqual(expected, got)
194 f.close()
195
Nick Coghlanc610aba2013-11-17 15:59:51 +1000196 def test_context_manager(self):
197 with dumbdbm.open(_fname, 'c') as db:
198 db["dumbdbm context manager"] = "context manager"
199
200 with dumbdbm.open(_fname, 'r') as db:
201 self.assertEqual(list(db.keys()), [b"dumbdbm context manager"])
202
Benjamin Petersone3083d32014-04-26 16:56:52 -0400203 with self.assertRaises(dumbdbm.error):
Nick Coghlanc610aba2013-11-17 15:59:51 +1000204 db.keys()
205
Benjamin Petersone3083d32014-04-26 16:56:52 -0400206 def test_check_closed(self):
207 f = dumbdbm.open(_fname, 'c')
208 f.close()
209
210 for meth in (partial(operator.delitem, f),
211 partial(operator.setitem, f, 'b'),
212 partial(operator.getitem, f),
213 partial(operator.contains, f)):
214 with self.assertRaises(dumbdbm.error) as cm:
215 meth('test')
216 self.assertEqual(str(cm.exception),
217 "DBM object has already been closed")
218
219 for meth in (operator.methodcaller('keys'),
220 operator.methodcaller('iterkeys'),
221 operator.methodcaller('items'),
222 len):
223 with self.assertRaises(dumbdbm.error) as cm:
224 meth(f)
225 self.assertEqual(str(cm.exception),
226 "DBM object has already been closed")
227
Serhiy Storchakab398d332014-06-10 21:16:00 +0300228 def test_create_new(self):
229 with dumbdbm.open(_fname, 'n') as f:
230 for k in self._dict:
231 f[k] = self._dict[k]
232
233 with dumbdbm.open(_fname, 'n') as f:
234 self.assertEqual(f.keys(), [])
235
Serhiy Storchaka74eb8b22015-02-16 00:30:43 +0200236 def test_eval(self):
237 with open(_fname + '.dir', 'w') as stream:
238 stream.write("str(print('Hacked!')), 0\n")
239 with support.captured_stdout() as stdout:
240 with self.assertRaises(ValueError):
241 with dumbdbm.open(_fname) as f:
242 pass
243 self.assertEqual(stdout.getvalue(), '')
244
Serhiy Storchaka0122ae92016-07-06 12:21:58 +0300245 def test_warn_on_ignored_flags(self):
246 for value in ('r', 'w'):
247 _delete_files()
248 with self.assertWarnsRegex(DeprecationWarning,
249 "The database file is missing, the "
250 "semantics of the 'c' flag will "
251 "be used."):
252 f = dumbdbm.open(_fname, value)
253 f.close()
254
255 def test_invalid_flag(self):
256 for flag in ('x', 'rf', None):
257 with self.assertWarnsRegex(DeprecationWarning,
258 "Flag must be one of "
259 "'r', 'w', 'c', or 'n'"):
260 f = dumbdbm.open(_fname, flag)
261 f.close()
262
Serhiy Storchaka028ace12016-12-07 10:56:39 +0200263 @unittest.skipUnless(hasattr(os, 'chmod'), 'test needs os.chmod()')
264 def test_readonly_files(self):
265 with support.temp_dir() as dir:
266 fname = os.path.join(dir, 'db')
267 with dumbdbm.open(fname, 'n') as f:
268 self.assertEqual(list(f.keys()), [])
269 for key in self._dict:
270 f[key] = self._dict[key]
271 os.chmod(fname + ".dir", stat.S_IRUSR)
272 os.chmod(fname + ".dat", stat.S_IRUSR)
273 os.chmod(dir, stat.S_IRUSR|stat.S_IXUSR)
274 with dumbdbm.open(fname, 'r') as f:
275 self.assertEqual(sorted(f.keys()), sorted(self._dict))
276 f.close() # don't write
277
Skip Montanaroc08fe822002-03-17 23:03:42 +0000278 def tearDown(self):
279 _delete_files()
280
281 def setUp(self):
282 _delete_files()
283
Barry Warsaw3ca656f2001-11-13 20:16:52 +0000284
285if __name__ == "__main__":
Ezio Melottif79493b2013-03-01 11:23:28 +0200286 unittest.main()