aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock2
-rw-r--r--app/controllers/request_controller.rb6
-rw-r--r--app/helpers/application_helper.rb6
-rw-r--r--app/models/comment.rb2
-rw-r--r--app/models/incoming_message.rb2
-rw-r--r--app/models/info_request.rb4
-rw-r--r--app/models/outgoing_message.rb2
-rw-r--r--app/models/public_body.rb2
-rw-r--r--app/models/track_thing.rb4
-rw-r--r--app/views/admin_public_body/import_csv.rhtml2
-rw-r--r--app/views/admin_public_body/show.rhtml2
-rw-r--r--app/views/comment/_comment_form.rhtml2
-rw-r--r--app/views/general/blog.rhtml4
-rw-r--r--app/views/general/search.rhtml2
-rw-r--r--app/views/layouts/contact_mailer.rhtml2
-rw-r--r--app/views/layouts/outgoing_mailer.rhtml2
-rw-r--r--app/views/layouts/request_mailer.rhtml2
-rw-r--r--app/views/layouts/user_mailer.rhtml2
-rw-r--r--app/views/public_body/_list_sidebar_extra.rhtml2
-rw-r--r--app/views/public_body/list.rhtml2
-rw-r--r--app/views/public_body/show.rhtml2
-rw-r--r--app/views/request/_after_actions.rhtml2
-rw-r--r--app/views/request/_followup.rhtml10
-rw-r--r--app/views/request/_hidden_correspondence.rhtml12
-rw-r--r--app/views/request/_sidebar.rhtml18
-rw-r--r--app/views/request/followup_bad.rhtml12
-rw-r--r--app/views/request/hidden.rhtml6
-rw-r--r--app/views/request/new.rhtml18
-rw-r--r--app/views/request/new_please_describe.rhtml2
-rw-r--r--app/views/request/preview.rhtml8
-rw-r--r--app/views/request/select_authority.rhtml4
-rw-r--r--app/views/request/show.rhtml8
-rw-r--r--app/views/request/show_response.rhtml4
-rw-r--r--app/views/track/_tracking_links.rhtml2
-rw-r--r--app/views/track_mailer/event_digest.rhtml2
-rw-r--r--app/views/user/_signup.rhtml8
-rw-r--r--app/views/user/no_cookies.rhtml4
-rw-r--r--app/views/user/show.rhtml2
-rw-r--r--app/views/user/wrong_user_unknown_email.rhtml4
-rw-r--r--lib/i18n_fixes.rb41
-rw-r--r--lib/make_html_4_compliant.rb3
-rw-r--r--lib/use_spans_for_errors.rb2
-rw-r--r--spec/lib/i18n_interpolation.rb38
-rw-r--r--vendor/plugins/rails_xss/MIT-LICENSE20
-rw-r--r--vendor/plugins/rails_xss/README.markdown91
-rw-r--r--vendor/plugins/rails_xss/Rakefile23
-rw-r--r--vendor/plugins/rails_xss/init.rb9
-rw-r--r--vendor/plugins/rails_xss/lib/rails_xss.rb3
-rw-r--r--vendor/plugins/rails_xss/lib/rails_xss/action_view.rb111
-rw-r--r--vendor/plugins/rails_xss/lib/rails_xss/erubis.rb35
-rw-r--r--vendor/plugins/rails_xss/lib/rails_xss/string_ext.rb65
-rw-r--r--vendor/plugins/rails_xss/lib/tasks/rails_xss_tasks.rake4
-rw-r--r--vendor/plugins/rails_xss/test/active_record_helper_test.rb74
-rw-r--r--vendor/plugins/rails_xss/test/asset_tag_helper_test.rb49
-rw-r--r--vendor/plugins/rails_xss/test/caching_test.rb54
-rw-r--r--vendor/plugins/rails_xss/test/content_for_test.rb39
-rw-r--r--vendor/plugins/rails_xss/test/date_helper_test.rb29
-rw-r--r--vendor/plugins/rails_xss/test/deprecated_output_safety_test.rb112
-rw-r--r--vendor/plugins/rails_xss/test/erb_util_test.rb36
-rw-r--r--vendor/plugins/rails_xss/test/form_helper_test.rb1447
-rw-r--r--vendor/plugins/rails_xss/test/form_tag_helper_test.rb354
-rw-r--r--vendor/plugins/rails_xss/test/javascript_helper_test.rb10
-rw-r--r--vendor/plugins/rails_xss/test/output_escaping_test.rb19
-rw-r--r--vendor/plugins/rails_xss/test/output_safety_test.rb115
-rw-r--r--vendor/plugins/rails_xss/test/rails_xss_test.rb23
-rw-r--r--vendor/plugins/rails_xss/test/raw_output_helper_test.rb18
-rw-r--r--vendor/plugins/rails_xss/test/safe_buffer_test.rb51
-rw-r--r--vendor/plugins/rails_xss/test/tag_helper_test.rb21
-rw-r--r--vendor/plugins/rails_xss/test/test_helper.rb6
-rw-r--r--vendor/plugins/rails_xss/test/text_helper_test.rb30
-rw-r--r--vendor/plugins/rails_xss/test/url_for_test.rb39
72 files changed, 3042 insertions, 113 deletions
diff --git a/Gemfile b/Gemfile
index 3c31ba6a8..0844b9636 100644
--- a/Gemfile
+++ b/Gemfile
@@ -38,6 +38,8 @@ gem 'zip'
gem 'capistrano'
gem 'syslog_protocol'
gem 'newrelic_rpm'
+# erubis is required by rails_xss. Both erubis and rails_xss can be removed after upgrading to Rails 3.
+gem 'erubis'
group :test do
gem 'fakeweb'
diff --git a/Gemfile.lock b/Gemfile.lock
index 3f584e1ce..d86425d16 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -27,6 +27,7 @@ GEM
fssm (>= 0.2.7)
sass (~> 3.1)
daemons (1.1.9)
+ erubis (2.7.0)
eventmachine (1.0.0)
fakeweb (1.3.0)
fast_gettext (0.6.8)
@@ -149,6 +150,7 @@ DEPENDENCIES
bootstrap-sass
capistrano
compass
+ erubis
fakeweb
fast_gettext (>= 0.6.0)
fastercsv (>= 1.5.5)
diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb
index 970dfca45..3e8c0a5f6 100644
--- a/app/controllers/request_controller.rb
+++ b/app/controllers/request_controller.rb
@@ -327,9 +327,9 @@ class RequestController < ApplicationController
message = ""
if @outgoing_message.contains_email?
if @user.nil?
- message += _("<p>You do not need to include your email in the request in order to get a reply, as we will ask for it on the next screen (<a href=\"%s\">details</a>).</p>") % [help_privacy_path+"#email_address"];
+ message += (_("<p>You do not need to include your email in the request in order to get a reply, as we will ask for it on the next screen (<a href=\"%s\">details</a>).</p>") % [help_privacy_path+"#email_address"]).html_safe;
else
- message += _("<p>You do not need to include your email in the request in order to get a reply (<a href=\"%s\">details</a>).</p>") % [help_privacy_path+"#email_address"];
+ message += (_("<p>You do not need to include your email in the request in order to get a reply (<a href=\"%s\">details</a>).</p>") % [help_privacy_path+"#email_address"]).html_safe;
end
message += _("<p>We recommend that you edit your request and remove the email address.
If you leave it, the email address will be sent to the authority, but will not be displayed on the site.</p>")
@@ -630,7 +630,7 @@ class RequestController < ApplicationController
if !params[:submitted_followup].nil? && !params[:reedit]
if @info_request.allow_new_responses_from == 'nobody'
- flash[:error] = _('Your follow up has not been sent because this request has been stopped to prevent spam. Please <a href="%s">contact us</a> if you really want to send a follow up message.') % [help_contact_path]
+ flash[:error] = (_('Your follow up has not been sent because this request has been stopped to prevent spam. Please <a href="%s">contact us</a> if you really want to send a follow up message.') % [help_contact_path]).html_safe
else
if @info_request.find_existing_outgoing_message(params[:outgoing_message][:body])
flash[:error] = _('You previously submitted that exact follow up message for this request.')
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 6411cf27e..b9ba712a4 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -35,15 +35,15 @@ module ApplicationHelper
end
end
- error_messages = []
+ error_messages = "".html_safe
for object in objects
object.errors.each do |attr, message|
- error_messages << content_tag(:li, message)
+ error_messages << content_tag(:li, h(message))
end
end
content_tag(:div,
- content_tag(:ul, error_messages.join),
+ content_tag(:ul, error_messages),
html
)
else
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 5507910e2..bcd1efca8 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -68,7 +68,7 @@ class Comment < ActiveRecord::Base
text = CGI.escapeHTML(text)
text = MySociety::Format.make_clickable(text, :contract => 1)
text = text.gsub(/\n/, '<br>')
- return text
+ return text.html_safe
end
# When posting a new comment, use this to check user hasn't double submitted.
diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb
index 339a7a3e2..3f551f420 100644
--- a/app/models/incoming_message.rb
+++ b/app/models/incoming_message.rb
@@ -695,7 +695,7 @@ class IncomingMessage < ActiveRecord::Base
text = text.gsub(/\n/, '<br>')
text = text.gsub(/(?:<br>\s*){2,}/, '<br><br>') # remove excess linebreaks that unnecessarily space it out
- return text
+ return text.html_safe
end
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index 3355b9443..cee9eb959 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -284,9 +284,9 @@ public
# into some sort of separate jurisdiction dependent file
if self.public_body.url_name == 'general_register_office'
# without GQ in the subject, you just get an auto response
- _('{{law_used_full}} request GQ - {{title}}',:law_used_full=>self.law_used_full,:title=>self.title)
+ _('{{law_used_full}} request GQ - {{title}}',:law_used_full=>self.law_used_full,:title=>self.title.html_safe)
else
- _('{{law_used_full}} request - {{title}}',:law_used_full=>self.law_used_full,:title=>self.title)
+ _('{{law_used_full}} request - {{title}}',:law_used_full=>self.law_used_full,:title=>self.title.html_safe)
end
end
def email_subject_followup(incoming_message = nil)
diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb
index 2e98e1021..441813e5f 100644
--- a/app/models/outgoing_message.rb
+++ b/app/models/outgoing_message.rb
@@ -252,7 +252,7 @@ class OutgoingMessage < ActiveRecord::Base
text = MySociety::Format.make_clickable(text, :contract => 1)
text.gsub!(/\[(email address|mobile number)\]/, '[<a href="/help/officers#mobiles">\1</a>]')
text = text.gsub(/\n/, '<br>')
- return text
+ return text.html_safe
end
def fully_destroy
diff --git a/app/models/public_body.rb b/app/models/public_body.rb
index 96f7733ed..f71520ee6 100644
--- a/app/models/public_body.rb
+++ b/app/models/public_body.rb
@@ -301,7 +301,7 @@ class PublicBody < ActiveRecord::Base
ret = ret + " and "
end
ret = ret + types[-1]
- return ret
+ return ret.html_safe
else
return _("A public authority")
end
diff --git a/app/models/track_thing.rb b/app/models/track_thing.rb
index 2a61eb858..81800f0ae 100644
--- a/app/models/track_thing.rb
+++ b/app/models/track_thing.rb
@@ -203,7 +203,7 @@ class TrackThing < ActiveRecord::Base
:verb_on_page => _("Follow this request"),
:verb_on_page_already => _("You are already following this request"),
# Email
- :title_in_email => _("New updates for the request '{{request_title}}'", :request_title => self.info_request.title),
+ :title_in_email => _("New updates for the request '{{request_title}}'", :request_title => self.info_request.title.html_safe),
:title_in_rss => _("New updates for the request '{{request_title}}'", :request_title => self.info_request.title),
# Authentication
:web => _("To follow the request '{{request_title}}'", :request_title => CGI.escapeHTML(self.info_request.title)),
@@ -270,7 +270,7 @@ class TrackThing < ActiveRecord::Base
:verb_on_page => _("Follow this person"),
:verb_on_page_already => _("You are already following this person"),
# Email
- :title_in_email => _("FOI requests by '{{user_name}}'", :user_name=>self.tracked_user.name),
+ :title_in_email => _("FOI requests by '{{user_name}}'", :user_name=>self.tracked_user.name.html_safe),
:title_in_rss => _("FOI requests by '{{user_name}}'", :user_name=>self.tracked_user.name),
# Authentication
:web => _("To follow requests by '{{user_name}}'", :user_name=>CGI.escapeHTML(self.tracked_user.name)),
diff --git a/app/views/admin_public_body/import_csv.rhtml b/app/views/admin_public_body/import_csv.rhtml
index 62908ba52..1c6100838 100644
--- a/app/views/admin_public_body/import_csv.rhtml
+++ b/app/views/admin_public_body/import_csv.rhtml
@@ -32,7 +32,7 @@
<label for="tag_behaviour">What to do with existing tags?</label>
<%= select_tag 'tag_behaviour',
"<option value='add' selected>Add new tags to existing ones</option>
- <option value='replace'>Replace existing tags with new ones</option>"
+ <option value='replace'>Replace existing tags with new ones</option>".html_safe
%>
</p>
diff --git a/app/views/admin_public_body/show.rhtml b/app/views/admin_public_body/show.rhtml
index 094007c02..cee306988 100644
--- a/app/views/admin_public_body/show.rhtml
+++ b/app/views/admin_public_body/show.rhtml
@@ -66,7 +66,7 @@
end
# Highlight entries which have changed since previous version
changed = (!['version', 'last_edit_editor', 'last_edit_comment'].include?(column.name)) && ((historic_public_body.send(column.name) != @public_body.sorted_versions[historic_public_body.version - 2].send(column.name)) || (historic_public_body.version == 1)) %>
- <td <%= changed ? ' class="entry_changed" ': '' %> >
+ <td <%= changed ? ' class="entry_changed" '.html_safe: '' %> >
<%=value%>
</td>
<% end %>
diff --git a/app/views/comment/_comment_form.rhtml b/app/views/comment/_comment_form.rhtml
index d430f25c8..120929643 100644
--- a/app/views/comment/_comment_form.rhtml
+++ b/app/views/comment/_comment_form.rhtml
@@ -13,7 +13,7 @@
<%= hidden_field_tag 'submitted_comment', 1 %>
<%= hidden_field_tag 'preview', 1 %>
<%= submit_tag _('Preview your annotation') %>
- <%= _(' (<strong>no ranty</strong> politics, read our <a href="%s">moderation policy</a>)') % [help_requesting_path+'#moderation'] %>
+ <%= raw(_(' (<strong>no ranty</strong> politics, read our <a href="%s">moderation policy</a>)') % [help_requesting_path+'#moderation']) %>
</p>
<% end %>
diff --git a/app/views/general/blog.rhtml b/app/views/general/blog.rhtml
index 5258e9bbd..07d6d2f14 100644
--- a/app/views/general/blog.rhtml
+++ b/app/views/general/blog.rhtml
@@ -26,9 +26,9 @@
<p class="subtitle"><%= _("Posted on {{date}} by {{author}}", :date=>simple_date(Time.parse(item['pubDate'][0])), :author=>item['creator']) %></p>
<div>
<% if item['encoded'] %>
- <%= item['encoded'] %>
+ <%= raw item['encoded'] %>
<% elsif item['description'] %>
- <%= item['description'] %>
+ <%= raw item['description'] %>
<% end %>
</div>
<p><em>
diff --git a/app/views/general/search.rhtml b/app/views/general/search.rhtml
index a1f8c8f04..6df12d980 100644
--- a/app/views/general/search.rhtml
+++ b/app/views/general/search.rhtml
@@ -164,7 +164,7 @@
<% if @spelling_correction %>
<p id="did_you_mean"><%= _('Did you mean: {{correction}}', :correction => search_link(@spelling_correction, @postfix)) %></p>
<% end %>
- <p><%= _('<a href="%s">Browse all</a> or <a href="%s">ask us to add one</a>.') % [list_public_bodies_default, help_requesting_path + '#missing_body'] %></p>
+ <p><%= raw(_('<a href="%s">Browse all</a> or <a href="%s">ask us to add one</a>.') % [list_public_bodies_default, help_requesting_path + '#missing_body']) %></p>
<% end %>
</div>
diff --git a/app/views/layouts/contact_mailer.rhtml b/app/views/layouts/contact_mailer.rhtml
index 5b8b44402..3cdc75009 100644
--- a/app/views/layouts/contact_mailer.rhtml
+++ b/app/views/layouts/contact_mailer.rhtml
@@ -1 +1 @@
-<%= MySociety::Format.wrap_email_body_by_paragraphs(yield) %>
+<%= raw MySociety::Format.wrap_email_body_by_paragraphs(yield) %>
diff --git a/app/views/layouts/outgoing_mailer.rhtml b/app/views/layouts/outgoing_mailer.rhtml
index dbb18483f..8bf8ef216 100644
--- a/app/views/layouts/outgoing_mailer.rhtml
+++ b/app/views/layouts/outgoing_mailer.rhtml
@@ -1 +1 @@
-<%= MySociety::Format.wrap_email_body_by_lines(yield) %>
+<%= raw MySociety::Format.wrap_email_body_by_lines(yield) %>
diff --git a/app/views/layouts/request_mailer.rhtml b/app/views/layouts/request_mailer.rhtml
index 5b8b44402..3cdc75009 100644
--- a/app/views/layouts/request_mailer.rhtml
+++ b/app/views/layouts/request_mailer.rhtml
@@ -1 +1 @@
-<%= MySociety::Format.wrap_email_body_by_paragraphs(yield) %>
+<%= raw MySociety::Format.wrap_email_body_by_paragraphs(yield) %>
diff --git a/app/views/layouts/user_mailer.rhtml b/app/views/layouts/user_mailer.rhtml
index 5b8b44402..3cdc75009 100644
--- a/app/views/layouts/user_mailer.rhtml
+++ b/app/views/layouts/user_mailer.rhtml
@@ -1 +1 @@
-<%= MySociety::Format.wrap_email_body_by_paragraphs(yield) %>
+<%= raw MySociety::Format.wrap_email_body_by_paragraphs(yield) %>
diff --git a/app/views/public_body/_list_sidebar_extra.rhtml b/app/views/public_body/_list_sidebar_extra.rhtml
index 6857a7eb5..54f20a736 100644
--- a/app/views/public_body/_list_sidebar_extra.rhtml
+++ b/app/views/public_body/_list_sidebar_extra.rhtml
@@ -1,5 +1,5 @@
<p>
- <%= _('<a href="%s">Are we missing a public authority?</a>') % [help_requesting_path + '#missing_body'] %>
+ <%= raw(_('<a href="%s">Are we missing a public authority?</a>') % [help_requesting_path + '#missing_body']) %>
</p>
<p>
<%= link_to _('List of all authorities (CSV)'), all_public_bodies_csv_url() %>
diff --git a/app/views/public_body/list.rhtml b/app/views/public_body/list.rhtml
index 3a64de1f7..94fbb759c 100644
--- a/app/views/public_body/list.rhtml
+++ b/app/views/public_body/list.rhtml
@@ -43,5 +43,5 @@
<%= render :partial => 'body_listing', :locals => { :public_bodies => @public_bodies } %>
<%= will_paginate(@public_bodies) %><br/>
- <%= _('<a href="%s">Can\'t find the one you want?</a>') % [help_requesting_path + '#missing_body'] %>
+ <%= raw _('<a href="%s">Can\'t find the one you want?</a>') % [help_requesting_path + '#missing_body'] %>
</div>
diff --git a/app/views/public_body/show.rhtml b/app/views/public_body/show.rhtml
index e13f9d1c0..6431b4742 100644
--- a/app/views/public_body/show.rhtml
+++ b/app/views/public_body/show.rhtml
@@ -4,7 +4,7 @@
<h2><%= _('Follow this authority')%></h2>
<% follower_count = TrackThing.count(:all, :conditions => ["public_body_id = ?", @public_body.id]) %>
- <p><%= n_("<span id='follow_count'>%d</span> person is following this authority", "<span id='follow_count'>%d</span> people are following this authority", follower_count) % follower_count %></p>
+ <p><%= raw(n_("<span id='follow_count'>%d</span> person is following this authority", "<span id='follow_count'>%d</span> people are following this authority", follower_count) % follower_count) %></p>
<%= render :partial => 'track/tracking_links', :locals => { :track_thing => @track_thing, :own_request => false, :location => 'sidebar' } %>
<h2><%= _('More about this authority')%></h2>
diff --git a/app/views/request/_after_actions.rhtml b/app/views/request/_after_actions.rhtml
index 221634549..3d74cf42d 100644
--- a/app/views/request/_after_actions.rhtml
+++ b/app/views/request/_after_actions.rhtml
@@ -7,7 +7,7 @@
<ul>
<% if @info_request.comments_allowed? %>
<li>
- <%= _('<a href="%s">Add an annotation</a> (to help the requester or others)') % [new_comment_url(:url_title => @info_request.url_title)] %>
+ <%= raw(_('<a href="%s">Add an annotation</a> (to help the requester or others)') % [new_comment_url(:url_title => @info_request.url_title)]) %>
</li>
<% end %>
<% if @old_unclassified %>
diff --git a/app/views/request/_followup.rhtml b/app/views/request/_followup.rhtml
index be57ac9ef..451932b8d 100644
--- a/app/views/request/_followup.rhtml
+++ b/app/views/request/_followup.rhtml
@@ -44,9 +44,9 @@
<% else %>
<% if @internal_review %>
<p>
- <%= _('If you are dissatisfied by the response you got from
+ <%= raw(_('If you are dissatisfied by the response you got from
the public authority, you have the right to
- complain (<a href="%s">details</a>).') % "http://foiwiki.com/foiwiki/index.php/Internal_reviews" %>
+ complain (<a href="%s">details</a>).') % "http://foiwiki.com/foiwiki/index.php/Internal_reviews") %>
</p>
<% end %>
@@ -63,14 +63,14 @@
<%= _('in term time') %>
<% end %>
<%= _('by <strong>{{date}}</strong>',:date=>simple_date(@info_request.date_response_required_by)) %>
- (<%= _('<a href="%s">details</a>') % ["#{help_requesting_path}#quickly_response"] %>).
+ (<%= raw(_('<a href="%s">details</a>') % ["#{help_requesting_path}#quickly_response"]) %>).
</p>
<% elsif status == 'waiting_response_very_overdue' %>
<p>
<%= _('The response to your request is <strong>long overdue</strong>. You can say that, by
law, under all circumstances, the authority should have responded
- by now') %> (<%= _('<a href="%s">details</a>') % ["#{help_requesting_path}#quickly_response"] %>).
+ by now') %> (<%= raw(_('<a href="%s">details</a>') % ["#{help_requesting_path}#quickly_response"]) %>).
</p>
<% end %>
@@ -98,7 +98,7 @@
<div>
<%= radio_button "outgoing_message", "what_doing", "internal_review", :id => "internal_review" %>
<label for="internal_review"><%= _('I am requesting an <strong>internal review</strong>') %>
- <%= _('<a href="%s">what\'s that?</a>') % ["/help/unhappy"] %>
+ <%= raw(_('<a href="%s">what\'s that?</a>') % ["/help/unhappy"]) %>
</label>
</div>
<div>
diff --git a/app/views/request/_hidden_correspondence.rhtml b/app/views/request/_hidden_correspondence.rhtml
index 0ea6fcddd..0873b312f 100644
--- a/app/views/request/_hidden_correspondence.rhtml
+++ b/app/views/request/_hidden_correspondence.rhtml
@@ -7,21 +7,21 @@
%>
<div class="correspondence" id="incoming-<%=incoming_message.id.to_s%>">
<p>
- <%= _('This response has been hidden. See annotations to find out why.
- If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.request_uri)] %>
+ <%= raw(_('This response has been hidden. See annotations to find out why.
+ If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.request_uri)]) %>
</p>
</div>
<% elsif [ 'sent', 'followup_sent', 'resent', 'followup_resent' ].include?(info_request_event.event_type) %>
<div class="correspondence" id="outgoing-<%=outgoing_message.id.to_s%>">
<p>
- <%= _('This outgoing message has been hidden. See annotations to
- find out why. If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.request_uri)] %>
+ <%= raw(_('This outgoing message has been hidden. See annotations to
+ find out why. If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.request_uri)]) %>
</p>
</div>
<% elsif info_request_event.event_type == 'comment' %>
<div class="comment_in_request" id="comment-<%=comment.id.to_s%>">
- <p><%= _('This comment has been hidden. See annotations to
- find out why. If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.request_uri)]%>
+ <p><%= raw(_('This comment has been hidden. See annotations to
+ find out why. If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.request_uri)]) %>
</p>
</div>
<% end %>
diff --git a/app/views/request/_sidebar.rhtml b/app/views/request/_sidebar.rhtml
index 18684943a..b669278f9 100644
--- a/app/views/request/_sidebar.rhtml
+++ b/app/views/request/_sidebar.rhtml
@@ -17,10 +17,10 @@
<% elsif @info_request.prominence == 'requester_only' %>
<%# The eccentric formatting of the following string is in order that it be identical
to the corresponding string in request/show.rhtml %>
- <p><%= _('This request is hidden, so that only you the requester can see it. Please
- <a href="%s">contact us</a> if you are not sure why.') % [help_requesting_path] %></p>
+ <p><%= raw(_('This request is hidden, so that only you the requester can see it. Please
+ <a href="%s">contact us</a> if you are not sure why.') % [help_requesting_path]) %></p>
<% else %>
- <p><%= _('This request has been marked for review by the site administrators, who have not hidden it at this time. If you believe it should be hidden, please <a href="%s">contact us</a>.') % [help_requesting_path] %></p>
+ <p><%= raw(_('This request has been marked for review by the site administrators, who have not hidden it at this time. If you believe it should be hidden, please <a href="%s">contact us</a>.') % [help_requesting_path]) %></p>
<% end %>
<% else %>
<p><%= _('Requests for personal information and vexatious requests are not considered valid for FOI purposes (<a href="/help/about">read more</a>).') %></p>
@@ -32,11 +32,15 @@
<div class="act_link">
<% tweet_link = "https://twitter.com/share?url=#{h(request.url)}&via=#{h(Configuration::twitter_username)}&text='#{h(@info_request.title)}'&related=#{_('alaveteli_foi:The software that runs {{site_name}}', :site_name => h(site_name))}" %>
- <%= link_to '<img src="/images/twitter-16.png" alt="twitter icon">', tweet_link %>
+ <% link_to tweet_link do %>
+ <%= image_tag "twitter-16.png", :alt => "twitter icon" %>
+ <% end %>
<%= link_to _("Tweet this request"), tweet_link %>
</div>
<div class="act_link">
- <%= link_to '<img src="/images/wordpress.png" alt="" class="rss">', "http://wordpress.com/"%>
+ <% link_to "http://wordpress.com/" do %>
+ <%= image_tag "wordpress.png", :class => "rss" %>
+ <% end %>
<%= link_to _("Start your own blog"), "http://wordpress.com/"%>
</div>
@@ -59,7 +63,7 @@
<!-- this link with this wording is here for legal reasons, discuss with
board and our lawyer before changing or removing it -->
- <p><small><%= _('<a href="%s">Are you the owner of
- any commercial copyright on this page?</a>') % [help_officers_path+"#copyright"] %></small></p>
+ <p><small><%= raw(_('<a href="%s">Are you the owner of
+ any commercial copyright on this page?</a>') % [help_officers_path+"#copyright"]) %></small></p>
</div>
diff --git a/app/views/request/followup_bad.rhtml b/app/views/request/followup_bad.rhtml
index 7efa3f826..c892263e6 100644
--- a/app/views/request/followup_bad.rhtml
+++ b/app/views/request/followup_bad.rhtml
@@ -9,21 +9,21 @@
<% if @reason == 'not_apply' %>
<!-- we should never get here, but just in case give a sensible message -->
<p><%= _('Freedom of Information law no longer applies to') %> <%=h @info_request.public_body.name %>.
- <%= _('From the request page, try replying to a particular message, rather than sending
+ <%= raw(_('From the request page, try replying to a particular message, rather than sending
a general followup. If you need to make a general followup, and know
- an email which will go to the right place, please <a href="%s">send it to us</a>.') % [help_contact_path] %>
+ an email which will go to the right place, please <a href="%s">send it to us</a>.') % [help_contact_path]) %>
</p>
<% elsif @reason == 'defunct' %>
<!-- we should never get here, but just in case give a sensible message -->
- <p><%=h @info_request.public_body.name %> <%= _('no longer exists. If you are trying to make
+ <p><%=h @info_request.public_body.name %> <%= raw(_('no longer exists. If you are trying to make
From the request page, try replying to a particular message, rather than sending
a general followup. If you need to make a general followup, and know
- an email which will go to the right place, please <a href="%s">send it to us</a>.') % [help_contact_path] %>
+ an email which will go to the right place, please <a href="%s">send it to us</a>.') % [help_contact_path]) %>
</p>
<% elsif @reason == 'bad_contact' %>
- <p><%= _('We do not have a working {{law_used_full}} address for {{public_body_name}}.',:law_used_full=>h(@info_request.law_used_full),:public_body_name=>h(@info_request.public_body.name)) %> <%= _('You may be able to find
+ <p><%= _('We do not have a working {{law_used_full}} address for {{public_body_name}}.',:law_used_full=>h(@info_request.law_used_full),:public_body_name=>h(@info_request.public_body.name)) %> <%= raw(_('You may be able to find
one on their website, or by phoning them up and asking. If you manage
- to find one, then please <a href="%s">send it to us</a>.') % [help_contact_path] %>
+ to find one, then please <a href="%s">send it to us</a>.') % [help_contact_path]) %>
</p>
<% elsif @reason == 'external' %>
<p><%= _("Followups cannot be sent for this request, as it was made externally, and published here by {{public_body_name}} on the requester's behalf.", :public_body_name => h(@info_request.public_body.name)) %>
diff --git a/app/views/request/hidden.rhtml b/app/views/request/hidden.rhtml
index a4afb63c6..2d038a663 100644
--- a/app/views/request/hidden.rhtml
+++ b/app/views/request/hidden.rhtml
@@ -6,13 +6,13 @@
<%=@details%>
</p>
-<p><%= _('The request you have tried to view has been removed. There are
+<p><%= raw(_('The request you have tried to view has been removed. There are
various reasons why we might have done this, sorry we can\'t be more specific here. Please <a
- href="%s">contact us</a> if you have any questions.') % [help_contact_path] %>
+ href="%s">contact us</a> if you have any questions.') % [help_contact_path]) %>
</p>
<% if @info_request.prominence == 'requester_only' %>
<p>
- <%= _('If you are the requester, then you may <a href="%s">sign in</a> to view the request.') % [signin_url(:r => request.request_uri)] %>
+ <%= raw(_('If you are the requester, then you may <a href="%s">sign in</a> to view the request.') % [signin_url(:r => request.request_uri)]) %>
</p>
<% end %>
diff --git a/app/views/request/new.rhtml b/app/views/request/new.rhtml
index fe4c2067d..f396ea9ec 100644
--- a/app/views/request/new.rhtml
+++ b/app/views/request/new.rhtml
@@ -98,7 +98,7 @@
<ul>
<li><%= _('Write your request in <strong>simple, precise language</strong>.') %></li>
<li><%= _('Ask for <strong>specific</strong> documents or information, this site is not suitable for general enquiries.') %></li>
- <li><%= _('Keep it <strong>focused</strong>, you\'ll be more likely to get what you want (<a href="%s">why?</a>).') % [help_requesting_path + '#focused'] %></li>
+ <li><%= raw(_('Keep it <strong>focused</strong>, you\'ll be more likely to get what you want (<a href="%s">why?</a>).') % [help_requesting_path + '#focused']) %></li>
</ul>
</div>
@@ -112,23 +112,23 @@
<% if !@user %>
<p class="form_note">
- <%= _('Everything that you enter on this page, including <strong>your name</strong>,
+ <%= raw(_('Everything that you enter on this page, including <strong>your name</strong>,
will be <strong>displayed publicly</strong> on
- this website forever (<a href="%s">why?</a>).') % [help_privacy_path+"#public_request"] %>
- <%= _('If you are thinking of using a pseudonym,
- please <a href="%s">read this first</a>.') % [help_privacy_path+"#real_name"] %>
+ this website forever (<a href="%s">why?</a>).') % [help_privacy_path+"#public_request"]) %>
+ <%= raw(_('If you are thinking of using a pseudonym,
+ please <a href="%s">read this first</a>.') % [help_privacy_path+"#real_name"]) %>
</p>
<% else %>
<p class="form_note">
- <%= _('Everything that you enter on this page
+ <%= raw(_('Everything that you enter on this page
will be <strong>displayed publicly</strong> on
- this website forever (<a href="%s">why?</a>).') % [help_privacy_path+"#public_request"] %>
+ this website forever (<a href="%s">why?</a>).') % [help_privacy_path+"#public_request"]) %>
</p>
<% end %>
<p class="form_note">
- <%= _("<strong> Can I request information about myself?</strong>\n" +
- "\t\t\t<a href=\"%s\">No! (Click here for details)</a>") % [help_requesting_path+"#data_protection"] %>
+ <%= raw(_("<strong> Can I request information about myself?</strong>\n" +
+ "\t\t\t<a href=\"%s\">No! (Click here for details)</a>") % [help_requesting_path+"#data_protection"]) %>
</p>
<div class="form_button">
diff --git a/app/views/request/new_please_describe.rhtml b/app/views/request/new_please_describe.rhtml
index ce80f51f0..ff27405b8 100644
--- a/app/views/request/new_please_describe.rhtml
+++ b/app/views/request/new_please_describe.rhtml
@@ -13,7 +13,7 @@ if they are successful yet or not.') %>
</ul>
<p>
- <%= _('When you\'re done, <strong>come back here</strong>, <a href="%s">reload this page</a> and file your new request.') % [request.request_uri] %>
+ <%= raw(_('When you\'re done, <strong>come back here</strong>, <a href="%s">reload this page</a> and file your new request.') % [request.request_uri]) %>
</p>
<p>
diff --git a/app/views/request/preview.rhtml b/app/views/request/preview.rhtml
index 45b6a3dc1..8d1fd753e 100644
--- a/app/views/request/preview.rhtml
+++ b/app/views/request/preview.rhtml
@@ -5,8 +5,8 @@
<h1><%= _('3. Now check your request') %></h1>
<ul>
<li><%= _('Check you haven\'t included any <strong>personal information</strong>.') %></li>
- <li><%= _('Your name, request and any responses will appear in <strong>search engines</strong>
- (<a href="%s">details</a>).') % [help_privacy_path+"#public_request"] %>
+ <li><%= raw(_('Your name, request and any responses will appear in <strong>search engines</strong>
+ (<a href="%s">details</a>).') % [help_privacy_path+"#public_request"]) %>
</li>
</ul>
@@ -28,8 +28,8 @@
</div>
<% end %>
- <p><%= _('<strong>Privacy note:</strong> If you want to request private information about
- yourself then <a href="%s">click here</a>.') % [help_requesting_path+"#data_protection"] %>
+ <p><%= raw(_('<strong>Privacy note:</strong> If you want to request private information about
+ yourself then <a href="%s">click here</a>.') % [help_requesting_path+"#data_protection"]) %>
<p>
<%= f.hidden_field(:title) %>
diff --git a/app/views/request/select_authority.rhtml b/app/views/request/select_authority.rhtml
index 1166c3ff9..652c24da9 100644
--- a/app/views/request/select_authority.rhtml
+++ b/app/views/request/select_authority.rhtml
@@ -33,9 +33,9 @@
<% form_tag({:controller => "request", :action => "select_authority"}, {:id => "search_form", :method => "get"}) do %>
<div>
<p>
- <%= _('First, type in the <strong>name of the UK public authority</strong> you\'d
+ <%= raw(_('First, type in the <strong>name of the UK public authority</strong> you\'d
like information from. <strong>By law, they have to respond</strong>
- (<a href="%s#%s">why?</a>).') % [help_about_url, "whybother_them"] %>
+ (<a href="%s#%s">why?</a>).') % [help_about_url, "whybother_them"]) %>
</p>
<%= text_field_tag 'query', params[:query], { :size => 30 } %>
<%= hidden_field_tag 'bodies', 1 %>
diff --git a/app/views/request/show.rhtml b/app/views/request/show.rhtml
index 7aff1aeab..0cae3a9aa 100644
--- a/app/views/request/show.rhtml
+++ b/app/views/request/show.rhtml
@@ -10,8 +10,8 @@
<% end %>
<% if @info_request.prominence == 'requester_only' %>
<p id="hidden_request">
- <%= _('This request is hidden, so that only you the requester can see it. Please
- <a href="%s">contact us</a> if you are not sure why.') % [help_requesting_path] %>
+ <%= raw(_('This request is hidden, so that only you the requester can see it. Please
+ <a href="%s">contact us</a> if you are not sure why.') % [help_requesting_path]) %>
</p>
<% end %>
@@ -80,11 +80,11 @@
<%= _('in term time') %>
<% end %>
<%= _('by') %> <strong><%= simple_date(@info_request.date_response_required_by) %></strong>
- (<%= _('<a href="%s">details</a>') % [help_requesting_path + '#quickly_response'] %>)
+ (<%= raw(_('<a href="%s">details</a>') % [help_requesting_path + '#quickly_response']) %>)
<% elsif @status == 'waiting_response_very_overdue' %>
<%= _('Response to this request is <strong>long overdue</strong>.') %>
<%= _('By law, under all circumstances, {{public_body_link}} should have responded by now',:public_body_link => public_body_link(@info_request.public_body)) %>
- (<%= _('<a href="%s">details</a>') % [help_requesting_path + '#quickly_response'] %>).
+ (<%= raw(_('<a href="%s">details</a>') % [help_requesting_path + '#quickly_response']) %>).
<% if !@info_request.is_external? %>
<%= _('You can <strong>complain</strong> by') %>
<%= link_to _("requesting an internal review"), show_response_no_followup_url(:id => @info_request.id, :incoming_message_id => nil) + "?internal_review=1#followup" %>.
diff --git a/app/views/request/show_response.rhtml b/app/views/request/show_response.rhtml
index c40b37c3b..ac1f04227 100644
--- a/app/views/request/show_response.rhtml
+++ b/app/views/request/show_response.rhtml
@@ -26,8 +26,8 @@
<%= _('The authority only has a <strong>paper copy</strong> of the information.') %>
</dt>
<dd>
- <%= _('At the bottom of this page, write a reply to them trying to persuade them to scan it in
- (<a href="%s">more details</a>).') % [help_privacy_path + '#postal_answer'] %>
+ <%= raw(_('At the bottom of this page, write a reply to them trying to persuade them to scan it in
+ (<a href="%s">more details</a>).') % [help_privacy_path + '#postal_answer']) %>
</dd>
<dt>
diff --git a/app/views/track/_tracking_links.rhtml b/app/views/track/_tracking_links.rhtml
index 3ba9d15e2..06e87ac74 100644
--- a/app/views/track/_tracking_links.rhtml
+++ b/app/views/track/_tracking_links.rhtml
@@ -21,7 +21,7 @@
</div>
<div class="feed_link feed_link_<%=location%>">
- <%= link_to '<img src="/images/feed-16.png" alt="">', do_track_url(track_thing, 'feed') %>
+ <%= link_to '<img src="/images/feed-16.png" alt="">'.html_safe, do_track_url(track_thing, 'feed') %>
<%= link_to (location == 'sidebar' ? _('RSS feed of updates') : _('RSS feed')), do_track_url(track_thing, 'feed') %>
</div>
<% end %>
diff --git a/app/views/track_mailer/event_digest.rhtml b/app/views/track_mailer/event_digest.rhtml
index 2c2e3c957..dc8132b99 100644
--- a/app/views/track_mailer/event_digest.rhtml
+++ b/app/views/track_mailer/event_digest.rhtml
@@ -57,7 +57,7 @@
main_text += "\n"
end
-%><%=main_text%><%= _("Alter your subscription")%>
+%><%=raw main_text%><%= _("Alter your subscription")%>
=======================
<% _("Please click on the link below to cancel or alter these emails.") %>
diff --git a/app/views/user/_signup.rhtml b/app/views/user/_signup.rhtml
index bb93b9617..913423ffa 100644
--- a/app/views/user/_signup.rhtml
+++ b/app/views/user/_signup.rhtml
@@ -10,8 +10,8 @@
<%= text_field 'user_signup', 'email', { :size => 20, :tabindex => 60 } %>
</p>
<div class="form_item_note">
- <%= _('We will not reveal your email address to anybody unless you or
- the law tell us to (<a href="%s">details</a>). ') %[help_privacy_path] %>
+ <%= raw(_('We will not reveal your email address to anybody unless you or
+ the law tell us to (<a href="%s">details</a>). ') %[help_privacy_path]) %>
</div>
<p>
@@ -19,11 +19,11 @@
<%= text_field 'user_signup', 'name', { :size => 20, :tabindex => 70 } %>
</p>
<div class="form_item_note">
- <%= _('Your <strong>name will appear publicly</strong>
+ <%= raw(_('Your <strong>name will appear publicly</strong>
(<a href="%s">why?</a>)
on this website and in search engines. If you
are thinking of using a pseudonym, please
- <a href="%s">read this first</a>.') % [help_privacy_path+"#public_request", help_privacy_path+"#real_name"] %>
+ <a href="%s">read this first</a>.') % [help_privacy_path+"#public_request", help_privacy_path+"#real_name"]) %>
</div>
<p>
diff --git a/app/views/user/no_cookies.rhtml b/app/views/user/no_cookies.rhtml
index b5c36b57e..c291367f2 100644
--- a/app/views/user/no_cookies.rhtml
+++ b/app/views/user/no_cookies.rhtml
@@ -12,11 +12,11 @@ browser. Then press refresh to have another go.')%></p>
<p><%= _('If your browser is set to accept cookies and you are seeing this message,
then there is probably a fault with our server.')%>
-<%= _('Please <a href="%s">get in touch</a> with us so we can fix it.') % [help_contact_path] %>
+<%= raw(_('Please <a href="%s">get in touch</a> with us so we can fix it.') % [help_contact_path]) %>
<%= _('Let us know what you were doing when this message
appeared and your browser and operating system type and version.')%></p>
-<p><%= _('If you are still having trouble, please <a href="%s">contact us</a>.') % [help_contact_path] %>
+<p><%= raw(_('If you are still having trouble, please <a href="%s">contact us</a>.') % [help_contact_path]) %>
</p>
diff --git a/app/views/user/show.rhtml b/app/views/user/show.rhtml
index 12a9d3f74..31ea2a70b 100644
--- a/app/views/user/show.rhtml
+++ b/app/views/user/show.rhtml
@@ -97,7 +97,7 @@
<% if not @is_you %>
<p id="user_not_logged_in">
- <%= _('<a href="%s">Sign in</a> to change password, subscriptions and more ({{user_name}} only)',:user_name=>h(@display_user.name)) % [signin_url(:r => request.request_uri)]%>
+ <%= raw(_('<a href="%s">Sign in</a> to change password, subscriptions and more ({{user_name}} only)',:user_name=>h(@display_user.name)) % [signin_url(:r => request.request_uri)]) %>
</p>
<% end %>
</div>
diff --git a/app/views/user/wrong_user_unknown_email.rhtml b/app/views/user/wrong_user_unknown_email.rhtml
index 77a2ca001..c59c56941 100644
--- a/app/views/user/wrong_user_unknown_email.rhtml
+++ b/app/views/user/wrong_user_unknown_email.rhtml
@@ -1,8 +1,8 @@
<p id="sign_in_reason">
-<%= @reason_params[:web] %>. <%= _('Unfortunately we don\'t know the FOI
+<%= @reason_params[:web] %>. <%= raw(_('Unfortunately we don\'t know the FOI
email address for that authority, so we can\'t validate this.
-Please <a href="%s">contact us</a> to sort it out.') % [help_contact_path] %>
+Please <a href="%s">contact us</a> to sort it out.') % [help_contact_path]) %>
</p>
diff --git a/lib/i18n_fixes.rb b/lib/i18n_fixes.rb
index 6e684d44a..a85faddcb 100644
--- a/lib/i18n_fixes.rb
+++ b/lib/i18n_fixes.rb
@@ -5,39 +5,36 @@
# override behaviour in fast_gettext/translation.rb
# so that we can interpolate our translation strings nicely
+# TODO: We could simplify a lot of this code (as in remove it) if we moved from using the {{value}}
+# convention in the translation strings for interpolation to %{value}. This is apparently the newer
+# convention.
+
def _(key, options = {})
- translation = FastGettext._(key) || key
+ translation = (FastGettext._(key) || key).html_safe
gettext_interpolate(translation, options)
end
-INTERPOLATION_RESERVED_KEYS = %w(scope default)
-MATCH = /(\\\\)?\{\{([^\}]+)\}\}/
+MATCH = /\{\{([^\}]+)\}\}/
def gettext_interpolate(string, values)
return string unless string.is_a?(String)
- if values.is_a?(Hash)
- string.gsub(MATCH) do
- escaped, pattern, key = $1, $2, $2.to_sym
-
- if escaped
- pattern
- elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
- raise I18n::ReservedInterpolationKey.new(pattern, string)
- elsif !values.include?(key)
- raise I18n::MissingInterpolationArgument.new(pattern, string)
+ # $1, $2 don't work with SafeBuffer so casting to string as workaround
+ safe = string.html_safe?
+ string = string.to_str.gsub(MATCH) do
+ pattern, key = $1, $1.to_sym
+
+ if !values.include?(key)
+ raise I18n::MissingInterpolationArgument.new(pattern, string)
+ else
+ v = values[key].to_s
+ if safe && !v.html_safe?
+ ERB::Util.h(v)
else
- values[key].to_s
+ v
end
end
- else
- reserved_keys = if defined?(I18n::RESERVED_KEYS) # rails 3+
- I18n::RESERVED_KEYS
- else
- I18n::Backend::Base::RESERVED_KEYS
- end
-
- string % values.except(*reserved_keys)
end
+ safe ? string.html_safe : string
end
diff --git a/lib/make_html_4_compliant.rb b/lib/make_html_4_compliant.rb
index 214eb9f1f..8926d5873 100644
--- a/lib/make_html_4_compliant.rb
+++ b/lib/make_html_4_compliant.rb
@@ -3,7 +3,6 @@
ActionView::Helpers::TagHelper.module_eval do
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
-
diff --git a/lib/use_spans_for_errors.rb b/lib/use_spans_for_errors.rb
index cda05c588..135453f78 100644
--- a/lib/use_spans_for_errors.rb
+++ b/lib/use_spans_for_errors.rb
@@ -8,5 +8,5 @@
#
# See http://dev.rubyonrails.org/ticket/2210
-ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| %(<span class="fieldWithErrors">#{html_tag}</span>)}
+ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| %(<span class="fieldWithErrors">#{html_tag}</span>).html_safe}
diff --git a/spec/lib/i18n_interpolation.rb b/spec/lib/i18n_interpolation.rb
index 6b745059c..e8d046757 100644
--- a/spec/lib/i18n_interpolation.rb
+++ b/spec/lib/i18n_interpolation.rb
@@ -8,5 +8,43 @@ describe "when using i18n" do
result = _('Hello {{dip}}', :dip => 'hummus')
result.should == 'Hello hummus'
end
+
+ it "should assume that simple translations are always html safe" do
+ _("Hello").should be_html_safe
+ end
+
end
+describe "gettext_interpolate" do
+ context "html unsafe string" do
+ let(:string) { "Hello {{a}}" }
+
+ it "should give an unsafe result" do
+ result = gettext_interpolate(string, :a => "foo")
+ result.should == "Hello foo"
+ result.should_not be_html_safe
+ end
+
+ it "should give an unsafe result" do
+ result = gettext_interpolate(string, :a => "foo".html_safe)
+ result.should == "Hello foo"
+ result.should_not be_html_safe
+ end
+ end
+
+ context "html safe string" do
+ let(:string) { "Hello {{a}}".html_safe }
+
+ it "should quote the input if it's unsafe" do
+ result = gettext_interpolate(string, :a => "foo&")
+ result.should == "Hello foo&amp;"
+ result.should be_html_safe
+ end
+
+ it "should not quote the input if it's safe" do
+ result = gettext_interpolate(string, :a => "foo&".html_safe)
+ result.should == "Hello foo&"
+ result.should be_html_safe
+ end
+ end
+end
diff --git a/vendor/plugins/rails_xss/MIT-LICENSE b/vendor/plugins/rails_xss/MIT-LICENSE
new file mode 100644
index 000000000..ed44a7bde
--- /dev/null
+++ b/vendor/plugins/rails_xss/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Koziarski Software Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/plugins/rails_xss/README.markdown b/vendor/plugins/rails_xss/README.markdown
new file mode 100644
index 000000000..1222ef38d
--- /dev/null
+++ b/vendor/plugins/rails_xss/README.markdown
@@ -0,0 +1,91 @@
+RailsXss
+========
+
+This plugin replaces the default ERB template handlers with erubis, and switches the behaviour to escape by default rather than requiring you to escape. This is consistent with the behaviour in Rails 3.0.
+
+Strings now have a notion of "html safe", which is false by default. Whenever rails copies a string into the response body it checks whether or not the string is safe, safe strings are copied verbatim into the response body, but unsafe strings are escaped first.
+
+All the XSS-proof helpers like link_to and form_tag now return safe strings, and will continue to work unmodified. If you have your own helpers which return strings you *know* are safe, you will need to explicitly tell rails that they're safe. For an example, take the following helper.
+
+
+ def some_helper
+ (1..5).map do |i|
+ "<li>#{i}</li>"
+ end.join("\n")
+ end
+
+With this plugin installed, the html will be escaped. So you will need to do one of the following:
+
+1) Use the raw helper in your template. raw will ensure that your string is copied verbatim into the response body.
+
+ <%= raw some_helper %>
+
+2) Mark the string as safe in the helper itself:
+
+ def some_helper
+ (1..5).map do |i|
+ "<li>#{i}</li>"
+ end.join("\n").html_safe
+ end
+
+3) Use the `safe_helper` meta programming method (WARNING: This is not supported by Rails 3, so if you're planning to
+eventually upgrade your app this alternative is not recommended):
+
+ module ApplicationHelper
+ def some_helper
+ #...
+ end
+ safe_helper :some_helper # not supported by Rails 3
+ end
+
+Example
+-------
+
+BEFORE:
+
+ <%= params[:own_me] %> => XSS attack
+ <%=h params[:own_me] %> => No XSS
+ <%= @blog_post.content %> => Displays the HTML
+
+AFTER:
+
+ <%= params[:own_me] %> => No XSS
+ <%=h params[:own_me] %> => No XSS (same result)
+ <%= @blog_post.content %> => *escapes* the HTML
+ <%= raw @blog_post.content %> => Displays the HTML
+
+
+Gotchas
+---
+
+#### textilize and simple_format do *not* return safe strings
+
+Both these methods support arbitrary HTML and are *not* safe to embed directly in your document. You'll need to do something like:
+
+ <%= sanitize(textilize(@blog_post.content_textile)) %>
+
+#### Safe strings aren't magic.
+
+Once a string has been marked as safe, the only operations which will maintain that HTML safety are String#<<, String#concat and String#+. All other operations are safety ignorant so it's still probably possible to break your app if you're doing something like
+
+ value = something_safe
+ value.gsub!(/a/, params[:own_me])
+
+Don't do that.
+
+#### String interpolation won't be safe, even when it 'should' be
+
+ value = "#{something_safe}#{something_else_safe}"
+ value.html_safe? # => false
+
+This is intended functionality and can't be fixed.
+
+Getting Started
+===============
+
+1. Install rails 2.3.8 or higher, or freeze rails from 2-3-stable.
+2. Install erubis (gem install erubis)
+3. Install this plugin (ruby script/plugin install git://github.com/rails/rails_xss.git)
+4. Report anything that breaks.
+
+Copyright (c) 2009 Koziarski Software Ltd, released under the MIT license. For full details see MIT-LICENSE included in this distribution.
diff --git a/vendor/plugins/rails_xss/Rakefile b/vendor/plugins/rails_xss/Rakefile
new file mode 100644
index 000000000..929ecbb81
--- /dev/null
+++ b/vendor/plugins/rails_xss/Rakefile
@@ -0,0 +1,23 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the rails_xss plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the rails_xss plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'RailsXss'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
diff --git a/vendor/plugins/rails_xss/init.rb b/vendor/plugins/rails_xss/init.rb
new file mode 100644
index 000000000..533eb1f36
--- /dev/null
+++ b/vendor/plugins/rails_xss/init.rb
@@ -0,0 +1,9 @@
+unless $gems_rake_task
+ if Rails::VERSION::MAJOR >= 3
+ $stderr.puts "You don't need to install rails_xss as a plugin for Rails 3 and after."
+ elsif Rails::VERSION::MAJOR <= 2 && Rails::VERSION::MINOR <= 3 && Rails::VERSION::TINY <= 7
+ $stderr.puts "rails_xss requires Rails 2.3.8 or later. Please upgrade to enable automatic HTML safety."
+ else
+ require 'rails_xss'
+ end
+end
diff --git a/vendor/plugins/rails_xss/lib/rails_xss.rb b/vendor/plugins/rails_xss/lib/rails_xss.rb
new file mode 100644
index 000000000..46d1b9a4a
--- /dev/null
+++ b/vendor/plugins/rails_xss/lib/rails_xss.rb
@@ -0,0 +1,3 @@
+require 'rails_xss/erubis'
+require 'rails_xss/action_view'
+require 'rails_xss/string_ext'
diff --git a/vendor/plugins/rails_xss/lib/rails_xss/action_view.rb b/vendor/plugins/rails_xss/lib/rails_xss/action_view.rb
new file mode 100644
index 000000000..c3f5e47df
--- /dev/null
+++ b/vendor/plugins/rails_xss/lib/rails_xss/action_view.rb
@@ -0,0 +1,111 @@
+module ActionView
+ class Base
+ def self.xss_safe?
+ true
+ end
+
+ module WithSafeOutputBuffer
+ # Rails version of with_output_buffer uses '' as the default buf
+ def with_output_buffer(buf = ActiveSupport::SafeBuffer.new) #:nodoc:
+ super buf
+ end
+ end
+
+ include WithSafeOutputBuffer
+ end
+
+ module Helpers
+ module CaptureHelper
+ def content_for(name, content = nil, &block)
+ ivar = "@content_for_#{name}"
+ content = capture(&block) if block_given?
+ instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{ERB::Util.h(content)}".html_safe)
+ nil
+ end
+ end
+
+ module TextHelper
+ def concat(string, unused_binding = nil)
+ if unused_binding
+ ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.", caller)
+ end
+
+ output_buffer.concat(string)
+ end
+
+ def simple_format(text, html_options={})
+ start_tag = tag('p', html_options, true)
+ text = ERB::Util.h(text).to_str.dup
+ text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
+ text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
+ text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
+ text.insert 0, start_tag
+ text.html_safe.safe_concat("</p>")
+ end
+ end
+
+ module TagHelper
+ private
+ def content_tag_string_with_escaping(name, content, options, escape = true)
+ content_tag_string_without_escaping(name, escape ? ERB::Util.h(content) : content, options, escape)
+ end
+ alias_method_chain :content_tag_string, :escaping
+ end
+
+ module UrlHelper
+ def link_to(*args, &block)
+ if block_given?
+ options = args.first || {}
+ html_options = args.second
+ concat(link_to(capture(&block), options, html_options))
+ else
+ name = args.first
+ options = args.second || {}
+ html_options = args.third
+
+ url = url_for(options)
+
+ if html_options
+ html_options = html_options.stringify_keys
+ href = html_options['href']
+ convert_options_to_javascript!(html_options, url)
+ tag_options = tag_options(html_options)
+ else
+ tag_options = nil
+ end
+
+ href_attr = "href=\"#{url}\"" unless href
+ "<a #{href_attr}#{tag_options}>#{ERB::Util.h(name || url)}</a>".html_safe
+ end
+ end
+ end
+
+ module JavaScriptHelper
+ def escape_javascript(javascript)
+ if javascript
+ javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) {|match| JS_ESCAPE_MAP[match] }
+ else
+ ''
+ end
+ end
+ end
+ end
+end
+
+module RailsXss
+ module SafeHelpers
+ def safe_helper(*names)
+ names.each do |helper_method_name|
+ aliased_target, punctuation = helper_method_name.to_s.sub(/([?!=])$/, ''), $1
+ module_eval <<-END
+ def #{aliased_target}_with_xss_safety#{punctuation}(*args, &block)
+ raw(#{aliased_target}_without_xss_safety#{punctuation}(*args, &block))
+ end
+ END
+ alias_method_chain helper_method_name, :xss_safety
+ end
+ end
+ end
+end
+
+Module.class_eval { include RailsXss::SafeHelpers }
diff --git a/vendor/plugins/rails_xss/lib/rails_xss/erubis.rb b/vendor/plugins/rails_xss/lib/rails_xss/erubis.rb
new file mode 100644
index 000000000..c8171c669
--- /dev/null
+++ b/vendor/plugins/rails_xss/lib/rails_xss/erubis.rb
@@ -0,0 +1,35 @@
+require 'erubis/helpers/rails_helper'
+
+module RailsXss
+ class Erubis < ::Erubis::Eruby
+ def add_preamble(src)
+ src << "@output_buffer = ActiveSupport::SafeBuffer.new;"
+ end
+
+ def add_text(src, text)
+ return if text.empty?
+ src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
+ end
+
+ BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
+
+ def add_expr_literal(src, code)
+ if code =~ BLOCK_EXPR
+ src << "@output_buffer.safe_concat((" << $1 << ").to_s);"
+ else
+ src << '@output_buffer << ((' << code << ').to_s);'
+ end
+ end
+
+ def add_expr_escaped(src, code)
+ src << '@output_buffer << ' << escaped_expr(code) << ';'
+ end
+
+ def add_postamble(src)
+ src << '@output_buffer.to_s'
+ end
+ end
+end
+
+Erubis::Helpers::RailsHelper.engine_class = RailsXss::Erubis
+Erubis::Helpers::RailsHelper.show_src = false
diff --git a/vendor/plugins/rails_xss/lib/rails_xss/string_ext.rb b/vendor/plugins/rails_xss/lib/rails_xss/string_ext.rb
new file mode 100644
index 000000000..ee32e47c8
--- /dev/null
+++ b/vendor/plugins/rails_xss/lib/rails_xss/string_ext.rb
@@ -0,0 +1,65 @@
+require 'active_support/deprecation'
+
+ActiveSupport::SafeBuffer.class_eval do
+ def concat(value)
+ if value.html_safe?
+ super(value)
+ else
+ super(ERB::Util.h(value))
+ end
+ end
+ alias << concat
+ UNSAFE_STRING_METHODS = ["capitalize", "chomp", "chop", "delete", "downcase", "gsub", "lstrip", "next", "reverse", "rstrip", "slice", "squeeze", "strip", "sub", "succ", "swapcase", "tr", "tr_s", "upcase"].freeze
+
+ for unsafe_method in UNSAFE_STRING_METHODS
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{unsafe_method}(*args)
+ super.to_str
+ end
+
+ def #{unsafe_method}!(*args)
+ raise TypeError, "Cannot modify SafeBuffer in place"
+ end
+ EOT
+ end
+end
+
+class String
+ def html_safe?
+ defined?(@_rails_html_safe)
+ end
+
+ def html_safe!
+ ActiveSupport::Deprecation.warn("Use html_safe with your strings instead of html_safe! See http://yehudakatz.com/2010/02/01/safebuffers-and-rails-3-0/ for the full story.", caller)
+ @_rails_html_safe = true
+ self
+ end
+
+ def add_with_safety(other)
+ result = add_without_safety(other)
+ if html_safe? && also_html_safe?(other)
+ result.html_safe!
+ else
+ result
+ end
+ end
+ alias_method :add_without_safety, :+
+ alias_method :+, :add_with_safety
+
+ def concat_with_safety(other_or_fixnum)
+ result = concat_without_safety(other_or_fixnum)
+ unless html_safe? && also_html_safe?(other_or_fixnum)
+ remove_instance_variable(:@_rails_html_safe) if defined?(@_rails_html_safe)
+ end
+ result
+ end
+
+ alias_method_chain :concat, :safety
+ undef_method :<<
+ alias_method :<<, :concat_with_safety
+
+ private
+ def also_html_safe?(other)
+ other.respond_to?(:html_safe?) && other.html_safe?
+ end
+end
diff --git a/vendor/plugins/rails_xss/lib/tasks/rails_xss_tasks.rake b/vendor/plugins/rails_xss/lib/tasks/rails_xss_tasks.rake
new file mode 100644
index 000000000..b8659f089
--- /dev/null
+++ b/vendor/plugins/rails_xss/lib/tasks/rails_xss_tasks.rake
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :rails_xss do
+# # Task goes here
+# end
diff --git a/vendor/plugins/rails_xss/test/active_record_helper_test.rb b/vendor/plugins/rails_xss/test/active_record_helper_test.rb
new file mode 100644
index 000000000..728ec0ac6
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/active_record_helper_test.rb
@@ -0,0 +1,74 @@
+require 'test_helper'
+
+class ActiveRecordHelperTest < ActionView::TestCase
+ silence_warnings do
+ Post = Struct.new("Post", :title, :author_name, :body, :secret, :written_on)
+ Post.class_eval do
+ alias_method :title_before_type_cast, :title unless respond_to?(:title_before_type_cast)
+ alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast)
+ alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast)
+ end
+ end
+
+ def setup_post
+ @post = Post.new
+ def @post.errors
+ Class.new {
+ def on(field)
+ case field.to_s
+ when "author_name"
+ "can't be empty"
+ when "body"
+ true
+ else
+ false
+ end
+ end
+ def empty?() false end
+ def count() 1 end
+ def full_messages() [ "Author name can't be empty" ] end
+ }.new
+ end
+
+ def @post.new_record?() true end
+ def @post.to_param() nil end
+
+ def @post.column_for_attribute(attr_name)
+ Post.content_columns.select { |column| column.name == attr_name }.first
+ end
+
+ silence_warnings do
+ def Post.content_columns() [ Column.new(:string, "title", "Title"), Column.new(:text, "body", "Body") ] end
+ end
+
+ @post.title = "Hello World"
+ @post.author_name = ""
+ @post.body = "Back to the hill and over it again!"
+ @post.secret = 1
+ @post.written_on = Date.new(2004, 6, 15)
+ end
+
+ def setup
+ setup_post
+
+ @response = ActionController::TestResponse.new
+
+ @controller = Object.new
+ def @controller.url_for(options)
+ options = options.symbolize_keys
+
+ [options[:action], options[:id].to_param].compact.join('/')
+ end
+ end
+
+ def test_text_field_with_errors_is_safe
+ assert text_field("post", "author_name").html_safe?
+ end
+
+ def test_text_field_with_errors
+ assert_dom_equal(
+ %(<div class="fieldWithErrors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /></div>),
+ text_field("post", "author_name")
+ )
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/asset_tag_helper_test.rb b/vendor/plugins/rails_xss/test/asset_tag_helper_test.rb
new file mode 100644
index 000000000..f58feda3d
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/asset_tag_helper_test.rb
@@ -0,0 +1,49 @@
+require 'test_helper'
+
+class AssetTagHelperTest < ActionView::TestCase
+ def setup
+ @controller = Class.new do
+ attr_accessor :request
+ def url_for(*args) "http://www.example.com" end
+ end.new
+ end
+
+ def test_auto_discovery_link_tag
+ assert_dom_equal(%(<link href="http://www.example.com" rel="Not so alternate" title="ATOM" type="application/atom+xml" />),
+ auto_discovery_link_tag(:atom, {}, {:rel => "Not so alternate"}))
+ end
+
+ def test_javascript_include_tag_with_blank_asset_id
+ ENV["RAILS_ASSET_ID"] = ""
+ assert_dom_equal(%(<script src="/javascripts/test.js" type="text/javascript"></script>\n<script src="/javascripts/prototype.js" type="text/javascript"></script>\n<script src="/javascripts/effects.js" type="text/javascript"></script>\n<script src="/javascripts/dragdrop.js" type="text/javascript"></script>\n<script src="/javascripts/controls.js" type="text/javascript"></script>\n<script src="/javascripts/application.js" type="text/javascript"></script>),
+ javascript_include_tag("test", :defaults))
+ end
+
+ def test_javascript_include_tag_with_given_asset_id
+ ENV["RAILS_ASSET_ID"] = "1"
+ 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))
+ ENV["RAILS_ASSET_ID"] = ""
+ 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_stylesheet_link_tag
+ assert_dom_equal(%(<link href="http://www.example.com/styles/style.css" media="screen" rel="stylesheet" type="text/css" />),
+ stylesheet_link_tag("http://www.example.com/styles/style"))
+ end
+
+ def test_stylesheet_link_tag_is_html_safe
+ 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_image_tag
+ assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" src="/images/mouse.png" />),
+ image_tag("mouse.png", :mouseover => image_path("mouse_over.png")))
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/caching_test.rb b/vendor/plugins/rails_xss/test/caching_test.rb
new file mode 100644
index 000000000..3ea41e8b5
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/caching_test.rb
@@ -0,0 +1,54 @@
+require 'test_helper'
+
+CACHE_DIR = 'test_cache'
+# Don't change '/../temp/' cavalierly or you might hose something you don't want hosed
+FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
+ActionController::Base.page_cache_directory = FILE_STORE_PATH
+ActionController::Base.cache_store = :file_store, FILE_STORE_PATH
+
+class FragmentCachingTestController < ActionController::Base
+ def some_action; end;
+end
+
+class FragmentCachingTest < ActionController::TestCase
+ def setup
+ ActionController::Base.perform_caching = true
+ @store = ActiveSupport::Cache::MemoryStore.new
+ ActionController::Base.cache_store = @store
+ @controller = FragmentCachingTestController.new
+ @params = {:controller => 'posts', :action => 'index'}
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @controller.params = @params
+ @controller.request = @request
+ @controller.response = @response
+ @controller.send(:initialize_current_url)
+ @controller.send(:initialize_template_class, @response)
+ @controller.send(:assign_shortcuts, @request, @response)
+ end
+
+ def test_fragment_for
+ @store.write('views/expensive', 'fragment content')
+ fragment_computed = false
+
+ buffer = 'generated till now -> '.html_safe
+ @controller.fragment_for(buffer, 'expensive') { fragment_computed = true }
+
+ assert !fragment_computed
+ assert_equal 'generated till now -> fragment content', buffer
+ end
+
+ def test_html_safety
+ assert_nil @store.read('views/name')
+ content = 'value'.html_safe
+ assert_equal content, @controller.write_fragment('name', content)
+
+ cached = @store.read('views/name')
+ assert_equal content, cached
+ assert_equal String, cached.class
+
+ html_safe = @controller.read_fragment('name')
+ assert_equal content, html_safe
+ assert html_safe.html_safe?
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/content_for_test.rb b/vendor/plugins/rails_xss/test/content_for_test.rb
new file mode 100644
index 000000000..45ba6762c
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/content_for_test.rb
@@ -0,0 +1,39 @@
+require 'test_helper'
+
+class ContentForTest < ActionView::TestCase
+
+ def test_content_for_should_yield_html_safe_string
+ content_for(:testing, "Some <p>html</p>")
+ content = instance_variable_get(:"@content_for_testing")
+ assert content.html_safe?
+ end
+
+ def test_content_for_should_escape_content
+ content_for(:testing, "Some <p>html</p>")
+ content = instance_variable_get(:"@content_for_testing")
+ expected = %{Some &lt;p&gt;html&lt;/p&gt;}
+ assert_dom_equal expected, content
+ end
+
+ def test_content_for_should_not_escape_html_safe_content
+ content_for(:testing, "Some <p>html</p>".html_safe)
+ content = instance_variable_get(:"@content_for_testing")
+ expected = %{Some <p>html</p>}
+ assert_dom_equal expected, content
+ end
+
+ def test_content_for_should_escape_content_from_block
+ content_for(:testing){ "Some <p>html</p>" }
+ content = instance_variable_get(:"@content_for_testing")
+ expected = %{Some &lt;p&gt;html&lt;/p&gt;}
+ assert_dom_equal expected, content
+ end
+
+ def test_content_for_should_not_escape_html_safe_content_from_block
+ content_for(:testing){ "Some <p>html</p>".html_safe }
+ content = instance_variable_get(:"@content_for_testing")
+ expected = %{Some <p>html</p>}
+ assert_dom_equal expected, content
+ end
+
+end
diff --git a/vendor/plugins/rails_xss/test/date_helper_test.rb b/vendor/plugins/rails_xss/test/date_helper_test.rb
new file mode 100644
index 000000000..daf010274
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/date_helper_test.rb
@@ -0,0 +1,29 @@
+require 'test_helper'
+
+class DateHelperTest < ActionView::TestCase
+ silence_warnings do
+ Post = Struct.new("Post", :id, :written_on, :updated_at)
+ end
+
+ def test_select_html_safety
+ assert select_day(16).html_safe?
+ assert select_month(8).html_safe?
+ assert select_year(Time.mktime(2003, 8, 16, 8, 4, 18)).html_safe?
+ assert select_minute(Time.mktime(2003, 8, 16, 8, 4, 18)).html_safe?
+ assert select_second(Time.mktime(2003, 8, 16, 8, 4, 18)).html_safe?
+
+ assert select_minute(8, :use_hidden => true).html_safe?
+ assert select_month(8, :prompt => 'Choose month').html_safe?
+
+ assert select_time(Time.mktime(2003, 8, 16, 8, 4, 18), {}, :class => 'selector').html_safe?
+ assert select_date(Time.mktime(2003, 8, 16), :date_separator => " / ", :start_year => 2003, :end_year => 2005, :prefix => "date[first]").html_safe?
+ end
+
+ def test_object_select_html_safety
+ @post = Post.new
+ @post.written_on = Date.new(2004, 6, 15)
+
+ assert date_select("post", "written_on", :default => Time.local(2006, 9, 19, 15, 16, 35), :include_blank => true).html_safe?
+ assert time_select("post", "written_on", :ignore_date => true).html_safe?
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/deprecated_output_safety_test.rb b/vendor/plugins/rails_xss/test/deprecated_output_safety_test.rb
new file mode 100644
index 000000000..e16f7ce0d
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/deprecated_output_safety_test.rb
@@ -0,0 +1,112 @@
+require 'test_helper'
+
+class DeprecatedOutputSafetyTest < ActiveSupport::TestCase
+ def setup
+ @string = "hello"
+ end
+
+ test "A string can be marked safe using html_safe!" do
+ assert_deprecated do
+ @string.html_safe!
+ assert @string.html_safe?
+ end
+ end
+
+ test "Marking a string safe returns the string using html_safe!" do
+ assert_deprecated do
+ assert_equal @string, @string.html_safe!
+ end
+ end
+
+ test "Adding a safe string to another safe string returns a safe string using html_safe!" do
+ assert_deprecated do
+ @other_string = "other".html_safe!
+ @string.html_safe!
+ @combination = @other_string + @string
+
+ assert_equal "otherhello", @combination
+ assert @combination.html_safe?
+ end
+ end
+
+ test "Adding an unsafe string to a safe string returns an unsafe string using html_safe!" do
+ assert_deprecated do
+ @other_string = "other".html_safe!
+ @combination = @other_string + "<foo>"
+ @other_combination = @string + "<foo>"
+
+ assert_equal "other<foo>", @combination
+ assert_equal "hello<foo>", @other_combination
+
+ assert !@combination.html_safe?
+ assert !@other_combination.html_safe?
+ end
+ end
+
+ test "Concatting safe onto unsafe yields unsafe using html_safe!" do
+ assert_deprecated do
+ @other_string = "other"
+ @string.html_safe!
+
+ @other_string.concat(@string)
+ assert !@other_string.html_safe?
+ end
+ end
+
+ test "Concatting unsafe onto safe yields unsafe using html_safe!" do
+ assert_deprecated do
+ @other_string = "other".html_safe!
+ string = @other_string.concat("<foo>")
+ assert_equal "other<foo>", string
+ assert !string.html_safe?
+ end
+ end
+
+ test "Concatting safe onto safe yields safe using html_safe!" do
+ assert_deprecated do
+ @other_string = "other".html_safe!
+ @string.html_safe!
+
+ @other_string.concat(@string)
+ assert @other_string.html_safe?
+ end
+ end
+
+ test "Concatting safe onto unsafe with << yields unsafe using html_safe!" do
+ assert_deprecated do
+ @other_string = "other"
+ @string.html_safe!
+
+ @other_string << @string
+ assert !@other_string.html_safe?
+ end
+ end
+
+ test "Concatting unsafe onto safe with << yields unsafe using html_safe!" do
+ assert_deprecated do
+ @other_string = "other".html_safe!
+ string = @other_string << "<foo>"
+ assert_equal "other<foo>", string
+ assert !string.html_safe?
+ end
+ end
+
+ test "Concatting safe onto safe with << yields safe using html_safe!" do
+ assert_deprecated do
+ @other_string = "other".html_safe!
+ @string.html_safe!
+
+ @other_string << @string
+ assert @other_string.html_safe?
+ end
+ end
+
+ test "Concatting a fixnum to safe always yields safe using html_safe!" do
+ assert_deprecated do
+ @string.html_safe!
+ @string.concat(13)
+ assert_equal "hello".concat(13), @string
+ assert @string.html_safe?
+ end
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/erb_util_test.rb b/vendor/plugins/rails_xss/test/erb_util_test.rb
new file mode 100644
index 000000000..9a04d38e6
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/erb_util_test.rb
@@ -0,0 +1,36 @@
+require 'test_helper'
+
+class ErbUtilTest < Test::Unit::TestCase
+ include ERB::Util
+
+ ERB::Util::HTML_ESCAPE.each do |given, expected|
+ define_method "test_html_escape_#{expected.gsub(/\W/, '')}" do
+ assert_equal expected, html_escape(given)
+ end
+
+ unless given == '"'
+ define_method "test_json_escape_#{expected.gsub(/\W/, '')}" do
+ assert_equal ERB::Util::JSON_ESCAPE[given], json_escape(given)
+ end
+ end
+ end
+
+ def test_html_escape_is_html_safe
+ escaped = h("<p>")
+ assert_equal "&lt;p&gt;", escaped
+ assert escaped.html_safe?
+ end
+
+ def test_html_escape_passes_html_escpe_unmodified
+ escaped = h("<p>".html_safe)
+ assert_equal "<p>", escaped
+ assert escaped.html_safe?
+ end
+
+ def test_rest_in_ascii
+ (0..127).to_a.map {|int| int.chr }.each do |chr|
+ next if %w(& " < >).include?(chr)
+ assert_equal chr, html_escape(chr)
+ end
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/form_helper_test.rb b/vendor/plugins/rails_xss/test/form_helper_test.rb
new file mode 100644
index 000000000..e5580d26c
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/form_helper_test.rb
@@ -0,0 +1,1447 @@
+require 'test_helper'
+
+silence_warnings do
+ Post = Struct.new(:title, :author_name, :body, :secret, :written_on, :cost)
+ Post.class_eval do
+ alias_method :title_before_type_cast, :title unless respond_to?(:title_before_type_cast)
+ alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast)
+ alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast)
+ alias_method :secret?, :secret
+
+ def new_record=(boolean)
+ @new_record = boolean
+ end
+
+ def new_record?
+ @new_record
+ end
+
+ attr_accessor :author
+ def author_attributes=(attributes); end
+
+ attr_accessor :comments
+ def comments_attributes=(attributes); end
+
+ attr_accessor :tags
+ def tags_attributes=(attributes); end
+ end
+
+ class Comment
+ attr_reader :id
+ attr_reader :post_id
+ def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end
+ def save; @id = 1; @post_id = 1 end
+ def new_record?; @id.nil? end
+ def to_param; @id; end
+ def name
+ @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
+ end
+
+ attr_accessor :relevances
+ def relevances_attributes=(attributes); end
+
+ end
+
+ class Tag
+ attr_reader :id
+ attr_reader :post_id
+ def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end
+ def save; @id = 1; @post_id = 1 end
+ def new_record?; @id.nil? end
+ def to_param; @id; end
+ def value
+ @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
+ end
+
+ attr_accessor :relevances
+ def relevances_attributes=(attributes); end
+
+ end
+
+ class CommentRelevance
+ attr_reader :id
+ attr_reader :comment_id
+ def initialize(id = nil, comment_id = nil); @id, @comment_id = id, comment_id end
+ def save; @id = 1; @comment_id = 1 end
+ def new_record?; @id.nil? end
+ def to_param; @id; end
+ def value
+ @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
+ end
+ end
+
+ class TagRelevance
+ attr_reader :id
+ attr_reader :tag_id
+ def initialize(id = nil, tag_id = nil); @id, @tag_id = id, tag_id end
+ def save; @id = 1; @tag_id = 1 end
+ def new_record?; @id.nil? end
+ def to_param; @id; end
+ def value
+ @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}"
+ end
+ end
+
+ class Author < Comment
+ attr_accessor :post
+ def post_attributes=(attributes); end
+ end
+end
+
+class FormHelperTest < ActionView::TestCase
+ tests ActionView::Helpers::FormHelper
+
+ def setup
+ super
+
+ # Create "label" locale for testing I18n label helpers
+ I18n.backend.store_translations 'label', {
+ :helpers => {
+ :label => {
+ :post => {
+ :body => "Write entire text here"
+ }
+ }
+ }
+ }
+
+ @post = Post.new
+ @comment = Comment.new
+ def @post.errors()
+ Class.new{
+ def on(field); "can't be empty" if field == "author_name"; end
+ def empty?() false end
+ def count() 1 end
+ def full_messages() [ "Author name can't be empty" ] end
+ }.new
+ end
+ def @post.id; 123; end
+ def @post.id_before_type_cast; 123; end
+ def @post.to_param; '123'; end
+
+ @post.title = "Hello World"
+ @post.author_name = ""
+ @post.body = "Back to the hill and over it again!"
+ @post.secret = 1
+ @post.written_on = Date.new(2004, 6, 15)
+
+ def Post.human_attribute_name(attribute)
+ attribute.to_s == "cost" ? "Total cost" : attribute.to_s.humanize
+ end
+
+ @controller = Class.new do
+ attr_reader :url_for_options
+ def url_for(options)
+ @url_for_options = options
+ "http://www.example.com"
+ end
+ end
+ @controller = @controller.new
+ end
+
+ def test_label
+ assert_dom_equal('<label for="post_title">Title</label>', label("post", "title"))
+ assert_dom_equal('<label for="post_title">The title goes here</label>', label("post", "title", "The title goes here"))
+ assert_dom_equal(
+ '<label class="title_label" for="post_title">Title</label>',
+ label("post", "title", nil, :class => 'title_label')
+ )
+ assert_dom_equal('<label for="post_secret">Secret?</label>', label("post", "secret?"))
+ end
+
+ def test_label_with_symbols
+ assert_dom_equal('<label for="post_title">Title</label>', label(:post, :title))
+ assert_dom_equal('<label for="post_secret">Secret?</label>', label(:post, :secret?))
+ end
+
+ def test_label_with_locales_strings
+ old_locale, I18n.locale = I18n.locale, :label
+ assert_dom_equal('<label for="post_body">Write entire text here</label>', label("post", "body"))
+ ensure
+ I18n.locale = old_locale
+ end
+
+ def test_label_with_human_attribute_name
+ old_locale, I18n.locale = I18n.locale, :label
+ assert_dom_equal('<label for="post_cost">Total cost</label>', label(:post, :cost))
+ ensure
+ I18n.locale = old_locale
+ end
+
+ def test_label_with_locales_symbols
+ old_locale, I18n.locale = I18n.locale, :label
+ assert_dom_equal('<label for="post_body">Write entire text here</label>', label(:post, :body))
+ ensure
+ I18n.locale = old_locale
+ end
+
+ def test_label_with_for_attribute_as_symbol
+ assert_dom_equal('<label for="my_for">Title</label>', label(:post, :title, nil, :for => "my_for"))
+ end
+
+ def test_label_with_for_attribute_as_string
+ assert_dom_equal('<label for="my_for">Title</label>', label(:post, :title, nil, "for" => "my_for"))
+ end
+
+ def test_label_with_id_attribute_as_symbol
+ assert_dom_equal('<label for="post_title" id="my_id">Title</label>', label(:post, :title, nil, :id => "my_id"))
+ end
+
+ def test_label_with_id_attribute_as_string
+ assert_dom_equal('<label for="post_title" id="my_id">Title</label>', label(:post, :title, nil, "id" => "my_id"))
+ end
+
+ def test_label_with_for_and_id_attributes_as_symbol
+ assert_dom_equal('<label for="my_for" id="my_id">Title</label>', label(:post, :title, nil, :for => "my_for", :id => "my_id"))
+ end
+
+ def test_label_with_for_and_id_attributes_as_string
+ assert_dom_equal('<label for="my_for" id="my_id">Title</label>', label(:post, :title, nil, "for" => "my_for", "id" => "my_id"))
+ end
+
+ def test_label_for_radio_buttons_with_value
+ assert_dom_equal('<label for="post_title_great_title">The title goes here</label>', label("post", "title", "The title goes here", :value => "great_title"))
+ assert_dom_equal('<label for="post_title_great_title">The title goes here</label>', label("post", "title", "The title goes here", :value => "great title"))
+ end
+
+ def test_text_field
+ assert_dom_equal(
+ '<input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />', text_field("post", "title")
+ )
+ assert_dom_equal(
+ '<input id="post_title" name="post[title]" size="30" type="password" value="Hello World" />', password_field("post", "title")
+ )
+ assert_dom_equal(
+ '<input id="person_name" name="person[name]" size="30" type="password" />', password_field("person", "name")
+ )
+ end
+
+ def test_text_field_with_escapes
+ @post.title = "<b>Hello World</b>"
+ assert_dom_equal(
+ '<input id="post_title" name="post[title]" size="30" type="text" value="&lt;b&gt;Hello World&lt;/b&gt;" />', text_field("post", "title")
+ )
+ end
+
+ def test_text_field_with_html_entities
+ @post.title = "The HTML Entity for & is &amp;"
+ assert_dom_equal(
+ '<input id="post_title" name="post[title]" size="30" type="text" value="The HTML Entity for &amp; is &amp;amp;" />',
+ text_field("post", "title")
+ )
+ end
+
+ def test_text_field_with_options
+ expected = '<input id="post_title" name="post[title]" size="35" type="text" value="Hello World" />'
+ assert_dom_equal expected, text_field("post", "title", "size" => 35)
+ assert_dom_equal expected, text_field("post", "title", :size => 35)
+ end
+
+ def test_text_field_assuming_size
+ expected = '<input id="post_title" maxlength="35" name="post[title]" size="35" type="text" value="Hello World" />'
+ assert_dom_equal expected, text_field("post", "title", "maxlength" => 35)
+ assert_dom_equal expected, text_field("post", "title", :maxlength => 35)
+ end
+
+ def test_text_field_removing_size
+ expected = '<input id="post_title" maxlength="35" name="post[title]" type="text" value="Hello World" />'
+ assert_dom_equal expected, text_field("post", "title", "maxlength" => 35, "size" => nil)
+ assert_dom_equal expected, text_field("post", "title", :maxlength => 35, :size => nil)
+ end
+
+ def test_text_field_doesnt_change_param_values
+ object_name = 'post[]'
+ expected = '<input id="post_123_title" name="post[123][title]" size="30" type="text" value="Hello World" />'
+ assert_equal expected, text_field(object_name, "title")
+ assert_equal object_name, "post[]"
+ end
+
+ def test_hidden_field
+ assert_dom_equal '<input id="post_title" name="post[title]" type="hidden" value="Hello World" />',
+ hidden_field("post", "title")
+ assert_dom_equal '<input id="post_secret" name="post[secret]" type="hidden" value="1" />',
+ hidden_field("post", "secret?")
+ end
+
+ def test_hidden_field_with_escapes
+ @post.title = "<b>Hello World</b>"
+ assert_dom_equal '<input id="post_title" name="post[title]" type="hidden" value="&lt;b&gt;Hello World&lt;/b&gt;" />',
+ hidden_field("post", "title")
+ end
+
+ def test_hidden_field_with_options
+ assert_dom_equal '<input id="post_title" name="post[title]" type="hidden" value="Something Else" />',
+ hidden_field("post", "title", :value => "Something Else")
+ end
+
+ def test_check_box
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret")
+ )
+ @post.secret = 0
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="0" /><input id="post_secret" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret")
+ )
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret" ,{"checked"=>"checked"})
+ )
+ @post.secret = true
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret")
+ )
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret?")
+ )
+
+ @post.secret = ['0']
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="0" /><input id="post_secret" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret")
+ )
+ @post.secret = ['1']
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret")
+ )
+ end
+
+ def test_check_box_with_explicit_checked_and_unchecked_values
+ @post.secret = "on"
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="off" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="on" />',
+ check_box("post", "secret", {}, "on", "off")
+ )
+ end
+
+ def test_checkbox_disabled_still_submits_checked_value
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="1" /><input checked="checked" disabled="disabled" id="post_secret" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret", { :disabled => :true })
+ )
+ end
+
+ def test_radio_button
+ assert_dom_equal('<input checked="checked" id="post_title_hello_world" name="post[title]" type="radio" value="Hello World" />',
+ radio_button("post", "title", "Hello World")
+ )
+ assert_dom_equal('<input id="post_title_goodbye_world" name="post[title]" type="radio" value="Goodbye World" />',
+ radio_button("post", "title", "Goodbye World")
+ )
+ assert_dom_equal('<input id="item_subobject_title_inside_world" name="item[subobject][title]" type="radio" value="inside world"/>',
+ radio_button("item[subobject]", "title", "inside world")
+ )
+ end
+
+ def test_radio_button_is_checked_with_integers
+ assert_dom_equal('<input checked="checked" id="post_secret_1" name="post[secret]" type="radio" value="1" />',
+ radio_button("post", "secret", "1")
+ )
+ end
+
+ def test_radio_button_respects_passed_in_id
+ assert_dom_equal('<input checked="checked" id="foo" name="post[secret]" type="radio" value="1" />',
+ radio_button("post", "secret", "1", :id=>"foo")
+ )
+ end
+
+ def test_radio_button_with_booleans
+ assert_dom_equal('<input id="post_secret_true" name="post[secret]" type="radio" value="true" />',
+ radio_button("post", "secret", true)
+ )
+
+ assert_dom_equal('<input id="post_secret_false" name="post[secret]" type="radio" value="false" />',
+ radio_button("post", "secret", false)
+ )
+ end
+
+ def test_text_area
+ assert_dom_equal(
+ '<textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea>',
+ text_area("post", "body")
+ )
+ end
+
+ def test_text_area_with_escapes
+ @post.body = "Back to <i>the</i> hill and over it again!"
+ assert_dom_equal(
+ '<textarea cols="40" id="post_body" name="post[body]" rows="20">Back to &lt;i&gt;the&lt;/i&gt; hill and over it again!</textarea>',
+ text_area("post", "body")
+ )
+ end
+
+ def test_text_area_with_alternate_value
+ assert_dom_equal(
+ '<textarea cols="40" id="post_body" name="post[body]" rows="20">Testing alternate values.</textarea>',
+ text_area("post", "body", :value => 'Testing alternate values.')
+ )
+ end
+
+ def test_text_area_with_html_entities
+ @post.body = "The HTML Entity for & is &amp;"
+ assert_dom_equal(
+ '<textarea cols="40" id="post_body" name="post[body]" rows="20">The HTML Entity for &amp; is &amp;amp;</textarea>',
+ text_area("post", "body")
+ )
+ end
+
+ def test_text_area_with_size_option
+ assert_dom_equal(
+ '<textarea cols="183" id="post_body" name="post[body]" rows="820">Back to the hill and over it again!</textarea>',
+ text_area("post", "body", :size => "183x820")
+ )
+ end
+
+ def test_explicit_name
+ assert_dom_equal(
+ '<input id="post_title" name="dont guess" size="30" type="text" value="Hello World" />', text_field("post", "title", "name" => "dont guess")
+ )
+ assert_dom_equal(
+ '<textarea cols="40" id="post_body" name="really!" rows="20">Back to the hill and over it again!</textarea>',
+ text_area("post", "body", "name" => "really!")
+ )
+ assert_dom_equal(
+ '<input name="i mean it" type="hidden" value="0" /><input checked="checked" id="post_secret" name="i mean it" type="checkbox" value="1" />',
+ check_box("post", "secret", "name" => "i mean it")
+ )
+ assert_dom_equal text_field("post", "title", "name" => "dont guess"),
+ text_field("post", "title", :name => "dont guess")
+ assert_dom_equal text_area("post", "body", "name" => "really!"),
+ text_area("post", "body", :name => "really!")
+ assert_dom_equal check_box("post", "secret", "name" => "i mean it"),
+ check_box("post", "secret", :name => "i mean it")
+ end
+
+ def test_explicit_id
+ assert_dom_equal(
+ '<input id="dont guess" name="post[title]" size="30" type="text" value="Hello World" />', text_field("post", "title", "id" => "dont guess")
+ )
+ assert_dom_equal(
+ '<textarea cols="40" id="really!" name="post[body]" rows="20">Back to the hill and over it again!</textarea>',
+ text_area("post", "body", "id" => "really!")
+ )
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="i mean it" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret", "id" => "i mean it")
+ )
+ assert_dom_equal text_field("post", "title", "id" => "dont guess"),
+ text_field("post", "title", :id => "dont guess")
+ assert_dom_equal text_area("post", "body", "id" => "really!"),
+ text_area("post", "body", :id => "really!")
+ assert_dom_equal check_box("post", "secret", "id" => "i mean it"),
+ check_box("post", "secret", :id => "i mean it")
+ end
+
+ def test_auto_index
+ pid = @post.id
+ assert_dom_equal(
+ "<label for=\"post_#{pid}_title\">Title</label>",
+ label("post[]", "title")
+ )
+ assert_dom_equal(
+ "<input id=\"post_#{pid}_title\" name=\"post[#{pid}][title]\" size=\"30\" type=\"text\" value=\"Hello World\" />", text_field("post[]","title")
+ )
+ assert_dom_equal(
+ "<textarea cols=\"40\" id=\"post_#{pid}_body\" name=\"post[#{pid}][body]\" rows=\"20\">Back to the hill and over it again!</textarea>",
+ text_area("post[]", "body")
+ )
+ assert_dom_equal(
+ "<input name=\"post[#{pid}][secret]\" type=\"hidden\" value=\"0\" /><input checked=\"checked\" id=\"post_#{pid}_secret\" name=\"post[#{pid}][secret]\" type=\"checkbox\" value=\"1\" />",
+ check_box("post[]", "secret")
+ )
+ assert_dom_equal(
+"<input checked=\"checked\" id=\"post_#{pid}_title_hello_world\" name=\"post[#{pid}][title]\" type=\"radio\" value=\"Hello World\" />",
+ radio_button("post[]", "title", "Hello World")
+ )
+ assert_dom_equal("<input id=\"post_#{pid}_title_goodbye_world\" name=\"post[#{pid}][title]\" type=\"radio\" value=\"Goodbye World\" />",
+ radio_button("post[]", "title", "Goodbye World")
+ )
+ end
+
+ def test_form_for
+ form_for(:post, @post, :html => { :id => 'create-post' }) do |f|
+ concat f.label(:title)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ concat f.submit('Create post')
+ end
+
+ expected =
+ "<form action='http://www.example.com' id='create-post' method='post'>" +
+ "<label for='post_title'>Title</label>" +
+ "<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
+ "<input name='commit' id='post_submit' type='submit' value='Create post' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_method
+ form_for(:post, @post, :html => { :id => 'create-post', :method => :put }) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<form action='http://www.example.com' id='create-post' method='post'>" +
+ "<div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div>" +
+ "<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_without_object
+ form_for(:post, :html => { :id => 'create-post' }) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<form action='http://www.example.com' id='create-post' method='post'>" +
+ "<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_index
+ form_for("post[]", @post) do |f|
+ concat f.label(:title)
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<form action='http://www.example.com' method='post'>" +
+ "<label for=\"post_123_title\">Title</label>" +
+ "<input name='post[123][title]' size='30' type='text' id='post_123_title' value='Hello World' />" +
+ "<textarea name='post[123][body]' id='post_123_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[123][secret]' type='hidden' value='0' />" +
+ "<input name='post[123][secret]' checked='checked' type='checkbox' id='post_123_secret' value='1' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_nil_index_option_override
+ form_for("post[]", @post, :index => nil) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[][title]' size='30' type='text' id='post__title' value='Hello World' />" +
+ "<textarea name='post[][body]' id='post__body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[][secret]' type='hidden' value='0' />" +
+ "<input name='post[][secret]' checked='checked' type='checkbox' id='post__secret' value='1' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for
+ form_for(:post, @post) do |f|
+ f.fields_for(:comment, @post) do |c|
+ concat c.text_field(:title)
+ end
+ end
+
+ expected = "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[comment][title]' size='30' type='text' id='post_comment_title' value='Hello World' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_nested_collections
+ form_for('post[]', @post) do |f|
+ concat f.text_field(:title)
+ f.fields_for('comment[]', @comment) do |c|
+ concat c.text_field(:name)
+ end
+ end
+
+ expected = "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[123][title]' size='30' type='text' id='post_123_title' value='Hello World' />" +
+ "<input name='post[123][comment][][name]' size='30' type='text' id='post_123_comment__name' value='new comment' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_index_and_parent_fields
+ form_for('post', @post, :index => 1) do |c|
+ concat c.text_field(:title)
+ c.fields_for('comment', @comment, :index => 1) do |r|
+ concat r.text_field(:name)
+ end
+ end
+
+ expected = "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[1][title]' size='30' type='text' id='post_1_title' value='Hello World' />" +
+ "<input name='post[1][comment][1][name]' size='30' type='text' id='post_1_comment_1_name' value='new comment' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_index_and_nested_fields_for
+ form_for(:post, @post, :index => 1) do |f|
+ f.fields_for(:comment, @post) do |c|
+ concat c.text_field(:title)
+ end
+ end
+
+ expected = "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[1][comment][title]' size='30' type='text' id='post_1_comment_title' value='Hello World' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_index_on_both
+ form_for(:post, @post, :index => 1) do |f|
+ f.fields_for(:comment, @post, :index => 5) do |c|
+ concat c.text_field(:title)
+ end
+ end
+
+ expected = "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[1][comment][5][title]' size='30' type='text' id='post_1_comment_5_title' value='Hello World' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_auto_index
+ form_for("post[]", @post) do |f|
+ f.fields_for(:comment, @post) do |c|
+ concat c.text_field(:title)
+ end
+ end
+
+ expected = "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[123][comment][title]' size='30' type='text' id='post_123_comment_title' value='Hello World' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_index_radio_button
+ form_for(:post, @post) do |f|
+ f.fields_for(:comment, @post, :index => 5) do |c|
+ concat c.radio_button(:title, "hello")
+ end
+ end
+
+ expected = "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[comment][5][title]' type='radio' id='post_comment_5_title_hello' value='hello' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_auto_index_on_both
+ form_for("post[]", @post) do |f|
+ f.fields_for("comment[]", @post) do |c|
+ concat c.text_field(:title)
+ end
+ end
+
+ expected = "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[123][comment][123][title]' size='30' type='text' id='post_123_comment_123_title' value='Hello World' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_index_and_auto_index
+ form_for("post[]", @post) do |f|
+ f.fields_for(:comment, @post, :index => 5) do |c|
+ concat c.text_field(:title)
+ end
+ end
+
+ form_for(:post, @post, :index => 1) do |f|
+ f.fields_for("comment[]", @post) do |c|
+ concat c.text_field(:title)
+ end
+ end
+
+ expected = "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[123][comment][5][title]' size='30' type='text' id='post_123_comment_5_title' value='Hello World' />" +
+ "</form>" +
+ "<form action='http://www.example.com' method='post'>" +
+ "<input name='post[1][comment][123][title]' size='30' type='text' id='post_1_comment_123_title' value='Hello World' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_a_new_record_on_a_nested_attributes_one_to_one_association
+ @post.author = Author.new
+
+ form_for(:post, @post) do |f|
+ concat f.text_field(:title)
+ f.fields_for(:author) do |af|
+ concat af.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_author_attributes_name" name="post[author_attributes][name]" size="30" type="text" value="new author" />' +
+ '</form>'
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_explicitly_passed_object_on_a_nested_attributes_one_to_one_association
+ form_for(:post, @post) do |f|
+ f.fields_for(:author, Author.new(123)) do |af|
+ assert_not_nil af.object
+ assert_equal 123, af.object.id
+ end
+ end
+ end
+
+ def test_nested_fields_for_with_an_existing_record_on_a_nested_attributes_one_to_one_association
+ @post.author = Author.new(321)
+
+ form_for(:post, @post) do |f|
+ concat f.text_field(:title)
+ f.fields_for(:author) do |af|
+ concat af.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_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">' +
+ '<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_name" name="post[author_attributes][name]" size="30" type="text" value="author #321" />' +
+ '</form>'
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association
+ @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.text_field(:name)
+ 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">' +
+ '<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_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #1" />' +
+ '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />' +
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="comment #2" />' +
+ '</form>'
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_new_records_on_a_nested_attributes_collection_association
+ @post.comments = [Comment.new, Comment.new]
+
+ 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.text_field(:name)
+ 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="new comment" />' +
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="new comment" />' +
+ '</form>'
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_existing_and_new_records_on_a_nested_attributes_collection_association
+ @post.comments = [Comment.new(321), Comment.new]
+
+ 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.text_field(:name)
+ 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 #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" />' +
+ '</form>'
+
+ assert_dom_equal expected, output_buffer
+ 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
+ @post.comments = [Comment.new(321), Comment.new]
+ yielded_comments = []
+
+ form_for(:post, @post) do |f|
+ concat f.text_field(:title)
+ f.fields_for(:comments) do |cf|
+ concat cf.text_field(:name)
+ yielded_comments << cf.object
+ 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 #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" />' +
+ '</form>'
+
+ assert_dom_equal expected, output_buffer
+ assert_equal yielded_comments, @post.comments
+ end
+
+ def test_nested_fields_for_with_child_index_option_override_on_a_nested_attributes_collection_association
+ @post.comments = []
+
+ form_for(:post, @post) do |f|
+ f.fields_for(:comments, Comment.new(321), :child_index => 'abc') do |cf|
+ concat cf.text_field(:name)
+ end
+ end
+
+ expected = '<form action="http://www.example.com" method="post">' +
+ '<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>'
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_nested_fields_uses_unique_indices_for_different_collection_associations
+ @post.comments = [Comment.new(321)]
+ @post.tags = [Tag.new(123), Tag.new(456)]
+ @post.comments[0].relevances = []
+ @post.tags[0].relevances = []
+ @post.tags[1].relevances = []
+ form_for(:post, @post) do |f|
+ f.fields_for(:comments, @post.comments[0]) do |cf|
+ concat cf.text_field(:name)
+ cf.fields_for(:relevances, CommentRelevance.new(314)) do |crf|
+ concat crf.text_field(:value)
+ end
+ end
+ f.fields_for(:tags, @post.tags[0]) do |tf|
+ concat tf.text_field(:value)
+ tf.fields_for(:relevances, TagRelevance.new(3141)) do |trf|
+ concat trf.text_field(:value)
+ end
+ end
+ f.fields_for('tags', @post.tags[1]) do |tf|
+ concat tf.text_field(:value)
+ tf.fields_for(:relevances, TagRelevance.new(31415)) do |trf|
+ concat trf.text_field(:value)
+ end
+ end
+ end
+
+ expected = '<form action="http://www.example.com" method="post">' +
+ '<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_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_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_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_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_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>'
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_fields_for
+ fields_for(:post, @post) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_fields_for_with_index
+ fields_for("post[]", @post) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<input name='post[123][title]' size='30' type='text' id='post_123_title' value='Hello World' />" +
+ "<textarea name='post[123][body]' id='post_123_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[123][secret]' type='hidden' value='0' />" +
+ "<input name='post[123][secret]' checked='checked' type='checkbox' id='post_123_secret' value='1' />"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_fields_for_with_nil_index_option_override
+ fields_for("post[]", @post, :index => nil) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<input name='post[][title]' size='30' type='text' id='post__title' value='Hello World' />" +
+ "<textarea name='post[][body]' id='post__body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[][secret]' type='hidden' value='0' />" +
+ "<input name='post[][secret]' checked='checked' type='checkbox' id='post__secret' value='1' />"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_fields_for_with_index_option_override
+ fields_for("post[]", @post, :index => "abc") do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<input name='post[abc][title]' size='30' type='text' id='post_abc_title' value='Hello World' />" +
+ "<textarea name='post[abc][body]' id='post_abc_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[abc][secret]' type='hidden' value='0' />" +
+ "<input name='post[abc][secret]' checked='checked' type='checkbox' id='post_abc_secret' value='1' />"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_fields_for_without_object
+ fields_for(:post) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_fields_for_with_only_object
+ fields_for(@post) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_fields_for_object_with_bracketed_name
+ fields_for("author[post]", @post) do |f|
+ concat f.label(:title)
+ concat f.text_field(:title)
+ end
+
+ assert_dom_equal "<label for=\"author_post_title\">Title</label>" +
+ "<input name='author[post][title]' size='30' type='text' id='author_post_title' value='Hello World' />",
+ output_buffer
+ end
+
+ def test_fields_for_object_with_bracketed_name_and_index
+ fields_for("author[post]", @post, :index => 1) do |f|
+ concat f.label(:title)
+ concat f.text_field(:title)
+ end
+
+ assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" +
+ "<input name='author[post][1][title]' size='30' type='text' id='author_post_1_title' value='Hello World' />",
+ output_buffer
+ end
+
+ def test_form_builder_does_not_have_form_for_method
+ assert ! ActionView::Helpers::FormBuilder.instance_methods.include?('form_for')
+ end
+
+ def test_form_for_and_fields_for
+ form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form|
+ concat post_form.text_field(:title)
+ concat post_form.text_area(:body)
+
+ fields_for(:parent_post, @post) do |parent_fields|
+ concat parent_fields.check_box(:secret)
+ end
+ end
+
+ expected =
+ "<form action='http://www.example.com' id='create-post' method='post'>" +
+ "<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='parent_post[secret]' type='hidden' value='0' />" +
+ "<input name='parent_post[secret]' checked='checked' type='checkbox' id='parent_post_secret' value='1' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_and_fields_for_with_object
+ form_for(:post, @post, :html => { :id => 'create-post' }) do |post_form|
+ concat post_form.text_field(:title)
+ concat post_form.text_area(:body)
+
+ post_form.fields_for(@comment) do |comment_fields|
+ concat comment_fields.text_field(:name)
+ end
+ end
+
+ expected =
+ "<form action='http://www.example.com' id='create-post' method='post'>" +
+ "<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[comment][name]' type='text' id='post_comment_name' value='new comment' size='30' />" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ class LabelledFormBuilder < ActionView::Helpers::FormBuilder
+ (field_helpers - %w(hidden_field)).each do |selector|
+ src, line = <<-END_SRC, __LINE__ + 1
+ def #{selector}(field, *args, &proc)
+ ("<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>").html_safe
+ end
+ END_SRC
+ class_eval src, __FILE__, line
+ end
+ end
+
+ def test_form_for_with_labelled_builder
+ form_for(:post, @post, :builder => LabelledFormBuilder) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<form action='http://www.example.com' method='post'>" +
+ "<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
+ "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
+ "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_default_form_builder
+ old_default_form_builder, ActionView::Base.default_form_builder =
+ ActionView::Base.default_form_builder, LabelledFormBuilder
+
+ form_for(:post, @post) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<form action='http://www.example.com' method='post'>" +
+ "<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
+ "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
+ "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ ensure
+ ActionView::Base.default_form_builder = old_default_form_builder
+ end
+
+ def test_default_form_builder_with_active_record_helpers
+ form_for(:post, @post) do |f|
+ concat f.error_message_on('author_name')
+ concat f.error_messages
+ end
+
+ expected = %(<form action='http://www.example.com' method='post'>) +
+ %(<div class='formError'>can't be empty</div>) +
+ %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) +
+ %(</form>)
+
+ assert_dom_equal expected, output_buffer
+
+ end
+
+ def test_default_form_builder_no_instance_variable
+ post = @post
+ @post = nil
+
+ form_for(:post, post) do |f|
+ concat f.error_message_on('author_name')
+ concat f.error_messages
+ end
+
+ expected = %(<form action='http://www.example.com' method='post'>) +
+ %(<div class='formError'>can't be empty</div>) +
+ %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) +
+ %(</form>)
+
+ assert_dom_equal expected, output_buffer
+
+ end
+
+ def test_default_form_builder_without_object
+
+ form_for(:post) do |f|
+ concat f.error_message_on('author_name')
+ concat f.error_messages
+ end
+
+ expected = %(<form action='http://www.example.com' method='post'>) +
+ %(<div class='formError'>can't be empty</div>) +
+ %(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) +
+ %(</form>)
+
+ assert_dom_equal expected, output_buffer
+
+ end
+
+ # Perhaps this test should be moved to prototype helper tests.
+ def test_remote_form_for_with_labelled_builder
+ self.extend ActionView::Helpers::PrototypeHelper
+
+ remote_form_for(:post, @post, :builder => LabelledFormBuilder) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ %(<form action="http://www.example.com" onsubmit="new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" method="post">) +
+ "<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
+ "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
+ "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>" +
+ "</form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_fields_for_with_labelled_builder
+ fields_for(:post, @post, :builder => LabelledFormBuilder) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected =
+ "<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
+ "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
+ "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_labelled_builder_with_nested_fields_for_without_options_hash
+ klass = nil
+
+ form_for(:post, @post, :builder => LabelledFormBuilder) do |f|
+ f.fields_for(:comments, Comment.new) do |nested_fields|
+ klass = nested_fields.class
+ ''
+ end
+ end
+
+ assert_equal LabelledFormBuilder, klass
+ end
+
+ def test_form_for_with_labelled_builder_with_nested_fields_for_with_options_hash
+ klass = nil
+
+ form_for(:post, @post, :builder => LabelledFormBuilder) do |f|
+ f.fields_for(:comments, Comment.new, :index => 'foo') do |nested_fields|
+ klass = nested_fields.class
+ ''
+ end
+ end
+
+ assert_equal LabelledFormBuilder, klass
+ end
+
+ class LabelledFormBuilderSubclass < LabelledFormBuilder; end
+
+ def test_form_for_with_labelled_builder_with_nested_fields_for_with_custom_builder
+ klass = nil
+
+ form_for(:post, @post, :builder => LabelledFormBuilder) do |f|
+ f.fields_for(:comments, Comment.new, :builder => LabelledFormBuilderSubclass) do |nested_fields|
+ klass = nested_fields.class
+ ''
+ end
+ end
+
+ assert_equal LabelledFormBuilderSubclass, klass
+ end
+
+ def test_form_for_with_html_options_adds_options_to_form_tag
+ form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
+ expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\"></form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_string_url_option
+ form_for(:post, @post, :url => 'http://www.otherdomain.com') do |f| end
+
+ assert_equal '<form action="http://www.otherdomain.com" method="post"></form>', output_buffer
+ end
+
+ def test_form_for_with_hash_url_option
+ form_for(:post, @post, :url => {:controller => 'controller', :action => 'action'}) do |f| end
+
+ assert_equal 'controller', @controller.url_for_options[:controller]
+ assert_equal 'action', @controller.url_for_options[:action]
+ end
+
+ def test_form_for_with_record_url_option
+ form_for(:post, @post, :url => @post) do |f| end
+
+ expected = "<form action=\"/posts/123\" method=\"post\"></form>"
+ assert_equal expected, output_buffer
+ end
+
+ def test_form_for_with_existing_object
+ form_for(@post) do |f| end
+
+ expected = "<form action=\"/posts/123\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0;display:inline\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>"
+ assert_equal expected, output_buffer
+ end
+
+ def test_form_for_with_new_object
+ post = Post.new
+ post.new_record = true
+ def post.id() nil end
+
+ form_for(post) do |f| end
+
+ expected = "<form action=\"/posts\" class=\"new_post\" id=\"new_post\" method=\"post\"></form>"
+ assert_equal expected, output_buffer
+ end
+
+ def test_form_for_with_existing_object_in_list
+ @post.new_record = false
+ @comment.save
+
+ form_for([@post, @comment]) {}
+
+ expected = %(<form action="#{comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0;display:inline"><input name="_method" type="hidden" value="put" /></div></form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_new_object_in_list
+ @post.new_record = false
+
+ form_for([@post, @comment]) {}
+
+ expected = %(<form action="#{comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_existing_object_and_namespace_in_list
+ @post.new_record = false
+ @comment.save
+
+ form_for([:admin, @post, @comment]) {}
+
+ expected = %(<form action="#{admin_comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0;display:inline"><input name="_method" type="hidden" value="put" /></div></form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_new_object_and_namespace_in_list
+ @post.new_record = false
+
+ form_for([:admin, @post, @comment]) {}
+
+ expected = %(<form action="#{admin_comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_existing_object_and_custom_url
+ form_for(@post, :url => "/super_posts") do |f| end
+
+ expected = "<form action=\"/super_posts\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0;display:inline\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>"
+ assert_equal expected, output_buffer
+ end
+
+ def test_remote_form_for_with_html_options_adds_options_to_form_tag
+ self.extend ActionView::Helpers::PrototypeHelper
+
+ remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
+ expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\" onsubmit=\"new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"></form>"
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ protected
+ def comments_path(post)
+ "/posts/#{post.id}/comments"
+ end
+ alias_method :post_comments_path, :comments_path
+
+ def comment_path(post, comment)
+ "/posts/#{post.id}/comments/#{comment.id}"
+ end
+ alias_method :post_comment_path, :comment_path
+
+ def admin_comments_path(post)
+ "/admin/posts/#{post.id}/comments"
+ end
+ alias_method :admin_post_comments_path, :admin_comments_path
+
+ def admin_comment_path(post, comment)
+ "/admin/posts/#{post.id}/comments/#{comment.id}"
+ end
+ alias_method :admin_post_comment_path, :admin_comment_path
+
+ def posts_path
+ "/posts"
+ end
+
+ def post_path(post)
+ "/posts/#{post.id}"
+ end
+
+ def protect_against_forgery?
+ false
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/form_tag_helper_test.rb b/vendor/plugins/rails_xss/test/form_tag_helper_test.rb
new file mode 100644
index 000000000..41eeceeb3
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/form_tag_helper_test.rb
@@ -0,0 +1,354 @@
+require 'test_helper'
+
+class FormTagHelperTest < ActionView::TestCase
+ def setup
+ @controller = Class.new do
+ def url_for(options)
+ "http://www.example.com"
+ end
+ end
+ @controller = @controller.new
+ end
+
+ VALID_HTML_ID = /^[A-Za-z][-_:.A-Za-z0-9]*$/ # see http://www.w3.org/TR/html4/types.html#type-name
+
+ def test_check_box_tag
+ actual = check_box_tag "admin"
+ expected = %(<input id="admin" name="admin" type="checkbox" value="1" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_check_box_tag_id_sanitized
+ label_elem = root_elem(check_box_tag("project[2][admin]"))
+ assert_match VALID_HTML_ID, label_elem['id']
+ end
+
+ def test_form_tag
+ actual = form_tag
+ expected = %(<form action="http://www.example.com" method="post">)
+ assert_dom_equal expected, actual
+ end
+
+ def test_form_tag_multipart
+ actual = form_tag({}, { 'multipart' => true })
+ expected = %(<form action="http://www.example.com" enctype="multipart/form-data" method="post">)
+ assert_dom_equal expected, actual
+ end
+
+ def test_form_tag_with_method_put
+ actual = form_tag({}, { :method => :put })
+ expected = %(<form action="http://www.example.com" method="post"><div style='margin:0;padding:0;display:inline'><input type="hidden" name="_method" value="put" /></div>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_form_tag_with_method_delete
+ actual = form_tag({}, { :method => :delete })
+ expected = %(<form action="http://www.example.com" method="post"><div style='margin:0;padding:0;display:inline'><input type="hidden" name="_method" value="delete" /></div>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_form_tag_with_block_in_erb
+ __in_erb_template = ''
+ form_tag("http://example.com") { concat "Hello world!" }
+
+ expected = %(<form action="http://example.com" method="post">Hello world!</form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_tag_with_block_and_method_in_erb
+ __in_erb_template = ''
+ form_tag("http://example.com", :method => :put) { concat "Hello world!" }
+
+ expected = %(<form action="http://example.com" method="post"><div style='margin:0;padding:0;display:inline'><input type="hidden" name="_method" value="put" /></div>Hello world!</form>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_hidden_field_tag
+ actual = hidden_field_tag "id", 3
+ expected = %(<input id="id" name="id" type="hidden" value="3" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_hidden_field_tag_id_sanitized
+ input_elem = root_elem(hidden_field_tag("item[][title]"))
+ assert_match VALID_HTML_ID, input_elem['id']
+ end
+
+ def test_file_field_tag
+ assert_dom_equal "<input name=\"picsplz\" type=\"file\" id=\"picsplz\" />", file_field_tag("picsplz")
+ end
+
+ def test_file_field_tag_with_options
+ assert_dom_equal "<input name=\"picsplz\" type=\"file\" id=\"picsplz\" class=\"pix\"/>", file_field_tag("picsplz", :class => "pix")
+ end
+
+ def test_password_field_tag
+ actual = password_field_tag
+ expected = %(<input id="password" name="password" type="password" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_radio_button_tag
+ actual = radio_button_tag "people", "david"
+ expected = %(<input id="people_david" name="people" type="radio" value="david" />)
+ assert_dom_equal expected, actual
+
+ actual = radio_button_tag("num_people", 5)
+ expected = %(<input id="num_people_5" name="num_people" type="radio" value="5" />)
+ assert_dom_equal expected, actual
+
+ actual = radio_button_tag("gender", "m") + radio_button_tag("gender", "f")
+ expected = %(<input id="gender_m" name="gender" type="radio" value="m" /><input id="gender_f" name="gender" type="radio" value="f" />)
+ assert_dom_equal expected, actual
+
+ actual = radio_button_tag("opinion", "-1") + radio_button_tag("opinion", "1")
+ expected = %(<input id="opinion_-1" name="opinion" type="radio" value="-1" /><input id="opinion_1" name="opinion" type="radio" value="1" />)
+ assert_dom_equal expected, actual
+
+ actual = radio_button_tag("person[gender]", "m")
+ expected = %(<input id="person_gender_m" name="person[gender]" type="radio" value="m" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_select_tag
+ actual = select_tag "people", "<option>david</option>".html_safe
+ expected = %(<select id="people" name="people"><option>david</option></select>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_select_tag_with_multiple
+ actual = select_tag "colors", "<option>Red</option><option>Blue</option><option>Green</option>".html_safe, :multiple => :true
+ expected = %(<select id="colors" multiple="multiple" name="colors"><option>Red</option><option>Blue</option><option>Green</option></select>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_select_tag_disabled
+ actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, :disabled => :true
+ expected = %(<select id="places" disabled="disabled" name="places"><option>Home</option><option>Work</option><option>Pub</option></select>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_select_tag_id_sanitized
+ input_elem = root_elem(select_tag("project[1]people", "<option>david</option>"))
+ assert_match VALID_HTML_ID, input_elem['id']
+ end
+
+ def test_select_tag_with_array_options
+ assert_deprecated /array/ do
+ select_tag "people", ["<option>david</option>"]
+ end
+ end
+
+ def test_text_area_tag_size_string
+ actual = text_area_tag "body", "hello world", "size" => "20x40"
+ expected = %(<textarea cols="20" id="body" name="body" rows="40">hello world</textarea>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_area_tag_size_symbol
+ actual = text_area_tag "body", "hello world", :size => "20x40"
+ expected = %(<textarea cols="20" id="body" name="body" rows="40">hello world</textarea>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_area_tag_should_disregard_size_if_its_given_as_an_integer
+ actual = text_area_tag "body", "hello world", :size => 20
+ expected = %(<textarea id="body" name="body">hello world</textarea>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_area_tag_id_sanitized
+ input_elem = root_elem(text_area_tag("item[][description]"))
+ assert_match VALID_HTML_ID, input_elem['id']
+ end
+
+ def test_text_area_tag_escape_content
+ actual = text_area_tag "body", "<b>hello world</b>", :size => "20x40"
+ expected = %(<textarea cols="20" id="body" name="body" rows="40">&lt;b&gt;hello world&lt;/b&gt;</textarea>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_area_tag_unescaped_content
+ actual = text_area_tag "body", "<b>hello world</b>", :size => "20x40", :escape => false
+ expected = %(<textarea cols="20" id="body" name="body" rows="40"><b>hello world</b></textarea>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_area_tag_unescaped_nil_content
+ actual = text_area_tag "body", nil, :escape => false
+ expected = %(<textarea id="body" name="body"></textarea>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_field_tag
+ actual = text_field_tag "title", "Hello!"
+ expected = %(<input id="title" name="title" type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_field_tag_class_string
+ actual = text_field_tag "title", "Hello!", "class" => "admin"
+ expected = %(<input class="admin" id="title" name="title" type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_field_tag_size_symbol
+ actual = text_field_tag "title", "Hello!", :size => 75
+ expected = %(<input id="title" name="title" size="75" type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_field_tag_size_string
+ actual = text_field_tag "title", "Hello!", "size" => "75"
+ expected = %(<input id="title" name="title" size="75" type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_field_tag_maxlength_symbol
+ actual = text_field_tag "title", "Hello!", :maxlength => 75
+ expected = %(<input id="title" name="title" maxlength="75" type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_field_tag_maxlength_string
+ actual = text_field_tag "title", "Hello!", "maxlength" => "75"
+ expected = %(<input id="title" name="title" maxlength="75" type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_field_disabled
+ actual = text_field_tag "title", "Hello!", :disabled => :true
+ expected = %(<input id="title" name="title" disabled="disabled" type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_field_tag_with_multiple_options
+ actual = text_field_tag "title", "Hello!", :size => 70, :maxlength => 80
+ expected = %(<input id="title" name="title" size="70" maxlength="80" type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_text_field_tag_id_sanitized
+ input_elem = root_elem(text_field_tag("item[][title]"))
+ assert_match VALID_HTML_ID, input_elem['id']
+ end
+
+ def test_label_tag_without_text
+ actual = label_tag "title"
+ expected = %(<label for="title">Title</label>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_label_tag_with_symbol
+ actual = label_tag :title
+ expected = %(<label for="title">Title</label>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_label_tag_with_text
+ actual = label_tag "title", "My Title"
+ expected = %(<label for="title">My Title</label>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_label_tag_class_string
+ actual = label_tag "title", "My Title", "class" => "small_label"
+ expected = %(<label for="title" class="small_label">My Title</label>)
+ assert_dom_equal expected, actual
+ end
+
+ def test_label_tag_id_sanitized
+ label_elem = root_elem(label_tag("item[title]"))
+ assert_match VALID_HTML_ID, label_elem['for']
+ end
+
+ def test_boolean_options
+ assert_dom_equal %(<input checked="checked" disabled="disabled" id="admin" name="admin" readonly="readonly" type="checkbox" value="1" />), check_box_tag("admin", 1, true, 'disabled' => true, :readonly => "yes")
+ assert_dom_equal %(<input checked="checked" id="admin" name="admin" type="checkbox" value="1" />), check_box_tag("admin", 1, true, :disabled => false, :readonly => nil)
+ assert_dom_equal %(<input type="checkbox" />), tag(:input, :type => "checkbox", :checked => false)
+ assert_dom_equal %(<select id="people" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people", "<option>david</option>".html_safe, :multiple => true)
+ assert_dom_equal %(<select id="people_" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people[]", "<option>david</option>".html_safe, :multiple => true)
+ assert_dom_equal %(<select id="people" name="people"><option>david</option></select>), select_tag("people", "<option>david</option>".html_safe, :multiple => nil)
+ end
+
+ def test_stringify_symbol_keys
+ actual = text_field_tag "title", "Hello!", :id => "admin"
+ expected = %(<input id="admin" name="title" type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_submit_tag
+ assert_dom_equal(
+ %(<input name='commit' onclick="if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';alert('hello!');result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Save" />),
+ submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!')")
+ )
+ end
+
+ def test_submit_tag_with_no_onclick_options
+ assert_dom_equal(
+ %(<input name='commit' onclick="if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Save" />),
+ submit_tag("Save", :disable_with => "Saving...")
+ )
+ end
+
+ def test_submit_tag_with_confirmation
+ assert_dom_equal(
+ %(<input name='commit' type='submit' value='Save' onclick="if (!confirm('Are you sure?')) return false; return true;"/>),
+ submit_tag("Save", :confirm => "Are you sure?")
+ )
+ end
+
+ def test_submit_tag_with_confirmation_and_with_disable_with
+ assert_dom_equal(
+ %(<input name="commit" onclick="if (!confirm('Are you sure?')) return false; if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Save" />),
+ submit_tag("Save", :disable_with => "Saving...", :confirm => "Are you sure?")
+ )
+ end
+
+ def test_image_submit_tag_with_confirmation
+ assert_dom_equal(
+ %(<input type="image" src="/images/save.gif" onclick="return confirm('Are you sure?');"/>),
+ image_submit_tag("save.gif", :confirm => "Are you sure?")
+ )
+ end
+
+ def test_pass
+ assert_equal 1, 1
+ end
+
+ def test_field_set_tag_in_erb
+ __in_erb_template = ''
+ field_set_tag("Your details") { concat "Hello world!" }
+
+ expected = %(<fieldset><legend>Your details</legend>Hello world!</fieldset>)
+ assert_dom_equal expected, output_buffer
+
+ self.output_buffer = ''.html_safe
+ field_set_tag { concat "Hello world!" }
+
+ expected = %(<fieldset>Hello world!</fieldset>)
+ assert_dom_equal expected, output_buffer
+
+ self.output_buffer = ''.html_safe
+ field_set_tag('') { concat "Hello world!" }
+
+ expected = %(<fieldset>Hello world!</fieldset>)
+ assert_dom_equal expected, output_buffer
+
+ self.output_buffer = ''.html_safe
+ field_set_tag('', :class => 'format') { concat "Hello world!" }
+
+ expected = %(<fieldset class="format">Hello world!</fieldset>)
+ assert_dom_equal expected, output_buffer
+ end
+
+ def protect_against_forgery?
+ false
+ end
+
+ private
+
+ def root_elem(rendered_content)
+ HTML::Document.new(rendered_content).root.children[0]
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/javascript_helper_test.rb b/vendor/plugins/rails_xss/test/javascript_helper_test.rb
new file mode 100644
index 000000000..691d97a15
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/javascript_helper_test.rb
@@ -0,0 +1,10 @@
+require 'test_helper'
+
+class JavascriptHelperTest < ActionView::TestCase
+ def test_escape_javascript_with_safebuffer
+ given = %('quoted' "double-quoted" new-line:\n </closed>)
+ expect = %(\\'quoted\\' \\"double-quoted\\" new-line:\\n <\\/closed>)
+ assert_equal expect, escape_javascript(given)
+ assert_equal expect, escape_javascript(ActiveSupport::SafeBuffer.new(given))
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/output_escaping_test.rb b/vendor/plugins/rails_xss/test/output_escaping_test.rb
new file mode 100644
index 000000000..8b6f8b83c
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/output_escaping_test.rb
@@ -0,0 +1,19 @@
+require 'test_helper'
+
+class OutputEscapingTest < ActiveSupport::TestCase
+
+ test "escape_html shouldn't die when passed nil" do
+ assert ERB::Util.h(nil).blank?
+ end
+
+ test "escapeHTML should escape strings" do
+ assert_equal "&lt;&gt;&quot;", ERB::Util.h("<>\"")
+ end
+
+ test "escapeHTML shouldn't touch explicitly safe strings" do
+ # TODO this seems easier to compose and reason about, but
+ # this should be verified
+ assert_equal "<", ERB::Util.h("<".html_safe)
+ end
+
+end
diff --git a/vendor/plugins/rails_xss/test/output_safety_test.rb b/vendor/plugins/rails_xss/test/output_safety_test.rb
new file mode 100644
index 000000000..2e376477d
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/output_safety_test.rb
@@ -0,0 +1,115 @@
+require 'test_helper'
+
+class OutputSafetyTest < ActiveSupport::TestCase
+ def setup
+ @string = "hello"
+ @object = Class.new(Object) do
+ def to_s
+ "other"
+ end
+ end.new
+ end
+
+ test "A string is unsafe by default" do
+ assert !@string.html_safe?
+ end
+
+ test "A string can be marked safe" do
+ string = @string.html_safe
+ assert string.html_safe?
+ end
+
+ test "Marking a string safe returns the string" do
+ assert_equal @string, @string.html_safe
+ end
+
+ test "A fixnum is safe by default" do
+ assert 5.html_safe?
+ end
+
+ test "An object is unsafe by default" do
+ assert !@object.html_safe?
+ end
+
+ test "Adding an object to a safe string returns a safe string" do
+ string = @string.html_safe
+ string << @object
+
+ assert_equal "helloother", string
+ assert string.html_safe?
+ end
+
+ test "Adding a safe string to another safe string returns a safe string" do
+ @other_string = "other".html_safe
+ string = @string.html_safe
+ @combination = @other_string + string
+
+ assert_equal "otherhello", @combination
+ assert @combination.html_safe?
+ end
+
+ test "Adding an unsafe string to a safe string escapes it and returns a safe string" do
+ @other_string = "other".html_safe
+ @combination = @other_string + "<foo>"
+ @other_combination = @string + "<foo>"
+
+ assert_equal "other&lt;foo&gt;", @combination
+ assert_equal "hello<foo>", @other_combination
+
+ assert @combination.html_safe?
+ assert !@other_combination.html_safe?
+ end
+
+ test "Concatting safe onto unsafe yields unsafe" do
+ @other_string = "other"
+
+ string = @string.html_safe
+ @other_string.concat(string)
+ assert !@other_string.html_safe?
+ end
+
+ test "Concatting unsafe onto safe yields escaped safe" do
+ @other_string = "other".html_safe
+ string = @other_string.concat("<foo>")
+ assert_equal "other&lt;foo&gt;", string
+ assert string.html_safe?
+ end
+
+ test "Concatting safe onto safe yields safe" do
+ @other_string = "other".html_safe
+ string = @string.html_safe
+
+ @other_string.concat(string)
+ assert @other_string.html_safe?
+ end
+
+ test "Concatting safe onto unsafe with << yields unsafe" do
+ @other_string = "other"
+ string = @string.html_safe
+
+ @other_string << string
+ assert !@other_string.html_safe?
+ end
+
+ test "Concatting unsafe onto safe with << yields escaped safe" do
+ @other_string = "other".html_safe
+ string = @other_string << "<foo>"
+ assert_equal "other&lt;foo&gt;", string
+ assert string.html_safe?
+ end
+
+ test "Concatting safe onto safe with << yields safe" do
+ @other_string = "other".html_safe
+ string = @string.html_safe
+
+ @other_string << string
+ assert @other_string.html_safe?
+ end
+
+ test "Concatting a fixnum to safe always yields safe" do
+ string = @string.html_safe
+ string = string.concat(13)
+ assert_equal "hello".concat(13), string
+ assert string.html_safe?
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/rails_xss_test.rb b/vendor/plugins/rails_xss/test/rails_xss_test.rb
new file mode 100644
index 000000000..b6268bafd
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/rails_xss_test.rb
@@ -0,0 +1,23 @@
+require 'test_helper'
+
+class RailsXssTest < ActiveSupport::TestCase
+ test "ERB::Util.h should mark its return value as safe and escape it" do
+ escaped = ERB::Util.h("<p>")
+ assert_equal "&lt;p&gt;", escaped
+ assert escaped.html_safe?
+ end
+
+ test "ERB::Util.h should leave previously safe strings alone " do
+ # TODO this seems easier to compose and reason about, but
+ # this should be verified
+ escaped = ERB::Util.h("<p>".html_safe)
+ assert_equal "<p>", escaped
+ assert escaped.html_safe?
+ end
+
+ test "ERB::Util.h should not implode when passed a non-string" do
+ assert_nothing_raised do
+ assert_equal "1", ERB::Util.h(1)
+ end
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/raw_output_helper_test.rb b/vendor/plugins/rails_xss/test/raw_output_helper_test.rb
new file mode 100644
index 000000000..2a67f976e
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/raw_output_helper_test.rb
@@ -0,0 +1,18 @@
+require 'test_helper'
+
+class RawOutputHelperTest < ActionView::TestCase
+
+ 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
diff --git a/vendor/plugins/rails_xss/test/safe_buffer_test.rb b/vendor/plugins/rails_xss/test/safe_buffer_test.rb
new file mode 100644
index 000000000..a0a2eccee
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/safe_buffer_test.rb
@@ -0,0 +1,51 @@
+require 'test_helper'
+
+class SafeBufferTest < ActiveSupport::TestCase
+ def setup
+ @buffer = ActiveSupport::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 not mess with a previously escape test" do
+ @buffer << ERB::Util.html_escape("<script>")
+ assert_equal "&lt;script&gt;", @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 ActiveSupport::SafeBuffer, new_buffer.class
+ end
+
+ test "Should not return a safe buffer when using sub" do
+ assert !@buffer.sub('', "asdf").html_safe?
+ end
+
+ test "Should raise argument error when using sub!" do
+ assert_raise TypeError do
+ @buffer.sub!('', "asdf")
+ end
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/tag_helper_test.rb b/vendor/plugins/rails_xss/test/tag_helper_test.rb
new file mode 100644
index 000000000..2a4280943
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/tag_helper_test.rb
@@ -0,0 +1,21 @@
+require 'test_helper'
+
+class TagHelperTest < ActionView::TestCase
+
+ def test_content_tag
+ 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"),
+ content_tag("a", "Create", :href => "create")
+ assert_equal "<p>&lt;script&gt;evil_js&lt;/script&gt;</p>",
+ content_tag(:p, '<script>evil_js</script>')
+ assert_equal "<p><script>evil_js</script></p>",
+ content_tag(:p, '<script>evil_js</script>', nil, false)
+ end
+
+ def test_tag_honors_html_safe_for_param_values
+ ['1&amp;2', '1 &lt; 2', '&#8220;test&#8220;'].each do |escaped|
+ assert_equal %(<a href="#{escaped}" />), tag('a', :href => escaped.html_safe)
+ end
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/test_helper.rb b/vendor/plugins/rails_xss/test/test_helper.rb
new file mode 100644
index 000000000..d9594e446
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/test_helper.rb
@@ -0,0 +1,6 @@
+abort 'RAILS_ROOT=/path/to/rails/2.3/app rake test' unless ENV['RAILS_ROOT']
+require File.expand_path('config/environment', ENV['RAILS_ROOT'])
+require File.expand_path('../../init', __FILE__)
+require 'active_support/test_case'
+require 'action_view/test_case'
+require 'test/unit'
diff --git a/vendor/plugins/rails_xss/test/text_helper_test.rb b/vendor/plugins/rails_xss/test/text_helper_test.rb
new file mode 100644
index 000000000..b74ae547c
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/text_helper_test.rb
@@ -0,0 +1,30 @@
+require 'test_helper'
+
+class TextHelperTest < ActionView::TestCase
+
+ def setup
+ @controller = Class.new do
+ attr_accessor :request
+ def url_for(*args) "http://www.example.com" end
+ end.new
+ end
+
+ def test_simple_format_with_escaping_html_options
+ assert_dom_equal(%(<p class="intro">It's nice to have options.</p>),
+ simple_format("It's nice to have options.", :class=>"intro"))
+ end
+
+ def test_simple_format_should_not_escape_safe_content
+ assert_dom_equal(%(<p>This is <script>safe_js</script>.</p>),
+ simple_format('This is <script>safe_js</script>.'.html_safe))
+ end
+
+ def test_simple_format_escapes_unsafe_content
+ assert_dom_equal(%(<p>This is &lt;script&gt;evil_js&lt;/script&gt;.</p>),
+ simple_format('This is <script>evil_js</script>.'))
+ end
+
+ def test_truncate_should_not_be_html_safe
+ assert !truncate("Hello World!", :length => 12).html_safe?
+ end
+end
diff --git a/vendor/plugins/rails_xss/test/url_for_test.rb b/vendor/plugins/rails_xss/test/url_for_test.rb
new file mode 100644
index 000000000..b13451bfb
--- /dev/null
+++ b/vendor/plugins/rails_xss/test/url_for_test.rb
@@ -0,0 +1,39 @@
+require 'test_helper'
+
+class UrlHelperTest < ActionView::TestCase
+
+ def abcd(hash = {})
+ hash_for(:a => :b, :c => :d).merge(hash)
+ end
+
+ def hash_for(opts = {})
+ {:controller => "foo", :action => "bar"}.merge(opts)
+ end
+
+ def test_url_for_does_not_escape_urls_if_explicitly_stated
+ assert_equal "/foo/bar?a=b&c=d", url_for(abcd(:escape => false))
+ end
+
+ def test_link_tag_with_img
+ link = link_to("<img src='/favicon.jpg' />".html_safe, "/")
+ expected = %{<a href="/"><img src='/favicon.jpg' /></a>}
+ assert_dom_equal expected, link
+ end
+
+ def test_link_to_should_not_escape_content_for_html_safe
+ link = link_to("Some <p>html</p>".html_safe, "/")
+ expected = %{<a href="/">Some <p>html</p></a>}
+ assert_dom_equal link, expected
+ end
+
+ def test_link_to_escapes_content_for_non_safe
+ link = link_to("Some <p>html</p>", "/")
+ expected = %{<a href="/">Some &lt;p&gt;html&lt;/p&gt;</a>}
+ assert_dom_equal link, expected
+ end
+
+ def test_url_for_escaping_is_safety_aware
+ assert url_for(abcd(:escape => true)).html_safe?, "escaped urls should be html_safe?"
+ assert !url_for(abcd(:escape => false)).html_safe?, "non-escaped urls should not be html_safe?"
+ end
+end