git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60525 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
eregon 2017-10-28 15:15:48 +00:00
Родитель 6530b14cee
Коммит 8c5b60eb22
218 изменённых файлов: 4069 добавлений и 328 удалений

Просмотреть файл

@ -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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше