require "./spec_helper"
require "../support/number"
require "spec/helpers/string"
require "big"
# use same name for `sprintf` and `IO#printf` so that `assert_prints` can be leveraged
private def fprintf(format, *args)
sprintf(format, *args)
end
private def fprintf(io : IO, format, *args)
io.printf(format, *args)
end
private def assert_sprintf(format, args, result, *, file = __FILE__, line = __LINE__)
assert_prints fprintf(format, args), result, file: file, line: line
end
describe "::sprintf" do
it "works" do
assert_sprintf "Hello %d world", 123, "Hello 123 world"
assert_sprintf "Hello %d world", [123], "Hello 123 world"
assert_sprintf "foo %d bar %s baz %d goo", [1, "hello", 2], "foo 1 bar hello baz 2 goo"
end
it "accepts multiple positional arguments" do
assert_prints fprintf("%d %d %d", 1, 23, 456), "1 23 456"
assert_prints fprintf("%*.*d,%*s", 10, 6, 123, 10, "foo"), " 000123, foo"
assert_prints fprintf("foo"), "foo"
end
it "doesn't format %%" do
assert_sprintf "%%%d", 1, "%1"
assert_sprintf "%%*%%", [1, 2, 3], "%*%"
end
it "doesn't accept modifiers for %%" do
expect_raises(ArgumentError) { sprintf("%0%") }
expect_raises(ArgumentError) { sprintf("%+%") }
expect_raises(ArgumentError) { sprintf("%-%") }
expect_raises(ArgumentError) { sprintf("% %") }
expect_raises(ArgumentError) { sprintf("%#%") }
expect_raises(ArgumentError) { sprintf("%.0%") }
expect_raises(ArgumentError) { sprintf("%*%", 1) }
expect_raises(ArgumentError) { sprintf("%0%") }
expect_raises(ArgumentError) { sprintf("%+%") }
expect_raises(ArgumentError) { sprintf("%-%") }
expect_raises(ArgumentError) { sprintf("% %") }
expect_raises(ArgumentError) { sprintf("%#%") }
expect_raises(ArgumentError) { sprintf("%.0%") }
expect_raises(ArgumentError) { sprintf("%*%", 1) }
end
context "integers" do
context "base specifier" do
it "supports base 2" do
assert_sprintf "%b", 123, "1111011"
assert_sprintf "%+b", 123, "+1111011"
assert_sprintf "% b", 123, " 1111011"
assert_sprintf "%-b", 123, "1111011"
assert_sprintf "%10b", 123, " 1111011"
assert_sprintf "%-10b", 123, "1111011 "
end
it "supports base 8" do
assert_sprintf "%o", 123, "173"
assert_sprintf "%+o", 123, "+173"
assert_sprintf "% o", 123, " 173"
assert_sprintf "%-o", 123, "173"
assert_sprintf "%6o", 123, " 173"
assert_sprintf "%-6o", 123, "173 "
end
it "supports base 10" do
assert_sprintf "%d", 123, "123"
assert_sprintf "%+d", 123, "+123"
assert_sprintf "% d", 123, " 123"
assert_sprintf "%-d", 123, "123"
assert_sprintf "%6d", 123, " 123"
assert_sprintf "%-6d", 123, "123 "
assert_sprintf "%i", 123, "123"
assert_sprintf "%+i", 123, "+123"
assert_sprintf "% i", 123, " 123"
assert_sprintf "%-i", 123, "123"
assert_sprintf "%6i", 123, " 123"
assert_sprintf "%-6i", 123, "123 "
end
it "supports base 16" do
assert_sprintf "%x", 123, "7b"
assert_sprintf "%+x", 123, "+7b"
assert_sprintf "% x", 123, " 7b"
assert_sprintf "%-x", 123, "7b"
assert_sprintf "%6x", 123, " 7b"
assert_sprintf "%-6x", 123, "7b "
assert_sprintf "%X", 123, "7B"
assert_sprintf "%+X", 123, "+7B"
assert_sprintf "% X", 123, " 7B"
assert_sprintf "%-X", 123, "7B"
assert_sprintf "%6X", 123, " 7B"
assert_sprintf "%-6X", 123, "7B "
assert_sprintf "こんに%xちは", 123, "こんに7bちは"
assert_sprintf "こんに%Xちは", 123, "こんに7Bちは"
end
end
context "width specifier" do
it "sets the minimum length of the string" do
assert_sprintf "%20d", 123, " 123"
assert_sprintf "%20d", -123, " -123"
assert_sprintf "%20d", 0, " 0"
assert_sprintf "%4d", 123, " 123"
assert_sprintf "%4d", -123, "-123"
assert_sprintf "%4d", 0, " 0"
assert_sprintf "%2d", 123, "123"
assert_sprintf "%2d", -123, "-123"
assert_sprintf "%2d", 0, " 0"
assert_sprintf "%*d", [20, 123], " 123"
assert_sprintf "%*d", [20, -123], " -123"
assert_sprintf "%*d", [20, 0], " 0"
assert_sprintf "%*d", [0, 123], "123"
assert_sprintf "%*d", [0, -123], "-123"
assert_sprintf "%*d", [0, 0], "0"
end
it "left-justifies on negative width" do
assert_sprintf "%*d", [-20, 123], "123 "
assert_sprintf "%*d", [-20, -123], "-123 "
assert_sprintf "%*d", [-20, 0], "0 "
assert_sprintf "%*d", [-4, 123], "123 "
assert_sprintf "%*d", [-4, -123], "-123"
assert_sprintf "%*d", [-4, 0], "0 "
assert_sprintf "%*d", [-2, 123], "123"
assert_sprintf "%*d", [-2, -123], "-123"
assert_sprintf "%*d", [-2, 0], "0 "
assert_sprintf "%-*d", [-20, 123], "123 "
assert_sprintf "%-*d", [-20, -123], "-123 "
assert_sprintf "%-*d", [-20, 0], "0 "
end
end
context "precision specifier" do
it "sets the minimum length of the number part" do
assert_sprintf "%.12d", 123, "000000000123"
assert_sprintf "%.12d", -123, "-000000000123"
assert_sprintf "%.12d", 0, "000000000000"
assert_sprintf "%.4d", 123, "0123"
assert_sprintf "%.4d", -123, "-0123"
assert_sprintf "%.4d", 0, "0000"
assert_sprintf "%.2d", 123, "123"
assert_sprintf "%.2d", -123, "-123"
assert_sprintf "%.2d", 0, "00"
assert_sprintf "%.0d", 123, "123"
assert_sprintf "%.0d", -123, "-123"
assert_sprintf "%.0d", 0, ""
end
it "can be used with width" do
assert_sprintf "%20.12d", 123, " 000000000123"
assert_sprintf "%20.12d", -123, " -000000000123"
assert_sprintf "%20.12d", 0, " 000000000000"
assert_sprintf "%-20.12d", 123, "000000000123 "
assert_sprintf "%-20.12d", -123, "-000000000123 "
assert_sprintf "%-20.12d", 0, "000000000000 "
assert_sprintf "%8.12d", 123, "000000000123"
assert_sprintf "%8.12d", -123, "-000000000123"
assert_sprintf "%8.12d", 0, "000000000000"
assert_sprintf "%+13.12d", 123, "+000000000123"
assert_sprintf "%+13.12d", -123, "-000000000123"
assert_sprintf "%+13.12d", 0, "+000000000000"
assert_sprintf "%- 20.12d", 123, " 000000000123 "
assert_sprintf "%- 20.12d", -123, "-000000000123 "
assert_sprintf "%- 20.12d", 0, " 000000000000 "
assert_sprintf "%*.*d", [20, 12, 123], " 000000000123"
assert_sprintf "%*.*d", [20, 12, -123], " -000000000123"
assert_sprintf "%*.*d", [20, 12, 0], " 000000000000"
assert_sprintf "%*.*d", [-20, -12, 123], "123 "
assert_sprintf "%*.*d", [-20, -12, -123], "-123 "
assert_sprintf "%*.*d", [-20, -12, 0], "0 "
end
it "is ignored if precision argument is negative" do
assert_sprintf "%.*d", [-2, 123], "123"
assert_sprintf "%.*d", [-2, -123], "-123"
assert_sprintf "%.*d", [-2, 0], "0"
assert_sprintf "%020.*d", [-2, 123], "00000000000000000123"
assert_sprintf "%020.*d", [-2, -123], "-0000000000000000123"
assert_sprintf "%020.*d", [-2, 0], "00000000000000000000"
end
end
context "sharp flag" do
it "adds a base prefix" do
assert_sprintf "%#b", 123, "0b1111011"
assert_sprintf "%#o", 123, "0o173"
assert_sprintf "%#x", 123, "0x7b"
assert_sprintf "%#X", 123, "0X7B"
assert_sprintf "%#b", -123, "-0b1111011"
assert_sprintf "%#o", -123, "-0o173"
assert_sprintf "%#x", -123, "-0x7b"
assert_sprintf "%#X", -123, "-0X7B"
end
it "omits the base prefix for 0" do
assert_sprintf "%#b", 0, "0"
assert_sprintf "%#o", 0, "0"
assert_sprintf "%#x", 0, "0"
assert_sprintf "%#X", 0, "0"
end
end
context "plus flag" do
it "writes a plus sign for positive integers" do
assert_sprintf "%+d", 123, "+123"
assert_sprintf "%+d", -123, "-123"
assert_sprintf "%+d", 0, "+0"
end
it "writes plus sign after left space-padding" do
assert_sprintf "%+20d", 123, " +123"
assert_sprintf "%+20d", -123, " -123"
assert_sprintf "%+20d", 0, " +0"
end
it "writes plus sign before left zero-padding" do
assert_sprintf "%+020d", 123, "+0000000000000000123"
assert_sprintf "%+020d", -123, "-0000000000000000123"
assert_sprintf "%+020d", 0, "+0000000000000000000"
end
end
context "space flag" do
it "writes a space for positive integers" do
assert_sprintf "% d", 123, " 123"
assert_sprintf "% d", -123, "-123"
assert_sprintf "% d", 0, " 0"
end
it "writes space before left padding" do
assert_sprintf "% 20d", 123, " 123"
assert_sprintf "% 20d", -123, " -123"
assert_sprintf "% 20d", 0, " 0"
assert_sprintf "% 020d", 123, " 0000000000000000123"
assert_sprintf "% 020d", -123, "-0000000000000000123"
assert_sprintf "% 020d", 0, " 0000000000000000000"
end
it "is ignored if plus flag is also specified" do
assert_sprintf "%+ d", 123, "+123"
assert_sprintf "% +d", 123, "+123"
assert_sprintf "%+ 20d", 123, " +123"
assert_sprintf "% +20d", 123, " +123"
assert_sprintf "%+ 020d", 123, "+0000000000000000123"
assert_sprintf "% +020d", 123, "+0000000000000000123"
end
end
context "zero flag" do
it "left-pads the result with zeros" do
assert_sprintf "%020d", 123, "00000000000000000123"
assert_sprintf "%020d", -123, "-0000000000000000123"
assert_sprintf "%020d", 0, "00000000000000000000"
assert_sprintf "%+020d", 123, "+0000000000000000123"
assert_sprintf "%+020d", -123, "-0000000000000000123"
assert_sprintf "%+020d", 0, "+0000000000000000000"
assert_sprintf "% 020d", 123, " 0000000000000000123"
assert_sprintf "% 020d", -123, "-0000000000000000123"
assert_sprintf "% 020d", 0, " 0000000000000000000"
end
it "is ignored if string is left-justified" do
assert_sprintf "%-020d", 123, "123 "
assert_sprintf "%-020d", -123, "-123 "
assert_sprintf "%-020d", 0, "0 "
assert_sprintf "%0-20d", 123, "123 "
assert_sprintf "%0-20d", -123, "-123 "
assert_sprintf "%0-20d", 0, "0 "
assert_sprintf "%0*d", [-20, 123], "123 "
assert_sprintf "%0*d", [-20, -123], "-123 "
assert_sprintf "%0*d", [-20, 0], "0 "
assert_sprintf "%-0*d", [-20, 123], "123 "
assert_sprintf "%-0*d", [-20, -123], "-123 "
assert_sprintf "%-0*d", [-20, 0], "0 "
end
it "is ignored if precision is specified" do
assert_sprintf "%020.12d", 123, " 000000000123"
assert_sprintf "%020.12d", -123, " -000000000123"
assert_sprintf "%020.12d", 0, " 000000000000"
assert_sprintf "%020.*d", [12, 123], " 000000000123"
assert_sprintf "%020.*d", [12, -123], " -000000000123"
assert_sprintf "%020.*d", [12, 0], " 000000000000"
assert_sprintf "%020.*d", [-12, 123], "00000000000000000123"
assert_sprintf "%020.*d", [-12, -123], "-0000000000000000123"
assert_sprintf "%020.*d", [-12, 0], "00000000000000000000"
end
end
context "minus flag" do
it "left-justifies the string" do
assert_sprintf "%-d", 123, "123"
assert_sprintf "%-d", -123, "-123"
assert_sprintf "%-d", 0, "0"
assert_sprintf "%-20d", 123, "123 "
assert_sprintf "%-20d", -123, "-123 "
assert_sprintf "%-20d", 0, "0 "
assert_sprintf "%-4d", 123, "123 "
assert_sprintf "%-4d", -123, "-123"
assert_sprintf "%-4d", 0, "0 "
assert_sprintf "%-2d", 123, "123"
assert_sprintf "%-2d", -123, "-123"
assert_sprintf "%-2d", 0, "0 "
end
it "reserves space for the number prefix" do
assert_sprintf "%-+20d", 123, "+123 "
assert_sprintf "%-+20d", -123, "-123 "
assert_sprintf "%-+20d", 0, "+0 "
assert_sprintf "%- 20d", 123, " 123 "
assert_sprintf "%- 20d", -123, "-123 "
assert_sprintf "%- 20d", 0, " 0 "
assert_sprintf "%-#20b", 123, "0b1111011 "
assert_sprintf "%-#20b", -123, "-0b1111011 "
assert_sprintf "%-#20b", 0, "0 "
end
end
it "works with Int*::MIN" do
assert_sprintf "%d", Int8::MIN, "-128"
assert_sprintf "%d", Int16::MIN, "-32768"
assert_sprintf "%d", Int32::MIN, "-2147483648"
assert_sprintf "%d", Int64::MIN, "-9223372036854775808"
end
it "works with BigInt" do
assert_sprintf "%d", 123.to_big_i, "123"
assert_sprintf "%300.250d", 10.to_big_i ** 200, "#{" " * 50}#{"0" * 49}1#{"0" * 200}"
assert_sprintf "%- #300.250X", 16.to_big_i ** 200 - 1, " 0X#{"0" * 50}#{"F" * 200}#{" " * 47}"
end
it "works with BigFloat" do
assert_sprintf "%d", 123.to_big_f, "123"
assert_sprintf "%80.70d", 2.to_big_i ** 200, " 0000000001606938044258990275541962092341162602522202993782792835301376"
assert_sprintf "%- #70.60X", 2.to_big_f ** 200 - 2.to_big_f ** 120, " 0X0000000000FFFFFFFFFFFFFFFFFFFF000000000000000000000000000000 "
end
it "works with BigDecimal" do
assert_sprintf "%d", 123.to_big_d, "123"
assert_sprintf "%300.250d", 10.to_big_d ** 200, "#{" " * 50}#{"0" * 49}1#{"0" * 200}"
assert_sprintf "%- #300.250X", 16.to_big_d ** 200 - 1, " 0X#{"0" * 50}#{"F" * 200}#{" " * 47}"
end
end
it "doesn't stop at null character when doing '%'" do
assert_sprintf "1\u{0}%i\u{0}3", 2, "1\u00002\u00003"
end
if String::Formatter::HAS_RYU_PRINTF
describe "floats" do
context "fixed format" do
it "works" do
assert_sprintf "%f", 123, "123.000000"
assert_sprintf "%12f", 123.45, " 123.450000"
assert_sprintf "%-12f", 123.45, "123.450000 "
assert_sprintf "% f", 123.45, " 123.450000"
assert_sprintf "%+f", 123, "+123.000000"
assert_sprintf "%012f", 123, "00123.000000"
assert_sprintf "%.f", 1234.56, "1235"
assert_sprintf "%.2f", 1234.5678, "1234.57"
assert_sprintf "%10.2f", 1234.5678, " 1234.57"
assert_sprintf "%*.2f", [10, 1234.5678], " 1234.57"
assert_sprintf "%*.*f", [10, 2, 1234.5678], " 1234.57"
assert_sprintf "%.2f", 2.536_f32, "2.54"
assert_sprintf "%+0*.*f", [10, 2, 2.536_f32], "+000002.54"
assert_sprintf "%#.0f", 1234.56, "1235."
assert_sprintf "%#.1f", 1234.56, "1234.6"
expect_raises(ArgumentError, "Expected dynamic value '*' to be an Int - \"not a number\" (String)") do
sprintf("%*f", ["not a number", 2.536_f32])
end
assert_sprintf "%12.2f %12.2f %6.2f %.2f", [2.0, 3.0, 4.0, 5.0], " 2.00 3.00 4.00 5.00"
assert_sprintf "%f", 1e15, "1000000000000000.000000"
end
end
context "scientific format" do
it "works" do
assert_sprintf "%e", 123.45, "1.234500e+02"
assert_sprintf "%E", 123.45, "1.234500E+02"
assert_sprintf "%e", Float64::MAX, "1.797693e+308"
assert_sprintf "%e", Float64::MIN_POSITIVE, "2.225074e-308"
assert_sprintf "%e", Float64::MIN_SUBNORMAL, "4.940656e-324"
assert_sprintf "%e", 0.0, "0.000000e+00"
assert_sprintf "%e", -0.0, "-0.000000e+00"
assert_sprintf "%e", -Float64::MIN_SUBNORMAL, "-4.940656e-324"
assert_sprintf "%e", -Float64::MIN_POSITIVE, "-2.225074e-308"
assert_sprintf "%e", Float64::MIN, "-1.797693e+308"
end
context "width specifier" do
it "sets the minimum length of the string" do
assert_sprintf "%20e", 123.45, " 1.234500e+02"
assert_sprintf "%20e", -123.45, " -1.234500e+02"
assert_sprintf "%+20e", 123.45, " +1.234500e+02"
assert_sprintf "%13e", 123.45, " 1.234500e+02"
assert_sprintf "%13e", -123.45, "-1.234500e+02"
assert_sprintf "%+13e", 123.45, "+1.234500e+02"
assert_sprintf "%12e", 123.45, "1.234500e+02"
assert_sprintf "%12e", -123.45, "-1.234500e+02"
assert_sprintf "%+12e", 123.45, "+1.234500e+02"
assert_sprintf "%2e", 123.45, "1.234500e+02"
assert_sprintf "%2e", -123.45, "-1.234500e+02"
assert_sprintf "%+2e", 123.45, "+1.234500e+02"
end
it "left-justifies on negative width" do
assert_sprintf "%*e", [-20, 123.45], "1.234500e+02 "
end
end
context "precision specifier" do
it "sets the minimum length of the fractional part" do
assert_sprintf "%.0e", 2.0, "2e+00"
assert_sprintf "%.0e", 2.5.prev_float, "2e+00"
assert_sprintf "%.0e", 2.5, "2e+00"
assert_sprintf "%.0e", 2.5.next_float, "3e+00"
assert_sprintf "%.0e", 3.0, "3e+00"
assert_sprintf "%.0e", 3.5.prev_float, "3e+00"
assert_sprintf "%.0e", 3.5, "4e+00"
assert_sprintf "%.0e", 3.5.next_float, "4e+00"
assert_sprintf "%.0e", 4.0, "4e+00"
assert_sprintf "%.0e", 9.5, "1e+01"
assert_sprintf "%.100e", 1.1, "1.1000000000000000888178419700125232338905334472656250000000000000000000000000000000000000000000000000e+00"
assert_sprintf "%.10000e", 1.0, "1.#{"0" * 10000}e+00"
assert_sprintf "%.1000e", Float64::MIN_POSITIVE.prev_float,
"2.2250738585072008890245868760858598876504231122409594654935248025624400092282356951" \
"787758888037591552642309780950434312085877387158357291821993020294379224223559819827" \
"501242041788969571311791082261043971979604000454897391938079198936081525613113376149" \
"842043271751033627391549782731594143828136275113838604094249464942286316695429105080" \
"201815926642134996606517803095075913058719846423906068637102005108723282784678843631" \
"944515866135041223479014792369585208321597621066375401613736583044193603714778355306" \
"682834535634005074073040135602968046375918583163124224521599262546494300836851861719" \
"422417646455137135420132217031370496583210154654068035397417906022589503023501937519" \
"773030945763173210852507299305089761582519159720757232455434770912461317493580281734" \
"466552734375000000000000000000000000000000000000000000000000000000000000000000000000" \
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000" \
"000000000000000000000000000000000000000000000000000000000000000000000000000000e-308"
end
it "can be used with width" do
assert_sprintf "%20.13e", 123.45, " 1.2345000000000e+02"
assert_sprintf "%20.13e", -123.45, "-1.2345000000000e+02"
assert_sprintf "%20.13e", 0.0, " 0.0000000000000e+00"
assert_sprintf "%-20.13e", 123.45, "1.2345000000000e+02 "
assert_sprintf "%-20.13e", -123.45, "-1.2345000000000e+02"
assert_sprintf "%-20.13e", 0.0, "0.0000000000000e+00 "
assert_sprintf "%8.13e", 123.45, "1.2345000000000e+02"
assert_sprintf "%8.13e", -123.45, "-1.2345000000000e+02"
assert_sprintf "%8.13e", 0.0, "0.0000000000000e+00"
end
it "is ignored if precision argument is negative" do
assert_sprintf "%.*e", [-2, 123.45], "1.234500e+02"
end
end
context "sharp flag" do
it "prints a decimal point even if no digits follow" do
assert_sprintf "%#.0e", 1.0, "1.e+00"
assert_sprintf "%#.0e", 10000.0, "1.e+04"
assert_sprintf "%#.0e", 1.0e+23, "1.e+23"
assert_sprintf "%#.0e", 1.0e-100, "1.e-100"
assert_sprintf "%#.0e", 0.0, "0.e+00"
assert_sprintf "%#.0e", -0.0, "-0.e+00"
end
end
context "plus flag" do
it "writes a plus sign for positive values" do
assert_sprintf "%+e", 123.45, "+1.234500e+02"
assert_sprintf "%+e", -123.45, "-1.234500e+02"
assert_sprintf "%+e", 0.0, "+0.000000e+00"
end
it "writes plus sign after left space-padding" do
assert_sprintf "%+20e", 123.45, " +1.234500e+02"
assert_sprintf "%+20e", -123.45, " -1.234500e+02"
assert_sprintf "%+20e", 0.0, " +0.000000e+00"
end
it "writes plus sign before left zero-padding" do
assert_sprintf "%+020e", 123.45, "+00000001.234500e+02"
assert_sprintf "%+020e", -123.45, "-00000001.234500e+02"
assert_sprintf "%+020e", 0.0, "+00000000.000000e+00"
end
end
context "space flag" do
it "writes a space for positive values" do
assert_sprintf "% e", 123.45, " 1.234500e+02"
assert_sprintf "% e", -123.45, "-1.234500e+02"
assert_sprintf "% e", 0.0, " 0.000000e+00"
end
it "writes space before left space-padding" do
assert_sprintf "% 20e", 123.45, " 1.234500e+02"
assert_sprintf "% 20e", -123.45, " -1.234500e+02"
assert_sprintf "% 20e", 0.0, " 0.000000e+00"
assert_sprintf "% 020e", 123.45, " 00000001.234500e+02"
assert_sprintf "% 020e", -123.45, "-00000001.234500e+02"
assert_sprintf "% 020e", 0.0, " 00000000.000000e+00"
end
it "is ignored if plus flag is also specified" do
assert_sprintf "% +e", 123.45, "+1.234500e+02"
assert_sprintf "%+ e", -123.45, "-1.234500e+02"
end
end
context "zero flag" do
it "left-pads the result with zeros" do
assert_sprintf "%020e", 123.45, "000000001.234500e+02"
assert_sprintf "%020e", -123.45, "-00000001.234500e+02"
assert_sprintf "%020e", 0.0, "000000000.000000e+00"
end
it "is ignored if string is left-justified" do
assert_sprintf "%-020e", 123.45, "1.234500e+02 "
assert_sprintf "%-020e", -123.45, "-1.234500e+02 "
assert_sprintf "%-020e", 0.0, "0.000000e+00 "
end
it "can be used with precision" do
assert_sprintf "%020.12e", 123.45, "001.234500000000e+02"
assert_sprintf "%020.12e", -123.45, "-01.234500000000e+02"
assert_sprintf "%020.12e", 0.0, "000.000000000000e+00"
end
end
context "minus flag" do
it "left-justifies the string" do
assert_sprintf "%-20e", 123.45, "1.234500e+02 "
assert_sprintf "%-20e", -123.45, "-1.234500e+02 "
assert_sprintf "%-20e", 0.0, "0.000000e+00 "
end
end
end
context "general format" do
it "works" do
assert_sprintf "%g", 123.45, "123.45"
assert_sprintf "%G", 123.45, "123.45"
assert_sprintf "%g", 1.2345e-5, "1.2345e-05"
assert_sprintf "%G", 1.2345e-5, "1.2345E-05"
assert_sprintf "%g", 1.2345e+25, "1.2345e+25"
assert_sprintf "%G", 1.2345e+25, "1.2345E+25"
assert_sprintf "%g", Float64::MAX, "1.79769e+308"
assert_sprintf "%g", Float64::MIN_POSITIVE, "2.22507e-308"
assert_sprintf "%g", Float64::MIN_SUBNORMAL, "4.94066e-324"
assert_sprintf "%g", 0.0, "0"
assert_sprintf "%g", -0.0, "-0"
assert_sprintf "%g", -Float64::MIN_SUBNORMAL, "-4.94066e-324"
assert_sprintf "%g", -Float64::MIN_POSITIVE, "-2.22507e-308"
assert_sprintf "%g", Float64::MIN, "-1.79769e+308"
end
context "width specifier" do
it "sets the minimum length of the string" do
assert_sprintf "%10g", 123.45, " 123.45"
assert_sprintf "%10g", -123.45, " -123.45"
assert_sprintf "%+10g", 123.45, " +123.45"
assert_sprintf "%7g", 123.45, " 123.45"
assert_sprintf "%7g", -123.45, "-123.45"
assert_sprintf "%+7g", 123.45, "+123.45"
assert_sprintf "%6g", 123.45, "123.45"
assert_sprintf "%6g", -123.45, "-123.45"
assert_sprintf "%+6g", 123.45, "+123.45"
assert_sprintf "%2g", 123.45, "123.45"
assert_sprintf "%2g", -123.45, "-123.45"
assert_sprintf "%+2g", 123.45, "+123.45"
end
it "left-justifies on negative width" do
assert_sprintf "%*g", [-10, 123.45], "123.45 "
end
end
context "precision specifier" do
it "sets the precision of the value" do
assert_sprintf "%.0g", 123.45, "1e+02"
assert_sprintf "%.1g", 123.45, "1e+02"
assert_sprintf "%.2g", 123.45, "1.2e+02"
assert_sprintf "%.3g", 123.45, "123"
assert_sprintf "%.4g", 123.45, "123.5"
assert_sprintf "%.5g", 123.45, "123.45"
assert_sprintf "%.6g", 123.45, "123.45"
assert_sprintf "%.7g", 123.45, "123.45"
assert_sprintf "%.8g", 123.45, "123.45"
assert_sprintf "%.1000g", 123.45, "123.4500000000000028421709430404007434844970703125"
assert_sprintf "%.0g", 1.23e-45, "1e-45"
assert_sprintf "%.1g", 1.23e-45, "1e-45"
assert_sprintf "%.2g", 1.23e-45, "1.2e-45"
assert_sprintf "%.3g", 1.23e-45, "1.23e-45"
assert_sprintf "%.4g", 1.23e-45, "1.23e-45"
assert_sprintf "%.5g", 1.23e-45, "1.23e-45"
assert_sprintf "%.6g", 1.23e-45, "1.23e-45"
assert_sprintf "%.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125e-05"
end
it "can be used with width" do
assert_sprintf "%10.1g", 123.45, " 1e+02"
assert_sprintf "%10.2g", 123.45, " 1.2e+02"
assert_sprintf "%10.3g", 123.45, " 123"
assert_sprintf "%10.4g", 123.45, " 123.5"
assert_sprintf "%10.5g", 123.45, " 123.45"
assert_sprintf "%10.1g", -123.45, " -1e+02"
assert_sprintf "%10.2g", -123.45, " -1.2e+02"
assert_sprintf "%10.3g", -123.45, " -123"
assert_sprintf "%10.4g", -123.45, " -123.5"
assert_sprintf "%10.5g", -123.45, " -123.45"
assert_sprintf "%10.5g", 0, " 0"
assert_sprintf "%-10.1g", 123.45, "1e+02 "
assert_sprintf "%-10.2g", 123.45, "1.2e+02 "
assert_sprintf "%-10.3g", 123.45, "123 "
assert_sprintf "%-10.4g", 123.45, "123.5 "
assert_sprintf "%-10.5g", 123.45, "123.45 "
assert_sprintf "%-10.1g", -123.45, "-1e+02 "
assert_sprintf "%-10.2g", -123.45, "-1.2e+02 "
assert_sprintf "%-10.3g", -123.45, "-123 "
assert_sprintf "%-10.4g", -123.45, "-123.5 "
assert_sprintf "%-10.5g", -123.45, "-123.45 "
assert_sprintf "%-10.5g", 0, "0 "
assert_sprintf "%3.1g", 123.45, "1e+02"
assert_sprintf "%3.2g", 123.45, "1.2e+02"
assert_sprintf "%3.3g", 123.45, "123"
assert_sprintf "%3.4g", 123.45, "123.5"
assert_sprintf "%3.5g", 123.45, "123.45"
assert_sprintf "%3.1g", -123.45, "-1e+02"
assert_sprintf "%3.2g", -123.45, "-1.2e+02"
assert_sprintf "%3.3g", -123.45, "-123"
assert_sprintf "%3.4g", -123.45, "-123.5"
assert_sprintf "%3.5g", -123.45, "-123.45"
assert_sprintf "%1000.800g", 123.45, "#{" " * 950}123.4500000000000028421709430404007434844970703125"
end
it "is ignored if precision argument is negative" do
assert_sprintf "%.*g", [-2, 123.45], "123.45"
end
end
context "sharp flag" do
it "prints decimal point and trailing zeros" do
assert_sprintf "%#.0g", 12345, "1.e+04"
assert_sprintf "%#.6g", 12345, "12345.0"
assert_sprintf "%#.10g", 12345, "12345.00000"
assert_sprintf "%#.100g", 12345, "12345.#{"0" * 95}"
assert_sprintf "%#.1000g", 12345, "12345.#{"0" * 995}"
assert_sprintf "%#.0g", 1e-5, "1.e-05"
assert_sprintf "%#.6g", 1e-5, "1.00000e-05"
assert_sprintf "%#.10g", 1e-5, "1.000000000e-05"
assert_sprintf "%#.100g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 35}e-05"
assert_sprintf "%#.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 935}e-05"
assert_sprintf "%#15.0g", 12345, " 1.e+04"
assert_sprintf "%#15.6g", 12345, " 12345.0"
assert_sprintf "%#15.10g", 12345, " 12345.00000"
end
end
context "plus flag" do
it "writes a plus sign for positive values" do
assert_sprintf "%+g", 123.45, "+123.45"
assert_sprintf "%+g", -123.45, "-123.45"
assert_sprintf "%+g", 0.0, "+0"
end
it "writes plus sign after left space-padding" do
assert_sprintf "%+10g", 123.45, " +123.45"
assert_sprintf "%+10g", -123.45, " -123.45"
assert_sprintf "%+10g", 0.0, " +0"
end
it "writes plus sign before left zero-padding" do
assert_sprintf "%+010g", 123.45, "+000123.45"
assert_sprintf "%+010g", -123.45, "-000123.45"
assert_sprintf "%+010g", 0.0, "+000000000"
end
end
context "space flag" do
it "writes a space for positive values" do
assert_sprintf "% g", 123.45, " 123.45"
assert_sprintf "% g", -123.45, "-123.45"
assert_sprintf "% g", 0.0, " 0"
end
it "writes space before left space-padding" do
assert_sprintf "% 10g", 123.45, " 123.45"
assert_sprintf "% 10g", -123.45, " -123.45"
assert_sprintf "% 10g", 0.0, " 0"
assert_sprintf "% 010g", 123.45, " 000123.45"
assert_sprintf "% 010g", -123.45, "-000123.45"
assert_sprintf "% 010g", 0.0, " 000000000"
end
it "is ignored if plus flag is also specified" do
assert_sprintf "% +g", 123.45, "+123.45"
assert_sprintf "%+ g", -123.45, "-123.45"
end
end
context "zero flag" do
it "left-pads the result with zeros" do
assert_sprintf "%010g", 123.45, "0000123.45"
assert_sprintf "%010g", -123.45, "-000123.45"
assert_sprintf "%010g", 0.0, "0000000000"
end
it "is ignored if string is left-justified" do
assert_sprintf "%-010g", 123.45, "123.45 "
assert_sprintf "%-010g", -123.45, "-123.45 "
assert_sprintf "%-010g", 0.0, "0 "
end
it "can be used with precision" do
assert_sprintf "%010.2g", 123.45, "0001.2e+02"
assert_sprintf "%010.2g", -123.45, "-001.2e+02"
assert_sprintf "%010.2g", 0.0, "0000000000"
end
end
context "minus flag" do
it "left-justifies the string" do
assert_sprintf "%-10g", 123.45, "123.45 "
assert_sprintf "%-10g", -123.45, "-123.45 "
assert_sprintf "%-10g", 0.0, "0 "
assert_sprintf "%- 10g", 123.45, " 123.45 "
assert_sprintf "%- 10g", -123.45, "-123.45 "
assert_sprintf "%- 10g", 0.0, " 0 "
end
end
end
context "hex format" do
it "works" do
assert_sprintf "%a", 1194684.0, "0x1.23abcp+20"
assert_sprintf "%A", 1194684.0, "0X1.23ABCP+20"
assert_sprintf "%a", 12345678.45, "0x1.78c29ce666666p+23"
assert_sprintf "%A", 12345678.45, "0X1.78C29CE666666P+23"
assert_sprintf "%a", Float64::MAX, "0x1.fffffffffffffp+1023"
assert_sprintf "%a", Float64::MIN_POSITIVE, "0x1p-1022"
assert_sprintf "%a", Float64::MIN_SUBNORMAL, "0x0.0000000000001p-1022"
assert_sprintf "%a", 0.0, "0x0p+0"
assert_sprintf "%a", -0.0, "-0x0p+0"
assert_sprintf "%a", -Float64::MIN_SUBNORMAL, "-0x0.0000000000001p-1022"
assert_sprintf "%a", -Float64::MIN_POSITIVE, "-0x1p-1022"
assert_sprintf "%a", Float64::MIN, "-0x1.fffffffffffffp+1023"
end
context "width specifier" do
it "sets the minimum length of the string" do
assert_sprintf "%20a", hexfloat("0x1p+0"), " 0x1p+0"
assert_sprintf "%20a", hexfloat("0x1.2p+0"), " 0x1.2p+0"
assert_sprintf "%20a", hexfloat("0x1.23p+0"), " 0x1.23p+0"
assert_sprintf "%20a", hexfloat("0x1.234p+0"), " 0x1.234p+0"
assert_sprintf "%20a", hexfloat("0x1.2345p+0"), " 0x1.2345p+0"
assert_sprintf "%20a", hexfloat("0x1.23456p+0"), " 0x1.23456p+0"
assert_sprintf "%20a", hexfloat("0x1.234567p+0"), " 0x1.234567p+0"
assert_sprintf "%20a", hexfloat("0x1.2345678p+0"), " 0x1.2345678p+0"
assert_sprintf "%20a", hexfloat("0x1.23456789p+0"), " 0x1.23456789p+0"
assert_sprintf "%20a", hexfloat("0x1.23456789ap+0"), " 0x1.23456789ap+0"
assert_sprintf "%20a", hexfloat("0x1.23456789abp+0"), " 0x1.23456789abp+0"
assert_sprintf "%20a", hexfloat("0x1.23456789abcp+0"), " 0x1.23456789abcp+0"
assert_sprintf "%20a", hexfloat("-0x1p+0"), " -0x1p+0"
assert_sprintf "%20a", hexfloat("-0x1.2p+0"), " -0x1.2p+0"
assert_sprintf "%20a", hexfloat("-0x1.23p+0"), " -0x1.23p+0"
assert_sprintf "%20a", hexfloat("-0x1.234p+0"), " -0x1.234p+0"
assert_sprintf "%20a", hexfloat("-0x1.2345p+0"), " -0x1.2345p+0"
assert_sprintf "%20a", hexfloat("-0x1.23456p+0"), " -0x1.23456p+0"
assert_sprintf "%20a", hexfloat("-0x1.234567p+0"), " -0x1.234567p+0"
assert_sprintf "%20a", hexfloat("-0x1.2345678p+0"), " -0x1.2345678p+0"
assert_sprintf "%20a", hexfloat("-0x1.23456789p+0"), " -0x1.23456789p+0"
assert_sprintf "%20a", hexfloat("-0x1.23456789ap+0"), " -0x1.23456789ap+0"
assert_sprintf "%20a", hexfloat("-0x1.23456789abp+0"), " -0x1.23456789abp+0"
assert_sprintf "%20a", hexfloat("-0x1.23456789abcp+0"), " -0x1.23456789abcp+0"
assert_sprintf "%+20a", 1194684.0, " +0x1.23abcp+20"
assert_sprintf "%14a", 1194684.0, " 0x1.23abcp+20"
assert_sprintf "%14a", -1194684.0, "-0x1.23abcp+20"
assert_sprintf "%+14a", 1194684.0, "+0x1.23abcp+20"
assert_sprintf "%13a", 1194684.0, "0x1.23abcp+20"
assert_sprintf "%13a", -1194684.0, "-0x1.23abcp+20"
assert_sprintf "%+13a", 1194684.0, "+0x1.23abcp+20"
assert_sprintf "%2a", 1194684.0, "0x1.23abcp+20"
assert_sprintf "%2a", -1194684.0, "-0x1.23abcp+20"
assert_sprintf "%+2a", 1194684.0, "+0x1.23abcp+20"
end
it "left-justifies on negative width" do
assert_sprintf "%*a", [-20, 1194684.0], "0x1.23abcp+20 "
end
end
context "precision specifier" do
it "sets the minimum length of the fractional part" do
assert_sprintf "%.0a", 0.0, "0x0p+0"
assert_sprintf "%.0a", (Float64::MIN_POSITIVE / 2).prev_float, "0x0p-1022"
assert_sprintf "%.0a", Float64::MIN_POSITIVE / 2, "0x0p-1022"
assert_sprintf "%.0a", (Float64::MIN_POSITIVE / 2).next_float, "0x1p-1022"
assert_sprintf "%.0a", Float64::MIN_POSITIVE.prev_float, "0x1p-1022"
assert_sprintf "%.0a", Float64::MIN_POSITIVE, "0x1p-1022"
assert_sprintf "%.0a", 0.0625, "0x1p-4"
assert_sprintf "%.0a", 0.0625.next_float, "0x1p-4"
assert_sprintf "%.0a", 0.09375.prev_float, "0x1p-4"
assert_sprintf "%.0a", 0.09375, "0x2p-4"
assert_sprintf "%.0a", 0.09375.next_float, "0x2p-4"
assert_sprintf "%.0a", 0.125.prev_float, "0x2p-4"
assert_sprintf "%.0a", 0.125, "0x1p-3"
assert_sprintf "%.1a", 2.0, "0x1.0p+1"
assert_sprintf "%.1a", 2.0.next_float, "0x1.0p+1"
assert_sprintf "%.1a", 2.0625.prev_float, "0x1.0p+1"
assert_sprintf "%.1a", 2.0625, "0x1.0p+1"
assert_sprintf "%.1a", 2.0625.next_float, "0x1.1p+1"
assert_sprintf "%.1a", 2.125.prev_float, "0x1.1p+1"
assert_sprintf "%.1a", 2.125, "0x1.1p+1"
assert_sprintf "%.1a", 2.125.next_float, "0x1.1p+1"
assert_sprintf "%.1a", 2.1875.prev_float, "0x1.1p+1"
assert_sprintf "%.1a", 2.1875, "0x1.2p+1"
assert_sprintf "%.1a", 2.1875.next_float, "0x1.2p+1"
assert_sprintf "%.1a", 2.25.prev_float, "0x1.2p+1"
assert_sprintf "%.1a", 2.25, "0x1.2p+1"
assert_sprintf "%.1a", 60.0, "0x1.ep+5"
assert_sprintf "%.1a", 60.0.next_float, "0x1.ep+5"
assert_sprintf "%.1a", 61.0.prev_float, "0x1.ep+5"
assert_sprintf "%.1a", 61.0, "0x1.ep+5"
assert_sprintf "%.1a", 61.0.next_float, "0x1.fp+5"
assert_sprintf "%.1a", 62.0.prev_float, "0x1.fp+5"
assert_sprintf "%.1a", 62.0, "0x1.fp+5"
assert_sprintf "%.1a", 62.0.next_float, "0x1.fp+5"
assert_sprintf "%.1a", 63.0.prev_float, "0x1.fp+5"
assert_sprintf "%.1a", 63.0, "0x2.0p+5"
assert_sprintf "%.1a", 63.0.next_float, "0x2.0p+5"
assert_sprintf "%.1a", 64.0.prev_float, "0x2.0p+5"
assert_sprintf "%.1a", 64.0, "0x1.0p+6"
assert_sprintf "%.4a", 65536.0, "0x1.0000p+16"
assert_sprintf "%.4a", 65536.0.next_float, "0x1.0000p+16"
assert_sprintf "%.4a", 65536.5.prev_float, "0x1.0000p+16"
assert_sprintf "%.4a", 65536.5, "0x1.0000p+16"
assert_sprintf "%.4a", 65536.5.next_float, "0x1.0001p+16"
assert_sprintf "%.4a", 65537.0.prev_float, "0x1.0001p+16"
assert_sprintf "%.4a", 65537.0, "0x1.0001p+16"
assert_sprintf "%.4a", 65537.0.next_float, "0x1.0001p+16"
assert_sprintf "%.4a", 65537.5.prev_float, "0x1.0001p+16"
assert_sprintf "%.4a", 65537.5, "0x1.0002p+16"
assert_sprintf "%.4a", 65537.5.next_float, "0x1.0002p+16"
assert_sprintf "%.4a", 65538.0.prev_float, "0x1.0002p+16"
assert_sprintf "%.4a", 65538.0, "0x1.0002p+16"
assert_sprintf "%.4a", 131070.0, "0x1.fffep+16"
assert_sprintf "%.4a", 131070.0.next_float, "0x1.fffep+16"
assert_sprintf "%.4a", 131070.5.prev_float, "0x1.fffep+16"
assert_sprintf "%.4a", 131070.5, "0x1.fffep+16"
assert_sprintf "%.4a", 131070.5.next_float, "0x1.ffffp+16"
assert_sprintf "%.4a", 131071.0.prev_float, "0x1.ffffp+16"
assert_sprintf "%.4a", 131071.0, "0x1.ffffp+16"
assert_sprintf "%.4a", 131071.0.next_float, "0x1.ffffp+16"
assert_sprintf "%.4a", 131071.5.prev_float, "0x1.ffffp+16"
assert_sprintf "%.4a", 131071.5, "0x2.0000p+16"
assert_sprintf "%.4a", 131071.5.next_float, "0x2.0000p+16"
assert_sprintf "%.4a", 131072.0.prev_float, "0x2.0000p+16"
assert_sprintf "%.4a", 131072.0, "0x1.0000p+17"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x01, "0x0.000000000000p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x07, "0x0.000000000000p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x08, "0x0.000000000000p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x09, "0x0.000000000001p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x0f, "0x0.000000000001p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x10, "0x0.000000000001p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x11, "0x0.000000000001p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x17, "0x0.000000000001p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x18, "0x0.000000000002p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x19, "0x0.000000000002p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x1f, "0x0.000000000002p-1022"
assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x20, "0x0.000000000002p-1022"
assert_sprintf "%.17a", Float64::MAX, "0x1.fffffffffffff0000p+1023"
assert_sprintf "%.16a", Float64::MAX, "0x1.fffffffffffff000p+1023"
assert_sprintf "%.15a", Float64::MAX, "0x1.fffffffffffff00p+1023"
assert_sprintf "%.14a", Float64::MAX, "0x1.fffffffffffff0p+1023"
assert_sprintf "%.13a", Float64::MAX, "0x1.fffffffffffffp+1023"
assert_sprintf "%.12a", Float64::MAX, "0x2.000000000000p+1023"
assert_sprintf "%.11a", Float64::MAX, "0x2.00000000000p+1023"
assert_sprintf "%.10a", Float64::MAX, "0x2.0000000000p+1023"
assert_sprintf "%.9a", Float64::MAX, "0x2.000000000p+1023"
assert_sprintf "%.8a", Float64::MAX, "0x2.00000000p+1023"
assert_sprintf "%.7a", Float64::MAX, "0x2.0000000p+1023"
assert_sprintf "%.6a", Float64::MAX, "0x2.000000p+1023"
assert_sprintf "%.5a", Float64::MAX, "0x2.00000p+1023"
assert_sprintf "%.4a", Float64::MAX, "0x2.0000p+1023"
assert_sprintf "%.3a", Float64::MAX, "0x2.000p+1023"
assert_sprintf "%.2a", Float64::MAX, "0x2.00p+1023"
assert_sprintf "%.1a", Float64::MAX, "0x2.0p+1023"
assert_sprintf "%.0a", Float64::MAX, "0x2p+1023"
assert_sprintf "%.1000a", 1194684.0, "0x1.23abc#{"0" * 995}p+20"
end
it "can be used with width" do
assert_sprintf "%20.8a", 1194684.0, " 0x1.23abc000p+20"
assert_sprintf "%20.8a", -1194684.0, " -0x1.23abc000p+20"
assert_sprintf "%20.8a", 0.0, " 0x0.00000000p+0"
assert_sprintf "%-20.8a", 1194684.0, "0x1.23abc000p+20 "
assert_sprintf "%-20.8a", -1194684.0, "-0x1.23abc000p+20 "
assert_sprintf "%-20.8a", 0.0, "0x0.00000000p+0 "
assert_sprintf "%4.8a", 1194684.0, "0x1.23abc000p+20"
assert_sprintf "%4.8a", -1194684.0, "-0x1.23abc000p+20"
assert_sprintf "%4.8a", 0.0, "0x0.00000000p+0"
end
it "is ignored if precision argument is negative" do
assert_sprintf "%.*a", [-2, 1194684.0], "0x1.23abcp+20"
end
end
context "sharp flag" do
it "prints a decimal point even if no digits follow" do
assert_sprintf "%#a", 1.0, "0x1.p+0"
assert_sprintf "%#a", Float64::MIN_POSITIVE, "0x1.p-1022"
assert_sprintf "%#a", 2.0 ** -234, "0x1.p-234"
assert_sprintf "%#a", 2.0 ** 1021, "0x1.p+1021"
assert_sprintf "%#a", 0.0, "0x0.p+0"
assert_sprintf "%#a", -0.0, "-0x0.p+0"
assert_sprintf "%#.0a", 1.0, "0x1.p+0"
assert_sprintf "%#.0a", Float64::MIN_POSITIVE, "0x1.p-1022"
assert_sprintf "%#.0a", 2.0 ** -234, "0x1.p-234"
assert_sprintf "%#.0a", 2.0 ** 1021, "0x1.p+1021"
assert_sprintf "%#.0a", 1194684.0, "0x1.p+20"
assert_sprintf "%#.0a", 0.0, "0x0.p+0"
assert_sprintf "%#.0a", -0.0, "-0x0.p+0"
end
end
context "plus flag" do
it "writes a plus sign for positive values" do
assert_sprintf "%+a", 1194684.0, "+0x1.23abcp+20"
assert_sprintf "%+a", -1194684.0, "-0x1.23abcp+20"
assert_sprintf "%+a", 0.0, "+0x0p+0"
end
it "writes plus sign after left space-padding" do
assert_sprintf "%+20a", 1194684.0, " +0x1.23abcp+20"
assert_sprintf "%+20a", -1194684.0, " -0x1.23abcp+20"
assert_sprintf "%+20a", 0.0, " +0x0p+0"
end
it "writes plus sign before left zero-padding" do
assert_sprintf "%+020a", 1194684.0, "+0x0000001.23abcp+20"
assert_sprintf "%+020a", -1194684.0, "-0x0000001.23abcp+20"
assert_sprintf "%+020a", 0.0, "+0x00000000000000p+0"
end
end
context "space flag" do
it "writes a space for positive values" do
assert_sprintf "% a", 1194684.0, " 0x1.23abcp+20"
assert_sprintf "% a", -1194684.0, "-0x1.23abcp+20"
assert_sprintf "% a", 0.0, " 0x0p+0"
end
it "writes space before left space-padding" do
assert_sprintf "% 20a", 1194684.0, " 0x1.23abcp+20"
assert_sprintf "% 20a", -1194684.0, " -0x1.23abcp+20"
assert_sprintf "% 20a", 0.0, " 0x0p+0"
assert_sprintf "% 020a", 1194684.0, " 0x0000001.23abcp+20"
assert_sprintf "% 020a", -1194684.0, "-0x0000001.23abcp+20"
assert_sprintf "% 020a", 0.0, " 0x00000000000000p+0"
end
it "is ignored if plus flag is also specified" do
assert_sprintf "% +a", 1194684.0, "+0x1.23abcp+20"
assert_sprintf "%+ a", -1194684.0, "-0x1.23abcp+20"
end
end
context "zero flag" do
it "left-pads the result with zeros" do
assert_sprintf "%020a", 1194684.0, "0x00000001.23abcp+20"
assert_sprintf "%020a", -1194684.0, "-0x0000001.23abcp+20"
assert_sprintf "%020a", 0.0, "0x000000000000000p+0"
end
it "is ignored if string is left-justified" do
assert_sprintf "%-020a", 1194684.0, "0x1.23abcp+20 "
assert_sprintf "%-020a", -1194684.0, "-0x1.23abcp+20 "
assert_sprintf "%-020a", 0.0, "0x0p+0 "
end
it "can be used with precision" do
assert_sprintf "%020.8a", 1194684.0, "0x00001.23abc000p+20"
assert_sprintf "%020.8a", -1194684.0, "-0x0001.23abc000p+20"
assert_sprintf "%020.8a", 0.0, "0x000000.00000000p+0"
end
end
context "minus flag" do
it "left-justifies the string" do
assert_sprintf "%-20a", 1194684.0, "0x1.23abcp+20 "
assert_sprintf "%-20a", -1194684.0, "-0x1.23abcp+20 "
assert_sprintf "%-20a", 0.0, "0x0p+0 "
end
end
end
[Float32, Float64].each do |float|
it "infinities" do
pos_inf = float.new(1) / float.new(0)
neg_inf = float.new(-1) / float.new(0)
assert_sprintf "%f", pos_inf, "inf"
assert_sprintf "%a", pos_inf, "inf"
assert_sprintf "%e", pos_inf, "inf"
assert_sprintf "%g", pos_inf, "inf"
assert_sprintf "%A", pos_inf, "INF"
assert_sprintf "%E", pos_inf, "INF"
assert_sprintf "%G", pos_inf, "INF"
assert_sprintf "%f", neg_inf, "-inf"
assert_sprintf "%G", neg_inf, "-INF"
assert_sprintf "%2f", pos_inf, "inf"
assert_sprintf "%4f", pos_inf, " inf"
assert_sprintf "%6f", pos_inf, " inf"
assert_sprintf "%2f", neg_inf, "-inf"
assert_sprintf "%4f", neg_inf, "-inf"
assert_sprintf "%6f", neg_inf, " -inf"
assert_sprintf "% f", pos_inf, " inf"
assert_sprintf "% 2f", pos_inf, " inf"
assert_sprintf "% 4f", pos_inf, " inf"
assert_sprintf "% 6f", pos_inf, " inf"
assert_sprintf "% f", neg_inf, "-inf"
assert_sprintf "% 2f", neg_inf, "-inf"
assert_sprintf "% 4f", neg_inf, "-inf"
assert_sprintf "% 6f", neg_inf, " -inf"
assert_sprintf "%+f", pos_inf, "+inf"
assert_sprintf "%+2f", pos_inf, "+inf"
assert_sprintf "%+4f", pos_inf, "+inf"
assert_sprintf "%+6f", pos_inf, " +inf"
assert_sprintf "%+f", neg_inf, "-inf"
assert_sprintf "%+2f", neg_inf, "-inf"
assert_sprintf "%+4f", neg_inf, "-inf"
assert_sprintf "%+6f", neg_inf, " -inf"
assert_sprintf "%+ f", pos_inf, "+inf"
assert_sprintf "%-4f", pos_inf, "inf "
assert_sprintf "%-6f", pos_inf, "inf "
assert_sprintf "%-4f", neg_inf, "-inf"
assert_sprintf "%-6f", neg_inf, "-inf "
assert_sprintf "% -4f", pos_inf, " inf"
assert_sprintf "% -6f", pos_inf, " inf "
assert_sprintf "% -4f", neg_inf, "-inf"
assert_sprintf "% -6f", neg_inf, "-inf "
assert_sprintf "%-+4f", pos_inf, "+inf"
assert_sprintf "%-+6f", pos_inf, "+inf "
assert_sprintf "%-+4f", neg_inf, "-inf"
assert_sprintf "%-+6f", neg_inf, "-inf "
assert_sprintf "%-+ 6f", pos_inf, "+inf "
assert_sprintf "%06f", pos_inf, " inf"
assert_sprintf "%-06f", pos_inf, "inf "
assert_sprintf "%06f", neg_inf, " -inf"
assert_sprintf "%-06f", neg_inf, "-inf "
assert_sprintf "%.1f", pos_inf, "inf"
assert_sprintf "%#f", pos_inf, "inf"
end
it "not-a-numbers" do
pos_nan = Math.copysign(float.new(0) / float.new(0), 1)
neg_nan = Math.copysign(float.new(0) / float.new(0), -1)
assert_sprintf "%f", pos_nan, "nan"
assert_sprintf "%a", pos_nan, "nan"
assert_sprintf "%e", pos_nan, "nan"
assert_sprintf "%g", pos_nan, "nan"
assert_sprintf "%A", pos_nan, "NAN"
assert_sprintf "%E", pos_nan, "NAN"
assert_sprintf "%G", pos_nan, "NAN"
assert_sprintf "%f", neg_nan, "nan"
assert_sprintf "%a", neg_nan, "nan"
assert_sprintf "%e", neg_nan, "nan"
assert_sprintf "%g", neg_nan, "nan"
assert_sprintf "%A", neg_nan, "NAN"
assert_sprintf "%E", neg_nan, "NAN"
assert_sprintf "%G", neg_nan, "NAN"
assert_sprintf "%+f", pos_nan, "+nan"
assert_sprintf "%+f", neg_nan, "+nan"
end
end
end
else
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_i8, "B"
assert_sprintf "%c", 67_i16, "C"
assert_sprintf "%c", 68_i32, "D"
assert_sprintf "%c", 69_i64, "E"
assert_sprintf "%c", 97_u8, "a"
assert_sprintf "%c", 98_u16, "b"
assert_sprintf "%c", 99_u32, "c"
assert_sprintf "%c", 100_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"
assert_sprintf "%-s", 'a', "a"
assert_sprintf "%20s", 'a', " a"
assert_sprintf "%-20s", 'a', "a "
assert_sprintf "%*s", [10, 123], " 123"
assert_sprintf "%*s", [-10, 123], "123 "
assert_sprintf "%.5s", "foo bar baz", "foo b"
assert_sprintf "%.*s", [5, "foo bar baz"], "foo b"
assert_sprintf "%*.*s", [20, 5, "foo bar baz"], " foo b"
assert_sprintf "%-*.*s", [20, 5, "foo bar baz"], "foo b "
end
it "calls to_s on non-strings" do
span = 1.second
assert_sprintf "%s", span, span.to_s
end
end
context "plain substitution" do
it "substitutes one placeholder" do
assert_sprintf "change %{this}", {"this" => "nothing"}, "change nothing"
assert_sprintf "change %{this}", {this: "nothing"}, "change nothing"
end
it "substitutes multiple placeholder" do
assert_sprintf "change %{this} and %{more}", {"this" => "nothing", "more" => "something"}, "change nothing and something"
assert_sprintf "change %{this} and %{more}", {this: "nothing", more: "something"}, "change nothing and something"
end
it "throws an error when the key is not found" do
expect_raises(KeyError) { sprintf("change %{this}", {"that" => "wrong key"}) }
expect_raises(KeyError) { sprintf("change %{this}", {that: "wrong key"}) }
end
it "raises if expecting hash or named tuple but not given" do
expect_raises(ArgumentError, "One hash or named tuple required") { sprintf("change %{this}", "this") }
end
it "doesn't raise if 1-element list of hash or named tuple given" do
assert_sprintf "change %{this}", [{"this" => "nothing"}], "change nothing"
assert_sprintf "change %{this}", [{this: "nothing"}], "change nothing"
assert_sprintf "change %{this}", { {"this" => "nothing"} }, "change nothing"
assert_sprintf "change %{this}", { {this: "nothing"} }, "change nothing"
end
it "raises on unbalanced curly" do
expect_raises(ArgumentError, "Malformed name - unmatched parenthesis") { sprintf("change %{this", {"this" => 1}) }
end
it "doesn't raise on balanced curly with null byte" do
assert_sprintf "change %{this\u{0}}", {"this\u{0}" => 1}, "change 1"
end
it "raises if sequential parameters also given" do
expect_raises(ArgumentError, "Cannot mix named parameters with sequential ones") { sprintf("%{this}%d", {"this" => 1}) }
end
it "raises if numbered parameters also given" do
expect_raises(ArgumentError, "Cannot mix named parameters with numbered ones") { sprintf("%{this} %1$d", {"this" => 1}) }
end
it "doesn't raise if formatted substitution also given" do
assert_sprintf "%{foo}%s", {"foo" => "x", "bar" => "y"}, "xy"
end
end
context "formatted substitution" do
it "applies formatting to %<...> placeholder" do
assert_sprintf "change %.2f", {"this" => 23.456}, "change 23.46"
assert_sprintf "change %.2f", {this: 23.456}, "change 23.46"
end
it "raises if sequential parameters also given" do
expect_raises(ArgumentError, "Cannot mix named parameters with sequential ones") { sprintf("%d%d", {"this" => 1}) }
end
it "raises if numbered parameters also given" do
expect_raises(ArgumentError, "Cannot mix named parameters with numbered ones") { sprintf("%1$d", {"this" => 1}) }
expect_raises(ArgumentError, "Cannot mix named parameters with numbered ones") { sprintf("%*1$d", {"this" => 1}) }
expect_raises(ArgumentError, "Cannot mix named parameters with numbered ones") { sprintf("%.*1$d", {"this" => 1}) }
expect_raises(ArgumentError, "Cannot mix named parameters with numbered ones") { sprintf("%d %1$d", {"this" => 1}) }
end
it "doesn't raise if plain substitution also given" do
assert_sprintf "%s%{bar}", {"foo" => "x", "bar" => "y"}, "xy"
end
end
context "sequential parameters" do
it "raises if named parameters also given" do
expect_raises(ArgumentError, "Cannot mix sequential parameters with named ones") { sprintf("%d%{this}", 1) }
expect_raises(ArgumentError, "Cannot mix sequential parameters with named ones") { sprintf("%d%d", 1) }
end
it "raises if numbered parameters also given" do
expect_raises(ArgumentError, "Cannot mix sequential parameters with numbered ones") { sprintf("%d %1$d", 1) }
end
end
context "numbered parameters" do
it "gets argument at specified index" do
assert_sprintf "%2$d %3$x %1$s", ["foo", 123, 0xabc], "123 abc foo"
end
it "gets width and precision specifier at specified index" do
assert_sprintf "%2$*1$d", [5, 123], " 123"
assert_sprintf "%2$.*1$s", [5, "abcdefghij"], "abcde"
assert_sprintf "%-3$*1$.*2$s", [10, 5, "abcdefghij"], "abcde "
end
it "raises if index is out of bounds" do
expect_raises(ArgumentError, "Too few arguments") { sprintf("%1$d") }
expect_raises(ArgumentError, "Too few arguments") { sprintf("%5$d", 1, 2, 3, 4) }
end
it "raises if index is zero" do
expect_raises(ArgumentError) { sprintf("%0$d") }
expect_raises(ArgumentError) { sprintf("%1$*0$d", 1) }
expect_raises(ArgumentError) { sprintf("%1$.*0$d", 1) }
end
it "can be used before flags" do
assert_sprintf "%1$ d", 123, " 123"
assert_sprintf "%1$+d", 123, "+123"
assert_sprintf "%1$5d", 123, " 123"
assert_sprintf "%1$-5d", 123, "123 "
assert_sprintf "%1$#x", 123, "0x7b"
end
it "raises if multiple indices specified" do
expect_raises(ArgumentError, "Cannot specify parameter number more than once") { sprintf("%1$2$d", 1, 2) }
expect_raises(ArgumentError, "Cannot specify parameter number more than once") { sprintf("%1$-2$d", 1, 2) }
end
it "raises if used as width or precision specifier of a sequential parameter" do
expect_raises(ArgumentError, "Cannot mix numbered parameters with sequential ones") { sprintf("%*1$d", 1) }
expect_raises(ArgumentError, "Cannot mix numbered parameters with sequential ones") { sprintf("%.*1$d", 1) }
end
it "raises if sequential parameters also given" do
expect_raises(ArgumentError, "Cannot mix numbered parameters with sequential ones") { sprintf("%1$d %d", 1) }
end
it "raises if named parameters also given" do
expect_raises(ArgumentError, "Cannot mix numbered parameters with named ones") { sprintf("%1$d %{this}", 1) }
expect_raises(ArgumentError, "Cannot mix numbered parameters with named ones") { sprintf("%1$d %d", 1) }
end
end
end