diff --git a/spec/std/base64_spec.cr b/spec/std/base64_spec.cr index 1a5b021b2956..a0fd3d6bc885 100644 --- a/spec/std/base64_spec.cr +++ b/spec/std/base64_spec.cr @@ -1,6 +1,18 @@ require "spec" require "base64" require "crystal/digest/md5" +require "../support/string" + +# rearrange parameters for `assert_prints` +{% for method in %w(encode strict_encode urlsafe_encode) %} + private def base64_{{ method.id }}(io : IO, data, *args) + Base64.{{ method.id }}(data, io, *args) + end + + private def base64_{{ method.id }}(data, *args) + Base64.{{ method.id }}(data, *args) + end +{% end %} describe "Base64" do context "simple test" do @@ -9,7 +21,7 @@ describe "Base64" do "abcdefg" => "YWJjZGVmZw==\n"} eqs.each do |a, b| it "encode #{a.inspect} to #{b.inspect}" do - Base64.encode(a).should eq(b) + assert_prints base64_encode(a), b end it "decode from #{b.inspect} to #{a.inspect}" do Base64.decode(b).should eq(a.to_slice) @@ -32,15 +44,15 @@ describe "Base64" do it "encodes byte slice" do slice = Bytes.new(5) { 1_u8 } - Base64.encode(slice).should eq("AQEBAQE=\n") - Base64.strict_encode(slice).should eq("AQEBAQE=") + assert_prints base64_encode(slice), "AQEBAQE=\n" + assert_prints base64_strict_encode(slice), "AQEBAQE=" end it "encodes static array" do array = uninitialized StaticArray(UInt8, 5) (0...5).each { |i| array[i] = 1_u8 } - Base64.encode(array).should eq("AQEBAQE=\n") - Base64.strict_encode(array).should eq("AQEBAQE=") + assert_prints base64_encode(array), "AQEBAQE=\n" + assert_prints base64_strict_encode(array), "AQEBAQE=" end describe "base" do @@ -50,7 +62,7 @@ describe "Base64" do "hahahโŠ™โ“งโŠ™" => "aGFoYWjiipnik6fiipk=\n"} eqs.each do |a, b| it "encode #{a.inspect} to #{b.inspect}" do - Base64.encode(a).should eq(b) + assert_prints base64_encode(a), b end it "decode from #{b.inspect} to #{a.inspect}" do Base64.decode(b).should eq(a.to_slice) @@ -63,20 +75,16 @@ describe "Base64" do "Now is the time for all good coders\nto learn Crystal") end - it "encode to stream" do + it "encode to stream returns number of written characters" do io = IO::Memory.new count = Base64.encode("Now is the time for all good coders\nto learn Crystal", io) count.should eq 74 - io.rewind - io.gets_to_end.should eq "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g\nQ3J5c3RhbA==\n" end - it "decode from stream" do + it "decode from stream returns number of written bytes" do io = IO::Memory.new count = Base64.decode("Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gQ3J5c3RhbA==", io) count.should eq 52 - io.rewind - io.gets_to_end.should eq "Now is the time for all good coders\nto learn Crystal" end it "big message" do @@ -151,22 +159,19 @@ describe "Base64" do describe "scrict" do it "encode" do - Base64.strict_encode("Now is the time for all good coders\nto learn Crystal").should eq( - "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gQ3J5c3RhbA==") + assert_prints base64_strict_encode("Now is the time for all good coders\nto learn Crystal"), + "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gQ3J5c3RhbA==" end it "with spec symbols" do s = String.build { |b| (160..179).each { |i| b << i.chr } } se = "wqDCocKiwqPCpMKlwqbCp8KowqnCqsKrwqzCrcKuwq/CsMKxwrLCsw==" - Base64.strict_encode(s).should eq(se) + assert_prints base64_strict_encode(s), se end - it "encode to stream" do + it "encode to stream returns number of written characters" do s = String.build { |b| (160..179).each { |i| b << i.chr } } - se = "wqDCocKiwqPCpMKlwqbCp8KowqnCqsKrwqzCrcKuwq/CsMKxwrLCsw==" io = IO::Memory.new Base64.strict_encode(s, io).should eq(56) - io.rewind - io.gets_to_end.should eq se end end @@ -174,16 +179,13 @@ describe "Base64" do it "work" do s = String.build { |b| (160..179).each { |i| b << i.chr } } se = "wqDCocKiwqPCpMKlwqbCp8KowqnCqsKrwqzCrcKuwq_CsMKxwrLCsw==" - Base64.urlsafe_encode(s).should eq(se) + assert_prints base64_urlsafe_encode(s), se end - it "encode to stream" do + it "encode to stream returns number of written characters" do s = String.build { |b| (160..179).each { |i| b << i.chr } } - se = "wqDCocKiwqPCpMKlwqbCp8KowqnCqsKrwqzCrcKuwq_CsMKxwrLCsw==" io = IO::Memory.new Base64.urlsafe_encode(s, io).should eq(56) - io.rewind - io.gets_to_end.should eq se end end end diff --git a/spec/std/csv/csv_build_spec.cr b/spec/std/csv/csv_build_spec.cr index 5dbd865fed34..7cbb91f7f746 100644 --- a/spec/std/csv/csv_build_spec.cr +++ b/spec/std/csv/csv_build_spec.cr @@ -1,10 +1,11 @@ require "spec" require "csv" +require "../../support/string" describe CSV do describe "build" do it "builds two rows" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row do |row| row << "one" row << "two" @@ -13,12 +14,11 @@ describe CSV do row << "three" row << "four" end - end - string.should eq("one,two\nthree,four\n") + end, "one,two\nthree,four\n") end it "builds with numbers" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row do |row| row << 1 row << 2 @@ -27,137 +27,120 @@ describe CSV do row << 3 row << 4 end - end - string.should eq("1,2\n3,4\n") + end, "1,2\n3,4\n") end it "builds with commas" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row do |row| row << %(hello,world) end - end - string.should eq(%("hello,world"\n)) + end, %("hello,world"\n)) end it "builds with custom separator" do - string = CSV.build(separator: ';') do |csv| + assert_prints(CSV.build(separator: ';') do |csv| csv.row do |row| row << "one" row << "two" row << "thr;ee" end - end - string.should eq(%(one;two;"thr;ee"\n)) + end, %(one;two;"thr;ee"\n)) end it "builds with quotes" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row do |row| row << %(he said "no") end - end - string.should eq(%("he said ""no"""\n)) + end, %("he said ""no"""\n)) end it "builds with custom quote character" do - string = CSV.build(quote_char: '\'') do |csv| + assert_prints(CSV.build(quote_char: '\'') do |csv| csv.row do |row| row << %(he said 'no') end - end - string.should eq(%('he said ''no'''\n)) + end, %('he said ''no'''\n)) end it "builds row from enumerable" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row [1, 2, 3] - end - string.should eq("1,2,3\n") + end, "1,2,3\n") end it "builds row from splat" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row 1, 2, 3 - end - string.should eq("1,2,3\n") + end, "1,2,3\n") end it "skips inside row" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row do |row| row << 1 row.skip_cell row << 2 end - end - string.should eq("1,,2\n") + end, "1,,2\n") end it "concats enumerable to row" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row do |row| row << 1 row.concat [2, 3, 4] row << 5 end - end - string.should eq("1,2,3,4,5\n") + end, "1,2,3,4,5\n") end it "concats splat to row" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row do |row| row << 1 row.concat 2, 3, 4 row << 5 end - end - string.should eq("1,2,3,4,5\n") + end, "1,2,3,4,5\n") end it "builds with commas" do - string = CSV.build do |csv| + assert_prints(CSV.build do |csv| csv.row do |row| row << " , " row << " , " end - end - string.should eq(%(" , "," , "\n)) + end, %(" , "," , "\n)) end it "builds with quoting" do - string = CSV.build(quoting: CSV::Builder::Quoting::NONE) do |csv| + assert_prints(CSV.build(quoting: CSV::Builder::Quoting::NONE) do |csv| csv.row 1, "doesn't", " , ", %(he said "no") - end - string.should eq(%(1,doesn't, , ,he said "no"\n)) + end, %(1,doesn't, , ,he said "no"\n)) - string = CSV.build(quoting: CSV::Builder::Quoting::RFC) do |csv| + assert_prints(CSV.build(quoting: CSV::Builder::Quoting::RFC) do |csv| csv.row 1, "doesn't", " , ", %(he said "no") - end - string.should eq(%(1,doesn't," , ","he said ""no"""\n)) + end, %(1,doesn't," , ","he said ""no"""\n)) - string = CSV.build(quoting: CSV::Builder::Quoting::ALL) do |csv| + assert_prints(CSV.build(quoting: CSV::Builder::Quoting::ALL) do |csv| csv.row 1, "doesn't", " , ", %(he said "no") - end - string.should eq(%("1","doesn't"," , ","he said ""no"""\n)) + end, %("1","doesn't"," , ","he said ""no"""\n)) end it "builds with inside quoted chars and symbols" do - string = CSV.build(quoting: CSV::Builder::Quoting::NONE) do |csv| + assert_prints(CSV.build(quoting: CSV::Builder::Quoting::NONE) do |csv| csv.row 'c', '\'', '"', :sym, :"s'm", :"s\"m" - end - string.should eq(%(c,',",sym,s'm,s"m\n)) + end, %(c,',",sym,s'm,s"m\n)) - string = CSV.build(quoting: CSV::Builder::Quoting::RFC) do |csv| + assert_prints(CSV.build(quoting: CSV::Builder::Quoting::RFC) do |csv| csv.row 'c', '\'', '"', :sym, :"s'm", :"s\"m" - end - string.should eq(%(c,',"""",sym,s'm,"s""m"\n)) + end, %(c,',"""",sym,s'm,"s""m"\n)) - string = CSV.build(quoting: CSV::Builder::Quoting::ALL) do |csv| + assert_prints(CSV.build(quoting: CSV::Builder::Quoting::ALL) do |csv| csv.row 'c', '\'', '"', :sym, :"s'm", :"s\"m" - end - string.should eq(%("c","'","""","sym","s'm","s""m"\n)) + end, %("c","'","""","sym","s'm","s""m"\n)) end end end diff --git a/spec/std/http/http_spec.cr b/spec/std/http/http_spec.cr index d89cebb31032..6d23b9356cd6 100644 --- a/spec/std/http/http_spec.cr +++ b/spec/std/http/http_spec.cr @@ -1,5 +1,14 @@ require "spec" require "http" +require "../../support/string" + +private def http_quote_string(io : IO, string) + HTTP.quote_string(string, io) +end + +private def http_quote_string(string) + HTTP.quote_string(string) +end describe HTTP do it "parses RFC 1123" do @@ -57,10 +66,10 @@ describe HTTP do describe ".quote_string" do it "quotes a string" do - HTTP.quote_string("foo!#():;?~").should eq("foo!#():;?~") - HTTP.quote_string(%q(foo"bar\baz)).should eq(%q(foo\"bar\\baz)) - HTTP.quote_string("\t ").should eq("\\\t\\ ") - HTTP.quote_string("it works ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚๐Ÿ‘Œ๐Ÿ‘Œ๐Ÿ‘Œ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚").should eq("it\\ works\\ ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚๐Ÿ‘Œ๐Ÿ‘Œ๐Ÿ‘Œ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚") + assert_prints http_quote_string("foo!#():;?~"), "foo!#():;?~" + assert_prints http_quote_string(%q(foo"bar\baz)), %q(foo\"bar\\baz) + assert_prints http_quote_string("\t "), "\\\t\\ " + assert_prints http_quote_string("it works ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚๐Ÿ‘Œ๐Ÿ‘Œ๐Ÿ‘Œ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚"), "it\\ works\\ ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚๐Ÿ‘Œ๐Ÿ‘Œ๐Ÿ‘Œ๐Ÿ˜‚๐Ÿ˜‚๐Ÿ˜‚" end it "raises on invalid characters" do diff --git a/spec/std/mime/media_type_spec.cr b/spec/std/mime/media_type_spec.cr index f1a00ef70ad4..aa5deedb90f1 100644 --- a/spec/std/mime/media_type_spec.cr +++ b/spec/std/mime/media_type_spec.cr @@ -1,5 +1,6 @@ require "../spec_helper" require "mime/media_type" +require "../../support/string" private def parse(string) type = MIME::MediaType.parse(string) @@ -8,7 +9,7 @@ private def parse(string) end private def assert_format(string, format = string, file = __FILE__, line = __LINE__) - MIME::MediaType.parse(string).to_s.should eq(format), file: file, line: line + assert_prints MIME::MediaType.parse(string).to_s, format, file: file, line: line end describe MIME::MediaType do diff --git a/spec/std/time/format_spec.cr b/spec/std/time/format_spec.cr index ddcb581beed4..f0987921b7ca 100644 --- a/spec/std/time/format_spec.cr +++ b/spec/std/time/format_spec.cr @@ -1,4 +1,5 @@ require "./spec_helper" +require "../../support/string" def parse_time(format, string) Time.parse_utc(format, string) @@ -15,123 +16,123 @@ describe Time::Format do t2 = Time.utc 2014, 1, 2, 15, 4, 5, nanosecond: 6_000_000 t3 = Time.utc 2014, 1, 2, 12, 4, 5, nanosecond: 6_000_000 - t.to_s("%Y").should eq("2014") - Time.utc(1, 1, 2, 3, 4, 5, nanosecond: 6).to_s("%Y").should eq("0001") - - t.to_s("%C").should eq("20") - t.to_s("%y").should eq("14") - t.to_s("%m").should eq("01") - t.to_s("%_m").should eq(" 1") - t.to_s("%_%_m2").should eq("%_ 12") - t.to_s("%-m").should eq("1") - t.to_s("%-%-m2").should eq("%-12") - t.to_s("%B").should eq("January") - t.to_s("%^B").should eq("JANUARY") - t.to_s("%^%^B2").should eq("%^JANUARY2") - t.to_s("%b").should eq("Jan") - t.to_s("%^b").should eq("JAN") - t.to_s("%h").should eq("Jan") - t.to_s("%^h").should eq("JAN") - t.to_s("%d").should eq("02") - t.to_s("%-d").should eq("2") - t.to_s("%e").should eq(" 2") - t.to_s("%j").should eq("002") - t.to_s("%H").should eq("03") - - t.to_s("%k").should eq(" 3") - t2.to_s("%k").should eq("15") - - t.to_s("%I").should eq("03") - t2.to_s("%I").should eq("03") - t3.to_s("%I").should eq("12") - - t.to_s("%l").should eq(" 3") - t2.to_s("%l").should eq(" 3") - t3.to_s("%l").should eq("12") + assert_prints t.to_s("%Y"), "2014" + assert_prints Time.utc(1, 1, 2, 3, 4, 5, nanosecond: 6).to_s("%Y"), "0001" + + assert_prints t.to_s("%C"), "20" + assert_prints t.to_s("%y"), "14" + assert_prints t.to_s("%m"), "01" + assert_prints t.to_s("%_m"), " 1" + assert_prints t.to_s("%_%_m2"), "%_ 12" + assert_prints t.to_s("%-m"), "1" + assert_prints t.to_s("%-%-m2"), "%-12" + assert_prints t.to_s("%B"), "January" + assert_prints t.to_s("%^B"), "JANUARY" + assert_prints t.to_s("%^%^B2"), "%^JANUARY2" + assert_prints t.to_s("%b"), "Jan" + assert_prints t.to_s("%^b"), "JAN" + assert_prints t.to_s("%h"), "Jan" + assert_prints t.to_s("%^h"), "JAN" + assert_prints t.to_s("%d"), "02" + assert_prints t.to_s("%-d"), "2" + assert_prints t.to_s("%e"), " 2" + assert_prints t.to_s("%j"), "002" + assert_prints t.to_s("%H"), "03" + + assert_prints t.to_s("%k"), " 3" + assert_prints t2.to_s("%k"), "15" + + assert_prints t.to_s("%I"), "03" + assert_prints t2.to_s("%I"), "03" + assert_prints t3.to_s("%I"), "12" + + assert_prints t.to_s("%l"), " 3" + assert_prints t2.to_s("%l"), " 3" + assert_prints t3.to_s("%l"), "12" # Note: we purposely match %p to am/pm and %P to AM/PM (makes more sense) - t.to_s("%p").should eq("am") - t2.to_s("%p").should eq("pm") - - t.to_s("%P").should eq("AM") - t2.to_s("%P").should eq("PM") - - t.to_s("%M").to_s.should eq("04") - t.to_s("%S").to_s.should eq("05") - t.to_s("%L").to_s.should eq("006") - t.to_s("%N").to_s.should eq("006000000") - t.to_s("%3N").to_s.should eq("006") - t.to_s("%6N").to_s.should eq("006000") - t.to_s("%9N").to_s.should eq("006000000") - - t.to_s("%z").should eq("+0000") - t.to_s("%:z").should eq("+00:00") - t.to_s("%::z").should eq("+00:00:00") - t.to_s("%^Z").should eq("UTC") - t.to_s("%Z").should eq("UTC") + assert_prints t.to_s("%p"), "am" + assert_prints t2.to_s("%p"), "pm" + + assert_prints t.to_s("%P"), "AM" + assert_prints t2.to_s("%P"), "PM" + + assert_prints t.to_s("%M"), "04" + assert_prints t.to_s("%S"), "05" + assert_prints t.to_s("%L"), "006" + assert_prints t.to_s("%N"), "006000000" + assert_prints t.to_s("%3N"), "006" + assert_prints t.to_s("%6N"), "006000" + assert_prints t.to_s("%9N"), "006000000" + + assert_prints t.to_s("%z"), "+0000" + assert_prints t.to_s("%:z"), "+00:00" + assert_prints t.to_s("%::z"), "+00:00:00" + assert_prints t.to_s("%^Z"), "UTC" + assert_prints t.to_s("%Z"), "UTC" with_zoneinfo do zoned = Time.local(2017, 11, 24, 13, 5, 6, location: Time::Location.load("Europe/Berlin")) - zoned.to_s("%z").should eq("+0100") - zoned.to_s("%:z").should eq("+01:00") - zoned.to_s("%::z").should eq("+01:00:00") - zoned.to_s("%^Z").should eq("CET") - zoned.to_s("%Z").should eq("Europe/Berlin") + assert_prints zoned.to_s("%z"), "+0100" + assert_prints zoned.to_s("%:z"), "+01:00" + assert_prints zoned.to_s("%::z"), "+01:00:00" + assert_prints zoned.to_s("%^Z"), "CET" + assert_prints zoned.to_s("%Z"), "Europe/Berlin" zoned = Time.local(2017, 11, 24, 13, 5, 6, location: Time::Location.load("America/Buenos_Aires")) - zoned.to_s("%z").should eq("-0300") - zoned.to_s("%:z").should eq("-03:00") - zoned.to_s("%::z").should eq("-03:00:00") - zoned.to_s("%^Z").should eq("-03") - zoned.to_s("%Z").should eq("America/Buenos_Aires") + assert_prints zoned.to_s("%z"), "-0300" + assert_prints zoned.to_s("%:z"), "-03:00" + assert_prints zoned.to_s("%::z"), "-03:00:00" + assert_prints zoned.to_s("%^Z"), "-03" + assert_prints zoned.to_s("%Z"), "America/Buenos_Aires" end offset = Time.local(2017, 11, 24, 13, 5, 6, location: Time::Location.fixed(9000)) - offset.to_s("%z").should eq("+0230") - offset.to_s("%:z").should eq("+02:30") - offset.to_s("%::z").should eq("+02:30:00") - offset.to_s("%^Z").should eq("+02:30") - offset.to_s("%Z").should eq("+02:30") + assert_prints offset.to_s("%z"), "+0230" + assert_prints offset.to_s("%:z"), "+02:30" + assert_prints offset.to_s("%::z"), "+02:30:00" + assert_prints offset.to_s("%^Z"), "+02:30" + assert_prints offset.to_s("%Z"), "+02:30" offset = Time.local(2017, 11, 24, 13, 5, 6, location: Time::Location.fixed(9001)) - offset.to_s("%z").should eq("+0230") - offset.to_s("%:z").should eq("+02:30") - offset.to_s("%::z").should eq("+02:30:01") - offset.to_s("%^Z").should eq("+02:30:01") - offset.to_s("%Z").should eq("+02:30:01") - - t.to_s("%A").to_s.should eq("Thursday") - t.to_s("%^A").to_s.should eq("THURSDAY") - t.to_s("%a").to_s.should eq("Thu") - t.to_s("%^a").to_s.should eq("THU") - t.to_s("%u").to_s.should eq("4") - t.to_s("%w").to_s.should eq("4") - - t3 = Time.utc 2014, 1, 5 # A Sunday - t3.to_s("%u").to_s.should eq("7") - t3.to_s("%w").to_s.should eq("0") - - Time.utc(1985, 4, 12).to_s("%G-W%V-%u").should eq "1985-W15-5" - Time.utc(2005, 1, 1).to_s("%G-W%V-%u").should eq "2004-W53-6" - Time.utc(2005, 1, 2).to_s("%G-W%V-%u").should eq "2004-W53-7" - Time.utc(2005, 12, 31).to_s("%G-W%V-%u").should eq "2005-W52-6" - Time.utc(2006, 1, 1).to_s("%G-W%V-%u").should eq "2005-W52-7" - Time.utc(2006, 1, 2).to_s("%G-W%V-%u").should eq "2006-W01-1" - Time.utc(2006, 12, 31).to_s("%G-W%V-%u").should eq "2006-W52-7" - Time.utc(2007, 1, 1).to_s("%G-W%V-%u").should eq "2007-W01-1" - Time.utc(2007, 12, 30).to_s("%G-W%V-%u").should eq "2007-W52-7" - Time.utc(2007, 12, 31).to_s("%G-W%V-%u").should eq "2008-W01-1" - Time.utc(2008, 1, 1).to_s("%G-W%V-%u").should eq "2008-W01-2" - Time.utc(2008, 12, 28).to_s("%G-W%V-%u").should eq "2008-W52-7" - Time.utc(2008, 12, 29).to_s("%G-W%V-%u").should eq "2009-W01-1" - Time.utc(2008, 12, 30).to_s("%G-W%V-%u").should eq "2009-W01-2" - Time.utc(2008, 12, 31).to_s("%G-W%V-%u").should eq "2009-W01-3" - Time.utc(2009, 1, 1).to_s("%G-W%V-%u").should eq "2009-W01-4" - Time.utc(2009, 12, 31).to_s("%G-W%V-%u").should eq "2009-W53-4" - Time.utc(2010, 1, 1).to_s("%G-W%V-%u").should eq "2009-W53-5" - Time.utc(2010, 1, 2).to_s("%G-W%V-%u").should eq "2009-W53-6" - Time.utc(2010, 1, 3).to_s("%G-W%V-%u").should eq "2009-W53-7" - Time.utc(1985, 4, 12).to_s("%g-W%V-%u").should eq "85-W15-5" + assert_prints offset.to_s("%z"), "+0230" + assert_prints offset.to_s("%:z"), "+02:30" + assert_prints offset.to_s("%::z"), "+02:30:01" + assert_prints offset.to_s("%^Z"), "+02:30:01" + assert_prints offset.to_s("%Z"), "+02:30:01" + + assert_prints t.to_s("%A"), "Thursday" + assert_prints t.to_s("%^A"), "THURSDAY" + assert_prints t.to_s("%a"), "Thu" + assert_prints t.to_s("%^a"), "THU" + assert_prints t.to_s("%u"), "4" + assert_prints t.to_s("%w"), "4" + + t4 = Time.utc 2014, 1, 5 # A Sunday + assert_prints t4.to_s("%u"), "7" + assert_prints t4.to_s("%w"), "0" + + assert_prints Time.utc(1985, 4, 12).to_s("%G-W%V-%u"), "1985-W15-5" + assert_prints Time.utc(2005, 1, 1).to_s("%G-W%V-%u"), "2004-W53-6" + assert_prints Time.utc(2005, 1, 2).to_s("%G-W%V-%u"), "2004-W53-7" + assert_prints Time.utc(2005, 12, 31).to_s("%G-W%V-%u"), "2005-W52-6" + assert_prints Time.utc(2006, 1, 1).to_s("%G-W%V-%u"), "2005-W52-7" + assert_prints Time.utc(2006, 1, 2).to_s("%G-W%V-%u"), "2006-W01-1" + assert_prints Time.utc(2006, 12, 31).to_s("%G-W%V-%u"), "2006-W52-7" + assert_prints Time.utc(2007, 1, 1).to_s("%G-W%V-%u"), "2007-W01-1" + assert_prints Time.utc(2007, 12, 30).to_s("%G-W%V-%u"), "2007-W52-7" + assert_prints Time.utc(2007, 12, 31).to_s("%G-W%V-%u"), "2008-W01-1" + assert_prints Time.utc(2008, 1, 1).to_s("%G-W%V-%u"), "2008-W01-2" + assert_prints Time.utc(2008, 12, 28).to_s("%G-W%V-%u"), "2008-W52-7" + assert_prints Time.utc(2008, 12, 29).to_s("%G-W%V-%u"), "2009-W01-1" + assert_prints Time.utc(2008, 12, 30).to_s("%G-W%V-%u"), "2009-W01-2" + assert_prints Time.utc(2008, 12, 31).to_s("%G-W%V-%u"), "2009-W01-3" + assert_prints Time.utc(2009, 1, 1).to_s("%G-W%V-%u"), "2009-W01-4" + assert_prints Time.utc(2009, 12, 31).to_s("%G-W%V-%u"), "2009-W53-4" + assert_prints Time.utc(2010, 1, 1).to_s("%G-W%V-%u"), "2009-W53-5" + assert_prints Time.utc(2010, 1, 2).to_s("%G-W%V-%u"), "2009-W53-6" + assert_prints Time.utc(2010, 1, 3).to_s("%G-W%V-%u"), "2009-W53-7" + assert_prints Time.utc(1985, 4, 12).to_s("%g-W%V-%u"), "85-W15-5" # TODO %U # TODO %W # TODO %s @@ -139,48 +140,48 @@ describe Time::Format do # TODO %t # TODO %% - t.to_s("%%").should eq("%") - t.to_s("%c").should eq(t.to_s("%a %b %e %T %Y")) - t.to_s("%D").should eq(t.to_s("%m/%d/%y")) - t.to_s("%F").should eq(t.to_s("%Y-%m-%d")) + assert_prints t.to_s("%%"), "%" + assert_prints t.to_s("%c"), t.to_s("%a %b %e %T %Y") + assert_prints t.to_s("%D"), t.to_s("%m/%d/%y") + assert_prints t.to_s("%F"), t.to_s("%Y-%m-%d") # TODO %v - t.to_s("%x").should eq(t.to_s("%D")) - t.to_s("%X").should eq(t.to_s("%T")) - t.to_s("%r").should eq(t.to_s("%I:%M:%S %P")) - t.to_s("%R").should eq(t.to_s("%H:%M")) - t.to_s("%T").should eq(t.to_s("%H:%M:%S")) + assert_prints t.to_s("%x"), t.to_s("%D") + assert_prints t.to_s("%X"), t.to_s("%T") + assert_prints t.to_s("%r"), t.to_s("%I:%M:%S %P") + assert_prints t.to_s("%R"), t.to_s("%H:%M") + assert_prints t.to_s("%T"), t.to_s("%H:%M:%S") - t.to_s("%Y-%m-hello").should eq("2014-01-hello") + assert_prints t.to_s("%Y-%m-hello"), "2014-01-hello" - t = Time.utc 2014, 1, 2, 3, 4, 5, nanosecond: 6 - t.to_s("%s").should eq("1388631845") + t5 = Time.utc 2014, 1, 2, 3, 4, 5, nanosecond: 6 + assert_prints t5.to_s("%s"), "1388631845" end end it "formats standard formats" do time = Time.utc(2016, 2, 15) - time.to_rfc3339.should eq "2016-02-15T00:00:00Z" + assert_prints time.to_rfc3339, "2016-02-15T00:00:00Z" Time.parse_rfc3339(time.to_rfc3339).should eq time - time.to_rfc2822.should eq "Mon, 15 Feb 2016 00:00:00 +0000" + assert_prints time.to_rfc2822, "Mon, 15 Feb 2016 00:00:00 +0000" Time.parse_rfc2822(time.to_rfc2822).should eq time end it "formats rfc3339 with different fraction digits" do time = Time.utc(2016, 2, 15, 8, 23, 45, nanosecond: 123456789) - time.to_rfc3339.should eq "2016-02-15T08:23:45Z" - time.to_rfc3339(fraction_digits: 0).should eq "2016-02-15T08:23:45Z" - time.to_rfc3339(fraction_digits: 3).should eq "2016-02-15T08:23:45.123Z" - time.to_rfc3339(fraction_digits: 6).should eq "2016-02-15T08:23:45.123456Z" - time.to_rfc3339(fraction_digits: 9).should eq "2016-02-15T08:23:45.123456789Z" + assert_prints time.to_rfc3339, "2016-02-15T08:23:45Z" + assert_prints time.to_rfc3339(fraction_digits: 0), "2016-02-15T08:23:45Z" + assert_prints time.to_rfc3339(fraction_digits: 3), "2016-02-15T08:23:45.123Z" + assert_prints time.to_rfc3339(fraction_digits: 6), "2016-02-15T08:23:45.123456Z" + assert_prints time.to_rfc3339(fraction_digits: 9), "2016-02-15T08:23:45.123456789Z" expect_raises(ArgumentError, "Invalid fraction digits: 5") { time.to_rfc3339(fraction_digits: 5) } expect_raises(ArgumentError, "Invalid fraction digits: -1") { time.to_rfc3339(fraction_digits: -1) } time = Time.utc(2016, 2, 15, 8, 23, 45) - time.to_rfc3339.should eq "2016-02-15T08:23:45Z" - time.to_rfc3339(fraction_digits: 0).should eq "2016-02-15T08:23:45Z" - time.to_rfc3339(fraction_digits: 3).should eq "2016-02-15T08:23:45.000Z" - time.to_rfc3339(fraction_digits: 6).should eq "2016-02-15T08:23:45.000000Z" - time.to_rfc3339(fraction_digits: 9).should eq "2016-02-15T08:23:45.000000000Z" + assert_prints time.to_rfc3339, "2016-02-15T08:23:45Z" + assert_prints time.to_rfc3339(fraction_digits: 0), "2016-02-15T08:23:45Z" + assert_prints time.to_rfc3339(fraction_digits: 3), "2016-02-15T08:23:45.000Z" + assert_prints time.to_rfc3339(fraction_digits: 6), "2016-02-15T08:23:45.000000Z" + assert_prints time.to_rfc3339(fraction_digits: 9), "2016-02-15T08:23:45.000000000Z" end it "parses empty" do diff --git a/spec/std/uri_spec.cr b/spec/std/uri_spec.cr index a2c973548d7b..f14165a27b54 100644 --- a/spec/std/uri_spec.cr +++ b/spec/std/uri_spec.cr @@ -1,5 +1,6 @@ require "spec" require "uri" +require "../support/string" private def assert_uri(string, file = __FILE__, line = __LINE__, **args) it "`#{string}`", file, line do @@ -8,45 +9,22 @@ private def assert_uri(string, file = __FILE__, line = __LINE__, **args) end end -private def it_encodes(string, expected_result, file = __FILE__, line = __LINE__, **options) - it "encodes #{string.inspect}", file, line do - URI.encode(string, **options).should eq(expected_result), file: file, line: line - - String.build do |io| - URI.encode(string, io, **options) - end.should eq(expected_result), file: file, line: line +# rearrange parameters for `assert_prints` +{% for method in %w(encode encode_www_form decode decode_www_form) %} + private def uri_{{ method.id }}(string, **options) + URI.{{ method.id }}(string, **options) end -end - -private def it_decodes(string, expected_result, file = __FILE__, line = __LINE__, **options) - it "decodes #{string.inspect}", file, line do - URI.decode(string, **options).should eq(expected_result), file: file, line: line - String.build do |io| - URI.decode(string, io, **options) - end.should eq(expected_result), file: file, line: line + private def uri_{{ method.id }}(io : IO, string, **options) + URI.{{ method.id }}(string, io, **options) end -end - -private def it_encodes_www_form(string, expected_result, file = __FILE__, line = __LINE__, **options) - it "encodes #{string.inspect}", file, line do - URI.encode_www_form(string, **options).should eq(expected_result), file: file, line: line - String.build do |io| - URI.encode_www_form(string, io, **options) - end.should eq(expected_result), file: file, line: line - end -end - -private def it_decodes_www_form(string, expected_result, file = __FILE__, line = __LINE__, **options) - it "decodes #{string.inspect}", file, line do - URI.decode_www_form(string, **options).should eq(expected_result), file: file, line: line - - String.build do |io| - URI.decode_www_form(string, io, **options) - end.should eq(expected_result), file: file, line: line + private def it_{{ method.gsub(/code/, "codes").id }}(string, expected_result, file = __FILE__, line = __LINE__, **options) + it "{{ method[0...6].id }}s #{string.inspect}", file: file, line: line do + assert_prints uri_{{ method.id }}(string, **options), expected_result, file: file, line: line + end end -end +{% end %} # This helper method is used in the specs for #relativize and also ensures the # reversibility of #relativize and #resolve. @@ -311,39 +289,39 @@ describe "URI" do end describe "#to_s" do - it { URI.new("http", "www.example.com").to_s.should eq("http://www.example.com") } - it { URI.new("http", "www.example.com", 80).to_s.should eq("http://www.example.com:80") } - it { URI.new("http", "www.example.com", user: "alice").to_s.should eq("http://alice@www.example.com") } - it { URI.new("http", "www.example.com", user: "alice", password: "s3cr3t").to_s.should eq("http://alice:s3cr3t@www.example.com") } - it { URI.new("http", "www.example.com", user: ":D").to_s.should eq("http://%3AD@www.example.com") } - it { URI.new("http", "www.example.com", user: ":D", password: "@_@").to_s.should eq("http://%3AD:%40_%40@www.example.com") } - it { URI.new("http", "www.example.com", user: "@al:ce", password: "s/cr3t").to_s.should eq("http://%40al%3Ace:s%2Fcr3t@www.example.com") } - it { URI.new("http", "www.example.com", fragment: "top").to_s.should eq("http://www.example.com#top") } - it { URI.new("http", "www.example.com", 80, "/hello").to_s.should eq("http://www.example.com:80/hello") } - it { URI.new("http", "www.example.com", 80, "/hello", "a=1").to_s.should eq("http://www.example.com:80/hello?a=1") } - it { URI.new("mailto", path: "foo@example.com").to_s.should eq("mailto:foo@example.com") } - it { URI.new("file", path: "/foo.html").to_s.should eq("file:/foo.html") } - it { URI.new("file", path: "foo.html").to_s.should eq("file:foo.html") } - it { URI.new("file", host: "host", path: "foo.html").to_s.should eq("file://host/foo.html") } - it { URI.new(path: "//foo").to_s.should eq("/.//foo") } - it { URI.new(host: "host", path: "//foo").to_s.should eq("//host//foo") } + it { assert_prints URI.new("http", "www.example.com").to_s, "http://www.example.com" } + it { assert_prints URI.new("http", "www.example.com", 80).to_s, "http://www.example.com:80" } + it { assert_prints URI.new("http", "www.example.com", user: "alice").to_s, "http://alice@www.example.com" } + it { assert_prints URI.new("http", "www.example.com", user: "alice", password: "s3cr3t").to_s, "http://alice:s3cr3t@www.example.com" } + it { assert_prints URI.new("http", "www.example.com", user: ":D").to_s, "http://%3AD@www.example.com" } + it { assert_prints URI.new("http", "www.example.com", user: ":D", password: "@_@").to_s, "http://%3AD:%40_%40@www.example.com" } + it { assert_prints URI.new("http", "www.example.com", user: "@al:ce", password: "s/cr3t").to_s, "http://%40al%3Ace:s%2Fcr3t@www.example.com" } + it { assert_prints URI.new("http", "www.example.com", fragment: "top").to_s, "http://www.example.com#top" } + it { assert_prints URI.new("http", "www.example.com", 80, "/hello").to_s, "http://www.example.com:80/hello" } + it { assert_prints URI.new("http", "www.example.com", 80, "/hello", "a=1").to_s, "http://www.example.com:80/hello?a=1" } + it { assert_prints URI.new("mailto", path: "foo@example.com").to_s, "mailto:foo@example.com" } + it { assert_prints URI.new("file", path: "/foo.html").to_s, "file:/foo.html" } + it { assert_prints URI.new("file", path: "foo.html").to_s, "file:foo.html" } + it { assert_prints URI.new("file", host: "host", path: "foo.html").to_s, "file://host/foo.html" } + it { assert_prints URI.new(path: "//foo").to_s, "/.//foo" } + it { assert_prints URI.new(host: "host", path: "//foo").to_s, "//host//foo" } it "preserves non-default port" do - URI.new("http", "www.example.com", 1234).to_s.should eq("http://www.example.com:1234") - URI.new("https", "www.example.com", 1234).to_s.should eq("https://www.example.com:1234") - URI.new("ftp", "www.example.com", 1234).to_s.should eq("ftp://www.example.com:1234") - URI.new("sftp", "www.example.com", 1234).to_s.should eq("sftp://www.example.com:1234") - URI.new("ldap", "www.example.com", 1234).to_s.should eq("ldap://www.example.com:1234") - URI.new("ldaps", "www.example.com", 1234).to_s.should eq("ldaps://www.example.com:1234") + assert_prints URI.new("http", "www.example.com", 1234).to_s, "http://www.example.com:1234" + assert_prints URI.new("https", "www.example.com", 1234).to_s, "https://www.example.com:1234" + assert_prints URI.new("ftp", "www.example.com", 1234).to_s, "ftp://www.example.com:1234" + assert_prints URI.new("sftp", "www.example.com", 1234).to_s, "sftp://www.example.com:1234" + assert_prints URI.new("ldap", "www.example.com", 1234).to_s, "ldap://www.example.com:1234" + assert_prints URI.new("ldaps", "www.example.com", 1234).to_s, "ldaps://www.example.com:1234" end it "preserves port for unknown scheme" do - URI.new("xyz", "www.example.com").to_s.should eq("xyz://www.example.com") - URI.new("xyz", "www.example.com", 1234).to_s.should eq("xyz://www.example.com:1234") + assert_prints URI.new("xyz", "www.example.com").to_s, "xyz://www.example.com" + assert_prints URI.new("xyz", "www.example.com", 1234).to_s, "xyz://www.example.com:1234" end it "preserves port for nil scheme" do - URI.new(nil, "www.example.com", 1234).to_s.should eq("//www.example.com:1234") + assert_prints URI.new(nil, "www.example.com", 1234).to_s, "//www.example.com:1234" end end diff --git a/spec/support/string.cr b/spec/support/string.cr index fa04bf25c077..0aa9d988d9c1 100644 --- a/spec/support/string.cr +++ b/spec/support/string.cr @@ -43,8 +43,8 @@ macro assert_prints(call, str, *, file = __FILE__, line = __LINE__) String.build do |io| {% if call.receiver %}{{ call.receiver }}.{% end %}{{ call.name }}( io, - {% for arg in call.args %} ({{ arg }}), {% end %} - {% if call.named_args %} {% for narg in call.named_args %} {{ narg.name }}: ({{ narg.value }}), {% end %} {% end %} + {% for arg in call.args %} {{ arg }}, {% end %} + {% if call.named_args %} {% for narg in call.named_args %} {{ narg.name }}: {{ narg.value }}, {% end %} {% end %} ) {{ call.block }} end.should eq(%str), file: %file, line: %line @@ -52,8 +52,8 @@ macro assert_prints(call, str, *, file = __FILE__, line = __LINE__) string_build_via_utf16 do |io| {% if call.receiver %}{{ call.receiver }}.{% end %}{{ call.name }}( io, - {% for arg in call.args %} ({{ arg }}), {% end %} - {% if call.named_args %} {% for narg in call.named_args %} {{ narg.name }}: ({{ narg.value }}), {% end %} {% end %} + {% for arg in call.args %} {{ arg }}, {% end %} + {% if call.named_args %} {% for narg in call.named_args %} {{ narg.name }}: {{ narg.value }}, {% end %} {% end %} ) {{ call.block }} end.should eq(%str), file: %file, line: %line {% end %} diff --git a/src/base64.cr b/src/base64.cr index 36bb482d5634..677e8326ee14 100644 --- a/src/base64.cr +++ b/src/base64.cr @@ -61,7 +61,7 @@ module Base64 def encode(data, io : IO) count = 0 encode_with_new_lines(data.to_slice) do |byte| - io.write_byte byte + io << byte.unsafe_chr count += 1 end io.flush @@ -123,7 +123,7 @@ module Base64 count = 0 to_base64(data.to_slice, alphabet, pad: pad) do |byte| count += 1 - io.write_byte byte + io << byte.unsafe_chr end io.flush count diff --git a/src/csv/builder.cr b/src/csv/builder.cr index 49410f9647ac..9a9c1457b263 100644 --- a/src/csv/builder.cr +++ b/src/csv/builder.cr @@ -84,12 +84,12 @@ class CSV::Builder def quote_cell(value : String) append_cell do @io << @quote_char - value.each_byte do |byte| - case byte + value.each_char do |char| + case char when @quote_char @io << @quote_char << @quote_char else - @io.write_byte byte + @io << char end end @io << @quote_char diff --git a/src/http/common.cr b/src/http/common.cr index 18a3a062467d..1a3691de8e4c 100644 --- a/src/http/common.cr +++ b/src/http/common.cr @@ -412,16 +412,16 @@ module HTTP def self.quote_string(string, io) : Nil # Escaping rules: https://evolvis.org/pipermail/evolvis-platfrm-discuss/2014-November/000675.html - string.each_byte do |byte| - case byte - when '\t'.ord, ' '.ord, '"'.ord, '\\'.ord + string.each_char do |char| + case char + when '\t', ' ', '"', '\\' io << '\\' - when 0x00..0x1F, 0x7F - raise ArgumentError.new("String contained invalid character #{byte.chr.inspect}") + when '\u{00}'..'\u{1F}', '\u{7F}' + raise ArgumentError.new("String contained invalid character #{char.inspect}") else # output byte as is end - io.write_byte byte + io << char end end diff --git a/src/mime/media_type.cr b/src/mime/media_type.cr index 3db89f1b5c45..939433c03acf 100644 --- a/src/mime/media_type.cr +++ b/src/mime/media_type.cr @@ -494,16 +494,16 @@ module MIME # :nodoc: def self.quote_string(string, io) : Nil - string.each_byte do |byte| - case byte - when '"'.ord, '\\'.ord + string.each_char do |char| + case char + when '"', '\\' io << '\\' - when 0x00..0x1F, 0x7F - raise ArgumentError.new("String contained invalid character #{byte.chr.inspect}") + when '\u{00}'..'\u{1F}', '\u{7F}' + raise ArgumentError.new("String contained invalid character #{char.inspect}") else # leave the byte as is end - io.write_byte byte + io << char end end end diff --git a/src/time/format/formatter.cr b/src/time/format/formatter.cr index 3eafed806857..982183673e1e 100644 --- a/src/time/format/formatter.cr +++ b/src/time/format/formatter.cr @@ -255,30 +255,30 @@ struct Time::Format end def pad2(value, padding) : Nil - io.write_byte padding.ord.to_u8 if value < 10 + io << padding if value < 10 io << value end def pad3(value, padding) : Nil - io.write_byte padding.ord.to_u8 if value < 100 + io << padding if value < 100 pad2 value, padding end def pad4(value, padding) : Nil - io.write_byte padding.ord.to_u8 if value < 1000 + io << padding if value < 1000 pad3 value, padding end def pad6(value, padding) : Nil - io.write_byte padding.ord.to_u8 if value < 100000 - io.write_byte padding.ord.to_u8 if value < 10000 + io << padding if value < 100000 + io << padding if value < 10000 pad4 value, padding end def pad9(value, padding) : Nil - io.write_byte padding.ord.to_u8 if value < 100000000 - io.write_byte padding.ord.to_u8 if value < 10000000 - io.write_byte padding.ord.to_u8 if value < 1000000 + io << padding if value < 100000000 + io << padding if value < 10000000 + io << padding if value < 1000000 pad6 value, padding end end diff --git a/src/uri/encoding.cr b/src/uri/encoding.cr index 3f241c0916c1..0ec14ec3131f 100644 --- a/src/uri/encoding.cr +++ b/src/uri/encoding.cr @@ -191,12 +191,15 @@ class URI def self.decode(string : String, io : IO, *, plus_to_space : Bool = false, &block) : Nil i = 0 bytesize = string.bytesize + buffer = IO::Memory.new(bytesize) + while i < bytesize byte = string.to_unsafe[i] char = byte.unsafe_chr - i = decode_one(string, bytesize, i, byte, char, io, plus_to_space) { |byte| yield byte } + i = decode_one(string, bytesize, i, byte, char, buffer, plus_to_space) { |byte| yield byte } end - io + + io.write_string(buffer.to_slice) end # URL-encodes *string* and writes the result to an `IO`. @@ -216,12 +219,12 @@ class URI string.each_byte do |byte| char = byte.unsafe_chr if char == ' ' && space_to_plus - io.write_byte '+'.ord.to_u8 + io << '+' elsif char.ascii? && yield(byte) && (!space_to_plus || char != '+') - io.write_byte byte + io << char else - io.write_byte '%'.ord.to_u8 - io.write_byte '0'.ord.to_u8 if byte < 16 + io << '%' + io << '0' if byte < 16 byte.to_s(io, 16, upcase: true) end end