require 'abstract_unit'
class UrlEncodedParamsParsingTest < ActionController::IntegrationTest
class TestController < ActionController::Base
class << self
attr_accessor :last_request_parameters, :last_request_type
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 unbalanced query string with array" do
assert_parses(
{'location' => ["1", "2"], 'age_group' => ["2"]},
"location[]=1&location[]=2&age_group[]=2"
)
end
test "parses nested hash" do
query = [
"note[viewers][viewer][][type]=User",
"note[viewers][viewer][][id]=1",
"note[viewers][viewer][][type]=Group",
"note[viewers][viewer][][id]=2"
].join("&")
expected = { "note" => { "viewers"=>{"viewer"=>[{ "id"=>"1", "type"=>"User"}, {"type"=>"Group", "id"=>"2"} ]} } }
assert_parses(expected, query)
end
test "parses more complex nesting" do
query = [
"customers[boston][first][name]=David",
"customers[boston][first][url]=http://David",
"customers[boston][second][name]=Allan",
"customers[boston][second][url]=http://Allan",
"something_else=blah",
"something_nil=",
"something_empty=",
"products[first]=Apple Computer",
"products[second]=Pc",
"=Save"
].join("&")
expected = {
"customers" => {
"boston" => {
"first" => {
"name" => "David",
"url" => "http://David"
},
"second" => {
"name" => "Allan",
"url" => "http://Allan"
}
}
},
"something_else" => "blah",
"something_empty" => "",
"something_nil" => "",
"products" => {
"first" => "Apple Computer",
"second" => "Pc"
}
}
assert_parses expected, query
end
test "parses params with array" do
query = "selected[]=1&selected[]=2&selected[]=3"
expected = { "selected" => [ "1", "2", "3" ] }
assert_parses expected, query
end
test "parses params with non alphanumeric name" do
query = "a/b[c]=d"
expected = { "a/b" => { "c" => "d" }}
assert_parses expected, query
end
test "parses params with single brackets in the middle" do
query = "a/b[c]d=e"
expected = { "a/b" => {} }
assert_parses expected, query
end
test "parses params with separated brackets" do
query = "a/b@[c]d[e]=f"
expected = { "a/b@" => { }}
assert_parses expected, query
end
test "parses params with separated brackets and array" do
query = "a/b@[c]d[e][]=f"
expected = { "a/b@" => { }}
assert_parses expected, query
end
test "parses params with unmatched brackets and array" do
query = "a/b@[c][d[e][]=f"
expected = { "a/b@" => { "c" => { }}}
assert_parses expected, query
end
test "parses params with nil key" do
query = "=&test2=value1"
expected = { "test2" => "value1" }
assert_parses expected, query
end
test "parses params with array prefix and hashes" do
query = "a[][b][c]=d"
expected = {"a" => [{"b" => {"c" => "d"}}]}
assert_parses expected, query
end
test "parses params with complex nesting" do
query = "a[][b][c][][d][]=e"
expected = {"a" => [{"b" => {"c" => [{"d" => ["e"]}]}}]}
assert_parses expected, query
end
test "parses params with file path" do
query = [
"customers[boston][first][name]=David",
"something_else=blah",
"logo=#{File.expand_path(__FILE__)}"
].join("&")
expected = {
"customers" => {
"boston" => {
"first" => {
"name" => "David"
}
}
},
"something_else" => "blah",
"logo" => File.expand_path(__FILE__),
}
assert_parses expected, query
end
test "passes through rack middleware and parses params" do
with_muck_middleware do
assert_parses({ "a" => { "b" => "c" } }, "a[b]=c")
end
end
# The lint wrapper is used in integration tests
# instead of a normal StringIO class
InputWrapper = Rack::Lint::InputWrapper
test "passes through rack middleware and parses params with unwindable input" do
InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE)
with_muck_middleware do
assert_parses({ "a" => { "b" => "c" } }, "a[b]=c")
end
end
private
class MuckMiddleware
def initialize(app)
@app = app
end
def call(env)
req = Rack::Request.new(env)
req.params # Parse params
@app.call(env)
end
end
def with_muck_middleware
original_middleware = ActionController::Dispatcher.middleware
middleware = original_middleware.dup
middleware.insert_after ActionController::RewindableInput, MuckMiddleware
ActionController::Dispatcher.middleware = middleware
yield
ActionController::Dispatcher.middleware = original_middleware
end
def with_test_routing
with_routing do |set|
set.draw do |map|
map.connect ':action', :controller => "url_encoded_params_parsing_test/test"
end
yield
end
end
def assert_parses(expected, actual)
with_test_routing do
post "/parse", actual
assert_response :ok
assert_equal(expected, TestController.last_request_parameters)
end
end
end