diff --git a/test/test_respond_to.rb b/test/test_respond_to.rb new file mode 100644 index 0000000..981f141 --- /dev/null +++ b/test/test_respond_to.rb @@ -0,0 +1,57 @@ +require 'minitest/autorun' +require 'prism' +require 'support' + +class WidgetsController < Prism::Controller + def show + respond_to do |format| + format.html { html("

widget #{params['id']}

") } + format.json { json(id: params['id'], kind: 'widget') } + end + end + + def flexible + respond_to do |format| + format.html { html('only html declared') } + end + end +end + +class WidgetsApp < Prism::Application + get '/widgets/:id', to: 'widgets#show', format: true + get '/flexible', to: 'widgets#flexible', format: true +end + +class RespondToTest < Minitest::Test + include TestSupport + + def call(method, path, **opts) + WidgetsApp.call(env_for(method, path, **opts)) + end + + def test_explicit_json_extension_wins_over_accept_header + status, headers, body = call('GET', '/widgets/7.json', headers: { 'Accept' => 'text/html' }) + assert_equal 200, status + assert_equal 'application/json', headers['Content-Type'] + assert_equal({ 'id' => '7', 'kind' => 'widget' }, JSON.parse(body.join)) + end + + def test_no_extension_falls_back_to_accept_header + status, headers, body = call('GET', '/widgets/7', headers: { 'Accept' => 'application/json' }) + assert_equal 200, status + assert_equal 'application/json', headers['Content-Type'] + assert_equal({ 'id' => '7', 'kind' => 'widget' }, JSON.parse(body.join)) + end + + def test_no_extension_no_accept_header_defaults_to_html + status, headers, body = call('GET', '/widgets/7') + assert_equal 200, status + assert_includes headers['Content-Type'], 'text/html' + assert_equal '

widget 7

', body.join + end + + def test_unhandled_format_is_406 + status, = call('GET', '/flexible.json') + assert_equal 406, status + end +end diff --git a/test/test_responder.rb b/test/test_responder.rb new file mode 100644 index 0000000..232357b --- /dev/null +++ b/test/test_responder.rb @@ -0,0 +1,60 @@ +require 'minitest/autorun' +require 'prism' + +class ResponderTest < Minitest::Test + def test_dispatches_to_matching_format_block + responder = Prism::Responder.new + responder.html { 'html-body' } + responder.json { 'json-body' } + + assert_equal 'html-body', responder.respond(:html) + assert_equal 'json-body', responder.respond(:json) + end + + def test_unknown_format_raises + responder = Prism::Responder.new + responder.html { 'html-body' } + + assert_raises(Prism::Responder::UnknownFormat) { responder.respond(:json) } + end + + def test_any_without_args_is_a_catch_all_fallback + responder = Prism::Responder.new + responder.html { 'html-body' } + responder.any { 'fallback' } + + assert_equal 'html-body', responder.respond(:html) + assert_equal 'fallback', responder.respond(:json) + assert_equal 'fallback', responder.respond(:xml) + end + + def test_any_with_explicit_formats_only_fills_those_in + responder = Prism::Responder.new + responder.any(:json, :xml) { 'api-fallback' } + + assert_equal 'api-fallback', responder.respond(:json) + assert_equal 'api-fallback', responder.respond(:xml) + assert_raises(Prism::Responder::UnknownFormat) { responder.respond(:html) } + end + + def test_any_does_not_override_an_explicit_block + responder = Prism::Responder.new + responder.json { 'explicit' } + responder.any { 'fallback' } + + assert_equal 'explicit', responder.respond(:json) + end + + def test_handles_predicate + responder = Prism::Responder.new + responder.html { 'x' } + + assert responder.handles?(:html) + refute responder.handles?(:json) + end + + def test_calling_a_format_method_without_a_block_raises + responder = Prism::Responder.new + assert_raises(NoMethodError) { responder.frobnicate } + end +end diff --git a/test/test_response.rb b/test/test_response.rb index 4175760..a651f03 100644 --- a/test/test_response.rb +++ b/test/test_response.rb @@ -29,4 +29,48 @@ class ResponseTest < Minitest::Test response.set_cookie('b', '2') assert_equal 2, response.headers['Set-Cookie'].split("\n").size end + + def test_stream_marks_the_response_as_streaming + response = Prism::Response.new + refute response.streaming? + response.stream { |out| out.write('x') } + assert response.streaming? + end + + def test_stream_body_is_a_streaming_body_not_wrapped_in_an_array + response = Prism::Response.new + response.stream { |out| out.write('x') } + _status, _headers, body = response.finish + assert_instance_of Prism::StreamingBody, body + end + + def test_streamed_chunks_are_produced_in_write_order + response = Prism::Response.new + response.stream do |out| + out.write('one') + out.write('two') + end + _status, _headers, body = response.finish + + collected = [] + body.each { |chunk| collected << chunk } + assert_equal %w[one two], collected + end + + # Regression: `body = value` used to run every assignment through + # Kernel#Array, which - given an object with neither #to_ary nor #to_a, + # like StreamingBody - wraps it as a one-element Array containing the + # streaming object itself instead of leaving it alone, breaking the + # #each-based chunking contract Server#write_response relies on. + def test_assigning_a_streaming_body_directly_is_not_wrapped_in_an_array + response = Prism::Response.new + response.body = Prism::StreamingBody.new { |out| out.write('x') } + assert_instance_of Prism::StreamingBody, response.body + end + + def test_assigning_an_ordinary_string_is_still_wrapped_in_an_array + response = Prism::Response.new + response.body = 'plain' + assert_equal ['plain'], response.body + end end