This commit is contained in:
Benoit Daloze 2022-06-26 14:50:14 +02:00
Родитель f616e81637
Коммит d3d5ef0cca
74 изменённых файлов: 1201 добавлений и 324 удалений

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

@ -99,6 +99,9 @@ Lint/DuplicateElsifCondition:
Lint/OutOfRangeRegexpRef:
Enabled: false
Lint/InheritException:
Enabled: false
Lint/ElseLayout:
Exclude:
- 'language/if_spec.rb'

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

@ -50,17 +50,6 @@ Lint/IneffectiveAccessModifier:
- 'core/module/fixtures/classes.rb'
- 'language/fixtures/private.rb'
# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: runtime_error, standard_error
Lint/InheritException:
Exclude:
- 'core/enumerator/lazy/fixtures/classes.rb'
- 'core/exception/fixtures/common.rb'
- 'core/module/fixtures/autoload_ex1.rb'
- 'shared/kernel/raise.rb'
# Offense count: 72
# Cop supports --auto-correct.
Lint/LiteralInInterpolation:

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

@ -205,6 +205,12 @@ describe "Array#fill with (filler, index, length)" do
-> { [].fill('a', obj) }.should raise_error(TypeError)
end
it "raises a TypeError when the length is not numeric" do
-> { [1, 2, 3].fill("x", 1, "foo") }.should raise_error(TypeError, /no implicit conversion of String into Integer/)
-> { [1, 2, 3].fill("x", 1, :"foo") }.should raise_error(TypeError, /no implicit conversion of Symbol into Integer/)
-> { [1, 2, 3].fill("x", 1, Object.new) }.should raise_error(TypeError, /no implicit conversion of Object into Integer/)
end
not_supported_on :opal do
it "raises an ArgumentError or RangeError for too-large sizes" do
error_types = [RangeError, ArgumentError]

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

@ -40,6 +40,68 @@ module ArraySpecs
a
end
# Chi squared critical values for tests with n degrees of freedom at 99% confidence.
# Values obtained from NIST Engineering Statistic Handbook at
# https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm
CHI_SQUARED_CRITICAL_VALUES = [
0,
6.635, 9.210, 11.345, 13.277, 15.086, 16.812, 18.475, 20.090, 21.666, 23.209,
24.725, 26.217, 27.688, 29.141, 30.578, 32.000, 33.409, 34.805, 36.191, 37.566,
38.932, 40.289, 41.638, 42.980, 44.314, 45.642, 46.963, 48.278, 49.588, 50.892,
52.191, 53.486, 54.776, 56.061, 57.342, 58.619, 59.893, 61.162, 62.428, 63.691,
64.950, 66.206, 67.459, 68.710, 69.957, 71.201, 72.443, 73.683, 74.919, 76.154,
77.386, 78.616, 79.843, 81.069, 82.292, 83.513, 84.733, 85.950, 87.166, 88.379,
89.591, 90.802, 92.010, 93.217, 94.422, 95.626, 96.828, 98.028, 99.228, 100.425,
101.621, 102.816, 104.010, 105.202, 106.393, 107.583, 108.771, 109.958, 111.144, 112.329,
113.512, 114.695, 115.876, 117.057, 118.236, 119.414, 120.591, 121.767, 122.942, 124.116,
125.289, 126.462, 127.633, 128.803, 129.973, 131.141, 132.309, 133.476, 134.642, 135.807,
]
def self.measure_sample_fairness(size, samples, iters)
ary = Array.new(size) { |x| x }
(samples).times do |i|
chi_results = []
3.times do
counts = Array.new(size) { 0 }
expected = iters / size
iters.times do
x = ary.sample(samples)[i]
counts[x] += 1
end
chi_squared = 0.0
counts.each do |count|
chi_squared += (((count - expected) ** 2) * 1.0 / expected)
end
chi_results << chi_squared
break if chi_squared <= CHI_SQUARED_CRITICAL_VALUES[size]
end
chi_results.min.should <= CHI_SQUARED_CRITICAL_VALUES[size]
end
end
def self.measure_sample_fairness_large_sample_size(size, samples, iters)
ary = Array.new(size) { |x| x }
counts = Array.new(size) { 0 }
expected = iters * samples / size
iters.times do
ary.sample(samples).each do |sample|
counts[sample] += 1
end
end
chi_squared = 0.0
counts.each do |count|
chi_squared += (((count - expected) ** 2) * 1.0 / expected)
end
# Chi squared critical values for tests with 4 degrees of freedom
# Values obtained from NIST Engineering Statistic Handbook at
# https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm
chi_squared.should <= CHI_SQUARED_CRITICAL_VALUES[size]
end
class MyArray < Array
# The #initialize method has a different signature than Array to help
# catch places in the specs that do not assert the #initialize is not

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

@ -3,16 +3,14 @@ require_relative 'fixtures/classes'
describe "Array#sample" do
it "samples evenly" do
ary = [0, 1, 2, 3]
3.times do |i|
counts = [0, 0, 0, 0]
4000.times do
counts[ary.sample(3)[i]] += 1
end
counts.each do |count|
(800..1200).should include(count)
end
end
ArraySpecs.measure_sample_fairness(4, 1, 400)
ArraySpecs.measure_sample_fairness(4, 2, 400)
ArraySpecs.measure_sample_fairness(4, 3, 400)
ArraySpecs.measure_sample_fairness(40, 3, 400)
ArraySpecs.measure_sample_fairness(40, 4, 400)
ArraySpecs.measure_sample_fairness(40, 8, 400)
ArraySpecs.measure_sample_fairness(40, 16, 400)
ArraySpecs.measure_sample_fairness_large_sample_size(100, 80, 4000)
end
it "returns nil for an empty Array" do

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

@ -41,13 +41,13 @@ describe "Dir.foreach" do
it "accepts an encoding keyword for the encoding of the entries" do
dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: "utf-8").to_a.sort
dirs.each {|dir| dir.encoding.should == Encoding::UTF_8}
dirs.each { |dir| dir.encoding.should == Encoding::UTF_8 }
dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::UTF_16LE).to_a.sort
dirs.each {|dir| dir.encoding.should == Encoding::UTF_16LE}
dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1).to_a.sort
dirs.each { |dir| dir.encoding.should == Encoding::ISO_8859_1 }
Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::UTF_16LE) do |f|
f.encoding.should == Encoding::UTF_16LE
Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1) do |f|
f.encoding.should == Encoding::ISO_8859_1
end
end

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

@ -93,7 +93,7 @@ describe "SignalException" do
platform_is_not :windows do
it "runs after at_exit" do
output = ruby_exe(<<-RUBY, exit_status: nil)
output = ruby_exe(<<-RUBY, exit_status: :SIGKILL)
at_exit do
puts "hello"
$stdout.flush
@ -107,7 +107,7 @@ describe "SignalException" do
end
it "cannot be trapped with Signal.trap" do
ruby_exe(<<-RUBY, exit_status: nil)
ruby_exe(<<-RUBY, exit_status: :SIGPROF)
Signal.trap("PROF") {}
raise(SignalException, "PROF")
RUBY
@ -116,7 +116,7 @@ describe "SignalException" do
end
it "self-signals for USR1" do
ruby_exe("raise(SignalException, 'USR1')", exit_status: nil)
ruby_exe("raise(SignalException, 'USR1')", exit_status: :SIGUSR1)
$?.termsig.should == Signal.list.fetch('USR1')
end
end

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

@ -494,6 +494,14 @@ describe "File.open" do
File.open(@file, "w") { |f| f.puts "testing" }
File.size(@file).should > 0
File.open(@file, "rb+") do |f|
f.binmode?.should == true
f.external_encoding.should == Encoding::ASCII_8BIT
f.pos.should == 0
f.should_not.eof?
end
File.open(@file, "r+b") do |f|
f.binmode?.should == true
f.external_encoding.should == Encoding::ASCII_8BIT
f.pos.should == 0
f.should_not.eof?
end

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

@ -36,4 +36,8 @@ describe "Float#/" do
-> { 13.0 / "10" }.should raise_error(TypeError)
-> { 13.0 / :symbol }.should raise_error(TypeError)
end
it "divides correctly by Rational numbers" do
(1.2345678901234567 / Rational(1, 10000000000000000000)).should == 1.2345678901234567e+19
end
end

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

@ -103,6 +103,70 @@ describe "Float#round" do
5.55.round(1, half: :up).should eql(5.6)
5.55.round(1, half: :down).should eql(5.5)
5.55.round(1, half: :even).should eql(5.6)
-5.55.round(1, half: nil).should eql(-5.6)
-5.55.round(1, half: :up).should eql(-5.6)
-5.55.round(1, half: :down).should eql(-5.5)
-5.55.round(1, half: :even).should eql(-5.6)
end
it "preserves cases where neighbouring floating pointer number increase the decimal places" do
4.8100000000000005.round(5, half: nil).should eql(4.81)
4.8100000000000005.round(5, half: :up).should eql(4.81)
4.8100000000000005.round(5, half: :down).should eql(4.81)
4.8100000000000005.round(5, half: :even).should eql(4.81)
-4.8100000000000005.round(5, half: nil).should eql(-4.81)
-4.8100000000000005.round(5, half: :up).should eql(-4.81)
-4.8100000000000005.round(5, half: :down).should eql(-4.81)
-4.8100000000000005.round(5, half: :even).should eql(-4.81)
4.81.round(5, half: nil).should eql(4.81)
4.81.round(5, half: :up).should eql(4.81)
4.81.round(5, half: :down).should eql(4.81)
4.81.round(5, half: :even).should eql(4.81)
-4.81.round(5, half: nil).should eql(-4.81)
-4.81.round(5, half: :up).should eql(-4.81)
-4.81.round(5, half: :down).should eql(-4.81)
-4.81.round(5, half: :even).should eql(-4.81)
4.809999999999999.round(5, half: nil).should eql(4.81)
4.809999999999999.round(5, half: :up).should eql(4.81)
4.809999999999999.round(5, half: :down).should eql(4.81)
4.809999999999999.round(5, half: :even).should eql(4.81)
-4.809999999999999.round(5, half: nil).should eql(-4.81)
-4.809999999999999.round(5, half: :up).should eql(-4.81)
-4.809999999999999.round(5, half: :down).should eql(-4.81)
-4.809999999999999.round(5, half: :even).should eql(-4.81)
end
ruby_bug "", ""..."3.3" do
# These numbers are neighbouring floating point numbers round a
# precise value. They test that the rounding modes work correctly
# round that value and precision is not lost which might cause
# incorrect results.
it "does not lose precision during the rounding process" do
767573.1875850001.round(5, half: nil).should eql(767573.18759)
767573.1875850001.round(5, half: :up).should eql(767573.18759)
767573.1875850001.round(5, half: :down).should eql(767573.18759)
767573.1875850001.round(5, half: :even).should eql(767573.18759)
-767573.1875850001.round(5, half: nil).should eql(-767573.18759)
-767573.1875850001.round(5, half: :up).should eql(-767573.18759)
-767573.1875850001.round(5, half: :down).should eql(-767573.18759)
-767573.1875850001.round(5, half: :even).should eql(-767573.18759)
767573.187585.round(5, half: nil).should eql(767573.18759)
767573.187585.round(5, half: :up).should eql(767573.18759)
767573.187585.round(5, half: :down).should eql(767573.18758)
767573.187585.round(5, half: :even).should eql(767573.18758)
-767573.187585.round(5, half: nil).should eql(-767573.18759)
-767573.187585.round(5, half: :up).should eql(-767573.18759)
-767573.187585.round(5, half: :down).should eql(-767573.18758)
-767573.187585.round(5, half: :even).should eql(-767573.18758)
767573.1875849998.round(5, half: nil).should eql(767573.18758)
767573.1875849998.round(5, half: :up).should eql(767573.18758)
767573.1875849998.round(5, half: :down).should eql(767573.18758)
767573.1875849998.round(5, half: :even).should eql(767573.18758)
-767573.1875849998.round(5, half: nil).should eql(-767573.18758)
-767573.1875849998.round(5, half: :up).should eql(-767573.18758)
-767573.1875849998.round(5, half: :down).should eql(-767573.18758)
-767573.1875849998.round(5, half: :even).should eql(-767573.18758)
end
end
it "raises FloatDomainError for exceptional values with a half option" do

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

@ -223,26 +223,25 @@ describe "Integer#chr with an encoding argument" do
# #5864
it "raises RangeError if self is invalid as a codepoint in the specified encoding" do
[ [0x80, "US-ASCII"],
[0x0100, "BINARY"],
[0x0100, "EUC-JP"],
[0xA1A0, "EUC-JP"],
[0xA1, "EUC-JP"],
[0x80, "SHIFT_JIS"],
[0xE0, "SHIFT_JIS"],
[0x0100, "ISO-8859-9"],
[620, "TIS-620"],
[0xD800, "UTF-8"],
[0xDBFF, "UTF-8"],
[0xDC00, "UTF-8"],
[0xDFFF, "UTF-8"],
[0xD800, "UTF-16"],
[0xDBFF, "UTF-16"],
[0xDC00, "UTF-16"],
[0xDFFF, "UTF-16"],
].each do |integer, encoding_name|
-> { integer.chr(encoding_name) }.should raise_error(RangeError)
end
-> { 0x80.chr("US-ASCII") }.should raise_error(RangeError)
-> { 0x0100.chr("BINARY") }.should raise_error(RangeError)
-> { 0x0100.chr("EUC-JP") }.should raise_error(RangeError)
-> { 0xA1A0.chr("EUC-JP") }.should raise_error(RangeError)
-> { 0xA1.chr("EUC-JP") }.should raise_error(RangeError)
-> { 0x80.chr("SHIFT_JIS") }.should raise_error(RangeError)
-> { 0xE0.chr("SHIFT_JIS") }.should raise_error(RangeError)
-> { 0x0100.chr("ISO-8859-9") }.should raise_error(RangeError)
-> { 620.chr("TIS-620") }.should raise_error(RangeError)
# UTF-16 surrogate range
-> { 0xD800.chr("UTF-8") }.should raise_error(RangeError)
-> { 0xDBFF.chr("UTF-8") }.should raise_error(RangeError)
-> { 0xDC00.chr("UTF-8") }.should raise_error(RangeError)
-> { 0xDFFF.chr("UTF-8") }.should raise_error(RangeError)
# UTF-16 surrogate range
-> { 0xD800.chr("UTF-16") }.should raise_error(RangeError)
-> { 0xDBFF.chr("UTF-16") }.should raise_error(RangeError)
-> { 0xDC00.chr("UTF-16") }.should raise_error(RangeError)
-> { 0xDFFF.chr("UTF-16") }.should raise_error(RangeError)
end
it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do

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

@ -55,6 +55,11 @@ describe "Integer#fdiv" do
num.fdiv(den).should == -0.5555555555555556
end
it "rounds to the correct float for bignum denominators" do
1.fdiv(10**324).should == 0.0
1.fdiv(10**323).should == 1.0e-323
end
it "performs floating-point division between self and a Float" do
8.fdiv(9.0).should be_close(0.888888888888889, TOLERANCE)
end

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

@ -73,21 +73,11 @@ describe "IO#advise" do
end
end
platform_is :linux do
guard -> { platform_is :linux and kernel_version_is '3.6' } do # [ruby-core:65355] tmpfs is not supported
it "supports the willneed advice type" do
require 'etc'
uname = if Etc.respond_to?(:uname)
Etc.uname[:release]
else
`uname -r`.chomp
end
if (uname.split('.').map(&:to_i) <=> [3,6]) < 0
skip "[ruby-core:65355] tmpfs is not supported"
else
@io.advise(:willneed).should be_nil
end
end
end
it "raises an IOError if the stream is closed" do
@io.close

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

@ -108,6 +108,14 @@ module IOSpecs
"linha ", "cinco.\nHere ", "is ", "line ", "six.\n" ]
end
def self.lines_space_separator_without_trailing_spaces
[ "Voici", "la", "ligne", "une.\nQui",
"\303\250", "la", "linea", "due.\n\n\nAqu\303\255",
"est\303\241", "la", "l\303\255nea", "tres.\nHier",
"ist", "Zeile", "vier.\n\nEst\303\241", "aqui", "a",
"linha", "cinco.\nHere", "is", "line", "six.\n" ]
end
def self.lines_arbitrary_separator
[ "Voici la ligne une.\nQui \303\250",
" la linea due.\n\n\nAqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.\n\nEst\303\241 aqui a linha cinco.\nHere is line six.\n" ]
@ -119,6 +127,12 @@ module IOSpecs
"Est\303\241 aqui a linha cinco.\nHere is line six.\n" ]
end
def self.paragraphs_without_trailing_new_line_characters
[ "Voici la ligne une.\nQui \303\250 la linea due.",
"Aqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.",
"Est\303\241 aqui a linha cinco.\nHere is line six.\n" ]
end
# Creates an IO instance for an existing fixture file. The
# file should obviously not be deleted.
def self.io_fixture(name, mode = "r:utf-8")

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

@ -119,6 +119,16 @@ describe "IO#gets" do
it "returns the first line without a trailing newline character" do
@io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
end
ruby_version_is "3.0" do
it "raises exception when options passed as Hash" do
-> { @io.gets({ chomp: true }) }.should raise_error(TypeError)
-> {
@io.gets("\n", 1, { chomp: true })
}.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
end
end
@ -200,6 +210,10 @@ describe "IO#gets" do
it "reads all bytes when pass a separator and reading more than all bytes" do
@io.gets("\t", 100).should == "one\n\ntwo\n\nthree\nfour\n"
end
it "returns empty string when 0 passed as a limit" do
@io.gets(0).should == ""
end
end
describe "IO#gets" do

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

@ -43,9 +43,40 @@ describe "IO#readline" do
end
end
describe "when passed limit" do
it "reads limit bytes" do
@io.readline(3).should == "Voi"
end
it "returns an empty string when passed 0 as a limit" do
@io.readline(0).should == ""
end
end
describe "when passed separator and limit" do
it "reads limit bytes till the separator" do
# Voici la ligne une.\
@io.readline(" ", 4).should == "Voic"
@io.readline(" ", 4).should == "i "
@io.readline(" ", 4).should == "la "
@io.readline(" ", 4).should == "lign"
@io.readline(" ", 4).should == "e "
end
end
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
ruby_version_is "3.0" do
it "raises exception when options passed as Hash" do
-> { @io.readline({ chomp: true }) }.should raise_error(TypeError)
-> {
@io.readline("\n", 1, { chomp: true })
}.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
end
end

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

@ -101,6 +101,28 @@ describe "IO#readlines" do
@io.readlines(obj).should == IOSpecs.lines_r_separator
end
end
describe "when passed limit" do
it "raises ArgumentError when passed 0 as a limit" do
-> { @io.readlines(0) }.should raise_error(ArgumentError)
end
end
describe "when passed chomp" do
it "returns the first line without a trailing newline character" do
@io.readlines(chomp: true).should == IOSpecs.lines_without_newline_characters
end
ruby_version_is "3.0" do
it "raises exception when options passed as Hash" do
-> { @io.readlines({ chomp: true }) }.should raise_error(TypeError)
-> {
@io.readlines("\n", 1, { chomp: true })
}.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
end
end
describe "IO#readlines" do

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

@ -161,6 +161,54 @@ describe :io_each, shared: true do
@io.send(@method, chomp: true) { |s| ScratchPad << s }
ScratchPad.recorded.should == IOSpecs.lines_without_newline_characters
end
ruby_version_is "3.0" do
it "raises exception when options passed as Hash" do
-> {
@io.send(@method, { chomp: true }) { |s| }
}.should raise_error(TypeError)
-> {
@io.send(@method, "\n", 1, { chomp: true }) { |s| }
}.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
end
end
end
describe "when passed chomp and a separator" do
it "yields each line without separator to the passed block" do
@io.send(@method, " ", chomp: true) { |s| ScratchPad << s }
ScratchPad.recorded.should == IOSpecs.lines_space_separator_without_trailing_spaces
end
end
describe "when passed chomp and empty line as a separator" do
it "yields each paragraph without trailing new line characters" do
@io.send(@method, "", 1024, chomp: true) { |s| ScratchPad << s }
ScratchPad.recorded.should == IOSpecs.paragraphs_without_trailing_new_line_characters
end
end
describe "when passed chomp and nil as a separator" do
it "yields self's content without trailing new line character" do
@io.pos = 100
@io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six."]
end
end
describe "when passed chomp, nil as a separator, and a limit" do
it "yields each line of limit size without truncating trailing new line character" do
# 43 - is a size of the 1st paragraph in the file
@io.send(@method, nil, 43, chomp: true) { |s| ScratchPad << s }
ScratchPad.recorded.should == [
"Voici la ligne une.\nQui è la linea due.\n\n\n",
"Aquí está la línea tres.\n" + "Hier ist Zeile ",
"vier.\n\nEstá aqui a linha cinco.\nHere is li",
"ne six.\n"
]
end
end
end

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

@ -78,6 +78,14 @@ describe :io_readlines_options_19, shared: true do
result = IO.send(@method, @name, -2, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines
end
ruby_bug "#18767", ""..."3.3" do
describe "when passed limit" do
it "raises ArgumentError when passed 0 as a limit" do
-> { IO.send(@method, @name, 0, &@object) }.should raise_error(ArgumentError)
end
end
end
end
describe "when the object is a String" do
@ -92,31 +100,35 @@ describe :io_readlines_options_19, shared: true do
end
end
describe "when the object is a Hash" do
it "uses the value as the options hash" do
describe "when the object is an options Hash" do
ruby_version_is "3.0" do
it "raises TypeError exception" do
-> {
IO.send(@method, @name, { chomp: true }, &@object)
}.should raise_error(TypeError)
end
end
end
describe "when the object is neither Integer nor String" do
it "raises TypeError exception" do
obj = mock("not io readlines limit")
-> {
IO.send(@method, @name, obj, &@object)
}.should raise_error(TypeError)
end
end
end
describe "when passed name, keyword arguments" do
it "uses the keyword arguments as options" do
result = IO.send(@method, @name, mode: "r", &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines
end
end
end
describe "when passed name, object, object" do
describe "when the first object is an Integer" do
it "uses the second object as an options Hash" do
-> do
IO.send(@method, @filename, 10, mode: "w", &@object)
end.should raise_error(IOError)
end
it "calls #to_hash to convert the second object to a Hash" do
options = mock("io readlines options Hash")
options.should_receive(:to_hash).and_return({ mode: "w" })
-> do
IO.send(@method, @filename, 10, **options, &@object)
end.should raise_error(IOError)
end
end
describe "when the first object is a String" do
it "uses the second object as a limit if it is an Integer" do
result = IO.send(@method, @name, " ", 10, &@object)
@ -129,32 +141,18 @@ describe :io_readlines_options_19, shared: true do
result = IO.send(@method, @name, " ", limit, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
it "uses the second object as an options Hash" do
-> do
IO.send(@method, @filename, " ", mode: "w", &@object)
end.should raise_error(IOError)
end
it "calls #to_hash to convert the second object to a Hash" do
options = mock("io readlines options Hash")
options.should_receive(:to_hash).and_return({ mode: "w" })
-> do
IO.send(@method, @filename, " ", **options, &@object)
end.should raise_error(IOError)
end
end
describe "when the first object is not a String or Integer" do
it "calls #to_str to convert the object to a String" do
sep = mock("io readlines separator")
sep.should_receive(:to_str).at_least(1).and_return(" ")
result = IO.send(@method, @name, sep, 10, mode: "r", &@object)
result = IO.send(@method, @name, sep, 10, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
it "uses the second object as a limit if it is an Integer" do
result = IO.send(@method, @name, " ", 10, mode: "r", &@object)
result = IO.send(@method, @name, " ", 10, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
@ -164,24 +162,59 @@ describe :io_readlines_options_19, shared: true do
result = IO.send(@method, @name, " ", limit, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
end
it "uses the second object as an options Hash" do
describe "when the second object is neither Integer nor String" do
it "raises TypeError exception" do
obj = mock("not io readlines limit")
-> {
IO.send(@method, @name, " ", obj, &@object)
}.should raise_error(TypeError)
end
end
describe "when the second object is an options Hash" do
ruby_version_is "3.0" do
it "raises TypeError exception" do
-> {
IO.send(@method, @name, "", { chomp: true }, &@object)
}.should raise_error(TypeError)
end
end
end
end
describe "when passed name, object, keyword arguments" do
describe "when the first object is an Integer" do
it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, 10, mode: "w", &@object)
end.should raise_error(IOError)
end
end
describe "when the first object is a String" do
it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, " ", mode: "w", &@object)
end.should raise_error(IOError)
end
end
describe "when the first object is not a String or Integer" do
it "uses the keyword arguments as options" do
sep = mock("io readlines separator")
sep.should_receive(:to_str).at_least(1).and_return(" ")
it "calls #to_hash to convert the second object to a Hash" do
options = mock("io readlines options Hash")
options.should_receive(:to_hash).and_return({ mode: "w" })
-> do
IO.send(@method, @filename, " ", **options, &@object)
IO.send(@method, @filename, sep, mode: "w", &@object)
end.should raise_error(IOError)
end
end
end
describe "when passed name, separator, limit, options" do
describe "when passed name, separator, limit, keyword arguments" do
it "calls #to_path to convert the name object" do
name = mock("io name to_path")
name.should_receive(:to_path).and_return(@name)
@ -203,12 +236,24 @@ describe :io_readlines_options_19, shared: true do
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
it "calls #to_hash to convert the options object" do
options = mock("io readlines options Hash")
options.should_receive(:to_hash).and_return({ mode: "w" })
it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, " ", 10, **options, &@object)
IO.send(@method, @filename, " ", 10, mode: "w", &@object)
end.should raise_error(IOError)
end
describe "when passed chomp, nil as a separator, and a limit" do
it "yields each line of limit size without truncating trailing new line character" do
# 43 - is a size of the 1st paragraph in the file
result = IO.send(@method, @name, nil, 43, chomp: true, &@object)
(result ? result : ScratchPad.recorded).should == [
"Voici la ligne une.\nQui è la linea due.\n\n\n",
"Aquí está la línea tres.\n" + "Hier ist Zeile ",
"vier.\n\nEstá aqui a linha cinco.\nHere is li",
"ne six.\n"
]
end
end
end
end

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

@ -67,6 +67,12 @@ describe "Kernel#instance_variable_get when passed Symbol" do
it "raises a NameError when the passed Symbol is an invalid instance variable name" do
-> { @obj.instance_variable_get(:"@0") }.should raise_error(NameError)
end
it "returns nil or raises for frozen objects" do
nil.instance_variable_get(:@foo).should == nil
-> { nil.instance_variable_get(:foo) }.should raise_error(NameError)
:foo.instance_variable_get(:@foo).should == nil
end
end
describe "Kernel#instance_variable_get when passed String" do

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

@ -95,5 +95,11 @@ describe "Kernel#instance_variable_set" do
o.instance_variable_set(:@💙, 42)
o.instance_variable_get(:@💙).should == 42
end
it "raises for frozen objects" do
-> { nil.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
-> { nil.instance_variable_set(:foo, 42) }.should raise_error(NameError)
-> { :foo.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
end
end
end

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

@ -41,6 +41,19 @@ describe "Kernel#remove_instance_variable" do
end.should raise_error(TypeError)
end
it "raises a FrozenError if self is frozen" do
o = Object.new
o.freeze
-> { o.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
-> { o.remove_instance_variable(:foo) }.should raise_error(NameError)
end
it "raises for frozen objects" do
-> { nil.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
-> { nil.remove_instance_variable(:foo) }.should raise_error(NameError)
-> { :foo.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
end
describe "when passed a String" do
it_behaves_like :kernel_remove_instance_variable, nil, "@greeting"
end

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

@ -568,6 +568,25 @@ describe :kernel_require, shared: true do
-> { @object.require("unicode_normalize") }.should raise_error(LoadError)
end
ruby_version_is "3.0" do
it "does not load a file earlier on the $LOAD_PATH when other similar features were already loaded" do
Dir.chdir CODE_LOADING_DIR do
@object.send(@method, "../code/load_fixture").should be_true
end
ScratchPad.recorded.should == [:loaded]
$LOAD_PATH.unshift "#{CODE_LOADING_DIR}/b"
# This loads because the above load was not on the $LOAD_PATH
@object.send(@method, "load_fixture").should be_true
ScratchPad.recorded.should == [:loaded, :loaded]
$LOAD_PATH.unshift "#{CODE_LOADING_DIR}/c"
# This does not load because the above load was on the $LOAD_PATH
@object.send(@method, "load_fixture").should be_false
ScratchPad.recorded.should == [:loaded, :loaded]
end
end
end
describe "(shell expansion)" do

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

@ -45,6 +45,12 @@ describe "Math.ldexp" do
it "accepts any second argument that can be coerced with Integer()" do
Math.ldexp(3.23, MathSpecs::Integer.new).should be_close(12.92, TOLERANCE)
end
it "returns correct value that closes to the max value of double type" do
Math.ldexp(0.5122058490966879, 1024).should == 9.207889385574391e+307
Math.ldexp(0.9999999999999999, 1024).should == 1.7976931348623157e+308
Math.ldexp(0.99999999999999999, 1024).should == Float::INFINITY
end
end
describe "Math#ldexp" do

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

@ -23,4 +23,12 @@ describe "Module#class_variables" do
c.extend ModuleSpecs::MVars
c.class_variables.should_not include(:@@mvar)
end
it "returns the correct class variables when inherit is given" do
ModuleSpecs::SubCVars.class_variables(false).should == [:@@sub]
ModuleSpecs::SubCVars.new.singleton_class.class_variables(false).should == []
ModuleSpecs::SubCVars.class_variables(true).should == [:@@sub, :@@cls, :@@meta]
ModuleSpecs::SubCVars.new.singleton_class.class_variables(true).should == [:@@sub, :@@cls, :@@meta]
end
end

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

@ -352,6 +352,10 @@ module ModuleSpecs
end
end
class SubCVars < CVars
@@sub = :sub
end
module MVars
@@mvar = :mvar
end

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

@ -52,7 +52,7 @@ describe "Process.clock_gettime" do
end
# These specs need macOS 10.12+ / darwin 16+
guard_not -> { platform_is_not(:darwin) or RUBY_PLATFORM[/darwin\d+/].to_i >= 16 } do
guard -> { platform_is_not(:darwin) or kernel_version_is '16' } do
platform_is :linux, :openbsd, :darwin do
it "CLOCK_PROCESS_CPUTIME_ID" do
Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should be_an_instance_of(Float)
@ -65,20 +65,6 @@ describe "Process.clock_gettime" do
end
end
platform_is :freebsd, :openbsd do
it "CLOCK_VIRTUAL" do
Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
end
it "CLOCK_PROF" do
Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
end
it "CLOCK_UPTIME" do
Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
end
end
platform_is :linux, :darwin do
it "CLOCK_MONOTONIC_RAW" do
Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should be_an_instance_of(Float)
@ -95,6 +81,21 @@ describe "Process.clock_gettime" do
Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should be_an_instance_of(Float)
end
end
end
platform_is :freebsd, :openbsd do
it "CLOCK_VIRTUAL" do
Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
end
it "CLOCK_PROF" do
Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
end
it "CLOCK_UPTIME" do
Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
end
end
platform_is :freebsd do
it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do
@ -117,21 +118,33 @@ describe "Process.clock_gettime" do
end
end
platform_is :linux do
it "CLOCK_REALTIME_COARSE and CLOCK_REALTIME_ALARM" do
guard -> { platform_is :linux and kernel_version_is '2.6.32' } do
it "CLOCK_REALTIME_COARSE" do
Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float)
Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
end
it "CLOCK_MONOTONIC_COARSE" do
Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float)
end
end
it "CLOCK_BOOTTIME and CLOCK_BOOTTIME_ALARM" do
guard -> { platform_is :linux and kernel_version_is '2.6.39' } do
it "CLOCK_BOOTTIME" do
skip "No Process::CLOCK_BOOTTIME" unless defined?(Process::CLOCK_BOOTTIME)
Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float)
end
end
guard -> { platform_is "x86_64-linux" and kernel_version_is '3.0' } do
it "CLOCK_REALTIME_ALARM" do
skip "No Process::CLOCK_REALTIME_ALARM" unless defined?(Process::CLOCK_REALTIME_ALARM)
Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
end
it "CLOCK_BOOTTIME_ALARM" do
skip "No Process::CLOCK_BOOTTIME_ALARM" unless defined?(Process::CLOCK_BOOTTIME_ALARM)
Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float)
end
end
end
end
end

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

@ -15,5 +15,44 @@ describe "Process.egid" do
end
describe "Process.egid=" do
it "needs to be reviewed for spec completeness"
platform_is_not :windows do
it "raises TypeError if not passed an Integer or String" do
-> { Process.egid = Object.new }.should raise_error(TypeError)
end
it "sets the effective group id to its own gid if given the username corresponding to its own gid" do
raise unless Process.gid == Process.egid
require "etc"
group = Etc.getgrgid(Process.gid).name
Process.egid = group
Process.egid.should == Process.gid
end
as_user do
it "raises Errno::ERPERM if run by a non superuser trying to set the root group id" do
-> { Process.egid = 0 }.should raise_error(Errno::EPERM)
end
platform_is :linux do
it "raises Errno::ERPERM if run by a non superuser trying to set the group id from group name" do
-> { Process.egid = "root" }.should raise_error(Errno::EPERM)
end
end
end
as_superuser do
context "when ran by a superuser" do
it "sets the effective group id for the current process if run by a superuser" do
code = <<-RUBY
Process.egid = 1
puts Process.egid
RUBY
ruby_exe(code).should == "1\n"
end
end
end
end
end

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

@ -21,9 +21,19 @@ describe "Process.euid=" do
-> { Process.euid = Object.new }.should raise_error(TypeError)
end
it "sets the effective user id to its own uid if given the username corresponding to its own uid" do
raise unless Process.uid == Process.euid
require "etc"
user = Etc.getpwuid(Process.uid).name
Process.euid = user
Process.euid.should == Process.uid
end
as_user do
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id" do
-> { (Process.euid = 0)}.should raise_error(Errno::EPERM)
-> { Process.euid = 0 }.should raise_error(Errno::EPERM)
end
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id from username" do

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

@ -349,7 +349,7 @@ describe "Process.spawn" do
pgid = Process.getpgid(Process.pid)
# The process group is not available on all platforms.
# See "man proc" - /proc/[pid]/stat - (5) pgrp
# In Travis arm64 environment, the value is 0.
# In Travis aarch64 environment, the value is 0.
#
# $ cat /proc/[pid]/stat
# 19179 (ruby) S 19160 0 0 ...

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

@ -8,7 +8,7 @@ describe "Process::Status#==" do
end
it "returns true when compared to the integer status of a terminated child" do
ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : nil)
ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
$?.to_i.should == $?
$?.should == $?.to_i
end

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

@ -14,7 +14,7 @@ describe "Process::Status#exited?" do
describe "for a terminated child" do
before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do

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

@ -11,7 +11,7 @@ describe "Process::Status#exitstatus" do
describe "for a child that raised SignalException" do
before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do

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

@ -13,7 +13,7 @@ describe "Process::Status#signaled?" do
describe "for a terminated child" do
before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do

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

@ -23,7 +23,7 @@ describe "Process::Status#success?" do
describe "for a child that was terminated" do
before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do

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

@ -13,7 +13,7 @@ describe "Process::Status#termsig" do
describe "for a child that raised SignalException" do
before :each do
ruby_exe("raise SignalException, 'SIGTERM'", exit_status: nil)
ruby_exe("raise SignalException, 'SIGTERM'", exit_status: :SIGTERM)
end
platform_is_not :windows do
@ -25,7 +25,7 @@ describe "Process::Status#termsig" do
describe "for a child that was sent a signal" do
before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do

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

@ -7,7 +7,7 @@ describe "Process::Status#to_i" do
end
it "returns an integer when the child is signaled" do
ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : nil)
ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : :SIGTERM)
$?.to_i.should be_an_instance_of(Integer)
end
end

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

@ -12,6 +12,11 @@ describe :regexp_quote, shared: true do
Regexp.send(@method, :symbol).should == 'symbol'
end
it "works with substrings" do
str = ".+[]()"[1...-1]
Regexp.send(@method, str).should == '\+\[\]\('
end
it "sets the encoding of the result to US-ASCII if there are only US-ASCII characters present in the input String" do
str = "abc".force_encoding("euc-jp")
Regexp.send(@method, str).encoding.should == Encoding::US_ASCII

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

@ -254,12 +254,10 @@ describe "Signal.trap" do
r.close
loop { w.write("a"*1024) }
RUBY
out = ruby_exe(code, exit_status: nil)
out = ruby_exe(code, exit_status: :SIGPIPE)
status = $?
out.should == "nil\n"
status.should.signaled?
status.termsig.should be_kind_of(Integer)
Signal.signame(status.termsig).should == "PIPE"
end
end

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

@ -35,6 +35,10 @@ describe "String#capitalize" do
it "does not capitalize non-ASCII characters" do
"ßet".capitalize(:ascii).should == "ßet"
end
it "handles non-ASCII substrings properly" do
"garçon"[1..-1].capitalize(:ascii).should == "Arçon"
end
end
describe "full Unicode case mapping adapted for Turkic languages" do

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

@ -49,4 +49,13 @@ describe "String#dup" do
orig.should == "xtring"
dup.should == "string"
end
it "does not modify the original setbyte-mutated string when changing dupped string" do
orig = "a"
orig.setbyte 0, "b".ord
copy = orig.dup
orig.setbyte 0, "c".ord
orig.should == "c"
copy.should == "b"
end
end

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

@ -69,4 +69,13 @@ describe "String#insert with index, other" do
"あれ".insert 0, pat
end.should raise_error(Encoding::CompatibilityError)
end
it "should not call subclassed string methods" do
cls = Class.new(String) do
def replace(arg)
raise "should not call replace"
end
end
cls.new("abcd").insert(0, 'X').should == "Xabcd"
end
end

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

@ -50,4 +50,10 @@ describe "String#lstrip!" do
-> { "hello".freeze.lstrip! }.should raise_error(FrozenError)
-> { "".freeze.lstrip! }.should raise_error(FrozenError)
end
it "raises an ArgumentError if the first codepoint is invalid" do
s = "\xDFabc".force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
-> { s.lstrip! }.should raise_error(ArgumentError)
end
end

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

@ -46,4 +46,10 @@ describe "String#rstrip!" do
-> { "hello".freeze.rstrip! }.should raise_error(FrozenError)
-> { "".freeze.rstrip! }.should raise_error(FrozenError)
end
it "raises an ArgumentError if the last codepoint is invalid" do
s = "abc\xDF".force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
-> { s.rstrip! }.should raise_error(ArgumentError)
end
end

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

@ -14,6 +14,11 @@ describe "String#scrub with a default replacement" do
"abc\u3042#{x81}".scrub.should == "abc\u3042\uFFFD"
end
it "replaces invalid byte sequences in lazy substrings" do
x81 = [0x81].pack('C').force_encoding('utf-8')
"abc\u3042#{x81}def"[1...-1].scrub.should == "bc\u3042\uFFFDde"
end
it "returns a copy of self when the input encoding is BINARY" do
input = "foo".encode('BINARY')

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

@ -375,10 +375,20 @@ describe :string_slice_regexp_index, shared: true do
"hello there".send(@method, /(what?)/, 1).should == nil
end
it "returns nil if the index is larger than the number of captures" do
"hello there".send(@method, /hello (.)/, 2).should == nil
# You can't refer to 0 using negative indices
"hello there".send(@method, /hello (.)/, -2).should == nil
end
it "returns nil if there is no capture for the given index" do
"hello there".send(@method, /[aeiou](.)\1/, 2).should == nil
# You can't refer to 0 using negative indices
"hello there".send(@method, /[aeiou](.)\1/, -2).should == nil
end
it "returns nil if the given capture group was not matched but still sets $~" do
"test".send(@method, /te(z)?/, 1).should == nil
$~[0].should == "te"
$~[1].should == nil
end
it "calls to_int on the given index" do

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

@ -3,12 +3,17 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "String#split with String" do
it "throws an ArgumentError if the string is not a valid" do
s = "\xDF".force_encoding(Encoding::UTF_8)
-> { s.split }.should raise_error(ArgumentError)
-> { s.split(':') }.should raise_error(ArgumentError)
end
it "throws an ArgumentError if the pattern is not a valid string" do
str = 'проверка'
broken_str = 'проверка'
broken_str.force_encoding('binary')
broken_str.chop!
broken_str.force_encoding('utf-8')
broken_str = "\xDF".force_encoding(Encoding::UTF_8)
-> { str.split(broken_str) }.should raise_error(ArgumentError)
end
@ -218,6 +223,12 @@ describe "String#split with String" do
end
describe "String#split with Regexp" do
it "throws an ArgumentError if the string is not a valid" do
s = "\xDF".force_encoding(Encoding::UTF_8)
-> { s.split(/./) }.should raise_error(ArgumentError)
end
it "divides self on regexp matches" do
" now's the time".split(/ /).should == ["", "now's", "", "the", "time"]
" x\ny ".split(/ /).should == ["", "x\ny"]

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

@ -20,4 +20,9 @@ describe "String#unpack with format 'Z'" do
["\x00a\x00 bc \x00", ["", "c"]]
].should be_computed_by(:unpack, "Z5Z")
end
it "does not advance past the null byte when given a 'Z' format specifier" do
"a\x00\x0f".unpack('Zxc').should == ['a', 15]
"a\x00\x0f".unpack('Zcc').should == ['a', 0, 15]
end
end

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

@ -102,6 +102,30 @@ describe "Thread#raise on a sleeping thread" do
raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:")
end
end
it "calls #exception in both the caller and in the target thread" do
cls = Class.new(Exception) do
attr_accessor :log
def initialize(*args)
@log = [] # This is shared because the super #exception uses a shallow clone
super
end
def exception(*args)
@log << [self, Thread.current, args]
super
end
end
exc = cls.new
@thr.raise exc, "Thread#raise #exception spec"
@thr.join
ScratchPad.recorded.should.is_a?(cls)
exc.log.should == [
[exc, Thread.current, ["Thread#raise #exception spec"]],
[ScratchPad.recorded, @thr, []]
]
end
end
describe "Thread#raise on a running thread" do

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

@ -0,0 +1 @@
ScratchPad << :loaded

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

@ -300,6 +300,44 @@ describe 'Optional variable assignments' do
(@b[:k] ||= 12).should == 12
end
it 'correctly handles a splatted argument for the index' do
(@b[*[:k]] ||= 12).should == 12
end
it "evaluates the index precisely once" do
ary = [:x, :y]
@a[:x] = 15
@a[ary.pop] ||= 25
ary.should == [:x]
@a.should == { x: 15, y: 25 }
end
it "evaluates the index arguments in the correct order" do
ary = Class.new(Array) do
def [](x, y)
super(x + 3 * y)
end
def []=(x, y, value)
super(x + 3 * y, value)
end
end.new
ary[0, 0] = 1
ary[1, 0] = 1
ary[2, 0] = nil
ary[3, 0] = 1
ary[4, 0] = 1
ary[5, 0] = 1
ary[6, 0] = nil
foo = [0, 2]
ary[foo.pop, foo.pop] ||= 2
ary[2, 0].should == 2
ary[6, 0].should == nil
end
it 'returns the assigned value, not the result of the []= method with +=' do
@b[:k] = 17
(@b[:k] += 12).should == 29

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

@ -570,7 +570,6 @@ describe "Predefined global $/" do
($/ = "xyz").should == "xyz"
end
it "changes $-0" do
$/ = "xyz"
$-0.should equal($/)
@ -641,6 +640,45 @@ describe "Predefined global $-0" do
end
end
describe "Predefined global $\\" do
before :each do
@verbose, $VERBOSE = $VERBOSE, nil
@dollar_backslash = $\
end
after :each do
$\ = @dollar_backslash
$VERBOSE = @verbose
end
it "can be assigned a String" do
str = "abc"
$\ = str
$\.should equal(str)
end
it "can be assigned nil" do
$\ = nil
$\.should be_nil
end
it "returns the value assigned" do
($\ = "xyz").should == "xyz"
end
it "does not call #to_str to convert the object to a String" do
obj = mock("$\\ value")
obj.should_not_receive(:to_str)
-> { $\ = obj }.should raise_error(TypeError)
end
it "raises a TypeError if assigned not String" do
-> { $\ = 1 }.should raise_error(TypeError)
-> { $\ = true }.should raise_error(TypeError)
end
end
describe "Predefined global $," do
after :each do
$, = nil
@ -1340,3 +1378,29 @@ describe "$LOAD_PATH.resolve_feature_path" do
end
end
end
# Some other pre-defined global variables
describe "Predefined global $=" do
before :each do
@verbose, $VERBOSE = $VERBOSE, nil
@dollar_assign = $=
end
after :each do
$= = @dollar_assign
$VERBOSE = @verbose
end
it "warns when accessed" do
-> { a = $= }.should complain(/is no longer effective/)
end
it "warns when assigned" do
-> { $= = "_" }.should complain(/is no longer effective/)
end
it "returns the value assigned" do
($= = "xyz").should == "xyz"
end
end

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

@ -849,4 +849,22 @@ describe "Instance variables" do
-> { obj.foobar }.should_not complain(verbose: true)
end
end
describe "global variable" do
context "when global variable is uninitialized" do
it "warns about accessing uninitialized global variable in verbose mode" do
obj = Object.new
def obj.foobar; a = $specs_uninitialized_global_variable; end
-> { obj.foobar }.should complain(/warning: global variable `\$specs_uninitialized_global_variable' not initialized/, verbose: true)
end
it "doesn't warn at lazy initialization" do
obj = Object.new
def obj.foobar; $specs_uninitialized_global_variable_lazy ||= 42; end
-> { obj.foobar }.should_not complain(verbose: true)
end
end
end
end

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

@ -213,3 +213,13 @@ describe "Using yield in a singleton class literal" do
end
end
end
describe "Using yield in non-lambda block" do
it 'raises a SyntaxError' do
code = <<~RUBY
1.times { yield }
RUBY
-> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
end
end

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

@ -128,4 +128,22 @@ describe "ObjectSpace.trace_object_allocations" do
ObjectSpace.trace_object_allocations_stop
end
end
it "returns nil for class_path, generation, method_id, sourcefile, and sourceline for immutable objects" do
ObjectSpace.trace_object_allocations_start
begin
one = nil
two = 42
three = :foo
[one, two, three].each do |i|
ObjectSpace.allocation_class_path(i).should == nil
ObjectSpace.allocation_generation(i).should == nil
ObjectSpace.allocation_method_id(i).should == nil
ObjectSpace.allocation_sourcefile(i).should == nil
ObjectSpace.allocation_sourceline(i).should == nil
end
ensure
ObjectSpace.trace_object_allocations_stop
end
end
end

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

@ -0,0 +1,78 @@
require_relative '../../../../spec_helper'
require 'openssl'
describe "OpenSSL::X509::Name.verify" do
it "returns true for valid certificate" do
key = OpenSSL::PKey::RSA.new 2048
cert = OpenSSL::X509::Certificate.new
cert.version = 2
cert.serial = 1
cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
cert.issuer = cert.subject
cert.public_key = key.public_key
cert.not_before = Time.now
cert.not_after = cert.not_before + 365 * 24 * 60 * 60
cert.sign key, OpenSSL::Digest.new('SHA1')
store = OpenSSL::X509::Store.new
store.add_cert(cert)
store.verify(cert).should == true
end
it "returns false for an expired certificate" do
key = OpenSSL::PKey::RSA.new 2048
cert = OpenSSL::X509::Certificate.new
cert.version = 2
cert.serial = 1
cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
cert.issuer = cert.subject
cert.public_key = key.public_key
cert.not_before = Time.now - 10
cert.not_after = Time.now - 5
cert.sign key, OpenSSL::Digest.new('SHA1')
store = OpenSSL::X509::Store.new
store.add_cert(cert)
store.verify(cert).should == false
end
it "returns false for an expired root certificate" do
root_key = OpenSSL::PKey::RSA.new 2048
root_cert = OpenSSL::X509::Certificate.new
root_cert.version = 2
root_cert.serial = 1
root_cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
root_cert.issuer = root_cert.subject
root_cert.public_key = root_key.public_key
root_cert.not_before = Time.now - 10
root_cert.not_after = Time.now - 5
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = root_cert
ef.issuer_certificate = root_cert
root_cert.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
root_cert.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
root_cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
root_cert.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
root_cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
key = OpenSSL::PKey::RSA.new 2048
cert = OpenSSL::X509::Certificate.new
cert.version = 2
cert.serial = 2
cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby certificate"
cert.issuer = root_cert.subject
cert.public_key = key.public_key
cert.not_before = Time.now
cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = cert
ef.issuer_certificate = root_cert
cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true))
cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
store = OpenSSL::X509::Store.new
store.add_cert(root_cert)
store.add_cert(cert)
store.verify(cert).should == false
end
end

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

@ -17,3 +17,7 @@ end
describe "StringIO#each_line when passed chomp" do
it_behaves_like :stringio_each_chomp, :each_line
end
describe "StringIO#each_line when passed limit" do
it_behaves_like :stringio_each_limit, :each_line
end

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

@ -17,3 +17,11 @@ end
describe "StringIO#each when passed chomp" do
it_behaves_like :stringio_each_chomp, :each
end
describe "StringIO#each when passed chomp" do
it_behaves_like :stringio_each_separator_and_chomp, :each
end
describe "StringIO#each when passed limit" do
it_behaves_like :stringio_each_limit, :each
end

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

@ -171,6 +171,10 @@ describe "StringIO#gets when passed [limit]" do
it "returns a blank string when passed a limit of 0" do
@io.gets(0).should == ""
end
it "ignores it when passed a negative limit" do
@io.gets(-4).should == "this>is>an>example"
end
end
describe "StringIO#gets when passed [separator] and [limit]" do

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

@ -128,3 +128,23 @@ describe "StringIO#readline when passed [chomp]" do
io.readline(chomp: true).should == "this>is>an>example"
end
end
describe "StringIO#readline when passed [limit]" do
before :each do
@io = StringIO.new("this>is>an>example")
end
it "returns the data read until the limit is met" do
io = StringIO.new("this>is>an>example\n")
io.readline(3).should == "thi"
end
it "returns a blank string when passed a limit of 0" do
@io.readline(0).should == ""
end
it "ignores it when the limit is negative" do
seen = []
@io.readline(-4).should == "this>is>an>example"
end
end

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

@ -98,3 +98,21 @@ describe "StringIO#readlines when passed [chomp]" do
io.readlines(chomp: true).should == ["this>is", "an>example"]
end
end
describe "StringIO#readlines when passed [limit]" do
before :each do
@io = StringIO.new("a b c d e\n1 2 3 4 5")
end
it "returns the data read until the limit is met" do
@io.readlines(4).should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"]
end
it "raises ArgumentError when limit is 0" do
-> { @io.readlines(0) }.should raise_error(ArgumentError)
end
it "ignores it when the limit is negative" do
@io.readlines(-4).should == ["a b c d e\n", "1 2 3 4 5"]
end
end

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

@ -123,4 +123,41 @@ describe :stringio_each_chomp, shared: true do
io.send(@method, chomp: true) {|s| seen << s }
seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"]
end
it "returns each line with removed newline characters when called without block" do
seen = []
io = StringIO.new("a b \rc d e\n1 2 3 4 5\r\nthe end")
enum = io.send(@method, chomp: true)
enum.each {|s| seen << s }
seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"]
end
end
describe :stringio_each_separator_and_chomp, shared: true do
it "yields each line with removed separator to the passed block" do
seen = []
io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end")
io.send(@method, "|", chomp: true) {|s| seen << s }
seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"]
end
it "returns each line with removed separator when called without block" do
seen = []
io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end")
enum = io.send(@method, "|", chomp: true)
enum.each {|s| seen << s }
seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"]
end
end
describe :stringio_each_limit, shared: true do
before :each do
@io = StringIO.new("a b c d e\n1 2 3 4 5")
end
it "returns the data read until the limit is met" do
seen = []
@io.send(@method, 4) { |s| seen << s }
seen.should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"]
end
end

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

@ -2,7 +2,12 @@ require_relative '../../spec_helper'
require "zlib"
describe "Zlib.crc_table" do
# This spec fails when zlib.h and libz.so are not from the same version.
# In older zlib (< 1.2.7 it seems), get_crc_table() is stored as u64[],
# but in newer zlib, get_crc_table() is stored as u32[].
# Technically, there is ABI breakage between those zlib versions,
# but get_crc_table() is an "undocumented function" according to zlib.h.
guard -> { ENV["RUBY_SPEC_TEST_ZLIB_CRC_TABLE"] != "false" } do
it "returns the same value as zlib's get_crc_table()" do
Zlib.crc_table.should == [
0, 1996959894, 3993919788, 2567524794,
@ -71,5 +76,5 @@ describe "Zlib.crc_table" do
3020668471, 3272380065, 1510334235, 755167117,
]
end
end
end

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

@ -196,16 +196,6 @@ describe "C-API Class function" do
end
end
describe "rb_define_method" do
it "defines a method taking variable arguments as a C array if the argument count is -1" do
@s.rb_method_varargs_1(1, 3, 7, 4).should == [1, 3, 7, 4]
end
it "defines a method taking variable arguments as a Ruby array if the argument count is -2" do
@s.rb_method_varargs_2(1, 3, 7, 4).should == [1, 3, 7, 4]
end
end
describe "rb_class2name" do
it "returns the class name" do
@s.rb_class2name(CApiClassSpecs).should == "CApiClassSpecs"

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

@ -613,15 +613,15 @@ describe "C-API Encoding function" do
it 'converts a Unicode codepoint to a UTF-8 C string' do
str = ' ' * 6
{
0 => "\x01",
0x7f => "\xC2\x80",
0x7ff => "\xE0\xA0\x80",
0xffff => "\xF0\x90\x80\x80",
0x1fffff => "\xF8\x88\x80\x80\x80",
0x3ffffff => "\xFC\x84\x80\x80\x80\x80",
1 => "\x01",
0x80 => "\xC2\x80",
0x800 => "\xE0\xA0\x80",
0x10000 => "\xF0\x90\x80\x80",
0x200000 => "\xF8\x88\x80\x80\x80",
0x4000000 => "\xFC\x84\x80\x80\x80\x80",
}.each do |num, result|
len = @s.rb_uv_to_utf8(str, num + 1)
str[0..len-1].should == result
len = @s.rb_uv_to_utf8(str, num)
str.byteslice(0, len).should == result
end
end
end

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

@ -142,19 +142,6 @@ static VALUE class_spec_include_module(VALUE self, VALUE klass, VALUE module) {
return klass;
}
static VALUE class_spec_method_var_args_1(int argc, VALUE *argv, VALUE self) {
VALUE ary = rb_ary_new();
int i;
for (i = 0; i < argc; i++) {
rb_ary_push(ary, argv[i]);
}
return ary;
}
static VALUE class_spec_method_var_args_2(VALUE self, VALUE argv) {
return argv;
}
void Init_class_spec(void) {
VALUE cls = rb_define_class("CApiClassSpecs", rb_cObject);
rb_define_method(cls, "define_call_super_method", class_spec_define_call_super_method, 2);
@ -185,8 +172,6 @@ void Init_class_spec(void) {
rb_define_method(cls, "rb_define_class_id_under", class_spec_rb_define_class_id_under, 3);
rb_define_method(cls, "rb_define_class_variable", class_spec_define_class_variable, 3);
rb_define_method(cls, "rb_include_module", class_spec_include_module, 2);
rb_define_method(cls, "rb_method_varargs_1", class_spec_method_var_args_1, -1);
rb_define_method(cls, "rb_method_varargs_2", class_spec_method_var_args_2, -2);
}
#ifdef __cplusplus

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

@ -275,7 +275,9 @@ static VALUE encoding_spec_rb_enc_str_asciionly_p(VALUE self, VALUE str) {
}
static VALUE encoding_spec_rb_uv_to_utf8(VALUE self, VALUE buf, VALUE num) {
return INT2NUM(rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num)));
int len = rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num));
RB_ENC_CODERANGE_CLEAR(buf);
return INT2NUM(len);
}
static VALUE encoding_spec_ONIGENC_MBC_CASE_FOLD(VALUE self, VALUE str) {

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

@ -9,18 +9,6 @@ static VALUE module_specs_test_method(VALUE self) {
return ID2SYM(rb_intern("test_method"));
}
static VALUE module_specs_test_method_2required(VALUE self, VALUE arg1, VALUE arg2) {
return ID2SYM(rb_intern("test_method_2required"));
}
static VALUE module_specs_test_method_c_array(int argc, VALUE *argv, VALUE self) {
return ID2SYM(rb_intern("test_method_c_array"));
}
static VALUE module_specs_test_method_ruby_array(VALUE self, VALUE args) {
return ID2SYM(rb_intern("test_method_ruby_array"));
}
static VALUE module_specs_const_defined(VALUE self, VALUE klass, VALUE id) {
return rb_const_defined(klass, SYM2ID(id)) ? Qtrue : Qfalse;
}
@ -88,19 +76,25 @@ static VALUE module_specs_rb_define_method(VALUE self, VALUE cls, VALUE str_name
return Qnil;
}
static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE cls, VALUE str_name) {
rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_2required, 2);
return Qnil;
static VALUE module_specs_method_var_args_1(int argc, VALUE *argv, VALUE self) {
VALUE ary = rb_ary_new();
int i;
for (i = 0; i < argc; i++) {
rb_ary_push(ary, argv[i]);
}
return ary;
}
static VALUE module_specs_rb_define_method_c_array(VALUE self, VALUE cls, VALUE str_name) {
rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_c_array, -1);
return Qnil;
static VALUE module_specs_method_var_args_2(VALUE self, VALUE argv) {
return argv;
}
static VALUE module_specs_rb_define_method_ruby_array(VALUE self, VALUE cls, VALUE str_name) {
rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_ruby_array, -2);
return Qnil;
static VALUE module_specs_rb_define_method_1required(VALUE self, VALUE arg1) {
return arg1;
}
static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE arg1, VALUE arg2) {
return arg2;
}
static VALUE module_specs_rb_define_module_function(VALUE self, VALUE cls, VALUE str_name) {
@ -155,25 +149,21 @@ void Init_module_spec(void) {
rb_define_method(cls, "rb_define_module_under", module_specs_rb_define_module_under, 2);
rb_define_method(cls, "rb_define_const", module_specs_define_const, 3);
rb_define_method(cls, "rb_define_global_const", module_specs_define_global_const, 2);
rb_define_method(cls, "rb_define_global_function",
module_specs_rb_define_global_function, 1);
rb_define_method(cls, "rb_define_global_function", module_specs_rb_define_global_function, 1);
rb_define_method(cls, "rb_define_method", module_specs_rb_define_method, 2);
rb_define_method(cls, "rb_define_method_varargs_1", module_specs_method_var_args_1, -1);
rb_define_method(cls, "rb_define_method_varargs_2", module_specs_method_var_args_2, -2);
rb_define_method(cls, "rb_define_method_1required", module_specs_rb_define_method_1required, 1);
rb_define_method(cls, "rb_define_method_2required", module_specs_rb_define_method_2required, 2);
rb_define_method(cls, "rb_define_method_c_array", module_specs_rb_define_method_c_array, 2);
rb_define_method(cls, "rb_define_method_ruby_array", module_specs_rb_define_method_ruby_array, 2);
rb_define_method(cls, "rb_define_module_function",
module_specs_rb_define_module_function, 2);
rb_define_method(cls, "rb_define_module_function", module_specs_rb_define_module_function, 2);
rb_define_method(cls, "rb_define_private_method",
module_specs_rb_define_private_method, 2);
rb_define_method(cls, "rb_define_private_method", module_specs_rb_define_private_method, 2);
rb_define_method(cls, "rb_define_protected_method",
module_specs_rb_define_protected_method, 2);
rb_define_method(cls, "rb_define_protected_method", module_specs_rb_define_protected_method, 2);
rb_define_method(cls, "rb_define_singleton_method",
module_specs_rb_define_singleton_method, 2);
rb_define_method(cls, "rb_define_singleton_method", module_specs_rb_define_singleton_method, 2);
rb_define_method(cls, "rb_undef_method", module_specs_rb_undef_method, 2);
rb_define_method(cls, "rb_undef", module_specs_rb_undef, 2);

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

@ -301,6 +301,13 @@ static VALUE so_is_rb_type_p_data(VALUE self, VALUE obj) {
return Qfalse;
}
static VALUE so_is_rb_type_p_file(VALUE self, VALUE obj) {
if(rb_type_p(obj, T_FILE)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_object(VALUE self, VALUE obj) {
if(BUILTIN_TYPE(obj) == T_OBJECT) {
return Qtrue;
@ -478,6 +485,7 @@ void Init_object_spec(void) {
rb_define_method(cls, "rb_is_rb_type_p_module", so_is_rb_type_p_module, 1);
rb_define_method(cls, "rb_is_rb_type_p_class", so_is_rb_type_p_class, 1);
rb_define_method(cls, "rb_is_rb_type_p_data", so_is_rb_type_p_data, 1);
rb_define_method(cls, "rb_is_rb_type_p_file", so_is_rb_type_p_file, 1);
rb_define_method(cls, "rb_is_builtin_type_object", so_is_builtin_type_object, 1);
rb_define_method(cls, "rb_is_builtin_type_array", so_is_builtin_type_array, 1);
rb_define_method(cls, "rb_is_builtin_type_module", so_is_builtin_type_module, 1);

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

@ -49,6 +49,12 @@ VALUE regexp_spec_match(VALUE self, VALUE regexp, VALUE str) {
return rb_funcall(regexp, rb_intern("match"), 1, str);
}
VALUE regexp_spec_memcicmp(VALUE self, VALUE str1, VALUE str2) {
long l1 = RSTRING_LEN(str1);
long l2 = RSTRING_LEN(str2);
return INT2FIX(rb_memcicmp(RSTRING_PTR(str1), RSTRING_PTR(str2), l1 < l2 ? l1 : l2));
}
void Init_regexp_spec(void) {
VALUE cls = rb_define_class("CApiRegexpSpecs", rb_cObject);
rb_define_method(cls, "match", regexp_spec_match, 2);
@ -60,6 +66,7 @@ void Init_regexp_spec(void) {
rb_define_method(cls, "rb_reg_match_backref_get", regexp_spec_reg_match_backref_get, 2);
rb_define_method(cls, "rb_reg_options", regexp_spec_rb_reg_options, 1);
rb_define_method(cls, "rb_reg_regcomp", regexp_spec_rb_reg_regcomp, 1);
rb_define_method(cls, "rb_memcicmp", regexp_spec_memcicmp, 2);
}
#ifdef __cplusplus

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

@ -252,22 +252,30 @@ describe "CApiModule" do
cls.new.method(:test_method).arity.should == 0
end
it "returns the correct arity when argc of the method in class is -1" do
cls = Class.new
@m.rb_define_method_c_array(cls, "test_method_c_array")
cls.new.method(:test_method_c_array).arity.should == -1
end
it "returns the correct arity when argc of the method in class is -2" do
cls = Class.new
@m.rb_define_method_ruby_array(cls, "test_method_ruby_array")
cls.new.method(:test_method_ruby_array).arity.should == -1
it "returns the correct arity when argc of the method in class is 1" do
@m.rb_define_method_1required(42).should == 42
@m.method(:rb_define_method_1required).arity.should == 1
end
it "returns the correct arity when argc of the method in class is 2" do
cls = Class.new
@m.rb_define_method_2required(cls, "test_method_2required")
cls.new.method(:test_method_2required).arity.should == 2
@m.rb_define_method_2required(1, 2).should == 2
@m.method(:rb_define_method_2required).arity.should == 2
end
it "defines a method taking variable arguments as a C array if the argument count is -1" do
@m.rb_define_method_varargs_1(1, 3, 7, 4).should == [1, 3, 7, 4]
end
it "returns the correct arity when argc of the method in class is -1" do
@m.method(:rb_define_method_varargs_1).arity.should == -1
end
it "defines a method taking variable arguments as a Ruby array if the argument count is -2" do
@m.rb_define_method_varargs_2(1, 3, 7, 4).should == [1, 3, 7, 4]
end
it "returns the correct arity when argc of the method in class is -2" do
@m.method(:rb_define_method_varargs_2).arity.should == -1
end
it "defines a method on a module" do

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

@ -30,6 +30,7 @@ describe "CApiObject" do
class ObjectTest
def initialize
@foo = 7
yield if block_given?
end
def foo
@ -88,6 +89,15 @@ describe "CApiObject" do
o.initialized.should be_true
o.arguments.should == [:one, :two]
end
it "passes the block to #initialize" do
v = nil
o = @o.rb_obj_alloc(ObjectTest)
@o.rb_obj_call_init(o, 0, []) do
v = :foo
end
v.should == :foo
end
end
describe "rb_is_instance_of" do
@ -513,6 +523,21 @@ describe "CApiObject" do
@o.rb_is_type_class(ObjectTest).should == true
@o.rb_is_type_data(Time.now).should == true
end
it "returns T_FILE for instances of IO and subclasses" do
STDERR.class.should == IO
@o.rb_is_rb_type_p_file(STDERR).should == true
File.open(__FILE__) do |f|
f.class.should == File
@o.rb_is_rb_type_p_file(f).should == true
end
require 'socket'
TCPServer.open(0) do |s|
@o.rb_is_rb_type_p_file(s).should == true
end
end
end
describe "rb_check_type" do

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

@ -109,4 +109,20 @@ describe "C-API Regexp function" do
thr.join
end
end
describe "rb_memicmp" do
it "returns 0 for identical strings" do
@p.rb_memcicmp('Hello', 'Hello').should == 0
end
it "returns 0 for strings which only differ in case" do
@p.rb_memcicmp('Hello', 'HELLO').should == 0
@p.rb_memcicmp('HELLO', 'Hello').should == 0
end
it "returns the difference between the first non matching characters" do
@p.rb_memcicmp('Hello', 'HELLP').should == -1
@p.rb_memcicmp('HELLp', 'Hello').should == 1
end
end
end

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

@ -14,8 +14,7 @@ else
end
end
# Running directly with ruby some_spec.rb
unless ENV['MSPEC_RUNNER']
unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb
mspec_lib = File.expand_path("../../mspec/lib", __FILE__)
$LOAD_PATH << mspec_lib if File.directory?(mspec_lib)
@ -26,7 +25,13 @@ unless ENV['MSPEC_RUNNER']
puts "Please add -Ipath/to/mspec/lib or clone mspec as a sibling to run the specs."
exit 1
end
end
ruby_version_is ""..."2.7" do
abort "This version of ruby/spec requires Ruby 2.7+"
end
unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb
ARGV.unshift $0
MSpecRun.main
end