summaryrefslogtreecommitdiff
path: root/spec/ruby
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2022-03-03 14:43:14 +0100
committerBenoit Daloze <eregontp@gmail.com>2022-03-03 14:43:14 +0100
commit3b21818db1fac0c22f16364eab2d8cc0067abd63 (patch)
tree6776a6bfe92db4e35da1ff01e09c40d4c4c20351 /spec/ruby
parent1dc6bed0ca6ca379f1c4b2e9fc0dee72dbf1e205 (diff)
Update to ruby/spec@82cd3a3
Diffstat (limited to 'spec/ruby')
-rw-r--r--spec/ruby/.mspec.constants1
-rw-r--r--spec/ruby/core/array/each_spec.rb35
-rw-r--r--spec/ruby/core/dir/fixtures/common.rb18
-rw-r--r--spec/ruby/core/dir/glob_spec.rb25
-rw-r--r--spec/ruby/core/dir/read_spec.rb14
-rw-r--r--spec/ruby/core/exception/interrupt_spec.rb9
-rw-r--r--spec/ruby/core/io/close_spec.rb6
-rw-r--r--spec/ruby/core/rational/minus_spec.rb48
-rw-r--r--spec/ruby/core/string/shared/to_sym.rb9
-rw-r--r--spec/ruby/core/thread/report_on_exception_spec.rb21
-rw-r--r--spec/ruby/language/file_spec.rb12
-rw-r--r--spec/ruby/language/predefined_spec.rb10
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c6
-rw-r--r--spec/ruby/optional/capi/object_spec.rb19
-rw-r--r--spec/ruby/optional/capi/string_spec.rb4
-rw-r--r--spec/ruby/shared/rational/minus.rb48
16 files changed, 213 insertions, 72 deletions
diff --git a/spec/ruby/.mspec.constants b/spec/ruby/.mspec.constants
index 6b70274c52..c070e35496 100644
--- a/spec/ruby/.mspec.constants
+++ b/spec/ruby/.mspec.constants
@@ -73,6 +73,7 @@ EvalBindingProcA
Exception2MessageMapper
ExceptionForMatrix
Fcntl
+Fiddle
FileStat
FileUtils
Find
diff --git a/spec/ruby/core/array/each_spec.rb b/spec/ruby/core/array/each_spec.rb
index 256647d61e..cf8e9da6d8 100644
--- a/spec/ruby/core/array/each_spec.rb
+++ b/spec/ruby/core/array/each_spec.rb
@@ -3,9 +3,10 @@ require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
require_relative '../enumerable/shared/enumeratorized'
-# Modifying a collection while the contents are being iterated
-# gives undefined behavior. See
-# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
+# Mutating the array while it is being iterated is discouraged as it can result in confusing behavior.
+# Yet a Ruby implementation must not crash in such a case, and following the simple CRuby behavior makes sense.
+# CRuby simply reads the array storage and checks the size for every iteration;
+# like `i = 0; while i < size; yield self[i]; end`
describe "Array#each" do
it "yields each element to the block" do
@@ -15,6 +16,34 @@ describe "Array#each" do
a.should == [1, 2, 3]
end
+ it "yields each element to the block even if the array is changed during iteration" do
+ a = [1, 2, 3, 4, 5]
+ iterated = []
+ a.each { |x| iterated << x; a << x+5 if x.even? }
+ iterated.should == [1, 2, 3, 4, 5, 7, 9]
+ end
+
+ it "yields only elements that are still in the array" do
+ a = [0, 1, 2, 3, 4]
+ iterated = []
+ a.each { |x| iterated << x; a.pop if x.even? }
+ iterated.should == [0, 1, 2]
+ end
+
+ it "yields elements based on an internal index" do
+ a = [0, 1, 2, 3, 4]
+ iterated = []
+ a.each { |x| iterated << x; a.shift if x.even? }
+ iterated.should == [0, 2, 4]
+ end
+
+ it "yields the same element multiple times if inserting while iterating" do
+ a = [1, 2]
+ iterated = []
+ a.each { |x| iterated << x; a.unshift(0) if a.size == 2 }
+ iterated.should == [1, 1, 2]
+ end
+
it "yields each element to a block that takes multiple arguments" do
a = [[1, 2], :a, [3, 4]]
b = []
diff --git a/spec/ruby/core/dir/fixtures/common.rb b/spec/ruby/core/dir/fixtures/common.rb
index 637fe93e2f..a8d6e69c44 100644
--- a/spec/ruby/core/dir/fixtures/common.rb
+++ b/spec/ruby/core/dir/fixtures/common.rb
@@ -101,12 +101,30 @@ module DirSpecs
@mock_dir_files
end
+ def self.mock_dir_links
+ unless @mock_dir_links
+ @mock_dir_links = []
+ platform_is_not :windows do
+ @mock_dir_links += [
+ ['special/ln', 'subdir_one']
+ ]
+ end
+ end
+ @mock_dir_links
+ end
+
def self.create_mock_dirs
mock_dir_files.each do |name|
file = File.join mock_dir, name
mkdir_p File.dirname(file)
touch file
end
+ mock_dir_links.each do |link, target|
+ full_link = File.join mock_dir, link
+ full_target = File.join mock_dir, target
+
+ File.symlink full_target, full_link
+ end
end
def self.delete_mock_dirs
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index 295a7ab920..43dac73eee 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -222,5 +222,30 @@ describe "Dir.glob" do
Dir.rmdir('no_permission')
end
end
+
+ it "will follow symlinks when processing a `*/` pattern." do
+ expected = ['special/ln/nondotfile']
+ Dir.glob('special/*/nondotfile').should == expected
+ end
+
+ it "will not follow symlinks when recursively traversing directories" do
+ expected = %w[
+ deeply/nondotfile
+ nondotfile
+ subdir_one/nondotfile
+ subdir_two/nondotfile
+ ]
+ Dir.glob('**/nondotfile').sort.should == expected
+ end
+
+ it "will follow symlinks when testing directory after recursive directory in pattern" do
+ expected = %w[
+ deeply/nondotfile
+ special/ln/nondotfile
+ subdir_one/nondotfile
+ subdir_two/nondotfile
+ ]
+ Dir.glob('**/*/nondotfile').sort.should == expected
+ end
end
end
diff --git a/spec/ruby/core/dir/read_spec.rb b/spec/ruby/core/dir/read_spec.rb
index 2953aad72f..276930c6b7 100644
--- a/spec/ruby/core/dir/read_spec.rb
+++ b/spec/ruby/core/dir/read_spec.rb
@@ -54,16 +54,16 @@ describe "Dir#read" do
old_external_encoding = Encoding::default_external
Encoding.default_internal = Encoding::UTF_8
Encoding.default_external = Encoding::SHIFT_JIS
- dir = Dir.open(File.join(DirSpecs.mock_dir, 'special'))
shift_jis_entries = []
begin
- -> {
- while entry = dir.read
- shift_jis_entries << entry
- end
- }.should_not raise_error
+ Dir.open(File.join(DirSpecs.mock_dir, 'special')) do |d|
+ -> {
+ while entry = d.read
+ shift_jis_entries << entry
+ end
+ }.should_not raise_error
+ end
ensure
- dir.close
Encoding.default_internal = old_internal_encoding
Encoding.default_external = old_external_encoding
end
diff --git a/spec/ruby/core/exception/interrupt_spec.rb b/spec/ruby/core/exception/interrupt_spec.rb
index a7501efadc..299b5b81f3 100644
--- a/spec/ruby/core/exception/interrupt_spec.rb
+++ b/spec/ruby/core/exception/interrupt_spec.rb
@@ -48,4 +48,13 @@ describe "Interrupt" do
RUBY
out.should == "Interrupt: #{Signal.list["INT"]}\n"
end
+
+ platform_is_not :windows do
+ it "shows the backtrace and has a signaled exit status" do
+ err = IO.popen([*ruby_exe, '-e', 'Process.kill :INT, Process.pid; sleep'], err: [:child, :out], &:read)
+ $?.termsig.should == Signal.list.fetch('INT')
+ err.should.include? ': Interrupt'
+ err.should.include? "from -e:1:in `<main>'"
+ end
+ end
end
diff --git a/spec/ruby/core/io/close_spec.rb b/spec/ruby/core/io/close_spec.rb
index eb560eaf67..3a44cc8b17 100644
--- a/spec/ruby/core/io/close_spec.rb
+++ b/spec/ruby/core/io/close_spec.rb
@@ -44,6 +44,12 @@ describe "IO#close" do
@io.close.should be_nil
end
+ it "does not call the #flush method but flushes the stream internally" do
+ @io.should_not_receive(:flush)
+ @io.close
+ @io.should.closed?
+ end
+
it 'raises an IOError with a clear message' do
matching_exception = nil
diff --git a/spec/ruby/core/rational/minus_spec.rb b/spec/ruby/core/rational/minus_spec.rb
index 9e0f81556b..a61b62ebe6 100644
--- a/spec/ruby/core/rational/minus_spec.rb
+++ b/spec/ruby/core/rational/minus_spec.rb
@@ -1,7 +1,51 @@
-require_relative '../../shared/rational/minus'
+require_relative '../../spec_helper'
require_relative '../../shared/rational/arithmetic_exception_in_coerce'
describe "Rational#-" do
- it_behaves_like :rational_minus, :-
it_behaves_like :rational_arithmetic_exception_in_coerce, :-
+
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational - obj
+ end
+
+ it "calls #- on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:-).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational - obj).should == :result
+ end
+end
+
+describe "Rational#- passed a Rational" do
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4))
+ (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2))
+
+ (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4))
+ end
+end
+
+describe "Rational#- passed a Float" do
+ it "returns the result of subtracting other from self as a Float" do
+ (Rational(3, 4) - 0.2).should eql(0.55)
+ (Rational(3, 4) - 2.5).should eql(-1.75)
+ end
+end
+
+describe "Rational#- passed an Integer" do
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) - 1).should eql(Rational(-1, 4))
+ (Rational(3, 4) - 2).should eql(Rational(-5, 4))
+ end
end
diff --git a/spec/ruby/core/string/shared/to_sym.rb b/spec/ruby/core/string/shared/to_sym.rb
index 416f302aef..7bd3a0510c 100644
--- a/spec/ruby/core/string/shared/to_sym.rb
+++ b/spec/ruby/core/string/shared/to_sym.rb
@@ -53,6 +53,15 @@ describe :string_to_sym, shared: true do
sym.to_s.should == binary_string
end
+ it "ignores exising symbols with different encoding" do
+ source = "fée"
+
+ iso_symbol = source.force_encoding(Encoding::ISO_8859_1).send(@method)
+ iso_symbol.encoding.should == Encoding::ISO_8859_1
+ binary_symbol = source.force_encoding(Encoding::BINARY).send(@method)
+ binary_symbol.encoding.should == Encoding::BINARY
+ end
+
it "raises an EncodingError for UTF-8 String containing invalid bytes" do
invalid_utf8 = "\xC3"
invalid_utf8.should_not.valid_encoding?
diff --git a/spec/ruby/core/thread/report_on_exception_spec.rb b/spec/ruby/core/thread/report_on_exception_spec.rb
index bf50a167df..e7f400819a 100644
--- a/spec/ruby/core/thread/report_on_exception_spec.rb
+++ b/spec/ruby/core/thread/report_on_exception_spec.rb
@@ -60,6 +60,27 @@ describe "Thread#report_on_exception=" do
t.join
}.should raise_error(RuntimeError, "Thread#report_on_exception specs")
end
+
+ it "prints the backtrace even if the thread was killed just after Thread#raise" do
+ t = nil
+ ready = false
+ -> {
+ t = Thread.new {
+ Thread.current.report_on_exception = true
+ ready = true
+ sleep
+ }
+
+ Thread.pass until ready and t.stop?
+ t.raise RuntimeError, "Thread#report_on_exception before kill spec"
+ t.kill
+ Thread.pass while t.alive?
+ }.should output("", /Thread.+terminated with exception.+Thread#report_on_exception before kill spec/m)
+
+ -> {
+ t.join
+ }.should raise_error(RuntimeError, "Thread#report_on_exception before kill spec")
+ end
end
describe "when set to false" do
diff --git a/spec/ruby/language/file_spec.rb b/spec/ruby/language/file_spec.rb
index 729dee1008..136b262d07 100644
--- a/spec/ruby/language/file_spec.rb
+++ b/spec/ruby/language/file_spec.rb
@@ -12,18 +12,10 @@ describe "The __FILE__ pseudo-variable" do
end
end
-describe "The __FILE__ pseudo-variable" do
- it_behaves_like :language___FILE__, :require, CodeLoadingSpecs::Method.new
-end
-
-describe "The __FILE__ pseudo-variable" do
+describe "The __FILE__ pseudo-variable with require" do
it_behaves_like :language___FILE__, :require, Kernel
end
-describe "The __FILE__ pseudo-variable" do
- it_behaves_like :language___FILE__, :load, CodeLoadingSpecs::Method.new
-end
-
-describe "The __FILE__ pseudo-variable" do
+describe "The __FILE__ pseudo-variable with load" do
it_behaves_like :language___FILE__, :load, Kernel
end
diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb
index 732e66b9e7..8eb7511c0e 100644
--- a/spec/ruby/language/predefined_spec.rb
+++ b/spec/ruby/language/predefined_spec.rb
@@ -835,6 +835,8 @@ describe "Execution variable $:" do
it "can be changed via <<" do
$: << "foo"
$:.should include("foo")
+ ensure
+ $:.delete("foo")
end
it "is read-only" do
@@ -850,6 +852,14 @@ describe "Execution variable $:" do
$-I = []
}.should raise_error(NameError)
end
+
+ it "default $LOAD_PATH entries until sitelibdir included have @gem_prelude_index set" do
+ $:.should.include?(RbConfig::CONFIG['sitelibdir'])
+ idx = $:.index(RbConfig::CONFIG['sitelibdir'])
+
+ $:[idx..-1].all? { |p| p.instance_variable_defined?(:@gem_prelude_index) }.should be_true
+ $:[0...idx].all? { |p| !p.instance_variable_defined?(:@gem_prelude_index) }.should be_true
+ end
end
describe "Global variable $\"" do
diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c
index 6c4b66fc06..2670f24661 100644
--- a/spec/ruby/optional/capi/ext/object_spec.c
+++ b/spec/ruby/optional/capi/ext/object_spec.c
@@ -118,11 +118,14 @@ static VALUE so_rb_obj_call_init(VALUE self, VALUE object,
return Qnil;
}
+static VALUE so_rb_obj_class(VALUE self, VALUE obj) {
+ return rb_obj_class(obj);
+}
+
static VALUE so_rbobjclassname(VALUE self, VALUE obj) {
return rb_str_new2(rb_obj_classname(obj));
}
-
static VALUE object_spec_rb_obj_freeze(VALUE self, VALUE obj) {
return rb_obj_freeze(obj);
}
@@ -442,6 +445,7 @@ void Init_object_spec(void) {
rb_define_method(cls, "rb_obj_alloc", so_rb_obj_alloc, 1);
rb_define_method(cls, "rb_obj_dup", so_rb_obj_dup, 1);
rb_define_method(cls, "rb_obj_call_init", so_rb_obj_call_init, 3);
+ rb_define_method(cls, "rb_obj_class", so_rb_obj_class, 1);
rb_define_method(cls, "rb_obj_classname", so_rbobjclassname, 1);
rb_define_method(cls, "rb_obj_freeze", object_spec_rb_obj_freeze, 1);
rb_define_method(cls, "rb_obj_frozen_p", object_spec_rb_obj_frozen_p, 1);
diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb
index ab11367060..8791a4bc76 100644
--- a/spec/ruby/optional/capi/object_spec.rb
+++ b/spec/ruby/optional/capi/object_spec.rb
@@ -480,12 +480,31 @@ describe "CApiObject" do
end
end
+ describe "rb_obj_class" do
+ it "returns the class of an object" do
+ @o.rb_obj_class(nil).should == NilClass
+ @o.rb_obj_class(0).should == Integer
+ @o.rb_obj_class(0.1).should == Float
+ @o.rb_obj_class(ObjectTest.new).should == ObjectTest
+ end
+
+ it "does not return the singleton class if it exists" do
+ o = ObjectTest.new
+ o.singleton_class
+ @o.rb_obj_class(o).should equal ObjectTest
+ end
+ end
+
describe "rb_obj_classname" do
it "returns the class name of an object" do
@o.rb_obj_classname(nil).should == 'NilClass'
@o.rb_obj_classname(0).should == 'Integer'
@o.rb_obj_classname(0.1).should == 'Float'
@o.rb_obj_classname(ObjectTest.new).should == 'ObjectTest'
+
+ o = ObjectTest.new
+ o.singleton_class
+ @o.rb_obj_classname(o).should == 'ObjectTest'
end
end
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 0cf22e0287..9291630ace 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -611,7 +611,9 @@ describe "C-API String function" do
filename = fixture(__FILE__, "read.txt")
str = ""
capacities = @s.RSTRING_PTR_read(str, filename)
- capacities.should == [30, 53]
+ capacities[0].should >= 30
+ capacities[1].should >= 53
+ capacities[0].should < capacities[1]
str.should == "fixture file contents to test read() with RSTRING_PTR"
end
end
diff --git a/spec/ruby/shared/rational/minus.rb b/spec/ruby/shared/rational/minus.rb
deleted file mode 100644
index 0a0946fdb9..0000000000
--- a/spec/ruby/shared/rational/minus.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../spec_helper'
-
-describe :rational_minus_rat, shared: true do
- it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4))
- (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2))
-
- (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4))
- end
-end
-
-describe :rational_minus_int, shared: true do
- it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) - 1).should eql(Rational(-1, 4))
- (Rational(3, 4) - 2).should eql(Rational(-5, 4))
- end
-end
-
-describe :rational_minus_float, shared: true do
- it "returns the result of subtracting other from self as a Float" do
- (Rational(3, 4) - 0.2).should eql(0.55)
- (Rational(3, 4) - 2.5).should eql(-1.75)
- end
-end
-
-describe :rational_minus, shared: true do
- it "calls #coerce on the passed argument with self" do
- rational = Rational(3, 4)
- obj = mock("Object")
- obj.should_receive(:coerce).with(rational).and_return([1, 2])
-
- rational - obj
- end
-
- it "calls #- on the coerced Rational with the coerced Object" do
- rational = Rational(3, 4)
-
- coerced_rational = mock("Coerced Rational")
- coerced_rational.should_receive(:-).and_return(:result)
-
- coerced_obj = mock("Coerced Object")
-
- obj = mock("Object")
- obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
-
- (rational - obj).should == :result
- end
-end