1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/gdbm/test_gdbm.rb
naruse 332938df51 merge revision(s) 61501,61758: [Backport #14481]
fix concurrent test.

	* test/rubygems/test_require.rb (test_concurrent_require):
	  Synchronizations should be in ensure clause. Sometimes
	  `require` fails (not sure why) and latch is not released.
	  Such case introduces unlimited awaiting.
	  This patch soleve this problem.


	skip some tests so that no failure occurs in root privilege

	Some tests had failed on `sudo make test-all`, mainly because root can
	access any files regardless of permission.  This change adds `skip`
	guards into such tests.

	Note that almost all tests in which `skip` guards is added, already have
	"windows" guard.  This is because there is no support to avoid read
	access by owner on Windows.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_5@62834 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-03-19 08:15:16 +00:00

733 lines
18 KiB
Ruby

# frozen_string_literal: false
begin
require 'gdbm'
rescue LoadError
end
if defined? GDBM
require 'test/unit'
require 'envutil' unless defined?(EnvUtil)
require 'tmpdir'
require 'fileutils'
class TestGDBM_RDONLY < Test::Unit::TestCase
def TestGDBM_RDONLY.uname_s
require 'rbconfig'
case RbConfig::CONFIG['target_os']
when 'cygwin'
require 'etc'
Etc.uname[:sysname]
else
RbConfig::CONFIG['target_os']
end
end
SYSTEM = uname_s
def setup
@tmpdir = Dir.mktmpdir("tmptest_gdbm")
@prefix = "tmptest_gdbm_#{$$}"
@path = "#{@tmpdir}/#{@prefix}_"
# prepare to make readonly GDBM file
GDBM.open("#{@tmpdir}/#{@prefix}_rdonly", 0400) {|gdbm|
gdbm['foo'] = 'FOO'
}
assert_instance_of(GDBM, @gdbm_rdonly = GDBM.new("#{@tmpdir}/#{@prefix}_rdonly", nil))
end
def teardown
assert_nil(@gdbm_rdonly.close)
ObjectSpace.each_object(GDBM) do |obj|
obj.close unless obj.closed?
end
FileUtils.remove_entry_secure @tmpdir
end
def test_delete_rdonly
skip("skipped because root can open anything") if Process.uid == 0
if /^CYGWIN_9/ !~ SYSTEM
assert_raise(GDBMError) {
@gdbm_rdonly.delete("foo")
}
assert_nil(@gdbm_rdonly.delete("bar"))
end
end
end
class TestGDBM < Test::Unit::TestCase
SYSTEM = TestGDBM_RDONLY::SYSTEM
def setup
@tmpdir = Dir.mktmpdir("tmptest_gdbm")
@prefix = "tmptest_gdbm_#{$$}"
@path = "#{@tmpdir}/#{@prefix}_"
assert_instance_of(GDBM, @gdbm = GDBM.new(@path))
end
def teardown
assert_nil(@gdbm.close)
ObjectSpace.each_object(GDBM) do |obj|
obj.close unless obj.closed?
end
begin
FileUtils.remove_entry_secure @tmpdir
rescue
system("fuser", *Dir.entries(@tmpdir).grep(/\A(?!\.\.?\z)/), chdir: @tmpdir)
else
return
end
FileUtils.remove_entry_secure @tmpdir
end
def check_size(expect, gdbm=@gdbm)
assert_equal(expect, gdbm.size)
n = 0
gdbm.each { n+=1 }
assert_equal(expect, n)
if expect == 0
assert_equal(true, gdbm.empty?)
else
assert_equal(false, gdbm.empty?)
end
end
def test_s_new_has_no_block
# GDBM.new ignore the block
foo = true
assert_instance_of(GDBM, gdbm = GDBM.new("#{@tmpdir}/#{@prefix}") { foo = false })
assert_equal(foo, true)
assert_nil(gdbm.close)
end
def test_s_open_create_new
return if /^CYGWIN_9/ =~ SYSTEM
save_mask = File.umask(0)
begin
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}"))
gdbm.close
assert_equal(File.stat("#{@tmpdir}/#{@prefix}").mode & 0777, 0666) unless /mswin|mingw/ =~ RUBY_PLATFORM
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}2", 0644))
gdbm.close
assert_equal(File.stat("#{@tmpdir}/#{@prefix}2").mode & 0777, 0644)
ensure
File.umask save_mask
end
end
def test_s_open_no_create
skip "gdbm_open(GDBM_WRITER) is broken on libgdbm 1.8.0" if /1\.8\.0/ =~ GDBM::VERSION
assert_nil(gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", nil))
ensure
gdbm.close if gdbm
end
def test_s_open_3rd_arg
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0644,
GDBM::FAST))
gdbm.close
# gdbm 1.8.0 specific
if defined? GDBM::SYNC
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0644,
GDBM::SYNC))
gdbm.close
end
# gdbm 1.8.0 specific
if defined? GDBM::NOLOCK
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0644,
GDBM::NOLOCK))
gdbm.close
end
end
def test_s_open_with_block
assert_equal(GDBM.open("#{@tmpdir}/#{@prefix}") { :foo }, :foo)
end
def open_db_child(dbname, *opts)
opts = [0644, *opts].map(&:inspect).join(', ')
args = [EnvUtil.rubybin, "-rgdbm", "-e", <<-SRC, dbname]
STDOUT.sync = true
gdbm = GDBM.open(ARGV.shift, #{opts})
puts gdbm.class
gets
SRC
IO.popen(args, "r+") do |f|
dbclass = f.gets
assert_equal("GDBM", dbclass.chomp)
yield
end
end
def test_s_open_lock
skip "GDBM.open would block when opening already locked gdbm file on platforms without flock and with lockf" if /solaris|aix/ =~ RUBY_PLATFORM
dbname = "#{@tmpdir}/#{@prefix}"
open_db_child(dbname) do
assert_raise(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
GDBM.open(dbname, 0644) {|gdbm|
assert_instance_of(GDBM, gdbm)
}
}
end
end
=begin
# Is it guaranteed on many OS?
def test_s_open_lock_one_process
# locking on one process
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0644))
assert_raise(Errno::EWOULDBLOCK) {
begin
GDBM.open("#{@tmpdir}/#{@prefix}", 0644)
rescue Errno::EAGAIN
raise Errno::EWOULDBLOCK
end
}
end
=end
def test_s_open_nolock
dbname = "#{@tmpdir}/#{@prefix}"
open_db_child(dbname, GDBM::NOLOCK) do
assert_nothing_raised(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
GDBM.open(dbname, 0644) {|gdbm2|
assert_instance_of(GDBM, gdbm2)
}
}
end
STDERR.puts Dir.glob("#{dbname}*") if $DEBUG
# The following test fails on Windows because flock() implementation
# is different from Unix.
return if /mswin|mingw/ =~ RUBY_PLATFORM
open_db_child(dbname) do
assert_nothing_raised(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
# this test is failed on Cygwin98 (???)
GDBM.open(dbname, 0644, GDBM::NOLOCK) {|gdbm2|
assert_instance_of(GDBM, gdbm2)
}
}
end
end if defined? GDBM::NOLOCK # gdbm 1.8.0 specific
def test_s_open_error
skip if Process.uid == 0 # because root can open anything
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0))
assert_raise(Errno::EACCES, Errno::EWOULDBLOCK) {
GDBM.open("#{@tmpdir}/#{@prefix}", 0)
}
gdbm.close
end
def test_close
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}"))
assert_nil(gdbm.close)
# closed GDBM file
assert_raise(RuntimeError) { gdbm.close }
end
def test_aref
assert_equal('bar', @gdbm['foo'] = 'bar')
assert_equal('bar', @gdbm['foo'])
assert_nil(@gdbm['bar'])
end
def test_fetch
assert_equal('bar', @gdbm['foo']='bar')
assert_equal('bar', @gdbm.fetch('foo'))
# key not found
assert_raise(IndexError) {
@gdbm.fetch('bar')
}
# test for `ifnone' arg
assert_equal('baz', @gdbm.fetch('bar', 'baz'))
# test for `ifnone' block
assert_equal('foobar', @gdbm.fetch('bar') {|key| 'foo' + key })
end
def test_aset
num = 0
2.times {|i|
assert_equal('foo', @gdbm['foo'] = 'foo')
assert_equal('foo', @gdbm['foo'])
assert_equal('bar', @gdbm['foo'] = 'bar')
assert_equal('bar', @gdbm['foo'])
num += 1 if i == 0
assert_equal(num, @gdbm.size)
# assign nil
assert_equal('', @gdbm['bar'] = '')
assert_equal('', @gdbm['bar'])
num += 1 if i == 0
assert_equal(num, @gdbm.size)
# empty string
assert_equal('', @gdbm[''] = '')
assert_equal('', @gdbm[''])
num += 1 if i == 0
assert_equal(num, @gdbm.size)
# Integer
assert_equal('200', @gdbm['100'] = '200')
assert_equal('200', @gdbm['100'])
num += 1 if i == 0
assert_equal(num, @gdbm.size)
# Big key and value
assert_equal('y' * 100, @gdbm['x' * 100] = 'y' * 100)
assert_equal('y' * 100, @gdbm['x' * 100])
num += 1 if i == 0
assert_equal(num, @gdbm.size)
}
end
def test_key
assert_equal('bar', @gdbm['foo'] = 'bar')
assert_equal('foo', @gdbm.key('bar'))
assert_nil(@gdbm['bar'])
end
def test_values_at
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
assert_equal(values.reverse, @gdbm.values_at(*keys.reverse))
end
def test_select_with_block
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
ret = @gdbm.select {|k,v|
assert_equal(k.upcase, v)
k != "bar"
}
assert_equal([['baz', 'BAZ'], ['foo', 'FOO']],
ret.sort)
end
def test_length
num = 10
assert_equal(0, @gdbm.size)
num.times {|i|
i = i.to_s
@gdbm[i] = i
}
assert_equal(num, @gdbm.size)
@gdbm.shift
assert_equal(num - 1, @gdbm.size)
end
def test_empty?
assert_equal(true, @gdbm.empty?)
@gdbm['foo'] = 'FOO'
assert_equal(false, @gdbm.empty?)
end
def test_each_pair
n = 0
@gdbm.each_pair { n += 1 }
assert_equal(0, n)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
n = 0
ret = @gdbm.each_pair {|key, val|
assert_not_nil(i = keys.index(key))
assert_equal(val, values[i])
n += 1
}
assert_equal(keys.size, n)
assert_equal(@gdbm, ret)
end
def test_each_value
n = 0
@gdbm.each_value { n += 1 }
assert_equal(0, n)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
n = 0
ret = @gdbm.each_value {|val|
assert_not_nil(key = @gdbm.key(val))
assert_not_nil(i = keys.index(key))
assert_equal(val, values[i])
n += 1
}
assert_equal(keys.size, n)
assert_equal(@gdbm, ret)
end
def test_each_key
n = 0
@gdbm.each_key { n += 1 }
assert_equal(0, n)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
n = 0
ret = @gdbm.each_key {|key|
assert_not_nil(i = keys.index(key))
assert_equal(@gdbm[key], values[i])
n += 1
}
assert_equal(keys.size, n)
assert_equal(@gdbm, ret)
end
def test_each_key_without_block
assert_kind_of Enumerator, @gdbm.each_key
end
def test_keys
assert_equal([], @gdbm.keys)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
assert_equal(keys.sort, @gdbm.keys.sort)
assert_equal(values.sort, @gdbm.values.sort)
end
def test_values
test_keys
end
def test_shift
assert_nil(@gdbm.shift)
assert_equal(0, @gdbm.size)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
ret_keys = []
ret_values = []
while ret = @gdbm.shift
ret_keys.push ret[0]
ret_values.push ret[1]
assert_equal(keys.size - ret_keys.size, @gdbm.size)
end
assert_equal(keys.sort, ret_keys.sort)
assert_equal(values.sort, ret_values.sort)
end
def test_delete
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
key = keys[1]
assert_nil(@gdbm.delete(key))
assert_equal(0, @gdbm.size)
@gdbm[keys[0]], @gdbm[keys[1]], @gdbm[keys[2]] = values
assert_equal('BAR', @gdbm.delete(key))
assert_nil(@gdbm[key])
assert_equal(2, @gdbm.size)
assert_nil(@gdbm.delete(key))
end
def test_delete_with_block
key = 'no called block'
@gdbm[key] = 'foo'
assert_equal('foo', @gdbm.delete(key) {|k| k.replace 'called block'})
assert_equal('no called block', key)
assert_equal(0, @gdbm.size)
key = 'no called block'
assert_equal(:blockval,
@gdbm.delete(key) {|k| k.replace 'called block'; :blockval})
assert_equal('called block', key)
assert_equal(0, @gdbm.size)
end
def test_delete_if
v = "0"
100.times {@gdbm[v] = v; v = v.next}
ret = @gdbm.delete_if {|key, val| key.to_i < 50}
assert_equal(@gdbm, ret)
check_size(50, @gdbm)
ret = @gdbm.delete_if {|key, val| key.to_i >= 50}
assert_equal(@gdbm, ret)
check_size(0, @gdbm)
# break
v = "0"
100.times {@gdbm[v] = v; v = v.next}
check_size(100, @gdbm)
n = 0;
@gdbm.delete_if {|key, val|
break if n > 50
n+=1
true
}
assert_equal(51, n)
check_size(49, @gdbm)
@gdbm.clear
# raise
v = "0"
100.times {@gdbm[v] = v; v = v.next}
check_size(100, @gdbm)
n = 0;
begin
@gdbm.delete_if {|key, val|
raise "runtime error" if n > 50
n+=1
true
}
rescue RuntimeError
end
assert_equal(51, n)
check_size(49, @gdbm)
end
def test_reject
v = "0"
100.times {@gdbm[v] = v; v = v.next}
hash = @gdbm.reject {|key, val| key.to_i < 50}
assert_instance_of(Hash, hash)
assert_equal(100, @gdbm.size)
assert_equal(50, hash.size)
hash.each_pair {|key,val|
assert_equal(false, key.to_i < 50)
assert_equal(key, val)
}
hash = @gdbm.reject {|key, val| key.to_i < 100}
assert_instance_of(Hash, hash)
assert_equal(true, hash.empty?)
end
def test_clear
v = "1"
100.times {v = v.next; @gdbm[v] = v}
assert_equal(@gdbm, @gdbm.clear)
# validate GDBM#size
i = 0
@gdbm.each { i += 1 }
assert_equal(@gdbm.size, i)
assert_equal(0, i)
end
def test_invert
v = "0"
100.times {@gdbm[v] = v; v = v.next}
hash = @gdbm.invert
assert_instance_of(Hash, hash)
assert_equal(100, hash.size)
hash.each_pair {|key, val|
assert_equal(key.to_i, val.to_i)
}
end
def test_update
hash = {}
v = "0"
100.times {v = v.next; hash[v] = v}
@gdbm["101"] = "101"
@gdbm.update hash
assert_equal(101, @gdbm.size)
@gdbm.each_pair {|key, val|
assert_equal(key.to_i, val.to_i)
}
end
def test_replace
hash = {}
v = "0"
100.times {v = v.next; hash[v] = v}
@gdbm["101"] = "101"
@gdbm.replace hash
assert_equal(100, @gdbm.size)
@gdbm.each_pair {|key, val|
assert_equal(key.to_i, val.to_i)
}
end
def test_reorganize
size1 = File.size(@path)
i = "1"
1000.times {i = i.next; @gdbm[i] = i}
@gdbm.clear
@gdbm.sync
size2 = File.size(@path)
@gdbm.reorganize
@gdbm.sync
size3 = File.size(@path)
# p [size1, size2, size3]
assert_equal(true, size1 < size2)
# this test is failed on Cygwin98. `GDBM version 1.8.0, as of May 19, 1999'
assert_equal(true, size3 < size2)
assert_equal(size1, size3)
end
def test_sync
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0666, GDBM::FAST))
assert_equal(gdbm.sync, gdbm)
gdbm.close
assert_instance_of(GDBM, gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", 0666))
assert_equal(gdbm.sync, gdbm)
gdbm.close
end
def test_cachesize=
assert_equal(@gdbm.cachesize = 1024, 1024)
end
def test_fastmode=
assert_equal(@gdbm.fastmode = true, true)
end
def test_syncmode=
assert_equal(@gdbm.syncmode = true, true)
end
def test_haskey?
assert_equal('bar', @gdbm['foo']='bar')
assert_equal(true, @gdbm.has_key?('foo'))
assert_equal(false, @gdbm.has_key?('bar'))
end
def test_has_value?
assert_equal('bar', @gdbm['foo']='bar')
assert_equal(true, @gdbm.has_value?('bar'))
assert_equal(false, @gdbm.has_value?('foo'))
end
def test_to_a
v = "0"
100.times {v = v.next; @gdbm[v] = v}
ary = @gdbm.to_a
assert_instance_of(Array, ary)
assert_equal(100, ary.size)
ary.each {|key,val|
assert_equal(key.to_i, val.to_i)
}
end
def test_to_hash
v = "0"
100.times {v = v.next; @gdbm[v] = v}
hash = @gdbm.to_hash
assert_instance_of(Hash, hash)
assert_equal(100, hash.size)
hash.each {|key,val|
assert_equal(key.to_i, val.to_i)
}
end
end
class TestGDBM2 < Test::Unit::TestCase
def setup
@tmproot = Dir.mktmpdir('ruby-gdbm')
end
def teardown
FileUtils.remove_entry_secure @tmproot if File.directory?(@tmproot)
end
def test_reader_open_notexist
assert_raise(Errno::ENOENT) {
GDBM.open("#{@tmproot}/a", 0666, GDBM::READER)
}
end
def test_writer_open_notexist
skip "gdbm_open(GDBM_WRITER) is broken on libgdbm 1.8.0" if /1\.8\.0/ =~ GDBM::VERSION
assert_raise(Errno::ENOENT) {
GDBM.open("#{@tmproot}/a", 0666, GDBM::WRITER)
}
end
def test_wrcreat_open_notexist
v = GDBM.open("#{@tmproot}/a", 0666, GDBM::WRCREAT)
assert_instance_of(GDBM, v)
v.close
end
def test_newdb_open_notexist
v = GDBM.open("#{@tmproot}/a", 0666, GDBM::NEWDB)
assert_instance_of(GDBM, v)
v.close
end
def test_reader_open
GDBM.open("#{@tmproot}/a.dbm") {} # create a db.
v = GDBM.open("#{@tmproot}/a.dbm", nil, GDBM::READER) {|d|
assert_raise(GDBMError) { d["k"] = "v" }
true
}
assert(v)
end
def test_newdb_open
GDBM.open("#{@tmproot}/a.dbm") {|dbm|
dbm["k"] = "v"
}
v = GDBM.open("#{@tmproot}/a.dbm", nil, GDBM::NEWDB) {|d|
assert_equal(0, d.length)
assert_nil(d["k"])
true
}
assert(v)
end
def test_freeze
GDBM.open("#{@tmproot}/a.dbm") {|d|
d.freeze
assert_raise(FrozenError) { d["k"] = "v" }
}
end
end
end