diff --git a/test/run_all.rb b/test/run_all.rb new file mode 100644 index 0000000..fa1309c --- /dev/null +++ b/test/run_all.rb @@ -0,0 +1,6 @@ +$LOAD_PATH.unshift(File.expand_path('../lib', __dir__)) +$LOAD_PATH.unshift(__dir__) + +require 'minitest/autorun' + +Dir[File.join(__dir__, 'test_*.rb')].sort.each { |file| require file } diff --git a/test/support.rb b/test/support.rb new file mode 100644 index 0000000..8b513ee --- /dev/null +++ b/test/support.rb @@ -0,0 +1,24 @@ +require 'prism' +require 'stringio' + +module TestSupport + def env_for(method, path, headers: {}, body: nil, cookies: nil) + path_part, query = path.split('?', 2) + env = { + 'REQUEST_METHOD' => method.to_s.upcase, + 'PATH_INFO' => path_part, + 'QUERY_STRING' => query.to_s, + 'rack.input' => StringIO.new(body || ''), + 'CONTENT_LENGTH' => (body ? body.bytesize.to_s : '0') + } + headers.each do |name, value| + if name.downcase == 'content-type' + env['CONTENT_TYPE'] = value + else + env["HTTP_#{name.upcase.tr('-', '_')}"] = value + end + end + env['HTTP_COOKIE'] = cookies if cookies + env + end +end diff --git a/test/test_inflector.rb b/test/test_inflector.rb new file mode 100644 index 0000000..155e102 --- /dev/null +++ b/test/test_inflector.rb @@ -0,0 +1,37 @@ +require 'minitest/autorun' +require 'prism' + +class InflectorTest < Minitest::Test + include Prism::Inflector + + def test_underscore + assert_equal 'posts_controller', underscore('PostsController') + assert_equal 'html_parser', underscore('HTMLParser') + end + + def test_camelize + assert_equal 'PostsController', camelize('posts_controller') + end + + def test_pluralize + assert_equal 'posts', pluralize('post') + assert_equal 'categories', pluralize('category') + assert_equal 'boxes', pluralize('box') + assert_equal 'leaves', pluralize('leaf') + end + + def test_singularize + assert_equal 'category', singularize('categories') + assert_equal 'post', singularize('posts') + assert_equal 'box', singularize('boxes') + end + + def test_tableize + assert_equal 'categories', tableize('Category') + assert_equal 'posts', tableize('Post') + end + + def test_classify + assert_equal 'Category', classify('categories') + end +end diff --git a/test/test_request.rb b/test/test_request.rb new file mode 100644 index 0000000..7ef944d --- /dev/null +++ b/test/test_request.rb @@ -0,0 +1,46 @@ +require 'minitest/autorun' +require 'prism' +require 'support' + +class RequestTest < Minitest::Test + include TestSupport + + def test_query_params + request = Prism::Request.new(env_for('GET', '/s?q=ruby&page=3')) + assert_equal 'ruby', request.params['q'] + assert_equal '3', request.params['page'] + end + + def test_json_body + payload = JSON.generate(name: 'foksiu', role: 'admin') + request = Prism::Request.new(env_for('POST', '/u', headers: { 'Content-Type' => 'application/json' }, body: payload)) + assert_equal 'foksiu', request.params['name'] + assert_equal 'admin', request.params[:role] + end + + def test_form_body + request = Prism::Request.new(env_for('POST', '/u', headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }, body: 'a=1&b=two')) + assert_equal '1', request.params['a'] + assert_equal 'two', request.params['b'] + end + + def test_cookies + request = Prism::Request.new(env_for('GET', '/', cookies: 'foo=bar; baz=qux')) + assert_equal 'bar', request.cookies['foo'] + assert_equal 'qux', request.cookies['baz'] + end + + def test_headers + request = Prism::Request.new(env_for('GET', '/', headers: { 'X-Custom' => 'yes' })) + assert_equal 'yes', request.headers['X-Custom'] + end + + def test_params_precedence + env = env_for('POST', '/x?id=query', + headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }, + body: 'id=body') + request = Prism::Request.new(env) + request.path_params = { 'id' => 'path' } + assert_equal 'path', request.params['id'] + end +end diff --git a/test/test_response.rb b/test/test_response.rb new file mode 100644 index 0000000..4175760 --- /dev/null +++ b/test/test_response.rb @@ -0,0 +1,32 @@ +require 'minitest/autorun' +require 'prism' + +class ResponseTest < Minitest::Test + def test_defaults + status, headers, body = Prism::Response.new.finish + assert_equal 200, status + assert_equal 'text/html;charset=utf-8', headers['Content-Type'] + assert_equal [], body + end + + def test_write + response = Prism::Response.new + response << 'a' + response.write('b') + assert_equal %w[a b], response.finish[2] + end + + def test_set_cookie + response = Prism::Response.new + response.set_cookie('token', 'abc def') + assert_includes response.headers['Set-Cookie'], 'token=abc+def' + assert_includes response.headers['Set-Cookie'], 'HttpOnly' + end + + def test_multiple_cookies + response = Prism::Response.new + response.set_cookie('a', '1') + response.set_cookie('b', '2') + assert_equal 2, response.headers['Set-Cookie'].split("\n").size + end +end diff --git a/test/test_router.rb b/test/test_router.rb new file mode 100644 index 0000000..53686cf --- /dev/null +++ b/test/test_router.rb @@ -0,0 +1,94 @@ +require 'minitest/autorun' +require 'prism' + +class RouterTest < Minitest::Test + def setup + @router = Prism::Router.new + end + + def test_static_match + @router.add('GET', '/health') {} + matches = @router.matches('GET', '/health') + assert_equal 1, matches.size + assert_equal({}, matches.first[1]) + end + + def test_named_param + @router.add('GET', '/users/:id') {} + _, params = @router.matches('GET', '/users/42').first + assert_equal '42', params['id'] + end + + def test_multiple_params + @router.add('GET', '/users/:uid/posts/:pid') {} + _, params = @router.matches('GET', '/users/7/posts/99').first + assert_equal '7', params['uid'] + assert_equal '99', params['pid'] + end + + def test_wildcard + @router.add('GET', '/files/*') {} + _, params = @router.matches('GET', '/files/a/b/c.txt').first + assert_equal ['a/b/c.txt'], params['splat'] + end + + def test_method_mismatch + @router.add('POST', '/submit') {} + assert_empty @router.matches('GET', '/submit') + end + + def test_no_match + @router.add('GET', '/x') {} + assert_empty @router.matches('GET', '/y') + end + + def test_param_unescape + @router.add('GET', '/say/:word') {} + _, params = @router.matches('GET', '/say/hello%20world').first + assert_equal 'hello world', params['word'] + end + + def test_dot_is_literal + @router.add('GET', '/a.b') {} + assert_empty @router.matches('GET', '/axb') + assert_equal 1, @router.matches('GET', '/a.b').size + end + + def test_all_http_verbs_supported + %w[GET POST PUT PATCH DELETE OPTIONS HEAD].each do |verb| + @router.add(verb, '/verb-check') {} + assert_equal 1, @router.matches(verb, '/verb-check').size, "#{verb} should match" + end + end + + def test_named_route_path + @router.add('GET', '/posts/:id', name: :post) {} + assert_equal '/posts/7', @router.path_to(:post, id: 7) + end + + def test_named_route_path_escapes_values + @router.add('GET', '/search/:term', name: :search) {} + assert_equal '/search/hello%20world', @router.path_to(:search, term: 'hello world') + end + + def test_named_route_missing_param_raises + @router.add('GET', '/posts/:id', name: :post) {} + assert_raises(ArgumentError) { @router.path_to(:post, {}) } + end + + def test_unknown_named_route_raises + assert_raises(ArgumentError) { @router.path_to(:nope) } + end + + def test_controller_route_flag + route = @router.add('GET', '/posts/:id', to: 'posts#show') + assert route.controller_route? + assert_equal 'posts', route.controller_name + assert_equal 'show', route.action_name + end + + def test_block_route_is_not_a_controller_route + route = @router.add('GET', '/health') {} + refute route.controller_route? + end +end