summaryrefslogtreecommitdiff
path: root/spec/ruby/core
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core')
-rw-r--r--spec/ruby/core/array/drop_spec.rb18
-rw-r--r--spec/ruby/core/class/to_s_spec.rb23
-rw-r--r--spec/ruby/core/data/constants_spec.rb15
-rw-r--r--spec/ruby/core/env/assoc_spec.rb2
-rw-r--r--spec/ruby/core/env/delete_spec.rb6
-rw-r--r--spec/ruby/core/env/each_key_spec.rb2
-rw-r--r--spec/ruby/core/env/each_value_spec.rb2
-rw-r--r--spec/ruby/core/env/index_spec.rb6
-rw-r--r--spec/ruby/core/env/keys_spec.rb4
-rw-r--r--spec/ruby/core/env/rehash_spec.rb6
-rw-r--r--spec/ruby/core/env/replace_spec.rb50
-rw-r--r--spec/ruby/core/env/shared/to_hash.rb13
-rw-r--r--spec/ruby/core/env/shared/update.rb44
-rw-r--r--spec/ruby/core/env/to_a_spec.rb5
-rw-r--r--spec/ruby/core/env/to_h_spec.rb5
-rw-r--r--spec/ruby/core/env/values_at_spec.rb28
-rw-r--r--spec/ruby/core/env/values_spec.rb9
-rw-r--r--spec/ruby/core/exception/args_spec.rb5
-rw-r--r--spec/ruby/core/exception/arguments_spec.rb11
-rw-r--r--spec/ruby/core/exception/backtrace_spec.rb12
-rw-r--r--spec/ruby/core/exception/case_compare_spec.rb36
-rw-r--r--spec/ruby/core/exception/destination_encoding_name_spec.rb18
-rw-r--r--spec/ruby/core/exception/destination_encoding_spec.rb18
-rw-r--r--spec/ruby/core/exception/error_bytes_spec.rb9
-rw-r--r--spec/ruby/core/exception/error_char_spec.rb9
-rw-r--r--spec/ruby/core/exception/exception_spec.rb54
-rw-r--r--spec/ruby/core/exception/hierarchy_spec.rb62
-rw-r--r--spec/ruby/core/exception/interrupt_spec.rb6
-rw-r--r--spec/ruby/core/exception/readagain_bytes_spec.rb9
-rw-r--r--spec/ruby/core/exception/script_error_spec.rb15
-rw-r--r--spec/ruby/core/exception/signal_exception_spec.rb51
-rw-r--r--spec/ruby/core/exception/source_encoding_name_spec.rb18
-rw-r--r--spec/ruby/core/exception/source_encoding_spec.rb18
-rw-r--r--spec/ruby/core/exception/standard_error_spec.rb61
-rw-r--r--spec/ruby/core/exception/system_call_error_spec.rb69
-rw-r--r--spec/ruby/core/exception/to_s_spec.rb16
-rw-r--r--spec/ruby/core/file/ftype_spec.rb5
-rw-r--r--spec/ruby/core/file/lutime_spec.rb40
-rw-r--r--spec/ruby/core/file/open_spec.rb8
-rw-r--r--spec/ruby/core/float/comparison_spec.rb32
-rw-r--r--spec/ruby/core/integer/constants_spec.rb25
-rw-r--r--spec/ruby/core/io/popen_spec.rb41
-rw-r--r--spec/ruby/core/kernel/rand_spec.rb10
-rw-r--r--spec/ruby/core/kernel/shared/load.rb36
-rw-r--r--spec/ruby/core/marshal/dump_spec.rb6
-rw-r--r--spec/ruby/core/marshal/shared/load.rb13
-rw-r--r--spec/ruby/core/matchdata/allocate_spec.rb10
-rw-r--r--spec/ruby/core/matchdata/dup_spec.rb14
-rw-r--r--spec/ruby/core/matchdata/regexp_spec.rb6
-rw-r--r--spec/ruby/core/module/autoload_spec.rb21
-rw-r--r--spec/ruby/core/module/fixtures/autoload_self_during_require.rb5
-rw-r--r--spec/ruby/core/module/fixtures/classes.rb3
-rw-r--r--spec/ruby/core/module/fixtures/multi/foo.rb6
-rw-r--r--spec/ruby/core/module/fixtures/multi/foo/bar_baz.rb11
-rw-r--r--spec/ruby/core/module/shared/set_visibility.rb17
-rw-r--r--spec/ruby/core/module/to_s_spec.rb31
-rw-r--r--spec/ruby/core/module/undef_method_spec.rb33
-rw-r--r--spec/ruby/core/process/clock_getres_spec.rb5
-rw-r--r--spec/ruby/core/process/clock_gettime_spec.rb93
-rw-r--r--spec/ruby/core/process/exec_spec.rb33
-rw-r--r--spec/ruby/core/process/fixtures/common.rb8
-rw-r--r--spec/ruby/core/process/status/equal_value_spec.rb12
-rw-r--r--spec/ruby/core/process/status/exitstatus_spec.rb2
-rw-r--r--spec/ruby/core/process/status/termsig_spec.rb8
-rw-r--r--spec/ruby/core/process/status/to_i_spec.rb10
-rw-r--r--spec/ruby/core/process/times_spec.rb26
-rw-r--r--spec/ruby/core/process/tms/cstime_spec.rb9
-rw-r--r--spec/ruby/core/process/tms/cutime_spec.rb9
-rw-r--r--spec/ruby/core/process/tms/element_reference_spec.rb5
-rw-r--r--spec/ruby/core/process/tms/members_spec.rb5
-rw-r--r--spec/ruby/core/process/tms/new_spec.rb5
-rw-r--r--spec/ruby/core/process/tms/stime_spec.rb9
-rw-r--r--spec/ruby/core/process/tms/utime_spec.rb9
-rw-r--r--spec/ruby/core/regexp/match_spec.rb4
-rw-r--r--spec/ruby/core/struct/clone_spec.rb7
-rw-r--r--spec/ruby/core/struct/dup_spec.rb3
-rw-r--r--spec/ruby/core/struct/instance_variable_get_spec.rb16
-rw-r--r--spec/ruby/core/struct/new_spec.rb25
-rw-r--r--spec/ruby/core/struct/shared/dup.rb9
-rw-r--r--spec/ruby/core/time/new_spec.rb6
80 files changed, 1097 insertions, 329 deletions
diff --git a/spec/ruby/core/array/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb
index 89b8534af4..84ea86b04c 100644
--- a/spec/ruby/core/array/drop_spec.rb
+++ b/spec/ruby/core/array/drop_spec.rb
@@ -30,4 +30,22 @@ describe "Array#drop" do
ary.shift
ary.drop(1).should == [2]
end
+
+ it "tries to convert the passed argument to an Integer using #to_int" do
+ obj = mock("to_int")
+ obj.should_receive(:to_int).and_return(2)
+
+ [1, 2, 3].drop(obj).should == [3]
+ end
+
+ it "raises a TypeError when the passed argument can't be coerced to Integer" do
+ -> { [1, 2].drop("cat") }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError when the passed argument isn't an integer and #to_int returns non-Integer" do
+ obj = mock("to_int")
+ obj.should_receive(:to_int).and_return("cat")
+
+ -> { [1, 2].drop(obj) }.should raise_error(TypeError)
+ end
end
diff --git a/spec/ruby/core/class/to_s_spec.rb b/spec/ruby/core/class/to_s_spec.rb
deleted file mode 100644
index 2055593a03..0000000000
--- a/spec/ruby/core/class/to_s_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-describe "Class#to_s" do
- it 'regular class returns same name as Module#to_s' do
- String.to_s.should == 'String'
- end
-
- describe 'singleton class' do
- it 'for modules includes module name' do
- CoreClassSpecs.singleton_class.to_s.should == '#<Class:CoreClassSpecs>'
- end
-
- it 'for classes includes class name' do
- CoreClassSpecs::Record.singleton_class.to_s.should == '#<Class:CoreClassSpecs::Record>'
- end
-
- it 'for objects includes class name and object ID' do
- obj = CoreClassSpecs::Record.new
- obj.singleton_class.to_s.should =~ /#<Class:#<CoreClassSpecs::Record:0x[0-9a-f]+>>/
- end
- end
-end
diff --git a/spec/ruby/core/data/constants_spec.rb b/spec/ruby/core/data/constants_spec.rb
new file mode 100644
index 0000000000..1b4c0d2df3
--- /dev/null
+++ b/spec/ruby/core/data/constants_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+describe "Data" do
+ it "is a subclass of Object" do
+ suppress_warning do
+ Data.superclass.should == Object
+ end
+ end
+
+ ruby_version_is "2.5" do
+ it "is deprecated" do
+ -> { Data }.should complain(/constant ::Data is deprecated/)
+ end
+ end
+end
diff --git a/spec/ruby/core/env/assoc_spec.rb b/spec/ruby/core/env/assoc_spec.rb
index 9946e328a9..c7a388db75 100644
--- a/spec/ruby/core/env/assoc_spec.rb
+++ b/spec/ruby/core/env/assoc_spec.rb
@@ -26,6 +26,6 @@ describe "ENV.assoc" do
end
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> { ENV.assoc(Object.new) }.should raise_error(TypeError)
+ -> { ENV.assoc(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
end
diff --git a/spec/ruby/core/env/delete_spec.rb b/spec/ruby/core/env/delete_spec.rb
index e875df4aeb..b7fe1ee675 100644
--- a/spec/ruby/core/env/delete_spec.rb
+++ b/spec/ruby/core/env/delete_spec.rb
@@ -30,6 +30,12 @@ describe "ENV.delete" do
ScratchPad.recorded.should == "foo"
end
+ it "does not evaluate the block if the envirionment variable exists" do
+ ENV["foo"] = "bar"
+ ENV.delete("foo") { |name| fail "Should not happen" }
+ ENV["foo"].should == nil
+ end
+
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
-> { ENV.delete(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/each_key_spec.rb b/spec/ruby/core/env/each_key_spec.rb
index 5c5cf4f80e..0efcb09900 100644
--- a/spec/ruby/core/env/each_key_spec.rb
+++ b/spec/ruby/core/env/each_key_spec.rb
@@ -10,7 +10,7 @@ describe "ENV.each_key" do
ENV.clear
ENV["1"] = "3"
ENV["2"] = "4"
- ENV.each_key { |k| e << k }
+ ENV.each_key { |k| e << k }.should equal(ENV)
e.should include("1")
e.should include("2")
ensure
diff --git a/spec/ruby/core/env/each_value_spec.rb b/spec/ruby/core/env/each_value_spec.rb
index ea29b3a0d7..60d9f605d8 100644
--- a/spec/ruby/core/env/each_value_spec.rb
+++ b/spec/ruby/core/env/each_value_spec.rb
@@ -10,7 +10,7 @@ describe "ENV.each_value" do
ENV.clear
ENV["1"] = "3"
ENV["2"] = "4"
- ENV.each_value { |v| e << v }
+ ENV.each_value { |v| e << v }.should equal(ENV)
e.should include("3")
e.should include("4")
ensure
diff --git a/spec/ruby/core/env/index_spec.rb b/spec/ruby/core/env/index_spec.rb
index 04986a0421..43875f5a50 100644
--- a/spec/ruby/core/env/index_spec.rb
+++ b/spec/ruby/core/env/index_spec.rb
@@ -3,4 +3,10 @@ require_relative 'shared/key'
describe "ENV.index" do
it_behaves_like :env_key, :index
+
+ it "warns about deprecation" do
+ -> do
+ ENV.index("foo")
+ end.should complain(/warning: ENV.index is deprecated; use ENV.key/)
+ end
end
diff --git a/spec/ruby/core/env/keys_spec.rb b/spec/ruby/core/env/keys_spec.rb
index 3699b2c225..b074a8f7c7 100644
--- a/spec/ruby/core/env/keys_spec.rb
+++ b/spec/ruby/core/env/keys_spec.rb
@@ -2,8 +2,8 @@ require_relative '../../spec_helper'
describe "ENV.keys" do
- it "returns all the keys" do
- ENV.keys.sort.should == ENV.to_hash.keys.sort
+ it "returns an array of the keys" do
+ ENV.keys.should == ENV.to_hash.keys
end
it "returns the keys in the locale encoding" do
diff --git a/spec/ruby/core/env/rehash_spec.rb b/spec/ruby/core/env/rehash_spec.rb
index e724feaa39..3782e4b727 100644
--- a/spec/ruby/core/env/rehash_spec.rb
+++ b/spec/ruby/core/env/rehash_spec.rb
@@ -1 +1,7 @@
require_relative '../../spec_helper'
+
+describe "ENV.rehash" do
+ it "returns nil" do
+ ENV.rehash.should == nil
+ end
+end
diff --git a/spec/ruby/core/env/replace_spec.rb b/spec/ruby/core/env/replace_spec.rb
index 8837deea4a..9fc67643d1 100644
--- a/spec/ruby/core/env/replace_spec.rb
+++ b/spec/ruby/core/env/replace_spec.rb
@@ -1,15 +1,51 @@
require_relative '../../spec_helper'
describe "ENV.replace" do
+ before :each do
+ @orig = ENV.to_hash
+ ENV.delete("foo")
+ end
+
+ after :each do
+ ENV.replace(@orig)
+ end
it "replaces ENV with a Hash" do
- ENV["foo"] = "bar"
- e = ENV.reject { |k, v| k == "foo" }
- e["baz"] = "bam"
- ENV.replace e
- ENV["foo"].should == nil
- ENV["baz"].should == "bam"
- ENV.delete "baz"
+ ENV.replace("foo" => "0", "bar" => "1").should equal(ENV)
+ ENV.size.should == 2
+ ENV["foo"].should == "0"
+ ENV["bar"].should == "1"
+ end
+
+ it "raises TypeError if the argument is not a Hash" do
+ -> { ENV.replace(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into Hash")
+ ENV.to_hash.should == @orig
+ end
+
+ it "raises TypeError if a key is not a String" do
+ -> { ENV.replace(Object.new => "0") }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ ENV.to_hash.should == @orig
+ end
+
+ it "raises TypeError if a value is not a String" do
+ -> { ENV.replace("foo" => Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ ENV.to_hash.should == @orig
+ end
+
+ it "raises Errno::EINVAL when the key contains the '=' character" do
+ -> { ENV.replace("foo=" =>"bar") }.should raise_error(Errno::EINVAL)
+ end
+
+ it "raises Errno::EINVAL when the key is an empty string" do
+ -> { ENV.replace("" => "bar") }.should raise_error(Errno::EINVAL)
+ end
+
+ it "does not accept good data preceding an error" do
+ -> { ENV.replace("foo" => "1", Object.new => Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
+ it "does not accept good data following an error" do
+ -> { ENV.replace(Object.new => Object.new, "foo" => "0") }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ ENV.to_hash.should == @orig
+ end
end
diff --git a/spec/ruby/core/env/shared/to_hash.rb b/spec/ruby/core/env/shared/to_hash.rb
index 254054c14d..bfa5699e8d 100644
--- a/spec/ruby/core/env/shared/to_hash.rb
+++ b/spec/ruby/core/env/shared/to_hash.rb
@@ -1,10 +1,17 @@
describe :env_to_hash, shared: true do
+ before :each do
+ @saved_foo = ENV["foo"]
+ end
+
+ after :each do
+ ENV["foo"]= @saved_foo
+ end
+
it "returns the ENV as a hash" do
ENV["foo"] = "bar"
h = ENV.send(@method)
h.should be_an_instance_of(Hash)
h["foo"].should == "bar"
- ENV.delete "foo"
end
it "uses the locale encoding for keys" do
@@ -18,5 +25,9 @@ describe :env_to_hash, shared: true do
it "duplicates the ENV when converting to a Hash" do
h = ENV.send(@method)
h.should_not equal ENV
+ h.size.should == ENV.size
+ h.each_pair do |k, v|
+ ENV[k].should == v
+ end
end
end
diff --git a/spec/ruby/core/env/shared/update.rb b/spec/ruby/core/env/shared/update.rb
index 430cda5185..129a56544c 100644
--- a/spec/ruby/core/env/shared/update.rb
+++ b/spec/ruby/core/env/shared/update.rb
@@ -9,8 +9,8 @@ describe :env_update, shared: true do
ENV["bar"] = @saved_bar
end
- it "adds the parameter hash to ENV" do
- ENV.send @method, {"foo" => "0", "bar" => "1"}
+ it "adds the parameter hash to ENV, returning ENV" do
+ ENV.send(@method, "foo" => "0", "bar" => "1").should equal(ENV)
ENV["foo"].should == "0"
ENV["bar"].should == "1"
end
@@ -19,17 +19,43 @@ describe :env_update, shared: true do
ENV.send(@method, {"foo" => "0", "bar" => "1"}).should equal(ENV)
end
- it "yields key, the old value and the new value when replacing entries" do
+ it "yields key, the old value and the new value when replacing an entry" do
ENV.send @method, {"foo" => "0", "bar" => "3"}
a = []
ENV.send @method, {"foo" => "1", "bar" => "4"} do |key, old, new|
a << [key, old, new]
+ new
+ end
+ a[0].should == ["foo", "0", "1"]
+ a[1].should == ["bar", "3", "4"]
+ end
+
+ it "yields key, the old value and the new value when replacing an entry" do
+ ENV.send @method, {"foo" => "0", "bar" => "3"}
+ ENV.send @method, {"foo" => "1", "bar" => "4"} do |key, old, new|
(new.to_i + 1).to_s
end
ENV["foo"].should == "2"
ENV["bar"].should == "5"
- a[0].should == ["foo", "0", "1"]
- a[1].should == ["bar", "3", "4"]
+ end
+
+ ruby_version_is "2.7" do
+ # BUG: https://bugs.ruby-lang.org/issues/16192
+ it "does not evaluate the block when the name is new" do
+ ENV.delete("bar")
+ ENV.send @method, {"foo" => "0"}
+ ENV.send(@method, "bar" => "1") { |key, old, new| fail "Should not get here" }
+ ENV["bar"].should == "1"
+ end
+
+ # BUG: https://bugs.ruby-lang.org/issues/16192
+ it "does not use the block's return value as the value when the name is new" do
+ ENV.delete("bar")
+ ENV.send @method, {"foo" => "0"}
+ ENV.send(@method, "bar" => "1") { |key, old, new| "Should not use this value" }
+ ENV["foo"].should == "0"
+ ENV["bar"].should == "1"
+ end
end
it "returns ENV when block given" do
@@ -44,6 +70,14 @@ describe :env_update, shared: true do
-> { ENV.send @method, "foo" => Object.new }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
+ it "raises Errno::EINVAL when a name contains the '=' character" do
+ -> { ENV.send(@method, "foo=" => "bar") }.should raise_error(Errno::EINVAL)
+ end
+
+ it "raises Errno::EINVAL when a name is an empty string" do
+ -> { ENV.send(@method, "" => "bar") }.should raise_error(Errno::EINVAL)
+ end
+
it "updates good data preceding an error" do
ENV["foo"] = "0"
begin
diff --git a/spec/ruby/core/env/to_a_spec.rb b/spec/ruby/core/env/to_a_spec.rb
index ed290a48a5..25441eb029 100644
--- a/spec/ruby/core/env/to_a_spec.rb
+++ b/spec/ruby/core/env/to_a_spec.rb
@@ -3,11 +3,10 @@ require_relative '../../spec_helper'
describe "ENV.to_a" do
it "returns the ENV as an array" do
- ENV["foo"] = "bar"
a = ENV.to_a
a.is_a?(Array).should == true
- a.find { |e| e.first == "foo" }.should == ["foo", "bar"]
- ENV.delete "foo"
+ a.size.should == ENV.size
+ ENV.each_pair { |k, v| a.should include([k, v])}
end
it "returns the entries in the locale encoding" do
diff --git a/spec/ruby/core/env/to_h_spec.rb b/spec/ruby/core/env/to_h_spec.rb
index 81a17700e9..822167aa2b 100644
--- a/spec/ruby/core/env/to_h_spec.rb
+++ b/spec/ruby/core/env/to_h_spec.rb
@@ -19,6 +19,11 @@ describe "ENV.to_h" do
ENV.to_h { |k, v| [k, v.upcase] }.should == { 'a' => "B", 'c' => "D" }
end
+ it "does not require the array elements to be strings" do
+ ENV.replace("a" => "b", "c" => "d")
+ ENV.to_h { |k, v| [k.to_sym, v.to_sym] }.should == { :a => :b, :c => :d }
+ end
+
it "raises ArgumentError if block returns longer or shorter array" do
-> do
ENV.to_h { |k, v| [k, v.upcase, 1] }
diff --git a/spec/ruby/core/env/values_at_spec.rb b/spec/ruby/core/env/values_at_spec.rb
index 906d8b01f2..ee970e5f65 100644
--- a/spec/ruby/core/env/values_at_spec.rb
+++ b/spec/ruby/core/env/values_at_spec.rb
@@ -1,17 +1,37 @@
require_relative '../../spec_helper'
describe "ENV.values_at" do
+ before :each do
+ @saved_foo = ENV["foo"]
+ @saved_bar = ENV["bar"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ ENV["bar"] = @saved_bar
+ end
- it "returns an array of the values referenced by the parameters as keys" do
+ it "returns an array of the values corresponding to the given keys" do
ENV["foo"] = "oof"
ENV["bar"] = "rab"
- ENV.values_at.should == []
ENV.values_at("bar", "foo").should == ["rab", "oof"]
- ENV.delete "foo"
- ENV.delete "bar"
+ end
+
+ it "returns an empty array if no keys specified" do
+ ENV.values_at.should == []
+ end
+
+ it "returns nil for each key that is not a name" do
+ ENV["foo"] = "oof"
+ ENV["bar"] = "rab"
+ ENV.values_at("x", "bar", "y", "foo", "z").should == [nil, "rab", nil, "oof", nil]
end
it "uses the locale encoding" do
ENV.values_at(ENV.keys.first).first.encoding.should == Encoding.find('locale')
end
+
+ it "raises TypeError when a key is not coercible to String" do
+ -> { ENV.values_at("foo", Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
end
diff --git a/spec/ruby/core/env/values_spec.rb b/spec/ruby/core/env/values_spec.rb
index 2e4e69c23b..919d7ffb7c 100644
--- a/spec/ruby/core/env/values_spec.rb
+++ b/spec/ruby/core/env/values_spec.rb
@@ -3,14 +3,7 @@ require_relative '../../spec_helper'
describe "ENV.values" do
it "returns an array of the values" do
- orig = ENV.to_hash
- begin
- ENV.replace "a" => "b", "c" => "d"
- a = ENV.values
- a.sort.should == ["b", "d"]
- ensure
- ENV.replace orig
- end
+ ENV.values.should == ENV.to_hash.values
end
it "uses the locale encoding" do
diff --git a/spec/ruby/core/exception/args_spec.rb b/spec/ruby/core/exception/args_spec.rb
deleted file mode 100644
index 005c2dd198..0000000000
--- a/spec/ruby/core/exception/args_spec.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "NoMethodError#args" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/core/exception/arguments_spec.rb b/spec/ruby/core/exception/arguments_spec.rb
deleted file mode 100644
index 0b283e9a54..0000000000
--- a/spec/ruby/core/exception/arguments_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "ArgumentError" do
- it "is a subclass of StandardError" do
- StandardError.should be_ancestor_of(ArgumentError)
- end
-
- it "gives its own class name as message if it has no message" do
- ArgumentError.new.message.should == "ArgumentError"
- end
-end
diff --git a/spec/ruby/core/exception/backtrace_spec.rb b/spec/ruby/core/exception/backtrace_spec.rb
index 5e140f8d9b..2d6825180a 100644
--- a/spec/ruby/core/exception/backtrace_spec.rb
+++ b/spec/ruby/core/exception/backtrace_spec.rb
@@ -47,7 +47,7 @@ describe "Exception#backtrace" do
end
end
- it "produces a backtrace for an exception captured using $!" do
+ it "captures the backtrace for an exception into $!" do
exception = begin
raise
rescue RuntimeError
@@ -57,6 +57,16 @@ describe "Exception#backtrace" do
exception.backtrace.first.should =~ /backtrace_spec/
end
+ it "captures the backtrace for an exception into $@" do
+ backtrace = begin
+ raise
+ rescue RuntimeError
+ $@
+ end
+
+ backtrace.first.should =~ /backtrace_spec/
+ end
+
it "returns an Array that can be updated" do
begin
raise
diff --git a/spec/ruby/core/exception/case_compare_spec.rb b/spec/ruby/core/exception/case_compare_spec.rb
index a4c9eaa6bf..87b9dee3ca 100644
--- a/spec/ruby/core/exception/case_compare_spec.rb
+++ b/spec/ruby/core/exception/case_compare_spec.rb
@@ -1,5 +1,39 @@
require_relative '../../spec_helper'
describe "SystemCallError.===" do
- it "needs to be reviewed for spec completeness"
+ before :all do
+ @example_errno_class = Errno::EINVAL
+ @example_errno = @example_errno_class::Errno
+ end
+
+ it "returns true for an instance of the same class" do
+ Errno::EINVAL.should === Errno::EINVAL.new
+ end
+
+ it "returns true if errnos same" do
+ e = SystemCallError.new('foo', @example_errno)
+ @example_errno_class.===(e).should == true
+ end
+
+ it "returns false if errnos different" do
+ e = SystemCallError.new('foo', @example_errno + 1)
+ @example_errno_class.===(e).should == false
+ end
+
+ it "returns false if arg is not kind of SystemCallError" do
+ e = Object.new
+ @example_errno_class.===(e).should == false
+ end
+
+ it "returns true if receiver is generic and arg is kind of SystemCallError" do
+ unknown_error_number = Errno.constants.size
+ e = SystemCallError.new('foo', @example_errno)
+ SystemCallError.===(e).should == true
+ end
+
+ it "returns false if receiver is generic and arg is not kind of SystemCallError" do
+ unknown_error_number = Errno.constants.size
+ e = Object.new
+ SystemCallError.===(e).should == false
+ end
end
diff --git a/spec/ruby/core/exception/destination_encoding_name_spec.rb b/spec/ruby/core/exception/destination_encoding_name_spec.rb
index b6ffff8c9c..a9e6474974 100644
--- a/spec/ruby/core/exception/destination_encoding_name_spec.rb
+++ b/spec/ruby/core/exception/destination_encoding_name_spec.rb
@@ -1,9 +1,23 @@
require_relative '../../spec_helper'
describe "Encoding::UndefinedConversionError#destination_encoding_name" do
- it "needs to be reviewed for spec completeness"
+ it "returns the destination encoding name" do
+ ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::UndefinedConversionError => e
+ e.destination_encoding_name.should == "EUC-JP"
+ end
+ end
end
describe "Encoding::InvalidByteSequenceError#destination_encoding_name" do
- it "needs to be reviewed for spec completeness"
+ it "returns the destination encoding name" do
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::InvalidByteSequenceError => e
+ e.destination_encoding_name.should == "UTF-8"
+ end
+ end
end
diff --git a/spec/ruby/core/exception/destination_encoding_spec.rb b/spec/ruby/core/exception/destination_encoding_spec.rb
index c3ad0342a1..5709c31e55 100644
--- a/spec/ruby/core/exception/destination_encoding_spec.rb
+++ b/spec/ruby/core/exception/destination_encoding_spec.rb
@@ -1,9 +1,23 @@
require_relative '../../spec_helper'
describe "Encoding::UndefinedConversionError#destination_encoding" do
- it "needs to be reviewed for spec completeness"
+ it "returns the destination encoding" do
+ ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::UndefinedConversionError => e
+ e.destination_encoding.should == Encoding::EUC_JP
+ end
+ end
end
describe "Encoding::InvalidByteSequenceError#destination_encoding" do
- it "needs to be reviewed for spec completeness"
+ it "returns the destination encoding" do
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::InvalidByteSequenceError => e
+ e.destination_encoding.should == Encoding::UTF_8
+ end
+ end
end
diff --git a/spec/ruby/core/exception/error_bytes_spec.rb b/spec/ruby/core/exception/error_bytes_spec.rb
index 2a95bcfdf4..66dd4b62c1 100644
--- a/spec/ruby/core/exception/error_bytes_spec.rb
+++ b/spec/ruby/core/exception/error_bytes_spec.rb
@@ -1,5 +1,12 @@
require_relative '../../spec_helper'
describe "Encoding::InvalidByteSequenceError#error_bytes" do
- it "needs to be reviewed for spec completeness"
+ it "returns the error bytes" do
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::InvalidByteSequenceError => e
+ e.error_bytes.should == "\xA0".force_encoding("ASCII-8BIT")
+ end
+ end
end
diff --git a/spec/ruby/core/exception/error_char_spec.rb b/spec/ruby/core/exception/error_char_spec.rb
index c0256af03a..f95ae2a6ce 100644
--- a/spec/ruby/core/exception/error_char_spec.rb
+++ b/spec/ruby/core/exception/error_char_spec.rb
@@ -1,5 +1,12 @@
require_relative '../../spec_helper'
describe "Encoding::UndefinedConversionError#error_char" do
- it "needs to be reviewed for spec completeness"
+ it "returns the error char" do
+ ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::UndefinedConversionError => e
+ e.error_char.should == "\u00A0"
+ end
+ end
end
diff --git a/spec/ruby/core/exception/exception_spec.rb b/spec/ruby/core/exception/exception_spec.rb
index 3a01366920..d6f5283bd9 100644
--- a/spec/ruby/core/exception/exception_spec.rb
+++ b/spec/ruby/core/exception/exception_spec.rb
@@ -6,48 +6,6 @@ describe "Exception.exception" do
it_behaves_like :exception_new, :exception
end
-describe "Exception" do
- it "is a Class" do
- Exception.should be_kind_of(Class)
- end
-
- it "is a superclass of NoMemoryError" do
- Exception.should be_ancestor_of(NoMemoryError)
- end
-
- it "is a superclass of ScriptError" do
- Exception.should be_ancestor_of(ScriptError)
- end
-
- it "is a superclass of SignalException" do
- Exception.should be_ancestor_of(SignalException)
- end
-
- it "is a superclass of Interrupt" do
- SignalException.should be_ancestor_of(Interrupt)
- end
-
- it "is a superclass of StandardError" do
- Exception.should be_ancestor_of(StandardError)
- end
-
- it "is a superclass of SystemExit" do
- Exception.should be_ancestor_of(SystemExit)
- end
-
- it "is a superclass of SystemStackError" do
- Exception.should be_ancestor_of(SystemStackError)
- end
-
- it "is a superclass of SecurityError" do
- Exception.should be_ancestor_of(SecurityError)
- end
-
- it "is a superclass of EncodingError" do
- Exception.should be_ancestor_of(EncodingError)
- end
-end
-
describe "Exception#exception" do
it "returns self when passed no argument" do
e = RuntimeError.new
@@ -82,6 +40,18 @@ describe "Exception#exception" do
raised_second.should == caught_second
end
+ it "captures an exception into $!" do
+ exception = begin
+ raise
+ rescue RuntimeError
+ $!
+ end
+
+ exception.class.should == RuntimeError
+ exception.message.should == ""
+ exception.backtrace.first.should =~ /exception_spec/
+ end
+
class CustomArgumentError < StandardError
attr_reader :val
def initialize(val)
diff --git a/spec/ruby/core/exception/hierarchy_spec.rb b/spec/ruby/core/exception/hierarchy_spec.rb
new file mode 100644
index 0000000000..e52811c761
--- /dev/null
+++ b/spec/ruby/core/exception/hierarchy_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../spec_helper'
+
+describe "Exception" do
+ it "has the right class hierarchy" do
+ hierarchy = {
+ Exception => {
+ NoMemoryError => nil,
+ ScriptError => {
+ LoadError => nil,
+ NotImplementedError => nil,
+ SyntaxError => nil,
+ },
+ SecurityError => nil,
+ SignalException => {
+ Interrupt => nil,
+ },
+ StandardError => {
+ ArgumentError => {
+ UncaughtThrowError => nil,
+ },
+ EncodingError => nil,
+ FiberError => nil,
+ IOError => {
+ EOFError => nil,
+ },
+ IndexError => {
+ KeyError => nil,
+ StopIteration => {
+ ClosedQueueError => nil,
+ },
+ },
+ LocalJumpError => nil,
+ NameError => {
+ NoMethodError => nil,
+ },
+ RangeError => {
+ FloatDomainError => nil,
+ },
+ RegexpError => nil,
+ RuntimeError => nil,
+ SystemCallError => nil,
+ ThreadError => nil,
+ TypeError => nil,
+ ZeroDivisionError => nil,
+ },
+ SystemExit => nil,
+ SystemStackError => nil,
+ },
+ }
+ ruby_version_is "2.5" do
+ hierarchy[Exception][StandardError][RuntimeError] = {FrozenError => nil}
+ end
+ traverse = -> parent_class, parent_subclass_hash {
+ parent_subclass_hash.each do |child_class, child_subclass_hash|
+ child_class.class.should == Class
+ child_class.superclass.should == parent_class
+ traverse.call(child_class, child_subclass_hash) if child_subclass_hash
+ end
+ }
+ traverse.call(Object, hierarchy)
+ end
+end
diff --git a/spec/ruby/core/exception/interrupt_spec.rb b/spec/ruby/core/exception/interrupt_spec.rb
index bc01b7b703..14f294bec6 100644
--- a/spec/ruby/core/exception/interrupt_spec.rb
+++ b/spec/ruby/core/exception/interrupt_spec.rb
@@ -1,11 +1,5 @@
require_relative '../../spec_helper'
-describe "Interrupt" do
- it "is a subclass of SignalException" do
- Interrupt.superclass.should == SignalException
- end
-end
-
describe "Interrupt.new" do
it "returns an instance of interrupt with no message given" do
e = Interrupt.new
diff --git a/spec/ruby/core/exception/readagain_bytes_spec.rb b/spec/ruby/core/exception/readagain_bytes_spec.rb
index f7e8d9d1d3..0f1e24f1cf 100644
--- a/spec/ruby/core/exception/readagain_bytes_spec.rb
+++ b/spec/ruby/core/exception/readagain_bytes_spec.rb
@@ -1,5 +1,12 @@
require_relative '../../spec_helper'
describe "Encoding::InvalidByteSequenceError#readagain_bytes" do
- it "needs to be reviewed for spec completeness"
+ it "returns the next byte" do
+ begin
+ "abc\xa4def".encode("ISO-8859-1", "EUC-JP")
+ rescue Encoding::InvalidByteSequenceError => e
+ e.error_bytes.should == "\xA4".force_encoding("ASCII-8BIT")
+ e.readagain_bytes.should == 'd'
+ end
+ end
end
diff --git a/spec/ruby/core/exception/script_error_spec.rb b/spec/ruby/core/exception/script_error_spec.rb
deleted file mode 100644
index e33a5d3a58..0000000000
--- a/spec/ruby/core/exception/script_error_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "ScriptError" do
- it "is a superclass of LoadError" do
- ScriptError.should be_ancestor_of(LoadError)
- end
-
- it "is a superclass of NotImplementedError" do
- ScriptError.should be_ancestor_of(NotImplementedError)
- end
-
- it "is a superclass of SyntaxError" do
- ScriptError.should be_ancestor_of(SyntaxError)
- end
-end
diff --git a/spec/ruby/core/exception/signal_exception_spec.rb b/spec/ruby/core/exception/signal_exception_spec.rb
index e0b30236f7..e494e18cde 100644
--- a/spec/ruby/core/exception/signal_exception_spec.rb
+++ b/spec/ruby/core/exception/signal_exception_spec.rb
@@ -30,6 +30,12 @@ describe "SignalException.new" do
-> { SignalException.new("NONEXISTENT") }.should raise_error(ArgumentError)
end
+ ruby_version_is "2.6" do
+ it "raises an exception with an invalid first argument type" do
+ -> { SignalException.new(Object.new) }.should raise_error(ArgumentError)
+ end
+ end
+
it "takes a signal symbol without SIG prefix as the first argument" do
exc = SignalException.new(:INT)
exc.signo.should == Signal.list["INT"]
@@ -72,3 +78,48 @@ describe "rescuing SignalException" do
end
end
end
+
+describe "SignalException" do
+ it "can be rescued" do
+ ruby_exe(<<-RUBY)
+ begin
+ raise SignalException, 'SIGKILL'
+ rescue SignalException
+ exit(0)
+ end
+ exit(1)
+ RUBY
+
+ $?.exitstatus.should == 0
+ end
+
+ platform_is_not :windows do
+ it "runs after at_exit" do
+ output = ruby_exe(<<-RUBY)
+ at_exit do
+ puts "hello"
+ $stdout.flush
+ end
+
+ raise SignalException, 'SIGKILL'
+ RUBY
+
+ $?.termsig.should == Signal.list.fetch("KILL")
+ output.should == "hello\n"
+ end
+
+ it "cannot be trapped with Signal.trap" do
+ ruby_exe(<<-RUBY)
+ Signal.trap("PROF") {}
+ raise(SignalException, "PROF")
+ RUBY
+
+ $?.termsig.should == Signal.list.fetch("PROF")
+ end
+
+ it "self-signals for USR1" do
+ ruby_exe("raise(SignalException, 'USR1')")
+ $?.termsig.should == Signal.list.fetch('USR1')
+ end
+ end
+end
diff --git a/spec/ruby/core/exception/source_encoding_name_spec.rb b/spec/ruby/core/exception/source_encoding_name_spec.rb
index bd8bc359b6..6f5dbd01aa 100644
--- a/spec/ruby/core/exception/source_encoding_name_spec.rb
+++ b/spec/ruby/core/exception/source_encoding_name_spec.rb
@@ -1,9 +1,23 @@
require_relative '../../spec_helper'
describe "Encoding::UndefinedConversionError#source_encoding_name" do
- it "needs to be reviewed for spec completeness"
+ it "returns the source encoding name" do
+ ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::UndefinedConversionError => e
+ e.source_encoding_name.should == "UTF-8"
+ end
+ end
end
describe "Encoding::InvalidByteSequenceError#source_encoding_name" do
- it "needs to be reviewed for spec completeness"
+ it "returns the source encoding name" do
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::InvalidByteSequenceError => e
+ e.source_encoding_name.should == "EUC-JP"
+ end
+ end
end
diff --git a/spec/ruby/core/exception/source_encoding_spec.rb b/spec/ruby/core/exception/source_encoding_spec.rb
index 65ac98d791..fac38e75f4 100644
--- a/spec/ruby/core/exception/source_encoding_spec.rb
+++ b/spec/ruby/core/exception/source_encoding_spec.rb
@@ -1,9 +1,23 @@
require_relative '../../spec_helper'
describe "Encoding::UndefinedConversionError#source_encoding" do
- it "needs to be reviewed for spec completeness"
+ it "returns the source encoding" do
+ ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::UndefinedConversionError => e
+ e.source_encoding.should == Encoding::UTF_8
+ end
+ end
end
describe "Encoding::InvalidByteSequenceError#source_encoding" do
- it "needs to be reviewed for spec completeness"
+ it "returns the source encoding" do
+ ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
+ begin
+ ec.convert("\xa0")
+ rescue Encoding::InvalidByteSequenceError => e
+ e.source_encoding.should == Encoding::EUC_JP
+ end
+ end
end
diff --git a/spec/ruby/core/exception/standard_error_spec.rb b/spec/ruby/core/exception/standard_error_spec.rb
index 1b469b5090..17e98ce7f0 100644
--- a/spec/ruby/core/exception/standard_error_spec.rb
+++ b/spec/ruby/core/exception/standard_error_spec.rb
@@ -1,56 +1,23 @@
require_relative '../../spec_helper'
describe "StandardError" do
- it "is a superclass of ArgumentError" do
- StandardError.should be_ancestor_of(ArgumentError)
- end
-
- it "is a superclass of IOError" do
- StandardError.should be_ancestor_of(IOError)
- end
-
- it "is a superclass of IndexError" do
- StandardError.should be_ancestor_of(IndexError)
- end
-
- it "is a superclass of LocalJumpError" do
- StandardError.should be_ancestor_of(LocalJumpError)
- end
-
- it "is a superclass of NameError" do
- StandardError.should be_ancestor_of(NameError)
- end
-
- it "is a superclass of RangeError" do
- StandardError.should be_ancestor_of(RangeError)
- end
-
- it "is a superclass of RegexpError" do
- StandardError.should be_ancestor_of(RegexpError)
- end
-
- it "is a superclass of RuntimeError" do
- StandardError.should be_ancestor_of(RuntimeError)
- end
-
- it "is a superclass of SystemCallError" do
- StandardError.should be_ancestor_of(SystemCallError.new("").class)
- end
- it "is a superclass of ThreadError" do
- StandardError.should be_ancestor_of(ThreadError)
- end
-
- it "is a superclass of TypeError" do
- StandardError.should be_ancestor_of(TypeError)
+ it "rescues StandardError" do
+ begin
+ raise StandardError
+ rescue => exception
+ exception.class.should == StandardError
+ end
end
- it "is a superclass of ZeroDivisionError" do
- StandardError.should be_ancestor_of(ZeroDivisionError)
+ it "rescues subclass of StandardError" do
+ begin
+ raise RuntimeError
+ rescue => exception
+ exception.class.should == RuntimeError
+ end
end
- ruby_version_is '2.5' do
- it "is a superclass of FrozenError" do
- StandardError.should be_ancestor_of(FrozenError)
- end
+ it "does not rescue superclass of StandardError" do
+ -> { begin; raise Exception; rescue; end }.should raise_error(Exception)
end
end
diff --git a/spec/ruby/core/exception/system_call_error_spec.rb b/spec/ruby/core/exception/system_call_error_spec.rb
index c07c8af72c..c510ae440f 100644
--- a/spec/ruby/core/exception/system_call_error_spec.rb
+++ b/spec/ruby/core/exception/system_call_error_spec.rb
@@ -20,41 +20,82 @@ describe "SystemCallError" do
end
describe "SystemCallError.new" do
+ before :all do
+ @example_errno = Errno::EINVAL::Errno
+ @example_errno_class = Errno::EINVAL
+ @last_known_errno = Errno.constants.size - 1
+ @unknown_errno = Errno.constants.size
+ end
+
it "requires at least one argument" do
-> { SystemCallError.new }.should raise_error(ArgumentError)
end
it "accepts single Fixnum argument as errno" do
SystemCallError.new(-2**24).errno.should == -2**24
- SystemCallError.new(42).errno.should == 42
+ SystemCallError.new(-1).errno.should == -1
+ SystemCallError.new(0).errno.should == 0
+ SystemCallError.new(@last_known_errno).errno.should == @last_known_errno
+ SystemCallError.new(@unknown_errno).errno.should == @unknown_errno
SystemCallError.new(2**24).errno.should == 2**24
end
+ it "constructs a SystemCallError for an unknown error number" do
+ SystemCallError.new(-2**24).should be_an_instance_of(SystemCallError)
+ SystemCallError.new(-1).should be_an_instance_of(SystemCallError)
+ SystemCallError.new(@unknown_errno).should be_an_instance_of(SystemCallError)
+ SystemCallError.new(2**24).should be_an_instance_of(SystemCallError)
+ end
+
it "constructs the appropriate Errno class" do
- # EINVAL should be more or less mortable across the platforms,
- # so let's use it then.
- SystemCallError.new(22).should be_kind_of(SystemCallError)
- SystemCallError.new(22).should be_an_instance_of(Errno::EINVAL)
- SystemCallError.new(2**28).should be_an_instance_of(SystemCallError)
+ e = SystemCallError.new(@example_errno)
+ e.should be_kind_of(SystemCallError)
+ e.should be_an_instance_of(@example_errno_class)
end
it "accepts an optional custom message preceding the errno" do
- exc = SystemCallError.new("custom message", 22)
- exc.should be_an_instance_of(Errno::EINVAL)
- exc.errno.should == 22
- exc.message.should == "Invalid argument - custom message"
+ exc = SystemCallError.new("custom message", @example_errno)
+ exc.should be_an_instance_of(@example_errno_class)
+ exc.errno.should == @example_errno
+ exc.message.should == 'Invalid argument - custom message'
end
it "accepts an optional third argument specifying the location" do
- exc = SystemCallError.new("custom message", 22, "location")
- exc.should be_an_instance_of(Errno::EINVAL)
- exc.errno.should == 22
- exc.message.should == "Invalid argument @ location - custom message"
+ exc = SystemCallError.new("custom message", @example_errno, "location")
+ exc.should be_an_instance_of(@example_errno_class)
+ exc.errno.should == @example_errno
+ exc.message.should == 'Invalid argument @ location - custom message'
+ end
+
+ it "coerces location if it is not a String" do
+ e = SystemCallError.new('foo', 1, :not_a_string)
+ e.message.should =~ /@ not_a_string - foo/
end
it "returns an arity of -1 for the initialize method" do
SystemCallError.instance_method(:initialize).arity.should == -1
end
+
+ it "converts to Integer if errno is a Float" do
+ SystemCallError.new('foo', 2.0).should == SystemCallError.new('foo', 2)
+ SystemCallError.new('foo', 2.9).should == SystemCallError.new('foo', 2)
+ end
+
+ it "converts to Integer if errno is a Complex convertible to Integer" do
+ SystemCallError.new('foo', Complex(2.9, 0)).should == SystemCallError.new('foo', 2)
+ end
+
+ it "raises TypeError if message is not a String" do
+ -> { SystemCallError.new(:foo, 1) }.should raise_error(TypeError, /no implicit conversion of Symbol into String/)
+ end
+
+ it "raises TypeError if errno is not an Integer" do
+ -> { SystemCallError.new('foo', 'bar') }.should raise_error(TypeError, /no implicit conversion of String into Integer/)
+ end
+
+ it "raises RangeError if errno is a Complex not convertible to Integer" do
+ -> { SystemCallError.new('foo', Complex(2.9, 1)) }.should raise_error(RangeError, /can't convert/)
+ end
end
describe "SystemCallError#errno" do
diff --git a/spec/ruby/core/exception/to_s_spec.rb b/spec/ruby/core/exception/to_s_spec.rb
index 8570b18cfd..4c4c7ab432 100644
--- a/spec/ruby/core/exception/to_s_spec.rb
+++ b/spec/ruby/core/exception/to_s_spec.rb
@@ -19,5 +19,19 @@ describe "Exception#to_s" do
end
describe "NameError#to_s" do
- it "needs to be reviewed for spec completeness"
+ it "raises its own message for an undefined variable" do
+ begin
+ puts not_defined
+ rescue => exception
+ exception.message.should =~ /undefined local variable or method `not_defined'/
+ end
+ end
+
+ it "raises its own message for an undefined constant" do
+ begin
+ puts NotDefined
+ rescue => exception
+ exception.message.should =~ /uninitialized constant NotDefined/
+ end
+ end
end
diff --git a/spec/ruby/core/file/ftype_spec.rb b/spec/ruby/core/file/ftype_spec.rb
index 20e9af7e5f..8ff70baa80 100644
--- a/spec/ruby/core/file/ftype_spec.rb
+++ b/spec/ruby/core/file/ftype_spec.rb
@@ -12,8 +12,9 @@ describe "File.ftype" do
end
it "raises Errno::ENOENT if the file is not valid" do
- l = -> { File.ftype("/#{$$}#{Time.now.to_f}") }
- l.should raise_error(Errno::ENOENT)
+ -> {
+ File.ftype("/#{$$}#{Time.now.to_f}")
+ }.should raise_error(Errno::ENOENT)
end
it "returns a String" do
diff --git a/spec/ruby/core/file/lutime_spec.rb b/spec/ruby/core/file/lutime_spec.rb
new file mode 100644
index 0000000000..7449bc4389
--- /dev/null
+++ b/spec/ruby/core/file/lutime_spec.rb
@@ -0,0 +1,40 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "2.5" do
+ describe "File.lutime" do
+ platform_is_not :windows do
+ before :each do
+ @atime = Time.utc(2000)
+ @mtime = Time.utc(2001)
+ @file = tmp("specs_lutime_file")
+ @symlink = tmp("specs_lutime_symlink")
+ touch @file
+ File.symlink(@file, @symlink)
+ end
+
+ after :each do
+ rm_r @file, @symlink
+ end
+
+ it "sets the access and modification time for a regular file" do
+ File.lutime(@atime, @mtime, @file)
+ stat = File.stat(@file)
+ stat.atime.should == @atime
+ stat.mtime.should === @mtime
+ end
+
+ it "sets the access and modification time for a symlink" do
+ original = File.stat(@file)
+
+ File.lutime(@atime, @mtime, @symlink)
+ stat = File.lstat(@symlink)
+ stat.atime.should == @atime
+ stat.mtime.should === @mtime
+
+ file = File.stat(@file)
+ file.atime.should == original.atime
+ file.mtime.should == original.mtime
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/file/open_spec.rb b/spec/ruby/core/file/open_spec.rb
index 93f1972ac6..e3c5618795 100644
--- a/spec/ruby/core/file/open_spec.rb
+++ b/spec/ruby/core/file/open_spec.rb
@@ -623,6 +623,14 @@ describe "File.open" do
end
end
+ ruby_version_is "2.5" do
+ it "raises ArgumentError if mixing :newline and binary mode" do
+ -> {
+ File.open(@file, "rb", newline: :universal) {}
+ }.should raise_error(ArgumentError, "newline decorator with binary mode")
+ end
+ end
+
ruby_version_is "2.6" do
context "'x' flag" do
before :each do
diff --git a/spec/ruby/core/float/comparison_spec.rb b/spec/ruby/core/float/comparison_spec.rb
index 4205d95c83..2dc993a176 100644
--- a/spec/ruby/core/float/comparison_spec.rb
+++ b/spec/ruby/core/float/comparison_spec.rb
@@ -16,6 +16,38 @@ describe "Float#<=>" do
(1.0 <=> "1").should be_nil
end
+ it "compares using #coerce when argument is not a Float" do
+ klass = Class.new do
+ attr_reader :call_count
+ def coerce(other)
+ @call_count ||= 0
+ @call_count += 1
+ [other, 42.0]
+ end
+ end
+
+ coercible = klass.new
+ (2.33 <=> coercible).should == -1
+ (42.0 <=> coercible).should == 0
+ (43.0 <=> coercible).should == 1
+ coercible.call_count.should == 3
+ end
+
+ ruby_version_is "2.5" do
+ it "raises TypeError when #coerce misbehaves" do
+ klass = Class.new do
+ def coerce(other)
+ :incorrect
+ end
+ end
+
+ bad_coercible = klass.new
+ -> {
+ 4.2 <=> bad_coercible
+ }.should raise_error(TypeError, "coerce must return [x, y]")
+ end
+ end
+
# The 4 tests below are taken from matz's revision 23730 for Ruby trunk
#
it "returns 1 when self is Infinity and other is a Bignum" do
diff --git a/spec/ruby/core/integer/constants_spec.rb b/spec/ruby/core/integer/constants_spec.rb
new file mode 100644
index 0000000000..3b8b01e330
--- /dev/null
+++ b/spec/ruby/core/integer/constants_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+
+describe "Fixnum" do
+ it "is unified into Integer" do
+ suppress_warning do
+ Fixnum.should equal(Integer)
+ end
+ end
+
+ it "is deprecated" do
+ -> { Fixnum }.should complain(/constant ::Fixnum is deprecated/)
+ end
+end
+
+describe "Bignum" do
+ it "is unified into Integer" do
+ suppress_warning do
+ Bignum.should equal(Integer)
+ end
+ end
+
+ it "is deprecated" do
+ -> { Bignum }.should complain(/constant ::Bignum is deprecated/)
+ end
+end
diff --git a/spec/ruby/core/io/popen_spec.rb b/spec/ruby/core/io/popen_spec.rb
index 622b3a9394..4f873e61cd 100644
--- a/spec/ruby/core/io/popen_spec.rb
+++ b/spec/ruby/core/io/popen_spec.rb
@@ -1,13 +1,22 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative '../process/fixtures/common'
describe "IO.popen" do
+ ProcessSpecs.use_system_ruby(self)
+
before :each do
+ @fname = tmp("IO_popen_spec")
@io = nil
+ @var = "$FOO"
+ platform_is :windows do
+ @var = "%FOO%"
+ end
end
after :each do
- @io.close if @io
+ @io.close if @io and !@io.closed?
+ rm_r @fname
end
it "returns an open IO" do
@@ -16,27 +25,15 @@ describe "IO.popen" do
end
it "reads a read-only pipe" do
- @io = IO.popen(ruby_cmd('puts "foo"'), "r")
+ @io = IO.popen('echo foo', "r")
@io.read.should == "foo\n"
end
it "raises IOError when writing a read-only pipe" do
- @io = IO.popen(ruby_cmd('puts "foo"'), "r")
+ @io = IO.popen('echo foo', "r")
-> { @io.write('bar') }.should raise_error(IOError)
@io.read.should == "foo\n"
end
-end
-
-describe "IO.popen" do
- before :each do
- @fname = tmp("IO_popen_spec")
- @io = nil
- end
-
- after :each do
- @io.close if @io and !@io.closed?
- rm_r @fname
- end
it "sees an infinitely looping subprocess exit when read pipe is closed" do
io = IO.popen ruby_cmd('r = loop{puts "y"; 0} rescue 1; exit r'), 'r'
@@ -97,16 +94,6 @@ describe "IO.popen" do
mode.should_receive(:to_str).and_return("r")
@io = IO.popen(ruby_cmd('exit 0'), mode)
end
-end
-
-describe "IO.popen" do
- before :each do
- @io = nil
- end
-
- after :each do
- @io.close if @io
- end
describe "with a block" do
it "yields an open IO to the block" do
@@ -171,13 +158,13 @@ describe "IO.popen" do
context "with a leading ENV Hash" do
it "accepts a single String command" do
- IO.popen({"FOO" => "bar"}, ruby_cmd('puts ENV["FOO"]')) do |io|
+ IO.popen({"FOO" => "bar"}, "echo #{@var}") do |io|
io.read.should == "bar\n"
end
end
it "accepts a single String command, and an IO mode" do
- IO.popen({"FOO" => "bar"}, ruby_cmd('puts ENV["FOO"]'), "r") do |io|
+ IO.popen({"FOO" => "bar"}, "echo #{@var}", "r") do |io|
io.read.should == "bar\n"
end
end
diff --git a/spec/ruby/core/kernel/rand_spec.rb b/spec/ruby/core/kernel/rand_spec.rb
index 843b5d10a2..a82b4fba74 100644
--- a/spec/ruby/core/kernel/rand_spec.rb
+++ b/spec/ruby/core/kernel/rand_spec.rb
@@ -138,6 +138,16 @@ describe "Kernel.rand" do
rand(KernelSpecs::CustomRangeFloat.new(1.0)..KernelSpecs::CustomRangeFloat.new(42.0)).should be_an_instance_of(KernelSpecs::CustomRangeFloat)
rand(Time.now..Time.now).should be_an_instance_of(Time)
end
+
+ it "is random on boot" do
+ results = 2.times.map {
+ out = ruby_exe('p rand', options: '--disable-gems')
+ Float(out)
+ }
+ results.size.should == 2
+ # this is technically flaky, but very unlikely in a good distribution
+ results[0].should_not == results[1]
+ end
end
describe "Kernel#rand" do
diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb
index 14bf5f27da..120619abef 100644
--- a/spec/ruby/core/kernel/shared/load.rb
+++ b/spec/ruby/core/kernel/shared/load.rb
@@ -1,3 +1,5 @@
+main = self
+
describe :kernel_load, shared: true do
before :each do
CodeLoadingSpecs.spec_setup
@@ -95,13 +97,45 @@ describe :kernel_load, shared: true do
@object.load(path, true)
Object.const_defined?(:LoadSpecWrap).should be_false
+
+ wrap_module = ScratchPad.recorded[1]
+ wrap_module.should be_an_instance_of(Module)
end
it "allows referencing outside namespaces" do
path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
- ScratchPad.recorded.first.should be_an_instance_of(Class)
+ ScratchPad.recorded[0].should equal(String)
+ end
+
+ it "sets self as a copy of the top-level main" do
+ path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ @object.load(path, true)
+
+ top_level = ScratchPad.recorded[2]
+ top_level.to_s.should == "main"
+ top_level.method(:to_s).owner.should == top_level.singleton_class
+ top_level.should_not equal(main)
+ top_level.should be_an_instance_of(Object)
+ end
+
+ it "includes modules included in main's singleton class in self's class" do
+ mod = Module.new
+ main.extend(mod)
+
+ main_ancestors = main.singleton_class.ancestors[1..-1]
+ main_ancestors.first.should == mod
+
+ path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ @object.load(path, true)
+
+ top_level = ScratchPad.recorded[2]
+ top_level_ancestors = top_level.singleton_class.ancestors[-main_ancestors.size..-1]
+ top_level_ancestors.should == main_ancestors
+
+ wrap_module = ScratchPad.recorded[1]
+ top_level.singleton_class.ancestors.should == [top_level.singleton_class, wrap_module, *main_ancestors]
end
describe "with top-level methods" do
diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb
index 3a7a083dd8..fc78ca4ff9 100644
--- a/spec/ruby/core/marshal/dump_spec.rb
+++ b/spec/ruby/core/marshal/dump_spec.rb
@@ -473,6 +473,12 @@ describe "Marshal.dump" do
Marshal.dump(obj).should == "\x04\bo:\x0EException\a:\tmesg\"\bfoo:\abt[\x06\"\x12foo/bar.rb:10"
end
+ it "dumps instance variables if they exist" do
+ obj = Exception.new("foo")
+ obj.instance_variable_set(:@ivar, 1)
+ Marshal.dump(obj).should == "\x04\bo:\x0EException\b:\tmesg\"\bfoo:\abt0:\n@ivari\x06"
+ end
+
it "dumps the cause for the exception" do
exc = nil
begin
diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb
index b90a6a99ce..302d3d5bda 100644
--- a/spec/ruby/core/marshal/shared/load.rb
+++ b/spec/ruby/core/marshal/shared/load.rb
@@ -531,6 +531,19 @@ describe :marshal_load, shared: true do
loaded.message.should == obj.message
loaded.backtrace.should == obj.backtrace
end
+
+ it "loads an marshalled exception with ivars" do
+ s = 'hi'
+ arr = [:so, :so, s, s]
+ obj = Exception.new("foo")
+ obj.instance_variable_set :@arr, arr
+
+ loaded = Marshal.send(@method, "\x04\bo:\x0EException\b:\tmesg\"\bfoo:\abt0:\t@arr[\t:\aso;\t\"\ahi@\b")
+ new_arr = loaded.instance_variable_get :@arr
+
+ loaded.message.should == obj.message
+ new_arr.should == arr
+ end
end
describe "for an Object" do
diff --git a/spec/ruby/core/matchdata/allocate_spec.rb b/spec/ruby/core/matchdata/allocate_spec.rb
new file mode 100644
index 0000000000..9f3ada4018
--- /dev/null
+++ b/spec/ruby/core/matchdata/allocate_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+
+describe "MatchData.allocate" do
+ ruby_version_is "2.7" do
+ it "is undefined" do
+ # https://bugs.ruby-lang.org/issues/16294
+ -> { MatchData.allocate }.should raise_error(NoMethodError)
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/dup_spec.rb b/spec/ruby/core/matchdata/dup_spec.rb
new file mode 100644
index 0000000000..70877f07eb
--- /dev/null
+++ b/spec/ruby/core/matchdata/dup_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+
+describe "MatchData#dup" do
+ it "duplicates the match data" do
+ original = /ll/.match("hello")
+ original.instance_variable_set(:@custom_ivar, 42)
+ duplicate = original.dup
+
+ duplicate.instance_variable_get(:@custom_ivar).should == 42
+ original.regexp.should == duplicate.regexp
+ original.string.should == duplicate.string
+ original.offset(0).should == duplicate.offset(0)
+ end
+end
diff --git a/spec/ruby/core/matchdata/regexp_spec.rb b/spec/ruby/core/matchdata/regexp_spec.rb
index 7a4783434c..099b59c559 100644
--- a/spec/ruby/core/matchdata/regexp_spec.rb
+++ b/spec/ruby/core/matchdata/regexp_spec.rb
@@ -11,6 +11,12 @@ describe "MatchData#regexp" do
m.regexp.should == /hay/
end
+ it "returns the same Regexp used to match" do
+ r = /hay/
+ m = 'haystack'.match(r)
+ m.regexp.object_id.should == r.object_id
+ end
+
it "returns a Regexp for the result of gsub(String)" do
'he[[o'.gsub('[', ']')
$~.regexp.should == /\[/
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index df434e8e60..db95704cc7 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -652,6 +652,27 @@ describe "Module#autoload" do
ModuleSpecs::Autoload::AutoloadDuringRequire.should be_kind_of(Class)
end
+ it "does not call #require a second time and does not warn if feature sets and trigger autoload on itself" do
+ main = TOPLEVEL_BINDING.eval("self")
+ main.should_not_receive(:require)
+
+ -> {
+ Kernel.require fixture(__FILE__, "autoload_self_during_require.rb")
+ }.should_not complain(verbose: true)
+ ModuleSpecs::Autoload::AutoloadSelfDuringRequire.should be_kind_of(Class)
+ end
+
+ it "handles multiple autoloads in the same file" do
+ $LOAD_PATH.unshift(File.expand_path('../fixtures/multi', __FILE__))
+ begin
+ require 'foo/bar_baz'
+ ModuleSpecs::Autoload::Foo::Bar.should be_kind_of(Class)
+ ModuleSpecs::Autoload::Foo::Baz.should be_kind_of(Class)
+ ensure
+ $LOAD_PATH.shift
+ end
+ end
+
it "calls #to_path on non-string filenames" do
p = mock('path')
p.should_receive(:to_path).and_return @non_existent
diff --git a/spec/ruby/core/module/fixtures/autoload_self_during_require.rb b/spec/ruby/core/module/fixtures/autoload_self_during_require.rb
new file mode 100644
index 0000000000..f4a514a807
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/autoload_self_during_require.rb
@@ -0,0 +1,5 @@
+module ModuleSpecs::Autoload
+ autoload :AutoloadSelfDuringRequire, __FILE__
+ class AutoloadSelfDuringRequire
+ end
+end
diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb
index ef70eaf9cf..40777cdbbd 100644
--- a/spec/ruby/core/module/fixtures/classes.rb
+++ b/spec/ruby/core/module/fixtures/classes.rb
@@ -6,6 +6,9 @@ module ModuleSpecs
CONST = :plain_constant
+ class NamedClass
+ end
+
module PrivConstModule
PRIVATE_CONSTANT = 1
private_constant :PRIVATE_CONSTANT
diff --git a/spec/ruby/core/module/fixtures/multi/foo.rb b/spec/ruby/core/module/fixtures/multi/foo.rb
new file mode 100644
index 0000000000..549996f08f
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/multi/foo.rb
@@ -0,0 +1,6 @@
+module ModuleSpecs::Autoload
+ module Foo
+ autoload :Bar, 'foo/bar_baz'
+ autoload :Baz, 'foo/bar_baz'
+ end
+end
diff --git a/spec/ruby/core/module/fixtures/multi/foo/bar_baz.rb b/spec/ruby/core/module/fixtures/multi/foo/bar_baz.rb
new file mode 100644
index 0000000000..53d3849e1f
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/multi/foo/bar_baz.rb
@@ -0,0 +1,11 @@
+require 'foo'
+
+module ModuleSpecs::Autoload
+ module Foo
+ class Bar
+ end
+
+ class Baz
+ end
+ end
+end
diff --git a/spec/ruby/core/module/shared/set_visibility.rb b/spec/ruby/core/module/shared/set_visibility.rb
index c39d59e05d..a04b1a54a0 100644
--- a/spec/ruby/core/module/shared/set_visibility.rb
+++ b/spec/ruby/core/module/shared/set_visibility.rb
@@ -5,6 +5,23 @@ describe :set_visibility, shared: true do
Module.should have_private_instance_method(@method, false)
end
+ describe "with argument" do
+ it "does not clone method from the ancestor when setting to the same visibility in a child" do
+ visibility = @method
+ parent = Module.new {
+ def test_method; end
+ send(visibility, :test_method)
+ }
+
+ child = Module.new {
+ include parent
+ send(visibility, :test_method)
+ }
+
+ child.should_not send(:"have_#{visibility}_instance_method", :test_method, false)
+ end
+ end
+
describe "without arguments" do
it "sets visibility to following method definitions" do
visibility = @method
diff --git a/spec/ruby/core/module/to_s_spec.rb b/spec/ruby/core/module/to_s_spec.rb
index bebdcf6e1b..29f6ecf726 100644
--- a/spec/ruby/core/module/to_s_spec.rb
+++ b/spec/ruby/core/module/to_s_spec.rb
@@ -2,17 +2,44 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Module#to_s" do
+ it 'returns the name of the module if it has a name' do
+ Enumerable.to_s.should == 'Enumerable'
+ String.to_s.should == 'String'
+ end
+
it "returns the full constant path leading to the module" do
ModuleSpecs::LookupMod.to_s.should == "ModuleSpecs::LookupMod"
end
it "works with an anonymous module" do
m = Module.new
- m.to_s.should =~ /#<Module:0x[0-9a-f]+>/
+ m.to_s.should =~ /\A#<Module:0x\h+>\z/
end
it "works with an anonymous class" do
c = Class.new
- c.to_s.should =~ /#<Class:0x[0-9a-f]+>/
+ c.to_s.should =~ /\A#<Class:0x\h+>\z/
+ end
+
+ it 'for the singleton class of an object of an anonymous class' do
+ klass = Class.new
+ obj = klass.new
+ sclass = obj.singleton_class
+ sclass.to_s.should == "#<Class:#{obj}>"
+ sclass.to_s.should =~ /\A#<Class:#<#{klass}:0x\h+>>\z/
+ sclass.to_s.should =~ /\A#<Class:#<#<Class:0x\h+>:0x\h+>>\z/
+ end
+
+ it 'for a singleton class of a module includes the module name' do
+ ModuleSpecs.singleton_class.to_s.should == '#<Class:ModuleSpecs>'
+ end
+
+ it 'for a metaclass includes the class name' do
+ ModuleSpecs::NamedClass.singleton_class.to_s.should == '#<Class:ModuleSpecs::NamedClass>'
+ end
+
+ it 'for objects includes class name and object ID' do
+ obj = ModuleSpecs::NamedClass.new
+ obj.singleton_class.to_s.should =~ /\A#<Class:#<ModuleSpecs::NamedClass:0x\h+>>\z/
end
end
diff --git a/spec/ruby/core/module/undef_method_spec.rb b/spec/ruby/core/module/undef_method_spec.rb
index 9b2c9240f4..b101778962 100644
--- a/spec/ruby/core/module/undef_method_spec.rb
+++ b/spec/ruby/core/module/undef_method_spec.rb
@@ -56,8 +56,37 @@ describe "Module#undef_method" do
@module.send(:undef_method, :method_to_undef).should equal(@module)
end
- it "raises a NameError when passed a missing name" do
- -> { @module.send :undef_method, :not_exist }.should raise_error(NameError) { |e|
+ it "raises a NameError when passed a missing name for a module" do
+ -> { @module.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for module `#{@module}'/) { |e|
+ # a NameError and not a NoMethodError
+ e.class.should == NameError
+ }
+ end
+
+ it "raises a NameError when passed a missing name for a class" do
+ klass = Class.new
+ -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for class `#{klass}'/) { |e|
+ # a NameError and not a NoMethodError
+ e.class.should == NameError
+ }
+ end
+
+ it "raises a NameError when passed a missing name for a singleton class" do
+ klass = Class.new
+ obj = klass.new
+ sclass = obj.singleton_class
+
+ -> { sclass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for class `#{sclass}'/) { |e|
+ e.message.should include('`#<Class:#<#<Class:')
+
+ # a NameError and not a NoMethodError
+ e.class.should == NameError
+ }
+ end
+
+ it "raises a NameError when passed a missing name for a metaclass" do
+ klass = String.singleton_class
+ -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for class `String'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
diff --git a/spec/ruby/core/process/clock_getres_spec.rb b/spec/ruby/core/process/clock_getres_spec.rb
index 7112b0520a..f1ecb74010 100644
--- a/spec/ruby/core/process/clock_getres_spec.rb
+++ b/spec/ruby/core/process/clock_getres_spec.rb
@@ -8,10 +8,7 @@ describe "Process.clock_getres" do
# NOTE: Look at fixtures/clocks.rb for clock and OS-specific exclusions
ProcessSpecs.clock_constants_for_resolution_checks.each do |name, value|
it "matches the clock in practice for Process::#{name}" do
- times = []
- 10_000.times do
- times << Process.clock_gettime(value, :nanosecond)
- end
+ times = 10_000.times.map { Process.clock_gettime(value, :nanosecond) }
reported = Process.clock_getres(value, :nanosecond)
# The clock should not be more accurate than reported (times should be
diff --git a/spec/ruby/core/process/clock_gettime_spec.rb b/spec/ruby/core/process/clock_gettime_spec.rb
index d3f973d7ae..59e1406e02 100644
--- a/spec/ruby/core/process/clock_gettime_spec.rb
+++ b/spec/ruby/core/process/clock_gettime_spec.rb
@@ -41,4 +41,97 @@ describe "Process.clock_gettime" do
t2.should be_close(t1, TIME_TOLERANCE)
end
end
+
+ describe "supports the platform clocks mentioned in the documentation" do
+ it "CLOCK_REALTIME" do
+ Process.clock_gettime(Process::CLOCK_REALTIME).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_MONOTONIC" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC).should be_an_instance_of(Float)
+ end
+
+ # These specs need macOS 10.12+ / darwin 16+
+ guard_not -> { platform_is_not(:darwin) or RUBY_PLATFORM[/darwin\d+/].to_i >= 16 } do
+ platform_is :linux, :openbsd, :darwin do
+ it "CLOCK_PROCESS_CPUTIME_ID" do
+ Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :linux, :freebsd, :openbsd, :darwin do
+ it "CLOCK_THREAD_CPUTIME_ID" do
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :freebsd, :openbsd do
+ it "CLOCK_VIRTUAL" do
+ Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_PROF" do
+ Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_UPTIME" do
+ Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :linux, :darwin do
+ it "CLOCK_MONOTONIC_RAW" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :darwin do
+ it "CLOCK_MONOTONIC_RAW_APPROX" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW_APPROX).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_UPTIME_RAW and CLOCK_UPTIME_RAW_APPROX" do
+ Process.clock_gettime(Process::CLOCK_UPTIME_RAW).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :freebsd do
+ it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_SECOND" do
+ Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :linux do
+ it "CLOCK_REALTIME_COARSE and CLOCK_REALTIME_ALARM" do
+ Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_MONOTONIC_COARSE" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_BOOTTIME and CLOCK_BOOTTIME_ALARM" do
+ Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float)
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/process/exec_spec.rb b/spec/ruby/core/process/exec_spec.rb
index 848990c6dc..5a6e3fc1a4 100644
--- a/spec/ruby/core/process/exec_spec.rb
+++ b/spec/ruby/core/process/exec_spec.rb
@@ -200,9 +200,9 @@ describe "Process.exec" do
it "maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value" do
map_fd_fixture = fixture __FILE__, "map_fd.rb"
cmd = <<-EOC
- f = File.open("#{@name}", "w+")
+ f = File.open(#{@name.inspect}, "w+")
child_fd = f.fileno + 1
- File.open("#{@child_fd_file}", "w") { |io| io.print child_fd }
+ File.open(#{@child_fd_file.inspect}, "w") { |io| io.print child_fd }
Process.exec "#{ruby_cmd(map_fd_fixture)} \#{child_fd}", { child_fd => f }
EOC
@@ -212,6 +212,35 @@ describe "Process.exec" do
File.read(@name).should == "writing to fd: #{child_fd}"
end
+
+ it "lets the process after exec have specified file descriptor despite close_on_exec" do
+ map_fd_fixture = fixture __FILE__, "map_fd.rb"
+ cmd = <<-EOC
+ f = File.open(#{@name.inspect}, 'w+')
+ puts(f.fileno, f.close_on_exec?)
+ STDOUT.flush
+ Process.exec("#{ruby_cmd(map_fd_fixture)} \#{f.fileno}", f.fileno => f.fileno)
+ EOC
+
+ output = ruby_exe(cmd, escape: true)
+ child_fd, close_on_exec = output.split
+
+ child_fd.to_i.should > STDERR.fileno
+ close_on_exec.should == 'true'
+ File.read(@name).should == "writing to fd: #{child_fd}"
+ end
+
+ it "sets close_on_exec to false on specified fd even when it fails" do
+ cmd = <<-EOC
+ f = File.open(#{__FILE__.inspect}, 'r')
+ puts(f.close_on_exec?)
+ Process.exec('/', f.fileno => f.fileno) rescue nil
+ puts(f.close_on_exec?)
+ EOC
+
+ output = ruby_exe(cmd, escape: true)
+ output.split.should == ['true', 'false']
+ end
end
end
end
diff --git a/spec/ruby/core/process/fixtures/common.rb b/spec/ruby/core/process/fixtures/common.rb
index bdbf1e654b..f49513d262 100644
--- a/spec/ruby/core/process/fixtures/common.rb
+++ b/spec/ruby/core/process/fixtures/common.rb
@@ -3,11 +3,15 @@ module ProcessSpecs
if defined?(MSpecScript::SYSTEM_RUBY)
context.send(:before, :all) do
@ruby = ::RUBY_EXE
- Object.const_set(:RUBY_EXE, MSpecScript::SYSTEM_RUBY)
+ suppress_warning {
+ Object.const_set(:RUBY_EXE, MSpecScript::SYSTEM_RUBY)
+ }
end
context.send(:after, :all) do
- Object.const_set(:RUBY_EXE, @ruby)
+ suppress_warning {
+ Object.const_set(:RUBY_EXE, @ruby)
+ }
end
end
end
diff --git a/spec/ruby/core/process/status/equal_value_spec.rb b/spec/ruby/core/process/status/equal_value_spec.rb
index 9e9a2d0a2b..444ce1775b 100644
--- a/spec/ruby/core/process/status/equal_value_spec.rb
+++ b/spec/ruby/core/process/status/equal_value_spec.rb
@@ -1,5 +1,15 @@
require_relative '../../../spec_helper'
describe "Process::Status#==" do
- it "needs to be reviewed for spec completeness"
+ it "returns true when compared to the integer status of an exited child" do
+ ruby_exe("exit(29)")
+ $?.to_i.should == $?
+ $?.should == $?.to_i
+ end
+
+ it "returns true when compared to the integer status of a terminated child" do
+ ruby_exe("Process.kill(:KILL, $$); exit(29)")
+ $?.to_i.should == $?
+ $?.should == $?.to_i
+ end
end
diff --git a/spec/ruby/core/process/status/exitstatus_spec.rb b/spec/ruby/core/process/status/exitstatus_spec.rb
index cd46b2081f..d6c6965b9e 100644
--- a/spec/ruby/core/process/status/exitstatus_spec.rb
+++ b/spec/ruby/core/process/status/exitstatus_spec.rb
@@ -11,7 +11,7 @@ describe "Process::Status#exitstatus" do
describe "for a child that raised SignalException" do
before :each do
- ruby_exe("raise SignalException, 'SIGTERM'")
+ ruby_exe("Process.kill(:KILL, $$); exit(42)")
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb
index 1482d27146..204708bc1b 100644
--- a/spec/ruby/core/process/status/termsig_spec.rb
+++ b/spec/ruby/core/process/status/termsig_spec.rb
@@ -1,9 +1,7 @@
require_relative '../../../spec_helper'
describe "Process::Status#termsig" do
-
describe "for a child that exited normally" do
-
before :each do
ruby_exe("exit(0)")
end
@@ -26,26 +24,20 @@ describe "Process::Status#termsig" do
end
describe "for a child that was sent a signal" do
-
before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)")
end
platform_is_not :windows do
-
it "returns the signal" do
$?.termsig.should == Signal.list["KILL"]
end
-
end
platform_is :windows do
-
it "always returns nil" do
$?.termsig.should be_nil
end
-
end
-
end
end
diff --git a/spec/ruby/core/process/status/to_i_spec.rb b/spec/ruby/core/process/status/to_i_spec.rb
index 37b7bdb1e4..a284f64f86 100644
--- a/spec/ruby/core/process/status/to_i_spec.rb
+++ b/spec/ruby/core/process/status/to_i_spec.rb
@@ -1,5 +1,13 @@
require_relative '../../../spec_helper'
describe "Process::Status#to_i" do
- it "needs to be reviewed for spec completeness"
+ it "returns an integer when the child exits" do
+ ruby_exe('exit 48')
+ $?.to_i.should be_an_instance_of(Integer)
+ end
+
+ it "returns an integer when the child is signaled" do
+ ruby_exe('raise SignalException, "TERM"')
+ $?.to_i.should be_an_instance_of(Integer)
+ end
end
diff --git a/spec/ruby/core/process/times_spec.rb b/spec/ruby/core/process/times_spec.rb
index 07b4fa5c9f..f148954262 100644
--- a/spec/ruby/core/process/times_spec.rb
+++ b/spec/ruby/core/process/times_spec.rb
@@ -7,21 +7,19 @@ describe "Process.times" do
it "returns current cpu times" do
t = Process.times
+ user = t.utime
- # Do busy work for a wall-clock interval.
- start = Time.now
- 1 until (Time.now - start) > 0.5
+ 1 until Process.times.utime > user
+ Process.times.utime.should > user
+ end
- # Ensure times is larger. NOTE that there is no
- # guarantee of an upper bound since anything may be
- # happening at the OS level, so we ONLY check that at
- # least an interval has elapsed. Also, we are assuming
- # there is a correlation between wall clock time and
- # process time. In practice, there is an observed
- # discrepancy often 10% or greater. In other words,
- # this is a very fuzzy test.
- t2 = Process.times
- diff = (t2.utime + t2.stime) - (t.utime + t.stime)
- diff.should > 0
+ ruby_version_is "2.5" do
+ platform_is_not :windows do
+ it "uses getrusage when available to improve precision beyond milliseconds" do
+ times = 100.times.map { Process.times }
+ times.count { |t| ((t.utime * 1e6).to_i % 1000) > 0 }.should > 0
+ times.count { |t| ((t.stime * 1e6).to_i % 1000) > 0 }.should > 0
+ end
+ end
end
end
diff --git a/spec/ruby/core/process/tms/cstime_spec.rb b/spec/ruby/core/process/tms/cstime_spec.rb
deleted file mode 100644
index 207d4391c0..0000000000
--- a/spec/ruby/core/process/tms/cstime_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Process::Tms#cstime" do
- it "needs to be reviewed for spec completeness"
-end
-
-describe "Process::Tms#cstime=" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/core/process/tms/cutime_spec.rb b/spec/ruby/core/process/tms/cutime_spec.rb
deleted file mode 100644
index 390280f005..0000000000
--- a/spec/ruby/core/process/tms/cutime_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Process::Tms#cutime" do
- it "needs to be reviewed for spec completeness"
-end
-
-describe "Process::Tms#cutime=" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/core/process/tms/element_reference_spec.rb b/spec/ruby/core/process/tms/element_reference_spec.rb
deleted file mode 100644
index 84a34089ae..0000000000
--- a/spec/ruby/core/process/tms/element_reference_spec.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Process::Tms.[]" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/core/process/tms/members_spec.rb b/spec/ruby/core/process/tms/members_spec.rb
deleted file mode 100644
index 005a8baec1..0000000000
--- a/spec/ruby/core/process/tms/members_spec.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Process::Tms.members" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/core/process/tms/new_spec.rb b/spec/ruby/core/process/tms/new_spec.rb
deleted file mode 100644
index 9dd1f5a8f2..0000000000
--- a/spec/ruby/core/process/tms/new_spec.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Process::Tms.new" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/core/process/tms/stime_spec.rb b/spec/ruby/core/process/tms/stime_spec.rb
deleted file mode 100644
index 4104b625e2..0000000000
--- a/spec/ruby/core/process/tms/stime_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Process::Tms#stime" do
- it "needs to be reviewed for spec completeness"
-end
-
-describe "Process::Tms#stime=" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/core/process/tms/utime_spec.rb b/spec/ruby/core/process/tms/utime_spec.rb
deleted file mode 100644
index 28371590e9..0000000000
--- a/spec/ruby/core/process/tms/utime_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-
-describe "Process::Tms#utime" do
- it "needs to be reviewed for spec completeness"
-end
-
-describe "Process::Tms#utime=" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/core/regexp/match_spec.rb b/spec/ruby/core/regexp/match_spec.rb
index 0ce8347d2d..f31b893f5e 100644
--- a/spec/ruby/core/regexp/match_spec.rb
+++ b/spec/ruby/core/regexp/match_spec.rb
@@ -38,6 +38,10 @@ describe "Regexp#match" do
-> { Regexp.allocate.match('foo') }.should raise_error(TypeError)
end
+ it "raises TypeError on an uninitialized Regexp" do
+ -> { Regexp.allocate.match('foo'.encode("UTF-16LE")) }.should raise_error(TypeError)
+ end
+
describe "with [string, position]" do
describe "when given a positive position" do
it "matches the input at a given position" do
diff --git a/spec/ruby/core/struct/clone_spec.rb b/spec/ruby/core/struct/clone_spec.rb
new file mode 100644
index 0000000000..40c4d52d57
--- /dev/null
+++ b/spec/ruby/core/struct/clone_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/dup'
+
+describe "Struct-based class#clone" do
+ it_behaves_like :struct_dup, :clone
+end
diff --git a/spec/ruby/core/struct/dup_spec.rb b/spec/ruby/core/struct/dup_spec.rb
index cb54b7ceee..8b50c39014 100644
--- a/spec/ruby/core/struct/dup_spec.rb
+++ b/spec/ruby/core/struct/dup_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/dup'
describe "Struct-based class#dup" do
+ it_behaves_like :struct_dup, :dup
+
# From https://github.com/jruby/jruby/issues/3686
it "retains an included module in the ancestor chain for the struct's singleton class" do
klass = Struct.new(:foo)
diff --git a/spec/ruby/core/struct/instance_variable_get_spec.rb b/spec/ruby/core/struct/instance_variable_get_spec.rb
new file mode 100644
index 0000000000..e4a3ea87dc
--- /dev/null
+++ b/spec/ruby/core/struct/instance_variable_get_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Struct#instance_variable_get" do
+ it "returns nil for attributes" do
+ car = StructClasses::Car.new("Hugo", "Foo", "1972")
+ car.instance_variable_get(:@make).should be_nil
+ end
+
+ it "returns a user value for variables with the same name as attributes" do
+ car = StructClasses::Car.new("Hugo", "Foo", "1972")
+ car.instance_variable_set :@make, "explicit"
+ car.instance_variable_get(:@make).should == "explicit"
+ car.make.should == "Hugo"
+ end
+end
diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb
index f888106950..564c49af01 100644
--- a/spec/ruby/core/struct/new_spec.rb
+++ b/spec/ruby/core/struct/new_spec.rb
@@ -74,6 +74,10 @@ describe "Struct.new" do
end
end
+ it "raises ArgumentError when there is a duplicate member" do
+ -> { Struct.new(:foo, :foo) }.should raise_error(ArgumentError, "duplicate member: foo")
+ end
+
it "raises a TypeError if object is not a Symbol" do
obj = mock(':ruby')
def obj.to_sym() :ruby end
@@ -147,7 +151,6 @@ describe "Struct.new" do
context "keyword_init: true option" do
before :all do
@struct_with_kwa = Struct.new(:name, :legs, keyword_init: true)
- @struct_without_kwa = Struct.new(:name, :legs, keyword_init: false)
end
it "creates a class that accepts keyword arguments to initialize" do
@@ -156,6 +159,10 @@ describe "Struct.new" do
obj.legs.should == 4
end
+ it "raises when there is a duplicate member" do
+ -> { Struct.new(:foo, :foo, keyword_init: true) }.should raise_error(ArgumentError, "duplicate member: foo")
+ end
+
describe "new class instantiation" do
it "accepts arguments as hash as well" do
obj = @struct_with_kwa.new({name: "elefant", legs: 4})
@@ -163,6 +170,18 @@ describe "Struct.new" do
obj.legs.should == 4
end
+ it "allows missing arguments" do
+ obj = @struct_with_kwa.new(name: "elefant")
+ obj.name.should == "elefant"
+ obj.legs.should be_nil
+ end
+
+ it "allows no arguments" do
+ obj = @struct_with_kwa.new
+ obj.name.should be_nil
+ obj.legs.should be_nil
+ end
+
it "raises ArgumentError when passed not declared keyword argument" do
-> {
@struct_with_kwa.new(name: "elefant", legs: 4, foo: "bar")
@@ -184,6 +203,10 @@ describe "Struct.new" do
end
context "keyword_init: false option" do
+ before :all do
+ @struct_without_kwa = Struct.new(:name, :legs, keyword_init: false)
+ end
+
it "behaves like it does without :keyword_init option" do
obj = @struct_without_kwa.new("elefant", 4)
obj.name.should == "elefant"
diff --git a/spec/ruby/core/struct/shared/dup.rb b/spec/ruby/core/struct/shared/dup.rb
new file mode 100644
index 0000000000..994f3f443e
--- /dev/null
+++ b/spec/ruby/core/struct/shared/dup.rb
@@ -0,0 +1,9 @@
+describe :struct_dup, shared: true do
+ it "duplicates members" do
+ klass = Struct.new(:foo, :bar)
+ instance = klass.new(14, 2)
+ duped = instance.send(@method)
+ duped.foo.should == 14
+ duped.bar.should == 2
+ end
+end
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index dcdd83a085..01ee47faa1 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -113,6 +113,12 @@ describe "Time.new with a utc_offset argument" do
it "raises ArgumentError if the utc_offset argument is greater than or equal to 10e9" do
-> { Time.new(2000, 1, 1, 0, 0, 0, 1000000000) }.should raise_error(ArgumentError)
end
+
+ it "raises ArgumentError if the month is greater than 12" do
+ # For some reason MRI uses a different message for month in 13-15 and month>=16
+ -> { Time.new(2000, 13, 1, 0, 0, 0, "+01:00") }.should raise_error(ArgumentError, /(mon|argument) out of range/)
+ -> { Time.new(2000, 16, 1, 0, 0, 0, "+01:00") }.should raise_error(ArgumentError, "argument out of range")
+ end
end
ruby_version_is "2.6" do