зеркало из https://github.com/github/ruby.git
Update to ruby/spec@3a510bb
This commit is contained in:
Родитель
40c9a3dad5
Коммит
815db5c028
|
@ -63,7 +63,6 @@ Lint/LiteralInInterpolation:
|
|||
- 'language/string_spec.rb'
|
||||
- 'language/symbol_spec.rb'
|
||||
- 'language/undef_spec.rb'
|
||||
- 'library/net/ftp/connect_spec.rb'
|
||||
|
||||
# Offense count: 8
|
||||
# Cop supports --auto-correct.
|
||||
|
|
|
@ -73,6 +73,11 @@ describe "Encoding#replicate" do
|
|||
Encoding::US_ASCII.replicate('MY-US-ASCII')
|
||||
}.should complain(/warning: Encoding#replicate is deprecated and will be removed in Ruby 3.3; use the original encoding instead/)
|
||||
end
|
||||
|
||||
it "raises EncodingError if too many encodings" do
|
||||
code = '1_000.times {|i| Encoding::US_ASCII.replicate("R_#{i}") }'
|
||||
ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "3.3" do
|
||||
|
|
|
@ -342,4 +342,10 @@ module EnumerableSpecs
|
|||
@block.call(*args)
|
||||
end
|
||||
end
|
||||
|
||||
# Set is a core class since Ruby 3.2
|
||||
ruby_version_is '3.2' do
|
||||
class SetSubclass < Set
|
||||
end
|
||||
end
|
||||
end # EnumerableSpecs utility classes
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
require_relative '../../spec_helper'
|
||||
require_relative 'fixtures/classes'
|
||||
|
||||
ruby_version_is "3.2" do
|
||||
describe "Enumerable#to_set" do
|
||||
it "returns a new Set created from self" do
|
||||
[1, 2, 3].to_set.should == Set[1, 2, 3]
|
||||
{a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
|
||||
end
|
||||
|
||||
it "passes down passed blocks" do
|
||||
[1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
|
||||
end
|
||||
|
||||
it "instantiates an object of provided as the first argument set class" do
|
||||
set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass)
|
||||
set.should be_kind_of(EnumerableSpecs::SetSubclass)
|
||||
set.to_a.sort.should == [1, 2, 3]
|
||||
end
|
||||
|
||||
it "does not need explicit `require 'set'`" do
|
||||
output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
|
||||
puts [1, 2, 3].to_set
|
||||
RUBY
|
||||
|
||||
output.chomp.should == "#<Set: {1, 2, 3}>"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +1,12 @@
|
|||
require_relative '../../spec_helper'
|
||||
require_relative 'shared/update_time'
|
||||
|
||||
describe "File.lutime" do
|
||||
platform_is_not :windows do
|
||||
platform_is_not :windows do
|
||||
describe "File.lutime" do
|
||||
it_behaves_like :update_time, :lutime
|
||||
end
|
||||
|
||||
describe "File.lutime" do
|
||||
before :each do
|
||||
@atime = Time.utc(2000)
|
||||
@mtime = Time.utc(2001)
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
describe :update_time, shared: true do
|
||||
before :all do
|
||||
@time_is_float = platform_is :windows
|
||||
end
|
||||
|
||||
before :each do
|
||||
@atime = Time.now
|
||||
@mtime = Time.now
|
||||
@file1 = tmp("specs_file_utime1")
|
||||
@file2 = tmp("specs_file_utime2")
|
||||
touch @file1
|
||||
touch @file2
|
||||
end
|
||||
|
||||
after :each do
|
||||
rm_r @file1, @file2
|
||||
end
|
||||
|
||||
it "sets the access and modification time of each file" do
|
||||
File.send(@method, @atime, @mtime, @file1, @file2)
|
||||
|
||||
if @time_is_float
|
||||
File.atime(@file1).should be_close(@atime, 0.0001)
|
||||
File.mtime(@file1).should be_close(@mtime, 0.0001)
|
||||
File.atime(@file2).should be_close(@atime, 0.0001)
|
||||
File.mtime(@file2).should be_close(@mtime, 0.0001)
|
||||
else
|
||||
File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
|
||||
File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
|
||||
end
|
||||
end
|
||||
|
||||
it "uses the current times if two nil values are passed" do
|
||||
tn = Time.now
|
||||
File.send(@method, nil, nil, @file1, @file2)
|
||||
|
||||
if @time_is_float
|
||||
File.atime(@file1).should be_close(tn, 0.050)
|
||||
File.mtime(@file1).should be_close(tn, 0.050)
|
||||
File.atime(@file2).should be_close(tn, 0.050)
|
||||
File.mtime(@file2).should be_close(tn, 0.050)
|
||||
else
|
||||
File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
|
||||
File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
|
||||
end
|
||||
end
|
||||
|
||||
it "accepts an object that has a #to_path method" do
|
||||
File.send(@method, @atime, @mtime, mock_to_path(@file1), mock_to_path(@file2))
|
||||
end
|
||||
|
||||
it "accepts numeric atime and mtime arguments" do
|
||||
if @time_is_float
|
||||
File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2)
|
||||
|
||||
File.atime(@file1).should be_close(@atime, 0.0001)
|
||||
File.mtime(@file1).should be_close(@mtime, 0.0001)
|
||||
File.atime(@file2).should be_close(@atime, 0.0001)
|
||||
File.mtime(@file2).should be_close(@mtime, 0.0001)
|
||||
else
|
||||
File.send(@method, @atime.to_i, @mtime.to_i, @file1, @file2)
|
||||
|
||||
File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
|
||||
File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
|
||||
end
|
||||
end
|
||||
|
||||
it "may set nanosecond precision" do
|
||||
t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
|
||||
File.send(@method, t, t, @file1)
|
||||
|
||||
File.atime(@file1).nsec.should.between?(0, 123500000)
|
||||
File.mtime(@file1).nsec.should.between?(0, 123500000)
|
||||
end
|
||||
|
||||
it "returns the number of filenames in the arguments" do
|
||||
File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2).should == 2
|
||||
end
|
||||
|
||||
platform_is :linux do
|
||||
platform_is wordsize: 64 do
|
||||
it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do
|
||||
# https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
|
||||
# "Therefore, timestamps should not overflow until May 2446."
|
||||
# https://lwn.net/Articles/804382/
|
||||
# "On-disk timestamps hitting the y2038 limit..."
|
||||
# The problem seems to be being improved, but currently it actually fails on XFS on RHEL8
|
||||
# https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz
|
||||
# Amazon Linux 2023 returns 2486-07-02 in this example
|
||||
# http://rubyci.s3.amazonaws.com/amazon2023/ruby-master/log/20230322T063004Z.fail.html.gz
|
||||
time = Time.at(1<<44)
|
||||
File.send(@method, time, time, @file1)
|
||||
|
||||
[559444, 2486, 2446, 2038].should.include? File.atime(@file1).year
|
||||
[559444, 2486, 2446, 2038].should.include? File.mtime(@file1).year
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,102 +1,6 @@
|
|||
require_relative '../../spec_helper'
|
||||
require_relative 'shared/update_time'
|
||||
|
||||
describe "File.utime" do
|
||||
|
||||
before :all do
|
||||
@time_is_float = platform_is :windows
|
||||
end
|
||||
|
||||
before :each do
|
||||
@atime = Time.now
|
||||
@mtime = Time.now
|
||||
@file1 = tmp("specs_file_utime1")
|
||||
@file2 = tmp("specs_file_utime2")
|
||||
touch @file1
|
||||
touch @file2
|
||||
end
|
||||
|
||||
after :each do
|
||||
rm_r @file1, @file2
|
||||
end
|
||||
|
||||
it "sets the access and modification time of each file" do
|
||||
File.utime(@atime, @mtime, @file1, @file2)
|
||||
if @time_is_float
|
||||
File.atime(@file1).should be_close(@atime, 0.0001)
|
||||
File.mtime(@file1).should be_close(@mtime, 0.0001)
|
||||
File.atime(@file2).should be_close(@atime, 0.0001)
|
||||
File.mtime(@file2).should be_close(@mtime, 0.0001)
|
||||
else
|
||||
File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
|
||||
File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
|
||||
end
|
||||
end
|
||||
|
||||
it "uses the current times if two nil values are passed" do
|
||||
tn = Time.now
|
||||
File.utime(nil, nil, @file1, @file2)
|
||||
if @time_is_float
|
||||
File.atime(@file1).should be_close(tn, 0.050)
|
||||
File.mtime(@file1).should be_close(tn, 0.050)
|
||||
File.atime(@file2).should be_close(tn, 0.050)
|
||||
File.mtime(@file2).should be_close(tn, 0.050)
|
||||
else
|
||||
File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
|
||||
File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
|
||||
end
|
||||
end
|
||||
|
||||
it "accepts an object that has a #to_path method" do
|
||||
File.utime(@atime, @mtime, mock_to_path(@file1), mock_to_path(@file2))
|
||||
end
|
||||
|
||||
it "accepts numeric atime and mtime arguments" do
|
||||
if @time_is_float
|
||||
File.utime(@atime.to_f, @mtime.to_f, @file1, @file2)
|
||||
File.atime(@file1).should be_close(@atime, 0.0001)
|
||||
File.mtime(@file1).should be_close(@mtime, 0.0001)
|
||||
File.atime(@file2).should be_close(@atime, 0.0001)
|
||||
File.mtime(@file2).should be_close(@mtime, 0.0001)
|
||||
else
|
||||
File.utime(@atime.to_i, @mtime.to_i, @file1, @file2)
|
||||
File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
|
||||
File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
|
||||
File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
|
||||
end
|
||||
end
|
||||
|
||||
it "may set nanosecond precision" do
|
||||
t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
|
||||
File.utime(t, t, @file1)
|
||||
File.atime(@file1).nsec.should.between?(0, 123500000)
|
||||
File.mtime(@file1).nsec.should.between?(0, 123500000)
|
||||
end
|
||||
|
||||
it "returns the number of filenames in the arguments" do
|
||||
File.utime(@atime.to_f, @mtime.to_f, @file1, @file2).should == 2
|
||||
end
|
||||
|
||||
platform_is :linux do
|
||||
platform_is wordsize: 64 do
|
||||
it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do
|
||||
# https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
|
||||
# "Therefore, timestamps should not overflow until May 2446."
|
||||
# https://lwn.net/Articles/804382/
|
||||
# "On-disk timestamps hitting the y2038 limit..."
|
||||
# The problem seems to be being improved, but currently it actually fails on XFS on RHEL8
|
||||
# https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz
|
||||
# Amazon Linux 2023 returns 2486-07-02 in this example
|
||||
# http://rubyci.s3.amazonaws.com/amazon2023/ruby-master/log/20230322T063004Z.fail.html.gz
|
||||
time = Time.at(1<<44)
|
||||
File.utime(time, time, @file1)
|
||||
[559444, 2486, 2446, 2038].should.include? File.atime(@file1).year
|
||||
[559444, 2486, 2446, 2038].should.include? File.mtime(@file1).year
|
||||
end
|
||||
end
|
||||
end
|
||||
it_behaves_like :update_time, :utime
|
||||
end
|
||||
|
|
|
@ -4,3 +4,11 @@ require_relative '../../shared/file/exist'
|
|||
describe "FileTest.exist?" do
|
||||
it_behaves_like :file_exist, :exist?, FileTest
|
||||
end
|
||||
|
||||
ruby_version_is "3.2" do
|
||||
describe "FileTest.exists?" do
|
||||
it "has been removed" do
|
||||
FileTest.should_not.respond_to?(:exists?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,6 +14,20 @@ describe "Kernel#!~" do
|
|||
(obj !~ :foo).should == false
|
||||
end
|
||||
|
||||
ruby_version_is ""..."3.2" do
|
||||
it "returns true if self does not respond to #=~" do
|
||||
suppress_warning do
|
||||
(Object.new !~ :foo).should == true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "3.2" do
|
||||
it "raises NoMethodError if self does not respond to #=~" do
|
||||
-> { Object.new !~ :foo }.should raise_error(NoMethodError)
|
||||
end
|
||||
end
|
||||
|
||||
it 'can be overridden in subclasses' do
|
||||
obj = KernelSpecs::NotMatch.new
|
||||
(obj !~ :bar).should == :foo
|
||||
|
|
|
@ -22,6 +22,8 @@ describe "Method#parameters" do
|
|||
local_is_not_parameter = {}
|
||||
end
|
||||
|
||||
def forward_parameters(...) end
|
||||
|
||||
def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end
|
||||
|
||||
define_method(:one_optional_defined_method) {|x = 1|}
|
||||
|
@ -267,6 +269,20 @@ describe "Method#parameters" do
|
|||
end
|
||||
end
|
||||
|
||||
ruby_version_is ""..."3.1" do
|
||||
it "returns [:rest, :*], [:block, :&] for forward parameters operator" do
|
||||
m = MethodSpecs::Methods.new
|
||||
m.method(:forward_parameters).parameters.should == [[:rest, :*], [:block, :&]]
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "3.1" do
|
||||
it "returns [:rest, :*], [:keyrest, :**], [:block, :&] for forward parameters operator" do
|
||||
m = MethodSpecs::Methods.new
|
||||
m.method(:forward_parameters).parameters.should == [[:rest, :*], [:keyrest, :**], [:block, :&]]
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the args and block for a splat and block argument" do
|
||||
m = MethodSpecs::Methods.new
|
||||
m.method(:one_splat_one_block).parameters.should == [[:rest, :args], [:block, :block]]
|
||||
|
|
|
@ -33,6 +33,16 @@ describe "Proc#parameters" do
|
|||
it "regards named parameters in lambda as optional if lambda: false keyword used" do
|
||||
-> x { }.parameters(lambda: false).first.first.should == :opt
|
||||
end
|
||||
|
||||
it "regards named parameters in procs and lambdas as required if lambda keyword is truthy" do
|
||||
proc {|x| }.parameters(lambda: 123).first.first.should == :req
|
||||
-> x { }.parameters(lambda: 123).first.first.should == :req
|
||||
end
|
||||
|
||||
it "ignores the lambda keyword if it is nil" do
|
||||
proc {|x|}.parameters(lambda: nil).first.first.should == :opt
|
||||
-> x { }.parameters(lambda: nil).first.first.should == :req
|
||||
end
|
||||
end
|
||||
|
||||
it "regards optional keyword parameters in procs as optional" do
|
||||
|
@ -160,4 +170,8 @@ describe "Proc#parameters" do
|
|||
[:block, :_]
|
||||
]
|
||||
end
|
||||
|
||||
it "returns :nokey for **nil parameter" do
|
||||
proc { |**nil| }.parameters.should == [[:nokey]]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,6 +10,18 @@ describe "String#to_i" do
|
|||
"1_2_3asdf".to_i.should == 123
|
||||
end
|
||||
|
||||
it "ignores multiple non-consecutive underscoes when the first digit is 0" do
|
||||
(2..16).each do |base|
|
||||
"0_0_010".to_i(base).should == base;
|
||||
end
|
||||
end
|
||||
|
||||
it "bails out at the first double underscore if the first digit is 0" do
|
||||
(2..16).each do |base|
|
||||
"010__1".to_i(base).should == base;
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores leading whitespaces" do
|
||||
[ " 123", " 123", "\r\n\r\n123", "\t\t123",
|
||||
"\r\n\t\n123", " \t\n\r\t 123"].each do |str|
|
||||
|
|
|
@ -29,7 +29,7 @@ describe "Net::FTP#connect" do
|
|||
ruby_version_is ""..."3.1" do
|
||||
it "prints a small debug line when in debug mode" do
|
||||
@ftp.debug_mode = true
|
||||
-> { @ftp.connect(@server.hostname, @server.server_port) }.should output(/#{"connect: "}#{@server.hostname}#{", "}#{@server.server_port}#{"\\nget: 220 Dummy FTP Server ready!"}/)
|
||||
-> { @ftp.connect(@server.hostname, @server.server_port) }.should output(/connect: #{@server.hostname}, #{@server.server_port}\nget: 220 Dummy FTP Server ready!/)
|
||||
@ftp.debug_mode = false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
require_relative '../../spec_helper'
|
||||
|
||||
describe 'Set' do
|
||||
ruby_version_is '3.2' do
|
||||
it 'is available without explicit requiring' do
|
||||
output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
|
||||
puts Set.new([1, 2, 3])
|
||||
RUBY
|
||||
output.chomp.should == "#<Set: {1, 2, 3}>"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@
|
|||
require_relative 'spec_helper'
|
||||
require_relative 'fixtures/encoding'
|
||||
|
||||
load_extension('encoding')
|
||||
extension_path = load_extension('encoding')
|
||||
|
||||
describe :rb_enc_get_index, shared: true do
|
||||
it "returns the index of the encoding of a String" do
|
||||
|
@ -559,19 +559,19 @@ describe "C-API Encoding function" do
|
|||
|
||||
describe "rb_ascii8bit_encindex" do
|
||||
it "returns an index for the ASCII-8BIT encoding" do
|
||||
@s.rb_ascii8bit_encindex().should >= 0
|
||||
@s.rb_ascii8bit_encindex().should == 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "rb_utf8_encindex" do
|
||||
it "returns an index for the UTF-8 encoding" do
|
||||
@s.rb_utf8_encindex().should >= 0
|
||||
@s.rb_utf8_encindex().should == 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "rb_usascii_encindex" do
|
||||
it "returns an index for the US-ASCII encoding" do
|
||||
@s.rb_usascii_encindex().should >= 0
|
||||
@s.rb_usascii_encindex().should == 2
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -721,4 +721,27 @@ describe "C-API Encoding function" do
|
|||
str.bytes.should == [0, 0x24]
|
||||
end
|
||||
end
|
||||
|
||||
describe "rb_define_dummy_encoding" do
|
||||
it "defines the dummy encoding" do
|
||||
@s.rb_define_dummy_encoding("FOO")
|
||||
enc = Encoding.find("FOO")
|
||||
enc.should.dummy?
|
||||
end
|
||||
|
||||
it "returns the index of the dummy encoding" do
|
||||
index = @s.rb_define_dummy_encoding("BAR")
|
||||
index.should == Encoding.list.size - 1
|
||||
end
|
||||
|
||||
ruby_version_is "3.2" do
|
||||
it "raises EncodingError if too many encodings" do
|
||||
code = <<-RUBY
|
||||
require #{extension_path.dump}
|
||||
1_000.times {|i| CApiEncodingSpecs.new.rb_define_dummy_encoding("R_\#{i}") }
|
||||
RUBY
|
||||
ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -320,6 +320,10 @@ static VALUE encoding_spec_rb_enc_left_char_head(VALUE self, VALUE str, VALUE of
|
|||
return LONG2NUM(result - ptr);
|
||||
}
|
||||
|
||||
static VALUE encoding_spec_rb_define_dummy_encoding(VALUE self, VALUE name) {
|
||||
return INT2NUM(rb_define_dummy_encoding(RSTRING_PTR(name)));
|
||||
}
|
||||
|
||||
void Init_encoding_spec(void) {
|
||||
VALUE cls;
|
||||
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
|
||||
|
@ -379,6 +383,7 @@ void Init_encoding_spec(void) {
|
|||
rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2);
|
||||
rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1);
|
||||
rb_define_method(cls, "rb_enc_left_char_head", encoding_spec_rb_enc_left_char_head, 2);
|
||||
rb_define_method(cls, "rb_define_dummy_encoding", encoding_spec_rb_define_dummy_encoding, 1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -51,10 +51,6 @@ VALUE string_spec_rb_str_set_len_RSTRING_LEN(VALUE self, VALUE str, VALUE len) {
|
|||
return INT2FIX(RSTRING_LEN(str));
|
||||
}
|
||||
|
||||
VALUE string_spec_rb_str_fstring(VALUE self, VALUE str) {
|
||||
return rb_str_to_interned_str(str);
|
||||
}
|
||||
|
||||
VALUE string_spec_rb_str_buf_new(VALUE self, VALUE len, VALUE str) {
|
||||
VALUE buf;
|
||||
|
||||
|
@ -576,11 +572,19 @@ static VALUE string_spec_rb_str_unlocktmp(VALUE self, VALUE str) {
|
|||
return rb_str_unlocktmp(str);
|
||||
}
|
||||
|
||||
static VALUE string_spec_rb_enc_interned_str_cstr(VALUE self, VALUE str, VALUE enc) {
|
||||
rb_encoding *e = rb_to_encoding(enc);
|
||||
return rb_enc_interned_str_cstr(RSTRING_PTR(str), e);
|
||||
}
|
||||
|
||||
static VALUE string_spec_rb_str_to_interned_str(VALUE self, VALUE str) {
|
||||
return rb_str_to_interned_str(str);
|
||||
}
|
||||
|
||||
void Init_string_spec(void) {
|
||||
VALUE cls = rb_define_class("CApiStringSpecs", rb_cObject);
|
||||
rb_define_method(cls, "rb_cstr2inum", string_spec_rb_cstr2inum, 2);
|
||||
rb_define_method(cls, "rb_cstr_to_inum", string_spec_rb_cstr_to_inum, 3);
|
||||
rb_define_method(cls, "rb_fstring", string_spec_rb_str_fstring, 1);
|
||||
rb_define_method(cls, "rb_str2inum", string_spec_rb_str2inum, 2);
|
||||
rb_define_method(cls, "rb_str_append", string_spec_rb_str_append, 2);
|
||||
rb_define_method(cls, "rb_str_buf_new", string_spec_rb_str_buf_new, 2);
|
||||
|
@ -677,6 +681,8 @@ void Init_string_spec(void) {
|
|||
rb_define_method(cls, "rb_str_catf", string_spec_rb_str_catf, 1);
|
||||
rb_define_method(cls, "rb_str_locktmp", string_spec_rb_str_locktmp, 1);
|
||||
rb_define_method(cls, "rb_str_unlocktmp", string_spec_rb_str_unlocktmp, 1);
|
||||
rb_define_method(cls, "rb_enc_interned_str_cstr", string_spec_rb_enc_interned_str_cstr, 2);
|
||||
rb_define_method(cls, "rb_str_to_interned_str", string_spec_rb_str_to_interned_str, 1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -498,25 +498,6 @@ describe "C-API String function" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "rb_fstring" do
|
||||
it 'returns self if the String is frozen' do
|
||||
input = 'foo'.freeze
|
||||
output = @s.rb_fstring(input)
|
||||
|
||||
output.should equal(input)
|
||||
output.should.frozen?
|
||||
end
|
||||
|
||||
it 'returns a frozen copy if the String is not frozen' do
|
||||
input = 'foo'
|
||||
output = @s.rb_fstring(input)
|
||||
|
||||
output.should.frozen?
|
||||
output.should_not equal(input)
|
||||
output.should == 'foo'
|
||||
end
|
||||
end
|
||||
|
||||
describe "rb_str_subseq" do
|
||||
it "returns a byte-indexed substring" do
|
||||
str = "\x00\x01\x02\x03\x04".force_encoding("binary")
|
||||
|
@ -1227,4 +1208,59 @@ end
|
|||
-> { @s.rb_str_unlocktmp("test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string')
|
||||
end
|
||||
end
|
||||
|
||||
describe "rb_enc_interned_str_cstr" do
|
||||
it "returns a frozen string" do
|
||||
str = "hello"
|
||||
val = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
|
||||
|
||||
val.should.is_a?(String)
|
||||
val.encoding.should == Encoding::US_ASCII
|
||||
val.should.frozen?
|
||||
end
|
||||
|
||||
it "returns the same frozen string" do
|
||||
str = "hello"
|
||||
result1 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
|
||||
result2 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
|
||||
result1.should.equal?(result2)
|
||||
end
|
||||
|
||||
it "returns different frozen strings for different encodings" do
|
||||
str = "hello"
|
||||
result1 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
|
||||
result2 = @s.rb_enc_interned_str_cstr(str, Encoding::UTF_8)
|
||||
result1.should_not.equal?(result2)
|
||||
end
|
||||
|
||||
it "returns the same string as String#-@" do
|
||||
@s.rb_enc_interned_str_cstr("hello", Encoding::UTF_8).should.equal?(-"hello")
|
||||
end
|
||||
end
|
||||
|
||||
describe "rb_str_to_interned_str" do
|
||||
it "returns a frozen string" do
|
||||
str = "hello"
|
||||
result = @s.rb_str_to_interned_str(str)
|
||||
result.should.is_a?(String)
|
||||
result.should.frozen?
|
||||
end
|
||||
|
||||
it "returns the same frozen string" do
|
||||
str = "hello"
|
||||
result1 = @s.rb_str_to_interned_str(str)
|
||||
result2 = @s.rb_str_to_interned_str(str)
|
||||
result1.should.equal?(result2)
|
||||
end
|
||||
|
||||
it "returns different frozen strings for different encodings" do
|
||||
result1 = @s.rb_str_to_interned_str("hello".force_encoding(Encoding::US_ASCII))
|
||||
result2 = @s.rb_str_to_interned_str("hello".force_encoding(Encoding::UTF_8))
|
||||
result1.should_not.equal?(result2)
|
||||
end
|
||||
|
||||
it "returns the same string as String#-@" do
|
||||
@s.rb_str_to_interned_str("hello").should.equal?(-"hello")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче