blob: f1c7d34085c5eee508219449ea70bc07f1a02870 [file] [log] [blame]
Kristján Valur Jónsson42a40c52009-04-01 11:28:47 +00001from test import support
2gdbm = support.import_module("dbm.gnu") #skip if not supported
Christian Heimesdd15f6c2008-03-16 00:07:10 +00003import unittest
4import os
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +02005from test.support import TESTFN, TESTFN_NONASCII, unlink
Christian Heimesdd15f6c2008-03-16 00:07:10 +00006
Roger E. Massefab8ab81996-12-20 22:36:52 +00007
Guido van Rossumf35ad332006-08-25 23:40:32 +00008filename = TESTFN
Roger E. Masse62a017c1996-12-17 19:54:27 +00009
Christian Heimesdd15f6c2008-03-16 00:07:10 +000010class TestGdbm(unittest.TestCase):
Victor Stinner00f9edb2018-06-19 23:29:22 +020011 @staticmethod
12 def setUpClass():
13 if support.verbose:
14 try:
Xiang Zhangb248e952018-06-20 21:23:30 +080015 from _gdbm import _GDBM_VERSION as version
16 except ImportError:
Victor Stinner00f9edb2018-06-19 23:29:22 +020017 pass
18 else:
19 print(f"gdbm version: {version}")
20
Christian Heimesdd15f6c2008-03-16 00:07:10 +000021 def setUp(self):
22 self.g = None
Fred Drake004d5e62000-10-23 17:22:08 +000023
Christian Heimesdd15f6c2008-03-16 00:07:10 +000024 def tearDown(self):
25 if self.g is not None:
26 self.g.close()
27 unlink(filename)
Roger E. Masse62a017c1996-12-17 19:54:27 +000028
Christian Heimesdd15f6c2008-03-16 00:07:10 +000029 def test_key_methods(self):
30 self.g = gdbm.open(filename, 'c')
31 self.assertEqual(self.g.keys(), [])
32 self.g['a'] = 'b'
33 self.g['12345678910'] = '019237410982340912840198242'
Brett Cannon7317c1e2008-11-25 19:19:17 +000034 self.g[b'bytes'] = b'data'
Christian Heimesdd15f6c2008-03-16 00:07:10 +000035 key_set = set(self.g.keys())
Brett Cannon45dea652008-11-25 21:27:00 +000036 self.assertEqual(key_set, set([b'a', b'bytes', b'12345678910']))
Serhiy Storchaka7d6392c2013-10-25 00:06:52 +030037 self.assertIn('a', self.g)
Benjamin Peterson577473f2010-01-19 00:09:57 +000038 self.assertIn(b'a', self.g)
Brett Cannon7317c1e2008-11-25 19:19:17 +000039 self.assertEqual(self.g[b'bytes'], b'data')
Christian Heimesdd15f6c2008-03-16 00:07:10 +000040 key = self.g.firstkey()
41 while key:
Benjamin Peterson577473f2010-01-19 00:09:57 +000042 self.assertIn(key, key_set)
Christian Heimesdd15f6c2008-03-16 00:07:10 +000043 key_set.remove(key)
44 key = self.g.nextkey(key)
Georg Brandld9e833c2010-12-04 09:14:36 +000045 # get() and setdefault() work as in the dict interface
Serhiy Storchaka2e38cc32018-04-29 12:38:06 +030046 self.assertEqual(self.g.get(b'a'), b'b')
47 self.assertIsNone(self.g.get(b'xxx'))
Georg Brandld9e833c2010-12-04 09:14:36 +000048 self.assertEqual(self.g.get(b'xxx', b'foo'), b'foo')
Serhiy Storchaka2e38cc32018-04-29 12:38:06 +030049 with self.assertRaises(KeyError):
50 self.g['xxx']
Georg Brandld9e833c2010-12-04 09:14:36 +000051 self.assertEqual(self.g.setdefault(b'xxx', b'foo'), b'foo')
52 self.assertEqual(self.g[b'xxx'], b'foo')
Christian Heimesdd15f6c2008-03-16 00:07:10 +000053
54 def test_error_conditions(self):
55 # Try to open a non-existent database.
56 unlink(filename)
57 self.assertRaises(gdbm.error, gdbm.open, filename, 'r')
58 # Try to access a closed database.
59 self.g = gdbm.open(filename, 'c')
60 self.g.close()
61 self.assertRaises(gdbm.error, lambda: self.g['a'])
62 # try pass an invalid open flag
63 self.assertRaises(gdbm.error, lambda: gdbm.open(filename, 'rx').close())
64
65 def test_flags(self):
66 # Test the flag parameter open() by trying all supported flag modes.
67 all = set(gdbm.open_flags)
68 # Test standard flags (presumably "crwn").
69 modes = all - set('fsu')
Georg Brandl16684eb2012-02-20 22:48:06 +010070 for mode in sorted(modes): # put "c" mode first
Christian Heimesdd15f6c2008-03-16 00:07:10 +000071 self.g = gdbm.open(filename, mode)
72 self.g.close()
73
74 # Test additional flags (presumably "fsu").
75 flags = all - set('crwn')
76 for mode in modes:
77 for flag in flags:
78 self.g = gdbm.open(filename, mode + flag)
79 self.g.close()
80
81 def test_reorganize(self):
82 self.g = gdbm.open(filename, 'c')
83 size0 = os.path.getsize(filename)
84
Victor Stinnerc44d8e52018-06-19 17:37:07 +020085 # bpo-33901: on macOS with gdbm 1.15, an empty database uses 16 MiB
86 # and adding an entry of 10,000 B has no effect on the file size.
87 # Add size0 bytes to make sure that the file size changes.
88 value_size = max(size0, 10000)
89 self.g['x'] = 'x' * value_size
Christian Heimesdd15f6c2008-03-16 00:07:10 +000090 size1 = os.path.getsize(filename)
Victor Stinnerc44d8e52018-06-19 17:37:07 +020091 self.assertGreater(size1, size0)
Christian Heimesdd15f6c2008-03-16 00:07:10 +000092
93 del self.g['x']
94 # 'size' is supposed to be the same even after deleting an entry.
95 self.assertEqual(os.path.getsize(filename), size1)
96
97 self.g.reorganize()
98 size2 = os.path.getsize(filename)
Victor Stinnerc44d8e52018-06-19 17:37:07 +020099 self.assertLess(size2, size1)
Serhiy Storchaka22525de2018-06-19 13:31:48 +0300100 self.assertGreaterEqual(size2, size0)
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000101
Nick Coghlanc610aba2013-11-17 15:59:51 +1000102 def test_context_manager(self):
103 with gdbm.open(filename, 'c') as db:
104 db["gdbm context manager"] = "context manager"
105
106 with gdbm.open(filename, 'r') as db:
107 self.assertEqual(list(db.keys()), [b"gdbm context manager"])
108
109 with self.assertRaises(gdbm.error) as cm:
110 db.keys()
111 self.assertEqual(str(cm.exception),
112 "GDBM object has already been closed")
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000113
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200114 def test_bytes(self):
115 with gdbm.open(filename, 'c') as db:
116 db[b'bytes key \xbd'] = b'bytes value \xbd'
117 with gdbm.open(filename, 'r') as db:
118 self.assertEqual(list(db.keys()), [b'bytes key \xbd'])
119 self.assertTrue(b'bytes key \xbd' in db)
120 self.assertEqual(db[b'bytes key \xbd'], b'bytes value \xbd')
121
122 def test_unicode(self):
123 with gdbm.open(filename, 'c') as db:
124 db['Unicode key \U0001f40d'] = 'Unicode value \U0001f40d'
125 with gdbm.open(filename, 'r') as db:
126 self.assertEqual(list(db.keys()), ['Unicode key \U0001f40d'.encode()])
127 self.assertTrue('Unicode key \U0001f40d'.encode() in db)
128 self.assertTrue('Unicode key \U0001f40d' in db)
129 self.assertEqual(db['Unicode key \U0001f40d'.encode()],
130 'Unicode value \U0001f40d'.encode())
131 self.assertEqual(db['Unicode key \U0001f40d'],
132 'Unicode value \U0001f40d'.encode())
133
Xiang Zhang4fb0b8b2018-12-12 20:46:55 +0800134 def test_write_readonly_file(self):
135 with gdbm.open(filename, 'c') as db:
136 db[b'bytes key'] = b'bytes value'
137 with gdbm.open(filename, 'r') as db:
138 with self.assertRaises(gdbm.error):
139 del db[b'not exist key']
140 with self.assertRaises(gdbm.error):
141 del db[b'bytes key']
142 with self.assertRaises(gdbm.error):
143 db[b'not exist key'] = b'not exist value'
144
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200145 @unittest.skipUnless(TESTFN_NONASCII,
146 'requires OS support of non-ASCII encodings')
147 def test_nonascii_filename(self):
148 filename = TESTFN_NONASCII
149 self.addCleanup(unlink, filename)
150 with gdbm.open(filename, 'c') as db:
151 db[b'key'] = b'value'
152 self.assertTrue(os.path.exists(filename))
153 with gdbm.open(filename, 'r') as db:
154 self.assertEqual(list(db.keys()), [b'key'])
155 self.assertTrue(b'key' in db)
156 self.assertEqual(db[b'key'], b'value')
157
Zsolt Cserna9df346b2018-09-27 21:54:34 +0200158 def test_nonexisting_file(self):
159 nonexisting_file = 'nonexisting-file'
160 with self.assertRaises(gdbm.error) as cm:
161 gdbm.open(nonexisting_file)
162 self.assertIn(nonexisting_file, str(cm.exception))
163 self.assertEqual(cm.exception.filename, nonexisting_file)
164
Serhiy Storchaka6f600ff2018-02-26 16:02:22 +0200165
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000166if __name__ == '__main__':
Ezio Melottif79493b2013-03-01 11:23:28 +0200167 unittest.main()