test_dbm_gnu.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. from test import support
  2. from test.support import import_helper, cpython_only
  3. gdbm = import_helper.import_module("dbm.gnu") #skip if not supported
  4. import unittest
  5. import os
  6. from test.support.os_helper import TESTFN, TESTFN_NONASCII, unlink, FakePath
  7. filename = TESTFN
  8. class TestGdbm(unittest.TestCase):
  9. @staticmethod
  10. def setUpClass():
  11. if support.verbose:
  12. try:
  13. from _gdbm import _GDBM_VERSION as version
  14. except ImportError:
  15. pass
  16. else:
  17. print(f"gdbm version: {version}")
  18. def setUp(self):
  19. self.g = None
  20. def tearDown(self):
  21. if self.g is not None:
  22. self.g.close()
  23. unlink(filename)
  24. @cpython_only
  25. def test_disallow_instantiation(self):
  26. # Ensure that the type disallows instantiation (bpo-43916)
  27. self.g = gdbm.open(filename, 'c')
  28. support.check_disallow_instantiation(self, type(self.g))
  29. 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'
  34. self.g[b'bytes'] = b'data'
  35. key_set = set(self.g.keys())
  36. self.assertEqual(key_set, set([b'a', b'bytes', b'12345678910']))
  37. self.assertIn('a', self.g)
  38. self.assertIn(b'a', self.g)
  39. self.assertEqual(self.g[b'bytes'], b'data')
  40. key = self.g.firstkey()
  41. while key:
  42. self.assertIn(key, key_set)
  43. key_set.remove(key)
  44. key = self.g.nextkey(key)
  45. # get() and setdefault() work as in the dict interface
  46. self.assertEqual(self.g.get(b'a'), b'b')
  47. self.assertIsNone(self.g.get(b'xxx'))
  48. self.assertEqual(self.g.get(b'xxx', b'foo'), b'foo')
  49. with self.assertRaises(KeyError):
  50. self.g['xxx']
  51. self.assertEqual(self.g.setdefault(b'xxx', b'foo'), b'foo')
  52. self.assertEqual(self.g[b'xxx'], b'foo')
  53. def test_error_conditions(self):
  54. # Try to open a non-existent database.
  55. unlink(filename)
  56. self.assertRaises(gdbm.error, gdbm.open, filename, 'r')
  57. # Try to access a closed database.
  58. self.g = gdbm.open(filename, 'c')
  59. self.g.close()
  60. self.assertRaises(gdbm.error, lambda: self.g['a'])
  61. # try pass an invalid open flag
  62. self.assertRaises(gdbm.error, lambda: gdbm.open(filename, 'rx').close())
  63. def test_flags(self):
  64. # Test the flag parameter open() by trying all supported flag modes.
  65. all = set(gdbm.open_flags)
  66. # Test standard flags (presumably "crwn").
  67. modes = all - set('fsu')
  68. for mode in sorted(modes): # put "c" mode first
  69. self.g = gdbm.open(filename, mode)
  70. self.g.close()
  71. # Test additional flags (presumably "fsu").
  72. flags = all - set('crwn')
  73. for mode in modes:
  74. for flag in flags:
  75. self.g = gdbm.open(filename, mode + flag)
  76. self.g.close()
  77. def test_reorganize(self):
  78. self.g = gdbm.open(filename, 'c')
  79. size0 = os.path.getsize(filename)
  80. # bpo-33901: on macOS with gdbm 1.15, an empty database uses 16 MiB
  81. # and adding an entry of 10,000 B has no effect on the file size.
  82. # Add size0 bytes to make sure that the file size changes.
  83. value_size = max(size0, 10000)
  84. self.g['x'] = 'x' * value_size
  85. size1 = os.path.getsize(filename)
  86. self.assertGreater(size1, size0)
  87. del self.g['x']
  88. # 'size' is supposed to be the same even after deleting an entry.
  89. self.assertEqual(os.path.getsize(filename), size1)
  90. self.g.reorganize()
  91. size2 = os.path.getsize(filename)
  92. self.assertLess(size2, size1)
  93. self.assertGreaterEqual(size2, size0)
  94. def test_context_manager(self):
  95. with gdbm.open(filename, 'c') as db:
  96. db["gdbm context manager"] = "context manager"
  97. with gdbm.open(filename, 'r') as db:
  98. self.assertEqual(list(db.keys()), [b"gdbm context manager"])
  99. with self.assertRaises(gdbm.error) as cm:
  100. db.keys()
  101. self.assertEqual(str(cm.exception),
  102. "GDBM object has already been closed")
  103. def test_bytes(self):
  104. with gdbm.open(filename, 'c') as db:
  105. db[b'bytes key \xbd'] = b'bytes value \xbd'
  106. with gdbm.open(filename, 'r') as db:
  107. self.assertEqual(list(db.keys()), [b'bytes key \xbd'])
  108. self.assertTrue(b'bytes key \xbd' in db)
  109. self.assertEqual(db[b'bytes key \xbd'], b'bytes value \xbd')
  110. def test_unicode(self):
  111. with gdbm.open(filename, 'c') as db:
  112. db['Unicode key \U0001f40d'] = 'Unicode value \U0001f40d'
  113. with gdbm.open(filename, 'r') as db:
  114. self.assertEqual(list(db.keys()), ['Unicode key \U0001f40d'.encode()])
  115. self.assertTrue('Unicode key \U0001f40d'.encode() in db)
  116. self.assertTrue('Unicode key \U0001f40d' in db)
  117. self.assertEqual(db['Unicode key \U0001f40d'.encode()],
  118. 'Unicode value \U0001f40d'.encode())
  119. self.assertEqual(db['Unicode key \U0001f40d'],
  120. 'Unicode value \U0001f40d'.encode())
  121. def test_write_readonly_file(self):
  122. with gdbm.open(filename, 'c') as db:
  123. db[b'bytes key'] = b'bytes value'
  124. with gdbm.open(filename, 'r') as db:
  125. with self.assertRaises(gdbm.error):
  126. del db[b'not exist key']
  127. with self.assertRaises(gdbm.error):
  128. del db[b'bytes key']
  129. with self.assertRaises(gdbm.error):
  130. db[b'not exist key'] = b'not exist value'
  131. @unittest.skipUnless(TESTFN_NONASCII,
  132. 'requires OS support of non-ASCII encodings')
  133. def test_nonascii_filename(self):
  134. filename = TESTFN_NONASCII
  135. self.addCleanup(unlink, filename)
  136. with gdbm.open(filename, 'c') as db:
  137. db[b'key'] = b'value'
  138. self.assertTrue(os.path.exists(filename))
  139. with gdbm.open(filename, 'r') as db:
  140. self.assertEqual(list(db.keys()), [b'key'])
  141. self.assertTrue(b'key' in db)
  142. self.assertEqual(db[b'key'], b'value')
  143. def test_nonexisting_file(self):
  144. nonexisting_file = 'nonexisting-file'
  145. with self.assertRaises(gdbm.error) as cm:
  146. gdbm.open(nonexisting_file)
  147. self.assertIn(nonexisting_file, str(cm.exception))
  148. self.assertEqual(cm.exception.filename, nonexisting_file)
  149. def test_open_with_pathlib_path(self):
  150. gdbm.open(FakePath(filename), "c").close()
  151. def test_open_with_bytes_path(self):
  152. gdbm.open(os.fsencode(filename), "c").close()
  153. def test_open_with_pathlib_bytes_path(self):
  154. gdbm.open(FakePath(os.fsencode(filename)), "c").close()
  155. if __name__ == '__main__':
  156. unittest.main()