summaryrefslogtreecommitdiff
path: root/spec/ruby/core/string/modulo_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/string/modulo_spec.rb')
-rw-r--r--spec/ruby/core/string/modulo_spec.rb262
1 files changed, 126 insertions, 136 deletions
diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb
index fc4972b9d7..46e0aa0f36 100644
--- a/spec/ruby/core/string/modulo_spec.rb
+++ b/spec/ruby/core/string/modulo_spec.rb
@@ -1,10 +1,24 @@
require_relative '../../spec_helper'
+require_relative '../kernel/shared/sprintf'
+require_relative '../kernel/shared/sprintf_encoding'
require_relative 'fixtures/classes'
require_relative '../../shared/hash/key_error'
describe "String#%" do
+ it_behaves_like :kernel_sprintf, -> format, *args {
+ format % args
+ }
+
+ it_behaves_like :kernel_sprintf_encoding, -> format, *args {
+ format % args
+ }
+end
+
+# TODO: these specs are mostly redundant with kernel/shared/sprintf.rb specs.
+# These specs should be moved there and deduplicated.
+describe "String#%" do
context "when key is missing from passed-in hash" do
- it_behaves_like :key_error, -> (obj, key) { "%{#{key}}" % obj }, { a: 5 }
+ it_behaves_like :key_error, -> obj, key { "%{#{key}}" % obj }, { a: 5 }
end
it "formats multiple expressions" do
@@ -32,51 +46,57 @@ describe "String#%" do
end
it "raises if a compatible encoding can't be found" do
- lambda { "hello %s".encode("utf-8") % "world".encode("UTF-16LE") }.should raise_error(Encoding::CompatibilityError)
+ -> { "hello %s".encode("utf-8") % "world".encode("UTF-16LE") }.should raise_error(Encoding::CompatibilityError)
end
end
- ruby_version_is ""..."2.5" do
- it "formats single % character at the end as literal %" do
- ("%" % []).should == "%"
- ("foo%" % []).should == "foo%"
- end
+ it "raises an error if single % appears at the end" do
+ -> { ("%" % []) }.should raise_error(ArgumentError)
+ -> { ("foo%" % [])}.should raise_error(ArgumentError)
end
- ruby_version_is "2.5" do
- it "raises an error if single % appears at the end" do
- lambda { ("%" % []) }.should raise_error(ArgumentError)
- lambda { ("foo%" % [])}.should raise_error(ArgumentError)
+ ruby_version_is ""..."3.4" do
+ it "formats single % character before a newline as literal %" do
+ ("%\n" % []).should == "%\n"
+ ("foo%\n" % []).should == "foo%\n"
+ ("%\n.3f" % 1.2).should == "%\n.3f"
end
- end
- it "formats single % character before a newline as literal %" do
- ("%\n" % []).should == "%\n"
- ("foo%\n" % []).should == "foo%\n"
- ("%\n.3f" % 1.2).should == "%\n.3f"
- end
+ it "formats single % character before a NUL as literal %" do
+ ("%\0" % []).should == "%\0"
+ ("foo%\0" % []).should == "foo%\0"
+ ("%\0.3f" % 1.2).should == "%\0.3f"
+ end
- it "formats single % character before a NUL as literal %" do
- ("%\0" % []).should == "%\0"
- ("foo%\0" % []).should == "foo%\0"
- ("%\0.3f" % 1.2).should == "%\0.3f"
- end
+ it "raises an error if single % appears anywhere else" do
+ -> { (" % " % []) }.should raise_error(ArgumentError)
+ -> { ("foo%quux" % []) }.should raise_error(ArgumentError)
+ end
- it "raises an error if single % appears anywhere else" do
- lambda { (" % " % []) }.should raise_error(ArgumentError)
- lambda { ("foo%quux" % []) }.should raise_error(ArgumentError)
- end
+ it "raises an error if NULL or \\n appear anywhere else in the format string" do
+ begin
+ old_debug, $DEBUG = $DEBUG, false
- it "raises an error if NULL or \\n appear anywhere else in the format string" do
- begin
- old_debug, $DEBUG = $DEBUG, false
+ -> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
+ ensure
+ $DEBUG = old_debug
+ end
+ end
+ end
- lambda { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
- lambda { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
- lambda { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
- lambda { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
- ensure
- $DEBUG = old_debug
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError if % is not followed by a conversion specifier" do
+ -> { "%" % [] }.should raise_error(ArgumentError)
+ -> { "%\n" % [] }.should raise_error(ArgumentError)
+ -> { "%\0" % [] }.should raise_error(ArgumentError)
+ -> { " % " % [] }.should raise_error(ArgumentError)
+ -> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
end
end
@@ -99,8 +119,8 @@ describe "String#%" do
s = $stderr
$stderr = IOStub.new
- lambda { "" % [1, 2, 3] }.should raise_error(ArgumentError)
- lambda { "%s" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "%s" % [1, 2, 3] }.should raise_error(ArgumentError)
ensure
$DEBUG = old_debug
$stderr = s
@@ -120,26 +140,34 @@ describe "String#%" do
end
end
- it "replaces trailing absolute argument specifier without type with percent sign" do
- ("hello %1$" % "foo").should == "hello %"
+ ruby_version_is ""..."3.4" do
+ it "replaces trailing absolute argument specifier without type with percent sign" do
+ ("hello %1$" % "foo").should == "hello %"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError if absolute argument specifier is followed by a conversion specifier" do
+ -> { "hello %1$" % "foo" }.should raise_error(ArgumentError)
+ end
end
it "raises an ArgumentError when given invalid argument specifiers" do
- lambda { "%1" % [] }.should raise_error(ArgumentError)
- lambda { "%+" % [] }.should raise_error(ArgumentError)
- lambda { "%-" % [] }.should raise_error(ArgumentError)
- lambda { "%#" % [] }.should raise_error(ArgumentError)
- lambda { "%0" % [] }.should raise_error(ArgumentError)
- lambda { "%*" % [] }.should raise_error(ArgumentError)
- lambda { "%." % [] }.should raise_error(ArgumentError)
- lambda { "%_" % [] }.should raise_error(ArgumentError)
- lambda { "%0$s" % "x" }.should raise_error(ArgumentError)
- lambda { "%*0$s" % [5, "x"] }.should raise_error(ArgumentError)
- lambda { "%*1$.*0$1$s" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "%1" % [] }.should raise_error(ArgumentError)
+ -> { "%+" % [] }.should raise_error(ArgumentError)
+ -> { "%-" % [] }.should raise_error(ArgumentError)
+ -> { "%#" % [] }.should raise_error(ArgumentError)
+ -> { "%0" % [] }.should raise_error(ArgumentError)
+ -> { "%*" % [] }.should raise_error(ArgumentError)
+ -> { "%." % [] }.should raise_error(ArgumentError)
+ -> { "%_" % [] }.should raise_error(ArgumentError)
+ -> { "%0$s" % "x" }.should raise_error(ArgumentError)
+ -> { "%*0$s" % [5, "x"] }.should raise_error(ArgumentError)
+ -> { "%*1$.*0$1$s" % [1, 2, 3] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when multiple positional argument tokens are given for one format specifier" do
- lambda { "%1$1$s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%1$1$s" % "foo" }.should raise_error(ArgumentError)
end
it "respects positional arguments and precision tokens given for one format specifier" do
@@ -155,36 +183,36 @@ describe "String#%" do
end
it "raises an ArgumentError when multiple width star tokens are given for one format specifier" do
- lambda { "%**s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%**s" % [5, 5, 5] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when a width star token is seen after a width token" do
- lambda { "%5*s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%5*s" % [5, 5] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when multiple precision tokens are given" do
- lambda { "%.5.5s" % 5 }.should raise_error(ArgumentError)
- lambda { "%.5.*s" % [5, 5] }.should raise_error(ArgumentError)
- lambda { "%.*.5s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%.5.5s" % 5 }.should raise_error(ArgumentError)
+ -> { "%.5.*s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%.*.5s" % [5, 5] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when there are less arguments than format specifiers" do
("foo" % []).should == "foo"
- lambda { "%s" % [] }.should raise_error(ArgumentError)
- lambda { "%s %s" % [1] }.should raise_error(ArgumentError)
+ -> { "%s" % [] }.should raise_error(ArgumentError)
+ -> { "%s %s" % [1] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when absolute and relative argument numbers are mixed" do
- lambda { "%s %1$s" % "foo" }.should raise_error(ArgumentError)
- lambda { "%1$s %s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%s %1$s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%1$s %s" % "foo" }.should raise_error(ArgumentError)
- lambda { "%s %2$s" % ["foo", "bar"] }.should raise_error(ArgumentError)
- lambda { "%2$s %s" % ["foo", "bar"] }.should raise_error(ArgumentError)
+ -> { "%s %2$s" % ["foo", "bar"] }.should raise_error(ArgumentError)
+ -> { "%2$s %s" % ["foo", "bar"] }.should raise_error(ArgumentError)
- lambda { "%*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- lambda { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- lambda { "%*2$.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- lambda { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*2$.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
end
it "allows reuse of the one argument multiple via absolute argument numbers" do
@@ -193,13 +221,13 @@ describe "String#%" do
end
it "always interprets an array argument as a list of argument parameters" do
- lambda { "%p" % [] }.should raise_error(ArgumentError)
+ -> { "%p" % [] }.should raise_error(ArgumentError)
("%p" % [1]).should == "1"
("%p %p" % [1, 2]).should == "1 2"
end
it "always interprets an array subclass argument as a list of argument parameters" do
- lambda { "%p" % StringSpecs::MyArray[] }.should raise_error(ArgumentError)
+ -> { "%p" % StringSpecs::MyArray[] }.should raise_error(ArgumentError)
("%p" % StringSpecs::MyArray[1]).should == "1"
("%p %p" % StringSpecs::MyArray[1, 2]).should == "1 2"
end
@@ -270,7 +298,7 @@ describe "String#%" do
x = mock("string modulo to_ary")
x.should_receive(:to_ary).and_return("x")
- lambda { "%s" % x }.should raise_error(TypeError)
+ -> { "%s" % x }.should raise_error(TypeError)
end
it "tries to convert the argument to Array by calling #to_ary" do
@@ -297,27 +325,6 @@ describe "String#%" do
end
end
- it "always taints the result when the format string is tainted" do
- universal = mock('0')
- def universal.to_int() 0 end
- def universal.to_str() "0" end
- def universal.to_f() 0.0 end
-
- [
- "", "foo",
- "%b", "%B", "%c", "%d", "%e", "%E",
- "%f", "%g", "%G", "%i", "%o", "%p",
- "%s", "%u", "%x", "%X"
- ].each do |format|
- subcls_format = StringSpecs::MyString.new(format)
- subcls_format.taint
- format.taint
-
- (format % universal).tainted?.should == true
- (subcls_format % universal).tainted?.should == true
- end
- end
-
it "supports binary formats using %b for positive numbers" do
("%b" % 10).should == "1010"
("% b" % 10).should == " 1010"
@@ -377,15 +384,15 @@ describe "String#%" do
("%*c" % [10, 3]).should == " \003"
("%c" % 42).should == "*"
- lambda { "%c" % Object }.should raise_error(TypeError)
+ -> { "%c" % Object }.should raise_error(TypeError)
end
it "supports single character strings as argument for %c" do
("%c" % 'A').should == "A"
end
- it "raises an exception for multiple character strings as argument for %c" do
- lambda { "%c" % 'AA' }.should raise_error(ArgumentError)
+ it "supports only the first character as argument for %c" do
+ ("%c" % 'AA').should == "A"
end
it "calls to_str on argument for %c formats" do
@@ -555,7 +562,7 @@ describe "String#%" do
("%1$p" % [10, 5]).should == "10"
("%-22p" % 10).should == "10 "
("%*p" % [10, 10]).should == " 10"
- ("%p" % {capture: 1}).should == "{:capture=>1}"
+ ("%p" % {capture: 1}).should == {capture: 1}.inspect
("%p" % "str").should == "\"str\""
end
@@ -571,18 +578,6 @@ describe "String#%" do
# ("%p" % obj).should == "obj"
end
- it "taints result for %p when argument.inspect is tainted" do
- obj = mock('x')
- def obj.inspect() "x".taint end
-
- ("%p" % obj).tainted?.should == true
-
- obj = mock('x'); obj.taint
- def obj.inspect() "x" end
-
- ("%p" % obj).tainted?.should == false
- end
-
it "supports string formats using %s" do
("%s" % "hello").should == "hello"
("%s" % "").should == ""
@@ -611,15 +606,10 @@ describe "String#%" do
# ("%s" % obj).should == "obj"
end
- it "taints result for %s when argument is tainted" do
- ("%s" % "x".taint).tainted?.should == true
- ("%s" % mock('x').taint).tainted?.should == true
- end
-
# MRI crashes on this one.
# See http://groups.google.com/group/ruby-core-google/t/c285c18cd94c216d
it "raises an ArgumentError for huge precisions for %s" do
- block = lambda { "%.25555555555555555555555555555555555555s" % "hello world" }
+ block = -> { "%.25555555555555555555555555555555555555s" % "hello world" }
block.should raise_error(ArgumentError)
end
@@ -712,19 +702,19 @@ describe "String#%" do
(format % "0b1101").should == (format % Kernel.Integer("0b1101"))
(format % "0b1101_0000").should == (format % Kernel.Integer("0b1101_0000"))
(format % "0777").should == (format % Kernel.Integer("0777"))
- lambda {
+ -> {
# see [ruby-core:14139] for more details
(format % "0777").should == (format % Kernel.Integer("0777"))
}.should_not raise_error(ArgumentError)
- lambda { format % "0__7_7_7" }.should raise_error(ArgumentError)
+ -> { format % "0__7_7_7" }.should raise_error(ArgumentError)
- lambda { format % "" }.should raise_error(ArgumentError)
- lambda { format % "x" }.should raise_error(ArgumentError)
- lambda { format % "5x" }.should raise_error(ArgumentError)
- lambda { format % "08" }.should raise_error(ArgumentError)
- lambda { format % "0b2" }.should raise_error(ArgumentError)
- lambda { format % "123__456" }.should raise_error(ArgumentError)
+ -> { format % "" }.should raise_error(ArgumentError)
+ -> { format % "x" }.should raise_error(ArgumentError)
+ -> { format % "5x" }.should raise_error(ArgumentError)
+ -> { format % "08" }.should raise_error(ArgumentError)
+ -> { format % "0b2" }.should raise_error(ArgumentError)
+ -> { format % "123__456" }.should raise_error(ArgumentError)
obj = mock('5')
obj.should_receive(:to_i).and_return(5)
@@ -751,21 +741,25 @@ describe "String#%" do
(format % "-10.4e-20").should == (format % -10.4e-20)
(format % ".5").should == (format % 0.5)
(format % "-.5").should == (format % -0.5)
+
+ ruby_version_is "3.4" do
+ (format % "10.").should == (format % 10)
+ end
+
# Something's strange with this spec:
# it works just fine in individual mode, but not when run as part of a group
(format % "10_1_0.5_5_5").should == (format % 1010.555)
(format % "0777").should == (format % 777)
- lambda { format % "" }.should raise_error(ArgumentError)
- lambda { format % "x" }.should raise_error(ArgumentError)
- lambda { format % "." }.should raise_error(ArgumentError)
- lambda { format % "10." }.should raise_error(ArgumentError)
- lambda { format % "5x" }.should raise_error(ArgumentError)
- lambda { format % "0b1" }.should raise_error(ArgumentError)
- lambda { format % "10e10.5" }.should raise_error(ArgumentError)
- lambda { format % "10__10" }.should raise_error(ArgumentError)
- lambda { format % "10.10__10" }.should raise_error(ArgumentError)
+ -> { format % "" }.should raise_error(ArgumentError)
+ -> { format % "x" }.should raise_error(ArgumentError)
+ -> { format % "." }.should raise_error(ArgumentError)
+ -> { format % "5x" }.should raise_error(ArgumentError)
+ -> { format % "0b1" }.should raise_error(ArgumentError)
+ -> { format % "10e10.5" }.should raise_error(ArgumentError)
+ -> { format % "10__10" }.should raise_error(ArgumentError)
+ -> { format % "10.10__10" }.should raise_error(ArgumentError)
obj = mock('5.0')
obj.should_receive(:to_f).and_return(5.0)
@@ -775,10 +769,6 @@ describe "String#%" do
it "behaves as if calling Kernel#Float for #{format} arguments, when the passed argument is hexadecimal string" do
(format % "0xA").should == (format % 0xA)
end
-
- it "doesn't taint the result for #{format} when argument is tainted" do
- (format % "5".taint).tainted?.should == false
- end
end
describe "when format string contains %{} sections" do
@@ -787,7 +777,7 @@ describe "String#%" do
end
it "should raise ArgumentError if no hash given" do
- lambda {"%{foo}" % []}.should raise_error(ArgumentError)
+ -> {"%{foo}" % []}.should raise_error(ArgumentError)
end
end
@@ -797,11 +787,11 @@ describe "String#%" do
end
it "raises KeyError if key is missing from passed-in hash" do
- lambda {"%<foo>d" % {}}.should raise_error(KeyError)
+ -> {"%<foo>d" % {}}.should raise_error(KeyError)
end
it "should raise ArgumentError if no hash given" do
- lambda {"%<foo>" % []}.should raise_error(ArgumentError)
+ -> {"%<foo>" % []}.should raise_error(ArgumentError)
end
end
end