<commit_before>require 'spec_helper'

describe Grape::Endpoint do
  subject { Class.new(Grape::API) }
  def app; subject end

  describe '#initialize' do
    it 'takes a settings stack, options, and a block' do
      p = Proc.new {}
      expect {
        Grape::Endpoint.new(Grape::Util::HashStack.new, {
          :path => '/',
          :method => :get
        }, &p)
      }.not_to raise_error
    end
  end

  it 'sets itself in the env upon call' do
    subject.get('/'){ "Hello world." }
    get '/'
    last_request.env['api.endpoint'].should be_kind_of(Grape::Endpoint)
  end

  describe '#status' do
    it 'is callable from within a block' do
      subject.get('/home') do
        status 206
        "Hello"
      end

      get '/home'
      last_response.status.should == 206
      last_response.body.should == "Hello"
    end
  end

  describe '#header' do
    it 'is callable from within a block' do
      subject.get('/hey') do
        header 'X-Awesome', 'true'
        "Awesome"
      end

      get '/hey'
      last_response.headers['X-Awesome'].should == 'true'
    end
  end

  describe '#headers' do
    before do
      subject.get('/headers') do
        headers.to_json
      end
    end
    it 'includes request headers' do
      get '/headers'
      JSON.parse(last_response.body).should == {
        "Host" => "example.org",
        "Cookie" => ""
      }
    end
    it 'includes additional request headers' do
      get '/headers', nil, { "HTTP_X_GRAPE_CLIENT" => "1" }
      JSON.parse(last_response.body)["X-Grape-Client"].should == "1"
    end
  end

  describe '#cookies' do
    it 'is callable from within a block' do
      subject.get('/get/cookies') do
        cookies['my-awesome-cookie1'] = 'is cool'
        cookies['my-awesome-cookie2'] = {
            :value => 'is cool too',
            :domain => 'my.example.com',
            :path => '/',
            :secure => true,
        }
        cookies[:cookie3] = 'symbol'
        cookies['cookie4'] = 'secret code here'
      end

      get('/get/cookies')

      last_response.headers['Set-Cookie'].split("\n").sort.should eql [
        "cookie3=symbol",
        "cookie4=secret+code+here",
        "my-awesome-cookie1=is+cool",
        "my-awesome-cookie2=is+cool+too; domain=my.example.com; path=/; secure"
      ]
    end

    it 'sets browser cookies and does not set response cookies' do
      subject.get('/username') do
        cookies[:username]
      end
      get('/username', {}, 'HTTP_COOKIE' => 'username=mrplum; sandbox=true')

      last_response.body.should == 'mrplum'
      last_response.headers['Set-Cookie'].should_not =~ /username=mrplum/
      last_response.headers['Set-Cookie'].should_not =~ /sandbox=true/
    end

    it 'sets and update browser cookies' do
      subject.get('/username') do
        cookies[:sandbox] = true if cookies[:sandbox] == 'false'
        cookies[:username] += "_test"
      end
      get('/username', {}, 'HTTP_COOKIE' => 'username=user; sandbox=false')
      last_response.body.should == 'user_test'
      last_response.headers['Set-Cookie'].should =~ /username=user_test/
      last_response.headers['Set-Cookie'].should =~ /sandbox=true/
    end

    it 'deletes cookie' do
      subject.get('/test') do
        sum = 0
        cookies.each do |name, val|
          sum += val.to_i
          cookies.delete name
        end
        sum
      end
      get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
      last_response.body.should == '3'
      cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
        cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
        [ cookie.name, cookie ]
      end]
      cookies.size.should == 2
      [ "and_this", "delete_this_cookie" ].each do |cookie_name|
        cookie = cookies[cookie_name]
        cookie.should_not be_nil
        cookie.value.should == "deleted"
        cookie.expired?.should be_true
      end
    end

    it 'deletes cookies with path' do
      subject.get('/test') do
        sum = 0
        cookies.each do |name, val|
          sum += val.to_i
          cookies.delete name, { :path => '/test' }
        end
        sum
      end
      get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
      last_response.body.should == '3'
      cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
        cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
        [ cookie.name, cookie ]
      end]
      cookies.size.should == 2
      [ "and_this", "delete_this_cookie" ].each do |cookie_name|
        cookie = cookies[cookie_name]
        cookie.should_not be_nil
        cookie.value.should == "deleted"
        cookie.path.should == "/test"
        cookie.expired?.should be_true
      end
    end
  end

  describe '#declared' do
    before do
      subject.params do
        requires :first
        optional :second
      end
    end

    it 'has as many keys as there are declared params' do
      subject.get '/declared' do
        declared(params).keys.size.should == 2
        ""
      end

      get '/declared?first=present'
      last_response.status.should == 200
    end

    it 'filters out any additional params that are given' do
      subject.get '/declared' do
        declared(params).key?(:other).should == false
        ""
      end

      get '/declared?first=one&other=two'
      last_response.status.should == 200
    end

    it 'stringifies if that option is passed' do
      subject.get '/declared' do
        declared(params, :stringify => true)["first"].should == "one"
        ""
      end

      get '/declared?first=one&other=two'
      last_response.status.should == 200
    end

    it 'does not include missing attributes if that option is passed' do
      subject.get '/declared' do
        declared(params, :include_missing => false)[:second].should == nil
        ""
      end

      get '/declared?first=one&other=two'
      last_response.status.should == 200
    end
  end

  describe '#params' do
    it 'is available to the caller' do
      subject.get('/hey') do
        params[:howdy]
      end

      get '/hey?howdy=hey'
      last_response.body.should == 'hey'
    end

    it 'parses from path segments' do
      subject.get('/hey/:id') do
        params[:id]
      end

      get '/hey/12'
      last_response.body.should == '12'
    end

    it 'deeply converts nested params' do
      subject.get '/location' do
        params[:location][:city]
      end
      get '/location?location[city]=Dallas'
      last_response.body.should == 'Dallas'
    end

    context 'with special requirements' do
      it 'parses email param with provided requirements for params' do
        subject.get('/:person_email', :requirements => { :person_email => /.*/ }) do
        params[:person_email]
        end

        get '/<EMAIL>'
        last_response.body.should == '<EMAIL>'

        get '<EMAIL>'
        last_response.body.should == '<EMAIL>'
      end

      it 'parses many params with provided regexps' do
        subject.get('/:person_email/test/:number',
          :requirements => {
            :person_email => /someone@(.*).com/,
            :number => /[0-9]/ }) do
        params[:person_email] << params[:number]
        end

        get '/someone@example.com/test/1'
        last_response.body.should == '<EMAIL>1'

        get '/someone@testing.wrong/test/1'
        last_response.status.should == 404

        get '<EMAIL>/test/wrong_number'
        last_response.status.should == 404

        get '<EMAIL>/wrong_middle/1'
        last_response.status.should == 404
      end

      context 'namespace requirements' do
        before :each do
          subject.namespace :outer, :requirements => { :person_email => /abc@(.*).com/ } do
            get('/:person_email') do
              params[:person_email]
            end

            namespace :inner, :requirements => {:number => /[0-9]/, :person_email => /someone@(.*).com/ }do
              get '/:person_email/test/:number' do
                params[:person_email] << params[:number]
              end
            end
          end
        end
        it "parse email param with provided requirements for params" do
          get '/outer/<EMAIL>'
          last_response.body.should == '<EMAIL>'
        end

        it "should override outer namespace's requirements" do
          get '/outer/inner/some<EMAIL>/test/1'
          last_response.status.should == 404

          get '/outer/inner/<EMAIL>/test/1'
          last_response.status.should == 200
          last_response.body.should == '<EMAIL>'
        end

      end
    end

    context 'from body parameters' do
      before(:each) do
        subject.post '/request_body' do
          params[:user]
        end
        subject.put '/request_body' do
          params[:user]
        end
      end

      it 'converts JSON bodies to params' do
        post '/request_body', MultiJson.dump(:user => '<NAME>.'), {'CONTENT_TYPE' => 'application/json'}
        last_response.body.should == 'Bobby T.'
      end

      it 'does not convert empty JSON bodies to params' do
        put '/request_body', '', {'CONTENT_TYPE' => 'application/json'}
        last_response.body.should == ''
      end

      it 'converts XML bodies to params' do
        post '/request_body', '<user>Bobby T.</user>', {'CONTENT_TYPE' => 'application/xml'}
        last_response.body.should == 'Bobby T.'
      end

      it 'converts XML bodies to params' do
        put '/request_body', '<user><NAME>.</user>', {'CONTENT_TYPE' => 'application/xml'}
        last_response.body.should == 'B<NAME>.'
      end

      it 'does not include parameters not defined by the body' do
        subject.post '/omitted_params' do
          params[:version].should == nil
          params[:user].should == 'Bob'
        end
        post '/omitted_params', MultiJson.dump(:user => 'Bob'), {'CONTENT_TYPE' => 'application/json'}
      end
    end

    it "responds with a 406 for an unsupported content-type" do
      subject.format :json
      # subject.content_type :json, "application/json"
      subject.put '/request_body' do
        params[:user]
      end
      put '/request_body', '<user><NAME>.</user>', {'CONTENT_TYPE' => 'application/xml'}
      last_response.status.should == 406
      last_response.body.should == '{"error":"The requested content-type \'application/xml\' is not supported."}'
    end

  end

  describe '#error!' do
    it 'accepts a message' do
      subject.get('/hey') do
        error! "This is not valid."
        "This is valid."
      end

      get '/hey'
      last_response.status.should == 403
      last_response.body.should == "This is not valid."
    end

    it 'accepts a code' do
      subject.get('/hey') do
        error! "Unauthorized.", 401
      end

      get '/hey'
      last_response.status.should == 401
      last_response.body.should == "Unauthorized."
    end

    it 'accepts an object and render it in format' do
      subject.get '/hey' do
        error!({'dude' => 'rad'}, 403)
      end

      get '/hey.json'
      last_response.status.should == 403
      last_response.body.should == '{"dude":"rad"}'
    end
  end

  describe '#redirect' do
    it 'redirects to a url with status 302' do
      subject.get('/hey') do
        redirect "/ha"
      end
      get '/hey'
      last_response.status.should eq 302
      last_response.headers['Location'].should eq "/ha"
      last_response.body.should eq ""
    end

    it 'has status code 303 if it is not get request and it is http 1.1' do
      subject.post('/hey') do
        redirect "/ha"
      end
      post '/hey', {}, 'HTTP_VERSION' => 'HTTP/1.1'
      last_response.status.should eq 303
      last_response.headers['Location'].should eq "/ha"
    end

    it 'support permanent redirect' do
      subject.get('/hey') do
        redirect "/ha", :permanent => true
      end
      get '/hey'
      last_response.status.should eq 301
      last_response.headers['Location'].should eq "/ha"
      last_response.body.should eq ""
    end
  end

  it 'does not persist params between calls' do
    subject.post('/new') do
      params[:text]
    end

    post '/new', :text => 'abc'
    last_response.body.should == 'abc'

    post '/new', :text => 'def'
    last_response.body.should == 'def'
  end

  it 'resets all instance variables (except block) between calls' do
    subject.helpers do
      def memoized
        @memoized ||= params[:howdy]
      end
    end

    subject.get('/hello') do
      memoized
    end

    get '/hello?howdy=hey'
    last_response.body.should == 'hey'
    get '/hello?howdy=yo'
    last_response.body.should == 'yo'
  end

  it 'allows explicit return calls' do
    subject.get('/home') do
      return "Hello"
    end

    get '/home'
    last_response.status.should == 200
    last_response.body.should == "Hello"
  end

  describe '.generate_api_method' do
    it 'raises NameError if the method name is already in use' do
      expect {
        Grape::Endpoint.generate_api_method("version", &proc{})
      }.to raise_error(NameError)
    end
    it 'raises ArgumentError if a block is not given' do
      expect {
        Grape::Endpoint.generate_api_method("GET without a block method")
      }.to raise_error(ArgumentError)
    end
    it 'returns a Proc' do
      Grape::Endpoint.generate_api_method("GET test for a proc", &proc{}).should be_a Proc
    end
  end

  context 'filters' do
    describe 'before filters' do
      it 'runs the before filter if set' do
        subject.before{ env['before_test'] = "OK" }
        subject.get('/before_test'){ env['before_test'] }

        get '/before_test'
        last_response.body.should == "OK"
      end
    end

    describe 'after filters' do
      it 'overrides the response body if it sets it' do
        subject.after{ body "after" }
        subject.get('/after_test'){ "during" }
        get '/after_test'
        last_response.body.should == 'after'
      end

      it 'does not override the response body with its return' do
        subject.after{ "after" }
        subject.get('/after_test'){ "body" }
        get '/after_test'
        last_response.body.should == "body"
      end
    end
  end

  context 'anchoring' do
    verbs = %w(post get head delete put options patch)

    verbs.each do |verb|
      it 'allows for the anchoring option with a #{verb.upcase} method' do
        subject.send(verb, '/example', :anchor => true) do
          verb
        end
        send(verb, '/example/and/some/more')
        last_response.status.should eql 404
      end

      it 'anchors paths by default for the #{verb.upcase} method' do
        subject.send(verb, '/example') do
          verb
        end
        send(verb, '/example/and/some/more')
        last_response.status.should eql 404
      end

      it 'responds to /example/and/some/more for the non-anchored #{verb.upcase} method' do
        subject.send(verb, '/example', :anchor => false) do
          verb
        end
        send(verb, '/example/and/some/more')
        last_response.status.should eql verb == "post" ? 201 : 200
        last_response.body.should eql verb == 'head' ? '' : verb
      end
    end
  end

  context 'request' do
    it 'should be set to the url requested' do
      subject.get('/url') do
        request.url
      end
      get '/url'
      last_response.body.should == "http://example.org/url"
    end
    [ 'v1', :v1 ].each do |version|
      it 'should include version #{version}' do
        subject.version version, :using => :path
        subject.get('/url') do
          request.url
        end
        get "/#{version}/url"
        last_response.body.should == "http://example.org/#{version}/url"
      end
    end
    it 'should include prefix' do
      subject.version 'v1', :using => :path
      subject.prefix 'api'
      subject.get('/url') do
        request.url
      end
      get '/api/v1/url'
      last_response.body.should == "http://example.org/api/v1/url"
    end
  end

end<commit_msg>Add failing spec for before filters on nested APIs<commit_after>require 'spec_helper'

describe Grape::Endpoint do
  subject { Class.new(Grape::API) }
  def app; subject end

  describe '#initialize' do
    it 'takes a settings stack, options, and a block' do
      p = Proc.new {}
      expect {
        Grape::Endpoint.new(Grape::Util::HashStack.new, {
          :path => '/',
          :method => :get
        }, &p)
      }.not_to raise_error
    end
  end

  it 'sets itself in the env upon call' do
    subject.get('/'){ "Hello world." }
    get '/'
    last_request.env['api.endpoint'].should be_kind_of(Grape::Endpoint)
  end

  describe '#status' do
    it 'is callable from within a block' do
      subject.get('/home') do
        status 206
        "Hello"
      end

      get '/home'
      last_response.status.should == 206
      last_response.body.should == "Hello"
    end
  end

  describe '#header' do
    it 'is callable from within a block' do
      subject.get('/hey') do
        header 'X-Awesome', 'true'
        "Awesome"
      end

      get '/hey'
      last_response.headers['X-Awesome'].should == 'true'
    end
  end

  describe '#headers' do
    before do
      subject.get('/headers') do
        headers.to_json
      end
    end
    it 'includes request headers' do
      get '/headers'
      JSON.parse(last_response.body).should == {
        "Host" => "example.org",
        "Cookie" => ""
      }
    end
    it 'includes additional request headers' do
      get '/headers', nil, { "HTTP_X_GRAPE_CLIENT" => "1" }
      JSON.parse(last_response.body)["X-Grape-Client"].should == "1"
    end
  end

  describe '#cookies' do
    it 'is callable from within a block' do
      subject.get('/get/cookies') do
        cookies['my-awesome-cookie1'] = 'is cool'
        cookies['my-awesome-cookie2'] = {
            :value => 'is cool too',
            :domain => 'my.example.com',
            :path => '/',
            :secure => true,
        }
        cookies[:cookie3] = 'symbol'
        cookies['cookie4'] = 'secret code here'
      end

      get('/get/cookies')

      last_response.headers['Set-Cookie'].split("\n").sort.should eql [
        "cookie3=symbol",
        "cookie4=secret+code+here",
        "my-awesome-cookie1=is+cool",
        "my-awesome-cookie2=is+cool+too; domain=my.example.com; path=/; secure"
      ]
    end

    it 'sets browser cookies and does not set response cookies' do
      subject.get('/username') do
        cookies[:username]
      end
      get('/username', {}, 'HTTP_COOKIE' => 'username=mrplum; sandbox=true')

      last_response.body.should == 'mrplum'
      last_response.headers['Set-Cookie'].should_not =~ /username=mrplum/
      last_response.headers['Set-Cookie'].should_not =~ /sandbox=true/
    end

    it 'sets and update browser cookies' do
      subject.get('/username') do
        cookies[:sandbox] = true if cookies[:sandbox] == 'false'
        cookies[:username] += "_test"
      end
      get('/username', {}, 'HTTP_COOKIE' => 'username=user; sandbox=false')
      last_response.body.should == 'user_test'
      last_response.headers['Set-Cookie'].should =~ /username=user_test/
      last_response.headers['Set-Cookie'].should =~ /sandbox=true/
    end

    it 'deletes cookie' do
      subject.get('/test') do
        sum = 0
        cookies.each do |name, val|
          sum += val.to_i
          cookies.delete name
        end
        sum
      end
      get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
      last_response.body.should == '3'
      cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
        cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
        [ cookie.name, cookie ]
      end]
      cookies.size.should == 2
      [ "and_this", "delete_this_cookie" ].each do |cookie_name|
        cookie = cookies[cookie_name]
        cookie.should_not be_nil
        cookie.value.should == "deleted"
        cookie.expired?.should be_true
      end
    end

    it 'deletes cookies with path' do
      subject.get('/test') do
        sum = 0
        cookies.each do |name, val|
          sum += val.to_i
          cookies.delete name, { :path => '/test' }
        end
        sum
      end
      get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
      last_response.body.should == '3'
      cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
        cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
        [ cookie.name, cookie ]
      end]
      cookies.size.should == 2
      [ "and_this", "delete_this_cookie" ].each do |cookie_name|
        cookie = cookies[cookie_name]
        cookie.should_not be_nil
        cookie.value.should == "deleted"
        cookie.path.should == "/test"
        cookie.expired?.should be_true
      end
    end
  end

  describe '#declared' do
    before do
      subject.params do
        requires :first
        optional :second
      end
    end

    it 'has as many keys as there are declared params' do
      subject.get '/declared' do
        declared(params).keys.size.should == 2
        ""
      end

      get '/declared?first=present'
      last_response.status.should == 200
    end

    it 'filters out any additional params that are given' do
      subject.get '/declared' do
        declared(params).key?(:other).should == false
        ""
      end

      get '/declared?first=one&other=two'
      last_response.status.should == 200
    end

    it 'stringifies if that option is passed' do
      subject.get '/declared' do
        declared(params, :stringify => true)["first"].should == "one"
        ""
      end

      get '/declared?first=one&other=two'
      last_response.status.should == 200
    end

    it 'does not include missing attributes if that option is passed' do
      subject.get '/declared' do
        declared(params, :include_missing => false)[:second].should == nil
        ""
      end

      get '/declared?first=one&other=two'
      last_response.status.should == 200
    end
  end

  describe '#params' do
    it 'is available to the caller' do
      subject.get('/hey') do
        params[:howdy]
      end

      get '/hey?howdy=hey'
      last_response.body.should == 'hey'
    end

    it 'parses from path segments' do
      subject.get('/hey/:id') do
        params[:id]
      end

      get '/hey/12'
      last_response.body.should == '12'
    end

    it 'deeply converts nested params' do
      subject.get '/location' do
        params[:location][:city]
      end
      get '/location?location[city]=Dallas'
      last_response.body.should == 'Dallas'
    end

    context 'with special requirements' do
      it 'parses email param with provided requirements for params' do
        subject.get('/:person_email', :requirements => { :person_email => /.*/ }) do
        params[:person_email]
        end

        get '/<EMAIL>'
        last_response.body.should == '<EMAIL>'

        get '<EMAIL>'
        last_response.body.should == '<EMAIL>'
      end

      it 'parses many params with provided regexps' do
        subject.get('/:person_email/test/:number',
          :requirements => {
            :person_email => /someone@(.*).com/,
            :number => /[0-9]/ }) do
        params[:person_email] << params[:number]
        end

        get '/someone@example.<EMAIL>/test/1'
        last_response.body.should == '<EMAIL>1'

        get '/someone@testing.wrong/test/1'
        last_response.status.should == 404

        get 'someone@test.com/test/wrong_number'
        last_response.status.should == 404

        get 'someone@test.com/wrong_middle/1'
        last_response.status.should == 404
      end

      context 'namespace requirements' do
        before :each do
          subject.namespace :outer, :requirements => { :person_email => /abc@(.*).com/ } do
            get('/:person_email') do
              params[:person_email]
            end

            namespace :inner, :requirements => {:number => /[0-9]/, :person_email => /someone@(.*).com/ }do
              get '/:person_email/test/:number' do
                params[:person_email] << params[:number]
              end
            end
          end
        end
        it "parse email param with provided requirements for params" do
          get '/outer/<EMAIL>'
          last_response.body.should == '<EMAIL>'
        end

        it "should override outer namespace's requirements" do
          get '/outer/inner/someone@testing.wrong/test/1'
          last_response.status.should == 404

          get '/outer/inner/<EMAIL>/test/1'
          last_response.status.should == 200
          last_response.body.should == '<EMAIL>'
        end

      end
    end

    context 'from body parameters' do
      before(:each) do
        subject.post '/request_body' do
          params[:user]
        end
        subject.put '/request_body' do
          params[:user]
        end
      end

      it 'converts JSON bodies to params' do
        post '/request_body', MultiJson.dump(:user => '<NAME>.'), {'CONTENT_TYPE' => 'application/json'}
        last_response.body.should == 'Bobby T.'
      end

      it 'does not convert empty JSON bodies to params' do
        put '/request_body', '', {'CONTENT_TYPE' => 'application/json'}
        last_response.body.should == ''
      end

      it 'converts XML bodies to params' do
        post '/request_body', '<user>Bobby T.</user>', {'CONTENT_TYPE' => 'application/xml'}
        last_response.body.should == 'Bobby T.'
      end

      it 'converts XML bodies to params' do
        put '/request_body', '<user>Bobby T.</user>', {'CONTENT_TYPE' => 'application/xml'}
        last_response.body.should == 'Bobby T.'
      end

      it 'does not include parameters not defined by the body' do
        subject.post '/omitted_params' do
          params[:version].should == nil
          params[:user].should == 'Bob'
        end
        post '/omitted_params', MultiJson.dump(:user => 'Bob'), {'CONTENT_TYPE' => 'application/json'}
      end
    end

    it "responds with a 406 for an unsupported content-type" do
      subject.format :json
      # subject.content_type :json, "application/json"
      subject.put '/request_body' do
        params[:user]
      end
      put '/request_body', '<user>Bobby T.</user>', {'CONTENT_TYPE' => 'application/xml'}
      last_response.status.should == 406
      last_response.body.should == '{"error":"The requested content-type \'application/xml\' is not supported."}'
    end

  end

  describe '#error!' do
    it 'accepts a message' do
      subject.get('/hey') do
        error! "This is not valid."
        "This is valid."
      end

      get '/hey'
      last_response.status.should == 403
      last_response.body.should == "This is not valid."
    end

    it 'accepts a code' do
      subject.get('/hey') do
        error! "Unauthorized.", 401
      end

      get '/hey'
      last_response.status.should == 401
      last_response.body.should == "Unauthorized."
    end

    it 'accepts an object and render it in format' do
      subject.get '/hey' do
        error!({'dude' => 'rad'}, 403)
      end

      get '/hey.json'
      last_response.status.should == 403
      last_response.body.should == '{"dude":"rad"}'
    end
  end

  describe '#redirect' do
    it 'redirects to a url with status 302' do
      subject.get('/hey') do
        redirect "/ha"
      end
      get '/hey'
      last_response.status.should eq 302
      last_response.headers['Location'].should eq "/ha"
      last_response.body.should eq ""
    end

    it 'has status code 303 if it is not get request and it is http 1.1' do
      subject.post('/hey') do
        redirect "/ha"
      end
      post '/hey', {}, 'HTTP_VERSION' => 'HTTP/1.1'
      last_response.status.should eq 303
      last_response.headers['Location'].should eq "/ha"
    end

    it 'support permanent redirect' do
      subject.get('/hey') do
        redirect "/ha", :permanent => true
      end
      get '/hey'
      last_response.status.should eq 301
      last_response.headers['Location'].should eq "/ha"
      last_response.body.should eq ""
    end
  end

  it 'does not persist params between calls' do
    subject.post('/new') do
      params[:text]
    end

    post '/new', :text => 'abc'
    last_response.body.should == 'abc'

    post '/new', :text => 'def'
    last_response.body.should == 'def'
  end

  it 'resets all instance variables (except block) between calls' do
    subject.helpers do
      def memoized
        @memoized ||= params[:howdy]
      end
    end

    subject.get('/hello') do
      memoized
    end

    get '/hello?howdy=hey'
    last_response.body.should == 'hey'
    get '/hello?howdy=yo'
    last_response.body.should == 'yo'
  end

  it 'allows explicit return calls' do
    subject.get('/home') do
      return "Hello"
    end

    get '/home'
    last_response.status.should == 200
    last_response.body.should == "Hello"
  end

  describe '.generate_api_method' do
    it 'raises NameError if the method name is already in use' do
      expect {
        Grape::Endpoint.generate_api_method("version", &proc{})
      }.to raise_error(NameError)
    end
    it 'raises ArgumentError if a block is not given' do
      expect {
        Grape::Endpoint.generate_api_method("GET without a block method")
      }.to raise_error(ArgumentError)
    end
    it 'returns a Proc' do
      Grape::Endpoint.generate_api_method("GET test for a proc", &proc{}).should be_a Proc
    end
  end

  context 'filters' do
    describe 'before filters' do
      it 'runs the before filter if set' do
        subject.before{ env['before_test'] = "OK" }
        subject.get('/before_test'){ env['before_test'] }

        get '/before_test'
        last_response.body.should == "OK"
      end
    end

    describe 'after filters' do
      it 'overrides the response body if it sets it' do
        subject.after{ body "after" }
        subject.get('/after_test'){ "during" }
        get '/after_test'
        last_response.body.should == 'after'
      end

      it 'does not override the response body with its return' do
        subject.after{ "after" }
        subject.get('/after_test'){ "body" }
        get '/after_test'
        last_response.body.should == "body"
      end
    end
  end

  context 'anchoring' do
    verbs = %w(post get head delete put options patch)

    verbs.each do |verb|
      it 'allows for the anchoring option with a #{verb.upcase} method' do
        subject.send(verb, '/example', :anchor => true) do
          verb
        end
        send(verb, '/example/and/some/more')
        last_response.status.should eql 404
      end

      it 'anchors paths by default for the #{verb.upcase} method' do
        subject.send(verb, '/example') do
          verb
        end
        send(verb, '/example/and/some/more')
        last_response.status.should eql 404
      end

      it 'responds to /example/and/some/more for the non-anchored #{verb.upcase} method' do
        subject.send(verb, '/example', :anchor => false) do
          verb
        end
        send(verb, '/example/and/some/more')
        last_response.status.should eql verb == "post" ? 201 : 200
        last_response.body.should eql verb == 'head' ? '' : verb
      end
    end
  end

  context 'request' do
    it 'should be set to the url requested' do
      subject.get('/url') do
        request.url
      end
      get '/url'
      last_response.body.should == "http://example.org/url"
    end
    [ 'v1', :v1 ].each do |version|
      it 'should include version #{version}' do
        subject.version version, :using => :path
        subject.get('/url') do
          request.url
        end
        get "/#{version}/url"
        last_response.body.should == "http://example.org/#{version}/url"
      end
    end
    it 'should include prefix' do
      subject.version 'v1', :using => :path
      subject.prefix 'api'
      subject.get('/url') do
        request.url
      end
      get '/api/v1/url'
      last_response.body.should == "http://example.org/api/v1/url"
    end
  end

  describe "nested APIs" do
    class DicaprioAPI < Grape::API
      get 'even_deeper' do
        env['before_test']
      end
    end

    class APIV1 < Grape::API
      mount DicaprioAPI
    end

    class BaseAPI < Grape::API
      before do
        raise "from before filter"
        env['before_test'] = "OK"
      end
      mount APIV1
    end

    def app; BaseAPI; end

    describe 'before filters' do
      it 'runs the before filter if set on a deeply nested Grape API' do
        get '/even_deeper'
        last_response.body.should == "OK"
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.12700778778291555, 'fraction_numerical': 0.007848624969578973, 'mean_word_length': 2.1481516950775714, 'pattern_counts': {'":': 4, '<': 53, '<?xml version=': 0, '>': 128, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 8}, 'pii_count': 6, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2616349', 'n_tokens_mistral': 10269, 'n_tokens_neox': 9835, 'n_words': 2675}