PageRenderTime 58ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/test/gdbm/test_gdbm.rb

https://github.com/ahwuyeah/ruby
Ruby | 716 lines | 559 code | 123 blank | 34 comment | 28 complexity | 8c249f33f5b5fef6c6cd911384f24c0d MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-3.0, Unlicense, GPL-2.0
  1. begin
  2. require 'gdbm'
  3. rescue LoadError
  4. end
  5. if defined? GDBM
  6. require 'test/unit'
  7. require 'tmpdir'
  8. require 'fileutils'
  9. require_relative '../ruby/envutil'
  10. class TestGDBM_RDONLY < Test::Unit::TestCase
  11. def TestGDBM_RDONLY.uname_s
  12. require 'rbconfig'
  13. case RbConfig::CONFIG['target_os']
  14. when 'cygwin'
  15. require 'etc'
  16. Etc.uname[:sysname]
  17. else
  18. RbConfig::CONFIG['target_os']
  19. end
  20. end
  21. SYSTEM = uname_s
  22. def setup
  23. @tmpdir = Dir.mktmpdir("tmptest_gdbm")
  24. @prefix = "tmptest_gdbm_#{$$}"
  25. @path = "#{@tmpdir}/#{@prefix}_"
  26. # prepare to make readonly GDBM file
  27. GDBM.open("#{@tmpdir}/#{@prefix}_rdonly", 0400) {|gdbm|
  28. gdbm['foo'] = 'FOO'
  29. }
  30. assert_instance_of(GDBM, @gdbm_rdonly = GDBM.new("#{@tmpdir}/#{@prefix}_rdonly", nil))
  31. end
  32. def teardown
  33. assert_nil(@gdbm_rdonly.close)
  34. ObjectSpace.each_object(GDBM) do |obj|
  35. obj.close unless obj.closed?
  36. end
  37. FileUtils.remove_entry_secure @tmpdir
  38. end
  39. def test_delete_rdonly
  40. if /^CYGWIN_9/ !~ SYSTEM
  41. assert_raise(GDBMError) {
  42. @gdbm_rdonly.delete("foo")
  43. }
  44. assert_nil(@gdbm_rdonly.delete("bar"))
  45. end
  46. end
  47. end
  48. class TestGDBM < Test::Unit::TestCase
  49. SYSTEM = TestGDBM_RDONLY::SYSTEM
  50. def setup
  51. @tmpdir = Dir.mktmpdir("tmptest_gdbm")
  52. @prefix = "tmptest_gdbm_#{$$}"
  53. @path = "#{@tmpdir}/#{@prefix}_"
  54. assert_instance_of(GDBM, @gdbm = GDBM.new(@path))
  55. end
  56. def teardown
  57. assert_nil(@gdbm.close)
  58. ObjectSpace.each_object(GDBM) do |obj|
  59. obj.close unless obj.closed?
  60. end
  61. FileUtils.remove_entry_secure @tmpdir
  62. end
  63. def check_size(expect, gdbm=@gdbm)
  64. assert_equal(expect, gdbm.size)
  65. n = 0
  66. gdbm.each { n+=1 }
  67. assert_equal(expect, n)
  68. if expect == 0
  69. assert_equal(true, gdbm.empty?)
  70. else
  71. assert_equal(false, gdbm.empty?)
  72. end
  73. end
  74. def test_s_new_has_no_block
  75. # GDBM.new ignore the block
  76. foo = true
  77. assert_instance_of(GDBM, gdbm = GDBM.new("#{@tmpdir}/#{@prefix}") { foo = false })
  78. assert_equal(foo, true)
  79. assert_nil(gdbm.close)
  80. end
  81. def test_s_open_create_new
  82. return if /^CYGWIN_9/ =~ SYSTEM
  83. save_mask = File.umask(0)
  84. begin
  85. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}"))
  86. gdbm.close
  87. assert_equal(File.stat("#{@tmpdir}/#{@prefix}").mode & 0777, 0666) unless /mswin|mingw/ =~ RUBY_PLATFORM
  88. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}2", 0644))
  89. gdbm.close
  90. assert_equal(File.stat("#{@tmpdir}/#{@prefix}2").mode & 0777, 0644)
  91. ensure
  92. File.umask save_mask
  93. end
  94. end
  95. def test_s_open_no_create
  96. skip "gdbm_open(GDBM_WRITER) is broken on libgdbm 1.8.0" if /1\.8\.0/ =~ GDBM::VERSION
  97. assert_nil(gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", nil))
  98. ensure
  99. gdbm.close if gdbm
  100. end
  101. def test_s_open_3rd_arg
  102. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0644,
  103. GDBM::FAST))
  104. gdbm.close
  105. # gdbm 1.8.0 specific
  106. if defined? GDBM::SYNC
  107. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0644,
  108. GDBM::SYNC))
  109. gdbm.close
  110. end
  111. # gdbm 1.8.0 specific
  112. if defined? GDBM::NOLOCK
  113. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0644,
  114. GDBM::NOLOCK))
  115. gdbm.close
  116. end
  117. end
  118. def test_s_open_with_block
  119. assert_equal(GDBM.open("#{@tmpdir}/#{@prefix}") { :foo }, :foo)
  120. end
  121. def open_db_child(dbname, *opts)
  122. opts = [0644, *opts].map(&:inspect).join(', ')
  123. args = [EnvUtil.rubybin, "-rgdbm", "-e", <<-SRC, dbname]
  124. STDOUT.sync = true
  125. gdbm = GDBM.open(ARGV.shift, #{opts})
  126. puts gdbm.class
  127. gets
  128. SRC
  129. IO.popen(args, "r+") do |f|
  130. dbclass = f.gets
  131. assert_equal("GDBM", dbclass.chomp)
  132. yield
  133. end
  134. end
  135. def test_s_open_lock
  136. skip "GDBM.open would block when opening already locked gdbm file on platforms without flock and with lockf" if /solaris/ =~ RUBY_PLATFORM
  137. dbname = "#{@tmpdir}/#{@prefix}"
  138. open_db_child(dbname) do
  139. assert_raise(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
  140. GDBM.open(dbname, 0644) {|gdbm|
  141. assert_instance_of(GDBM, gdbm)
  142. }
  143. }
  144. end
  145. end
  146. =begin
  147. # Is it guaranteed on many OS?
  148. def test_s_open_lock_one_process
  149. # locking on one process
  150. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0644))
  151. assert_raise(Errno::EWOULDBLOCK) {
  152. begin
  153. GDBM.open("#{@tmpdir}/#{@prefix}", 0644)
  154. rescue Errno::EAGAIN
  155. raise Errno::EWOULDBLOCK
  156. end
  157. }
  158. end
  159. =end
  160. def test_s_open_nolock
  161. dbname = "#{@tmpdir}/#{@prefix}"
  162. open_db_child(dbname, GDBM::NOLOCK) do
  163. assert_nothing_raised(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
  164. GDBM.open(dbname, 0644) {|gdbm2|
  165. assert_instance_of(GDBM, gdbm2)
  166. }
  167. }
  168. end
  169. STDERR.puts Dir.glob("#{dbname}*") if $DEBUG
  170. # The following test fails on Windows because flock() implementation
  171. # is different from Unix.
  172. return if /mswin|mingw/ =~ RUBY_PLATFORM
  173. open_db_child(dbname) do
  174. assert_nothing_raised(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
  175. # this test is failed on Cygwin98 (???)
  176. GDBM.open(dbname, 0644, GDBM::NOLOCK) {|gdbm2|
  177. assert_instance_of(GDBM, gdbm2)
  178. }
  179. }
  180. end
  181. end if defined? GDBM::NOLOCK # gdbm 1.8.0 specific
  182. def test_s_open_error
  183. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0))
  184. assert_raise(Errno::EACCES, Errno::EWOULDBLOCK) {
  185. GDBM.open("#{@tmpdir}/#{@prefix}", 0)
  186. }
  187. gdbm.close
  188. end
  189. def test_close
  190. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}"))
  191. assert_nil(gdbm.close)
  192. # closed GDBM file
  193. assert_raise(RuntimeError) { gdbm.close }
  194. end
  195. def test_aref
  196. assert_equal('bar', @gdbm['foo'] = 'bar')
  197. assert_equal('bar', @gdbm['foo'])
  198. assert_nil(@gdbm['bar'])
  199. end
  200. def test_fetch
  201. assert_equal('bar', @gdbm['foo']='bar')
  202. assert_equal('bar', @gdbm.fetch('foo'))
  203. # key not found
  204. assert_raise(IndexError) {
  205. @gdbm.fetch('bar')
  206. }
  207. # test for `ifnone' arg
  208. assert_equal('baz', @gdbm.fetch('bar', 'baz'))
  209. # test for `ifnone' block
  210. assert_equal('foobar', @gdbm.fetch('bar') {|key| 'foo' + key })
  211. end
  212. def test_aset
  213. num = 0
  214. 2.times {|i|
  215. assert_equal('foo', @gdbm['foo'] = 'foo')
  216. assert_equal('foo', @gdbm['foo'])
  217. assert_equal('bar', @gdbm['foo'] = 'bar')
  218. assert_equal('bar', @gdbm['foo'])
  219. num += 1 if i == 0
  220. assert_equal(num, @gdbm.size)
  221. # assign nil
  222. assert_equal('', @gdbm['bar'] = '')
  223. assert_equal('', @gdbm['bar'])
  224. num += 1 if i == 0
  225. assert_equal(num, @gdbm.size)
  226. # empty string
  227. assert_equal('', @gdbm[''] = '')
  228. assert_equal('', @gdbm[''])
  229. num += 1 if i == 0
  230. assert_equal(num, @gdbm.size)
  231. # Fixnum
  232. assert_equal('200', @gdbm['100'] = '200')
  233. assert_equal('200', @gdbm['100'])
  234. num += 1 if i == 0
  235. assert_equal(num, @gdbm.size)
  236. # Big key and value
  237. assert_equal('y' * 100, @gdbm['x' * 100] = 'y' * 100)
  238. assert_equal('y' * 100, @gdbm['x' * 100])
  239. num += 1 if i == 0
  240. assert_equal(num, @gdbm.size)
  241. }
  242. end
  243. def test_key
  244. assert_equal('bar', @gdbm['foo'] = 'bar')
  245. assert_equal('foo', @gdbm.key('bar'))
  246. assert_nil(@gdbm['bar'])
  247. end
  248. def test_values_at
  249. keys = %w(foo bar baz)
  250. values = %w(FOO BAR BAZ)
  251. @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
  252. assert_equal(values.reverse, @gdbm.values_at(*keys.reverse))
  253. end
  254. def test_select_with_block
  255. keys = %w(foo bar baz)
  256. values = %w(FOO BAR BAZ)
  257. @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
  258. ret = @gdbm.select {|k,v|
  259. assert_equal(k.upcase, v)
  260. k != "bar"
  261. }
  262. assert_equal([['baz', 'BAZ'], ['foo', 'FOO']],
  263. ret.sort)
  264. end
  265. def test_length
  266. num = 10
  267. assert_equal(0, @gdbm.size)
  268. num.times {|i|
  269. i = i.to_s
  270. @gdbm[i] = i
  271. }
  272. assert_equal(num, @gdbm.size)
  273. @gdbm.shift
  274. assert_equal(num - 1, @gdbm.size)
  275. end
  276. def test_empty?
  277. assert_equal(true, @gdbm.empty?)
  278. @gdbm['foo'] = 'FOO'
  279. assert_equal(false, @gdbm.empty?)
  280. end
  281. def test_each_pair
  282. n = 0
  283. @gdbm.each_pair { n += 1 }
  284. assert_equal(0, n)
  285. keys = %w(foo bar baz)
  286. values = %w(FOO BAR BAZ)
  287. @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
  288. n = 0
  289. ret = @gdbm.each_pair {|key, val|
  290. assert_not_nil(i = keys.index(key))
  291. assert_equal(val, values[i])
  292. n += 1
  293. }
  294. assert_equal(keys.size, n)
  295. assert_equal(@gdbm, ret)
  296. end
  297. def test_each_value
  298. n = 0
  299. @gdbm.each_value { n += 1 }
  300. assert_equal(0, n)
  301. keys = %w(foo bar baz)
  302. values = %w(FOO BAR BAZ)
  303. @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
  304. n = 0
  305. ret = @gdbm.each_value {|val|
  306. assert_not_nil(key = @gdbm.key(val))
  307. assert_not_nil(i = keys.index(key))
  308. assert_equal(val, values[i])
  309. n += 1
  310. }
  311. assert_equal(keys.size, n)
  312. assert_equal(@gdbm, ret)
  313. end
  314. def test_each_key
  315. n = 0
  316. @gdbm.each_key { n += 1 }
  317. assert_equal(0, n)
  318. keys = %w(foo bar baz)
  319. values = %w(FOO BAR BAZ)
  320. @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
  321. n = 0
  322. ret = @gdbm.each_key {|key|
  323. assert_not_nil(i = keys.index(key))
  324. assert_equal(@gdbm[key], values[i])
  325. n += 1
  326. }
  327. assert_equal(keys.size, n)
  328. assert_equal(@gdbm, ret)
  329. end
  330. def test_keys
  331. assert_equal([], @gdbm.keys)
  332. keys = %w(foo bar baz)
  333. values = %w(FOO BAR BAZ)
  334. @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
  335. assert_equal(keys.sort, @gdbm.keys.sort)
  336. assert_equal(values.sort, @gdbm.values.sort)
  337. end
  338. def test_values
  339. test_keys
  340. end
  341. def test_shift
  342. assert_nil(@gdbm.shift)
  343. assert_equal(0, @gdbm.size)
  344. keys = %w(foo bar baz)
  345. values = %w(FOO BAR BAZ)
  346. @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
  347. ret_keys = []
  348. ret_values = []
  349. while ret = @gdbm.shift
  350. ret_keys.push ret[0]
  351. ret_values.push ret[1]
  352. assert_equal(keys.size - ret_keys.size, @gdbm.size)
  353. end
  354. assert_equal(keys.sort, ret_keys.sort)
  355. assert_equal(values.sort, ret_values.sort)
  356. end
  357. def test_delete
  358. keys = %w(foo bar baz)
  359. values = %w(FOO BAR BAZ)
  360. key = keys[1]
  361. assert_nil(@gdbm.delete(key))
  362. assert_equal(0, @gdbm.size)
  363. @gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
  364. assert_equal('BAR', @gdbm.delete(key))
  365. assert_nil(@gdbm[key])
  366. assert_equal(2, @gdbm.size)
  367. assert_nil(@gdbm.delete(key))
  368. end
  369. def test_delete_with_block
  370. key = 'no called block'
  371. @gdbm[key] = 'foo'
  372. assert_equal('foo', @gdbm.delete(key) {|k| k.replace 'called block'})
  373. assert_equal('no called block', key)
  374. assert_equal(0, @gdbm.size)
  375. key = 'no called block'
  376. assert_equal(:blockval,
  377. @gdbm.delete(key) {|k| k.replace 'called block'; :blockval})
  378. assert_equal('called block', key)
  379. assert_equal(0, @gdbm.size)
  380. end
  381. def test_delete_if
  382. v = "0"
  383. 100.times {@gdbm[v] = v; v = v.next}
  384. ret = @gdbm.delete_if {|key, val| key.to_i < 50}
  385. assert_equal(@gdbm, ret)
  386. check_size(50, @gdbm)
  387. ret = @gdbm.delete_if {|key, val| key.to_i >= 50}
  388. assert_equal(@gdbm, ret)
  389. check_size(0, @gdbm)
  390. # break
  391. v = "0"
  392. 100.times {@gdbm[v] = v; v = v.next}
  393. check_size(100, @gdbm)
  394. n = 0;
  395. @gdbm.delete_if {|key, val|
  396. break if n > 50
  397. n+=1
  398. true
  399. }
  400. assert_equal(51, n)
  401. check_size(49, @gdbm)
  402. @gdbm.clear
  403. # raise
  404. v = "0"
  405. 100.times {@gdbm[v] = v; v = v.next}
  406. check_size(100, @gdbm)
  407. n = 0;
  408. begin
  409. @gdbm.delete_if {|key, val|
  410. raise "runtime error" if n > 50
  411. n+=1
  412. true
  413. }
  414. rescue
  415. end
  416. assert_equal(51, n)
  417. check_size(49, @gdbm)
  418. end
  419. def test_reject
  420. v = "0"
  421. 100.times {@gdbm[v] = v; v = v.next}
  422. hash = @gdbm.reject {|key, val| key.to_i < 50}
  423. assert_instance_of(Hash, hash)
  424. assert_equal(100, @gdbm.size)
  425. assert_equal(50, hash.size)
  426. hash.each_pair {|key,val|
  427. assert_equal(false, key.to_i < 50)
  428. assert_equal(key, val)
  429. }
  430. hash = @gdbm.reject {|key, val| key.to_i < 100}
  431. assert_instance_of(Hash, hash)
  432. assert_equal(true, hash.empty?)
  433. end
  434. def test_clear
  435. v = "1"
  436. 100.times {v = v.next; @gdbm[v] = v}
  437. assert_equal(@gdbm, @gdbm.clear)
  438. # validate GDBM#size
  439. i = 0
  440. @gdbm.each { i += 1 }
  441. assert_equal(@gdbm.size, i)
  442. assert_equal(0, i)
  443. end
  444. def test_invert
  445. v = "0"
  446. 100.times {@gdbm[v] = v; v = v.next}
  447. hash = @gdbm.invert
  448. assert_instance_of(Hash, hash)
  449. assert_equal(100, hash.size)
  450. hash.each_pair {|key, val|
  451. assert_equal(key.to_i, val.to_i)
  452. }
  453. end
  454. def test_update
  455. hash = {}
  456. v = "0"
  457. 100.times {v = v.next; hash[v] = v}
  458. @gdbm["101"] = "101"
  459. @gdbm.update hash
  460. assert_equal(101, @gdbm.size)
  461. @gdbm.each_pair {|key, val|
  462. assert_equal(key.to_i, val.to_i)
  463. }
  464. end
  465. def test_replace
  466. hash = {}
  467. v = "0"
  468. 100.times {v = v.next; hash[v] = v}
  469. @gdbm["101"] = "101"
  470. @gdbm.replace hash
  471. assert_equal(100, @gdbm.size)
  472. @gdbm.each_pair {|key, val|
  473. assert_equal(key.to_i, val.to_i)
  474. }
  475. end
  476. def test_reorganize
  477. size1 = File.size(@path)
  478. i = "1"
  479. 1000.times {i = i.next; @gdbm[i] = i}
  480. @gdbm.clear
  481. @gdbm.sync
  482. size2 = File.size(@path)
  483. @gdbm.reorganize
  484. size3 = File.size(@path)
  485. # p [size1, size2, size3]
  486. assert_equal(true, size1 < size2)
  487. # this test is failed on Cygwin98. `GDBM version 1.8.0, as of May 19, 1999'
  488. assert_equal(true, size3 < size2)
  489. assert_equal(size1, size3)
  490. end
  491. def test_sync
  492. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0666, GDBM::FAST))
  493. assert_equal(gdbm.sync, gdbm)
  494. gdbm.close
  495. assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0666))
  496. assert_equal(gdbm.sync, gdbm)
  497. gdbm.close
  498. end
  499. def test_cachesize=
  500. assert_equal(@gdbm.cachesize = 1024, 1024)
  501. end
  502. def test_fastmode=
  503. assert_equal(@gdbm.fastmode = true, true)
  504. end
  505. def test_syncmode=
  506. assert_equal(@gdbm.syncmode = true, true)
  507. end
  508. def test_haskey?
  509. assert_equal('bar', @gdbm['foo']='bar')
  510. assert_equal(true, @gdbm.has_key?('foo'))
  511. assert_equal(false, @gdbm.has_key?('bar'))
  512. end
  513. def test_has_value?
  514. assert_equal('bar', @gdbm['foo']='bar')
  515. assert_equal(true, @gdbm.has_value?('bar'))
  516. assert_equal(false, @gdbm.has_value?('foo'))
  517. end
  518. def test_to_a
  519. v = "0"
  520. 100.times {v = v.next; @gdbm[v] = v}
  521. ary = @gdbm.to_a
  522. assert_instance_of(Array, ary)
  523. assert_equal(100, ary.size)
  524. ary.each {|key,val|
  525. assert_equal(key.to_i, val.to_i)
  526. }
  527. end
  528. def test_to_hash
  529. v = "0"
  530. 100.times {v = v.next; @gdbm[v] = v}
  531. hash = @gdbm.to_hash
  532. assert_instance_of(Hash, hash)
  533. assert_equal(100, hash.size)
  534. hash.each {|key,val|
  535. assert_equal(key.to_i, val.to_i)
  536. }
  537. end
  538. end
  539. class TestGDBM2 < Test::Unit::TestCase
  540. def setup
  541. @tmproot = Dir.mktmpdir('ruby-gdbm')
  542. end
  543. def teardown
  544. FileUtils.remove_entry_secure @tmproot if File.directory?(@tmproot)
  545. end
  546. def test_reader_open_notexist
  547. assert_raise(Errno::ENOENT) {
  548. GDBM.open("#{@tmproot}/a", 0666, GDBM::READER)
  549. }
  550. end
  551. def test_writer_open_notexist
  552. skip "gdbm_open(GDBM_WRITER) is broken on libgdbm 1.8.0" if /1\.8\.0/ =~ GDBM::VERSION
  553. assert_raise(Errno::ENOENT) {
  554. GDBM.open("#{@tmproot}/a", 0666, GDBM::WRITER)
  555. }
  556. end
  557. def test_wrcreat_open_notexist
  558. v = GDBM.open("#{@tmproot}/a", 0666, GDBM::WRCREAT)
  559. assert_instance_of(GDBM, v)
  560. v.close
  561. end
  562. def test_newdb_open_notexist
  563. v = GDBM.open("#{@tmproot}/a", 0666, GDBM::NEWDB)
  564. assert_instance_of(GDBM, v)
  565. v.close
  566. end
  567. def test_reader_open
  568. GDBM.open("#{@tmproot}/a.dbm") {} # create a db.
  569. v = GDBM.open("#{@tmproot}/a.dbm", nil, GDBM::READER) {|d|
  570. assert_raise(GDBMError) { d["k"] = "v" }
  571. true
  572. }
  573. assert(v)
  574. end
  575. def test_newdb_open
  576. GDBM.open("#{@tmproot}/a.dbm") {|dbm|
  577. dbm["k"] = "v"
  578. }
  579. v = GDBM.open("#{@tmproot}/a.dbm", nil, GDBM::NEWDB) {|d|
  580. assert_equal(0, d.length)
  581. assert_nil(d["k"])
  582. true
  583. }
  584. assert(v)
  585. end
  586. def test_freeze
  587. GDBM.open("#{@tmproot}/a.dbm") {|d|
  588. d.freeze
  589. assert_raise(RuntimeError) { d["k"] = "v" }
  590. }
  591. end
  592. end
  593. end