require 'spec_helper'

describe Pancake::MimeTypes do
  before do
    Pancake::MimeTypes.reset!
  end

  it "should have many types" do
    Pancake::MimeTypes.types.should be_an(Array)
  end

  it "should have a type for each mime type defined in Rack::Mime::MIME_TYPES" do
    Rack::Mime::MIME_TYPES.each do |ext, type|
      ext =~ /\.(.*)$/
      t = Pancake::MimeTypes.type_by_extension($1)
      t.should_not be_nil
      t.should be_an_instance_of(Pancake::MimeTypes::Type)
      t.type_strings.should include(type)
    end
  end

  it "should find the type from an extension" do
    t = Pancake::MimeTypes.type_by_extension("html")
    t.should_not be_nil
    t.type_strings.should include("text/html")
  end

  it "should allow me to add a new mime type" do
    t = Pancake::MimeTypes::Type.new("foo", "text/foobar")
    type = Pancake::MimeTypes.type_by_extension("foo")
    type.should_not be_nil
    type.type_strings.should have(1).item
    type.type_strings.should include("text/foobar")
  end

  describe Pancake::MimeTypes::Type do
    include Pancake::MimeTypes

    before do
      @type = Pancake::MimeTypes::Type.new("html", "text/html")
    end

    it "should have one extension" do
      @type.extension.should == "html"
    end

    it "should tell me the type strings" do
      @type.type_strings.should include("text/html")
    end

    it "should allow me to add type strings" do
      @type.type_strings << "text/foo_html"
      @type.type_strings.should include("text/foo_html")
    end

    it "should not add duplicate type strings" do
      @type.type_strings.should have(1).item
      @type.type_strings << "text/html"
      @type.type_strings.should have(2).items
      @type.type_strings.should include("text/html")
    end

    it "should add non duplicate tpe strying" do
      @type.type_strings.should have(1).item
      @type.type_strings << "text/foo_html"
      @type.type_strings.should have(2).items
      @type.type_strings.should include("text/foo_html")
    end
  end

  describe "grouping types" do
    it "should allow me to create a group of mime types" do
      Pancake::MimeTypes.group(:html).should be_an(Enumerable)
    end

    it "should allow me to add mime types to the group" do
      Pancake::MimeTypes.group_as(:foo, "html", "xhtml")
      r = Pancake::MimeTypes.group(:foo)
      r.should have(2).items
      r.should include(Pancake::MimeTypes.type_by_extension("html"))
      r.should include(Pancake::MimeTypes.type_by_extension("xhtml"))
    end

    it "should allow me to add to a group without creating duplicates" do
      t = Pancake::MimeTypes::Type.new("foo", "foo/bar")
      Pancake::MimeTypes.group_as(:bar, "xhtml", "html")
      Pancake::MimeTypes.group(:bar).should have(2).items
      Pancake::MimeTypes.group(:bar).should_not include(t)
      Pancake::MimeTypes.group_as(:bar, "html", "foo", "xhtml")
      Pancake::MimeTypes.group(:bar).should have(3).items
      Pancake::MimeTypes.group(:bar).should include(t)
    end

    it "should allow me to look up a mime type via a string or symbol identifier" do
      Pancake::MimeTypes.group(:html).should eql(Pancake::MimeTypes.group("html"))
    end

    it "should be empty empty when accessing a non existant mime type" do
      r = Pancake::MimeTypes.group(:not_a_mime)
      r.should_not be_nil
      r.should be_empty
      r.should respond_to(:each)
    end

    it "should populate the group with the types when first acessing when a type with that extension exists" do
      r = Pancake::MimeTypes.group(:xml)
      r.should_not be_empty
      r.each do |t|
        t.should be_an_instance_of(Pancake::MimeTypes::Type)
      end
    end
  end

  describe "prepared groups" do
    it "should prepare the html group" do
      g = Pancake::MimeTypes.group(:html)
      g.should have(3).items
      ["html", "htm", "xhtml"].each do |ext|
        t = Pancake::MimeTypes.type_by_extension(ext)
        g.should include(t)
      end
    end

    it "should parepare the text group" do
      g = Pancake::MimeTypes.group(:text)
      g.should have(2).items
      ["text", "txt"].each do |ext|
        t = Pancake::MimeTypes.type_by_extension(ext)
        g.should include(t)
      end
    end

    it "should prepare the svg group" do
      g = Pancake::MimeTypes.group(:svg)
      g.should have(2).items
      ["svg", "svgz"].each do |ext|
        t = Pancake::MimeTypes.type_by_extension(ext)
        g.should include(t)
      end
    end


    it "should add the text/xml to the xml format" do
      t = Pancake::MimeTypes.type_by_extension("xml")
      t.type_strings.should include("text/xml", "application/xml")
    end
  end

  describe "format from accept type" do
    it "should return the first matching type" do
      accept_type = "text/plain"
      group, at, r = Pancake::MimeTypes.negotiate_accept_type(accept_type, :text)
      group.should == :text
      at.should == accept_type
      r.should_not be_nil
      r.type_strings.should include("text/plain")
    end

    it "should return the first type if the matching type is */*" do
      accept_type = "*/*;application/xml"
      group, at, r = Pancake::MimeTypes.negotiate_accept_type(accept_type, :text, :xml, :html)
      at.should == "text/plain"
      group.should == :text
      r.should_not be_nil
      r.type_strings.should include("text/plain")
    end

    it "should use */* if avaiable" do
      accept_type = "application/xml,*/*"
      group, at, r = Pancake::MimeTypes.negotiate_accept_type(accept_type, :html, :xml)
      at.should == "text/html"
      group.should == :html
      r.should_not be_nil
    end

    describe "matching on :any" do
      it "should use match :any for a request" do
        accept_type = "text/xml,*/*"
        group, at, r = Pancake::MimeTypes.negotiate_accept_type(accept_type, :any)
        group.should == :any
        at.should == "text/xml"
        r.should_not be_nil
      end

      it "should match :any for a request with a defualt given" do
        accept_types = "*/*"
        group, at, r = Pancake::MimeTypes.negotiate_accept_type(accept_types, :any, :json)
        group.should == :any
        at.should == "application/json"
        r.should_not be_nil
      end

      it "should allow a specified mime type when a default is set" do
        accept_types = "text/plain"
        group, at, r = Pancake::MimeTypes.negotiate_accept_type(accept_types, :any, :json)
        group.should == :any
        at.should == "text/plain"
        r.should_not be_nil
      end

      it "should match text/html for a request with only */* with no default" do
        accept_types = "*/*"
        group, at, r = Pancake::MimeTypes.negotiate_accept_type(accept_types, :any)
        at.should == "text/html"
        group.should == :any
      end
    end

    it "should return nil if there is no matching class" do
      accept_type = "text/xml"
      group, r = Pancake::MimeTypes.negotiate_accept_type(accept_type, :text, :html)
      r.should be_nil
      group.should be_nil
    end

    it "should return a type when it is not in the first position" do
      accept_type = "text/xml, text/html,text/plain;"
      group, at, r = Pancake::MimeTypes.negotiate_accept_type(accept_type, :svg, :text)
      group.should == :text
      r.should_not be_nil
      r.type_strings.should include("text/plain")
      r.extension.should == "text"
    end

    it "should recognize the type from a quality value" do
      accept_type = "text/plain;q=0.5,text/html;q=0.8"
      group, at,  r = Pancake::MimeTypes.negotiate_accept_type(accept_type, :text, :html)
      group.should == :html
      r.should_not be_nil
      r.type_strings.should include("text/html")
      r.extension.should == "html"
    end
  end

  describe "mime from extension" do
    it "should recognize the mime type from the extension" do
      group, at, r = Pancake::MimeTypes.negotiate_by_extension("text", :html, :text)
      group.should == :text
      at.should == "text/plain"
      r.should == Pancake::MimeTypes.type_by_extension("text")
    end

    it "should recognize grouped mimes by extension" do
      Pancake::MimeTypes.group_as(:foo, "text", "txt", "html")
      group, at, r = Pancake::MimeTypes.negotiate_by_extension("txt", :foo)
      group.should == :foo
      at.should == "text/plain"
      r.extension.should == "txt"
      group, at, r = Pancake::MimeTypes.negotiate_by_extension("text", :foo)
      r.extension.should == "text"
      group, at, r = Pancake::MimeTypes.negotiate_by_extension("html", :foo)
      r.extension.should == "html"
      at.should == "text/html"
    end

    it "should not negotiate by extension when there the extension is not part of the accepted types" do
      Pancake::MimeTypes.group_as(:bar, "text")
      group, at, r = Pancake::MimeTypes.negotiate_by_extension("svg", :bar)
      group.should be_nil
      at.should be_nil
      r.should be_nil
    end

    it "should negotiate when any by extension" do
      group, at, r = Pancake::MimeTypes.negotiate_by_extension("xml", :any)
      group.should == :any
      at.should == "application/xml"
      r.should_not be_nil
    end

  end
end

