aboutsummaryrefslogtreecommitdiffstats
path: root/spec/ruby/core
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core')
-rw-r--r--spec/ruby/core/array/at_spec.rb4
-rw-r--r--spec/ruby/core/array/intersection_spec.rb4
-rw-r--r--spec/ruby/core/array/max_spec.rb6
-rw-r--r--spec/ruby/core/array/min_spec.rb6
-rw-r--r--spec/ruby/core/array/pack/buffer_spec.rb52
-rw-r--r--spec/ruby/core/array/permutation_spec.rb2
-rw-r--r--spec/ruby/core/array/pop_spec.rb2
-rw-r--r--spec/ruby/core/array/shift_spec.rb2
-rw-r--r--spec/ruby/core/array/sum_spec.rb44
-rw-r--r--spec/ruby/core/bignum/bignum_spec.rb12
-rw-r--r--spec/ruby/core/complex/finite_spec.rb36
-rw-r--r--spec/ruby/core/complex/infinite_spec.rb34
-rw-r--r--spec/ruby/core/dir/empty_spec.rb33
-rw-r--r--spec/ruby/core/dir/glob_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/primitive_convert_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb6
-rw-r--r--spec/ruby/core/encoding/converter/putback_spec.rb3
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb2
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb2
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb2
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/any_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/cycle_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/drop_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/uniq_spec.rb65
-rw-r--r--spec/ruby/core/enumerator/lazy/force_spec.rb2
-rw-r--r--spec/ruby/core/false/dup_spec.rb9
-rw-r--r--spec/ruby/core/file/empty_spec.rb15
-rw-r--r--spec/ruby/core/file/readlink_spec.rb23
-rw-r--r--spec/ruby/core/file/shared/fnmatch.rb10
-rw-r--r--spec/ruby/core/fixnum/fixnum_spec.rb12
-rw-r--r--spec/ruby/core/float/ceil_spec.rb10
-rw-r--r--spec/ruby/core/float/dup_spec.rb10
-rw-r--r--spec/ruby/core/float/floor_spec.rb10
-rw-r--r--spec/ruby/core/float/round_spec.rb14
-rw-r--r--spec/ruby/core/float/truncate_spec.rb10
-rw-r--r--spec/ruby/core/hash/delete_spec.rb4
-rw-r--r--spec/ruby/core/hash/transform_values_spec.rb21
-rw-r--r--spec/ruby/core/integer/ceil_spec.rb15
-rw-r--r--spec/ruby/core/integer/digits_spec.rb34
-rw-r--r--spec/ruby/core/integer/dup_spec.rb10
-rw-r--r--spec/ruby/core/integer/floor_spec.rb15
-rw-r--r--spec/ruby/core/integer/integer_spec.rb7
-rw-r--r--spec/ruby/core/integer/round_spec.rb48
-rw-r--r--spec/ruby/core/integer/shared/integer_rounding.rb31
-rw-r--r--spec/ruby/core/integer/sqrt_spec.rb33
-rw-r--r--spec/ruby/core/integer/truncate_spec.rb15
-rw-r--r--spec/ruby/core/io/advise_spec.rb2
-rw-r--r--spec/ruby/core/io/fixtures/classes.rb12
-rw-r--r--spec/ruby/core/io/gets_spec.rb10
-rw-r--r--spec/ruby/core/io/readline_spec.rb8
-rw-r--r--spec/ruby/core/io/shared/each.rb9
-rw-r--r--spec/ruby/core/io/shared/readlines.rb7
-rw-r--r--spec/ruby/core/kernel/equal_value_spec.rb6
-rw-r--r--spec/ruby/core/main/fixtures/classes.rb3
-rw-r--r--spec/ruby/core/main/fixtures/string_refinement.rb7
-rw-r--r--spec/ruby/core/main/fixtures/string_refinement_user.rb11
-rw-r--r--spec/ruby/core/main/using_spec.rb134
-rw-r--r--spec/ruby/core/module/fixtures/refine.rb13
-rw-r--r--spec/ruby/core/module/fixtures/using.rb10
-rw-r--r--spec/ruby/core/module/refine_spec.rb616
-rw-r--r--spec/ruby/core/module/using_spec.rb276
-rw-r--r--spec/ruby/core/mutex/lock_spec.rb11
-rw-r--r--spec/ruby/core/nil/dup_spec.rb9
-rw-r--r--spec/ruby/core/numeric/coerce_spec.rb2
-rw-r--r--spec/ruby/core/numeric/finite_spec.rb10
-rw-r--r--spec/ruby/core/numeric/infinite_spec.rb10
-rw-r--r--spec/ruby/core/process/wait2_spec.rb5
-rw-r--r--spec/ruby/core/random/bytes_spec.rb4
-rw-r--r--spec/ruby/core/string/capitalize_spec.rb8
-rw-r--r--spec/ruby/core/string/casecmp_spec.rb74
-rw-r--r--spec/ruby/core/string/downcase_spec.rb8
-rw-r--r--spec/ruby/core/string/lines_spec.rb9
-rw-r--r--spec/ruby/core/string/new_spec.rb7
-rw-r--r--spec/ruby/core/string/shared/chars.rb6
-rw-r--r--spec/ruby/core/string/shared/codepoints.rb2
-rw-r--r--spec/ruby/core/string/shared/each_line.rb14
-rw-r--r--spec/ruby/core/string/shared/to_sym.rb67
-rw-r--r--spec/ruby/core/string/swapcase_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack1_spec.rb12
-rw-r--r--spec/ruby/core/string/upcase_spec.rb9
-rw-r--r--spec/ruby/core/struct/initialize_spec.rb2
-rw-r--r--spec/ruby/core/symbol/capitalize_spec.rb7
-rw-r--r--spec/ruby/core/symbol/casecmp_spec.rb106
-rw-r--r--spec/ruby/core/symbol/downcase_spec.rb7
-rw-r--r--spec/ruby/core/symbol/dup_spec.rb9
-rw-r--r--spec/ruby/core/symbol/swapcase_spec.rb7
-rw-r--r--spec/ruby/core/symbol/upcase_spec.rb7
-rw-r--r--spec/ruby/core/thread/element_set_spec.rb8
-rw-r--r--spec/ruby/core/thread/fixtures/classes.rb7
-rw-r--r--spec/ruby/core/thread/join_spec.rb5
-rw-r--r--spec/ruby/core/thread/key_spec.rb2
-rw-r--r--spec/ruby/core/thread/raise_spec.rb6
-rw-r--r--spec/ruby/core/thread/report_on_exception_spec.rb102
-rw-r--r--spec/ruby/core/thread/shared/exit.rb2
-rw-r--r--spec/ruby/core/thread/value_spec.rb5
-rw-r--r--spec/ruby/core/time/shared/now.rb12
-rw-r--r--spec/ruby/core/time/shared/time_params.rb6
-rw-r--r--spec/ruby/core/tracepoint/callee_id_spec.rb20
-rw-r--r--spec/ruby/core/tracepoint/fixtures/classes.rb8
-rw-r--r--spec/ruby/core/true/dup_spec.rb9
-rw-r--r--spec/ruby/core/warning/warn_spec.rb60
102 files changed, 2367 insertions, 122 deletions
diff --git a/spec/ruby/core/array/at_spec.rb b/spec/ruby/core/array/at_spec.rb
index e40c26f2cc..f2af0e13a1 100644
--- a/spec/ruby/core/array/at_spec.rb
+++ b/spec/ruby/core/array/at_spec.rb
@@ -15,7 +15,7 @@ describe "Array#at" do
a.at(7).should == nil
end
- it "returns the (-n)'th elemet from the last, for the given negative index n" do
+ it "returns the (-n)'th element from the last, for the given negative index n" do
a = [1, 2, 3, 4, 5, 6]
a.at(-1).should == 6
a.at(-2).should == 5
@@ -50,7 +50,7 @@ describe "Array#at" do
lambda { [].at("cat") }.should raise_error(TypeError)
end
- it "raises an ArgumentError when 2 or more arguments is passed" do
+ it "raises an ArgumentError when 2 or more arguments are passed" do
lambda { [:a, :b].at(0,1) }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/array/intersection_spec.rb b/spec/ruby/core/array/intersection_spec.rb
index 4d6c2a12d3..e399509ea7 100644
--- a/spec/ruby/core/array/intersection_spec.rb
+++ b/spec/ruby/core/array/intersection_spec.rb
@@ -19,7 +19,7 @@ describe "Array#&" do
it "does not modify the original Array" do
a = [1, 1, 3, 5]
- a & [1, 2, 3]
+ (a & [1, 2, 3]).should == [1, 3]
a.should == [1, 1, 3, 5]
end
@@ -52,7 +52,7 @@ describe "Array#&" do
obj1.stub!(:hash).and_return(0)
obj2.stub!(:hash).and_return(0)
obj1.should_receive(:eql?).at_least(1).and_return(true)
- obj2.should_receive(:eql?).at_least(1).and_return(true)
+ obj2.stub!(:eql?).and_return(true)
([obj1] & [obj2]).should == [obj1]
([obj1, obj1, obj2, obj2] & [obj2]).should == [obj1]
diff --git a/spec/ruby/core/array/max_spec.rb b/spec/ruby/core/array/max_spec.rb
index cf6a48c2e3..db1d755645 100644
--- a/spec/ruby/core/array/max_spec.rb
+++ b/spec/ruby/core/array/max_spec.rb
@@ -1,6 +1,12 @@
require File.expand_path('../../../spec_helper', __FILE__)
describe "Array#max" do
+ ruby_version_is "2.4" do
+ it "is defined on Array" do
+ [1].method(:max).owner.should equal Array
+ end
+ end
+
it "returns nil with no values" do
[].max.should == nil
end
diff --git a/spec/ruby/core/array/min_spec.rb b/spec/ruby/core/array/min_spec.rb
index 53fe4e0692..59f3814da2 100644
--- a/spec/ruby/core/array/min_spec.rb
+++ b/spec/ruby/core/array/min_spec.rb
@@ -1,6 +1,12 @@
require File.expand_path('../../../spec_helper', __FILE__)
describe "Array#min" do
+ ruby_version_is "2.4" do
+ it "is defined on Array" do
+ [1].method(:max).owner.should equal Array
+ end
+ end
+
it "returns nil with no values" do
[].min.should == nil
end
diff --git a/spec/ruby/core/array/pack/buffer_spec.rb b/spec/ruby/core/array/pack/buffer_spec.rb
new file mode 100644
index 0000000000..928f7db731
--- /dev/null
+++ b/spec/ruby/core/array/pack/buffer_spec.rb
@@ -0,0 +1,52 @@
+# encoding: ascii-8bit
+
+require File.expand_path('../../../../spec_helper', __FILE__)
+
+ruby_version_is '2.4' do
+ describe "Aray#pack with `buffer` option" do
+ it "returns specified buffer" do
+ n = [ 65, 66, 67 ]
+ buffer = " "*3
+ result = n.pack("ccc", buffer: buffer) #=> "ABC"
+ result.should equal(buffer)
+ end
+
+ it "adds result at the end of buffer content" do
+ n = [ 65, 66, 67 ] # result without buffer is "ABC"
+
+ buffer = ""
+ n.pack("ccc", buffer: buffer).should == "ABC"
+
+ buffer = "123"
+ n.pack("ccc", buffer: buffer).should == "123ABC"
+
+ buffer = "12345"
+ n.pack("ccc", buffer: buffer).should == "12345ABC"
+ end
+
+ it "raises TypeError exception if buffer is not String" do
+ lambda { [65].pack("ccc", buffer: []) }.should raise_error(
+ TypeError, "buffer must be String, not Array")
+ end
+
+ context "offset (@) is specified" do
+ it 'keeps buffer content if it is longer than offset' do
+ n = [ 65, 66, 67 ]
+ buffer = "123456"
+ n.pack("@3ccc", buffer: buffer).should == "123ABC"
+ end
+
+ it "fills the gap with \0 if buffer content is shorter than offset" do
+ n = [ 65, 66, 67 ]
+ buffer = "123"
+ n.pack("@6ccc", buffer: buffer).should == "123\0\0\0ABC"
+ end
+
+ it 'does not keep buffer content if it is longer than offset + result' do
+ n = [ 65, 66, 67 ]
+ buffer = "1234567890"
+ n.pack("@3ccc", buffer: buffer).should == "123ABC"
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/array/permutation_spec.rb b/spec/ruby/core/array/permutation_spec.rb
index 8a80b93c3b..c0eba57a3e 100644
--- a/spec/ruby/core/array/permutation_spec.rb
+++ b/spec/ruby/core/array/permutation_spec.rb
@@ -52,7 +52,7 @@ describe "Array#permutation" do
end
it "returns no permutations when the given length has no permutations" do
- @numbers.permutation(9).entries.size == 0
+ @numbers.permutation(9).entries.size.should == 0
@numbers.permutation(9) { |n| @yielded << n }
@yielded.should == []
end
diff --git a/spec/ruby/core/array/pop_spec.rb b/spec/ruby/core/array/pop_spec.rb
index 313dc4189e..ea649c6585 100644
--- a/spec/ruby/core/array/pop_spec.rb
+++ b/spec/ruby/core/array/pop_spec.rb
@@ -119,7 +119,7 @@ describe "Array#pop" do
a.should == []
end
- it "raises a TypeError when the passed n can be coerced to Integer" do
+ it "raises a TypeError when the passed n cannot be coerced to Integer" do
lambda{ [1, 2].pop("cat") }.should raise_error(TypeError)
lambda{ [1, 2].pop(nil) }.should raise_error(TypeError)
end
diff --git a/spec/ruby/core/array/shift_spec.rb b/spec/ruby/core/array/shift_spec.rb
index e5d25e2050..a7b6f58392 100644
--- a/spec/ruby/core/array/shift_spec.rb
+++ b/spec/ruby/core/array/shift_spec.rb
@@ -104,7 +104,7 @@ describe "Array#shift" do
a.should == []
end
- it "raises a TypeError when the passed n can be coerced to Integer" do
+ it "raises a TypeError when the passed n cannot be coerced to Integer" do
lambda{ [1, 2].shift("cat") }.should raise_error(TypeError)
lambda{ [1, 2].shift(nil) }.should raise_error(TypeError)
end
diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb
new file mode 100644
index 0000000000..6548655c35
--- /dev/null
+++ b/spec/ruby/core/array/sum_spec.rb
@@ -0,0 +1,44 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is '2.4' do
+ describe "Array#sum" do
+ it "returns the sum of elements" do
+ [1, 2, 3].sum.should == 6
+ end
+
+ it "applies a block to each element before adding if it's given" do
+ [1, 2, 3].sum { |i| i * 10 }.should == 60
+ end
+
+ it "returns init value if array is empty" do
+ [].sum(-1).should == -1
+ end
+
+ it "returns 0 if array is empty and init is omitted" do
+ [].sum.should == 0
+ end
+
+ it "adds init value to the sum of elemens" do
+ [1, 2, 3].sum(10).should == 16
+ end
+
+ it "can be used for non-numeric objects by providing init value" do
+ ["a", "b", "c"].sum("").should == "abc"
+ end
+
+ it 'raises TypeError if any element are not numeric' do
+ lambda { ["a"].sum }.should raise_error(TypeError)
+ end
+
+ it 'raises TypeError if any element cannot be added to init value' do
+ lambda { [1].sum([]) }.should raise_error(TypeError)
+ end
+
+ it "calls + to sum the elements" do
+ a = mock("a")
+ b = mock("b")
+ a.should_receive(:+).with(b).and_return(42)
+ [b].sum(a).should == 42
+ end
+ end
+end
diff --git a/spec/ruby/core/bignum/bignum_spec.rb b/spec/ruby/core/bignum/bignum_spec.rb
index cf99bb4937..3df43aec2d 100644
--- a/spec/ruby/core/bignum/bignum_spec.rb
+++ b/spec/ruby/core/bignum/bignum_spec.rb
@@ -16,4 +16,16 @@ describe "Bignum" do
Bignum.new
end.should raise_error(NoMethodError)
end
+
+ ruby_version_is '2.4' do
+ it "unified into Integer" do
+ Bignum.should equal(Integer)
+ end
+
+ it "is deprecated" do
+ -> {
+ Bignum
+ }.should complain(/constant ::Bignum is deprecated/)
+ end
+ end
end
diff --git a/spec/ruby/core/complex/finite_spec.rb b/spec/ruby/core/complex/finite_spec.rb
new file mode 100644
index 0000000000..e9ee19bef3
--- /dev/null
+++ b/spec/ruby/core/complex/finite_spec.rb
@@ -0,0 +1,36 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.4" do
+ describe "Complex#finite?" do
+ it "returns true if magnitude is finite" do
+ (1+1i).finite?.should == true
+ end
+
+ it "returns false for positive infinity" do
+ value = Complex(Float::INFINITY, 42)
+ value.finite?.should == false
+ end
+
+ it "returns false for positive complex with infinite imaginary" do
+ value = Complex(1, Float::INFINITY)
+ value.finite?.should == false
+ end
+
+ it "returns false for negative infinity" do
+ value = -Complex(Float::INFINITY, 42)
+ value.finite?.should == false
+ end
+
+ it "returns false for negative complex with infinite imaginary" do
+ value = -Complex(1, Float::INFINITY)
+ value.finite?.should == false
+ end
+
+ ruby_bug "#14014", "2.4"..."2.5" do
+ it "returns false for NaN" do
+ value = Complex(Float::NAN, Float::NAN)
+ value.finite?.should == false
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/complex/infinite_spec.rb b/spec/ruby/core/complex/infinite_spec.rb
new file mode 100644
index 0000000000..79792c3169
--- /dev/null
+++ b/spec/ruby/core/complex/infinite_spec.rb
@@ -0,0 +1,34 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.4" do
+ describe "Complex#infinite?" do
+ it "returns nil if magnitude is finite" do
+ (1+1i).infinite?.should == nil
+ end
+
+ it "returns 1 for positive infinity" do
+ value = Complex(Float::INFINITY, 42).infinite?
+ value.should == 1
+ end
+
+ it "returns 1 for positive complex with infinite imaginary" do
+ value = Complex(1, Float::INFINITY).infinite?
+ value.should == 1
+ end
+
+ it "returns -1 for negative infinity" do
+ value = -Complex(Float::INFINITY, 42).infinite?
+ value.should == -1
+ end
+
+ it "returns -1 for negative complex with infinite imaginary" do
+ value = -Complex(1, Float::INFINITY).infinite?
+ value.should == -1
+ end
+
+ it "returns nil for NaN" do
+ value = Complex(0, Float::NAN).infinite?
+ value.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/core/dir/empty_spec.rb b/spec/ruby/core/dir/empty_spec.rb
new file mode 100644
index 0000000000..861a538f84
--- /dev/null
+++ b/spec/ruby/core/dir/empty_spec.rb
@@ -0,0 +1,33 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.4" do
+ describe "Dir.empty?" do
+ before :all do
+ @empty_dir = tmp("empty_dir")
+ mkdir_p @empty_dir
+ end
+
+ after :all do
+ rm_r @empty_dir
+ end
+
+ it "returns true for empty directories" do
+ result = Dir.empty? @empty_dir
+ result.should be_true
+ end
+
+ it "returns false for non-empty directories" do
+ result = Dir.empty? __dir__
+ result.should be_false
+ end
+
+ it "returns false for a non-directory" do
+ result = Dir.empty? __FILE__
+ result.should be_false
+ end
+
+ it "raises ENOENT for nonexistent directories" do
+ lambda { Dir.empty? tmp("nonexistent") }.should raise_error(Errno::ENOENT)
+ end
+ end
+end
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index b65b738b61..4a9230f8b3 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -68,7 +68,7 @@ describe "Dir.glob" do
Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected
end
- # This is a seperate case to check **/ coming after a constant
+ # This is a separate case to check **/ coming after a constant
# directory as well.
it "recursively matches any subdirectories except './' or '../' with '**/' and option File::FNM_DOTMATCH" do
expected = %w[
diff --git a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
index b9d6288bb2..ed479c6b13 100644
--- a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
@@ -89,7 +89,7 @@ with_feature :encoding do
@ec.primitive_convert("","",nil,nil, {after_output: true}).should == :finished
end
- it "sets the destination buffer's encoding to the destination encoding if the conversion suceeded" do
+ it "sets the destination buffer's encoding to the destination encoding if the conversion succeeded" do
dest = "".force_encoding('utf-8')
dest.encoding.should == Encoding::UTF_8
@ec.primitive_convert("\u{98}",dest).should == :finished
diff --git a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
index f92c95c6d5..cba654b9fe 100644
--- a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
@@ -16,15 +16,13 @@ with_feature :encoding do
it "returns [:source_buffer_empty,nil,nil,nil, nil] when #convert last succeeded" do
ec = Encoding::Converter.new('ascii','utf-8')
- ec.convert("a".force_encoding('ascii')).should == "a".\
- force_encoding('utf-8')
+ ec.convert("a".force_encoding('ascii')).should == "a".force_encoding('utf-8')
ec.primitive_errinfo.should == [:source_buffer_empty, nil, nil, nil, nil]
end
it "returns [:destination_buffer_full,nil,nil,nil,nil] when #primitive_convert last returned :destination_buffer_full" do
ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
- ec.primitive_convert("\u{9999}", "", 0, 0, partial_input: false) \
- .should == :destination_buffer_full
+ ec.primitive_convert("\u{9999}", "", 0, 0, partial_input: false).should == :destination_buffer_full
ec.primitive_errinfo.should == [:destination_buffer_full, nil, nil, nil, nil]
end
diff --git a/spec/ruby/core/encoding/converter/putback_spec.rb b/spec/ruby/core/encoding/converter/putback_spec.rb
index 69ce59e89b..3ed1ad9956 100644
--- a/spec/ruby/core/encoding/converter/putback_spec.rb
+++ b/spec/ruby/core/encoding/converter/putback_spec.rb
@@ -40,8 +40,7 @@ with_feature :encoding do
src = "\x00\xd8\x61\x00"
dst = ""
ec.primitive_convert(src, dst).should == :invalid_byte_sequence
- ec.primitive_errinfo.should ==
- [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
+ ec.primitive_errinfo.should == [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
ec.putback(1).should == "\x00".force_encoding("utf-16le")
ec.putback.should == "a".force_encoding("utf-16le")
ec.putback.should == ""
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
index 41320c5207..428b292c68 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
@@ -23,7 +23,7 @@ with_feature :encoding do
# conversion from ISO-8859-1 -> UTF-8 succeeded, but the conversion from
# UTF-8 to EUC-JP failed. IOW, it failed when the source encoding was
# UTF-8, so UTF-8 is regarded as the source encoding.
- it "is equal to the source encoding at the stage of the conversion path where the error occured" do
+ it "is equal to the source encoding at the stage of the conversion path where the error occurred" do
@exception2.source_encoding_name.should == 'UTF-8'
end
end
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
index 75514e5229..09379acc5d 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
@@ -28,7 +28,7 @@ with_feature :encoding do
# FIXME: Derive example where the failure occurs at the UTF-8 ->
# ISO-8859-1 case so as to better illustrate the issue
- it "is equal to the source encoding at the stage of the conversion path where the error occured" do
+ it "is equal to the source encoding at the stage of the conversion path where the error occurred" do
@exception2.source_encoding.should == Encoding::EUC_JP
end
end
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
index 4a7aba2044..742184250f 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
@@ -23,7 +23,7 @@ with_feature :encoding do
# conversion from ISO-8859-1 -> UTF-8 succeeded, but the conversion from
# UTF-8 to EUC-JP failed. IOW, it failed when the source encoding was
# UTF-8, so UTF-8 is regarded as the source encoding.
- it "is equal to the source encoding at the stage of the conversion path where the error occured" do
+ it "is equal to the source encoding at the stage of the conversion path where the error occurred" do
@exception2.source_encoding_name.should == 'UTF-8'
end
end
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
index 984862646c..0489ad82bf 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
@@ -24,7 +24,7 @@ with_feature :encoding do
# conversion from ISO-8859-1 -> UTF-8 succeeded, but the conversion from
# UTF-8 to EUC-JP failed. IOW, it failed when the source encoding was
# UTF-8, so UTF-8 is regarded as the source encoding.
- it "is equal to the source encoding at the stage of the conversion path where the error occured" do
+ it "is equal to the source encoding at the stage of the conversion path where the error occurred" do
@exception2.source_encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb
index 4f7af68b07..4a7511f649 100644
--- a/spec/ruby/core/enumerable/any_spec.rb
+++ b/spec/ruby/core/enumerable/any_spec.rb
@@ -68,11 +68,11 @@ describe "Enumerable#any?" do
describe "with block" do
it "returns true if the block ever returns other than false or nil" do
- @enum.any? { true } == true
- @enum.any? { 0 } == true
- @enum.any? { 1 } == true
+ @enum.any? { true }.should == true
+ @enum.any? { 0 }.should == true
+ @enum.any? { 1 }.should == true
- @enum1.any? { Object.new } == true
+ @enum1.any? { Object.new }.should == true
@enum1.any?{ |o| o < 1 }.should == true
@enum1.any?{ |o| 5 }.should == true
diff --git a/spec/ruby/core/enumerable/cycle_spec.rb b/spec/ruby/core/enumerable/cycle_spec.rb
index 2f5760992d..9089a94963 100644
--- a/spec/ruby/core/enumerable/cycle_spec.rb
+++ b/spec/ruby/core/enumerable/cycle_spec.rb
@@ -69,7 +69,7 @@ describe "Enumerable#cycle" do
enum.cycle(obj).to_a.should == [3, 2, 1, 3, 2, 1]
end
- it "raises a TypeError when the passed n can be coerced to Integer" do
+ it "raises a TypeError when the passed n cannot be coerced to Integer" do
enum = EnumerableSpecs::Numerous.new
lambda{ enum.cycle("cat"){} }.should raise_error(TypeError)
end
diff --git a/spec/ruby/core/enumerable/drop_spec.rb b/spec/ruby/core/enumerable/drop_spec.rb
index 1bcdc0ee9a..4013a639ce 100644
--- a/spec/ruby/core/enumerable/drop_spec.rb
+++ b/spec/ruby/core/enumerable/drop_spec.rb
@@ -34,7 +34,7 @@ describe "Enumerable#drop" do
EnumerableSpecs::Numerous.new(3, 2, 1, :go).drop(4).should == []
end
- it "raises a TypeError when the passed n can be coerced to Integer" do
+ it "raises a TypeError when the passed n cannot be coerced to Integer" do
lambda{ @enum.drop("hat") }.should raise_error(TypeError)
lambda{ @enum.drop(nil) }.should raise_error(TypeError)
end
diff --git a/spec/ruby/core/enumerable/uniq_spec.rb b/spec/ruby/core/enumerable/uniq_spec.rb
index 0ede0170ce..5ca7556aed 100644
--- a/spec/ruby/core/enumerable/uniq_spec.rb
+++ b/spec/ruby/core/enumerable/uniq_spec.rb
@@ -7,6 +7,71 @@ ruby_version_is '2.4' do
[0, 1, 2, 3].to_enum.uniq { |n| n.even? }.should == [0, 1]
end
+ it "uses eql? semantics" do
+ [1.0, 1].to_enum.uniq.should == [1.0, 1]
+ end
+
+ it "compares elements first with hash" do
+ x = mock('0')
+ x.should_receive(:hash).at_least(1).and_return(0)
+ y = mock('0')
+ y.should_receive(:hash).at_least(1).and_return(0)
+
+ [x, y].to_enum.uniq.should == [x, y]
+ end
+
+ it "does not compare elements with different hash codes via eql?" do
+ x = mock('0')
+ x.should_not_receive(:eql?)
+ y = mock('1')
+ y.should_not_receive(:eql?)
+
+ x.should_receive(:hash).at_least(1).and_return(0)
+ y.should_receive(:hash).at_least(1).and_return(1)
+
+ [x, y].to_enum.uniq.should == [x, y]
+ end
+
+ it "compares elements with matching hash codes with #eql?" do
+ a = Array.new(2) do
+ obj = mock('0')
+ obj.should_receive(:hash).at_least(1).and_return(0)
+
+ def obj.eql?(o)
+ # It's undefined whether the impl does a[0].eql?(a[1]) or
+ # a[1].eql?(a[0]) so we taint both.
+ taint
+ o.taint
+ false
+ end
+
+ obj
+ end
+
+ a.uniq.should == a
+ a[0].tainted?.should == true
+ a[1].tainted?.should == true
+
+ a = Array.new(2) do
+ obj = mock('0')
+ obj.should_receive(:hash).at_least(1).and_return(0)
+
+ def obj.eql?(o)
+ # It's undefined whether the impl does a[0].eql?(a[1]) or
+ # a[1].eql?(a[0]) so we taint both.
+ taint
+ o.taint
+ true
+ end
+
+ obj
+ end
+
+ a.to_enum.uniq.size.should == 1
+ a[0].tainted?.should == true
+ a[1].tainted?.should == true
+ end
+
context 'when yielded with multiple arguments' do
before :each do
@enum = Object.new.to_enum
diff --git a/spec/ruby/core/enumerator/lazy/force_spec.rb b/spec/ruby/core/enumerator/lazy/force_spec.rb
index 03ff9a0fb6..1a218c1b0f 100644
--- a/spec/ruby/core/enumerator/lazy/force_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/force_spec.rb
@@ -24,7 +24,7 @@ describe "Enumerator::Lazy#force" do
(0..Float::INFINITY).lazy.map(&:succ).take(2).force.should == [1, 2]
@eventsmixed.take(1).map(&:succ).force.should == [1]
- ScratchPad.recorded == [:after_yields]
+ ScratchPad.recorded.should == [:before_yield]
end
end
end
diff --git a/spec/ruby/core/false/dup_spec.rb b/spec/ruby/core/false/dup_spec.rb
new file mode 100644
index 0000000000..b04e641a41
--- /dev/null
+++ b/spec/ruby/core/false/dup_spec.rb
@@ -0,0 +1,9 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is '2.4' do
+ describe "FalseClass#dup" do
+ it "returns self" do
+ false.dup.should equal(false)
+ end
+ end
+end
diff --git a/spec/ruby/core/file/empty_spec.rb b/spec/ruby/core/file/empty_spec.rb
new file mode 100644
index 0000000000..766aa95e46
--- /dev/null
+++ b/spec/ruby/core/file/empty_spec.rb
@@ -0,0 +1,15 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+require File.expand_path('../../../shared/file/zero', __FILE__)
+
+describe "File.empty?" do
+ ruby_version_is "2.4" do
+ it_behaves_like :file_zero, :empty?, File
+ it_behaves_like :file_zero_missing, :empty?, File
+
+ platform_is :solaris do
+ it "returns false for /dev/null" do
+ File.empty?('/dev/null').should == true
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/file/readlink_spec.rb b/spec/ruby/core/file/readlink_spec.rb
index 6db2c09780..b529cd1355 100644
--- a/spec/ruby/core/file/readlink_spec.rb
+++ b/spec/ruby/core/file/readlink_spec.rb
@@ -3,7 +3,7 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe "File.readlink" do
# symlink/readlink are not supported on Windows
platform_is_not :windows do
- describe "File.readlink with absolute paths" do
+ describe "with absolute paths" do
before :each do
@file = tmp('file_readlink.txt')
@link = tmp('file_readlink.lnk')
@@ -35,7 +35,26 @@ describe "File.readlink" do
end
end
- describe "File.readlink when changing the working directory" do
+ describe "with paths containing unicode characters" do
+ before :each do
+ @file = tmp('tàrget.txt')
+ @link = tmp('lïnk.lnk')
+ File.symlink(@file, @link)
+ end
+
+ after :each do
+ rm_r @file, @link
+ end
+
+ it "returns the name of the file referenced by the given link" do
+ touch @file
+ result = File.readlink(@link)
+ result.encoding.should equal Encoding.find('filesystem')
+ result.should == @file.dup.force_encoding(Encoding.find('filesystem'))
+ end
+ end
+
+ describe "when changing the working directory" do
before :each do
@cwd = Dir.pwd
@tmpdir = tmp("/readlink")
diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb
index 80e37b3fff..9b423ae47e 100644
--- a/spec/ruby/core/file/shared/fnmatch.rb
+++ b/spec/ruby/core/file/shared/fnmatch.rb
@@ -75,11 +75,11 @@ describe :file_fnmatch, shared: true do
File.send(@method, 'c*t', 'c/a/b/t').should == true
end
- it "matches ranges of characters using bracket expresions (e.g. [a-z])" do
+ it "matches ranges of characters using bracket expression (e.g. [a-z])" do
File.send(@method, 'ca[a-z]', 'cat').should == true
end
- it "matches ranges of characters using bracket expresions, taking case into account" do
+ it "matches ranges of characters using bracket expression, taking case into account" do
File.send(@method, '[a-z]', 'D').should == false
File.send(@method, '[^a-z]', 'D').should == true
File.send(@method, '[A-Z]', 'd').should == false
@@ -92,7 +92,7 @@ describe :file_fnmatch, shared: true do
File.send(@method, '/ca[s][s-t]/rul[a-b]/[z]he/[x-Z]orld', '/cats/rule/the/World').should == false
end
- it "matches ranges of characters using exclusive bracket expresions (e.g. [^t] or [!t])" do
+ it "matches ranges of characters using exclusive bracket expression (e.g. [^t] or [!t])" do
File.send(@method, 'ca[^t]', 'cat').should == false
File.send(@method, 'ca[!t]', 'cat').should == false
end
@@ -106,13 +106,13 @@ describe :file_fnmatch, shared: true do
end
platform_is_not :windows do
- it "doesn't match case sensitive characters on platfroms with case sensitive paths, when flags include FNM_SYSCASE" do
+ it "doesn't match case sensitive characters on platforms with case sensitive paths, when flags include FNM_SYSCASE" do
File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == false
end
end
platform_is :windows do
- it "matches case sensitive characters on platfroms with case insensitive paths, when flags include FNM_SYSCASE" do
+ it "matches case sensitive characters on platforms with case insensitive paths, when flags include FNM_SYSCASE" do
File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == true
end
end
diff --git a/spec/ruby/core/fixnum/fixnum_spec.rb b/spec/ruby/core/fixnum/fixnum_spec.rb
index 8a050fd25e..7f72f95e94 100644
--- a/spec/ruby/core/fixnum/fixnum_spec.rb
+++ b/spec/ruby/core/fixnum/fixnum_spec.rb
@@ -16,4 +16,16 @@ describe "Fixnum" do
Fixnum.new
end.should raise_error(NoMethodError)
end
+
+ ruby_version_is '2.4' do
+ it "is unified into Integer" do
+ Fixnum.should equal(Integer)
+ end
+
+ it "is deprecated" do
+ -> {
+ Fixnum
+ }.should complain(/constant ::Fixnum is deprecated/)
+ end
+ end
end
diff --git a/spec/ruby/core/float/ceil_spec.rb b/spec/ruby/core/float/ceil_spec.rb
index 8037164c68..f1d9dcd823 100644
--- a/spec/ruby/core/float/ceil_spec.rb
+++ b/spec/ruby/core/float/ceil_spec.rb
@@ -10,4 +10,14 @@ describe "Float#ceil" do
-9223372036854775808.1.ceil.should eql(-9223372036854775808)
+9223372036854775808.1.ceil.should eql(+9223372036854775808)
end
+
+ ruby_version_is "2.4" do
+ it "returns the smallest number greater than or equal to self with an optionally given precision" do
+ 2.1679.ceil(0).should eql(3)
+ 214.94.ceil(-1).should eql(220)
+ 7.0.ceil(1).should eql(7.0)
+ -1.234.ceil(2).should eql(-1.23)
+ 5.123812.ceil(4).should eql(5.1239)
+ end
+ end
end
diff --git a/spec/ruby/core/float/dup_spec.rb b/spec/ruby/core/float/dup_spec.rb
new file mode 100644
index 0000000000..775dc2913c
--- /dev/null
+++ b/spec/ruby/core/float/dup_spec.rb
@@ -0,0 +1,10 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is '2.4' do
+ describe "Float#dup" do
+ it "returns self" do
+ float = 2.4
+ float.dup.should equal(float)
+ end
+ end
+end
diff --git a/spec/ruby/core/float/floor_spec.rb b/spec/ruby/core/float/floor_spec.rb
index 63a5138366..6da5d5c5ee 100644
--- a/spec/ruby/core/float/floor_spec.rb
+++ b/spec/ruby/core/float/floor_spec.rb
@@ -10,4 +10,14 @@ describe "Float#floor" do
-9223372036854775808.1.floor.should eql(-9223372036854775808)
+9223372036854775808.1.floor.should eql(+9223372036854775808)
end
+
+ ruby_version_is "2.4" do
+ it "returns the largest number less than or equal to self with an optionally given precision" do
+ 2.1679.floor(0).should eql(2)
+ 214.94.floor(-1).should eql(210)
+ 7.0.floor(1).should eql(7.0)
+ -1.234.floor(2).should eql(-1.24)
+ 5.123812.floor(4).should eql(5.1238)
+ end
+ end
end
diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb
index 46d23b36d0..56668d5856 100644
--- a/spec/ruby/core/float/round_spec.rb
+++ b/spec/ruby/core/float/round_spec.rb
@@ -84,4 +84,18 @@ describe "Float#round" do
-2.5e200.round(-200).should eql( -3 * 10 ** 200 )
-2.4e200.round(-200).should eql( -2 * 10 ** 200 )
end
+
+ ruby_version_is "2.4" do
+ it "returns different rounded values depending on the half option" do
+ 2.5.round(half: :up).should eql(3)
+ 2.5.round(half: :down).should eql(2)
+ 2.5.round(half: :even).should eql(2)
+ 3.5.round(half: :up).should eql(4)
+ 3.5.round(half: :down).should eql(3)
+ 3.5.round(half: :even).should eql(4)
+ (-2.5).round(half: :up).should eql(-3)
+ (-2.5).round(half: :down).should eql(-2)
+ (-2.5).round(half: :even).should eql(-2)
+ end
+ end
end
diff --git a/spec/ruby/core/float/truncate_spec.rb b/spec/ruby/core/float/truncate_spec.rb
index 85ee8ef580..7feeb81735 100644
--- a/spec/ruby/core/float/truncate_spec.rb
+++ b/spec/ruby/core/float/truncate_spec.rb
@@ -3,4 +3,14 @@ require File.expand_path('../shared/to_i', __FILE__)
describe "Float#truncate" do
it_behaves_like(:float_to_i, :truncate)
+
+ ruby_version_is "2.4" do
+ it "returns self truncated to an optionally given precision" do
+ 2.1679.truncate(0).should eql(2)
+ 7.1.truncate(1).should eql(7.1)
+ 214.94.truncate(-1).should eql(210)
+ -1.234.truncate(2).should eql(-1.23)
+ 5.123812.truncate(4).should eql(5.1238)
+ end
+ end
end
diff --git a/spec/ruby/core/hash/delete_spec.rb b/spec/ruby/core/hash/delete_spec.rb
index a45b8cd171..a41fad3586 100644
--- a/spec/ruby/core/hash/delete_spec.rb
+++ b/spec/ruby/core/hash/delete_spec.rb
@@ -11,13 +11,13 @@ describe "Hash#delete" do
it "calls supplied block if the key is not found" do
{ a: 1, b: 10, c: 100 }.delete(:d) { 5 }.should == 5
Hash.new(:default).delete(:d) { 5 }.should == 5
- Hash.new { :defualt }.delete(:d) { 5 }.should == 5
+ Hash.new { :default }.delete(:d) { 5 }.should == 5
end
it "returns nil if the key is not found when no block is given" do
{ a: 1, b: 10, c: 100 }.delete(:d).should == nil
Hash.new(:default).delete(:d).should == nil
- Hash.new { :defualt }.delete(:d).should == nil
+ Hash.new { :default }.delete(:d).should == nil
end
# MRI explicitly implements this behavior
diff --git a/spec/ruby/core/hash/transform_values_spec.rb b/spec/ruby/core/hash/transform_values_spec.rb
index 7e4ff45bea..0c9e43d621 100644
--- a/spec/ruby/core/hash/transform_values_spec.rb
+++ b/spec/ruby/core/hash/transform_values_spec.rb
@@ -24,6 +24,15 @@ ruby_version_is "2.4" do
enumerator.each(&:succ).should == { a: 2, b: 3, c: 4 }
end
end
+
+ it "returns a Hash instance, even on subclasses" do
+ klass = Class.new(Hash)
+ h = klass.new
+ h[:foo] = 42
+ r = h.transform_values{|v| 2 * v}
+ r[:foo].should == 84
+ r.class.should == Hash
+ end
end
describe "Hash#transform_values!" do
@@ -41,6 +50,14 @@ ruby_version_is "2.4" do
@hash.should == { a: 2, b: 3, c: 4 }
end
+ it "partially modifies the contents if we broke from the block" do
+ @hash.transform_values! do |v|
+ break if v == 3
+ 100 + v
+ end
+ @hash.should == { a: 101, b: 102, c: 3}
+ end
+
context "when no block is given" do
it "returns a sized Enumerator" do
enumerator = @hash.transform_values!
@@ -56,6 +73,10 @@ ruby_version_is "2.4" do
@hash.freeze
end
+ it "raises a RuntimeError on an empty hash" do
+ ->{ {}.freeze.transform_values!(&:succ) }.should raise_error(RuntimeError)
+ end
+
it "keeps pairs and raises a RuntimeError" do
->{ @hash.transform_values!(&:succ) }.should raise_error(RuntimeError)
@hash.should == @initial_pairs
diff --git a/spec/ruby/core/integer/ceil_spec.rb b/spec/ruby/core/integer/ceil_spec.rb
index 7a49ede0df..31c56f378d 100644
--- a/spec/ruby/core/integer/ceil_spec.rb
+++ b/spec/ruby/core/integer/ceil_spec.rb
@@ -1,6 +1,21 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../shared/to_i', __FILE__)
+require File.expand_path('../shared/integer_rounding', __FILE__)
describe "Integer#ceil" do
it_behaves_like(:integer_to_i, :ceil)
+ it_behaves_like(:integer_rounding_positive_precision, :ceil)
+
+ ruby_version_is "2.4" do
+ context "precision argument specified as part of the ceil method is negative" do
+ it "returns the smallest integer greater than self with at least precision.abs trailing zeros" do
+ 18.ceil(-1).should eql(20)
+ 18.ceil(-2).should eql(100)
+ 18.ceil(-3).should eql(1000)
+ -1832.ceil(-1).should eql(-1830)
+ -1832.ceil(-2).should eql(-1800)
+ -1832.ceil(-3).should eql(-1000)
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/integer/digits_spec.rb b/spec/ruby/core/integer/digits_spec.rb
new file mode 100644
index 0000000000..3546a654eb
--- /dev/null
+++ b/spec/ruby/core/integer/digits_spec.rb
@@ -0,0 +1,34 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.4" do
+ describe "Integer#digits" do
+ it "returns an array of place values in base-10 by default" do
+ 12345.digits.should == [5,4,3,2,1]
+ end
+
+ it "returns digits by place value of a given radix" do
+ 12345.digits(7).should == [4,6,6,0,5]
+ end
+
+ it "converts the radix with #to_int" do
+ 12345.digits(mock_int(2)).should == [1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1]
+ end
+
+ it "returns [0] when called on 0, regardless of base" do
+ 0.digits.should == [0]
+ 0.digits(7).should == [0]
+ end
+
+ it "raises ArgumentError when calling with a radix less than 2" do
+ lambda { 12345.digits(1) }.should raise_error(ArgumentError)
+ end
+
+ it "raises ArgumentError when calling with a negative radix" do
+ lambda { 12345.digits(-2) }.should raise_error(ArgumentError)
+ end
+
+ it "raises Math::DomainError when calling digits on a negative number" do
+ lambda { -12345.digits(7) }.should raise_error(Math::DomainError)
+ end
+ end
+end
diff --git a/spec/ruby/core/integer/dup_spec.rb b/spec/ruby/core/integer/dup_spec.rb
new file mode 100644
index 0000000000..f46bdf89bd
--- /dev/null
+++ b/spec/ruby/core/integer/dup_spec.rb
@@ -0,0 +1,10 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is '2.4' do
+ describe "Integer#dup" do
+ it "returns self" do
+ int = 2
+ int.dup.should equal(int)
+ end
+ end
+end
diff --git a/spec/ruby/core/integer/floor_spec.rb b/spec/ruby/core/integer/floor_spec.rb
index b533a84ad4..9babcd9a3e 100644
--- a/spec/ruby/core/integer/floor_spec.rb
+++ b/spec/ruby/core/integer/floor_spec.rb
@@ -1,6 +1,21 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../shared/to_i', __FILE__)
+require File.expand_path('../shared/integer_rounding', __FILE__)
describe "Integer#floor" do
it_behaves_like(:integer_to_i, :floor)
+ it_behaves_like(:integer_rounding_positive_precision, :floor)
+
+ ruby_version_is "2.4" do
+ context "precision argument specified as part of the floor method is negative" do
+ it "returns the largest integer less than self with at least precision.abs trailing zeros" do
+ 1832.floor(-1).should eql(1830)
+ 1832.floor(-2).should eql(1800)
+ 1832.floor(-3).should eql(1000)
+ -1832.floor(-1).should eql(-1840)
+ -1832.floor(-2).should eql(-1900)
+ -1832.floor(-3).should eql(-2000)
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/integer/integer_spec.rb b/spec/ruby/core/integer/integer_spec.rb
index a6f406cba0..393f072563 100644
--- a/spec/ruby/core/integer/integer_spec.rb
+++ b/spec/ruby/core/integer/integer_spec.rb
@@ -4,6 +4,13 @@ describe "Integer" do
it "includes Comparable" do
Integer.include?(Comparable).should == true
end
+
+ ruby_version_is "2.4" do
+ it "is the class of both small and large integers" do
+ 42.class.should equal(Integer)
+ bignum_value.class.should equal(Integer)
+ end
+ end
end
describe "Integer#integer?" do
diff --git a/spec/ruby/core/integer/round_spec.rb b/spec/ruby/core/integer/round_spec.rb
index 5cc9aa3881..5a46e6cba6 100644
--- a/spec/ruby/core/integer/round_spec.rb
+++ b/spec/ruby/core/integer/round_spec.rb
@@ -1,10 +1,12 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../shared/to_i', __FILE__)
+require File.expand_path('../shared/integer_rounding', __FILE__)
describe "Integer#round" do
it_behaves_like(:integer_to_i, :round)
+ it_behaves_like(:integer_rounding_positive_precision, :round)
- ruby_version_is ""..."2.5" do
+ ruby_version_is ""..."2.5" do # Not just since 2.4
it "rounds itself as a float if passed a positive precision" do
[2, -4, 10**70, -10**100].each do |v|
v.round(42).should eql(v.to_f)
@@ -12,20 +14,6 @@ describe "Integer#round" do
end
end
- ruby_version_is "2.5" do
- it "returns itself if passed a positive precision" do
- [2, -4, 10**70, -10**100].each do |v|
- v.round(42).should eql(v)
- end
- end
- end
-
- it "returns itself if passed zero" do
- [2, -4, 10**70, -10**100].each do |v|
- v.round(0).should eql(v)
- end
- end
-
# redmine:5228
it "returns itself rounded if passed a negative value" do
+249.round(-2).should eql(+200)
@@ -74,4 +62,34 @@ describe "Integer#round" do
obj.stub!(:to_int).and_return([])
lambda { 42.round(obj) }.should raise_error(TypeError)
end
+
+ ruby_version_is "2.4" do
+ it "returns different rounded values depending on the half option" do
+ 25.round(-1, half: :up).should eql(30)
+ 25.round(-1, half: :down).should eql(20)
+ 25.round(-1, half: :even).should eql(20)
+ 35.round(-1, half: :up).should eql(40)
+ 35.round(-1, half: :down).should eql(30)
+ 35.round(-1, half: :even).should eql(40)
+ (-25).round(-1, half: :up).should eql(-30)
+ (-25).round(-1, half: :down).should eql(-20)
+ (-25).round(-1, half: :even).should eql(-20)
+ end
+ end
+
+ ruby_version_is "2.4"..."2.5" do
+ it "returns itself as a float if passed a positive precision and the half option" do
+ 35.round(1, half: :up).should eql(35.0)
+ 35.round(1, half: :down).should eql(35.0)
+ 35.round(1, half: :even).should eql(35.0)
+ end
+ end
+
+ ruby_version_is "2.5" do
+ it "returns itself if passed a positive precision and the half option" do
+ 35.round(1, half: :up).should eql(35)
+ 35.round(1, half: :down).should eql(35)
+ 35.round(1, half: :even).should eql(35)
+ end
+ end
end
diff --git a/spec/ruby/core/integer/shared/integer_rounding.rb b/spec/ruby/core/integer/shared/integer_rounding.rb
new file mode 100644
index 0000000000..ecbda1bb4a
--- /dev/null
+++ b/spec/ruby/core/integer/shared/integer_rounding.rb
@@ -0,0 +1,31 @@
+describe :integer_rounding_positive_precision, shared: true do
+ it "returns self if not passed a precision" do
+ [2, -4, 10**70, -10**100].each do |v|
+ v.send(@method).should eql(v)
+ end
+ end
+
+ ruby_version_is "2.4" do
+ it "returns self if passed a precision of zero" do
+ [2, -4, 10**70, -10**100].each do |v|
+ v.send(@method, 0).should eql(v)
+ end
+ end
+ end
+
+ ruby_version_is "2.4"..."2.5" do
+ it "returns itself as a float if passed a positive precision" do
+ [2, -4, 10**70, -10**100].each do |v|
+ v.send(@method, 42).should eql(v.to_f)
+ end
+ end
+ end
+
+ ruby_version_is "2.5" do
+ it "returns itself if passed a positive precision" do
+ [2, -4, 10**70, -10**100].each do |v|
+ v.send(@method, 42).should eql(v)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/integer/sqrt_spec.rb b/spec/ruby/core/integer/sqrt_spec.rb
new file mode 100644
index 0000000000..b7d9ef441b
--- /dev/null
+++ b/spec/ruby/core/integer/sqrt_spec.rb
@@ -0,0 +1,33 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.5" do
+ describe "Integer.sqrt" do
+ it "returns an integer" do
+ Integer.sqrt(10).should be_kind_of(Integer)
+ end
+
+ it "returns the integer square root of the argument" do
+ Integer.sqrt(0).should == 0
+ Integer.sqrt(1).should == 1
+ Integer.sqrt(24).should == 4
+ Integer.sqrt(25).should == 5
+ Integer.sqrt(10**400).should == 10**200
+ end
+
+ it "raises a Math::DomainError if the argument is negative" do
+ lambda { Integer.sqrt(-4) }.should raise_error(Math::DomainError)
+ end
+
+ it "accepts any argument that can be coerced to Integer" do
+ Integer.sqrt(10.0).should == 3
+ end
+
+ it "converts the argument with #to_int" do
+ Integer.sqrt(mock_int(10)).should == 3
+ end
+
+ it "raises a TypeError if the argument cannot be coerced to Integer" do
+ lambda { Integer.sqrt("test") }.should raise_error(TypeError)
+ end
+ end
+end
diff --git a/spec/ruby/core/integer/truncate_spec.rb b/spec/ruby/core/integer/truncate_spec.rb
index b503b1e4e8..429ab1a312 100644
--- a/spec/ruby/core/integer/truncate_spec.rb
+++ b/spec/ruby/core/integer/truncate_spec.rb
@@ -1,6 +1,21 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../shared/to_i', __FILE__)
+require File.expand_path('../shared/integer_rounding', __FILE__)
describe "Integer#truncate" do
it_behaves_like(:integer_to_i, :truncate)
+ it_behaves_like(:integer_rounding_positive_precision, :truncate)
+
+ ruby_version_is "2.4" do
+ context "precision argument specified as part of the truncate method is negative" do
+ it "returns an integer with at least precision.abs trailing zeros" do
+ 1832.truncate(-1).should eql(1830)
+ 1832.truncate(-2).should eql(1800)
+ 1832.truncate(-3).should eql(1000)
+ -1832.truncate(-1).should eql(-1830)
+ -1832.truncate(-2).should eql(-1800)
+ -1832.truncate(-3).should eql(-1000)
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/io/advise_spec.rb b/spec/ruby/core/io/advise_spec.rb
index 460b50a59d..44cd32df94 100644
--- a/spec/ruby/core/io/advise_spec.rb
+++ b/spec/ruby/core/io/advise_spec.rb
@@ -17,7 +17,7 @@ describe "IO#advise" do
}.should raise_error(TypeError)
end
- it "raises a TypeError if offsert cannot be coerced to an Integer" do
+ it "raises a TypeError if offset cannot be coerced to an Integer" do
lambda {
@io.advise(:normal, "wat")
}.should raise_error(TypeError)
diff --git a/spec/ruby/core/io/fixtures/classes.rb b/spec/ruby/core/io/fixtures/classes.rb
index fb431d5023..a771e3d929 100644
--- a/spec/ruby/core/io/fixtures/classes.rb
+++ b/spec/ruby/core/io/fixtures/classes.rb
@@ -20,6 +20,18 @@ module IOSpecs
"Here is line six.\n" ]
end
+ def self.lines_without_newline_characters
+ [ "Voici la ligne une.",
+ "Qui \303\250 la linea due.",
+ "",
+ "",
+ "Aqu\303\255 est\303\241 la l\303\255nea tres.",
+ "Hier ist Zeile vier.",
+ "",
+ "Est\303\241 aqui a linha cinco.",
+ "Here is line six." ]
+ end
+
def self.lines_limit
[ "Voici la l",
"igne une.\n",
diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb
index d984e795c2..6e0518b512 100644
--- a/spec/ruby/core/io/gets_spec.rb
+++ b/spec/ruby/core/io/gets_spec.rb
@@ -138,6 +138,14 @@ describe "IO#gets" do
end
end
end
+
+ ruby_version_is "2.4" do
+ describe "when passed chomp" do
+ it "returns the first line without a trailing newline character" do
+ @io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
+ end
+ end
+ end
end
describe "IO#gets" do
@@ -191,7 +199,7 @@ describe "IO#gets" do
@io.gets(obj, 5).should == "one\n"
end
- it "reads to the default seperator when passed a single argument greater than the number of bytes to the separator" do
+ it "reads to the default separator when passed a single argument greater than the number of bytes to the separator" do
@io.gets(6).should == "one\n"
end
diff --git a/spec/ruby/core/io/readline_spec.rb b/spec/ruby/core/io/readline_spec.rb
index 39706948eb..a1cddafe5c 100644
--- a/spec/ruby/core/io/readline_spec.rb
+++ b/spec/ruby/core/io/readline_spec.rb
@@ -42,4 +42,12 @@ describe "IO#readline" do
$_.should == line
end
end
+
+ ruby_version_is "2.4" do
+ describe "when passed chomp" do
+ it "returns the first line without a trailing newline character" do
+ @io.readline(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb
index dc07434ecd..d87303b54a 100644
--- a/spec/ruby/core/io/shared/each.rb
+++ b/spec/ruby/core/io/shared/each.rb
@@ -114,6 +114,15 @@ describe :io_each, shared: true do
ScratchPad.recorded.should == IOSpecs.paragraphs
end
end
+
+ ruby_version_is "2.4" do
+ describe "when passed chomp" do
+ it "yields each line without trailing newline characters to the passed block" do
+ @io.send(@method, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines_without_newline_characters
+ end
+ end
+ end
end
describe :io_each_default_separator, shared: true do
diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb
index 4cb821274a..f545d8876a 100644
--- a/spec/ruby/core/io/shared/readlines.rb
+++ b/spec/ruby/core/io/shared/readlines.rb
@@ -17,6 +17,13 @@ describe :io_readlines, shared: true do
result = IO.send(@method, @name, "", &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_empty_separator
end
+
+ ruby_version_is "2.4" do
+ it "yields a sequence of lines without trailing newline characters when chomp is passed" do
+ result = IO.send(@method, @name, chomp: true, &@object)
+ (result ? result : ScratchPad.recorded).should == IOSpecs.lines_without_newline_characters
+ end
+ end
end
describe :io_readlines_options_19, shared: true do
diff --git a/spec/ruby/core/kernel/equal_value_spec.rb b/spec/ruby/core/kernel/equal_value_spec.rb
index 670987ead2..a66493f283 100644
--- a/spec/ruby/core/kernel/equal_value_spec.rb
+++ b/spec/ruby/core/kernel/equal_value_spec.rb
@@ -7,9 +7,9 @@ describe "Kernel#==" do
o2 = mock('o2')
(o1 == o1).should == true
(o2 == o2).should == true
- (o1 == o2).should== false
+ (o1 == o2).should == false
(nil == nil).should == true
- (o1 == nil).should== false
- (nil == o2).should== false
+ (o1 == nil).should == false
+ (nil == o2).should == false
end
end
diff --git a/spec/ruby/core/main/fixtures/classes.rb b/spec/ruby/core/main/fixtures/classes.rb
index 0b74080492..6aba948ce0 100644
--- a/spec/ruby/core/main/fixtures/classes.rb
+++ b/spec/ruby/core/main/fixtures/classes.rb
@@ -4,8 +4,11 @@ module MainSpecs
module WrapIncludeModule
end
+
+ DATA = {}
end
+
def main_public_method
end
public :main_public_method
diff --git a/spec/ruby/core/main/fixtures/string_refinement.rb b/spec/ruby/core/main/fixtures/string_refinement.rb
new file mode 100644
index 0000000000..2dc6de52ca
--- /dev/null
+++ b/spec/ruby/core/main/fixtures/string_refinement.rb
@@ -0,0 +1,7 @@
+module StringRefinement
+ refine(String) do
+ def foo
+ 'foo'
+ end
+ end
+end
diff --git a/spec/ruby/core/main/fixtures/string_refinement_user.rb b/spec/ruby/core/main/fixtures/string_refinement_user.rb
new file mode 100644
index 0000000000..48620c325f
--- /dev/null
+++ b/spec/ruby/core/main/fixtures/string_refinement_user.rb
@@ -0,0 +1,11 @@
+using StringRefinement
+
+module MainSpecs
+ DATA[:in_module] = 'hello'.foo
+
+ def self.call_foo(x)
+ x.foo
+ end
+end
+
+MainSpecs::DATA[:toplevel] = 'hello'.foo
diff --git a/spec/ruby/core/main/using_spec.rb b/spec/ruby/core/main/using_spec.rb
new file mode 100644
index 0000000000..ed18cdca39
--- /dev/null
+++ b/spec/ruby/core/main/using_spec.rb
@@ -0,0 +1,134 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.0.0" do
+ require File.expand_path('../fixtures/classes', __FILE__)
+ require File.expand_path('../fixtures/string_refinement', __FILE__)
+
+ describe "main.using" do
+ it "requires one Module argument" do
+ lambda do
+ eval('using', TOPLEVEL_BINDING)
+ end.should raise_error(ArgumentError)
+
+ lambda do
+ eval('using "foo"', TOPLEVEL_BINDING)
+ end.should raise_error(TypeError)
+ end
+
+ it "uses refinements from the given module only in the target file" do
+ load File.expand_path('../fixtures/string_refinement_user.rb', __FILE__)
+ MainSpecs::DATA[:in_module].should == 'foo'
+ MainSpecs::DATA[:toplevel].should == 'foo'
+ lambda do
+ 'hello'.foo
+ end.should raise_error(NoMethodError)
+ end
+
+ it "uses refinements from the given module for method calls in the target file" do
+ load File.expand_path('../fixtures/string_refinement_user.rb', __FILE__)
+ lambda do
+ 'hello'.foo
+ end.should raise_error(NoMethodError)
+ MainSpecs.call_foo('hello').should == 'foo'
+ end
+
+ it "uses refinements from the given module in the eval string" do
+ cls = MainSpecs::DATA[:cls] = Class.new {def foo; 'foo'; end}
+ MainSpecs::DATA[:mod] = Module.new do
+ refine(cls) do
+ def foo; 'bar'; end
+ end
+ end
+ eval(<<-EOS, TOPLEVEL_BINDING).should == 'bar'
+ using MainSpecs::DATA[:mod]
+ MainSpecs::DATA[:cls].new.foo
+ EOS
+ end
+
+ it "does not affect methods defined before it is called" do
+ cls = Class.new {def foo; 'foo'; end}
+ MainSpecs::DATA[:mod] = Module.new do
+ refine(cls) do
+ def foo; 'bar'; end
+ end
+ end
+ x = MainSpecs::DATA[:x] = Object.new
+ eval <<-EOS, TOPLEVEL_BINDING
+ x = MainSpecs::DATA[:x]
+ def x.before_using(obj)
+ obj.foo
+ end
+ using MainSpecs::DATA[:mod]
+ def x.after_using(obj)
+ obj.foo
+ end
+ EOS
+
+ obj = cls.new
+ x.before_using(obj).should == 'foo'
+ x.after_using(obj).should == 'bar'
+ end
+
+ it "propagates refinements added to existing modules after it is called" do
+ cls = Class.new {def foo; 'foo'; end}
+ mod = MainSpecs::DATA[:mod] = Module.new do
+ refine(cls) do
+ def foo; 'quux'; end
+ end
+ end
+ x = MainSpecs::DATA[:x] = Object.new
+ eval <<-EOS, TOPLEVEL_BINDING
+ using MainSpecs::DATA[:mod]
+ x = MainSpecs::DATA[:x]
+ def x.call_foo(obj)
+ obj.foo
+ end
+ def x.call_bar(obj)
+ obj.bar
+ end
+ EOS
+
+ obj = cls.new
+ x.call_foo(obj).should == 'quux'
+
+ mod.module_eval do
+ refine(cls) do
+ def bar; 'quux'; end
+ end
+ end
+
+ x.call_bar(obj).should == 'quux'
+ end
+
+ it "does not propagate refinements of new modules added after it is called" do
+ cls = Class.new {def foo; 'foo'; end}
+ cls2 = Class.new {def bar; 'bar'; end}
+ mod = MainSpecs::DATA[:mod] = Module.new do
+ refine(cls) do
+ def foo; 'quux'; end
+ end
+ end
+ x = MainSpecs::DATA[:x] = Object.new
+ eval <<-EOS, TOPLEVEL_BINDING
+ using MainSpecs::DATA[:mod]
+ x = MainSpecs::DATA[:x]
+ def x.call_foo(obj)
+ obj.foo
+ end
+ def x.call_bar(obj)
+ obj.bar
+ end
+ EOS
+
+ x.call_foo(cls.new).should == 'quux'
+
+ mod.module_eval do
+ refine(cls2) do
+ def bar; 'quux'; end
+ end
+ end
+
+ x.call_bar(cls2.new).should == 'bar'
+ end
+ end
+end
diff --git a/spec/ruby/core/module/fixtures/refine.rb b/spec/ruby/core/module/fixtures/refine.rb
new file mode 100644
index 0000000000..46975361dd
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/refine.rb
@@ -0,0 +1,13 @@
+module ModuleSpecs
+ class ClassWithFoo
+ def foo; "foo" end
+ end
+
+ module PrependedModule
+ def foo; "foo from prepended module"; end
+ end
+
+ module IncludedModule
+ def foo; "foo from included module"; end
+ end
+end
diff --git a/spec/ruby/core/module/fixtures/using.rb b/spec/ruby/core/module/fixtures/using.rb
new file mode 100644
index 0000000000..0ed9355af1
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/using.rb
@@ -0,0 +1,10 @@
+module ModuleSpecs
+ module EmptyRefinement
+ end
+
+ module RefinementForStringToS
+ refine String do
+ def to_s; "hello from refinement"; end
+ end
+ end
+end
diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb
new file mode 100644
index 0000000000..03e70915e2
--- /dev/null
+++ b/spec/ruby/core/module/refine_spec.rb
@@ -0,0 +1,616 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+require File.expand_path('../fixtures/refine', __FILE__)
+
+describe "Module#refine" do
+ it "runs its block in an anonymous module" do
+ inner_self = nil
+ mod = Module.new do
+ refine String do
+ inner_self = self
+ end
+ end
+
+ mod.should_not == inner_self
+ inner_self.should be_kind_of(Module)
+ inner_self.name.should == nil
+ end
+
+ it "uses the same anonymous module for future refines of the same class" do
+ selves = []
+ mod = Module.new do
+ refine String do
+ selves << self
+ end
+ end
+
+ mod.module_eval do
+ refine String do
+ selves << self
+ end
+ end
+
+ selves[0].should == selves[1]
+ end
+
+ it "adds methods defined in its block to the anonymous module's public instance methods" do
+ inner_self = nil
+ mod = Module.new do
+ refine String do
+ def blah
+ "blah"
+ end
+ inner_self = self
+ end
+ end
+
+ inner_self.public_instance_methods.should include(:blah)
+ end
+
+ it "returns created anonymous module" do
+ inner_self = nil
+ result = nil
+ mod = Module.new do
+ result = refine String do
+ inner_self = self
+ end
+ end
+
+ result.should == inner_self
+ end
+
+ it "raises ArgumentError if not passed an argument" do
+ lambda do
+ Module.new do
+ refine {}
+ end
+ end.should raise_error(ArgumentError)
+ end
+
+ it "raises TypeError if not passed a class" do
+ lambda do
+ Module.new do
+ refine("foo") {}
+ end
+ end.should raise_error(TypeError)
+ end
+
+ ruby_version_is "" ... "2.4" do
+ it "raises TypeError if passed a module" do
+ lambda do
+ Module.new do
+ refine(Enumerable) {}
+ end
+ end.should raise_error(TypeError)
+ end
+ end
+
+ ruby_version_is "2.4" do
+ it "accepts a module as argument" do
+ inner_self = nil
+ Module.new do
+ refine(Enumerable) do
+ def blah
+ end
+ inner_self = self
+ end
+ end
+
+ inner_self.public_instance_methods.should include(:blah)
+ end
+ end
+
+ it "raises ArgumentError if not given a block" do
+ lambda do
+ Module.new do
+ refine String
+ end
+ end.should raise_error(ArgumentError)
+ end
+
+ it "applies refinements to calls in the refine block" do
+ result = nil
+ Module.new do
+ refine(String) do
+ def foo; "foo"; end
+ result = "hello".foo
+ end
+ end
+ result.should == "foo"
+ end
+
+ it "doesn't apply refinements outside the refine block" do
+ Module.new do
+ refine(String) {def foo; "foo"; end}
+ -> () {
+ "hello".foo
+ }.should raise_error(NoMethodError)
+ end
+ end
+
+ it "does not apply refinements to external scopes not using the module" do
+ Module.new do
+ refine(String) {def foo; 'foo'; end}
+ end
+
+ lambda {"hello".foo}.should raise_error(NoMethodError)
+ end
+
+ # When defining multiple refinements in the same module,
+ # inside a refine block all refinements from the same
+ # module are active when a refined method is called
+ it "makes available all refinements from the same module" do
+ refinement = Module.new do
+ refine Integer do
+ def to_json_format
+ to_s
+ end
+ end
+
+ refine Array do
+ def to_json_format
+ "[" + map { |i| i.to_json_format }.join(", ") + "]"
+ end
+ end
+
+ refine Hash do
+ def to_json_format
+ "{" + map { |k, v| k.to_s.dump + ": " + v.to_json_format }.join(", ") + "}"
+ end
+ end
+ end
+
+ result = nil
+
+ Module.new do
+ using refinement
+
+ result = [{1 => 2}, {3 => 4}].to_json_format
+ end
+
+ result.should == '[{"1": 2}, {"3": 4}]'
+ end
+
+ it "does not make available methods from another refinement module" do
+ refinery_integer = Module.new do
+ refine Integer do
+ def to_json_format
+ to_s
+ end
+ end
+ end
+
+ refinery_array = Module.new do
+ refine Array do
+ def to_json_format
+ "[" + map { |i| i.to_json_format }.join(",") + "]"
+ end
+ end
+ end
+
+ result = nil
+
+ -> () {
+ Module.new do
+ using refinery_integer
+ using refinery_array
+
+ [1, 2].to_json_format
+ end
+ }.should raise_error(NoMethodError)
+ end
+
+ # method lookup:
+ # * The prepended modules from the refinement for C
+ # * The refinement for C
+ # * The included modules from the refinement for C
+ # * The prepended modules of C
+ # * C
+ # * The included modules of C
+ describe "method lookup" do
+ it "looks in the object singleton class first" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+
+ obj = ModuleSpecs::ClassWithFoo.new
+ class << obj
+ def foo; "foo from singleton class"; end
+ end
+ result = obj.foo
+ end
+
+ result.should == "foo from singleton class"
+ end
+
+ it "looks in prepended modules from the refinement first" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ include ModuleSpecs::IncludedModule
+ prepend ModuleSpecs::PrependedModule
+
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.foo
+ end
+
+ result.should == "foo from prepended module"
+ end
+
+ it "looks in refinement then" do
+ refinement = Module.new do
+ refine(ModuleSpecs::ClassWithFoo) do
+ include ModuleSpecs::IncludedModule
+
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.foo
+ end
+
+ result.should == "foo from refinement"
+ end
+
+ it "looks in included modules from the refinement then" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ include ModuleSpecs::IncludedModule
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.foo
+ end
+
+ result.should == "foo from included module"
+ end
+
+ it "looks in the class then" do
+ refinement = Module.new do
+ refine(ModuleSpecs::ClassWithFoo) { }
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.foo
+ end
+
+ result.should == "foo"
+ end
+ end
+
+
+ # methods in a subclass have priority over refinements in a superclass
+ it "does not override methods in subclasses" do
+ subclass = Class.new(ModuleSpecs::ClassWithFoo) do
+ def foo; "foo from subclass"; end
+ end
+
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = subclass.new.foo
+ end
+
+ result.should == "foo from subclass"
+ end
+
+ context "for methods accesses indirectly" do
+ ruby_version_is "" ... "2.4" do
+ it "is not honored by Kernel#send" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.send :foo
+ end
+
+ result.should == "foo"
+ end
+
+ it "is not honored by BasicObject#__send__" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.__send__ :foo
+ end
+
+ result.should == "foo"
+ end
+
+ it "is not honored by Symbol#to_proc" do
+ refinement = Module.new do
+ refine Integer do
+ def to_s
+ "(#{super})"
+ end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = [1, 2, 3].map(&:to_s)
+ end
+
+ result.should == ["1", "2", "3"]
+ end
+ end
+
+ ruby_version_is "2.4" do
+ it "is honored by Kernel#send" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.send :foo
+ end
+
+ result.should == "foo from refinement"
+ end
+
+ it "is honored by BasicObject#__send__" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.__send__ :foo
+ end
+
+ result.should == "foo from refinement"
+ end
+
+ it "is honored by Symbol#to_proc" do
+ refinement = Module.new do
+ refine Integer do
+ def to_s
+ "(#{super})"
+ end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = [1, 2, 3].map(&:to_s)
+ end
+
+ result.should == ["(1)", "(2)", "(3)"]
+ end
+ end
+
+ it "is honored by Kernel#binding" do
+ refinement = Module.new do
+ refine String do
+ def to_s
+ "hello from refinement"
+ end
+ end
+ end
+
+ klass = Class.new do
+ using refinement
+
+ def foo
+ "foo".to_s
+ end
+
+ def get_binding
+ binding
+ end
+ end
+
+ result = Kernel.eval("self.foo()", klass.new.get_binding)
+ result.should == "hello from refinement"
+ end
+
+ it "is not honored by Kernel#method" do
+ klass = Class.new
+ refinement = Module.new do
+ refine klass do
+ def foo; end
+ end
+ end
+
+ -> {
+ Module.new do
+ using refinement
+ klass.new.method(:foo)
+ end
+ }.should raise_error(NameError, /undefined method `foo'/)
+ end
+
+ it "is not honored by Kernel#respond_to?" do
+ klass = Class.new
+ refinement = Module.new do
+ refine klass do
+ def foo; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = klass.new.respond_to?(:foo)
+ end
+
+ result.should == false
+ end
+ end
+
+ context "when super is called in a refinement" do
+ it "looks in the included to refinery module" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ include ModuleSpecs::IncludedModule
+
+ def foo
+ super
+ end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.foo
+ end
+
+ result.should == "foo from included module"
+ end
+
+ it "looks in the refined class" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ def foo
+ super
+ end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = ModuleSpecs::ClassWithFoo.new.foo
+ end
+
+ result.should == "foo"
+ end
+
+ # super in a method of a refinement invokes the method in the refined
+ # class even if there is another refinement which has been activated
+ # in the same context.
+ it "looks in the refined class even if there is another active refinement" do
+ refinement = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ def foo
+ "foo from refinement"
+ end
+ end
+ end
+
+ refinement_with_super = Module.new do
+ refine ModuleSpecs::ClassWithFoo do
+ def foo
+ super
+ end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ using refinement_with_super
+ result = ModuleSpecs::ClassWithFoo.new.foo
+ end
+
+ result.should == "foo"
+ end
+ end
+
+ # Refinements are inherited by module inclusion.
+ # That is, using activates all refinements in the ancestors of the specified module.
+ # Refinements in a descendant have priority over refinements in an ancestor.
+ context "module inclusion" do
+ it "activates all refinements from all ancestors" do
+ refinement_included = Module.new do
+ refine Integer do
+ def to_json_format
+ to_s
+ end
+ end
+ end
+
+ refinement = Module.new do
+ include refinement_included
+
+ refine Array do
+ def to_json_format
+ "[" + map { |i| i.to_s }.join(", ") + "]"
+ end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = [5.to_json_format, [1, 2, 3].to_json_format]
+ end
+
+ result.should == ["5", "[1, 2, 3]"]
+ end
+
+ it "overrides methods of ancestors by methods in descendants" do
+ refinement_included = Module.new do
+ refine Integer do
+ def to_json_format
+ to_s
+ end
+ end
+ end
+
+ refinement = Module.new do
+ include refinement_included
+
+ refine Integer do
+ def to_json_format
+ "hello from refinement"
+ end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = 5.to_json_format
+ end
+
+ result.should == "hello from refinement"
+ end
+ end
+end
+
diff --git a/spec/ruby/core/module/using_spec.rb b/spec/ruby/core/module/using_spec.rb
new file mode 100644
index 0000000000..32e8f8f96b
--- /dev/null
+++ b/spec/ruby/core/module/using_spec.rb
@@ -0,0 +1,276 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+require File.expand_path('../fixtures/using', __FILE__)
+
+describe "Module#using" do
+ it "imports class refinements from module into the current class/module" do
+ refinement = Module.new do
+ refine Integer do
+ def foo; "foo"; end
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = 1.foo
+ end
+
+ result.should == "foo"
+ end
+
+ it "accepts module as argument" do
+ refinement = Module.new do
+ refine Integer do
+ def foo; "foo"; end
+ end
+ end
+
+ -> () {
+ Module.new do
+ using refinement
+ end
+ }.should_not raise_error
+ end
+
+ it "accepts module without refinements" do
+ mod = Module.new
+
+ -> () {
+ Module.new do
+ using mod
+ end
+ }.should_not raise_error
+ end
+
+ it "does not accept class" do
+ klass = Class.new
+
+ -> () {
+ Module.new do
+ using klass
+ end
+ }.should raise_error(TypeError)
+ end
+
+ it "raises TypeError if passed something other than module" do
+ -> () {
+ Module.new do
+ using "foo"
+ end
+ }.should raise_error(TypeError)
+ end
+
+ it "returns self" do
+ refinement = Module.new
+
+ result = nil
+ mod = Module.new do
+ result = using refinement
+ end
+
+ result.should equal(mod)
+ end
+
+ it "works in classes too" do
+ refinement = Module.new do
+ refine Integer do
+ def foo; "foo"; end
+ end
+ end
+
+ result = nil
+ Class.new do
+ using refinement
+ result = 1.foo
+ end
+
+ result.should == "foo"
+ end
+
+ it "raises error in method scope" do
+ mod = Module.new do
+ def self.foo
+ using ModuleSpecs::EmptyRefinement
+ end
+ end
+
+ -> () {
+ mod.foo
+ }.should raise_error(RuntimeError, /Module#using is not permitted in methods/)
+ end
+
+ it "activates refinement even for existed objects" do
+ result = nil
+
+ Module.new do
+ klass = Class.new do
+ def foo; "foo"; end
+ end
+
+ refinement = Module.new do
+ refine klass do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ obj = klass.new
+ using refinement
+ result = obj.foo
+ end
+
+ result.should == "foo from refinement"
+ end
+
+ it "activates updates when refinement reopens later" do
+ result = nil
+
+ Module.new do
+ klass = Class.new do
+ def foo; "foo"; end
+ end
+
+ refinement = Module.new do
+ refine klass do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ using refinement
+
+ refinement.class_eval do
+ refine klass do
+ def foo; "foo from reopened refinement"; end
+ end
+ end
+
+ obj = klass.new
+ result = obj.foo
+ end
+
+ result.should == "foo from reopened refinement"
+ end
+
+ describe "scope of refinement" do
+ it "is active until the end of current class/module" do
+ ScratchPad.record []
+
+ Module.new do
+ Class.new do
+ using ModuleSpecs::RefinementForStringToS
+ ScratchPad << "1".to_s
+ end
+
+ ScratchPad << "1".to_s
+ end
+
+ ScratchPad.recorded.should == ["hello from refinement", "1"]
+ end
+
+ # Refinements are lexical in scope.
+ # Refinements are only active within a scope after the call to using.
+ # Any code before the using statement will not have the refinement activated.
+ it "is not active before the `using` call" do
+ ScratchPad.record []
+
+ Module.new do
+ Class.new do
+ ScratchPad << "1".to_s
+ using ModuleSpecs::RefinementForStringToS
+ ScratchPad << "1".to_s
+ end
+ end
+
+ ScratchPad.recorded.should == ["1", "hello from refinement"]
+ end
+
+ # If you call a method that is defined outside the current scope
+ # the refinement will be deactivated
+ it "is not active for code defined outside the current scope" do
+ result = nil
+
+ Module.new do
+ klass = Class.new do
+ def foo; "foo"; end
+ end
+
+ refinement = Module.new do
+ refine klass do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ def self.call_foo(c)
+ c.foo
+ end
+
+ using refinement
+
+ result = call_foo(klass.new)
+ end
+
+ result.should == "foo"
+ end
+
+ # If a method is defined in a scope where a refinement is active
+ # the refinement will be active when the method is called.
+ it "is active for method defined in a scope wherever it's called" do
+ klass = Class.new do
+ def foo; "foo"; end
+ end
+
+ mod = Module.new do
+ refinement = Module.new do
+ refine klass do
+ def foo; "foo from refinement"; end
+ end
+ end
+
+ using refinement
+
+ def self.call_foo(c)
+ c.foo
+ end
+ end
+
+ c = klass.new
+ mod.call_foo(c).should == "foo from refinement"
+ end
+
+ it "is not active if `using` call is not evaluated" do
+ result = nil
+
+ Module.new do
+ if false
+ using ModuleSpecs::RefinementForStringToS
+ end
+ result = "1".to_s
+ end
+
+ result.should == "1"
+ end
+
+ # The refinements in module are not activated automatically
+ # if the class is reopened later
+ it "is not active when class/module reopens" do
+ refinement = Module.new do
+ refine String do
+ def to_s
+ "hello from refinement"
+ end
+ end
+ end
+
+ result = []
+ klass = Class.new do
+ using refinement
+ result << "1".to_s
+ end
+
+ klass.class_eval do
+ result << "1".to_s
+ end
+
+ result.should == ["hello from refinement", "1"]
+ end
+ end
+end
diff --git a/spec/ruby/core/mutex/lock_spec.rb b/spec/ruby/core/mutex/lock_spec.rb
index 98deabe056..b5c2b168e8 100644
--- a/spec/ruby/core/mutex/lock_spec.rb
+++ b/spec/ruby/core/mutex/lock_spec.rb
@@ -33,14 +33,9 @@ describe "Mutex#lock" do
# related to this ML thread.
it "raises a ThreadError when used recursively" do
m = Mutex.new
-
- th = Thread.new do
- m.lock
+ m.lock
+ -> {
m.lock
- end
-
- lambda do
- th.join
- end.should raise_error(ThreadError)
+ }.should raise_error(ThreadError)
end
end
diff --git a/spec/ruby/core/nil/dup_spec.rb b/spec/ruby/core/nil/dup_spec.rb
new file mode 100644
index 0000000000..10b1209736
--- /dev/null
+++ b/spec/ruby/core/nil/dup_spec.rb
@@ -0,0 +1,9 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is '2.4' do
+ describe "NilClass#dup" do
+ it "returns self" do
+ nil.dup.should equal(nil)
+ end
+ end
+end
diff --git a/spec/ruby/core/numeric/coerce_spec.rb b/spec/ruby/core/numeric/coerce_spec.rb
index 9b6297d5da..820d900dd5 100644
--- a/spec/ruby/core/numeric/coerce_spec.rb
+++ b/spec/ruby/core/numeric/coerce_spec.rb
@@ -17,7 +17,7 @@ describe "Numeric#coerce" do
# I (emp) think that this behavior is actually a bug in MRI. It's here as documentation
# of the behavior until we find out if it's a bug.
quarantine! do
- it "considers the presense of a metaclass when checking the class of the objects" do
+ it "considers the presence of a metaclass when checking the class of the objects" do
a = NumericSpecs::Subclass.new
b = NumericSpecs::Subclass.new
diff --git a/spec/ruby/core/numeric/finite_spec.rb b/spec/ruby/core/numeric/finite_spec.rb
new file mode 100644
index 0000000000..9fb2252845
--- /dev/null
+++ b/spec/ruby/core/numeric/finite_spec.rb
@@ -0,0 +1,10 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.4" do
+ describe "Numeric#finite?" do
+ it "returns true by default" do
+ o = mock_numeric("finite")
+ o.finite?.should be_true
+ end
+ end
+end
diff --git a/spec/ruby/core/numeric/infinite_spec.rb b/spec/ruby/core/numeric/infinite_spec.rb
new file mode 100644
index 0000000000..a527cb4370
--- /dev/null
+++ b/spec/ruby/core/numeric/infinite_spec.rb
@@ -0,0 +1,10 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.4" do
+ describe "Numeric#infinite?" do
+ it "returns nil by default" do
+ o = mock_numeric("infinite")
+ o.infinite?.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/core/process/wait2_spec.rb b/spec/ruby/core/process/wait2_spec.rb
index 8e1ac763f1..d1f3a47b7f 100644
--- a/spec/ruby/core/process/wait2_spec.rb
+++ b/spec/ruby/core/process/wait2_spec.rb
@@ -5,8 +5,11 @@ describe "Process.wait2" do
# HACK: this kludge is temporarily necessary because some
# misbehaving spec somewhere else does not clear processes
begin
+ Process.wait(-1, Process::WNOHANG)
+ $stderr.puts "Leaked process before wait2 specs! Waiting for it"
leaked = Process.waitall
- puts "leaked before wait2 specs: #{leaked}" unless leaked.empty?
+ $stderr.puts "leaked before wait2 specs: #{leaked}"
+ rescue Errno::ECHILD # No child processes
rescue NotImplementedError
end
end
diff --git a/spec/ruby/core/random/bytes_spec.rb b/spec/ruby/core/random/bytes_spec.rb
index 2434a4e72e..d954261329 100644
--- a/spec/ruby/core/random/bytes_spec.rb
+++ b/spec/ruby/core/random/bytes_spec.rb
@@ -19,14 +19,14 @@ describe "Random#bytes" do
end
# Should double check this is official spec
- it "returns the same numeric output for a given seed accross all implementations and platforms" do
+ it "returns the same numeric output for a given seed across all implementations and platforms" do
rnd = Random.new(33)
rnd.bytes(2).should == "\x14\\"
rnd.bytes(1000) # skip some
rnd.bytes(2).should == "\xA1p"
end
- it "returns the same numeric output for a given huge seed accross all implementations and platforms" do
+ it "returns the same numeric output for a given huge seed across all implementations and platforms" do
rnd = Random.new(bignum_value ** 4)
rnd.bytes(2).should == "_\x91"
rnd.bytes(1000) # skip some
diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb
index e2d2b68caa..497e1453cd 100644
--- a/spec/ruby/core/string/capitalize_spec.rb
+++ b/spec/ruby/core/string/capitalize_spec.rb
@@ -44,6 +44,14 @@ describe "String#capitalize!" do
a.should == "Hello"
end
+ ruby_version_is '2.4' do
+ it "capitalizes self in place for all of Unicode" do
+ a = "äöü"
+ a.capitalize!.should equal(a)
+ a.should == "Äöü"
+ end
+ end
+
it "returns nil when no changes are made" do
a = "Hello"
a.capitalize!.should == nil
diff --git a/spec/ruby/core/string/casecmp_spec.rb b/spec/ruby/core/string/casecmp_spec.rb
index fdb888ff2b..c77d97815c 100644
--- a/spec/ruby/core/string/casecmp_spec.rb
+++ b/spec/ruby/core/string/casecmp_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: ascii-8bit -*-
+# -*- encoding: utf-8 -*-
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../fixtures/classes.rb', __FILE__)
@@ -40,10 +40,10 @@ describe "String#casecmp independent of case" do
describe "in UTF-8 mode" do
describe "for non-ASCII characters" do
before :each do
- @upper_a_tilde = "\xc3\x83"
- @lower_a_tilde = "\xc3\xa3"
- @upper_a_umlaut = "\xc3\x84"
- @lower_a_umlaut = "\xc3\xa4"
+ @upper_a_tilde = "Ã"
+ @lower_a_tilde = "ã"
+ @upper_a_umlaut = "Ä"
+ @lower_a_umlaut = "ä"
end
it "returns -1 when numerically less than other" do
@@ -118,3 +118,67 @@ describe "String#casecmp independent of case" do
end
end
end
+
+ruby_version_is "2.4" do
+ describe 'String#casecmp? independent of case' do
+ it 'returns true when equal to other' do
+ 'abc'.casecmp?('abc').should == true
+ 'abc'.casecmp?('ABC').should == true
+ end
+
+ it 'returns false when not equal to other' do
+ 'abc'.casecmp?('DEF').should == false
+ 'abc'.casecmp?('def').should == false
+ end
+
+ it "tries to convert other to string using to_str" do
+ other = mock('x')
+ other.should_receive(:to_str).and_return("abc")
+
+ "abc".casecmp?(other).should == true
+ end
+
+ describe 'for UNICODE characters' do
+ it 'returns true when downcase(:fold) on unicode' do
+ 'äöü'.casecmp?('ÄÖÜ').should == true
+ end
+ end
+
+ describe "when comparing a subclass instance" do
+ it 'returns true when equal to other' do
+ a = StringSpecs::MyString.new "a"
+ 'a'.casecmp?(a).should == true
+ 'A'.casecmp?(a).should == true
+ end
+
+ it 'returns false when not equal to other' do
+ b = StringSpecs::MyString.new "a"
+ 'b'.casecmp?(b).should == false
+ 'B'.casecmp?(b).should == false
+ end
+ end
+
+ describe "in UTF-8 mode" do
+ describe "for non-ASCII characters" do
+ before :each do
+ @upper_a_tilde = "Ã"
+ @lower_a_tilde = "ã"
+ @upper_a_umlaut = "Ä"
+ @lower_a_umlaut = "ä"
+ end
+
+ it "returns true when they are the same with normalized case" do
+ @upper_a_tilde.casecmp?(@lower_a_tilde).should == true
+ end
+
+ it "returns false when they are unrelated" do
+ @upper_a_tilde.casecmp?(@upper_a_umlaut).should == false
+ end
+
+ it "returns true when they have the same bytes" do
+ @upper_a_tilde.casecmp?(@upper_a_tilde).should == true
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb
index 9ebc4f2bd1..f591c0fa09 100644
--- a/spec/ruby/core/string/downcase_spec.rb
+++ b/spec/ruby/core/string/downcase_spec.rb
@@ -46,6 +46,14 @@ describe "String#downcase!" do
a.should == "hello"
end
+ ruby_version_is '2.4' do
+ it "modifies self in place for all of Unicode" do
+ a = "ÄÖÜ"
+ a.downcase!.should equal(a)
+ a.should == "äöü"
+ end
+ end
+
it "returns nil if no modifications were made" do
a = "hello"
a.downcase!.should == nil
diff --git a/spec/ruby/core/string/lines_spec.rb b/spec/ruby/core/string/lines_spec.rb
index 6aa47ea728..e5f24816af 100644
--- a/spec/ruby/core/string/lines_spec.rb
+++ b/spec/ruby/core/string/lines_spec.rb
@@ -10,4 +10,13 @@ describe "String#lines" do
ary = "hello world".send(@method, ' ')
ary.should == ["hello ", "world"]
end
+
+ ruby_version_is '2.4' do
+ context "when `chomp` keyword argument is passed" do
+ it "removes new line characters" do
+ "hello \nworld\n".lines(chomp: true).should == ["hello ", "world"]
+ "hello \r\nworld\r\n".lines(chomp: true).should == ["hello ", "world"]
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/string/new_spec.rb b/spec/ruby/core/string/new_spec.rb
index 0a246f6f53..b429ac48d2 100644
--- a/spec/ruby/core/string/new_spec.rb
+++ b/spec/ruby/core/string/new_spec.rb
@@ -15,6 +15,13 @@ describe "String.new" do
end
end
+ ruby_version_is "2.4" do
+ it "accepts a capacity argument" do
+ String.new("", capacity: 100_000).should == ""
+ String.new("abc", capacity: 100_000).should == "abc"
+ end
+ end
+
it "returns a fully-formed String" do
str = String.new
str.size.should == 0
diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb
index 2f7280a95f..c1cf324dc5 100644
--- a/spec/ruby/core/string/shared/chars.rb
+++ b/spec/ruby/core/string/shared/chars.rb
@@ -42,10 +42,8 @@ describe :string_chars, shared: true do
it "returns a different character if the String is transcoded" do
s = "\u{20AC}".force_encoding('UTF-8')
s.encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
- s.encode('iso-8859-15').send(@method).to_a.should == [
- [0xA4].pack('C').force_encoding('iso-8859-15')]
- s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == [
- "\u{20AC}".force_encoding('UTF-8')]
+ s.encode('iso-8859-15').send(@method).to_a.should == [[0xA4].pack('C').force_encoding('iso-8859-15')]
+ s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
end
it "uses the String's encoding to determine what characters it contains" do
diff --git a/spec/ruby/core/string/shared/codepoints.rb b/spec/ruby/core/string/shared/codepoints.rb
index 1ee13c82f4..68f82b4468 100644
--- a/spec/ruby/core/string/shared/codepoints.rb
+++ b/spec/ruby/core/string/shared/codepoints.rb
@@ -48,7 +48,7 @@ describe :string_codepoints, shared: true do
s.should == s2
end
- it "is synonomous with #bytes for Strings which are single-byte optimisable" do
+ it "is synonymous with #bytes for Strings which are single-byte optimisable" do
s = "(){}".encode('ascii')
s.ascii_only?.should be_true
s.send(@method).to_a.should == s.bytes.to_a
diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb
index fe8b76b47b..dee741e270 100644
--- a/spec/ruby/core/string/shared/each_line.rb
+++ b/spec/ruby/core/string/shared/each_line.rb
@@ -133,4 +133,18 @@ end
it "raises a TypeError when the separator is a symbol" do
lambda { "hello world".send(@method, :o).to_a }.should raise_error(TypeError)
end
+
+ ruby_version_is '2.4' do
+ context "when `chomp` keyword argument is passed" do
+ it "removes new line characters" do
+ a = []
+ "hello \nworld\n".send(@method, chomp: true) { |s| a << s }
+ a.should == ["hello ", "world"]
+
+ a = []
+ "hello \r\nworld\r\n".send(@method, chomp: true) { |s| a << s }
+ a.should == ["hello ", "world"]
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/string/shared/to_sym.rb b/spec/ruby/core/string/shared/to_sym.rb
index 501247078d..1180d64712 100644
--- a/spec/ruby/core/string/shared/to_sym.rb
+++ b/spec/ruby/core/string/shared/to_sym.rb
@@ -1,24 +1,63 @@
describe :string_to_sym, shared: true do
it "returns the symbol corresponding to self" do
- "Koala".send(@method).should == :Koala
- 'cat'.send(@method).should == :cat
- '@cat'.send(@method).should == :@cat
- 'cat and dog'.send(@method).should == :"cat and dog"
- "abc=".send(@method).should == :abc=
+ "Koala".send(@method).should equal :Koala
+ 'cat'.send(@method).should equal :cat
+ '@cat'.send(@method).should equal :@cat
+ 'cat and dog'.send(@method).should equal :"cat and dog"
+ "abc=".send(@method).should equal :abc=
end
it "does not special case +(binary) and -(binary)" do
- "+(binary)".send(@method).should == :"+(binary)"
- "-(binary)".send(@method).should == :"-(binary)"
+ "+(binary)".send(@method).should equal :"+(binary)"
+ "-(binary)".send(@method).should equal :"-(binary)"
end
it "does not special case certain operators" do
- [ ["!@", :"!@"],
- ["~@", :"~@"],
- ["!(unary)", :"!(unary)"],
- ["~(unary)", :"~(unary)"],
- ["+(unary)", :"+(unary)"],
- ["-(unary)", :"-(unary)"]
- ].should be_computed_by(@method)
+ "!@".send(@method).should equal :"!@"
+ "~@".send(@method).should equal :"~@"
+ "!(unary)".send(@method).should equal :"!(unary)"
+ "~(unary)".send(@method).should equal :"~(unary)"
+ "+(unary)".send(@method).should equal :"+(unary)"
+ "-(unary)".send(@method).should equal :"-(unary)"
+ end
+
+ it "returns a US-ASCII Symbol for a UTF-8 String containing only US-ASCII characters" do
+ sym = "foobar".send(@method)
+ sym.encoding.should == Encoding::US_ASCII
+ sym.should equal :"foobar"
+ end
+
+ it "returns a US-ASCII Symbol for a binary String containing only US-ASCII characters" do
+ sym = "foobar".b.send(@method)
+ sym.encoding.should == Encoding::US_ASCII
+ sym.should equal :"foobar"
+ end
+
+ it "returns a UTF-8 Symbol for a UTF-8 String containing non US-ASCII characters" do
+ sym = "il était une fois".send(@method)
+ sym.encoding.should == Encoding::UTF_8
+ sym.should equal :"il était une #{'fois'}"
+ end
+
+ it "returns a UTF-16LE Symbol for a UTF-16LE String containing non US-ASCII characters" do
+ utf16_str = "UtéF16".encode(Encoding::UTF_16LE)
+ sym = utf16_str.send(@method)
+ sym.encoding.should == Encoding::UTF_16LE
+ sym.to_s.should == utf16_str
+ end
+
+ it "returns a binary Symbol for a binary String containing non US-ASCII characters" do
+ binary_string = "binarí".b
+ sym = binary_string.send(@method)
+ sym.encoding.should == Encoding::BINARY
+ sym.to_s.should == binary_string
+ end
+
+ it "raises an EncodingError for UTF-8 String containing invalid bytes" do
+ invalid_utf8 = "\xC3"
+ invalid_utf8.valid_encoding?.should == false
+ -> {
+ invalid_utf8.send(@method)
+ }.should raise_error(EncodingError, /invalid/)
end
end
diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb
index e9af647727..c2b583acab 100644
--- a/spec/ruby/core/string/swapcase_spec.rb
+++ b/spec/ruby/core/string/swapcase_spec.rb
@@ -41,6 +41,14 @@ describe "String#swapcase!" do
a.should == "CyBeR_pUnK11"
end
+ ruby_version_is '2.4' do
+ it "modifies self in place for all of Unicode" do
+ a = "äÖü"
+ a.swapcase!.should equal(a)
+ a.should == "ÄöÜ"
+ end
+ end
+
it "returns nil if no modifications were made" do
a = "+++---111222???"
a.swapcase!.should == nil
diff --git a/spec/ruby/core/string/unpack1_spec.rb b/spec/ruby/core/string/unpack1_spec.rb
new file mode 100644
index 0000000000..6941bc1173
--- /dev/null
+++ b/spec/ruby/core/string/unpack1_spec.rb
@@ -0,0 +1,12 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.4" do
+ describe "String#unpack1" do
+ it "returns the first value of #unpack" do
+ "ABCD".unpack1('x3C').should == "ABCD".unpack('x3C')[0]
+ "\u{3042 3044 3046}".unpack1("U*").should == 0x3042
+ "aG9nZWZ1Z2E=".unpack1("m").should == "hogefuga"
+ "A".unpack1("B*").should == "01000001"
+ end
+ end
+end
diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb
index 2fdcce86b9..0094380664 100644
--- a/spec/ruby/core/string/upcase_spec.rb
+++ b/spec/ruby/core/string/upcase_spec.rb
@@ -46,6 +46,15 @@ describe "String#upcase!" do
a.should == "HELLO"
end
+
+ ruby_version_is '2.4' do
+ it "modifies self in place for all of Unicode" do
+ a = "äöü"
+ a.upcase!.should equal(a)
+ a.should == "ÄÖÜ"
+ end
+ end
+
it "returns nil if no modifications were made" do
a = "HELLO"
a.upcase!.should == nil
diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb
index 59fc5ef9aa..989459114a 100644
--- a/spec/ruby/core/struct/initialize_spec.rb
+++ b/spec/ruby/core/struct/initialize_spec.rb
@@ -37,7 +37,7 @@ describe "Struct#initialize" do
car.make.should == nil # still nil despite override in Honda#initialize b/c of super order
end
- it "can be overriden" do
+ it "can be overridden" do
StructClasses::SubclassX.new(:y).new.key.should == :value
end
end
diff --git a/spec/ruby/core/symbol/capitalize_spec.rb b/spec/ruby/core/symbol/capitalize_spec.rb
index cf7e8a007f..73850a2a8c 100644
--- a/spec/ruby/core/symbol/capitalize_spec.rb
+++ b/spec/ruby/core/symbol/capitalize_spec.rb
@@ -21,6 +21,13 @@ describe "Symbol#capitalize" do
end
end
+ ruby_version_is '2.4' do
+ it "capitalizes the first character if it is Unicode" do
+ :"äöü".capitalize.should == :"Äöü"
+ :"aou".capitalize.should == :"Aou"
+ end
+ end
+
it "converts subsequent uppercase ASCII characters to their lowercase equivalents" do
:lOWER.capitalize.should == :Lower
end
diff --git a/spec/ruby/core/symbol/casecmp_spec.rb b/spec/ruby/core/symbol/casecmp_spec.rb
index 942bd15998..352c5b99cb 100644
--- a/spec/ruby/core/symbol/casecmp_spec.rb
+++ b/spec/ruby/core/symbol/casecmp_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# -*- encoding: utf-8 -*-
require File.expand_path('../../../spec_helper', __FILE__)
describe "Symbol#casecmp with Symbol" do
@@ -11,10 +11,10 @@ describe "Symbol#casecmp with Symbol" do
it "doesn't consider non-ascii characters equal that aren't" do
# -- Latin-1 --
- upper_a_tilde = :"\xC3"
- upper_a_umlaut = :"\xC4"
- lower_a_tilde = :"\xE3"
- lower_a_umlaut = :"\xE4"
+ upper_a_tilde = "\xC3".b.to_sym
+ upper_a_umlaut = "\xC4".b.to_sym
+ lower_a_tilde = "\xE3".b.to_sym
+ lower_a_umlaut = "\xE4".b.to_sym
lower_a_tilde.casecmp(lower_a_umlaut).should_not == 0
lower_a_umlaut.casecmp(lower_a_tilde).should_not == 0
@@ -22,10 +22,10 @@ describe "Symbol#casecmp with Symbol" do
upper_a_umlaut.casecmp(upper_a_tilde).should_not == 0
# -- UTF-8 --
- upper_a_tilde = :"\xC3\x83"
- upper_a_umlaut = :"\xC3\x84"
- lower_a_tilde = :"\xC3\xA3"
- lower_a_umlaut = :"\xC3\xA4"
+ upper_a_tilde = :"Ã"
+ lower_a_tilde = :"ã"
+ upper_a_umlaut = :"Ä"
+ lower_a_umlaut = :"ä"
lower_a_tilde.casecmp(lower_a_umlaut).should_not == 0
lower_a_umlaut.casecmp(lower_a_tilde).should_not == 0
@@ -35,10 +35,10 @@ describe "Symbol#casecmp with Symbol" do
it "doesn't do case mapping for non-ascii characters" do
# -- Latin-1 --
- upper_a_tilde = :"\xC3"
- upper_a_umlaut = :"\xC4"
- lower_a_tilde = :"\xE3"
- lower_a_umlaut = :"\xE4"
+ upper_a_tilde = "\xC3".b.to_sym
+ upper_a_umlaut = "\xC4".b.to_sym
+ lower_a_tilde = "\xE3".b.to_sym
+ lower_a_umlaut = "\xE4".b.to_sym
upper_a_tilde.casecmp(lower_a_tilde).should == -1
upper_a_umlaut.casecmp(lower_a_umlaut).should == -1
@@ -46,10 +46,10 @@ describe "Symbol#casecmp with Symbol" do
lower_a_umlaut.casecmp(upper_a_umlaut).should == 1
# -- UTF-8 --
- upper_a_tilde = :"\xC3\x83"
- upper_a_umlaut = :"\xC3\x84"
- lower_a_tilde = :"\xC3\xA3"
- lower_a_umlaut = :"\xC3\xA4"
+ upper_a_tilde = :"Ã"
+ lower_a_tilde = :"ã"
+ upper_a_umlaut = :"Ä"
+ lower_a_umlaut = :"ä"
upper_a_tilde.casecmp(lower_a_tilde).should == -1
upper_a_umlaut.casecmp(lower_a_umlaut).should == -1
@@ -72,3 +72,75 @@ describe "Symbol#casecmp" do
:abc.casecmp(obj).should be_nil
end
end
+
+ruby_version_is "2.4" do
+ describe 'Symbol#casecmp?' do
+ it "compares symbols without regard to case" do
+ :abcdef.casecmp?(:abcde).should == false
+ :aBcDeF.casecmp?(:abcdef).should == true
+ :abcdef.casecmp?(:abcdefg).should == false
+ :abcdef.casecmp?(:ABCDEF).should == true
+ end
+
+ it "doesn't consider non-ascii characters equal that aren't" do
+ # -- Latin-1 --
+ upper_a_tilde = "\xC3".b.to_sym
+ upper_a_umlaut = "\xC4".b.to_sym
+ lower_a_tilde = "\xE3".b.to_sym
+ lower_a_umlaut = "\xE4".b.to_sym
+
+ lower_a_tilde.casecmp?(lower_a_umlaut).should_not == true
+ lower_a_umlaut.casecmp?(lower_a_tilde).should_not == true
+ upper_a_tilde.casecmp?(upper_a_umlaut).should_not == true
+ upper_a_umlaut.casecmp?(upper_a_tilde).should_not == true
+
+ # -- UTF-8 --
+ upper_a_tilde = :"Ã"
+ lower_a_tilde = :"ã"
+ upper_a_umlaut = :"Ä"
+ lower_a_umlaut = :"ä"
+
+ lower_a_tilde.casecmp?(lower_a_umlaut).should_not == true
+ lower_a_umlaut.casecmp?(lower_a_tilde).should_not == true
+ upper_a_tilde.casecmp?(upper_a_umlaut).should_not == true
+ upper_a_umlaut.casecmp?(upper_a_tilde).should_not == true
+ end
+
+ it "doesn't do case mapping for non-ascii and non-unicode characters" do
+ # -- Latin-1 --
+ upper_a_tilde = "\xC3".b.to_sym
+ upper_a_umlaut = "\xC4".b.to_sym
+ lower_a_tilde = "\xE3".b.to_sym
+ lower_a_umlaut = "\xE4".b.to_sym
+
+ upper_a_tilde.casecmp?(lower_a_tilde).should == false
+ upper_a_umlaut.casecmp?(lower_a_umlaut).should == false
+ lower_a_tilde.casecmp?(upper_a_tilde).should == false
+ lower_a_umlaut.casecmp?(upper_a_umlaut).should == false
+ end
+
+ it 'does case mapping for unicode characters' do
+ # -- UTF-8 --
+ upper_a_tilde = :"Ã"
+ lower_a_tilde = :"ã"
+ upper_a_umlaut = :"Ä"
+ lower_a_umlaut = :"ä"
+
+ upper_a_tilde.casecmp?(lower_a_tilde).should == true
+ upper_a_umlaut.casecmp?(lower_a_umlaut).should == true
+ lower_a_tilde.casecmp?(upper_a_tilde).should == true
+ lower_a_umlaut.casecmp?(upper_a_umlaut).should == true
+ end
+
+ it 'returns nil when comparing characters with different encodings' do
+ # -- Latin-1 --
+ upper_a_tilde = "\xC3".b.to_sym
+
+ # -- UTF-8 --
+ lower_a_tilde = :"ã"
+
+ upper_a_tilde.casecmp?(lower_a_tilde).should == nil
+ lower_a_tilde.casecmp?(upper_a_tilde).should == nil
+ end
+ end
+end
diff --git a/spec/ruby/core/symbol/downcase_spec.rb b/spec/ruby/core/symbol/downcase_spec.rb
index 0b2422ad3e..6eb19e087a 100644
--- a/spec/ruby/core/symbol/downcase_spec.rb
+++ b/spec/ruby/core/symbol/downcase_spec.rb
@@ -20,6 +20,13 @@ describe "Symbol#downcase" do
end
end
+ ruby_version_is '2.4' do
+ it "uncapitalizes all Unicode characters" do
+ "ÄÖÜ".to_sym.downcase.should == :"äöü"
+ "AOU".to_sym.downcase.should == :"aou"
+ end
+ end
+
it "leaves non-alphabetic ASCII characters as they were" do
"Glark?!?".to_sym.downcase.should == :"glark?!?"
end
diff --git a/spec/ruby/core/symbol/dup_spec.rb b/spec/ruby/core/symbol/dup_spec.rb
new file mode 100644
index 0000000000..2ca4d84078
--- /dev/null
+++ b/spec/ruby/core/symbol/dup_spec.rb
@@ -0,0 +1,9 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is '2.4' do
+ describe "Symbol#dup" do
+ it "returns self" do
+ :a_symbol.dup.should equal(:a_symbol)
+ end
+ end
+end
diff --git a/spec/ruby/core/symbol/swapcase_spec.rb b/spec/ruby/core/symbol/swapcase_spec.rb
index fdc42ec477..3124f782bc 100644
--- a/spec/ruby/core/symbol/swapcase_spec.rb
+++ b/spec/ruby/core/symbol/swapcase_spec.rb
@@ -28,6 +28,13 @@ describe "Symbol#swapcase" do
end
end
+ ruby_version_is '2.4' do
+ it "swaps the case for Unicode characters" do
+ "äÖü".to_sym.swapcase.should == :"ÄöÜ"
+ "aOu".to_sym.swapcase.should == :"AoU"
+ end
+ end
+
it "leaves non-alphabetic ASCII characters as they were" do
"Glark?!?".to_sym.swapcase.should == :"gLARK?!?"
end
diff --git a/spec/ruby/core/symbol/upcase_spec.rb b/spec/ruby/core/symbol/upcase_spec.rb
index fce62af100..fe2c88d294 100644
--- a/spec/ruby/core/symbol/upcase_spec.rb
+++ b/spec/ruby/core/symbol/upcase_spec.rb
@@ -16,6 +16,13 @@ describe "Symbol#upcase" do
end
end
+ ruby_version_is '2.4' do
+ it "capitalizes all Unicode characters" do
+ "äöü".to_sym.upcase.should == :"ÄÖÜ"
+ "aou".to_sym.upcase.should == :"AOU"
+ end
+ end
+
it "leaves non-alphabetic ASCII characters as they were" do
"Glark?!?".to_sym.upcase.should == :"GLARK?!?"
end
diff --git a/spec/ruby/core/thread/element_set_spec.rb b/spec/ruby/core/thread/element_set_spec.rb
index 47b4d06328..b76078f685 100644
--- a/spec/ruby/core/thread/element_set_spec.rb
+++ b/spec/ruby/core/thread/element_set_spec.rb
@@ -9,12 +9,12 @@ describe "Thread#[]=" do
it "raises a RuntimeError if the thread is frozen" do
running = false
t = Thread.new do
- Thread.pass until running
t.freeze
- t[:foo] = "bar"
+ -> {
+ t[:foo] = "bar"
+ }.should raise_error(RuntimeError, /frozen/)
end
- running = true
- lambda { t.join }.should raise_error(RuntimeError)
+ t.join
end
it "raises exceptions on the wrong type of keys" do
diff --git a/spec/ruby/core/thread/fixtures/classes.rb b/spec/ruby/core/thread/fixtures/classes.rb
index b572c8dd82..601e515e3e 100644
--- a/spec/ruby/core/thread/fixtures/classes.rb
+++ b/spec/ruby/core/thread/fixtures/classes.rb
@@ -120,7 +120,10 @@ module ThreadSpecs
end
def self.status_of_thread_with_uncaught_exception
- t = Thread.new { raise "error" }
+ t = Thread.new {
+ Thread.current.report_on_exception = false
+ raise "error"
+ }
begin
t.join
rescue RuntimeError
@@ -159,6 +162,7 @@ module ThreadSpecs
def self.dying_thread_ensures(kill_method_name=:kill)
Thread.new do
+ Thread.current.report_on_exception = false
begin
Thread.current.send(kill_method_name)
ensure
@@ -169,6 +173,7 @@ module ThreadSpecs
def self.dying_thread_with_outer_ensure(kill_method_name=:kill)
Thread.new do
+ Thread.current.report_on_exception = false
begin
begin
Thread.current.send(kill_method_name)
diff --git a/spec/ruby/core/thread/join_spec.rb b/spec/ruby/core/thread/join_spec.rb
index a6dd2da9a3..249b3d333e 100644
--- a/spec/ruby/core/thread/join_spec.rb
+++ b/spec/ruby/core/thread/join_spec.rb
@@ -46,7 +46,10 @@ describe "Thread#join" do
end
it "raises any exceptions encountered in the thread body" do
- t = Thread.new { raise NotImplementedError.new("Just kidding") }
+ t = Thread.new {
+ Thread.current.report_on_exception = false
+ raise NotImplementedError.new("Just kidding")
+ }
lambda { t.join }.should raise_error(NotImplementedError)
end
diff --git a/spec/ruby/core/thread/key_spec.rb b/spec/ruby/core/thread/key_spec.rb
index 6cdfc3ca7f..d82a21ab39 100644
--- a/spec/ruby/core/thread/key_spec.rb
+++ b/spec/ruby/core/thread/key_spec.rb
@@ -9,7 +9,7 @@ describe "Thread#key?" do
@th.join
end
- it "tests for existance of thread local variables using symbols or strings" do
+ it "tests for existence of thread local variables using symbols or strings" do
@th.key?(:oliver).should == true
@th.key?("oliver").should == true
@th.key?(:stanley).should == false
diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb
index 93e0f048b1..8724d26202 100644
--- a/spec/ruby/core/thread/raise_spec.rb
+++ b/spec/ruby/core/thread/raise_spec.rb
@@ -51,6 +51,7 @@ describe "Thread#raise on a sleeping thread" do
it "is captured and raised by Thread#value" do
t = Thread.new do
+ Thread.current.report_on_exception = false
sleep
end
@@ -62,6 +63,7 @@ describe "Thread#raise on a sleeping thread" do
it "raises a RuntimeError when called with no arguments inside rescue" do
t = Thread.new do
+ Thread.current.report_on_exception = false
begin
1/0
rescue ZeroDivisionError
@@ -113,6 +115,7 @@ describe "Thread#raise on a running thread" do
it "can go unhandled" do
t = Thread.new do
+ Thread.current.report_on_exception = false
loop { Thread.pass }
end
@@ -123,6 +126,7 @@ describe "Thread#raise on a running thread" do
it "raises the given argument even when there is an active exception" do
raised = false
t = Thread.new do
+ Thread.current.report_on_exception = false
begin
1/0
rescue ZeroDivisionError
@@ -142,6 +146,7 @@ describe "Thread#raise on a running thread" do
it "raises a RuntimeError when called with no arguments inside rescue" do
raised = false
t = Thread.new do
+ Thread.current.report_on_exception = false
begin
1/0
rescue ZeroDivisionError
@@ -164,6 +169,7 @@ describe "Thread#raise on same thread" do
it "raises a RuntimeError when called with no arguments inside rescue" do
t = Thread.new do
+ Thread.current.report_on_exception = false
begin
1/0
rescue ZeroDivisionError
diff --git a/spec/ruby/core/thread/report_on_exception_spec.rb b/spec/ruby/core/thread/report_on_exception_spec.rb
new file mode 100644
index 0000000000..4128dad470
--- /dev/null
+++ b/spec/ruby/core/thread/report_on_exception_spec.rb
@@ -0,0 +1,102 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is "2.4" do
+ describe "Thread.report_on_exception" do
+ it "defaults to false" do
+ ruby_exe("p Thread.report_on_exception").should == "false\n"
+ end
+ end
+
+ describe "Thread.report_on_exception=" do
+ before :each do
+ @report_on_exception = Thread.report_on_exception
+ end
+
+ after :each do
+ Thread.report_on_exception = @report_on_exception
+ end
+
+ it "changes the default value for new threads" do
+ Thread.report_on_exception = true
+ Thread.report_on_exception.should == true
+ t = Thread.new {}
+ t.join
+ t.report_on_exception.should == true
+ end
+ end
+
+ describe "Thread#report_on_exception" do
+ it "returns whether the Thread will print a backtrace if it exits with an exception" do
+ t = Thread.new { Thread.current.report_on_exception = true }
+ t.join
+ t.report_on_exception.should == true
+
+ t = Thread.new { Thread.current.report_on_exception = false }
+ t.join
+ t.report_on_exception.should == false
+ end
+ end
+
+ describe "Thread#report_on_exception=" do
+ describe "when set to true" do
+ it "prints a backtrace on $stderr if it terminates with an exception" do
+ t = nil
+ -> {
+ t = Thread.new {
+ Thread.current.report_on_exception = true
+ raise RuntimeError, "Thread#report_on_exception specs"
+ }
+ Thread.pass while t.alive?
+ }.should output("", /Thread.+terminated with exception.+Thread#report_on_exception specs/m)
+
+ -> {
+ t.join
+ }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ end
+ end
+
+ describe "when set to false" do
+ it "lets the thread terminates silently with an exception" do
+ t = nil
+ -> {
+ t = Thread.new {
+ Thread.current.report_on_exception = false
+ raise RuntimeError, "Thread#report_on_exception specs"
+ }
+ Thread.pass while t.alive?
+ }.should output("", "")
+
+ -> {
+ t.join
+ }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ end
+ end
+
+ ruby_bug "#13163", "2.4"..."2.5" do
+ describe "when used in conjunction with Thread#abort_on_exception" do
+ it "first reports then send the exception back to the main Thread" do
+ t = nil
+ mutex = Mutex.new
+ mutex.lock
+ -> {
+ t = Thread.new {
+ Thread.current.abort_on_exception = true
+ Thread.current.report_on_exception = true
+ mutex.lock
+ mutex.unlock
+ raise RuntimeError, "Thread#report_on_exception specs"
+ }
+
+ -> {
+ mutex.sleep(5)
+ }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ }.should output("", /Thread.+terminated with exception.+Thread#report_on_exception specs/m)
+
+ -> {
+ t.join
+ }.should raise_error(RuntimeError, "Thread#report_on_exception specs")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/thread/shared/exit.rb b/spec/ruby/core/thread/shared/exit.rb
index f15da360fd..0c9198c538 100644
--- a/spec/ruby/core/thread/shared/exit.rb
+++ b/spec/ruby/core/thread/shared/exit.rb
@@ -112,7 +112,7 @@ describe :thread_exit, shared: true do
quarantine! do
- it "propogates inner exception to Thread.join if there is an outer ensure clause" do
+ it "propagates inner exception to Thread.join if there is an outer ensure clause" do
thread = ThreadSpecs.dying_thread_with_outer_ensure(@method) { }
lambda { thread.join }.should raise_error(RuntimeError, "In dying thread")
end
diff --git a/spec/ruby/core/thread/value_spec.rb b/spec/ruby/core/thread/value_spec.rb
index 82c0cbf762..3d900959df 100644
--- a/spec/ruby/core/thread/value_spec.rb
+++ b/spec/ruby/core/thread/value_spec.rb
@@ -7,7 +7,10 @@ describe "Thread#value" do
end
it "re-raises an error for an uncaught exception" do
- t = Thread.new { raise "Hello" }
+ t = Thread.new {
+ Thread.current.report_on_exception = false
+ raise "Hello"
+ }
lambda { t.value }.should raise_error(RuntimeError, "Hello")
end
diff --git a/spec/ruby/core/time/shared/now.rb b/spec/ruby/core/time/shared/now.rb
index f570aeedd2..c35115fcf4 100644
--- a/spec/ruby/core/time/shared/now.rb
+++ b/spec/ruby/core/time/shared/now.rb
@@ -5,4 +5,16 @@ describe :time_now, shared: true do
TimeSpecs::SubTime.send(@method).should be_an_instance_of(TimeSpecs::SubTime)
TimeSpecs::MethodHolder.send(@method).should be_an_instance_of(Time)
end
+
+ it "sets the current time" do
+ now = TimeSpecs::MethodHolder.send(@method)
+ now.to_f.should be_close(Process.clock_gettime(Process::CLOCK_REALTIME), 10.0)
+ end
+
+ it "uses the local timezone" do
+ with_timezone("PDT", -8) do
+ now = TimeSpecs::MethodHolder.send(@method)
+ now.utc_offset.should == (-8 * 60 * 60)
+ end
+ end
end
diff --git a/spec/ruby/core/time/shared/time_params.rb b/spec/ruby/core/time/shared/time_params.rb
index 87b52d9f8d..120d8d3af1 100644
--- a/spec/ruby/core/time/shared/time_params.rb
+++ b/spec/ruby/core/time/shared/time_params.rb
@@ -116,10 +116,8 @@ describe :time_params, shared: true do
end
it "interprets all numerals as base 10" do
- Time.send(@method, "2000", "08", "08", "08", "08", "08").should ==
- Time.send(@method, 2000, 8, 8, 8, 8, 8)
- Time.send(@method, "2000", "09", "09", "09", "09", "09").should ==
- Time.send(@method, 2000, 9, 9, 9, 9, 9)
+ Time.send(@method, "2000", "08", "08", "08", "08", "08").should == Time.send(@method, 2000, 8, 8, 8, 8, 8)
+ Time.send(@method, "2000", "09", "09", "09", "09", "09").should == Time.send(@method, 2000, 9, 9, 9, 9, 9)
end
it "handles fractional seconds as a Float" do
diff --git a/spec/ruby/core/tracepoint/callee_id_spec.rb b/spec/ruby/core/tracepoint/callee_id_spec.rb
new file mode 100644
index 0000000000..b7571027d6
--- /dev/null
+++ b/spec/ruby/core/tracepoint/callee_id_spec.rb
@@ -0,0 +1,20 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+require File.expand_path('../fixtures/classes', __FILE__)
+
+ruby_version_is '2.4' do
+ describe "TracePoint#callee_id" do
+ it "returns the called name of the method being called" do
+ a = []
+ obj = TracePointSpec::ClassWithMethodAlias.new
+
+ TracePoint.new(:call) do |tp|
+ a << tp.callee_id
+ end.enable do
+ obj.m_alias
+ end
+
+ a.should == [:m_alias]
+ end
+ end
+end
+
diff --git a/spec/ruby/core/tracepoint/fixtures/classes.rb b/spec/ruby/core/tracepoint/fixtures/classes.rb
new file mode 100644
index 0000000000..fd22ac319d
--- /dev/null
+++ b/spec/ruby/core/tracepoint/fixtures/classes.rb
@@ -0,0 +1,8 @@
+module TracePointSpec
+ class ClassWithMethodAlias
+ def m
+ end
+ alias_method :m_alias, :m
+ end
+end
+
diff --git a/spec/ruby/core/true/dup_spec.rb b/spec/ruby/core/true/dup_spec.rb
new file mode 100644
index 0000000000..cdf60e5bd6
--- /dev/null
+++ b/spec/ruby/core/true/dup_spec.rb
@@ -0,0 +1,9 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+
+ruby_version_is '2.4' do
+ describe "TrueClass#dup" do
+ it "returns self" do
+ true.dup.should equal(true)
+ end
+ end
+end
diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb
new file mode 100644
index 0000000000..44e9eb707b
--- /dev/null
+++ b/spec/ruby/core/warning/warn_spec.rb
@@ -0,0 +1,60 @@
+require File.expand_path("../../../spec_helper", __FILE__)
+
+describe "Warning.warn" do
+ ruby_version_is "2.4" do
+ it "complains" do
+ -> {
+ Warning.warn("Chunky bacon!")
+ }.should complain("Chunky bacon!")
+ end
+
+ it "extends itself" do
+ Warning.singleton_class.ancestors.should include(Warning)
+ end
+
+ it "has Warning as the method owner" do
+ ruby_exe("p Warning.method(:warn).owner").should == "Warning\n"
+ end
+
+ it "can be overridden" do
+ code = <<-RUBY
+ $stdout.sync = true
+ $stderr.sync = true
+ def Warning.warn(msg)
+ if msg.start_with?("A")
+ puts msg.upcase
+ else
+ super
+ end
+ end
+ Warning.warn("A warning!")
+ Warning.warn("warning from stderr\n")
+ RUBY
+ ruby_exe(code, args: "2>&1").should == %Q[A WARNING!\nwarning from stderr\n]
+ end
+
+ it "is called by parser warnings" do
+ Warning.should_receive(:warn)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ eval "{ key: :value, key: :value2 }"
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+ end
+
+ ruby_version_is "2.5" do
+ it "is called by Kernel.warn" do
+ Warning.should_receive(:warn)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+ end
+end