rails--rails/actionpack/test/controller/routing_test.rb

648 lines
24 KiB
Ruby

require File.dirname(__FILE__) + '/../abstract_unit'
require 'test/unit'
RunTimeTests = ARGV.include? 'time'
module ActionController::CodeGeneration
class SourceTests < Test::Unit::TestCase
attr_accessor :source
def setup
@source = Source.new
end
def test_initial_state
assert_equal [], source.lines
assert_equal 0, source.indentation_level
end
def test_trivial_operations
source << "puts 'Hello World'"
assert_equal ["puts 'Hello World'"], source.lines
assert_equal "puts 'Hello World'", source.to_s
source.line "puts 'Goodbye World'"
assert_equal ["puts 'Hello World'", "puts 'Goodbye World'"], source.lines
assert_equal "puts 'Hello World'\nputs 'Goodbye World'", source.to_s
end
def test_indentation
source << "x = gets.to_i"
source << 'if x.odd?'
source.indent { source << "puts 'x is odd!'" }
source << 'else'
source.indent { source << "puts 'x is even!'" }
source << 'end'
assert_equal ["x = gets.to_i", "if x.odd?", " puts 'x is odd!'", 'else', " puts 'x is even!'", 'end'], source.lines
text = "x = gets.to_i
if x.odd?
puts 'x is odd!'
else
puts 'x is even!'
end"
assert_equal text, source.to_s
end
end
class CodeGeneratorTests < Test::Unit::TestCase
attr_accessor :generator
def setup
@generator = CodeGenerator.new
end
def test_initial_state
assert_equal [], generator.source.lines
assert_equal [], generator.locals
end
def test_trivial_operations
["puts 'Hello World'", "puts 'Goodbye World'"].each {|l| generator << l}
assert_equal ["puts 'Hello World'", "puts 'Goodbye World'"], generator.source.lines
assert_equal "puts 'Hello World'\nputs 'Goodbye World'", generator.to_s
end
def test_if
generator << "x = gets.to_i"
generator.if("x.odd?") { generator << "puts 'x is odd!'" }
assert_equal "x = gets.to_i\nif x.odd?\n puts 'x is odd!'\nend", generator.to_s
end
def test_else
test_if
generator.else { generator << "puts 'x is even!'" }
assert_equal "x = gets.to_i\nif x.odd?\n puts 'x is odd!'\nelse \n puts 'x is even!'\nend", generator.to_s
end
def test_dup
generator << 'x = 2'
generator.locals << :x
g = generator.dup
assert_equal generator.source, g.source
assert_equal generator.locals, g.locals
g << 'y = 3'
g.locals << :y
assert_equal [:x, :y], g.locals # Make sure they don't share the same array.
assert_equal [:x], generator.locals
end
end
# XXX Extract to test/controller/fake_controllers.rb
module Object::Controllers
def self.const_available?(*args)
const_defined?(*args)
end
class ContentController
end
module Admin
def self.const_available?(*args)
const_defined?(*args)
end
class UserController
end
end
end
class RecognitionTests < Test::Unit::TestCase
attr_accessor :generator
alias :g :generator
def setup
@generator = RecognitionGenerator.new
end
def go(components)
g.current = components.first
g.after = components[1..-1] || []
g.go
end
def execute(path, show = false)
path = path.split('/') if path.is_a? String
source = "index, path = 0, #{path.inspect}\n#{g.to_s}"
puts source if show
r = eval source
r ? r.symbolize_keys : nil
end
Static = ::ActionController::Routing::StaticComponent
Dynamic = ::ActionController::Routing::DynamicComponent
Path = ::ActionController::Routing::PathComponent
Controller = ::ActionController::Routing::ControllerComponent
def test_all_static
c = %w(hello world how are you).collect {|str| Static.new(str)}
g.result :controller, "::Controllers::ContentController", true
g.constant_result :action, 'index'
go c
assert_nil execute('x')
assert_nil execute('hello/world/how')
assert_nil execute('hello/world/how/are')
assert_nil execute('hello/world/how/are/you/today')
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, execute('hello/world/how/are/you'))
end
def test_basic_dynamic
c = [Static.new("hi"), Dynamic.new(:action)]
g.result :controller, "::Controllers::ContentController", true
go c
assert_nil execute('boo')
assert_nil execute('boo/blah')
assert_nil execute('hi')
assert_nil execute('hi/dude/what')
assert_equal({:controller => ::Controllers::ContentController, :action => 'dude'}, execute('hi/dude'))
end
def test_dynamic_with_default
c = [Static.new("hi"), Dynamic.new(:action, :default => 'index')]
g.result :controller, "::Controllers::ContentController", true
go c
assert_nil execute('boo')
assert_nil execute('boo/blah')
assert_nil execute('hi/dude/what')
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, execute('hi'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, execute('hi/index'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'dude'}, execute('hi/dude'))
end
def test_dynamic_with_string_condition
c = [Static.new("hi"), Dynamic.new(:action, :condition => 'index')]
g.result :controller, "::Controllers::ContentController", true
go c
assert_nil execute('boo')
assert_nil execute('boo/blah')
assert_nil execute('hi')
assert_nil execute('hi/dude/what')
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, execute('hi/index'))
assert_nil execute('hi/dude')
end
def test_dynamic_with_regexp_condition
c = [Static.new("hi"), Dynamic.new(:action, :condition => /^[a-z]+$/)]
g.result :controller, "::Controllers::ContentController", true
go c
assert_nil execute('boo')
assert_nil execute('boo/blah')
assert_nil execute('hi')
assert_nil execute('hi/FOXY')
assert_nil execute('hi/138708jkhdf')
assert_nil execute('hi/dkjfl8792343dfsf')
assert_nil execute('hi/dude/what')
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, execute('hi/index'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'dude'}, execute('hi/dude'))
end
def test_dynamic_with_regexp_and_default
c = [Static.new("hi"), Dynamic.new(:action, :condition => /^[a-z]+$/, :default => 'index')]
g.result :controller, "::Controllers::ContentController", true
go c
assert_nil execute('boo')
assert_nil execute('boo/blah')
assert_nil execute('hi/FOXY')
assert_nil execute('hi/138708jkhdf')
assert_nil execute('hi/dkjfl8792343dfsf')
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, execute('hi'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, execute('hi/index'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'dude'}, execute('hi/dude'))
assert_nil execute('hi/dude/what')
end
def test_path
c = [Static.new("hi"), Path.new(:file)]
g.result :controller, "::Controllers::ContentController", true
g.constant_result :action, "download"
go c
assert_nil execute('boo')
assert_nil execute('boo/blah')
assert_equal({:controller => ::Controllers::ContentController, :action => 'download', :file => []}, execute('hi'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'download', :file => %w(books agile_rails_dev.pdf)},
execute('hi/books/agile_rails_dev.pdf'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'download', :file => ['dude']}, execute('hi/dude'))
assert_equal 'dude/what', execute('hi/dude/what')[:file].to_s
end
def test_controller
c = [Static.new("hi"), Controller.new(:controller)]
g.constant_result :action, "hi"
go c
assert_nil execute('boo')
assert_nil execute('boo/blah')
assert_nil execute('hi/x')
assert_nil execute('hi/13870948')
assert_nil execute('hi/content/dog')
assert_nil execute('hi/admin/user/foo')
assert_equal({:controller => ::Controllers::ContentController, :action => 'hi'}, execute('hi/content'))
assert_equal({:controller => ::Controllers::Admin::UserController, :action => 'hi'}, execute('hi/admin/user'))
end
def test_standard_route(time = ::RunTimeTests)
c = [Controller.new(:controller), Dynamic.new(:action, :default => 'index'), Dynamic.new(:id, :default => nil)]
go c
# Make sure we get the right answers
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, execute('content'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'list'}, execute('content/list'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'show', :id => '10'}, execute('content/show/10'))
assert_equal({:controller => ::Controllers::Admin::UserController, :action => 'index'}, execute('admin/user'))
assert_equal({:controller => ::Controllers::Admin::UserController, :action => 'list'}, execute('admin/user/list'))
assert_equal({:controller => ::Controllers::Admin::UserController, :action => 'show', :id => 'nseckar'}, execute('admin/user/show/nseckar'))
assert_nil execute('content/show/10/20')
assert_nil execute('food')
if time
source = "def self.execute(path)
path = path.split('/') if path.is_a? String
index = 0
r = #{g.to_s}
end"
eval(source)
GC.start
n = 1000
time = Benchmark.realtime do n.times {
execute('content')
execute('content/list')
execute('content/show/10')
execute('admin/user')
execute('admin/user/list')
execute('admin/user/show/nseckar')
execute('admin/user/show/nseckar/dude')
execute('admin/why/show/nseckar')
execute('content/show/10/20')
execute('food')
} end
time -= Benchmark.realtime do n.times { } end
puts "\n\nRecognition:"
per_url = time / (n * 10)
puts "#{per_url * 1000} ms/url"
puts "#{1 / per_url} urls/s\n\n"
end
end
def test_default_route
g.result :controller, "::Controllers::ContentController", true
g.constant_result :action, 'index'
go []
assert_nil execute('x')
assert_nil execute('hello/world/how')
assert_nil execute('hello/world/how/are')
assert_nil execute('hello/world/how/are/you/today')
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, execute([]))
end
end
class GenerationTests < Test::Unit::TestCase
attr_accessor :generator
alias :g :generator
def setup
@generator = GenerationGenerator.new # ha!
end
def go(components)
g.current = components.first
g.after = components[1..-1] || []
g.go
end
def execute(options, recall, show = false)
source = "\n
expire_on = ::ActionController::Routing.expiry_hash(options, recall)
hash = merged = recall.merge(options)
not_expired = true
#{g.to_s}\n\n"
puts source if show
eval(source)
end
Static = ::ActionController::Routing::StaticComponent
Dynamic = ::ActionController::Routing::DynamicComponent
Path = ::ActionController::Routing::PathComponent
Controller = ::ActionController::Routing::ControllerComponent
def test_all_static_no_requirements
c = [Static.new("hello"), Static.new("world")]
go c
assert_equal "hello/world", execute({}, {})
end
def test_basic_dynamic
c = [Static.new("hi"), Dynamic.new(:action)]
go c
assert_equal 'hi/index', execute({:action => 'index'}, {:action => 'index'})
assert_equal 'hi/show', execute({:action => 'show'}, {:action => 'index'})
assert_equal 'hi/list+people', execute({}, {:action => 'list people'})
assert_nil execute({},{})
end
def test_dynamic_with_default
c = [Static.new("hi"), Dynamic.new(:action, :default => 'index')]
go c
assert_equal 'hi', execute({:action => 'index'}, {:action => 'index'})
assert_equal 'hi/show', execute({:action => 'show'}, {:action => 'index'})
assert_equal 'hi/list+people', execute({}, {:action => 'list people'})
assert_equal 'hi', execute({}, {})
end
def test_dynamic_with_regexp_condition
c = [Static.new("hi"), Dynamic.new(:action, :condition => /^[a-z]+$/)]
go c
assert_equal 'hi/index', execute({:action => 'index'}, {:action => 'index'})
assert_nil execute({:action => 'fox5'}, {:action => 'index'})
assert_nil execute({:action => 'something_is_up'}, {:action => 'index'})
assert_nil execute({}, {:action => 'list people'})
assert_equal 'hi/abunchofcharacter', execute({:action => 'abunchofcharacter'}, {})
assert_nil execute({}, {})
end
def test_dynamic_with_default_and_regexp_condition
c = [Static.new("hi"), Dynamic.new(:action, :default => 'index', :condition => /^[a-z]+$/)]
go c
assert_equal 'hi', execute({:action => 'index'}, {:action => 'index'})
assert_nil execute({:action => 'fox5'}, {:action => 'index'})
assert_nil execute({:action => 'something_is_up'}, {:action => 'index'})
assert_nil execute({}, {:action => 'list people'})
assert_equal 'hi/abunchofcharacter', execute({:action => 'abunchofcharacter'}, {})
assert_equal 'hi', execute({}, {})
end
def test_path
c = [Static.new("hi"), Path.new(:file)]
go c
assert_equal 'hi', execute({:file => []}, {})
assert_equal 'hi/books/agile_rails_dev.pdf', execute({:file => %w(books agile_rails_dev.pdf)}, {})
assert_equal 'hi/books/development%26whatever/agile_rails_dev.pdf', execute({:file => %w(books development&whatever agile_rails_dev.pdf)}, {})
assert_equal 'hi', execute({:file => ''}, {})
assert_equal 'hi/books/agile_rails_dev.pdf', execute({:file => 'books/agile_rails_dev.pdf'}, {})
assert_equal 'hi/books/development%26whatever/agile_rails_dev.pdf', execute({:file => 'books/development&whatever/agile_rails_dev.pdf'}, {})
end
def test_controller
c = [Static.new("hi"), Controller.new(:controller)]
go c
assert_nil execute({}, {})
assert_equal 'hi/content', execute({:controller => 'content'}, {})
assert_equal 'hi/admin/user', execute({:controller => 'admin/user'}, {})
assert_equal 'hi/content', execute({}, {:controller => 'content'})
assert_equal 'hi/admin/user', execute({}, {:controller => 'admin/user'})
end
def test_standard_route(time = ::RunTimeTests)
c = [Controller.new(:controller), Dynamic.new(:action, :default => 'index'), Dynamic.new(:id, :default => nil)]
go c
# Make sure we get the right answers
assert_equal('content', execute({:action => 'index'}, {:controller => 'content', :action => 'list'}))
assert_equal('content/list', execute({:action => 'list'}, {:controller => 'content', :action => 'index'}))
assert_equal('content/show/10', execute({:action => 'show', :id => '10'}, {:controller => 'content', :action => 'list'}))
assert_equal('admin/user', execute({:action => 'index'}, {:controller => 'admin/user', :action => 'list'}))
assert_equal('admin/user/list', execute({:action => 'list'}, {:controller => 'admin/user', :action => 'index'}))
assert_equal('admin/user/show/10', execute({:action => 'show', :id => '10'}, {:controller => 'admin/user', :action => 'list'}))
if time
GC.start
n = 1000
time = Benchmark.realtime do n.times {
execute({:action => 'index'}, {:controller => 'content', :action => 'list'})
execute({:action => 'list'}, {:controller => 'content', :action => 'index'})
execute({:action => 'show', :id => '10'}, {:controller => 'content', :action => 'list'})
execute({:action => 'index'}, {:controller => 'admin/user', :action => 'list'})
execute({:action => 'list'}, {:controller => 'admin/user', :action => 'index'})
execute({:action => 'show', :id => '10'}, {:controller => 'admin/user', :action => 'list'})
} end
time -= Benchmark.realtime do n.times { } end
puts "\n\nGeneration:"
per_url = time / (n * 6)
puts "#{per_url * 1000} ms/url"
puts "#{1 / per_url} urls/s\n\n"
end
end
def test_default_route
g.if(g.check_conditions(:controller => 'content', :action => 'welcome')) { go [] }
assert_nil execute({:controller => 'foo', :action => 'welcome'}, {})
assert_nil execute({:controller => 'content', :action => 'elcome'}, {})
assert_nil execute({:action => 'elcome'}, {:controller => 'content'})
assert_equal '', execute({:controller => 'content', :action => 'welcome'}, {})
assert_equal '', execute({:action => 'welcome'}, {:controller => 'content'})
assert_equal '', execute({:action => 'welcome', :id => '10'}, {:controller => 'content'})
end
end
class RouteTests < Test::Unit::TestCase
def route(*args)
@route = ::ActionController::Routing::Route.new(*args) unless args.empty?
return @route
end
def rec(path, show = false)
path = path.split('/') if path.is_a? String
index = 0
source = route.write_recognition.to_s
puts "\n\n#{source}\n\n" if show
r = eval(source)
r ? r.symbolize_keys : r
end
def gen(options, recall = nil, show = false)
recall ||= options.dup
expire_on = ::ActionController::Routing.expiry_hash(options, recall)
hash = merged = recall.merge(options)
not_expired = true
source = route.write_generation.to_s
puts "\n\n#{source}\n\n" if show
eval(source)
end
def test_static
route 'hello/world', :known => 'known_value'
assert_nil rec('hello/turn')
assert_nil rec('turn/world')
assert_equal({:known => 'known_value'}, rec('hello/world'))
assert_nil gen(:known => 'foo')
assert_nil gen({})
assert_equal 'hello/world', gen(:known => 'known_value')
assert_equal 'hello/world', gen(:known => 'known_value', :extra => 'hi')
assert_equal [:extra], route.extra_keys(:known => 'known_value', :extra => 'hi')
end
def test_dynamic
route 'hello/:name', :controller => 'content', :action => 'show_person'
assert_nil rec('hello')
assert_nil rec('foo/bar')
assert_equal({:controller => ::Controllers::ContentController, :action => 'show_person', :name => 'rails'}, rec('hello/rails'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'show_person', :name => 'Nicholas Seckar'}, rec('hello/Nicholas+Seckar'))
assert_nil gen(:controller => 'content', :action => 'show_dude', :name => 'rails')
assert_nil gen(:controller => 'content', :action => 'show_person')
assert_nil gen(:controller => 'admin/user', :action => 'show_person', :name => 'rails')
assert_equal 'hello/rails', gen(:controller => 'content', :action => 'show_person', :name => 'rails')
assert_equal 'hello/Nicholas+Seckar', gen(:controller => 'content', :action => 'show_person', :name => 'Nicholas Seckar')
end
def test_typical
route ':controller/:action/:id', :action => 'index', :id => nil
assert_nil rec('hello')
assert_nil rec('foo bar')
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}, rec('content'))
assert_equal({:controller => ::Controllers::Admin::UserController, :action => 'index'}, rec('admin/user'))
assert_equal({:controller => ::Controllers::Admin::UserController, :action => 'index'}, rec('admin/user/index'))
assert_equal({:controller => ::Controllers::Admin::UserController, :action => 'list'}, rec('admin/user/list'))
assert_equal({:controller => ::Controllers::Admin::UserController, :action => 'show', :id => '10'}, rec('admin/user/show/10'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'list'}, rec('content/list'))
assert_equal({:controller => ::Controllers::ContentController, :action => 'show', :id => '10'}, rec('content/show/10'))
assert_equal 'content', gen(:controller => 'content', :action => 'index')
assert_equal 'content/list', gen(:controller => 'content', :action => 'list')
assert_equal 'content/show/10', gen(:controller => 'content', :action => 'show', :id => '10')
assert_equal 'admin/user', gen(:controller => 'admin/user', :action => 'index')
assert_equal 'admin/user', gen(:controller => 'admin/user')
assert_equal 'admin/user', gen({:controller => 'admin/user'}, {:controller => 'content', :action => 'list', :id => '10'})
assert_equal 'admin/user/show/10', gen(:controller => 'admin/user', :action => 'show', :id => '10')
end
end
class RouteSetTests < Test::Unit::TestCase
attr_reader :rs
def setup
@rs = ::ActionController::Routing::RouteSet.new
@rs.draw {|m| m.connect ':controller/:action/:id' }
end
def test_default_setup
assert_equal({:controller => ::Controllers::ContentController, :action => 'index'}.stringify_keys, rs.recognize_path(%w(content)))
assert_equal({:controller => ::Controllers::ContentController, :action => 'list'}.stringify_keys, rs.recognize_path(%w(content list)))
assert_equal({:controller => ::Controllers::ContentController, :action => 'show', :id => '10'}.stringify_keys, rs.recognize_path(%w(content show 10)))
assert_equal({:controller => ::Controllers::Admin::UserController, :action => 'show', :id => '10'}.stringify_keys, rs.recognize_path(%w(admin user show 10)))
assert_equal ['admin/user/show/10', {}], rs.generate({:controller => 'admin/user', :action => 'show', :id => 10})
assert_equal ['admin/user/show', {}], rs.generate({:action => 'show'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
assert_equal ['admin/user/list/10', {}], rs.generate({}, {:controller => 'admin/user', :action => 'list', :id => '10'})
end
def test_time_recognition
n = 10000
if RunTimeTests
GC.start
rectime = Benchmark.realtime do
n.times do
rs.recognize_path(%w(content))
rs.recognize_path(%w(content list))
rs.recognize_path(%w(content show 10))
rs.recognize_path(%w(admin user))
rs.recognize_path(%w(admin user list))
rs.recognize_path(%w(admin user show 10))
end
end
puts "\n\nRecognition (RouteSet):"
per_url = rectime / (n * 6)
puts "#{per_url * 1000} ms/url"
puts "#{1 / per_url} url/s\n\n"
end
end
def test_time_generation
n = 5000
if RunTimeTests
GC.start
pairs = [
[{:controller => 'content', :action => 'index'}, {:controller => 'content', :action => 'show'}],
[{:controller => 'content'}, {:controller => 'content', :action => 'index'}],
[{:controller => 'content', :action => 'list'}, {:controller => 'content', :action => 'index'}],
[{:controller => 'content', :action => 'show', :id => '10'}, {:controller => 'content', :action => 'list'}],
[{:controller => 'admin/user', :action => 'index'}, {:controller => 'admin/user', :action => 'show'}],
[{:controller => 'admin/user'}, {:controller => 'admin/user', :action => 'index'}],
[{:controller => 'admin/user', :action => 'list'}, {:controller => 'admin/user', :action => 'index'}],
[{:controller => 'admin/user', :action => 'show', :id => '10'}, {:controller => 'admin/user', :action => 'list'}],
]
p = nil
gentime = Benchmark.realtime do
n.times do
pairs.each {|(a, b)| rs.generate(a, b)}
end
end
puts "\n\nGeneration (RouteSet): (#{(n * 8)} urls)"
per_url = gentime / (n * 8)
puts "#{per_url * 1000} ms/url"
puts "#{1 / per_url} url/s\n\n"
end
end
def test_basic_named_route
rs.home '', :controller => 'content', :action => 'list'
x = setup_for_named_route
assert_equal({:controller => 'content', :action => 'list'},
x.new.send(:home_url))
end
def test_named_route_with_option
rs.page 'page/:title', :controller => 'content', :action => 'show_page'
x = setup_for_named_route
assert_equal({:controller => 'content', :action => 'show_page', :title => 'new stuff'},
x.new.send(:page_url, :title => 'new stuff'))
end
def setup_for_named_route
x = Class.new
x.send(:define_method, :url_for) {|x| x}
x.send :include, ::ActionController::Routing::NamedRoutes
x
end
end
end