aboutsummaryrefslogblamecommitdiffstats
path: root/actionpack/test/dispatch/request/json_params_parsing_test.rb
blob: bbf98912f3b5ea8ec5948869301ad6dca860ddf7 (plain) (tree)
1
2
3
4
5

                             
                       
 
                                                             
















                                                                     
                                            
                                                                                 


     

                                                                      
                                                          
                                                                                             


     

                                                          
                                            
                                                                                        


     
                                                                                    
                  
         
                                                                                         


     

                                              
                         
                                                                 

                  
                              
                                                                         

                  
                         
                                                                       


     

                                              

                                                   
                                                                                                                                                                                              
                                  
                                        
                                                                          


       

                                                           



                                                                                                                                  
         



                                                             


       
                                                  
                        
                                                                                                                      



                                                                           

                                                     
                          
                                                       





                                                                      
                           
                   
                                               
                                                                       
             
           
             


         


                                                                     
                                 






                                                                     
                                                     









                                                   
                                                                         
                                                                         




                                                          
                                                                         
                                                                                


     

                                                    
                                                                                 
                                                                


     
                                                                     








                                                                                            


                                                                                  








                                                                                            

     


                                                     
                                                       

                                                                       
                                                                                          





                                     
                                               
                                          
             




             
# frozen_string_literal: true

require "abstract_unit"

class JsonParamsParsingTest < ActionDispatch::IntegrationTest
  class TestController < ActionController::Base
    class << self
      attr_accessor :last_request_parameters
    end

    def parse
      self.class.last_request_parameters = request.request_parameters
      head :ok
    end
  end

  def teardown
    TestController.last_request_parameters = nil
  end

  test "parses json params for application json" do
    assert_parses(
      { "person" => { "name" => "David" } },
      "{\"person\": {\"name\": \"David\"}}", "CONTENT_TYPE" => "application/json"
    )
  end

  test "parses boolean and number json params for application json" do
    assert_parses(
      { "item" => { "enabled" => false, "count" => 10 } },
      "{\"item\": {\"enabled\": false, \"count\": 10}}", "CONTENT_TYPE" => "application/json"
    )
  end

  test "parses json params for application jsonrequest" do
    assert_parses(
      { "person" => { "name" => "David" } },
      "{\"person\": {\"name\": \"David\"}}", "CONTENT_TYPE" => "application/jsonrequest"
    )
  end

  test "does not parse unregistered media types such as application/vnd.api+json" do
    assert_parses(
      {},
      "{\"person\": {\"name\": \"David\"}}", "CONTENT_TYPE" => "application/vnd.api+json"
    )
  end

  test "nils are stripped from collections" do
    assert_parses(
      { "person" => [] },
      "{\"person\":[null]}", "CONTENT_TYPE" => "application/json"
    )
    assert_parses(
      { "person" => ["foo"] },
      "{\"person\":[\"foo\",null]}", "CONTENT_TYPE" => "application/json"
    )
    assert_parses(
      { "person" => [] },
      "{\"person\":[null, null]}", "CONTENT_TYPE" => "application/json"
    )
  end

  test "logs error if parsing unsuccessful" do
    with_test_routing do
      output = StringIO.new
      json = "[\"person]\": {\"name\": \"David\"}}"
      post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => ActiveSupport::Logger.new(output) }
      assert_response :bad_request
      output.rewind && err = output.read
      assert err.match?(/Error occurred while parsing request parameters/)
    end
  end

  test "occurring a parse error if parsing unsuccessful" do
    with_test_routing do
      $stderr = StringIO.new # suppress the log
      json = "[\"person]\": {\"name\": \"David\"}}"
      exception = assert_raise(ActionDispatch::Http::Parameters::ParseError) do
        post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => false }
      end
      assert_equal JSON::ParserError, exception.cause.class
      assert_equal exception.cause.message, exception.message
    ensure
      $stderr = STDERR
    end
  end

  test "raw_post is not empty for JSON request" do
    with_test_routing do
      post "/parse", params: '{"posts": [{"title": "Post Title"}]}', headers: { "CONTENT_TYPE" => "application/json" }
      assert_equal '{"posts": [{"title": "Post Title"}]}', request.raw_post
    end
  end

  private
    def assert_parses(expected, actual, headers = {})
      with_test_routing do
        post "/parse", params: actual, headers: headers
        assert_response :ok
        assert_equal(expected, TestController.last_request_parameters)
      end
    end

    def with_test_routing
      with_routing do |set|
        set.draw do
          ActiveSupport::Deprecation.silence do
            post ":action", to: ::JsonParamsParsingTest::TestController
          end
        end
        yield
      end
    end
end

class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest
  class UsersController < ActionController::Base
    wrap_parameters format: :json

    class << self
      attr_accessor :last_request_parameters, :last_parameters
    end

    def parse
      self.class.last_request_parameters = request.request_parameters
      self.class.last_parameters = params.to_unsafe_h
      head :ok
    end
  end

  def teardown
    UsersController.last_request_parameters = nil
  end

  test "parses json params for application json" do
    assert_parses(
      { "user" => { "username" => "sikachu" }, "username" => "sikachu" },
      "{\"username\": \"sikachu\"}", "CONTENT_TYPE" => "application/json"
    )
  end

  test "parses json params for application jsonrequest" do
    assert_parses(
      { "user" => { "username" => "sikachu" }, "username" => "sikachu" },
      "{\"username\": \"sikachu\"}", "CONTENT_TYPE" => "application/jsonrequest"
    )
  end

  test "parses json with non-object JSON content" do
    assert_parses(
      { "user" => { "_json" => "string content" }, "_json" => "string content" },
      "\"string content\"", "CONTENT_TYPE" => "application/json"
    )
  end

  test "parses json params after custom json mime type registered" do
    Mime::Type.unregister :json
    Mime::Type.register "application/json", :json, %w(application/vnd.rails+json)
    assert_parses(
      { "user" => { "username" => "meinac" }, "username" => "meinac" },
      "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/json"
    )
  ensure
    Mime::Type.unregister :json
    Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
  end

  test "parses json params after custom json mime type registered with synonym" do
    Mime::Type.unregister :json
    Mime::Type.register "application/json", :json, %w(application/vnd.rails+json)
    assert_parses(
      { "user" => { "username" => "meinac" }, "username" => "meinac" },
      "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/vnd.rails+json"
    )
  ensure
    Mime::Type.unregister :json
    Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
  end

  private
    def assert_parses(expected, actual, headers = {})
      with_test_routing(UsersController) do
        post "/parse", params: actual, headers: headers
        assert_response :ok
        assert_equal(expected, UsersController.last_request_parameters)
        assert_equal(expected.merge("action" => "parse"), UsersController.last_parameters)
      end
    end

    def with_test_routing(controller)
      with_routing do |set|
        set.draw do
          ActiveSupport::Deprecation.silence do
            post ":action", to: controller
          end
        end
        yield
      end
    end
end