From a66bc2c01194a9c017c874a30db5b3b6bd95e966 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 28 May 2019 22:41:48 +0200 Subject: [PATCH] Update to ruby/spec@9a501a8 --- spec/ruby/CONTRIBUTING.md | 4 +- spec/ruby/core/enumerable/shared/find.rb | 4 + spec/ruby/core/exception/backtrace_spec.rb | 15 + spec/ruby/core/exception/cause_spec.rb | 12 + spec/ruby/core/file/expand_path_spec.rb | 2 + spec/ruby/core/hash/constructor_spec.rb | 2 +- spec/ruby/core/hash/hash_spec.rb | 8 + spec/ruby/core/hash/merge_spec.rb | 18 + spec/ruby/core/kernel/autoload_spec.rb | 2 +- spec/ruby/core/marshal/dump_spec.rb | 11 +- spec/ruby/core/module/name_spec.rb | 6 +- spec/ruby/core/proc/new_spec.rb | 11 + spec/ruby/core/proc/shared/call_arguments.rb | 22 + spec/ruby/core/regexp/compile_spec.rb | 13 +- spec/ruby/core/regexp/new_spec.rb | 13 +- .../shared/{new_ascii_8bit.rb => new.rb} | 198 +++----- spec/ruby/core/regexp/shared/new_ascii.rb | 464 ------------------ spec/ruby/core/string/uminus_spec.rb | 17 + spec/ruby/language/yield_spec.rb | 4 + .../library/bigdecimal/BigDecimal_spec.rb | 28 ++ spec/ruby/library/bigdecimal/clone_spec.rb | 6 + .../ruby/library/bigdecimal/constants_spec.rb | 76 +++ spec/ruby/library/bigdecimal/dup_spec.rb | 6 + spec/ruby/library/bigdecimal/hash_spec.rb | 30 ++ spec/ruby/library/bigdecimal/inspect_spec.rb | 7 + spec/ruby/library/bigdecimal/shared/clone.rb | 24 + spec/ruby/library/bigdecimal/to_d_spec.rb | 11 + .../library/objectspace/memsize_of_spec.rb | 30 ++ .../reachable_objects_from_spec.rb | 61 +++ .../basicsocket/do_not_reverse_lookup_spec.rb | 64 +++ spec/ruby/library/socket/fixtures/classes.rb | 21 +- .../socket/socket/tcp_server_loop_spec.rb | 9 +- .../socket/socket/udp_server_loop_spec.rb | 14 +- .../socket/socket/unix_server_loop_spec.rb | 9 +- spec/ruby/library/tempfile/open_spec.rb | 8 + spec/ruby/optional/capi/ext/hash_spec.c | 6 + spec/ruby/optional/capi/ext/kernel_spec.c | 12 + spec/ruby/optional/capi/ext/util_spec.c | 25 + spec/ruby/optional/capi/hash_spec.rb | 5 + spec/ruby/optional/capi/kernel_spec.rb | 16 + spec/ruby/optional/capi/util_spec.rb | 44 ++ 41 files changed, 699 insertions(+), 639 deletions(-) rename spec/ruby/core/regexp/shared/{new_ascii_8bit.rb => new.rb} (89%) delete mode 100644 spec/ruby/core/regexp/shared/new_ascii.rb create mode 100644 spec/ruby/library/bigdecimal/clone_spec.rb create mode 100644 spec/ruby/library/bigdecimal/constants_spec.rb create mode 100644 spec/ruby/library/bigdecimal/dup_spec.rb create mode 100644 spec/ruby/library/bigdecimal/hash_spec.rb create mode 100644 spec/ruby/library/bigdecimal/shared/clone.rb create mode 100644 spec/ruby/library/bigdecimal/to_d_spec.rb create mode 100644 spec/ruby/library/objectspace/memsize_of_spec.rb create mode 100644 spec/ruby/library/objectspace/reachable_objects_from_spec.rb diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md index dd33f7bf4fb897..2f9b13837256be 100644 --- a/spec/ruby/CONTRIBUTING.md +++ b/spec/ruby/CONTRIBUTING.md @@ -188,7 +188,7 @@ variables from the implementor spec: `@method` and `@object`, which the implemen Here's an example of a snippet of a shared spec and two specs which integrates it: -``` ruby +```ruby # core/hash/shared/key.rb describe :hash_key_p, shared: true do it "returns true if the key's matching value was false" do @@ -216,7 +216,7 @@ Sometimes, shared specs require more context from the implementor class than a s this by passing a lambda as the method, which will have the scope of the implementor. Here's an example of how this is used currently: -``` ruby +```ruby describe :kernel_sprintf, shared: true do it "raises TypeError exception if cannot convert to Integer" do -> { @method.call("%b", Object.new) }.should raise_error(TypeError) diff --git a/spec/ruby/core/enumerable/shared/find.rb b/spec/ruby/core/enumerable/shared/find.rb index 5c097509cdaa21..3435ce36584c6f 100644 --- a/spec/ruby/core/enumerable/shared/find.rb +++ b/spec/ruby/core/enumerable/shared/find.rb @@ -49,6 +49,10 @@ @empty.send(@method, fail_proc) {|e| true}.should == "yay" end + it "ignores the ifnone argument when nil" do + @numerous.send(@method, nil) {|e| false }.should == nil + end + it "passes through the values yielded by #each_with_index" do [:a, :b].each_with_index.send(@method) { |x, i| ScratchPad << [x, i]; nil } ScratchPad.recorded.should == [[:a, 0], [:b, 1]] diff --git a/spec/ruby/core/exception/backtrace_spec.rb b/spec/ruby/core/exception/backtrace_spec.rb index 70c75bda1e4078..5e140f8d9b4fb5 100644 --- a/spec/ruby/core/exception/backtrace_spec.rb +++ b/spec/ruby/core/exception/backtrace_spec.rb @@ -65,4 +65,19 @@ e.backtrace[0].should == "backtrace first" end end + + it "returns the same array after duping" do + begin + raise + rescue RuntimeError => err + bt = err.backtrace + err.dup.backtrace.should equal(bt) + + new_bt = ['hi'] + err.set_backtrace new_bt + + err.backtrace.should == new_bt + err.dup.backtrace.should equal(new_bt) + end + end end diff --git a/spec/ruby/core/exception/cause_spec.rb b/spec/ruby/core/exception/cause_spec.rb index 007df413666191..cf4aaeb1880e85 100644 --- a/spec/ruby/core/exception/cause_spec.rb +++ b/spec/ruby/core/exception/cause_spec.rb @@ -41,4 +41,16 @@ e.cause.should equal(cause) } end + + it "is not set to the exception itself when it is re-raised" do + -> { + begin + raise RuntimeError + rescue RuntimeError => e + raise e + end + }.should raise_error(RuntimeError) { |e| + e.cause.should == nil + } + end end diff --git a/spec/ruby/core/file/expand_path_spec.rb b/spec/ruby/core/file/expand_path_spec.rb index 90aa44e2c4bea1..1d972023a335ed 100644 --- a/spec/ruby/core/file/expand_path_spec.rb +++ b/spec/ruby/core/file/expand_path_spec.rb @@ -225,6 +225,8 @@ user = ENV.delete("USER") begin Etc.getlogin != nil + rescue + false ensure ENV["USER"] = user end diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb index d32117b5a18a9e..14674a018bd7d6 100644 --- a/spec/ruby/core/hash/constructor_spec.rb +++ b/spec/ruby/core/hash/constructor_spec.rb @@ -54,7 +54,7 @@ end ruby_version_is "2.7" do - it "ignores elements that are not arrays" do + it "raises for elements that are not arrays" do -> { Hash[[:a]].should == {} }.should raise_error(ArgumentError) diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb index 7c26f02640fa44..3649d4d8de0f62 100644 --- a/spec/ruby/core/hash/hash_spec.rb +++ b/spec/ruby/core/hash/hash_spec.rb @@ -11,6 +11,14 @@ { 0=>2, 11=>1 }.hash.should == { 11=>1, 0=>2 }.hash end + it "returns a value in which element values do not cancel each other out" do + { a: 2, b: 2 }.hash.should_not == { a: 7, b: 7 }.hash + end + + it "returns a value in which element keys and values do not cancel each other out" do + { :a => :a }.hash.should_not == { :b => :b }.hash + end + it "generates a hash for recursive hash structures" do h = {} h[:a] = h diff --git a/spec/ruby/core/hash/merge_spec.rb b/spec/ruby/core/hash/merge_spec.rb index e90beae87a8790..54abcb816d411c 100644 --- a/spec/ruby/core/hash/merge_spec.rb +++ b/spec/ruby/core/hash/merge_spec.rb @@ -63,6 +63,24 @@ merge_pairs.should == each_pairs end + it "preserves the order of merged elements" do + h1 = { 1 => 2, 3 => 4, 5 => 6 } + h2 = { 1 => 7 } + merge_pairs = [] + h1.merge(h2).each_pair { |k, v| merge_pairs << [k, v] } + merge_pairs.should == [[1,7], [3, 4], [5, 6]] + end + + it "preserves the order of merged elements for large hashes" do + h1 = {} + h2 = {} + merge_pairs = [] + expected_pairs = [] + (1..100).each { |x| h1[x] = x; h2[101 - x] = x; expected_pairs << [x, 101 - x] } + h1.merge(h2).each_pair { |k, v| merge_pairs << [k, v] } + merge_pairs.should == expected_pairs + end + ruby_version_is "2.6" do it "accepts multiple hashes" do result = { a: 1 }.merge({ b: 2 }, { c: 3 }, { d: 4 }) diff --git a/spec/ruby/core/kernel/autoload_spec.rb b/spec/ruby/core/kernel/autoload_spec.rb index 3e7a63ede0b3b4..68732a69ef73ae 100644 --- a/spec/ruby/core/kernel/autoload_spec.rb +++ b/spec/ruby/core/kernel/autoload_spec.rb @@ -57,7 +57,7 @@ def check_autoload(const) end describe "when Object is frozen" do - it "raises a FrozenError before defining the constant" do + it "raises a #{frozen_error_class} before defining the constant" do ruby_exe(fixture(__FILE__, "autoload_frozen.rb")).should == "#{frozen_error_class} - nil" end end diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb index b041a95d4b9b0b..53a0b3197de024 100644 --- a/spec/ruby/core/marshal/dump_spec.rb +++ b/spec/ruby/core/marshal/dump_spec.rb @@ -449,14 +449,13 @@ def obj.foo; end zone = ":\tzoneI\"\bAST\x06:\x06EF" # Last is 'F' (US-ASCII) [ "#{base}#{offset}#{zone}", "#{base}#{zone}#{offset}" ].should include(dump) end - - it "dumps the zone, but not the offset if zone is UTC" do - dump = Marshal.dump(@utc) - zone = ":\tzoneI\"\bUTC\x06:\x06EF" # Last is 'F' (US-ASCII) - dump.should == "\x04\bIu:\tTime\r#{@utc_dump}\x06#{zone}" - end end + it "dumps the zone, but not the offset if zone is UTC" do + dump = Marshal.dump(@utc) + zone = ":\tzoneI\"\bUTC\x06:\x06EF" # Last is 'F' (US-ASCII) + dump.should == "\x04\bIu:\tTime\r#{@utc_dump}\x06#{zone}" + end end describe "with an Exception" do diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb index 5b0fd88729d1fb..d64684319c0b08 100644 --- a/spec/ruby/core/module/name_spec.rb +++ b/spec/ruby/core/module/name_spec.rb @@ -15,13 +15,13 @@ it "is not nil for a nested module created with the module keyword" do m = Module.new module m::N; end - m::N.name.should =~ /#::N/ + m::N.name.should =~ /\A#::N\z/ end it "changes when the module is reachable through a constant path" do m = Module.new module m::N; end - m::N.name.should =~ /#::N/ + m::N.name.should =~ /\A#::N\z/ ModuleSpecs::Anonymous::WasAnnon = m::N m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon" end @@ -42,7 +42,7 @@ module ModuleToRemove module m::Child; end child = m::Child m.send(:remove_const, :Child) - child.name.should =~ /#::Child/ + child.name.should =~ /\A#::Child\z/ end it "is set when opened with the module keyword" do diff --git a/spec/ruby/core/proc/new_spec.rb b/spec/ruby/core/proc/new_spec.rb index 7579bfe1b6f68b..60a7320e4bed4e 100644 --- a/spec/ruby/core/proc/new_spec.rb +++ b/spec/ruby/core/proc/new_spec.rb @@ -190,6 +190,17 @@ def some_method prc.call.should == "hello" end + + it "uses the implicit block from an enclosing method when called inside a block" do + def some_method + proc do |&block| + Proc.new + end.call { "failing" } + end + prc = some_method { "hello" } + + prc.call.should == "hello" + end end ruby_version_is "2.7" do diff --git a/spec/ruby/core/proc/shared/call_arguments.rb b/spec/ruby/core/proc/shared/call_arguments.rb index 2e510b194eecef..a937bd99d074e0 100644 --- a/spec/ruby/core/proc/shared/call_arguments.rb +++ b/spec/ruby/core/proc/shared/call_arguments.rb @@ -4,4 +4,26 @@ lambda {|&b| b.send(@method)}.send(@method) {1 + 1}.should == 2 proc {|&b| b.send(@method)}.send(@method) {1 + 1}.should == 2 end + + it "yields to the block given at declaration and not to the block argument" do + proc_creator = Object.new + def proc_creator.create + Proc.new do |&b| + yield + end + end + a_proc = proc_creator.create { 7 } + a_proc.send(@method) { 3 }.should == 7 + end + + it "can call its block argument declared with a block argument" do + proc_creator = Object.new + def proc_creator.create(method_name) + Proc.new do |&b| + yield + b.send(method_name) + end + end + a_proc = proc_creator.create(@method) { 7 } + a_proc.call { 3 }.should == 10 + end end diff --git a/spec/ruby/core/regexp/compile_spec.rb b/spec/ruby/core/regexp/compile_spec.rb index 4088c17c3cc7f3..329cb4f753ce92 100644 --- a/spec/ruby/core/regexp/compile_spec.rb +++ b/spec/ruby/core/regexp/compile_spec.rb @@ -1,18 +1,15 @@ require_relative '../../spec_helper' -require_relative 'shared/new_ascii' -require_relative 'shared/new_ascii_8bit' +require_relative 'shared/new' describe "Regexp.compile" do - it_behaves_like :regexp_new_ascii, :compile - it_behaves_like :regexp_new_ascii_8bit, :compile + it_behaves_like :regexp_new, :compile end describe "Regexp.compile given a String" do - it_behaves_like :regexp_new_string_ascii, :compile - it_behaves_like :regexp_new_string_ascii_8bit, :compile + it_behaves_like :regexp_new_string, :compile + it_behaves_like :regexp_new_string_binary, :compile end describe "Regexp.compile given a Regexp" do - it_behaves_like :regexp_new_regexp_ascii, :compile - it_behaves_like :regexp_new_regexp_ascii_8bit, :compile + it_behaves_like :regexp_new_regexp, :compile end diff --git a/spec/ruby/core/regexp/new_spec.rb b/spec/ruby/core/regexp/new_spec.rb index dbac7a5a33824d..8259b61714955b 100644 --- a/spec/ruby/core/regexp/new_spec.rb +++ b/spec/ruby/core/regexp/new_spec.rb @@ -1,20 +1,17 @@ require_relative '../../spec_helper' -require_relative 'shared/new_ascii' -require_relative 'shared/new_ascii_8bit' +require_relative 'shared/new' describe "Regexp.new" do - it_behaves_like :regexp_new_ascii, :new - it_behaves_like :regexp_new_ascii_8bit, :new + it_behaves_like :regexp_new, :new end describe "Regexp.new given a String" do - it_behaves_like :regexp_new_string_ascii, :new - it_behaves_like :regexp_new_string_ascii_8bit, :new + it_behaves_like :regexp_new_string, :new end describe "Regexp.new given a Regexp" do - it_behaves_like :regexp_new_regexp_ascii, :new - it_behaves_like :regexp_new_regexp_ascii_8bit, :new + it_behaves_like :regexp_new_regexp, :new + it_behaves_like :regexp_new_string_binary, :compile end describe "Regexp.new given a Fixnum" do diff --git a/spec/ruby/core/regexp/shared/new_ascii_8bit.rb b/spec/ruby/core/regexp/shared/new.rb similarity index 89% rename from spec/ruby/core/regexp/shared/new_ascii_8bit.rb rename to spec/ruby/core/regexp/shared/new.rb index 5110a0838073e5..e8b80ad7c7a6f8 100644 --- a/spec/ruby/core/regexp/shared/new_ascii_8bit.rb +++ b/spec/ruby/core/regexp/shared/new.rb @@ -1,6 +1,6 @@ # -*- encoding: ascii-8bit -*- -describe :regexp_new_ascii_8bit, shared: true do +describe :regexp_new, shared: true do it "requires one argument and creates a new regular expression object" do Regexp.send(@method, '').is_a?(Regexp).should == true end @@ -24,7 +24,7 @@ class RegexpSpecsSubclassTwo < Regexp; end end end -describe :regexp_new_string_ascii_8bit, shared: true do +describe :regexp_new_string, shared: true do it "uses the String argument as an unescaped literal to construct a Regexp object" do Regexp.send(@method, "^hi{2,3}fo.o$").should == /^hi{2,3}fo.o$/ end @@ -146,6 +146,10 @@ class RegexpSpecsSubclassTwo < Regexp; end lambda { Regexp.send(@method, "\\") }.should raise_error(RegexpError) end + it "does not raise a Regexp error if there is an escaped trailing backslash" do + lambda { Regexp.send(@method, "\\\\") }.should_not raise_error(RegexpError) + end + it "accepts a backspace followed by a character" do Regexp.send(@method, "\\N").should == /#{"\x5c"+"N"}/ end @@ -158,14 +162,6 @@ class RegexpSpecsSubclassTwo < Regexp; end Regexp.send(@method, "\11").should == /#{"\x09"}/ end - it "accepts a three-digit octal value" do - Regexp.send(@method, "\315").should == /#{"\xcd"}/ - end - - it "interprets a digit following a three-digit octal value as a character" do - Regexp.send(@method, "\3762").should == /#{"\xfe2"}/ - end - it "accepts a one-digit hexadecimal value" do Regexp.send(@method, "\x9n").should == /#{"\x09n"}/ end @@ -242,118 +238,6 @@ class RegexpSpecsSubclassTwo < Regexp; end Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/ end - it "accepts '\\c\\n'" do - Regexp.send(@method, "\C-\n").should == /#{"\x0a"}/ - end - - it "accepts '\\c\\t'" do - Regexp.send(@method, "\C-\t").should == /#{"\x09"}/ - end - - it "accepts '\\c\\r'" do - Regexp.send(@method, "\C-\r").should == /#{"\x0d"}/ - end - - it "accepts '\\c\\f'" do - Regexp.send(@method, "\C-\f").should == /#{"\x0c"}/ - end - - it "accepts '\\c\\v'" do - Regexp.send(@method, "\C-\v").should == /#{"\x0b"}/ - end - - it "accepts '\\c\\a'" do - Regexp.send(@method, "\C-\a").should == /#{"\x07"}/ - end - - it "accepts '\\c\\e'" do - Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/ - end - - it "accepts '\\M-\\n'" do - Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/ - end - - it "accepts '\\M-\\t'" do - Regexp.send(@method, "\M-\t").should == /#{"\x89"}/ - end - - it "accepts '\\M-\\r'" do - Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/ - end - - it "accepts '\\M-\\f'" do - Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/ - end - - it "accepts '\\M-\\v'" do - Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/ - end - - it "accepts '\\M-\\a'" do - Regexp.send(@method, "\M-\a").should == /#{"\x87"}/ - end - - it "accepts '\\M-\\e'" do - Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/ - end - - it "accepts '\\M-\\C-\\n'" do - Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/ - end - - it "accepts '\\M-\\C-\\t'" do - Regexp.send(@method, "\M-\t").should == /#{"\x89"}/ - end - - it "accepts '\\M-\\C-\\r'" do - Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/ - end - - it "accepts '\\M-\\C-\\f'" do - Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/ - end - - it "accepts '\\M-\\C-\\v'" do - Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/ - end - - it "accepts '\\M-\\C-\\a'" do - Regexp.send(@method, "\M-\a").should == /#{"\x87"}/ - end - - it "accepts '\\M-\\C-\\e'" do - Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/ - end - - it "accepts '\\M-\\c\\n'" do - Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/ - end - - it "accepts '\\M-\\c\\t'" do - Regexp.send(@method, "\M-\t").should == /#{"\x89"}/ - end - - it "accepts '\\M-\\c\\r'" do - Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/ - end - - it "accepts '\\M-\\c\\f'" do - Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/ - end - - it "accepts '\\M-\\c\\v'" do - Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/ - end - - it "accepts '\\M-\\c\\a'" do - Regexp.send(@method, "\M-\a").should == /#{"\x87"}/ - end - - it "accepts '\\M-\\c\\e'" do - Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/ - end - it "accepts multiple consecutive '\\' characters" do Regexp.send(@method, "\\\\\\N").should == /#{"\\\\\\"+"N"}/ end @@ -494,7 +378,75 @@ class RegexpSpecsSubclassTwo < Regexp; end end end -describe :regexp_new_regexp_ascii_8bit, shared: true do +describe :regexp_new_string_binary, shared: true do + describe "with escaped characters" do + it "accepts a three-digit octal value" do + Regexp.send(@method, "\315").should == /#{"\xcd"}/ + end + + it "interprets a digit following a three-digit octal value as a character" do + Regexp.send(@method, "\3762").should == /#{"\xfe2"}/ + end + + it "accepts '\\M-\\n'" do + Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/ + end + + it "accepts '\\M-\\t'" do + Regexp.send(@method, "\M-\t").should == /#{"\x89"}/ + end + + it "accepts '\\M-\\r'" do + Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/ + end + + it "accepts '\\M-\\f'" do + Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/ + end + + it "accepts '\\M-\\v'" do + Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/ + end + + it "accepts '\\M-\\a'" do + Regexp.send(@method, "\M-\a").should == /#{"\x87"}/ + end + + it "accepts '\\M-\\e'" do + Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/ + end + + it "accepts '\\M-\\C-\\n'" do + Regexp.send(@method, "\M-\C-\n").should == /#{"\x8a"}/ + end + + it "accepts '\\M-\\C-\\t'" do + Regexp.send(@method, "\M-\C-\t").should == /#{"\x89"}/ + end + + it "accepts '\\M-\\C-\\r'" do + Regexp.send(@method, "\M-\C-\r").should == /#{"\x8d"}/ + end + + it "accepts '\\M-\\C-\\f'" do + Regexp.send(@method, "\M-\C-\f").should == /#{"\x8c"}/ + end + + it "accepts '\\M-\\C-\\v'" do + Regexp.send(@method, "\M-\C-\v").should == /#{"\x8b"}/ + end + + it "accepts '\\M-\\C-\\a'" do + Regexp.send(@method, "\M-\C-\a").should == /#{"\x87"}/ + end + + it "accepts '\\M-\\C-\\e'" do + Regexp.send(@method, "\M-\C-\e").should == /#{"\x9b"}/ + end + end +end + +describe :regexp_new_regexp, shared: true do it "uses the argument as a literal to construct a Regexp object" do Regexp.send(@method, /^hi{2,3}fo.o$/).should == /^hi{2,3}fo.o$/ end diff --git a/spec/ruby/core/regexp/shared/new_ascii.rb b/spec/ruby/core/regexp/shared/new_ascii.rb deleted file mode 100644 index 98c458312e832d..00000000000000 --- a/spec/ruby/core/regexp/shared/new_ascii.rb +++ /dev/null @@ -1,464 +0,0 @@ -# -*- encoding: binary -*- -describe :regexp_new_ascii, shared: true do - it "requires one argument and creates a new regular expression object" do - Regexp.send(@method, '').is_a?(Regexp).should == true - end - - it "works by default for subclasses with overridden #initialize" do - class RegexpSpecsSubclass < Regexp - def initialize(*args) - super - @args = args - end - - attr_accessor :args - end - - class RegexpSpecsSubclassTwo < Regexp; end - - RegexpSpecsSubclass.send(@method, "hi").should be_kind_of(RegexpSpecsSubclass) - RegexpSpecsSubclass.send(@method, "hi").args.first.should == "hi" - - RegexpSpecsSubclassTwo.send(@method, "hi").should be_kind_of(RegexpSpecsSubclassTwo) - end -end - -describe :regexp_new_string_ascii, shared: true do - it "uses the String argument as an unescaped literal to construct a Regexp object" do - Regexp.send(@method, "^hi{2,3}fo.o$").should == /^hi{2,3}fo.o$/ - end - - it "raises a RegexpError when passed an incorrect regexp" do - lambda { Regexp.send(@method, "^[$", 0) }.should raise_error(RegexpError) - end - - it "does not set Regexp options if only given one argument" do - r = Regexp.send(@method, 'Hi') - (r.options & Regexp::IGNORECASE).should == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - end - - it "does not set Regexp options if second argument is nil or false" do - r = Regexp.send(@method, 'Hi', nil) - (r.options & Regexp::IGNORECASE).should == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - - r = Regexp.send(@method, 'Hi', false) - (r.options & Regexp::IGNORECASE).should == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - end - - it "sets options from second argument if it is one of the Fixnum option constants" do - r = Regexp.send(@method, 'Hi', Regexp::IGNORECASE) - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - - r = Regexp.send(@method, 'Hi', Regexp::MULTILINE) - (r.options & Regexp::IGNORECASE).should == 0 - (r.options & Regexp::MULTILINE).should_not == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - - not_supported_on :opal do - r = Regexp.send(@method, 'Hi', Regexp::EXTENDED) - (r.options & Regexp::IGNORECASE).should == 0 - (r.options & Regexp::MULTILINE).should == 0 - (r.options & Regexp::EXTENDED).should_not == 1 - end - end - - it "accepts a Fixnum of two or more options ORed together as the second argument" do - r = Regexp.send(@method, 'Hi', Regexp::IGNORECASE | Regexp::EXTENDED) - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should == 0 - (r.options & Regexp::EXTENDED).should_not == 0 - end - - it "treats any non-Fixnum, non-nil, non-false second argument as IGNORECASE" do - r = Regexp.send(@method, 'Hi', Object.new) - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - end - - it "ignores the third argument if it is 'e' or 'euc' (case-insensitive)" do - lambda { - Regexp.send(@method, 'Hi', nil, 'e').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'euc').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'E').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'EUC').encoding.should == Encoding::US_ASCII - }.should complain(/encoding option is ignored/) - end - - it "ignores the third argument if it is 's' or 'sjis' (case-insensitive)" do - lambda { - Regexp.send(@method, 'Hi', nil, 's').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'sjis').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'S').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'SJIS').encoding.should == Encoding::US_ASCII - }.should complain(/encoding option is ignored/) - end - - it "ignores the third argument if it is 'u' or 'utf8' (case-insensitive)" do - lambda { - Regexp.send(@method, 'Hi', nil, 'u').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'utf8').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'U').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'UTF8').encoding.should == Encoding::US_ASCII - }.should complain(/encoding option is ignored/) - end - - it "uses US_ASCII encoding if third argument is 'n' or 'none' (case insensitive) and only ascii characters" do - Regexp.send(@method, 'Hi', nil, 'n').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'none').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'N').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'NONE').encoding.should == Encoding::US_ASCII - end - - it "uses ASCII_8BIT encoding if third argument is 'n' or 'none' (case insensitive) and non-ascii characters" do - a = "(?:[\x8E\xA1-\xFE])" - str = "\A(?:#{a}|x*)\z" - - Regexp.send(@method, str, nil, 'N').encoding.should == Encoding::ASCII_8BIT - Regexp.send(@method, str, nil, 'n').encoding.should == Encoding::ASCII_8BIT - Regexp.send(@method, str, nil, 'none').encoding.should == Encoding::ASCII_8BIT - Regexp.send(@method, str, nil, 'NONE').encoding.should == Encoding::ASCII_8BIT - end - - describe "with escaped characters" do - it "raises a Regexp error if there is a trailing backslash" do - lambda { Regexp.send(@method, "\\") }.should raise_error(RegexpError) - end - - it "does not raise a Regexp error if there is an escaped trailing backslash" do - lambda { Regexp.send(@method, "\\\\") }.should_not raise_error(RegexpError) - end - - it "accepts a backspace followed by a character" do - Regexp.send(@method, "\\N").should == /#{"\x5c"+"N"}/ - end - - it "accepts a one-digit octal value" do - Regexp.send(@method, "\0").should == /#{"\x00"}/ - end - - it "accepts a two-digit octal value" do - Regexp.send(@method, "\11").should == /#{"\x09"}/ - end - - it "accepts a one-digit hexadecimal value" do - Regexp.send(@method, "\x9n").should == /#{"\x09n"}/ - end - - it "accepts a two-digit hexadecimal value" do - Regexp.send(@method, "\x23").should == /#{"\x23"}/ - end - - it "interprets a digit following a two-digit hexadecimal value as a character" do - Regexp.send(@method, "\x420").should == /#{"\x420"}/ - end - - it "raises a RegexpError if \\x is not followed by any hexadecimal digits" do - lambda { Regexp.send(@method, "\\" + "xn") }.should raise_error(RegexpError) - end - - it "accepts an escaped string interpolation" do - Regexp.send(@method, "\#{abc}").should == /#{"\#{abc}"}/ - end - - it "accepts '\\n'" do - Regexp.send(@method, "\n").should == /#{"\x0a"}/ - end - - it "accepts '\\t'" do - Regexp.send(@method, "\t").should == /#{"\x09"}/ - end - - it "accepts '\\r'" do - Regexp.send(@method, "\r").should == /#{"\x0d"}/ - end - - it "accepts '\\f'" do - Regexp.send(@method, "\f").should == /#{"\x0c"}/ - end - - it "accepts '\\v'" do - Regexp.send(@method, "\v").should == /#{"\x0b"}/ - end - - it "accepts '\\a'" do - Regexp.send(@method, "\a").should == /#{"\x07"}/ - end - - it "accepts '\\e'" do - Regexp.send(@method, "\e").should == /#{"\x1b"}/ - end - - it "accepts '\\C-\\n'" do - Regexp.send(@method, "\C-\n").should == /#{"\x0a"}/ - end - - it "accepts '\\C-\\t'" do - Regexp.send(@method, "\C-\t").should == /#{"\x09"}/ - end - - it "accepts '\\C-\\r'" do - Regexp.send(@method, "\C-\r").should == /#{"\x0d"}/ - end - - it "accepts '\\C-\\f'" do - Regexp.send(@method, "\C-\f").should == /#{"\x0c"}/ - end - - it "accepts '\\C-\\v'" do - Regexp.send(@method, "\C-\v").should == /#{"\x0b"}/ - end - - it "accepts '\\C-\\a'" do - Regexp.send(@method, "\C-\a").should == /#{"\x07"}/ - end - - it "accepts '\\C-\\e'" do - Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/ - end - - it "accepts '\\c\\n'" do - Regexp.send(@method, "\C-\n").should == /#{"\x0a"}/ - end - - it "accepts '\\c\\t'" do - Regexp.send(@method, "\C-\t").should == /#{"\x09"}/ - end - - it "accepts '\\c\\r'" do - Regexp.send(@method, "\C-\r").should == /#{"\x0d"}/ - end - - it "accepts '\\c\\f'" do - Regexp.send(@method, "\C-\f").should == /#{"\x0c"}/ - end - - it "accepts '\\c\\v'" do - Regexp.send(@method, "\C-\v").should == /#{"\x0b"}/ - end - - it "accepts '\\c\\a'" do - Regexp.send(@method, "\C-\a").should == /#{"\x07"}/ - end - - it "accepts '\\c\\e'" do - Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/ - end - - it "accepts multiple consecutive '\\' characters" do - Regexp.send(@method, "\\\\\\N").should == /#{"\\\\\\"+"N"}/ - end - - it "accepts characters and escaped octal digits" do - Regexp.send(@method, "abc\076").should == /#{"abc\x3e"}/ - end - - it "accepts escaped octal digits and characters" do - Regexp.send(@method, "\076abc").should == /#{"\x3eabc"}/ - end - - it "accepts characters and escaped hexadecimal digits" do - Regexp.send(@method, "abc\x42").should == /#{"abc\x42"}/ - end - - it "accepts escaped hexadecimal digits and characters" do - Regexp.send(@method, "\x3eabc").should == /#{"\x3eabc"}/ - end - - it "accepts escaped hexadecimal and octal digits" do - Regexp.send(@method, "\061\x42").should == /#{"\x31\x42"}/ - end - - it "accepts \\u{H} for a single Unicode codepoint" do - Regexp.send(@method, "\u{f}").should == /#{"\x0f"}/ - end - - it "accepts \\u{HH} for a single Unicode codepoint" do - Regexp.send(@method, "\u{7f}").should == /#{"\x7f"}/ - end - - it "accepts \\u{HHH} for a single Unicode codepoint" do - Regexp.send(@method, "\u{07f}").should == /#{"\x7f"}/ - end - - it "accepts \\u{HHHH} for a single Unicode codepoint" do - Regexp.send(@method, "\u{0000}").should == /#{"\x00"}/ - end - - it "accepts \\u{HHHHH} for a single Unicode codepoint" do - Regexp.send(@method, "\u{00001}").should == /#{"\x01"}/ - end - - it "accepts \\u{HHHHHH} for a single Unicode codepoint" do - Regexp.send(@method, "\u{000000}").should == /#{"\x00"}/ - end - - it "accepts characters followed by \\u{HHHH}" do - Regexp.send(@method, "abc\u{3042}").should == /#{"abc\u3042"}/ - end - - it "accepts \\u{HHHH} followed by characters" do - Regexp.send(@method, "\u{3042}abc").should == /#{"\u3042abc"}/ - end - - it "accepts escaped hexadecimal digits followed by \\u{HHHH}" do - Regexp.send(@method, "\x42\u{3042}").should == /#{"\x42\u3042"}/ - end - - it "accepts escaped octal digits followed by \\u{HHHH}" do - Regexp.send(@method, "\056\u{3042}").should == /#{"\x2e\u3042"}/ - end - - it "accepts a combination of escaped octal and hexadecimal digits and \\u{HHHH}" do - Regexp.send(@method, "\056\x42\u{3042}\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/ - end - - it "accepts \\uHHHH for a single Unicode codepoint" do - Regexp.send(@method, "\u3042").should == /#{"\u3042"}/ - end - - it "accepts characters followed by \\uHHHH" do - Regexp.send(@method, "abc\u3042").should == /#{"abc\u3042"}/ - end - - it "accepts \\uHHHH followed by characters" do - Regexp.send(@method, "\u3042abc").should == /#{"\u3042abc"}/ - end - - it "accepts escaped hexadecimal digits followed by \\uHHHH" do - Regexp.send(@method, "\x42\u3042").should == /#{"\x42\u3042"}/ - end - - it "accepts escaped octal digits followed by \\uHHHH" do - Regexp.send(@method, "\056\u3042").should == /#{"\x2e\u3042"}/ - end - - it "accepts a combination of escaped octal and hexadecimal digits and \\uHHHH" do - Regexp.send(@method, "\056\x42\u3042\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/ - end - - it "raises a RegexpError if less than four digits are given for \\uHHHH" do - lambda { Regexp.send(@method, "\\" + "u304") }.should raise_error(RegexpError) - end - - it "raises a RegexpError if the \\u{} escape is empty" do - lambda { Regexp.send(@method, "\\" + "u{}") }.should raise_error(RegexpError) - end - - it "raises a RegexpError if more than six hexadecimal digits are given" do - lambda { Regexp.send(@method, "\\" + "u{0ffffff}") }.should raise_error(RegexpError) - end - - it "returns a Regexp with US-ASCII encoding if only 7-bit ASCII characters are present regardless of the input String's encoding" do - Regexp.send(@method, "abc").encoding.should == Encoding::US_ASCII - end - - it "returns a Regexp with source String having US-ASCII encoding if only 7-bit ASCII characters are present regardless of the input String's encoding" do - Regexp.send(@method, "abc").source.encoding.should == Encoding::US_ASCII - end - - it "returns a Regexp with US-ASCII encoding if UTF-8 escape sequences using only 7-bit ASCII are present" do - Regexp.send(@method, "\u{61}").encoding.should == Encoding::US_ASCII - end - - it "returns a Regexp with source String having US-ASCII encoding if UTF-8 escape sequences using only 7-bit ASCII are present" do - Regexp.send(@method, "\u{61}").source.encoding.should == Encoding::US_ASCII - end - - it "returns a Regexp with UTF-8 encoding if any UTF-8 escape sequences outside 7-bit ASCII are present" do - Regexp.send(@method, "\u{ff}").encoding.should == Encoding::UTF_8 - end - - it "returns a Regexp with source String having UTF-8 encoding if any UTF-8 escape sequences outside 7-bit ASCII are present" do - Regexp.send(@method, "\u{ff}").source.encoding.should == Encoding::UTF_8 - end - - it "returns a Regexp with the input String's encoding" do - str = "\x82\xa0".force_encoding(Encoding::Shift_JIS) - Regexp.send(@method, str).encoding.should == Encoding::Shift_JIS - end - - it "returns a Regexp with source String having the input String's encoding" do - str = "\x82\xa0".force_encoding(Encoding::Shift_JIS) - Regexp.send(@method, str).source.encoding.should == Encoding::Shift_JIS - end - end -end - -describe :regexp_new_regexp_ascii, shared: true do - it "uses the argument as a literal to construct a Regexp object" do - Regexp.send(@method, /^hi{2,3}fo.o$/).should == /^hi{2,3}fo.o$/ - end - - it "preserves any options given in the Regexp literal" do - (Regexp.send(@method, /Hi/i).options & Regexp::IGNORECASE).should_not == 0 - (Regexp.send(@method, /Hi/m).options & Regexp::MULTILINE).should_not == 0 - not_supported_on :opal do - (Regexp.send(@method, /Hi/x).options & Regexp::EXTENDED).should_not == 0 - end - - not_supported_on :opal do - r = Regexp.send @method, /Hi/imx - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should_not == 0 - (r.options & Regexp::EXTENDED).should_not == 0 - end - - r = Regexp.send @method, /Hi/ - (r.options & Regexp::IGNORECASE).should == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - end - - it "does not honour options given as additional arguments" do - r = nil - lambda { - r = Regexp.send @method, /hi/, Regexp::IGNORECASE - }.should complain(/flags ignored/) - (r.options & Regexp::IGNORECASE).should == 0 - end - - not_supported_on :opal do - it "sets the encoding to UTF-8 if the Regexp literal has the 'u' option" do - Regexp.send(@method, /Hi/u).encoding.should == Encoding::UTF_8 - end - - it "sets the encoding to EUC-JP if the Regexp literal has the 'e' option" do - Regexp.send(@method, /Hi/e).encoding.should == Encoding::EUC_JP - end - - it "sets the encoding to Windows-31J if the Regexp literal has the 's' option" do - Regexp.send(@method, /Hi/s).encoding.should == Encoding::Windows_31J - end - - it "sets the encoding to US-ASCII if the Regexp literal has the 'n' option and the source String is ASCII only" do - Regexp.send(@method, /Hi/n).encoding.should == Encoding::US_ASCII - end - - it "sets the encoding to source String's encoding if the Regexp literal has the 'n' option and the source String is not ASCII only" do - Regexp.send(@method, Regexp.new("\\xff", nil, 'n')).encoding.should == Encoding::ASCII_8BIT - end - end -end diff --git a/spec/ruby/core/string/uminus_spec.rb b/spec/ruby/core/string/uminus_spec.rb index fd9e8c1d52731d..dace04846c1d6a 100644 --- a/spec/ruby/core/string/uminus_spec.rb +++ b/spec/ruby/core/string/uminus_spec.rb @@ -41,6 +41,23 @@ (-dynamic).should_not equal("this string is frozen".freeze) (-dynamic).should_not equal(-"this string is frozen".freeze) + (-dynamic).should == "this string is frozen" + end + + it "does not deduplicate tainted strings" do + dynamic = %w(this string is frozen).join(' ') + dynamic.taint + (-dynamic).should_not equal("this string is frozen".freeze) + (-dynamic).should_not equal(-"this string is frozen".freeze) + (-dynamic).should == "this string is frozen" + end + + it "does not deduplicate strings with additional instance variables" do + dynamic = %w(this string is frozen).join(' ') + dynamic.instance_variable_set(:@foo, :bar) + (-dynamic).should_not equal("this string is frozen".freeze) + (-dynamic).should_not equal(-"this string is frozen".freeze) + (-dynamic).should == "this string is frozen" end end diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb index e4e84481742cdc..8ab698196aa3d0 100644 --- a/spec/ruby/language/yield_spec.rb +++ b/spec/ruby/language/yield_spec.rb @@ -19,6 +19,10 @@ it "ignores assignment to the explicit block argument and calls the passed block" do @y.ze { 42 }.should == 42 end + + it "does not pass a named block to the block being yielded to" do + @y.z() { |&block| block == nil }.should == true + end end describe "taking a single argument" do diff --git a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb index 2312a4e910ec7f..98b3f47703a60e 100644 --- a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb +++ b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb @@ -100,6 +100,34 @@ neg_inf.should < 0 end + describe "accepts NaN and [+-]Infinity as Float values" do + it "works without an explicit precision" do + BigDecimal(Float::NAN).nan?.should == true + + pos_inf = BigDecimal(Float::INFINITY) + pos_inf.finite?.should == false + pos_inf.should > 0 + pos_inf.should == BigDecimal("+Infinity") + + neg_inf = BigDecimal(-Float::INFINITY) + neg_inf.finite?.should == false + neg_inf.should < 0 + end + + it "works with an explicit precision" do + BigDecimal(Float::NAN, Float::DIG).nan?.should == true + + pos_inf = BigDecimal(Float::INFINITY, Float::DIG) + pos_inf.finite?.should == false + pos_inf.should > 0 + pos_inf.should == BigDecimal("+Infinity") + + neg_inf = BigDecimal(-Float::INFINITY, Float::DIG) + neg_inf.finite?.should == false + neg_inf.should < 0 + end + end + it "allows for [eEdD] as exponent separator" do reference = BigDecimal("12345.67E89") diff --git a/spec/ruby/library/bigdecimal/clone_spec.rb b/spec/ruby/library/bigdecimal/clone_spec.rb new file mode 100644 index 00000000000000..b3a1c61d6a6a01 --- /dev/null +++ b/spec/ruby/library/bigdecimal/clone_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/clone' + +describe "BigDecimal#dup" do + it_behaves_like :bigdecimal_clone, :clone +end diff --git a/spec/ruby/library/bigdecimal/constants_spec.rb b/spec/ruby/library/bigdecimal/constants_spec.rb new file mode 100644 index 00000000000000..1e08c6779bc0e7 --- /dev/null +++ b/spec/ruby/library/bigdecimal/constants_spec.rb @@ -0,0 +1,76 @@ +require_relative '../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal constants" do + ruby_version_is "2.5" do + it "defines a VERSION value" do + BigDecimal.const_defined?(:VERSION).should be_true + end + end + + it "has a BASE value" do + platform_is wordsize: 64 do + BigDecimal::BASE.should == 1000000000 + end + + platform_is wordsize: 32 do + BigDecimal::BASE.should == 10000 + end + end + + it "has a NaN value" do + BigDecimal::NAN.nan?.should be_true + end + + it "has an INFINITY value" do + BigDecimal::INFINITY.infinite?.should == 1 + end + + describe "exception-related constants" do + [ + [:EXCEPTION_ALL, 0xff], + [:EXCEPTION_INFINITY, 0x01], + [:EXCEPTION_NaN, 0x02], + [:EXCEPTION_UNDERFLOW, 0x04], + [:EXCEPTION_OVERFLOW, 0x01], + [:EXCEPTION_ZERODIVIDE, 0x10] + ].each do |const, value| + it "has a #{const} value" do + BigDecimal.const_get(const).should == value + end + end + end + + describe "rounding-related constants" do + [ + [:ROUND_MODE, 0x100], + [:ROUND_UP, 1], + [:ROUND_DOWN, 2], + [:ROUND_HALF_UP, 3], + [:ROUND_HALF_DOWN, 4], + [:ROUND_CEILING, 5], + [:ROUND_FLOOR, 6], + [:ROUND_HALF_EVEN, 7] + ].each do |const, value| + it "has a #{const} value" do + BigDecimal.const_get(const).should == value + end + end + end + + describe "sign-related constants" do + [ + [:SIGN_NaN, 0], + [:SIGN_POSITIVE_ZERO, 1], + [:SIGN_NEGATIVE_ZERO, -1], + [:SIGN_POSITIVE_FINITE, 2], + [:SIGN_NEGATIVE_FINITE, -2], + [:SIGN_POSITIVE_INFINITE, 3], + [:SIGN_NEGATIVE_INFINITE, -3] + ].each do |const, value| + it "has a #{const} value" do + BigDecimal.const_get(const).should == value + end + end + end +end diff --git a/spec/ruby/library/bigdecimal/dup_spec.rb b/spec/ruby/library/bigdecimal/dup_spec.rb new file mode 100644 index 00000000000000..bfabaf6e8b7c29 --- /dev/null +++ b/spec/ruby/library/bigdecimal/dup_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/clone' + +describe "BigDecimal#dup" do + it_behaves_like :bigdecimal_clone, :dup +end diff --git a/spec/ruby/library/bigdecimal/hash_spec.rb b/spec/ruby/library/bigdecimal/hash_spec.rb new file mode 100644 index 00000000000000..7581c90f681bee --- /dev/null +++ b/spec/ruby/library/bigdecimal/hash_spec.rb @@ -0,0 +1,30 @@ +require_relative '../../spec_helper' +require 'bigdecimal' + +describe "BidDecimal#hash" do + describe "two BigDecimal objects with the same value" do + it "should have the same hash for ordinary values" do + BigDecimal('1.2920').hash.should == BigDecimal('1.2920').hash + end + + it "should have the same hash for infinite values" do + BigDecimal("+Infinity").hash.should == BigDecimal("+Infinity").hash + BigDecimal("-Infinity").hash.should == BigDecimal("-Infinity").hash + end + + it "should have the same hash for NaNs" do + BigDecimal("NaN").hash.should == BigDecimal("NaN").hash + end + + it "should have the same hash for zero values" do + BigDecimal("+0").hash.should == BigDecimal("+0").hash + BigDecimal("-0").hash.should == BigDecimal("-0").hash + end + end + + describe "two BigDecimal objects with numerically equal values" do + it "should have the same hash value" do + BigDecimal("1.2920").hash.should == BigDecimal("1.2920000").hash + end + end +end diff --git a/spec/ruby/library/bigdecimal/inspect_spec.rb b/spec/ruby/library/bigdecimal/inspect_spec.rb index cd2f1a3cd492f4..18e9ca9a0ce69a 100644 --- a/spec/ruby/library/bigdecimal/inspect_spec.rb +++ b/spec/ruby/library/bigdecimal/inspect_spec.rb @@ -14,4 +14,11 @@ it "looks like this" do @bigdec.inspect.should == "0.12345678e4" end + + it "properly cases non-finite values" do + BigDecimal("NaN").inspect.should == "NaN" + BigDecimal("Infinity").inspect.should == "Infinity" + BigDecimal("+Infinity").inspect.should == "Infinity" + BigDecimal("-Infinity").inspect.should == "-Infinity" + end end diff --git a/spec/ruby/library/bigdecimal/shared/clone.rb b/spec/ruby/library/bigdecimal/shared/clone.rb new file mode 100644 index 00000000000000..e58df3a94b0758 --- /dev/null +++ b/spec/ruby/library/bigdecimal/shared/clone.rb @@ -0,0 +1,24 @@ +require 'bigdecimal' + +describe :bigdecimal_clone, shared: true do + before :each do + @obj = BigDecimal("1.2345") + end + + ruby_version_is "" ... "2.5" do + it "copies the BigDecimal's value to a newly allocated object" do + copy = @obj.public_send(@method) + + copy.should_not equal(@obj) + copy.should == @obj + end + end + + ruby_version_is "2.5" do + it "returns self" do + copy = @obj.public_send(@method) + + copy.should equal(@obj) + end + end +end diff --git a/spec/ruby/library/bigdecimal/to_d_spec.rb b/spec/ruby/library/bigdecimal/to_d_spec.rb new file mode 100644 index 00000000000000..8e20901fd9f6e8 --- /dev/null +++ b/spec/ruby/library/bigdecimal/to_d_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../spec_helper' +require 'bigdecimal' +require 'bigdecimal/util' + + +describe "Float#to_d" do + it "returns appropriate BigDecimal zero for signed zero" do + -0.0.to_d.sign.should == -1 + 0.0.to_d.sign.should == 1 + end +end diff --git a/spec/ruby/library/objectspace/memsize_of_spec.rb b/spec/ruby/library/objectspace/memsize_of_spec.rb new file mode 100644 index 00000000000000..06a80d9f9cdd7c --- /dev/null +++ b/spec/ruby/library/objectspace/memsize_of_spec.rb @@ -0,0 +1,30 @@ +require_relative '../../spec_helper' +require 'objspace' + +describe "ObjectSpace.memsize_of" do + it "returns 0 for true, false and nil" do + ObjectSpace.memsize_of(true).should == 0 + ObjectSpace.memsize_of(false).should == 0 + ObjectSpace.memsize_of(nil).should == 0 + end + + it "returns 0 for small Integers" do + ObjectSpace.memsize_of(42).should == 0 + end + + it "returns an Integer for an Object" do + obj = Object.new + ObjectSpace.memsize_of(obj).should be_kind_of(Integer) + ObjectSpace.memsize_of(obj).should > 0 + end + + it "is larger if the Object has more instance variables" do + obj = Object.new + before = ObjectSpace.memsize_of(obj) + 100.times do |i| + obj.instance_variable_set(:"@foo#{i}", nil) + end + after = ObjectSpace.memsize_of(obj) + after.should > before + end +end diff --git a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb new file mode 100644 index 00000000000000..7e70bc85691989 --- /dev/null +++ b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb @@ -0,0 +1,61 @@ +require_relative '../../spec_helper' +require 'objspace' + +describe "ObjectSpace.reachable_objects_from" do + it "returns nil for true and false" do + ObjectSpace.reachable_objects_from(true).should == nil + ObjectSpace.reachable_objects_from(false).should == nil + end + + it "returns nil for nil" do + ObjectSpace.reachable_objects_from(nil).should == nil + end + + it "returns nil for small Integers" do + ObjectSpace.reachable_objects_from(42).should == nil + end + + it "enumerates objects directly reachable from a given object" do + ObjectSpace.reachable_objects_from(['a', 'b', 'c']).should include(Array, 'a', 'b', 'c') + ObjectSpace.reachable_objects_from(Object.new).should == [Object] + end + + it "finds an object stored in an Array" do + obj = Object.new + ary = [obj] + reachable = ObjectSpace.reachable_objects_from(ary) + reachable.should include(obj) + end + + it "finds an object stored in a copy-on-write Array" do + removed = Object.new + obj = Object.new + ary = [removed, obj] + ary.shift + reachable = ObjectSpace.reachable_objects_from(ary) + reachable.should include(obj) + reachable.should_not include(removed) + end + + it "finds an object stored in a Queue" do + require 'thread' + o = Object.new + q = Queue.new + q << o + + reachable = ObjectSpace.reachable_objects_from(q) + reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) } + reachable.should include(o) + end + + it "finds an object stored in a SizedQueue" do + require 'thread' + o = Object.new + q = SizedQueue.new(3) + q << o + + reachable = ObjectSpace.reachable_objects_from(q) + reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) } + reachable.should include(o) + end +end diff --git a/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb b/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb index 85a66275f8ee05..a8800a849326a2 100644 --- a/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb +++ b/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb @@ -37,3 +37,67 @@ @socket.peeraddr[2].should == "127.0.0.1" end end + +describe :socket_do_not_reverse_lookup, shared: true do + it "inherits from BasicSocket.do_not_reverse_lookup when the socket is created" do + @socket = @method.call + reverse = BasicSocket.do_not_reverse_lookup + @socket.do_not_reverse_lookup.should == reverse + + BasicSocket.do_not_reverse_lookup = !reverse + @socket.do_not_reverse_lookup.should == reverse + end + + it "is true when BasicSocket.do_not_reverse_lookup is true" do + BasicSocket.do_not_reverse_lookup = true + @socket = @method.call + @socket.do_not_reverse_lookup.should == true + end + + it "is false when BasicSocket.do_not_reverse_lookup is false" do + BasicSocket.do_not_reverse_lookup = false + @socket = @method.call + @socket.do_not_reverse_lookup.should == false + end + + it "can be changed with #do_not_reverse_lookup=" do + @socket = @method.call + reverse = @socket.do_not_reverse_lookup + @socket.do_not_reverse_lookup = !reverse + @socket.do_not_reverse_lookup.should == !reverse + end +end + +describe "BasicSocket#do_not_reverse_lookup" do + before :each do + @do_not_reverse_lookup = BasicSocket.do_not_reverse_lookup + @server = TCPServer.new('127.0.0.1', 0) + @port = @server.addr[1] + end + + after :each do + @server.close unless @server.closed? + @socket.close if @socket && !@socket.closed? + BasicSocket.do_not_reverse_lookup = @do_not_reverse_lookup + end + + describe "for an TCPSocket.new socket" do + it_behaves_like :socket_do_not_reverse_lookup, -> { + TCPSocket.new('127.0.0.1', @port) + } + end + + describe "for an TCPServer#accept socket" do + before :each do + @client = TCPSocket.new('127.0.0.1', @port) + end + + after :each do + @client.close if @client && !@client.closed? + end + + it_behaves_like :socket_do_not_reverse_lookup, -> { + @server.accept + } + end +end diff --git a/spec/ruby/library/socket/fixtures/classes.rb b/spec/ruby/library/socket/fixtures/classes.rb index 4cfa084333cb20..6cc7ecb389e56d 100644 --- a/spec/ruby/library/socket/fixtures/classes.rb +++ b/spec/ruby/library/socket/fixtures/classes.rb @@ -72,24 +72,11 @@ def self.each_ip_protocol end def self.loop_with_timeout(timeout = TIME_TOLERANCE) - require 'timeout' - time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + start = Process.clock_gettime(Process::CLOCK_MONOTONIC) - loop do - if Process.clock_gettime(Process::CLOCK_MONOTONIC) - time >= timeout - raise TimeoutError, "Did not succeed within #{timeout} seconds" - end - - sleep 0.01 # necessary on OSX; don't know why - yield - end - end - - def self.wait_until_success(timeout = TIME_TOLERANCE) - loop_with_timeout(timeout) do - begin - return yield - rescue + while yield == :retry + if Process.clock_gettime(Process::CLOCK_MONOTONIC) - start >= timeout + raise RuntimeError, "Did not succeed within #{timeout} seconds" end end end diff --git a/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb b/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb index 617e3d445c69f2..15865a028c4466 100644 --- a/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb +++ b/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb @@ -31,8 +31,13 @@ end end - SocketSpecs.wait_until_success do - @client.connect(Socket.sockaddr_in(@port, '127.0.0.1')) + SocketSpecs.loop_with_timeout do + begin + @client.connect(Socket.sockaddr_in(@port, '127.0.0.1')) + rescue SystemCallError + sleep 0.01 + :retry + end end # At this point the connection has been set up but the thread may not yet diff --git a/spec/ruby/library/socket/socket/udp_server_loop_spec.rb b/spec/ruby/library/socket/socket/udp_server_loop_spec.rb index 95f73a5c35f1b6..c6abfb4eb9abf0 100644 --- a/spec/ruby/library/socket/socket/udp_server_loop_spec.rb +++ b/spec/ruby/library/socket/socket/udp_server_loop_spec.rb @@ -35,9 +35,17 @@ @client.connect(Socket.sockaddr_in(@port, '127.0.0.1')) SocketSpecs.loop_with_timeout do - SocketSpecs.wait_until_success { @client.write('hello') } - - break if msg + begin + @client.write('hello') + rescue SystemCallError + sleep 0.01 + :retry + else + unless msg + sleep 0.001 + :retry + end + end end msg.should == 'hello' diff --git a/spec/ruby/library/socket/socket/unix_server_loop_spec.rb b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb index 52c535cd450f7a..a2d2ad9fdb252e 100644 --- a/spec/ruby/library/socket/socket/unix_server_loop_spec.rb +++ b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb @@ -39,7 +39,14 @@ end end - @client = SocketSpecs.wait_until_success { Socket.unix(@path) } + SocketSpecs.loop_with_timeout do + begin + @client = Socket.unix(@path) + rescue SystemCallError + sleep 0.01 + :retry + end + end thread.join(2) diff --git a/spec/ruby/library/tempfile/open_spec.rb b/spec/ruby/library/tempfile/open_spec.rb index c4c3d91051757b..ef2c95376f2ce6 100644 --- a/spec/ruby/library/tempfile/open_spec.rb +++ b/spec/ruby/library/tempfile/open_spec.rb @@ -49,6 +49,14 @@ tempfile.binmode?.should be_true end end + + it "uses a blank string for basename when passed no arguments" do + Tempfile.open() do |tempfile| + @tempfile = tempfile + tempfile.closed?.should be_false + end + @tempfile.should_not == nil + end end describe "Tempfile.open when passed a block" do diff --git a/spec/ruby/optional/capi/ext/hash_spec.c b/spec/ruby/optional/capi/ext/hash_spec.c index 4e9312a1d19b44..c8735cec2c429b 100644 --- a/spec/ruby/optional/capi/ext/hash_spec.c +++ b/spec/ruby/optional/capi/ext/hash_spec.c @@ -96,6 +96,11 @@ VALUE hash_spec_rb_hash_lookup2(VALUE self, VALUE hash, VALUE key, VALUE def) { return rb_hash_lookup2(hash, key, def); } +VALUE hash_spec_rb_hash_lookup2_default_undef(VALUE self, VALUE hash, VALUE key) { + VALUE ret = rb_hash_lookup2(hash, key, Qundef); + return ret == Qundef ? Qtrue : Qfalse; +} + VALUE hash_spec_rb_hash_new(VALUE self) { return rb_hash_new(); } @@ -127,6 +132,7 @@ void Init_hash_spec(void) { rb_define_method(cls, "rb_hash_lookup_nil", hash_spec_rb_hash_lookup_nil, 2); rb_define_method(cls, "rb_hash_lookup", hash_spec_rb_hash_lookup, 2); rb_define_method(cls, "rb_hash_lookup2", hash_spec_rb_hash_lookup2, 3); + rb_define_method(cls, "rb_hash_lookup2_default_undef", hash_spec_rb_hash_lookup2_default_undef, 2); rb_define_method(cls, "rb_hash_new", hash_spec_rb_hash_new, 0); rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1); rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2); diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c index 48e2b1ca954c27..ed6e08a880ff66 100644 --- a/spec/ruby/optional/capi/ext/kernel_spec.c +++ b/spec/ruby/optional/capi/ext/kernel_spec.c @@ -175,6 +175,17 @@ static VALUE kernel_spec_rb_protect_yield(VALUE self, VALUE obj, VALUE ary) { return res; } +static VALUE kernel_spec_rb_eval_string_protect(VALUE self, VALUE str, VALUE ary) { + int status = 0; + VALUE res = rb_eval_string_protect(RSTRING_PTR(str), &status); + rb_ary_store(ary, 0, INT2NUM(23)); + rb_ary_store(ary, 1, res); + if (status) { + rb_jump_tag(status); + } + return res; +} + VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) { errno = 1; if(msg == Qnil) { @@ -301,6 +312,7 @@ void Init_kernel_spec(void) { rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4); rb_define_method(cls, "rb_rescue2", kernel_spec_rb_rescue2, -1); rb_define_method(cls, "rb_protect_yield", kernel_spec_rb_protect_yield, 2); + rb_define_method(cls, "rb_eval_string_protect", kernel_spec_rb_eval_string_protect, 2); rb_define_method(cls, "rb_catch", kernel_spec_rb_catch, 2); rb_define_method(cls, "rb_catch_obj", kernel_spec_rb_catch_obj, 2); rb_define_method(cls, "rb_sys_fail", kernel_spec_rb_sys_fail, 1); diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c index d99ed12e14b8a1..181949ee4b28db 100644 --- a/spec/ruby/optional/capi/ext/util_spec.c +++ b/spec/ruby/optional/capi/ext/util_spec.c @@ -44,6 +44,30 @@ VALUE util_spec_rb_scan_args(VALUE self, VALUE argv, VALUE fmt, VALUE expected, return INT2NUM(result); } +static VALUE util_spec_rb_get_kwargs(VALUE self, VALUE keyword_hash, VALUE keys, VALUE required, VALUE optional) { + int req = FIX2INT(required); + int opt = FIX2INT(optional); + int len = RARRAY_LEN(keys); + + int values_len = req + (opt < 0 ? -1 - opt : opt); + int i = 0; + + ID *ids = malloc(sizeof(VALUE) * len); + VALUE *results = malloc(sizeof(VALUE) * values_len); + int extracted = 0; + VALUE ary = Qundef; + + for (i = 0; i < len; i++) { + ids[i] = SYM2ID(rb_ary_entry(keys, i)); + } + + extracted = rb_get_kwargs(keyword_hash, ids, req, opt, results); + ary = rb_ary_new_from_values(extracted, results); + free(results); + free(ids); + return ary; +} + static VALUE util_spec_rb_long2int(VALUE self, VALUE n) { return INT2NUM(rb_long2int(NUM2LONG(n))); } @@ -64,6 +88,7 @@ static VALUE util_spec_rb_sourceline(VALUE self) { void Init_util_spec(void) { VALUE cls = rb_define_class("CApiUtilSpecs", rb_cObject); rb_define_method(cls, "rb_scan_args", util_spec_rb_scan_args, 4); + rb_define_method(cls, "rb_get_kwargs", util_spec_rb_get_kwargs, 4); rb_define_method(cls, "rb_long2int", util_spec_rb_long2int, 1); rb_define_method(cls, "rb_iter_break", util_spec_rb_iter_break, 0); rb_define_method(cls, "rb_sourcefile", util_spec_rb_sourcefile, 0); diff --git a/spec/ruby/optional/capi/hash_spec.rb b/spec/ruby/optional/capi/hash_spec.rb index f584e730066b3e..92dc62d55b3112 100644 --- a/spec/ruby/optional/capi/hash_spec.rb +++ b/spec/ruby/optional/capi/hash_spec.rb @@ -211,6 +211,11 @@ @s.rb_hash_lookup2(hash, :chunky, 10).should == 10 end + + it "returns undefined if that is the default value specified" do + hsh = Hash.new(0) + @s.rb_hash_lookup2_default_undef(hsh, :chunky).should be_true + end end end diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb index ab6c2bceef55de..3fb2c8ed2d3f41 100644 --- a/spec/ruby/optional/capi/kernel_spec.rb +++ b/spec/ruby/optional/capi/kernel_spec.rb @@ -292,6 +292,22 @@ end end + describe "rb_eval_string_protect" do + it "will evaluate the given string" do + proof = [] + res = @s.rb_eval_string_protect('1 + 7', proof) + proof.should == [23, 8] + end + + it "will allow cleanup code to be run when an exception is raised" do + proof = [] + lambda do + @s.rb_eval_string_protect('raise RuntimeError', proof) + end.should raise_error(RuntimeError) + proof.should == [23, nil] + end + end + describe "rb_rescue" do before :each do @proc = lambda { |x| x } diff --git a/spec/ruby/optional/capi/util_spec.rb b/spec/ruby/optional/capi/util_spec.rb index 33dc30df8568cd..5f8f9c6e3b1caa 100644 --- a/spec/ruby/optional/capi/util_spec.rb +++ b/spec/ruby/optional/capi/util_spec.rb @@ -154,6 +154,50 @@ end end + describe "rb_get_kwargs" do + it "extracts required arguments in the order requested" do + h = { :a => 7, :b => 5 } + @o.rb_get_kwargs(h, [:b, :a], 2, 0).should == [5, 7] + h.should == {} + end + + it "extracts required and optional arguments in the order requested" do + h = { :a => 7, :c => 12, :b => 5 } + @o.rb_get_kwargs(h, [:b, :a, :c], 2, 1).should == [5, 7, 12] + h.should == {} + end + + it "accepts nil instead of a hash when only optional arguments are requested" do + h = nil + @o.rb_get_kwargs(h, [:b, :a, :c], 0, 3).should == [] + h.should == nil + end + + it "raises an error if a required argument is not in the hash" do + h = { :a => 7, :c => 12, :b => 5 } + lambda { @o.rb_get_kwargs(h, [:b, :d], 2, 0) }.should raise_error(ArgumentError, /missing keyword: d/) + h.should == {:a => 7, :c => 12} + end + + it "does not raise an error for an optional argument not in the hash" do + h = { :a => 7, :b => 5 } + @o.rb_get_kwargs(h, [:b, :a, :c], 2, 1).should == [5, 7] + h.should == {} + end + + it "raises an error if there are additional arguments and optional is positive" do + h = { :a => 7, :c => 12, :b => 5 } + lambda { @o.rb_get_kwargs(h, [:b, :a], 2, 0) }.should raise_error(ArgumentError, /unknown keyword: c/) + h.should == {:c => 12} + end + + it "leaves additional arguments in the hash if optional is negative" do + h = { :a => 7, :c => 12, :b => 5 } + @o.rb_get_kwargs(h, [:b, :a], 2, -1).should == [5, 7] + h.should == {:c => 12} + end + end + platform_is wordsize: 64 do describe "rb_long2int" do it "raises a RangeError if the value is outside the range of a C int" do