diff --git a/test/test_middleware_params.rb b/test/test_middleware_params.rb
new file mode 100644
index 0000000..d3eada3
--- /dev/null
+++ b/test/test_middleware_params.rb
@@ -0,0 +1,43 @@
+require 'minitest/autorun'
+require 'prism'
+require 'support'
+
+class MiddlewareParamsTest < Minitest::Test
+ include TestSupport
+
+ def setup
+ @seen_env = nil
+ downstream = lambda do |env|
+ @seen_env = env
+ [200, {}, ['ok']]
+ end
+ @app = Prism::Middleware::ParamsParser.new(downstream)
+ end
+
+ def test_valid_json_body_passes_through
+ env = env_for('POST', '/echo', headers: { 'Content-Type' => 'application/json' }, body: '{"a":1}')
+ status, = @app.call(env)
+ assert_equal 200, status
+ end
+
+ def test_malformed_json_body_returns_400_before_reaching_app
+ env = env_for('POST', '/echo', headers: { 'Content-Type' => 'application/json' }, body: '{not-json')
+ status, headers, body = @app.call(env)
+ assert_equal 400, status
+ assert_equal 'application/json', headers['Content-Type']
+ assert_includes JSON.parse(body.join)['error'], 'invalid JSON'
+ assert_nil @seen_env, 'downstream app must not run on malformed body'
+ end
+
+ def test_downstream_can_still_read_the_body_after_validation
+ env = env_for('POST', '/echo', headers: { 'Content-Type' => 'application/json' }, body: '{"a":1}')
+ @app.call(env)
+ assert_equal({ 'a' => 1 }, JSON.parse(@seen_env['rack.input'].read))
+ end
+
+ def test_non_json_body_is_left_alone
+ env = env_for('POST', '/echo', headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }, body: 'a=1')
+ status, = @app.call(env)
+ assert_equal 200, status
+ end
+end
diff --git a/test/test_middleware_static.rb b/test/test_middleware_static.rb
new file mode 100644
index 0000000..f236894
--- /dev/null
+++ b/test/test_middleware_static.rb
@@ -0,0 +1,71 @@
+require 'minitest/autorun'
+require 'prism'
+require 'tmpdir'
+require 'fileutils'
+
+class MiddlewareStaticTest < Minitest::Test
+ def setup
+ @root = Dir.mktmpdir('prism-static-root')
+ File.write(File.join(@root, 'index.html'), '
static
')
+ FileUtils.mkdir_p(File.join(@root, 'css'))
+ File.write(File.join(@root, 'css', 'app.css'), 'body { color: red; }')
+ @downstream = ->(env) { [404, {}, ["app: #{env['PATH_INFO']}"]] }
+ @app = Prism::Middleware::Static.new(@downstream, root: @root)
+ end
+
+ def teardown
+ FileUtils.remove_entry(@root)
+ end
+
+ def env_for(path, method: 'GET')
+ { 'REQUEST_METHOD' => method, 'PATH_INFO' => path }
+ end
+
+ def test_serves_existing_file
+ status, headers, body = @app.call(env_for('/index.html'))
+ assert_equal 200, status
+ assert_equal 'text/html;charset=utf-8', headers['Content-Type']
+ assert_equal 'static
', body.join
+ end
+
+ def test_serves_nested_file_with_correct_content_type
+ status, headers, body = @app.call(env_for('/css/app.css'))
+ assert_equal 200, status
+ assert_equal 'text/css', headers['Content-Type']
+ assert_equal 'body { color: red; }', body.join
+ end
+
+ def test_falls_through_to_app_when_file_missing
+ status, _, body = @app.call(env_for('/nope.html'))
+ assert_equal 404, status
+ assert_equal 'app: /nope.html', body.join
+ end
+
+ def test_blocks_path_traversal_outside_root
+ status, _, body = @app.call(env_for('/../../../../etc/passwd'))
+ assert_equal 404, status
+ assert_equal 'app: /../../../../etc/passwd', body.join
+ end
+
+ def test_serves_directory_index_when_requesting_a_folder
+ FileUtils.mkdir_p(File.join(@root, 'docs'))
+ File.write(File.join(@root, 'docs', 'index.html'), 'docs home
')
+ status, headers, body = @app.call(env_for('/docs'))
+ assert_equal 200, status
+ assert_equal 'text/html;charset=utf-8', headers['Content-Type']
+ assert_equal 'docs home
', body.join
+ end
+
+ def test_falls_through_when_directory_has_no_index_file
+ FileUtils.mkdir_p(File.join(@root, 'empty-dir'))
+ status, _, body = @app.call(env_for('/empty-dir'))
+ assert_equal 404, status
+ assert_equal 'app: /empty-dir', body.join
+ end
+
+ def test_ignores_non_get_head_requests
+ status, _, body = @app.call(env_for('/index.html', method: 'POST'))
+ assert_equal 404, status
+ assert_equal 'app: /index.html', body.join
+ end
+end