Merge branch 'bzr/golem' of /Users/distler/Sites/code/instiki

This commit is contained in:
Jacques Distler 2009-11-30 19:40:48 -06:00
commit 17b1e6e96e
187 changed files with 2316 additions and 891 deletions

View file

@ -212,11 +212,11 @@ class AdminControllerTest < ActionController::TestCase
def test_remove_orphaned_pages def test_remove_orphaned_pages
@wiki.system.update_attribute(:password, 'pswd') @wiki.system.update_attribute(:password, 'pswd')
page_order = [@home, pages(:my_way), @oak, pages(:smart_engine), pages(:that_way), @liquor] page_order = [@home, pages(:my_way), @oak, pages(:smart_engine), pages(:that_way), @liquor]
test_renderer(@web.page('liquor').revisions.last).display_content(true) x_test_renderer(@web.page('liquor').revisions.last).display_content(true)
orphan_page_linking_to_oak_and_redirecting_to_liquor = @wiki.write_page('wiki1', 'Pine', orphan_page_linking_to_oak_and_redirecting_to_liquor = @wiki.write_page('wiki1', 'Pine',
"Refers to [[Oak]] and to [[booze]].\n" + "Refers to [[Oak]] and to [[booze]].\n" +
"category: trees", "category: trees",
Time.now, Author.new('TreeHugger', '127.0.0.2'), test_renderer) Time.now, Author.new('TreeHugger', '127.0.0.2'), x_test_renderer)
r = process('remove_orphaned_pages', 'web' => 'wiki1', 'system_password_orphaned' => 'pswd') r = process('remove_orphaned_pages', 'web' => 'wiki1', 'system_password_orphaned' => 'pswd')
@ -249,7 +249,7 @@ class AdminControllerTest < ActionController::TestCase
orphan_page_linking_to_oak = @wiki.write_page('wiki1', 'Pine', orphan_page_linking_to_oak = @wiki.write_page('wiki1', 'Pine',
"Refers to [[Oak]].\n" + "Refers to [[Oak]].\n" +
"category: trees", "category: trees",
Time.now, Author.new('TreeHugger', '127.0.0.2'), test_renderer) Time.now, Author.new('TreeHugger', '127.0.0.2'), x_test_renderer)
r = process('remove_orphaned_pages_in_category', 'web' => 'wiki1', 'category' => 'trees','system_password_orphaned_in_category' => 'pswd') r = process('remove_orphaned_pages_in_category', 'web' => 'wiki1', 'category' => 'trees','system_password_orphaned_in_category' => 'pswd')

View file

@ -55,7 +55,7 @@ class WikiControllerTest < ActionController::TestCase
def test_authors def test_authors
@wiki.write_page('wiki1', 'BreakSortingOrder', @wiki.write_page('wiki1', 'BreakSortingOrder',
"This page breaks the accidentally correct sorting order of authors", "This page breaks the accidentally correct sorting order of authors",
Time.now, Author.new('BreakingTheOrder', '127.0.0.2'), test_renderer) Time.now, Author.new('BreakingTheOrder', '127.0.0.2'), x_test_renderer)
r = process('authors', 'web' => 'wiki1') r = process('authors', 'web' => 'wiki1')
@ -106,7 +106,7 @@ class WikiControllerTest < ActionController::TestCase
def test_edit_page_with_special_symbols def test_edit_page_with_special_symbols
@wiki.write_page('wiki1', 'With : Special /> symbols', @wiki.write_page('wiki1', 'With : Special /> symbols',
'This page has special symbols in the name', Time.now, Author.new('Special', '127.0.0.3'), 'This page has special symbols in the name', Time.now, Author.new('Special', '127.0.0.3'),
test_renderer) x_test_renderer)
r = process 'edit', 'web' => 'wiki1', 'id' => 'With : Special /> symbols' r = process 'edit', 'web' => 'wiki1', 'id' => 'With : Special /> symbols'
assert_response(:success) assert_response(:success)
@ -118,7 +118,7 @@ class WikiControllerTest < ActionController::TestCase
def test_export_xhtml def test_export_xhtml
@request.accept = 'application/xhtml+xml' @request.accept = 'application/xhtml+xml'
# rollback homepage to a version that is easier to match # rollback homepage to a version that is easier to match
@home.rollback(0, Time.now, 'Rick', test_renderer) @home.rollback(0, Time.now, 'Rick', x_test_renderer)
r = process 'export_html', 'web' => 'wiki1' r = process 'export_html', 'web' => 'wiki1'
assert_response(:success, bypass_body_parsing = true) assert_response(:success, bypass_body_parsing = true)
@ -149,7 +149,7 @@ class WikiControllerTest < ActionController::TestCase
def test_export_html def test_export_html
@request.accept = 'tex/html' @request.accept = 'tex/html'
# rollback homepage to a version that is easier to match # rollback homepage to a version that is easier to match
@home.rollback(0, Time.now, 'Rick', test_renderer) @home.rollback(0, Time.now, 'Rick', x_test_renderer)
r = process 'export_html', 'web' => 'wiki1' r = process 'export_html', 'web' => 'wiki1'
assert_response(:success, bypass_body_parsing = true) assert_response(:success, bypass_body_parsing = true)
@ -423,7 +423,7 @@ class WikiControllerTest < ActionController::TestCase
page2 = @wiki.write_page('wiki1', 'Page2', page2 = @wiki.write_page('wiki1', 'Page2',
"Page2 contents.\n" + "Page2 contents.\n" +
"category: categorized", "category: categorized",
Time.now, Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Time.now, Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
r = process('recently_revised', 'web' => 'wiki1') r = process('recently_revised', 'web' => 'wiki1')
assert_response(:success) assert_response(:success)
@ -508,7 +508,7 @@ class WikiControllerTest < ActionController::TestCase
def test_atom_with_headlines def test_atom_with_headlines
@title_with_spaces = @wiki.write_page('wiki1', 'Title With Spaces', @title_with_spaces = @wiki.write_page('wiki1', 'Title With Spaces',
'About spaces', 1.hour.ago, Author.new('TreeHugger', '127.0.0.2'), test_renderer) 'About spaces', 1.hour.ago, Author.new('TreeHugger', '127.0.0.2'), x_test_renderer)
@request.host = 'localhost' @request.host = 'localhost'
@request.port = 8080 @request.port = 8080
@ -622,7 +622,7 @@ class WikiControllerTest < ActionController::TestCase
# Since we're declaring <title> to be of type="html", the content is unescaped once before interpreting. # Since we're declaring <title> to be of type="html", the content is unescaped once before interpreting.
# Evidently, the desired behaviour is that the final result be HTML-encoded. Hence the double-encoding here. # Evidently, the desired behaviour is that the final result be HTML-encoded. Hence the double-encoding here.
@wiki.write_page('wiki1', 'Title&With&Ampersands', @wiki.write_page('wiki1', 'Title&With&Ampersands',
'About spaces', 1.hour.ago, Author.new('NitPicker', '127.0.0.3'), test_renderer) 'About spaces', 1.hour.ago, Author.new('NitPicker', '127.0.0.3'), x_test_renderer)
r = process 'atom_with_headlines', 'web' => 'wiki1' r = process 'atom_with_headlines', 'web' => 'wiki1'
@ -633,7 +633,7 @@ class WikiControllerTest < ActionController::TestCase
def test_atom_timestamp def test_atom_timestamp
new_page = @wiki.write_page('wiki1', 'PageCreatedAtTheBeginningOfCtime', new_page = @wiki.write_page('wiki1', 'PageCreatedAtTheBeginningOfCtime',
'Created on 1 Jan 1970 at 0:00:00 Z', Time.at(0), Author.new('NitPicker', '127.0.0.3'), 'Created on 1 Jan 1970 at 0:00:00 Z', Time.at(0), Author.new('NitPicker', '127.0.0.3'),
test_renderer) x_test_renderer)
r = process 'atom_with_headlines', 'web' => 'wiki1' r = process 'atom_with_headlines', 'web' => 'wiki1'
assert_tag :tag =>'published', assert_tag :tag =>'published',
@ -921,7 +921,7 @@ class WikiControllerTest < ActionController::TestCase
def test_show_page_with_multiple_revisions def test_show_page_with_multiple_revisions
@wiki.write_page('wiki1', 'HomePage', 'Second revision of the HomePage end', Time.now, @wiki.write_page('wiki1', 'HomePage', 'Second revision of the HomePage end', Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
r = process('show', 'id' => 'HomePage', 'web' => 'wiki1') r = process('show', 'id' => 'HomePage', 'web' => 'wiki1')
@ -931,7 +931,7 @@ class WikiControllerTest < ActionController::TestCase
def test_recursive_include def test_recursive_include
@wiki.write_page('wiki1', 'HomePage', 'Self-include: [[!include HomePage]]', Time.now, @wiki.write_page('wiki1', 'HomePage', 'Self-include: [[!include HomePage]]', Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
r = process('show', 'id' => 'HomePage', 'web' => 'wiki1') r = process('show', 'id' => 'HomePage', 'web' => 'wiki1')
@ -941,9 +941,9 @@ class WikiControllerTest < ActionController::TestCase
def test_recursive_include_II def test_recursive_include_II
@wiki.write_page('wiki1', 'Foo', "extra fun [[!include HomePage]]", Time.now, @wiki.write_page('wiki1', 'Foo', "extra fun [[!include HomePage]]", Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
@wiki.write_page('wiki1', 'HomePage', "Recursive-include:\n\n[[!include Foo]]", Time.now, @wiki.write_page('wiki1', 'HomePage', "Recursive-include:\n\n[[!include Foo]]", Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
r = process('show', 'id' => 'HomePage', 'web' => 'wiki1') r = process('show', 'id' => 'HomePage', 'web' => 'wiki1')
@ -953,11 +953,11 @@ class WikiControllerTest < ActionController::TestCase
def test_recursive_include_III def test_recursive_include_III
@wiki.write_page('wiki1', 'Bar', "extra fun\n\n[[!include HomePage]]", Time.now, @wiki.write_page('wiki1', 'Bar', "extra fun\n\n[[!include HomePage]]", Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
@wiki.write_page('wiki1', 'Foo', "[[!include Bar]]\n\n[[!include Bar]]", Time.now, @wiki.write_page('wiki1', 'Foo', "[[!include Bar]]\n\n[[!include Bar]]", Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
@wiki.write_page('wiki1', 'HomePage', "Recursive-include:\n\n[[!include Foo]]", Time.now, @wiki.write_page('wiki1', 'HomePage', "Recursive-include:\n\n[[!include Foo]]", Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
r = process('show', 'id' => 'HomePage', 'web' => 'wiki1') r = process('show', 'id' => 'HomePage', 'web' => 'wiki1')
@ -967,11 +967,11 @@ class WikiControllerTest < ActionController::TestCase
def test_nonrecursive_include def test_nonrecursive_include
@wiki.write_page('wiki1', 'Bar', "extra fun\n\n[[HomePage]]", Time.now, @wiki.write_page('wiki1', 'Bar', "extra fun\n\n[[HomePage]]", Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
@wiki.write_page('wiki1', 'Foo', "[[!include Bar]]\n\n[[!include Bar]]", Time.now, @wiki.write_page('wiki1', 'Foo', "[[!include Bar]]\n\n[[!include Bar]]", Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
@wiki.write_page('wiki1', 'HomePage', "Nonrecursive-include:\n\n[[!include Foo]]", Time.now, @wiki.write_page('wiki1', 'HomePage', "Nonrecursive-include:\n\n[[!include Foo]]", Time.now,
Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
r = process('show', 'id' => 'HomePage', 'web' => 'wiki1') r = process('show', 'id' => 'HomePage', 'web' => 'wiki1')
@ -1258,7 +1258,7 @@ HisWay would be MyWay $\sin(x) \includegraphics[width=3em]{foo}$ in kinda ThatWa
def test_tex_with_blackboard_digits def test_tex_with_blackboard_digits
@wiki.write_page('wiki1', 'Page2', @wiki.write_page('wiki1', 'Page2',
"Page2 contents $\\mathbb{01234}$.\n", "Page2 contents $\\mathbb{01234}$.\n",
Time.now, Author.new('AnotherAuthor', '127.0.0.2'), test_renderer) Time.now, Author.new('AnotherAuthor', '127.0.0.2'), x_test_renderer)
r = process('tex', 'web' => 'wiki1', 'id' => 'Page2') r = process('tex', 'web' => 'wiki1', 'id' => 'Page2')
assert_response(:success) assert_response(:success)

View file

@ -43,13 +43,13 @@ class Test::Unit::TestCase
(1..30).each do |i| (1..30).each do |i|
@wiki.write_page('wiki1', "page#{i}", "Test page #{i}\ncategory: test", @wiki.write_page('wiki1', "page#{i}", "Test page #{i}\ncategory: test",
Time.local(1976, 10, i, 12, 00, 00), Author.new('Dema', '127.0.0.2'), Time.local(1976, 10, i, 12, 00, 00), Author.new('Dema', '127.0.0.2'),
test_renderer) x_test_renderer)
end end
end end
@web = Web.find(@web.id) @web = Web.find(@web.id)
end end
def test_renderer(revision = nil) def x_test_renderer(revision = nil)
PageRenderer.setup_url_generator(StubUrlGenerator.new) PageRenderer.setup_url_generator(StubUrlGenerator.new)
PageRenderer.new(revision) PageRenderer.new(revision)
end end

View file

@ -15,14 +15,14 @@ class PageRendererTest < ActiveSupport::TestCase
def test_wiki_word_linking def test_wiki_word_linking
@web.add_page('SecondPage', 'Yo, yo. Have you EverBeenHated', @web.add_page('SecondPage', 'Yo, yo. Have you EverBeenHated',
Time.now, 'DavidHeinemeierHansson', test_renderer) Time.now, 'DavidHeinemeierHansson', x_test_renderer)
assert_equal("<p>Yo, yo. Have you <span class='newWikiWord'>Ever Been Hated" + assert_equal("<p>Yo, yo. Have you <span class='newWikiWord'>Ever Been Hated" +
"<a href='../show/EverBeenHated'>?</a></span></p>", "<a href='../show/EverBeenHated'>?</a></span></p>",
rendered_content(@web.page("SecondPage"))) rendered_content(@web.page("SecondPage")))
@web.add_page('EverBeenHated', 'Yo, yo. Have you EverBeenHated', Time.now, @web.add_page('EverBeenHated', 'Yo, yo. Have you EverBeenHated', Time.now,
'DavidHeinemeierHansson', test_renderer) 'DavidHeinemeierHansson', x_test_renderer)
assert_equal("<p>Yo, yo. Have you <a class='existingWikiWord' " + assert_equal("<p>Yo, yo. Have you <a class='existingWikiWord' " +
"href='../show/EverBeenHated'>Ever Been Hated</a></p>", "href='../show/EverBeenHated'>Ever Been Hated</a></p>",
rendered_content(@web.page("SecondPage"))) rendered_content(@web.page("SecondPage")))
@ -30,18 +30,18 @@ class PageRendererTest < ActiveSupport::TestCase
def test_wiki_words def test_wiki_words
assert_equal %w( HisWay MyWay SmartEngine SmartEngineGUI ThatWay ), assert_equal %w( HisWay MyWay SmartEngine SmartEngineGUI ThatWay ),
test_renderer(@revision).wiki_words.sort x_test_renderer(@revision).wiki_words.sort
@wiki.write_page('wiki1', 'NoWikiWord', 'hey you!', Time.now, 'Me', test_renderer) @wiki.write_page('wiki1', 'NoWikiWord', 'hey you!', Time.now, 'Me', x_test_renderer)
assert_equal [], test_renderer(@wiki.read_page('wiki1', 'NoWikiWord').revisions.last).wiki_words assert_equal [], x_test_renderer(@wiki.read_page('wiki1', 'NoWikiWord').revisions.last).wiki_words
end end
def test_existing_pages def test_existing_pages
assert_equal %w( MyWay SmartEngine ThatWay ), test_renderer(@revision).existing_pages.sort assert_equal %w( MyWay SmartEngine ThatWay ), x_test_renderer(@revision).existing_pages.sort
end end
def test_unexisting_pages def test_unexisting_pages
assert_equal %w( HisWay SmartEngineGUI ), test_renderer(@revision).unexisting_pages.sort assert_equal %w( HisWay SmartEngineGUI ), x_test_renderer(@revision).unexisting_pages.sort
end end
def test_content_with_wiki_links def test_content_with_wiki_links
@ -56,7 +56,7 @@ class PageRendererTest < ActiveSupport::TestCase
"<a class='existingWikiWord' href='../show/SmartEngine'>Smart Engine</a> in that " + "<a class='existingWikiWord' href='../show/SmartEngine'>Smart Engine</a> in that " +
"<span class='newWikiWord'>Smart Engine GUI" + "<span class='newWikiWord'>Smart Engine GUI" +
"<a href='../show/SmartEngineGUI'>?</a></span></p>", "<a href='../show/SmartEngineGUI'>?</a></span></p>",
test_renderer(@revision).display_content x_test_renderer(@revision).display_content
end end
def test_markdown def test_markdown
@ -349,7 +349,7 @@ END_THM
assert_equal "<tt>hello</tt> that <span class='newWikiWord'>Smart Engine GUI" + assert_equal "<tt>hello</tt> that <span class='newWikiWord'>Smart Engine GUI" +
"<a href='../show/SmartEngineGUI'>?</a></span>\n\n", "<a href='../show/SmartEngineGUI'>?</a></span>\n\n",
test_renderer(@revision).display_content x_test_renderer(@revision).display_content
end end
# def test_content_with_auto_links # def test_content_with_auto_links
@ -555,7 +555,7 @@ END_THM
%{<a class='existingWikiWord' href='MyWay.html'>My Way</a> OverThere \342\200\223 see } + %{<a class='existingWikiWord' href='MyWay.html'>My Way</a> OverThere \342\200\223 see } +
"<a class='existingWikiWord' href='SmartEngine.html'>Smart Engine</a> in that " + "<a class='existingWikiWord' href='SmartEngine.html'>Smart Engine</a> in that " +
"<span class='newWikiWord'>Smart Engine GUI</span></p>", "<span class='newWikiWord'>Smart Engine GUI</span></p>",
test_renderer(@revision).display_content_for_export x_test_renderer(@revision).display_content_for_export
end end
def test_double_replacing def test_double_replacing
@ -564,21 +564,21 @@ END_THM
"<a href='../show/VersionHistory'>?</a></span></p>\n\n<p>cry " + "<a href='../show/VersionHistory'>?</a></span></p>\n\n<p>cry " +
"<span class='newWikiWord'>Version History<a href='../show/VersionHistory'>?</a>" + "<span class='newWikiWord'>Version History<a href='../show/VersionHistory'>?</a>" +
'</span></p>', '</span></p>',
test_renderer(@revision).display_content x_test_renderer(@revision).display_content
@revision.content = "f\r\nVersionHistory\r\n\r\ncry VersionHistory" @revision.content = "f\r\nVersionHistory\r\n\r\ncry VersionHistory"
assert_equal "<p>f <span class='newWikiWord'>Version History" + assert_equal "<p>f <span class='newWikiWord'>Version History" +
"<a href='../show/VersionHistory'>?</a></span></p>\n\n<p>cry " + "<a href='../show/VersionHistory'>?</a></span></p>\n\n<p>cry " +
"<span class='newWikiWord'>Version History<a href='../show/VersionHistory'>?</a>" + "<span class='newWikiWord'>Version History<a href='../show/VersionHistory'>?</a>" +
"</span></p>", "</span></p>",
test_renderer(@revision).display_content x_test_renderer(@revision).display_content
end end
def test_difficult_wiki_words def test_difficult_wiki_words
@revision.content = "[[It's just awesome GUI!]]" @revision.content = "[[It's just awesome GUI!]]"
assert_equal "<p><span class='newWikiWord'>It&#39;s just awesome GUI!" + assert_equal "<p><span class='newWikiWord'>It&#39;s just awesome GUI!" +
"<a href='../show/It%27s+just+awesome+GUI%21'>?</a></span></p>", "<a href='../show/It%27s+just+awesome+GUI%21'>?</a></span></p>",
test_renderer(@revision).display_content x_test_renderer(@revision).display_content
end end
def test_revisions_diff def test_revisions_diff
@ -589,7 +589,7 @@ END_THM
@page.reload @page.reload
assert_equal "<p><span> What a<del class='diffmod'> blue</del><ins class='diffmod'> red" + assert_equal "<p><span> What a<del class='diffmod'> blue</del><ins class='diffmod'> red" +
"</ins> and lovely morning<ins class='diffins'> today</ins></span></p>", test_renderer(@page.revisions.last).display_diff "</ins> and lovely morning<ins class='diffins'> today</ins></span></p>", x_test_renderer(@page.revisions.last).display_diff
end end
def test_nowiki_sanitization def test_nowiki_sanitization
@ -687,7 +687,7 @@ END_THM
def test_references_creation_links def test_references_creation_links
new_page = @web.add_page('NewPage', 'HomePage NewPage', new_page = @web.add_page('NewPage', 'HomePage NewPage',
Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', test_renderer) Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', x_test_renderer)
references = new_page.wiki_references(true) references = new_page.wiki_references(true)
assert_equal 2, references.size assert_equal 2, references.size
@ -699,7 +699,7 @@ END_THM
def test_references_creation_includes def test_references_creation_includes
new_page = @web.add_page('NewPage', '[[!include IncludedPage]]', new_page = @web.add_page('NewPage', '[[!include IncludedPage]]',
Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', test_renderer) Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', x_test_renderer)
references = new_page.wiki_references(true) references = new_page.wiki_references(true)
assert_equal 1, references.size assert_equal 1, references.size
@ -709,7 +709,7 @@ END_THM
def test_references_creation_categories def test_references_creation_categories
new_page = @web.add_page('NewPage', "Foo\ncategory: NewPageCategory", new_page = @web.add_page('NewPage', "Foo\ncategory: NewPageCategory",
Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', test_renderer) Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', x_test_renderer)
references = new_page.wiki_references(true) references = new_page.wiki_references(true)
assert_equal 1, references.size assert_equal 1, references.size
@ -719,7 +719,7 @@ END_THM
def test_references_creation_sanitized_categories def test_references_creation_sanitized_categories
new_page = @web.add_page('NewPage', "Foo\ncategory: <script>alert('XSS');</script>", new_page = @web.add_page('NewPage', "Foo\ncategory: <script>alert('XSS');</script>",
Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', test_renderer) Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', x_test_renderer)
references = new_page.wiki_references(true) references = new_page.wiki_references(true)
assert_equal 1, references.size assert_equal 1, references.size
@ -728,49 +728,49 @@ END_THM
end end
def test_rendering_included_page_under_different_modes def test_rendering_included_page_under_different_modes
included = @web.add_page('Included', 'link to HomePage', Time.now, 'AnAuthor', test_renderer) included = @web.add_page('Included', 'link to HomePage', Time.now, 'AnAuthor', x_test_renderer)
main = @web.add_page('Main', '[[!include Included]]', Time.now, 'AnAuthor', test_renderer) main = @web.add_page('Main', '[[!include Included]]', Time.now, 'AnAuthor', x_test_renderer)
assert_equal "<p>link to <a class='existingWikiWord' href='../show/HomePage'>Home Page</a></p>", assert_equal "<p>link to <a class='existingWikiWord' href='../show/HomePage'>Home Page</a></p>",
test_renderer(main).display_content x_test_renderer(main).display_content
assert_equal "<p>link to <a class='existingWikiWord' href='../published/HomePage'>Home Page</a></p>", assert_equal "<p>link to <a class='existingWikiWord' href='../published/HomePage'>Home Page</a></p>",
test_renderer(main).display_published x_test_renderer(main).display_published
assert_equal "<p>link to <a class='existingWikiWord' href='HomePage.html'>Home Page</a></p>", assert_equal "<p>link to <a class='existingWikiWord' href='HomePage.html'>Home Page</a></p>",
test_renderer(main).display_content_for_export x_test_renderer(main).display_content_for_export
end end
def test_rendering_included_page_backslashes_in_equations def test_rendering_included_page_backslashes_in_equations
included = @web.add_page('Included', '\\\\ $\begin{matrix} a \\\\ b\end{matrix}$', Time.now, 'AnAuthor', test_renderer) included = @web.add_page('Included', '\\\\ $\begin{matrix} a \\\\ b\end{matrix}$', Time.now, 'AnAuthor', x_test_renderer)
main = @web.add_page('Main', '[[!include Included]]', Time.now, 'AnAuthor', test_renderer) main = @web.add_page('Main', '[[!include Included]]', Time.now, 'AnAuthor', x_test_renderer)
assert_equal "<p>\\ <math class='maruku-mathml' display='inline' " + assert_equal "<p>\\ <math class='maruku-mathml' display='inline' " +
"xmlns='http://www.w3.org/1998/Math/MathML'><mrow><mtable rowspacing='0.5ex'>" + "xmlns='http://www.w3.org/1998/Math/MathML'><mrow><mtable rowspacing='0.5ex'>" +
"<mtr><mtd><mi>a</mi></mtd></mtr> <mtr><mtd><mi>b</mi></mtd></mtr></mtable>" + "<mtr><mtd><mi>a</mi></mtd></mtr> <mtr><mtd><mi>b</mi></mtd></mtr></mtable>" +
"</mrow></math></p>", "</mrow></math></p>",
test_renderer(main).display_content x_test_renderer(main).display_content
end end
private private
def add_sample_pages def add_sample_pages
@in_love = @web.add_page('EverBeenInLove', 'Who am I me', @in_love = @web.add_page('EverBeenInLove', 'Who am I me',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson', test_renderer) Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson', x_test_renderer)
@hated = @web.add_page('EverBeenHated', 'I am me EverBeenHated', @hated = @web.add_page('EverBeenHated', 'I am me EverBeenHated',
Time.local(2004, 4, 4, 16, 51), 'DavidHeinemeierHansson', test_renderer) Time.local(2004, 4, 4, 16, 51), 'DavidHeinemeierHansson', x_test_renderer)
end end
def assert_markup_parsed_as(expected_output, input) def assert_markup_parsed_as(expected_output, input)
revision = Revision.new(:page => @page, :content => input, :author => Author.new('AnAuthor')) revision = Revision.new(:page => @page, :content => input, :author => Author.new('AnAuthor'))
assert_equal expected_output, test_renderer(revision).display_content(true), 'Rendering output not as expected' assert_equal expected_output, x_test_renderer(revision).display_content(true), 'Rendering output not as expected'
end end
def assert_match_markup_parsed_as(expected_output, input) def assert_match_markup_parsed_as(expected_output, input)
revision = Revision.new(:page => @page, :content => input, :author => Author.new('AnAuthor')) revision = Revision.new(:page => @page, :content => input, :author => Author.new('AnAuthor'))
assert_match expected_output, test_renderer(revision).display_content, 'Rendering output not as expected' assert_match expected_output, x_test_renderer(revision).display_content, 'Rendering output not as expected'
end end
def rendered_content(page) def rendered_content(page)
test_renderer(page.revisions.last).display_content x_test_renderer(page.revisions.last).display_content
end end
end end

View file

@ -33,7 +33,7 @@ class PageTest < ActiveSupport::TestCase
def test_revise def test_revise
@page.revise('HisWay would be MyWay in kinda lame', @page.name, Time.local(2004, 4, 4, 16, 52), @page.revise('HisWay would be MyWay in kinda lame', @page.name, Time.local(2004, 4, 4, 16, 52),
'MarianneSyhler', test_renderer) 'MarianneSyhler', x_test_renderer)
@page.reload @page.reload
assert_equal 2, @page.revisions.length, 'Should have two revisions' assert_equal 2, @page.revisions.length, 'Should have two revisions'
@ -45,14 +45,14 @@ class PageTest < ActiveSupport::TestCase
def test_revise_continous_revision def test_revise_continous_revision
@page.revise('HisWay would be MyWay in kinda lame', @page.name, Time.local(2004, 4, 4, 16, 55), @page.revise('HisWay would be MyWay in kinda lame', @page.name, Time.local(2004, 4, 4, 16, 55),
'MarianneSyhler', test_renderer) 'MarianneSyhler', x_test_renderer)
@page.reload @page.reload
assert_equal 2, @page.revisions.length assert_equal 2, @page.revisions.length
assert_equal 'HisWay would be MyWay in kinda lame', @page.content assert_equal 'HisWay would be MyWay in kinda lame', @page.content
# consecutive revision by the same author within 30 minutes doesn't create a new revision # consecutive revision by the same author within 30 minutes doesn't create a new revision
@page.revise('HisWay would be MyWay in kinda update', @page.name, Time.local(2004, 4, 4, 16, 57), @page.revise('HisWay would be MyWay in kinda update', @page.name, Time.local(2004, 4, 4, 16, 57),
'MarianneSyhler', test_renderer) 'MarianneSyhler', x_test_renderer)
@page.reload @page.reload
assert_equal 2, @page.revisions.length assert_equal 2, @page.revisions.length
assert_equal 'HisWay would be MyWay in kinda update', @page.content assert_equal 'HisWay would be MyWay in kinda update', @page.content
@ -60,7 +60,7 @@ class PageTest < ActiveSupport::TestCase
# but consecutive revision by another author results in a new revision # but consecutive revision by another author results in a new revision
@page.revise('HisWay would be MyWay in the house', @page.name, Time.local(2004, 4, 4, 16, 58), @page.revise('HisWay would be MyWay in the house', @page.name, Time.local(2004, 4, 4, 16, 58),
'DavidHeinemeierHansson', test_renderer) 'DavidHeinemeierHansson', x_test_renderer)
@page.reload @page.reload
assert_equal 3, @page.revisions.length assert_equal 3, @page.revisions.length
assert_equal 'HisWay would be MyWay in the house', @page.content assert_equal 'HisWay would be MyWay in the house', @page.content
@ -68,14 +68,14 @@ class PageTest < ActiveSupport::TestCase
# consecutive update after 30 minutes since the last one also creates a new revision, # consecutive update after 30 minutes since the last one also creates a new revision,
# even when it is by the same author # even when it is by the same author
@page.revise('HisWay would be MyWay in my way', @page.name, Time.local(2004, 4, 4, 17, 30), @page.revise('HisWay would be MyWay in my way', @page.name, Time.local(2004, 4, 4, 17, 30),
'DavidHeinemeierHansson', test_renderer) 'DavidHeinemeierHansson', x_test_renderer)
@page.reload @page.reload
assert_equal 4, @page.revisions.length assert_equal 4, @page.revisions.length
end end
def test_change_name def test_change_name
@page.revise('HisWay would be MyWay in my way', 'SecondPage', Time.local(2004, 4, 5, 17, 56), @page.revise('HisWay would be MyWay in my way', 'SecondPage', Time.local(2004, 4, 5, 17, 56),
'MarianneSyhler', test_renderer) 'MarianneSyhler', x_test_renderer)
@page.reload @page.reload
assert_equal "Second Page", @page.plain_name assert_equal "Second Page", @page.plain_name
@ -91,7 +91,7 @@ class PageTest < ActiveSupport::TestCase
revisions_number_before = @page.revisions.size revisions_number_before = @page.revisions.size
assert_raises(Instiki::ValidationError) { assert_raises(Instiki::ValidationError) {
@page.revise(@page.current_revision.content, @page.name, Time.now, 'AlexeyVerkhovsky', test_renderer) @page.revise(@page.current_revision.content, @page.name, Time.now, 'AlexeyVerkhovsky', x_test_renderer)
} }
assert_equal last_revision_before, @page.current_revision(true) assert_equal last_revision_before, @page.current_revision(true)
@ -102,7 +102,7 @@ class PageTest < ActiveSupport::TestCase
web = Web.find(1) web = Web.find(1)
new_page = Page.new(:web => web, :name => 'NewPage') new_page = Page.new(:web => web, :name => 'NewPage')
new_page.revise('Reference to WantedPage, and to WantedPage2', 'NewPage', Time.now, 'AlexeyVerkhovsky', new_page.revise('Reference to WantedPage, and to WantedPage2', 'NewPage', Time.now, 'AlexeyVerkhovsky',
test_renderer) x_test_renderer)
references = new_page.wiki_references(true) references = new_page.wiki_references(true)
assert_equal 2, references.size assert_equal 2, references.size
@ -112,7 +112,7 @@ class PageTest < ActiveSupport::TestCase
assert_equal WikiReference::WANTED_PAGE, references[1].link_type assert_equal WikiReference::WANTED_PAGE, references[1].link_type
wanted_page = Page.new(:web => web, :name => 'WantedPage') wanted_page = Page.new(:web => web, :name => 'WantedPage')
wanted_page.revise('And here it is!', 'WantedPage', Time.now, 'AlexeyVerkhovsky', test_renderer) wanted_page.revise('And here it is!', 'WantedPage', Time.now, 'AlexeyVerkhovsky', x_test_renderer)
# link type stored for NewPage -> WantedPage reference should change from WANTED to LINKED # link type stored for NewPage -> WantedPage reference should change from WANTED to LINKED
# reference NewPage -> WantedPage2 should remain the same # reference NewPage -> WantedPage2 should remain the same
@ -128,7 +128,7 @@ class PageTest < ActiveSupport::TestCase
web = Web.find(1) web = Web.find(1)
new_page = Page.new(:web => web, :name => 'NewPage') new_page = Page.new(:web => web, :name => 'NewPage')
new_page.revise('Reference to HappyPage, and to WantedPage2', 'NewPage', Time.local(2004, 4, 5, 17, 56), 'AlexeyVerkhovsky', new_page.revise('Reference to HappyPage, and to WantedPage2', 'NewPage', Time.local(2004, 4, 5, 17, 56), 'AlexeyVerkhovsky',
test_renderer) x_test_renderer)
references = new_page.wiki_references(true) references = new_page.wiki_references(true)
assert_equal 2, references.size assert_equal 2, references.size
@ -140,7 +140,7 @@ class PageTest < ActiveSupport::TestCase
assert_equal ["HappyPage", "HisWay", "OverThere", "WantedPage2"], wanted_pages assert_equal ["HappyPage", "HisWay", "OverThere", "WantedPage2"], wanted_pages
my_page = Page.new(:web => web, :name => 'MyPage') my_page = Page.new(:web => web, :name => 'MyPage')
my_page.revise("[[!redirects HappyPage]]\nAnd here it is!", 'MyPage', Time.now, 'AlexeyVerkhovsky', test_renderer) my_page.revise("[[!redirects HappyPage]]\nAnd here it is!", 'MyPage', Time.now, 'AlexeyVerkhovsky', x_test_renderer)
my_references = my_page.wiki_references(true) my_references = my_page.wiki_references(true)
assert_equal 1, my_references.size assert_equal 1, my_references.size
assert_equal 'HappyPage', my_references[0].referenced_name assert_equal 'HappyPage', my_references[0].referenced_name
@ -152,7 +152,7 @@ class PageTest < ActiveSupport::TestCase
# reference NewPage -> WantedPage2 should remain the same # reference NewPage -> WantedPage2 should remain the same
references = new_page.wiki_references #(true) references = new_page.wiki_references #(true)
assert_match( "Reference to <a class='existingWikiWord' href='\.\./show/MyPage'>Happy Page</a>", assert_match( "Reference to <a class='existingWikiWord' href='\.\./show/MyPage'>Happy Page</a>",
test_renderer(new_page.revisions.last).display_content(true) ) x_test_renderer(new_page.revisions.last).display_content(true) )
assert_equal 2, references.size assert_equal 2, references.size
assert_equal 'HappyPage', references[0].referenced_name assert_equal 'HappyPage', references[0].referenced_name
# Doesn't work, since picking up the change in wiki_references requires a database query. # Doesn't work, since picking up the change in wiki_references requires a database query.
@ -163,12 +163,12 @@ class PageTest < ActiveSupport::TestCase
assert_equal ["HisWay", "OverThere", "WantedPage2"], wanted_pages assert_equal ["HisWay", "OverThere", "WantedPage2"], wanted_pages
new_page.revise('Reference to HappyPage and to WantedPage2.pdf and [[foo.pdf]]', 'NewPage', Time.now, 'AlexeyVerkhovsky', new_page.revise('Reference to HappyPage and to WantedPage2.pdf and [[foo.pdf]]', 'NewPage', Time.now, 'AlexeyVerkhovsky',
test_renderer) x_test_renderer)
references = new_page.wiki_references(true) references = new_page.wiki_references(true)
assert_equal( "<p>Reference to <a class='existingWikiWord' href='\.\./show/MyPage'>Happy Page</a>" + assert_equal( "<p>Reference to <a class='existingWikiWord' href='\.\./show/MyPage'>Happy Page</a>" +
" and to <span class='newWikiWord'>Wanted Page2<a href='../show/WantedPage2'>?</a></span>.pdf " + " and to <span class='newWikiWord'>Wanted Page2<a href='../show/WantedPage2'>?</a></span>.pdf " +
"and <span class='wikilink-error'><b>Illegal link (target contains a &#39;.&#39;):</b> foo.pdf</span></p>", "and <span class='wikilink-error'><b>Illegal link (target contains a &#39;.&#39;):</b> foo.pdf</span></p>",
test_renderer(new_page.revisions.last).display_content(true) ) x_test_renderer(new_page.revisions.last).display_content(true) )
assert_equal 3, references.size assert_equal 3, references.size
# now it works. # now it works.
assert_equal 'HappyPage', references[0].referenced_name assert_equal 'HappyPage', references[0].referenced_name
@ -182,11 +182,11 @@ class PageTest < ActiveSupport::TestCase
end end
def test_rollback def test_rollback
@page.revise("spot two", @page.name, Time.now, "David", test_renderer) @page.revise("spot two", @page.name, Time.now, "David", x_test_renderer)
@page.revise("spot three", @page.name, Time.now + 2000, "David", test_renderer) @page.revise("spot three", @page.name, Time.now + 2000, "David", x_test_renderer)
assert_equal 3, @page.revisions(true).length, "Should have three revisions" assert_equal 3, @page.revisions(true).length, "Should have three revisions"
@page.current_revision(true) @page.current_revision(true)
@page.rollback(0, Time.now, '127.0.0.1', test_renderer) @page.rollback(0, Time.now, '127.0.0.1', x_test_renderer)
assert_equal "HisWay would be MyWay $\\sin(x)\\begin{svg}<svg/>\\end{svg}\\includegraphics[width=3em]{foo}$ in kinda ThatWay in HisWay though MyWay \\\\OverThere -- see SmartEngine in that SmartEngineGUI", @page.current_revision(true).content assert_equal "HisWay would be MyWay $\\sin(x)\\begin{svg}<svg/>\\end{svg}\\includegraphics[width=3em]{foo}$ in kinda ThatWay in HisWay though MyWay \\\\OverThere -- see SmartEngine in that SmartEngineGUI", @page.current_revision(true).content
end end
end end

View file

@ -61,9 +61,9 @@ class WebTest < ActiveSupport::TestCase
def test_new_page_linked_from_mother_page def test_new_page_linked_from_mother_page
# this was a bug in revision 204 # this was a bug in revision 204
home = @web.add_page('HomePage', 'This page refers to AnotherPage', home = @web.add_page('HomePage', 'This page refers to AnotherPage',
Time.local(2004, 4, 4, 16, 50), 'Alexey Verkhovsky', test_renderer) Time.local(2004, 4, 4, 16, 50), 'Alexey Verkhovsky', x_test_renderer)
@web.add_page('AnotherPage', 'This is \AnotherPage', @web.add_page('AnotherPage', 'This is \AnotherPage',
Time.local(2004, 4, 4, 16, 51), 'Alexey Verkhovsky', test_renderer) Time.local(2004, 4, 4, 16, 51), 'Alexey Verkhovsky', x_test_renderer)
@web.pages(true) @web.pages(true)
assert_equal [home], @web.select.pages_that_link_to('AnotherPage') assert_equal [home], @web.select.pages_that_link_to('AnotherPage')
@ -73,13 +73,13 @@ class WebTest < ActiveSupport::TestCase
add_sample_pages add_sample_pages
home = @web.add_page('HomePage', home = @web.add_page('HomePage',
'This is a home page, it should not be an orphan', 'This is a home page, it should not be an orphan',
Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', test_renderer) Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', x_test_renderer)
author = @web.add_page('AlexeyVerkhovsky', author = @web.add_page('AlexeyVerkhovsky',
'This is an author page, it should not be an orphan', 'This is an author page, it should not be an orphan',
Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', test_renderer) Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky', x_test_renderer)
self_linked = @web.add_page('SelfLinked', self_linked = @web.add_page('SelfLinked',
"I am SelfLinked and link to EverBeenInLove\ncategory: fubar", "I am SelfLinked and link to EverBeenInLove\ncategory: fubar",
Time.local(2004, 4, 4, 16, 50), 'AnonymousCoward', test_renderer) Time.local(2004, 4, 4, 16, 50), 'AnonymousCoward', x_test_renderer)
# page that links to itself, and nobody else links to it must be an orphan # page that links to itself, and nobody else links to it must be an orphan
assert_equal ['EverBeenHated', 'SelfLinked'], assert_equal ['EverBeenHated', 'SelfLinked'],
@ -102,8 +102,8 @@ class WebTest < ActiveSupport::TestCase
def add_sample_pages def add_sample_pages
@in_love = @web.add_page('EverBeenInLove', "Who am I me\ncategory: fubar", @in_love = @web.add_page('EverBeenInLove', "Who am I me\ncategory: fubar",
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson', test_renderer) Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson', x_test_renderer)
@hated = @web.add_page('EverBeenHated', 'I am me EverBeenHated', @hated = @web.add_page('EverBeenHated', 'I am me EverBeenHated',
Time.local(2004, 4, 4, 16, 51), 'DavidHeinemeierHansson', test_renderer) Time.local(2004, 4, 4, 16, 51), 'DavidHeinemeierHansson', x_test_renderer)
end end
end end

View file

@ -1,3 +1,7 @@
*2.3.5 (November 25, 2009)*
* Minor Bug Fixes and deprecation warnings
*2.3.4 (September 4, 2009)* *2.3.4 (September 4, 2009)*
* Minor bug fixes. * Minor bug fixes.

View file

@ -54,7 +54,7 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer" s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org" s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 2.3.4' + PKG_BUILD) s.add_dependency('actionpack', '= 2.3.5' + PKG_BUILD)
s.has_rdoc = true s.has_rdoc = true
s.requirements << 'none' s.requirements << 'none'

View file

@ -43,6 +43,7 @@ module Racc
class Parser class Parser
old_verbose, $VERBOSE = $VERBOSE, nil
Racc_Runtime_Version = '1.4.5' Racc_Runtime_Version = '1.4.5'
Racc_Runtime_Revision = '$Revision: 1.7 $'.split[1] Racc_Runtime_Revision = '$Revision: 1.7 $'.split[1]
@ -71,6 +72,7 @@ module Racc
Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R
Racc_Runtime_Type = 'ruby' Racc_Runtime_Type = 'ruby'
end end
$VERBOSE = old_verbose
def Parser.racc_runtime_type def Parser.racc_runtime_type
Racc_Runtime_Type Racc_Runtime_Type

View file

@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 2 MAJOR = 2
MINOR = 3 MINOR = 3
TINY = 4 TINY = 5
STRING = [MAJOR, MINOR, TINY].join('.') STRING = [MAJOR, MINOR, TINY].join('.')
end end

View file

@ -1 +1,2 @@
require 'action_mailer' require 'action_mailer'
ActiveSupport::Deprecation.warn 'require "actionmailer" is deprecated and will be removed in Rails 3. Use require "action_mailer" instead.'

View file

@ -1,5 +1,5 @@
module ExampleHelper module ExampleHelper
def example_format(text) def example_format(text)
"<em><strong><small>#{text}</small></strong></em>" "<em><strong><small>#{h(text)}</small></strong></em>".html_safe!
end end
end end

View file

@ -570,7 +570,9 @@ class ActionMailerTest < Test::Unit::TestCase
mail = TestMailer.create_signed_up(@recipient) mail = TestMailer.create_signed_up(@recipient)
logger = mock() logger = mock()
logger.expects(:info).with("Sent mail to #{@recipient}") logger.expects(:info).with("Sent mail to #{@recipient}")
logger.expects(:debug).with("\n#{mail.encoded}") logger.expects(:debug).with() do |logged_text|
logged_text =~ /\[Signed up\] Welcome/
end
TestMailer.logger = logger TestMailer.logger = logger
TestMailer.deliver_signed_up(@recipient) TestMailer.deliver_signed_up(@recipient)
end end

View file

@ -1,3 +1,15 @@
*2.3.5 (November 25, 2009)*
* Minor Bug Fixes and deprecation warnings
* Ruby 1.9 Support
* Fix filtering parameters when there are Fixnum or other un-dupable values.
* Improvements to ActionView::TestCase
* Compatiblity with the rails_xss plugin
*2.3.4 (September 4, 2009)* *2.3.4 (September 4, 2009)*
* Sanitize multibyte strings before escaping them with escape_once. CVE-2009-3009 * Sanitize multibyte strings before escaping them with escape_once. CVE-2009-3009

View file

@ -79,7 +79,7 @@ spec = Gem::Specification.new do |s|
s.has_rdoc = true s.has_rdoc = true
s.requirements << 'none' s.requirements << 'none'
s.add_dependency('activesupport', '= 2.3.4' + PKG_BUILD) s.add_dependency('activesupport', '= 2.3.5' + PKG_BUILD)
s.add_dependency('rack', '~> 1.0.0') s.add_dependency('rack', '~> 1.0.0')
s.require_path = 'lib' s.require_path = 'lib'

View file

@ -1,87 +0,0 @@
$:.push File.join(File.dirname(__FILE__), "..", "lib")
$:.push File.join(File.dirname(__FILE__), "..", "..", "activesupport", "lib")
require "action_controller"
class Runner
def initialize(app, output)
@app, @output = app, output
end
def puts(*)
super if @output
end
def call(env)
env['n'].to_i.times { @app.call(env) }
@app.call(env).tap { |response| report(env, response) }
end
def report(env, response)
if ENV["DEBUG"]
out = env['rack.errors']
p response.headers
out.puts response.status, response.headers.to_yaml, '---'
response.body.each { |part| out.puts part }
out.puts '---'
end
end
def self.puts(*)
super if @output
end
def self.run(app, n, label = nil, uri = "/", output = true)
@output = output
puts label, '=' * label.size if label
env = Rack::MockRequest.env_for(uri).merge('n' => n, 'rack.input' => StringIO.new(''), 'rack.errors' => $stdout)
t = Benchmark.realtime { new(app, output).call(env) }
puts "%d ms / %d req = %.1f usec/req" % [10**3 * t, n, 10**6 * t / n]
puts
end
end
N = (ENV['N'] || 1000).to_i
class BasePostController < ActionController::Base
append_view_path "#{File.dirname(__FILE__)}/views"
def index
render :text => 'Hello'
end
def partial
render :partial => "/partial"
end
def many_partials
render :partial => "/many_partials"
end
def partial_collection
render :partial => "/collection", :collection => [1,2,3,4,5,6,7,8,9,10]
end
def show_template
render :template => "template"
end
end
# p BasePostController.call(Rack::MockRequest.env_for("/?action=index").merge("REQUEST_URI" => "/")).body
Runner.run(BasePostController, N, 'index', "/?action=index", false)
Runner.run(BasePostController, N, 'partial', "/?action=partial", false)
Runner.run(BasePostController, N, 'many partials', "/?action=many_partials", false)
Runner.run(BasePostController, N, 'collection', "/?action=partial_collection", false)
Runner.run(BasePostController, N, 'template', "/?action=show_template", false)
(ENV["M"] || 1).to_i.times do
Runner.run(BasePostController, N, 'index', "/?action=index")
Runner.run(BasePostController, N, 'partial', "/?action=partial")
Runner.run(BasePostController, N, 'many partials', "/?action=many_partials")
Runner.run(BasePostController, N, 'collection', "/?action=partial_collection")
Runner.run(BasePostController, N, 'template', "/?action=show_template")
end
# Runner.run(BasePostController.action(:many_partials), N, 'index')
# Runner.run(BasePostController.action(:many_partials), N, 'many_partials')
# Runner.run(BasePostController.action(:partial_collection), N, 'collection')
# Runner.run(BasePostController.action(:show_template), N, 'template')

View file

@ -1 +0,0 @@
<%= collection %>

View file

@ -1 +0,0 @@
Hello

View file

@ -1,10 +0,0 @@
<%= render :partial => '/hello' %>
<%= render :partial => '/hello' %>
<%= render :partial => '/hello' %>
<%= render :partial => '/hello' %>
<%= render :partial => '/hello' %>
<%= render :partial => '/hello' %>
<%= render :partial => '/hello' %>
<%= render :partial => '/hello' %>
<%= render :partial => '/hello' %>
<%= render :partial => '/hello' %>

View file

@ -1,10 +0,0 @@
<%= "Hello" %>
<%= "Hello" %>
<%= "Hello" %>
<%= "Hello" %>
<%= "Hello" %>
<%= "Hello" %>
<%= "Hello" %>
<%= "Hello" %>
<%= "Hello" %>
<%= "Hello" %>

View file

@ -1 +0,0 @@
+ <%= yield %> +

View file

@ -1 +0,0 @@
Hello <%= yield %> Goodbye

View file

@ -1 +0,0 @@
Hello

View file

@ -37,6 +37,7 @@ begin
rescue Gem::LoadError rescue Gem::LoadError
require 'action_controller/vendor/rack-1.1.pre/rack' require 'action_controller/vendor/rack-1.1.pre/rack'
end end
require 'action_controller/cgi_ext'
module ActionController module ActionController
# TODO: Review explicit to see if they will automatically be handled by # TODO: Review explicit to see if they will automatically be handled by
@ -74,6 +75,7 @@ module ActionController
autoload :SessionManagement, 'action_controller/session_management' autoload :SessionManagement, 'action_controller/session_management'
autoload :StatusCodes, 'action_controller/status_codes' autoload :StatusCodes, 'action_controller/status_codes'
autoload :Streaming, 'action_controller/streaming' autoload :Streaming, 'action_controller/streaming'
autoload :StringCoercion, 'action_controller/string_coercion'
autoload :TestCase, 'action_controller/test_case' autoload :TestCase, 'action_controller/test_case'
autoload :TestProcess, 'action_controller/test_process' autoload :TestProcess, 'action_controller/test_process'
autoload :Translation, 'action_controller/translation' autoload :Translation, 'action_controller/translation'

View file

@ -1,6 +1,18 @@
module ActionController module ActionController
module Assertions module Assertions
module DomAssertions module DomAssertions
def self.strip_whitespace!(nodes)
nodes.reject! do |node|
if node.is_a?(HTML::Text)
node.content.strip!
node.content.empty?
else
strip_whitespace! node.children
false
end
end
end
# Test two HTML strings for equivalency (e.g., identical up to reordering of attributes) # Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)
# #
# ==== Examples # ==== Examples
@ -12,13 +24,15 @@ module ActionController
clean_backtrace do clean_backtrace do
expected_dom = HTML::Document.new(expected).root expected_dom = HTML::Document.new(expected).root
actual_dom = HTML::Document.new(actual).root actual_dom = HTML::Document.new(actual).root
full_message = build_message(message, "<?> expected to be == to\n<?>.", expected_dom.to_s, actual_dom.to_s) DomAssertions.strip_whitespace!(expected_dom.children)
DomAssertions.strip_whitespace!(actual_dom.children)
full_message = build_message(message, "<?> expected but was\n<?>.", expected_dom.to_s, actual_dom.to_s)
assert_block(full_message) { expected_dom == actual_dom } assert_block(full_message) { expected_dom == actual_dom }
end end
end end
# The negated form of +assert_dom_equivalent+. # The negated form of +assert_dom_equal+.
# #
# ==== Examples # ==== Examples
# #
@ -29,8 +43,10 @@ module ActionController
clean_backtrace do clean_backtrace do
expected_dom = HTML::Document.new(expected).root expected_dom = HTML::Document.new(expected).root
actual_dom = HTML::Document.new(actual).root actual_dom = HTML::Document.new(actual).root
full_message = build_message(message, "<?> expected to be != to\n<?>.", expected_dom.to_s, actual_dom.to_s) DomAssertions.strip_whitespace!(expected_dom.children)
DomAssertions.strip_whitespace!(actual_dom.children)
full_message = build_message(message, "<?> expected to be != to\n<?>.", expected_dom.to_s, actual_dom.to_s)
assert_block(full_message) { expected_dom != actual_dom } assert_block(full_message) { expected_dom != actual_dom }
end end
end end

View file

@ -16,7 +16,7 @@ module ActionController
# #
# Use +css_select+ to select elements without making an assertions, either # Use +css_select+ to select elements without making an assertions, either
# from the response HTML or elements selected by the enclosing assertion. # from the response HTML or elements selected by the enclosing assertion.
# #
# In addition to HTML responses, you can make the following assertions: # In addition to HTML responses, you can make the following assertions:
# * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations. # * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations.
# * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions. # * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
@ -24,6 +24,12 @@ module ActionController
# #
# Also see HTML::Selector to learn how to use selectors. # Also see HTML::Selector to learn how to use selectors.
module SelectorAssertions module SelectorAssertions
def initialize(*args)
super
@selected = nil
end
# :call-seq: # :call-seq:
# css_select(selector) => array # css_select(selector) => array
# css_select(element, selector) => array # css_select(element, selector) => array
@ -53,8 +59,8 @@ module ActionController
# end # end
# #
# # Selects all list items in unordered lists # # Selects all list items in unordered lists
# items = css_select("ul>li") # items = css_select("ul>li")
# #
# # Selects all form tags and then all inputs inside the form # # Selects all form tags and then all inputs inside the form
# forms = css_select("form") # forms = css_select("form")
# forms.each do |form| # forms.each do |form|
@ -212,7 +218,7 @@ module ActionController
# Otherwise just operate on the response document. # Otherwise just operate on the response document.
root = response_from_page_or_rjs root = response_from_page_or_rjs
end end
# First or second argument is the selector: string and we pass # First or second argument is the selector: string and we pass
# all remaining arguments. Array and we pass the argument. Also # all remaining arguments. Array and we pass the argument. Also
# accepts selector itself. # accepts selector itself.
@ -225,7 +231,7 @@ module ActionController
selector = arg selector = arg
else raise ArgumentError, "Expecting a selector as the first argument" else raise ArgumentError, "Expecting a selector as the first argument"
end end
# Next argument is used for equality tests. # Next argument is used for equality tests.
equals = {} equals = {}
case arg = args.shift case arg = args.shift
@ -315,10 +321,10 @@ module ActionController
# Returns all matches elements. # Returns all matches elements.
matches matches
end end
def count_description(min, max) #:nodoc: def count_description(min, max) #:nodoc:
pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')} pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')}
if min && max && (max != min) if min && max && (max != min)
"between #{min} and #{max} elements" "between #{min} and #{max} elements"
elsif min && !(min == 1 && max == 1) elsif min && !(min == 1 && max == 1)
@ -327,7 +333,7 @@ module ActionController
"at most #{max} #{pluralize['element', max]}" "at most #{max} #{pluralize['element', max]}"
end end
end end
# :call-seq: # :call-seq:
# assert_select_rjs(id?) { |elements| ... } # assert_select_rjs(id?) { |elements| ... }
# assert_select_rjs(statement, id?) { |elements| ... } # assert_select_rjs(statement, id?) { |elements| ... }
@ -344,7 +350,7 @@ module ActionController
# that update or insert an element with that identifier. # that update or insert an element with that identifier.
# #
# Use the first argument to narrow down assertions to only statements # Use the first argument to narrow down assertions to only statements
# of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>, # of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>,
# <tt>:show</tt>, <tt>:hide</tt>, <tt>:toggle</tt>, <tt>:remove</tt> and # <tt>:show</tt>, <tt>:hide</tt>, <tt>:toggle</tt>, <tt>:remove</tt> and
# <tt>:insert_html</tt>. # <tt>:insert_html</tt>.
# #
@ -488,7 +494,7 @@ module ActionController
# end # end
# end # end
# end # end
# #
# #
# # Selects all paragraph tags from within the description of an RSS feed # # Selects all paragraph tags from within the description of an RSS feed
# assert_select_feed :rss, 2.0 do # assert_select_feed :rss, 2.0 do

View file

@ -502,7 +502,7 @@ module ActionController #:nodoc:
end end
elsif block_given? elsif block_given?
key = key.dup key = key.dup
value = value.dup if value value = value.dup if value.duplicable?
yield key, value yield key, value
filtered_parameters[key] = value filtered_parameters[key] = value
else else

View file

@ -22,6 +22,7 @@ module ActionController #:nodoc:
# ActionController::Base.cache_store = :file_store, "/path/to/cache/directory" # ActionController::Base.cache_store = :file_store, "/path/to/cache/directory"
# ActionController::Base.cache_store = :drb_store, "druby://localhost:9192" # ActionController::Base.cache_store = :drb_store, "druby://localhost:9192"
# ActionController::Base.cache_store = :mem_cache_store, "localhost" # ActionController::Base.cache_store = :mem_cache_store, "localhost"
# ActionController::Base.cache_store = :mem_cache_store, Memcached::Rails.new("localhost:11211")
# ActionController::Base.cache_store = MyOwnStore.new("parameter") # ActionController::Base.cache_store = MyOwnStore.new("parameter")
module Caching module Caching
autoload :Actions, 'action_controller/caching/actions' autoload :Actions, 'action_controller/caching/actions'

View file

@ -87,8 +87,9 @@ module ActionController #:nodoc:
def delete(key, options = {}) def delete(key, options = {})
options.symbolize_keys! options.symbolize_keys!
options[:path] = "/" unless options.has_key?(:path) options[:path] = "/" unless options.has_key?(:path)
super(key.to_s) value = super(key.to_s)
@controller.response.delete_cookie(key, options) @controller.response.delete_cookie(key, options)
value
end end
end end
end end

View file

@ -227,9 +227,9 @@ module ActionController
end end
def decode_credentials(header) def decode_credentials(header)
header.to_s.gsub(/^Digest\s+/,'').split(',').inject({}) do |hash, pair| header.to_s.gsub(/^Digest\s+/,'').split(',').inject({}.with_indifferent_access) do |hash, pair|
key, value = pair.split('=', 2) key, value = pair.split('=', 2)
hash[key.strip.to_sym] = value.to_s.gsub(/^"|"$/,'').gsub(/'/, '') hash[key.strip] = value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')
hash hash
end end
end end
@ -289,6 +289,7 @@ module ActionController
# allow a user to use new nonce without prompting user again for their # allow a user to use new nonce without prompting user again for their
# username and password. # username and password.
def validate_nonce(request, value, seconds_to_timeout=5*60) def validate_nonce(request, value, seconds_to_timeout=5*60)
return false if value.nil?
t = Base64.decode64(value).split(":").first.to_i t = Base64.decode64(value).split(":").first.to_i
nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
end end

View file

@ -1,6 +1,7 @@
require 'stringio' require 'stringio'
require 'uri' require 'uri'
require 'active_support/test_case' require 'active_support/test_case'
require 'action_controller/rack_lint_patch'
module ActionController module ActionController
module Integration #:nodoc: module Integration #:nodoc:
@ -268,7 +269,9 @@ module ActionController
env["QUERY_STRING"] ||= "" env["QUERY_STRING"] ||= ""
data = data.is_a?(IO) ? data : StringIO.new(data || '') data ||= ''
data.force_encoding(Encoding::ASCII_8BIT) if data.respond_to?(:force_encoding)
data = data.is_a?(IO) ? data : StringIO.new(data)
env.update( env.update(
"REQUEST_METHOD" => method.to_s.upcase, "REQUEST_METHOD" => method.to_s.upcase,
@ -476,6 +479,11 @@ EOF
end end
module Runner module Runner
def initialize(*args)
super
@integration_session = nil
end
# Reset the current session. This is useful for testing multiple sessions # Reset the current session. This is useful for testing multiple sessions
# in a single test case. # in a single test case.
def reset! def reset!
@ -543,8 +551,12 @@ EOF
# Delegate unhandled messages to the current session instance. # Delegate unhandled messages to the current session instance.
def method_missing(sym, *args, &block) def method_missing(sym, *args, &block)
reset! unless @integration_session reset! unless @integration_session
returning @integration_session.__send__(sym, *args, &block) do if @integration_session.respond_to?(sym)
copy_session_variables! returning @integration_session.__send__(sym, *args, &block) do
copy_session_variables!
end
else
super
end end
end end
end end

View file

@ -194,6 +194,11 @@ module ActionController #:nodoc:
end end
end end
def initialize(*args)
super
@real_format = nil
end
# Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method # Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
# is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method # is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
# object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return # object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
@ -221,7 +226,7 @@ module ActionController #:nodoc:
end end
def find_layout(layout, format, html_fallback=false) #:nodoc: def find_layout(layout, format, html_fallback=false) #:nodoc:
view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", format, html_fallback) view_paths.find_template(layout.to_s =~ /\A\/|layouts\// ? layout : "layouts/#{layout}", format, html_fallback)
rescue ActionView::MissingTemplate rescue ActionView::MissingTemplate
raise if Mime::Type.lookup_by_extension(format.to_s).html? raise if Mime::Type.lookup_by_extension(format.to_s).html?
end end

View file

@ -10,3 +10,5 @@ use lambda { ActionController::Base.session_store },
use "ActionController::ParamsParser" use "ActionController::ParamsParser"
use "Rack::MethodOverride" use "Rack::MethodOverride"
use "Rack::Head" use "Rack::Head"
use "ActionController::StringCoercion"

View file

@ -76,8 +76,7 @@ module ActionController
record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1 record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
end end
record = extract_record(record_or_hash_or_array) record = extract_record(record_or_hash_or_array)
namespace = extract_namespace(record_or_hash_or_array)
args = case record_or_hash_or_array args = case record_or_hash_or_array
when Hash; [ record_or_hash_or_array ] when Hash; [ record_or_hash_or_array ]
@ -98,8 +97,7 @@ module ActionController
end end
args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)} args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options)
url_options = options.except(:action, :routing_type) url_options = options.except(:action, :routing_type)
unless url_options.empty? unless url_options.empty?
@ -153,7 +151,7 @@ module ActionController
options[:routing_type] || :url options[:routing_type] || :url
end end
def build_named_route_call(records, namespace, inflection, options = {}) def build_named_route_call(records, inflection, options = {})
unless records.is_a?(Array) unless records.is_a?(Array)
record = extract_record(records) record = extract_record(records)
route = '' route = ''
@ -163,7 +161,7 @@ module ActionController
if parent.is_a?(Symbol) || parent.is_a?(String) if parent.is_a?(Symbol) || parent.is_a?(String)
string << "#{parent}_" string << "#{parent}_"
else else
string << "#{RecordIdentifier.__send__("plural_class_name", parent)}".singularize string << RecordIdentifier.__send__("plural_class_name", parent).singularize
string << "_" string << "_"
end end
end end
@ -172,12 +170,12 @@ module ActionController
if record.is_a?(Symbol) || record.is_a?(String) if record.is_a?(Symbol) || record.is_a?(String)
route << "#{record}_" route << "#{record}_"
else else
route << "#{RecordIdentifier.__send__("plural_class_name", record)}" route << RecordIdentifier.__send__("plural_class_name", record)
route = route.singularize if inflection == :singular route = route.singularize if inflection == :singular
route << "_" route << "_"
end end
action_prefix(options) + namespace + route + routing_type(options).to_s action_prefix(options) + route + routing_type(options).to_s
end end
def extract_record(record_or_hash_or_array) def extract_record(record_or_hash_or_array)
@ -187,18 +185,5 @@ module ActionController
else record_or_hash_or_array else record_or_hash_or_array
end end
end end
# Remove the first symbols from the array and return the url prefix
# implied by those symbols.
def extract_namespace(record_or_hash_or_array)
return "" unless record_or_hash_or_array.is_a?(Array)
namespace_keys = []
while (key = record_or_hash_or_array.first) && key.is_a?(String) || key.is_a?(Symbol)
namespace_keys << record_or_hash_or_array.shift
end
namespace_keys.map {|k| "#{k}_"}.join
end
end end
end end

View file

@ -0,0 +1,36 @@
# Rack 1.0 does not allow string subclass body. This does not play well with our ActionView::SafeBuffer.
# The next release of Rack will be allowing string subclass body - http://github.com/rack/rack/commit/de668df02802a0335376a81ba709270e43ba9d55
# TODO : Remove this monkey patch after the next release of Rack
module RackLintPatch
module AllowStringSubclass
def self.included(base)
base.send :alias_method, :each, :each_with_hack
end
def each_with_hack
@closed = false
@body.each { |part|
assert("Body yielded non-string value #{part.inspect}") {
part.kind_of?(String)
}
yield part
}
if @body.respond_to?(:to_path)
assert("The file identified by body.to_path does not exist") {
::File.exist? @body.to_path
}
end
end
end
begin
app = proc {|env| [200, {"Content-Type" => "text/plain", "Content-Length" => "12"}, [Class.new(String).new("Hello World!")]] }
response = Rack::MockRequest.new(Rack::Lint.new(app)).get('/')
rescue Rack::Lint::LintError => e
raise(e) unless e.message =~ /Body yielded non-string value/
Rack::Lint.send :include, AllowStringSubclass
end
end

View file

@ -89,9 +89,13 @@ module ActionController #:nodoc:
request.method == :get || request.method == :get ||
request.xhr? || request.xhr? ||
!verifiable_request_format? || !verifiable_request_format? ||
form_authenticity_token == params[request_forgery_protection_token] form_authenticity_token == form_authenticity_param
end end
def form_authenticity_param
params[request_forgery_protection_token]
end
def verifiable_request_format? def verifiable_request_format?
!request.content_type.nil? && request.content_type.verify_request? !request.content_type.nil? && request.content_type.verify_request?
end end

View file

@ -47,7 +47,8 @@ module ActionController # :nodoc:
@block = nil @block = nil
@body = "", @body = "",
@session, @assigns = [], [] @session = []
@assigns = []
end end
def location; headers['Location'] end def location; headers['Location'] end

View file

@ -0,0 +1,29 @@
module ActionController
class StringCoercion
class UglyBody < ActiveSupport::BasicObject
def initialize(body)
@body = body
end
def each
@body.each do |part|
yield part.to_s
end
end
private
def method_missing(*args, &block)
@body.__send__(*args, &block)
end
end
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
[status, headers, UglyBody.new(body)]
end
end
end

View file

@ -105,6 +105,11 @@ module ActionController
class TestCase < ActiveSupport::TestCase class TestCase < ActiveSupport::TestCase
include TestProcess include TestProcess
def initialize(*args)
super
@controller = nil
end
module Assertions module Assertions
%w(response selector tag dom routing model).each do |kind| %w(response selector tag dom routing model).each do |kind|
include ActionController::Assertions.const_get("#{kind.camelize}Assertions") include ActionController::Assertions.const_get("#{kind.camelize}Assertions")
@ -195,7 +200,7 @@ module ActionController
@controller.send(:initialize_current_url) @controller.send(:initialize_current_url)
end end
end end
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local # Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
def rescue_action_in_public! def rescue_action_in_public!
@request.remote_addr = '208.77.188.166' # example.com @request.remote_addr = '208.77.188.166' # example.com

View file

@ -91,7 +91,7 @@ module ActionController #:nodoc:
@path || super() @path || super()
end end
def assign_parameters(controller_path, action, parameters) def assign_parameters(controller_path, action, parameters = {})
parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action) parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action)
extra_keys = ActionController::Routing::Routes.extra_keys(parameters) extra_keys = ActionController::Routing::Routes.extra_keys(parameters)
non_path_parameters = get? ? query_parameters : request_parameters non_path_parameters = get? ? query_parameters : request_parameters

View file

@ -1,12 +1,12 @@
module ActionController module ActionController
module Translation module Translation
def translate(*args) def translate(*args)
I18n.translate *args I18n.translate(*args)
end end
alias :t :translate alias :t :translate
def localize(*args) def localize(*args)
I18n.localize *args I18n.localize(*args)
end end
alias :l :localize alias :l :localize
end end

View file

@ -3,14 +3,14 @@ module ActionController
def self.included(base) def self.included(base)
base.class_eval do base.class_eval do
attr_accessor :original_path, :content_type attr_accessor :original_path, :content_type
alias_method :local_path, :path alias_method :local_path, :path if method_defined?(:path)
end end
end end
def self.extended(object) def self.extended(object)
object.class_eval do object.class_eval do
attr_accessor :original_path, :content_type attr_accessor :original_path, :content_type
alias_method :local_path, :path alias_method :local_path, :path if method_defined?(:path)
end end
end end

View file

@ -162,7 +162,7 @@ module HTML #:nodoc:
end end
closing = ( scanner.scan(/\//) ? :close : nil ) closing = ( scanner.scan(/\//) ? :close : nil )
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[\w:-]+/) return Text.new(parent, line, pos, content) unless name = scanner.scan(/[-:\w\x00-\x09\x0b-\x0c\x0e-\x1f]+/)
name.downcase! name.downcase!
unless closing unless closing

View file

@ -2,7 +2,7 @@ module ActionPack #:nodoc:
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 2 MAJOR = 2
MINOR = 3 MINOR = 3
TINY = 4 TINY = 5
STRING = [MAJOR, MINOR, TINY].join('.') STRING = [MAJOR, MINOR, TINY].join('.')
end end

View file

@ -49,10 +49,10 @@ module ActionView
autoload :TemplateHandler, 'action_view/template_handler' autoload :TemplateHandler, 'action_view/template_handler'
autoload :TemplateHandlers, 'action_view/template_handlers' autoload :TemplateHandlers, 'action_view/template_handlers'
autoload :Helpers, 'action_view/helpers' autoload :Helpers, 'action_view/helpers'
autoload :SafeBuffer, 'action_view/safe_buffer'
end end
class ERB require 'action_view/erb/util'
autoload :Util, 'action_view/erb/util'
end
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml" I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"

View file

@ -187,13 +187,18 @@ module ActionView #:nodoc:
@@cache_template_loading = nil @@cache_template_loading = nil
cattr_accessor :cache_template_loading cattr_accessor :cache_template_loading
# :nodoc:
def self.xss_safe?
false
end
def self.cache_template_loading? def self.cache_template_loading?
ActionController::Base.allow_concurrency || (cache_template_loading.nil? ? !ActiveSupport::Dependencies.load? : cache_template_loading) ActionController::Base.allow_concurrency || (cache_template_loading.nil? ? !ActiveSupport::Dependencies.load? : cache_template_loading)
end end
attr_internal :request attr_internal :request
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, delegate :request_forgery_protection_token, :params, :session, :cookies, :response, :headers,
:flash, :logger, :action_name, :controller_name, :to => :controller :flash, :logger, :action_name, :controller_name, :to => :controller
module CompiledTemplates #:nodoc: module CompiledTemplates #:nodoc:

View file

@ -18,6 +18,12 @@ class ERB
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] } s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
end end
undef :h
alias h html_escape
module_function :html_escape
module_function :h
# A utility method for escaping HTML entities in JSON strings. # A utility method for escaping HTML entities in JSON strings.
# This method is also aliased as <tt>j</tt>. # This method is also aliased as <tt>j</tt>.
# #

View file

@ -14,6 +14,7 @@ module ActionView #:nodoc:
autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper' autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper'
autoload :NumberHelper, 'action_view/helpers/number_helper' autoload :NumberHelper, 'action_view/helpers/number_helper'
autoload :PrototypeHelper, 'action_view/helpers/prototype_helper' autoload :PrototypeHelper, 'action_view/helpers/prototype_helper'
autoload :RawOutputHelper, 'action_view/helpers/raw_output_helper'
autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper' autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper'
autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper' autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper'
autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper' autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper'
@ -45,6 +46,7 @@ module ActionView #:nodoc:
include JavaScriptHelper include JavaScriptHelper
include NumberHelper include NumberHelper
include PrototypeHelper include PrototypeHelper
include RawOutputHelper
include RecordIdentificationHelper include RecordIdentificationHelper
include RecordTagHelper include RecordTagHelper
include SanitizeHelper include SanitizeHelper

View file

@ -3,7 +3,7 @@ require 'action_view/helpers/form_helper'
module ActionView module ActionView
class Base class Base
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>" } @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe! }
cattr_accessor :field_error_proc cattr_accessor :field_error_proc
end end
@ -171,7 +171,7 @@ module ActionView
options = params.extract_options!.symbolize_keys options = params.extract_options!.symbolize_keys
if object = options.delete(:object) if object = options.delete(:object)
objects = [object].flatten objects = Array.wrap(object)
else else
objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact
end end
@ -290,7 +290,7 @@ module ActionView
end end
def error_wrapping(html_tag, has_error) def error_wrapping(html_tag, has_error)
has_error ? Base.field_error_proc.call(html_tag, self) : html_tag has_error ? Base.field_error_proc.call(html_tag, self).html_safe! : html_tag
end end
def error_message def error_message

View file

@ -285,7 +285,7 @@ module ActionView
end end
javascript_src_tag(joined_javascript_name, options) javascript_src_tag(joined_javascript_name, options)
else else
expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n") expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe!
end end
end end
@ -434,7 +434,7 @@ module ActionView
end end
stylesheet_tag(joined_stylesheet_name, options) stylesheet_tag(joined_stylesheet_name, options)
else else
expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n") expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe!
end end
end end

View file

@ -118,13 +118,13 @@ module ActionView
def content_for(name, content = nil, &block) def content_for(name, content = nil, &block)
ivar = "@content_for_#{name}" ivar = "@content_for_#{name}"
content = capture(&block) if block_given? content = capture(&block) if block_given?
instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}") instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}".html_safe!)
nil nil
end end
# Use an alternate output buffer for the duration of the block. # Use an alternate output buffer for the duration of the block.
# Defaults to a new empty string. # Defaults to a new empty string.
def with_output_buffer(buf = '') #:nodoc: def with_output_buffer(buf = "") #:nodoc:
self.output_buffer, old_buffer = buf, output_buffer self.output_buffer, old_buffer = buf, output_buffer
yield yield
output_buffer output_buffer

View file

@ -26,8 +26,10 @@ module ActionView
# 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days # 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
# 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month # 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
# 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months # 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months
# 1 yr <-> 2 yrs minus 1 secs # => about 1 year # 1 yr <-> 1 yr, 3 months # => about 1 year
# 2 yrs <-> max time or date # => over [2..X] years # 1 yr, 3 months <-> 1 yr, 9 months # => over 1 year
# 1 yr, 9 months <-> 2 yr minus 1 sec # => almost 2 years
# 2 yrs <-> max time or date # => (same rules as 1 yr)
# #
# With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds: # With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds:
# 0-4 secs # => less than 5 seconds # 0-4 secs # => less than 5 seconds
@ -43,17 +45,18 @@ module ActionView
# distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour # distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour
# distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute # distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
# distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds # distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds
# distance_of_time_in_words(from_time, 3.years.from_now) # => over 3 years # distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years
# distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days # distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days
# distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute # distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute
# distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute # distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute
# distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute # distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute
# distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year # distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year
# distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => over 4 years # distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years
# distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => about 4 years
# #
# to_time = Time.now + 6.years + 19.days # to_time = Time.now + 6.years + 19.days
# distance_of_time_in_words(from_time, to_time, true) # => over 6 years # distance_of_time_in_words(from_time, to_time, true) # => about 6 years
# distance_of_time_in_words(to_time, from_time, true) # => over 6 years # distance_of_time_in_words(to_time, from_time, true) # => about 6 years
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute # distance_of_time_in_words(Time.now, Time.now) # => less than a minute
# #
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {}) def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
@ -81,12 +84,21 @@ module ActionView
when 2..44 then locale.t :x_minutes, :count => distance_in_minutes when 2..44 then locale.t :x_minutes, :count => distance_in_minutes
when 45..89 then locale.t :about_x_hours, :count => 1 when 45..89 then locale.t :about_x_hours, :count => 1
when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round
when 1440..2879 then locale.t :x_days, :count => 1 when 1440..2529 then locale.t :x_days, :count => 1
when 2880..43199 then locale.t :x_days, :count => (distance_in_minutes / 1440).round when 2530..43199 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round
when 43200..86399 then locale.t :about_x_months, :count => 1 when 43200..86399 then locale.t :about_x_months, :count => 1
when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes / 43200).round when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round
when 525600..1051199 then locale.t :about_x_years, :count => 1 else
else locale.t :over_x_years, :count => (distance_in_minutes / 525600).round distance_in_years = distance_in_minutes / 525600
minute_offset_for_leap_year = (distance_in_years / 4) * 1440
remainder = ((distance_in_minutes - minute_offset_for_leap_year) % 525600)
if remainder < 131400
locale.t(:about_x_years, :count => distance_in_years)
elsif remainder < 394200
locale.t(:over_x_years, :count => distance_in_years)
else
locale.t(:almost_x_years, :count => distance_in_years + 1)
end
end end
end end
end end
@ -904,15 +916,15 @@ module ActionView
class InstanceTag #:nodoc: class InstanceTag #:nodoc:
def to_date_select_tag(options = {}, html_options = {}) def to_date_select_tag(options = {}, html_options = {})
datetime_selector(options, html_options).select_date datetime_selector(options, html_options).select_date.html_safe!
end end
def to_time_select_tag(options = {}, html_options = {}) def to_time_select_tag(options = {}, html_options = {})
datetime_selector(options, html_options).select_time datetime_selector(options, html_options).select_time.html_safe!
end end
def to_datetime_select_tag(options = {}, html_options = {}) def to_datetime_select_tag(options = {}, html_options = {})
datetime_selector(options, html_options).select_datetime datetime_selector(options, html_options).select_datetime.html_safe!
end end
private private
@ -923,7 +935,7 @@ module ActionView
options[:field_name] = @method_name options[:field_name] = @method_name
options[:include_position] = true options[:include_position] = true
options[:prefix] ||= @object_name options[:prefix] ||= @object_name
options[:index] = @auto_index if @auto_index && !options.has_key?(:index) options[:index] = @auto_index if defined?(@auto_index) && @auto_index && !options.has_key?(:index)
options[:datetime_separator] ||= ' &mdash; ' options[:datetime_separator] ||= ' &mdash; '
options[:time_separator] ||= ' : ' options[:time_separator] ||= ' : '

View file

@ -280,7 +280,7 @@ module ActionView
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {})) concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
fields_for(object_name, *(args << options), &proc) fields_for(object_name, *(args << options), &proc)
concat('</form>') concat('</form>'.html_safe!)
end end
def apply_form_for_options!(object_or_array, options) #:nodoc: def apply_form_for_options!(object_or_array, options) #:nodoc:
@ -445,6 +445,15 @@ module ActionView
# <% end %> # <% end %>
# <% end %> # <% end %>
# #
# Or a collection to be used:
#
# <% form_for @person, :url => { :action => "update" } do |person_form| %>
# ...
# <% person_form.fields_for :projects, @active_projects do |project_fields| %>
# Name: <%= project_fields.text_field :name %>
# <% end %>
# <% end %>
#
# When projects is already an association on Person you can use # When projects is already an association on Person you can use
# +accepts_nested_attributes_for+ to define the writer method for you: # +accepts_nested_attributes_for+ to define the writer method for you:
# #
@ -788,7 +797,7 @@ module ActionView
add_default_name_and_id(options) add_default_name_and_id(options)
hidden = tag("input", "name" => options["name"], "type" => "hidden", "value" => options['disabled'] && checked ? checked_value : unchecked_value) hidden = tag("input", "name" => options["name"], "type" => "hidden", "value" => options['disabled'] && checked ? checked_value : unchecked_value)
checkbox = tag("input", options) checkbox = tag("input", options)
hidden + checkbox (hidden + checkbox).html_safe!
end end
def to_boolean_select_tag(options = {}) def to_boolean_select_tag(options = {})
@ -930,7 +939,7 @@ module ActionView
end end
end end
(field_helpers - %w(label check_box radio_button fields_for)).each do |selector| (field_helpers - %w(label check_box radio_button fields_for hidden_field)).each do |selector|
src = <<-end_src src = <<-end_src
def #{selector}(method, options = {}) # def text_field(method, options = {}) def #{selector}(method, options = {}) # def text_field(method, options = {})
@template.send( # @template.send( @template.send( # @template.send(
@ -989,6 +998,11 @@ module ActionView
def radio_button(method, tag_value, options = {}) def radio_button(method, tag_value, options = {})
@template.radio_button(@object_name, method, tag_value, objectify_options(options)) @template.radio_button(@object_name, method, tag_value, objectify_options(options))
end end
def hidden_field(method, options = {})
@emitted_hidden_id = true if method == :id
@template.hidden_field(@object_name, method, objectify_options(options))
end
def error_message_on(method, *args) def error_message_on(method, *args)
@template.error_message_on(@object, method, *args) @template.error_message_on(@object, method, *args)
@ -1002,6 +1016,10 @@ module ActionView
@template.submit_tag(value, options.reverse_merge(:id => "#{object_name}_submit")) @template.submit_tag(value, options.reverse_merge(:id => "#{object_name}_submit"))
end end
def emitted_hidden_id?
@emitted_hidden_id
end
private private
def objectify_options(options) def objectify_options(options)
@default_options.merge(options.merge(:object => @object)) @default_options.merge(options.merge(:object => @object))
@ -1013,18 +1031,21 @@ module ActionView
def fields_for_with_nested_attributes(association_name, args, block) def fields_for_with_nested_attributes(association_name, args, block)
name = "#{object_name}[#{association_name}_attributes]" name = "#{object_name}[#{association_name}_attributes]"
association = @object.send(association_name) association = args.first
explicit_object = args.first if args.first.respond_to?(:new_record?)
if association.respond_to?(:new_record?)
association = [association] if @object.send(association_name).is_a?(Array)
elsif !association.is_a?(Array)
association = @object.send(association_name)
end
if association.is_a?(Array) if association.is_a?(Array)
children = explicit_object ? [explicit_object] : association
explicit_child_index = args.last[:child_index] if args.last.is_a?(Hash) explicit_child_index = args.last[:child_index] if args.last.is_a?(Hash)
association.map do |child|
children.map do |child|
fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, args, block) fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, args, block)
end.join end.join
else elsif association
fields_for_nested_model(name, explicit_object || association, args, block) fields_for_nested_model(name, association, args, block)
end end
end end
@ -1033,8 +1054,8 @@ module ActionView
@template.fields_for(name, object, *args, &block) @template.fields_for(name, object, *args, &block)
else else
@template.fields_for(name, object, *args) do |builder| @template.fields_for(name, object, *args) do |builder|
@template.concat builder.hidden_field(:id)
block.call(builder) block.call(builder)
@template.concat builder.hidden_field(:id) unless builder.emitted_hidden_id?
end end
end end
end end

View file

@ -296,7 +296,7 @@ module ActionView
options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>) options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>)
end end
options_for_select.join("\n") options_for_select.join("\n").html_safe!
end end
# Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the

View file

@ -432,7 +432,7 @@ module ActionView
concat(tag(:fieldset, options, true)) concat(tag(:fieldset, options, true))
concat(content_tag(:legend, legend)) unless legend.blank? concat(content_tag(:legend, legend)) unless legend.blank?
concat(content) concat(content)
concat("</fieldset>") concat("</fieldset>".html_safe!)
end end
private private
@ -459,14 +459,14 @@ module ActionView
def form_tag_html(html_options) def form_tag_html(html_options)
extra_tags = extra_tags_for_form(html_options) extra_tags = extra_tags_for_form(html_options)
tag(:form, html_options, true) + extra_tags (tag(:form, html_options, true) + extra_tags).html_safe!
end end
def form_tag_in_block(html_options, &block) def form_tag_in_block(html_options, &block)
content = capture(&block) content = capture(&block)
concat(form_tag_html(html_options)) concat(form_tag_html(html_options))
concat(content) concat(content)
concat("</form>") concat("</form>".html_safe!)
end end
def token_tag def token_tag

View file

@ -246,6 +246,11 @@ module ActionView
# number_to_human_size(483989, :precision => 0) # => 473 KB # number_to_human_size(483989, :precision => 0) # => 473 KB
# number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB # number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
# #
# Zeros after the decimal point are always stripped out, regardless of the
# specified precision:
# helper.number_to_human_size(1234567890123, :precision => 5) # => "1.12283 TB"
# helper.number_to_human_size(524288000, :precision=>5) # => "500 MB"
#
# You can still use <tt>number_to_human_size</tt> with the old API that accepts the # You can still use <tt>number_to_human_size</tt> with the old API that accepts the
# +precision+ as its optional second parameter: # +precision+ as its optional second parameter:
# number_to_human_size(1234567, 2) # => 1.18 MB # number_to_human_size(1234567, 2) # => 1.18 MB
@ -291,7 +296,7 @@ module ActionView
:precision => precision, :precision => precision,
:separator => separator, :separator => separator,
:delimiter => delimiter :delimiter => delimiter
).sub(/(\d)(#{escaped_separator}[1-9]*)?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '') ).sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit) storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
rescue rescue
number number

View file

@ -393,7 +393,7 @@ module ActionView
concat(form_remote_tag(options)) concat(form_remote_tag(options))
fields_for(object_name, *(args << options), &proc) fields_for(object_name, *(args << options), &proc)
concat('</form>') concat('</form>'.html_safe!)
end end
alias_method :form_remote_for, :remote_form_for alias_method :form_remote_for, :remote_form_for

View file

@ -0,0 +1,9 @@
module ActionView #:nodoc:
module Helpers #:nodoc:
module RawOutputHelper
def raw(stringish)
stringish.to_s.html_safe!
end
end
end
end

View file

@ -49,7 +49,11 @@ module ActionView
# confuse browsers. # confuse browsers.
# #
def sanitize(html, options = {}) def sanitize(html, options = {})
self.class.white_list_sanitizer.sanitize(html, options) returning self.class.white_list_sanitizer.sanitize(html, options) do |sanitized|
if sanitized
sanitized.html_safe!
end
end
end end
# Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute. # Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute.
@ -72,7 +76,11 @@ module ActionView
# strip_tags("<div id='top-bar'>Welcome to my website!</div>") # strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# # => Welcome to my website! # # => Welcome to my website!
def strip_tags(html) def strip_tags(html)
self.class.full_sanitizer.sanitize(html) returning self.class.full_sanitizer.sanitize(html) do |sanitized|
if sanitized
sanitized.html_safe!
end
end
end end
# Strips all link tags from +text+ leaving just the link text. # Strips all link tags from +text+ leaving just the link text.

View file

@ -38,7 +38,7 @@ module ActionView
# tag("img", { :src => "open &amp; shut.png" }, false, false) # tag("img", { :src => "open &amp; shut.png" }, false, false)
# # => <img src="open &amp; shut.png" /> # # => <img src="open &amp; shut.png" />
def tag(name, options = nil, open = false, escape = true) def tag(name, options = nil, open = false, escape = true)
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}" "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe!
end end
# Returns an HTML block tag of type +name+ surrounding the +content+. Add # Returns an HTML block tag of type +name+ surrounding the +content+. Add
@ -91,7 +91,7 @@ module ActionView
# cdata_section(File.read("hello_world.txt")) # cdata_section(File.read("hello_world.txt"))
# # => <![CDATA[<hello from a text file]]> # # => <![CDATA[<hello from a text file]]>
def cdata_section(content) def cdata_section(content)
"<![CDATA[#{content}]]>" "<![CDATA[#{content}]]>".html_safe!
end end
# Returns an escaped version of +html+ without affecting existing escaped entities. # Returns an escaped version of +html+ without affecting existing escaped entities.
@ -125,7 +125,7 @@ module ActionView
def content_tag_string(name, content, options, escape = true) def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options tag_options = tag_options(options, escape) if options
"<#{name}#{tag_options}>#{content}</#{name}>" "<#{name}#{tag_options}>#{content}</#{name}>".html_safe!
end end
def tag_options(options, escape = true) def tag_options(options, escape = true)
@ -142,7 +142,7 @@ module ActionView
else else
attrs = options.map { |key, value| %(#{key}="#{value}") } attrs = options.map { |key, value| %(#{key}="#{value}") }
end end
" #{attrs.sort * ' '}" unless attrs.empty? " #{attrs.sort * ' '}".html_safe! unless attrs.empty?
end end
end end
end end

View file

@ -21,7 +21,7 @@ module ActionView
# Delegates to I18n.localize with no additional functionality. # Delegates to I18n.localize with no additional functionality.
def localize(*args) def localize(*args)
I18n.localize *args I18n.localize(*args)
end end
alias :l :localize alias :l :localize

View file

@ -219,7 +219,7 @@ module ActionView
if block_given? if block_given?
options = args.first || {} options = args.first || {}
html_options = args.second html_options = args.second
concat(link_to(capture(&block), options, html_options)) concat(link_to(capture(&block), options, html_options).html_safe!)
else else
name = args.first name = args.first
options = args.second || {} options = args.second || {}
@ -237,7 +237,7 @@ module ActionView
end end
href_attr = "href=\"#{url}\"" unless href href_attr = "href=\"#{url}\"" unless href
"<a #{href_attr}#{tag_options}>#{name || url}</a>" "<a #{href_attr}#{tag_options}>#{name || url}</a>".html_safe!
end end
end end
@ -309,7 +309,7 @@ module ActionView
html_options.merge!("type" => "submit", "value" => name) html_options.merge!("type" => "submit", "value" => name)
"<form method=\"#{form_method}\" action=\"#{escape_once url}\" class=\"button-to\"><div>" + "<form method=\"#{form_method}\" action=\"#{escape_once url}\" class=\"button-to\"><div>" +
method_tag + tag("input", html_options) + request_token_tag + "</div></form>" method_tag + tag("input", html_options) + request_token_tag + "</div></form>".html_safe!
end end

View file

@ -91,6 +91,9 @@
over_x_years: over_x_years:
one: "over 1 year" one: "over 1 year"
other: "over {{count}} years" other: "over {{count}} years"
almost_x_years:
one: "almost 1 year"
other: "almost {{count}} years"
prompts: prompts:
year: "Year" year: "Year"
month: "Month" month: "Month"

View file

@ -221,7 +221,7 @@ module ActionView
result = template.render_partial(self, object, local_assigns.dup, as) result = template.render_partial(self, object, local_assigns.dup, as)
index += 1 index += 1
result result
end.join(spacer) end.join(spacer).html_safe!
end end
def _pick_partial_template(partial_path) #:nodoc: def _pick_partial_template(partial_path) #:nodoc:

View file

@ -0,0 +1,28 @@
module ActionView #:nodoc:
class SafeBuffer < String
def <<(value)
if value.html_safe?
super(value)
else
super(ERB::Util.h(value))
end
end
def concat(value)
self << value
end
def html_safe?
true
end
def html_safe!
self
end
def to_s
self
end
end
end

View file

@ -57,9 +57,14 @@ module ActionView #:nodoc:
end end
class EagerPath < Path class EagerPath < Path
def initialize(path)
super
@loaded = false
end
def load! def load!
return if @loaded return if @loaded
@paths = {} @paths = {}
templates_in_path do |template| templates_in_path do |template|
template.load! template.load!
@ -103,8 +108,9 @@ module ActionView #:nodoc:
@@exempt_from_layout.merge(regexps) @@exempt_from_layout.merge(regexps)
end end
attr_accessor :template_path, :filename, :load_path, :base_path attr_accessor :template_path, :load_path, :base_path
attr_accessor :locale, :name, :format, :extension attr_accessor :locale, :name, :format, :extension
attr_writer :filename
delegate :to_s, :to => :path delegate :to_s, :to => :path
def initialize(template_path, load_path = nil) def initialize(template_path, load_path = nil)

View file

@ -22,11 +22,52 @@ module ActionView
end end
class TestCase < ActiveSupport::TestCase class TestCase < ActiveSupport::TestCase
class TestController < ActionController::Base
attr_accessor :request, :response, :params
def self.controller_path
''
end
def initialize
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@params = {}
send(:initialize_current_url)
end
end
include ActionController::TestCase::Assertions include ActionController::TestCase::Assertions
include ActionController::TestProcess include ActionController::TestProcess
include ActionController::PolymorphicRoutes
include ActionController::RecordIdentifier
include ActionView::Helpers
include ActionController::Helpers
class_inheritable_accessor :helper_class class_inheritable_accessor :helper_class
@@helper_class = nil attr_accessor :controller, :output_buffer, :rendered
setup :setup_with_controller
def setup_with_controller
@controller = TestController.new
@output_buffer = ''
@rendered = ''
self.class.send(:include_helper_modules!)
make_test_case_available_to_view!
end
def render(options = {}, local_assigns = {}, &block)
@rendered << output = _view.render(options, local_assigns, &block)
output
end
def protect_against_forgery?
false
end
class << self class << self
def tests(helper_class) def tests(helper_class)
@ -46,42 +87,76 @@ module ActionView
rescue NameError rescue NameError
nil nil
end end
end
include ActionView::Helpers def helper_method(*methods)
include ActionController::PolymorphicRoutes # Almost a duplicate from ActionController::Helpers
include ActionController::RecordIdentifier methods.flatten.each do |method|
master_helper_module.module_eval <<-end_eval
setup :setup_with_helper_class def #{method}(*args, &block) # def current_user(*args, &block)
_test_case.send(%(#{method}), *args, &block) # test_case.send(%(current_user), *args, &block)
def setup_with_helper_class end # end
if helper_class && !self.class.ancestors.include?(helper_class) end_eval
self.class.send(:include, helper_class) end
end end
self.output_buffer = '' private
def include_helper_modules!
helper(helper_class) if helper_class
include master_helper_module
end
end end
class TestController < ActionController::Base
attr_accessor :request, :response, :params
def initialize
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@params = {}
send(:initialize_current_url)
end
end
protected
attr_accessor :output_buffer
private private
def make_test_case_available_to_view!
test_case_instance = self
master_helper_module.module_eval do
define_method(:_test_case) { test_case_instance }
private :_test_case
end
end
def _view
view = ActionView::Base.new(ActionController::Base.view_paths, _assigns, @controller)
view.helpers.include master_helper_module
view.output_buffer = self.output_buffer
view
end
# Support the selector assertions
#
# Need to experiment if this priority is the best one: rendered => output_buffer
def response_from_page_or_rjs
HTML::Document.new(rendered.blank? ? output_buffer : rendered).root
end
EXCLUDE_IVARS = %w{
@output_buffer
@fixture_cache
@method_name
@_result
@loaded_fixtures
@test_passed
@view
}
def _instance_variables
instance_variables - EXCLUDE_IVARS
end
def _assigns
_instance_variables.inject({}) do |hash, var|
name = var[1..-1].to_sym
hash[name] = instance_variable_get(var)
hash
end
end
def method_missing(selector, *args) def method_missing(selector, *args)
controller = TestController.new if ActionController::Routing::Routes.named_routes.helpers.include?(selector)
return controller.__send__(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector) @controller.__send__(selector, *args)
super else
super
end
end end
end end
end end

View file

@ -1 +1,2 @@
require 'action_pack' require 'action_pack'
ActiveSupport::Deprecation.warn 'require "actionpack" is deprecated and will be removed in Rails 3. Use require "action_pack" instead.'

View file

@ -114,6 +114,13 @@ class CookieTest < ActionController::TestCase
assert_equal %w{1 2 3}, jar["pages"] assert_equal %w{1 2 3}, jar["pages"]
end end
def test_cookiejar_delete_removes_item_and_returns_its_value
@request.cookies["user_name"] = "david"
@controller.response = @response
jar = ActionController::CookieJar.new(@controller)
assert_equal "david", jar.delete("user_name")
end
def test_delete_cookie_with_path def test_delete_cookie_with_path
get :delete_cookie_with_path get :delete_cookie_with_path
assert_equal ["user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT"], @response.headers["Set-Cookie"] assert_equal ["user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT"], @response.headers["Set-Cookie"]

View file

@ -0,0 +1,53 @@
require 'abstract_unit'
class DomAssertionsTest < ActionView::TestCase
def setup
super
@html_only = '<ul><li>foo</li><li>bar</li></ul>'
@html_with_meaningless_whitespace = %{
<ul>
<li>\tfoo </li>
<li>
bar
</li>
</ul>
}
@more_html_with_meaningless_whitespace = %{<ul>
<li>foo</li>
<li>bar</li></ul>}
end
test "assert_dom_equal strips meaningless whitespace from expected string" do
assert_dom_equal @html_with_meaningless_whitespace, @html_only
end
test "assert_dom_equal strips meaningless whitespace from actual string" do
assert_dom_equal @html_only, @html_with_meaningless_whitespace
end
test "assert_dom_equal strips meaningless whitespace from both expected and actual strings" do
assert_dom_equal @more_html_with_meaningless_whitespace, @html_with_meaningless_whitespace
end
test "assert_dom_not_equal strips meaningless whitespace from expected string" do
assert_assertion_fails { assert_dom_not_equal @html_with_meaningless_whitespace, @html_only }
end
test "assert_dom_not_equal strips meaningless whitespace from actual string" do
assert_assertion_fails { assert_dom_not_equal @html_only, @html_with_meaningless_whitespace }
end
test "assert_dom_not_equal strips meaningless whitespace from both expected and actual strings" do
assert_assertion_fails do
assert_dom_not_equal @more_html_with_meaningless_whitespace, @html_with_meaningless_whitespace
end
end
private
def assert_assertion_fails
assert_raise(ActiveSupport::TestCase::Assertion) { yield }
end
end

View file

@ -18,6 +18,7 @@ class FilterParamTest < Test::Unit::TestCase
test_hashes = [[{},{},[]], test_hashes = [[{},{},[]],
[{'foo'=>nil},{'foo'=>nil},[]], [{'foo'=>nil},{'foo'=>nil},[]],
[{'foo'=>'bar'},{'foo'=>'bar'},[]], [{'foo'=>'bar'},{'foo'=>'bar'},[]],
[{'foo'=>1},{'foo'=>1},[]],
[{'foo'=>'bar'},{'foo'=>'bar'},%w'food'], [{'foo'=>'bar'},{'foo'=>'bar'},%w'food'],
[{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'], [{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'],
[{'foo'=>'bar', 'bar'=>'foo'},{'foo'=>'[FILTERED]', 'bar'=>'foo'},%w'foo baz'], [{'foo'=>'bar', 'bar'=>'foo'},{'foo'=>'[FILTERED]', 'bar'=>'foo'},%w'foo baz'],

View file

@ -19,6 +19,7 @@ class SanitizerTest < ActionController::TestCase
assert_equal "This has a here.", sanitizer.sanitize("This has a <!-- comment --> here.") assert_equal "This has a here.", sanitizer.sanitize("This has a <!-- comment --> here.")
assert_equal "This has a here.", sanitizer.sanitize("This has a <![CDATA[<section>]]> here.") assert_equal "This has a here.", sanitizer.sanitize("This has a <![CDATA[<section>]]> here.")
assert_equal "This has an unclosed ", sanitizer.sanitize("This has an unclosed <![CDATA[<section>]] here...") assert_equal "This has an unclosed ", sanitizer.sanitize("This has an unclosed <![CDATA[<section>]] here...")
assert_equal "non printable char is a tag", sanitizer.sanitize("<\x07a href='/hello'>non printable char is a tag</a>")
[nil, '', ' '].each { |blank| assert_equal blank, sanitizer.sanitize(blank) } [nil, '', ' '].each { |blank| assert_equal blank, sanitizer.sanitize(blank) }
end end

View file

@ -92,6 +92,23 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
assert_equal "Authentication Failed", @response.body assert_equal "Authentication Failed", @response.body
end end
test "authentication request with missing nonce should return 401" do
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please', :remove_nonce => true)
get :display
assert_response :unauthorized
assert_equal "Authentication Failed", @response.body
end
test "authentication request with Basic auth credentials should return 401" do
ActionController::Base.session_options[:secret] = "session_options_secret"
@request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials('pretty', 'please')
get :display
assert_response :unauthorized
assert_equal "Authentication Failed", @response.body
end
test "authentication request with invalid opaque" do test "authentication request with invalid opaque" do
@request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'foo', :opaque => "xxyyzz") @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'foo', :opaque => "xxyyzz")
get :display get :display
@ -220,9 +237,14 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
assert_response :unauthorized assert_response :unauthorized
remove_nonce = options.delete(:remove_nonce)
credentials = decode_credentials(@response.headers['WWW-Authenticate']) credentials = decode_credentials(@response.headers['WWW-Authenticate'])
credentials.merge!(options) credentials.merge!(options)
credentials.merge!(:uri => @request.env['REQUEST_URI'].to_s) credentials.merge!(:uri => @request.env['REQUEST_URI'].to_s)
credentials.delete(:nonce) if remove_nonce
ActionController::HttpAuthentication::Digest.encode_credentials(method, credentials, password, options[:password_is_ha1]) ActionController::HttpAuthentication::Digest.encode_credentials(method, credentials, password, options[:password_is_ha1])
end end

View file

@ -207,6 +207,24 @@ class IntegrationTestTest < Test::Unit::TestCase
assert_equal ::ActionController::Integration::Session, session2.class assert_equal ::ActionController::Integration::Session, session2.class
assert_not_equal session1, session2 assert_not_equal session1, session2
end end
# RSpec mixes Matchers (which has a #method_missing) into
# IntegrationTest's superclass. Make sure IntegrationTest does not
# try to delegate these methods to the session object.
def test_does_not_prevent_method_missing_passing_up_to_ancestors
mixin = Module.new do
def method_missing(name, *args)
name.to_s == 'foo' ? 'pass' : super
end
end
@test.class.superclass.__send__(:include, mixin)
begin
assert_equal 'pass', @test.foo
ensure
# leave other tests as unaffected as possible
mixin.__send__(:remove_method, :method_missing)
end
end
end end
# Tests that integration tests don't call Controller test methods for processing. # Tests that integration tests don't call Controller test methods for processing.
@ -443,3 +461,23 @@ class MetalTest < ActionController::IntegrationTest
assert_equal '', response.body assert_equal '', response.body
end end
end end
class StringSubclassBodyTest < ActionController::IntegrationTest
class SafeString < String
end
class SafeStringMiddleware
def self.call(env)
[200, {"Content-Type" => "text/plain", "Content-Length" => "12"}, [SafeString.new("Hello World!")]]
end
end
def setup
@integration_session = ActionController::Integration::Session.new(SafeStringMiddleware)
end
def test_string_subclass_body
get '/'
assert_equal 'Hello World!', response.body
end
end

View file

@ -83,6 +83,11 @@ class AbsolutePathLayoutController < LayoutTest
layout File.expand_path(File.expand_path(__FILE__) + '/../../fixtures/layout_tests/layouts/layout_test.rhtml') layout File.expand_path(File.expand_path(__FILE__) + '/../../fixtures/layout_tests/layouts/layout_test.rhtml')
end end
class AbsolutePathWithoutLayoutsController < LayoutTest
# Absolute layout path without 'layouts' in it.
layout File.expand_path(File.expand_path(__FILE__) + '/../../fixtures/layout_tests/abs_path_layout.rhtml')
end
class HasOwnLayoutController < LayoutTest class HasOwnLayoutController < LayoutTest
layout 'item' layout 'item'
end end
@ -153,6 +158,12 @@ class LayoutSetInResponseTest < ActionController::TestCase
get :hello get :hello
assert_equal "layout_test.rhtml hello.rhtml", @response.body.strip assert_equal "layout_test.rhtml hello.rhtml", @response.body.strip
end end
def test_absolute_pathed_layout_without_layouts_in_path
@controller = AbsolutePathWithoutLayoutsController.new
get :hello
assert_equal "abs_path_layout.rhtml hello.rhtml", @response.body.strip
end
end end
class RenderWithTemplateOptionController < LayoutTest class RenderWithTemplateOptionController < LayoutTest

View file

@ -290,4 +290,8 @@ class PolymorphicRoutesTest < ActiveSupport::TestCase
polymorphic_url([:taxes]) polymorphic_url([:taxes])
end end
def test_with_array_containing_symbols
expects(:new_article_url).with()
polymorphic_url([:new, :article])
end
end end

View file

@ -22,7 +22,7 @@ module RequestForgeryProtectionActions
def unsafe def unsafe
render :text => 'pwn' render :text => 'pwn'
end end
def rescue_action(e) raise e end def rescue_action(e) raise e end
end end
@ -44,6 +44,13 @@ class FreeCookieController < RequestForgeryProtectionController
end end
end end
class CustomAuthenticityParamController < RequestForgeryProtectionController
def form_authenticity_param
'foobar'
end
end
# common test methods # common test methods
module RequestForgeryProtectionTests module RequestForgeryProtectionTests
@ -245,3 +252,14 @@ class FreeCookieControllerTest < ActionController::TestCase
end end
end end
end end
class CustomAuthenticityParamControllerTest < ActionController::TestCase
def setup
ActionController::Base.request_forgery_protection_token = :authenticity_token
end
def test_should_allow_custom_token
post :index, :authenticity_token => 'foobar'
assert_response :ok
end
end

View file

@ -107,7 +107,11 @@ class StaticSegmentTest < Test::Unit::TestCase
end end
end end
class DynamicSegmentTest < Test::Unit::TestCase class DynamicSegmentTest < ActiveSupport::TestCase
def setup
@segment = nil
end
def segment(options = {}) def segment(options = {})
unless @segment unless @segment
@segment = ROUTING::DynamicSegment.new(:a, options) @segment = ROUTING::DynamicSegment.new(:a, options)
@ -341,7 +345,11 @@ class ControllerSegmentTest < Test::Unit::TestCase
end end
end end
class PathSegmentTest < Test::Unit::TestCase class PathSegmentTest < ActiveSupport::TestCase
def setup
@segment = nil
end
def segment(options = {}) def segment(options = {})
unless @segment unless @segment
@segment = ROUTING::PathSegment.new(:path, options) @segment = ROUTING::PathSegment.new(:path, options)
@ -754,7 +762,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed) ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed)
end end
def teardown def teardown
@rs.clear! @rs.clear!
end end
@ -1094,21 +1102,21 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/} map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
end end
exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") } exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") }
assert_match /^post_url failed to generate/, exception.message assert_match(/^post_url failed to generate/, exception.message)
from_match = exception.message.match(/from \{[^\}]+\}/).to_s from_match = exception.message.match(/from \{[^\}]+\}/).to_s
assert_match /:bad_param=>"foo"/, from_match assert_match(/:bad_param=>"foo"/, from_match)
assert_match /:action=>"show"/, from_match assert_match(/:action=>"show"/, from_match)
assert_match /:controller=>"post"/, from_match assert_match(/:controller=>"post"/, from_match)
expected_match = exception.message.match(/expected: \{[^\}]+\}/).to_s expected_match = exception.message.match(/expected: \{[^\}]+\}/).to_s
assert_no_match /:bad_param=>"foo"/, expected_match assert_no_match(/:bad_param=>"foo"/, expected_match)
assert_match /:action=>"show"/, expected_match assert_match( /:action=>"show"/, expected_match)
assert_match /:controller=>"post"/, expected_match assert_match( /:controller=>"post"/, expected_match)
diff_match = exception.message.match(/diff: \{[^\}]+\}/).to_s diff_match = exception.message.match(/diff: \{[^\}]+\}/).to_s
assert_match /:bad_param=>"foo"/, diff_match assert_match( /:bad_param=>"foo"/, diff_match)
assert_no_match /:action=>"show"/, diff_match assert_no_match(/:action=>"show"/, diff_match)
assert_no_match /:controller=>"post"/, diff_match assert_no_match(/:controller=>"post"/, diff_match)
end end
# this specifies the case where your formerly would get a very confusing error message with an empty diff # this specifies the case where your formerly would get a very confusing error message with an empty diff
@ -2564,10 +2572,10 @@ class RouteLoadingTest < Test::Unit::TestCase
routes.reload routes.reload
end end
def test_load_multiple_configurations def test_load_multiple_configurations
routes.add_configuration_file("engines.rb") routes.add_configuration_file("engines.rb")
File.expects(:stat).at_least_once.returns(@stat) File.expects(:stat).at_least_once.returns(@stat)
routes.expects(:load).with('./config/routes.rb') routes.expects(:load).with('./config/routes.rb')

View file

@ -33,11 +33,11 @@ class ActionController::TestSessionTest < ActiveSupport::TestCase
assert_equal('value', session[:key]) assert_equal('value', session[:key])
end end
def test_calling_delete_removes_item def test_calling_delete_removes_item_and_returns_its_value
session = ActionController::TestSession.new session = ActionController::TestSession.new
session[:key] = 'value' session[:key] = 'value'
assert_equal('value', session[:key]) assert_equal('value', session[:key])
session.delete(:key) assert_equal('value', session.delete(:key))
assert_nil(session[:key]) assert_nil(session[:key])
end end

View file

@ -0,0 +1 @@
abs_path_layout.rhtml <%= yield %>

View file

@ -0,0 +1 @@
<%= render_from_helper %>

View file

@ -183,7 +183,7 @@ class ActiveRecordHelperTest < ActionView::TestCase
end end
def test_form_with_action_option def test_form_with_action_option
@response.body = form("post", :action => "sign") output_buffer << form("post", :action => "sign")
assert_select "form[action=sign]" do |form| assert_select "form[action=sign]" do |form|
assert_select "input[type=submit][value=Sign]" assert_select "input[type=submit][value=Sign]"
end end

View file

@ -164,6 +164,11 @@ class AssetTagHelperTest < ActionView::TestCase
assert_dom_equal(%(<script src="/javascripts/prototype.js?1" type="text/javascript"></script>\n<script src="/javascripts/effects.js?1" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js?1" type="text/javascript"></script>\n<script src="/javascripts/controls.js?1" type="text/javascript"></script>\n<script src="/javascripts/application.js?1" type="text/javascript"></script>), javascript_include_tag(:defaults)) assert_dom_equal(%(<script src="/javascripts/prototype.js?1" type="text/javascript"></script>\n<script src="/javascripts/effects.js?1" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js?1" type="text/javascript"></script>\n<script src="/javascripts/controls.js?1" type="text/javascript"></script>\n<script src="/javascripts/application.js?1" type="text/javascript"></script>), javascript_include_tag(:defaults))
end end
def test_javascript_include_tag_is_html_safe
assert javascript_include_tag(:defaults).html_safe?
assert javascript_include_tag("prototype").html_safe?
end
def test_register_javascript_include_default def test_register_javascript_include_default
ENV["RAILS_ASSET_ID"] = "" ENV["RAILS_ASSET_ID"] = ""
ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'slider' ActionView::Helpers::AssetTagHelper::register_javascript_include_default 'slider'
@ -206,6 +211,13 @@ class AssetTagHelperTest < ActionView::TestCase
StyleLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } StyleLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end end
def test_stylesheet_link_tag_is_html_safe
ENV["RAILS_ASSET_ID"] = ""
assert stylesheet_link_tag('dir/file').html_safe?
assert stylesheet_link_tag('dir/other/file', 'dir/file2').html_safe?
assert stylesheet_tag('dir/file', {}).html_safe?
end
def test_custom_stylesheet_expansions def test_custom_stylesheet_expansions
ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :monkey => ["head", "body", "tail"] ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :monkey => ["head", "body", "tail"]
assert_dom_equal %(<link href="/stylesheets/first.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/head.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/body.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/tail.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/last.css" media="screen" rel="stylesheet" type="text/css" />), stylesheet_link_tag('first', :monkey, 'last') assert_dom_equal %(<link href="/stylesheets/first.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/head.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/body.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/tail.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/stylesheets/last.css" media="screen" rel="stylesheet" type="text/css" />), stylesheet_link_tag('first', :monkey, 'last')

View file

@ -4,14 +4,14 @@ require 'action_view/helpers/benchmark_helper'
class BenchmarkHelperTest < ActionView::TestCase class BenchmarkHelperTest < ActionView::TestCase
tests ActionView::Helpers::BenchmarkHelper tests ActionView::Helpers::BenchmarkHelper
def teardown def setup
controller.logger.send(:clear_buffer) super
controller.logger = ActiveSupport::BufferedLogger.new(StringIO.new)
controller.logger.auto_flushing = false
end end
def controller def teardown
logger = ActiveSupport::BufferedLogger.new(StringIO.new) controller.logger.send(:clear_buffer)
logger.auto_flushing = false
@controller ||= Struct.new(:logger).new(logger)
end end
def test_without_block def test_without_block

View file

@ -2,8 +2,9 @@ require 'abstract_unit'
require 'controller/fake_models' require 'controller/fake_models'
class CompiledTemplatesTest < Test::Unit::TestCase class CompiledTemplatesTest < Test::Unit::TestCase
def setup def setup
@explicit_view_paths = nil
@compiled_templates = ActionView::Base::CompiledTemplates @compiled_templates = ActionView::Base::CompiledTemplates
@compiled_templates.instance_methods.each do |m| @compiled_templates.instance_methods.each do |m|
@compiled_templates.send(:remove_method, m) if m =~ /^_run_/ @compiled_templates.send(:remove_method, m) if m =~ /^_run_/

View file

@ -20,15 +20,16 @@ class DateHelperDistanceOfTimeInWordsI18nTests < Test::Unit::TestCase
[60.seconds, true] => [:'x_minutes', 1], [60.seconds, true] => [:'x_minutes', 1],
# without include_seconds # without include_seconds
[29.seconds, false] => [:'less_than_x_minutes', 1], [29.seconds, false] => [:'less_than_x_minutes', 1],
[60.seconds, false] => [:'x_minutes', 1], [60.seconds, false] => [:'x_minutes', 1],
[44.minutes, false] => [:'x_minutes', 44], [44.minutes, false] => [:'x_minutes', 44],
[61.minutes, false] => [:'about_x_hours', 1], [61.minutes, false] => [:'about_x_hours', 1],
[24.hours, false] => [:'x_days', 1], [24.hours, false] => [:'x_days', 1],
[30.days, false] => [:'about_x_months', 1], [30.days, false] => [:'about_x_months', 1],
[60.days, false] => [:'x_months', 2], [60.days, false] => [:'x_months', 2],
[1.year, false] => [:'about_x_years', 1], [1.year, false] => [:'about_x_years', 1],
[3.years, false] => [:'over_x_years', 3] [3.years + 6.months, false] => [:'over_x_years', 3],
[3.years + 10.months, false] => [:'almost_x_years', 4]
}.each do |passed, expected| }.each do |passed, expected|
assert_distance_of_time_in_words_translates_key passed, expected assert_distance_of_time_in_words_translates_key passed, expected

View file

@ -53,13 +53,14 @@ class DateHelperTest < ActionView::TestCase
assert_equal "about 2 hours", distance_of_time_in_words(from, to + 89.minutes + 30.seconds) assert_equal "about 2 hours", distance_of_time_in_words(from, to + 89.minutes + 30.seconds)
assert_equal "about 24 hours", distance_of_time_in_words(from, to + 23.hours + 59.minutes + 29.seconds) assert_equal "about 24 hours", distance_of_time_in_words(from, to + 23.hours + 59.minutes + 29.seconds)
# 1440..2879 # 1440..2529
assert_equal "1 day", distance_of_time_in_words(from, to + 23.hours + 59.minutes + 30.seconds) assert_equal "1 day", distance_of_time_in_words(from, to + 23.hours + 59.minutes + 30.seconds)
assert_equal "1 day", distance_of_time_in_words(from, to + 47.hours + 59.minutes + 29.seconds) assert_equal "1 day", distance_of_time_in_words(from, to + 41.hours + 59.minutes + 29.seconds)
# 2880..43199 # 2530..43199
assert_equal "2 days", distance_of_time_in_words(from, to + 47.hours + 59.minutes + 30.seconds) assert_equal "2 days", distance_of_time_in_words(from, to + 42.hours + 59.minutes + 30.seconds)
assert_equal "29 days", distance_of_time_in_words(from, to + 29.days + 23.hours + 59.minutes + 29.seconds) assert_equal "3 days", distance_of_time_in_words(from, to + 2.days + 12.hours)
assert_equal "30 days", distance_of_time_in_words(from, to + 29.days + 23.hours + 59.minutes + 29.seconds)
# 43200..86399 # 43200..86399
assert_equal "about 1 month", distance_of_time_in_words(from, to + 29.days + 23.hours + 59.minutes + 30.seconds) assert_equal "about 1 month", distance_of_time_in_words(from, to + 29.days + 23.hours + 59.minutes + 30.seconds)
@ -69,13 +70,28 @@ class DateHelperTest < ActionView::TestCase
assert_equal "2 months", distance_of_time_in_words(from, to + 59.days + 23.hours + 59.minutes + 30.seconds) assert_equal "2 months", distance_of_time_in_words(from, to + 59.days + 23.hours + 59.minutes + 30.seconds)
assert_equal "12 months", distance_of_time_in_words(from, to + 1.years - 31.seconds) assert_equal "12 months", distance_of_time_in_words(from, to + 1.years - 31.seconds)
# 525600..1051199 # > 525599
assert_equal "about 1 year", distance_of_time_in_words(from, to + 1.years - 30.seconds) assert_equal "about 1 year", distance_of_time_in_words(from, to + 1.years - 30.seconds)
assert_equal "about 1 year", distance_of_time_in_words(from, to + 2.years - 31.seconds) assert_equal "about 1 year", distance_of_time_in_words(from, to + 1.years + 3.months - 1.day)
assert_equal "over 1 year", distance_of_time_in_words(from, to + 1.years + 6.months)
# > 1051199 assert_equal "almost 2 years", distance_of_time_in_words(from, to + 2.years - 3.months + 1.day)
assert_equal "over 2 years", distance_of_time_in_words(from, to + 2.years + 30.seconds) assert_equal "about 2 years", distance_of_time_in_words(from, to + 2.years + 3.months - 1.day)
assert_equal "over 10 years", distance_of_time_in_words(from, to + 10.years) assert_equal "over 2 years", distance_of_time_in_words(from, to + 2.years + 3.months + 1.day)
assert_equal "over 2 years", distance_of_time_in_words(from, to + 2.years + 9.months - 1.day)
assert_equal "almost 3 years", distance_of_time_in_words(from, to + 2.years + 9.months + 1.day)
assert_equal "almost 5 years", distance_of_time_in_words(from, to + 5.years - 3.months + 1.day)
assert_equal "about 5 years", distance_of_time_in_words(from, to + 5.years + 3.months - 1.day)
assert_equal "over 5 years", distance_of_time_in_words(from, to + 5.years + 3.months + 1.day)
assert_equal "over 5 years", distance_of_time_in_words(from, to + 5.years + 9.months - 1.day)
assert_equal "almost 6 years", distance_of_time_in_words(from, to + 5.years + 9.months + 1.day)
assert_equal "almost 10 years", distance_of_time_in_words(from, to + 10.years - 3.months + 1.day)
assert_equal "about 10 years", distance_of_time_in_words(from, to + 10.years + 3.months - 1.day)
assert_equal "over 10 years", distance_of_time_in_words(from, to + 10.years + 3.months + 1.day)
assert_equal "over 10 years", distance_of_time_in_words(from, to + 10.years + 9.months - 1.day)
assert_equal "almost 11 years", distance_of_time_in_words(from, to + 10.years + 9.months + 1.day)
# test to < from # test to < from
assert_equal "about 4 hours", distance_of_time_in_words(from + 4.hours, to) assert_equal "about 4 hours", distance_of_time_in_words(from + 4.hours, to)
@ -104,7 +120,7 @@ class DateHelperTest < ActionView::TestCase
def test_distance_in_words_with_dates def test_distance_in_words_with_dates
start_date = Date.new 1975, 1, 31 start_date = Date.new 1975, 1, 31
end_date = Date.new 1977, 1, 31 end_date = Date.new 1977, 1, 31
assert_equal("over 2 years", distance_of_time_in_words(start_date, end_date)) assert_equal("about 2 years", distance_of_time_in_words(start_date, end_date))
end end
def test_distance_in_words_with_integers def test_distance_in_words_with_integers

View file

@ -697,6 +697,26 @@ class FormHelperTest < ActionView::TestCase
end end
end end
expected = '<form action="http://www.example.com" method="post">' +
'<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
'<input id="post_author_attributes_name" name="post[author_attributes][name]" size="30" type="text" value="author #321" />' +
'<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' +
'</form>'
assert_dom_equal expected, output_buffer
end
def test_nested_fields_for_with_existing_records_on_a_nested_attributes_one_to_one_association_with_explicit_hidden_field_placement
@post.author = Author.new(321)
form_for(:post, @post) do |f|
concat f.text_field(:title)
f.fields_for(:author) do |af|
concat af.hidden_field(:id)
concat af.text_field(:name)
end
end
expected = '<form action="http://www.example.com" method="post">' + expected = '<form action="http://www.example.com" method="post">' +
'<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' + '<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
'<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' + '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' +
@ -718,6 +738,30 @@ class FormHelperTest < ActionView::TestCase
end end
end end
expected = '<form action="http://www.example.com" method="post">' +
'<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
'<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #1" />' +
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="comment #2" />' +
'<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />' +
'</form>'
assert_dom_equal expected, output_buffer
end
def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association_with_explicit_hidden_field_placement
@post.comments = Array.new(2) { |id| Comment.new(id + 1) }
form_for(:post, @post) do |f|
concat f.text_field(:title)
@post.comments.each do |comment|
f.fields_for(:comments, comment) do |cf|
concat cf.hidden_field(:id)
concat cf.text_field(:name)
end
end
end
expected = '<form action="http://www.example.com" method="post">' + expected = '<form action="http://www.example.com" method="post">' +
'<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' + '<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
@ -764,14 +808,50 @@ class FormHelperTest < ActionView::TestCase
expected = '<form action="http://www.example.com" method="post">' + expected = '<form action="http://www.example.com" method="post">' +
'<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' + '<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
'<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #321" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #321" />' +
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="new comment" />' + '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="new comment" />' +
'</form>' '</form>'
assert_dom_equal expected, output_buffer assert_dom_equal expected, output_buffer
end end
def test_nested_fields_for_with_an_empty_supplied_attributes_collection
form_for(:post, @post) do |f|
concat f.text_field(:title)
f.fields_for(:comments, []) do |cf|
concat cf.text_field(:name)
end
end
expected = '<form action="http://www.example.com" method="post">' +
'<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
'</form>'
assert_dom_equal expected, output_buffer
end
def test_nested_fields_for_with_existing_records_on_a_supplied_nested_attributes_collection
@post.comments = Array.new(2) { |id| Comment.new(id + 1) }
form_for(:post, @post) do |f|
concat f.text_field(:title)
f.fields_for(:comments, @post.comments) do |cf|
concat cf.text_field(:name)
end
end
expected = '<form action="http://www.example.com" method="post">' +
'<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
'<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #1" />' +
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="comment #2" />' +
'<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />' +
'</form>'
assert_dom_equal expected, output_buffer
end
def test_nested_fields_for_on_a_nested_attributes_collection_association_yields_only_builder def test_nested_fields_for_on_a_nested_attributes_collection_association_yields_only_builder
@post.comments = [Comment.new(321), Comment.new] @post.comments = [Comment.new(321), Comment.new]
yielded_comments = [] yielded_comments = []
@ -786,8 +866,8 @@ class FormHelperTest < ActionView::TestCase
expected = '<form action="http://www.example.com" method="post">' + expected = '<form action="http://www.example.com" method="post">' +
'<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' + '<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
'<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #321" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #321" />' +
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
'<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="new comment" />' + '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="new comment" />' +
'</form>' '</form>'
@ -805,8 +885,8 @@ class FormHelperTest < ActionView::TestCase
end end
expected = '<form action="http://www.example.com" method="post">' + expected = '<form action="http://www.example.com" method="post">' +
'<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />' +
'<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" size="30" type="text" value="comment #321" />' + '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" size="30" type="text" value="comment #321" />' +
'<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />' +
'</form>' '</form>'
assert_dom_equal expected, output_buffer assert_dom_equal expected, output_buffer
@ -840,18 +920,18 @@ class FormHelperTest < ActionView::TestCase
end end
expected = '<form action="http://www.example.com" method="post">' + expected = '<form action="http://www.example.com" method="post">' +
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
'<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #321" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #321" />' +
'<input id="post_comments_attributes_0_relevances_attributes_0_id" name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' +
'<input id="post_comments_attributes_0_relevances_attributes_0_value" name="post[comments_attributes][0][relevances_attributes][0][value]" size="30" type="text" value="commentrelevance #314" />' + '<input id="post_comments_attributes_0_relevances_attributes_0_value" name="post[comments_attributes][0][relevances_attributes][0][value]" size="30" type="text" value="commentrelevance #314" />' +
'<input id="post_tags_attributes_0_id" name="post[tags_attributes][0][id]" type="hidden" value="123" />' + '<input id="post_comments_attributes_0_relevances_attributes_0_id" name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' +
'<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
'<input id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" size="30" type="text" value="tag #123" />' + '<input id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" size="30" type="text" value="tag #123" />' +
'<input id="post_tags_attributes_0_relevances_attributes_0_id" name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" />' +
'<input id="post_tags_attributes_0_relevances_attributes_0_value" name="post[tags_attributes][0][relevances_attributes][0][value]" size="30" type="text" value="tagrelevance #3141" />' + '<input id="post_tags_attributes_0_relevances_attributes_0_value" name="post[tags_attributes][0][relevances_attributes][0][value]" size="30" type="text" value="tagrelevance #3141" />' +
'<input id="post_tags_attributes_1_id" name="post[tags_attributes][1][id]" type="hidden" value="456" />' + '<input id="post_tags_attributes_0_relevances_attributes_0_id" name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" />' +
'<input id="post_tags_attributes_0_id" name="post[tags_attributes][0][id]" type="hidden" value="123" />' +
'<input id="post_tags_attributes_1_value" name="post[tags_attributes][1][value]" size="30" type="text" value="tag #456" />' + '<input id="post_tags_attributes_1_value" name="post[tags_attributes][1][value]" size="30" type="text" value="tag #456" />' +
'<input id="post_tags_attributes_1_relevances_attributes_0_id" name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" />' +
'<input id="post_tags_attributes_1_relevances_attributes_0_value" name="post[tags_attributes][1][relevances_attributes][0][value]" size="30" type="text" value="tagrelevance #31415" />' + '<input id="post_tags_attributes_1_relevances_attributes_0_value" name="post[tags_attributes][1][relevances_attributes][0][value]" size="30" type="text" value="tagrelevance #31415" />' +
'<input id="post_tags_attributes_1_relevances_attributes_0_id" name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" />' +
'<input id="post_tags_attributes_1_id" name="post[tags_attributes][1][id]" type="hidden" value="456" />' +
'</form>' '</form>'
assert_dom_equal expected, output_buffer assert_dom_equal expected, output_buffer
@ -1024,7 +1104,7 @@ class FormHelperTest < ActionView::TestCase
(field_helpers - %w(hidden_field)).each do |selector| (field_helpers - %w(hidden_field)).each do |selector|
src = <<-END_SRC src = <<-END_SRC
def #{selector}(field, *args, &proc) def #{selector}(field, *args, &proc)
"<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>" ("<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>").html_safe!
end end
END_SRC END_SRC
class_eval src, __FILE__, __LINE__ class_eval src, __FILE__, __LINE__

View file

@ -118,6 +118,10 @@ class NumberHelperTest < ActionView::TestCase
assert_equal '1.01 KB', number_to_human_size(1.0123.kilobytes, :precision => 2) assert_equal '1.01 KB', number_to_human_size(1.0123.kilobytes, :precision => 2)
assert_equal '1.01 KB', number_to_human_size(1.0100.kilobytes, :precision => 4) assert_equal '1.01 KB', number_to_human_size(1.0100.kilobytes, :precision => 4)
assert_equal '10 KB', number_to_human_size(10.000.kilobytes, :precision => 4) assert_equal '10 KB', number_to_human_size(10.000.kilobytes, :precision => 4)
assert_equal '1 TB', number_to_human_size(1234567890123, :precision => 0)
assert_equal '500 MB', number_to_human_size(524288000, :precision=>0)
assert_equal '40 KB', number_to_human_size(41010, :precision => 0)
assert_equal '40 KB', number_to_human_size(41100, :precision => 0)
end end
def test_number_to_human_size_with_custom_delimiter_and_separator def test_number_to_human_size_with_custom_delimiter_and_separator

View file

@ -0,0 +1,21 @@
require 'abstract_unit'
require 'testing_sandbox'
class RawOutputHelperTest < ActionView::TestCase
tests ActionView::Helpers::RawOutputHelper
include TestingSandbox
def setup
@string = "hello"
end
test "raw returns the safe string" do
result = raw(@string)
assert_equal @string, result
assert result.html_safe?
end
test "raw handles nil values correctly" do
assert_equal "", raw(nil)
end
end

View file

@ -39,7 +39,16 @@ class SanitizeHelperTest < ActionView::TestCase
%{This is a test.\n\n\nIt no longer contains any HTML.\n}, strip_tags( %{This is a test.\n\n\nIt no longer contains any HTML.\n}, strip_tags(
%{<title>This is <b>a <a href="" target="_blank">test</a></b>.</title>\n\n<!-- it has a comment -->\n\n<p>It no <b>longer <strong>contains <em>any <strike>HTML</strike></em>.</strong></b></p>\n})) %{<title>This is <b>a <a href="" target="_blank">test</a></b>.</title>\n\n<!-- it has a comment -->\n\n<p>It no <b>longer <strong>contains <em>any <strike>HTML</strike></em>.</strong></b></p>\n}))
assert_equal "This has a here.", strip_tags("This has a <!-- comment --> here.") assert_equal "This has a here.", strip_tags("This has a <!-- comment --> here.")
[nil, '', ' '].each { |blank| assert_equal blank, strip_tags(blank) } [nil, '', ' '].each do |blank|
stripped = strip_tags(blank)
assert_equal blank, stripped
assert stripped.html_safe? unless blank.nil?
end
assert strip_tags("<script>").html_safe?
end
def test_sanitize_is_marked_safe
assert sanitize("<html><script></script></html>").html_safe?
end end
def assert_sanitized(text, expected = nil) def assert_sanitized(text, expected = nil)

View file

@ -34,6 +34,7 @@ class TagHelperTest < ActionView::TestCase
def test_content_tag def test_content_tag
assert_equal "<a href=\"create\">Create</a>", content_tag("a", "Create", "href" => "create") assert_equal "<a href=\"create\">Create</a>", content_tag("a", "Create", "href" => "create")
assert content_tag("a", "Create", "href" => "create").html_safe?
assert_equal content_tag("a", "Create", "href" => "create"), assert_equal content_tag("a", "Create", "href" => "create"),
content_tag("a", "Create", :href => "create") content_tag("a", "Create", :href => "create")
end end

View file

@ -0,0 +1,36 @@
require 'abstract_unit'
class SafeBufferTest < ActionView::TestCase
def setup
@buffer = ActionView::SafeBuffer.new
end
test "Should look like a string" do
assert @buffer.is_a?(String)
assert_equal "", @buffer
end
test "Should escape a raw string which is passed to them" do
@buffer << "<script>"
assert_equal "&lt;script&gt;", @buffer
end
test "Should NOT escape a safe value passed to it" do
@buffer << "<script>".html_safe!
assert_equal "<script>", @buffer
end
test "Should not mess with an innocuous string" do
@buffer << "Hello"
assert_equal "Hello", @buffer
end
test "Should be considered safe" do
assert @buffer.html_safe?
end
test "Should return a safe buffer when calling to_s" do
new_buffer = @buffer.to_s
assert_equal ActionView::SafeBuffer, new_buffer.class
end
end

View file

@ -1,8 +1,176 @@
require 'abstract_unit' require 'abstract_unit'
class TestCaseTest < ActionView::TestCase module ActionView
def test_should_have_current_url class TestCase
controller = TestController.new module ATestHelper
assert_nothing_raised(NoMethodError){ controller.url_for({:controller => "foo", :action => "index"}) } end
module AnotherTestHelper
def from_another_helper
'Howdy!'
end
end
module ASharedTestHelper
def from_shared_helper
'Holla!'
end
end
helper ASharedTestHelper
module SharedTests
def self.included(test_case)
test_case.class_eval do
test "helpers defined on ActionView::TestCase are available" do
assert test_case.ancestors.include?(ASharedTestHelper)
assert_equal 'Holla!', from_shared_helper
end
end
end
end
class GeneralViewTest < ActionView::TestCase
include SharedTests
test_case = self
test "works without testing a helper module" do
assert_equal 'Eloy', render('developers/developer', :developer => stub(:name => 'Eloy'))
end
test "can render a layout with block" do
assert_equal "Before (ChrisCruft)\n!\nAfter",
render(:layout => "test/layout_for_partial", :locals => {:name => "ChrisCruft"}) {"!"}
end
helper AnotherTestHelper
test "additional helper classes can be specified as in a controller" do
assert test_case.ancestors.include?(AnotherTestHelper)
assert_equal 'Howdy!', from_another_helper
end
end
class ClassMethodsTest < ActionView::TestCase
include SharedTests
test_case = self
tests ATestHelper
test "tests the specified helper module" do
assert_equal ATestHelper, test_case.helper_class
assert test_case.ancestors.include?(ATestHelper)
end
helper AnotherTestHelper
test "additional helper classes can be specified as in a controller" do
assert test_case.ancestors.include?(AnotherTestHelper)
assert_equal 'Howdy!', from_another_helper
test_case.helper_class.module_eval do
def render_from_helper
from_another_helper
end
end
assert_equal 'Howdy!', render(:partial => 'test/from_helper')
end
end
class ATestHelperTest < ActionView::TestCase
include SharedTests
test_case = self
test "inflects the name of the helper module to test from the test case class" do
assert_equal ATestHelper, test_case.helper_class
assert test_case.ancestors.include?(ATestHelper)
end
test "a configured test controller is available" do
assert_kind_of ActionController::Base, controller
assert_equal '', controller.controller_path
end
test "helper class that is being tested is always included in view instance" do
self.class.helper_class.module_eval do
def render_from_helper
render :partial => 'customer', :collection => @customers
end
end
TestController.stubs(:controller_path).returns('test')
@customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')]
assert_match /Hello: EloyHello: Manfred/, render(:partial => 'test/from_helper')
end
test "no additional helpers should shared across test cases" do
assert !test_case.ancestors.include?(AnotherTestHelper)
assert_raise(NoMethodError) { send :from_another_helper }
end
test "is able to use routes" do
controller.request.assign_parameters('foo', 'index')
assert_equal '/foo', url_for
assert_equal '/bar', url_for(:controller => 'bar')
end
test "is able to use named routes" do
with_routing do |set|
set.draw { |map| map.resources :contents }
assert_equal 'http://test.host/contents/new', new_content_url
assert_equal 'http://test.host/contents/1', content_url(:id => 1)
end
end
test "named routes can be used from helper included in view" do
with_routing do |set|
set.draw { |map| map.resources :contents }
master_helper_module.module_eval do
def render_from_helper
new_content_url
end
end
assert_equal 'http://test.host/contents/new', render(:partial => 'test/from_helper')
end
end
test "is able to render partials with local variables" do
assert_equal 'Eloy', render('developers/developer', :developer => stub(:name => 'Eloy'))
assert_equal 'Eloy', render(:partial => 'developers/developer',
:locals => { :developer => stub(:name => 'Eloy') })
end
test "is able to render partials from templates and also use instance variables" do
TestController.stubs(:controller_path).returns('test')
@customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')]
assert_match /Hello: EloyHello: Manfred/, render(:file => 'test/list')
end
test "is able to make methods available to the view" do
master_helper_module.module_eval do
def render_from_helper; from_test_case end
end
assert_equal 'Word!', render(:partial => 'test/from_helper')
end
def from_test_case; 'Word!'; end
helper_method :from_test_case
end
class AssertionsTest < ActionView::TestCase
def render_from_helper
form_tag('/foo') do
concat render(:text => '<ul><li>foo</li></ul>')
end
end
helper_method :render_from_helper
test "uses the output_buffer for assert_select" do
render(:partial => 'test/from_helper')
assert_select 'form' do
assert_select 'li', :text => 'foo'
end
end
end
end end
end end

View file

@ -1,3 +1,11 @@
*2.3.5 (November 25, 2009)*
* Minor Bug Fixes and deprecation warnings
* 1.9 Compatibility
* Numerous fixes to the nested attributes functionality
*2.3.4 (September 4, 2009)* *2.3.4 (September 4, 2009)*
* PostgreSQL: XML datatype support. #1874 [Leonardo Borges] * PostgreSQL: XML datatype support. #1874 [Leonardo Borges]

View file

@ -192,7 +192,7 @@ spec = Gem::Specification.new do |s|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) } s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end end
s.add_dependency('activesupport', '= 2.3.4' + PKG_BUILD) s.add_dependency('activesupport', '= 2.3.5' + PKG_BUILD)
s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite" s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite" s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"

View file

@ -0,0 +1 @@
performance.sql

View file

@ -275,9 +275,10 @@ module ActiveRecord
# You can manipulate objects and associations before they are saved to the database, but there is some special behavior you should be # You can manipulate objects and associations before they are saved to the database, but there is some special behavior you should be
# aware of, mostly involving the saving of associated objects. # aware of, mostly involving the saving of associated objects.
# #
# Unless you enable the :autosave option on a <tt>has_one</tt>, <tt>belongs_to</tt>, # Unless you set the :autosave option on a <tt>has_one</tt>, <tt>belongs_to</tt>,
# <tt>has_many</tt>, or <tt>has_and_belongs_to_many</tt> association, # <tt>has_many</tt>, or <tt>has_and_belongs_to_many</tt> association. Setting it
# in which case the members are always saved. # to +true+ will _always_ save the members, whereas setting it to +false+ will
# _never_ save the members.
# #
# === One-to-one associations # === One-to-one associations
# #
@ -874,7 +875,9 @@ module ActiveRecord
# if the real class name is Person, you'll have to specify it with this option. # if the real class name is Person, you'll have to specify it with this option.
# [:conditions] # [:conditions]
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+ # Specify the conditions that the associated object must meet in order to be included as a +WHERE+
# SQL fragment, such as <tt>rank = 5</tt>. # SQL fragment, such as <tt>rank = 5</tt>. Record creation from the association is scoped if a hash
# is used. <tt>has_one :account, :conditions => {:enabled => true}</tt> will create an enabled account with <tt>@company.create_account</tt>
# or <tt>@company.build_account</tt>.
# [:order] # [:order]
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment, # Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
# such as <tt>last_name, first_name DESC</tt>. # such as <tt>last_name, first_name DESC</tt>.
@ -1324,8 +1327,8 @@ module ActiveRecord
end end
define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value| define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value|
ids = (new_value || []).reject { |nid| nid.blank? } ids = (new_value || []).reject { |nid| nid.blank? }.map(&:to_i)
send("#{reflection.name}=", reflection.klass.find(ids)) send("#{reflection.name}=", reflection.klass.find(ids).index_by(&:id).values_at(*ids))
end end
end end
end end
@ -1408,7 +1411,7 @@ module ActiveRecord
if reflection.options.include?(:dependent) if reflection.options.include?(:dependent)
# Add polymorphic type if the :as option is present # Add polymorphic type if the :as option is present
dependent_conditions = [] dependent_conditions = []
dependent_conditions << "#{reflection.primary_key_name} = \#{record.quoted_id}" dependent_conditions << "#{reflection.primary_key_name} = \#{record.#{reflection.name}.send(:owner_quoted_id)}"
dependent_conditions << "#{reflection.options[:as]}_type = '#{base_class.name}'" if reflection.options[:as] dependent_conditions << "#{reflection.options[:as]}_type = '#{base_class.name}'" if reflection.options[:as]
dependent_conditions << sanitize_sql(reflection.options[:conditions], reflection.quoted_table_name) if reflection.options[:conditions] dependent_conditions << sanitize_sql(reflection.options[:conditions], reflection.quoted_table_name) if reflection.options[:conditions]
dependent_conditions << extra_conditions if extra_conditions dependent_conditions << extra_conditions if extra_conditions

View file

@ -210,15 +210,14 @@ module ActiveRecord
# Forwards any missing method call to the \target. # Forwards any missing method call to the \target.
def method_missing(method, *args) def method_missing(method, *args)
if load_target if load_target
unless @target.respond_to?(method) if @target.respond_to?(method)
message = "undefined method `#{method.to_s}' for \"#{@target}\":#{@target.class.to_s}" if block_given?
raise NoMethodError, message @target.send(method, *args) { |*block_args| yield(*block_args) }
end else
@target.send(method, *args)
if block_given? end
@target.send(method, *args) { |*block_args| yield(*block_args) }
else else
@target.send(method, *args) super
end end
end end
end end

View file

@ -24,8 +24,8 @@ module ActiveRecord
def has_primary_key? def has_primary_key?
return @has_primary_key unless @has_primary_key.nil? return @has_primary_key unless @has_primary_key.nil?
@has_primary_key = (ActiveRecord::Base.connection.supports_primary_key? && @has_primary_key = (@owner.connection.supports_primary_key? &&
ActiveRecord::Base.connection.primary_key(@reflection.options[:join_table])) @owner.connection.primary_key(@reflection.options[:join_table]))
end end
protected protected

Some files were not shown because too many files have changed in this diff Show more