aboutsummaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/admin_censor_rule_controller_spec.rb2
-rw-r--r--spec/controllers/admin_general_controller_spec.rb2
-rw-r--r--spec/controllers/admin_public_body_controller_spec.rb18
-rw-r--r--spec/controllers/admin_request_controller_spec.rb4
-rw-r--r--spec/controllers/admin_track_controller_spec.rb2
-rw-r--r--spec/controllers/admin_user_controller_spec.rb2
-rw-r--r--spec/controllers/api_controller_spec.rb134
-rw-r--r--spec/controllers/comment_controller_spec.rb2
-rw-r--r--spec/controllers/general_controller_spec.rb54
-rw-r--r--spec/controllers/help_controller_spec.rb2
-rw-r--r--spec/controllers/public_body_controller_spec.rb14
-rw-r--r--spec/controllers/request_controller_spec.rb45
-rw-r--r--spec/controllers/services_controller_spec.rb4
-rw-r--r--spec/controllers/track_controller_spec.rb8
-rw-r--r--spec/controllers/user_controller_spec.rb18
-rw-r--r--spec/fixtures/files/dos-linebreaks.email31
-rw-r--r--spec/fixtures/files/humberside-police-odd-mime-type.email25
-rw-r--r--spec/fixtures/files/incoming-request-attachment-headers.email50
-rw-r--r--spec/fixtures/files/incoming-request-attachment-unknown-extension.email5
-rw-r--r--spec/fixtures/files/many-attachments-date-header.email451
-rw-r--r--spec/fixtures/files/rfc822-attachment.email147
-rw-r--r--spec/lib/i18n_interpolation.rb3
-rw-r--r--spec/lib/mail_handler/mail_handler_spec.rb362
-rw-r--r--spec/models/incoming_message_spec.rb110
-rw-r--r--spec/models/info_request_event_spec.rb2
-rw-r--r--spec/models/info_request_spec.rb32
-rw-r--r--spec/models/public_body_spec.rb4
-rw-r--r--spec/models/user_spec.rb8
-rw-r--r--spec/spec_helper.rb271
-rw-r--r--spec/spec_helper.rb.rails2152
-rw-r--r--spec/support/email_helpers.rb23
-rw-r--r--spec/support/load_file_fixtures.rb14
-rw-r--r--spec/support/validate_html.rb65
-rw-r--r--spec/support/xapian_index.rb21
-rw-r--r--spec/views/public_body/show.rhtml_spec.rb64
-rw-r--r--spec/views/request/_after_actions.rhtml_spec.rb61
-rw-r--r--spec/views/request/_describe_state.rhtml_spec.rb28
-rw-r--r--spec/views/request/list.rhtml_spec.rb36
-rw-r--r--spec/views/request/show.rhtml_spec.rb26
-rw-r--r--spec/views/request_game/play.rhtml_spec.rb8
40 files changed, 1733 insertions, 577 deletions
diff --git a/spec/controllers/admin_censor_rule_controller_spec.rb b/spec/controllers/admin_censor_rule_controller_spec.rb
index 8893a858b..c4860da3f 100644
--- a/spec/controllers/admin_censor_rule_controller_spec.rb
+++ b/spec/controllers/admin_censor_rule_controller_spec.rb
@@ -1,7 +1,7 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe AdminCensorRuleController, "when making censor rules from the admin interface" do
- integrate_views
+ render_views
before { basic_auth_login @request }
it "should create a censor rule and purge the corresponding request from varnish" do
diff --git a/spec/controllers/admin_general_controller_spec.rb b/spec/controllers/admin_general_controller_spec.rb
index dc1eb0d97..b0b65857f 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
diff --git a/spec/controllers/admin_public_body_controller_spec.rb b/spec/controllers/admin_public_body_controller_spec.rb
index 504ddc5cc..c1d3f5014 100644
--- a/spec/controllers/admin_public_body_controller_spec.rb
+++ b/spec/controllers/admin_public_body_controller_spec.rb
@@ -1,7 +1,7 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe AdminPublicBodyController, "when administering public bodies" do
- integrate_views
+ render_views
before do
@old_filters = ActionController::Routing::Routes.filters
@@ -154,7 +154,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()
@@ -263,7 +263,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
@@ -288,7 +288,7 @@ describe AdminPublicBodyController, "when administering public bodies with i18n"
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, {
@@ -308,10 +308,10 @@ describe AdminPublicBodyController, "when administering public bodies with i18n"
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,7 +325,7 @@ describe AdminPublicBodyController, "when administering public bodies with i18n"
end
describe AdminPublicBodyController, "when creating public bodies with i18n" do
- integrate_views
+ render_views
before do
@old_filters = ActionController::Routing::Routes.filters
@@ -357,12 +357,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..0709f6b0b 100644
--- a/spec/controllers/admin_request_controller_spec.rb
+++ b/spec/controllers/admin_request_controller_spec.rb
@@ -1,7 +1,7 @@
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
@@ -82,7 +82,7 @@ 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
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 8d8a39950..1c320f85c 100644
--- a/spec/controllers/api_controller_spec.rb
+++ b/spec/controllers/api_controller_spec.rb
@@ -2,7 +2,7 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
def normalise_whitespace(s)
- s = s.gsub(/^\s+|\s+$/, "")
+ s = s.gsub(/\A\s+|\s+\Z/, "")
s = s.gsub(/\s+/, " ")
return s
end
@@ -14,23 +14,36 @@ Spec::Matchers.define :be_equal_modulo_whitespace_to do |expected|
end
describe ApiController, "when using the API" do
- it "should check the API key" do
- request_data = {
+
+ describe 'checking API keys' do
+ before do
+ @number_of_requests = InfoRequest.count
+ @request_data = {
"title" => "Tell me about your chickens",
"body" => "Dear Sir,\n\nI should like to know about your chickens.\n\nYours in faith,\nBob\n",
-
+
"external_url" => "http://www.example.gov.uk/foi/chickens_23",
"external_user_name" => "Bob Smith",
}
-
- number_of_requests = InfoRequest.count
+ end
+
+ it 'should check that an API key is given as a param' do
expect {
- post :create_request, :k => "This is not really an API key", :request_json => request_data.to_json
+ post :create_request, :request_json => @request_data.to_json
}.to raise_error ApplicationController::PermissionDenied
-
- InfoRequest.count.should == number_of_requests
+ InfoRequest.count.should == @number_of_requests
+ end
+
+ it "should check the API key" do
+ expect {
+ post :create_request,
+ :k => "This is not really an API key",
+ :request_json => @request_data.to_json
+ }.to raise_error ApplicationController::PermissionDenied
+ InfoRequest.count.should == @number_of_requests
+ end
end
-
+
it "should create a new request from a POST" do
number_of_requests = InfoRequest.count(
:conditions => [
@@ -38,61 +51,61 @@ describe ApiController, "when using the API" do
public_bodies(:geraldine_public_body).id
]
)
-
+
request_data = {
"title" => "Tell me about your chickens",
"body" => "Dear Sir,\n\nI should like to know about your chickens.\n\nYours in faith,\nBob\n",
-
+
"external_url" => "http://www.example.gov.uk/foi/chickens_23",
"external_user_name" => "Bob Smith",
}
-
+
post :create_request, :k => public_bodies(:geraldine_public_body).api_key, :request_json => request_data.to_json
response.should be_success
response.content_type.should == "application/json"
-
+
response_body = ActiveSupport::JSON.decode(response.body)
response_body["errors"].should be_nil
response_body["url"].should =~ /^http/
-
+
InfoRequest.count(:conditions => [
"public_body_id = ?",
public_bodies(:geraldine_public_body).id]
).should == number_of_requests + 1
-
+
new_request = InfoRequest.find(response_body["id"])
new_request.user_id.should be_nil
new_request.external_user_name.should == request_data["external_user_name"]
new_request.external_url.should == request_data["external_url"]
-
+
new_request.title.should == request_data["title"]
new_request.last_event_forming_initial_request.outgoing_message.body.should == request_data["body"].strip
-
+
new_request.public_body_id.should == public_bodies(:geraldine_public_body).id
end
-
+
def _create_request
post :create_request,
:k => public_bodies(:geraldine_public_body).api_key,
:request_json => {
"title" => "Tell me about your chickens",
"body" => "Dear Sir,\n\nI should like to know about your chickens.\n\nYours in faith,\nBob\n",
-
+
"external_url" => "http://www.example.gov.uk/foi/chickens_23",
"external_user_name" => "Bob Smith",
}.to_json
response.content_type.should == "application/json"
return ActiveSupport::JSON.decode(response.body)["id"]
end
-
+
it "should add a response to a request" do
# First we need an external request
request_id = info_requests(:external_request).id
-
+
# Initially it has no incoming messages
IncomingMessage.count(:conditions => ["info_request_id = ?", request_id]).should == 0
-
+
# Now add one
sent_at = "2012-05-28T12:35:39+01:00"
response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
@@ -104,13 +117,13 @@ describe ApiController, "when using the API" do
"sent_at" => sent_at,
"body" => response_body
}.to_json
-
+
# And make sure it worked
response.should be_success
incoming_messages = IncomingMessage.all(:conditions => ["info_request_id = ?", request_id])
incoming_messages.count.should == 1
incoming_message = incoming_messages[0]
-
+
incoming_message.sent_at.should == Time.iso8601(sent_at)
incoming_message.get_main_body_text_folded.should be_equal_modulo_whitespace_to(response_body)
end
@@ -118,10 +131,10 @@ describe ApiController, "when using the API" do
it "should add a followup to a request" do
# First we need an external request
request_id = info_requests(:external_request).id
-
+
# Initially it has one outgoing message
OutgoingMessage.count(:conditions => ["info_request_id = ?", request_id]).should == 1
-
+
# Add another, as a followup
sent_at = "2012-05-29T12:35:39+01:00"
followup_body = "Pls answer ASAP.\nkthxbye\n"
@@ -133,7 +146,7 @@ describe ApiController, "when using the API" do
"sent_at" => sent_at,
"body" => followup_body
}.to_json
-
+
# Make sure it worked
response.should be_success
followup_messages = OutgoingMessage.all(
@@ -141,15 +154,15 @@ describe ApiController, "when using the API" do
)
followup_messages.size.should == 1
followup_message = followup_messages[0]
-
+
followup_message.last_sent_at.should == Time.iso8601(sent_at)
followup_message.body.should == followup_body.strip
end
-
+
it "should not allow internal requests to be updated" do
n_incoming_messages = IncomingMessage.count
n_outgoing_messages = OutgoingMessage.count
-
+
request_id = info_requests(:naughty_chicken_request).id
post :add_correspondence,
:k => public_bodies(:geraldine_public_body).api_key,
@@ -159,20 +172,20 @@ describe ApiController, "when using the API" do
"sent_at" => Time.now.iso8601,
"body" => "xxx"
}.to_json
-
+
response.status.should == "500 Internal Server Error"
ActiveSupport::JSON.decode(response.body)["errors"].should == [
"Request #{request_id} cannot be updated using the API"]
-
+
IncomingMessage.count.should == n_incoming_messages
OutgoingMessage.count.should == n_outgoing_messages
end
-
+
it "should not allow other people's requests to be updated" do
request_id = _create_request
n_incoming_messages = IncomingMessage.count
n_outgoing_messages = OutgoingMessage.count
-
+
post :add_correspondence,
:k => public_bodies(:humpadink_public_body).api_key,
:id => request_id,
@@ -181,15 +194,15 @@ describe ApiController, "when using the API" do
"sent_at" => Time.now.iso8601,
"body" => "xxx"
}.to_json
-
+
response.status.should == "500 Internal Server Error"
ActiveSupport::JSON.decode(response.body)["errors"].should == [
"You do not own request #{request_id}"]
-
+
IncomingMessage.count.should == n_incoming_messages
OutgoingMessage.count.should == n_outgoing_messages
end
-
+
it "should not allow files to be attached to a followup" do
post :add_correspondence,
:k => public_bodies(:geraldine_public_body).api_key,
@@ -202,21 +215,21 @@ describe ApiController, "when using the API" do
:attachments => [
fixture_file_upload("files/tfl.pdf")
]
-
-
+
+
# Make sure it worked
response.status.to_i.should == 500
errors = ActiveSupport::JSON.decode(response.body)["errors"]
errors.should == ["You cannot attach files to messages in the 'request' direction"]
end
-
+
it "should allow files to be attached to a response" do
# First we need an external request
request_id = info_requests(:external_request).id
-
+
# Initially it has no incoming messages
IncomingMessage.count(:conditions => ["info_request_id = ?", request_id]).should == 0
-
+
# Now add one
sent_at = "2012-05-28T12:35:39+01:00"
response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
@@ -231,34 +244,33 @@ describe ApiController, "when using the API" do
:attachments => [
fixture_file_upload("files/tfl.pdf")
]
-
+
# And make sure it worked
response.should be_success
incoming_messages = IncomingMessage.all(:conditions => ["info_request_id = ?", request_id])
incoming_messages.count.should == 1
incoming_message = incoming_messages[0]
-
+
incoming_message.sent_at.should == Time.iso8601(sent_at)
incoming_message.get_main_body_text_folded.should be_equal_modulo_whitespace_to(response_body)
-
+
# Get the attachment
attachments = incoming_message.get_attachments_for_display
attachments.size.should == 1
attachment = attachments[0]
-
attachment.filename.should == "tfl.pdf"
- attachment.body.should == load_file_fixture("tfl.pdf")
+ attachment.body.should == load_file_fixture("tfl.pdf", as_binary=true)
end
-
+
it "should show information about a request" do
info_request = info_requests(:naughty_chicken_request)
get :show_request,
:k => public_bodies(:geraldine_public_body).api_key,
:id => info_request.id
-
+
response.should be_success
assigns[:request].id.should == info_request.id
-
+
r = ActiveSupport::JSON.decode(response.body)
r["title"].should == info_request.title
# Let’s not test all the fields here, because it would
@@ -266,13 +278,13 @@ describe ApiController, "when using the API" do
# assigns them and changing assignment to an equality
# check, which does not really test anything at all.
end
-
+
it "should show an Atom feed of new request events" do
get :body_request_events,
:id => public_bodies(:geraldine_public_body).id,
:k => public_bodies(:geraldine_public_body).api_key,
:feed_type => "atom"
-
+
response.should be_success
response.should render_template("api/request_events.atom")
assigns[:events].size.should > 0
@@ -288,7 +300,7 @@ describe ApiController, "when using the API" do
:id => public_bodies(:geraldine_public_body).id,
:k => public_bodies(:geraldine_public_body).api_key,
:feed_type => "json"
-
+
response.should be_success
assigns[:events].size.should > 0
assigns[:events].each do |event|
@@ -296,13 +308,13 @@ describe ApiController, "when using the API" do
event.outgoing_message.should_not be_nil
event.event_type.should satisfy {|x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x)}
end
-
+
assigns[:event_data].size.should == assigns[:events].size
assigns[:event_data].each do |event_record|
event_record[:event_type].should satisfy {|x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x)}
end
end
-
+
it "should honour the since_event_id parameter" do
get :body_request_events,
:id => public_bodies(:geraldine_public_body).id,
@@ -311,7 +323,7 @@ describe ApiController, "when using the API" do
response.should be_success
first_event = assigns[:event_data][0]
second_event_id = assigns[:event_data][1][:event_id]
-
+
get :body_request_events,
:id => public_bodies(:geraldine_public_body).id,
:k => public_bodies(:geraldine_public_body).api_key,
@@ -320,14 +332,14 @@ describe ApiController, "when using the API" do
response.should be_success
assigns[:event_data].should == [first_event]
end
-
+
it "should honour the since_date parameter for the Atom feed" do
get :body_request_events,
:id => public_bodies(:humpadink_public_body).id,
:k => public_bodies(:humpadink_public_body).api_key,
:since_date => "2010-01-01",
:feed_type => "atom"
-
+
response.should be_success
response.should render_template("api/request_events.atom")
assigns[:events].size.should > 0
@@ -335,7 +347,7 @@ describe ApiController, "when using the API" do
event.created_at.should >= Date.new(2010, 1, 1)
end
end
-
+
it "should return a JSON 404 error for non-existent requests" do
request_id = 123459876 # Let's hope this doesn't exist!
sent_at = "2012-05-28T12:35:39+01:00"
@@ -351,7 +363,7 @@ describe ApiController, "when using the API" do
response.status.should == "404 Not Found"
ActiveSupport::JSON.decode(response.body)["errors"].should == ["Could not find request 123459876"]
end
-
+
it "should return a JSON 500 error if we try to add correspondence to a request we don't own" do
request_id = info_requests(:naughty_chicken_request).id
sent_at = "2012-05-28T12:35:39+01:00"
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 830486493..9684732a5 100644
--- a/spec/controllers/general_controller_spec.rb
+++ b/spec/controllers/general_controller_spec.rb
@@ -35,7 +35,7 @@ end
describe GeneralController, "when showing the frontpage" do
- integrate_views
+ render_views
before do
public_body = mock_model(PublicBody, :name => "Example Public Body",
@@ -97,8 +97,57 @@ describe GeneralController, "when showing the frontpage" do
response.should be_success
end
+ describe 'when there is more than one locale' do
+
+ describe 'when using the default locale' 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
+ end
+
+ def set_default_locale_in_urls(value)
+ Configuration.stub!(:include_default_locale_in_urls).and_return(value)
+ load Rails.root.join("config/initializers/fast_gettext.rb")
+ end
+
+ describe 'when the config value INCLUDE_DEFAULT_LOCALE_IN_URLS is false' do
+
+ before do
+ set_default_locale_in_urls(false)
+ end
+
+ it 'should generate URLs without a locale prepended' do
+ get :frontpage
+ response.should_not have_text(@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)
+ end
+ end
+
+ it 'should generate URLs with a locale prepended when the config value
+ INCLUDE_DEFAULT_LOCALE_IN_URLS is true' do
+ set_default_locale_in_urls(true)
+ get :frontpage
+ response.should have_text(@default_lang_home_link)
+ end
+
+ after do
+ set_default_locale_in_urls(@old_include_default_locale_in_urls)
+ end
+
+ end
+ end
+
+
describe "when using different locale settings" do
home_link_regex = /href=".*\/en\//
+
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)
@@ -137,6 +186,7 @@ describe GeneralController, "when showing the frontpage" do
FastGettext.default_available_locales = old_fgt_available_locales
I18n.available_locales = old_i18n_available_locales
end
+
end
end
describe GeneralController, "when showing the front page with fixture data" do
@@ -185,7 +235,7 @@ end
describe GeneralController, 'when using xapian search' do
- integrate_views
+ render_views
# rebuild xapian index after fixtures loaded
before(:each) do
diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb
index 28fd08c80..0f6f75eb9 100644
--- a/spec/controllers/help_controller_spec.rb
+++ b/spec/controllers/help_controller_spec.rb
@@ -1,7 +1,7 @@
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
diff --git a/spec/controllers/public_body_controller_spec.rb b/spec/controllers/public_body_controller_spec.rb
index 29ece18cb..a0841b621 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
@@ -44,14 +44,14 @@ describe PublicBodyController, "when showing a body" do
end
it "should assign the body using different locale from that used for url_name" do
- PublicBody.with_locale(:es) do
+ I18n.with_locale(:es) do
get :show, {:url_name => "dfh", :view => 'all'}
assigns[:public_body].notes.should == "Baguette"
end
end
it "should assign the body using same locale as that used in url_name" do
- PublicBody.with_locale(:es) do
+ I18n.with_locale(:es) do
get :show, {:url_name => "edfh", :view => 'all'}
assigns[:public_body].notes.should == "Baguette"
end
@@ -79,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
@@ -87,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',
@@ -95,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
@@ -193,7 +193,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/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb
index e898fb91b..9e14153a7 100644
--- a/spec/controllers/request_controller_spec.rb
+++ b/spec/controllers/request_controller_spec.rb
@@ -59,19 +59,6 @@ describe RequestController, "when listing recent requests" do
:conditions => "id in (select info_request_id from info_request_events where created_at between '2007-10-13'::date and '2007-11-01'::date)")
end
- it "should make a sane-sized cache tag" do
- get :list, :view => 'all', :request_date_after => '13/10/2007', :request_date_before => '01/11/2007'
- assigns[:cache_tag].size.should <= 32
- end
-
- it "should vary the cache tag with locale" do
- get :list, :view => 'all', :request_date_after => '13/10/2007', :request_date_before => '01/11/2007'
- en_tag = assigns[:cache_tag]
- session[:locale] = :es
- get :list, :view => 'all', :request_date_after => '13/10/2007', :request_date_before => '01/11/2007'
- assigns[:cache_tag].should_not == en_tag
- end
-
it "should list internal_review requests as unresolved ones" do
get :list, :view => 'awaiting'
@@ -134,7 +121,7 @@ end
describe RequestController, "when changing things that appear on the request page" do
- integrate_views
+ render_views
it "should purge the downstream cache when mail is received" do
ir = info_requests(:fancy_dog_request)
@@ -200,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
@@ -458,7 +445,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)
@@ -757,7 +744,7 @@ describe RequestController, "when showing one request" do
assigns[:url_path].should_not == old_path
response.location.should have_text(/#{assigns[:url_path]}/)
zipfile = Zip::ZipFile.open(File.join(File.dirname(__FILE__), "../../cache/zips", assigns[:url_path])) { |zipfile|
- zipfile.count.should == 5 # the message, two hello.txt, the unknown attachment, and its empty message
+ zipfile.count.should == 4 # the message, two hello.txt plus the unknown attachment
}
end
@@ -908,7 +895,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)
@@ -1144,7 +1131,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
@@ -1577,7 +1564,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
@@ -1659,7 +1646,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
@@ -1804,7 +1791,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
@@ -1834,7 +1821,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
@@ -1887,7 +1874,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
@@ -1966,7 +1953,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
@@ -1989,7 +1976,7 @@ 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
@@ -2099,7 +2086,7 @@ end
describe RequestController, "when doing type ahead searches" do
- integrate_views
+ render_views
it "should return nothing for the empty query string" do
get :search_typeahead, :q => ""
@@ -2157,7 +2144,7 @@ describe RequestController, "when doing type ahead searches" do
end
describe RequestController, "when showing similar requests" do
- integrate_views
+ render_views
it "should work" do
get :similar, :url_title => info_requests(:badger_request).url_title
@@ -2191,7 +2178,7 @@ describe RequestController, "when reporting a request when not logged in" do
end
describe RequestController, "when reporting a request (logged in)" do
- integrate_views
+ render_views
before do
@user = users(:robin_user)
diff --git a/spec/controllers/services_controller_spec.rb b/spec/controllers/services_controller_spec.rb
index a701ae247..d2d22826a 100644
--- a/spec/controllers/services_controller_spec.rb
+++ b/spec/controllers/services_controller_spec.rb
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe ServicesController, "when using web services" do
- integrate_views
+ render_views
# store and restore the locale in the context of the test suite to isolate
# changes made in these tests
@@ -40,4 +40,4 @@ describe ServicesController, "when using web services" do
FastGettext.set_locale(@old_locale)
end
-end \ No newline at end of file
+end
diff --git a/spec/controllers/track_controller_spec.rb b/spec/controllers/track_controller_spec.rb
index c785960b5..cd7932e90 100644
--- a/spec/controllers/track_controller_spec.rb
+++ b/spec/controllers/track_controller_spec.rb
@@ -56,7 +56,7 @@ describe TrackController, "when making a new track on a request" do
end
describe TrackController, "when sending alerts for a track" do
- integrate_views
+ render_views
include LinkToHelper # for main_url
before(:each) do
@@ -134,7 +134,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
@@ -164,7 +164,7 @@ 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 +206,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..db64bdcaf 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")
@@ -228,7 +228,7 @@ describe UserController, "when signing in" do
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',
@@ -285,7 +285,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
@@ -309,7 +309,7 @@ describe UserController, "when signing out" do
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)
@@ -346,7 +346,7 @@ describe UserController, "when sending another user a message" do
end
describe UserController, "when changing password" do
- integrate_views
+ render_views
it "should show the email form when not logged in" do
get :signchangepassword
@@ -416,7 +416,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
@@ -561,7 +561,7 @@ 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)
@@ -631,7 +631,7 @@ describe UserController, "when showing JSON version for API" do
end
describe UserController, "when viewing the wall" do
- integrate_views
+ render_views
before(:each) do
get_fixtures_xapian_index
diff --git a/spec/fixtures/files/dos-linebreaks.email b/spec/fixtures/files/dos-linebreaks.email
new file mode 100644
index 000000000..1f5f1473f
--- /dev/null
+++ b/spec/fixtures/files/dos-linebreaks.email
@@ -0,0 +1,31 @@
+From email@example.com Wed Mar 12 14:58:26 2008
+Return-path: email@example.com>
+Envelope-to: request-xxx-xxxxxx@whatdotheyknow.com
+Delivery-date: Wed, 12 Mar 2008 14:58:26 +0000
+Received: from example.com ([0.0.0.0]:1368 helo=example.com)
+ by tea.ukcod.org.uk with esmtp (Exim 4.50)
+ id 1JZSPS-0002yK-Rq
+ for request-60-3548031c@whatdotheyknow.com; Wed, 12 Mar 2008 14:58:26 +0000
+X-MimeOLE: Produced By Microsoft Exchange V0.0.0.0
+Content-class: urn:content-classes:message
+MIME-Version: 1.0
+Content-Type: text/plain;
+ charset="us-ascii"
+Content-Transfer-Encoding: quoted-printable
+Disposition-Notification-To: "A Person" email@example.com>
+Subject: RE: Freedom of Information request - Plans for the East Oxford Community Centre
+Date: Wed, 12 Mar 2008 14:59:04 -0000
+Message-ID: <3D8BEC617D49EF45A9E6D103A83FD30331BF84@local>
+X-MS-Has-Attach:
+X-MS-TNEF-Correlator:
+Thread-Topic: Freedom of Information request
+Thread-Index: AciDziuIcYirFQ7GT36VyP2ABE14qgAg1c0w
+From: "A Person" email@example.com>
+To: FOI Person <EMAIL_TO>
+X-OriginalArrivalTime: 12 Mar 2008 14:59:04.0368 (UTC) FILETIME=[9D245300:01C88451]
+X-SEF-7853D99-ADF1-478E-8894-213D316B8FFA: 1
+X-SEF-Processed: 6_0_1_111__2008_03_12_14_59_05
+
+Thank you for your Freedom of Information request. I have forwarded it=0D=0A=
+to the relevant department for their reply.=0D=0A=0D=0A
+
diff --git a/spec/fixtures/files/humberside-police-odd-mime-type.email b/spec/fixtures/files/humberside-police-odd-mime-type.email
index 5514b29da..ae4ceeffe 100644
--- a/spec/fixtures/files/humberside-police-odd-mime-type.email
+++ b/spec/fixtures/files/humberside-police-odd-mime-type.email
@@ -3,19 +3,20 @@ Return-path: <>
Envelope-to: request-5335-xxxxxxxx@whatdotheyknow.com
Delivery-date: Thu, 01 Jan 2009 15:56:20 +0000
Received: from earth.karoo.kcom.com ([212.50.160.55]:62894)
- by sandwich.ukcod.org.uk with esmtp (Exim 4.63)
- id 1LIPuG-0004AJ-B3
- for request-5335-xxxxxxxx@whatdotheyknow.com; Thu, 01 Jan 2009 15:56:20 +0000
+ by sandwich.ukcod.org.uk with esmtp (Exim 4.63)
+ id 1LIPuG-0004AJ-B3
+ for request-5335-xxxxxxxx@whatdotheyknow.com; Thu, 01 Jan 2009 15:56:20 +0000
Received: from unknown (HELO smtp-in.karoo.kcom.com) ([10.102.8.11])
by earth.karoo.kcom.com with ESMTP; 01 Jan 2009 15:44:42 +0000
Received: from exim by smtp-in.karoo.kcom.comwith local (Exim 4.30)
- id 1LIPu0-0004fg-G6 server-id smtp-in4
- for request-5335-xxxxxxxx@whatdotheyknow.com; Thu, 01 Jan 2009 15:56:04 +0000
+ id 1LIPu0-0004fg-G6 server-id smtp-in4
+ for request-5335-xxxxxxxx@whatdotheyknow.com; Thu, 01 Jan 2009 15:56:04 +0000
X-Failed-Recipients: clerk@humberside-pa.karoo.co.uk
Reply-To: Postmaster <postmaster@karoo.kcom.com>
Auto-Submitted: auto-generated
From: Mail Delivery System <Mailer-Daemon@karoo.co.uk>
To: request-5335-xxxxxxxx@whatdotheyknow.com
+Cc: request-5335-xxxxxxxx@whatdotheyknow.com
Subject: Mail delivery failed : returning message to sender
X-Mailer: Karoo Mailcore [version 2.0-IB]
MIME-Version: 1.0
@@ -52,19 +53,19 @@ Content-Transfer-Encoding: 8bit
Return-path: <request-5335-xxxxxxxx@whatdotheyknow.com>
Received: from [212.50.160.60] (helo=venus.karoo.kcom.com)
- by smtp-in.karoo.kcom.comwith esmtp (Exim 4.30)
- id 1LIPu0-0004fc-FM server-id smtp-in4
- for clerk@humberside-pa.karoo.co.uk; Thu, 01 Jan 2009 15:56:04 +0000
+ by smtp-in.karoo.kcom.comwith esmtp (Exim 4.30)
+ id 1LIPu0-0004fc-FM server-id smtp-in4
+ for clerk@humberside-pa.karoo.co.uk; Thu, 01 Jan 2009 15:56:04 +0000
X-IronPort-Anti-Spam-Filtered: true
X-IronPort-Anti-Spam-Result: AnECAF9nXElSb+bUmWdsb2JhbACMZQGHFQEBAQEBCAsKBxG2eIVy
-X-IronPort-AV: E=Sophos;i="4.36,313,1228089600";
+X-IronPort-AV: E=Sophos;i="4.36,313,1228089600";
d="scan'208";a="465483300"
Received: from sandwich.ukcod.org.uk ([82.111.230.212])
by venus.karoo.kcom.com with ESMTP; 01 Jan 2009 15:46:44 +0000
Received: from foi by sandwich.ukcod.org.uk with local (Exim 4.63)
- (envelope-from <request-5335-xxxxxxxx@whatdotheyknow.com>)
- id 1LIPtz-0004AG-OC
- for clerk@humberside-pa.karoo.co.uk; Thu, 01 Jan 2009 15:56:03 +0000
+ (envelope-from <request-5335-xxxxxxxx@whatdotheyknow.com>)
+ id 1LIPtz-0004AG-OC
+ for clerk@humberside-pa.karoo.co.uk; Thu, 01 Jan 2009 15:56:03 +0000
From: John Jarman <request-5335-xxxxxxxx@whatdotheyknow.com>
To: FOI requests at Humberside Police Authority <clerk@humberside-pa.karoo.co.uk>
Subject: Freedom of Information request - Police Injury Award Pensions
diff --git a/spec/fixtures/files/incoming-request-attachment-headers.email b/spec/fixtures/files/incoming-request-attachment-headers.email
new file mode 100644
index 000000000..80e71556d
--- /dev/null
+++ b/spec/fixtures/files/incoming-request-attachment-headers.email
@@ -0,0 +1,50 @@
+From foi@example.com Mon Oct 06 13:45:38 2008
+Return-path: <foi@example.com>
+Envelope-to: foi@sandwich.ukcod.org.uk
+Delivery-date: Mon, 06 Oct 2008 13:45:38 +0100
+Message-Id: <s8ea1156.098@example.com>
+X-Mailer: Novell GroupWise Internet Agent 6.5.4
+Date: Mon, 06 Oct 2008 13:23:00 +0100
+From: "Steve Knight" <foi@example.com>
+To: <request-xxxx-xxxxx@whatdotheyknow.com>
+Subject: FOI request
+Mime-Version: 1.0
+Content-Type: multipart/mixed; boundary="=__PartFDD45234.0__="
+X-Proofpoint-Virus-Version: vendor=nai engine=5.2.00 definitions=5398 signatures=473327
+X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 classifier= adjust=0 reason=limit engine=3.1.0-0805090000 definitions=main-0810060054
+
+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.
+--=__PartFDD45234.0__=
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+Dear Mr Requester,
+
+Here is some information.
+
+--=__PartFDD45234.0__=
+Content-Type: message/rfc822
+
+Date: Fri, 23 May 2008 17:02:11 +0100
+From: "David Bishop" <foi2@example.com>
+To: "foi" <foi3@example.com>
+Subject: Foi request
+Mime-Version: 1.0
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+Extra info.
+
+--=__PartFDD45234.0__=
+Content-Type: image/jpeg; name="info.jpg"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename="info.jpg"
+
+xxxx
+
+--=__PartFDD45234.0__=--
+
diff --git a/spec/fixtures/files/incoming-request-attachment-unknown-extension.email b/spec/fixtures/files/incoming-request-attachment-unknown-extension.email
index b3485ec2d..aecd9a52c 100644
--- a/spec/fixtures/files/incoming-request-attachment-unknown-extension.email
+++ b/spec/fixtures/files/incoming-request-attachment-unknown-extension.email
@@ -4,17 +4,16 @@ Subject: Same attachment twice
Content-Type: multipart/mixed; boundary="Q68bSM7Ycu6FN28Q"
Content-Disposition: inline
-
--Q68bSM7Ycu6FN28Q
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline
-
--Q68bSM7Ycu6FN28Q
Content-Type: application/x-nonsense
Content-Disposition: attachment; filename="hello.qwglhm"
This is an unusual sort of file.
---Q68bSM7Ycu6FN28Q
+--Q68bSM7Ycu6FN28Q--
+
diff --git a/spec/fixtures/files/many-attachments-date-header.email b/spec/fixtures/files/many-attachments-date-header.email
new file mode 100644
index 000000000..a241e2456
--- /dev/null
+++ b/spec/fixtures/files/many-attachments-date-header.email
@@ -0,0 +1,451 @@
+From email@example.com Wed Apr 14 11:23:08 2010
+Return-path: <email@example.com>
+Envelope-to: email@example.com
+Delivery-date: Wed, 14 Apr 2010 11:23:08 +0100
+X-TM-IMSS-Message-ID:<email@example.com>
+Received: from example.com ([0.0.0.0]) by example.com ([0.0.0.0]) with ESMTP (TREND IMSS SMTP Service 7.0) id 1ec0f7ac0002a77f ; Wed, 14 Apr 2010 11:22:52 +0100
+Received: from GWGATE-MTA by example.com
+ with Novell_GroupWise; Wed, 14 Apr 2010 11:22:53 +0100
+Message-Id: <email@example.com>
+X-Mailer: Novell GroupWise Internet Agent 8.0.1
+Date: Wed, 14 Apr 2010 11:22:47 +0100
+From: "A Person" <email@example.com>
+To: <email@example.com>
+Cc: "FOI FOI" <email@example.com>,
+ "A Person" <email@example.com>
+Subject: Fwd: Re: Freedom of Information request
+References: <email@example.com>
+ <email@example.com>
+Mime-Version: 1.0
+Content-Type: multipart/mixed; boundary="=__Part163C9567.0__="
+
+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.
+
+--=__Part163C9567.0__=
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+Some information
+
+
+--=__Part163C9567.0__=
+Content-Type: message/rfc822
+
+Date: Wed, 10 Mar 2010 14:17:52 +0000
+From: "A Person" <email@example.com>
+To: "A Person" <email@example.com>
+Subject: Re: xxx
+Mime-Version: 1.0
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+2
+
+--=__Part163C9567.0__=
+Content-Type: message/rfc822
+
+Return-path: <email@example.com>
+Received: from example.com ([0.0.0.0])
+ by example.com with ESMTP; Tue, 24 Nov 2009 10:45:58 +0000
+X-TM-IMSS-Message-ID:<email@example.com>
+Received: from example.com ([0.0.0.0]) by example.com ([0.0.0.0]) with SMTP (TREND IMSS SMTP Service 7.0) id 00660acd00000f42 ; Tue, 24 Nov 2009 10:45:55 +0000
+Received: from source ([0.0.0.0]) (using TLSv1) by eu1sys200aob115.postini.com ([0.0.0.0]) with SMTP
+ ID email@example.com Tue, 24 Nov 2009 10:45:56 UTC
+Received: from example.com ([::1]) by
+ example.com ([::1]) with mapi; Tue, 24 Nov 2009
+ 10:45:53 +0000
+From: A Person <email@example.com>
+To: email@example.com <email@example.com>
+Date: Tue, 24 Nov 2009 10:45:52 +0000
+Subject: example
+Thread-Topic: example
+Thread-Index: AcpnbI2i+XAmfHFVTFy0eGDpVJhXoQFhVeZw
+Message-ID: <email@example.com>
+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="_006_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_"
+MIME-Version: 1.0
+X-TM-AS-Product-Ver: IMSS-0.0.0.0-0.0.0.0-17028.005
+X-TM-AS-Result: No--19.329-5.0-31-1
+X-imss-scan-details: No--19.329-5.0-31-1
+X-TM-AS-User-Approved-Sender: No
+X-TM-AS-User-Blocked-Sender: No
+
+
+--_006_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_
+Content-Type: multipart/related;
+ boundary="_005_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_";
+ type="multipart/alternative"
+
+--_005_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_
+Content-Type: multipart/alternative;
+ boundary="_000_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_"
+
+--_000_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_
+Content-Type: text/plain; charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+
+
+3
+
+--_000_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_
+Content-Type: text/html; charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+
+4
+
+--_000_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_--
+
+--_005_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_
+Content-Type: image/gif; name="image001.gif"
+Content-Description: image001.gif
+Content-Disposition: inline; filename="image001.gif"; size=5445;
+ creation-date="Tue, 17 Nov 2009 09:58:46 GMT";
+ modification-date="Tue, 17 Nov 2009 09:58:46 GMT"
+Content-ID: <email@example.com>
+Content-Transfer-Encoding: base64
+
+5
+--_005_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_--
+
+--_006_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_
+Content-Type: application/vnd.ms-excel;
+ name="particpant list.xls"
+Content-Description: particpant list.xls
+Content-Disposition: attachment;
+ filename="particpant list.xls"; size=21504;
+ creation-date="Mon, 02 Nov 2009 09:42:37 GMT";
+ modification-date="Tue, 24 Nov 2009 10:45:52 GMT"
+Content-Transfer-Encoding: base64
+
+6
+
+--_006_B3BDF1D06801114FA040D0F1BEE7CF9C48FD3549evs02ukcommonpu_--
+--=__Part163C9567.0__=
+Content-Type: message/rfc822
+
+Return-path: <email@example.com>
+Received: from example.com ([0.0.0.0])
+ by example.com with ESMTP; Thu, 03 Dec 2009 09:29:07 +0000
+X-TM-IMSS-Message-ID:<email@example.com>
+Received: from eu1sys200aog116.obsmtp.com ([0.0.0.0]) by example.com ([0.0.0.0]) with SMTP (TREND IMSS SMTP Service 7.0) id 0ac1bf1b0001116e ; Thu, 3 Dec 2009 09:29:04 +0000
+Received: from source ([0.0.0.0]) (using TLSv1) by eu1sys200aob116.postini.com ([0.0.0.0]) with SMTP
+ ID email@example.com Thu, 03 Dec 2009 09:29:06 UTC
+Received: from example.com ([::1]) by
+ example.com ([::1]) with mapi; Thu, 3 Dec 2009 09:29:03
+ +0000
+From: A Person <email@example.com>
+To: 'A Person' <email@example.com>
+Date: Thu, 3 Dec 2009 09:29:03 +0000
+Subject: RE: example
+Thread-Topic: example
+Thread-Index: AcpuoEyRvzM8fXw+THuj/617pjnvCgFWqZdQ
+Message-ID: <email@example.com>
+References: <email@example.com>
+ <email@example.com>
+In-Reply-To: <email@example.com>
+Accept-Language: en-US, en-GB
+Content-Language: en-US
+X-MS-Has-Attach:
+X-MS-TNEF-Correlator:
+acceptlanguage: en-US, en-GB
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: base64
+MIME-Version: 1.0
+X-TM-AS-Product-Ver: IMSS-0.0.0.0-0.0.0.0-17046.004
+X-TM-AS-Result: No--16.791-5.0-31-1
+X-imss-scan-details: No--16.791-5.0-31-1
+X-TM-AS-User-Approved-Sender: No
+X-TM-AS-User-Blocked-Sender: No
+
+
+7
+--=__Part163C9567.0__=
+Content-Type: message/rfc822
+
+Return-path: <email@example.com>
+Received: from example.com ([0.0.0.0])
+ by example.com with ESMTP; Wed, 25 Nov 2009 22:26:23 +0000
+X-TM-IMSS-Message-ID:<email@example.com>
+Received: from eu1sys200aog105.obsmtp.com ([0.0.0.0]) by example.com ([0.0.0.0]) with SMTP (TREND IMSS SMTP Service 7.0) id 034354c900007016 ; Wed, 25 Nov 2009 22:26:19 +0000
+Received: from source ([0.0.0.0]) (using TLSv1) by eu1sys200aob105.postini.com ([0.0.0.0]) with SMTP
+ ID email@example.com Wed, 25 Nov 2009 22:26:21 UTC
+Received: from example.com ([::1]) by
+ example.com ([::1]) with mapi; Wed, 25 Nov 2009
+ 22:26:15 +0000
+From: A Person <email@example.com>
+To: email@example.com <email@example.com>
+CC: A Person <email@example.com>
+Date: Wed, 25 Nov 2009 22:26:12 +0000
+Subject: As promised - Masterclass info (example)
+Thread-Topic: As promised - Masterclass info (example)
+Thread-Index: AcpuHcJ4yrR8PBHZTVCU/RLGzwqsDAAACGwQ
+Message-ID: <email@example.com>
+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="_007_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_"
+MIME-Version: 1.0
+X-TM-AS-Product-Ver: IMSS-0.0.0.0-0.0.0.0-17032.000
+X-TM-AS-Result: No--26.167-5.0-31-1
+X-imss-scan-details: No--26.167-5.0-31-1
+X-TM-AS-User-Approved-Sender: No
+X-TM-AS-User-Blocked-Sender: No
+
+
+--_007_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_
+Content-Type: multipart/related;
+ boundary="_006_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_";
+ type="multipart/alternative"
+
+--_006_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_
+Content-Type: multipart/alternative;
+ boundary="_000_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_"
+
+--_000_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: base64
+
+8
+--_000_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_
+Content-Type: text/html; charset="utf-8"
+Content-Transfer-Encoding: base64
+
+9
+--_000_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_--
+
+--_006_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_
+Content-Type: image/gif; name="image001.gif"
+Content-Description: image001.gif
+Content-Disposition: inline; filename="image001.gif"; size=5445;
+ creation-date="Wed, 25 Nov 2009 22:26:14 GMT";
+ modification-date="Wed, 25 Nov 2009 22:26:14 GMT"
+Content-ID: <email@example.com>
+Content-Transfer-Encoding: base64
+
+
+10
+
+--_006_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_--
+
+--_007_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_
+Content-Type: application/msword;
+ name= "Participant List.doc"
+Content-Description: Participant List.doc
+Content-Disposition: attachment;
+ filename="Participant List.doc"; size=112640;
+ creation-date="Wed, 25 Nov 2009 22:17:24 GMT";
+ modification-date="Wed, 25 Nov 2009 11:43:48 GMT"
+Content-Transfer-Encoding: base64
+
+11
+--_007_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_
+Content-Type: application/msword; name="Information & Booking Form.doc"
+Content-Description: Information & Booking Form.doc
+Content-Disposition: attachment; filename="Information & Booking Form.doc"; size=84480;
+ creation-date="Wed, 25 Nov 2009 22:17:40 GMT";
+ modification-date="Wed, 04 Nov 2009 14:42:54 GMT"
+Content-Transfer-Encoding: base64
+
+12
+
+--_007_B3BDF1D06801114FA040D0F1BEE7CF9C48DC6D82evs02ukcommonpu_--
+--=__Part163C9567.0__=
+Content-Type: message/rfc822
+
+Return-path: <email@example.com>
+Received: from example.com ([0.0.0.0])
+ by example.com with ESMTP; Fri, 04 Dec 2009 10:00:05 +0000
+X-TM-IMSS-Message-ID:<email@example.com>
+Received: from eu1sys200aog109.obsmtp.com ([0.0.0.0]) by example.com ([0.0.0.0]) with SMTP (TREND IMSS SMTP Service 7.0) id 100473260001a476 ; Fri, 4 Dec 2009 10:00:01 +0000
+Received: from source ([0.0.0.0]) (using TLSv1) by eu1sys200aob109.postini.com ([0.0.0.0]) with SMTP
+ ID email@example.com Fri, 04 Dec 2009 10:00:04 UTC
+Received: from example.com ([::1]) by
+ example.com ([::1]) with mapi; Fri, 4 Dec 2009 10:00:01
+ +0000
+From: A Person <email@example.com>
+To: email@example.com <email@example.com>
+Date: Fri, 4 Dec 2009 10:00:01 +0000
+Subject: Re: As promised - info (example)
+Thread-Topic: As promised - info (example)
+Thread-Index: AcpzhLeBjBId8eZATYudOfBgN6CPXQBQ9Pok
+Message-ID: <email@example.com>
+Accept-Language: en-US, en-GB
+Content-Language: en-US
+X-MS-Has-Attach:
+X-MS-TNEF-Correlator:
+acceptlanguage: en-US, en-GB
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: base64
+MIME-Version: 1.0
+X-TM-AS-Product-Ver: IMSS-0.0.0.0-0.0.0.0-17048.005
+X-TM-AS-Result: No--24.171-5.0-31-1
+X-imss-scan-details: No--24.171-5.0-31-1
+X-TM-AS-User-Approved-Sender: No
+X-TM-AS-User-Blocked-Sender: No
+
+13
+--=__Part163C9567.0__=
+Content-Type: message/rfc822
+
+Return-path: <email@example.com>
+Received: from example.com ([0.0.0.0])
+ by example.com with ESMTP; Sun, 21 Mar 2010 21:53:38 +0000
+X-TM-IMSS-Message-ID:<email@example.com>
+Received: from eu1sys200aog117.obsmtp.com ([0.0.0.0]) by example.com ([0.0.0.0]) with SMTP (TREND IMSS SMTP Service 7.0) id 1e3611c1000d37df ; Sun, 21 Mar 2010 21:53:32 +0000
+Received: from source ([0.0.0.0]) (using TLSv1) by eu1sys200aob117.postini.com ([0.0.0.0]) with SMTP
+ ID email@example.com Sun, 21 Mar 2010 21:53:37 UTC
+Received: from example.com ([::1]) by exchhub01
+ ([0.0.0.0]) with mapi; Sun, 21 Mar 2010 21:53:34 +0000
+From: A Person <email@example.com>
+To: email@example.com <email@example.com>
+CC: A Person <email@example.com>
+Date: Sun, 21 Mar 2010 21:53:32 +0000
+Subject: Thank you from example
+Thread-Topic: Thank you from example
+Thread-Index: AcrJQPL4xb9zjXMHRJGTjAxo3X/kfA==
+Message-ID: <email@example.com>
+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/related;
+ boundary="_004_B3BDF1D06801114FA040D0F1BEE7CF9C5E14635Bevs02ukcommonpu_";
+ type="multipart/alternative"
+MIME-Version: 1.0
+X-TM-AS-Product-Ver: IMSS-0.0.0.0-0.0.0.0-17266.002
+X-TM-AS-Result: No--26.373-5.0-31-1
+X-imss-scan-details: No--26.373-5.0-31-1
+X-TM-AS-User-Approved-Sender: No
+X-TM-AS-User-Blocked-Sender: No
+
+
+--_004_B3BDF1D06801114FA040D0F1BEE7CF9C5E14635Bevs02ukcommonpu_
+Content-Type: multipart/alternative;
+ boundary="_000_B3BDF1D06801114FA040D0F1BEE7CF9C5E14635Bevs02ukcommonpu_"
+
+--_000_B3BDF1D06801114FA040D0F1BEE7CF9C5E14635Bevs02ukcommonpu_
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: quoted-printable
+
+14
+
+--_000_B3BDF1D06801114FA040D0F1BEE7CF9C5E14635Bevs02ukcommonpu_
+Content-Type: text/html; charset="us-ascii"
+Content-Transfer-Encoding: quoted-printable
+
+15
+
+--_000_B3BDF1D06801114FA040D0F1BEE7CF9C5E14635Bevs02ukcommonpu_--
+
+--_004_B3BDF1D06801114FA040D0F1BEE7CF9C5E14635Bevs02ukcommonpu_
+Content-Type: image/gif; name="image001.gif"
+Content-Description: image001.gif
+Content-Disposition: inline; filename="image001.gif"; size=5445;
+ creation-date="Sun, 21 Mar 2010 21:53:33 GMT";
+ modification-date="Sun, 21 Mar 2010 21:53:33 GMT"
+Content-ID: <email@example.com>
+Content-Transfer-Encoding: base64
+
+16
+--_004_B3BDF1D06801114FA040D0F1BEE7CF9C5E14635Bevs02ukcommonpu_--
+--=__Part163C9567.0__=
+Content-Type: message/rfc822
+
+Return-path: <email@example.com>
+Received: from example.com ([0.0.0.0])
+ by example.com with ESMTP; Tue, 23 Feb 2010 15:33:48 +0000
+X-TM-IMSS-Message-ID:<email@example.com>
+Received: from eu1sys200aog112.obsmtp.com ([0.0.0.0]) by example.com ([0.0.0.0]) with SMTP (TREND IMSS SMTP Service 7.0) id 96f54043000f2e72 ; Tue, 23 Feb 2010 15:33:48 +0000
+Received: from source ([0.0.0.0]) by eu1sys200aob112.postini.com ([0.0.0.0]) with SMTP
+ ID email@example.com Tue, 23 Feb 2010 15:33:47 UTC
+Received: from gla-002561-lap ([0.0.0.0]) by example.com with Microsoft SMTPSVC(0.0.0.0);
+ Tue, 23 Feb 2010 15:33:46 +0000
+Reply-To: email@example.com
+From: email@example.com
+To: email@example.com
+Subject: example - Meeting - Tuesday 2nd March
+Date: 23 February 2010 15:33
+X-Mailer: Internet Professional v1.15
+Return-Path: email@example.com
+Message-ID: <email@example.com>
+X-OriginalArrivalTime: 23 Feb 2010 15:33:46.0648 (UTC) FILETIME=[96CEC980:01CAB49D]
+X-TM-AS-Product-Ver: IMSS-0.0.0.0-0.0.0.0-17212.000
+X-TM-AS-Result: No--16.146-5.0-31-1
+X-imss-scan-details: No--16.146-5.0-31-1
+X-TM-AS-User-Approved-Sender: No
+X-TM-AS-User-Blocked-Sender: No
+
+17
+
+--=__Part163C9567.0__=
+Content-Type: message/rfc822
+
+Return-path: <email@example.com>
+Received: from example.com ([0.0.0.0])
+ by example.com with ESMTP; Mon, 08 Mar 2010 09:21:42 +0000
+X-TM-IMSS-Message-ID:<email@example.com>
+Received: from eu1sys200aog117.obsmtp.com ([0.0.0.0]) by example.com ([0.0.0.0]) with SMTP (TREND IMSS SMTP Service 7.0) id d8931aff001580d6 ; Mon, 8 Mar 2010 09:21:40 +0000
+Received: from source ([0.0.0.0]) by eu1sys200aob117.postini.com ([0.0.0.0]) with SMTP
+ ID email@example.com Mon, 08 Mar 2010 09:21:39 UTC
+Received: from gla-002561-lap ([0.0.0.0]) by example.com with Microsoft SMTPSVC(0.0.0.0);
+ Mon, 8 Mar 2010 09:21:36 +0000
+Reply-To: email@example.com
+From: email@example.com
+To: email@example.com
+Subject: example - Help needed
+Date: 08 March 2010 09:21
+X-Mailer: Internet Professional v1.15
+MIME-Version: 1.0
+Content-Type: multipart/mixed;boundary="_NextPart_00009D35-00000F3C-00271781-26DF"
+Return-Path: email@example.com
+Message-ID: <email@example.com>
+X-OriginalArrivalTime: 08 Mar 2010 09:21:36.0283 (UTC) FILETIME=[C03E3EB0:01CABEA0]
+X-TM-AS-Product-Ver: IMSS-0.0.0.0-0.0.0.0-17236.006
+X-TM-AS-Result: No--32.111-5.0-31-1
+X-imss-scan-details: No--32.111-5.0-31-1
+X-TM-AS-User-Approved-Sender: No
+X-TM-AS-User-Blocked-Sender: No
+
+This message is in MIME format. Since your mail reader does not
+understand this format, some or all of this message may not be legible.
+--_NextPart_00009D35-00000F3C-00271781-26DF
+Content-Type: text/plain
+Content-Transfer-Encoding: 7bit
+
+18
+
+--_NextPart_00009D35-00000F3C-00271781-26DF
+Content-Type: application/octet-stream;name="Information Pack.pdf"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;filename="Information Pack.pdf";size=106688
+
+19
+--_NextPart_00009D35-00000F3C-00271781-26DF--
+--=__Part163C9567.0__=
+Content-Type: message/rfc822
+
+Date: Wed, 02 Dec 2009 19:21:27 +0000
+From: "A Person" <email@example.com>
+To: "A Person" <email@example.com>
+Subject: Re: As promised - info (example)
+Mime-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline
+
+20
+--=__Part163C9567.0__=--
+
diff --git a/spec/fixtures/files/rfc822-attachment.email b/spec/fixtures/files/rfc822-attachment.email
new file mode 100644
index 000000000..ae58a06af
--- /dev/null
+++ b/spec/fixtures/files/rfc822-attachment.email
@@ -0,0 +1,147 @@
+From foi.officer@example.com Fri Mar 14 08:39:57 2008
+Return-path: <foi.officer@example.com>
+Envelope-to: request-bounce-xx-xxxxx@whatdotheyknow.com
+Delivery-date: Fri, 14 Mar 2008 08:39:57 +0000
+Received: from service27.mimecast.com ([213.235.63.79]:55305)
+ by tea.ukcod.org.uk with smtp (Exim 4.50)
+ id 1Ja5SH-0005iP-Jm
+ for xxx@whatdotheyknow.com; Fri, 14 Mar 2008 08:39:57 +0000
+Received: from mailscan.ad.example.com (mailgate.example.com [194.70.143.2])
+ by service27.mimecast.com;
+ Fri, 14 Mar 2008 08:38:47 +0000
+Received: from exch2serv.ad.example.com ([201.234.62.4]) by mailscan.ad.example.com with InterScan Message Security Suite; Fri, 14 Mar 2008 08:38:47 -0000
+X-MIMEOLE: Produced By Microsoft Exchange V6.0.6603.0
+content-class: urn:content-classes:message
+MIME-Version: 1.0
+Subject:
+Date: Fri, 14 Mar 2008 08:38:46 -0000
+Message-ID: <0F3951EA9DCFB246827E1F6513F6C79D096DDADB@exch2serv.ad.example.com>
+X-MS-Has-Attach: yes
+X-MS-TNEF-Correlator:
+Thread-Index: AciFrtIeS9pyMOhuQdyxkm5305zs9g==
+From: "An FOI Officer" <foi.officer@example.com>
+To: "On" <request-bounce-xx-xxxxx@whatdotheyknow.com>
+X-MC-Unique: 108031408384702301
+Content-Type: multipart/mixed;
+ boundary="----_=_NextPart_001_01C885AE.D1BF23AC"
+
+This is a multi-part message in MIME format.
+
+------_=_NextPart_001_01C885AE.D1BF23AC
+Content-Type: multipart/alternative;
+ boundary="MCBoundary=_108031408384800401"
+
+--MCBoundary=_108031408384800401
+Content-Type: text/plain; charset=WINDOWS-1252
+Content-Transfer-Encoding: quoted-printable
+
+
+ <<Freedom of Information request >>=20
+
+
+e-mail: foi.officer@example.com=20
+
+
+
+
+***************************************************************************=
+********
+The information in this Email and any attachments is personal to the
+sender and the views of the author may not necessarily reflect those
+of Borough Council. The information is strictly confidential
+and is intended only for the named person or organisation to whom it is
+addressed as it may contain privileged and confidential information. If
+you are not the intended recipient do not copy, distribute or use this
+Email, and please notify the sender. Please note that we cannot
+guarantee that this message or any attachment is virus free or has not
+been intercepted and amended.
+***************************************************************************=
+********
+
+Disclaimer=20
+---------------------------------------------------------------------------=
+----------------
+This email message has been scanned for viruses by Mimecast.
+Mimecast delivers a complete managed email solution from a single web based=
+ platform.
+For more information please visit www.mimecast.com
+---------------------------------------------------------------------------=
+----------------
+--MCBoundary=_108031408384800401
+Content-Type: text/html; charset=WINDOWS-1252
+Content-Transfer-Encoding: quoted-printable
+
+<HTML><BODY> =20
+ <BR>
+ &lt;&lt;Freedom of Information request &gt;&gt; <BR>
+<BR>
+e-mail: <a href=3D"mailto:foi.officer@example.com">foi.officer@example.com</a> <BR>
+<BR>
+<BR>
+<BR>
+<BR>
+***************************************************************************=
+********<BR>
+The information in this Email and any attachments is personal to the<B=
+R>
+sender and the views of the author may not necessarily reflect those<BR=
+>
+of Borough Council. The information is strictly confidential<B=
+R>
+and is intended only for the named person or organisation to whom it is<BR>
+addressed as it may contain privileged and confidential information. If<B=
+R>
+you are not the intended recipient do not copy, distribute or use this=
+<BR>
+Email, and please notify the sender. Please note that we cannot<B=
+R>
+guarantee that this message or any attachment is virus free or has not<BR>
+been intercepted and amended.<BR>
+***************************************************************************=
+********<BR>
+
+ <BR>
+ <BR>
+ <span style=3D"font-family:Arial; Font-size:10.0pt">
+ Disclaimer <p>
+ <hr width=3D"100%">
+ This email message has been scanned for viruses by Mimecast.<BR>
+ Mimecast delivers a complete managed email solution from a single we=
+b based platform.<BR>
+ For more information please visit <a href=3D"http://www.mimecast.com=
+">http://www.mimecast.com</a>
+ <hr width=3D"100%">
+ </span>
+ </BODY></HTML>
+
+
+--MCBoundary=_108031408384800401--
+------_=_NextPart_001_01C885AE.D1BF23AC
+Content-Type: message/rfc822
+Content-Transfer-Encoding: 7bit
+
+X-MIMEOLE: Produced By Microsoft Exchange V6.0.6603.0
+content-class: urn:content-classes:message
+MIME-Version: 1.0
+Subject: Freedom of Information request
+Date: Thu, 13 Mar 2008 16:57:33 -0000
+Message-ID: <0F3951EA9DCFB246827E1F6513F6C79D098AC8C5@exch2serv.ad.example.com>
+X-MS-Has-Attach:
+X-MS-TNEF-Correlator:
+Thread-Topic: Freedom of Information request
+Thread-Index: AciE9w0L7QnQlahDQS+Zjrz40mr8KAAD5KuQAADg+1AABjC9wAAAXtJgAAEHJvAAAHTxwA==
+X-Priority: 1
+Priority: Urgent
+Importance: high
+From: "An FOI Officer" <foi.officer@example.com>
+To: <request-bounce-xx-xxxxx@whatdotheyno.com>
+Content-Type: text/plain;
+ charset="utf-8"
+Content-Transfer-Encoding: base64
+
+c29tZSBleGFtcGxlIHRleHQ=
+
+------_=_NextPart_001_01C885AE.D1BF23AC--
+
+
+
diff --git a/spec/lib/i18n_interpolation.rb b/spec/lib/i18n_interpolation.rb
index 8c86413ad..6b745059c 100644
--- a/spec/lib/i18n_interpolation.rb
+++ b/spec/lib/i18n_interpolation.rb
@@ -1,6 +1,3 @@
-# This is a test of the set_content_type monkey patch in
-# lib/tmail_extensions.rb
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "when using i18n" do
diff --git a/spec/lib/mail_handler/mail_handler_spec.rb b/spec/lib/mail_handler/mail_handler_spec.rb
index a3fba0698..ae65210f2 100644
--- a/spec/lib/mail_handler/mail_handler_spec.rb
+++ b/spec/lib/mail_handler/mail_handler_spec.rb
@@ -1,6 +1,12 @@
# coding: utf-8
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
+def create_message_from(from_field)
+ mail_data = load_file_fixture('incoming-request-plain.email')
+ mail_data.gsub!('EMAIL_FROM', from_field)
+ mail = MailHandler.mail_from_raw_email(mail_data)
+end
+
describe 'when creating a mail object from raw data' do
it 'should correctly parse a multipart email with a linebreak in the boundary' do
@@ -17,7 +23,361 @@ describe 'when creating a mail object from raw data' do
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.body.is_utf8?.should == true
+ MailHandler.get_part_body(mail).is_utf8?.should == true
+ end
+
+end
+
+describe 'when asked for the from name' do
+
+ it 'should return nil if there is a blank "From" field' do
+ mail = create_message_from('')
+ MailHandler.get_from_name(mail).should == nil
+ end
+
+ it 'should correctly return an encoded name from the from field' do
+ mail = get_fixture_mail('quoted-subject-iso8859-1.email')
+ MailHandler.get_from_name(mail).should == 'Coordenação de Relacionamento, Pesquisa e Informação/CEDI'
+ end
+
+ it 'should get a name from a "From" field with a name and address' do
+ mail = get_fixture_mail('incoming-request-oft-attachments.email')
+ MailHandler.get_from_name(mail).should == 'Public Authority'
+ end
+
+ it 'should return nil from a "From" field that is just a name'do
+ mail = get_fixture_mail('track-response-webshield-bounce.email')
+ MailHandler.get_from_name(mail).should == nil
+ end
+
+end
+
+describe 'when asked for the from address' do
+
+ it 'should return nil if there is a blank "From" field' do
+ mail = create_message_from('')
+ MailHandler.get_from_address(mail).should == nil
+ end
+
+ it 'should correctly return an address from a mail that has an encoded name in the from field' do
+ mail = get_fixture_mail('quoted-subject-iso8859-1.email')
+ MailHandler.get_from_address(mail).should == 'geraldinequango@localhost'
+ end
+
+ it 'should return nil if there is no address in the "From" field' do
+ mail = get_fixture_mail('track-response-webshield-bounce.email')
+ MailHandler.get_from_address(mail).should == nil
+ end
+
+ it 'should return the "From" email address if there is one' do
+ mail = get_fixture_mail('track-response-abcmail-oof.email')
+ MailHandler.get_from_address(mail).should == 'Name.Removed@example.gov.uk'
+ end
+
+ it 'should get an address from a "From" field with a name and address' do
+ mail = get_fixture_mail('incoming-request-oft-attachments.email')
+ MailHandler.get_from_address(mail).should == 'public@authority.gov.uk'
+ end
+end
+
+describe 'when asked for all the addresses a mail has been sent to' do
+
+ it 'should return an array containing the envelope-to address and the to address, and the cc address if there is one' do
+ mail_data = load_file_fixture('humberside-police-odd-mime-type.email')
+ mail_data.gsub!('Envelope-to: request-5335-xxxxxxxx@whatdotheyknow.com',
+ 'Envelope-to: request-5555-xxxxxxxx@whatdotheyknow.com')
+ mail_data.gsub!('Cc: request-5335-xxxxxxxx@whatdotheyknow.com',
+ 'Cc: request-3333-xxxxxxxx@whatdotheyknow.com')
+ mail = MailHandler.mail_from_raw_email(mail_data)
+ MailHandler.get_all_addresses(mail).should == ['request-5335-xxxxxxxx@whatdotheyknow.com',
+ 'request-3333-xxxxxxxx@whatdotheyknow.com',
+ 'request-5555-xxxxxxxx@whatdotheyknow.com']
+ end
+
+ it 'should only return unique values' do
+ # envelope-to and to fields are the same
+ mail = get_fixture_mail('humberside-police-odd-mime-type.email')
+ MailHandler.get_all_addresses(mail).should == ['request-5335-xxxxxxxx@whatdotheyknow.com']
+ end
+
+ it 'should handle the absence of an envelope-to or cc field' do
+ mail_data = load_file_fixture('autoresponse-header.email')
+ mail_data.gsub!('To: FOI Person <EMAIL_TO>',
+ 'To: FOI Person <request-5555-xxxxxxxx@whatdotheyknow.com>')
+ mail = MailHandler.mail_from_raw_email(mail_data)
+ MailHandler.get_all_addresses(mail).should == ["request-5555-xxxxxxxx@whatdotheyknow.com"]
+ end
+end
+
+describe 'when asked for auto_submitted' do
+
+ it 'should return a string value for an email with an auto-submitted header' do
+ mail = get_fixture_mail('autoresponse-header.email')
+ MailHandler.get_auto_submitted(mail).should == 'auto-replied'
+ end
+
+ it 'should return a nil value for an email with no auto-submitted header' do
+ mail = get_fixture_mail('incoming-request-plain.email')
+ MailHandler.get_auto_submitted(mail).should == nil
+ end
+
+end
+
+describe 'when asked if there is an empty return path' do
+
+ it 'should return true if there is an empty return-path specified' do
+ mail = get_fixture_mail('empty-return-path.email')
+ MailHandler.empty_return_path?(mail).should == true
+ end
+
+ it 'should return false if there is no return-path header' do
+ mail = get_fixture_mail('incoming-request-attach-attachments.email')
+ MailHandler.empty_return_path?(mail).should == false
+ end
+
+ it 'should return false if there is a return path address' do
+ mail = get_fixture_mail('autoresponse-header.email')
+ MailHandler.empty_return_path?(mail).should == false
+ end
+end
+
+describe 'when deriving a name, email and formatted address from a message from a line' do
+
+ def should_render_from_address(from_line, 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
+
+ it 'should correctly render a name with quoted commas' do
+ should_render_from_address('"Clare College, Cambridge" <test@test.test>',
+ ['Clare College, Cambridge',
+ 'test@test.test',
+ '"Clare College, Cambridge" <test@test.test>'])
end
+ it 'should correctly reproduce a simple name and email that does not need quotes' do
+ should_render_from_address('"FOI Person" <foiperson@localhost>',
+ ['FOI Person',
+ 'foiperson@localhost',
+ 'FOI Person <foiperson@localhost>'])
+ end
+
+ it 'should render an address with no name' do
+ should_render_from_address("foiperson@localhost",
+ [nil,
+ "foiperson@localhost",
+ "foiperson@localhost"])
+ end
+
+ it 'should quote a name with a square bracked in it' do
+ should_render_from_address('"FOI [ Person" <foiperson@localhost>',
+ ['FOI [ Person',
+ 'foiperson@localhost',
+ '"FOI [ Person" <foiperson@localhost>'])
+ end
+
+ it 'should quote a name with an @ in it' do
+ should_render_from_address('"FOI @ Person" <foiperson@localhost>',
+ ['FOI @ Person',
+ 'foiperson@localhost',
+ '"FOI @ Person" <foiperson@localhost>'])
+ end
+
+
+ it 'should quote a name with quotes in it' do
+ should_render_from_address('"FOI \" Person" <foiperson@localhost>',
+ ['FOI " Person',
+ 'foiperson@localhost',
+ '"FOI \" Person" <foiperson@localhost>'])
+ end
+
+end
+
+describe 'when getting the content type of a mail part' do
+
+ def expect_content_type(fixture_file, content_type)
+ mail = get_fixture_mail(fixture_file)
+ MailHandler.get_content_type(mail).should == content_type
+ end
+
+ it 'should correctly return a type of "multipart/report"' do
+ expect_content_type('track-response-multipart-report.email', 'multipart/report')
+ end
+
+ it 'should correctly return a type of "text/plain"' do
+ expect_content_type('track-response-abcmail-oof.email', 'text/plain')
+ end
+
+ it 'should correctly return a type of "multipart/mixed"' do
+ expect_content_type('track-response-messageclass-oof.email', 'multipart/mixed')
+ end
+
+ it 'should correctly return the types in an example bounce report' do
+ mail = get_fixture_mail('track-response-ms-bounce.email')
+ report = mail.parts.detect{ |part| MailHandler.get_content_type(part) == 'multipart/report'}
+ MailHandler.get_content_type(report.parts[0]).should == 'text/plain'
+ MailHandler.get_content_type(report.parts[1]).should == 'message/delivery-status'
+ MailHandler.get_content_type(report.parts[2]).should == 'message/rfc822'
+ end
+
+end
+
+describe 'when getting header strings' do
+
+ def expect_header_string(fixture_file, header, header_string)
+ mail = get_fixture_mail(fixture_file)
+ MailHandler.get_header_string(header, mail).should == header_string
+ end
+
+ it 'should return the contents of a "Subject" header' do
+ expect_header_string('track-response-ms-bounce.email',
+ 'Subject',
+ 'Delivery Status Notification (Delay)')
+ end
+
+ it 'should return the contents of an "X-Failed-Recipients" header' do
+ expect_header_string('autoresponse-header.email',
+ 'X-Failed-Recipients',
+ 'enquiries@cheese.com')
+ end
+
+ it 'should return the contents of an example "" header' do
+ expect_header_string('track-response-messageclass-oof.email',
+ 'X-POST-MessageClass',
+ '9; Autoresponder')
+ end
+
+end
+
+describe "when parsing HTML mail" do
+ it "should display UTF-8 characters in the plain text version correctly" do
+ html = "<html><b>foo</b> është"
+ plain_text = MailHandler.get_attachment_text_one_file('text/html', html)
+ plain_text.should match(/është/)
+ end
+
+end
+
+describe "when getting the attachment text" do
+ it "should not raise an error if the expansion of a zip file raises an error" do
+ mock_entry = mock('ZipFile entry', :file? => true)
+ mock_entries = [mock_entry]
+ mock_entries.stub!(:close)
+ mock_entry.stub!(:get_input_stream).and_raise("invalid distance too far back")
+ Zip::ZipFile.stub!(:open).and_return(mock_entries)
+ MailHandler.get_attachment_text_one_file('application/zip', "some string")
+ end
+
+end
+
+describe 'when getting attachment attributes' do
+
+ 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')
+ attributes = MailHandler.get_attachment_attributes(mail)
+ attributes.size.should == 2
+ end
+
+ it 'should expand a mail attached as text' do
+ mail = get_fixture_mail('rfc822-attachment.email')
+ attributes = MailHandler.get_attachment_attributes(mail)
+ attributes.size.should == 2
+ rfc_attachment = attributes[1]
+ rfc_attachment[:within_rfc822_subject].should == 'Freedom of Information request'
+ headers = ['Date: Thu, 13 Mar 2008 16:57:33 +0000',
+ 'Subject: Freedom of Information request',
+ 'From: An FOI Officer <foi.officer@example.com>',
+ 'To: request-bounce-xx-xxxxx@whatdotheyno.com']
+ rfc_attachment[:body].should == "#{headers.join("\n")}\n\nsome example text"
+ end
+
+ it 'should handle a mail which causes Tmail to generate a blank header value' do
+ mail = get_fixture_mail('many-attachments-date-header.email')
+ attributes = MailHandler.get_attachment_attributes(mail)
+ 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')
+ attributes = MailHandler.get_attachment_attributes(mail)
+
+ expected_attributes = [ { :content_type=>"text/plain",
+ :url_part_number=>1,
+ :within_rfc822_subject=>nil,
+ :filename=>nil},
+ { :content_type=>"text/plain",
+ :url_part_number=>2,
+ :within_rfc822_subject=>"Re: xxx",
+ :filename=>nil},
+ { :content_type=>"text/html",
+ :url_part_number=>4,
+ :within_rfc822_subject=>"example",
+ :filename=>nil},
+ { :content_type=>"image/gif", :url_part_number=>5,
+ :within_rfc822_subject=>"example",
+ :filename=>"image001.gif"},
+ { :content_type=>"application/vnd.ms-excel",
+ :url_part_number=>6,
+ :within_rfc822_subject=>"example",
+ :filename=>"particpant list.xls"},
+ { :content_type=>"text/plain",
+ :url_part_number=>7,
+ :within_rfc822_subject=>"RE: example",
+ :filename=>nil},
+ { :content_type=>"text/html",
+ :url_part_number=>9,
+ :within_rfc822_subject=>"As promised - Masterclass info (example)",
+ :filename=>nil},
+ { :content_type=>"image/gif",
+ :url_part_number=>10,
+ :within_rfc822_subject=>"As promised - Masterclass info (example)",
+ :filename=>"image001.gif"},
+ { :content_type=>"application/vnd.ms-word",
+ :url_part_number=>11,
+ :within_rfc822_subject=>"As promised - Masterclass info (example)",
+ :filename=>"Participant List.doc"},
+ { :content_type=>"application/vnd.ms-word",
+ :url_part_number=>12,
+ :within_rfc822_subject=>"As promised - Masterclass info (example)",
+ :filename=>"Information & Booking Form.doc"},
+ { :content_type=>"text/plain",
+ :url_part_number=>13,
+ :within_rfc822_subject=>"Re: As promised - info (example)",
+ :filename=>nil},
+ { :content_type=>"text/html",
+ :url_part_number=>15,
+ :within_rfc822_subject=>"Thank you from example",
+ :filename=>nil},
+ { :content_type=>"image/gif",
+ :url_part_number=>16,
+ :within_rfc822_subject=>"Thank you from example",
+ :filename=>"image001.gif"},
+ { :content_type=>"text/plain",
+ :url_part_number=>17,
+ :within_rfc822_subject=>"example - Meeting - Tuesday 2nd March",
+ :filename=>nil},
+ { :content_type=>"text/plain",
+ :url_part_number=>18,
+ :within_rfc822_subject=>"example - Help needed",
+ :filename=>nil},
+ { :content_type=>"application/pdf",
+ :url_part_number=>19,
+ :within_rfc822_subject=>"example - Help needed",
+ :filename=>"Information Pack.pdf"},
+ { :content_type=>"text/plain",
+ :url_part_number=>20,
+ :within_rfc822_subject=>"Re: As promised - info (example)",
+ :filename=>nil} ]
+
+ attributes.each_with_index do |attr, index|
+ attr.delete(:charset)
+ attr.delete(:body)
+ attr.delete(:hexdigest)
+ attr.should == expected_attributes[index]
+ end
+ end
end
diff --git a/spec/models/incoming_message_spec.rb b/spec/models/incoming_message_spec.rb
index fdbcd1e23..97bf78cb6 100644
--- a/spec/models/incoming_message_spec.rb
+++ b/spec/models/incoming_message_spec.rb
@@ -26,13 +26,8 @@ describe IncomingMessage, " when dealing with incoming mail" do
@im.sent_at.should == @im.mail.date
end
- it "should be able to parse emails with quoted commas in" do
- em = "\"Clare College, Cambridge\" <test@test.test>"
- TMail::Address.parse(em)
- 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")
@@ -73,6 +68,14 @@ describe IncomingMessage, " when dealing with incoming mail" do
message.get_main_body_text_internal.should include("The above text was badly encoded")
end
+ it 'should convert DOS-style linebreaks to Unix style' do
+ ir = info_requests(:fancy_dog_request)
+ receive_incoming_mail('dos-linebreaks.email', ir.incoming_email)
+ message = ir.incoming_messages[1]
+ message.parse_raw_email!
+ message.get_main_body_text_internal.should_not match(/\r\n/)
+ end
+
it "should fold multiline sections" do
{
"foo\n--------\nconfidential" => "foo\nFOLDED_QUOTED_SECTION\n", # basic test
@@ -107,27 +110,6 @@ describe IncomingMessage, " when dealing with incoming mail" do
end
-describe IncomingMessage, "when parsing HTML mail" do
- it "should display UTF-8 characters in the plain text version correctly" do
- html = "<html><b>foo</b> është"
- plain_text = IncomingMessage._get_attachment_text_internal_one_file('text/html', html)
- plain_text.should match(/është/)
- end
-
-end
-
-describe IncomingMessage, "when getting the attachment text" do
-
- it "should not raise an error if the expansion of a zip file raises an error" do
- mock_entry = mock('ZipFile entry', :file? => true)
- mock_entry.stub!(:get_input_stream).and_raise("invalid distance too far back")
- Zip::ZipFile.stub!(:open).and_return([mock_entry])
- IncomingMessage._get_attachment_text_internal_one_file('application/zip', "some string")
- end
-
-end
-
-
describe IncomingMessage, " display attachments" do
it "should not show slashes in filenames" do
@@ -143,7 +125,7 @@ describe IncomingMessage, " display attachments" do
# http://www.whatdotheyknow.com/request/post_commercial_manager_librarie#incoming-17233
foi_attachment.within_rfc822_subject = "FOI/09/066 RESPONSE TO FOI REQUEST RECEIVED 21st JANUARY 2009"
foi_attachment.content_type = 'text/plain'
- foi_attachment.ensure_filename!
+ foi_attachment.ensure_filename!
expected_display_filename = foi_attachment.within_rfc822_subject.gsub(/\//, " ") + ".txt"
foi_attachment.display_filename.should == expected_display_filename
end
@@ -194,59 +176,50 @@ describe IncomingMessage, " folding quoted parts of emails" do
end
describe IncomingMessage, " checking validity to reply to" do
- def test_email(result, email, return_path, autosubmitted = nil)
- @address = mock(TMail::Address)
- @address.stub!(:spec).and_return(email)
-
- @return_path = mock(TMail::ReturnPathHeader)
- @return_path.stub!(:addr).and_return(return_path)
- if !autosubmitted.nil?
- @autosubmitted = TMail::UnstructuredHeader.new("auto-submitted", autosubmitted)
- end
- @mail = mock(TMail::Mail)
- @mail.stub!(:from_addrs).and_return( [ @address ] )
- @mail.stub!(:[]).with("return-path").and_return(@return_path)
- @mail.stub!(:[]).with("auto-submitted").and_return(@autosubmitted)
-
+ def test_email(result, email, empty_return_path, autosubmitted = nil)
+ @mail = mock('mail')
+ MailHandler.stub!(:get_from_address).and_return(email)
+ MailHandler.stub!(:empty_return_path?).with(@mail).and_return(empty_return_path)
+ MailHandler.stub!(:get_auto_submitted).with(@mail).and_return(autosubmitted)
@incoming_message = IncomingMessage.new()
@incoming_message.stub!(:mail).and_return(@mail)
@incoming_message._calculate_valid_to_reply_to.should == result
end
it "says a valid email is fine" do
- test_email(true, "team@mysociety.org", nil)
+ test_email(true, "team@mysociety.org", false)
end
it "says postmaster email is bad" do
- test_email(false, "postmaster@mysociety.org", nil)
+ test_email(false, "postmaster@mysociety.org", false)
end
it "says Mailer-Daemon email is bad" do
- test_email(false, "Mailer-Daemon@mysociety.org", nil)
+ test_email(false, "Mailer-Daemon@mysociety.org", false)
end
it "says case mangled MaIler-DaemOn email is bad" do
- test_email(false, "MaIler-DaemOn@mysociety.org", nil)
+ test_email(false, "MaIler-DaemOn@mysociety.org", false)
end
it "says Auto_Reply email is bad" do
- test_email(false, "Auto_Reply@mysociety.org", nil)
+ test_email(false, "Auto_Reply@mysociety.org", false)
end
it "says DoNotReply email is bad" do
- test_email(false, "DoNotReply@tube.tfl.gov.uk", nil)
+ test_email(false, "DoNotReply@tube.tfl.gov.uk", false)
end
it "says a filled-out return-path is fine" do
- test_email(true, "team@mysociety.org", "Return-path: <foo@baz.com>")
+ test_email(true, "team@mysociety.org", false)
end
it "says an empty return-path is bad" do
- test_email(false, "team@mysociety.org", "<>")
+ test_email(false, "team@mysociety.org", true)
end
it "says an auto-submitted keyword is bad" do
- test_email(false, "team@mysociety.org", nil, "auto-replied")
+ test_email(false, "team@mysociety.org", false, "auto-replied")
end
end
@@ -340,12 +313,12 @@ describe IncomingMessage, " when censoring data" do
orig_pdf = load_file_fixture('tfl.pdf')
pdf = orig_pdf.dup
- orig_text = IncomingMessage._get_attachment_text_internal_one_file('application/pdf', pdf)
+ orig_text = MailHandler.get_attachment_text_one_file('application/pdf', pdf)
orig_text.should match(/foi@tfl.gov.uk/)
@im.binary_mask_stuff!(pdf, "application/pdf")
- masked_text = IncomingMessage._get_attachment_text_internal_one_file('application/pdf', pdf)
+ masked_text = MailHandler.get_attachment_text_one_file('application/pdf', pdf)
masked_text.should_not match(/foi@tfl.gov.uk/)
masked_text.should match(/xxx@xxx.xxx.xx/)
config['USE_GHOSTSCRIPT_COMPRESSION'] = previous
@@ -455,6 +428,24 @@ end
describe IncomingMessage, "when messages are attached to messages" do
+ it 'should expand an RFC822 attachment' do
+ mail_body = load_file_fixture('rfc822-attachment.email')
+ mail = MailHandler.mail_from_raw_email(mail_body)
+
+ im = incoming_messages(:useless_incoming_message)
+ im.stub!(:mail).and_return(mail)
+
+ attachments = im.get_attachments_for_display
+ attachments.size.should == 1
+ attachment = attachments.first
+
+ attachment.content_type.should == 'text/plain'
+ attachment.filename.should == "Freedom of Information request.txt"
+ attachment.charset.should == "utf-8"
+ attachment.within_rfc822_subject.should == "Freedom of Information request"
+ attachment.hexdigest.should == 'f10fe56e4f2287685a58b71329f09639'
+ end
+
it "should flatten all the attachments out" do
mail = get_fixture_mail('incoming-request-attach-attachments.email')
@@ -470,6 +461,19 @@ describe IncomingMessage, "when messages are attached to messages" do
'hello.txt',
]
end
+
+ it 'should add headers to attached plain text message bodies' do
+ mail_body = load_file_fixture('incoming-request-attachment-headers.email')
+ mail = MailHandler.mail_from_raw_email(mail_body)
+
+ im = incoming_messages(:useless_incoming_message)
+ im.stub!(:mail).and_return(mail)
+
+ attachments = im.get_attachments_for_display
+ attachments.size.should == 2
+ attachments[0].body.should match('Date: Fri, 23 May 2008')
+ end
+
end
describe IncomingMessage, "when Outlook messages are attached to messages" do
diff --git a/spec/models/info_request_event_spec.rb b/spec/models/info_request_event_spec.rb
index 796f8b840..842246fd8 100644
--- a/spec/models/info_request_event_spec.rb
+++ b/spec/models/info_request_event_spec.rb
@@ -21,7 +21,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
diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb
index 2aeac2fec..a1a6e6c27 100644
--- a/spec/models/info_request_spec.rb
+++ b/spec/models/info_request_spec.rb
@@ -2,6 +2,22 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe InfoRequest do
+ describe 'when generating a user name slug' do
+
+ before do
+ @public_body = mock_model(PublicBody, :url_name => 'example_body',
+ :eir_only? => false)
+ @info_request = InfoRequest.new(:external_url => 'http://www.example.com',
+ :external_user_name => 'Example User',
+ :public_body => @public_body)
+ end
+
+ it 'should generate a slug for an example user name' do
+ @info_request.user_name_slug.should == 'example_body_example_user'
+ end
+
+ end
+
describe "guessing a request from an email" do
before(:each) do
@@ -410,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')
+ @mock_response_event = mock_model(InfoRequestEvent, :created_at => Time.now - 22.days, :event_type => 'response')
@info_request = InfoRequest.new(:prominence => 'normal',
:awaiting_description => true,
:info_request_events => [@mock_response_event, @mock_comment_event])
@@ -441,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')
diff --git a/spec/models/public_body_spec.rb b/spec/models/public_body_spec.rb
index c2e0a6353..f247f561c 100644
--- a/spec/models/public_body_spec.rb
+++ b/spec/models/public_body_spec.rb
@@ -210,7 +210,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 +231,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
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index e31c3f1b5..651ba4b65 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -152,10 +152,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/spec_helper.rb b/spec/spec_helper.rb
index d4dad591d..3c170ed16 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,35 +1,26 @@
-# 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'
+# 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'
-# set a default username and password so we can test
-config = MySociety::Config.load_default()
-config['ADMIN_USERNAME'] = 'foo'
-config['ADMIN_PASSWORD'] = 'baz'
+# 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}
-# 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'
+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
-# 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
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
- # fixture_path must end in a separator
- config.fixture_path = File.join(Rails.root, 'spec', 'fixtures') + File::SEPARATOR
+ # The order (!) of this is important thanks to foreign keys
config.global_fixtures = :users,
:public_bodies,
:public_body_translations,
@@ -46,213 +37,19 @@ Spec::Runner.configure do |config|
:holidays,
:track_things_sent_emails
-
- # == 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)
- file_name = file_fixture_name(file_name)
- content = File.read(file_name)
- 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])
- 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
- 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
-
-# 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
- 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"
- 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
-
-
-# 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 :(
-
-class ApplicationController < ActionController::Base
- def set_popup_banner
- @popup_banner = nil
- end
+ # 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"
end
diff --git a/spec/spec_helper.rb.rails2 b/spec/spec_helper.rb.rails2
new file mode 100644
index 000000000..3be11c0c7
--- /dev/null
+++ b/spec/spec_helper.rb.rails2
@@ -0,0 +1,152 @@
+# 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
+# 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
+
+# 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
+
+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
+
+# 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 load_test_categories
+ PublicBodyCategories.add(:en, [
+ "Local and regional",
+ [ "local_council", "Local councils", "a local council" ],
+ "Miscellaneous",
+ [ "other", "Miscellaneous", "miscellaneous" ],])
+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 :(
+
+class ApplicationController < ActionController::Base
+ def set_popup_banner
+ @popup_banner = nil
+ end
+end
diff --git a/spec/support/email_helpers.rb b/spec/support/email_helpers.rb
new file mode 100644
index 000000000..7e98c39f6
--- /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.read(email_name)
+ 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..08079f654
--- /dev/null
+++ b/spec/support/load_file_fixtures.rb
@@ -0,0 +1,14 @@
+def file_fixture_name(file_name)
+ return File.join(RSpec.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
+ end
+ return content
+end
diff --git a/spec/support/validate_html.rb b/spec/support/validate_html.rb
new file mode 100644
index 000000000..ba40b395a
--- /dev/null
+++ b/spec/support/validate_html.rb
@@ -0,0 +1,65 @@
+# 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
+ 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
+
+# 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
+ class TestCase
+ module Behavior
+ # 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 { render_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
+ end
+ else
+ puts "WARNING: HTML validation script " + $html_validation_script + " not found"
+ end
+end
diff --git a/spec/support/xapian_index.rb b/spec/support/xapian_index.rb
new file mode 100644
index 000000000..21f6192ef
--- /dev/null
+++ b/spec/support/xapian_index.rb
@@ -0,0 +1,21 @@
+# 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
diff --git a/spec/views/public_body/show.rhtml_spec.rb b/spec/views/public_body/show.rhtml_spec.rb
index b68b3f43b..1a972a661 100644
--- a/spec/views/public_body/show.rhtml_spec.rb
+++ b/spec/views/public_body/show.rhtml_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,62 @@ 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
+ render
+ controller.response.should be_success
end
it "should be valid HTML" do
- render "public_body/show"
+ render
validate_as_body response.body
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 +80,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/request/_after_actions.rhtml_spec.rb b/spec/views/request/_after_actions.rhtml_spec.rb
index 5b4734c52..54fef8cab 100644
--- a/spec/views/request/_after_actions.rhtml_spec.rb
+++ b/spec/views/request/_after_actions.rhtml_spec.rb
@@ -14,51 +14,27 @@ describe 'when displaying actions that can be taken with regard to a request' do
:public_body => @mock_body,
:comments_allowed? => true,
:url_title => 'test_request')
- 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
@@ -66,21 +42,30 @@ 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
end
diff --git a/spec/views/request/_describe_state.rhtml_spec.rb b/spec/views/request/_describe_state.rhtml_spec.rb
index 18778d5d2..41b308d75 100644
--- a/spec/views/request/_describe_state.rhtml_spec.rb
+++ b/spec/views/request/_describe_state.rhtml_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.rhtml_spec.rb
index 94ece5e76..8e34147b5 100644
--- a/spec/views/request/list.rhtml_spec.rb
+++ b/spec/views/request/list.rhtml_spec.rb
@@ -1,14 +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"] = ""
- # we're not testing the interlock plugin's cache
- template.stub!(:view_cache).and_yield
+ assign :page, 1
+ assign :per_page, 10
end
def make_mock_event
@@ -31,22 +27,22 @@ 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)
+ it "should be successful", :focus => true do
+ 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.rhtml_spec.rb
index 4429e9e58..6e36a7ab6 100644
--- a/spec/views/request/show.rhtml_spec.rb
+++ b/spec/views/request/show.rhtml_spec.rb
@@ -23,32 +23,32 @@ describe 'when viewing an information request' do
end
def request_page
- assigns[:info_request] = @mock_request
- assigns[:info_request_events] = []
- assigns[:status] = @mock_request.calculate_status
- template.stub!(:render_partial)
+ assign :info_request, @mock_request
+ assign :info_request_events, []
+ assign :status, @mock_request.calculate_status
+ view.stub!(:render_partial)
render 'request/show'
end
it 'should show the sidebar' do
- template.should_receive(:render_partial).with(:partial => 'sidebar', :locals => {})
+ view.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 => {})
+ view.should_receive(:render_partial).with(:partial => 'after_actions', :locals => {})
request_page
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 +61,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 +74,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
@@ -99,7 +99,7 @@ describe 'when viewing an information request' do
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')
+ response.should have_selector("a[href=#{expected_url}]", :content => 'send a follow up message')
end
end
@@ -119,7 +119,7 @@ describe 'when viewing an information request' do
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')
+ 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.rhtml_spec.rb
index 24fb6d75d..0353f25b5 100644
--- a/spec/views/request_game/play.rhtml_spec.rb
+++ b/spec/views/request_game/play.rhtml_spec.rb
@@ -22,10 +22,10 @@ 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