From ffce41d2d3b2e4793c54d5303c90c5fe7eb91e73 Mon Sep 17 00:00:00 2001 From: Ben Bowers Date: Sat, 26 Oct 2024 16:26:17 -0400 Subject: [PATCH] Change sprintf "%c" to support only Char and Int::Primitive types, raising an ArgumentError otherwise. (#11022) --- spec/std/sprintf_spec.cr | 24 ++++++++++++++++++++++++ src/string/formatter.cr | 9 ++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/spec/std/sprintf_spec.cr b/spec/std/sprintf_spec.cr index a91ce8030915..d2407f703449 100644 --- a/spec/std/sprintf_spec.cr +++ b/spec/std/sprintf_spec.cr @@ -1176,6 +1176,30 @@ describe "::sprintf" do pending "floats" end + context "chars" do + it "works" do + assert_sprintf "%c", 'a', "a" + assert_sprintf "%3c", 'R', " R" + assert_sprintf "%-3c", 'L', "L " + assert_sprintf "%c", '▞', "▞" + assert_sprintf "%c", 65, "A" + assert_sprintf "%c", 66.to_i8, "B" + assert_sprintf "%c", 67.to_i16, "C" + assert_sprintf "%c", 68.to_i32, "D" + assert_sprintf "%c", 69.to_i64, "E" + assert_sprintf "%c", 97.to_u8, "a" + assert_sprintf "%c", 98.to_u16, "b" + assert_sprintf "%c", 99.to_u32, "c" + assert_sprintf "%c", 100.to_u64, "d" + assert_sprintf "%c", 0x259E, "▞" + end + + it "raises if not a Char or Int" do + expect_raises(ArgumentError, "Expected a char or integer") { sprintf("%c", "this") } + expect_raises(ArgumentError, "Expected a char or integer") { sprintf("%c", 17.34) } + end + end + context "strings" do it "works" do assert_sprintf "%s", 'a', "a" diff --git a/src/string/formatter.cr b/src/string/formatter.cr index 60da55a2601f..0e96f05cb050 100644 --- a/src/string/formatter.cr +++ b/src/string/formatter.cr @@ -248,8 +248,15 @@ struct String::Formatter(A) end def char(flags, arg) : Nil + val = if arg.is_a?(Char) + arg + elsif arg.is_a?(Int::Primitive) + arg.chr + else + raise ArgumentError.new("Expected a char or integer, not #{arg.inspect}") + end pad 1, flags if flags.left_padding? - @io << arg + @io << val pad 1, flags if flags.right_padding? end