require "spec"
require "http/formdata"
require "http/server/response"

describe HTTP::FormData do
  describe ".parse(IO, String)" do
    it "parses formdata" do
      formdata = <<-FORMDATA
        --foo
        Content-Disposition: form-data; name="foo"

        bar
        --foo--
        FORMDATA

      res = nil
      HTTP::FormData.parse(IO::Memory.new(formdata.gsub('\n', "\r\n")), "foo") do |part|
        res = part.body.gets_to_end if part.name == "foo"
      end
      res.should eq("bar")
    end
  end

  describe ".parse(HTTP::Request)" do
    it "parses formdata" do
      formdata = <<-FORMDATA
        --foo
        Content-Disposition: form-data; name="foo"

        bar
        --foo--
        FORMDATA
      headers = HTTP::Headers{"Content-Type" => "multipart/form-data; boundary=foo"}
      request = HTTP::Request.new("GET", "/", headers, formdata.gsub('\n', "\r\n"))

      res = nil
      HTTP::FormData.parse(request) do |part|
        res = part.body.gets_to_end if part.name == "foo"
      end
      res.should eq("bar")
    end

    it "raises on empty body" do
      headers = HTTP::Headers{"Content-Type" => "multipart/form-data; boundary=foo"}
      req = HTTP::Request.new("GET", "/", headers)
      expect_raises(HTTP::FormData::Error, "body is empty") do
        HTTP::FormData.parse(req) { }
      end
    end

    it "raises on no Content-Type" do
      req = HTTP::Request.new("GET", "/", body: "")
      expect_raises(HTTP::FormData::Error, "could not find boundary in Content-Type") do
        HTTP::FormData.parse(req) { }
      end
    end

    it "raises on invalid Content-Type" do
      headers = HTTP::Headers{"Content-Type" => "multipart/form-data; boundary="}
      req = HTTP::Request.new("GET", "/", headers, body: "")
      expect_raises(HTTP::FormData::Error, "could not find boundary in Content-Type") do
        HTTP::FormData.parse(req) { }
      end
    end
  end

  describe ".parse_content_disposition(String)" do
    it "parses all Content-Disposition fields" do
      name, meta = HTTP::FormData.parse_content_disposition %q(form-data; name=foo; filename="foo\"\\bar\ baz\\"; creation-date="Wed, 12 Feb 1997 16:29:51 -0500"; modification-date="12 Feb 1997 16:29:51 -0500"; read-date="Wed, 12 Feb 1997 16:29:51 -0500"; size=432334)

      name.should eq("foo")
      meta.filename.should eq(%q(foo"\bar baz\))
      meta.creation_time.should eq(Time.utc(1997, 2, 12, 21, 29, 51, nanosecond: 0))
      meta.modification_time.should eq(Time.utc(1997, 2, 12, 21, 29, 51, nanosecond: 0))
      meta.read_time.should eq(Time.utc(1997, 2, 12, 21, 29, 51, nanosecond: 0))
      meta.size.should eq(432334)
    end
  end

  describe ".build(IO, String)" do
    it "builds a message" do
      io = IO::Memory.new
      HTTP::FormData.build(io, "boundary") do |g|
        g.field("foo", "bar")
      end

      expected = <<-MULTIPART
        --boundary
        Content-Disposition: form-data; name="foo"

        bar
        --boundary--
        MULTIPART
      io.to_s.should eq(expected.gsub('\n', "\r\n"))
    end
  end

  describe ".build(HTTP::Server::Response, String)" do
    it "builds a message" do
      io = IO::Memory.new
      response = HTTP::Server::Response.new(io)
      HTTP::FormData.build(response, "boundary") do |g|
        g.field("foo", "bar")
      end
      response.close

      expected = <<-MULTIPART
        HTTP/1.1 200 OK
        Content-Type: multipart/form-data; boundary="boundary"
        Content-Length: 75

        --boundary
        Content-Disposition: form-data; name="foo"

        bar
        --boundary--
        MULTIPART

      io.to_s.should eq(expected.gsub('\n', "\r\n"))
    end
  end
end
