# encoding: UTF-8 # == Schema Information # # Table name: public_bodies # # id :integer not null, primary key # name :text not null # short_name :text default(""), not null # request_email :text not null # version :integer not null # last_edit_editor :string(255) not null # last_edit_comment :text not null # created_at :datetime not null # updated_at :datetime not null # url_name :text not null # home_page :text default(""), not null # notes :text default(""), not null # first_letter :string(255) not null # publication_scheme :text default(""), not null # api_key :string(255) not null # info_requests_count :integer default(0), not null # disclosure_log :text default(""), not null # info_requests_successful_count :integer # info_requests_not_held_count :integer # info_requests_overdue_count :integer # info_requests_visible_classified_count :integer # require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe PublicBody do describe :translations_attributes= do context 'translation_attrs is a Hash' do it 'does not persist translations' do body = FactoryGirl.create(:public_body) body.translations_attributes = { :es => { :locale => 'es', :name => 'El Body' } } expect(PublicBody.find(body.id).translations.size).to eq(1) end it 'creates a new translation' do body = FactoryGirl.create(:public_body) body.translations_attributes = { :es => { :locale => 'es', :name => 'El Body' } } body.save body.reload expect(body.name(:es)).to eq('El Body') end it 'updates an existing translation' do body = FactoryGirl.create(:public_body) body.translations_attributes = { 'es' => { :locale => 'es', :name => 'El Body' } } body.save body.translations_attributes = { 'es' => { :id => body.translation_for(:es).id, :locale => 'es', :name => 'Renamed' } } body.save expect(body.name(:es)).to eq('Renamed') end it 'updates an existing translation and creates a new translation' do body = FactoryGirl.create(:public_body) body.translations.create(:locale => 'es', :name => 'El Body') expect(body.translations.size).to eq(2) body.translations_attributes = { 'es' => { :id => body.translation_for(:es).id, :locale => 'es', :name => 'Renamed' }, 'fr' => { :locale => 'fr', :name => 'Le Body' } } expect(body.translations.size).to eq(3) I18n.with_locale(:es) { expect(body.name).to eq('Renamed') } I18n.with_locale(:fr) { expect(body.name).to eq('Le Body') } end it 'skips empty translations' do body = FactoryGirl.create(:public_body) body.translations.create(:locale => 'es', :name => 'El Body') expect(body.translations.size).to eq(2) body.translations_attributes = { 'es' => { :id => body.translation_for(:es).id, :locale => 'es', :name => 'Renamed' }, 'fr' => { :locale => 'fr' } } expect(body.translations.size).to eq(2) end end end end describe PublicBody, " using tags" do before do @public_body = PublicBody.new(:name => 'Aardvark Monitoring Service', :short_name => 'AMS', :request_email => 'foo@flourish.org', :last_edit_editor => 'test', :last_edit_comment => '') end it 'should correctly convert a tag string into tags' do @public_body.tag_string = 'stilton emmental' @public_body.tag_string.should == 'stilton emmental' @public_body.has_tag?('stilton').should be_true @public_body.has_tag?('emmental').should be_true @public_body.has_tag?('jarlsberg').should be_false end it 'should strip spaces from tag strings' do @public_body.tag_string = ' chesire lancashire' @public_body.tag_string.should == 'chesire lancashire' end it 'should work with other white space, such as tabs and new lines' do @public_body.tag_string = "chesire\n\tlancashire" @public_body.tag_string.should == 'chesire lancashire' end it 'changing tags should remove presence of the old ones' do @public_body.tag_string = 'stilton' @public_body.tag_string.should == 'stilton' @public_body.has_tag?('stilton').should be_true @public_body.has_tag?('jarlsberg').should be_false @public_body.tag_string = 'jarlsberg' @public_body.tag_string.should == 'jarlsberg' @public_body.has_tag?('stilton').should be_false @public_body.has_tag?('jarlsberg').should be_true end it 'should be able to append tags' do @public_body.tag_string.should == '' @public_body.add_tag_if_not_already_present('cheddar') @public_body.tag_string.should == 'cheddar' @public_body.has_tag?('cheddar').should be_true end it 'should ignore repeat tags' do @public_body.tag_string = 'stilton stilton' @public_body.tag_string.should == 'stilton' end end describe PublicBody, " using machine tags" do before do @public_body = PublicBody.new(:name => 'Aardvark Monitoring Service', :short_name => 'AMS', :request_email => 'foo@flourish.org', :last_edit_editor => 'test', :last_edit_comment => '') end it 'should parse machine tags' do @public_body.tag_string = 'wondrous cheese:green' @public_body.tag_string.should == 'wondrous cheese:green' @public_body.has_tag?('cheese:green').should be_false @public_body.has_tag?('cheese').should be_true @public_body.get_tag_values('cheese').should == ['green'] @public_body.get_tag_values('wondrous').should == [] lambda { @public_body.get_tag_values('notthere').should raise_error(PublicBody::TagNotFound) } end it 'should cope with colons in value' do @public_body.tag_string = 'url:http://www.flourish.org' @public_body.tag_string.should == 'url:http://www.flourish.org' @public_body.has_tag?('url').should be_true @public_body.get_tag_values('url').should == ['http://www.flourish.org'] end it 'should allow multiple tags of the same sort' do @public_body.tag_string = 'url:http://www.theyworkforyou.com/ url:http://www.fixmystreet.com/' @public_body.has_tag?('url').should be_true @public_body.get_tag_values('url').should == ['http://www.theyworkforyou.com/', 'http://www.fixmystreet.com/'] end end describe PublicBody, "when finding_by_tags" do before do @geraldine = public_bodies(:geraldine_public_body) @geraldine.tag_string = 'rabbit' @humpadink = public_bodies(:humpadink_public_body) @humpadink.tag_string = 'coney:5678 coney:1234' end it 'should be able to find bodies by string' do found = PublicBody.find_by_tag('rabbit') found.should == [ @geraldine ] end it 'should be able to find when there are multiple tags in one body, without returning duplicates' do found = PublicBody.find_by_tag('coney') found.should == [ @humpadink ] end end describe PublicBody, " when making up the URL name" do before do @public_body = PublicBody.new end it 'should remove spaces, and make lower case' do @public_body.name = 'Some Authority' @public_body.url_name.should == 'some_authority' end it 'should not allow a numeric name' do @public_body.name = '1234' @public_body.url_name.should == 'body' end end describe PublicBody, " when saving" do before do @public_body = PublicBody.new end def set_default_attributes(public_body) public_body.name = "Testing Public Body" public_body.short_name = "TPB" public_body.request_email = "request@localhost" public_body.last_edit_editor = "*test*" public_body.last_edit_comment = "This is a test" end it "should not be valid without setting some parameters" do @public_body.should_not be_valid end it "should not be valid with misformatted request email" do set_default_attributes(@public_body) @public_body.request_email = "requestBOOlocalhost" @public_body.should_not be_valid @public_body.should have(1).errors_on(:request_email) end it "should save" do set_default_attributes(@public_body) @public_body.save! end it "should update first_letter" do set_default_attributes(@public_body) @public_body.first_letter.should be_nil @public_body.save! @public_body.first_letter.should == 'T' end it "should update first letter, even if it's a multibyte character" do pb = PublicBody.new(:name => 'åccents, lower-case', :short_name => 'ALC', :request_email => 'foo@localhost', :last_edit_editor => 'test', :last_edit_comment => '') pb.first_letter.should be_nil pb.save! pb.first_letter.should == 'Å' end it "should not save if the url_name is already taken" do existing = FactoryGirl.create(:public_body) pb = PublicBody.new(existing.attributes) pb.should have(1).errors_on(:url_name) end it "should save the name when renaming an existing public body" do public_body = public_bodies(:geraldine_public_body) public_body.name = "Mark's Public Body" public_body.save! public_body.name.should == "Mark's Public Body" end it 'should update the right translation when in a locale with an underscore' do AlaveteliLocalization.set_locales('he_IL', 'he_IL') public_body = public_bodies(:humpadink_public_body) translation_count = public_body.translations.size public_body.name = 'Renamed' public_body.save! public_body.translations.size.should == translation_count end it 'should not create a new version when nothing has changed' do @public_body.versions.size.should == 0 set_default_attributes(@public_body) @public_body.save! @public_body.versions.size.should == 1 @public_body.save! @public_body.versions.size.should == 1 end it 'should create a new version if something has changed' do @public_body.versions.size.should == 0 set_default_attributes(@public_body) @public_body.save! @public_body.versions.size.should == 1 @public_body.name = 'Test' @public_body.save! @public_body.versions.size.should == 2 end end describe PublicBody, "when searching" do it "should find by existing url name" do body = PublicBody.find_by_url_name_with_historic('dfh') body.id.should == 3 end it "should find by historic url name" do body = PublicBody.find_by_url_name_with_historic('hdink') body.id.should == 3 body.class.to_s.should == 'PublicBody' end it "should cope with not finding any" do body = PublicBody.find_by_url_name_with_historic('idontexist') body.should be_nil end it "should cope with duplicate historic names" do body = PublicBody.find_by_url_name_with_historic('dfh') # create history with short name "mouse" twice in it body.short_name = 'Mouse' body.url_name.should == 'mouse' body.save! body.request_email = 'dummy@localhost' body.save! # but a different name now body.short_name = 'Stilton' body.url_name.should == 'stilton' body.save! # try and find by it body = PublicBody.find_by_url_name_with_historic('mouse') body.id.should == 3 body.class.to_s.should == 'PublicBody' end it "should cope with same url_name across multiple locales" 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 body.save! # now try to retrieve it body = PublicBody.find_by_url_name_with_historic('tgq') body.id.should == public_bodies(:geraldine_public_body).id body.name.should == "El A Geraldine Quango" end end it 'should not raise an error on a name with a single quote in it' do body = PublicBody.find_by_url_name_with_historic("belfast city council'") end end describe PublicBody, "when asked for the internal_admin_body" do before(:each) do # Make sure that there's no internal_admin_body before each of # these tests: PublicBody.connection.delete("DELETE FROM public_bodies WHERE url_name = 'internal_admin_body'") PublicBody.connection.delete("DELETE FROM public_body_translations WHERE url_name = 'internal_admin_body'") end it "should create the internal_admin_body if it didn't exist" do iab = PublicBody.internal_admin_body iab.should_not be_nil end it "should find the internal_admin_body even if the default locale has changed since it was created" do with_default_locale("en") do I18n.with_locale(:en) do iab = PublicBody.internal_admin_body iab.should_not be_nil end end with_default_locale("es") do I18n.with_locale(:es) do iab = PublicBody.internal_admin_body iab.should_not be_nil end end end 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 I18n.with_locale(:es) do PublicBody.internal_admin_body end # second time lambda {PublicBody.internal_admin_body }.should_not raise_error(ActiveRecord::RecordInvalid) end end describe PublicBody, " when loading CSV files" do before(:each) do # InternalBody is created the first time it's accessed, which happens sometimes during imports, # depending on the tag used. By accessing it here before every test, it doesn't disturb our checks later on PublicBody.internal_admin_body end it "should import even if no email is provided" do errors, notes = PublicBody.import_csv("1,aBody", '', 'replace', true, 'someadmin') # true means dry run errors.should == [] notes.size.should == 2 notes[0].should == "line 1: creating new authority 'aBody' (locale: en):\n\t{\"name\":\"aBody\"}" notes[1].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( .+\n)*You may want to delete them manually.\n/ end it "should do a dry run successfully" do original_count = PublicBody.count csv_contents = normalize_string_to_utf8(load_file_fixture("fake-authority-type.csv")) errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', true, 'someadmin') # true means dry run errors.should == [] notes.size.should == 6 notes[0..4].should == [ "line 1: creating new authority 'North West Fake Authority' (locale: en):\n\t\{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\"\}", "line 2: creating new authority 'Scottish Fake Authority' (locale: en):\n\t\{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\"\}", "line 3: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t\{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\"\}", "line 4: creating new authority 'Gobierno de Aragón' (locale: en):\n\t\{\"name\":\"Gobierno de Arag\\u00f3n\",\"request_email\":\"spain_foi@localhost\"}", "line 5: creating new authority 'Nordic æøå' (locale: en):\n\t{\"name\":\"Nordic \\u00e6\\u00f8\\u00e5\",\"request_email\":\"no_foi@localhost\"}" ] notes[5].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( .+\n)*You may want to delete them manually.\n/ PublicBody.count.should == original_count end it "should do full run successfully" do original_count = PublicBody.count csv_contents = normalize_string_to_utf8(load_file_fixture("fake-authority-type.csv")) errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', false, 'someadmin') # false means real run errors.should == [] notes.size.should == 6 notes[0..4].should == [ "line 1: creating new authority 'North West Fake Authority' (locale: en):\n\t\{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\"\}", "line 2: creating new authority 'Scottish Fake Authority' (locale: en):\n\t\{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\"\}", "line 3: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t\{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\"\}", "line 4: creating new authority 'Gobierno de Aragón' (locale: en):\n\t\{\"name\":\"Gobierno de Arag\\u00f3n\",\"request_email\":\"spain_foi@localhost\"}", "line 5: creating new authority 'Nordic æøå' (locale: en):\n\t{\"name\":\"Nordic \\u00e6\\u00f8\\u00e5\",\"request_email\":\"no_foi@localhost\"}" ] notes[5].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( .+\n)*You may want to delete them manually.\n/ PublicBody.count.should == original_count + 5 end it "should do imports without a tag successfully" do original_count = PublicBody.count csv_contents = normalize_string_to_utf8(load_file_fixture("fake-authority-type.csv")) errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', false, 'someadmin') # false means real run errors.should == [] notes.size.should == 6 notes[0..4].should == [ "line 1: creating new authority 'North West Fake Authority' (locale: en):\n\t\{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\"\}", "line 2: creating new authority 'Scottish Fake Authority' (locale: en):\n\t\{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\"\}", "line 3: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t\{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\"\}", "line 4: creating new authority 'Gobierno de Aragón' (locale: en):\n\t\{\"name\":\"Gobierno de Arag\\u00f3n\",\"request_email\":\"spain_foi@localhost\"}", "line 5: creating new authority 'Nordic æøå' (locale: en):\n\t{\"name\":\"Nordic \\u00e6\\u00f8\\u00e5\",\"request_email\":\"no_foi@localhost\"}" ] notes[5].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( .+\n)*You may want to delete them manually.\n/ PublicBody.count.should == original_count + 5 end it "should handle a field list and fields out of order" do original_count = PublicBody.count csv_contents = load_file_fixture("fake-authority-type-with-field-names.csv") errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', true, 'someadmin') # true means dry run errors.should == [] notes.size.should == 4 notes[0..2].should == [ "line 2: creating new authority 'North West Fake Authority' (locale: en):\n\t\{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\",\"home_page\":\"http://northwest.org\"\}", "line 3: creating new authority 'Scottish Fake Authority' (locale: en):\n\t\{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\",\"home_page\":\"http://scottish.org\",\"tag_string\":\"scottish\"\}", "line 4: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t\{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\",\"tag_string\":\"fake aTag\"\}", ] notes[3].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( .+\n)*You may want to delete them manually.\n/ PublicBody.count.should == original_count end it "should import tags successfully when the import tag is not set" do csv_contents = load_file_fixture("fake-authority-type-with-field-names.csv") errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', false, 'someadmin') # false means real run PublicBody.find_by_name('North West Fake Authority').tag_array_for_search.should == [] PublicBody.find_by_name('Scottish Fake Authority').tag_array_for_search.should == ['scottish'] PublicBody.find_by_name('Fake Authority of Northern Ireland').tag_array_for_search.should == ['aTag', 'fake'] # Import again to check the 'add' tag functionality works new_tags_file = load_file_fixture('fake-authority-add-tags.csv') errors, notes = PublicBody.import_csv(new_tags_file, '', 'add', false, 'someadmin') # false means real run # Check tags were added successfully PublicBody.find_by_name('North West Fake Authority').tag_array_for_search.should == ['aTag'] PublicBody.find_by_name('Scottish Fake Authority').tag_array_for_search.should == ['aTag', 'scottish'] PublicBody.find_by_name('Fake Authority of Northern Ireland').tag_array_for_search.should == ['aTag', 'fake'] end it "should import tags successfully when the import tag is set" do csv_contents = load_file_fixture("fake-authority-type-with-field-names.csv") errors, notes = PublicBody.import_csv(csv_contents, 'fake', 'add', false, 'someadmin') # false means real run # Check new bodies were imported successfully PublicBody.find_by_name('North West Fake Authority').tag_array_for_search.should == ['fake'] PublicBody.find_by_name('Scottish Fake Authority').tag_array_for_search.should == ['fake', 'scottish'] PublicBody.find_by_name('Fake Authority of Northern Ireland').tag_array_for_search.should == ['aTag', 'fake'] # Import again to check the 'replace' tag functionality works new_tags_file = load_file_fixture('fake-authority-add-tags.csv') errors, notes = PublicBody.import_csv(new_tags_file, 'fake', 'replace', false, 'someadmin') # false means real run # Check tags were added successfully PublicBody.find_by_name('North West Fake Authority').tag_array_for_search.should == ['aTag', 'fake'] PublicBody.find_by_name('Scottish Fake Authority').tag_array_for_search.should == ['aTag', 'fake'] PublicBody.find_by_name('Fake Authority of Northern Ireland').tag_array_for_search.should == ['aTag', 'fake'] end context 'when the import tag is set' do context 'with a new body' do it 'appends the import tag when no tag_string is specified' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page ,q@localhost,Quango,,http://example.org CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, 'imported', 'add', false, 'someadmin') expected = %W(imported) expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) end it 'appends the import tag when a tag_string is specified' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page ,q@localhost,Quango,first_tag second_tag,http://example.org CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, 'imported', 'add', false, 'someadmin') expected = %W(first_tag imported second_tag) expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) end it 'replaces with the import tag when no tag_string is specified' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page ,q@localhost,Quango,,http://example.org CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, 'imported', 'replace', false, 'someadmin') expected = %W(imported) expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) end it 'replaces with the import tag and tag_string when a tag_string is specified' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page ,q@localhost,Quango,first_tag second_tag,http://example.org CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, 'imported', 'replace', false, 'someadmin') expected = %W(first_tag imported second_tag) expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) end end context 'an existing body without tags' do before do @body = FactoryGirl.create(:public_body, :name => 'Existing Body') end it 'will not import if there is an existing body without the tag' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page #{ @body.id },#{ @body.request_email },"#{ @body.name }",,#{ @body.home_page } CSV # csv, tag, tag_behaviour, dry_run, editor errors, notes = PublicBody.import_csv(csv, 'imported', 'add', false, 'someadmin') expected = %W(imported) errors.should include("error: line 2: Name Name is already taken for authority 'Existing Body'") end end context 'an existing body with tags' do before do @body = FactoryGirl.create(:public_body, :tag_string => 'imported first_tag second_tag') end it 'created with tags, different tags in csv, add import tag' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page #{ @body.id },#{ @body.request_email },"#{ @body.name }","first_tag new_tag",#{ @body.home_page } CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, 'imported', 'add', false, 'someadmin') expected = %W(first_tag imported new_tag second_tag) expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) end it 'created with tags, different tags in csv, replace import tag' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page #{ @body.id },#{ @body.request_email },"#{ @body.name }","first_tag new_tag",#{ @body.home_page } CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, 'imported', 'replace', false, 'someadmin') expected = %W(first_tag imported new_tag) expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) end end end context 'when the import tag is not set' do context 'with a new body' do it 'it is empty if no tag_string is set' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page ,q@localhost,Quango,,http://example.org CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'add', false, 'someadmin') expected = [] expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) end it 'uses the specified tag_string' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page ,q@localhost,Quango,first_tag,http://example.org CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'add', false, 'someadmin') expected = %W(first_tag) expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) end it 'replaces with empty if no tag_string is set' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page ,q@localhost,Quango,,http://example.org CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') expected = [] expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) end it 'replaces with the specified tag_string' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page ,q@localhost,Quango,first_tag,http://example.org CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') expected = %W(first_tag) expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) end end context 'with an existing body without tags' do before do @body = FactoryGirl.create(:public_body) end it 'appends when no tag_string is specified' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page #{ @body.id },#{ @body.request_email },"#{ @body.name }",,#{ @body.home_page } CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'add', false, 'someadmin') expected = [] expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) end it 'appends when a tag_string is specified' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page #{ @body.id },#{ @body.request_email },"#{ @body.name }",new_tag,#{ @body.home_page } CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'add', false, 'someadmin') expected = %W(new_tag) expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) end it 'replaces when no tag_string is specified' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page #{ @body.id },#{ @body.request_email },"#{ @body.name }",,#{ @body.home_page } CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') expected = [] expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) end it 'replaces when a tag_string is specified' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page #{ @body.id },#{ @body.request_email },"#{ @body.name }",new_tag,#{ @body.home_page } CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') expected = %W(new_tag) expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) end end describe 'with an existing body with tags' do before do @body = FactoryGirl.create(:public_body, :tag_string => 'first_tag second_tag') end it 'created with tags, different tags in csv, add tags' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page #{ @body.id },#{ @body.request_email },"#{ @body.name }","first_tag new_tag",#{ @body.home_page } CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'add', false, 'someadmin') expected = %W(first_tag new_tag second_tag) expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) end it 'created with tags, different tags in csv, replace' do csv = <<-CSV.strip_heredoc #id,request_email,name,tag_string,home_page #{ @body.id },#{ @body.request_email },"#{ @body.name }","first_tag new_tag",#{ @body.home_page } CSV # csv, tag, tag_behaviour, dry_run, editor PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') expected = %W(first_tag new_tag) expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) end end end it "should create bodies with names in multiple locales" do original_count = PublicBody.count csv_contents = load_file_fixture("fake-authority-type-with-field-names.csv") errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', false, 'someadmin', [:en, :es]) errors.should == [] notes.size.should == 7 notes[0..5].should == [ "line 2: creating new authority 'North West Fake Authority' (locale: en):\n\t{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\",\"home_page\":\"http://northwest.org\"}", "line 2: creating new authority 'North West Fake Authority' (locale: es):\n\t{\"name\":\"Autoridad del Nordeste\"}", "line 3: creating new authority 'Scottish Fake Authority' (locale: en):\n\t{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\",\"home_page\":\"http://scottish.org\",\"tag_string\":\"scottish\"}", "line 3: creating new authority 'Scottish Fake Authority' (locale: es):\n\t{\"name\":\"Autoridad Escocesa\"}", "line 4: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\",\"tag_string\":\"fake aTag\"}", "line 4: creating new authority 'Fake Authority of Northern Ireland' (locale: es):\n\t{\"name\":\"Autoridad Irlandesa\"}", ] notes[6].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( .+\n)*You may want to delete them manually.\n/ PublicBody.count.should == original_count + 3 # TODO: Not sure why trying to do a I18n.with_locale fails here. Seems related to # the way categories are loaded every time from the PublicBody class. For now we just # test some translation was done. body = PublicBody.find_by_name('North West Fake Authority') body.translated_locales.map{|l|l.to_s}.sort.should == ["en", "es"] end it "should not fail if a locale is not found in the input file" do original_count = PublicBody.count csv_contents = load_file_fixture("fake-authority-type-with-field-names.csv") # Depending on the runtime environment (Ruby version? OS?) the list of available locales # is made of strings or symbols, so we use 'en' here as a string to test both scenarios. # See https://github.com/mysociety/alaveteli/issues/193 errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', true, 'someadmin', ['en', :xx]) # true means dry run errors.should == [] notes.size.should == 4 notes[0..2].should == [ "line 2: creating new authority 'North West Fake Authority' (locale: en):\n\t{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\",\"home_page\":\"http://northwest.org\"}", "line 3: creating new authority 'Scottish Fake Authority' (locale: en):\n\t{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\",\"home_page\":\"http://scottish.org\",\"tag_string\":\"scottish\"}", "line 4: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\",\"tag_string\":\"fake aTag\"}", ] notes[3].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( .+\n)*You may want to delete them manually.\n/ PublicBody.count.should == original_count end it "should be able to load CSV from a file as well as a string" do # Essentially the same code is used for import_csv_from_file # as import_csv, so this is just a basic check that # import_csv_from_file can load from a file at all. (It would # be easy to introduce a regression that broke this, because # of the confusing change in behaviour of CSV.parse between # Ruby 1.8 and 1.9.) original_count = PublicBody.count filename = file_fixture_name('fake-authority-type-with-field-names.csv') PublicBody.import_csv_from_file(filename, '', 'replace', false, 'someadmin') PublicBody.count.should == original_count + 3 end it "should handle active record validation errors" do csv = <<-CSV #name,request_email,short_name Foobar,a@example.com,foobar Foobar Test,b@example.com,foobar CSV csv_contents = normalize_string_to_utf8(csv) errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', true, 'someadmin') # true means dry run errors.should include("error: line 3: Url name URL name is already taken for authority 'Foobar Test'") end it 'has a default list of fields to import' do expected_fields = [ ['name', '(i18n)Existing records cannot be renamed'], ['short_name', '(i18n)'], ['request_email', '(i18n)'], ['notes', '(i18n)'], ['publication_scheme', '(i18n)'], ['disclosure_log', '(i18n)'], ['home_page', ''], ['tag_string', '(tags separated by spaces)'], ] expect(PublicBody.csv_import_fields).to eq(expected_fields) end it 'allows you to override the default list of fields to import' do old_csv_import_fields = PublicBody.csv_import_fields.clone expected_fields = [ ['name', '(i18n)Existing records cannot be renamed'], ['short_name', '(i18n)'], ] PublicBody.csv_import_fields = expected_fields expect(PublicBody.csv_import_fields).to eq(expected_fields) # Reset our change so that we don't affect other specs PublicBody.csv_import_fields = old_csv_import_fields end it 'allows you to append to the default list of fields to import' do old_csv_import_fields = PublicBody.csv_import_fields.clone expected_fields = [ ['name', '(i18n)Existing records cannot be renamed'], ['short_name', '(i18n)'], ['request_email', '(i18n)'], ['notes', '(i18n)'], ['publication_scheme', '(i18n)'], ['disclosure_log', '(i18n)'], ['home_page', ''], ['tag_string', '(tags separated by spaces)'], ['a_new_field', ''], ] PublicBody.csv_import_fields << ['a_new_field', ''] expect(PublicBody.csv_import_fields).to eq(expected_fields) # Reset our change so that we don't affect other specs PublicBody.csv_import_fields = old_csv_import_fields end it "should import translations for fields whose values are the same as the default locale's" do original_count = PublicBody.count csv_contents = load_file_fixture("multiple-locales-same-name.csv") errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', true, 'someadmin', ['en', 'es']) # true means dry run errors.should == [] notes.size.should == 3 notes[0..1].should == [ "line 2: creating new authority 'Test' (locale: en):\n\t{\"name\":\"Test\",\"request_email\":\"test@test.es\",\"home_page\":\"http://www.test.es/\",\"tag_string\":\"37\"}", "line 2: creating new authority 'Test' (locale: es):\n\t{\"name\":\"Test\"}", ] notes[2].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( .+\n)*You may want to delete them manually.\n/ PublicBody.count.should == original_count end end describe PublicBody do describe "calculated home page" do it "should return the home page verbatim if it's present" do public_body = PublicBody.new public_body.home_page = "http://www.example.com" public_body.calculated_home_page.should == "http://www.example.com" end it "should return the home page based on the request email domain if it has one" do public_body = PublicBody.new public_body.stub!(:request_email_domain).and_return "public-authority.com" public_body.calculated_home_page.should == "http://www.public-authority.com" end it "should return nil if there's no home page and the email domain can't be worked out" do public_body = PublicBody.new public_body.stub!(:request_email_domain).and_return nil public_body.calculated_home_page.should be_nil end it "should ensure home page URLs start with http://" do public_body = PublicBody.new public_body.home_page = "example.com" public_body.calculated_home_page.should == "http://example.com" end it "should not add http when https is present" do public_body = PublicBody.new public_body.home_page = "https://example.com" public_body.calculated_home_page.should == "https://example.com" end end describe 'when asked for notes without html' do before do @public_body = PublicBody.new(:notes => 'some notes') end it 'should remove simple tags from notes' do @public_body.notes_without_html.should == 'some notes' end end describe :site_administration? do it 'is true when the body has the site_administration tag' do p = FactoryGirl.build(:public_body, :tag_string => 'site_administration') p.site_administration?.should be_true end it 'is false when the body does not have the site_administration tag' do p = FactoryGirl.build(:public_body) p.site_administration?.should be_false end end describe :has_request_email? do before do @body = PublicBody.new(:request_email => 'test@example.com') end it 'should return false if request_email is nil' do @body.request_email = nil @body.has_request_email?.should == false end it 'should return false if the request email is "blank"' do @body.request_email = 'blank' @body.has_request_email?.should == false end it 'should return false if the request email is an empty string' do @body.request_email = '' @body.has_request_email?.should == false end it 'should return true if the request email is an email address' do @body.has_request_email?.should == true end end describe :special_not_requestable_reason do before do @body = PublicBody.new end it 'should return true if the body is defunct' do @body.stub!(:defunct?).and_return(true) @body.special_not_requestable_reason?.should == true end it 'should return true if FOI does not apply' do @body.stub!(:not_apply?).and_return(true) @body.special_not_requestable_reason?.should == true end it 'should return false if the body is not defunct and FOI applies' do @body.special_not_requestable_reason?.should == false end end end describe PublicBody, " when override all public body request emails set" do it "should return the overridden request email" do AlaveteliConfiguration.should_receive(:override_all_public_body_request_emails).twice.and_return("catch_all_test_email@foo.com") @geraldine = public_bodies(:geraldine_public_body) @geraldine.request_email.should == "catch_all_test_email@foo.com" end end describe PublicBody, "when calculating statistics" do it "should not include unclassified or hidden requests in percentages" do with_hidden_and_successful_requests do totals_data = PublicBody.get_request_totals(n=3, highest=true, minimum_requests=1) # For the total number of requests, we still include # hidden or unclassified requests: totals_data['public_bodies'][-1].name.should == "Geraldine Quango" totals_data['totals'][-1].should == 4 # However, for percentages, don't include the hidden or # unclassified requests. So, for the Geraldine Quango # we've made sure that there are only two visible and # classified requests, one of which is successful, so the # percentage should be 50%: percentages_data = PublicBody.get_request_percentages(column='info_requests_successful_count', n=3, highest=false, minimum_requests=1) geraldine_index = percentages_data['public_bodies'].index do |pb| pb.name == "Geraldine Quango" end percentages_data['y_values'][geraldine_index].should == 50 end end it "should only return totals for those with at least a minimum number of requests" do minimum_requests = 1 with_enough_info_requests = PublicBody.where(["info_requests_count >= ?", minimum_requests]).length all_data = PublicBody.get_request_totals 4, true, minimum_requests all_data['public_bodies'].length.should == with_enough_info_requests end it "should only return percentages for those with at least a minimum number of requests" do with_hidden_and_successful_requests do # With minimum requests at 3, this should return nil # (corresponding to zero public bodies) since the only # public body with just more than 3 info requests (The # Geraldine Quango) has a hidden and an unclassified # request within this block: minimum_requests = 3 with_enough_info_requests = PublicBody.where(["info_requests_visible_classified_count >= ?", minimum_requests]).length all_data = PublicBody.get_request_percentages(column='info_requests_successful_count', n=10, true, minimum_requests) all_data.should be_nil end end it "should only return those with at least a minimum number of requests, but not tagged 'test'" do hpb = PublicBody.find_by_name 'Department for Humpadinking' original_tag_string = hpb.tag_string hpb.add_tag_if_not_already_present 'test' begin minimum_requests = 1 with_enough_info_requests = PublicBody.where(["info_requests_count >= ?", minimum_requests]) all_data = PublicBody.get_request_totals 4, true, minimum_requests all_data['public_bodies'].length.should == 3 ensure hpb.tag_string = original_tag_string end end end describe PublicBody, 'when asked for popular bodies' do it 'should return bodies correctly when passed the hyphenated version of the locale' do AlaveteliConfiguration.stub!(:frontpage_publicbody_examples).and_return('') PublicBody.popular_bodies('he-IL').should == [public_bodies(:humpadink_public_body)] end end describe PublicBody do describe :is_requestable? do before do @body = PublicBody.new(:request_email => 'test@example.com') end it 'should return false if the body is defunct' do @body.stub!(:defunct?).and_return true @body.is_requestable?.should == false end it 'should return false if FOI does not apply' do @body.stub!(:not_apply?).and_return true @body.is_requestable?.should == false end it 'should return false there is no request_email' do @body.stub!(:has_request_email?).and_return false @body.is_requestable?.should == false end it 'should return true if the request email is an email address' do @body.is_requestable?.should == true end end describe :is_followupable? do before do @body = PublicBody.new(:request_email => 'test@example.com') end it 'should return false there is no request_email' do @body.stub!(:has_request_email?).and_return false @body.is_followupable?.should == false end it 'should return true if the request email is an email address' do @body.is_followupable?.should == true end end describe :not_requestable_reason do before do @body = PublicBody.new(:request_email => 'test@example.com') end it 'should return "defunct" if the body is defunct' do @body.stub!(:defunct?).and_return true @body.not_requestable_reason.should == 'defunct' end it 'should return "not_apply" if FOI does not apply' do @body.stub!(:not_apply?).and_return true @body.not_requestable_reason.should == 'not_apply' end it 'should return "bad_contact" there is no request_email' do @body.stub!(:has_request_email?).and_return false @body.not_requestable_reason.should == 'bad_contact' end it 'should raise an error if the body is not defunct, FOI applies and has an email address' do expected_error = "not_requestable_reason called with type that has no reason" lambda{ @body.not_requestable_reason }.should raise_error(expected_error) end end end describe PublicBody::Translation do it 'requires a locale' do translation = PublicBody::Translation.new translation.valid? expect(translation.errors[:locale]).to eq(["can't be blank"]) end it 'is valid if all required attributes are assigned' do translation = PublicBody::Translation.new(:locale => I18n.default_locale) expect(translation).to be_valid end end