ruby/test/sdbm/test_sdbm.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

544 lines
12 KiB
Ruby

# frozen_string_literal: false
require 'test/unit'
require 'tmpdir'
begin
require 'sdbm'
rescue LoadError
end
class TestSDBM < Test::Unit::TestCase
def setup
@tmpdir = Dir.mktmpdir("tmptest_sdbm")
@prefix = "tmptest_sdbm_#{$$}"
@path = "#{@tmpdir}/#{@prefix}_"
assert_instance_of(SDBM, @sdbm = SDBM.new(@path))
end
def teardown
assert_nil(@sdbm.close)
ObjectSpace.each_object(SDBM) do |obj|
obj.close unless obj.closed?
end
FileUtils.remove_entry_secure @tmpdir
end
def check_size(expect, sdbm=@sdbm)
assert_equal(expect, sdbm.size)
n = 0
sdbm.each { n+=1 }
assert_equal(expect, n)
if expect == 0
assert_equal(true, sdbm.empty?)
else
assert_equal(false, sdbm.empty?)
end
end
def test_version
assert(! SDBM.const_defined?(:VERSION))
end
def test_s_new_has_no_block
# SDBM.new ignore the block
foo = true
assert_instance_of(SDBM, sdbm = SDBM.new("#{@tmpdir}/#{@prefix}") { foo = false })
assert_equal(foo, true)
assert_nil(sdbm.close)
end
def test_s_open_no_create
assert_nil(sdbm = SDBM.open("#{@tmpdir}/#{@prefix}", nil))
ensure
sdbm.close if sdbm
end
def test_s_open_with_block
assert_equal(SDBM.open("#{@tmpdir}/#{@prefix}") { :foo }, :foo)
end
=begin
# Is it guaranteed on many OS?
def test_s_open_lock_one_process
# locking on one process
assert_instance_of(SDBM, sdbm = SDBM.open("#{@tmpdir}/#{@prefix}", 0644))
assert_raise(Errno::EWOULDBLOCK) {
begin
SDBM.open("#{@tmpdir}/#{@prefix}", 0644)
rescue Errno::EAGAIN
raise Errno::EWOULDBLOCK
end
}
end
=end
def open_db_child(dbname, *opts)
opts = [0644, *opts].map(&:inspect).join(', ')
args = [EnvUtil.rubybin, "-rsdbm", <<-SRC, dbname]
STDOUT.sync = true
gdbm = SDBM.open(ARGV.shift, #{opts})
puts sdbm.class
gets
SRC
IO.popen(args, "r+") do |f|
dbclass = f.gets
assert_equal("SDBM", dbclass.chomp)
yield
end
end
def test_s_open_nolock
dbname = "#{@tmpdir}/#{@prefix}"
open_db_child(dbname, SDBM::NOLOCK) do
assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
SDBM.open(dbname, 0644) {|sdbm|
assert_instance_of(SDBM, sdbm)
}
}
end
p Dir.glob("#{@tmpdir}/#{@prefix}*") if $DEBUG
open_db_child(dbname) do
assert_no_exception(Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EACCES) {
# this test is failed on Cygwin98 (???)
SDBM.open(dbname, 0644, SDBM::NOLOCK) {|sdbm|
assert_instance_of(SDBM, sdbm)
}
}
end
end if defined? SDBM::NOLOCK # sdbm 1.8.0 specific
def test_s_open_error
skip "doesn't support to avoid read access by owner on Windows" if /mswin|mingw/ =~ RUBY_PLATFORM
skip "skipped because root can open anything" if Process.uid == 0
assert_instance_of(SDBM, sdbm = SDBM.open("#{@tmpdir}/#{@prefix}", 0))
assert_raise(Errno::EACCES) {
SDBM.open("#{@tmpdir}/#{@prefix}", 0)
}
sdbm.close
end
def test_close
assert_instance_of(SDBM, sdbm = SDBM.open("#{@tmpdir}/#{@prefix}"))
assert_nil(sdbm.close)
# closed SDBM file
assert_raise(SDBMError) { sdbm.close }
end
def test_aref
assert_equal('bar', @sdbm['foo'] = 'bar')
assert_equal('bar', @sdbm['foo'])
assert_nil(@sdbm['bar'])
end
def test_fetch
assert_equal('bar', @sdbm['foo']='bar')
assert_equal('bar', @sdbm.fetch('foo'))
# key not found
assert_raise(IndexError) {
@sdbm.fetch('bar')
}
# test for `ifnone' arg
assert_equal('baz', @sdbm.fetch('bar', 'baz'))
# test for `ifnone' block
assert_equal('foobar', @sdbm.fetch('bar') {|key| 'foo' + key })
end
def test_aset
num = 0
2.times {|i|
assert_equal('foo', @sdbm['foo'] = 'foo')
assert_equal('foo', @sdbm['foo'])
assert_equal('bar', @sdbm['foo'] = 'bar')
assert_equal('bar', @sdbm['foo'])
num += 1 if i == 0
assert_equal(num, @sdbm.size)
# assign nil
assert_equal('', @sdbm['bar'] = '')
assert_equal('', @sdbm['bar'])
num += 1 if i == 0
assert_equal(num, @sdbm.size)
# empty string
assert_equal('', @sdbm[''] = '')
assert_equal('', @sdbm[''])
num += 1 if i == 0
assert_equal(num, @sdbm.size)
# Integer
assert_equal('200', @sdbm['100'] = '200')
assert_equal('200', @sdbm['100'])
num += 1 if i == 0
assert_equal(num, @sdbm.size)
# Big key and value
assert_equal('y' * 100, @sdbm['x' * 100] = 'y' * 100)
assert_equal('y' * 100, @sdbm['x' * 100])
num += 1 if i == 0
assert_equal(num, @sdbm.size)
}
end
def test_key
assert_equal('bar', @sdbm['foo'] = 'bar')
assert_equal('foo', @sdbm.key('bar'))
assert_nil(@sdbm['bar'])
end
def test_values_at
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
assert_equal(values.reverse, @sdbm.values_at(*keys.reverse))
end
def test_select_with_block
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
ret = @sdbm.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, @sdbm.size)
num.times {|i|
i = i.to_s
@sdbm[i] = i
}
assert_equal(num, @sdbm.size)
@sdbm.shift
assert_equal(num - 1, @sdbm.size)
end
def test_empty?
assert_equal(true, @sdbm.empty?)
@sdbm['foo'] = 'FOO'
assert_equal(false, @sdbm.empty?)
end
def test_each_pair
n = 0
@sdbm.each_pair { n += 1 }
assert_equal(0, n)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
n = 0
ret = @sdbm.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(@sdbm, ret)
end
def test_each_value
n = 0
@sdbm.each_value { n += 1 }
assert_equal(0, n)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
n = 0
ret = @sdbm.each_value {|val|
assert_not_nil(key = @sdbm.key(val))
assert_not_nil(i = keys.index(key))
assert_equal(val, values[i])
n += 1
}
assert_equal(keys.size, n)
assert_equal(@sdbm, ret)
end
def test_each_key
n = 0
@sdbm.each_key { n += 1 }
assert_equal(0, n)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
n = 0
ret = @sdbm.each_key {|key|
assert_not_nil(i = keys.index(key))
assert_equal(@sdbm[key], values[i])
n += 1
}
assert_equal(keys.size, n)
assert_equal(@sdbm, ret)
end
def test_keys
assert_equal([], @sdbm.keys)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
assert_equal(keys.sort, @sdbm.keys.sort)
assert_equal(values.sort, @sdbm.values.sort)
end
def test_values
test_keys
end
def test_shift
assert_nil(@sdbm.shift)
assert_equal(0, @sdbm.size)
keys = %w(foo bar baz)
values = %w(FOO BAR BAZ)
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
ret_keys = []
ret_values = []
while ret = @sdbm.shift
ret_keys.push ret[0]
ret_values.push ret[1]
assert_equal(keys.size - ret_keys.size, @sdbm.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(@sdbm.delete(key))
assert_equal(0, @sdbm.size)
@sdbm[keys[0]], @sdbm[keys[1]], @sdbm[keys[2]] = values
assert_equal('BAR', @sdbm.delete(key))
assert_nil(@sdbm[key])
assert_equal(2, @sdbm.size)
assert_nil(@sdbm.delete(key))
end
def test_delete_with_block
key = 'no called block'
@sdbm[key] = 'foo'
assert_equal('foo', @sdbm.delete(key) {|k| k.replace 'called block'; :blockval})
assert_equal(0, @sdbm.size)
key = 'no called block'
assert_equal(:blockval, @sdbm.delete(key) {|k| k.replace 'called block'; :blockval})
assert_equal(0, @sdbm.size)
end
def test_delete_if
v = "0"
100.times {@sdbm[v] = v; v = v.next}
ret = @sdbm.delete_if {|key, val| key.to_i < 50}
assert_equal(@sdbm, ret)
check_size(50, @sdbm)
ret = @sdbm.delete_if {|key, val| key.to_i >= 50}
assert_equal(@sdbm, ret)
check_size(0, @sdbm)
# break
v = "0"
100.times {@sdbm[v] = v; v = v.next}
check_size(100, @sdbm)
n = 0;
@sdbm.delete_if {|key, val|
break if n > 50
n+=1
true
}
assert_equal(51, n)
check_size(49, @sdbm)
@sdbm.clear
# raise
v = "0"
100.times {@sdbm[v] = v; v = v.next}
check_size(100, @sdbm)
n = 0;
begin
@sdbm.delete_if {|key, val|
raise "runtime error" if n > 50
n+=1
true
}
rescue RuntimeError
end
assert_equal(51, n)
check_size(49, @sdbm)
end
def test_reject
v = "0"
100.times {@sdbm[v] = v; v = v.next}
hash = @sdbm.reject {|key, val| key.to_i < 50}
assert_instance_of(Hash, hash)
assert_equal(100, @sdbm.size)
assert_equal(50, hash.size)
hash.each_pair {|key,val|
assert_equal(false, key.to_i < 50)
assert_equal(key, val)
}
hash = @sdbm.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; @sdbm[v] = v}
assert_equal(@sdbm, @sdbm.clear)
# validate SDBM#size
i = 0
@sdbm.each { i += 1 }
assert_equal(@sdbm.size, i)
assert_equal(0, i)
end
def test_invert
v = "0"
100.times {@sdbm[v] = v; v = v.next}
hash = @sdbm.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}
@sdbm["101"] = "101"
@sdbm.update hash
assert_equal(101, @sdbm.size)
@sdbm.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}
@sdbm["101"] = "101"
@sdbm.replace hash
assert_equal(100, @sdbm.size)
@sdbm.each_pair {|key, val|
assert_equal(key.to_i, val.to_i)
}
end
def test_haskey?
assert_equal('bar', @sdbm['foo']='bar')
assert_equal(true, @sdbm.has_key?('foo'))
assert_equal(false, @sdbm.has_key?('bar'))
end
def test_has_value?
assert_equal('bar', @sdbm['foo']='bar')
assert_equal(true, @sdbm.has_value?('bar'))
assert_equal(false, @sdbm.has_value?('foo'))
end
def test_to_a
v = "0"
100.times {v = v.next; @sdbm[v] = v}
ary = @sdbm.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; @sdbm[v] = v}
hash = @sdbm.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
def test_closed
assert_equal(false, @sdbm.closed?)
@sdbm.close
assert_equal(true, @sdbm.closed?)
@sdbm = SDBM.new(@path)
end
def test_readonly
skip "skipped because root can read anything" if /mswin|mingw/ !~ RUBY_PLATFORM && Process.uid == 0
@sdbm["bar"] = "baz"
@sdbm.close
File.chmod(0444, @path + ".dir")
File.chmod(0444, @path + ".pag")
@sdbm = SDBM.new(@path)
assert_raise(SDBMError) { @sdbm["bar"] = "foo" }
assert_raise(SDBMError) { @sdbm.delete("bar") }
assert_raise(SDBMError) { @sdbm.delete_if { true } }
assert_raise(SDBMError) { @sdbm.clear }
assert_nil(@sdbm.store("bar", nil))
end
def test_update2
obj = Object.new
def obj.each_pair
yield []
end
assert_raise(ArgumentError) { @sdbm.update(obj) }
end
end if defined? SDBM