diff options
Diffstat (limited to 'spec')
89 files changed, 3000 insertions, 1651 deletions
diff --git a/spec/controllers/admin_censor_rule_controller_spec.rb b/spec/controllers/admin_censor_rule_controller_spec.rb index fb9ddf594..37ffd9764 100644 --- a/spec/controllers/admin_censor_rule_controller_spec.rb +++ b/spec/controllers/admin_censor_rule_controller_spec.rb @@ -1,20 +1,16 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe AdminCensorRuleController, "when making censor rules from the admin interface" do - integrate_views - before do - basic_auth_login @request - PurgeRequest.destroy_all - end - - + render_views + before { basic_auth_login @request } + it "should create a censor rule and purge the corresponding request from varnish" do - ir = info_requests(:fancy_dog_request) + ir = info_requests(:fancy_dog_request) post :create, :censor_rule => { :text => "meat", :replacement => "tofu", :last_edit_comment => "none", - :info_request => ir + :info_request_id => ir } PurgeRequest.all().first.model_id.should == ir.id end diff --git a/spec/controllers/admin_general_controller_spec.rb b/spec/controllers/admin_general_controller_spec.rb index dc1eb0d97..971960762 100644 --- a/spec/controllers/admin_general_controller_spec.rb +++ b/spec/controllers/admin_general_controller_spec.rb @@ -4,7 +4,7 @@ describe AdminGeneralController do describe "when viewing front page of admin interface" do - integrate_views + render_views before { basic_auth_login @request } it "should render the front page" do @@ -14,8 +14,7 @@ describe AdminGeneralController do it "should redirect to include trailing slash" do get :index - response.should redirect_to(:controller => 'admin_general', - :action => 'index') + response.should redirect_to admin_general_index_url(:trailing_slash => true) end end diff --git a/spec/controllers/admin_public_body_controller_spec.rb b/spec/controllers/admin_public_body_controller_spec.rb index 504ddc5cc..8a72db724 100644 --- a/spec/controllers/admin_public_body_controller_spec.rb +++ b/spec/controllers/admin_public_body_controller_spec.rb @@ -1,16 +1,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe AdminPublicBodyController, "when administering public bodies" do - integrate_views - - before do - @old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new - end - - after do - ActionController::Routing::Routes.filters = @old_filters - end + render_views it "shows the index page" do get :index @@ -38,7 +29,7 @@ describe AdminPublicBodyController, "when administering public bodies" do it "saves edits to a public body" do public_bodies(:humpadink_public_body).name.should == "Department for Humpadinking" post :update, { :id => 3, :public_body => { :name => "Renamed", :short_name => "", :tag_string => "some tags", :request_email => 'edited@localhost', :last_edit_comment => 'From test code' } } - response.flash[:notice].should include('successful') + request.flash[:notice].should include('successful') pb = PublicBody.find(public_bodies(:humpadink_public_body).id) pb.name.should == "Renamed" end @@ -66,7 +57,7 @@ describe AdminPublicBodyController, "when administering public bodies" do it "mass assigns tags" do n = PublicBody.count post :mass_tag_add, { :new_tag => "department", :table_name => "substring" } - response.flash[:notice].should == "Added tag to table of bodies." + request.flash[:notice].should == "Added tag to table of bodies." response.should redirect_to(:action=>'list') PublicBody.find_by_tag("department").count.should == n end @@ -86,8 +77,7 @@ describe AdminPublicBodyController, "when administering public bodies" do before do PublicBody.stub!(:import_csv).and_return([[],[]]) - @file_object = mock("a file upload", :read => 'some contents', - :original_filename => 'contents.txt') + @file_object = fixture_file_upload('/files/fake-authority-type.csv') end it 'should handle a nil csv file param' do @@ -106,7 +96,7 @@ describe AdminPublicBodyController, "when administering public bodies" do it 'should assign the original filename to the view' do post :import_csv, { :csv_file => @file_object, :commit => 'Dry run'} - assigns[:original_csv_file].should == 'contents.txt' + assigns[:original_csv_file].should == 'fake-authority-type.csv' end end @@ -154,7 +144,7 @@ end describe AdminPublicBodyController, "when administering public bodies and paying attention to authentication" do - integrate_views + render_views before do config = MySociety::Config.load_default() @@ -215,6 +205,19 @@ describe AdminPublicBodyController, "when administering public bodies and paying PublicBody.count.should == n - 1 end + it "doesn't let people with good emergency account credentials log in if the emergency user is disabled" do + setup_emergency_credentials('biz', 'fuz') + AlaveteliConfiguration.stub!(:disable_emergency_user).and_return(true) + n = PublicBody.count + basic_auth_login(@request, "biz", "fuz") + post :show, { :id => public_bodies(:humpadink_public_body).id, :emergency => 1} + session[:using_admin].should == nil + n = PublicBody.count + post :destroy, { :id => public_bodies(:forlorn_public_body).id } + session[:using_admin].should == nil + PublicBody.count.should == n + end + it "allows superusers to do stuff" do session[:user_id] = users(:admin_user).id @request.env["HTTP_AUTHORIZATION"] = "" @@ -263,7 +266,7 @@ describe AdminPublicBodyController, "when administering public bodies and paying end describe AdminPublicBodyController, "when administering public bodies with i18n" do - integrate_views + render_views it "shows the index page" do get :index @@ -282,13 +285,13 @@ describe AdminPublicBodyController, "when administering public bodies with i18n" get :edit, {:id => 3, :locale => :en} # When editing a body, the controller returns all available translations - assigns[:public_body].translation("es").name.should == 'El Department for Humpadinking' + assigns[:public_body].find_translation_by_locale("es").name.should == 'El Department for Humpadinking' assigns[:public_body].name.should == 'Department for Humpadinking' response.should render_template('edit') end it "saves edits to a public body" do - PublicBody.with_locale(:es) do + I18n.with_locale(:es) do pb = PublicBody.find(id=3) pb.name.should == "El Department for Humpadinking" post :update, { @@ -304,14 +307,14 @@ describe AdminPublicBodyController, "when administering public bodies with i18n" } } } - response.flash[:notice].should include('successful') + request.flash[:notice].should include('successful') end pb = PublicBody.find(public_bodies(:humpadink_public_body).id) - PublicBody.with_locale(:es) do + I18n.with_locale(:es) do pb.name.should == "Renamed" end - PublicBody.with_locale(:en) do + I18n.with_locale(:en) do pb.name.should == "Department for Humpadinking" end end @@ -325,16 +328,7 @@ describe AdminPublicBodyController, "when administering public bodies with i18n" end describe AdminPublicBodyController, "when creating public bodies with i18n" do - integrate_views - - before do - @old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new - end - - after do - ActionController::Routing::Routes.filters = @old_filters - end + render_views it "creates a new public body in one locale" do n = PublicBody.count @@ -357,12 +351,12 @@ describe AdminPublicBodyController, "when creating public bodies with i18n" do body = PublicBody.find_by_name("New Quango") body.translations.map {|t| t.locale.to_s}.sort.should == ["en", "es"] - PublicBody.with_locale(:en) do + I18n.with_locale(:en) do body.name.should == "New Quango" body.url_name.should == "new_quango" body.first_letter.should == "N" end - PublicBody.with_locale(:es) do + I18n.with_locale(:es) do body.name.should == "Mi Nuevo Quango" body.url_name.should == "mi_nuevo_quango" body.first_letter.should == "M" diff --git a/spec/controllers/admin_request_controller_spec.rb b/spec/controllers/admin_request_controller_spec.rb index 8a3934685..b7b726507 100644 --- a/spec/controllers/admin_request_controller_spec.rb +++ b/spec/controllers/admin_request_controller_spec.rb @@ -1,16 +1,11 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe AdminRequestController, "when administering requests" do - integrate_views + render_views before { basic_auth_login @request } before(:each) do load_raw_emails_data - @old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new - end - after do - ActionController::Routing::Routes.filters = @old_filters end it "shows the index/list page" do @@ -39,7 +34,7 @@ describe AdminRequestController, "when administering requests" do :awaiting_description => false, :allow_new_responses_from => 'anybody', :handle_rejected_responses => 'bounce' } } - response.flash[:notice].should include('successful') + request.flash[:notice].should include('successful') ir = InfoRequest.find(info_requests(:fancy_dog_request).id) ir.title.should == "Renamed" end @@ -64,7 +59,7 @@ describe AdminRequestController, "when administering requests" do it "saves edits to an outgoing_message" do outgoing_messages(:useless_outgoing_message).body.should include("fancy dog") post :update_outgoing, { :id => outgoing_messages(:useless_outgoing_message), :outgoing_message => { :body => "Why do you have such a delicious cat?" } } - response.flash[:notice].should include('successful') + request.flash[:notice].should include('successful') ir = OutgoingMessage.find(outgoing_messages(:useless_outgoing_message).id) ir.body.should include("delicious cat") end @@ -82,15 +77,10 @@ describe AdminRequestController, "when administering requests" do end describe AdminRequestController, "when administering the holding pen" do - integrate_views + render_views before(:each) do basic_auth_login @request load_raw_emails_data - @old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new - end - after do - ActionController::Routing::Routes.filters = @old_filters end it "shows a rejection reason for an incoming message from an invalid address" do @@ -100,7 +90,7 @@ describe AdminRequestController, "when administering the holding pen" do ir.save! receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "frob@nowhere.com") get :show_raw_email, :id => InfoRequest.holding_pen_request.get_last_response.raw_email.id - response.should have_text(/Only the authority can reply to this request/) + response.should contain "Only the authority can reply to this request" end it "allows redelivery even to a closed request" do @@ -164,7 +154,7 @@ describe AdminRequestController, "when administering the holding pen" do receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "") InfoRequest.holding_pen_request.incoming_messages.length.should == 2 get :show_raw_email, :id => interesting_email - response.should have_text(/Could not identify the request/) + response.should contain "Could not identify the request" assigns[:info_requests][0].should == ir end @@ -260,13 +250,13 @@ describe AdminRequestController, "when administering the holding pen" do end it 'should not send a notification email' do - ContactMailer.should_not_receive(:deliver_from_admin_message) + ContactMailer.should_not_receive(:from_admin_message) make_request end it 'should add a notice to the flash saying that the request has been hidden' do make_request - response.flash[:notice].should == "This external request has been hidden" + request.flash[:notice].should == "This external request has been hidden" end it 'should expire the file cache for the request' do diff --git a/spec/controllers/admin_track_controller_spec.rb b/spec/controllers/admin_track_controller_spec.rb index 728c79f1f..f2de6c0d3 100644 --- a/spec/controllers/admin_track_controller_spec.rb +++ b/spec/controllers/admin_track_controller_spec.rb @@ -1,7 +1,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe AdminTrackController, "when administering tracks" do - integrate_views + render_views it "shows the list page" do get :list diff --git a/spec/controllers/admin_user_controller_spec.rb b/spec/controllers/admin_user_controller_spec.rb index cf3665c9f..a6e5a0d7e 100644 --- a/spec/controllers/admin_user_controller_spec.rb +++ b/spec/controllers/admin_user_controller_spec.rb @@ -1,7 +1,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe AdminUserController, "when administering users" do - integrate_views + render_views it "shows the index/list page" do get :index diff --git a/spec/controllers/api_controller_spec.rb b/spec/controllers/api_controller_spec.rb index 1c320f85c..66b8e33f0 100644 --- a/spec/controllers/api_controller_spec.rb +++ b/spec/controllers/api_controller_spec.rb @@ -7,7 +7,7 @@ def normalise_whitespace(s) return s end -Spec::Matchers.define :be_equal_modulo_whitespace_to do |expected| +RSpec::Matchers.define :be_equal_modulo_whitespace_to do |expected| match do |actual| normalise_whitespace(actual) == normalise_whitespace(expected) end @@ -173,7 +173,7 @@ describe ApiController, "when using the API" do "body" => "xxx" }.to_json - response.status.should == "500 Internal Server Error" + response.status.should == 500 ActiveSupport::JSON.decode(response.body)["errors"].should == [ "Request #{request_id} cannot be updated using the API"] @@ -195,7 +195,7 @@ describe ApiController, "when using the API" do "body" => "xxx" }.to_json - response.status.should == "500 Internal Server Error" + response.status.should == 500 ActiveSupport::JSON.decode(response.body)["errors"].should == [ "You do not own request #{request_id}"] @@ -213,12 +213,12 @@ describe ApiController, "when using the API" do "body" => "Are you joking, or are you serious?" }.to_json, :attachments => [ - fixture_file_upload("files/tfl.pdf") + fixture_file_upload("/files/tfl.pdf") ] # Make sure it worked - response.status.to_i.should == 500 + response.status.should == 500 errors = ActiveSupport::JSON.decode(response.body)["errors"] errors.should == ["You cannot attach files to messages in the 'request' direction"] end @@ -242,7 +242,7 @@ describe ApiController, "when using the API" do "body" => response_body }.to_json, :attachments => [ - fixture_file_upload("files/tfl.pdf") + fixture_file_upload("/files/tfl.pdf") ] # And make sure it worked @@ -259,7 +259,7 @@ describe ApiController, "when using the API" do attachments.size.should == 1 attachment = attachments[0] attachment.filename.should == "tfl.pdf" - attachment.body.should == load_file_fixture("tfl.pdf", as_binary=true) + attachment.body.should == load_file_fixture("tfl.pdf") end it "should show information about a request" do @@ -286,7 +286,7 @@ describe ApiController, "when using the API" do :feed_type => "atom" response.should be_success - response.should render_template("api/request_events.atom") + response.should render_template("api/request_events") assigns[:events].size.should > 0 assigns[:events].each do |event| event.info_request.public_body.should == public_bodies(:geraldine_public_body) @@ -341,7 +341,7 @@ describe ApiController, "when using the API" do :feed_type => "atom" response.should be_success - response.should render_template("api/request_events.atom") + response.should render_template("api/request_events") assigns[:events].size.should > 0 assigns[:events].each do |event| event.created_at.should >= Date.new(2010, 1, 1) @@ -360,7 +360,7 @@ describe ApiController, "when using the API" do "sent_at" => sent_at, "body" => response_body }.to_json - response.status.should == "404 Not Found" + response.status.should == 404 ActiveSupport::JSON.decode(response.body)["errors"].should == ["Could not find request 123459876"] end @@ -376,7 +376,7 @@ describe ApiController, "when using the API" do "sent_at" => sent_at, "body" => response_body }.to_json - response.status.should == "500 Internal Server Error" + response.status.should == 500 ActiveSupport::JSON.decode(response.body)["errors"].should == ["Request #{request_id} cannot be updated using the API"] end end diff --git a/spec/controllers/comment_controller_spec.rb b/spec/controllers/comment_controller_spec.rb index 4a7acee23..c03615ce2 100644 --- a/spec/controllers/comment_controller_spec.rb +++ b/spec/controllers/comment_controller_spec.rb @@ -1,7 +1,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe CommentController, "when commenting on a request" do - integrate_views + render_views it "should give an error and render 'new' template when body text is just some whitespace" do post :new, :url_title => info_requests(:naughty_chicken_request).url_title, diff --git a/spec/controllers/general_controller_spec.rb b/spec/controllers/general_controller_spec.rb index 642ed0e05..bce12248b 100644 --- a/spec/controllers/general_controller_spec.rb +++ b/spec/controllers/general_controller_spec.rb @@ -12,30 +12,39 @@ describe GeneralController, "when trying to show the blog" do it "should fail silently if the blog is returning an error" do FakeWeb.register_uri(:get, %r|.*|, :body => "Error", :status => ["500", "Error"]) get :blog - response.status.should == "200 OK" + response.status.should == 200 assigns[:blog_items].count.should == 0 end end describe GeneralController, 'when getting the blog feed' do + before do + AlaveteliConfiguration.stub!(:blog_feed).and_return("http://blog.example.com") + end + it 'should add a lang param correctly to a url with no querystring' do - Configuration.stub!(:blog_feed).and_return("http://blog.example.com") get :blog assigns[:feed_url].should == "http://blog.example.com?lang=en" end it 'should add a lang param correctly to a url with an existing querystring' do - Configuration.stub!(:blog_feed).and_return("http://blog.example.com?alt=rss") + AlaveteliConfiguration.stub!(:blog_feed).and_return("http://blog.example.com?alt=rss") get :blog assigns[:feed_url].should == "http://blog.example.com?alt=rss&lang=en" end + it 'should parse an item from an example feed' do + controller.stub!(:quietly_try_to_open).and_return(load_file_fixture("blog_feed.atom")) + get :blog + assigns[:blog_items].count.should == 1 + end + end describe GeneralController, "when showing the frontpage" do - integrate_views + render_views before do public_body = mock_model(PublicBody, :name => "Example Public Body", @@ -58,14 +67,14 @@ describe GeneralController, "when showing the frontpage" do it "should render the front page with default language" do get :frontpage - response.should have_tag('html[lang="en"]') + response.should have_selector('html[lang="en"]') end it "should render the front page with default language" do old_default_locale = I18n.default_locale I18n.default_locale = "es" get :frontpage - response.should have_tag('html[lang="es"]') + response.should have_selector('html[lang="es"]') I18n.default_locale = old_default_locale end @@ -77,7 +86,7 @@ describe GeneralController, "when showing the frontpage" do old_default_locale = I18n.default_locale I18n.default_locale = "es" get :frontpage - response.should have_tag('html[lang="es"]') + response.should have_selector('html[lang="es"]') I18n.default_locale = old_default_locale end @@ -87,7 +96,7 @@ describe GeneralController, "when showing the frontpage" do accept_language = "es-ES,en-GB,en-US;q=0.8,en;q=0.6" request.env['HTTP_ACCEPT_LANGUAGE'] = accept_language get :frontpage - response.should have_tag('html[lang="es"]') + response.should have_selector('html[lang="es"]') request.env['HTTP_ACCEPT_LANGUAGE'] = nil end @@ -104,11 +113,11 @@ describe GeneralController, "when showing the frontpage" do before do @default_lang_home_link = /href=".*\/en\// @other_lang_home_link = /href=".*\/es\// - @old_include_default_locale_in_urls = Configuration::include_default_locale_in_urls + @old_include_default_locale_in_urls = AlaveteliConfiguration::include_default_locale_in_urls end def set_default_locale_in_urls(value) - Configuration.stub!(:include_default_locale_in_urls).and_return(value) + AlaveteliConfiguration.stub!(:include_default_locale_in_urls).and_return(value) load Rails.root.join("config/initializers/fast_gettext.rb") end @@ -120,13 +129,13 @@ describe GeneralController, "when showing the frontpage" do it 'should generate URLs without a locale prepended' do get :frontpage - response.should_not have_text(@default_lang_home_link) + response.should_not contain @default_lang_home_link end it 'should render the front page in the default language when no locale param is present and the session locale is not the default' do get(:frontpage, {}, {:locale => 'es'}) - response.should_not have_text(@other_lang_home_link) + response.should_not contain @other_lang_home_link end end @@ -134,7 +143,7 @@ describe GeneralController, "when showing the frontpage" do INCLUDE_DEFAULT_LOCALE_IN_URLS is true' do set_default_locale_in_urls(true) get :frontpage - response.should have_text(@default_lang_home_link) + response.body.should match /#{@default_lang_home_link}/ end after do @@ -150,28 +159,28 @@ describe GeneralController, "when showing the frontpage" do it "should generate URLs with a locale prepended when there's more than one locale set" do get :frontpage - response.should have_text(home_link_regex) + response.body.should match home_link_regex end it "should use our test PO files rather than the application one" do I18n.default_locale = :es get :frontpage - response.should have_text(/XOXO/) + response.body.should match /XOXO/ I18n.default_locale = :en end it "should generate URLs that include the locale when using one that includes an underscore" do I18n.default_locale = :"en_GB" get :frontpage - response.should have_text(/href="\/en_GB\//) + response.body.should match /href="\/en_GB\// I18n.default_locale = :en end it "should fall back to the language if the territory is unknown" do I18n.default_locale = :"en_US" get :frontpage - response.should have_text(/href="\/en\//) - response.should_not have_text(/href="\/en_US\//) + response.body.should match /href="\/en\// + response.body.should_not match /href="\/en_US\// I18n.default_locale = :en end @@ -181,7 +190,7 @@ describe GeneralController, "when showing the frontpage" do FastGettext.default_available_locales = I18n.available_locales = ['en'] get :frontpage - response.should_not have_text(home_link_regex) + response.should_not contain home_link_regex FastGettext.default_available_locales = old_fgt_available_locales I18n.available_locales = old_i18n_available_locales @@ -235,7 +244,7 @@ end describe GeneralController, 'when using xapian search' do - integrate_views + render_views # rebuild xapian index after fixtures loaded before(:each) do @@ -249,7 +258,7 @@ describe GeneralController, 'when using xapian search' do end it "should find info request when searching for '\"fancy dog\"'" do - get :search, :combined => ['"fancy dog"'] + get :search, :combined => '"fancy dog"' response.should render_template('search') assigns[:xapian_requests].matches_estimated.should == 1 assigns[:xapian_requests].results.size.should == 1 @@ -259,7 +268,7 @@ describe GeneralController, 'when using xapian search' do end it "should find public body and incoming message when searching for 'geraldine quango'" do - get :search, :combined => ['geraldine quango'] + get :search, :combined => 'geraldine quango' response.should render_template('search') assigns[:xapian_requests].matches_estimated.should == 1 @@ -272,7 +281,7 @@ describe GeneralController, 'when using xapian search' do end it "should filter results based on end of URL being 'all'" do - get :search, :combined => ['"bob"', "all"] + get :search, :combined => "bob/all" assigns[:xapian_requests].results.map{|x| x[:model]}.should =~ [ info_request_events(:useless_outgoing_message_event), info_request_events(:silly_outgoing_message_event), @@ -284,14 +293,14 @@ describe GeneralController, 'when using xapian search' do end it "should filter results based on end of URL being 'users'" do - get :search, :combined => ['"bob"', "users"] + get :search, :combined => "bob/users" assigns[:xapian_requests].should == nil assigns[:xapian_users].results.map{|x| x[:model]}.should == [users(:bob_smith_user)] assigns[:xapian_bodies].should == nil end it "should filter results based on end of URL being 'requests'" do - get :search, :combined => ['"bob"', "requests"] + get :search, :combined => "bob/requests" assigns[:xapian_requests].results.map{|x|x[:model]}.should =~ [ info_request_events(:useless_outgoing_message_event), info_request_events(:silly_outgoing_message_event), @@ -303,7 +312,7 @@ describe GeneralController, 'when using xapian search' do end it "should filter results based on end of URL being 'bodies'" do - get :search, :combined => ['"quango"', "bodies"] + get :search, :combined => "quango/bodies" assigns[:xapian_requests].should == nil assigns[:xapian_users].should == nil assigns[:xapian_bodies].results.map{|x|x[:model]}.should == [public_bodies(:geraldine_public_body)] @@ -317,7 +326,7 @@ describe GeneralController, 'when using xapian search' do end it "should not show unconfirmed users" do - get :search, :combined => ["unconfirmed", "users"] + get :search, :combined => "unconfirmed/users" response.should render_template('search') assigns[:xapian_users].results.map{|x|x[:model]}.should == [] end @@ -328,15 +337,14 @@ describe GeneralController, 'when using xapian search' do u.save! update_xapian_index - get :search, :combined => ["unconfirmed", "users"] + get :search, :combined => "unconfirmed/users" response.should render_template('search') assigns[:xapian_users].results.map{|x|x[:model]}.should == [u] end it "should show tracking links for requests-only searches" do - get :search, :combined => ['"bob"', "requests"] + get :search, :combined => "bob/requests" response.body.should include('Track this search') end end - diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index 28fd08c80..c47e1abd3 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -1,8 +1,9 @@ +# -*- coding: utf-8 -*- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe HelpController, "when using help" do - integrate_views - + render_views + it "shows the about page" do get :about end @@ -12,7 +13,7 @@ describe HelpController, "when using help" do end it "sends a contact message" do - post :contact, { :contact => { + post :contact, { :contact => { :name => "Vinny Vanilli", :email => "vinny@localhost", :subject => "Why do I have such an ace name?", @@ -27,5 +28,27 @@ describe HelpController, "when using help" do deliveries.clear end + describe 'when requesting a page in a supported locale ' do + + before do + # Allow us to supply the locale manually + RoutingFilter.active = false + # Prepend our fixture templates + fixture_theme_path = File.join(Rails.root, 'spec', 'fixtures', 'theme_views', 'theme_one') + controller.prepend_view_path fixture_theme_path + end + + after do + RoutingFilter.active = true + end + + it 'should render the locale-specific template if available' do + get :contact, {:locale => 'es'} + response.body.should match('contáctenos theme one') + end + + end + + end diff --git a/spec/controllers/public_body_controller_spec.rb b/spec/controllers/public_body_controller_spec.rb index 5f4012737..22d8418c9 100644 --- a/spec/controllers/public_body_controller_spec.rb +++ b/spec/controllers/public_body_controller_spec.rb @@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe PublicBodyController, "when showing a body" do - integrate_views + render_views before(:each) do load_raw_emails_data @@ -43,33 +43,28 @@ describe PublicBodyController, "when showing a body" do :conditions => ["public_body_id = ?", public_bodies(:humpadink_public_body).id]) end - it "should assign the body using different locale from that used for url_name" do - PublicBody.with_locale(:es) do - get :show, {:url_name => "dfh", :view => 'all'} - assigns[:public_body].notes.should == "Baguette" - end + it "should redirect to the canonical name in the chosen locale" do + get :show, {:url_name => "dfh", :view => 'all', :show_locale => "es"} + response.should redirect_to "http://test.host/es/body/edfh" end it "should assign the body using same locale as that used in url_name" do - PublicBody.with_locale(:es) do - get :show, {:url_name => "edfh", :view => 'all'} - assigns[:public_body].notes.should == "Baguette" - end + get :show, {:url_name => "edfh", :view => 'all', :show_locale => "es"} + response.should contain("Baguette") end it "should redirect use to the relevant locale even when url_name is for a different locale" do - old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new + RoutingFilter.active = false get :show, {:url_name => "edfh", :view => 'all'} response.should redirect_to "http://test.host/body/dfh" - ActionController::Routing::Routes.filters = old_filters + RoutingFilter.active = true end it "should remember the filter (view) setting on redirecting" do get :show, :show_locale => "es", :url_name => "tgq", :view => 'successful' - response.should redirect_to show_public_body_successful_url(:url_name => "etgq") + response.should redirect_to 'http://test.host/es/body/etgq/successful' end it "should redirect to newest name if you use historic name of public body in URL" do @@ -84,7 +79,7 @@ describe PublicBodyController, "when showing a body" do end describe PublicBodyController, "when listing bodies" do - integrate_views + render_views it "should be successful" do get :list @@ -92,7 +87,7 @@ describe PublicBodyController, "when listing bodies" do end it "should list all bodies from default locale, even when there are no translations for selected locale" do - PublicBody.with_locale(:en) do + I18n.with_locale(:en) do @english_only = PublicBody.new(:name => 'English only', :short_name => 'EO', :request_email => 'english@flourish.org', @@ -100,7 +95,7 @@ describe PublicBodyController, "when listing bodies" do :last_edit_comment => '') @english_only.save end - PublicBody.with_locale(:es) do + I18n.with_locale(:es) do get :list assigns[:public_bodies].include?(@english_only).should == true end @@ -112,9 +107,12 @@ describe PublicBodyController, "when listing bodies" do response.should render_template('list') - assigns[:public_bodies].should == PublicBody.all( - :conditions => "id <> #{PublicBody.internal_admin_body.id}", - :order => "(select name from public_body_translations where public_body_id=public_bodies.id and locale='en')") + assigns[:public_bodies].should == [ public_bodies(:other_public_body), + public_bodies(:humpadink_public_body), + public_bodies(:forlorn_public_body), + public_bodies(:geraldine_public_body), + public_bodies(:sensible_walks_public_body), + public_bodies(:silly_walks_public_body) ] assigns[:tag].should == "all" assigns[:description].should == "" end @@ -152,11 +150,20 @@ describe PublicBodyController, "when listing bodies" do get :list, :tag => "other" response.should render_template('list') - assigns[:public_bodies].should =~ PublicBody.all(:conditions => "id not in (#{public_bodies(:humpadink_public_body).id}, #{PublicBody.internal_admin_body.id})") + assigns[:public_bodies].should == [ public_bodies(:other_public_body), + public_bodies(:forlorn_public_body), + public_bodies(:geraldine_public_body), + public_bodies(:sensible_walks_public_body), + public_bodies(:silly_walks_public_body) ] get :list response.should render_template('list') - assigns[:public_bodies].should =~ PublicBody.all(:conditions => "id <> #{PublicBody.internal_admin_body.id}") + assigns[:public_bodies].should == [ public_bodies(:other_public_body), + public_bodies(:humpadink_public_body), + public_bodies(:forlorn_public_body), + public_bodies(:geraldine_public_body), + public_bodies(:sensible_walks_public_body), + public_bodies(:silly_walks_public_body) ] end it "should list a machine tagged thing, should get it in both ways" do @@ -198,7 +205,7 @@ end describe PublicBodyController, "when doing type ahead searches" do - integrate_views + render_views before(:each) do load_raw_emails_data diff --git a/spec/controllers/reports_controller_spec.rb b/spec/controllers/reports_controller_spec.rb new file mode 100644 index 000000000..fa8c72eaa --- /dev/null +++ b/spec/controllers/reports_controller_spec.rb @@ -0,0 +1,104 @@ +require 'spec_helper' + +describe ReportsController, "when reporting a request when not logged in" do + it "should only allow logged-in users to report requests" do + post :create, :request_id => info_requests(:badger_request).url_title, :reason => "my reason" + + flash[:notice].should =~ /You need to be logged in/ + response.should redirect_to show_request_path(:url_title => info_requests(:badger_request).url_title) + end +end + +describe ReportsController, "when reporting a request (logged in)" do + render_views + + before do + @user = users(:robin_user) + session[:user_id] = @user.id + end + + it "should 404 for non-existent requests" do + lambda { + post :create, :request_id => "hjksfdhjk_louytu_qqxxx" + }.should raise_error(ActiveRecord::RecordNotFound) + end + + it "should mark a request as having been reported" do + ir = info_requests(:badger_request) + title = ir.url_title + ir.attention_requested.should == false + + post :create, :request_id => title, :reason => "my reason" + response.should redirect_to show_request_path(:url_title => title) + + ir.reload + ir.attention_requested.should == true + ir.described_state.should == "attention_requested" + end + + it "should pass on the reason and message" do + info_request = mock_model(InfoRequest, :url_title => "foo", :attention_requested= => nil, :save! => nil) + InfoRequest.should_receive(:find_by_url_title!).with("foo").and_return(info_request) + info_request.should_receive(:report!).with("Not valid request", "It's just not", @user) + post :create, :request_id => "foo", :reason => "Not valid request", :message => "It's just not" + end + + it "should not allow a request to be reported twice" do + title = info_requests(:badger_request).url_title + + post :create, :request_id => title, :reason => "my reason" + response.should redirect_to show_request_url(:url_title => title) + + post :create, :request_id => title, :reason => "my reason" + response.should redirect_to show_request_url(:url_title => title) + flash[:notice].should =~ /has already been reported/ + end + + it "should send an email from the reporter to admins" do + ir = info_requests(:badger_request) + title = ir.url_title + post :create, :request_id => title, :reason => "my reason" + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.subject.should =~ /attention_requested/ + mail.from.should include(@user.email) + mail.body.should include(@user.name) + end + + it "should force the user to pick a reason" do + info_request = mock_model(InfoRequest, :report! => nil, :url_title => "foo", + :report_reasons => ["Not FOIish enough"]) + InfoRequest.should_receive(:find_by_url_title!).with("foo").and_return(info_request) + + post :create, :request_id => "foo", :reason => "" + response.should render_template("new") + flash[:error].should == "Please choose a reason" + end +end + +describe ReportsController, "#new_report_request" do + let(:info_request) { mock_model(InfoRequest, :url_title => "foo") } + before :each do + InfoRequest.should_receive(:find_by_url_title!).with("foo").and_return(info_request) + end + + context "not logged in" do + it "should require the user to be logged in" do + get :new, :request_id => "foo" + response.should_not render_template("new") + end + end + + context "logged in" do + before :each do + session[:user_id] = users(:bob_smith_user).id + end + it "should show the form" do + get :new, :request_id => "foo" + response.should render_template("new") + end + end +end + + diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index 21dd0853a..c73576c50 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -2,7 +2,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe RequestController, "when listing recent requests" do - before(:each) do load_raw_emails_data get_fixtures_xapian_index @@ -90,12 +89,14 @@ describe RequestController, "when listing recent requests" do end it "should assign the first page of results" do - xap_results = mock_model(ActsAsXapian::Search, + xap_results = mock(ActsAsXapian::Search, :results => (1..25).to_a.map { |m| { :model => m } }, :matches_estimated => 1000000) - InfoRequest.should_receive(:full_search). - with([InfoRequestEvent]," (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)", "created_at", anything, anything, anything, anything). + ActsAsXapian::Search.should_receive(:new). + with([InfoRequestEvent]," (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)", + :sort_by_prefix => "created_at", :offset => 0, :limit => 25, :sort_by_ascending => true, + :collapse_by_prefix => "request_collapse"). and_return(xap_results) get :list, :view => 'all' assigns[:list_results].size.should == 25 @@ -103,7 +104,7 @@ describe RequestController, "when listing recent requests" do end it "should return 404 for pages we don't want to serve up" do - xap_results = mock_model(ActsAsXapian::Search, + xap_results = mock(ActsAsXapian::Search, :results => (1..25).to_a.map { |m| { :model => m } }, :matches_estimated => 1000000) lambda { @@ -120,10 +121,7 @@ describe RequestController, "when listing recent requests" do end describe RequestController, "when changing things that appear on the request page" do - - before do - PurgeRequest.destroy_all - end + render_views it "should purge the downstream cache when mail is received" do ir = info_requests(:fancy_dog_request) @@ -138,7 +136,7 @@ describe RequestController, "when changing things that appear on the request pag it "should purge the downstream cache when a followup is made" do session[:user_id] = users(:bob_smith_user).id ir = info_requests(:fancy_dog_request) - post :show_response, :outgoing_message => { :body => "What a useless response! You suck.", :what_doing => 'normal_sort' }, :id => ir.id, :incoming_message_id => incoming_messages(:useless_incoming_message), :submitted_followup => 1 + post :show_response, :outgoing_message => { :body => "What a useless response! You suck.", :what_doing => 'normal_sort' }, :id => ir.id, :submitted_followup => 1 PurgeRequest.all().first.model_id.should == ir.id end it "should purge the downstream cache when the request is categorised" do @@ -189,7 +187,7 @@ describe RequestController, "when changing things that appear on the request pag end describe RequestController, "when showing one request" do - integrate_views + render_views before(:each) do load_raw_emails_data @@ -218,20 +216,20 @@ describe RequestController, "when showing one request" do end it "should redirect from a numeric URL to pretty one" do - get :show, :url_title => info_requests(:naughty_chicken_request).id + get :show, :url_title => info_requests(:naughty_chicken_request).id.to_s response.should redirect_to(:action => 'show', :url_title => info_requests(:naughty_chicken_request).url_title) end it 'should show actions the request owner can take' do get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' - response.should have_tag('div#owner_actions') + response.should have_selector('div#owner_actions') end describe 'when the request does allow comments' do it 'should have a comment link' do get :show, { :url_title => 'why_do_you_have_such_a_fancy_dog' }, { :user_id => users(:admin_user).id } - response.should have_tag('#anyone_actions', /Add an annotation/) + response.should have_selector('#anyone_actions', :content => "Add an annotation") end end @@ -239,10 +237,40 @@ describe RequestController, "when showing one request" do it 'should not have a comment link' do get :show, { :url_title => 'spam_1' }, { :user_id => users(:admin_user).id } - response.should_not have_tag('#anyone_actions', /Add an annotation/) + response.should_not have_selector('#anyone_actions', :content => "Add an annotation") end end + context "when the request has not yet been reported" do + it "should allow the user to report" do + title = info_requests(:badger_request).url_title + get :show, :url_title => title + response.should_not contain("This request has been reported") + response.should contain("Offensive?") + end + end + + context "when the request has been reported for admin attention" do + before :each do + info_requests(:fancy_dog_request).report!("", "", nil) + end + it "should inform the user" do + get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' + response.should contain("This request has been reported") + response.should_not contain("Offensive?") + end + + context "and then deemed okay and left to complete" do + before :each do + info_requests(:fancy_dog_request).set_described_state("successful") + end + it "should let the user know that the administrators have not hidden this request" do + get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' + response.body.should =~ (/the site administrators.*have not hidden it/) + end + end + end + describe 'when the request is being viewed by an admin' do describe 'if the request is awaiting description' do @@ -256,13 +284,13 @@ describe RequestController, "when showing one request" do it 'should show the describe state form' do get :show, { :url_title => 'why_do_you_have_such_a_fancy_dog' }, { :user_id => users(:admin_user).id } - response.should have_tag('div.describe_state_form') + response.should have_selector('div.describe_state_form') end it 'should ask the user to use the describe state from' do get :show, { :url_title => 'why_do_you_have_such_a_fancy_dog' }, { :user_id => users(:admin_user).id } - response.should have_tag('p#request_status', :text => /answer the question above/) + response.should have_selector('p#request_status', :content => "answer the question above") end end @@ -280,7 +308,7 @@ describe RequestController, "when showing one request" do it 'should give a link to requesting an internal review' do get :show, { :url_title => 'why_do_you_have_such_a_fancy_dog' }, { :user_id => users(:admin_user).id } - response.should have_tag('p#request_status', :text =>/requesting an internal review/) + response.should have_selector('p#request_status', :content => "requesting an internal review") end end @@ -298,7 +326,7 @@ describe RequestController, "when showing one request" do it 'should give a link to make a followup' do get :show, { :url_title => 'why_do_you_have_such_a_fancy_dog' }, { :user_id => users(:admin_user).id } - response.should have_tag('p#request_status a', :text =>/send a follow up message/) + response.should have_selector('p#request_status a', :content => "send a follow up message") end end @@ -315,7 +343,7 @@ describe RequestController, "when showing one request" do it 'should not display actions the request owner can take' do get :show, :url_title => 'balalas' - response.should_not have_tag('div#owner_actions') + response.should_not have_selector('div#owner_actions') end end @@ -341,12 +369,12 @@ describe RequestController, "when showing one request" do it 'should not show the describe state form' do make_request - response.should_not have_tag('div.describe_state_form') + response.should_not have_selector('div.describe_state_form') end it 'should not ask the user to use the describe state form' do make_request - response.should_not have_tag('p#request_status', :text => /answer the question above/) + response.should_not have_selector('p#request_status', :content => "answer the question above") end end @@ -363,7 +391,7 @@ describe RequestController, "when showing one request" do it 'should not give a link to requesting an internal review' do make_request - response.should_not have_tag('p#request_status', :text =>/requesting an internal review/) + response.should_not have_selector('p#request_status', :content => "requesting an internal review") end end @@ -379,12 +407,12 @@ describe RequestController, "when showing one request" do it 'should not give a link to make a followup' do make_request - response.should_not have_tag('p#request_status a', :text =>/send a follow up message/) + response.should_not have_selector('p#request_status a', :content => "send a follow up message") end it 'should not give a link to sign in (in the request status paragraph)' do make_request - response.should_not have_tag('p#request_status a', :text => /sign in/) + response.should_not have_selector('p#request_status a', :content => "sign in") end end @@ -447,7 +475,7 @@ describe RequestController, "when showing one request" do describe 'when handling incoming mail' do - integrate_views + render_views it "should receive incoming messages, send email to creator, and show them" do ir = info_requests(:fancy_dog_request) @@ -481,13 +509,13 @@ describe RequestController, "when showing one request" do (assigns[:info_request_events].size - size_before).should == 1 ir.reload - get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1 + get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'hello world.txt', :skip_cache => 1 response.content_type.should == "text/plain" - response.should have_text(/Second hello/) + response.should contain "Second hello" - get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 3, :file_name => ['hello.txt'], :skip_cache => 1 + get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 3, :file_name => 'hello world.txt', :skip_cache => 1 response.content_type.should == "text/plain" - response.should have_text(/First hello/) + response.should contain "First hello" end it 'should cache an attachment on a request with normal prominence' do @@ -498,24 +526,23 @@ describe RequestController, "when showing one request" do get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, - :file_name => ['hello.txt'] - + :file_name => 'hello world.txt' end it "should convert message body to UTF8" do ir = info_requests(:fancy_dog_request) receive_incoming_mail('iso8859_2_raw_email.email', ir.incoming_email) get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' - response.should have_text(/tënde/u) + response.should contain "tënde" end it "should generate valid HTML verson of plain text attachments" do ir = info_requests(:fancy_dog_request) receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email) ir.reload - get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1 + get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'hello world.txt.html', :skip_cache => 1 response.content_type.should == "text/html" - response.should have_text(/Second hello/) + response.should contain "Second hello" end # This is a regression test for a bug where URLs of this form were causing 500 errors @@ -534,11 +561,11 @@ describe RequestController, "when showing one request" do ir.reload ugly_id = "55195" lambda { - get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1 + get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => 'hello world.txt.html', :skip_cache => 1 }.should raise_error(ActiveRecord::RecordNotFound) lambda { - get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1 + get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => 'hello world.txt', :skip_cache => 1 }.should raise_error(ActiveRecord::RecordNotFound) end it "should return 404 when incoming message and request ids don't match" do @@ -547,7 +574,7 @@ describe RequestController, "when showing one request" do receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email) ir.reload lambda { - get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => wrong_id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1 + get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => wrong_id, :part => 2, :file_name => 'hello world.txt.html', :skip_cache => 1 }.should raise_error(ActiveRecord::RecordNotFound) end it "should return 404 for ugly URLs contain a request id that isn't an integer, even if the integer prefix refers to an actual request" do @@ -557,11 +584,11 @@ describe RequestController, "when showing one request" do ugly_id = "%d95" % [info_requests(:naughty_chicken_request).id] lambda { - get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1 + get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => 'hello world.txt.html', :skip_cache => 1 }.should raise_error(ActiveRecord::RecordNotFound) lambda { - get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1 + get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => 'hello world.txt', :skip_cache => 1 }.should raise_error(ActiveRecord::RecordNotFound) end it "should return 404 when incoming message and request ids don't match" do @@ -570,7 +597,7 @@ describe RequestController, "when showing one request" do receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email) ir.reload lambda { - get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => wrong_id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1 + get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => wrong_id, :part => 2, :file_name => 'hello world.txt.html', :skip_cache => 1 }.should raise_error(ActiveRecord::RecordNotFound) end @@ -578,41 +605,64 @@ describe RequestController, "when showing one request" do ir = info_requests(:fancy_dog_request) receive_incoming_mail('incoming-request-pdf-attachment.email', ir.incoming_email) ir.reload - get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['fs_50379341.pdf.html'], :skip_cache => 1 + get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'fs 50379341.pdf.html', :skip_cache => 1 response.content_type.should == "text/html" - response.should have_text(/Walberswick Parish Council/) + response.should contain "Walberswick Parish Council" end - it "should not cause a reparsing of the raw email, even when the result would be a 404" do + it "should not cause a reparsing of the raw email, even when the attachment can't be found" do ir = info_requests(:fancy_dog_request) receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email) ir.reload - attachment = IncomingMessage.get_attachment_by_url_part_number(ir.incoming_messages[1].get_attachments_for_display, 2) - attachment.body.should have_text(/Second hello/) + attachment = IncomingMessage.get_attachment_by_url_part_number_and_filename(ir.incoming_messages[1].get_attachments_for_display, 2, 'hello world.txt') + attachment.body.should contain "Second hello" # change the raw_email associated with the message; this only be reparsed when explicitly asked for ir.incoming_messages[1].raw_email.data = ir.incoming_messages[1].raw_email.data.sub("Second", "Third") - # asking for an attachment by the wrong filename results - # in a 404 for browsing users. This shouldn't cause a - # re-parse... - lambda { - get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt.baz.html'], :skip_cache => 1 - }.should raise_error(ActiveRecord::RecordNotFound) + # asking for an attachment by the wrong filename should result in redirecting + # back to the incoming message, but shouldn't cause a reparse: + get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'hello world.txt.baz.html', :skip_cache => 1 + response.status.should == 303 - attachment = IncomingMessage.get_attachment_by_url_part_number(ir.incoming_messages[1].get_attachments_for_display, 2) - attachment.body.should have_text(/Second hello/) + attachment = IncomingMessage.get_attachment_by_url_part_number_and_filename(ir.incoming_messages[1].get_attachments_for_display, 2, 'hello world.txt') + attachment.body.should contain "Second hello" # ...nor should asking for it by its correct filename... - get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1 - response.should_not have_text(/Third hello/) + get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'hello world.txt.html', :skip_cache => 1 + response.should_not contain "Third hello" # ...but if we explicitly ask for attachments to be extracted, then they should be force = true ir.incoming_messages[1].parse_raw_email!(force) - attachment = IncomingMessage.get_attachment_by_url_part_number(ir.incoming_messages[1].get_attachments_for_display, 2) - attachment.body.should have_text(/Second hello/) - get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1 - response.should have_text(/Third hello/) + ir.reload + attachment = IncomingMessage.get_attachment_by_url_part_number_and_filename(ir.incoming_messages[1].get_attachments_for_display, 2, 'hello world.txt') + attachment.body.should contain "Third hello" + get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'hello world.txt.html', :skip_cache => 1 + response.should contain "Third hello" + end + + it "should redirect to the incoming message if there's a wrong part number and an ambiguous filename" do + ir = info_requests(:fancy_dog_request) + receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email) + ir.reload + + im = ir.incoming_messages[1] + + attachment = IncomingMessage.get_attachment_by_url_part_number_and_filename(im.get_attachments_for_display, 5, 'hello world.txt') + attachment.should be_nil + + get :get_attachment_as_html, :incoming_message_id => im.id, :id => ir.id, :part => 5, :file_name => 'hello world.txt', :skip_cache => 1 + response.status.should == 303 + new_location = response.header['Location'] + new_location.should match(/request\/#{ir.url_title}#incoming-#{im.id}/) + end + + it "should find a uniquely named filename even if the URL part number was wrong" do + ir = info_requests(:fancy_dog_request) + receive_incoming_mail('incoming-request-pdf-attachment.email', ir.incoming_email) + ir.reload + get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 5, :file_name => 'fs 50379341.pdf', :skip_cache => 1 + response.content_type.should == "application/pdf" end it "should treat attachments with unknown extensions as binary" do @@ -620,19 +670,17 @@ describe RequestController, "when showing one request" do receive_incoming_mail('incoming-request-attachment-unknown-extension.email', ir.incoming_email) ir.reload - get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.qwglhm'], :skip_cache => 1 + get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'hello.qwglhm', :skip_cache => 1 response.content_type.should == "application/octet-stream" - response.should have_text(/an unusual sort of file/) + response.should contain "an unusual sort of file" end it "should not download attachments with wrong file name" do ir = info_requests(:fancy_dog_request) receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email) - lambda { - get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, - :file_name => ['http://trying.to.hack'] - }.should raise_error(ActiveRecord::RecordNotFound) + get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'http://trying.to.hack' + response.status.should == 303 end it "should censor attachments downloaded as binary" do @@ -648,9 +696,9 @@ describe RequestController, "when showing one request" do begin receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email) - get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1 + get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'hello world.txt', :skip_cache => 1 response.content_type.should == "text/plain" - response.should have_text(/xxxxxx hello/) + response.should contain "xxxxxx hello" ensure ir.censor_rules.clear end @@ -670,9 +718,9 @@ describe RequestController, "when showing one request" do receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email) ir.reload - get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1 + get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => 'hello world.txt', :skip_cache => 1 response.content_type.should == "text/plain" - response.should have_text(/xxxxxx hello/) + response.should contain "xxxxxx hello" ensure ir.user.censor_rules.clear end @@ -694,21 +742,27 @@ describe RequestController, "when showing one request" do get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' assert assigns[:info_request].info_request_events[3].incoming_message.get_attachments_for_display.count == 2 # the issue is that the info_request_events have got cached on them the old info_requests. - # where i'm at: trying to replace those fields that got re-read from the raw email. however tests are failing in very strange ways. currently I don't appear to be getting any attachments parsed in at all when in the template (see "*****" in _correspondence.rhtml) but do when I'm in the code. + # where i'm at: trying to replace those fields that got re-read from the raw email. however tests are failing in very strange ways. currently I don't appear to be getting any attachments parsed in at all when in the template (see "*****" in _correspondence.html.erb) but do when I'm in the code. # so at this point, assigns[:info_request].incoming_messages[1].get_attachments_for_display is returning stuff, but the equivalent thing in the template isn't. # but something odd is that the above is return a whole load of attachments which aren't there in the controller - response.body.should have_tag("p.attachment strong", /hello.txt/m) + response.body.should have_selector("p.attachment strong") do |s| + s.should contain /hello world.txt/m + end censor_rule = CensorRule.new() - censor_rule.text = "hello.txt" + # Note that the censor rule applies to the original filename, + # not the display_filename: + censor_rule.text = "hello-world.txt" censor_rule.replacement = "goodbye.txt" censor_rule.last_edit_editor = "unknown" censor_rule.last_edit_comment = "none" ir.censor_rules << censor_rule begin get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' - response.body.should have_tag("p.attachment strong", /goodbye.txt/m) + response.body.should have_selector("p.attachment strong") do |s| + s.should contain /goodbye.txt/m + end ensure ir.censor_rules.clear end @@ -731,19 +785,19 @@ describe RequestController, "when showing one request" do ir = info_requests(:fancy_dog_request) session[:user_id] = ir.user.id # bob_smith_user get :download_entire_request, :url_title => title - assigns[:url_path].should have_text(/#{title}.zip$/) + assigns[:url_path].should contain /#{title}.zip$/ old_path = assigns[:url_path] - response.location.should have_text(/#{assigns[:url_path]}$/) + response.location.should contain /#{assigns[:url_path]}$/ zipfile = Zip::ZipFile.open(File.join(File.dirname(__FILE__), "../../cache/zips", old_path)) { |zipfile| zipfile.count.should == 1 # just the message } receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email) get :download_entire_request, :url_title => title - assigns[:url_path].should have_text(/#{title}.zip$/) + assigns[:url_path].should contain /#{title}.zip$/ old_path = assigns[:url_path] - response.location.should have_text(/#{assigns[:url_path]}$/) + response.location.should contain /#{assigns[:url_path]}$/ zipfile = Zip::ZipFile.open(File.join(File.dirname(__FILE__), "../../cache/zips", old_path)) { |zipfile| - zipfile.count.should == 3 # the message plus two "hello.txt" files + zipfile.count.should == 3 # the message plus two "hello-world.txt" files } # The path of the zip file is based on the hash of the timestamp of the last request @@ -752,11 +806,11 @@ describe RequestController, "when showing one request" do sleep 1 receive_incoming_mail('incoming-request-attachment-unknown-extension.email', ir.incoming_email) get :download_entire_request, :url_title => title - assigns[:url_path].should have_text(/#{title}.zip$/) + assigns[:url_path].should contain /#{title}.zip$/ assigns[:url_path].should_not == old_path - response.location.should have_text(/#{assigns[:url_path]}/) + response.location.should contain assigns[:url_path] zipfile = Zip::ZipFile.open(File.join(File.dirname(__FILE__), "../../cache/zips", assigns[:url_path])) { |zipfile| - zipfile.count.should == 4 # the message, two hello.txt plus the unknown attachment + zipfile.count.should == 4 # the message, two hello-world.txt plus the unknown attachment } end @@ -764,14 +818,13 @@ describe RequestController, "when showing one request" do info_request = info_requests(:external_request) get :download_entire_request, { :url_title => info_request.url_title }, { :user_id => users(:bob_smith_user) } - response.location.should have_text(/#{assigns[:url_path]}$/) + response.location.should contain /#{assigns[:url_path]}$/ end end end end describe RequestController, "when changing prominence of a request" do - before(:each) do load_raw_emails_data end @@ -795,6 +848,16 @@ describe RequestController, "when changing prominence of a request" do response.should render_template('hidden') end + it 'should not show hidden requests if requested using json' do + ir = info_requests(:fancy_dog_request) + ir.prominence = 'hidden' + ir.save! + + session[:user_id] = ir.user.id # bob_smith_user + get :show, :url_title => 'why_do_you_have_such_a_fancy_dog', :format => 'json' + response.code.should == '410' + end + it "should show hidden requests if logged in as super user" do ir = info_requests(:fancy_dog_request) ir.prominence = 'hidden' @@ -853,14 +916,14 @@ describe RequestController, "when changing prominence of a request" do :part => 2, :skip_cache => 1 response.content_type.should == "text/html" - response.should_not have_text(/Second hello/) + response.should_not contain "Second hello" response.should render_template('request/hidden') get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 3, :skip_cache => 1 response.content_type.should == "text/html" - response.should_not have_text(/First hello/) + response.should_not contain "First hello" response.should render_template('request/hidden') response.code.should == '410' end @@ -876,7 +939,7 @@ describe RequestController, "when changing prominence of a request" do get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, - :file_name => ['hello.txt'] + :file_name => 'hello world.txt' end.should raise_error(ActiveRecord::RecordNotFound) end @@ -891,7 +954,7 @@ describe RequestController, "when changing prominence of a request" do get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, - :file_name => ['hello.txt'] + :file_name => 'hello world.txt' end.should raise_error(ActiveRecord::RecordNotFound) end @@ -904,11 +967,11 @@ end # end describe RequestController, "when searching for an authority" do - # Whether or not sign-in is required for this step is configurable, # so we make sure we're logged in, just in case before do @user = users(:bob_smith_user) + get_fixtures_xapian_index end it "should return nothing for the empty query string" do @@ -920,6 +983,7 @@ describe RequestController, "when searching for an authority" do end it "should return matching bodies" do + session[:user_id] = @user.id get :select_authority, :query => "Quango" @@ -944,7 +1008,7 @@ describe RequestController, "when searching for an authority" do end describe RequestController, "when creating a new request" do - integrate_views + render_views before do @user = users(:bob_smith_user) @@ -1036,7 +1100,7 @@ describe RequestController, "when creating a new request" do response.should redirect_to show_new_request_url(:url_title => ir.url_title) # This test uses an explicit path because it's relied in # Google Analytics goals: - response.redirected_to.should =~ /request\/why_is_your_quango_called_gerald\/new$/ + response.redirect_url.should =~ /request\/why_is_your_quango_called_gerald\/new$/ end it "should give an error if the same request is submitted twice" do @@ -1180,7 +1244,7 @@ describe RequestController, "when making a new request" do end describe RequestController, "when viewing an individual response for reply/followup" do - integrate_views + render_views before(:each) do load_raw_emails_data @@ -1201,7 +1265,7 @@ describe RequestController, "when viewing an individual response for reply/follo it "should offer the opportunity to reply to the main address" do session[:user_id] = users(:bob_smith_user).id get :show_response, :id => info_requests(:fancy_dog_request).id, :incoming_message_id => incoming_messages(:useless_incoming_message) - response.body.should have_tag("div#other_recipients ul li", /the main FOI contact address for/) + response.body.should have_selector("div#other_recipients ul li", :content => "the main FOI contact address for") end it "should offer an opportunity to reply to another address" do @@ -1211,17 +1275,32 @@ describe RequestController, "when viewing an individual response for reply/follo ir.save! receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "Frob <frob@bonce.com>") get :show_response, :id => ir.id, :incoming_message_id => incoming_messages(:useless_incoming_message) - response.body.should have_tag("div#other_recipients ul li", /Frob/) + response.body.should have_selector("div#other_recipients ul li", :content => "Frob") end - it "should not show individual responses if request hidden, even if request owner" do - ir = info_requests(:fancy_dog_request) - ir.prominence = 'hidden' - ir.save! + context 'when a request is hidden' do + + before do + ir = info_requests(:fancy_dog_request) + ir.prominence = 'hidden' + ir.save! + + session[:user_id] = users(:bob_smith_user).id + end + + it "should not show individual responses, even if request owner" do + get :show_response, :id => info_requests(:fancy_dog_request).id, :incoming_message_id => incoming_messages(:useless_incoming_message) + response.should render_template('request/hidden') + end + + it 'should respond to a json request for a hidden request with a 410 code and no body' do + get :show_response, :id => info_requests(:fancy_dog_request).id, + :incoming_message_id => incoming_messages(:useless_incoming_message), + :format => 'json' + + response.code.should == '410' + end - session[:user_id] = users(:bob_smith_user).id - get :show_response, :id => info_requests(:fancy_dog_request).id, :incoming_message_id => incoming_messages(:useless_incoming_message) - response.should render_template('request/hidden') end describe 'when viewing a response for an external request' do @@ -1250,8 +1329,7 @@ describe RequestController, "when classifying an information request" do end it 'should redirect to the request page' do - post :describe_state, :id => @external_request.id, - :submitted_describe_state => 1 + post :describe_state, :id => @external_request.id response.should redirect_to(:action => 'show', :controller => 'request', :url_title => @external_request.url_title) @@ -1271,8 +1349,7 @@ describe RequestController, "when classifying an information request" do def post_status(status) post :describe_state, :incoming_message => { :described_state => status }, :id => @dog_request.id, - :last_info_request_event_id => @dog_request.last_event_id_needing_description, - :submitted_describe_state => 1 + :last_info_request_event_id => @dog_request.last_event_id_needing_description end it "should require login" do @@ -1282,6 +1359,7 @@ describe RequestController, "when classifying an information request" do end it 'should ask whether the request is old and unclassified' do + session[:user_id] = users(:silly_name_user).id @dog_request.should_receive(:is_old_unclassified?) post_status('rejected') end @@ -1296,7 +1374,9 @@ describe RequestController, "when classifying an information request" do before do @dog_request.stub!(:is_old_unclassified?).and_return(true) - RequestMailer.stub!(:deliver_old_unclassified_updated) + mail_mock = mock("mail") + mail_mock.stub(:deliver) + RequestMailer.stub!(:old_unclassified_updated).and_return(mail_mock) end describe 'when the user is not logged in' do @@ -1319,7 +1399,7 @@ describe RequestController, "when classifying an information request" do it 'should classify the request' do @dog_request.stub!(:calculate_status).and_return('rejected') - @dog_request.should_receive(:set_described_state).with('rejected') + @dog_request.should_receive(:set_described_state).with('rejected', users(:silly_name_user), nil) post_status('rejected') end @@ -1333,7 +1413,7 @@ describe RequestController, "when classifying an information request" do end it 'should send an email to the requester letting them know someone has updated the status of their request' do - RequestMailer.should_receive(:deliver_old_unclassified_updated) + RequestMailer.should_receive(:old_unclassified_updated) post_status('rejected') end @@ -1347,6 +1427,26 @@ describe RequestController, "when classifying an information request" do flash[:notice].should == 'Thank you for updating this request!' end + context "playing the classification game" do + before :each do + session[:request_game] = true + end + + it "should continue the game after classifying a request" do + post_status("rejected") + flash[:notice].should =~ /There are some more requests below for you to classify/ + response.should redirect_to categorise_play_url + end + end + + it "should send a mail from the user who changed the state to requires_admin" do + post :describe_state, :incoming_message => { :described_state => "requires_admin", :message => "a message" }, :id => @dog_request.id, :incoming_message_id => incoming_messages(:useless_incoming_message), :last_info_request_event_id => @dog_request.last_event_id_needing_description + + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.from_addrs.first.to_s.should == users(:silly_name_user).email + end end end @@ -1362,7 +1462,7 @@ describe RequestController, "when classifying an information request" do it 'should update the status of the request' do @dog_request.stub!(:calculate_status).and_return('rejected') - @dog_request.should_receive(:set_described_state).with('rejected') + @dog_request.should_receive(:set_described_state).with('rejected', @admin_user, nil) post_status('rejected') end @@ -1384,7 +1484,9 @@ describe RequestController, "when classifying an information request" do end it 'should send an email to the requester letting them know someone has updated the status of their request' do - RequestMailer.should_receive(:deliver_old_unclassified_updated) + mail_mock = mock("mail") + mail_mock.stub :deliver + RequestMailer.should_receive(:old_unclassified_updated).and_return(mail_mock) post_status('rejected') end @@ -1413,7 +1515,7 @@ describe RequestController, "when classifying an information request" do it 'should update the status of the request' do @dog_request.stub!(:calculate_status).and_return('rejected') - @dog_request.should_receive(:set_described_state).with('rejected') + @dog_request.should_receive(:set_described_state).with('rejected', @admin_user, nil) post_status('rejected') end @@ -1423,7 +1525,7 @@ describe RequestController, "when classifying an information request" do end it 'should not send an email to the requester letting them know someone has updated the status of their request' do - RequestMailer.should_not_receive(:deliver_old_unclassified_updated) + RequestMailer.should_not_receive(:old_unclassified_updated) post_status('rejected') end @@ -1448,6 +1550,22 @@ describe RequestController, "when classifying an information request" do @dog_request.stub!(:each).and_return([@dog_request]) end + it "should let you know when you forget to select a status" do + post :describe_state, :id => @dog_request.id, + :last_info_request_event_id => @dog_request.last_event_id_needing_description + response.should redirect_to show_request_url(:url_title => @dog_request.url_title) + flash[:error].should == _("Please choose whether or not you got some of the information that you wanted.") + end + + it "should not change the status if the request has changed while viewing it" do + @dog_request.stub!(:last_event_id_needing_description).and_return(2) + + post :describe_state, :incoming_message => { :described_state => "rejected" }, + :id => @dog_request.id, :last_info_request_event_id => 1 + response.should redirect_to show_request_url(:url_title => @dog_request.url_title) + flash[:error].should =~ /The request has been updated since you originally loaded this page/ + end + it "should successfully classify response if logged in as user controlling request" do post_status('rejected') response.should redirect_to(:controller => 'help', :action => 'unhappy', :url_title => @dog_request.url_title) @@ -1464,26 +1582,38 @@ describe RequestController, "when classifying an information request" do end it 'should not send an email to the requester letting them know someone has updated the status of their request' do - RequestMailer.should_not_receive(:deliver_old_unclassified_updated) + RequestMailer.should_not_receive(:old_unclassified_updated) post_status('rejected') end - it "should send email when classified as requires_admin" do - post :describe_state, :incoming_message => { :described_state => "requires_admin" }, :id => @dog_request.id, :incoming_message_id => incoming_messages(:useless_incoming_message), :last_info_request_event_id => @dog_request.last_event_id_needing_description, :submitted_describe_state => 1 - response.should redirect_to(:controller => 'help', :action => 'contact') + it "should go to the page asking for more information when classified as requires_admin" do + post :describe_state, :incoming_message => { :described_state => "requires_admin" }, :id => @dog_request.id, :incoming_message_id => incoming_messages(:useless_incoming_message), :last_info_request_event_id => @dog_request.last_event_id_needing_description + response.should redirect_to describe_state_message_url(:url_title => @dog_request.url_title, :described_state => "requires_admin") @dog_request.reload - @dog_request.awaiting_description.should == false - @dog_request.described_state.should == 'requires_admin' - @dog_request.get_last_response_event.calculated_state.should == 'requires_admin' + @dog_request.described_state.should_not == 'requires_admin' + + ActionMailer::Base.deliveries.should be_empty + end + + context "message is included when classifying as requires_admin" do + it "should send an email including the message" do + post :describe_state, + :incoming_message => { + :described_state => "requires_admin", + :message => "Something weird happened" }, + :id => @dog_request.id, + :last_info_request_event_id => @dog_request.last_event_id_needing_description - deliveries = ActionMailer::Base.deliveries - deliveries.size.should == 1 - mail = deliveries[0] - mail.body.should =~ /as needing admin/ - mail.from_addrs.first.to_s.should == @request_owner.name_and_email + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.body.should =~ /as needing admin/ + mail.body.should =~ /Something weird happened/ + end end + it 'should say it is showing advice as to what to do next' do post_status('rejected') flash[:notice].should match(/Here is what to do now/) @@ -1507,7 +1637,7 @@ describe RequestController, "when classifying an information request" do end end - describe 'when redirecting after a successful status update by the request owner' do + describe 'after a successful status update by the request owner' do before do @request_owner = users(:bob_smith_user) @@ -1515,11 +1645,10 @@ describe RequestController, "when classifying an information request" do @dog_request = info_requests(:fancy_dog_request) @dog_request.stub!(:each).and_return([@dog_request]) InfoRequest.stub!(:find).and_return(@dog_request) - @old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new + RoutingFilter.active = false end after do - ActionController::Routing::Routes.filters = @old_filters + RoutingFilter.active = true end def request_url @@ -1535,77 +1664,161 @@ describe RequestController, "when classifying an information request" do response.should redirect_to("http://test.host/#{redirect_path}") end - it 'should redirect to the "request url" with a message in the right tense when status is updated to "waiting response" and the response is not overdue' do - @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date+1) - @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date+40) + context 'when status is updated to "waiting_response"' do - expect_redirect("waiting_response", "request/#{@dog_request.url_title}") - flash[:notice].should match(/should get a response/) - end + it 'should redirect to the "request url" with a message in the right tense when + the response is not overdue' do + @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date+1) + @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date+40) - it 'should redirect to the "request url" with a message in the right tense when status is updated to "waiting response" and the response is overdue' do - @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date-1) - @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date+40) - expect_redirect('waiting_response', request_url) - flash[:notice].should match(/should have got a response/) - end + expect_redirect("waiting_response", "request/#{@dog_request.url_title}") + flash[:notice].should match(/should get a response/) + end - it 'should redirect to the "request url" with a message in the right tense when status is updated to "waiting response" and the response is overdue' do - @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date-2) - @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date-1) - expect_redirect('waiting_response', unhappy_url) - flash[:notice].should match(/is long overdue/) - flash[:notice].should match(/by more than 40 working days/) - flash[:notice].should match(/within 20 working days/) - end + it 'should redirect to the "request url" with a message in the right tense when + the response is overdue' do + @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date-1) + @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date+40) + expect_redirect('waiting_response', request_url) + flash[:notice].should match(/should have got a response/) + end - it 'should redirect to the "request url" when status is updated to "not held"' do - expect_redirect('not_held', request_url) + it 'should redirect to the "request url" with a message in the right tense when + the response is overdue' do + @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date-2) + @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date-1) + expect_redirect('waiting_response', unhappy_url) + flash[:notice].should match(/is long overdue/) + flash[:notice].should match(/by more than 40 working days/) + flash[:notice].should match(/within 20 working days/) + end end - it 'should redirect to the "request url" when status is updated to "successful"' do - expect_redirect('successful', request_url) - end + context 'when status is updated to "not held"' do + + it 'should redirect to the "request url"' do + expect_redirect('not_held', request_url) + end - it 'should redirect to the "unhappy url" when status is updated to "rejected"' do - expect_redirect('rejected', "help/unhappy/#{@dog_request.url_title}") end - it 'should redirect to the "unhappy url" when status is updated to "partially successful"' do - expect_redirect('partially_successful', "help/unhappy/#{@dog_request.url_title}") + context 'when status is updated to "successful"' do + + it 'should redirect to the "request url"' do + expect_redirect('successful', request_url) + end + + it 'should show a message including the donation url if there is one' do + AlaveteliConfiguration.stub!(:donation_url).and_return('http://donations.example.com') + post_status('successful') + flash[:notice].should match('make a donation') + flash[:notice].should match('http://donations.example.com') + end + + it 'should show a message without reference to donations if there is no + donation url' do + AlaveteliConfiguration.stub!(:donation_url).and_return('') + post_status('successful') + flash[:notice].should_not match('make a donation') + end + end - it 'should redirect to the "response url" when status is updated to "waiting clarification" and there is a last response' do - incoming_message = mock_model(IncomingMessage) - @dog_request.stub!(:get_last_response).and_return(incoming_message) - expect_redirect('waiting_clarification', "request/#{@dog_request.id}/response/#{incoming_message.id}") + context 'when status is updated to "waiting clarification"' do + + it 'should redirect to the "response url" when there is a last response' do + incoming_message = mock_model(IncomingMessage) + @dog_request.stub!(:get_last_response).and_return(incoming_message) + expect_redirect('waiting_clarification', "request/#{@dog_request.id}/response/#{incoming_message.id}") + end + + it 'should redirect to the "response no followup url" when there are no events + needing description' do + @dog_request.stub!(:get_last_response).and_return(nil) + expect_redirect('waiting_clarification', "request/#{@dog_request.id}/response") + end + end - it 'should redirect to the "response no followup url" when status is updated to "waiting clarification" and there are no events needing description' do - @dog_request.stub!(:get_last_response).and_return(nil) - expect_redirect('waiting_clarification', "request/#{@dog_request.id}/response") + context 'when status is updated to "rejected"' do + + it 'should redirect to the "unhappy url"' do + expect_redirect('rejected', "help/unhappy/#{@dog_request.url_title}") + end + end - it 'should redirect to the "respond to last url" when status is updated to "gone postal"' do - expect_redirect('gone_postal', "request/#{@dog_request.id}/response/#{@dog_request.get_last_response.id}?gone_postal=1") + context 'when status is updated to "partially successful"' do + + it 'should redirect to the "unhappy url"' do + expect_redirect('partially_successful', "help/unhappy/#{@dog_request.url_title}") + end + + it 'should show a message including the donation url if there is one' do + AlaveteliConfiguration.stub!(:donation_url).and_return('http://donations.example.com') + post_status('successful') + flash[:notice].should match('make a donation') + flash[:notice].should match('http://donations.example.com') + end + + it 'should show a message without reference to donations if there is no + donation url' do + AlaveteliConfiguration.stub!(:donation_url).and_return('') + post_status('successful') + flash[:notice].should_not match('make a donation') + end + end - it 'should redirect to the "request url" when status is updated to "internal review"' do - expect_redirect('internal_review', request_url) + context 'when status is updated to "gone postal"' do + + it 'should redirect to the "respond to last url"' do + expect_redirect('gone_postal', "request/#{@dog_request.id}/response/#{@dog_request.get_last_response.id}?gone_postal=1") + end + end - it 'should redirect to the "help general url" when status is updated to "requires admin"' do - expect_redirect('requires_admin', "help/contact") + context 'when status updated to "internal review"' do + + it 'should redirect to the "request url"' do + expect_redirect('internal_review', request_url) + end + end - it 'should redirect to the "help general url" when status is updated to "error message"' do - expect_redirect('error_message', "help/contact") + context 'when status is updated to "requires admin"' do + + it 'should redirect to the "request url"' do + post :describe_state, :incoming_message => { + :described_state => 'requires_admin', + :message => "A message" }, + :id => @dog_request.id, + :last_info_request_event_id => @dog_request.last_event_id_needing_description + response.should redirect_to show_request_url(:url_title => @dog_request.url_title) + end + end - it 'should redirect to the "respond to last url url" when status is updated to "user_withdrawn"' do - expect_redirect('user_withdrawn', "request/#{@dog_request.id}/response/#{@dog_request.get_last_response.id}") + context 'when status is updated to "error message"' do + + it 'should redirect to the "request url"' do + post :describe_state, :incoming_message => { + :described_state => 'error_message', + :message => "A message" }, + :id => @dog_request.id, + :last_info_request_event_id => @dog_request.last_event_id_needing_description + response.should redirect_to show_request_url(:url_title => @dog_request.url_title) + end + end + context 'when status is updated to "user_withdrawn"' do + + it 'should redirect to the "respond to last url url" ' do + expect_redirect('user_withdrawn', "request/#{@dog_request.id}/response/#{@dog_request.get_last_response.id}") + end + + end end end @@ -1613,7 +1826,7 @@ describe RequestController, "when classifying an information request" do end describe RequestController, "when sending a followup message" do - integrate_views + render_views before(:each) do load_raw_emails_data @@ -1666,7 +1879,7 @@ describe RequestController, "when sending a followup message" do deliveries.size.should == 1 mail = deliveries[0] mail.body.should =~ /What a useless response! You suck./ - mail.to_addrs.first.to_s.should == "FOI Person <foiperson@localhost>" + mail.to_addrs.first.to_s.should == "foiperson@localhost" response.should redirect_to(:action => 'show', :url_title => info_requests(:fancy_dog_request).url_title) @@ -1695,7 +1908,7 @@ end # it can't check the URLs in the emails I don't think, ugh. describe RequestController, "sending overdue request alerts" do - integrate_views + render_views before(:each) do load_raw_emails_data @@ -1713,9 +1926,9 @@ describe RequestController, "sending overdue request alerts" do mail = chicken_mails[0] mail.body.should =~ /promptly, as normally/ - mail.to_addrs.first.to_s.should == info_requests(:naughty_chicken_request).user.name_and_email + mail.to_addrs.first.to_s.should == info_requests(:naughty_chicken_request).user.email - mail.body =~ /(http:\/\/.*\/c\/(.*))/ + mail.body.to_s =~ /(http:\/\/.*\/c\/(.*))/ mail_url = $1 mail_token = $2 @@ -1742,7 +1955,7 @@ describe RequestController, "sending overdue request alerts" do mail = chicken_mails[0] mail.body.should =~ /promptly, as normally/ - mail.to_addrs.first.to_s.should == info_requests(:naughty_chicken_request).user.name_and_email + mail.to_addrs.first.to_s.should == info_requests(:naughty_chicken_request).user.email end it "should send not actually send the overdue alert if the user is banned but should @@ -1770,9 +1983,9 @@ describe RequestController, "sending overdue request alerts" do mail = chicken_mails[0] mail.body.should =~ /required by law/ - mail.to_addrs.first.to_s.should == info_requests(:naughty_chicken_request).user.name_and_email + mail.to_addrs.first.to_s.should == info_requests(:naughty_chicken_request).user.email - mail.body =~ /(http:\/\/.*\/c\/(.*))/ + mail.body.to_s =~ /(http:\/\/.*\/c\/(.*))/ mail_url = $1 mail_token = $2 @@ -1840,7 +2053,7 @@ describe RequestController, "sending overdue request alerts" do end describe RequestController, "sending unclassified new response reminder alerts" do - integrate_views + render_views before(:each) do load_raw_emails_data @@ -1853,8 +2066,8 @@ describe RequestController, "sending unclassified new response reminder alerts" deliveries.size.should == 3 # sufficiently late it sends reminders too mail = deliveries[0] mail.body.should =~ /To let everyone know/ - mail.to_addrs.first.to_s.should == info_requests(:fancy_dog_request).user.name_and_email - mail.body =~ /(http:\/\/.*\/c\/(.*))/ + mail.to_addrs.first.to_s.should == info_requests(:fancy_dog_request).user.email + mail.body.to_s =~ /(http:\/\/.*\/c\/(.*))/ mail_url = $1 mail_token = $2 @@ -1870,7 +2083,7 @@ describe RequestController, "sending unclassified new response reminder alerts" end describe RequestController, "clarification required alerts" do - integrate_views + render_views before(:each) do load_raw_emails_data end @@ -1889,8 +2102,8 @@ describe RequestController, "clarification required alerts" do deliveries.size.should == 1 mail = deliveries[0] mail.body.should =~ /asked you to explain/ - mail.to_addrs.first.to_s.should == info_requests(:fancy_dog_request).user.name_and_email - mail.body =~ /(http:\/\/.*\/c\/(.*))/ + mail.to_addrs.first.to_s.should == info_requests(:fancy_dog_request).user.email + mail.body.to_s =~ /(http:\/\/.*\/c\/(.*))/ mail_url = $1 mail_token = $2 @@ -1923,7 +2136,7 @@ describe RequestController, "clarification required alerts" do end describe RequestController, "comment alerts" do - integrate_views + render_views before(:each) do load_raw_emails_data end @@ -1942,8 +2155,8 @@ describe RequestController, "comment alerts" do deliveries = ActionMailer::Base.deliveries mail = deliveries[0] mail.body.should =~ /has annotated your/ - mail.to_addrs.first.to_s.should == info_requests(:fancy_dog_request).user.name_and_email - mail.body =~ /(http:\/\/.*)/ + mail.to_addrs.first.to_s.should == info_requests(:fancy_dog_request).user.email + mail.body.to_s =~ /(http:\/\/.*)/ mail_url = $1 mail_url.should match("/request/why_do_you_have_such_a_fancy_dog#comment-#{new_comment.id}") @@ -1992,8 +2205,8 @@ describe RequestController, "comment alerts" do deliveries.size.should == 1 mail = deliveries[0] mail.body.should =~ /There are 2 new annotations/ - mail.to_addrs.first.to_s.should == info_requests(:fancy_dog_request).user.name_and_email - mail.body =~ /(http:\/\/.*)/ + mail.to_addrs.first.to_s.should == info_requests(:fancy_dog_request).user.email + mail.body.to_s =~ /(http:\/\/.*)/ mail_url = $1 mail_url.should match("/request/why_do_you_have_such_a_fancy_dog#comment-#{comments(:silly_comment).id}") @@ -2002,7 +2215,7 @@ describe RequestController, "comment alerts" do end describe RequestController, "when viewing comments" do - integrate_views + render_views before(:each) do load_raw_emails_data end @@ -2010,22 +2223,26 @@ describe RequestController, "when viewing comments" do it "should link to the user who submitted it" do session[:user_id] = users(:bob_smith_user).id get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' - response.body.should have_tag("div#comment-1 h2", /Silly.*left an annotation/m) - response.body.should_not have_tag("div#comment-1 h2", /You.*left an annotation/m) + response.body.should have_selector("div#comment-1 h2") do |s| + s.should contain /Silly.*left an annotation/m + s.should_not contain /You.*left an annotation/m + end end it "should link to the user who submitted to it, even if it is you" do session[:user_id] = users(:silly_name_user).id get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' - response.body.should have_tag("div#comment-1 h2", /Silly.*left an annotation/m) - response.body.should_not have_tag("div#comment-1 h2", /You.*left an annotation/m) + response.body.should have_selector("div#comment-1 h2") do |s| + s.should contain /Silly.*left an annotation/m + s.should_not contain /You.*left an annotation/m + end end end describe RequestController, "authority uploads a response from the web interface" do - integrate_views + render_views before(:each) do # domain after the @ is used for authentication of FOI officers, so to test it @@ -2063,7 +2280,7 @@ describe RequestController, "authority uploads a response from the web interface session[:user_id] = @normal_user.id # post up a photo of the parrot - parrot_upload = fixture_file_upload('files/parrot.png','image/png') + parrot_upload = fixture_file_upload('/files/parrot.png','image/png') post :upload_response, :url_title => 'why_do_you_have_such_a_fancy_dog', :body => "Find attached a picture of a parrot", :file_1 => parrot_upload, @@ -2091,7 +2308,7 @@ describe RequestController, "authority uploads a response from the web interface session[:user_id] = @foi_officer_user.id # post up a photo of the parrot - parrot_upload = fixture_file_upload('files/parrot.png','image/png') + parrot_upload = fixture_file_upload('/files/parrot.png','image/png') post :upload_response, :url_title => 'why_do_you_have_such_a_fancy_dog', :body => "Find attached a picture of a parrot", :file_1 => parrot_upload, @@ -2115,7 +2332,6 @@ describe RequestController, "authority uploads a response from the web interface end describe RequestController, "when showing JSON version for API" do - before(:each) do load_raw_emails_data end @@ -2134,25 +2350,28 @@ describe RequestController, "when showing JSON version for API" do end describe RequestController, "when doing type ahead searches" do + render_views - integrate_views + before :each do + get_fixtures_xapian_index + end it "should return nothing for the empty query string" do get :search_typeahead, :q => "" - response.should render_template('request/_search_ahead.rhtml') + response.should render_template('request/_search_ahead') assigns[:xapian_requests].should be_nil end it "should return a request matching the given keyword, but not users with a matching description" do get :search_typeahead, :q => "chicken" - response.should render_template('request/_search_ahead.rhtml') + response.should render_template('request/_search_ahead') assigns[:xapian_requests].results.size.should == 1 assigns[:xapian_requests].results[0][:model].title.should == info_requests(:naughty_chicken_request).title end it "should return all requests matching any of the given keywords" do get :search_typeahead, :q => "money dog" - response.should render_template('request/_search_ahead.rhtml') + response.should render_template('request/_search_ahead') assigns[:xapian_requests].results.map{|x|x[:model].info_request}.should =~ [ info_requests(:fancy_dog_request), info_requests(:naughty_chicken_request), @@ -2162,13 +2381,13 @@ describe RequestController, "when doing type ahead searches" do it "should not return matches for short words" do get :search_typeahead, :q => "a" - response.should render_template('request/_search_ahead.rhtml') + response.should render_template('request/_search_ahead') assigns[:xapian_requests].should be_nil end it "should do partial matches for longer words" do get :search_typeahead, :q => "chick" - response.should render_template('request/_search_ahead.rhtml') + response.should render_template('request/_search_ahead') assigns[:xapian_requests].results.size.should ==1 end @@ -2193,7 +2412,12 @@ describe RequestController, "when doing type ahead searches" do end describe RequestController, "when showing similar requests" do - integrate_views + render_views + + before do + get_fixtures_xapian_index + load_raw_emails_data + end it "should work" do get :similar, :url_title => info_requests(:badger_request).url_title @@ -2225,93 +2449,7 @@ describe RequestController, "when showing similar requests" do end - -describe RequestController, "when reporting a request when not logged in" do - it "should only allow logged-in users to report requests" do - get :report_request, :url_title => info_requests(:badger_request).url_title - post_redirect = PostRedirect.get_last_post_redirect - response.should redirect_to(:controller => 'user', :action => 'signin', :token => post_redirect.token) - end -end - -describe RequestController, "when reporting a request (logged in)" do - integrate_views - - before do - @user = users(:robin_user) - session[:user_id] = @user.id - end - - it "should 404 for non-existent requests" do - lambda { - post :report_request, :url_title => "hjksfdhjk_louytu_qqxxx" - }.should raise_error(ActiveRecord::RecordNotFound) - end - - it "should mark a request as having been reported" do - ir = info_requests(:badger_request) - title = ir.url_title - get :show, :url_title => title - assigns[:info_request].attention_requested.should == false - - post :report_request, :url_title => title - response.should redirect_to(:action => :show, :url_title => title) - - get :show, :url_title => title - response.should be_success - assigns[:info_request].attention_requested.should == true - assigns[:info_request].described_state.should == "attention_requested" - end - - it "should not allow a request to be reported twice" do - title = info_requests(:badger_request).url_title - - post :report_request, :url_title => title - response.should redirect_to(:action => :show, :url_title => title) - get :show, :url_title => title - response.should be_success - response.body.should include("has been reported") - - post :report_request, :url_title => title - response.should redirect_to(:action => :show, :url_title => title) - get :show, :url_title => title - response.should be_success - response.body.should include("has already been reported") - end - - it "should let users know a request has been reported" do - title = info_requests(:badger_request).url_title - get :show, :url_title => title - response.body.should include("Offensive?") - - post :report_request, :url_title => title - response.should redirect_to(:action => :show, :url_title => title) - - get :show, :url_title => title - response.body.should_not include("Offensive?") - response.body.should include("This request has been reported") - - info_requests(:badger_request).set_described_state("successful") - get :show, :url_title => title - response.body.should_not include("This request has been reported") - response.body.should =~ (/the site administrators.*have not hidden it/) - end - - it "should send an email from the reporter to admins" do - ir = info_requests(:badger_request) - title = ir.url_title - post :report_request, :url_title => title - deliveries = ActionMailer::Base.deliveries - deliveries.size.should == 1 - mail = deliveries[0] - mail.subject.should =~ /attention_requested/ - mail.from.should include(@user.email) - mail.body.should include(@user.name) - end -end - describe RequestController, "when caching fragments" do - it "should not fail with long filenames" do long_name = "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah.txt" info_request = mock(InfoRequest, :user_can_view? => true, @@ -2325,9 +2463,9 @@ describe RequestController, "when caching fragments" do attachment = mock(FoiAttachment, :display_filename => long_name, :body_as_html => ['some text', 'wrapper']) IncomingMessage.stub!(:find).with("44").and_return(incoming_message) - IncomingMessage.stub!(:get_attachment_by_url_part_number).and_return(attachment) + IncomingMessage.stub!(:get_attachment_by_url_part_number_and_filename).and_return(attachment) InfoRequest.stub!(:find).with("132").and_return(info_request) - params = { :file_name => [long_name], + params = { :file_name => long_name, :controller => "request", :action => "get_attachment_as_html", :id => "132", @@ -2338,4 +2476,3 @@ describe RequestController, "when caching fragments" do end - diff --git a/spec/controllers/services_controller_spec.rb b/spec/controllers/services_controller_spec.rb index a9950d520..399f48acb 100644 --- a/spec/controllers/services_controller_spec.rb +++ b/spec/controllers/services_controller_spec.rb @@ -4,7 +4,7 @@ require 'fakeweb' describe ServicesController, "when returning a message for people in other countries" do - integrate_views + render_views # store and restore the locale in the context of the test suite to isolate # changes made in these tests @@ -54,27 +54,27 @@ describe ServicesController, "when returning a message for people in other count it "should return the 'another country' message if the service responds OK" do config = MySociety::Config.load_default() config['ISO_COUNTRY_CODE'] = "DE" - Configuration.stub!(:gaze_url).and_return('http://denmark.com') + AlaveteliConfiguration.stub!(:gaze_url).and_return('http://denmark.com') FakeWeb.register_uri(:get, %r|denmark.com|, :body => "DK") get :other_country_message response.should be_success response.body.should == 'Hello! We have an <a href="/help/alaveteli?country_name=Deutschland">important message</a> for visitors outside Deutschland <span class="close-button">X</span>' end it "should default to no message if the country_from_ip domain doesn't exist" do - Configuration.stub!(:gaze_url).and_return('http://12123sdf14qsd.com') + AlaveteliConfiguration.stub!(:gaze_url).and_return('http://12123sdf14qsd.com') get :other_country_message response.should be_success response.body.should == '' end it "should default to no message if the country_from_ip service doesn't exist" do - Configuration.stub!(:gaze_url).and_return('http://www.google.com') + AlaveteliConfiguration.stub!(:gaze_url).and_return('http://www.google.com') get :other_country_message response.should be_success response.body.should == '' end it "should default to no message if the country_from_ip service returns an error" do FakeWeb.register_uri(:get, %r|500.com|, :body => "Error", :status => ["500", "Error"]) - Configuration.stub!(:gaze_url).and_return('http://500.com') + AlaveteliConfiguration.stub!(:gaze_url).and_return('http://500.com') get :other_country_message response.should be_success response.body.should == '' diff --git a/spec/controllers/track_controller_spec.rb b/spec/controllers/track_controller_spec.rb index c785960b5..1575bc84e 100644 --- a/spec/controllers/track_controller_spec.rb +++ b/spec/controllers/track_controller_spec.rb @@ -49,15 +49,14 @@ describe TrackController, "when making a new track on a request" do it "should save a search track and redirect to the right place" do session[:user_id] = @user.id @track_thing.should_receive(:save!) - get :track_search_query, :query_array => ["bob variety:sent"], :feed => 'track' + get :track_search_query, :query_array => "bob variety:sent", :feed => 'track' response.should redirect_to(:controller => 'general', :action => 'search', :combined => ["bob", "requests"]) end end describe TrackController, "when sending alerts for a track" do - integrate_views - include LinkToHelper # for main_url + render_views before(:each) do load_raw_emails_data @@ -66,8 +65,7 @@ describe TrackController, "when sending alerts for a track" do it "should send alerts" do # Don't do clever locale-insertion-unto-URL stuff - old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new + RoutingFilter.active = false # set the time the comment event happened at to within the last week ire = info_request_events(:silly_comment_event) @@ -81,7 +79,7 @@ describe TrackController, "when sending alerts for a track" do mail = deliveries[0] mail.body.should =~ /Alter your subscription/ mail.to_addrs.first.to_s.should include(users(:silly_name_user).email) - mail.body =~ /(http:\/\/.*\/c\/(.*))/ + mail.body.to_s =~ /(http:\/\/.*\/c\/(.*))/ mail_url = $1 mail_token = $2 @@ -105,7 +103,7 @@ describe TrackController, "when sending alerts for a track" do # Given we can't click the link, check the token is right instead post_redirect = PostRedirect.find_by_email_token(mail_token) - expected_url = main_url("/user/" + users(:silly_name_user).url_name + "#email_subscriptions") # XXX can't call URL making functions here, what is correct way to do this? + expected_url = show_user_url(:url_name => users(:silly_name_user).url_name, :anchor => "email_subscriptions") post_redirect.uri.should == expected_url # Check nothing more is delivered if we try again @@ -115,7 +113,7 @@ describe TrackController, "when sending alerts for a track" do deliveries.size.should == 0 # Restore the routing filters - ActionController::Routing::Routes.filters = old_filters + RoutingFilter.active = true end it "should send localised alerts" do @@ -134,7 +132,7 @@ describe TrackController, "when sending alerts for a track" do end describe TrackController, "when viewing RSS feed for a track" do - integrate_views + render_views before(:each) do load_raw_emails_data @@ -146,6 +144,7 @@ describe TrackController, "when viewing RSS feed for a track" do get :track_request, :feed => 'feed', :url_title => track_thing.info_request.url_title response.should render_template('track/atom_feed') + response.content_type.should == 'application/atom+xml' # XXX should check it is an atom.builder type being rendered, not sure how to assigns[:xapian_object].matches_estimated.should == 3 @@ -160,11 +159,23 @@ describe TrackController, "when viewing RSS feed for a track" do get :track_user, :feed => 'feed', :url_name => "there_is_no_such_user" }.should raise_error(ActiveRecord::RecordNotFound) end + + it 'should return atom/xml for a feed url without format specified, even if the + requester prefers json' do + + request.env['HTTP_ACCEPT'] = 'application/json,text/xml' + track_thing = track_things(:track_fancy_dog_request) + + get :track_request, :feed => 'feed', :url_title => track_thing.info_request.url_title + response.should render_template('track/atom_feed') + response.content_type.should == 'application/atom+xml' + end + end describe TrackController, "when viewing JSON version of a track feed" do - integrate_views + render_views before(:each) do load_raw_emails_data @@ -206,7 +217,7 @@ end describe TrackController, "when tracking a public body" do - integrate_views + render_views before(:each) do load_raw_emails_data diff --git a/spec/controllers/user_controller_spec.rb b/spec/controllers/user_controller_spec.rb index 23006803b..1d8e3dcc3 100644 --- a/spec/controllers/user_controller_spec.rb +++ b/spec/controllers/user_controller_spec.rb @@ -5,7 +5,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') # http://rspec.rubyforge.org/rspec-rails/1.1.12/classes/Spec/Rails/Example/ControllerExampleGroup.html describe UserController, "when showing a user" do - integrate_views + render_views before(:each) do load_raw_emails_data get_fixtures_xapian_index @@ -64,7 +64,7 @@ describe UserController, "when showing a user" do end describe UserController, "when signing in" do - integrate_views + render_views def get_last_postredirect post_redirects = PostRedirect.find_by_sql("select * from post_redirects order by id desc limit 1") @@ -74,7 +74,7 @@ describe UserController, "when signing in" do it "should show sign in / sign up page" do get :signin - response.should have_tag("input#signin_token") + response.should have_selector("input#signin_token") end it "should create post redirect to / when you just go to /signin" do @@ -100,8 +100,7 @@ describe UserController, "when signing in" do end it "should log in when you give right email/password, and redirect to where you were" do - old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new + RoutingFilter.active = false get :signin, :r => "/list" response.should render_template('sign') @@ -112,14 +111,13 @@ describe UserController, "when signing in" do session[:user_id].should == users(:bob_smith_user).id # response doesn't contain /en/ but redirect_to does... response.should redirect_to(:controller => 'request', :action => 'list', :post_redirect => 1) - response.should_not send_email + ActionMailer::Base.deliveries.should be_empty - ActionController::Routing::Routes.filters = old_filters + RoutingFilter.active = true end it "should not log you in if you use an invalid PostRedirect token, and shouldn't give 500 error either" do - old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new + RoutingFilter.active = false post_redirect = "something invalid" lambda { @@ -132,7 +130,7 @@ describe UserController, "when signing in" do response.should render_template('sign') assigns[:post_redirect].should == nil - ActionController::Routing::Routes.filters = old_filters + RoutingFilter.active = true end # No idea how to test this in the test framework :( @@ -152,12 +150,11 @@ describe UserController, "when signing in" do :token => post_redirect.token } response.should render_template('confirm') - response.should send_email + ActionMailer::Base.deliveries.should_not be_empty end it "should confirm your email, log you in and redirect you to where you were after you click an email link" do - old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new + RoutingFilter.active = false get :signin, :r => "/list" post_redirect = get_last_postredirect @@ -165,19 +162,19 @@ describe UserController, "when signing in" do post :signin, { :user_signin => { :email => 'unconfirmed@localhost', :password => 'jonespassword' }, :token => post_redirect.token } - response.should send_email + ActionMailer::Base.deliveries.should_not be_empty deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] - mail.body =~ /(http:\/\/.*(\/c\/(.*)))/ + mail.body.to_s =~ /(http:\/\/.*(\/c\/(.*)))/ mail_url = $1 mail_path = $2 mail_token = $3 # check is right confirmation URL mail_token.should == post_redirect.email_token - params_from(:get, mail_path).should == { :controller => 'user', :action => 'confirm', :email_token => mail_token } + Rails.application.routes.recognize_path(mail_path).should == { :controller => 'user', :action => 'confirm', :email_token => mail_token } # check confirmation URL works session[:user_id].should be_nil @@ -185,12 +182,11 @@ describe UserController, "when signing in" do session[:user_id].should == users(:unconfirmed_user).id response.should redirect_to(:controller => 'request', :action => 'list', :post_redirect => 1) - ActionController::Routing::Routes.filters = old_filters + RoutingFilter.active = true end it "should keep you logged in if you click a confirmation link and are already logged in as an admin" do - old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new + RoutingFilter.active = false get :signin, :r => "/list" post_redirect = get_last_postredirect @@ -198,19 +194,19 @@ describe UserController, "when signing in" do post :signin, { :user_signin => { :email => 'unconfirmed@localhost', :password => 'jonespassword' }, :token => post_redirect.token } - response.should send_email + ActionMailer::Base.deliveries.should_not be_empty deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] - mail.body =~ /(http:\/\/.*(\/c\/(.*)))/ + mail.body.to_s =~ /(http:\/\/.*(\/c\/(.*)))/ mail_url = $1 mail_path = $2 mail_token = $3 # check is right confirmation URL mail_token.should == post_redirect.email_token - params_from(:get, mail_path).should == { :controller => 'user', :action => 'confirm', :email_token => mail_token } + Rails.application.routes.recognize_path(mail_path).should == { :controller => 'user', :action => 'confirm', :email_token => mail_token } # Log in as an admin session[:user_id] = users(:admin_user).id @@ -222,19 +218,19 @@ describe UserController, "when signing in" do # And the redirect should still work, of course response.should redirect_to(:controller => 'request', :action => 'list', :post_redirect => 1) - ActionController::Routing::Routes.filters = old_filters + RoutingFilter.active = true end end describe UserController, "when signing up" do - integrate_views + render_views it "should be an error if you type the password differently each time" do post :signup, { :user_signup => { :email => 'new@localhost', :name => 'New Person', :password => 'sillypassword', :password_confirmation => 'sillypasswordtwo' } } - assigns[:user_signup].errors[:password].should == 'Please enter the same password twice' + assigns[:user_signup].errors[:password].should == ['Please enter the same password twice'] end it "should be an error to sign up with a misformatted email" do @@ -285,7 +281,7 @@ describe UserController, "when signing up" do end describe UserController, "when signing out" do - integrate_views + render_views it "should log you out and redirect to the home page" do session[:user_id] = users(:bob_smith_user).id @@ -295,21 +291,20 @@ describe UserController, "when signing out" do end it "should log you out and redirect you to where you were" do - old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new + RoutingFilter.active = false session[:user_id] = users(:bob_smith_user).id get :signout, :r => '/list' session[:user_id].should be_nil response.should redirect_to(:controller => 'request', :action => 'list') - ActionController::Routing::Routes.filters = old_filters + RoutingFilter.active = true end end describe UserController, "when sending another user a message" do - integrate_views + render_views it "should redirect to signin page if you go to the contact form and aren't signed in" do get :contact, :id => users(:silly_name_user) @@ -337,16 +332,16 @@ describe UserController, "when sending another user a message" do deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] - mail.body.should include("Bob Smith has used #{Configuration::site_name} to send you the message below") + mail.body.should include("Bob Smith has used #{AlaveteliConfiguration::site_name} to send you the message below") mail.body.should include("Just a test!") #mail.to_addrs.first.to_s.should == users(:silly_name_user).name_and_email # XXX fix some nastiness with quoting name_and_email - mail.from_addrs.first.to_s.should == users(:bob_smith_user).name_and_email + mail.from_addrs.first.to_s.should == users(:bob_smith_user).email end end describe UserController, "when changing password" do - integrate_views + render_views it "should show the email form when not logged in" do get :signchangepassword @@ -386,7 +381,7 @@ describe UserController, "when changing password" do post :signchangepassword, { :user => { :password => 'ooo', :password_confirmation => 'ooo' }, :submitted_signchangepassword_do => 1 } - users(:bob_smith_user).hashed_password.should != old_hash + users(:bob_smith_user).reload.hashed_password.should_not == old_hash response.should redirect_to(:controller => 'user', :action => 'show', :url_name => users(:bob_smith_user).url_name) end @@ -416,7 +411,7 @@ describe UserController, "when changing password" do end describe UserController, "when changing email address" do - integrate_views + render_views it "should require login" do get :signchangeemail @@ -500,10 +495,10 @@ describe UserController, "when changing email address" do deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] - mail.body.should include("confirm that you want to change") + mail.body.should include("confirm that you want to \nchange") mail.to.should == [ 'newbob@localhost' ] - mail.body =~ /(http:\/\/.*(\/c\/(.*)))/ + mail.body.to_s =~ /(http:\/\/.*(\/c\/(.*)))/ mail_url = $1 mail_path = $2 mail_token = $3 @@ -561,16 +556,13 @@ describe UserController, "when changing email address" do end describe UserController, "when using profile photos" do - integrate_views + render_views before do @user = users(:bob_smith_user) - @uploadedfile = File.open(file_fixture_name("parrot.png")) - @uploadedfile.stub!(:original_filename).and_return('parrot.png') - - @uploadedfile_2 = File.open(file_fixture_name("parrot.jpg")) - @uploadedfile_2.stub!(:original_filename).and_return('parrot.jpg') + @uploadedfile = fixture_file_upload("/files/parrot.png") + @uploadedfile_2 = fixture_file_upload("/files/parrot.jpg") end it "should not let you change profile photo if you're not logged in as the user" do @@ -631,9 +623,10 @@ describe UserController, "when showing JSON version for API" do end describe UserController, "when viewing the wall" do - integrate_views + render_views before(:each) do + load_raw_emails_data get_fixtures_xapian_index end diff --git a/spec/fixtures/files/blog_feed.atom b/spec/fixtures/files/blog_feed.atom new file mode 100644 index 000000000..f49693938 --- /dev/null +++ b/spec/fixtures/files/blog_feed.atom @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rss version="2.0" + xmlns:content="http://purl.org/rss/1.0/modules/content/" + xmlns:wfw="http://wellformedweb.org/CommentAPI/" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:atom="http://www.w3.org/2005/Atom" + xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" + xmlns:slash="http://purl.org/rss/1.0/modules/slash/" + > + +<channel> + <title>A Blog Feed</title> + <atom:link href="http://example.com/feed/" rel="self" type="application/rss+xml" /> + <link>http://www.example.com</link> + <description>Stuff</description> + <lastBuildDate>Tue, 30 Apr 2013 14:34:15 +0000</lastBuildDate> + <language>en</language> + <sy:updatePeriod>hourly</sy:updatePeriod> + <sy:updateFrequency>1</sy:updateFrequency> + <generator>http://wordpress.org/?v=3.3.2</generator> + <item> + <title>Example Post</title> + <link>http://www.example.com/example-post</link> + <comments>http://www.example.com/example-post#comments</comments> + <pubDate>Mon, 01 Apr 2013 19:26:08 +0000</pubDate> + <dc:creator>Example Blogger</dc:creator> + <category><![CDATA[FOI]]></category> + + <guid isPermaLink="false">http://www.example.com/?id=333</guid> + <description><![CDATA[An example post [...]]]></description> + <content:encoded><![CDATA[<h3>A blog post</h3> +<p>Example post</p> +]]></content:encoded> + <wfw:commentRss>http://www.example.com/feed/</wfw:commentRss> + <slash:comments>2</slash:comments> + </item> + + </channel> +</rss> diff --git a/spec/fixtures/files/incoming-request-two-same-name.email b/spec/fixtures/files/incoming-request-two-same-name.email index f1024d607..ecd322fe4 100644 --- a/spec/fixtures/files/incoming-request-two-same-name.email +++ b/spec/fixtures/files/incoming-request-two-same-name.email @@ -13,13 +13,13 @@ Content-Disposition: inline --Q68bSM7Ycu6FN28Q Content-Type: text/plain; charset=us-ascii -Content-Disposition: attachment; filename="hello.txt" +Content-Disposition: attachment; filename="hello-world.txt" Second hello --Q68bSM7Ycu6FN28Q Content-Type: text/plain; charset=us-ascii -Content-Disposition: attachment; filename="hello.txt" +Content-Disposition: attachment; filename="hello-world.txt" First hello diff --git a/spec/fixtures/files/inline-uuencode.email b/spec/fixtures/files/inline-uuencode.email new file mode 100644 index 000000000..3134ba3ad --- /dev/null +++ b/spec/fixtures/files/inline-uuencode.email @@ -0,0 +1,27 @@ +From foo@bar Mon Jun 01 17:14:44 2009 +Return-path: <foo@bar> +Envelope-to: foi@quux +Delivery-date: Mon, 01 Jun 2009 17:14:44 +0100 +From: <foo@bar> +To: <request-whatever@quux> +Subject: something or other +Date: Mon, 1 Jun 2009 17:14:37 +0100 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.3790.181 +Message-ID: <baz@xyzzy> + +Thanks for your email - here's a truncated attachment +for you: + +********************************************************************** + +begin 666 ResponseT7363 9.doc +MT,\1X*&Q&N$`````````````````````/@`#`/[_"0`&```````````````" +M````) ``````````$ ``+@````$```#^____`````",```!L````________ +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +#```` +` +end + +The original of this email was scanned for viruses or something +like that. diff --git a/spec/fixtures/files/malformed-to-and-cc.email b/spec/fixtures/files/malformed-to-and-cc.email new file mode 100644 index 000000000..4fbb6e21e --- /dev/null +++ b/spec/fixtures/files/malformed-to-and-cc.email @@ -0,0 +1,11 @@ +From foo@bar Wed Mar 12 14:58:26 2008 +Return-path: <foo@bar> +Subject: example email +To: <bar@example.org +Cc: baz@example.org> +From: quux@example.org +Date: Mon, 7 May 2012 12:47:06 +0100 +Mime-Version: 1.0 +Content-Type: text/plain; charset=utf-8 + +A very basic email, but with malformed To: and Cc: lines diff --git a/spec/fixtures/files/mislabelled-as-iso-8859-1.email b/spec/fixtures/files/mislabelled-as-iso-8859-1.email new file mode 100644 index 000000000..6c8e6109e --- /dev/null +++ b/spec/fixtures/files/mislabelled-as-iso-8859-1.email @@ -0,0 +1,20 @@ +From foo@bar Thu Mar 01 15:02:33 2012 +Return-path: <foo@bar> +Envelope-to: foi@quux +Delivery-date: Thu, 01 Mar 2012 15:02:33 +0000 +Date: Thu, 01 Mar 2012 15:01:58 +0000 +Subject: some FOI request +To: foi@quux +From: foo@bar +MIME-Version: 1.0 +Content-Type: text/plain; charset="iso-8859-1" +Content-Transfer-Encoding: 7bit +Message-Id: <2468@bar.local> + +Dear Whoever, + +THERE'S A DASH NEXT REQUEST FOR INFORMATION + +Best regards, +Other Person + diff --git a/spec/fixtures/files/multipart-no-final-boundary.email b/spec/fixtures/files/multipart-no-final-boundary.email new file mode 100644 index 000000000..9c16dad52 --- /dev/null +++ b/spec/fixtures/files/multipart-no-final-boundary.email @@ -0,0 +1,21 @@ +From foo@bar Thu Sep 13 10:34:44 2012 +Return-path: <foo@bar> +Envelope-to: foi@example.org +Delivery-date: Thu, 13 Sep 2012 10:34:44 +0100 +From: foo@bar +To: foi@example.org +Subject: an acknowledgement email +Date: Thu, 13 Sep 2012 10:08:03 +0100 +Message-ID: <987654@foo.local> +Content-Type: multipart/mixed; boundary="-----7D81B75CCC90D2974F7A1CBD" + +This is a multi-part message in MIME format. +-------7D81B75CCC90D2974F7A1CBD +Content-Type: text/html + +<div> + <p> + This is an acknowledgement of your email, that irritatingly + leaves out the final MIME boundary. + </p> +<div> diff --git a/spec/fixtures/files/nested-attachments-premature-end.email b/spec/fixtures/files/nested-attachments-premature-end.email new file mode 100644 index 000000000..6b13808dc --- /dev/null +++ b/spec/fixtures/files/nested-attachments-premature-end.email @@ -0,0 +1,110 @@ +From someone@example.org Mon May 15 13:10:29 2012 +Return-path: <someone@example.org> +Envelope-to: foi@example.org +Delivery-date: Mon, 15 May 2012 13:10:29 +0100 +Message-Id: <abcde@baz.local> +Date: Mon, 15 May 2012 09:48:48 +0100 +From: "Example Person" <someone@example.org> +To: <request@example.org> +Subject: some FOI request or other +Mime-Version: 1.0 +Content-Type: multipart/mixed; boundary="=__outer__=" + +This is a MIME message. If you are reading this text, you may want to +consider changing to a mail reader or gateway that understands how to +properly handle MIME multipart messages. + +--=__outer__= +Content-Type: multipart/alternative; boundary="=__inner__=" + +--=__inner__= +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +X-MIME-Autoconverted: from 8bit to quoted-printable by something + +Hello +=20 +Please find some information attached. +=20 + +--=__inner__= +Content-Description: HTML +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +<html> + <head> + <title>some title text</title> + </head> + <body> + <p>blah blah blah</p> + </body> +</html> + +--=__inner__=-- + +--=__outer__= +Content-Type: message/rfc822 + +Return-path: <foo@bar> +Date: Mon, 7 May 2012 12:47:06 +0100 +From: someone-else@example.org +To: foi@example.org +Message-Id: <56789@quux.local> +Subject: a freedom of information requests +Mime-Version: 1.0 +Content-Type: text/plain; charset=utf-8 + + Dear Whoever, + + Please could you let me know, um, whatever ... + + Yours faithfully, + + Whoever I Am + +--=__outer__= +Content-Type: text/plain; charset=US-ASCII +Content-Disposition: inline +Content-Transfer-Encoding: quoted-printable + + Dear Whowever, + =20 + Please could you let me know, um, whatever ... + =20 + Yours faithfully, + =20 + Whoever I Am + =20 + +--=__outer__=-- + +--=__outer__= +Content-Type: application/png; name="maroon-square.png" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="maroon-square.png" + +iVBORw0KGgoAAAANSUhEUgAAAEEAAABCCAYAAAAIY7vrAAAABmJLR0QA/wD/AP+g +vaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QQeDSEx8qultwAAABl0 +RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAMzSURBVHja7VtL2psw +DNS4rPv1Gj1Kt71Az9ZT9F7dN9MFGGThB/YfKDX2Kp8DRBpLowcKvn/5ShERiAgl +srh8aT93tJzWdae8XR0CEICwUx59K54H4QFKp0Eg5alrAwEYIDx5DRAGCAOEAcIA +QaUFfDoIHJawpEbOPd0dRPjJDWIUiEwt933+8es2Ovz++a3dCkREXmwD4ZbsVln6 +cLkef14duAMqAGCkY0A+jBNgXGFZU/eKa3fhZjlQqLhHKF9oFbpulE2Z/oFrXTd+ +nlOWkn1dMHXrAiWguq0iG9uk/REjBggPtgQOED781my4wwBhgDBAmPmUAwR0X0UO +dxggnA8CO5xocU8HoAoEDwA6nOyCH+ZMKQ4zy+QbNBoUirquMPBJcgPyJkOi+c7S +ohhn6ZctzDIrcFalIspYILG1et9WABUtt6WztLq+/0Amp9sCnsCBUhfvK4FLiRCA +QwC7JABGTngrIIPnIjf6R5We0uxz3j+FbCvdy2nlY/IgcfrMRQuFHIC9Sap3AW8n +2gZ+cZYCVn4LzBxxnykNgJpWN8lt7yw+QCMxan2s8lQXcNlDlpAW7YmIXMszTgoH +rU91+8OFYXN9ikz/LyLgExSCDlaO+cdGsIEQkyUAIgFMKRTEn3vDjFFHwWSIzEQC +cmN4IHVNGG2PQXhhsuRl3jihwQyB6H1274gV1BhKLKNt4ZEpkygeeoC+xytdK1cr +oX0EACphnTZXbbLMmL/YBGo9lSU1OmBONMnTlQUqTa4y1VgAddg0hdTR04lyT0Xq +8RYAyHVyBX6ET/9wTBD6TWVCMH5Qo3yhXju3bNY/BBMdsoLYBMmnzQdOP56O36s5 +40r1D7UWYV5dNT2nbxVBAHb43Y36CdbXfTii6isU/U7ZXLQ4w/V/wotFoilVF2kl +w7YCDrIPkj4/G9fao7q0rYSSJdgeSqmQrCU+r/j8rOv/gpuKPm5Lffen5eN+ljeo +rcfW0Om2Enm9KwDZAgrG98txX9cMe6X2E5SGU29VTE17lFAUkMybsXclndu31BGX +hcgWv8oxonYtkf/jhc10WPGgm2IZncKlu+sg8vLm7hDSwk3f2/wFEzN3v6aAXQ0A +AAAASUVORK5CYII= + +--=__outer__=-- + diff --git a/spec/fixtures/files/no-part-charset-random-data.email b/spec/fixtures/files/no-part-charset-random-data.email new file mode 100644 index 000000000..d51fd3f38 --- /dev/null +++ b/spec/fixtures/files/no-part-charset-random-data.email @@ -0,0 +1,30 @@ +From xxxx@yahoo.cn Mon Oct 08 14:01:34 2012 +Return-path: <xxxx@yahoo.cn> +Envelope-to: foi@atlas.ukcod.org.uk +Delivery-date: Mon, 08 Oct 2012 14:01:34 +0100 +Received: (qmail 63864 invoked from network); 8 Oct 2012 13:01:12 -0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.cn; s=s1024; t=1349701272; bh=T/mtlIYvhB/L5RO+CvTazeAdGf1n1zsGXBoA8EKGT9M=; h=Message-ID:X-Yahoo-Newman-Property:X-YMail-OSG:X-Yahoo-SMTP:Received:X-mailer:From:Subject:To:Content-Transfer-Encoding:Content-Type:Date; b=LYI/PXvA7DA746bmyprChUg7N8YDvN9XE/bhfTt5MW7siOmxHHzn1w+s5X33PvLI0x0UfJLo+MCkTnGPKnG5BYY38US8PkocJYyphrvF/eaUl3ALf8UvxHBOJX1iIi89Xp2NnfbS8lz9kZAWifb9GOnOA5/kLDcL5/WJXliit2k= +Message-ID: <xxxx@xxxx.yahoo.com> +X-Yahoo-Newman-Property: ymail-5 +X-YMail-OSG: nPs5jgsVM1myUoKjeEPTxxalz4BM6BZMEUYu.E8NPMPQyo_ + Yej8T2WCTurn767NOwhuDIqNxC2QGZINqfjmKcdyW7a1P_Zxqr9GsjgxODci + ihwr7qYAGDDbcsrB.PX4epnJZHl3yAwoGW.1ReEZnXQANFcNep7.zNEbZ_2k + RU1IhI9aHYvxPxt5RWugwOoFRh9P8Ym35A88IMazNtVaBiBEXF6Vk8Aqr9XP + 3Vh9xOT9Pn6X8qOUjNXkdb3xB4S5AAIRSE9mqhL1KzHBwdVQs25IoM_2FV2b + gPsQGgL4_mwBH0WcEMhdj7Kn6Nfb44L.50E_V3DH.8P7KzDK8zNVXSbAqohX + Qi6MzUK2frr8IyZyYzHb.ekff7kAcJgUoHvhnyPar8tRYxhQT3_xsUTzsx8N + oWckVPh_i3OT7U4ObgekqgtteMoYqPH2eF1SZXamGBAs- +X-Yahoo-SMTP: YUQHwRWswBDjbw_M.D6EP4KpT9khlJErDRBQi4ySZQ-- +X-mailer: MIME::Lite 3.027 (F2.74; T1.31; A2.07; B3.13; Q3.13) +From: =?GB2312?B?zsJKaWFu?= Bing <xxxx@yahoo.cn> +Subject: =?GB2312?B?yM7A1svJ?= +To: FOI Person <EMAIL_TO> +Content-Transfer-Encoding: base64 +Content-Type: text/plain +Date: Tue, 9 Oct 2012 20:53:06 +0800 + +HPBSqsndNBX+ER4hyBoPhhnclcWKVFgbevdD5cJvfI/ARbxRYqA28hZ49Pf6A/ks +NdVh4N5VPgRs/7SHYPfw5625pZJYTLj6nVdYk76sxnjiiAmwCJWGjPoWvO7nHUBv +fuLXtNVq5HmD0bWWjAbSk2n74PW7v5izbNO2fjHyiyX2CIof0rriXDmOldJqoebO +ejybrjG+Tahpu3FF1Mw98HfswzkdB46u/izLCzdUQVM= + diff --git a/spec/fixtures/files/part-without-charset-in-content-type.email b/spec/fixtures/files/part-without-charset-in-content-type.email new file mode 100644 index 000000000..439d52cc3 --- /dev/null +++ b/spec/fixtures/files/part-without-charset-in-content-type.email @@ -0,0 +1,38 @@ +From example@example.com Wed Sep 15 17:55:40 2010 +Return-path: <example@example.com> +Envelope-to: example@example.com +Delivery-date: Wed, 15 Sep 2010 17:55:40 +0100 +From: <example@example.com> +To: <request-xxxxx@whatdotheyknow.com> +Date: Wed, 15 Sep 2010 17:56:03 +0100 +Subject: FOI Internal Review response +Thread-Topic: FOI Internal Review response +Thread-Index: xxxxx +Message-ID: <xxxxxx> +Accept-Language: en-US, en-GB +Content-Language: en-US +X-MS-Has-Attach: yes +X-MS-TNEF-Correlator: +acceptlanguage: en-US, en-GB +Content-Type: multipart/mixed; + boundary="_002_E6527350F565F54A88C36C23F6C2B86702618AD0DF95SDCCPMSXMB5_" +MIME-Version: 1.0 + +--_002_E6527350F565F54A88C36C23F6C2B86702618AD0DF95SDCCPMSXMB5_ +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: base64 + +someencodedtext= + +--_002_E6527350F565F54A88C36C23F6C2B86702618AD0DF95SDCCPMSXMB5_ +Content-Type: document/pdf; name="document.pdf" +Content-Description: document.pdf +Content-Disposition: attachment; filename="document.pdf"; + size=62103; creation-date="Wed, 15 Sep 2010 17:54:27 GMT"; + modification-date="Wed, 15 Sep 2010 17:54:27 GMT" +Content-Transfer-Encoding: base64 + +somemoreencodedtext= + +--_002_E6527350F565F54A88C36C23F6C2B86702618AD0DF95SDCCPMSXMB5_-- + diff --git a/spec/fixtures/files/subject-bad-utf-8-trailing-base64.email b/spec/fixtures/files/subject-bad-utf-8-trailing-base64.email new file mode 100644 index 000000000..dad621877 --- /dev/null +++ b/spec/fixtures/files/subject-bad-utf-8-trailing-base64.email @@ -0,0 +1,5 @@ +From: foo@bar +To: baz@quux +Subject: =?UTF-8?B?aGVsbG/w?= + +Hello, this is the text of the email. diff --git a/spec/fixtures/files/subject-bad-utf-8-trailing-quoted-printable.email b/spec/fixtures/files/subject-bad-utf-8-trailing-quoted-printable.email new file mode 100644 index 000000000..b80deb4e8 --- /dev/null +++ b/spec/fixtures/files/subject-bad-utf-8-trailing-quoted-printable.email @@ -0,0 +1,5 @@ +From: foo@bar +To: baz@quux +Subject: =?UTF-8?Q?hello=F0=?= + +Hello, this is the text of the email. diff --git a/spec/fixtures/files/tnef-attachment-empty.email b/spec/fixtures/files/tnef-attachment-empty.email new file mode 100644 index 000000000..7967aa95b --- /dev/null +++ b/spec/fixtures/files/tnef-attachment-empty.email @@ -0,0 +1,196 @@ +From hello@blah.local Fri Feb 21 16:23:14 2013 +Return-path: <bar@example.org> +Envelope-to: foo@example.org +Delivery-date: Fri, 21 Feb 2013 16:23:14 +0000 +Content-Type: multipart/mixed; + boundary="_000_553468B23EE29B4F8836CBD0E1B2A15A275C3AA855POLNIEXMBV2po_" +From: <bar@example.org> +To: <foo@example.org> +Sender: <hello@blah.local> +Date: Fri, 21 Feb 2013 16:23:04 +0000 +Subject: here's a useless email +Message-ID: <12345@blah.local> +Accept-Language: en-US, en-GB +Content-Language: en-US +X-MS-Has-Attach: +X-MS-TNEF-Correlator: <12345@blah.local> +acceptlanguage: en-US, en-GB +MIME-Version: 1.0 + +--_000_553468B23EE29B4F8836CBD0E1B2A15A275C3AA855POLNIEXMBV2po_ +Content-Type: text/plain; charset="us-ascii" +Content-Transfer-Encoding: quoted-printable + +This attachment just has a body from one of the tests +in the tnef package in Debian. + +--_000_553468B23EE29B4F8836CBD0E1B2A15A275C3AA855POLNIEXMBV2po_ +Content-Disposition: attachment; filename="winmail.dat" +Content-Transfer-Encoding: base64 +Content-Type: application/ms-tnef; name="winmail.dat" + +eJ8+IiURAQaQCAAEAAAAAAABAAEAAQeQBgAIAAAA5AQAAAAAAADoAAENgAQAAgAA +AAIAAgABBYADAA4AAADVBwQAGQAKAA8AIwABADYBASCAAwAOAAAA1QcEABkACgAP +ACQAAQA3AQEJgAEAIQAAADBEREEwRkNCQ0MwN0MxNDE5MkVFODZGQzQyRDE1Qjk1 +AGYHAQSQBgBkAgAAAQAAAA8AAAAfAAEwAQAAABAAAAAzAGsAdQBzAGUAcgAyAAAA +HwACMAEAAAAGAAAARQBYAAAAAAAfAAMwAQAAAI4AAAAvAE8APQBCAFIALQBFAFgA +QwBIAC0AVABFAFMAVAAvAE8AVQA9AEYASQBSAFMAVAAgAEEARABNAEkATgBJAFMA +VABSAEEAVABJAFYARQAgAEcAUgBPAFUAUAAvAEMATgA9AFIARQBDAEkAUABJAEUA +TgBUAFMALwBDAE4APQAzAGsAdQBzAGUAcgAyAAAAAAADAAAwAAAAAAMA/18AAAAA +AwAVDAEAAAACAQswAQAAAEoAAABFWDovTz1CUi1FWENILVRFU1QvT1U9RklSU1Qg +QURNSU5JU1RSQVRJVkUgR1JPVVAvQ049UkVDSVBJRU5UUy9DTj0zS1VTRVIyAAAA +HwAgOgEAAAAQAAAAMwBrAHUAcwBlAHIAMgAAAAMA/V8BAAAACwBAOgAA+T8CAfdf +AQAAAGMAAAAAAAAA3KdAyMBCEBq0uQgAKy/hggEAAAAAAAAAL289QlItRVhDSC1U +RVNUL291PUZpcnN0IEFkbWluaXN0cmF0aXZlIEdyb3VwL2NuPVJlY2lwaWVudHMv +Y249M2t1c2VyMgAAAwAAOQAAAAAfAP45AQAAAEoAAAAzAGsAdQBzAGUAcgAyAEAA +YgByAGUAeABjAGgAYQBuAGcAZQAuAGQAbwBsAHAAaABpAG4AcwBlAGEAcgBjAGgA +LgBjAG8AbQAAAAAAAwBxOgAAAAAfAPZfAQAAABAAAAAzAGsAdQBzAGUAcgAyAAAA +m2sBA5AGAEwbAAAzAAAACwACAAEAAAAfABoAAQAAABIAAABJAFAATQAuAE4AbwB0 +AGUAAAAAAAMAJgAAAAAAAwA2AAAAAAAfADcAAQAAAB4AAABCAGkAbABsACAAbwBm +ACAAUgBpAGcAaAB0AHMAAAAAAEAAOQBgQvtkuknFAR8APQABAAAAAgAAAAAAAAAC +AUcAAQAAADgAAABjPXVzO2E9IDtwPUJSLUVYQ0gtVEVTVDtsPUJSLUVYQ0gtREVW +MS0wNTA0MjUxNzE1MzZaLTE0AB8AcAABAAAAHgAAAEIAaQBsAGwAIABvAGYAIABS +AGkAZwBoAHQAcwAAAAAAAgFxAAEAAAAWAAAAAcVJumT7yarjal9+TnmqsNvwaipi +/QAAHwAaDAEAAAAQAAAAMwBrAHIAZQBsAGEAeQAAAB8AHQ4BAAAAHgAAAEIAaQBs +AGwAIABvAGYAIABSAGkAZwBoAHQAcwAAAAAAAgETEAEAAADuFAAAPCFET0NUWVBF +IEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv +L0VOIj4NCjxIVE1MPjxIRUFEPg0KPE1FVEEgaHR0cC1lcXVpdj1Db250ZW50LVR5 +cGUgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXVzLWFzY2lpIj4NCjxNRVRB +IGNvbnRlbnQ9Ik1TSFRNTCA2LjAwLjM3OTAuMTgzMCIgbmFtZT1HRU5FUkFUT1I+ +PC9IRUFEPg0KPEJPRFk+DQo8RElWPg0KPERJVj48Rk9OVCBmYWNlPUFyaWFsIHNp +emU9Mj5USEUgQklMTCBPRiBSSUdIVFM8QlI+QW1lbmRtZW50cyAxLTEwIG9mIHRo +ZSANCkNvbnN0aXR1dGlvbjwvRk9OVD48L0RJVj4NCjxESVY+Jm5ic3A7PC9ESVY+ +DQo8RElWPjxGT05UIGZhY2U9QXJpYWwgc2l6ZT0yPlRoZSBDb252ZW50aW9ucyBv +ZiBhIG51bWJlciBvZiB0aGUgU3RhdGVzIGhhdmluZywgDQphdCB0aGUgdGltZSBv +ZiBhZG9wdGluZyB0aGUgQ29uc3RpdHV0aW9uLCBleHByZXNzZWQgYSBkZXNpcmUs +IGluIG9yZGVyIHRvIA0KcHJldmVudCBtaXNjb25zdHJ1Y3Rpb24gb3IgYWJ1c2Ug +b2YgaXRzIHBvd2VycywgdGhhdCBmdXJ0aGVyIGRlY2xhcmF0b3J5IGFuZCANCnJl +c3RyaWN0aXZlIGNsYXVzZXMgc2hvdWxkIGJlIGFkZGVkLCBhbmQgYXMgZXh0ZW5k +aW5nIHRoZSBncm91bmQgb2YgcHVibGljIA0KY29uZmlkZW5jZSBpbiB0aGUgR292 +ZXJubWVudCB3aWxsIGJlc3QgaW5zdXJlIHRoZSBiZW5lZmljZW50IGVuZHMgb2Yg +aXRzIA0KaW5zdGl0dXRpb247IDxCUj5SZXNvbHZlZCwgYnkgdGhlIFNlbmF0ZSBh +bmQgSG91c2Ugb2YgUmVwcmVzZW50YXRpdmVzIG9mIHRoZSANClVuaXRlZCBTdGF0 +ZXMgb2YgQW1lcmljYSwgaW4gQ29uZ3Jlc3MgYXNzZW1ibGVkLCB0d28tdGhpcmRz +IG9mIGJvdGggSG91c2VzIA0KY29uY3VycmluZywgdGhhdCB0aGUgZm9sbG93aW5n +IGFydGljbGVzIGJlIHByb3Bvc2VkIHRvIHRoZSBMZWdpc2xhdHVyZXMgb2YgdGhl +IA0Kc2V2ZXJhbCBTdGF0ZXMsIGFzIGFtZW5kbWVudHMgdG8gdGhlIENvbnN0aXR1 +dGlvbiBvZiB0aGUgVW5pdGVkIFN0YXRlczsgYWxsIG9yIA0KYW55IG9mIHdoaWNo +IGFydGljbGVzLCB3aGVuIHJhdGlmaWVkIGJ5IHRocmVlLWZvdXJ0aHMgb2YgdGhl +IHNhaWQgTGVnaXNsYXR1cmVzLCANCnRvIGJlIHZhbGlkIHRvIGFsbCBpbnRlbnRz +IGFuZCBwdXJwb3NlcyBhcyBwYXJ0IG9mIHRoZSBzYWlkIENvbnN0aXR1dGlvbiwg +DQpuYW1lbHk6IDwvRk9OVD48L0RJVj4NCjxESVY+Jm5ic3A7PC9ESVY+DQo8RElW +PjxGT05UIGZhY2U9QXJpYWwgc2l6ZT0yPkFtZW5kbWVudCBJPC9GT05UPjwvRElW +Pg0KPERJVj4mbmJzcDs8L0RJVj4NCjxESVY+PEZPTlQgZmFjZT1BcmlhbCBzaXpl +PTI+Q29uZ3Jlc3Mgc2hhbGwgbWFrZSBubyBsYXcgcmVzcGVjdGluZyBhbiANCmVz +dGFibGlzaG1lbnQgb2YgcmVsaWdpb24sIG9yIHByb2hpYml0aW5nIHRoZSBmcmVl +IGV4ZXJjaXNlIHRoZXJlb2Y7IG9yIA0KYWJyaWRnaW5nIHRoZSBmcmVlZG9tIG9m +IHNwZWVjaCwgb3Igb2YgdGhlIHByZXNzOyBvciB0aGUgcmlnaHQgb2YgdGhlIHBl +b3BsZSANCnBlYWNlYWJseSB0byBhc3NlbWJsZSwgYW5kIHRvIHBldGl0aW9uIHRo +ZSBnb3Zlcm5tZW50IGZvciBhIHJlZHJlc3Mgb2YgDQpncmlldmFuY2VzLiA8L0ZP +TlQ+PC9ESVY+DQo8RElWPiZuYnNwOzwvRElWPg0KPERJVj48Rk9OVCBmYWNlPUFy +aWFsIHNpemU9Mj5BbWVuZG1lbnQgSUk8L0ZPTlQ+PC9ESVY+DQo8RElWPiZuYnNw +OzwvRElWPg0KPERJVj48Rk9OVCBmYWNlPUFyaWFsIHNpemU9Mj5BIHdlbGwgcmVn +dWxhdGVkIG1pbGl0aWEsIGJlaW5nIG5lY2Vzc2FyeSB0byB0aGUgDQpzZWN1cml0 +eSBvZiBhIGZyZWUgc3RhdGUsIHRoZSByaWdodCBvZiB0aGUgcGVvcGxlIHRvIGtl +ZXAgYW5kIGJlYXIgYXJtcywgc2hhbGwgDQpub3QgYmUgaW5mcmluZ2VkLiA8L0ZP +TlQ+PC9ESVY+DQo8RElWPiZuYnNwOzwvRElWPg0KPERJVj48Rk9OVCBmYWNlPUFy +aWFsIHNpemU9Mj5BbWVuZG1lbnQgSUlJPC9GT05UPjwvRElWPg0KPERJVj4mbmJz +cDs8L0RJVj4NCjxESVY+PEZPTlQgZmFjZT1BcmlhbCBzaXplPTI+Tm8gc29sZGll +ciBzaGFsbCwgaW4gdGltZSBvZiBwZWFjZSBiZSBxdWFydGVyZWQgaW4gDQphbnkg +aG91c2UsIHdpdGhvdXQgdGhlIGNvbnNlbnQgb2YgdGhlIG93bmVyLCBub3IgaW4g +dGltZSBvZiB3YXIsIGJ1dCBpbiBhIG1hbm5lciANCnRvIGJlIHByZXNjcmliZWQg +YnkgbGF3LiA8L0ZPTlQ+PC9ESVY+DQo8RElWPiZuYnNwOzwvRElWPg0KPERJVj48 +Rk9OVCBmYWNlPUFyaWFsIHNpemU9Mj5BbWVuZG1lbnQgSVY8L0ZPTlQ+PC9ESVY+ +DQo8RElWPiZuYnNwOzwvRElWPg0KPERJVj48Rk9OVCBmYWNlPUFyaWFsIHNpemU9 +Mj5UaGUgcmlnaHQgb2YgdGhlIHBlb3BsZSB0byBiZSBzZWN1cmUgaW4gdGhlaXIg +DQpwZXJzb25zLCBob3VzZXMsIHBhcGVycywgYW5kIGVmZmVjdHMsIGFnYWluc3Qg +dW5yZWFzb25hYmxlIHNlYXJjaGVzIGFuZCANCnNlaXp1cmVzLCBzaGFsbCBub3Qg +YmUgdmlvbGF0ZWQsIGFuZCBubyB3YXJyYW50cyBzaGFsbCBpc3N1ZSwgYnV0IHVw +b24gcHJvYmFibGUgDQpjYXVzZSwgc3VwcG9ydGVkIGJ5IG9hdGggb3IgYWZmaXJt +YXRpb24sIGFuZCBwYXJ0aWN1bGFybHkgZGVzY3JpYmluZyB0aGUgcGxhY2UgDQp0 +byBiZSBzZWFyY2hlZCwgYW5kIHRoZSBwZXJzb25zIG9yIHRoaW5ncyB0byBiZSBz +ZWl6ZWQuIDwvRk9OVD48L0RJVj4NCjxESVY+Jm5ic3A7PC9ESVY+DQo8RElWPjxG +T05UIGZhY2U9QXJpYWwgc2l6ZT0yPkFtZW5kbWVudCBWPC9GT05UPjwvRElWPg0K +PERJVj4mbmJzcDs8L0RJVj4NCjxESVY+PEZPTlQgZmFjZT1BcmlhbCBzaXplPTI+ +Tm8gcGVyc29uIHNoYWxsIGJlIGhlbGQgdG8gYW5zd2VyIGZvciBhIGNhcGl0YWws +IG9yIA0Kb3RoZXJ3aXNlIGluZmFtb3VzIGNyaW1lLCB1bmxlc3Mgb24gYSBwcmVz +ZW50bWVudCBvciBpbmRpY3RtZW50IG9mIGEgZ3JhbmQganVyeSwgDQpleGNlcHQg +aW4gY2FzZXMgYXJpc2luZyBpbiB0aGUgbGFuZCBvciBuYXZhbCBmb3JjZXMsIG9y +IGluIHRoZSBtaWxpdGlhLCB3aGVuIGluIA0KYWN0dWFsIHNlcnZpY2UgaW4gdGlt +ZSBvZiB3YXIgb3IgcHVibGljIGRhbmdlcjsgbm9yIHNoYWxsIGFueSBwZXJzb24g +YmUgc3ViamVjdCANCmZvciB0aGUgc2FtZSBvZmZlbnNlIHRvIGJlIHR3aWNlIHB1 +dCBpbiBqZW9wYXJkeSBvZiBsaWZlIG9yIGxpbWI7IG5vciBzaGFsbCBiZSANCmNv +bXBlbGxlZCBpbiBhbnkgY3JpbWluYWwgY2FzZSB0byBiZSBhIHdpdG5lc3MgYWdh +aW5zdCBoaW1zZWxmLCBub3IgYmUgZGVwcml2ZWQgDQpvZiBsaWZlLCBsaWJlcnR5 +LCBvciBwcm9wZXJ0eSwgd2l0aG91dCBkdWUgcHJvY2VzcyBvZiBsYXc7IG5vciBz +aGFsbCBwcml2YXRlIA0KcHJvcGVydHkgYmUgdGFrZW4gZm9yIHB1YmxpYyB1c2Us +IHdpdGhvdXQganVzdCBjb21wZW5zYXRpb24uIDwvRk9OVD48L0RJVj4NCjxESVY+ +Jm5ic3A7PC9ESVY+DQo8RElWPjxGT05UIGZhY2U9QXJpYWwgc2l6ZT0yPkFtZW5k +bWVudCBWSTwvRk9OVD48L0RJVj4NCjxESVY+Jm5ic3A7PC9ESVY+DQo8RElWPjxG +T05UIGZhY2U9QXJpYWwgc2l6ZT0yPkluIGFsbCBjcmltaW5hbCBwcm9zZWN1dGlv +bnMsIHRoZSBhY2N1c2VkIHNoYWxsIA0KZW5qb3kgdGhlIHJpZ2h0IHRvIGEgc3Bl +ZWR5IGFuZCBwdWJsaWMgdHJpYWwsIGJ5IGFuIGltcGFydGlhbCBqdXJ5IG9mIHRo +ZSBzdGF0ZSANCmFuZCBkaXN0cmljdCB3aGVyZWluIHRoZSBjcmltZSBzaGFsbCBo +YXZlIGJlZW4gY29tbWl0dGVkLCB3aGljaCBkaXN0cmljdCBzaGFsbCANCmhhdmUg +YmVlbiBwcmV2aW91c2x5IGFzY2VydGFpbmVkIGJ5IGxhdywgYW5kIHRvIGJlIGlu +Zm9ybWVkIG9mIHRoZSBuYXR1cmUgYW5kIA0KY2F1c2Ugb2YgdGhlIGFjY3VzYXRp +b247IHRvIGJlIGNvbmZyb250ZWQgd2l0aCB0aGUgd2l0bmVzc2VzIGFnYWluc3Qg +aGltOyB0byANCmhhdmUgY29tcHVsc29yeSBwcm9jZXNzIGZvciBvYnRhaW5pbmcg +d2l0bmVzc2VzIGluIGhpcyBmYXZvciwgYW5kIHRvIGhhdmUgdGhlIA0KYXNzaXN0 +YW5jZSBvZiBjb3Vuc2VsIGZvciBoaXMgZGVmZW5zZS4gPC9GT05UPjwvRElWPg0K +PERJVj4mbmJzcDs8L0RJVj4NCjxESVY+PEZPTlQgZmFjZT1BcmlhbCBzaXplPTI+ +QW1lbmRtZW50IFZJSTwvRk9OVD48L0RJVj4NCjxESVY+Jm5ic3A7PC9ESVY+DQo8 +RElWPjxGT05UIGZhY2U9QXJpYWwgc2l6ZT0yPkluIHN1aXRzIGF0IGNvbW1vbiBs +YXcsIHdoZXJlIHRoZSB2YWx1ZSBpbiANCmNvbnRyb3ZlcnN5IHNoYWxsIGV4Y2Vl +ZCB0d2VudHkgZG9sbGFycywgdGhlIHJpZ2h0IG9mIHRyaWFsIGJ5IGp1cnkgc2hh +bGwgYmUgDQpwcmVzZXJ2ZWQsIGFuZCBubyBmYWN0IHRyaWVkIGJ5IGEganVyeSwg +c2hhbGwgYmUgb3RoZXJ3aXNlIHJlZXhhbWluZWQgaW4gYW55IA0KY291cnQgb2Yg +dGhlIFVuaXRlZCBTdGF0ZXMsIHRoYW4gYWNjb3JkaW5nIHRvIHRoZSBydWxlcyBv +ZiB0aGUgY29tbW9uIGxhdy4gDQo8L0ZPTlQ+PC9ESVY+DQo8RElWPiZuYnNwOzwv +RElWPg0KPERJVj48Rk9OVCBmYWNlPUFyaWFsIHNpemU9Mj5BbWVuZG1lbnQgVklJ +STwvRk9OVD48L0RJVj4NCjxESVY+Jm5ic3A7PC9ESVY+DQo8RElWPjxGT05UIGZh +Y2U9QXJpYWwgc2l6ZT0yPkV4Y2Vzc2l2ZSBiYWlsIHNoYWxsIG5vdCBiZSByZXF1 +aXJlZCwgbm9yIGV4Y2Vzc2l2ZSANCmZpbmVzIGltcG9zZWQsIG5vciBjcnVlbCBh +bmQgdW51c3VhbCBwdW5pc2htZW50cyBpbmZsaWN0ZWQuIDwvRk9OVD48L0RJVj4N +CjxESVY+Jm5ic3A7PC9ESVY+DQo8RElWPjxGT05UIGZhY2U9QXJpYWwgc2l6ZT0y +PkFtZW5kbWVudCBJWDwvRk9OVD48L0RJVj4NCjxESVY+Jm5ic3A7PC9ESVY+DQo8 +RElWPjxGT05UIGZhY2U9QXJpYWwgc2l6ZT0yPlRoZSBlbnVtZXJhdGlvbiBpbiB0 +aGUgQ29uc3RpdHV0aW9uLCBvZiBjZXJ0YWluIA0KcmlnaHRzLCBzaGFsbCBub3Qg +YmUgY29uc3RydWVkIHRvIGRlbnkgb3IgZGlzcGFyYWdlIG90aGVycyByZXRhaW5l +ZCBieSB0aGUgDQpwZW9wbGUuIDwvRk9OVD48L0RJVj4NCjxESVY+Jm5ic3A7PC9E +SVY+DQo8RElWPjxGT05UIGZhY2U9QXJpYWwgc2l6ZT0yPkFtZW5kbWVudCBYPC9G +T05UPjwvRElWPg0KPERJVj4mbmJzcDs8L0RJVj4NCjxESVY+PEZPTlQgZmFjZT1B +cmlhbCBzaXplPTI+VGhlIHBvd2VycyBub3QgZGVsZWdhdGVkIHRvIHRoZSBVbml0 +ZWQgU3RhdGVzIGJ5IA0KdGhlIENvbnN0aXR1dGlvbiwgbm9yIHByb2hpYml0ZWQg +YnkgaXQgdG8gdGhlIHN0YXRlcywgYXJlIHJlc2VydmVkIHRvIHRoZSBzdGF0ZXMg +DQpyZXNwZWN0aXZlbHksIG9yIHRvIHRoZSBwZW9wbGUuIDwvRk9OVD48L0RJVj48 +L0RJVj48L0JPRFk+PC9IVE1MPg0KAAAfADUQAQAAAKIAAAA8ADQANQAyADAARgA2 +ADEANQAxAEQAQQBGADIAQQA0ADQAQgBBADgANwA4AEIARgAyAEYAMwA4ADAAMwA0 +ADgARQAyADYARQA1AEAAYgByAC0AZQB4AGMAaAAtAGQAZQB2ADEALgBiAHIAZQB4 +AGMAaABhAG4AZwBlAC4AZABvAGwAcABoAGkAbgBzAGUAYQByAGMAaAAuAGMAbwBt +AD4AAAAAAAMAgBD/////HwDzEAEAAAAmAAAAQgBpAGwAbAAgAG8AZgAgAFIAaQBn +AGgAdABzAC4ARQBNAEwAAAAAAAsA9BAAAAAACwD1EAAAAAALAPYQAAAAAEAABzBR +lpFluknFAUAACDBRlpFluknFAQMA3j+fTgAAAwDxPwkEAAAfAPg/AQAAABAAAAAz +AGsAcgBlAGwAYQB5AAAAAgH5PwEAAABjAAAAAAAAANynQMjAQhAatLkIACsv4YIB +AAAAAAAAAC9PPUJSLUVYQ0gtVEVTVC9PVT1GSVJTVCBBRE1JTklTVFJBVElWRSBH +Uk9VUC9DTj1SRUNJUElFTlRTL0NOPTNLUkVMQVkAAB8A+j8BAAAAEAAAADMAawBy +AGUAbABhAHkAAAACAfs/AQAAAGMAAAAAAAAA3KdAyMBCEBq0uQgAKy/hggEAAAAA +AAAAL089QlItRVhDSC1URVNUL09VPUZJUlNUIEFETUlOSVNUUkFUSVZFIEdST1VQ +L0NOPVJFQ0lQSUVOVFMvQ049M0tSRUxBWQAAAwD9P+QEAAADABlAAAAAAAMAGkAA +AAAAHwAwQAEAAAAQAAAAMwBLAFIARQBMAEEAWQAAAB8AMUABAAAAEAAAADMASwBS +AEUATABBAFkAAAAfADhAAQAAABAAAAAzAEsAUgBFAEwAQQBZAAAAHwA5QAEAAAAQ +AAAAMwBLAFIARQBMAEEAWQAAAAMAdkD/////AwACWQAAFgADAAlZAgAAAAsAhYEI +IAYAAAAAAMAAAAAAAABGAAAAAA6FAAAAAAAAAwCdgQggBgAAAAAAwAAAAAAAAEYA +AAAAUoUAAJjDAQAfAJ6BCCAGAAAAAADAAAAAAAAARgAAAABUhQAAAQAAAAoAAAAx +ADEALgAwAAAAAAADAOmBCCAGAAAAAADAAAAAAAAARgAAAAABhQAAAAAAAAsA7oEI +IAYAAAAAAMAAAAAAAABGAAAAAAOFAAAAAAAAAwD4gQggBgAAAAAAwAAAAAAAAEYA +AAAAEIUAAAAAAAADAP+BCCAGAAAAAADAAAAAAAAARgAAAAAYhQAAAAAAAAsAIIII +IAYAAAAAAMAAAAAAAABGAAAAAAaFAAAAAAAACwAkggggBgAAAAAAwAAAAAAAAEYA +AAAAgoUAAAAAAAAfACaCCCAGAAAAAADAAAAAAAAARgAAAACDhQAAAQAAACYAAAA0 +ADAANQAxADMAMQA1ADEANwAtADIANQAwADQAMgAwADAANQAAAAAAAwBxggggBgAA +AAAAwAAAAAAAAEYAAAAAk4UAAAAAAAALACkAAAAAAAsAIwAAAAAAAgF/AAEAAABR +AAAAPDQ1MjBGNjE1MURBRjJBNDRCQTg3OEJGMkYzODAzNDhFMjZFNUBici1leGNo +LWRldjEuYnJleGNoYW5nZS5kb2xwaGluc2VhcmNoLmNvbT4AAAAAC/o= + +--_000_553468B23EE29B4F8836CBD0E1B2A15A275C3AA855POLNIEXMBV2po_-- + diff --git a/spec/fixtures/files/tnef-attachment-truncated.email b/spec/fixtures/files/tnef-attachment-truncated.email new file mode 100644 index 000000000..365a5a442 --- /dev/null +++ b/spec/fixtures/files/tnef-attachment-truncated.email @@ -0,0 +1,34 @@ +From hello@blah.local Fri Feb 21 16:23:14 2013 +Return-path: <bar@example.org> +Envelope-to: foo@example.org +Delivery-date: Fri, 21 Feb 2013 16:23:14 +0000 +Content-Type: multipart/mixed; + boundary="_000_553468B23EE29B4F8836CBD0E1B2A15A275C3AA855POLNIEXMBV2po_" +From: <bar@example.org> +To: <foo@example.org> +Sender: <hello@blah.local> +Date: Fri, 21 Feb 2013 16:23:04 +0000 +Subject: here's a useless email +Message-ID: <12345@blah.local> +Accept-Language: en-US, en-GB +Content-Language: en-US +X-MS-Has-Attach: +X-MS-TNEF-Correlator: <12345@blah.local> +acceptlanguage: en-US, en-GB +MIME-Version: 1.0 + +--_000_553468B23EE29B4F8836CBD0E1B2A15A275C3AA855POLNIEXMBV2po_ +Content-Type: text/plain; charset="us-ascii" +Content-Transfer-Encoding: quoted-printable + +Some introductory text here, before the malformed TNEF attachment. + +--_000_553468B23EE29B4F8836CBD0E1B2A15A275C3AA855POLNIEXMBV2po_ +Content-Disposition: attachment; filename="winmail.dat" +Content-Transfer-Encoding: base64 +Content-Type: application/ms-tnef; name="winmail.dat" + +eJ8+IkV9AQaQCAAEAAAAAAABAAEAAQeQBgAIAAAA5AQAAAAAAADoAAEJgAEAIQAAAEMyRUUzRUYx + +--_000_553468B23EE29B4F8836CBD0E1B2A15A275C3AA855POLNIEXMBV2po_-- + diff --git a/spec/fixtures/foi_attachments.yml b/spec/fixtures/foi_attachments.yml deleted file mode 100644 index 8b1378917..000000000 --- a/spec/fixtures/foi_attachments.yml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/spec/fixtures/info_request_events.yml b/spec/fixtures/info_request_events.yml index c1a00ad47..3907703d8 100644 --- a/spec/fixtures/info_request_events.yml +++ b/spec/fixtures/info_request_events.yml @@ -171,3 +171,14 @@ anonymous_external_outgoing_message_event: created_at: 2009-01-03 02:23:45.6789100 described_state: waiting_response calculated_state: waiting_response + +other_request_outgoing_message_event: + id: 916 + params_yaml: "--- \n\ + :outgoing_message_id: 10\n" + outgoing_message_id: 10 + info_request_id: 111 + event_type: sent + created_at: <%= Time.now %> + described_state: waiting_response + calculated_state: waiting_response diff --git a/spec/fixtures/info_requests.yml b/spec/fixtures/info_requests.yml index 9361ec486..97effd036 100644 --- a/spec/fixtures/info_requests.yml +++ b/spec/fixtures/info_requests.yml @@ -107,3 +107,15 @@ anonymous_external_request: awaiting_description: false comments_allowed: true idhash: 7654321a +other_request: + id: 111 + title: Another request + url_title: another_request + created_at: 2010-01-01 02:23:45.6789100 + updated_at: 2010-01-01 02:23:45.6789100 + public_body_id: 7 + user_id: 6 + described_state: waiting_response + awaiting_description: false + comments_allowed: true + idhash: b234567 diff --git a/spec/fixtures/locale/en/app.po b/spec/fixtures/locale/en/app.po index 91af9b72b..ee5c8d9c8 100644 --- a/spec/fixtures/locale/en/app.po +++ b/spec/fixtures/locale/en/app.po @@ -31,7 +31,7 @@ msgid "" msgstr "" #: app/views/comment/_comment_form.rhtml:16 -msgid " (<strong>no ranty</strong> politics, read our <a href=\"%s\">moderation policy</a>)" +msgid " (<strong>no ranty</strong> politics, read our <a href=\"{{url}}\">moderation policy</a>)" msgstr "" #: app/views/request/upload_response.rhtml:40 @@ -71,7 +71,7 @@ msgstr "" #: app/views/public_body/view_email.rhtml:30 msgid "" -" If you know the address to use, then please <a href=\"%s\">send it to us</a>.\n" +" If you know the address to use, then please <a href=\"{{url}}\">send it to us</a>.\n" " You may be able to find the address on their website, or by phoning them up and asking." msgstr "" @@ -123,20 +123,20 @@ msgid " when you send this message." msgstr "" #: app/views/public_body/show.rhtml:87 -msgid "%d Freedom of Information request to %s" -msgid_plural "%d Freedom of Information requests to %s" +msgid "{{count}} Freedom of Information request to {{public_body_name}}" +msgid_plural "{{count}} Freedom of Information requests to {{public_body_name}}" msgstr[0] "" msgstr[1] "" #: app/views/general/frontpage.rhtml:43 -msgid "%d request" -msgid_plural "%d requests" +msgid "{{count}} request" +msgid_plural "{{count}} requests" msgstr[0] "" msgstr[1] "" #: app/views/public_body/_body_listing_single.rhtml:21 -msgid "%d request made." -msgid_plural "%d requests made." +msgid "{{count}} request made." +msgid_plural "{{count}} requests made." msgstr[0] "" msgstr[1] "" @@ -187,43 +187,37 @@ msgstr "" msgid "3. Now check your request" msgstr "" -#: app/views/public_body/show.rhtml:56 -msgid "<a class=\"link_button_green\" href=\"{{url}}\">{{text}}</a>" -msgstr "" - #: app/views/request/_after_actions.rhtml:9 -msgid "<a href=\"%s\">Add an annotation</a> (to help the requester or others)" +msgid "<a href=\"{{url}}\">Add an annotation</a> (to help the requester or others)" msgstr "" #: app/views/public_body/list.rhtml:29 -msgid "<a href=\"%s\">Are we missing a public authority?</a>." +msgid "Are we missing a public authority?" msgstr "" #: app/views/request/_sidebar.rhtml:39 -msgid "" -"<a href=\"%s\">Are you the owner of\n" -" any commercial copyright on this page?</a>" +msgid "Are you the owner of any commercial copyright on this page?" msgstr "" #: app/views/general/search.rhtml:168 -msgid "<a href=\"%s\">Browse all</a> or <a href=\"%s\">ask us to add one</a>." +msgid "<a href=\"{{browse_url}}\">Browse all</a> or <a href=\"{{add_url}}\">ask us to add one</a>." msgstr "" #: app/views/public_body/list.rhtml:51 -msgid "<a href=\"%s\">Can't find the one you want?</a>" +msgid "Can't find the one you want?" msgstr "" #: app/views/user/show.rhtml:118 -msgid "<a href=\"%s\">Sign in</a> to change password, subscriptions and more ({{user_name}} only)" +msgid "<a href=\"{{url}}\">Sign in</a> to change password, subscriptions and more ({{user_name}} only)" msgstr "" #: app/views/request/_followup.rhtml:66 app/views/request/_followup.rhtml:73 #: app/views/request/show.rhtml:83 app/views/request/show.rhtml:87 -msgid "<a href=\"%s\">details</a>" +msgid "details" msgstr "" #: app/views/request/_followup.rhtml:101 -msgid "<a href=\"%s\">what's that?</a>" +msgid "what's that?" msgstr "" #: app/controllers/request_game_controller.rb:23 @@ -293,11 +287,11 @@ msgid "<p>We're glad you got some of the information that you wanted. If you fou msgstr "" #: app/controllers/request_controller.rb:318 -msgid "<p>You do not need to include your email in the request in order to get a reply (<a href=\"%s\">details</a>).</p>" +msgid "<p>You do not need to include your email in the request in order to get a reply (<a href=\"{{url}}\">details</a>).</p>" msgstr "" #: app/controllers/request_controller.rb:316 -msgid "<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>" +msgid "<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=\"{{url}}\">details</a>).</p>" msgstr "" #: app/controllers/request_controller.rb:324 @@ -327,7 +321,7 @@ msgstr "" #: app/views/request/new.rhtml:135 msgid "" "<strong> Can I request information about myself?</strong>\n" -"\t\t\t<a href=\"%s\">No! (Click here for details)</a>" +"\t\t\t<a href=\"{{url}}\">No! (Click here for details)</a>" msgstr "" #: app/views/general/_advanced_search_tips.rhtml:12 @@ -413,7 +407,7 @@ msgstr "" #: app/views/request/preview.rhtml:31 msgid "" "<strong>Privacy note:</strong> If you want to request private information about\n" -" yourself then <a href=\"%s\">click here</a>." +" yourself then <a href=\"{{url}}\">click here</a>." msgstr "" #: app/views/user/set_crop_profile_photo.rhtml:35 @@ -576,7 +570,7 @@ msgstr "" #: app/views/request/show_response.rhtml:29 msgid "" "At the bottom of this page, write a reply to them trying to persuade them to scan it in\n" -" (<a href=\"%s\">more details</a>)." +" (<a href=\"{{url}}\">more details</a>)." msgstr "" #: app/views/request/upload_response.rhtml:33 @@ -921,7 +915,7 @@ msgstr "" #: app/views/request/upload_response.rhtml:23 msgid "" "Enter your response below. You may attach one file (use email, or \n" -"<a href=\"%s\">contact us</a> if you need more)." +"<a href=\"{{url}}\">contact us</a> if you need more)." msgstr "" #: app/models/info_request.rb:259 app/models/info_request.rb:277 @@ -950,16 +944,16 @@ msgstr "" #: app/views/request/new.rhtml:128 msgid "" -"Everything that you enter on this page \n" +"Everything that you enter on this page\n" " will be <strong>displayed publicly</strong> on\n" -" this website forever (<a href=\"%s\">why?</a>)." +" this website forever (<a href=\"{{url}}\">why?</a>)." msgstr "" #: app/views/request/new.rhtml:120 msgid "" -"Everything that you enter on this page, including <strong>your name</strong>, \n" +"Everything that you enter on this page, including <strong>your name</strong>,\n" " will be <strong>displayed publicly</strong> on\n" -" this website forever (<a href=\"%s\">why?</a>)." +" this website forever (<a href=\"{{url}}\">why?</a>)." msgstr "" #: locale/model_attributes.rb:68 @@ -1007,7 +1001,7 @@ msgid "Failed to convert image to a PNG" msgstr "" #: app/models/profile_photo.rb:105 -msgid "Failed to convert image to the correct size: at %{cols}x%{rows}, need %{width}x%{height}" +msgid "Failed to convert image to the correct size: at {{cols}}x{{rows}}, need {{width}}x{{height}}" msgstr "" #: app/views/general/search.rhtml:117 @@ -1018,7 +1012,7 @@ msgstr "" msgid "" "First, type in the <strong>name of the UK public authority</strong> you'd \n" " like information from. <strong>By law, they have to respond</strong>\n" -" (<a href=\"%s#%s\">why?</a>)." +" (<a href=\"{{url}}\">why?</a>)." msgstr "" #: locale/model_attributes.rb:88 @@ -1147,7 +1141,7 @@ msgstr "" msgid "" "From the request page, try replying to a particular message, rather than sending\n" " a general followup. If you need to make a general followup, and know\n" -" an email which will go to the right place, please <a href=\"%s\">send it to us</a>." +" an email which will go to the right place, please <a href=\"{{url}}\">send it to us</a>." msgstr "" #: app/views/request/_correspondence.rhtml:12 @@ -1278,7 +1272,7 @@ msgid "I've received an <strong>error message</strong>" msgstr "" #: app/views/public_body/view_email.rhtml:28 -msgid "If the address is wrong, or you know a better address, please <a href=\"%s\">contact us</a>." +msgid "If the address is wrong, or you know a better address, please <a href=\"{{url}}\">contact us</a>." msgstr "" #: app/views/request_mailer/stopped_responses.rhtml:10 @@ -1292,21 +1286,21 @@ msgstr "" msgid "" "If you are dissatisfied by the response you got from\n" " the public authority, you have the right to\n" -" complain (<a href=\"%s\">details</a>)." +" complain (<a href=\"{{url}}\">details</a>)." msgstr "" #: app/views/user/no_cookies.rhtml:20 -msgid "If you are still having trouble, please <a href=\"%s\">contact us</a>." +msgid "If you are still having trouble, please <a href=\"{{url}}\">contact us</a>." msgstr "" #: app/views/request/hidden.rhtml:15 -msgid "If you are the requester, then you may <a href=\"%s\">sign in</a> to view the request." +msgid "If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the request." msgstr "" #: app/views/request/new.rhtml:123 msgid "" "If you are thinking of using a pseudonym,\n" -" please <a href=\"%s\">read this first</a>." +" please <a href=\"{{url}}\">read this first</a>." msgstr "" #: app/views/request/show.rhtml:105 @@ -1497,7 +1491,7 @@ msgid "Joined {{site_name}} in" msgstr "" #: app/views/request/new.rhtml:106 -msgid "Keep it <strong>focused</strong>, you'll be more likely to get what you want (<a href=\"%s\">why?</a>)." +msgid "Keep it <strong>focused</strong>, you'll be more likely to get what you want (<a href=\"{{url}}\">why?</a>)." msgstr "" #: app/views/request/_request_filter_form.rhtml:6 @@ -1837,7 +1831,7 @@ msgid "Please" msgstr "" #: app/views/user/no_cookies.rhtml:15 -msgid "Please <a href=\"%s\">get in touch</a> with us so we can fix it." +msgid "Please <a href=\"{{url}}\">get in touch</a> with us so we can fix it." msgstr "" #: app/views/request/show.rhtml:52 @@ -1990,7 +1984,7 @@ msgid "" msgstr "" #: app/models/outgoing_message.rb:157 -msgid "Please sign at the bottom with your name, or alter the \"%{signoff}\" signature" +msgid "Please sign at the bottom with your name, or alter the \"{{signoff}}\" signature" msgstr "" #: app/views/user/sign.rhtml:8 @@ -2337,8 +2331,9 @@ msgid "Search the site to find what you were looking for." msgstr "" #: app/views/public_body/show.rhtml:85 -msgid "Search within the %d Freedom of Information requests to %s" -msgid_plural "Search within the %d Freedom of Information requests made to %s" +msgid "Search within the {{count}} Freedom of Information requests to {{public_body_name}}" +msgid_plural "Search within the {{count}} Freedom of Information requests to {{public_body_name}}" + msgstr[0] "" msgstr[1] "" @@ -2680,10 +2675,7 @@ msgid "The request was refused by the public authority" msgstr "" #: app/views/request/hidden.rhtml:9 -msgid "" -"The request you have tried to view has been removed. There are\n" -"various reasons why we might have done this, sorry we can't be more specific here. Please <a\n" -" href=\"%s\">contact us</a> if you have any questions." +msgid "The request you have tried to view has been removed. There are\\nvarious reasons why we might have done this, sorry we can't be more specific here. Please <a\\n href=\"{{url}}\">contact us</a> if you have any questions." msgstr "" #: app/views/general/_advanced_search_tips.rhtml:36 @@ -2692,14 +2684,14 @@ msgstr "" #: app/views/request/_followup.rhtml:59 msgid "" -"The response to your request has been <strong>delayed</strong>. You can say that, \n" +"The response to your request has been <strong>delayed</strong>. You can say that,\n" " by law, the authority should normally have responded\n" " <strong>promptly</strong> and" msgstr "" #: app/views/request/_followup.rhtml:71 msgid "" -"The response to your request is <strong>long overdue</strong>. You can say that, by \n" +"The response to your request is <strong>long overdue</strong>. You can say that, by\n" " law, under all circumstances, the authority should have responded\n" " by now" msgstr "" @@ -2804,15 +2796,9 @@ msgstr "" msgid "There are {{count}} new annotations on your {{info_request}} request. Follow this link to see what they wrote." msgstr "" -#: app/views/public_body/show.rhtml:7 -msgid "There is %d person following this authority" -msgid_plural "There are %d people following this authority" -msgstr[0] "" -msgstr[1] "" - #: app/views/request/_sidebar.rhtml:5 -msgid "There is %d person following this request" -msgid_plural "There are %d people following this request" +msgid "There is {{count}} person following this request" +msgid_plural "There are {{count}} people following this request" msgstr[0] "" msgstr[1] "" @@ -2876,7 +2862,7 @@ msgstr "" #: app/views/request/_hidden_correspondence.rhtml:23 msgid "" "This comment has been hidden. See annotations to\n" -" find out why. If you are the requester, then you may <a href=\"%s\">sign in</a> to view the response." +" find out why. If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the response." msgstr "" #: app/views/request/new.rhtml:63 @@ -2906,7 +2892,7 @@ msgstr "" #: app/views/request/_hidden_correspondence.rhtml:17 msgid "" "This outgoing message has been hidden. See annotations to\n" -"\t\t\t\t\t\tfind out why. If you are the requester, then you may <a href=\"%s\">sign in</a> to view the response." +"\t\t\t\t\t\tfind out why. If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the response." msgstr "" #: app/views/request/_describe_state.rhtml:44 @@ -2919,14 +2905,14 @@ msgid "This person has made no Freedom of Information requests using this site." msgstr "" #: app/views/user/show.rhtml:149 -msgid "This person's %d Freedom of Information request" -msgid_plural "This person's %d Freedom of Information requests" +msgid "This person's {{count}} Freedom of Information request" +msgid_plural "This person's {{count}} Freedom of Information requests" msgstr[0] "" msgstr[1] "" #: app/views/user/show.rhtml:179 -msgid "This person's %d annotation" -msgid_plural "This person's %d annotations" +msgid "This person's {{count}} annotation" +msgid_plural "This person's {{count}} annotations" msgstr[0] "" msgstr[1] "" @@ -2965,7 +2951,7 @@ msgstr "" #: app/views/request/show.rhtml:11 msgid "" "This request is hidden, so that only you the requester can see it. Please\n" -" <a href=\"%s\">contact us</a> if you are not sure why." +" <a href=\"{{url}}\">contact us</a> if you are not sure why." msgstr "" #: app/views/request/_describe_state.rhtml:7 @@ -2976,7 +2962,7 @@ msgstr "" #: app/views/request/_hidden_correspondence.rhtml:10 msgid "" "This response has been hidden. See annotations to find out why.\n" -" If you are the requester, then you may <a href=\"%s\">sign in</a> to view the response." +" If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the response." msgstr "" #: app/views/request/details.rhtml:6 @@ -3202,7 +3188,7 @@ msgstr "" msgid "" "Unfortunately we don't know the FOI\n" "email address for that authority, so we can't validate this.\n" -"Please <a href=\"%s\">contact us</a> to sort it out." +"Please <a href=\"{{url}}\">contact us</a> to sort it out." msgstr "" #: app/views/request/new_bad_contact.rhtml:5 @@ -3439,7 +3425,7 @@ msgid "" msgstr "" #: app/views/request/new_please_describe.rhtml:16 -msgid "When you're done, <strong>come back here</strong>, <a href=\"%s\">reload this page</a> and file your new request." +msgid "When you're done, <strong>come back here</strong>, <a href=\"{{url}}\">reload this page</a> and file your new request." msgstr "" #: app/views/request/show_response.rhtml:13 @@ -3571,7 +3557,7 @@ msgstr "" msgid "" "You may be able to find\n" " one on their website, or by phoning them up and asking. If you manage\n" -" to find one, then please <a href=\"%s\">send it to us</a>." +" to find one, then please <a href=\"{{url}}\">send it to us</a>." msgstr "" #: app/views/request/new_bad_contact.rhtml:6 @@ -3642,24 +3628,19 @@ msgid "You've now cleared your profile photo" msgstr "" #: app/views/user/show.rhtml:149 -msgid "Your %d Freedom of Information request" -msgid_plural "Your %d Freedom of Information requests" +msgid "Your {{count}} Freedom of Information request" +msgid_plural "Your {{count}} Freedom of Information requests" msgstr[0] "" msgstr[1] "" #: app/views/user/show.rhtml:179 -msgid "Your %d annotation" -msgid_plural "Your %d annotations" +msgid "Your {{count}} annotation" +msgid_plural "Your {{count}} annotations" msgstr[0] "" msgstr[1] "" #: app/views/user/_signup.rhtml:22 -msgid "" -"Your <strong>name will appear publicly</strong> \n" -" (<a href=\"%s\">why?</a>)\n" -" on this website and in search engines. If you\n" -" are thinking of using a pseudonym, please \n" -" <a href=\"%s\">read this first</a>." +msgid "Your <strong>name will appear publicly</strong>\\n (<a href=\"{{why_url}}\">why?</a>)\\n on this website and in search engines. If you\\n are thinking of using a pseudonym, please\\n <a href=\"{{help_url}}\">read this first</a>." msgstr "" #: app/views/user/show.rhtml:172 @@ -3682,7 +3663,7 @@ msgid "Your email subscriptions" msgstr "" #: app/controllers/request_controller.rb:598 -msgid "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." +msgid "Your follow up has not been sent because this request has been stopped to prevent spam. Please <a href=\"{{url}}\">contact us</a> if you really want to send a follow up message." msgstr "" #: app/controllers/request_controller.rb:626 @@ -3712,7 +3693,7 @@ msgstr "" #: app/views/request/preview.rhtml:8 msgid "" "Your name, request and any responses will appear in <strong>search engines</strong>\n" -" (<a href=\"%s\">details</a>)." +" (<a href=\"{{url}}\">details</a>)." msgstr "" #: app/views/user/_signup.rhtml:18 @@ -3746,7 +3727,7 @@ msgid "Your request:" msgstr "" #: app/views/request/upload_response.rhtml:8 -msgid "Your response will <strong>appear on the Internet</strong>, <a href=\"%s\">read why</a> and answers to other questions." +msgid "Your response will <strong>appear on the Internet</strong>, <a href=\"{{url}}\">read why</a> and answers to other questions." msgstr "" #: app/views/comment/new.rhtml:63 @@ -3990,7 +3971,7 @@ msgid "" "no longer exists. If you are trying to make\n" " From the request page, try replying to a particular message, rather than sending\n" " a general followup. If you need to make a general followup, and know\n" -" an email which will go to the right place, please <a href=\"%s\">send it to us</a>." +" an email which will go to the right place, please <a href=\"{{url}}\">send it to us</a>." msgstr "" #: app/views/request/show.rhtml:72 diff --git a/spec/fixtures/locale/en_GB/app.po b/spec/fixtures/locale/en_GB/app.po index 91af9b72b..84997a319 100644 --- a/spec/fixtures/locale/en_GB/app.po +++ b/spec/fixtures/locale/en_GB/app.po @@ -31,7 +31,7 @@ msgid "" msgstr "" #: app/views/comment/_comment_form.rhtml:16 -msgid " (<strong>no ranty</strong> politics, read our <a href=\"%s\">moderation policy</a>)" +msgid " (<strong>no ranty</strong> politics, read our <a href=\"{{url}}\">moderation policy</a>)" msgstr "" #: app/views/request/upload_response.rhtml:40 @@ -71,7 +71,7 @@ msgstr "" #: app/views/public_body/view_email.rhtml:30 msgid "" -" If you know the address to use, then please <a href=\"%s\">send it to us</a>.\n" +" If you know the address to use, then please <a href=\"{{url}}\">send it to us</a>.\n" " You may be able to find the address on their website, or by phoning them up and asking." msgstr "" @@ -123,20 +123,20 @@ msgid " when you send this message." msgstr "" #: app/views/public_body/show.rhtml:87 -msgid "%d Freedom of Information request to %s" -msgid_plural "%d Freedom of Information requests to %s" +msgid "{{count}} Freedom of Information request to {{public_body_name}}" +msgid_plural "{{count}} Freedom of Information requests to {{public_body_name}}" msgstr[0] "" msgstr[1] "" #: app/views/general/frontpage.rhtml:43 -msgid "%d request" -msgid_plural "%d requests" +msgid "{{count}} request" +msgid_plural "{{count}} requests" msgstr[0] "" msgstr[1] "" #: app/views/public_body/_body_listing_single.rhtml:21 -msgid "%d request made." -msgid_plural "%d requests made." +msgid "{{count}} request made." +msgid_plural "{{count}} requests made." msgstr[0] "" msgstr[1] "" @@ -187,43 +187,37 @@ msgstr "" msgid "3. Now check your request" msgstr "" -#: app/views/public_body/show.rhtml:56 -msgid "<a class=\"link_button_green\" href=\"{{url}}\">{{text}}</a>" -msgstr "" - #: app/views/request/_after_actions.rhtml:9 -msgid "<a href=\"%s\">Add an annotation</a> (to help the requester or others)" +msgid "<a href=\"{{url}}\">Add an annotation</a> (to help the requester or others)" msgstr "" #: app/views/public_body/list.rhtml:29 -msgid "<a href=\"%s\">Are we missing a public authority?</a>." +msgid "Are we missing a public authority?" msgstr "" #: app/views/request/_sidebar.rhtml:39 -msgid "" -"<a href=\"%s\">Are you the owner of\n" -" any commercial copyright on this page?</a>" +msgid "Are you the owner of any commercial copyright on this page?" msgstr "" #: app/views/general/search.rhtml:168 -msgid "<a href=\"%s\">Browse all</a> or <a href=\"%s\">ask us to add one</a>." +msgid "<a href=\"{{browse_url}}\">Browse all</a> or <a href=\"{{add_url}}\">ask us to add one</a>." msgstr "" #: app/views/public_body/list.rhtml:51 -msgid "<a href=\"%s\">Can't find the one you want?</a>" +msgid "Can't find the one you want?" msgstr "" #: app/views/user/show.rhtml:118 -msgid "<a href=\"%s\">Sign in</a> to change password, subscriptions and more ({{user_name}} only)" +msgid "<a href=\"{{url}}\">Sign in</a> to change password, subscriptions and more ({{user_name}} only)" msgstr "" #: app/views/request/_followup.rhtml:66 app/views/request/_followup.rhtml:73 #: app/views/request/show.rhtml:83 app/views/request/show.rhtml:87 -msgid "<a href=\"%s\">details</a>" +msgid "details" msgstr "" #: app/views/request/_followup.rhtml:101 -msgid "<a href=\"%s\">what's that?</a>" +msgid "what's that?" msgstr "" #: app/controllers/request_game_controller.rb:23 @@ -293,11 +287,11 @@ msgid "<p>We're glad you got some of the information that you wanted. If you fou msgstr "" #: app/controllers/request_controller.rb:318 -msgid "<p>You do not need to include your email in the request in order to get a reply (<a href=\"%s\">details</a>).</p>" +msgid "<p>You do not need to include your email in the request in order to get a reply (<a href=\"{{url}}\">details</a>).</p>" msgstr "" #: app/controllers/request_controller.rb:316 -msgid "<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>" +msgid "<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=\"{{url}}\">details</a>).</p>" msgstr "" #: app/controllers/request_controller.rb:324 @@ -327,7 +321,7 @@ msgstr "" #: app/views/request/new.rhtml:135 msgid "" "<strong> Can I request information about myself?</strong>\n" -"\t\t\t<a href=\"%s\">No! (Click here for details)</a>" +"\t\t\t<a href=\"{{url}}\">No! (Click here for details)</a>" msgstr "" #: app/views/general/_advanced_search_tips.rhtml:12 @@ -413,7 +407,7 @@ msgstr "" #: app/views/request/preview.rhtml:31 msgid "" "<strong>Privacy note:</strong> If you want to request private information about\n" -" yourself then <a href=\"%s\">click here</a>." +" yourself then <a href=\"{{url}}\">click here</a>." msgstr "" #: app/views/user/set_crop_profile_photo.rhtml:35 @@ -576,7 +570,7 @@ msgstr "" #: app/views/request/show_response.rhtml:29 msgid "" "At the bottom of this page, write a reply to them trying to persuade them to scan it in\n" -" (<a href=\"%s\">more details</a>)." +" (<a href=\"{{url}}\">more details</a>)." msgstr "" #: app/views/request/upload_response.rhtml:33 @@ -921,7 +915,7 @@ msgstr "" #: app/views/request/upload_response.rhtml:23 msgid "" "Enter your response below. You may attach one file (use email, or \n" -"<a href=\"%s\">contact us</a> if you need more)." +"<a href=\"{{url}}\">contact us</a> if you need more)." msgstr "" #: app/models/info_request.rb:259 app/models/info_request.rb:277 @@ -950,16 +944,16 @@ msgstr "" #: app/views/request/new.rhtml:128 msgid "" -"Everything that you enter on this page \n" +"Everything that you enter on this page\n" " will be <strong>displayed publicly</strong> on\n" -" this website forever (<a href=\"%s\">why?</a>)." +" this website forever (<a href=\"{{url}}\">why?</a>)." msgstr "" #: app/views/request/new.rhtml:120 msgid "" -"Everything that you enter on this page, including <strong>your name</strong>, \n" +"Everything that you enter on this page, including <strong>your name</strong>,\n" " will be <strong>displayed publicly</strong> on\n" -" this website forever (<a href=\"%s\">why?</a>)." +" this website forever (<a href=\"{{url}}\">why?</a>)." msgstr "" #: locale/model_attributes.rb:68 @@ -1007,7 +1001,7 @@ msgid "Failed to convert image to a PNG" msgstr "" #: app/models/profile_photo.rb:105 -msgid "Failed to convert image to the correct size: at %{cols}x%{rows}, need %{width}x%{height}" +msgid "Failed to convert image to the correct size: at {{cols}}x{{rows}}, need {{width}}x{{height}}" msgstr "" #: app/views/general/search.rhtml:117 @@ -1018,7 +1012,7 @@ msgstr "" msgid "" "First, type in the <strong>name of the UK public authority</strong> you'd \n" " like information from. <strong>By law, they have to respond</strong>\n" -" (<a href=\"%s#%s\">why?</a>)." +" (<a href=\"{{url}}\">why?</a>)." msgstr "" #: locale/model_attributes.rb:88 @@ -1147,7 +1141,7 @@ msgstr "" msgid "" "From the request page, try replying to a particular message, rather than sending\n" " a general followup. If you need to make a general followup, and know\n" -" an email which will go to the right place, please <a href=\"%s\">send it to us</a>." +" an email which will go to the right place, please <a href=\"{{url}}\">send it to us</a>." msgstr "" #: app/views/request/_correspondence.rhtml:12 @@ -1278,7 +1272,7 @@ msgid "I've received an <strong>error message</strong>" msgstr "" #: app/views/public_body/view_email.rhtml:28 -msgid "If the address is wrong, or you know a better address, please <a href=\"%s\">contact us</a>." +msgid "If the address is wrong, or you know a better address, please <a href=\"{{url}}\">contact us</a>." msgstr "" #: app/views/request_mailer/stopped_responses.rhtml:10 @@ -1292,21 +1286,21 @@ msgstr "" msgid "" "If you are dissatisfied by the response you got from\n" " the public authority, you have the right to\n" -" complain (<a href=\"%s\">details</a>)." +" complain (<a href=\"{{url}}\">details</a>)." msgstr "" #: app/views/user/no_cookies.rhtml:20 -msgid "If you are still having trouble, please <a href=\"%s\">contact us</a>." +msgid "If you are still having trouble, please <a href=\"{{url}}\">contact us</a>." msgstr "" #: app/views/request/hidden.rhtml:15 -msgid "If you are the requester, then you may <a href=\"%s\">sign in</a> to view the request." +msgid "If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the request." msgstr "" #: app/views/request/new.rhtml:123 msgid "" "If you are thinking of using a pseudonym,\n" -" please <a href=\"%s\">read this first</a>." +" please <a href=\"{{url}}\">read this first</a>." msgstr "" #: app/views/request/show.rhtml:105 @@ -1497,7 +1491,7 @@ msgid "Joined {{site_name}} in" msgstr "" #: app/views/request/new.rhtml:106 -msgid "Keep it <strong>focused</strong>, you'll be more likely to get what you want (<a href=\"%s\">why?</a>)." +msgid "Keep it <strong>focused</strong>, you'll be more likely to get what you want (<a href=\"{{url}}\">why?</a>)." msgstr "" #: app/views/request/_request_filter_form.rhtml:6 @@ -1837,7 +1831,7 @@ msgid "Please" msgstr "" #: app/views/user/no_cookies.rhtml:15 -msgid "Please <a href=\"%s\">get in touch</a> with us so we can fix it." +msgid "Please <a href=\"{{url}}\">get in touch</a> with us so we can fix it." msgstr "" #: app/views/request/show.rhtml:52 @@ -1990,7 +1984,7 @@ msgid "" msgstr "" #: app/models/outgoing_message.rb:157 -msgid "Please sign at the bottom with your name, or alter the \"%{signoff}\" signature" +msgid "Please sign at the bottom with your name, or alter the \"{{signoff}}\" signature" msgstr "" #: app/views/user/sign.rhtml:8 @@ -2337,8 +2331,8 @@ msgid "Search the site to find what you were looking for." msgstr "" #: app/views/public_body/show.rhtml:85 -msgid "Search within the %d Freedom of Information requests to %s" -msgid_plural "Search within the %d Freedom of Information requests made to %s" +msgid "Search within the {{count}} Freedom of Information requests to {{public_body_name}}" +msgid_plural "Search within the {{count}} Freedom of Information requests to {{public_body_name}}" msgstr[0] "" msgstr[1] "" @@ -2680,10 +2674,7 @@ msgid "The request was refused by the public authority" msgstr "" #: app/views/request/hidden.rhtml:9 -msgid "" -"The request you have tried to view has been removed. There are\n" -"various reasons why we might have done this, sorry we can't be more specific here. Please <a\n" -" href=\"%s\">contact us</a> if you have any questions." +msgid "The request you have tried to view has been removed. There are\\nvarious reasons why we might have done this, sorry we can't be more specific here. Please <a\\n href=\"{{url}}\">contact us</a> if you have any questions." msgstr "" #: app/views/general/_advanced_search_tips.rhtml:36 @@ -2692,14 +2683,14 @@ msgstr "" #: app/views/request/_followup.rhtml:59 msgid "" -"The response to your request has been <strong>delayed</strong>. You can say that, \n" +"The response to your request has been <strong>delayed</strong>. You can say that,\n" " by law, the authority should normally have responded\n" " <strong>promptly</strong> and" msgstr "" #: app/views/request/_followup.rhtml:71 msgid "" -"The response to your request is <strong>long overdue</strong>. You can say that, by \n" +"The response to your request is <strong>long overdue</strong>. You can say that, by\n" " law, under all circumstances, the authority should have responded\n" " by now" msgstr "" @@ -2804,15 +2795,9 @@ msgstr "" msgid "There are {{count}} new annotations on your {{info_request}} request. Follow this link to see what they wrote." msgstr "" -#: app/views/public_body/show.rhtml:7 -msgid "There is %d person following this authority" -msgid_plural "There are %d people following this authority" -msgstr[0] "" -msgstr[1] "" - #: app/views/request/_sidebar.rhtml:5 -msgid "There is %d person following this request" -msgid_plural "There are %d people following this request" +msgid "There is {{count}} person following this request" +msgid_plural "There are {{count}} people following this request" msgstr[0] "" msgstr[1] "" @@ -2876,7 +2861,7 @@ msgstr "" #: app/views/request/_hidden_correspondence.rhtml:23 msgid "" "This comment has been hidden. See annotations to\n" -" find out why. If you are the requester, then you may <a href=\"%s\">sign in</a> to view the response." +" find out why. If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the response." msgstr "" #: app/views/request/new.rhtml:63 @@ -2906,7 +2891,7 @@ msgstr "" #: app/views/request/_hidden_correspondence.rhtml:17 msgid "" "This outgoing message has been hidden. See annotations to\n" -"\t\t\t\t\t\tfind out why. If you are the requester, then you may <a href=\"%s\">sign in</a> to view the response." +"\t\t\t\t\t\tfind out why. If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the response." msgstr "" #: app/views/request/_describe_state.rhtml:44 @@ -2919,14 +2904,14 @@ msgid "This person has made no Freedom of Information requests using this site." msgstr "" #: app/views/user/show.rhtml:149 -msgid "This person's %d Freedom of Information request" -msgid_plural "This person's %d Freedom of Information requests" +msgid "This person's {{count}} Freedom of Information request" +msgid_plural "This person's {{count}} Freedom of Information requests" msgstr[0] "" msgstr[1] "" #: app/views/user/show.rhtml:179 -msgid "This person's %d annotation" -msgid_plural "This person's %d annotations" +msgid "This person's {{count}} annotation" +msgid_plural "This person's {{count}} annotations" msgstr[0] "" msgstr[1] "" @@ -2965,7 +2950,7 @@ msgstr "" #: app/views/request/show.rhtml:11 msgid "" "This request is hidden, so that only you the requester can see it. Please\n" -" <a href=\"%s\">contact us</a> if you are not sure why." +" <a href=\"{{url}}\">contact us</a> if you are not sure why." msgstr "" #: app/views/request/_describe_state.rhtml:7 @@ -2976,7 +2961,7 @@ msgstr "" #: app/views/request/_hidden_correspondence.rhtml:10 msgid "" "This response has been hidden. See annotations to find out why.\n" -" If you are the requester, then you may <a href=\"%s\">sign in</a> to view the response." +" If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the response." msgstr "" #: app/views/request/details.rhtml:6 @@ -3202,7 +3187,7 @@ msgstr "" msgid "" "Unfortunately we don't know the FOI\n" "email address for that authority, so we can't validate this.\n" -"Please <a href=\"%s\">contact us</a> to sort it out." +"Please <a href=\"{{url}}\">contact us</a> to sort it out." msgstr "" #: app/views/request/new_bad_contact.rhtml:5 @@ -3439,7 +3424,7 @@ msgid "" msgstr "" #: app/views/request/new_please_describe.rhtml:16 -msgid "When you're done, <strong>come back here</strong>, <a href=\"%s\">reload this page</a> and file your new request." +msgid "When you're done, <strong>come back here</strong>, <a href=\"{{url}}\">reload this page</a> and file your new request." msgstr "" #: app/views/request/show_response.rhtml:13 @@ -3571,7 +3556,7 @@ msgstr "" msgid "" "You may be able to find\n" " one on their website, or by phoning them up and asking. If you manage\n" -" to find one, then please <a href=\"%s\">send it to us</a>." +" to find one, then please <a href=\"{{url}}\">send it to us</a>." msgstr "" #: app/views/request/new_bad_contact.rhtml:6 @@ -3642,24 +3627,19 @@ msgid "You've now cleared your profile photo" msgstr "" #: app/views/user/show.rhtml:149 -msgid "Your %d Freedom of Information request" -msgid_plural "Your %d Freedom of Information requests" +msgid "Your {{count}} Freedom of Information request" +msgid_plural "Your {{count}} Freedom of Information requests" msgstr[0] "" msgstr[1] "" #: app/views/user/show.rhtml:179 -msgid "Your %d annotation" -msgid_plural "Your %d annotations" +msgid "Your {{count}} annotation" +msgid_plural "Your {{count}} annotations" msgstr[0] "" msgstr[1] "" #: app/views/user/_signup.rhtml:22 -msgid "" -"Your <strong>name will appear publicly</strong> \n" -" (<a href=\"%s\">why?</a>)\n" -" on this website and in search engines. If you\n" -" are thinking of using a pseudonym, please \n" -" <a href=\"%s\">read this first</a>." +msgid "Your <strong>name will appear publicly</strong>\\n (<a href=\"{{why_url}}\">why?</a>)\\n on this website and in search engines. If you\\n are thinking of using a pseudonym, please\\n <a href=\"{{help_url}}\">read this first</a>." msgstr "" #: app/views/user/show.rhtml:172 @@ -3682,7 +3662,7 @@ msgid "Your email subscriptions" msgstr "" #: app/controllers/request_controller.rb:598 -msgid "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." +msgid "Your follow up has not been sent because this request has been stopped to prevent spam. Please <a href=\"{{url}}\">contact us</a> if you really want to send a follow up message." msgstr "" #: app/controllers/request_controller.rb:626 @@ -3712,7 +3692,7 @@ msgstr "" #: app/views/request/preview.rhtml:8 msgid "" "Your name, request and any responses will appear in <strong>search engines</strong>\n" -" (<a href=\"%s\">details</a>)." +" (<a href=\"{{url}}\">details</a>)." msgstr "" #: app/views/user/_signup.rhtml:18 @@ -3746,7 +3726,7 @@ msgid "Your request:" msgstr "" #: app/views/request/upload_response.rhtml:8 -msgid "Your response will <strong>appear on the Internet</strong>, <a href=\"%s\">read why</a> and answers to other questions." +msgid "Your response will <strong>appear on the Internet</strong>, <a href=\"{{url}}\">read why</a> and answers to other questions." msgstr "" #: app/views/comment/new.rhtml:63 @@ -3990,7 +3970,7 @@ msgid "" "no longer exists. If you are trying to make\n" " From the request page, try replying to a particular message, rather than sending\n" " a general followup. If you need to make a general followup, and know\n" -" an email which will go to the right place, please <a href=\"%s\">send it to us</a>." +" an email which will go to the right place, please <a href=\"{{url}}\">send it to us</a>." msgstr "" #: app/views/request/show.rhtml:72 diff --git a/spec/fixtures/locale/es/app.po b/spec/fixtures/locale/es/app.po index 4e54a1d40..d45d9b3b1 100644 --- a/spec/fixtures/locale/es/app.po +++ b/spec/fixtures/locale/es/app.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # David Cabo <david.cabo@gmail.com>, 2011, 2012. # skenaja <alex@alexskene.com>, 2011. @@ -35,9 +35,9 @@ msgstr " Esto aparecerá en tu perfil de {{site_name}}, para facilitar\n #: app/views/comment/_comment_form.rhtml:16 msgid "" -" (<strong>no ranty</strong> politics, read our <a href=\"%s\">moderation " +" (<strong>no ranty</strong> politics, read our <a href=\"{{url}}\">moderation " "policy</a>)" -msgstr " (<strong>sin ataques políticos</strong>, lea nuestra <a href=\"%s\">política de moderación</a>)" +msgstr " (<strong>sin ataques políticos</strong>, lea nuestra <a href=\"{{url}}\">política de moderación</a>)" #: app/views/request/upload_response.rhtml:40 msgid "" @@ -80,9 +80,9 @@ msgstr " Ideas sobre <strong>qué otra información pedir</strong> que el organi #: app/views/public_body/view_email.rhtml:30 msgid "" -" If you know the address to use, then please <a href=\"%s\">send it to us</a>.\n" +" If you know the address to use, then please <a href=\"{{url}}\">send it to us</a>.\n" " You may be able to find the address on their website, or by phoning them up and asking." -msgstr " Si conoces la dirección a utilizar, entonces por favor <a href=\"%s\">envíanosla</a>.\n Puede que la encuentres en su página web, o llamándoles por teléfono y preguntando." +msgstr " Si conoces la dirección a utilizar, entonces por favor <a href=\"{{url}}\">envíanosla</a>.\n Puede que la encuentres en su página web, o llamándoles por teléfono y preguntando." #: app/views/user/set_profile_about_me.rhtml:26 msgid "" @@ -140,22 +140,22 @@ msgid " when you send this message." msgstr " cuando envió este mensaje." #: app/views/public_body/show.rhtml:87 -msgid "%d Freedom of Information request to %s" -msgid_plural "%d Freedom of Information requests to %s" -msgstr[0] "%d solicitud de información a %s" -msgstr[1] "%d solicitudes de información a %s" +msgid "{{count}} Freedom of Information request to {{public_body_name}}" +msgid_plural "{{count}} Freedom of Information requests to {{public_body_name}}" +msgstr[0] "{{count}} solicitud de información a {{public_body_name}}" +msgstr[1] "{{count}} solicitudes de información a {{public_body_name}}" #: app/views/general/frontpage.rhtml:43 -msgid "%d request" -msgid_plural "%d requests" -msgstr[0] "%d solicitud" -msgstr[1] "%d solicitudes" +msgid "{{count}} request" +msgid_plural "{{count}} requests" +msgstr[0] "{{count}} solicitud" +msgstr[1] "{{count}} solicitudes" #: app/views/public_body/_body_listing_single.rhtml:21 -msgid "%d request made." -msgid_plural "%d requests made." -msgstr[0] "%d solicitud enviada." -msgstr[1] "%d solicitudes enviadas." +msgid "{{count}} request made." +msgid_plural "{{count}} requests made." +msgstr[0] "{{count}} solicitud enviada." +msgstr[1] "{{count}} solicitudes enviadas." #: app/views/request/new.rhtml:92 msgid "'Crime statistics by ward level for Wales'" @@ -204,46 +204,40 @@ msgstr "2. Solicite información" msgid "3. Now check your request" msgstr "3. Revisa tu solicitud" -#: app/views/public_body/show.rhtml:56 -msgid "<a class=\"link_button_green\" href=\"{{url}}\">{{text}}</a>" -msgstr "<a class=\"link_button_green\" href=\"{{url}}\">{{text}}</a>" - #: app/views/request/_after_actions.rhtml:9 -msgid "<a href=\"%s\">Add an annotation</a> (to help the requester or others)" -msgstr "<a href=\"%s\">Añade un comentario</a> (para ayudar al solicitante o a otros)" +msgid "<a href=\"{{url}}\">Add an annotation</a> (to help the requester or others)" +msgstr "<a href=\"{{url}}\">Añade un comentario</a> (para ayudar al solicitante o a otros)" #: app/views/public_body/list.rhtml:29 -msgid "<a href=\"%s\">Are we missing a public authority?</a>." -msgstr "<a href=\"%s\">¿Nos falta algún organismo público?</a>." +msgid "Are we missing a public authority?" +msgstr "¿Nos falta algún organismo público?." #: app/views/request/_sidebar.rhtml:39 -msgid "" -"<a href=\"%s\">Are you the owner of\n" -" any commercial copyright on this page?</a>" -msgstr "<a href=\"%s\">¿Posee el copyright\n de alguna información de esta página?</a>" +msgid "Are you the owner of any commercial copyright on this page?" +msgstr "¿Posee el copyright de alguna información de esta página?" #: app/views/general/search.rhtml:168 -msgid "<a href=\"%s\">Browse all</a> or <a href=\"%s\">ask us to add one</a>." -msgstr "<a href=\"%s\">Ver todas</a> o <a href=\"%s\">pídanos que añadamos una</a>." +msgid "<a href=\"{{browse_url}}\">Browse all</a> or <a href=\"{{add_url}}\">ask us to add one</a>." +msgstr "<a href=\"{{browse_url}}\">Ver todas</a> o <a href=\"{{add_url}}\">pídanos que añadamos una</a>." #: app/views/public_body/list.rhtml:51 -msgid "<a href=\"%s\">Can't find the one you want?</a>" -msgstr "<a href=\"%s\">¿No encuentra el que busca?</a>" +msgid "Can't find the one you want?" +msgstr "¿No encuentra el que busca?" #: app/views/user/show.rhtml:118 msgid "" -"<a href=\"%s\">Sign in</a> to change password, subscriptions and more " +"<a href=\"{{url}}\">Sign in</a> to change password, subscriptions and more " "({{user_name}} only)" -msgstr "<a href=\"%s\">Abre una sesión</a> para cambiar tu contraseña, suscripciones... (sólo {{user_name}})" +msgstr "<a href=\"{{url}}\">Abre una sesión</a> para cambiar tu contraseña, suscripciones... (sólo {{user_name}})" #: app/views/request/_followup.rhtml:66 app/views/request/_followup.rhtml:73 #: app/views/request/show.rhtml:83 app/views/request/show.rhtml:87 -msgid "<a href=\"%s\">details</a>" -msgstr "<a href=\"%s\">detalles</a>" +msgid "details" +msgstr "detalles" #: app/views/request/_followup.rhtml:101 -msgid "<a href=\"%s\">what's that?</a>" -msgstr "<a href=\"%s\">¿Qué es eso?</a>" +msgid "what's that?" +msgstr "¿Qué es eso?" #: app/controllers/request_game_controller.rb:23 msgid "" @@ -382,8 +376,8 @@ msgstr "<small>Si usas correo web o tiene filtros \"anti spam\", por favor compr #: app/views/request/new.rhtml:135 msgid "" "<strong> Can I request information about myself?</strong>\n" -"\t\t\t<a href=\"%s\">No! (Click here for details)</a>" -msgstr "<strong> ¿Puedo pedir información sobre mí?</strong>\n\t\t\t<a href=\"%s\">¡No! (Pulse aquí para más detalles)</a>" +"\t\t\t<a href=\"{{url}}\">No! (Click here for details)</a>" +msgstr "<strong> ¿Puedo pedir información sobre mí?</strong>\n\t\t\t<a href=\"{{url}}\">¡No! (Pulse aquí para más detalles)</a>" #: app/views/general/_advanced_search_tips.rhtml:12 msgid "" @@ -486,8 +480,8 @@ msgstr "<strong>Nota:</strong> Te estás enviando un mensaje a ti mismo, suponem #: app/views/request/preview.rhtml:31 msgid "" "<strong>Privacy note:</strong> If you want to request private information about\n" -" yourself then <a href=\"%s\">click here</a>." -msgstr "<strong>Nota sobre privacidad:</strong> Si quiere solicitar información privada\n sobre sí mismo entonces <a href=\"%s\">siga este enlace</a>." +" yourself then <a href=\"{{url}}\">click here</a>." +msgstr "<strong>Nota sobre privacidad:</strong> Si quiere solicitar información privada\n sobre sí mismo entonces <a href=\"{{url}}\">siga este enlace</a>." #: app/views/user/set_crop_profile_photo.rhtml:35 msgid "" @@ -667,8 +661,8 @@ msgstr "Pide documentos o información <strong>específica</strong>, esta web no #: app/views/request/show_response.rhtml:29 msgid "" "At the bottom of this page, write a reply to them trying to persuade them to scan it in\n" -" (<a href=\"%s\">more details</a>)." -msgstr "Al final de esta página, escribe una respuesta intentando convencerles de que lo escaneen\n (<a href=\"%s\">más detalles</a>)." +" (<a href=\"{{url}}\">more details</a>)." +msgstr "Al final de esta página, escribe una respuesta intentando convencerles de que lo escaneen\n (<a href=\"{{url}}\">más detalles</a>)." #: app/views/request/upload_response.rhtml:33 msgid "Attachment (optional):" @@ -1037,8 +1031,8 @@ msgstr "Introduzca las palabras que desee separadas por espacio, es decir <stron #: app/views/request/upload_response.rhtml:23 msgid "" "Enter your response below. You may attach one file (use email, or \n" -"<a href=\"%s\">contact us</a> if you need more)." -msgstr "Escribe tu solicitud a continuación. Puedes adjuntar un fichero (manda un correo,\n o <a href=\"%s\">contáctanos</a>, si necesita más)." +"<a href=\"{{url}}\">contact us</a> if you need more)." +msgstr "Escribe tu solicitud a continuación. Puedes adjuntar un fichero (manda un correo,\n o <a href=\"{{url}}\">contáctanos</a>, si necesita más)." #: app/models/info_request.rb:259 app/models/info_request.rb:277 msgid "Environmental Information Regulations" @@ -1066,17 +1060,17 @@ msgstr "Historial de eventos" #: app/views/request/new.rhtml:128 msgid "" -"Everything that you enter on this page \n" +"Everything that you enter on this page\n" " will be <strong>displayed publicly</strong> on\n" -" this website forever (<a href=\"%s\">why?</a>)." -msgstr "Todo lo que escriba en esta página \n estará <strong>disponible públicamente</strong> en\n está web para siempre (<a href=\"%s\">¿por qué?</a>)." +" this website forever (<a href=\"{{url}}\">why?</a>)." +msgstr "Todo lo que escriba en esta página \n estará <strong>disponible públicamente</strong> en\n está web para siempre (<a href=\"{{url}}\">¿por qué?</a>)." #: app/views/request/new.rhtml:120 msgid "" -"Everything that you enter on this page, including <strong>your name</strong>, \n" +"Everything that you enter on this page, including <strong>your name</strong>,\n" " will be <strong>displayed publicly</strong> on\n" -" this website forever (<a href=\"%s\">why?</a>)." -msgstr "Todo lo que escribas en esta página, incluyendo <strong>tu nombre</strong>, \n estará <strong>disponible públicamente</strong> en\n está web para siempre (<a href=\"%s\">¿por qué?</a>)." +" this website forever (<a href=\"{{url}}\">why?</a>)." +msgstr "Todo lo que escribas en esta página, incluyendo <strong>tu nombre</strong>, \n estará <strong>disponible públicamente</strong> en\n está web para siempre (<a href=\"{{url}}\">¿por qué?</a>)." #: locale/model_attributes.rb:68 msgid "EximLogDone|Filename" @@ -1123,10 +1117,8 @@ msgid "Failed to convert image to a PNG" msgstr "Error al convertir la imagen a PNG" #: app/models/profile_photo.rb:105 -msgid "" -"Failed to convert image to the correct size: at %{cols}x%{rows}, need " -"%{width}x%{height}" -msgstr "Error al convertir la imagen al tamaño adecuado: es %{cols}x%{rows}, debería ser %{width}x%{height}" +msgid "Failed to convert image to the correct size: at {{cols}}x{{rows}}, need {{width}}x{{height}}" +msgstr "Error al convertir la imagen al tamaño adecuado: es {{cols}}x{{rows}}, debería ser {{width}}x{{height}}" #: app/views/general/search.rhtml:117 msgid "Filter" @@ -1136,8 +1128,8 @@ msgstr "Filtrar" msgid "" "First, type in the <strong>name of the UK public authority</strong> you'd \n" " like information from. <strong>By law, they have to respond</strong>\n" -" (<a href=\"%s#%s\">why?</a>)." -msgstr "Primero, escribe el <strong>nombre de la institución</strong> a la que quieres pedir información. <strong>Están obligados a responder</strong> (<a href=\"%s#%s\">¿por qué?</a>)." +" (<a href=\"{{url}}\">why?</a>)." +msgstr "Primero, escribe el <strong>nombre de la institución</strong> a la que quieres pedir información. <strong>Están obligados a responder</strong> (<a href=\"{{url}}\">¿por qué?</a>)." #: locale/model_attributes.rb:88 msgid "FoiAttachment|Charset" @@ -1272,8 +1264,8 @@ msgstr "Solicitudes de información a" msgid "" "From the request page, try replying to a particular message, rather than sending\n" " a general followup. If you need to make a general followup, and know\n" -" an email which will go to the right place, please <a href=\"%s\">send it to us</a>." -msgstr "Desde la página de la solicitud, intenta responder a un mensaje en concreto, en vez de\n responder a la solicitud en general. Si necesitas hacerlo y tienes una dirección de\n correo válida, por favor <a href=\"%s\">mándanosla</a>." +" an email which will go to the right place, please <a href=\"{{url}}\">send it to us</a>." +msgstr "Desde la página de la solicitud, intenta responder a un mensaje en concreto, en vez de\n responder a la solicitud en general. Si necesitas hacerlo y tienes una dirección de\n correo válida, por favor <a href=\"{{url}}\">mándanosla</a>." #: app/views/request/_correspondence.rhtml:12 #: app/views/request/_correspondence.rhtml:36 @@ -1409,8 +1401,8 @@ msgstr "He recibido un <strong>mensaje de error</strong>" #: app/views/public_body/view_email.rhtml:28 msgid "" "If the address is wrong, or you know a better address, please <a " -"href=\"%s\">contact us</a>." -msgstr "Si la dirección es incorrecta, o conoce una más actualizada, por favor <a href=\"%s\">contáctenos</a>." +"href=\"{{url}}\">contact us</a>." +msgstr "Si la dirección es incorrecta, o conoce una más actualizada, por favor <a href=\"{{url}}\">contáctenos</a>." #: app/views/request_mailer/stopped_responses.rhtml:10 msgid "" @@ -1423,24 +1415,24 @@ msgstr "Si no es correcto, o te gustaría enviar una respuesta a la solicitud\no msgid "" "If you are dissatisfied by the response you got from\n" " the public authority, you have the right to\n" -" complain (<a href=\"%s\">details</a>)." -msgstr "Si no estás satisfecho con la respuesta que has recibido del\n organismo público, tienes derecho a\n apelar (<a href=\"%s\">detalles</a>)." +" complain (<a href=\"{{url}}\">details</a>)." +msgstr "Si no estás satisfecho con la respuesta que has recibido del\n organismo público, tienes derecho a\n apelar (<a href=\"{{url}}\">detalles</a>)." #: app/views/user/no_cookies.rhtml:20 -msgid "If you are still having trouble, please <a href=\"%s\">contact us</a>." -msgstr "Si aún tienes problemas, por favor <a href=\"%s\">contáctanos</a>." +msgid "If you are still having trouble, please <a href=\"{{url}}\">contact us</a>." +msgstr "Si aún tienes problemas, por favor <a href=\"{{url}}\">contáctanos</a>." #: app/views/request/hidden.rhtml:15 msgid "" -"If you are the requester, then you may <a href=\"%s\">sign in</a> to view " +"If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view " "the request." -msgstr "Si la solicitud es tuya, puedes <a href=\"%s\">abrir una sesión</a> para verla." +msgstr "Si la solicitud es tuya, puedes <a href=\"{{url}}\">abrir una sesión</a> para verla." #: app/views/request/new.rhtml:123 msgid "" "If you are thinking of using a pseudonym,\n" -" please <a href=\"%s\">read this first</a>." -msgstr "Si está pensando en utilizar un pseudónimo,\n por favor <a href=\"%s\">lea esto primero</a>." +" please <a href=\"{{url}}\">read this first</a>." +msgstr "Si está pensando en utilizar un pseudónimo,\n por favor <a href=\"{{url}}\">lea esto primero</a>." #: app/views/request/show.rhtml:105 msgid "If you are {{user_link}}, please" @@ -1639,8 +1631,8 @@ msgstr "Registrado en {{site_name}} el" #: app/views/request/new.rhtml:106 msgid "" "Keep it <strong>focused</strong>, you'll be more likely to get what you want" -" (<a href=\"%s\">why?</a>)." -msgstr "Sea <strong>específico</strong>, tendrá más probabilidades de conseguir lo que quiere (<a href=\"%s\">¿por qué?</a>)." +" (<a href=\"{{url}}\">why?</a>)." +msgstr "Sea <strong>específico</strong>, tendrá más probabilidades de conseguir lo que quiere (<a href=\"{{url}}\">¿por qué?</a>)." #: app/views/request/_request_filter_form.rhtml:6 msgid "Keywords" @@ -1990,8 +1982,8 @@ msgid "Please" msgstr "Por favor" #: app/views/user/no_cookies.rhtml:15 -msgid "Please <a href=\"%s\">get in touch</a> with us so we can fix it." -msgstr "Por favor <a href=\"%s\">contacta</a> con nosotros para que podamos arreglarlo." +msgid "Please <a href=\"{{url}}\">get in touch</a> with us so we can fix it." +msgstr "Por favor <a href=\"{{url}}\">contacta</a> con nosotros para que podamos arreglarlo." #: app/views/request/show.rhtml:52 msgid "" @@ -2154,10 +2146,8 @@ msgid "" msgstr "Por favor elije estas solicitudes una a una, y <strong>haz que se sepa</strong>\nsi han tenido éxito o no." #: app/models/outgoing_message.rb:157 -msgid "" -"Please sign at the bottom with your name, or alter the \"%{signoff}\" " -"signature" -msgstr "Por favor, firma con tu nombre en la parte inferior, o cambia la firma \"%{signoff}\"" +msgid "Please sign at the bottom with your name, or alter the \"{{signoff}}\" signature" +msgstr "Por favor, firma con tu nombre en la parte inferior, o cambia la firma \"{{signoff}}\"" #: app/views/user/sign.rhtml:8 msgid "Please sign in as " @@ -2519,10 +2509,10 @@ msgid "Search the site to find what you were looking for." msgstr "Buscar en esta web para encontrar lo que busca." #: app/views/public_body/show.rhtml:85 -msgid "Search within the %d Freedom of Information requests to %s" -msgid_plural "Search within the %d Freedom of Information requests made to %s" -msgstr[0] "Busca en la %d solicitud de información hecha a %s" -msgstr[1] "Busca en las %d solicitudes de información hechas a %s" +msgid "Search within the {{count}} Freedom of Information requests to {{public_body_name}}" +msgid_plural "Search within the {{count}} Freedom of Information requests to {{public_body_name}}" +msgstr[0] "Busca en la {{count}} solicitud de información hecha a {{public_body_name}}" +msgstr[1] "Busca en las {{count}} solicitudes de información hechas a {{public_body_name}}" #: app/views/user/show.rhtml:132 msgid "Search your contributions" @@ -2878,11 +2868,8 @@ msgid "The request was refused by the public authority" msgstr "La solicitud ha sido rechazada por el organismo" #: app/views/request/hidden.rhtml:9 -msgid "" -"The request you have tried to view has been removed. There are\n" -"various reasons why we might have done this, sorry we can't be more specific here. Please <a\n" -" href=\"%s\">contact us</a> if you have any questions." -msgstr "La solicitud que has intentado ver ha sido eliminada. Hay\nvarios posibles motivos para esto, pero no podemos ser más específicos aquí. Por favor <a\n href=\"%s\">contáctanos</a> si tiene cualquier pregunta." +msgid "The request you have tried to view has been removed. There are\\nvarious reasons why we might have done this, sorry we can't be more specific here. Please <a\\n href=\"{{url}}\">contact us</a> if you have any questions." +msgstr "La solicitud que has intentado ver ha sido eliminada. Hay\nvarios posibles motivos para esto, pero no podemos ser más específicos aquí. Por favor <a\n href=\"{{url}}\">contáctanos</a> si tiene cualquier pregunta." #: app/views/general/_advanced_search_tips.rhtml:36 msgid "The requester has abandoned this request for some reason" @@ -2890,14 +2877,14 @@ msgstr "El creador de la solicitud la ha cancelado por algún motivo" #: app/views/request/_followup.rhtml:59 msgid "" -"The response to your request has been <strong>delayed</strong>. You can say that, \n" +"The response to your request has been <strong>delayed</strong>. You can say that,\n" " by law, the authority should normally have responded\n" " <strong>promptly</strong> and" msgstr "La respuesta a tu solicitud ha sido <strong>retrasada</strong>.\n Por ley, el organismo debería normalmente haber respondido\n <strong>rápidamente</strong> y" #: app/views/request/_followup.rhtml:71 msgid "" -"The response to your request is <strong>long overdue</strong>. You can say that, by \n" +"The response to your request is <strong>long overdue</strong>. You can say that, by\n" " law, under all circumstances, the authority should have responded\n" " by now" msgstr "La respuesta a tu solicitud ha sido <strong>muy retrasada</strong>.\n Por ley, bajo cualquier circunstancia, el organismo ya debería\n haber respondido" @@ -3016,17 +3003,11 @@ msgid "" " this link to see what they wrote." msgstr "Hay {{count}} comentarios en tu solicitud {{info_request}}. Sigue este enlace para leer lo que dicen." -#: app/views/public_body/show.rhtml:7 -msgid "There is %d person following this authority" -msgid_plural "There are %d people following this authority" -msgstr[0] "Hay %d persona siguiendo a este organismo." -msgstr[1] "Hay %d personas siguiendo a este organismo." - #: app/views/request/_sidebar.rhtml:5 -msgid "There is %d person following this request" -msgid_plural "There are %d people following this request" -msgstr[0] "Hay %d persona siguiendo esta solicitud." -msgstr[1] "Hay %d personas siguiendo esta solicitud." +msgid "There is {{count}} person following this request" +msgid_plural "There are {{count}} people following this request" +msgstr[0] "Hay {{count}} persona siguiendo esta solicitud." +msgstr[1] "Hay {{count}} personas siguiendo esta solicitud." #: app/views/user/show.rhtml:8 msgid "" @@ -3099,8 +3080,8 @@ msgstr "Este organismo ya no existe, no pueden realizarse solicitudes de informa #: app/views/request/_hidden_correspondence.rhtml:23 msgid "" "This comment has been hidden. See annotations to\n" -" find out why. If you are the requester, then you may <a href=\"%s\">sign in</a> to view the response." -msgstr "Este respuesta está oculta. Revisa los comentarios\n para descubrir por qué. Si es tu solicitud, <a href=\"%s\">abre una sesión</a> para ver la respuesta." +" find out why. If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the response." +msgstr "Este respuesta está oculta. Revisa los comentarios\n para descubrir por qué. Si es tu solicitud, <a href=\"{{url}}\">abre una sesión</a> para ver la respuesta." #: app/views/request/new.rhtml:63 msgid "" @@ -3140,8 +3121,8 @@ msgstr "Esta es tu solicitud, por lo que recibirás correos automáticamente cua #: app/views/request/_hidden_correspondence.rhtml:17 msgid "" "This outgoing message has been hidden. See annotations to\n" -"\t\t\t\t\t\tfind out why. If you are the requester, then you may <a href=\"%s\">sign in</a> to view the response." -msgstr "Este mensaje está oculto. Lee los comentarios\n\t\t\t\t\t\tpara descubrir por qué. Si es tu solicitud, <a href=\"%s\">abra una sesión</a> para ver la respuesta." +"\t\t\t\t\t\tfind out why. If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the response." +msgstr "Este mensaje está oculto. Lee los comentarios\n\t\t\t\t\t\tpara descubrir por qué. Si es tu solicitud, <a href=\"{{url}}\">abra una sesión</a> para ver la respuesta." #: app/views/request/_describe_state.rhtml:44 #: app/views/request/_other_describe_state.rhtml:40 @@ -3154,16 +3135,16 @@ msgid "" msgstr "Esta persona no ha realizado solicitudes de información usando esta web." #: app/views/user/show.rhtml:149 -msgid "This person's %d Freedom of Information request" -msgid_plural "This person's %d Freedom of Information requests" -msgstr[0] "Tu %d solicitud de información" -msgstr[1] "Tus %d solicitudes de información" +msgid "This person's {{count}} Freedom of Information request" +msgid_plural "This person's {{count}} Freedom of Information requests" +msgstr[0] "Tu {{count}} solicitud de información" +msgstr[1] "Tus {{count}} solicitudes de información" #: app/views/user/show.rhtml:179 -msgid "This person's %d annotation" -msgid_plural "This person's %d annotations" -msgstr[0] "Tu %d comentario" -msgstr[1] "Tus %d comentarios" +msgid "This person's {{count}} annotation" +msgid_plural "This person's {{count}} annotations" +msgstr[0] "Tu {{count}} comentario" +msgstr[1] "Tus {{count}} comentarios" #: app/views/user/show.rhtml:172 msgid "This person's annotations" @@ -3204,8 +3185,8 @@ msgstr "Esta solicitud tiene visibilidad 'oculta'. Puedes verla sólo porque est #: app/views/request/show.rhtml:11 msgid "" "This request is hidden, so that only you the requester can see it. Please\n" -" <a href=\"%s\">contact us</a> if you are not sure why." -msgstr "Esta solicitud está oculta, por lo que sólo tú como creador puedes verla. Por favor\n <a href=\"%s\">contáctanos</a> si no estás seguro de por qué." +" <a href=\"{{url}}\">contact us</a> if you are not sure why." +msgstr "Esta solicitud está oculta, por lo que sólo tú como creador puedes verla. Por favor\n <a href=\"{{url}}\">contáctanos</a> si no estás seguro de por qué." #: app/views/request/_describe_state.rhtml:7 #: app/views/request/_other_describe_state.rhtml:10 @@ -3215,8 +3196,8 @@ msgstr "Esta solicitud está todavía en proceso:" #: app/views/request/_hidden_correspondence.rhtml:10 msgid "" "This response has been hidden. See annotations to find out why.\n" -" If you are the requester, then you may <a href=\"%s\">sign in</a> to view the response." -msgstr "Este respuesta está oculta. Revisa los comentarios\n para descubrir por qué. Si es tu solicitud, <a href=\"%s\">abre una sesión</a> para ver la respuesta." +" If you are the requester, then you may <a href=\"{{url}}\">sign in</a> to view the response." +msgstr "Este respuesta está oculta. Revisa los comentarios\n para descubrir por qué. Si es tu solicitud, <a href=\"{{url}}\">abre una sesión</a> para ver la respuesta." #: app/views/request/details.rhtml:6 msgid "" @@ -3450,8 +3431,8 @@ msgstr "Se encontró un tipo de resultado inesperado " msgid "" "Unfortunately we don't know the FOI\n" "email address for that authority, so we can't validate this.\n" -"Please <a href=\"%s\">contact us</a> to sort it out." -msgstr "Desgraciadamente no tenemos la dirección\nde correo para este organismo, así que no podemos validarlo.\nPor favor <a href=\"%s\">contáctenos</a> para arreglarlo." +"Please <a href=\"{{url}}\">contact us</a> to sort it out." +msgstr "Desgraciadamente no tenemos la dirección\nde correo para este organismo, así que no podemos validarlo.\nPor favor <a href=\"{{url}}\">contáctenos</a> para arreglarlo." #: app/views/request/new_bad_contact.rhtml:5 msgid "" @@ -3699,9 +3680,9 @@ msgstr "Cuando reciba la respuesta en papel, por favor ayude\n a que #: app/views/request/new_please_describe.rhtml:16 msgid "" -"When you're done, <strong>come back here</strong>, <a href=\"%s\">reload " +"When you're done, <strong>come back here</strong>, <a href=\"{{url}}\">reload " "this page</a> and file your new request." -msgstr "Cuando esté listo, <strong>vuelva aquí</strong>, <a href=\"%s\">recargue esta página</a> y cree una nueva solicitud." +msgstr "Cuando esté listo, <strong>vuelva aquí</strong>, <a href=\"{{url}}\">recargue esta página</a> y cree una nueva solicitud." #: app/views/request/show_response.rhtml:13 msgid "Which of these is happening?" @@ -3840,8 +3821,8 @@ msgstr "Puede <strong>adjuntar ficheros</strong>. Si quiere adjuntar un fichero\ msgid "" "You may be able to find\n" " one on their website, or by phoning them up and asking. If you manage\n" -" to find one, then please <a href=\"%s\">send it to us</a>." -msgstr "Puede que encuentres una\n en su página web, o preguntando por teléfono. Si la consigues\n por favor <a href=\"%s\">envíanosla</a>." +" to find one, then please <a href=\"{{url}}\">send it to us</a>." +msgstr "Puede que encuentres una\n en su página web, o preguntando por teléfono. Si la consigues\n por favor <a href=\"{{url}}\">envíanosla</a>." #: app/views/request/new_bad_contact.rhtml:6 msgid "" @@ -3914,25 +3895,20 @@ msgid "You've now cleared your profile photo" msgstr "Has borrado la foto de tu perfil" #: app/views/user/show.rhtml:149 -msgid "Your %d Freedom of Information request" -msgid_plural "Your %d Freedom of Information requests" -msgstr[0] "Tu %d solicitud de información" -msgstr[1] "Tus %d solicitudes de información" +msgid "Your {{count}} Freedom of Information request" +msgid_plural "Your {{count}} Freedom of Information requests" +msgstr[0] "Tu {{count}} solicitud de información" +msgstr[1] "Tus {{count}} solicitudes de información" #: app/views/user/show.rhtml:179 -msgid "Your %d annotation" -msgid_plural "Your %d annotations" -msgstr[0] "Tu %d comentario" -msgstr[1] "Tus %d comentarios" +msgid "Your {{count}} annotation" +msgid_plural "Your {{count}} annotations" +msgstr[0] "Tu {{count}} comentario" +msgstr[1] "Tus {{count}} comentarios" #: app/views/user/_signup.rhtml:22 -msgid "" -"Your <strong>name will appear publicly</strong> \n" -" (<a href=\"%s\">why?</a>)\n" -" on this website and in search engines. If you\n" -" are thinking of using a pseudonym, please \n" -" <a href=\"%s\">read this first</a>." -msgstr "<strong>Tu nombre aparecerá públicamente</strong> \n (<a href=\"%s\">¿por qué?</a>)\n en esta web y en motores de búsqueda. Si estás\n pensando en utilizar un seudónimo, por favor \n <a href=\"%s\">lee esto primero</a>." +msgid "Your <strong>name will appear publicly</strong> \\n (<a href=\"{{why_url}}\">why?</a>)\\n on this website and in search engines. If you\\n are thinking of using a pseudonym, please \\n <a href=\"{{help_url}}\">read this first</a>." +msgstr "<strong>Tu nombre aparecerá públicamente</strong> \n (<a href=\"{{why_url}}\">¿por qué?</a>)\n en esta web y en motores de búsqueda. Si estás\n pensando en utilizar un seudónimo, por favor \n <a href=\"{{help_url}}\">lee esto primero</a>." #: app/views/user/show.rhtml:172 msgid "Your annotations" @@ -3956,9 +3932,9 @@ msgstr "Tus suscripciones de correo" #: app/controllers/request_controller.rb:598 msgid "" "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 " +"prevent spam. Please <a href=\"{{url}}\">contact us</a> if you really want to " "send a follow up message." -msgstr "Tu respuesta no ha sido enviada porque esta solicitud ha sido bloqueada para evitar spam. Por favor <a href=\"%s\">contáctanos</a> si realmente quieres enviar una respuesta." +msgstr "Tu respuesta no ha sido enviada porque esta solicitud ha sido bloqueada para evitar spam. Por favor <a href=\"{{url}}\">contáctanos</a> si realmente quieres enviar una respuesta." #: app/controllers/request_controller.rb:626 msgid "Your follow up message has been sent on its way." @@ -3990,8 +3966,8 @@ msgstr "Tu nombre y su comentario aparecerán en los <strong>motores de búsqued #: app/views/request/preview.rhtml:8 msgid "" "Your name, request and any responses will appear in <strong>search engines</strong>\n" -" (<a href=\"%s\">details</a>)." -msgstr "Tu nombre, tu solicitud y cualquier respuesta aparecerán en los <strong>motores de búsqueda</strong>\n (<a href=\"%s\">detalles</a>)." +" (<a href=\"{{url}}\">details</a>)." +msgstr "Tu nombre, tu solicitud y cualquier respuesta aparecerán en los <strong>motores de búsqueda</strong>\n (<a href=\"{{url}}\">detalles</a>)." #: app/views/user/_signup.rhtml:18 msgid "Your name:" @@ -4028,8 +4004,8 @@ msgstr "Tu solicitud:" #: app/views/request/upload_response.rhtml:8 msgid "" "Your response will <strong>appear on the Internet</strong>, <a " -"href=\"%s\">read why</a> and answers to other questions." -msgstr "Tu respuesta <strong>aparecerá en Internet</strong>, <a href=\"%s\">lee por qué</a> y respuestas a otras preguntas." +"href=\"{{url}}\">read why</a> and answers to other questions." +msgstr "Tu respuesta <strong>aparecerá en Internet</strong>, <a href=\"{{url}}\">lee por qué</a> y respuestas a otras preguntas." #: app/views/comment/new.rhtml:63 msgid "" @@ -4276,8 +4252,8 @@ msgid "" "no longer exists. If you are trying to make\n" " From the request page, try replying to a particular message, rather than sending\n" " a general followup. If you need to make a general followup, and know\n" -" an email which will go to the right place, please <a href=\"%s\">send it to us</a>." -msgstr "ya no existe. \nDesde la página de la solicitud, intenta responder a un mensaje en concreto, en vez de\n responder a la solicitud en general. Si necesitas hacerlo y tienes una dirección de\n correo válida, por favor <a href=\"%s\">mándanosla</a>." +" an email which will go to the right place, please <a href=\"{{url}}\">send it to us</a>." +msgstr "ya no existe. \nDesde la página de la solicitud, intenta responder a un mensaje en concreto, en vez de\n responder a la solicitud en general. Si necesitas hacerlo y tienes una dirección de\n correo válida, por favor <a href=\"{{url}}\">mándanosla</a>." #: app/views/request/show.rhtml:72 msgid "normally" diff --git a/spec/fixtures/outgoing_messages.yml b/spec/fixtures/outgoing_messages.yml index 55df8473e..c71ee08bf 100644 --- a/spec/fixtures/outgoing_messages.yml +++ b/spec/fixtures/outgoing_messages.yml @@ -108,3 +108,14 @@ anonymous_external_outgoing_message: updated_at: 2009-01-12 01:56:58.586598 what_doing: normal_sort +other_outgoing_message: + id: 10 + info_request_id: 111 + message_type: initial_request + status: sent + body: "Just another request" + last_sent_at: <%= Time.now %> + created_at: 2009-01-12 01:56:58.586598 + updated_at: 2009-01-12 01:56:58.586598 + what_doing: normal_sort + diff --git a/spec/fixtures/public_bodies.yml b/spec/fixtures/public_bodies.yml index 615c4bcb6..65cba4b28 100644 --- a/spec/fixtures/public_bodies.yml +++ b/spec/fixtures/public_bodies.yml @@ -72,3 +72,18 @@ sensible_walks_public_body: created_at: 2008-10-25 10:51:01.161639 api_key: 5 info_requests_count: 1 +other_public_body: + id: 7 + version: 1 + name: 'Another Public Body' + first_letter: A + request_email: other@localhost + short_name: Another Public Body + url_name: another_public_body + notes: More notes + updated_at: 2008-10-25 10:51:01.161639 + last_edit_comment: Another edit + last_edit_editor: louise + created_at: 2008-10-25 10:51:01.161639 + api_key: 6 + info_requests_count: 0 diff --git a/spec/fixtures/public_body_translations.yml b/spec/fixtures/public_body_translations.yml index 24b14c470..61e07fb5b 100644 --- a/spec/fixtures/public_body_translations.yml +++ b/spec/fixtures/public_body_translations.yml @@ -88,3 +88,16 @@ sensible_walks_en_public_body_translation: notes: I bet you’ve never heard of it. publication_scheme: "" disclosure_log: "" + +other_public_body_translation: + id: 8 + public_body_id: 7 + locale: en + name: "Another Public Body" + first_letter: A + request_email: other@localhost + short_name: Another Public Body + url_name: another_public_body + notes: More notes + publication_scheme: "" + disclosure_log: "" diff --git a/spec/fixtures/theme_views/core/application_mailer/core_only.rhtml b/spec/fixtures/theme_views/core/application_mailer/core_only.html.erb index 53b7798ec..53b7798ec 100644 --- a/spec/fixtures/theme_views/core/application_mailer/core_only.rhtml +++ b/spec/fixtures/theme_views/core/application_mailer/core_only.html.erb diff --git a/spec/fixtures/theme_views/core/application_mailer/multipart_core_only.rhtml b/spec/fixtures/theme_views/core/application_mailer/multipart_core_only.html.erb index 646a349f8..646a349f8 100644 --- a/spec/fixtures/theme_views/core/application_mailer/multipart_core_only.rhtml +++ b/spec/fixtures/theme_views/core/application_mailer/multipart_core_only.html.erb diff --git a/spec/fixtures/theme_views/core/application_mailer/simple.rhtml b/spec/fixtures/theme_views/core/application_mailer/simple.html.erb index a3937c940..a3937c940 100644 --- a/spec/fixtures/theme_views/core/application_mailer/simple.rhtml +++ b/spec/fixtures/theme_views/core/application_mailer/simple.html.erb diff --git a/spec/fixtures/theme_views/theme_one/application_mailer/multipart_theme_only.rhtml b/spec/fixtures/theme_views/theme_one/application_mailer/multipart_theme_only.html.erb index d6423fbb4..d6423fbb4 100644 --- a/spec/fixtures/theme_views/theme_one/application_mailer/multipart_theme_only.rhtml +++ b/spec/fixtures/theme_views/theme_one/application_mailer/multipart_theme_only.html.erb diff --git a/spec/fixtures/theme_views/theme_one/application_mailer/simple.rhtml b/spec/fixtures/theme_views/theme_one/application_mailer/simple.html.erb index ad43e0c87..ad43e0c87 100644 --- a/spec/fixtures/theme_views/theme_one/application_mailer/simple.rhtml +++ b/spec/fixtures/theme_views/theme_one/application_mailer/simple.html.erb diff --git a/spec/fixtures/theme_views/theme_one/application_mailer/theme_only.rhtml b/spec/fixtures/theme_views/theme_one/application_mailer/theme_only.html.erb index 865445815..865445815 100644 --- a/spec/fixtures/theme_views/theme_one/application_mailer/theme_only.rhtml +++ b/spec/fixtures/theme_views/theme_one/application_mailer/theme_only.html.erb diff --git a/spec/fixtures/theme_views/theme_one/help/contact.es.html.erb b/spec/fixtures/theme_views/theme_one/help/contact.es.html.erb new file mode 100644 index 000000000..a294c8aa1 --- /dev/null +++ b/spec/fixtures/theme_views/theme_one/help/contact.es.html.erb @@ -0,0 +1 @@ +contáctenos theme one diff --git a/spec/fixtures/theme_views/theme_one/help/contact.html.erb b/spec/fixtures/theme_views/theme_one/help/contact.html.erb new file mode 100644 index 000000000..428c7368d --- /dev/null +++ b/spec/fixtures/theme_views/theme_one/help/contact.html.erb @@ -0,0 +1 @@ +Contact us diff --git a/spec/fixtures/track_things_sent_emails.yml b/spec/fixtures/track_things_sent_emails.yml deleted file mode 100644 index e69de29bb..000000000 --- a/spec/fixtures/track_things_sent_emails.yml +++ /dev/null diff --git a/spec/fixtures/users.yml b/spec/fixtures/users.yml index d6391c5e8..c9730d855 100644 --- a/spec/fixtures/users.yml +++ b/spec/fixtures/users.yml @@ -1,4 +1,4 @@ -bob_smith_user: +bob_smith_user: id: "1" name: Bob Smith url_name: bob_smith @@ -13,7 +13,7 @@ bob_smith_user: locale: 'en' about_me: 'I like making requests about fancy dogs and naughty chickens and stuff.' receive_email_alerts: true -silly_name_user: +silly_name_user: id: "2" name: "Silly <em>Name</em>" url_name: silly_emnameem @@ -28,7 +28,7 @@ silly_name_user: locale: 'en' about_me: '' receive_email_alerts: true -admin_user: +admin_user: id: "3" name: Joe Admin url_name: joe_admin @@ -43,7 +43,7 @@ admin_user: locale: '' about_me: '' receive_email_alerts: true -unconfirmed_user: +unconfirmed_user: id: "4" name: "Unconfirmed" url_name: unconfirmed @@ -71,3 +71,17 @@ robin_user: ban_text: '' about_me: 'I am the best' receive_email_alerts: true +another_user: + id: 6 + name: Another User + url_name: another_user + email: another@localhost + salt: "-6116981980.392287733335677" + hashed_password: 6b7cd45a5f35fd83febc0452a799530398bfb6e8 # jonespassword + updated_at: 2012-01-01 10:39:15.491593 + created_at: 2012-01-01 10:39:15.491593 + email_confirmed: true + admin_level: 'none' + ban_text: '' + about_me: 'Just another user' + receive_email_alerts: true diff --git a/spec/helpers/link_to_helper_spec.rb b/spec/helpers/link_to_helper_spec.rb index 030fd612d..4cc1d415b 100644 --- a/spec/helpers/link_to_helper_spec.rb +++ b/spec/helpers/link_to_helper_spec.rb @@ -8,36 +8,23 @@ describe LinkToHelper do before do @mock_request = mock_model(InfoRequest, :url_title => 'test_title') - @old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new + RoutingFilter.active = false end after do - ActionController::Routing::Routes.filters = @old_filters + RoutingFilter.active = true end it 'should return a path like /request/test_title' do - request_url(@mock_request).should == '/request/test_title' + request_path(@mock_request).should == '/request/test_title' end it 'should return a path including any extra parameters passed' do - request_url(@mock_request, {:update_status => 1}).should == '/request/test_title?update_status=1' + request_path(@mock_request, {:update_status => 1}).should == '/request/test_title?update_status=1' end end - describe "when appending something to a URL" do - it 'should append to things without query strings' do - main_url('/a', '.json').should == 'http://test.host/a.json' - end - it 'should append to things with query strings' do - main_url('/a?z=1', '.json').should == 'http://test.host/a.json?z=1' - end - it 'should fail silently with invalid URLs' do - main_url('/a?z=9%', '.json').should == 'http://test.host/a?z=9%' - end - end - describe 'when displaying a user admin link for a request' do it 'should return the text "An anonymous user (external)" in the case where there is no external username' do @@ -48,32 +35,6 @@ describe LinkToHelper do end - describe 'admin_url' do - context 'with no ADMIN_BASE_URL set' do - it 'should prepend the admin general index path to a simple string' do - admin_url('unclassified').should == 'http://test.host/en/admin/unclassified' - end - - it 'should prepend the admin general index path to a deeper URL' do - admin_url('request/show/123').should == 'http://test.host/en/admin/request/show/123' - end - end - - context 'with ADMIN_BASE_URL set' do - before(:each) do - Configuration::should_receive(:admin_base_url).and_return('https://www.example.com/secure/alaveteli-admin/') - end - - it 'should prepend the admin base URL to a simple string' do - admin_url('unclassified').should == 'https://www.example.com/secure/alaveteli-admin/unclassified' - end - - it 'should prepend the admin base URL to a deeper URL' do - admin_url('request/show/123').should == 'https://www.example.com/secure/alaveteli-admin/request/show/123' - end - end - end - describe 'simple_date' do it 'should respect time zones' do Time.use_zone('Australia/Sydney') do diff --git a/spec/integration/admin_spec.rb b/spec/integration/admin_spec.rb index e148ea3ca..8a5e59ba2 100644 --- a/spec/integration/admin_spec.rb +++ b/spec/integration/admin_spec.rb @@ -13,7 +13,7 @@ describe "When administering the site" do # Now fetch the "log in as" link to log in as Bob get_via_redirect "/admin/user/login_as/#{users(:bob_smith_user).id}", nil, { - "Authorization" => "Basic " + Base64.encode64("#{Configuration::admin_username}:#{Configuration::admin_password}").strip + "Authorization" => "Basic " + Base64.encode64("#{AlaveteliConfiguration::admin_username}:#{AlaveteliConfiguration::admin_password}").strip } response.should be_success session[:user_id].should == users(:bob_smith_user).id diff --git a/spec/integration/errors_spec.rb b/spec/integration/errors_spec.rb index a44ed7051..17a0153c2 100644 --- a/spec/integration/errors_spec.rb +++ b/spec/integration/errors_spec.rb @@ -1,53 +1,130 @@ +# -*- coding: utf-8 -*- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') -describe "When rendering errors" do +describe "When errors occur" do - before(:each) do - load_raw_emails_data - ActionController::Base.consider_all_requests_local = false + def set_consider_all_requests_local(value) + @requests_local = Rails.application.config.consider_all_requests_local + Rails.application.config.consider_all_requests_local = value end - after(:each) do - ActionController::Base.consider_all_requests_local = true + def restore_consider_all_requests_local + Rails.application.config.consider_all_requests_local = @requests_local end - it "should render a 404 for unrouteable URLs" do - get("/frobsnasm") - response.body.should include("The page doesn't exist") - response.code.should == "404" - end - it "should render a 404 for users that don't exist" do - get("/user/wobsnasm") - response.body.should include("The page doesn't exist") - response.code.should == "404" - end - it "should render a 404 for bodies that don't exist" do - get("/body/wobsnasm") - response.body.should include("The page doesn't exist") - response.code.should == "404" + before(:each) do + # This should happen automatically before each test but doesn't with these integration + # tests for some reason. + ActionMailer::Base.deliveries = [] end - it "should render a 500 for general errors" do - ir = info_requests(:naughty_chicken_request) - # Set an invalid state for the request. Note that update_attribute doesn't run the validations - ir.update_attribute(:described_state, "crotchety") - get("/request/#{ir.url_title}") - response.code.should == "500" + + after(:each) do + restore_consider_all_requests_local end - it "should render a 403 for attempts at directory listing for attachments" do - # make a fake cache - foi_cache_path = File.expand_path(File.join(File.dirname(__FILE__), '../../cache')) - FileUtils.mkdir_p(File.join(foi_cache_path, "views/en/request/101/101/response/1/attach/html/1")) - get("/request/101/response/1/attach/html/1/" ) - response.body.should include("Directory listing not allowed") - response.code.should == "403" - get("/request/101/response/1/attach/html" ) - response.body.should include("Directory listing not allowed") - response.code.should == "403" + + context 'when considering all requests local (by default all in development)' do + + before(:each) { set_consider_all_requests_local(true) } + + it 'should show a full trace for general errors' do + InfoRequest.stub!(:find_by_url_title!).and_raise("An example error") + get("/request/example") + response.body.should have_selector('div[id=traces]') + response.body.should match('An example error') + end + end - it "should render a 404 for non-existent 'details' pages for requests" do - get("/details/request/wobble" ) - response.body.should include("The page doesn't exist") - response.code.should == "404" + + context 'when not considering all requests local' do + + before(:each) { set_consider_all_requests_local(false) } + + it "should render a 404 for unrouteable URLs using the general/exception_caught template" do + get("/frobsnasm") + response.should render_template('general/exception_caught') + response.code.should == "404" + end + + it "should render a 404 for users or bodies that don't exist using the general/exception_caught + template" do + ['/user/wobsnasm', '/body/wobsnasm'].each do |non_existent_url| + get(non_existent_url) + response.should render_template('general/exception_caught') + response.code.should == "404" + end + end + + it "should render a 500 for general errors using the general/exception_caught template" do + InfoRequest.stub!(:find_by_url_title!).and_raise("An example error") + get("/request/example") + response.should render_template('general/exception_caught') + response.body.should match('An example error') + response.code.should == "500" + end + + it 'should render a 500 for json errors' do + InfoRequest.stub!(:find_by_url_title!).and_raise("An example error") + get("/request/example.json") + response.code.should == '500' + end + + it 'should render a 404 for a non-found xml request' do + get("/frobsnasm.xml") + response.code.should == '404' + end + + it 'should notify of a general error' do + InfoRequest.stub!(:find_by_url_title!).and_raise("An example error") + get("/request/example") + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.body.should =~ /An example error/ + end + + it 'should log a general error' do + Rails.logger.should_receive(:fatal) + InfoRequest.stub!(:find_by_url_title!).and_raise("An example error") + get("/request/example") + end + + it 'should assign the locale for the general/exception_caught template' do + InfoRequest.stub!(:find_by_url_title!).and_raise("An example error") + get("/es/request/example") + response.should render_template('general/exception_caught') + response.body.should match('Lo sentimos, hubo un problema procesando esta página') + response.body.should match('An example error') + end + + it "should render a 403 with text body for attempts at directory listing for attachments" do + # make a fake cache + foi_cache_path = File.expand_path(File.join(File.dirname(__FILE__), '../../cache')) + FileUtils.mkdir_p(File.join(foi_cache_path, "views/en/request/101/101/response/1/attach/html/1")) + get("/request/101/response/1/attach/html/1/" ) + response.body.should include("Directory listing not allowed") + response.code.should == "403" + get("/request/101/response/1/attach/html" ) + response.body.should include("Directory listing not allowed") + response.code.should == "403" + end + + it "return a 403 for a JSON PermissionDenied error" do + InfoRequest.stub!(:find_by_url_title!).and_raise(ApplicationController::PermissionDenied) + get("/request/example.json") + response.code.should == '403' + end + + context "in the admin interface" do + + it 'should show a full trace for general errors' do + InfoRequest.stub!(:find).and_raise("An example error") + get("/admin/request/show/333") + response.body.should have_selector('div[id=traces]') + response.body.should match('An example error') + end + + end + end -end +end diff --git a/spec/integration/request_controller_spec.rb b/spec/integration/request_controller_spec.rb new file mode 100644 index 000000000..9e585448b --- /dev/null +++ b/spec/integration/request_controller_spec.rb @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe RequestController, "when classifying an information request" do + + describe 'when the request is internal' do + + before(:each) do + load_raw_emails_data + @dog_request = info_requests(:fancy_dog_request) + # This should happen automatically before each test but doesn't with these integration + # tests for some reason. + ActionMailer::Base.deliveries = [] + end + + describe 'when logged in as the requestor' do + + before :each do + @request_owner = @dog_request.user + visit signin_path + fill_in "Your e-mail:", :with => @request_owner.email + fill_in "Password:", :with => "jonespassword" + click_button "Sign in" + end + + it "should send an email including the message" do + visit describe_state_message_path(:url_title => @dog_request.url_title, + :described_state => "requires_admin") + fill_in "Please tell us more:", :with => "Okay. I don't quite understand." + click_button "Submit status and send message" + + response.should contain "Thank you! We'll look into what happened and try and fix it up." + + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.body.should =~ /as needing admin/ + mail.body.should =~ /Okay. I don't quite understand./ + end + end + end +end diff --git a/spec/integration/search_request_spec.rb b/spec/integration/search_request_spec.rb index c564032a6..23a62e97b 100644 --- a/spec/integration/search_request_spec.rb +++ b/spec/integration/search_request_spec.rb @@ -13,10 +13,8 @@ describe "When searching" do end it "should redirect requests with search in query string to URL-based page" do - url = '/search/all?query=bob' - request_via_redirect("post", url) - response.request.url.should_not include(url) - response.request.url.should include("/search/bob/all") + post '/search/all?query=bob' + response.should redirect_to "/en/search/bob/all" end it "should correctly execute simple search" do diff --git a/spec/lib/ability_spec.rb b/spec/lib/ability_spec.rb new file mode 100644 index 000000000..f075d0f32 --- /dev/null +++ b/spec/lib/ability_spec.rb @@ -0,0 +1,51 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe Ability do + describe ".can_update_request_state?" do + context "old and unclassified request" do + let(:request) { mock_model(InfoRequest, :is_old_unclassified? => true) } + + context "logged out" do + let(:user) { nil } + before(:each) { request.stub!(:is_owning_user?).and_return(false) } + it { Ability::can_update_request_state?(user, request).should be_false } + end + + context "logged in but not owner of request" do + let(:user) { mock_model(User) } + before(:each) { request.stub!(:is_owning_user?).and_return(false) } + + it { Ability::can_update_request_state?(user, request).should be_true } + end + end + + context "new request" do + let(:request) { mock_model(InfoRequest, :is_old_unclassified? => false) } + + context "logged out" do + let(:user) { nil } + before(:each) { request.stub!(:is_owning_user?).and_return(false) } + + it { Ability::can_update_request_state?(user, request).should be_false } + end + + context "logged in" do + let(:user) { mock_model(User) } + + # An owner of a request can also be someone with admin powers + context "as owner of request" do + before(:each) { request.stub!(:is_owning_user?).and_return(true) } + + it { Ability::can_update_request_state?(user, request).should be_true } + end + + context "but not owner of request" do + before(:each) { request.stub!(:is_owning_user?).and_return(false) } + + it { Ability::can_update_request_state?(user, request).should be_false } + end + end + end + end +end + diff --git a/spec/lib/basic_encoding_tests.rb b/spec/lib/basic_encoding_tests.rb new file mode 100644 index 000000000..35d35fd4a --- /dev/null +++ b/spec/lib/basic_encoding_tests.rb @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +def bytes_to_binary_string( bytes, claimed_encoding = nil ) + claimed_encoding ||= 'ASCII-8BIT' + bytes_string = bytes.pack('c*') + if RUBY_VERSION.to_f >= 1.9 + bytes_string.force_encoding! claimed_encoding + end + bytes_string +end + +random_string = bytes_to_binary_string [ 0x0f, 0x58, 0x1c, 0x8f, 0xa4, 0xcf, + 0xf6, 0x8c, 0x9d, 0xa7, 0x06, 0xd9, + 0xf7, 0x90, 0x6c, 0x6f] + +windows_1252_string = bytes_to_binary_string [ 0x44, 0x41, 0x53, 0x48, 0x20, + 0x96, 0x20, 0x44, 0x41, 0x53, + 0x48 ] + +# It's a shame this example is so long, but if we don't take enough it +# gets misinterpreted as Shift_JIS + +gb_18030_bytes = [ 0xb9, 0xf3, 0xb9, 0xab, 0xcb, 0xbe, 0xb8, 0xba, 0xd4, 0xf0, + 0xc8, 0xcb, 0x28, 0xbe, 0xad, 0xc0, 0xed, 0x2f, 0xb2, 0xc6, + 0xce, 0xf1, 0x29, 0xc4, 0xfa, 0xba, 0xc3, 0xa3, 0xba, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0xb1, 0xbe, 0xb9, 0xab, 0xcb, 0xbe, 0xd4, + 0xda, 0x31, 0x39, 0x39, 0x37, 0xc4, 0xea, 0xb3, 0xc9, 0xc1, + 0xa2, 0xb9, 0xfa, 0xbc, 0xd2, 0xb9, 0xa4, 0xc9, 0xcc, 0xd7, + 0xa2, 0xb2, 0xe1, 0x2e, 0xca, 0xb5, 0xc1, 0xa6, 0xd0, 0xdb, + 0xba, 0xf1, 0xa1, 0xa3, 0xd3, 0xd0, 0xb6, 0xc0, 0xc1, 0xa2, + 0xcb, 0xb0, 0xce, 0xf1, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xd7, 0xa8, 0xd2, 0xb5, + 0xc8, 0xcb, 0xd4, 0xb1, 0x3b, 0xd4, 0xda, 0xc8, 0xab, 0xb9, + 0xfa, 0xb8, 0xf7, 0xb3, 0xc7, 0xca, 0xd0, 0xc9, 0xe8, 0xc1, + 0xa2, 0xb7, 0xd6, 0xb9, 0xab, 0xcb, 0xbe, 0xa3, 0xa8, 0xd5, + 0xe3, 0xbd, 0xad, 0xa1, 0xa2, 0xc9, 0xcf, 0xba, 0xa3, 0xa1, + 0xa2, 0xb9, 0xe3, 0xd6, 0xdd, 0xa1, 0xa2, 0xbd, 0xad, 0xcb, + 0xd5, 0xb5, 0xc8, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0xb5, 0xd8, 0xb7, 0xbd, 0xa3, + 0xa9, 0xd2, 0xf2, 0xbd, 0xf8, 0xcf, 0xee, 0xbd, 0xcf, 0xb6, + 0xe0, 0xcf, 0xd6, 0xcd, 0xea, 0xb3, 0xc9, 0xb2, 0xbb, 0xc1, + 0xcb, 0xc3, 0xbf, 0xd4, 0xc2, 0xcf, 0xfa, 0xca, 0xdb, 0xb6, + 0xee, 0xb6, 0xc8, 0xa1, 0xa3, 0xc3, 0xbf, 0xd4, 0xc2, 0xd3, + 0xd0, 0xd2, 0xbb, 0xb2, 0xbf, 0xb7, 0xd6, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xd4, + 0xf6, 0xd6, 0xb5, 0xb6, 0x90, 0xa3, 0xa8, 0x36, 0x2d, 0x37, + 0x25, 0xd7, 0xf3, 0xd3, 0xd2, 0x29, 0xba, 0xcd, 0xc6, 0xd5, + 0xc6, 0xb1, 0xa3, 0xa8, 0x30, 0x2e, 0x35, 0x25, 0x2d, 0x32, + 0x25, 0x20, 0xd7, 0xf3, 0xd3, 0xd2, 0xa3, 0xa9, 0xd3, 0xc5, + 0xbb, 0xdd, 0xb4, 0xfa, 0xbf, 0xaa, 0xbb, 0xf2, 0xba, 0xcf, + 0xd7, 0xf7, 0xa3, 0xac, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xb5, 0xe3, 0xca, 0xfd, + 0xbd, 0xcf, 0xb5, 0xcd, 0xa1, 0xa3, 0xb4, 0xfa, 0xc0, 0xed, + 0xb7, 0xb6, 0xce, 0xa7, 0xc8, 0xe7, 0xcf, 0xc2, 0xa3, 0xba, + 0x0d, 0x0a ] + +gb_18030_spam_string = bytes_to_binary_string gb_18030_bytes + +describe "normalize_string_to_utf8" do + + describe "when passed uniterpretable character data" do + + it "should reject it as invalid" do + + expect { + normalize_string_to_utf8 random_string + }.to raise_error(EncodingNormalizationError) + + expect { + normalize_string_to_utf8 random_string, 'UTF-8' + }.to raise_error(EncodingNormalizationError) + + end + end + + describe "when passed unlabelled Windows 1252 data" do + + it "should correctly convert it to UTF-8" do + + normalized = normalize_string_to_utf8 windows_1252_string + + normalized.should == "DASH – DASH" + + end + + end + + describe "when passed GB 18030 data" do + + it "should correctly convert it to UTF-8 if unlabelled" do + + normalized = normalize_string_to_utf8 gb_18030_spam_string + + normalized.should start_with("贵公司负责人") + + end + + end + +end + +describe "convert_string_to_utf8_or_binary" do + + describe "when passed uniterpretable character data" do + + it "should return it as a binary string" do + + converted = convert_string_to_utf8_or_binary random_string + converted.should == random_string + + if RUBY_VERSION.to_f >= 1.9 + converted.encoding.should == 'ASCII-8BIT' + end + + converted = convert_string_to_utf8_or_binary random_string,'UTF-8' + converted.should == random_string + + if RUBY_VERSION.to_f >= 1.9 + converted.encoding.should == 'ASCII-8BIT' + end + + end + end + + describe "when passed unlabelled Windows 1252 data" do + + it "should correctly convert it to UTF-8" do + + converted = convert_string_to_utf8_or_binary windows_1252_string + + converted.should == "DASH – DASH" + + if RUBY_VERSION.to_f >= 1.9 + converted.encoding.should == 'UTF-8' + end + end + + end + + describe "when passed GB 18030 data" do + + it "should correctly convert it to UTF-8 if unlabelled" do + + converted = convert_string_to_utf8_or_binary gb_18030_spam_string + + converted.should start_with("贵公司负责人") + + if RUBY_VERSION.to_f >= 1.9 + converted.encoding.should == 'UTF-8' + end + end + + end + +end diff --git a/spec/lib/i18n_interpolation.rb b/spec/lib/i18n_interpolation.rb index e8d046757..b07cf1e9a 100644 --- a/spec/lib/i18n_interpolation.rb +++ b/spec/lib/i18n_interpolation.rb @@ -12,7 +12,35 @@ describe "when using i18n" do it "should assume that simple translations are always html safe" do _("Hello").should be_html_safe end +end + +describe "n_" do + it "should return the translated singular" do + FastGettext.should_receive(:n_).with("Apple", "Apples", 1).and_return("Apfel") + n_("Apple", "Apples", 1).should == "Apfel" + end + + it "should return the translated plural" do + FastGettext.should_receive(:n_).with("Apple", "Apples", 3).and_return("Äpfel") + n_("Apple", "Apples", 3).should == "Äpfel" + end + it "should return the translated singular interpolated" do + FastGettext.should_receive(:n_).with("I eat {{count}} apple", "I eat {{count}} apples", 1). + and_return("Ich esse {{count}} Apfel") + n_("I eat {{count}} apple", "I eat {{count}} apples", 1, :count => 1).should == "Ich esse 1 Apfel" + end + + it "should return the translated plural interpolated" do + FastGettext.should_receive(:n_).with("I eat {{count}} apple", "I eat {{count}} apples", 3). + and_return("Ich esse {{count}} Äpfel") + n_("I eat {{count}} apple", "I eat {{count}} apples", 3, :count => 3).should == "Ich esse 3 Äpfel" + end + + it "should always be html safe when there is no interpolation" do + FastGettext.should_receive(:n_).with("Apple", "Apples", 1).and_return("Apfel") + n_("Apple", "Apples", 1).should be_html_safe + end end describe "gettext_interpolate" do diff --git a/spec/lib/mail_handler/mail_handler_spec.rb b/spec/lib/mail_handler/mail_handler_spec.rb index 48c32e2bc..d6e7ba5d2 100644 --- a/spec/lib/mail_handler/mail_handler_spec.rb +++ b/spec/lib/mail_handler/mail_handler_spec.rb @@ -20,12 +20,46 @@ describe 'when creating a mail object from raw data' do mail.to.should == ["request-66666-caa77777@whatdotheyknow.com", "foi@example.com"] end + it 'should return nil for malformed To: and Cc: lines' do + mail = get_fixture_mail('malformed-to-and-cc.email') + mail.to.should == nil + mail.cc.should == nil + end + it 'should convert an iso8859 email to utf8' do mail = get_fixture_mail('iso8859_2_raw_email.email') - mail.subject.should have_text(/gjatë/u) + mail.subject.should match /gjatë/u MailHandler.get_part_body(mail).is_utf8?.should == true end + it 'should not be confused by subject lines with malformed UTF-8 at the end' do + # The base64 subject line was generated with: + # printf "hello\360" | base64 + # ... and wrapping the result in '=?UTF-8?B?' and '?=' + mail = get_fixture_mail('subject-bad-utf-8-trailing-base64.email') + mail.subject.should == 'hello' + # The quoted printable subject line was generated with: + # printf "hello\360" | qprint -b -e + # ... and wrapping the result in '=?UTF-8?Q?' and '?=' + mail = get_fixture_mail('subject-bad-utf-8-trailing-quoted-printable.email') + mail.subject.should == 'hello' + end + + it 'should convert a Windows-1252 body mislabelled as ISO-8859-1 to UTF-8' do + mail = get_fixture_mail('mislabelled-as-iso-8859-1.email') + body = MailHandler.get_part_body(mail) + body.is_utf8?.should == true + # This email is broken in at least these two ways: + # 1. It contains a top bit set character (0x96) despite the + # "Content-Transfer-Encoding: 7bit" + # 2. The charset in the Content-Type header is "iso-8859-1" + # but 0x96 is actually a Windows-1252 en dash, which would + # be Unicode codepoint 2013. It should be possible to + # spot the mislabelling, since 0x96 isn't a valid + # ISO-8859-1 character. + body.should match(/ \xe2\x80\x93 /) + end + end describe 'when asked for the from name' do @@ -189,7 +223,7 @@ describe 'when deriving a name, email and formatted address from a message from it 'should quote a name with quotes in it' do should_render_from_address('"FOI \" Person" <foiperson@localhost>', - ['FOI " Person', + ['FOI \" Person', 'foiperson@localhost', '"FOI \" Person" <foiperson@localhost>']) end @@ -275,6 +309,12 @@ end describe 'when getting attachment attributes' do + it 'should handle a mail with a non-multipart part with no charset in the Content-Type header' do + mail = get_fixture_mail('part-without-charset-in-content-type.email') + attributes = MailHandler.get_attachment_attributes(mail) + attributes.size.should == 2 + end + it 'should get two attachment parts from a multipart mail with text and html alternatives and an image' do mail = get_fixture_mail('quoted-subject-iso8859-1.email') @@ -282,6 +322,13 @@ describe 'when getting attachment attributes' do attributes.size.should == 2 end + it 'should get one attachment from a multipart mail with text and HTML alternatives, which should be UTF-8' do + mail = get_fixture_mail('iso8859_2_raw_email.email') + attributes = MailHandler.get_attachment_attributes(mail) + attributes.length.should == 1 + attributes[0][:body].is_utf8?.should == true + end + it 'should expand a mail attached as text' do # Note that this spec will only pass using Tmail in the timezone set as datetime headers # are rendered out in the local time - using the Mail gem this is not necessary @@ -304,6 +351,52 @@ describe 'when getting attachment attributes' do attributes = MailHandler.get_attachment_attributes(mail) end + it 'should ignore truncated TNEF attachment' do + mail = get_fixture_mail('tnef-attachment-truncated.email') + attributes = MailHandler.get_attachment_attributes(mail) + attributes.length.should == 2 + end + + it 'should ignore anything beyond the final MIME boundary' do + pending do + # This example raw email has a premature closing boundary for + # the outer multipart/mixed - my reading of RFC 1521 is that + # the "epilogue" beyond that should be ignored. + # See https://github.com/mysociety/alaveteli/issues/922 for + # more discussion. + mail = get_fixture_mail('nested-attachments-premature-end.email') + attributes = MailHandler.get_attachment_attributes(mail) + attributes.length.should == 3 + end + end + + it 'should cope with a missing final MIME boundary' do + mail = get_fixture_mail('multipart-no-final-boundary.email') + attributes = MailHandler.get_attachment_attributes(mail) + attributes.length.should == 1 + attributes[0][:body].should match(/This is an acknowledgement of your email/) + attributes[0][:content_type].should == "text/plain" + attributes[0][:url_part_number].should == 1 + end + + it 'should ignore a TNEF attachment with no usable contents' do + # FIXME: "no usable contents" is slightly misleading. The + # attachment in this example email does have usable content in + # the body of the TNEF attachment, but the invocation of tnef + # historically used to unpack these attachments doesn't add + # the --save-body parameter, so that they have been ignored so + # far. We probably should include the body from such + # attachments, but, at the moment, with the pending upgrade to + # Rails 3, we just want to check that the behaviour is the + # same as before. + mail = get_fixture_mail('tnef-attachment-empty.email') + attributes = MailHandler.get_attachment_attributes(mail) + attributes.length.should == 2 + # This is the size of the TNEF-encoded attachment; currently, + # we expect the code just to return this without decoding: + attributes[1][:body].length.should == 7769 + end + it 'should produce a consistent set of url_part_numbers, content_types, within_rfc822_subjects and filenames from an example mail with lots of attachments' do mail = get_fixture_mail('many-attachments-date-header.email') @@ -385,3 +478,11 @@ describe 'when getting attachment attributes' do end end end + +describe 'when getting the address part from an address string' do + + it 'should handle non-ascii characters in the name input' do + address = "\"Someone’s name\" <test@example.com>" + MailHandler.address_from_string(address).should == 'test@example.com' + end +end diff --git a/spec/lib/sendmail_return_path_spec.rb b/spec/lib/sendmail_return_path_spec.rb index 137869b6e..83436c2bd 100644 --- a/spec/lib/sendmail_return_path_spec.rb +++ b/spec/lib/sendmail_return_path_spec.rb @@ -1,5 +1,10 @@ # This is a test of the monkey patches in sendmail_return_path.rb +# In Rails 3 the monkeypatches are not needed anymore because sendmail now has the "-f" flag +# set correctly. So, strictly these tests are testing the Rails internals. So, that means we really +# should delete them. Let's do that later when things have settled down. For the time being leave +# them in + require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe "when sending email with an altered return path" do @@ -28,10 +33,10 @@ describe "when sending email with an altered return path" do Net::SMTP.stub!(:new).and_return(mock_smtp) with_delivery_method :smtp do - ContactMailer.deliver_to_admin_message( + ContactMailer.to_admin_message( "Mr. Test", "test@localhost", "Test script spec/lib/sendmail_return_path_spec.rb", "This is just a test for a test script", nil, nil, nil - ) + ).deliver end deliveries = ActionMailer::Base.deliveries @@ -40,12 +45,12 @@ describe "when sending email with an altered return path" do it "should set the return path when sending email using sendmail" do with_stub_popen do - IO.should_receive(:popen).once.with('/usr/sbin/sendmail -i -t -f "test@localhost"', "w+") + IO.should_receive(:popen).once.with('/usr/sbin/sendmail -i -t -f "test@localhost" postmaster@localhost', "w+") with_delivery_method :sendmail do - ContactMailer.deliver_to_admin_message( + ContactMailer.to_admin_message( "Mr. Test", "test@localhost", "Test script spec/lib/sendmail_return_path_spec.rb", "This is just a test for a test script", nil, nil, nil - ) + ).deliver end end diff --git a/spec/lib/timezone_fixes_spec.rb b/spec/lib/timezone_fixes_spec.rb index 9d6ade526..8a9a3bf31 100644 --- a/spec/lib/timezone_fixes_spec.rb +++ b/spec/lib/timezone_fixes_spec.rb @@ -3,6 +3,11 @@ # We use MailServerLogDone here just as a totally random model that has a datetime type. require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') +# In Rails 3 the monkeypatch that these tests are testing is not necessary. So, +# since these tests are testing the Rails internals you could argue that they shouldn't +# be here. Well, you're right. But let's leave them in for the time being until the upgrade is finished. +# Then, we should probably delete this whole file + describe "when doing things with timezones" do it "should preserve time objects with local time conversion to default timezone UTC diff --git a/spec/models/application_mailer_spec.rb b/spec/mailers/application_mailer_spec.rb index acf5f43bc..d8993f78f 100644 --- a/spec/models/application_mailer_spec.rb +++ b/spec/mailers/application_mailer_spec.rb @@ -8,8 +8,7 @@ describe ApplicationMailer do def set_base_views ApplicationMailer.class_eval do @previous_view_paths = self.view_paths.dup - self.view_paths.clear - self.view_paths << File.join(Rails.root, 'spec', 'fixtures', 'theme_views', 'core') + self.view_paths = [File.join(Rails.root, 'spec', 'fixtures', 'theme_views', 'core')] end end @@ -27,13 +26,13 @@ describe ApplicationMailer do def prepend_theme_views(theme_name) ApplicationMailer.class_eval do - view_paths.unshift File.join(Rails.root, 'spec', 'fixtures', 'theme_views', theme_name) + prepend_view_path File.join(Rails.root, 'spec', 'fixtures', 'theme_views', theme_name) end end def append_theme_views(theme_name) ApplicationMailer.class_eval do - view_paths << File.join(Rails.root, 'spec', 'fixtures', 'theme_views', theme_name) + append_view_path File.join(Rails.root, 'spec', 'fixtures', 'theme_views', theme_name) end end @@ -45,11 +44,8 @@ describe ApplicationMailer do def create_multipart_method(method_name) ApplicationMailer.send(:define_method, method_name) do - attachment :content_type => 'message/rfc822', - :body => 'xxx', - :filename => "original.eml", - :transfer_encoding => '7bit', - :content_disposition => 'inline' + attachments['original.eml'] = 'xxx' + mail end end @@ -62,32 +58,32 @@ describe ApplicationMailer do it 'should render a theme template in preference to a core template' do prepend_theme_views('theme_one') - @mail = ApplicationMailer.create_simple() + @mail = ApplicationMailer.simple @mail.body.should match('Theme simple') end it 'should render the template provided by the theme if no template is available in core' do prepend_theme_views('theme_one') - @mail = ApplicationMailer.create_theme_only() + @mail = ApplicationMailer.theme_only @mail.body.should match('Theme only') end it 'should render the template provided by core if there is no theme template' do prepend_theme_views('theme_one') - @mail = ApplicationMailer.create_core_only() + @mail = ApplicationMailer.core_only @mail.body.should match('Core only') end - it 'should raise an error if the template is in neither core nor theme' do + it 'should render an empty body if the template is in neither core nor theme' do prepend_theme_views('theme_one') - expected_error = 'Missing template application_mailer/neither.erb in view path' - lambda{ ApplicationMailer.create_neither() }.should raise_error(/#{expected_error}/) + @mail = ApplicationMailer.neither + @mail.body.should be_empty end it 'should render a multipart email using a theme template' do prepend_theme_views('theme_one') create_multipart_method('multipart_theme_only') - @mail = ApplicationMailer.create_multipart_theme_only() + @mail = ApplicationMailer.multipart_theme_only @mail.parts.size.should == 2 message_part = @mail.parts[0].to_s message_part.should match("Theme multipart") @@ -96,7 +92,7 @@ describe ApplicationMailer do it 'should render a multipart email using a core template' do prepend_theme_views('theme_one') create_multipart_method('multipart_core_only') - @mail = ApplicationMailer.create_multipart_core_only() + @mail = ApplicationMailer.multipart_core_only @mail.parts.size.should == 2 message_part = @mail.parts[0].to_s message_part.should match("Core multipart") @@ -108,32 +104,32 @@ describe ApplicationMailer do it 'should render a core template in preference to a theme template' do append_theme_views('theme_one') - @mail = ApplicationMailer.create_simple() + @mail = ApplicationMailer.simple @mail.body.should match('Core simple') end it 'should render the template provided by the theme if no template is available in core' do append_theme_views('theme_one') - @mail = ApplicationMailer.create_theme_only() + @mail = ApplicationMailer.theme_only @mail.body.should match('Theme only') end it 'should render the template provided by core if there is no theme template' do append_theme_views('theme_one') - @mail = ApplicationMailer.create_core_only() + @mail = ApplicationMailer.core_only @mail.body.should match('Core only') end - it 'should raise an error if the template is in neither core nor theme' do + it 'should render an empty body if the template is in neither core nor theme' do append_theme_views('theme_one') - expected_error = 'Missing template application_mailer/neither.erb in view path' - lambda{ ApplicationMailer.create_neither() }.should raise_error(/#{expected_error}/) + @mail = ApplicationMailer.neither + @mail.body.should be_empty end it 'should render a multipart email using a core template' do append_theme_views('theme_one') create_multipart_method('multipart_core_only') - @mail = ApplicationMailer.create_multipart_core_only() + @mail = ApplicationMailer.multipart_core_only @mail.parts.size.should == 2 message_part = @mail.parts[0].to_s message_part.should match("Core multipart") @@ -142,7 +138,7 @@ describe ApplicationMailer do it 'should render a multipart email using a theme template' do append_theme_views('theme_one') create_multipart_method('multipart_theme_only') - @mail = ApplicationMailer.create_multipart_theme_only() + @mail = ApplicationMailer.multipart_theme_only @mail.parts.size.should == 2 message_part = @mail.parts[0].to_s message_part.should match("Theme multipart") diff --git a/spec/mailers/outgoing_mailer_spec.rb b/spec/mailers/outgoing_mailer_spec.rb new file mode 100644 index 000000000..a11d56dd3 --- /dev/null +++ b/spec/mailers/outgoing_mailer_spec.rb @@ -0,0 +1,133 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe OutgoingMailer, " when working out follow up names and addresses" do + + before do + @info_request = mock_model(InfoRequest, + :recipient_name_and_email => 'test <test@example.com>', + :recipient_email => 'test@example.com') + @info_request.stub_chain(:public_body, :name).and_return("Test Authority") + @incoming_message = mock_model(IncomingMessage, + :from_email => 'specific@example.com', + :safe_mail_from => 'Specific Person') + end + + def expect_address(info_request, incoming_message, expected_result) + mail = create_message_from(from_line) + name = MailHandler.get_from_name(mail) + email = MailHandler.get_from_address(mail) + address = MailHandler.address_from_name_and_email(name, email).to_s + [name, email, address].should == expected_result + end + + describe 'if there is no incoming message being replied to' do + + it 'should return the name and email address of the public body' do + OutgoingMailer.name_and_email_for_followup(@info_request, nil).should == 'test <test@example.com>' + OutgoingMailer.name_for_followup(@info_request, nil).should == 'Test Authority' + OutgoingMailer.email_for_followup(@info_request, nil).should == 'test@example.com' + end + + end + + describe 'if the incoming message being replied to is not valid to reply to' do + + before do + @incoming_message.stub!(:valid_to_reply_to?).and_return(false) + end + + it 'should return the safe name and email address of the public body' do + OutgoingMailer.name_and_email_for_followup(@info_request, @incoming_message).should == 'test <test@example.com>' + OutgoingMailer.name_for_followup(@info_request, @incoming_message).should == 'Test Authority' + OutgoingMailer.email_for_followup(@info_request, @incoming_message).should == 'test@example.com' + end + end + + describe 'if the incoming message is valid to reply to' do + + before do + @incoming_message.stub!(:valid_to_reply_to?).and_return(true) + end + + it 'should return the name and email address from the incoming message' do + OutgoingMailer.name_and_email_for_followup(@info_request, @incoming_message).should == 'Specific Person <specific@example.com>' + OutgoingMailer.name_for_followup(@info_request, @incoming_message).should == 'Specific Person' + OutgoingMailer.email_for_followup(@info_request, @incoming_message).should == 'specific@example.com' + end + + it 'should return the name of the public body if the incoming message does not have + a safe name' do + @incoming_message.stub!(:safe_mail_from).and_return(nil) + OutgoingMailer.name_for_followup(@info_request, @incoming_message).should == 'Test Authority' + end + + end + +end + +describe OutgoingMailer, "when working out follow up subjects" do + + before(:each) do + load_raw_emails_data + end + + it "should prefix the title with 'Freedom of Information request -' for initial requests" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + + ir.email_subject_request.should == "Freedom of Information request - Why do you have & such a fancy dog?" + end + + it "should use 'Re:' and inital request subject for followups which aren't replies to particular messages" do + ir = info_requests(:fancy_dog_request) + om = outgoing_messages(:useless_outgoing_message) + + OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" + end + + it "should prefix with Re: the subject of the message being replied to" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + om = outgoing_messages(:useless_outgoing_message) + om.incoming_message_followup = im + + OutgoingMailer.subject_for_followup(ir, om).should == "Re: Geraldine FOI Code AZXB421" + end + + it "should not add Re: prefix if there already is such a prefix" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + om = outgoing_messages(:useless_outgoing_message) + om.incoming_message_followup = im + + im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: Re: Geraldine FOI Code AZXB421") + OutgoingMailer.subject_for_followup(ir, om).should == "Re: Geraldine FOI Code AZXB421" + end + + it "should not add Re: prefix if there already is a lower case re: prefix" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + om = outgoing_messages(:useless_outgoing_message) + om.incoming_message_followup = im + + im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: re: Geraldine FOI Code AZXB421") + im.parse_raw_email! true + + OutgoingMailer.subject_for_followup(ir, om).should == "re: Geraldine FOI Code AZXB421" + end + + it "should use 'Re:' and initial request subject when replying to failed delivery notifications" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + om = outgoing_messages(:useless_outgoing_message) + om.incoming_message_followup = im + + im.raw_email.data = im.raw_email.data.sub("foiperson@localhost", "postmaster@localhost") + im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: Delivery Failed") + im.parse_raw_email! true + + OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" + end +end + + diff --git a/spec/models/request_mailer_spec.rb b/spec/mailers/request_mailer_spec.rb index 000a0c12e..23806b35b 100644 --- a/spec/models/request_mailer_spec.rb +++ b/spec/mailers/request_mailer_spec.rb @@ -28,13 +28,13 @@ describe RequestMailer, " when receiving incoming mail" do receive_incoming_mail('incoming-request-plain.email', 'dummy@localhost') ir.incoming_messages.size.should == 1 InfoRequest.holding_pen_request.incoming_messages.size.should == 1 - last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.get_last_event + last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.info_request_events.last last_event.params[:rejected_reason].should == "Could not identify the request from the email address" deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] - mail.to.should == [ Configuration::contact_email ] + mail.to.should == [ AlaveteliConfiguration::contact_email ] deliveries.clear end @@ -48,13 +48,13 @@ describe RequestMailer, " when receiving incoming mail" do receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "") ir.incoming_messages.size.should == 1 InfoRequest.holding_pen_request.incoming_messages.size.should == 1 - last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.get_last_event + last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.info_request_events.last last_event.params[:rejected_reason].should =~ /there is no "From" address/ deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] - mail.to.should == [ Configuration::contact_email ] + mail.to.should == [ AlaveteliConfiguration::contact_email ] deliveries.clear end @@ -68,13 +68,13 @@ describe RequestMailer, " when receiving incoming mail" do receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "frob@nowhere.com") ir.incoming_messages.size.should == 1 InfoRequest.holding_pen_request.incoming_messages.size.should == 1 - last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.get_last_event + last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.info_request_events.last last_event.params[:rejected_reason].should =~ /Only the authority can reply/ deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] - mail.to.should == [ Configuration::contact_email ] + mail.to.should == [ AlaveteliConfiguration::contact_email ] deliveries.clear end @@ -99,7 +99,7 @@ describe RequestMailer, " when receiving incoming mail" do mail.multipart?.should == true mail.parts.size.should == 2 message_part = mail.parts[0].to_s - bounced_mail = MailHandler.mail_from_raw_email(mail.parts[1].body) + bounced_mail = MailHandler.mail_from_raw_email(mail.parts[1].body.to_s) bounced_mail.to.should == [ ir.incoming_email ] bounced_mail.from.should == [ 'geraldinequango@localhost' ] bounced_mail.body.include?("That's so totally a rubbish question").should be_true @@ -153,14 +153,14 @@ describe RequestMailer, " when receiving incoming mail" do receive_incoming_mail('incoming-request-plain.email', ir.incoming_email) ir.incoming_messages.size.should == 1 InfoRequest.holding_pen_request.incoming_messages.size.should == 1 # arrives in holding pen - last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.get_last_event + last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.info_request_events.last last_event.params[:rejected_reason].should =~ /allow new responses from nobody/ # should be a message to admin regarding holding pen deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] - mail.to.should == [ Configuration::contact_email ] + mail.to.should == [ AlaveteliConfiguration::contact_email ] deliveries.clear end @@ -212,7 +212,9 @@ describe RequestMailer, "when sending reminders to requesters to classify a resp :url_title => 'test_title', :user => @mock_user) InfoRequest.stub!(:find).and_return([@mock_request]) - RequestMailer.stub!(:deliver_new_response_reminder_alert) + mail_mock = mock("mail") + mail_mock.stub(:deliver) + RequestMailer.stub(:new_response_reminder_alert).and_return(mail_mock) @sent_alert = mock_model(UserInfoRequestSentAlert, :user= =>nil, :info_request= => nil, :alert_type= => nil, @@ -244,7 +246,7 @@ describe RequestMailer, "when sending reminders to requesters to classify a resp query_params[:conditions].should == expected_conditions query_params[:include].should == [ :user ] query_params[:order].should == 'info_requests.id' - end + end.and_return [@mock_request] send_alerts end @@ -269,7 +271,7 @@ describe RequestMailer, "when sending reminders to requesters to classify a resp end it 'should not send the reminder' do - RequestMailer.should_not_receive(:deliver_new_response_reminder_alert) + RequestMailer.should_not_receive(:new_response_reminder_alert) send_alerts end @@ -293,7 +295,7 @@ describe RequestMailer, "when sending reminders to requesters to classify a resp end it 'should send the reminder' do - RequestMailer.should_receive(:deliver_new_response_reminder_alert) + RequestMailer.should_receive(:new_response_reminder_alert) send_alerts end end @@ -311,7 +313,7 @@ describe RequestMailer, 'when sending mail when someone has updated an old uncla :public_body => @public_body, :display_status => 'Refused.', :url_title => 'test_request') - @mail = RequestMailer.create_old_unclassified_updated(@info_request) + @mail = RequestMailer.old_unclassified_updated(@info_request) end it 'should have the subject "Someone has updated the status of your request"' do @@ -344,7 +346,7 @@ describe RequestMailer, 'when sending a new response email' do end it 'should not error when sending mails requests with characters requiring quoting in the subject' do - @mail = RequestMailer.create_new_response(@info_request, @incoming_message) + @mail = RequestMailer.new_response(@info_request, @incoming_message) end end @@ -362,20 +364,14 @@ describe RequestMailer, 'requires_admin' do end it 'body should contain the full admin URL' do - mail = RequestMailer.deliver_requires_admin(@info_request) + mail = RequestMailer.requires_admin(@info_request).deliver mail.body.should include('http://test.host/en/admin/request/show/123') end - context 'has an ADMIN_BASE_URL set' do - before(:each) do - Configuration::should_receive(:admin_base_url).and_return('http://our.proxy.server/admin/alaveteli/') - end - - it 'body should contain the full admin URL' do - mail = RequestMailer.deliver_requires_admin(@info_request) - - mail.body.should include('http://our.proxy.server/admin/alaveteli/request/show/123') - end + it "body should contain the message from the user" do + mail = RequestMailer.requires_admin(@info_request, nil, "Something has gone wrong").deliver + mail.body.should include 'Something has gone wrong' end + end diff --git a/spec/models/track_mailer_spec.rb b/spec/mailers/track_mailer_spec.rb index 9bf03c3d0..e8094b692 100644 --- a/spec/models/track_mailer_spec.rb +++ b/spec/mailers/track_mailer_spec.rb @@ -5,13 +5,15 @@ describe TrackMailer do describe 'when sending email alerts for tracked things' do before do - TrackMailer.stub!(:deliver_event_digest) + mail_mock = mock("mail") + mail_mock.stub(:deliver) + TrackMailer.stub!(:event_digest).and_return(mail_mock) Time.stub!(:now).and_return(Time.utc(2007, 11, 12, 23, 59)) end it 'should ask for all the users whose last daily track email was sent more than a day ago' do expected_conditions = [ "last_daily_track_email < ?", Time.utc(2007, 11, 11, 23, 59)] - User.should_receive(:find).with(:all, :conditions => expected_conditions).and_return([]) + User.should_receive(:find_each).with(:conditions => expected_conditions) TrackMailer.alert_tracks end @@ -24,7 +26,7 @@ describe TrackMailer do :url_name => 'test-name', :get_locale => 'en', :should_be_emailed? => true) - User.stub!(:find).and_return([@user]) + User.stub!(:find_each).and_yield(@user) @user.stub!(:receive_email_alerts).and_return(true) @user.stub!(:no_xapian_reindex=) end @@ -67,11 +69,15 @@ describe TrackMailer do @xapian_search = mock('xapian search', :results => []) @found_event = mock_model(InfoRequestEvent, :described_at => @track_thing.created_at + 1.day) @search_result = {:model => @found_event} - InfoRequest.stub!(:full_search).and_return(@xapian_search) + ActsAsXapian::Search.stub!(:new).and_return(@xapian_search) end it 'should ask for the events returned by the tracking query' do - InfoRequest.should_receive(:full_search).with([InfoRequestEvent], 'test query', 'described_at', true, nil, 100, 1).and_return(@xapian_search) + ActsAsXapian::Search.should_receive(:new).with([InfoRequestEvent], 'test query', + :sort_by_prefix => 'described_at', + :sort_by_ascending => true, + :collapse_by_prefix => nil, + :limit => 100).and_return(@xapian_search) TrackMailer.alert_tracks end @@ -79,21 +85,21 @@ describe TrackMailer do sent_email = mock_model(TrackThingsSentEmail, :info_request_event_id => @found_event.id) @track_things_sent_emails_array.stub!(:find).and_return([sent_email]) # this is for the date range find (created in last 14 days) @xapian_search.stub!(:results).and_return([@search_result]) - TrackMailer.should_not_receive(:deliver_event_digest) + TrackMailer.should_not_receive(:event_digest) TrackMailer.alert_tracks end it 'should not include in the email any events not sent in a previous tracking email that were described before the track was set up' do @found_event.stub!(:described_at).and_return(@track_thing.created_at - 1.day) @xapian_search.stub!(:results).and_return([@search_result]) - TrackMailer.should_not_receive(:deliver_event_digest) + TrackMailer.should_not_receive(:event_digest) TrackMailer.alert_tracks end it 'should include in the email any events that the user has not been sent a tracking email on that have been described since the track was set up' do @found_event.stub!(:described_at).and_return(@track_thing.created_at + 1.day) @xapian_search.stub!(:results).and_return([@search_result]) - TrackMailer.should_receive(:deliver_event_digest) + TrackMailer.should_receive(:event_digest) TrackMailer.alert_tracks end @@ -122,14 +128,14 @@ describe TrackMailer do :save! => true, :url_name => 'test-name', :should_be_emailed? => false) - User.stub!(:find).and_return([@user]) + User.stub!(:find_each).and_yield(@user) @user.stub!(:receive_email_alerts).and_return(true) @user.stub!(:no_xapian_reindex=) end it 'should not ask for any daily track things for the user' do expected_conditions = [ "tracking_user_id = ? and track_medium = ?", @user.id, 'email_daily' ] - TrackThing.should_not_receive(:find).with(:all, :conditions => expected_conditions).and_return([]) + TrackThing.should_not_receive(:find).with(:all, :conditions => expected_conditions) TrackMailer.alert_tracks end @@ -137,7 +143,7 @@ describe TrackMailer do @user.stub(:should_be_emailed?).and_return(true) @user.stub(:receive_email_alerts).and_return(false) expected_conditions = [ "tracking_user_id = ? and track_medium = ?", @user.id, 'email_daily' ] - TrackThing.should_not_receive(:find).with(:all, :conditions => expected_conditions).and_return([]) + TrackThing.should_not_receive(:find).with(:all, :conditions => expected_conditions) TrackMailer.alert_tracks end @@ -160,20 +166,19 @@ describe TrackMailer do describe 'delivering the email' do - before do + before :each do @post_redirect = mock_model(PostRedirect, :save! => true, :email_token => "token") PostRedirect.stub!(:new).and_return(@post_redirect) ActionMailer::Base.deliveries = [] + @user = mock_model(User, + :name_and_email => MailHandler.address_from_name_and_email('Tippy Test', 'tippy@localhost'), + :url_name => 'tippy_test' + ) + TrackMailer.event_digest(@user, []).deliver # no items in it email for minimal test end it 'should deliver one email, with right headers' do - @user = mock_model(User, - :name_and_email => MailHandler.address_from_name_and_email('Tippy Test', 'tippy@localhost'), - :url_name => 'tippy_test' - ) - - TrackMailer.deliver_event_digest(@user, []) # no items in it email for minimal test deliveries = ActionMailer::Base.deliveries if deliveries.size > 1 # debugging if there is an error deliveries.each do |d| @@ -190,6 +195,22 @@ describe TrackMailer do deliveries.clear end + + context "force ssl is off" do + # Force SSL is off in the tests. Since the code that selectively switches the protocols + # is in the initialiser for Rails it's hard to test. Hmmm... + # We could AlaveteliConfiguration.stub!(:force_ssl).and_return(true) but the config/environment.rb + # wouldn't get reloaded + + it "should have http links in the email" do + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + + mail.body.should include("http://") + mail.body.should_not include("https://") + end + end end end diff --git a/spec/models/censor_rule_spec.rb b/spec/models/censor_rule_spec.rb index c11b05a03..3782cc630 100644 --- a/spec/models/censor_rule_spec.rb +++ b/spec/models/censor_rule_spec.rb @@ -73,10 +73,10 @@ end describe 'when validating rules' do - describe 'should be invalid without text' do + it 'should be invalid without text' do censor_rule = CensorRule.new censor_rule.valid?.should == false - censor_rule.errors.on(:text).should == "can't be blank" + censor_rule.errors[:text].should == ["can't be blank"] end describe 'when validating a regexp rule' do @@ -96,7 +96,7 @@ describe 'when validating rules' do it 'should add an error message to the text field with the regexp error message' do Regexp.stub!(:new).and_raise(RegexpError.new("very bad regexp")) @censor_rule.valid?.should == false - @censor_rule.errors.on(:text).should == "very bad regexp" + @censor_rule.errors[:text].should == ["very bad regexp"] end end @@ -106,7 +106,7 @@ describe 'when validating rules' do it 'should not add any error message to the text field' do Regexp.stub!(:new) @censor_rule.valid? - @censor_rule.errors.on(:text).should == nil + @censor_rule.errors[:text].should == [] end end @@ -134,15 +134,21 @@ describe 'when validating rules' do it 'should not allow a global text censor rule (without user_id, request_id or public_body_id)' do @censor_rule.valid?.should == false - @expected_error = 'Censor must apply to an info request a user or a body; is invalid' - @censor_rule.errors.full_messages.should == [@expected_error] + + expected_error = ["Rule must apply to an info request, a user or a body"] + @censor_rule.errors[:user].should == expected_error + @censor_rule.errors[:info_request].should == expected_error + @censor_rule.errors[:public_body].should == expected_error end it 'should not allow a global regex censor rule (without user_id, request_id or public_body_id)' do @censor_rule.regexp = true @censor_rule.valid?.should == false - @expected_error = 'Censor must apply to an info request a user or a body; is invalid' - @censor_rule.errors.full_messages.should == [@expected_error] + + expected_error = ["Rule must apply to an info request, a user or a body"] + @censor_rule.errors[:user].should == expected_error + @censor_rule.errors[:info_request].should == expected_error + @censor_rule.errors[:public_body].should == expected_error end end diff --git a/spec/models/contact_mailer_spec.rb b/spec/models/contact_mailer_spec.rb deleted file mode 100644 index 202e45758..000000000 --- a/spec/models/contact_mailer_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') - -describe ContactMailer, " when blah" do - before do - end -end - - diff --git a/spec/models/foi_attachment_spec.rb b/spec/models/foi_attachment_spec.rb index 537a3363c..9b0115c44 100644 --- a/spec/models/foi_attachment_spec.rb +++ b/spec/models/foi_attachment_spec.rb @@ -1,6 +1,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') -describe FoiAttachment, " when calculating due date" do +describe FoiAttachment do before(:each) do load_raw_emails_data diff --git a/spec/models/incoming_message_spec.rb b/spec/models/incoming_message_spec.rb index f53a5856a..76d7eba2e 100644 --- a/spec/models/incoming_message_spec.rb +++ b/spec/models/incoming_message_spec.rb @@ -27,7 +27,7 @@ describe IncomingMessage, " when dealing with incoming mail" do end it "should correctly fold various types of footer" do - Dir.glob(File.join(Spec::Runner.configuration.fixture_path, "files", "email-folding-example-*.txt")).each do |file| + Dir.glob(File.join(RSpec.configuration.fixture_path, "files", "email-folding-example-*.txt")).each do |file| message = File.read(file) parsed = IncomingMessage.remove_quoted_sections(message) expected = File.read("#{file}.expected") @@ -59,12 +59,19 @@ describe IncomingMessage, " when dealing with incoming mail" do message.subject.should == "Câmara Responde: Banco de ideias" end - it 'should not error on display of a message which has no charset set on the body part and - is not good utf-8' do + it 'should deal with GB18030 text even if the charset is missing' do ir = info_requests(:fancy_dog_request) receive_incoming_mail('no-part-charset-bad-utf8.email', ir.incoming_email) message = ir.incoming_messages[1] message.parse_raw_email! + message.get_main_body_text_internal.should include("贵公司负责人") + end + + it 'should not error on display of a message which has no charset set on the body part and is not good UTF-8' do + ir = info_requests(:fancy_dog_request) + receive_incoming_mail('no-part-charset-random-data.email', ir.incoming_email) + message = ir.incoming_messages[1] + message.parse_raw_email! message.get_main_body_text_internal.should include("The above text was badly encoded") end @@ -353,7 +360,7 @@ describe IncomingMessage, " when censoring data" do end it "should apply hard-coded privacy rules to HTML files" do - data = "http://#{Configuration::domain}/c/cheese" + data = "http://#{AlaveteliConfiguration::domain}/c/cheese" @im.html_mask_stuff!(data) data.should == "[WDTK login link]" end @@ -405,12 +412,24 @@ describe IncomingMessage, " when uudecoding bad messages" do im.stub!(:mail).and_return(mail) im.extract_attachments! + im.reload attachments = im.foi_attachments attachments.size.should == 2 attachments[1].filename.should == 'moo.txt' im.get_attachments_for_display.size.should == 1 end + it "should still work when parsed from the raw email" do + raw_email = load_file_fixture 'inline-uuencode.email' + mail = MailHandler.mail_from_raw_email(raw_email) + im = incoming_messages :useless_incoming_message + im.stub!(:raw_email).and_return(raw_email) + im.stub!(:mail).and_return(mail) + im.parse_raw_email! + attachments = im.foi_attachments + attachments.size.should == 2 + end + it "should apply censor rules" do mail = get_fixture_mail('incoming-request-bad-uuencoding.email') @@ -523,3 +542,50 @@ describe IncomingMessage, "when TNEF attachments are attached to messages" do end end +describe IncomingMessage, "when extracting attachments" do + + before do + load_raw_emails_data + end + + it 'handles the case where reparsing changes the body of the main part + and the cached attachment has been deleted' do + # original set of attachment attributes + attachment_attributes = { :url_part_number => 1, + :within_rfc822_subject => nil, + :content_type => "text/plain", + :charset => nil, + :body => "No way!\n", + :hexdigest => "0c8b1b0f5cb9c94ed15a180e73b5c7d1", + :filename => nil } + + # Make a small change in the body returned for the attachment + new_attachment_attributes = attachment_attributes.merge(:body => "No way!", + :hexdigest => "74d2c0a41e074f9cebe49324d5b47414") + + + # Simulate parsing with the original attachments + MailHandler.stub!(:get_attachment_attributes).and_return([attachment_attributes]) + incoming_message = incoming_messages(:useless_incoming_message) + + # Extract the attachments + incoming_message.extract_attachments! + + # delete the cached file for the main body part + main = incoming_message.get_main_body_text_part + main.delete_cached_file! + + # Simulate reparsing with the slightly changed body + MailHandler.stub!(:get_attachment_attributes).and_return([new_attachment_attributes]) + + # Re-extract the attachments + incoming_message.extract_attachments! + + attachments = incoming_message.foi_attachments + attachments.size.should == 1 + attachments.first.hexdigest.should == "74d2c0a41e074f9cebe49324d5b47414" + attachments.first.body.should == 'No way!' + end + +end + diff --git a/spec/models/info_request_event_spec.rb b/spec/models/info_request_event_spec.rb index 796f8b840..eb0de8c86 100644 --- a/spec/models/info_request_event_spec.rb +++ b/spec/models/info_request_event_spec.rb @@ -1,3 +1,4 @@ +# coding: utf-8 require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe InfoRequestEvent do @@ -21,7 +22,7 @@ describe InfoRequestEvent do :event_type => 'sent', :params => {}) event.should_receive(:xapian_mark_needs_index) - event.run_callbacks(:after_save) + event.run_callbacks(:save) end end @@ -118,6 +119,13 @@ describe InfoRequestEvent do @info_request_event.same_email_as_previous_send?.should be_true end + it 'should handle non-ascii characters in the name input' do + address = "\"Someone’s name\" <test@example.com>" + @info_request_event.stub!(:params).and_return(:email => address) + @info_request_event.stub_chain(:info_request, :get_previous_email_sent_to).and_return(address) + @info_request_event.same_email_as_previous_send?.should be_true + end + end end diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb index 544852f91..f9ca44657 100644 --- a/spec/models/info_request_spec.rb +++ b/spec/models/info_request_spec.rb @@ -426,8 +426,8 @@ describe InfoRequest do before do Time.stub!(:now).and_return(Time.utc(2007, 11, 9, 23, 59)) - @mock_comment_event = safe_mock_model(InfoRequestEvent, :created_at => Time.now - 23.days, :event_type => 'comment') - @mock_response_event = safe_mock_model(InfoRequestEvent, :created_at => Time.now - 22.days, :event_type => 'response') + @mock_comment_event = mock_model(InfoRequestEvent, :created_at => Time.now - 23.days, :event_type => 'comment', :response? => false) + @mock_response_event = mock_model(InfoRequestEvent, :created_at => Time.now - 22.days, :event_type => 'response', :response? => true) @info_request = InfoRequest.new(:prominence => 'normal', :awaiting_description => true, :info_request_events => [@mock_response_event, @mock_comment_event]) @@ -457,16 +457,16 @@ describe InfoRequest do describe 'when applying censor rules' do before do - @global_rule = safe_mock_model(CensorRule, :apply_to_text! => nil, + @global_rule = mock_model(CensorRule, :apply_to_text! => nil, :apply_to_binary! => nil) - @user_rule = safe_mock_model(CensorRule, :apply_to_text! => nil, + @user_rule = mock_model(CensorRule, :apply_to_text! => nil, :apply_to_binary! => nil) - @request_rule = safe_mock_model(CensorRule, :apply_to_text! => nil, + @request_rule = mock_model(CensorRule, :apply_to_text! => nil, :apply_to_binary! => nil) - @body_rule = safe_mock_model(CensorRule, :apply_to_text! => nil, + @body_rule = mock_model(CensorRule, :apply_to_text! => nil, :apply_to_binary! => nil) - @user = safe_mock_model(User, :censor_rules => [@user_rule]) - @body = safe_mock_model(PublicBody, :censor_rules => [@body_rule]) + @user = mock_model(User, :censor_rules => [@user_rule]) + @body = mock_model(PublicBody, :censor_rules => [@body_rule]) @info_request = InfoRequest.new(:prominence => 'normal', :awaiting_description => true, :title => 'title') @@ -562,7 +562,48 @@ describe InfoRequest do @info_request.prominence = 'requester_only' @info_request.all_can_view?.should == false end + end + + describe 'when generating json for the api' do + + before do + @user = mock_model(User, :json_for_api => { :id => 20, + :url_name => 'alaveteli_user', + :name => 'Alaveteli User', + :ban_text => '', + :about_me => 'Hi' }) + end + it 'should return full user info for an internal request' do + @info_request = InfoRequest.new(:user => @user) + @info_request.user_json_for_api.should == { :id => 20, + :url_name => 'alaveteli_user', + :name => 'Alaveteli User', + :ban_text => '', + :about_me => 'Hi' } + end end + describe 'when working out a subject for a followup emails' do + + it "should not be confused by an nil subject in the incoming message" do + ir = info_requests(:fancy_dog_request) + im = mock_model(IncomingMessage, + :subject => nil, + :valid_to_reply_to? => true) + subject = ir.email_subject_followup im + subject.should match(/^Re: Freedom of Information request.*fancy dog/) + end + + it "should return a hash with the user's name for an external request" do + @info_request = InfoRequest.new(:external_url => 'http://www.example.com', + :external_user_name => 'External User') + @info_request.user_json_for_api.should == {:name => 'External User'} + end + + it 'should return "Anonymous user" for an anonymous external user' do + @info_request = InfoRequest.new(:external_url => 'http://www.example.com') + @info_request.user_json_for_api.should == {:name => 'Anonymous user'} + end + end end diff --git a/spec/models/mail_server_log_spec.rb b/spec/models/mail_server_log_spec.rb index d0a1d202f..2b44a4559 100644 --- a/spec/models/mail_server_log_spec.rb +++ b/spec/models/mail_server_log_spec.rb @@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe MailServerLog do describe ".load_file" do before :each do - Configuration.stub!(:incoming_email_domain).and_return("example.com") + AlaveteliConfiguration.stub!(:incoming_email_domain).and_return("example.com") File.stub_chain(:stat, :mtime).and_return(DateTime.new(2012, 10, 10)) end @@ -64,8 +64,8 @@ describe MailServerLog do describe ".email_addresses_on_line" do before :each do - Configuration.stub!(:incoming_email_domain).and_return("example.com") - Configuration.stub!(:incoming_email_prefix).and_return("foi+") + AlaveteliConfiguration.stub!(:incoming_email_domain).and_return("example.com") + AlaveteliConfiguration.stub!(:incoming_email_prefix).and_return("foi+") end it "recognises a single incoming email" do @@ -106,7 +106,7 @@ describe MailServerLog do # Postfix logs for a single email go over multiple lines. They are all tied together with the Queue ID. # See http://onlamp.com/onlamp/2004/01/22/postfix.html it "loads the postfix log and untangles seperate email transactions using the queue ID" do - Configuration.stub!(:incoming_email_domain).and_return("example.com") + AlaveteliConfiguration.stub!(:incoming_email_domain).and_return("example.com") log.stub!(:rewind) ir1 = info_requests(:fancy_dog_request) ir2 = info_requests(:naughty_chicken_request) @@ -135,7 +135,7 @@ describe MailServerLog do describe ".scan_for_postfix_queue_ids" do it "returns the queue ids of interest with the connected email addresses" do - Configuration.stub!(:incoming_email_domain).and_return("example.com") + AlaveteliConfiguration.stub!(:incoming_email_domain).and_return("example.com") MailServerLog.scan_for_postfix_queue_ids(log).should == { "CB55836EE58C" => ["request-14-e0e09f97@example.com"], "9634B16F7F7" => ["request-10-1234@example.com"] diff --git a/spec/models/outgoing_mailer_spec.rb b/spec/models/outgoing_mailer_spec.rb deleted file mode 100644 index 5d1ea2dfb..000000000 --- a/spec/models/outgoing_mailer_spec.rb +++ /dev/null @@ -1,140 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') - -describe OutgoingMailer, " when working out follow up addresses" do - # This is done with fixtures as the code is a bit tangled with the way it - # calls TMail. XXX untangle it and make these tests spread out and using - # mocks. Put parts of the tests in spec/lib/tmail_extensions.rb - before(:each) do - load_raw_emails_data - end - - it "should parse them right" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - - # check the basic entry in the fixture is fine - OutgoingMailer.name_and_email_for_followup(ir, im).should == "FOI Person <foiperson@localhost>" - OutgoingMailer.name_for_followup(ir, im).should == "FOI Person" - OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" - end - - it "should work when there is only an email address" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - - im.raw_email.data = im.raw_email.data.sub("\"FOI Person\" <foiperson@localhost>", "foiperson@localhost") - im.parse_raw_email! true - - # check the basic entry in the fixture is fine - OutgoingMailer.name_and_email_for_followup(ir, im).should == "foiperson@localhost" - OutgoingMailer.name_for_followup(ir, im).should == "Geraldine Quango" - OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" - end - - it "should quote funny characters" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - - im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI [ Person") - im.parse_raw_email! true - - # check the basic entry in the fixture is fine - OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI [ Person\" <foiperson@localhost>" - OutgoingMailer.name_for_followup(ir, im).should == "FOI [ Person" - OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" - end - - it "should quote quotes" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - - im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI \\\" Person") - im.parse_raw_email! true - - # check the basic entry in the fixture is fine - OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI \\\" Person\" <foiperson@localhost>" - OutgoingMailer.name_for_followup(ir, im).should == "FOI \" Person" - OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" - end - - it "should quote @ signs" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - - im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI @ Person") - im.parse_raw_email! true - - # check the basic entry in the fixture is fine - OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI @ Person\" <foiperson@localhost>" - OutgoingMailer.name_for_followup(ir, im).should == "FOI @ Person" - OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" - end - -end - -describe OutgoingMailer, "when working out follow up subjects" do - - before(:each) do - load_raw_emails_data - end - - it "should prefix the title with 'Freedom of Information request -' for initial requests" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - - ir.email_subject_request.should == "Freedom of Information request - Why do you have & such a fancy dog?" - end - - it "should use 'Re:' and inital request subject for followups which aren't replies to particular messages" do - ir = info_requests(:fancy_dog_request) - om = outgoing_messages(:useless_outgoing_message) - - OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" - end - - it "should prefix with Re: the subject of the message being replied to" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - om = outgoing_messages(:useless_outgoing_message) - om.incoming_message_followup = im - - OutgoingMailer.subject_for_followup(ir, om).should == "Re: Geraldine FOI Code AZXB421" - end - - it "should not add Re: prefix if there already is such a prefix" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - om = outgoing_messages(:useless_outgoing_message) - om.incoming_message_followup = im - - im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: Re: Geraldine FOI Code AZXB421") - OutgoingMailer.subject_for_followup(ir, om).should == "Re: Geraldine FOI Code AZXB421" - end - - it "should not add Re: prefix if there already is a lower case re: prefix" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - om = outgoing_messages(:useless_outgoing_message) - om.incoming_message_followup = im - - im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: re: Geraldine FOI Code AZXB421") - im.parse_raw_email! true - - OutgoingMailer.subject_for_followup(ir, om).should == "re: Geraldine FOI Code AZXB421" - end - - it "should use 'Re:' and initial request subject when replying to failed delivery notifications" do - ir = info_requests(:fancy_dog_request) - im = ir.incoming_messages[0] - om = outgoing_messages(:useless_outgoing_message) - om.incoming_message_followup = im - - im.raw_email.data = im.raw_email.data.sub("foiperson@localhost", "postmaster@localhost") - im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: Delivery Failed") - im.parse_raw_email! true - - OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" - end -end - - diff --git a/spec/models/outgoing_message_spec.rb b/spec/models/outgoing_message_spec.rb index 51bb6fdf5..60164fb31 100644 --- a/spec/models/outgoing_message_spec.rb +++ b/spec/models/outgoing_message_spec.rb @@ -16,7 +16,7 @@ describe OutgoingMessage, " when making an outgoing message" do it "should not index the email addresses" do # also used for track emails @outgoing_message.get_text_for_indexing.should_not include("foo@bar.com") - end + end it "should not display email addresses on page" do @outgoing_message.get_body_for_html_display.should_not include("foo@bar.com") @@ -33,6 +33,23 @@ describe OutgoingMessage, " when making an outgoing message" do it "should work out a salutation" do @om.get_salutation.should == "Dear Geraldine Quango," end + + it 'should produce the expected text for an internal review request' do + public_body = mock_model(PublicBody, :name => 'A test public body') + info_request = mock_model(InfoRequest, :public_body => public_body, + :url_title => 'a_test_title', + :title => 'A test title', + :apply_censor_rules_to_text! => nil) + outgoing_message = OutgoingMessage.new({ + :status => 'ready', + :message_type => 'followup', + :what_doing => 'internal_review', + :info_request => info_request + }) + expected_text = "I am writing to request an internal review of A test public body's handling of my FOI request 'A test title'." + outgoing_message.body.should include(expected_text) + end + end diff --git a/spec/models/public_body_spec.rb b/spec/models/public_body_spec.rb index c2e0a6353..bc693b4da 100644 --- a/spec/models/public_body_spec.rb +++ b/spec/models/public_body_spec.rb @@ -169,6 +169,14 @@ describe PublicBody, " when saving" do @public_body.save! @public_body.first_letter.should == 'T' end + + it "should save the name when renaming an existing public body" do + public_body = public_bodies(:geraldine_public_body) + public_body.name = "Mark's Public Body" + public_body.save! + + public_body.name.should == "Mark's Public Body" + end end describe PublicBody, "when searching" do @@ -210,7 +218,7 @@ describe PublicBody, "when searching" do end it "should cope with same url_name across multiple locales" do - PublicBody.with_locale(:es) do + I18n.with_locale(:es) do # use the unique spanish name to retrieve and edit body = PublicBody.find_by_url_name_with_historic('etgq') body.short_name = 'tgq' # Same as english version @@ -231,7 +239,7 @@ end describe PublicBody, " when dealing public body locales" do it "shouldn't fail if it internal_admin_body was created in a locale other than the default" do # first time, do it with the non-default locale - PublicBody.with_locale(:es) do + I18n.with_locale(:es) do PublicBody.internal_admin_body end @@ -378,7 +386,7 @@ describe PublicBody, " when loading CSV files" do PublicBody.count.should == original_count + 3 - # XXX Not sure why trying to do a PublicBody.with_locale fails here. Seems related to + # XXX Not sure why trying to do a I18n.with_locale fails here. Seems related to # the way categories are loaded every time from the PublicBody class. For now we just # test some translation was done. body = PublicBody.find_by_name('North West Fake Authority') diff --git a/spec/models/user_mailer_spec.rb b/spec/models/user_mailer_spec.rb deleted file mode 100644 index 0792aaab2..000000000 --- a/spec/models/user_mailer_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') - -describe UserMailer, " when blah" do - before do - end -end - - diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index e31c3f1b5..96c169604 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -27,11 +27,22 @@ describe User, "showing the name" do @user.name.should == 'Some Name' end - it 'should show if user has been banned' do - @user.ban_text = "Naughty user" - @user.name.should == 'Some Name (Account suspended)' + describe 'if user has been banned' do + + before do + @user.ban_text = "Naughty user" + end + + it 'should show an "Account suspended" suffix' do + @user.name.should == 'Some Name (Account suspended)' + end + + it 'should return a string when the user has been banned, not a SafeBuffer' do + @user.name.class.should == String + end end + end describe User, " when authenticating" do @@ -152,10 +163,10 @@ end describe User, "when reindexing referencing models" do before do - @request_event = safe_mock_model(InfoRequestEvent, :xapian_mark_needs_index => true) - @request = safe_mock_model(InfoRequest, :info_request_events => [@request_event]) - @comment_event = safe_mock_model(InfoRequestEvent, :xapian_mark_needs_index => true) - @comment = safe_mock_model(Comment, :info_request_events => [@comment_event]) + @request_event = mock_model(InfoRequestEvent, :xapian_mark_needs_index => true) + @request = mock_model(InfoRequest, :info_request_events => [@request_event]) + @comment_event = mock_model(InfoRequestEvent, :xapian_mark_needs_index => true) + @comment = mock_model(Comment, :info_request_events => [@comment_event]) @user = User.new(:comments => [@comment], :info_requests => [@request]) end diff --git a/spec/models/xapian_spec.rb b/spec/models/xapian_spec.rb index 8c99d550f..c40334142 100644 --- a/spec/models/xapian_spec.rb +++ b/spec/models/xapian_spec.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe User, " when indexing users with Xapian" do @@ -8,8 +9,7 @@ describe User, " when indexing users with Xapian" do end it "should search by name" do - # def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page) - xapian_object = InfoRequest.full_search([User], "Silly", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([User], "Silly", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model].should == users(:silly_name_user) end @@ -17,8 +17,7 @@ describe User, " when indexing users with Xapian" do it "should search by 'about me' text" do user = users(:bob_smith_user) - # def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page) - xapian_object = InfoRequest.full_search([User], "stuff", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([User], "stuff", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model].should == user @@ -26,10 +25,10 @@ describe User, " when indexing users with Xapian" do user.save! update_xapian_index - xapian_object = InfoRequest.full_search([User], "stuff", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([User], "stuff", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([User], "aardvark", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([User], "aardvark", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model].should == user end @@ -42,26 +41,26 @@ describe PublicBody, " when indexing public bodies with Xapian" do end it "should search index the main name field" do - xapian_object = InfoRequest.full_search([PublicBody], "humpadinking", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "humpadinking", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model].should == public_bodies(:humpadink_public_body) end it "should search index the notes field" do - xapian_object = InfoRequest.full_search([PublicBody], "albatross", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "albatross", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model].should == public_bodies(:humpadink_public_body) end it "should delete public bodies from the index when they are destroyed" do - xapian_object = InfoRequest.full_search([PublicBody], "albatross", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "albatross", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model].should == public_bodies(:humpadink_public_body) public_bodies(:forlorn_public_body).destroy update_xapian_index - xapian_object = InfoRequest.full_search([PublicBody], "lonely", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "lonely", :limit => 100) xapian_object.results.should == [] end @@ -75,13 +74,13 @@ describe PublicBody, " when indexing requests by body they are to" do end it "should find requests to the body" do - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:tgq", :limit => 100) xapian_object.results.size.should == PublicBody.find_by_url_name("tgq").info_requests.map(&:info_request_events).flatten.size end it "should update index correctly when URL name of body changes" do # initial search - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:tgq", :limit => 100) xapian_object.results.size.should == PublicBody.find_by_url_name("tgq").info_requests.map(&:info_request_events).flatten.size models_found_before = xapian_object.results.map { |x| x[:model] } @@ -93,9 +92,9 @@ describe PublicBody, " when indexing requests by body they are to" do update_xapian_index # check we get results expected - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:tgq", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:gq", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:gq", :limit => 100) xapian_object.results.size.should == PublicBody.find_by_url_name("gq").info_requests.map(&:info_request_events).flatten.size models_found_after = xapian_object.results.map { |x| x[:model] } @@ -113,11 +112,11 @@ describe PublicBody, " when indexing requests by body they are to" do update_xapian_index # check we get results expected - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:tgq", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:gq", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:gq", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:" + body.url_name, 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:#{body.url_name}", :limit => 100) xapian_object.results.size.should == public_bodies(:geraldine_public_body).info_requests.map(&:info_request_events).flatten.size models_found_after = xapian_object.results.map { |x| x[:model] } end @@ -130,13 +129,14 @@ describe User, " when indexing requests by user they are from" do end it "should find requests from the user" do - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith", + :sort_by_prefix => 'created_at', :sort_by_ascending => true, :limit => 100) xapian_object.results.map{|x|x[:model]}.should =~ InfoRequestEvent.all(:conditions => "info_request_id in (select id from info_requests where user_id = #{users(:bob_smith_user).id})") end it "should find just the sent message events from a particular user" do - # def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page) - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith variety:sent", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith variety:sent", + :sort_by_prefix => 'created_at', :sort_by_ascending => true, :limit => 100) xapian_object.results.map{|x|x[:model]}.should =~ InfoRequestEvent.all(:conditions => "info_request_id in (select id from info_requests where user_id = #{users(:bob_smith_user).id}) and event_type = 'sent'") xapian_object.results[2][:model].should == info_request_events(:useless_outgoing_message_event) xapian_object.results[1][:model].should == info_request_events(:silly_outgoing_message_event) @@ -150,8 +150,9 @@ describe User, " when indexing requests by user they are from" do update_xapian_index - # def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page) - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, 'request_collapse', 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith", + :sort_by_prefix => 'created_at', :sort_by_ascending => true, + :collapse_by_prefix => 'request_collapse', :limit => 100) xapian_object.results.map{|x|x[:model].info_request}.should =~ InfoRequest.all(:conditions => "user_id = #{users(:bob_smith_user).id}") end @@ -172,8 +173,7 @@ describe User, " when indexing requests by user they are from" do update_xapian_index - # def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page) - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:john_k", 'created_at', true, 'request_collapse', 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:john_k", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model].should == info_request_events(:silly_outgoing_message_event) end @@ -181,7 +181,8 @@ describe User, " when indexing requests by user they are from" do it "should update index correctly when URL name of user changes" do # initial search - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith", + :sort_by_prefix => 'created_at', :sort_by_ascending => true, :limit => 100) xapian_object.results.map{|x|x[:model]}.should =~ InfoRequestEvent.all(:conditions => "info_request_id in (select id from info_requests where user_id = #{users(:bob_smith_user).id})") models_found_before = xapian_object.results.map { |x| x[:model] } @@ -193,9 +194,10 @@ describe User, " when indexing requests by user they are from" do update_xapian_index # check we get results expected - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:robert_smith", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:robert_smith", + :sort_by_prefix => 'created_at', :sort_by_ascending => true, :limit => 100) models_found_after = xapian_object.results.map { |x| x[:model] } models_found_before.should == models_found_after end @@ -208,13 +210,13 @@ describe User, " when indexing comments by user they are by" do end it "should find requests from the user" do - xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_emnameem", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "commented_by:silly_emnameem", :limit => 100) xapian_object.results.size.should == 1 end it "should update index correctly when URL name of user changes" do # initial search - xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_emnameem", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "commented_by:silly_emnameem", :limit => 100) xapian_object.results.size.should == 1 models_found_before = xapian_object.results.map { |x| x[:model] } @@ -226,9 +228,9 @@ describe User, " when indexing comments by user they are by" do update_xapian_index # check we get results expected - xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_emnameem", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "commented_by:silly_emnameem", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_name", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "commented_by:silly_name", :limit => 100) xapian_object.results.size.should == 1 models_found_after = xapian_object.results.map { |x| x[:model] } @@ -243,7 +245,7 @@ describe InfoRequest, " when indexing requests by their title" do end it "should find events for the request" do - xapian_object = InfoRequest.full_search([InfoRequestEvent], "request:how_much_public_money_is_wasted_o", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "request:how_much_public_money_is_wasted_o", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model] == info_request_events(:silly_outgoing_message_event) end @@ -257,9 +259,9 @@ describe InfoRequest, " when indexing requests by their title" do update_xapian_index # check we get results expected - xapian_object = InfoRequest.full_search([InfoRequestEvent], "request:how_much_public_money_is_wasted_o", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "request:how_much_public_money_is_wasted_o", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([InfoRequestEvent], "request:really_naughty", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "request:really_naughty", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model] == info_request_events(:silly_outgoing_message_event) end @@ -277,11 +279,11 @@ describe InfoRequest, " when indexing requests by tag" do ir.save! update_xapian_index - xapian_object = InfoRequest.full_search([InfoRequestEvent], "tag:bunnyrabbit", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "tag:bunnyrabbit", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model] == info_request_events(:silly_outgoing_message_event) - xapian_object = InfoRequest.full_search([InfoRequestEvent], "tag:orangeaardvark", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "tag:orangeaardvark", :limit => 100) xapian_object.results.size.should == 0 end end @@ -298,14 +300,14 @@ describe PublicBody, " when indexing authorities by tag" do body.save! update_xapian_index - xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model] == public_bodies(:geraldine_public_body) - xapian_object = InfoRequest.full_search([PublicBody], "tag:mice:3", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice:3", :limit => 100) xapian_object.results.size.should == 1 xapian_object.results[0][:model] == public_bodies(:geraldine_public_body) - xapian_object = InfoRequest.full_search([PublicBody], "tag:orangeaardvark", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:orangeaardvark", :limit => 100) xapian_object.results.size.should == 0 end end @@ -327,11 +329,11 @@ describe PublicBody, " when only indexing selected things on a rebuild" do values = false texts = false rebuild_xapian_index(terms, values, texts, dropfirst) - xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) xapian_object.results.map{|x|x[:model]}.should =~ PublicBody.all # only reindex 'tag' and text dropfirst = true @@ -339,32 +341,57 @@ describe PublicBody, " when only indexing selected things on a rebuild" do values = false texts = true rebuild_xapian_index(terms, values, texts, dropfirst) - xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100) xapian_object.results.size.should == 1 - xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) xapian_object.results.size.should == 1 - xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) xapian_object.results.size.should == 0 # only reindex 'variety' term, but keeping the existing data in-place dropfirst = false terms = "V" texts = false rebuild_xapian_index(terms, values, texts, dropfirst) - xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100) xapian_object.results.size.should == 1 - xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) xapian_object.results.size.should == 1 - xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) xapian_object.results.map{|x|x[:model]}.should =~ PublicBody.all # only reindex 'variety' term, blowing away existing data dropfirst = true rebuild_xapian_index(terms, values, texts, dropfirst) - xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100) xapian_object.results.size.should == 0 - xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1) + xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100) xapian_object.results.map{|x|x[:model]}.should =~ PublicBody.all end end +# I would expect ActsAsXapian to have some tests under vendor/plugins/acts_as_xapian, but +# it looks like this is not the case. Putting a test here instead. +describe ActsAsXapian::Search, "#words_to_highlight" do + it "should return a list of words used in the search" do + s = ActsAsXapian::Search.new([PublicBody], "albatross words", :limit => 100) + s.words_to_highlight.should == ["albatross", "words"] + end + + it "should remove any operators" do + s = ActsAsXapian::Search.new([PublicBody], "albatross words tag:mice", :limit => 100) + s.words_to_highlight.should == ["albatross", "words"] + end + + # This is the current behaviour but it seems a little simplistic to me + it "should separate punctuation" do + s = ActsAsXapian::Search.new([PublicBody], "The doctor's patient", :limit => 100) + s.words_to_highlight.should == ["The", "doctor", "s", "patient"] + end + + it "should handle non-ascii characters" do + s = ActsAsXapian::Search.new([PublicBody], "adatigénylés words tag:mice", :limit => 100) + s.words_to_highlight.should == ["adatigénylés", "words"] + end + +end diff --git a/spec/script/mailin_spec.rb b/spec/script/mailin_spec.rb index f0bca2297..46ad39f7f 100644 --- a/spec/script/mailin_spec.rb +++ b/spec/script/mailin_spec.rb @@ -5,7 +5,7 @@ def mailin_test(email_filename) Dir.chdir Rails.root do xc = ExternalCommand.new("script/mailin") mail = load_file_fixture(email_filename) - ir = info_requests(:boring_request) + ir = info_requests(:other_request) mail.gsub!('EMAIL_TO', ir.incoming_email) mail.gsub!('EMAIL_FROM', 'responder@localhost') xc.run(mail) @@ -16,10 +16,24 @@ end describe "When importing mail into the application" do + # Turn off transactional fixtures for this suite - incoming message is imported + # outside the transaction via ExternalCommand, so needs to be destroyed outside the + # transaction + self.use_transactional_fixtures = false + it "should not produce any output and should return a 0 code on importing a plain email" do r = mailin_test("incoming-request-empty.email") r.status.should == 0 r.out.should == "" end + # Destroy the incoming message so that it doesn't affect other tests + after do + ir = info_requests(:other_request) + incoming_message = ir.incoming_messages[0] + incoming_message.fully_destroy + # And get rid of any remaining purge requests + PurgeRequest.destroy_all + end + end diff --git a/spec/spec.opts b/spec/spec.opts deleted file mode 100644 index ff5051c37..000000000 --- a/spec/spec.opts +++ /dev/null @@ -1,3 +0,0 @@ ---colour ---format -specdoc diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 561a75da6..a3b06cea8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,292 +1,153 @@ -# This file is copied to ~/spec when you run 'ruby script/generate rspec' -# from the project root directory. -ENV["RAILS_ENV"] = 'test' -require File.expand_path(File.join('..', '..', 'config', 'environment'), __FILE__) -require 'spec/autorun' -require 'spec/rails' - -# set a default username and password so we can test -config = MySociety::Config.load_default() -config['ADMIN_USERNAME'] = 'foo' -config['ADMIN_PASSWORD'] = 'baz' - -# tests assume 20 days -config['REPLY_LATE_AFTER_DAYS'] = 20 - -# register a fake Varnish server -require 'fakeweb' -FakeWeb.register_uri(:purge, %r|varnish.localdomain|, :body => "OK") - -# Uncomment the next line to use webrat's matchers -#require 'webrat/integrations/rspec-rails' - -# Use test-specific translations -FastGettext.add_text_domain 'app', :path => File.join(File.dirname(__FILE__), 'fixtures', 'locale'), :type => :po -FastGettext.default_text_domain = 'app' -Spec::Runner.configure do |config| - # If you're not using ActiveRecord you should remove these - # lines, delete config/database.yml and disable :active_record - # in your config/boot.rb - - # fixture_path must end in a separator - config.fixture_path = File.join(Rails.root, 'spec', 'fixtures') + File::SEPARATOR - config.global_fixtures = :users, - :public_bodies, - :public_body_translations, - :public_body_versions, - :info_requests, - :raw_emails, - :incoming_messages, - :outgoing_messages, - :comments, - :info_request_events, - :track_things, - :foi_attachments, - :has_tag_string_tags, - :holidays, - :track_things_sent_emails - - # This section makes the garbage collector run less often to speed up tests - last_gc_run = Time.now - - config.before(:each) do - GC.disable - end - - config.after(:each) do - if Time.now - last_gc_run > 4 - GC.enable - GC.start - last_gc_run = Time.now - end - end - - # == Fixtures - # - # You can declare fixtures for each example_group like this: - # describe "...." do - # fixtures :table_a, :table_b - # - # Alternatively, if you prefer to declare them only once, you can - # do so right here. Just uncomment the next line and replace the fixture - # names with your fixtures. - # - # config.global_fixtures = :table_a, :table_b - # - # If you declare global fixtures, be aware that they will be declared - # for all of your examples, even those that don't use them. - # - # You can also declare which fixtures to use (for example fixtures for test/fixtures): - # - # config.fixture_path = Rails.root + '/spec/fixtures/' - # - # == Mock Framework - # - # RSpec uses its own mocking framework by default. If you prefer to - # use mocha, flexmock or RR, uncomment the appropriate line: - # - # config.mock_with :mocha - # config.mock_with :flexmock - # config.mock_with :rr - # - # == Notes - # - # For more information take a look at Spec::Runner::Configuration and Spec::Runner -end - -# XXX No idea what namespace/class/module to put this in -def receive_incoming_mail(email_name, email_to, email_from = 'geraldinequango@localhost') - email_name = file_fixture_name(email_name) - content = File.read(email_name) - content.gsub!('EMAIL_TO', email_to) - content.gsub!('EMAIL_FROM', email_from) - RequestMailer.receive(content) -end - -def file_fixture_name(file_name) - return File.join(Spec::Runner.configuration.fixture_path, "files", file_name) -end - -def load_file_fixture(file_name, as_binary=false) - file_name = file_fixture_name(file_name) - content = File.open(file_name, 'r') do |file| - if as_binary - file.set_encoding(Encoding::BINARY) if file.respond_to?(:set_encoding) - end - file.read +require 'rubygems' +require 'spork' + +#uncomment the following line to use spork with the debugger +#require 'spork/ext/ruby-debug' +require 'simplecov' +require 'coveralls' +# Generate coverage locally in html as well as in coveralls.io +SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ + SimpleCov::Formatter::HTMLFormatter, + Coveralls::SimpleCov::Formatter +] +SimpleCov.start('rails') do + add_filter 'commonlib' + add_filter 'vendor/plugins' +end + +Spork.prefork do + # Loading more in this block will cause your tests to run faster. However, + # if you change any configuration or code from libraries loaded here, you'll + # need to restart spork for it take effect. + + # This file is copied to spec/ when you run 'rails generate rspec:install' + ENV["RAILS_ENV"] ||= 'test' + require File.expand_path("../../config/environment", __FILE__) + require 'rspec/rails' + require 'rspec/autorun' + + # Requires supporting ruby files with custom matchers and macros, etc, + # in spec/support/ and its subdirectories. + Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} + + # Use test-specific translations + FastGettext.add_text_domain 'app', :path => File.join(File.dirname(__FILE__), 'fixtures', 'locale'), :type => :po + FastGettext.default_text_domain = 'app' + + RSpec.configure do |config| + # ## Mock Framework + # + # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: + # + # config.mock_with :mocha + # config.mock_with :flexmock + # config.mock_with :rr + + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # The order (!) of this is important thanks to foreign keys + config.global_fixtures = :users, + :public_bodies, + :public_body_translations, + :public_body_versions, + :info_requests, + :raw_emails, + :incoming_messages, + :outgoing_messages, + :comments, + :info_request_events, + :track_things, + :has_tag_string_tags, + :holidays + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # If true, the base class of anonymous controllers will be inferred + # automatically. This will be the default behavior in future versions of + # rspec-rails. + config.infer_base_class_for_anonymous_controllers = false + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = "random" + + # This is a workaround for a strange thing where ActionMailer::Base.deliveries isn't being + # cleared out correctly in controller specs. So, do it here for everything. + config.before(:each) do + ActionMailer::Base.deliveries = [] end - return content -end -def parse_all_incoming_messages - IncomingMessage.find(:all).each{ |x| x.parse_raw_email! } -end - -def load_raw_emails_data - raw_emails_yml = File.join(Spec::Runner.configuration.fixture_path, "raw_emails.yml") - for raw_email_id in YAML::load_file(raw_emails_yml).map{|k,v| v["id"]} do - raw_email = RawEmail.find(raw_email_id) - raw_email.data = load_file_fixture("raw_emails/%d.email" % [raw_email_id]) + # Any test that messes with the locale needs to restore the state afterwards so that it + # doesn't interfere with any subsequent tests. This is made more complicated by the + # ApplicationController#set_gettext_locale which sets the locale and so you may be setting + # the locale in your tests and not even realising it. So, let's make things easier for + # ourselves and just always restore the locale for all tests. + config.before(:each) do + @save_i18n_locale = I18n.locale end -end -# Rebuild the current xapian index -def rebuild_xapian_index(terms = true, values = true, texts = true, dropfirst = true) - if dropfirst - begin - ActsAsXapian.readable_init - FileUtils.rm_r(ActsAsXapian.db_path) - rescue RuntimeError - end - ActsAsXapian.writable_init - ActsAsXapian.writable_db.close + config.after(:each) do + I18n.locale = @save_i18n_locale end - parse_all_incoming_messages - # safe_rebuild=true, which involves forking to avoid memory leaks, doesn't work well with rspec. - # unsafe is significantly faster, and we can afford possible memory leaks while testing. - models = [PublicBody, User, InfoRequestEvent] - ActsAsXapian.rebuild_index(models, verbose=false, terms, values, texts, safe_rebuild=false) -end - -# Create a clean xapian index based on the fixture files and the raw_email data. -def create_fixtures_xapian_index - load_raw_emails_data - rebuild_xapian_index -end -def update_xapian_index - ActsAsXapian.update_index(flush_to_disk=false, verbose=false) -end - -# Copy the xapian index created in create_fixtures_xapian_index to a temporary -# copy at the same level and point xapian at the copy -def get_fixtures_xapian_index() - # Create a base index for the fixtures if not already created - $existing_xapian_db ||= create_fixtures_xapian_index - # Store whatever the xapian db path is originally - $original_xapian_path ||= ActsAsXapian.db_path - path_array = $original_xapian_path.split(File::Separator) - path_array.pop - temp_path = File.join(path_array, 'test.temp') - FileUtils.remove_entry_secure(temp_path, force=true) - FileUtils.cp_r($original_xapian_path, temp_path) - ActsAsXapian.db_path = temp_path -end + # This section makes the garbage collector run less often to speed up tests + last_gc_run = Time.now -# Validate an entire HTML page -def validate_html(html) - $tempfilecount = $tempfilecount + 1 - tempfilename = File.join(Dir::tmpdir, "railshtmlvalidate."+$$.to_s+"."+$tempfilecount.to_s+".html") - File.open(tempfilename, "w+") do |f| - f.puts html - end - if not system($html_validation_script, *($html_validation_script_options +[tempfilename])) - raise "HTML validation error in " + tempfilename + " HTTP status: " + @response.response_code.to_s + config.before(:each) do + GC.disable end - File.unlink(tempfilename) - return true -end - -# Validate HTML fragment by wrapping it as the <body> of a page -def validate_as_body(html) - validate_html('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' + - "<html><head><title>Test</title></head><body>#{html}</body></html>") -end -def basic_auth_login(request, username = nil, password = nil) - username = Configuration::admin_username if username.nil? - password = Configuration::admin_password if password.nil? - request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("#{username}:#{password}") -end - -# Monkeypatch! Validate HTML in tests. -$html_validation_script_found = false -Configuration::utility_search_path.each do |d| - $html_validation_script = File.join(d, "validate") - $html_validation_script_options = ["--charset=utf-8"] - if File.file? $html_validation_script and File.executable? $html_validation_script - $html_validation_script_found = true - break - end -end -if $tempfilecount.nil? - $tempfilecount = 0 - if $html_validation_script_found - module ActionController - module TestProcess - # Hook into the process function, so can automatically get HTML after each request - alias :original_process :process - def is_fragment - # XXX there must be a better way of doing this! - return @request.query_parameters["action"] == "search_typeahead" - end - def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET') - self.original_process(action, parameters, session, flash, http_method) - # don't validate auto-generated HTML - return if @request.query_parameters["action"] == "get_attachment_as_html" - # XXX Is there a better way to check this than calling a private method? - return unless @response.template.controller.instance_eval { integrate_views? } - # And then if HTML, not a redirect (302, 301) - if @response.content_type == "text/html" && ! [301,302,401].include?(@response.response_code) - if !is_fragment - validate_html(@response.body) - else - # it's a partial - validate_as_body(@response.body) - end - end - end - end - end - else - puts "WARNING: HTML validation script " + $html_validation_script + " not found" + config.after(:each) do + if Time.now - last_gc_run > 4 + GC.enable + GC.start + last_gc_run = Time.now + end end -end - -# to_ary differs in Ruby 1.8 and 1.9 -# @see http://yehudakatz.com/2010/01/02/the-craziest-fing-bug-ive-ever-seen/ -def safe_mock_model(model, args = {}) - mock = mock_model(model, args) - mock.should_receive(:to_ary).any_number_of_times - mock -end - -def get_fixture_mail(filename) - MailHandler.mail_from_raw_email(load_file_fixture(filename)) -end - -def load_test_categories - PublicBodyCategories.add(:en, [ - "Local and regional", - [ "local_council", "Local councils", "a local council" ], - "Miscellaneous", - [ "other", "Miscellaneous", "miscellaneous" ],]) -end + end + # XXX No idea what namespace/class/module to put this in + # Create a clean xapian index based on the fixture files and the raw_email data. + def create_fixtures_xapian_index + load_raw_emails_data + rebuild_xapian_index + end -# Monkeypatch applicationcontroller because the `render_to_string` -# method in the original breaks all the rspec test assertions such as -# `should render_template('foo')`. Same problem as -# http://stackoverflow.com/questions/8174415/is-it-possible-to-assert-template-or-render-template-against-the-same-partial-wi -# - a bug in either Rails or Rspec I don't have the time to fix :( + def with_env_tz(new_tz = 'US/Eastern') + old_tz, ENV['TZ'] = ENV['TZ'], new_tz + yield + ensure + old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + end -class ApplicationController < ActionController::Base - def set_popup_banner - @popup_banner = nil - end -end + def with_active_record_default_timezone(zone) + old_zone, ActiveRecord::Base.default_timezone = ActiveRecord::Base.default_timezone, zone + yield + ensure + ActiveRecord::Base.default_timezone = old_zone + end + def load_test_categories + PublicBodyCategories.add(:en, [ + "Local and regional", + [ "local_council", "Local councils", "a local council" ], + "Miscellaneous", + [ "other", "Miscellaneous", "miscellaneous" ],]) + end -def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield -ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + def basic_auth_login(request, username = nil, password = nil) + username = AlaveteliConfiguration::admin_username if username.nil? + password = AlaveteliConfiguration::admin_password if password.nil? + request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("#{username}:#{password}") + end end -def with_active_record_default_timezone(zone) - old_zone, ActiveRecord::Base.default_timezone = ActiveRecord::Base.default_timezone, zone - yield -ensure - ActiveRecord::Base.default_timezone = old_zone +Spork.each_run do + # This code will be run each time you run your specs. end diff --git a/spec/support/email_helpers.rb b/spec/support/email_helpers.rb new file mode 100644 index 000000000..252b1f137 --- /dev/null +++ b/spec/support/email_helpers.rb @@ -0,0 +1,23 @@ +def load_raw_emails_data + raw_emails_yml = File.join(RSpec.configuration.fixture_path, "raw_emails.yml") + for raw_email_id in YAML::load_file(raw_emails_yml).map{|k,v| v["id"]} do + raw_email = RawEmail.find(raw_email_id) + raw_email.data = load_file_fixture("raw_emails/%d.email" % [raw_email_id]) + end +end + +def receive_incoming_mail(email_name, email_to, email_from = 'geraldinequango@localhost') + email_name = file_fixture_name(email_name) + content = File.open(email_name, 'rb') { |f| f.read } + content.gsub!('EMAIL_TO', email_to) + content.gsub!('EMAIL_FROM', email_from) + RequestMailer.receive(content) +end + +def get_fixture_mail(filename) + MailHandler.mail_from_raw_email(load_file_fixture(filename)) +end + +def parse_all_incoming_messages + IncomingMessage.find(:all).each{ |x| x.parse_raw_email! } +end diff --git a/spec/support/load_file_fixtures.rb b/spec/support/load_file_fixtures.rb new file mode 100644 index 000000000..a54505e99 --- /dev/null +++ b/spec/support/load_file_fixtures.rb @@ -0,0 +1,8 @@ +def file_fixture_name(file_name) + return File.join(RSpec.configuration.fixture_path, "files", file_name) +end + +def load_file_fixture(file_name) + file_name = file_fixture_name(file_name) + return File.open(file_name, 'rb') { |f| f.read } +end diff --git a/spec/support/xapian_index.rb b/spec/support/xapian_index.rb new file mode 100644 index 000000000..344c28ebb --- /dev/null +++ b/spec/support/xapian_index.rb @@ -0,0 +1,42 @@ +# Rebuild the current xapian index +def rebuild_xapian_index(terms = true, values = true, texts = true, dropfirst = true) + if dropfirst + begin + ActsAsXapian.readable_init + FileUtils.rm_r(ActsAsXapian.db_path) + rescue RuntimeError + end + ActsAsXapian.writable_init + ActsAsXapian.writable_db.close + end + parse_all_incoming_messages + # safe_rebuild=true, which involves forking to avoid memory leaks, doesn't work well with rspec. + # unsafe is significantly faster, and we can afford possible memory leaks while testing. + models = [PublicBody, User, InfoRequestEvent] + ActsAsXapian.rebuild_index(models, verbose=false, terms, values, texts, safe_rebuild=false) +end + +def update_xapian_index + ActsAsXapian.update_index(flush_to_disk=false, verbose=false) +end + +# Copy the xapian index created in create_fixtures_xapian_index to a temporary +# copy at the same level and point xapian at the copy +def get_fixtures_xapian_index() + # Create a base index for the fixtures if not already created + $existing_xapian_db ||= create_fixtures_xapian_index + # Store whatever the xapian db path is originally + $original_xapian_path ||= ActsAsXapian.db_path + path_array = $original_xapian_path.split(File::Separator) + path_array.pop + temp_path = File.join(path_array, 'test.temp') + FileUtils.remove_entry_secure(temp_path, force=true) + FileUtils.cp_r($original_xapian_path, temp_path) + ActsAsXapian.db_path = temp_path +end + +# Create a clean xapian index based on the fixture files and the raw_email data. +def create_fixtures_xapian_index + load_raw_emails_data + rebuild_xapian_index +end diff --git a/spec/views/public_body/show.rhtml_spec.rb b/spec/views/public_body/show.html.erb_spec.rb index b68b3f43b..0559fc8ef 100644 --- a/spec/views/public_body/show.rhtml_spec.rb +++ b/spec/views/public_body/show.html.erb_spec.rb @@ -1,6 +1,6 @@ require File.expand_path(File.join('..', '..', '..', 'spec_helper'), __FILE__) -describe "when viewing a body" do +describe "public_body/show" do before do @pb = mock_model(PublicBody, :name => 'Test Quango', @@ -17,64 +17,57 @@ describe "when viewing a body" do @pb.stub!(:is_requestable?).and_return(true) @pb.stub!(:has_notes?).and_return(false) @pb.stub!(:has_tag?).and_return(false) - @xap = mock_model(ActsAsXapian::Search, :matches_estimated => 2) + @xap = mock(ActsAsXapian::Search, :matches_estimated => 2) @xap.stub!(:results).and_return([ { :model => mock_event }, { :model => mock_event } ]) - assigns[:public_body] = @pb - assigns[:track_thing] = mock_model(TrackThing, - :track_type => 'public_body_updates', :public_body => @pb, :params => {}) - assigns[:xapian_requests] = @xap - assigns[:page] = 1 - assigns[:per_page] = 10 - # work round a bug in ActionController::TestRequest; allows request.query_string to work in the template - request.env["REQUEST_URI"] = "" + assign(:public_body, @pb) + assign(:track_thing, mock_model(TrackThing, + :track_type => 'public_body_updates', :public_body => @pb, :params => {})) + assign(:xapian_requests, @xap) + assign(:page, 1) + assign(:per_page, 10) end it "should be successful" do - render "public_body/show" - response.should be_success - end - - it "should be valid HTML" do - render "public_body/show" - validate_as_body response.body + render + controller.response.should be_success end it "should show the body's name" do - render "public_body/show" - response.should have_tag("h1", "Test Quango") + render + response.should have_selector('h1', :content => "Test Quango") end it "should tell total number of requests" do - render "public_body/show" - response.should include_text("4 Freedom of Information requests") + render + response.should match "4 Freedom of Information requests" end it "should cope with no results" do @pb.stub!(:info_requests).and_return([]) - render "public_body/show" - response.should have_tag("p", /Nobody has made any Freedom of Information requests/m) + render + response.should have_selector('p', :content => "Nobody has made any Freedom of Information requests") end it "should cope with Xapian being down" do - assigns[:xapian_requests] = nil - render "public_body/show" - response.should have_tag("p", /The search index is currently offline/m) + assign(:xapian_requests, nil) + render + response.should match "The search index is currently offline" end it "should link to Charity Commission site if we have numbers to do so" do @pb.stub!(:has_tag?).and_return(true) @pb.stub!(:get_tag_values).and_return(['98765', '12345']) - render "public_body/show" - response.should have_tag("div#header_right") do - with_tag("a[href*=?]", /charity-commission.gov.uk.*RegisteredCharityNumber=98765$/) + render + response.should have_selector("div#header_right") do + have_selector "a", :href => /charity-commission.gov.uk.*RegisteredCharityNumber=98765$/ end - response.should have_tag("div#header_right") do - with_tag("a[href*=?]", /charity-commission.gov.uk.*RegisteredCharityNumber=12345$/) + response.should have_selector("div#header_right") do + have_selector "a", :href => /www.charity-commission.gov.uk.*RegisteredCharityNumber=12345$/ end end @@ -82,17 +75,17 @@ describe "when viewing a body" do @pb.stub!(:has_tag?).and_return(true) @pb.stub!(:get_tag_values).and_return(['SC1234']) - render "public_body/show" - response.should have_tag("div#header_right") do - with_tag("a[href*=?]", /www.oscr.org.uk.*id=SC1234$/) + render + response.should have_selector("div#header_right") do + have_selector "a", :href => /www.oscr.org.uk.*id=SC1234$/ end end it "should not link to Charity Commission site if we don't have number" do - render "public_body/show" - response.should have_tag("div#header_right") do - without_tag("a[href*=?]", /charity-commission.gov.uk/) + render + response.should have_selector("div#header_right") do + have_selector "a", :href => /charity-commission.gov.uk/ end end diff --git a/spec/views/reports/new.erb_spec.rb b/spec/views/reports/new.erb_spec.rb new file mode 100644 index 000000000..66b738261 --- /dev/null +++ b/spec/views/reports/new.erb_spec.rb @@ -0,0 +1,29 @@ +require File.expand_path(File.join('..', '..', '..', 'spec_helper'), __FILE__) + +describe 'reports/new.html.erb' do + let(:info_request) { mock_model(InfoRequest, :url_title => "foo", :report_reasons => ["Weird"]) } + before :each do + assign(:info_request, info_request) + end + + it "should show a form" do + render + rendered.should have_selector("form") + end + + context "request has already been reported" do + before :each do + info_request.stub!(:attention_requested).and_return(true) + end + + it "should not show a form" do + render + rendered.should_not have_selector("form") + end + + it "should say it's already been reported" do + render + rendered.should contain("This request has already been reported") + end + end +end diff --git a/spec/views/request/_after_actions.rhtml_spec.rb b/spec/views/request/_after_actions.html.erb_spec.rb index 548990c9f..ae398f4ce 100644 --- a/spec/views/request/_after_actions.rhtml_spec.rb +++ b/spec/views/request/_after_actions.html.erb_spec.rb @@ -15,51 +15,27 @@ describe 'when displaying actions that can be taken with regard to a request' do :comments_allowed? => true, :url_title => 'test_request', :all_can_view? => true) - assigns[:info_request] = @mock_request - end - - def do_render - render :partial => 'request/after_actions' - end - - def expect_owner_div - do_render - response.should have_tag('div#owner_actions'){ yield } - end - - def expect_anyone_div - do_render - response.should have_tag('div#anyone_actions'){ yield } - end - - def expect_owner_link(text) - expect_owner_div{ with_tag('a', :text => text) } - end - - def expect_no_owner_link(text) - expect_owner_div{ without_tag('a', :text => text) } - end - - def expect_anyone_link(text) - expect_anyone_div{ with_tag('a', :text => text) } - end - - def expect_no_anyone_link(text) - expect_anyone_div{ without_tag('a', :text => text) } + assign :info_request, @mock_request end describe 'if the request is old and unclassified' do before do - assigns[:old_unclassified] = true + assign :old_unclassified, true end it 'should not display a link for the request owner to update the status of the request' do - expect_no_owner_link('Update the status of this request') + render :partial => 'request/after_actions' + response.should have_selector('div#owner_actions') do |div| + div.should_not have_selector('a', :content => 'Update the status of this request') + end end it 'should display a link for anyone to update the status of the request' do - expect_anyone_link('Update the status of this request') + render :partial => 'request/after_actions' + response.should have_selector('div#anyone_actions') do |div| + div.should have_selector('a', :content => 'Update the status of this request') + end end end @@ -67,27 +43,39 @@ describe 'when displaying actions that can be taken with regard to a request' do describe 'if the request is not old and unclassified' do before do - assigns[:old_unclassified] = false + assign :old_unclassified, false end it 'should display a link for the request owner to update the status of the request' do - expect_owner_link('Update the status of this request') + render :partial => 'request/after_actions' + response.should have_selector('div#owner_actions') do |div| + div.should have_selector('a', :content => 'Update the status of this request') + end end it 'should not display a link for anyone to update the status of the request' do - expect_no_anyone_link('Update the status of this request') + render :partial => 'request/after_actions' + response.should have_selector('div#anyone_actions') do |div| + div.should_not have_selector('a', :content => 'Update the status of this request') + end end end it 'should display a link for the request owner to request a review' do - expect_owner_link('Request an internal review') + render :partial => 'request/after_actions' + response.should have_selector('div#owner_actions') do |div| + div.should have_selector('a', :content => 'Request an internal review') + end end describe 'if the request is viewable by all' do it 'should display the link to download the entire request' do - expect_anyone_link('Download a zip file of all correspondence') + render :partial => 'request/after_actions' + response.should have_selector('div#anyone_actions') do |div| + div.should have_selector('a', :content => 'Download a zip file of all correspondence') + end end end @@ -95,7 +83,10 @@ describe 'when displaying actions that can be taken with regard to a request' do it 'should not display the link to download the entire request' do @mock_request.stub!(:all_can_view?).and_return(false) - expect_no_anyone_link('Download a zip file of all correspondence') + render :partial => 'request/after_actions' + response.should have_selector('div#anyone_actions') do |div| + div.should_not have_selector('a', :content => 'Download a zip file of all correspondence') + end end end diff --git a/spec/views/request/_describe_state.rhtml_spec.rb b/spec/views/request/_describe_state.html.erb_spec.rb index 18778d5d2..88dea53c5 100644 --- a/spec/views/request/_describe_state.rhtml_spec.rb +++ b/spec/views/request/_describe_state.html.erb_spec.rb @@ -4,12 +4,12 @@ describe 'when showing the form for describing the state of a request' do def expect_radio_button(value) do_render - response.should have_tag("input[type=radio][value=#{value}]") + response.should have_selector('input', :type => 'radio', :value => value) end def expect_no_radio_button(value) do_render - response.should_not have_tag("input[type=radio][value=#{value}]") + response.should_not have_selector('input', :type => 'radio', :value => value) end def do_render @@ -24,25 +24,25 @@ describe 'when showing the form for describing the state of a request' do :user_name => @mock_user.name, :is_external? => false ) - assigns[:info_request] = @mock_request + assign :info_request, @mock_request end describe 'if the user is a regular user (not the request owner)' do before do - assigns[:is_owning_user] = false + assign :is_owning_user, false end describe 'if the request is not old and unclassified' do it 'should not show the form' do do_render - response.should_not have_tag('h2', :text => 'What best describes the status of this request now?') + response.should_not have_selector('h2', :content => 'What best describes the status of this request now?') end it 'should give a link to login' do do_render - response.should have_tag('a', :text => 'sign in') + response.should have_selector('a', :content => 'sign in') end end @@ -50,22 +50,22 @@ describe 'when showing the form for describing the state of a request' do describe 'if the request is old and unclassified' do before do - assigns[:old_unclassified] = true + assign :old_unclassified, true end it 'should not show the form' do do_render - response.should_not have_tag('h2', :text => 'What best describes the status of this request now?') + response.should_not have_selector('h2', :content => 'What best describes the status of this request now?') end it 'should show the form for someone else to classify the request' do do_render - response.should have_tag('h2', :text => /We need your help/) + response.should have_selector('h2', :content => 'We need your help') end it 'should not give a link to login' do do_render - response.should_not have_tag('a', :text => 'sign in') + response.should_not have_selector('a', :content => 'sign in') end end @@ -74,7 +74,7 @@ describe 'when showing the form for describing the state of a request' do describe 'if showing the form to the user owning the request' do before do - assigns[:is_owning_user] = true + assign :is_owning_user, true end describe 'when the request is not in internal review' do @@ -100,7 +100,7 @@ describe 'when showing the form for describing the state of a request' do describe 'when the user has asked to update the status of the request' do before do - assigns[:update_status] = true + assign :update_status, true end it 'should show a radio button to set the status to "internal_review"' do @@ -129,7 +129,7 @@ describe 'when showing the form for describing the state of a request' do it 'should show the text "The review has finished and overall:"' do do_render - response.should have_tag('p', :text => 'The review has finished and overall:') + response.should have_selector('p', :content => 'The review has finished and overall:') end end @@ -170,4 +170,4 @@ describe 'when showing the form for describing the state of a request' do end end -end
\ No newline at end of file +end diff --git a/spec/views/request/list.rhtml_spec.rb b/spec/views/request/list.html.erb_spec.rb index 137bc359d..521d946bc 100644 --- a/spec/views/request/list.rhtml_spec.rb +++ b/spec/views/request/list.html.erb_spec.rb @@ -1,12 +1,10 @@ require File.expand_path(File.join('..', '..', '..', 'spec_helper'), __FILE__) -describe "when listing recent requests" do +describe "request/list" do before do - assigns[:page] = 1 - assigns[:per_page] = 10 - # work round a bug in ActionController::TestRequest; allows request.query_string to work in the template - request.env["REQUEST_URI"] = "" + assign :page, 1 + assign :per_page, 10 end def make_mock_event @@ -30,21 +28,21 @@ describe "when listing recent requests" do end it "should be successful" do - assigns[:list_results] = [ make_mock_event, make_mock_event ] - assigns[:matches_estimated] = 2 - assigns[:show_no_more_than] = 100 - render "request/list" - response.should have_tag("div.request_listing") - response.should_not have_tag("p", /No requests of this sort yet/m) + assign :list_results, [ make_mock_event, make_mock_event ] + assign :matches_estimated, 2 + assign :show_no_more_than, 100 + render + response.should have_selector("div.request_listing") + response.should_not have_selector("p", :content => "No requests of this sort yet") end it "should cope with no results" do - assigns[:list_results] = [ ] - assigns[:matches_estimated] = 0 - assigns[:show_no_more_than] = 0 - render "request/list" - response.should have_tag("p", /No requests of this sort yet/m) - response.should_not have_tag("div.request_listing") + assign :list_results, [ ] + assign :matches_estimated, 0 + assign :show_no_more_than, 0 + render + response.should have_selector("p", :content => "No requests of this sort yet") + response.should_not have_selector("div.request_listing") end end diff --git a/spec/views/request/show.rhtml_spec.rb b/spec/views/request/show.html.erb_spec.rb index 4429e9e58..4578268b2 100644 --- a/spec/views/request/show.rhtml_spec.rb +++ b/spec/views/request/show.html.erb_spec.rb @@ -1,6 +1,6 @@ require File.expand_path(File.join('..', '..', '..', 'spec_helper'), __FILE__) -describe 'when viewing an information request' do +describe 'request/show' do before do @mock_body = mock_model(PublicBody, :name => 'test body', @@ -19,36 +19,28 @@ describe 'when viewing an information request' do :is_external? => false, :calculate_status => 'waiting_response', :date_response_required_by => Date.today, - :prominence => 'normal') + :prominence => 'normal', + :comments_allowed? => true, + :all_can_view? => true, + :url_title => 'test_request') end def request_page - assigns[:info_request] = @mock_request - assigns[:info_request_events] = [] - assigns[:status] = @mock_request.calculate_status - template.stub!(:render_partial) - render 'request/show' - end - - it 'should show the sidebar' do - template.should_receive(:render_partial).with(:partial => 'sidebar', :locals => {}) - request_page - end - - it 'should show the actions people can take' do - template.should_receive(:render_partial).with(:partial => 'after_actions', :locals => {}) - request_page + assign :info_request, @mock_request + assign :info_request_events, [] + assign :status, @mock_request.calculate_status + render end describe 'when a status update has been requested' do before do - assigns[:update_status] = true + assign :update_status, true end it 'should show the first form for describing the state of the request' do request_page - response.should have_tag("div.describe_state_form#describe_state_form_1") + response.should have_selector("div.describe_state_form#describe_state_form_1") end end @@ -61,12 +53,12 @@ describe 'when viewing an information request' do it 'should show the first form for describing the state of the request' do request_page - response.should have_tag("div.describe_state_form#describe_state_form_1") + response.should have_selector("div.describe_state_form#describe_state_form_1") end it 'should show the second form for describing the state of the request' do request_page - response.should have_tag("div.describe_state_form#describe_state_form_2") + response.should have_selector("div.describe_state_form#describe_state_form_2") end end @@ -74,7 +66,7 @@ describe 'when viewing an information request' do describe 'when the user is the request owner' do before do - assigns[:is_owning_user] = true + assign :is_owning_user, true end describe 'when the request status is "waiting clarification"' do @@ -88,18 +80,13 @@ describe 'when viewing an information request' do before do @mock_response = mock_model(IncomingMessage) @mock_request.stub!(:get_last_response).and_return(@mock_response) - @old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new - end - after do - ActionController::Routing::Routes.filters = @old_filters end it 'should show a link to follow up the last response with clarification' do request_page - expected_url = "http://test.host/request/#{@mock_request.id}/response/#{@mock_response.id}#followup" - response.should have_tag("a[href=#{expected_url}]", :text => 'send a follow up message') + expected_url = "/en/request/#{@mock_request.id}/response/#{@mock_response.id}#followup" + response.should have_selector("a", :href => expected_url, :content => 'send a follow up message') end end @@ -108,18 +95,13 @@ describe 'when viewing an information request' do before do @mock_request.stub!(:get_last_response).and_return(nil) - @old_filters = ActionController::Routing::Routes.filters - ActionController::Routing::Routes.filters = RoutingFilter::Chain.new - end - after do - ActionController::Routing::Routes.filters = @old_filters end it 'should show a link to follow up the request without reference to a specific response' do request_page - expected_url = "http://test.host/request/#{@mock_request.id}/response#followup" - response.should have_tag("a[href=#{expected_url}]", :text => 'send a follow up message') + expected_url = "/en/request/#{@mock_request.id}/response#followup" + response.should have_selector("a", :href => expected_url, :content => 'send a follow up message') end end end diff --git a/spec/views/request_game/play.rhtml_spec.rb b/spec/views/request_game/play.html.erb_spec.rb index 24fb6d75d..b5cf57c23 100644 --- a/spec/views/request_game/play.rhtml_spec.rb +++ b/spec/views/request_game/play.html.erb_spec.rb @@ -1,6 +1,6 @@ require File.expand_path(File.join('..', '..', '..', 'spec_helper'), __FILE__) -describe 'when viewing the request game' do +describe 'request_game/play' do before do @mock_body = mock_model(PublicBody, :name => 'test body', @@ -22,15 +22,15 @@ describe 'when viewing the request game' do :initial_request_text => 'hi there', :display_status => 'Awaiting categorisation', :created_at => Time.now) - assigns[:league_table_28_days] = [] - assigns[:league_table_all_time] = [] - assigns[:requests] = [@mock_request] - assigns[:play_urls] = true + assign :league_table_28_days, [] + assign :league_table_all_time, [] + assign :requests, [@mock_request] + assign :play_urls, true end it 'should show the correct url for a request' do - render "request_game/play" - response.should include_text("/categorise/request/a_test_request") + render + response.should include("/categorise/request/a_test_request") end |