зеркало из https://github.com/github/ruby.git
Update to ruby/spec@a6b8805
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60525 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
6530b14cee
Коммит
8c5b60eb22
|
@ -7,13 +7,28 @@ AllCops:
|
|||
- command_line/fixtures/bad_syntax.rb
|
||||
DisabledByDefault: true
|
||||
|
||||
Layout/TrailingWhitespace:
|
||||
Enabled: true
|
||||
|
||||
Lint:
|
||||
Enabled: true
|
||||
|
||||
Lint/AssignmentInCondition:
|
||||
Enabled: false
|
||||
|
||||
Lint/LiteralInCondition:
|
||||
Lint/BooleanSymbol:
|
||||
Enabled: false
|
||||
|
||||
Lint/InterpolationCheck:
|
||||
Enabled: false
|
||||
|
||||
Lint/LiteralAsCondition:
|
||||
Enabled: false
|
||||
|
||||
Lint/UnneededRequireStatement:
|
||||
Enabled: false
|
||||
|
||||
Lint/RescueWithoutErrorClass:
|
||||
Enabled: false
|
||||
|
||||
Lint/UnifiedInteger:
|
||||
|
@ -38,3 +53,7 @@ Lint/Void:
|
|||
Lint/EmptyExpression:
|
||||
Exclude:
|
||||
- 'language/**/*.rb'
|
||||
|
||||
Lint/UriRegexp:
|
||||
Exclude:
|
||||
- 'library/uri/regexp_spec.rb'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# This configuration was generated by
|
||||
# `rubocop --auto-gen-config`
|
||||
# on 2017-06-18 19:12:38 +0200 using RuboCop version 0.49.1.
|
||||
# on 2017-10-09 20:22:01 +0200 using RuboCop version 0.50.0.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the offenses are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
|
@ -52,7 +52,7 @@ Lint/FloatOutOfRange:
|
|||
Exclude:
|
||||
- 'core/string/modulo_spec.rb'
|
||||
|
||||
# Offense count: 46
|
||||
# Offense count: 43
|
||||
Lint/FormatParameterMismatch:
|
||||
Exclude:
|
||||
- 'core/kernel/sprintf_spec.rb'
|
||||
|
@ -137,6 +137,7 @@ Lint/RescueException:
|
|||
- 'library/erb/filename_spec.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Lint/ScriptPermission:
|
||||
Exclude:
|
||||
- 'command_line/fixtures/bin/launcher.rb'
|
||||
|
@ -181,7 +182,7 @@ Lint/UnneededSplatExpansion:
|
|||
- 'language/send_spec.rb'
|
||||
- 'language/variables_spec.rb'
|
||||
|
||||
# Offense count: 53
|
||||
# Offense count: 55
|
||||
Lint/UnreachableCode:
|
||||
Exclude:
|
||||
- 'core/enumerator/lazy/fixtures/classes.rb'
|
||||
|
@ -198,7 +199,7 @@ Lint/UnreachableCode:
|
|||
- 'optional/capi/kernel_spec.rb'
|
||||
- 'shared/kernel/raise.rb'
|
||||
|
||||
# Offense count: 9
|
||||
# Offense count: 7
|
||||
# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
|
||||
Lint/UselessAccessModifier:
|
||||
Exclude:
|
||||
|
@ -206,6 +207,4 @@ Lint/UselessAccessModifier:
|
|||
- 'core/module/fixtures/classes.rb'
|
||||
- 'core/module/module_function_spec.rb'
|
||||
- 'core/module/private_class_method_spec.rb'
|
||||
- 'core/module/private_spec.rb'
|
||||
- 'core/module/protected_spec.rb'
|
||||
- 'core/module/public_spec.rb'
|
||||
- 'language/fixtures/send.rb'
|
||||
|
|
|
@ -3,21 +3,23 @@ language: ruby
|
|||
install:
|
||||
- git clone https://github.com/ruby/mspec.git ../mspec
|
||||
script:
|
||||
- if [ -n "$RUBOCOP" ]; then gem install rubocop -v 0.49.1 && rubocop; fi
|
||||
- if [ -n "$RUBOCOP" ]; then gem install rubocop -v 0.51.0 && rubocop; fi
|
||||
- ../mspec/bin/mspec $MSPEC_OPTS
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
rvm: 2.4.0
|
||||
osx_image: xcode9
|
||||
rvm: 2.4.2
|
||||
env: CHECK_LEAKS=true
|
||||
- os: linux
|
||||
rvm: 2.4.1
|
||||
rvm: 2.4.2
|
||||
env: MSPEC_OPTS="-R2 -ff"
|
||||
- os: linux
|
||||
rvm: 2.2.7
|
||||
rvm: 2.2.8
|
||||
- os: linux
|
||||
rvm: 2.3.4
|
||||
rvm: 2.3.5
|
||||
- os: linux
|
||||
rvm: 2.4.1
|
||||
rvm: 2.4.2
|
||||
env: CHECK_LEAKS=true RUBOCOP=true
|
||||
- os: linux
|
||||
rvm: ruby-head
|
||||
|
|
|
@ -48,9 +48,116 @@ You might also want to search for:
|
|||
|
||||
which indicates the file was generated but the method unspecified.
|
||||
|
||||
### Matchers and expectations
|
||||
|
||||
Here is a list of frequently-used matchers, which should be enough for most specs.
|
||||
There are a few extra specific matchers used in the couple specs that need it.
|
||||
|
||||
```ruby
|
||||
(1 + 2).should == 3 # Calls #==
|
||||
(1 + 2).should_not == 5
|
||||
|
||||
File.should equal(File) # Calls #equal? (tests identity)
|
||||
(1 + 2).should eql(3) # Calls #eql? (Hash equality)
|
||||
|
||||
1.should < 2
|
||||
2.should <= 2
|
||||
3.should >= 3
|
||||
4.should > 3
|
||||
|
||||
"Hello".should =~ /l{2}/ # Calls #=~ (Regexp match)
|
||||
|
||||
[].should be_empty # Calls #empty?
|
||||
[1,2,3].should include(2) # Calls #include?
|
||||
|
||||
(0.1 + 0.2).should be_close(0.3, TOLERANCE) # (0.2-0.1).abs < TOLERANCE
|
||||
(0.0/0.0).should be_nan # Calls Float#nan?
|
||||
(1.0/0.0).should be_positive_infinity
|
||||
(-1.0/0.0).should be_negative_infinity
|
||||
|
||||
3.14.should be_an_instance_of(Float) # Calls #instance_of?
|
||||
3.14.should be_kind_of(Numeric) # Calls #is_a?
|
||||
Numeric.should be_ancestor_of(Float) # Float.ancestors.include?(Numeric)
|
||||
|
||||
3.14.should respond_to(:to_i) # Calls #respond_to?
|
||||
Fixnum.should have_instance_method(:+)
|
||||
Array.should have_method(:new)
|
||||
# Also have_constant, have_private_instance_method, have_singleton_method, etc
|
||||
|
||||
-> {
|
||||
raise "oops"
|
||||
}.should raise_error(RuntimeError, /oops/)
|
||||
|
||||
# To avoid! Instead, use an expectation testing what the code in the lambda does.
|
||||
# If an exception is raised, it will fail the example anyway.
|
||||
-> { ... }.should_not raise_error
|
||||
|
||||
-> {
|
||||
Fixnum
|
||||
}.should complain(/constant ::Fixnum is deprecated/) # Expect a warning
|
||||
```
|
||||
|
||||
### Guards
|
||||
|
||||
Different guards are available as defined by mspec.
|
||||
Here is a list of the most commonly-used guards:
|
||||
|
||||
```ruby
|
||||
ruby_version_is ""..."2.4" do
|
||||
# Specs for RUBY_VERSION < 2.4
|
||||
end
|
||||
|
||||
ruby_version_is "2.4" do
|
||||
# Specs for RUBY_VERSION >= 2.4
|
||||
end
|
||||
|
||||
platform_is :windows do
|
||||
# Specs only valid on Windows
|
||||
end
|
||||
|
||||
platform_is_not :windows do
|
||||
# Specs valid on platforms other than Windows
|
||||
end
|
||||
|
||||
platform_is :linux, :darwin do # OR
|
||||
end
|
||||
|
||||
platform_is_not :linux, :darwin do # Not Linux and not Darwin
|
||||
end
|
||||
|
||||
platform_is wordsize: 64 do
|
||||
# 64-bit platform
|
||||
end
|
||||
|
||||
big_endian do
|
||||
# Big-endian platform
|
||||
end
|
||||
|
||||
# In case there is a bug in MRI but the expected behavior is obvious
|
||||
# First file a bug at https://bugs.ruby-lang.org/
|
||||
# It is better to use a ruby_version_is guard if there was a release with the fix
|
||||
ruby_bug '#13669', ''...'2.5' do
|
||||
it "works like this" do
|
||||
# Specify the expected behavior here, not the bug
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Combining guards
|
||||
guard -> { platform_is :windows and ruby_version_is ""..."2.3" } do
|
||||
# Windows and RUBY_VERSION < 2.3
|
||||
end
|
||||
|
||||
guard_not -> { platform_is :windows and ruby_version_is ""..."2.3" } do
|
||||
# The opposite
|
||||
end
|
||||
|
||||
# Custom guard
|
||||
max_uint = (1 << 32) - 1
|
||||
guard -> { max_uint <= fixnum_max } do
|
||||
end
|
||||
```
|
||||
|
||||
In general, the usage of guards should be minimized as possible.
|
||||
|
||||
There are no guards to define implementation-specific behavior because
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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[
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 == ""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,8 +4,11 @@ module MainSpecs
|
|||
|
||||
module WrapIncludeModule
|
||||
end
|
||||
|
||||
DATA = {}
|
||||
end
|
||||
|
||||
|
||||
def main_public_method
|
||||
end
|
||||
public :main_public_method
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
module StringRefinement
|
||||
refine(String) do
|
||||
def foo
|
||||
'foo'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
module ModuleSpecs
|
||||
module EmptyRefinement
|
||||
end
|
||||
|
||||
module RefinementForStringToS
|
||||
refine String do
|
||||
def to_s; "hello from refinement"; end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче