require "spec" require "mime/multipart" describe MIME::Multipart::Builder do it "generates valid multipart messages" do io = IO::Memory.new builder = MIME::Multipart::Builder.new(io, "fixed-boundary") headers = HTTP::Headers{"X-Foo" => "bar"} builder.body_part headers, "body part 1" headers = HTTP::Headers{"X-Type" => "Empty-Body", "X-Foo" => "Bar"} builder.body_part headers builder.finish expected_message = <<-MULTIPART --fixed-boundary X-Foo: bar body part 1 --fixed-boundary X-Type: Empty-Body X-Foo: Bar --fixed-boundary-- MULTIPART io.to_s.should eq(expected_message.gsub('\n', "\r\n")) end it "generates valid multipart messages with preamble and epilogue" do io = IO::Memory.new builder = MIME::Multipart::Builder.new(io, "fixed-boundary") builder.preamble "Here is a preamble to explain why multipart/mixed " builder.preamble "exists and why your mail client should support it" headers = HTTP::Headers{"X-Foo" => "bar"} builder.body_part headers, "body part 1" headers = HTTP::Headers{"X-Type" => "Empty-Body", "X-Foo" => "Bar"} builder.body_part headers builder.epilogue "Irrelevant text" builder.epilogue "Much more irrelevant text" builder.finish expected_message = <<-MULTIPART Here is a preamble to explain why multipart/mixed exists and why your mail client should support it --fixed-boundary X-Foo: bar body part 1 --fixed-boundary X-Type: Empty-Body X-Foo: Bar --fixed-boundary-- Irrelevant textMuch more irrelevant text MULTIPART io.to_s.should eq(expected_message.gsub('\n', "\r\n")) end describe "#content_type" do it "calculates the content type" do builder = MIME::Multipart::Builder.new(IO::Memory.new, "a delimiter string with a quote in \"") builder.content_type("alternative").should eq(%q(multipart/alternative; boundary="a delimiter string with a quote in \"")) end end describe ".preamble" do it "accepts different data types" do io = IO::Memory.new builder = MIME::Multipart::Builder.new(io, "boundary") builder.preamble "string\r\n" builder.preamble "slice\r\n".to_slice preamble_io = IO::Memory.new "io\r\n" builder.preamble preamble_io builder.preamble do |io| io.print "io" io << ' ' io.print "block" io << "\r\n" end builder.body_part(HTTP::Headers.new) builder.finish generated_multipart = io.to_s expected_multipart = <<-MULTIPART string slice io io block --boundary --boundary-- MULTIPART generated_multipart.should eq(expected_multipart.gsub('\n', "\r\n")) end it "raises when called after starting the body" do builder = MIME::Multipart::Builder.new(IO::Memory.new) builder.body_part HTTP::Headers.new, "test" expect_raises(MIME::Multipart::Error, "Cannot generate preamble: body already started") do builder.preamble "test" end end end describe ".body_part" do it "accepts different data types" do io = IO::Memory.new builder = MIME::Multipart::Builder.new(io, "boundary") headers = HTTP::Headers{"X-Foo" => "Bar"} builder.body_part headers, "string\r\n" builder.body_part headers, "slice".to_slice body_part_io = IO::Memory.new "io" builder.body_part headers, body_part_io builder.body_part(headers) do |io| io.print "io" io << ' ' io.print "block" end builder.body_part(headers) builder.finish generated_multipart = io.to_s expected_multipart = <<-MULTIPART --boundary X-Foo: Bar string --boundary X-Foo: Bar slice --boundary X-Foo: Bar io --boundary X-Foo: Bar io block --boundary X-Foo: Bar --boundary-- MULTIPART generated_multipart.should eq(expected_multipart.gsub('\n', "\r\n")) end it "raises when called after finishing" do builder = MIME::Multipart::Builder.new(IO::Memory.new) builder.body_part HTTP::Headers.new, "test" builder.finish expect_raises(MIME::Multipart::Error, "Cannot generate body part: already finished") do builder.body_part HTTP::Headers.new, "test" end end it "raises when called after epilogue" do builder = MIME::Multipart::Builder.new(IO::Memory.new) builder.body_part HTTP::Headers.new, "test" builder.epilogue "test" expect_raises(MIME::Multipart::Error, "Cannot generate body part: after epilogue") do builder.body_part HTTP::Headers.new, "test" end end end describe ".epilogue" do it "accepts different data types" do io = IO::Memory.new builder = MIME::Multipart::Builder.new(io, "boundary") builder.body_part(HTTP::Headers.new) builder.epilogue "string\r\n" builder.epilogue "slice\r\n".to_slice epilogue_io = IO::Memory.new "io\r\n" builder.epilogue epilogue_io builder.epilogue do |io| io.print "io" io << ' ' io.print "block" io << "\r\n" end builder.finish generated_multipart = io.to_s expected_multipart = <<-MULTIPART --boundary --boundary-- string slice io io block MULTIPART generated_multipart.should eq(expected_multipart.gsub('\n', "\r\n")) end it "raises when called after finishing" do builder = MIME::Multipart::Builder.new(IO::Memory.new) builder.body_part HTTP::Headers.new, "test" builder.finish expect_raises(MIME::Multipart::Error, "Cannot generate epilogue: already finished") do builder.epilogue "test" end end it "raises when called with no body parts" do builder = MIME::Multipart::Builder.new(IO::Memory.new) expect_raises(MIME::Multipart::Error, "Cannot generate epilogue: no body parts") do builder.epilogue "test" end builder.preamble "test" expect_raises(MIME::Multipart::Error, "Cannot generate epilogue: no body parts") do builder.epilogue "test" end end end describe ".finish" do it "raises if no body exists" do builder = MIME::Multipart::Builder.new(IO::Memory.new) expect_raises(MIME::Multipart::Error, "Cannot finish multipart: no body parts") do builder.finish end builder.preamble "test" expect_raises(MIME::Multipart::Error, "Cannot finish multipart: no body parts") do builder.finish end end it "raises if already finished" do builder = MIME::Multipart::Builder.new(IO::Memory.new) builder.body_part HTTP::Headers.new, "test" builder.finish expect_raises(MIME::Multipart::Error, "Cannot finish multipart: already finished") do builder.finish end end end end