Redmine 3.4.4

This commit is contained in:
Manuel Cillero 2018-02-02 22:19:29 +01:00
commit 64924a6376
2112 changed files with 259028 additions and 0 deletions

View file

@ -0,0 +1,192 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class AccountControllerOpenidTest < Redmine::ControllerTest
tests AccountController
fixtures :users, :roles
def setup
User.current = nil
Setting.openid = '1'
end
def teardown
Setting.openid = '0'
end
if Object.const_defined?(:OpenID)
def test_login_with_openid_for_existing_user
Setting.self_registration = '3'
existing_user = User.new(:firstname => 'Cool',
:lastname => 'User',
:mail => 'user@somedomain.com',
:identity_url => 'http://openid.example.com/good_user')
existing_user.login = 'cool_user'
assert existing_user.save!
post :login, :params => {
:openid_url => existing_user.identity_url
}
assert_redirected_to '/my/page'
end
def test_login_with_invalid_openid_provider
Setting.self_registration = '0'
post :login, :params => {
:openid_url => 'http;//openid.example.com/good_user'
}
assert_redirected_to home_url
end
def test_login_with_openid_for_existing_non_active_user
Setting.self_registration = '2'
existing_user = User.new(:firstname => 'Cool',
:lastname => 'User',
:mail => 'user@somedomain.com',
:identity_url => 'http://openid.example.com/good_user',
:status => User::STATUS_REGISTERED)
existing_user.login = 'cool_user'
assert existing_user.save!
post :login, :params => {
:openid_url => existing_user.identity_url
}
assert_redirected_to '/login'
end
def test_login_with_openid_with_new_user_created
Setting.self_registration = '3'
post :login, :params => {
:openid_url => 'http://openid.example.com/good_user'
}
assert_redirected_to '/my/account'
user = User.find_by_login('cool_user')
assert user
assert_equal 'Cool', user.firstname
assert_equal 'User', user.lastname
end
def test_login_with_openid_with_new_user_and_self_registration_off
Setting.self_registration = '0'
post :login, :params => {
:openid_url => 'http://openid.example.com/good_user'
}
assert_redirected_to home_url
user = User.find_by_login('cool_user')
assert_nil user
end
def test_login_with_openid_with_new_user_created_with_email_activation_should_have_a_token
Setting.self_registration = '1'
post :login, :params => {
:openid_url => 'http://openid.example.com/good_user'
}
assert_redirected_to '/login'
user = User.find_by_login('cool_user')
assert user
token = Token.find_by_user_id_and_action(user.id, 'register')
assert token
end
def test_login_with_openid_with_new_user_created_with_manual_activation
Setting.self_registration = '2'
post :login, :params => {
:openid_url => 'http://openid.example.com/good_user'
}
assert_redirected_to '/login'
user = User.find_by_login('cool_user')
assert user
assert_equal User::STATUS_REGISTERED, user.status
end
def test_login_with_openid_with_new_user_with_conflict_should_register
Setting.self_registration = '3'
existing_user = User.new(:firstname => 'Cool', :lastname => 'User', :mail => 'user@somedomain.com')
existing_user.login = 'cool_user'
assert existing_user.save!
post :login, :params => {
:openid_url => 'http://openid.example.com/good_user'
}
assert_response :success
assert_select 'input[name=?][value=?]', 'user[identity_url]', 'http://openid.example.com/good_user'
end
def test_login_with_openid_with_new_user_with_missing_information_should_register
Setting.self_registration = '3'
post :login, :params => {
:openid_url => 'http://openid.example.com/good_blank_user'
}
assert_response :success
assert_select 'input[name=?]', 'user[login]'
assert_select 'input[name=?]', 'user[password]'
assert_select 'input[name=?]', 'user[password_confirmation]'
assert_select 'input[name=?][value=?]', 'user[identity_url]', 'http://openid.example.com/good_blank_user'
end
def test_post_login_should_not_verify_token_when_using_open_id
ActionController::Base.allow_forgery_protection = true
AccountController.any_instance.stubs(:using_open_id?).returns(true)
AccountController.any_instance.stubs(:authenticate_with_open_id).returns(true)
post :login
assert_response 200
ensure
ActionController::Base.allow_forgery_protection = false
end
def test_register_after_login_failure_should_not_require_user_to_enter_a_password
Setting.self_registration = '3'
assert_difference 'User.count' do
post :register, :params => {
:user => {
:login => 'good_blank_user',
:password => '',
:password_confirmation => '',
:firstname => 'Cool',
:lastname => 'User',
:mail => 'user@somedomain.com',
:identity_url => 'http://openid.example.com/good_blank_user'
}
}
assert_response 302
end
user = User.order('id DESC').first
assert_equal 'http://openid.example.com/good_blank_user', user.identity_url
assert user.hashed_password.blank?, "Hashed password was #{user.hashed_password}"
end
def test_setting_openid_should_return_true_when_set_to_true
assert_equal true, Setting.openid?
end
else
puts "Skipping openid tests."
def test_dummy
end
end
end

View file

@ -0,0 +1,607 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class AccountControllerTest < Redmine::ControllerTest
fixtures :users, :email_addresses, :roles
def setup
User.current = nil
end
def test_get_login
get :login
assert_response :success
assert_select 'input[name=username]'
assert_select 'input[name=password]'
end
def test_get_login_while_logged_in_should_redirect_to_back_url_if_present
@request.session[:user_id] = 2
@request.env["HTTP_REFERER"] = 'http://test.host/issues/show/1'
get :login, :params => {
:back_url => 'http://test.host/issues/show/1'
}
assert_redirected_to '/issues/show/1'
assert_equal 2, @request.session[:user_id]
end
def test_get_login_while_logged_in_should_redirect_to_referer_without_back_url
@request.session[:user_id] = 2
@request.env["HTTP_REFERER"] = 'http://test.host/issues/show/1'
get :login
assert_redirected_to '/issues/show/1'
assert_equal 2, @request.session[:user_id]
end
def test_get_login_while_logged_in_should_redirect_to_home_by_default
@request.session[:user_id] = 2
get :login
assert_redirected_to '/'
assert_equal 2, @request.session[:user_id]
end
def test_login_should_redirect_to_back_url_param
# request.uri is "test.host" in test environment
back_urls = [
'http://test.host/issues/show/1',
'http://test.host/',
'/'
]
back_urls.each do |back_url|
post :login, :params => {
:username => 'jsmith',
:password => 'jsmith',
:back_url => back_url
}
assert_redirected_to back_url
end
end
def test_login_with_suburi_should_redirect_to_back_url_param
@relative_url_root = Redmine::Utils.relative_url_root
Redmine::Utils.relative_url_root = '/redmine'
back_urls = [
'http://test.host/redmine/issues/show/1',
'/redmine'
]
back_urls.each do |back_url|
post :login, :params => {
:username => 'jsmith',
:password => 'jsmith',
:back_url => back_url
}
assert_redirected_to back_url
end
ensure
Redmine::Utils.relative_url_root = @relative_url_root
end
def test_login_should_not_redirect_to_another_host
back_urls = [
'http://test.foo/fake',
'//test.foo/fake'
]
back_urls.each do |back_url|
post :login, :params => {
:username => 'jsmith',
:password => 'jsmith',
:back_url => back_url
}
assert_redirected_to '/my/page'
end
end
def test_login_with_suburi_should_not_redirect_to_another_suburi
@relative_url_root = Redmine::Utils.relative_url_root
Redmine::Utils.relative_url_root = '/redmine'
back_urls = [
'http://test.host/',
'http://test.host/fake',
'http://test.host/fake/issues',
'http://test.host/redmine/../fake',
'http://test.host/redmine/../fake/issues',
'http://test.host/redmine/%2e%2e/fake',
'//test.foo/fake',
'http://test.host//fake',
'http://test.host/\n//fake',
'//bar@test.foo',
'//test.foo',
'////test.foo',
'@test.foo',
'fake@test.foo',
'.test.foo'
]
back_urls.each do |back_url|
post :login, :params => {
:username => 'jsmith',
:password => 'jsmith',
:back_url => back_url
}
assert_redirected_to '/my/page'
end
ensure
Redmine::Utils.relative_url_root = @relative_url_root
end
def test_login_with_wrong_password
post :login, :params => {
:username => 'admin',
:password => 'bad'
}
assert_response :success
assert_select 'div.flash.error', :text => /Invalid user or password/
assert_select 'input[name=username][value=admin]'
assert_select 'input[name=password]'
assert_select 'input[name=password][value]', 0
end
def test_login_with_locked_account_should_fail
User.find(2).update_attribute :status, User::STATUS_LOCKED
post :login, :params => {
:username => 'jsmith',
:password => 'jsmith'
}
assert_redirected_to '/login'
assert_include 'locked', flash[:error]
assert_nil @request.session[:user_id]
end
def test_login_as_registered_user_with_manual_activation_should_inform_user
User.find(2).update_attribute :status, User::STATUS_REGISTERED
with_settings :self_registration => '2', :default_language => 'en' do
post :login, :params => {
:username => 'jsmith',
:password => 'jsmith'
}
assert_redirected_to '/login'
assert_include 'pending administrator approval', flash[:error]
end
end
def test_login_as_registered_user_with_email_activation_should_propose_new_activation_email
User.find(2).update_attribute :status, User::STATUS_REGISTERED
with_settings :self_registration => '1', :default_language => 'en' do
post :login, :params => {
:username => 'jsmith',
:password => 'jsmith'
}
assert_redirected_to '/login'
assert_equal 2, @request.session[:registered_user_id]
assert_include 'new activation email', flash[:error]
end
end
def test_login_should_rescue_auth_source_exception
source = AuthSource.create!(:name => 'Test')
User.find(2).update_attribute :auth_source_id, source.id
AuthSource.any_instance.stubs(:authenticate).raises(AuthSourceException.new("Something wrong"))
post :login, :params => {
:username => 'jsmith',
:password => 'jsmith'
}
assert_response 500
assert_select_error /Something wrong/
end
def test_login_should_reset_session
@controller.expects(:reset_session).once
post :login, :params => {
:username => 'jsmith',
:password => 'jsmith'
}
assert_response 302
end
def test_login_should_strip_whitespaces_from_user_name
post :login, :params => {
:username => ' jsmith ',
:password => 'jsmith'
}
assert_response 302
assert_equal 2, @request.session[:user_id]
end
def test_get_logout_should_not_logout
@request.session[:user_id] = 2
get :logout
assert_response :success
assert_equal 2, @request.session[:user_id]
end
def test_get_logout_with_anonymous_should_redirect
get :logout
assert_redirected_to '/'
end
def test_logout
@request.session[:user_id] = 2
post :logout
assert_redirected_to '/'
assert_nil @request.session[:user_id]
end
def test_logout_should_reset_session
@controller.expects(:reset_session).once
@request.session[:user_id] = 2
post :logout
assert_response 302
end
def test_get_register_with_registration_on
with_settings :self_registration => '3' do
get :register
assert_response :success
assert_select 'input[name=?]', 'user[password]'
assert_select 'input[name=?]', 'user[password_confirmation]'
end
end
def test_get_register_should_detect_user_language
with_settings :self_registration => '3' do
@request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'
get :register
assert_response :success
assert_select 'select[name=?]', 'user[language]' do
assert_select 'option[value=fr][selected=selected]'
end
end
end
def test_get_register_with_registration_off_should_redirect
with_settings :self_registration => '0' do
get :register
assert_redirected_to '/'
end
end
def test_get_register_should_show_hide_mail_preference
get :register
assert_select 'input[name=?][checked=checked]', 'pref[hide_mail]'
end
def test_get_register_should_show_hide_mail_preference_with_setting_turned_off
with_settings :default_users_hide_mail => '0' do
get :register
assert_select 'input[name=?]:not([checked=checked])', 'pref[hide_mail]'
end
end
# See integration/account_test.rb for the full test
def test_post_register_with_registration_on
with_settings :self_registration => '3' do
assert_difference 'User.count' do
post :register, :params => {
:user => {
:login => 'register',
:password => 'secret123',
:password_confirmation => 'secret123',
:firstname => 'John',
:lastname => 'Doe',
:mail => 'register@example.com'
}
}
assert_redirected_to '/my/account'
end
user = User.order('id DESC').first
assert_equal 'register', user.login
assert_equal 'John', user.firstname
assert_equal 'Doe', user.lastname
assert_equal 'register@example.com', user.mail
assert user.check_password?('secret123')
assert user.active?
end
end
def test_post_register_with_registration_off_should_redirect
with_settings :self_registration => '0' do
assert_no_difference 'User.count' do
post :register, :params => {
:user => {
:login => 'register',
:password => 'test',
:password_confirmation => 'test',
:firstname => 'John',
:lastname => 'Doe',
:mail => 'register@example.com'
}
}
assert_redirected_to '/'
end
end
end
def test_post_register_should_create_user_with_hide_mail_preference
with_settings :default_users_hide_mail => '0' do
user = new_record(User) do
post :register, :params => {
:user => {
:login => 'register',
:password => 'secret123',
:password_confirmation => 'secret123',
:firstname => 'John',
:lastname => 'Doe',
:mail => 'register@example.com'
},
:pref => {
:hide_mail => '1'
}
}
end
assert_equal true, user.pref.hide_mail
end
end
def test_get_lost_password_should_display_lost_password_form
get :lost_password
assert_response :success
assert_select 'input[name=mail]'
end
def test_lost_password_for_active_user_should_create_a_token
Token.delete_all
ActionMailer::Base.deliveries.clear
assert_difference 'ActionMailer::Base.deliveries.size' do
assert_difference 'Token.count' do
post :lost_password, :params => {
:mail => 'JSmith@somenet.foo'
}
assert_redirected_to '/login'
end
end
token = Token.order('id DESC').first
assert_equal User.find(2), token.user
assert_equal 'recovery', token.action
assert_select_email do
assert_select "a[href=?]", "http://localhost:3000/account/lost_password?token=#{token.value}"
end
end
def test_lost_password_with_whitespace_should_send_email_to_the_address
Token.delete_all
assert_difference 'ActionMailer::Base.deliveries.size' do
assert_difference 'Token.count' do
post :lost_password, params: {
mail: ' JSmith@somenet.foo '
}
assert_redirected_to '/login'
end
end
mail = ActionMailer::Base.deliveries.last
assert_equal ['jsmith@somenet.foo'], mail.bcc
end
def test_lost_password_using_additional_email_address_should_send_email_to_the_address
EmailAddress.create!(:user_id => 2, :address => 'anotherAddress@foo.bar')
Token.delete_all
assert_difference 'ActionMailer::Base.deliveries.size' do
assert_difference 'Token.count' do
post :lost_password, :params => {
:mail => 'ANOTHERaddress@foo.bar'
}
assert_redirected_to '/login'
end
end
mail = ActionMailer::Base.deliveries.last
assert_equal ['anotherAddress@foo.bar'], mail.bcc
end
def test_lost_password_for_unknown_user_should_fail
Token.delete_all
assert_no_difference 'Token.count' do
post :lost_password, :params => {
:mail => 'invalid@somenet.foo'
}
assert_response :success
end
end
def test_lost_password_for_non_active_user_should_fail
Token.delete_all
assert User.find(2).lock!
assert_no_difference 'Token.count' do
post :lost_password, :params => {
:mail => 'JSmith@somenet.foo'
}
assert_redirected_to '/account/lost_password'
end
end
def test_lost_password_for_user_who_cannot_change_password_should_fail
User.any_instance.stubs(:change_password_allowed?).returns(false)
assert_no_difference 'Token.count' do
post :lost_password, :params => {
:mail => 'JSmith@somenet.foo'
}
assert_response :success
end
end
def test_get_lost_password_with_token_should_redirect_with_token_in_session
user = User.find(2)
token = Token.create!(:action => 'recovery', :user => user)
get :lost_password, :params => {
:token => token.value
}
assert_redirected_to '/account/lost_password'
assert_equal token.value, request.session[:password_recovery_token]
end
def test_get_lost_password_with_token_in_session_should_display_the_password_recovery_form
user = User.find(2)
token = Token.create!(:action => 'recovery', :user => user)
request.session[:password_recovery_token] = token.value
get :lost_password
assert_response :success
assert_select 'input[type=hidden][name=token][value=?]', token.value
end
def test_get_lost_password_with_invalid_token_should_redirect
get :lost_password, :params => {
:token => "abcdef"
}
assert_redirected_to '/'
end
def test_post_lost_password_with_token_should_change_the_user_password
ActionMailer::Base.deliveries.clear
user = User.find(2)
token = Token.create!(:action => 'recovery', :user => user)
post :lost_password, :params => {
:token => token.value,
:new_password => 'newpass123',
:new_password_confirmation => 'newpass123'
}
assert_redirected_to '/login'
user.reload
assert user.check_password?('newpass123')
assert_nil Token.find_by_id(token.id), "Token was not deleted"
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_select_email do
assert_select 'a[href^=?]', 'http://localhost:3000/my/password', :text => 'Change password'
end
end
def test_post_lost_password_with_token_for_non_active_user_should_fail
user = User.find(2)
token = Token.create!(:action => 'recovery', :user => user)
user.lock!
post :lost_password, :params => {
:token => token.value,
:new_password => 'newpass123',
:new_password_confirmation => 'newpass123'
}
assert_redirected_to '/'
assert ! user.check_password?('newpass123')
end
def test_post_lost_password_with_token_and_password_confirmation_failure_should_redisplay_the_form
user = User.find(2)
token = Token.create!(:action => 'recovery', :user => user)
post :lost_password, :params => {
:token => token.value,
:new_password => 'newpass',
:new_password_confirmation => 'wrongpass'
}
assert_response :success
assert_not_nil Token.find_by_id(token.id), "Token was deleted"
assert_select 'input[type=hidden][name=token][value=?]', token.value
end
def test_post_lost_password_with_token_should_not_accept_same_password_if_user_must_change_password
user = User.find(2)
user.password = "originalpassword"
user.must_change_passwd = true
user.save!
token = Token.create!(:action => 'recovery', :user => user)
post :lost_password, :params => {
:token => token.value,
:new_password => 'originalpassword',
:new_password_confirmation => 'originalpassword'
}
assert_response :success
assert_not_nil Token.find_by_id(token.id), "Token was deleted"
assert_select '.flash', :text => /The new password must be different/
assert_select 'input[type=hidden][name=token][value=?]', token.value
end
def test_post_lost_password_with_token_should_reset_must_change_password
user = User.find(2)
user.password = "originalpassword"
user.must_change_passwd = true
user.save!
token = Token.create!(:action => 'recovery', :user => user)
post :lost_password, :params => {
:token => token.value,
:new_password => 'newpassword',
:new_password_confirmation => 'newpassword'
}
assert_redirected_to '/login'
assert_equal false, user.reload.must_change_passwd
end
def test_post_lost_password_with_invalid_token_should_redirect
post :lost_password, :params => {
:token => "abcdef",
:new_password => 'newpass',
:new_password_confirmation => 'newpass'
}
assert_redirected_to '/'
end
def test_activation_email_should_send_an_activation_email
User.find(2).update_attribute :status, User::STATUS_REGISTERED
@request.session[:registered_user_id] = 2
with_settings :self_registration => '1' do
assert_difference 'ActionMailer::Base.deliveries.size' do
get :activation_email
assert_redirected_to '/login'
end
end
end
def test_activation_email_without_session_data_should_fail
User.find(2).update_attribute :status, User::STATUS_REGISTERED
with_settings :self_registration => '1' do
assert_no_difference 'ActionMailer::Base.deliveries.size' do
get :activation_email
assert_redirected_to '/'
end
end
end
end

View file

@ -0,0 +1,220 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class ActivitiesControllerTest < Redmine::ControllerTest
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :users, :issue_categories,
:projects_trackers,
:roles,
:member_roles,
:members,
:groups_users,
:enabled_modules,
:journals, :journal_details
def test_project_index
get :index, :params => {
:id => 1,
:with_subprojects => 0
}
assert_response :success
assert_select 'h3', :text => /#{2.days.ago.to_date.day}/
assert_select 'dl dt.issue-edit a', :text => /(#{IssueStatus.find(2).name})/
end
def test_project_index_with_invalid_project_id_should_respond_404
get :index, :params => {
:id => 299
}
assert_response 404
end
def test_previous_project_index
get :index, :params => {
:id => 1,
:from => 2.days.ago.to_date
}
assert_response :success
assert_select 'h3', :text => /#{3.days.ago.to_date.day}/
assert_select 'dl dt.issue a', :text => /Cannot print recipes/
end
def test_global_index
@request.session[:user_id] = 1
get :index
assert_response :success
i5 = Issue.find(5)
d5 = User.find(1).time_to_date(i5.created_on)
assert_select 'h3', :text => /#{d5.day}/
assert_select 'dl dt.issue a', :text => /Subproject issue/
end
def test_user_index
@request.session[:user_id] = 1
get :index, :params => {
:user_id => 2
}
assert_response :success
assert_select 'h2 a[href="/users/2"]', :text => 'John Smith'
i1 = Issue.find(1)
d1 = User.find(1).time_to_date(i1.created_on)
assert_select 'h3', :text => /#{d1.day}/
assert_select 'dl dt.issue a', :text => /Cannot print recipes/
end
def test_user_index_with_invalid_user_id_should_respond_404
get :index, :params => {
:user_id => 299
}
assert_response 404
end
def test_index_atom_feed
get :index, :params => {
:format => 'atom',
:with_subprojects => 0
}
assert_response :success
assert_select 'feed' do
assert_select 'link[rel=self][href=?]', 'http://test.host/activity.atom?with_subprojects=0'
assert_select 'link[rel=alternate][href=?]', 'http://test.host/activity?with_subprojects=0'
assert_select 'entry' do
assert_select 'link[href=?]', 'http://test.host/issues/11'
end
end
end
def test_index_atom_feed_with_explicit_selection
get :index, :params => {
:format => 'atom',
:with_subprojects => 0,
:show_changesets => 1,
:show_documents => 1,
:show_files => 1,
:show_issues => 1,
:show_messages => 1,
:show_news => 1,
:show_time_entries => 1,
:show_wiki_edits => 1
}
assert_response :success
assert_select 'feed' do
assert_select 'link[rel=self][href=?]', 'http://test.host/activity.atom?show_changesets=1&show_documents=1&show_files=1&show_issues=1&show_messages=1&show_news=1&show_time_entries=1&show_wiki_edits=1&with_subprojects=0'
assert_select 'link[rel=alternate][href=?]', 'http://test.host/activity?show_changesets=1&show_documents=1&show_files=1&show_issues=1&show_messages=1&show_news=1&show_time_entries=1&show_wiki_edits=1&with_subprojects=0'
assert_select 'entry' do
assert_select 'link[href=?]', 'http://test.host/issues/11'
end
end
end
def test_index_atom_feed_with_one_item_type
with_settings :default_language => 'en' do
get :index, :params => {
:format => 'atom',
:show_issues => '1'
}
assert_response :success
assert_select 'title', :text => /Issues/
end
end
def test_index_atom_feed_with_user
get :index, :params => {
:user_id => 2,
:format => 'atom'
}
assert_response :success
assert_select 'title', :text => "Redmine: #{User.find(2).name}"
end
def test_index_should_show_private_notes_with_permission_only
journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Private notes', :private_notes => true)
@request.session[:user_id] = 2
get :index
assert_response :success
assert_select 'dl', :text => /Private notes/
Role.find(1).remove_permission! :view_private_notes
get :index
assert_response :success
assert_select 'dl', :text => /Private notes/, :count => 0
end
def test_index_with_submitted_scope_should_save_as_preference
@request.session[:user_id] = 2
get :index, :params => {
:show_issues => '1',
:show_messages => '1',
:submit => 'Apply'
}
assert_response :success
assert_equal %w(issues messages), User.find(2).pref.activity_scope.sort
end
def test_index_scope_should_default_to_user_preference
pref = User.find(2).pref
pref.activity_scope = %w(issues news)
pref.save!
@request.session[:user_id] = 2
get :index
assert_response :success
assert_select '#activity_scope_form' do
assert_select 'input[checked=checked]', 2
assert_select 'input[name=show_issues][checked=checked]'
assert_select 'input[name=show_news][checked=checked]'
end
end
def test_index_should_not_show_next_page_link
@request.session[:user_id] = 2
get :index
assert_response :success
assert_select '.pagination a', :text => /Previous/
assert_select '.pagination a', :text => /Next/, :count => 0
end
def test_index_up_to_yesterday_should_show_next_page_link
@request.session[:user_id] = 2
get :index, :params => {
:from => (User.find(2).today-1)
}
assert_response :success
assert_select '.pagination a', :text => /Previous/
assert_select '.pagination a', :text => /Next/
end
end

View file

@ -0,0 +1,166 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class AdminControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :email_addresses, :roles
def setup
User.current = nil
@request.session[:user_id] = 1 # admin
end
def test_index
get :index
assert_select 'div.nodata', 0
end
def test_index_with_no_configuration_data
delete_configuration_data
get :index
assert_select 'div.nodata'
end
def test_projects
get :projects
assert_response :success
assert_select 'tr.project.closed', 0
end
def test_projects_with_status_filter
get :projects, :params => {
:status => 1
}
assert_response :success
assert_select 'tr.project.closed', 0
end
def test_projects_with_name_filter
get :projects, :params => {
:name => 'store',
:status => ''
}
assert_response :success
assert_select 'tr.project td.name', :text => 'OnlineStore'
assert_select 'tr.project', 1
end
def test_load_default_configuration_data
delete_configuration_data
post :default_configuration, :params => {
:lang => 'fr'
}
assert_response :redirect
assert_nil flash[:error]
assert IssueStatus.find_by_name('Nouveau')
end
def test_load_default_configuration_data_should_rescue_error
delete_configuration_data
Redmine::DefaultData::Loader.stubs(:load).raises(Exception.new("Something went wrong"))
post :default_configuration, :params => {
:lang => 'fr'
}
assert_response :redirect
assert_not_nil flash[:error]
assert_match /Something went wrong/, flash[:error]
end
def test_test_email
user = User.find(1)
user.pref.no_self_notified = '1'
user.pref.save!
ActionMailer::Base.deliveries.clear
post :test_email
assert_redirected_to '/settings?tab=notifications'
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
user = User.find(1)
assert_equal [user.mail], mail.bcc
end
def test_test_email_failure_should_display_the_error
Mailer.stubs(:test_email).raises(Exception, 'Some error message')
post :test_email
assert_redirected_to '/settings?tab=notifications'
assert_match /Some error message/, flash[:error]
end
def test_no_plugins
Redmine::Plugin.stubs(:registered_plugins).returns({})
get :plugins
assert_response :success
assert_select '.nodata'
end
def test_plugins
# Register a few plugins
Redmine::Plugin.register :foo do
name 'Foo plugin'
author 'John Smith'
description 'This is a test plugin'
version '0.0.1'
settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings'
end
Redmine::Plugin.register :bar do
end
get :plugins
assert_response :success
assert_select 'tr#plugin-foo' do
assert_select 'td span.name', :text => 'Foo plugin'
assert_select 'td.configure a[href="/settings/plugin/foo"]'
end
assert_select 'tr#plugin-bar' do
assert_select 'td span.name', :text => 'Bar'
assert_select 'td.configure a', 0
end
end
def test_info
get :info
assert_response :success
end
def test_admin_menu_plugin_extension
Redmine::MenuManager.map :admin_menu do |menu|
menu.push :test_admin_menu_plugin_extension, '/foo/bar', :caption => 'Test'
end
get :index
assert_response :success
assert_select 'div#admin-menu a[href="/foo/bar"]', :text => 'Test'
Redmine::MenuManager.map :admin_menu do |menu|
menu.delete :test_admin_menu_plugin_extension
end
end
private
def delete_configuration_data
Role.where('builtin = 0').delete_all
Tracker.delete_all
IssueStatus.delete_all
Enumeration.delete_all
end
end

View file

@ -0,0 +1,610 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class AttachmentsControllerTest < Redmine::ControllerTest
fixtures :users, :projects, :roles, :members, :member_roles,
:enabled_modules, :issues, :trackers, :attachments,
:versions, :wiki_pages, :wikis, :documents
def setup
User.current = nil
set_fixtures_attachments_directory
end
def teardown
set_tmp_attachments_directory
end
def test_show_diff
['inline', 'sbs'].each do |dt|
# 060719210727_changeset_utf8.diff
get :show, :params => {
:id => 14,
:type => dt
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'th.filename', :text => /issues_controller.rb\t\(révision 1484\)/
assert_select 'td.line-code', :text => /Demande créée avec succès/
end
set_tmp_attachments_directory
end
def test_show_diff_replace_cannot_convert_content
with_settings :repositories_encodings => 'UTF-8' do
['inline', 'sbs'].each do |dt|
# 060719210727_changeset_iso8859-1.diff
get :show, :params => {
:id => 5,
:type => dt
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'th.filename', :text => /issues_controller.rb\t\(r\?vision 1484\)/
assert_select 'td.line-code', :text => /Demande cr\?\?e avec succ\?s/
end
end
set_tmp_attachments_directory
end
def test_show_diff_latin_1
with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
['inline', 'sbs'].each do |dt|
# 060719210727_changeset_iso8859-1.diff
get :show, :params => {
:id => 5,
:type => dt
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'th.filename', :text => /issues_controller.rb\t\(révision 1484\)/
assert_select 'td.line-code', :text => /Demande créée avec succès/
end
end
set_tmp_attachments_directory
end
def test_show_should_save_diff_type_as_user_preference
user1 = User.find(1)
user1.pref[:diff_type] = nil
user1.preference.save
user = User.find(1)
assert_nil user.pref[:diff_type]
@request.session[:user_id] = 1 # admin
get :show, :params => {
:id => 5
}
assert_response :success
user.reload
assert_equal "inline", user.pref[:diff_type]
get :show, :params => {
:id => 5,
:type => 'sbs'
}
assert_response :success
user.reload
assert_equal "sbs", user.pref[:diff_type]
end
def test_diff_show_filename_in_mercurial_export
set_tmp_attachments_directory
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("hg-export.diff", "text/plain"),
:author => User.find(1))
assert a.save
assert_equal 'hg-export.diff', a.filename
get :show, :params => {
:id => a.id,
:type => 'inline'
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'th.filename', :text => 'test1.txt'
end
def test_show_text_file
get :show, :params => {
:id => 4
}
assert_response :success
assert_equal 'text/html', @response.content_type
set_tmp_attachments_directory
end
def test_show_text_file_utf_8
set_tmp_attachments_directory
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("japanese-utf-8.txt", "text/plain"),
:author => User.find(1))
assert a.save
assert_equal 'japanese-utf-8.txt', a.filename
str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e".force_encoding('UTF-8')
get :show, :params => {
:id => a.id
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'tr#L1' do
assert_select 'th.line-num', :text => '1'
assert_select 'td', :text => /#{str_japanese}/
end
end
def test_show_text_file_replace_cannot_convert_content
set_tmp_attachments_directory
with_settings :repositories_encodings => 'UTF-8' do
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("iso8859-1.txt", "text/plain"),
:author => User.find(1))
assert a.save
assert_equal 'iso8859-1.txt', a.filename
get :show, :params => {
:id => a.id
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'tr#L7' do
assert_select 'th.line-num', :text => '7'
assert_select 'td', :text => /Demande cr\?\?e avec succ\?s/
end
end
end
def test_show_text_file_latin_1
set_tmp_attachments_directory
with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("iso8859-1.txt", "text/plain"),
:author => User.find(1))
assert a.save
assert_equal 'iso8859-1.txt', a.filename
get :show, :params => {
:id => a.id
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'tr#L7' do
assert_select 'th.line-num', :text => '7'
assert_select 'td', :text => /Demande créée avec succès/
end
end
end
def test_show_text_file_should_show_other_if_too_big
@request.session[:user_id] = 2
with_settings :file_max_size_displayed => 512 do
Attachment.find(4).update_attribute :filesize, 754.kilobyte
get :show, :params => {
:id => 4
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select '.nodata', :text => 'No preview available. Download the file instead.'
end
set_tmp_attachments_directory
end
def test_show_image
@request.session[:user_id] = 2
get :show, :params => {
:id => 16
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'img.filecontent', :src => attachments(:attachments_010).filename
end
def test_show_other_with_no_preview
@request.session[:user_id] = 2
get :show, :params => {
:id => 6
}
assert_equal 'text/html', @response.content_type
assert_select '.nodata', :text => 'No preview available. Download the file instead.'
set_tmp_attachments_directory
end
def test_show_file_from_private_issue_without_permission
get :show, :params => {
:id => 15
}
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2F15'
set_tmp_attachments_directory
end
def test_show_file_from_private_issue_with_permission
@request.session[:user_id] = 2
get :show, :params => {
:id => 15
}
assert_response :success
assert_select 'h2', :text => /private.diff/
set_tmp_attachments_directory
end
def test_show_file_without_container_should_be_allowed_to_author
set_tmp_attachments_directory
attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
@request.session[:user_id] = 2
get :show, :params => {
:id => attachment.id
}
assert_response 200
end
def test_show_file_without_container_should_be_denied_to_other_users
set_tmp_attachments_directory
attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
@request.session[:user_id] = 3
get :show, :params => {
:id => attachment.id
}
assert_response 403
end
def test_show_issue_attachment_should_highlight_issues_menu_item
get :show, :params => {
:id => 4
}
assert_response :success
assert_select '#main-menu a.issues.selected'
end
def test_show_invalid_should_respond_with_404
get :show, :params => {
:id => 999
}
assert_response 404
end
def test_download_text_file
get :download, :params => {
:id => 4
}
assert_response :success
assert_equal 'application/x-ruby', @response.content_type
etag = @response.etag
assert_not_nil etag
@request.env["HTTP_IF_NONE_MATCH"] = etag
get :download, :params => {
:id => 4
}
assert_response 304
set_tmp_attachments_directory
end
def test_download_js_file
set_tmp_attachments_directory
attachment = Attachment.create!(
:file => mock_file_with_options(:original_filename => "hello.js", :content_type => "text/javascript"),
:author_id => 2,
:container => Issue.find(1)
)
get :download, :params => {
:id => attachment.id
}
assert_response :success
assert_equal 'text/javascript', @response.content_type
end
def test_download_version_file_with_issue_tracking_disabled
Project.find(1).disable_module! :issue_tracking
get :download, :params => {
:id => 9
}
assert_response :success
end
def test_download_should_assign_content_type_if_blank
Attachment.find(4).update_attribute(:content_type, '')
get :download, :params => {
:id => 4
}
assert_response :success
assert_equal 'text/x-ruby', @response.content_type
set_tmp_attachments_directory
end
def test_download_should_assign_better_content_type_than_application_octet_stream
Attachment.find(4).update! :content_type => "application/octet-stream"
get :download, :params => {
:id => 4
}
assert_response :success
assert_equal 'text/x-ruby', @response.content_type
set_tmp_attachments_directory
end
def test_download_missing_file
get :download, :params => {
:id => 2
}
assert_response 404
set_tmp_attachments_directory
end
def test_download_should_be_denied_without_permission
get :download, :params => {
:id => 7
}
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdownload%2F7'
set_tmp_attachments_directory
end
if convert_installed?
def test_thumbnail
Attachment.clear_thumbnails
@request.session[:user_id] = 2
get :thumbnail, :params => {
:id => 16
}
assert_response :success
assert_equal 'image/png', response.content_type
etag = @response.etag
assert_not_nil etag
@request.env["HTTP_IF_NONE_MATCH"] = etag
get :thumbnail, :params => {
:id => 16
}
assert_response 304
end
def test_thumbnail_should_not_exceed_maximum_size
Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 800}
@request.session[:user_id] = 2
get :thumbnail, :params => {
:id => 16,
:size => 2000
}
end
def test_thumbnail_should_round_size
Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 250}
@request.session[:user_id] = 2
get :thumbnail, :params => {
:id => 16,
:size => 260
}
end
def test_thumbnail_should_return_404_for_non_image_attachment
@request.session[:user_id] = 2
get :thumbnail, :params => {
:id => 15
}
assert_response 404
end
def test_thumbnail_should_return_404_if_thumbnail_generation_failed
Attachment.any_instance.stubs(:thumbnail).returns(nil)
@request.session[:user_id] = 2
get :thumbnail, :params => {
:id => 16
}
assert_response 404
end
def test_thumbnail_should_be_denied_without_permission
get :thumbnail, :params => {
:id => 16
}
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fthumbnail%2F16'
end
else
puts '(ImageMagick convert not available)'
end
def test_edit_all
@request.session[:user_id] = 2
get :edit_all, :params => {
:object_type => 'issues',
:object_id => '2'
}
assert_response :success
assert_select 'form[action=?]', '/attachments/issues/2' do
Issue.find(2).attachments.each do |attachment|
assert_select "tr#attachment-#{attachment.id}"
end
assert_select 'tr#attachment-4' do
assert_select 'input[name=?][value=?]', 'attachments[4][filename]', 'source.rb'
assert_select 'input[name=?][value=?]', 'attachments[4][description]', 'This is a Ruby source file'
end
end
end
def test_edit_all_with_invalid_container_class_should_return_404
get :edit_all, :params => {
:object_type => 'nuggets',
:object_id => '3'
}
assert_response 404
end
def test_edit_all_with_invalid_object_should_return_404
get :edit_all, :params => {
:object_type => 'issues',
:object_id => '999'
}
assert_response 404
end
def test_edit_all_for_object_that_is_not_visible_should_return_403
get :edit_all, :params => {
:object_type => 'issues',
:object_id => '4'
}
assert_response 403
end
def test_update_all
@request.session[:user_id] = 2
patch :update_all, :params => {
:object_type => 'issues',
:object_id => '2',
:attachments => {
'1' => {
:filename => 'newname.text',
:description => ''
},
'4' => {
:filename => 'newname.rb',
:description => 'Renamed'
},
}
}
assert_response 302
attachment = Attachment.find(4)
assert_equal 'newname.rb', attachment.filename
assert_equal 'Renamed', attachment.description
end
def test_update_all_with_failure
@request.session[:user_id] = 2
patch :update_all, :params => {
:object_type => 'issues',
:object_id => '3',
:attachments => {
'1' => {
:filename => '',
:description => ''
},
'4' => {
:filename => 'newname.rb',
:description => 'Renamed'
},
}
}
assert_response :success
assert_select_error /file cannot be blank/i
# The other attachment should not be updated
attachment = Attachment.find(4)
assert_equal 'source.rb', attachment.filename
assert_equal 'This is a Ruby source file', attachment.description
end
def test_destroy_issue_attachment
set_tmp_attachments_directory
issue = Issue.find(3)
@request.session[:user_id] = 2
assert_difference 'issue.attachments.count', -1 do
assert_difference 'Journal.count' do
delete :destroy, :params => {
:id => 1
}
assert_redirected_to '/projects/ecookbook'
end
end
assert_nil Attachment.find_by_id(1)
j = Journal.order('id DESC').first
assert_equal issue, j.journalized
assert_equal 'attachment', j.details.first.property
assert_equal '1', j.details.first.prop_key
assert_equal 'error281.txt', j.details.first.old_value
assert_equal User.find(2), j.user
end
def test_destroy_wiki_page_attachment
set_tmp_attachments_directory
@request.session[:user_id] = 2
assert_difference 'Attachment.count', -1 do
delete :destroy, :params => {
:id => 3
}
assert_response 302
end
end
def test_destroy_project_attachment
set_tmp_attachments_directory
@request.session[:user_id] = 2
assert_difference 'Attachment.count', -1 do
delete :destroy, :params => {
:id => 8
}
assert_response 302
end
end
def test_destroy_version_attachment
set_tmp_attachments_directory
@request.session[:user_id] = 2
assert_difference 'Attachment.count', -1 do
delete :destroy, :params => {
:id => 9
}
assert_response 302
end
end
def test_destroy_version_attachment_with_issue_tracking_disabled
Project.find(1).disable_module! :issue_tracking
set_tmp_attachments_directory
@request.session[:user_id] = 2
assert_difference 'Attachment.count', -1 do
delete :destroy, :params => {
:id => 9
}
assert_response 302
end
end
def test_destroy_without_permission
set_tmp_attachments_directory
assert_no_difference 'Attachment.count' do
delete :destroy, :params => {
:id => 3
}
end
assert_response 302
assert Attachment.find_by_id(3)
end
end

View file

@ -0,0 +1,58 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class AttachmentsVisibilityTest < Redmine::ControllerTest
tests AttachmentsController
fixtures :users, :email_addresses, :projects, :roles, :members, :member_roles,
:enabled_modules, :projects_trackers, :issue_statuses, :enumerations,
:issues, :trackers, :versions
def setup
set_tmp_attachments_directory
@field = IssueCustomField.generate!(:field_format => 'attachment', :visible => true)
@attachment = new_record(Attachment) do
issue = Issue.generate
issue.custom_field_values = {@field.id => {:file => mock_file}}
issue.save!
end
end
def test_attachment_should_be_visible
@request.session[:user_id] = 2 # manager
get :show, :params => {:id => @attachment.id}
assert_response :success
@field.update!(:visible => false, :role_ids => [1])
get :show, :params => {:id => @attachment.id}
assert_response :success
end
def test_attachment_should_be_visible_with_permission
@request.session[:user_id] = 3 # developer
get :show, :params => {:id => @attachment.id}
assert_response :success
@field.update!(:visible => false, :role_ids => [1])
get :show, :params => {:id => @attachment.id}
assert_response 403
end
end

View file

@ -0,0 +1,204 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class AuthSourcesControllerTest < Redmine::ControllerTest
fixtures :users, :auth_sources
def setup
@request.session[:user_id] = 1
end
def test_index
get :index
assert_response :success
end
def test_new
get :new
assert_response :success
assert_select 'form#auth_source_form' do
assert_select 'input[name=type][value=AuthSourceLdap]'
assert_select 'input[name=?]', 'auth_source[host]'
end
end
def test_new_with_invalid_type_should_respond_with_404
get :new, :params => {
:type => 'foo'
}
assert_response 404
end
def test_create
assert_difference 'AuthSourceLdap.count' do
post :create, :params => {
:type => 'AuthSourceLdap',
:auth_source => {
:name => 'Test',
:host => '127.0.0.1',
:port => '389',
:attr_login => 'cn'
}
}
assert_redirected_to '/auth_sources'
end
source = AuthSourceLdap.order('id DESC').first
assert_equal 'Test', source.name
assert_equal '127.0.0.1', source.host
assert_equal 389, source.port
assert_equal 'cn', source.attr_login
end
def test_create_with_failure
assert_no_difference 'AuthSourceLdap.count' do
post :create, :params => {
:type => 'AuthSourceLdap',
:auth_source => {
:name => 'Test',
:host => '',
:port => '389',
:attr_login => 'cn'
}
}
assert_response :success
end
assert_select_error /host cannot be blank/i
end
def test_edit
get :edit, :params => {
:id => 1
}
assert_response :success
assert_select 'form#auth_source_form' do
assert_select 'input[name=?]', 'auth_source[host]'
end
end
def test_edit_should_not_contain_password
AuthSource.find(1).update_column :account_password, 'secret'
get :edit, :params => {
:id => 1
}
assert_response :success
assert_select 'input[value=secret]', 0
assert_select 'input[name=dummy_password][value^=xxxxxx]'
end
def test_edit_invalid_should_respond_with_404
get :edit, :params => {
:id => 99
}
assert_response 404
end
def test_update
put :update, :params => {
:id => 1,
:auth_source => {
:name => 'Renamed',
:host => '192.168.0.10',
:port => '389',
:attr_login => 'uid'
}
}
assert_redirected_to '/auth_sources'
source = AuthSourceLdap.find(1)
assert_equal 'Renamed', source.name
assert_equal '192.168.0.10', source.host
end
def test_update_with_failure
put :update, :params => {
:id => 1,
:auth_source => {
:name => 'Renamed',
:host => '',
:port => '389',
:attr_login => 'uid'
}
}
assert_response :success
assert_select_error /host cannot be blank/i
end
def test_destroy
assert_difference 'AuthSourceLdap.count', -1 do
delete :destroy, :params => {
:id => 1
}
assert_redirected_to '/auth_sources'
end
end
def test_destroy_auth_source_in_use
User.find(2).update_attribute :auth_source_id, 1
assert_no_difference 'AuthSourceLdap.count' do
delete :destroy, :params => {
:id => 1
}
assert_redirected_to '/auth_sources'
end
end
def test_test_connection
AuthSourceLdap.any_instance.stubs(:test_connection).returns(true)
get :test_connection, :params => {
:id => 1
}
assert_redirected_to '/auth_sources'
assert_not_nil flash[:notice]
assert_match /successful/i, flash[:notice]
end
def test_test_connection_with_failure
AuthSourceLdap.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError.new("Something went wrong"))
get :test_connection, :params => {
:id => 1
}
assert_redirected_to '/auth_sources'
assert_not_nil flash[:error]
assert_include 'Something went wrong', flash[:error]
end
def test_autocomplete_for_new_user
AuthSource.expects(:search).with('foo').returns([
{:login => 'foo1', :firstname => 'John', :lastname => 'Smith', :mail => 'foo1@example.net', :auth_source_id => 1},
{:login => 'Smith', :firstname => 'John', :lastname => 'Doe', :mail => 'foo2@example.net', :auth_source_id => 1}
])
get :autocomplete_for_new_user, :params => {
:term => 'foo'
}
assert_response :success
assert_equal 'application/json', response.content_type
json = ActiveSupport::JSON.decode(response.body)
assert_kind_of Array, json
assert_equal 2, json.size
assert_equal 'foo1', json.first['value']
assert_equal 'foo1 (John Smith)', json.first['label']
end
end

View file

@ -0,0 +1,141 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class AutoCompletesControllerTest < Redmine::ControllerTest
fixtures :projects, :issues, :issue_statuses,
:enumerations, :users, :issue_categories,
:trackers,
:projects_trackers,
:roles,
:member_roles,
:members,
:enabled_modules,
:journals, :journal_details
def test_issues_should_not_be_case_sensitive
get :issues, :params => {
:project_id => 'ecookbook',
:q => 'ReCiPe'
}
assert_response :success
assert_include "recipe", response.body
end
def test_issues_should_accept_term_param
get :issues, :params => {
:project_id => 'ecookbook',
:term => 'ReCiPe'
}
assert_response :success
assert_include "recipe", response.body
end
def test_issues_should_return_issue_with_given_id
get :issues, :params => {
:project_id => 'subproject1',
:q => '13'
}
assert_response :success
assert_include "Bug #13", response.body
end
def test_issues_should_return_issue_with_given_id_preceded_with_hash
get :issues, :params => {
:project_id => 'subproject1',
:q => '#13'
}
assert_response :success
assert_include "Bug #13", response.body
end
def test_auto_complete_with_scope_all_should_search_other_projects
get :issues, :params => {
:project_id => 'ecookbook',
:q => '13',
:scope => 'all'
}
assert_response :success
assert_include "Bug #13", response.body
end
def test_auto_complete_without_project_should_search_all_projects
get :issues, :params => {
:q => '13'
}
assert_response :success
assert_include "Bug #13", response.body
end
def test_auto_complete_without_scope_all_should_not_search_other_projects
get :issues, :params => {
:project_id => 'ecookbook',
:q => '13'
}
assert_response :success
assert_not_include "Bug #13", response.body
end
def test_issues_should_return_json
get :issues, :params => {
:project_id => 'subproject1',
:q => '13'
}
assert_response :success
json = ActiveSupport::JSON.decode(response.body)
assert_kind_of Array, json
issue = json.first
assert_kind_of Hash, issue
assert_equal 13, issue['id']
assert_equal 13, issue['value']
assert_equal 'Bug #13: Subproject issue two', issue['label']
end
def test_auto_complete_with_status_o_should_return_open_issues_only
get :issues, :params => {
:project_id => 'ecookbook',
:q => 'issue',
:status => 'o'
}
assert_response :success
assert_include "Issue due today", response.body
assert_not_include "closed", response.body
end
def test_auto_complete_with_status_c_should_return_closed_issues_only
get :issues, :params => {
:project_id => 'ecookbook',
:q => 'issue',
:status => 'c'
}
assert_response :success
assert_include "closed", response.body
assert_not_include "Issue due today", response.body
end
def test_auto_complete_with_issue_id_should_not_return_that_issue
get :issues, :params => {
:project_id => 'ecookbook',
:q => 'issue',
:issue_id => '12'
}
assert_response :success
assert_include "issue", response.body
assert_not_include "Bug #12: Closed issue on a locked version", response.body
end
end

View file

@ -0,0 +1,294 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class BoardsControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :members, :member_roles, :roles, :boards, :messages, :enabled_modules
def setup
User.current = nil
end
def test_index
get :index, :params => {
:project_id => 1
}
assert_response :success
assert_select 'table.boards'
end
def test_index_not_found
get :index, :params => {
:project_id => 97
}
assert_response 404
end
def test_index_should_show_messages_if_only_one_board
Project.find(1).boards.to_a.slice(1..-1).each(&:destroy)
get :index, :params => {
:project_id => 1
}
assert_response :success
assert_select 'table.boards', 0
assert_select 'table.messages'
end
def test_show
get :show, :params => {
:project_id => 1,
:id => 1
}
assert_response :success
assert_select 'table.messages tbody' do
assert_select 'tr', Board.find(1).topics.count
end
end
def test_show_should_display_sticky_messages_first
Message.update_all(:sticky => 0)
Message.where({:id => 1}).update_all({:sticky => 1})
get :show, :params => {
:project_id => 1,
:id => 1
}
assert_response :success
assert_select 'table.messages tbody' do
# row is here...
assert_select 'tr.sticky'
# ...and in first position
assert_select 'tr.sticky:first-child'
end
end
def test_show_should_display_message_with_last_reply_first
Message.update_all(:sticky => 0)
# Reply to an old topic
old_topic = Message.where(:board_id => 1, :parent_id => nil).order('created_on ASC').first
reply = Message.new(:board_id => 1, :subject => 'New reply', :content => 'New reply', :author_id => 2)
old_topic.children << reply
get :show, :params => {
:project_id => 1,
:id => 1
}
assert_response :success
assert_select 'table.messages tbody' do
assert_select "tr#message-#{old_topic.id}"
assert_select "tr#message-#{old_topic.id}:first-child"
end
end
def test_show_with_permission_should_display_the_new_message_form
@request.session[:user_id] = 2
get :show, :params => {
:project_id => 1,
:id => 1
}
assert_response :success
assert_select 'form#message-form' do
assert_select 'input[name=?]', 'message[subject]'
end
end
def test_show_atom
get :show, :params => {
:project_id => 1,
:id => 1,
:format => 'atom'
}
assert_response :success
assert_select 'feed > entry > title', :text => 'Help: RE: post 2'
end
def test_show_not_found
get :index, :params => {
:project_id => 1,
:id => 97
}
assert_response 404
end
def test_new
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 1
}
assert_response :success
assert_select 'select[name=?]', 'board[parent_id]' do
assert_select 'option', (Project.find(1).boards.size + 1)
assert_select 'option[value=""]'
assert_select 'option[value="1"]', :text => 'Help'
end
# &nbsp; replaced by nokogiri, not easy to test in DOM assertions
assert_not_include '<option value=""></option>', response.body
assert_include '<option value="">&nbsp;</option>', response.body
end
def test_new_without_project_boards
Project.find(1).boards.delete_all
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 1
}
assert_response :success
assert_select 'select[name=?]', 'board[parent_id]', 0
end
def test_create
@request.session[:user_id] = 2
assert_difference 'Board.count' do
post :create, :params => {
:project_id => 1,
:board => {
:name => 'Testing',
:description => 'Testing board creation'
}
}
end
assert_redirected_to '/projects/ecookbook/settings/boards'
board = Board.order('id DESC').first
assert_equal 'Testing', board.name
assert_equal 'Testing board creation', board.description
end
def test_create_with_parent
@request.session[:user_id] = 2
assert_difference 'Board.count' do
post :create, :params => {
:project_id => 1,
:board => {
:name => 'Testing',
:description => 'Testing',
:parent_id => 2
}
}
end
assert_redirected_to '/projects/ecookbook/settings/boards'
board = Board.order('id DESC').first
assert_equal Board.find(2), board.parent
end
def test_create_with_failure
@request.session[:user_id] = 2
assert_no_difference 'Board.count' do
post :create, :params => {
:project_id => 1,
:board => {
:name => '',
:description => 'Testing board creation'
}
}
end
assert_response :success
assert_select_error /Name cannot be blank/
end
def test_edit
@request.session[:user_id] = 2
get :edit, :params => {
:project_id => 1,
:id => 2
}
assert_response :success
assert_select 'input[name=?][value=?]', 'board[name]', 'Discussion'
end
def test_edit_with_parent
board = Board.generate!(:project_id => 1, :parent_id => 2)
@request.session[:user_id] = 2
get :edit, :params => {
:project_id => 1,
:id => board.id
}
assert_response :success
assert_select 'select[name=?]', 'board[parent_id]' do
assert_select 'option[value="2"][selected=selected]'
end
end
def test_update
@request.session[:user_id] = 2
assert_no_difference 'Board.count' do
put :update, :params => {
:project_id => 1,
:id => 2,
:board => {
:name => 'Testing',
:description => 'Testing board update'
}
}
end
assert_redirected_to '/projects/ecookbook/settings/boards'
assert_equal 'Testing', Board.find(2).name
end
def test_update_position
@request.session[:user_id] = 2
put :update, :params => {
:project_id => 1,
:id => 2,
:board => {
:position => 1
}
}
assert_redirected_to '/projects/ecookbook/settings/boards'
board = Board.find(2)
assert_equal 1, board.position
end
def test_update_with_failure
@request.session[:user_id] = 2
put :update, :params => {
:project_id => 1,
:id => 2,
:board => {
:name => '',
:description => 'Testing board update'
}
}
assert_response :success
assert_select_error /Name cannot be blank/
end
def test_destroy
@request.session[:user_id] = 2
assert_difference 'Board.count', -1 do
delete :destroy, :params => {
:project_id => 1,
:id => 2
}
end
assert_redirected_to '/projects/ecookbook/settings/boards'
assert_nil Board.find_by_id(2)
end
end

View file

@ -0,0 +1,116 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class CalendarsControllerTest < Redmine::ControllerTest
fixtures :projects,
:trackers,
:projects_trackers,
:roles,
:member_roles,
:members,
:enabled_modules,
:issues,
:issue_statuses,
:issue_relations,
:issue_categories,
:enumerations,
:queries
def test_show
get :show, :params => {
:project_id => 1
}
assert_response :success
end
def test_show_should_run_custom_queries
@query = IssueQuery.create!(:name => 'Calendar Query', :visibility => IssueQuery::VISIBILITY_PUBLIC)
get :show, :params => {
:query_id => @query.id
}
assert_response :success
assert_select 'h2', :text => 'Calendar Query'
end
def test_cross_project_calendar
get :show
assert_response :success
end
def test_week_number_calculation
with_settings :start_of_week => 7 do
get :show, :params => {
:month => '1',
:year => '2010'
}
assert_response :success
end
assert_select 'tr' do
assert_select 'td.week-number', :text => '53'
assert_select 'td.odd', :text => '27'
assert_select 'td.even', :text => '2'
end
assert_select 'tr' do
assert_select 'td.week-number', :text => '1'
assert_select 'td.odd', :text => '3'
assert_select 'td.even', :text => '9'
end
with_settings :start_of_week => 1 do
get :show, :params => {
:month => '1',
:year => '2010'
}
assert_response :success
end
assert_select 'tr' do
assert_select 'td.week-number', :text => '53'
assert_select 'td.even', :text => '28'
assert_select 'td.even', :text => '3'
end
assert_select 'tr' do
assert_select 'td.week-number', :text => '1'
assert_select 'td.even', :text => '4'
assert_select 'td.even', :text => '10'
end
end
def test_show_custom_query_with_multiple_sort_criteria
get :show, :params => {
:query_id => 5
}
assert_response :success
assert_select 'h2', :text => 'Open issues by priority and tracker'
end
def test_show_custom_query_with_group_by_option
get :show, :params => {
:query_id => 6
}
assert_response :success
assert_select 'h2', :text => 'Open issues grouped by tracker'
end
end

View file

@ -0,0 +1,82 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class CommentsControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles, :enabled_modules, :news, :comments
def setup
User.current = nil
end
def test_add_comment
@request.session[:user_id] = 2
post :create, :params => {
:id => 1,
:comment => {
:comments => 'This is a test comment'
}
}
assert_redirected_to '/news/1'
comment = News.find(1).comments.last
assert_not_nil comment
assert_equal 'This is a test comment', comment.comments
assert_equal User.find(2), comment.author
end
def test_empty_comment_should_not_be_added
@request.session[:user_id] = 2
assert_no_difference 'Comment.count' do
post :create, :params => {
:id => 1,
:comment => {
:comments => ''
}
}
assert_response :redirect
assert_redirected_to '/news/1'
end
end
def test_create_should_be_denied_if_news_is_not_commentable
News.any_instance.stubs(:commentable?).returns(false)
@request.session[:user_id] = 2
assert_no_difference 'Comment.count' do
post :create, :params => {
:id => 1,
:comment => {
:comments => 'This is a test comment'
}
}
assert_response 403
end
end
def test_destroy_comment
comments_count = News.find(1).comments.size
@request.session[:user_id] = 2
delete :destroy, :params => {
:id => 1,
:comment_id => 2
}
assert_redirected_to '/news/1'
assert_nil Comment.find_by_id(2)
assert_equal comments_count - 1, News.find(1).comments.size
end
end

View file

@ -0,0 +1,327 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class ContextMenusControllerTest < Redmine::ControllerTest
fixtures :projects,
:trackers,
:projects_trackers,
:roles,
:member_roles,
:members,
:enabled_modules,
:workflows,
:journals, :journal_details,
:versions,
:issues, :issue_statuses, :issue_categories,
:users,
:enumerations,
:time_entries
def test_context_menu_one_issue
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1]
}
assert_response :success
assert_select 'a.icon-edit[href=?]', '/issues/1/edit', :text => 'Edit'
assert_select 'a.icon-copy[href=?]', '/projects/ecookbook/issues/1/copy', :text => 'Copy'
assert_select 'a.icon-del[href=?]', '/issues?ids%5B%5D=1', :text => 'Delete'
# Statuses
assert_select 'a[href=?]', '/issues/bulk_update?ids%5B%5D=1&issue%5Bstatus_id%5D=5', :text => 'Closed'
assert_select 'a[href=?]', '/issues/bulk_update?ids%5B%5D=1&issue%5Bpriority_id%5D=8', :text => 'Immediate'
# No inactive priorities
assert_select 'a', :text => /Inactive Priority/, :count => 0
# Versions
assert_select 'a[href=?]', '/issues/bulk_update?ids%5B%5D=1&issue%5Bfixed_version_id%5D=3', :text => '2.0'
assert_select 'a[href=?]', '/issues/bulk_update?ids%5B%5D=1&issue%5Bfixed_version_id%5D=4', :text => 'eCookbook Subproject 1 - 2.0'
# Assignees
assert_select 'a[href=?]', '/issues/bulk_update?ids%5B%5D=1&issue%5Bassigned_to_id%5D=3', :text => 'Dave Lopper'
end
def test_context_menu_one_issue_by_anonymous
with_settings :default_language => 'en' do
get :issues, :params => {
:ids => [1]
}
assert_response :success
assert_select 'a.icon-del.disabled[href="#"]', :text => 'Delete'
end
end
def test_context_menu_multiple_issues_of_same_project
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1, 2]
}
assert_response :success
ids = [1, 2].map {|i| "ids%5B%5D=#{i}"}.join('&')
assert_select 'a.icon-edit[href=?]', "/issues/bulk_edit?#{ids}", :text => 'Edit'
assert_select 'a.icon-copy[href=?]', "/issues/bulk_edit?copy=1&#{ids}", :text => 'Copy'
assert_select 'a.icon-del[href=?]', "/issues?#{ids}", :text => 'Delete'
assert_select 'a[href=?]', "/issues/bulk_update?#{ids}&issue%5Bstatus_id%5D=5", :text => 'Closed'
assert_select 'a[href=?]', "/issues/bulk_update?#{ids}&issue%5Bpriority_id%5D=8", :text => 'Immediate'
assert_select 'a[href=?]', "/issues/bulk_update?#{ids}&issue%5Bassigned_to_id%5D=3", :text => 'Dave Lopper'
end
def test_context_menu_multiple_issues_of_different_projects
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1, 2, 6]
}
assert_response :success
ids = [1, 2, 6].map {|i| "ids%5B%5D=#{i}"}.join('&')
assert_select 'a.icon-edit[href=?]', "/issues/bulk_edit?#{ids}", :text => 'Edit'
assert_select 'a.icon-del[href=?]', "/issues?#{ids}", :text => 'Delete'
assert_select 'a[href=?]', "/issues/bulk_update?#{ids}&issue%5Bstatus_id%5D=5", :text => 'Closed'
assert_select 'a[href=?]', "/issues/bulk_update?#{ids}&issue%5Bpriority_id%5D=8", :text => 'Immediate'
assert_select 'a[href=?]', "/issues/bulk_update?#{ids}&issue%5Bassigned_to_id%5D=2", :text => 'John Smith'
end
def test_context_menu_should_include_list_custom_fields
field = IssueCustomField.create!(:name => 'List', :field_format => 'list',
:possible_values => ['Foo', 'Bar'], :is_for_all => true, :tracker_ids => [1, 2, 3])
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1]
}
assert_select "li.cf_#{field.id}" do
assert_select 'a[href="#"]', :text => 'List'
assert_select 'ul' do
assert_select 'a', 3
assert_select 'a[href=?]', "/issues/bulk_update?ids%5B%5D=1&issue%5Bcustom_field_values%5D%5B#{field.id}%5D=Foo", :text => 'Foo'
assert_select 'a[href=?]', "/issues/bulk_update?ids%5B%5D=1&issue%5Bcustom_field_values%5D%5B#{field.id}%5D=__none__", :text => 'none'
end
end
end
def test_context_menu_should_not_include_null_value_for_required_custom_fields
field = IssueCustomField.create!(:name => 'List', :is_required => true, :field_format => 'list',
:possible_values => ['Foo', 'Bar'], :is_for_all => true, :tracker_ids => [1, 2, 3])
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1, 2]
}
assert_select "li.cf_#{field.id}" do
assert_select 'a[href="#"]', :text => 'List'
assert_select 'ul' do
assert_select 'a', 2
assert_select 'a', :text => 'none', :count => 0
end
end
end
def test_context_menu_on_single_issue_should_select_current_custom_field_value
field = IssueCustomField.create!(:name => 'List', :field_format => 'list',
:possible_values => ['Foo', 'Bar'], :is_for_all => true, :tracker_ids => [1, 2, 3])
issue = Issue.find(1)
issue.custom_field_values = {field.id => 'Bar'}
issue.save!
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1]
}
assert_select "li.cf_#{field.id}" do
assert_select 'a[href="#"]', :text => 'List'
assert_select 'ul' do
assert_select 'a', 3
assert_select 'a.icon-checked', :text => 'Bar'
end
end
end
def test_context_menu_should_include_bool_custom_fields
field = IssueCustomField.create!(:name => 'Bool', :field_format => 'bool',
:is_for_all => true, :tracker_ids => [1, 2, 3])
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1]
}
assert_select "li.cf_#{field.id}" do
assert_select 'a[href="#"]', :text => 'Bool'
assert_select 'ul' do
assert_select 'a', 3
assert_select 'a[href=?]', "/issues/bulk_update?ids%5B%5D=1&issue%5Bcustom_field_values%5D%5B#{field.id}%5D=0", :text => 'No'
assert_select 'a[href=?]', "/issues/bulk_update?ids%5B%5D=1&issue%5Bcustom_field_values%5D%5B#{field.id}%5D=1", :text => 'Yes'
assert_select 'a[href=?]', "/issues/bulk_update?ids%5B%5D=1&issue%5Bcustom_field_values%5D%5B#{field.id}%5D=__none__", :text => 'none'
end
end
end
def test_context_menu_should_include_user_custom_fields
field = IssueCustomField.create!(:name => 'User', :field_format => 'user',
:is_for_all => true, :tracker_ids => [1, 2, 3])
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1]
}
assert_select "li.cf_#{field.id}" do
assert_select 'a[href="#"]', :text => 'User'
assert_select 'ul' do
assert_select 'a', Project.find(1).members.count + 1
assert_select 'a[href=?]', "/issues/bulk_update?ids%5B%5D=1&issue%5Bcustom_field_values%5D%5B#{field.id}%5D=2", :text => 'John Smith'
assert_select 'a[href=?]', "/issues/bulk_update?ids%5B%5D=1&issue%5Bcustom_field_values%5D%5B#{field.id}%5D=__none__", :text => 'none'
end
end
end
def test_context_menu_should_include_version_custom_fields
field = IssueCustomField.create!(:name => 'Version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1, 2, 3])
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1]
}
assert_select "li.cf_#{field.id}" do
assert_select 'a[href="#"]', :text => 'Version'
assert_select 'ul' do
assert_select 'a', Project.find(1).shared_versions.count + 1
assert_select 'a[href=?]', "/issues/bulk_update?ids%5B%5D=1&issue%5Bcustom_field_values%5D%5B#{field.id}%5D=3", :text => '2.0'
assert_select 'a[href=?]', "/issues/bulk_update?ids%5B%5D=1&issue%5Bcustom_field_values%5D%5B#{field.id}%5D=__none__", :text => 'none'
end
end
end
def test_context_menu_should_show_enabled_custom_fields_for_the_role_only
enabled_cf = IssueCustomField.generate!(:field_format => 'bool', :is_for_all => true, :tracker_ids => [1], :visible => false, :role_ids => [1,2])
disabled_cf = IssueCustomField.generate!(:field_format => 'bool', :is_for_all => true, :tracker_ids => [1], :visible => false, :role_ids => [2])
issue = Issue.generate!(:project_id => 1, :tracker_id => 1)
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [issue.id]
}
assert_select "li.cf_#{enabled_cf.id}"
assert_select "li.cf_#{disabled_cf.id}", 0
end
def test_context_menu_by_assignable_user_should_include_assigned_to_me_link
@request.session[:user_id] = 2
get :issues, :params => {
:ids => [1]
}
assert_response :success
assert_select 'a[href=?]', '/issues/bulk_update?ids%5B%5D=1&issue%5Bassigned_to_id%5D=2', :text => / me /
end
def test_context_menu_should_propose_shared_versions_for_issues_from_different_projects
@request.session[:user_id] = 2
version = Version.create!(:name => 'Shared', :sharing => 'system', :project_id => 1)
get :issues, :params => {
:ids => [1, 4]
}
assert_response :success
assert_select 'a', :text => 'eCookbook - Shared'
end
def test_context_menu_with_issue_that_is_not_visible_should_fail
get :issues, :params => {
:ids => [1, 4] # issue 4 is not visible
}
assert_response 302
end
def test_should_respond_with_404_without_ids
get :issues
assert_response 404
end
def test_time_entries_context_menu
@request.session[:user_id] = 2
get :time_entries, :params => {
:ids => [1, 2]
}
assert_response :success
assert_select 'a:not(.disabled)', :text => 'Edit'
end
def test_context_menu_for_one_time_entry
@request.session[:user_id] = 2
get :time_entries, :params => {
:ids => [1]
}
assert_response :success
assert_select 'a:not(.disabled)', :text => 'Edit'
end
def test_time_entries_context_menu_should_include_custom_fields
field = TimeEntryCustomField.generate!(:name => "Field", :field_format => "list", :possible_values => ["foo", "bar"])
@request.session[:user_id] = 2
get :time_entries, :params => {
:ids => [1, 2]
}
assert_response :success
assert_select "li.cf_#{field.id}" do
assert_select 'a[href="#"]', :text => "Field"
assert_select 'ul' do
assert_select 'a', 3
assert_select 'a[href=?]', "/time_entries/bulk_update?ids%5B%5D=1&ids%5B%5D=2&time_entry%5Bcustom_field_values%5D%5B#{field.id}%5D=foo", :text => 'foo'
assert_select 'a[href=?]', "/time_entries/bulk_update?ids%5B%5D=1&ids%5B%5D=2&time_entry%5Bcustom_field_values%5D%5B#{field.id}%5D=bar", :text => 'bar'
assert_select 'a[href=?]', "/time_entries/bulk_update?ids%5B%5D=1&ids%5B%5D=2&time_entry%5Bcustom_field_values%5D%5B#{field.id}%5D=__none__", :text => 'none'
end
end
end
def test_time_entries_context_menu_with_edit_own_time_entries_permission
@request.session[:user_id] = 2
Role.find_by_name('Manager').remove_permission! :edit_time_entries
Role.find_by_name('Manager').add_permission! :edit_own_time_entries
ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
get :time_entries, :params => {
:ids => ids
}
assert_response :success
assert_select 'a:not(.disabled)', :text => 'Edit'
end
def test_time_entries_context_menu_without_edit_permission
@request.session[:user_id] = 2
Role.find_by_name('Manager').remove_permission! :edit_time_entries
get :time_entries, :params => {
:ids => [1, 2]
}
assert_response :success
assert_select 'a.disabled', :text => 'Edit'
end
end

View file

@ -0,0 +1,150 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class CustomFieldEnumerationsControllerTest < Redmine::ControllerTest
fixtures :users, :email_addresses
def setup
@request.session[:user_id] = 1
@field = GroupCustomField.create!(:name => 'List', :field_format => 'enumeration', :is_required => false)
@foo = CustomFieldEnumeration.new(:name => 'Foo')
@bar = CustomFieldEnumeration.new(:name => 'Bar')
@field.enumerations << @foo
@field.enumerations << @bar
end
def test_index
get :index, :params => {
:custom_field_id => @field.id
}
assert_response :success
assert_select 'ul#custom_field_enumerations' do
assert_select 'li', 2
end
end
def test_create
assert_difference 'CustomFieldEnumeration.count' do
post :create, :params => {
:custom_field_id => @field.id,
:custom_field_enumeration => {
:name => 'Baz'
}
}
assert_redirected_to "/custom_fields/#{@field.id}/enumerations"
end
assert_equal 3, @field.reload.enumerations.count
enum = @field.enumerations.last
assert_equal 'Baz', enum.name
assert_equal true, enum.active
assert_equal 3, enum.position
end
def test_create_xhr
assert_difference 'CustomFieldEnumeration.count' do
post :create, :params => {
:custom_field_id => @field.id,
:custom_field_enumeration => {
:name => 'Baz'
}
},
:xhr => true
assert_response :success
end
end
def test_update_each
put :update_each, :params => {
:custom_field_id => @field.id,
:custom_field_enumerations => {
@bar.id.to_s => {
:position => "1",
:name => "Baz",
:active => "1"
},
@foo.id.to_s => {
:position => "2",
:name => "Foo",
:active => "0"
}
}
}
assert_response 302
@bar.reload
assert_equal "Baz", @bar.name
assert_equal true, @bar.active
assert_equal 1, @bar.position
@foo.reload
assert_equal "Foo", @foo.name
assert_equal false, @foo.active
assert_equal 2, @foo.position
end
def test_destroy
assert_difference 'CustomFieldEnumeration.count', -1 do
delete :destroy, :params => {
:custom_field_id => @field.id,
:id => @foo.id
}
assert_redirected_to "/custom_fields/#{@field.id}/enumerations"
end
assert_equal 1, @field.reload.enumerations.count
enum = @field.enumerations.last
assert_equal 'Bar', enum.name
end
def test_destroy_enumeration_in_use_should_display_destroy_form
group = Group.generate!
group.custom_field_values = {@field.id.to_s => @foo.id.to_s}
group.save!
assert_no_difference 'CustomFieldEnumeration.count' do
delete :destroy, :params => {
:custom_field_id => @field.id,
:id => @foo.id
}
assert_response :success
assert_select 'select[name=?]', 'reassign_to_id'
end
end
def test_destroy_enumeration_in_use_should_destroy_and_reassign_values
group = Group.generate!
group.custom_field_values = {@field.id.to_s => @foo.id.to_s}
group.save!
assert_difference 'CustomFieldEnumeration.count', -1 do
delete :destroy, :params => {
:custom_field_id => @field.id,
:id => @foo.id,
:reassign_to_id => @bar.id
}
assert_response 302
end
assert_equal @bar.id.to_s, group.reload.custom_field_value(@field)
end
end

View file

@ -0,0 +1,344 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class CustomFieldsControllerTest < Redmine::ControllerTest
fixtures :custom_fields, :custom_values,
:custom_fields_projects, :custom_fields_trackers,
:roles, :users,
:members, :member_roles,
:groups_users,
:trackers, :projects_trackers,
:enabled_modules,
:projects, :issues,
:issue_statuses,
:issue_categories,
:enumerations,
:workflows
def setup
@request.session[:user_id] = 1
end
def test_index
get :index
assert_response :success
assert_select 'table.custom_fields'
end
def test_new_without_type_should_render_select_type
get :new
assert_response :success
assert_select 'input[name=type]', CustomFieldsHelper::CUSTOM_FIELDS_TABS.size
assert_select 'input[name=type][checked=checked]', 1
end
def test_new_should_work_for_each_customized_class_and_format
custom_field_classes.each do |klass|
Redmine::FieldFormat.formats_for_custom_field_class(klass).each do |format|
get :new, :params => {
:type => klass.name,
:custom_field => {
:field_format => format.name
}
}
assert_response :success
assert_select 'form#custom_field_form' do
assert_select 'select[name=?]', 'custom_field[field_format]' do
assert_select 'option[value=?][selected=selected]', format.name
end
assert_select 'input[type=hidden][name=type][value=?]', klass.name
end
end
end
end
def test_new_should_have_string_default_format
get :new, :params => {
:type => 'IssueCustomField'
}
assert_response :success
assert_select 'select[name=?]', 'custom_field[field_format]' do
assert_select 'option[value=?][selected=selected]', 'string'
end
end
def test_new_issue_custom_field
get :new, :params => {
:type => 'IssueCustomField'
}
assert_response :success
assert_select 'form#custom_field_form' do
assert_select 'select#custom_field_field_format[name=?]', 'custom_field[field_format]' do
assert_select 'option[value=user]', :text => 'User'
assert_select 'option[value=version]', :text => 'Version'
end
assert_select 'input[type=checkbox][name=?]', 'custom_field[project_ids][]', Project.count
assert_select 'input[type=hidden][name=?]', 'custom_field[project_ids][]', 1
assert_select 'input[type=hidden][name=type][value=IssueCustomField]'
end
end
def test_new_time_entry_custom_field_should_not_show_trackers_and_projects
get :new, :params => {
:type => 'TimeEntryCustomField'
}
assert_response :success
assert_select 'form#custom_field_form' do
assert_select 'input[name=?]', 'custom_field[tracker_ids][]', 0
assert_select 'input[name=?]', 'custom_field[project_ids][]', 0
end
end
def test_default_value_should_be_an_input_for_string_custom_field
get :new, :params => {
:type => 'IssueCustomField',
:custom_field => {
:field_format => 'string'
}
}
assert_response :success
assert_select 'input[name=?]', 'custom_field[default_value]'
end
def test_default_value_should_be_a_textarea_for_text_custom_field
get :new, :params => {
:type => 'IssueCustomField',
:custom_field => {
:field_format => 'text'
}
}
assert_response :success
assert_select 'textarea[name=?]', 'custom_field[default_value]'
end
def test_default_value_should_be_a_checkbox_for_bool_custom_field
get :new, :params => {
:type => 'IssueCustomField',
:custom_field => {
:field_format => 'bool'
}
}
assert_response :success
assert_select 'select[name=?]', 'custom_field[default_value]' do
assert_select 'option', 3
end
end
def test_default_value_should_not_be_present_for_user_custom_field
get :new, :params => {
:type => 'IssueCustomField',
:custom_field => {
:field_format => 'user'
}
}
assert_response :success
assert_select '[name=?]', 'custom_field[default_value]', 0
end
def test_setting_full_width_layout_shoul_be_present_only_for_long_text_issue_custom_field
get :new, :params => {
:type => 'IssueCustomField',
:custom_field => {
:field_format => 'text'
}
}
assert_response :success
assert_select '[name=?]', 'custom_field[full_width_layout]'
get :new, :params => {
:type => 'IssueCustomField',
:custom_field => {
:field_format => 'list'
}
}
assert_response :success
assert_select '[name=?]', 'custom_field[full_width_layout]', 0
get :new, :params => {
:type => 'TimeEntryCustomField',
:custom_field => {
:field_format => 'text'
}
}
assert_response :success
assert_select '[name=?]', 'custom_field[full_width_layout]', 0
end
def test_new_js
get :new, :params => {
:type => 'IssueCustomField',
:custom_field => {
:field_format => 'list'
},
:format => 'js'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include '<option selected=\"selected\" value=\"list\">List<\/option>', response.body
end
def test_new_with_invalid_custom_field_class_should_render_select_type
get :new, :params => {
:type => 'UnknownCustomField'
}
assert_response :success
assert_select 'input[type=radio][name=type]'
end
def test_create_list_custom_field
field = new_record(IssueCustomField) do
post :create, :params => {
:type => "IssueCustomField",
:custom_field => {
:name => "test_post_new_list",
:default_value => "",
:min_length => "0",
:searchable => "0",
:regexp => "",
:is_for_all => "1",
:possible_values => "0.1\n0.2\n",
:max_length => "0",
:is_filter => "0",
:is_required =>"0",
:field_format => "list",
:tracker_ids => ["1", ""]
}
}
end
assert_redirected_to "/custom_fields/#{field.id}/edit"
assert_equal "test_post_new_list", field.name
assert_equal ["0.1", "0.2"], field.possible_values
assert_equal 1, field.trackers.size
end
def test_create_with_project_ids
assert_difference 'CustomField.count' do
post :create, :params => {
:type => "IssueCustomField",
:custom_field => {
:name => "foo",
:field_format => "string",
:is_for_all => "0",
:project_ids => ["1", "3", ""]
}
}
assert_response 302
end
field = IssueCustomField.order("id desc").first
assert_equal [1, 3], field.projects.map(&:id).sort
end
def test_create_with_failure
assert_no_difference 'CustomField.count' do
post :create, :params => {
:type => "IssueCustomField",
:custom_field => {
:name => ''
}
}
end
assert_response :success
assert_select_error /name cannot be blank/i
end
def test_create_without_type_should_render_select_type
assert_no_difference 'CustomField.count' do
post :create, :params => {
:custom_field => {
:name => ''
}
}
end
assert_response :success
assert_select 'input[type=radio][name=type]'
end
def test_edit
get :edit, :params => {
:id => 1
}
assert_response :success
assert_select 'input[name=?][value=?]', 'custom_field[name]', 'Database'
end
def test_edit_invalid_custom_field_should_render_404
get :edit, :params => {
:id => 99
}
assert_response 404
end
def test_update
put :update, :params => {
:id => 1,
:custom_field => {
:name => 'New name'
}
}
assert_redirected_to '/custom_fields/1/edit'
field = CustomField.find(1)
assert_equal 'New name', field.name
end
def test_update_with_failure
put :update, :params => {
:id => 1,
:custom_field => {
:name => ''
}
}
assert_response :success
assert_select_error /name cannot be blank/i
end
def test_destroy
custom_values_count = CustomValue.where(:custom_field_id => 1).count
assert custom_values_count > 0
assert_difference 'CustomField.count', -1 do
assert_difference 'CustomValue.count', - custom_values_count do
delete :destroy, :params => {
:id => 1
}
end
end
assert_redirected_to '/custom_fields?tab=IssueCustomField'
assert_nil CustomField.find_by_id(1)
assert_nil CustomValue.find_by_custom_field_id(1)
end
def custom_field_classes
files = Dir.glob(File.join(Rails.root, 'app/models/*_custom_field.rb')).map {|f| File.basename(f).sub(/\.rb$/, '') }
classes = files.map(&:classify).map(&:constantize)
assert classes.size > 0
classes
end
end

View file

@ -0,0 +1,230 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class DocumentsControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
:enabled_modules, :documents, :enumerations,
:groups_users, :attachments
def setup
User.current = nil
end
def test_index
# Sets a default category
e = Enumeration.find_by_name('Technical documentation')
e.update_attributes(:is_default => true)
get :index, :params => {
:project_id => 'ecookbook'
}
assert_response :success
# Default category selected in the new document form
assert_select 'select[name=?]', 'document[category_id]' do
assert_select 'option[selected=selected]', :text => 'Technical documentation'
assert ! DocumentCategory.find(16).active?
assert_select 'option[value="16"]', 0
end
end
def test_index_grouped_by_date
get :index, :params => {
:project_id => 'ecookbook',
:sort_by => 'date'
}
assert_response :success
assert_select 'h3', :text => '2007-02-12'
end
def test_index_grouped_by_title
get :index, :params => {
:project_id => 'ecookbook',
:sort_by => 'title'
}
assert_response :success
assert_select 'h3', :text => 'T'
end
def test_index_grouped_by_author
get :index, :params => {
:project_id => 'ecookbook',
:sort_by => 'author'
}
assert_response :success
assert_select 'h3', :text => 'John Smith'
end
def test_index_with_long_description
# adds a long description to the first document
doc = documents(:documents_001)
doc.update_attributes(:description => <<LOREM)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut egestas, mi vehicula varius varius, ipsum massa fermentum orci, eget tristique ante sem vel mi. Nulla facilisi. Donec enim libero, luctus ac sagittis sit amet, vehicula sagittis magna. Duis ultrices molestie ante, eget scelerisque sem iaculis vitae. Etiam fermentum mauris vitae metus pharetra condimentum fermentum est pretium. Proin sollicitudin elementum quam quis pharetra. Aenean facilisis nunc quis elit volutpat mollis. Aenean eleifend varius euismod. Ut dolor est, congue eget dapibus eget, elementum eu odio. Integer et lectus neque, nec scelerisque nisi. EndOfLineHere
Vestibulum non velit mi. Aliquam scelerisque libero ut nulla fringilla a sollicitudin magna rhoncus. Praesent a nunc lorem, ac porttitor eros. Sed ac diam nec neque interdum adipiscing quis quis justo. Donec arcu nunc, fringilla eu dictum at, venenatis ac sem. Vestibulum quis elit urna, ac mattis sapien. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
LOREM
get :index, :params => {
:project_id => 'ecookbook'
}
assert_response :success
# should only truncate on new lines to avoid breaking wiki formatting
assert_select '.wiki p', :text => (doc.description.split("\n").first + '...')
assert_select '.wiki p', :text => Regexp.new(Regexp.escape("EndOfLineHere..."))
end
def test_show
get :show, :params => {
:id => 1
}
assert_response :success
end
def test_new
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 1
}
assert_response :success
end
def test_create_with_one_attachment
ActionMailer::Base.deliveries.clear
@request.session[:user_id] = 2
set_tmp_attachments_directory
with_settings :notified_events => %w(document_added) do
post :create, :params => {
:project_id => 'ecookbook',
:document => {
:title => 'DocumentsControllerTest#test_post_new',
:description => 'This is a new document',
:category_id => 2
},
:attachments => {
'1' => {
'file' => uploaded_test_file('testfile.txt', 'text/plain')}
}
}
end
assert_redirected_to '/projects/ecookbook/documents'
document = Document.find_by_title('DocumentsControllerTest#test_post_new')
assert_not_nil document
assert_equal Enumeration.find(2), document.category
assert_equal 1, document.attachments.size
assert_equal 'testfile.txt', document.attachments.first.filename
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_create_with_failure
@request.session[:user_id] = 2
assert_no_difference 'Document.count' do
post :create, :params => {
:project_id => 'ecookbook',
:document => {
:title => ''
}
}
end
assert_response :success
assert_select_error /title cannot be blank/i
end
def test_create_non_default_category
@request.session[:user_id] = 2
category2 = Enumeration.find_by_name('User documentation')
category2.update_attributes(:is_default => true)
category1 = Enumeration.find_by_name('Uncategorized')
post :create, :params => {
:project_id => 'ecookbook',
:document => {
:title => 'no default',
:description => 'This is a new document',
:category_id => category1.id
}
}
assert_redirected_to '/projects/ecookbook/documents'
doc = Document.find_by_title('no default')
assert_not_nil doc
assert_equal category1.id, doc.category_id
assert_equal category1, doc.category
end
def test_edit
@request.session[:user_id] = 2
get :edit, :params => {
:id => 1
}
assert_response :success
end
def test_update
@request.session[:user_id] = 2
put :update, :params => {
:id => 1,
:document => {
:title => 'test_update'
}
}
assert_redirected_to '/documents/1'
document = Document.find(1)
assert_equal 'test_update', document.title
end
def test_update_with_failure
@request.session[:user_id] = 2
put :update, :params => {
:id => 1,
:document => {
:title => ''
}
}
assert_response :success
assert_select_error /title cannot be blank/i
end
def test_destroy
@request.session[:user_id] = 2
assert_difference 'Document.count', -1 do
delete :destroy, :params => {
:id => 1
}
end
assert_redirected_to '/projects/ecookbook/documents'
assert_nil Document.find_by_id(1)
end
def test_add_attachment
@request.session[:user_id] = 2
assert_difference 'Attachment.count' do
post :add_attachment, :params => {
:id => 1,
:attachments => {
'1' => {
'file' => uploaded_test_file('testfile.txt', 'text/plain')}
}
}
end
attachment = Attachment.order('id DESC').first
assert_equal Document.find(1), attachment.container
end
end

View file

@ -0,0 +1,246 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class EmailAddressesControllerTest < Redmine::ControllerTest
fixtures :users, :email_addresses
def setup
User.current = nil
end
def test_index_with_no_additional_emails
@request.session[:user_id] = 2
get :index, :params => {
:user_id => 2
}
assert_response :success
end
def test_index_with_additional_emails
@request.session[:user_id] = 2
EmailAddress.create!(:user_id => 2, :address => 'another@somenet.foo')
get :index, :params => {
:user_id => 2
}
assert_response :success
assert_select '.email', :text => 'another@somenet.foo'
end
def test_index_with_additional_emails_as_js
@request.session[:user_id] = 2
EmailAddress.create!(:user_id => 2, :address => 'another@somenet.foo')
get :index, :params => {
:user_id => 2
},
:xhr => true
assert_response :success
assert_include 'another@somenet.foo', response.body
end
def test_index_by_admin_should_be_allowed
@request.session[:user_id] = 1
get :index, :params => {
:user_id => 2
}
assert_response :success
end
def test_index_by_another_user_should_be_denied
@request.session[:user_id] = 3
get :index, :params => {
:user_id => 2
}
assert_response 403
end
def test_create
@request.session[:user_id] = 2
assert_difference 'EmailAddress.count' do
post :create, :params => {
:user_id => 2,
:email_address => {
:address => 'another@somenet.foo'
}
}
assert_response 302
assert_redirected_to '/users/2/email_addresses'
end
email = EmailAddress.order('id DESC').first
assert_equal 2, email.user_id
assert_equal 'another@somenet.foo', email.address
end
def test_create_as_js
@request.session[:user_id] = 2
assert_difference 'EmailAddress.count' do
post :create, :params => {
:user_id => 2,
:email_address => {
:address => 'another@somenet.foo'
}
},
:xhr => true
assert_response 200
end
end
def test_create_with_failure
@request.session[:user_id] = 2
assert_no_difference 'EmailAddress.count' do
post :create, :params => {
:user_id => 2,
:email_address => {
:address => 'invalid'
}
}
assert_response :success
assert_select_error /email is invalid/i
end
end
def test_create_should_send_security_notification
@request.session[:user_id] = 2
ActionMailer::Base.deliveries.clear
post :create, :params => {
:user_id => 2,
:email_address => {
:address => 'something@example.fr'
}
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match '0.0.0.0', mail
assert_mail_body_match I18n.t(:mail_body_security_notification_add, field: I18n.t(:field_mail), value: 'something@example.fr'), mail
assert_select_email do
assert_select 'a[href^=?]', 'http://localhost:3000/my/account', :text => 'My account'
end
# The old email address should be notified about a new address for security purposes
assert [mail.bcc, mail.cc].flatten.include?(User.find(2).mail)
assert [mail.bcc, mail.cc].flatten.include?('something@example.fr')
end
def test_update
@request.session[:user_id] = 2
email = EmailAddress.create!(:user_id => 2, :address => 'another@somenet.foo')
put :update, :params => {
:user_id => 2,
:id => email.id,
:notify => '0'
}
assert_response 302
assert_equal false, email.reload.notify
end
def test_update_as_js
@request.session[:user_id] = 2
email = EmailAddress.create!(:user_id => 2, :address => 'another@somenet.foo')
put :update, :params => {
:user_id => 2,
:id => email.id,
:notify => '0'
},
:xhr => true
assert_response 200
assert_equal false, email.reload.notify
end
def test_update_should_send_security_notification
@request.session[:user_id] = 2
email = EmailAddress.create!(:user_id => 2, :address => 'another@somenet.foo')
ActionMailer::Base.deliveries.clear
put :update, :params => {
:user_id => 2,
:id => email.id,
:notify => '0'
},
:xhr => true
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match I18n.t(:mail_body_security_notification_notify_disabled, value: 'another@somenet.foo'), mail
# The changed address should be notified for security purposes
assert [mail.bcc, mail.cc].flatten.include?('another@somenet.foo')
end
def test_destroy
@request.session[:user_id] = 2
email = EmailAddress.create!(:user_id => 2, :address => 'another@somenet.foo')
assert_difference 'EmailAddress.count', -1 do
delete :destroy, :params => {
:user_id => 2,
:id => email.id
}
assert_response 302
assert_redirected_to '/users/2/email_addresses'
end
end
def test_destroy_as_js
@request.session[:user_id] = 2
email = EmailAddress.create!(:user_id => 2, :address => 'another@somenet.foo')
assert_difference 'EmailAddress.count', -1 do
delete :destroy, :params => {
:user_id => 2,
:id => email.id
},
:xhr => true
assert_response 200
end
end
def test_should_not_destroy_default
@request.session[:user_id] = 2
assert_no_difference 'EmailAddress.count' do
delete :destroy, :params => {
:user_id => 2,
:id => User.find(2).email_address.id
}
assert_response 404
end
end
def test_destroy_should_send_security_notification
@request.session[:user_id] = 2
email = EmailAddress.create!(:user_id => 2, :address => 'another@somenet.foo')
ActionMailer::Base.deliveries.clear
delete :destroy, :params => {
:user_id => 2,
:id => email.id
},
:xhr => true
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match I18n.t(:mail_body_security_notification_remove, field: I18n.t(:field_mail), value: 'another@somenet.foo'), mail
# The removed address should be notified for security purposes
assert [mail.bcc, mail.cc].flatten.include?('another@somenet.foo')
end
end

View file

@ -0,0 +1,186 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class EnumerationsControllerTest < Redmine::ControllerTest
fixtures :enumerations, :issues, :users
def setup
@request.session[:user_id] = 1 # admin
end
def test_index
get :index
assert_response :success
assert_select 'table.enumerations'
end
def test_index_should_require_admin
@request.session[:user_id] = nil
get :index
assert_response 302
end
def test_new
get :new, :params => {
:type => 'IssuePriority'
}
assert_response :success
assert_select 'input[name=?][value=?]', 'enumeration[type]', 'IssuePriority'
assert_select 'input[name=?]', 'enumeration[name]'
end
def test_new_with_invalid_type_should_respond_with_404
get :new, :params => {
:type => 'UnknownType'
}
assert_response 404
end
def test_create
assert_difference 'IssuePriority.count' do
post :create, :params => {
:enumeration => {
:type => 'IssuePriority',
:name => 'Lowest'
}
}
end
assert_redirected_to '/enumerations'
e = IssuePriority.find_by_name('Lowest')
assert_not_nil e
end
def test_create_with_failure
assert_no_difference 'IssuePriority.count' do
post :create, :params => {
:enumeration => {
:type => 'IssuePriority',
:name => ''
}
}
end
assert_response :success
assert_select_error /name cannot be blank/i
end
def test_edit
get :edit, :params => {
:id => 6
}
assert_response :success
assert_select 'input[name=?][value=?]', 'enumeration[name]', 'High'
end
def test_edit_invalid_should_respond_with_404
get :edit, :params => {
:id => 999
}
assert_response 404
end
def test_update
assert_no_difference 'IssuePriority.count' do
put :update, :params => {
:id => 6,
:enumeration => {
:type => 'IssuePriority',
:name => 'New name'
}
}
end
assert_redirected_to '/enumerations'
e = IssuePriority.find(6)
assert_equal 'New name', e.name
end
def test_update_with_failure
assert_no_difference 'IssuePriority.count' do
put :update, :params => {
:id => 6,
:enumeration => {
:type => 'IssuePriority',
:name => ''
}
}
end
assert_response :success
assert_select_error /name cannot be blank/i
end
def test_update_position
assert_equal 2, Enumeration.find(2).position
put :update, :params => {
:id => 2,
:enumeration => {
:position => 1,
}
}
assert_response 302
assert_equal 1, Enumeration.find(2).position
end
def test_destroy_enumeration_not_in_use
assert_difference 'IssuePriority.count', -1 do
delete :destroy, :params => {
:id => 7
}
end
assert_redirected_to :controller => 'enumerations', :action => 'index'
assert_nil Enumeration.find_by_id(7)
end
def test_destroy_enumeration_in_use
assert_no_difference 'IssuePriority.count' do
delete :destroy, :params => {
:id => 4
}
end
assert_response :success
assert_not_nil Enumeration.find_by_id(4)
assert_select 'select[name=reassign_to_id]' do
assert_select 'option[value="6"]', :text => 'High'
end
end
def test_destroy_enumeration_in_use_with_reassignment
issue = Issue.where(:priority_id => 4).first
assert_difference 'IssuePriority.count', -1 do
delete :destroy, :params => {
:id => 4,
:reassign_to_id => 6
}
end
assert_redirected_to :controller => 'enumerations', :action => 'index'
assert_nil Enumeration.find_by_id(4)
# check that the issue was reassign
assert_equal 6, issue.reload.priority_id
end
def test_destroy_enumeration_in_use_with_blank_reassignment
assert_no_difference 'IssuePriority.count' do
delete :destroy, :params => {
:id => 4,
:reassign_to_id => ''
}
end
assert_response :success
end
end

View file

@ -0,0 +1,136 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class FilesControllerTest < Redmine::ControllerTest
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :users,
:email_addresses,
:issue_categories,
:projects_trackers,
:roles,
:member_roles,
:members,
:enabled_modules,
:journals, :journal_details,
:attachments,
:versions
def setup
@request.session[:user_id] = nil
Setting.default_language = 'en'
end
def test_index
get :index, :params => {
:project_id => 1
}
assert_response :success
# file attached to the project
assert_select 'a[href=?]', '/attachments/download/8/project_file.zip', :text => 'project_file.zip'
# file attached to a project's version
assert_select 'a[href=?]', '/attachments/download/9/version_file.zip', :text => 'version_file.zip'
end
def test_new
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 1
}
assert_response :success
assert_select 'select[name=?]', 'version_id'
end
def test_new_without_versions
Version.delete_all
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 1
}
assert_response :success
assert_select 'select[name=?]', 'version_id', 0
end
def test_create_file
set_tmp_attachments_directory
@request.session[:user_id] = 2
ActionMailer::Base.deliveries.clear
with_settings :notified_events => %w(file_added) do
assert_difference 'Attachment.count' do
post :create, :params => {
:project_id => 1,
:version_id => '',
:attachments => {
'1' => {
'file' => uploaded_test_file('testfile.txt', 'text/plain')}
}
}
assert_response :redirect
end
end
assert_redirected_to '/projects/ecookbook/files'
a = Attachment.order('created_on DESC').first
assert_equal 'testfile.txt', a.filename
assert_equal Project.find(1), a.container
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
assert_equal "[eCookbook] New file", mail.subject
assert_mail_body_match 'testfile.txt', mail
end
def test_create_version_file
set_tmp_attachments_directory
@request.session[:user_id] = 2
assert_difference 'Attachment.count' do
post :create, :params => {
:project_id => 1,
:version_id => '2',
:attachments => {
'1' => {
'file' => uploaded_test_file('testfile.txt', 'text/plain')}
}
}
assert_response :redirect
end
assert_redirected_to '/projects/ecookbook/files'
a = Attachment.order('created_on DESC').first
assert_equal 'testfile.txt', a.filename
assert_equal Version.find(2), a.container
end
def test_create_without_file
set_tmp_attachments_directory
@request.session[:user_id] = 2
assert_no_difference 'Attachment.count' do
post :create, :params => {
:project_id => 1,
:version_id => ''
}
assert_response :success
end
assert_select 'div.error', 'File is invalid'
end
end

View file

@ -0,0 +1,140 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class GanttsControllerTest < Redmine::ControllerTest
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :users, :issue_categories,
:projects_trackers,
:roles,
:member_roles,
:members,
:enabled_modules,
:versions
def test_gantt_should_work
i2 = Issue.find(2)
i2.update_attribute(:due_date, 1.month.from_now)
get :show, :params => {
:project_id => 1
}
assert_response :success
# Issue with start and due dates
i = Issue.find(1)
assert_not_nil i.due_date
assert_select "div a.issue", /##{i.id}/
# Issue with on a targeted version should not be in the events but loaded in the html
i = Issue.find(2)
assert_select "div a.issue", /##{i.id}/
end
def test_gantt_at_minimal_zoom
get :show, :params => {
:project_id => 1,
:zoom => 1
}
assert_response :success
assert_select 'input[type=hidden][name=zoom][value=?]', '1'
end
def test_gantt_at_maximal_zoom
get :show, :params => {
:project_id => 1,
:zoom => 4
}
assert_response :success
assert_select 'input[type=hidden][name=zoom][value=?]', '4'
end
def test_gantt_should_work_without_issue_due_dates
Issue.update_all("due_date = NULL")
get :show, :params => {
:project_id => 1
}
assert_response :success
end
def test_gantt_should_work_without_issue_and_version_due_dates
Issue.update_all("due_date = NULL")
Version.update_all("effective_date = NULL")
get :show, :params => {
:project_id => 1
}
assert_response :success
end
def test_gantt_should_work_cross_project
get :show
assert_response :success
end
def test_gantt_should_not_disclose_private_projects
get :show
assert_response :success
assert_select 'a', :text => /eCookbook/
# Root private project
assert_select 'a', :text => /OnlineStore/, :count => 0
# Private children of a public project
assert_select 'a', :text => /Private child of eCookbook/, :count => 0
end
def test_gantt_should_display_relations
IssueRelation.delete_all
issue1 = Issue.generate!(:start_date => 1.day.from_now.to_date, :due_date => 3.day.from_now.to_date)
issue2 = Issue.generate!(:start_date => 1.day.from_now.to_date, :due_date => 3.day.from_now.to_date)
IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => 'precedes')
get :show
assert_response :success
assert_select 'div.task_todo[id=?][data-rels*=?]', "task-todo-issue-#{issue1.id}", issue2.id.to_s
assert_select 'div.task_todo[id=?]:not([data-rels])', "task-todo-issue-#{issue2.id}"
end
def test_gantt_should_export_to_pdf
get :show, :params => {
:project_id => 1,
:format => 'pdf'
}
assert_response :success
assert_equal 'application/pdf', @response.content_type
assert @response.body.starts_with?('%PDF')
end
def test_gantt_should_export_to_pdf_cross_project
get :show, :params => {
:format => 'pdf'
}
assert_response :success
assert_equal 'application/pdf', @response.content_type
assert @response.body.starts_with?('%PDF')
end
if Object.const_defined?(:Magick)
def test_gantt_should_export_to_png
get :show, :params => {
:project_id => 1,
:format => 'png'
}
assert_response :success
assert_equal 'image/png', @response.content_type
end
end
end

View file

@ -0,0 +1,225 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class GroupsControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :members, :member_roles, :roles, :groups_users
def setup
@request.session[:user_id] = 1
end
def test_index
get :index
assert_response :success
assert_select 'table.groups'
end
def test_index_should_show_user_count
get :index
assert_response :success
assert_select 'tr#group-11 td.user_count', :text => '1'
end
def test_index_with_name_filter
Group.generate!(:name => "Clients")
get :index, :params => {
:name => "cli"
}
assert_response :success
assert_select 'table.groups tbody tr', 1
assert_select 'table.groups tbody td.name', :text => 'Clients'
end
def test_show
get :show, :params => {
:id => 10
}
assert_response :success
end
def test_show_invalid_should_return_404
get :show, :params => {
:id => 99
}
assert_response 404
end
def test_new
get :new
assert_response :success
assert_select 'input[name=?]', 'group[name]'
end
def test_create
assert_difference 'Group.count' do
post :create, :params => {
:group => {
:name => 'New group'
}
}
end
assert_redirected_to '/groups'
group = Group.order('id DESC').first
assert_equal 'New group', group.name
assert_equal [], group.users
end
def test_create_and_continue
assert_difference 'Group.count' do
post :create, :params => {
:group => {
:name => 'New group'
},
:continue => 'Create and continue'
}
end
assert_redirected_to '/groups/new'
group = Group.order('id DESC').first
assert_equal 'New group', group.name
end
def test_create_with_failure
assert_no_difference 'Group.count' do
post :create, :params => {
:group => {
:name => ''
}
}
end
assert_response :success
assert_select_error /Name cannot be blank/i
end
def test_edit
get :edit, :params => {
:id => 10
}
assert_response :success
assert_select 'div#tab-content-users'
assert_select 'div#tab-content-memberships' do
assert_select 'a', :text => 'Private child of eCookbook'
end
end
def test_update
new_name = 'New name'
put :update, :params => {
:id => 10,
:group => {
:name => new_name
}
}
assert_redirected_to '/groups'
group = Group.find(10)
assert_equal new_name, group.name
end
def test_update_with_failure
put :update, :params => {
:id => 10,
:group => {
:name => ''
}
}
assert_response :success
assert_select_error /Name cannot be blank/i
end
def test_destroy
assert_difference 'Group.count', -1 do
post :destroy, :params => {
:id => 10
}
end
assert_redirected_to '/groups'
end
def test_new_users
get :new_users, :params => {
:id => 10
}
assert_response :success
assert_select 'input[name=?]', 'user_search'
end
def test_xhr_new_users
get :new_users, :params => {
:id => 10
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
def test_add_users
assert_difference 'Group.find(10).users.count', 2 do
post :add_users, :params => {
:id => 10,
:user_ids => ['2', '3']
}
end
end
def test_xhr_add_users
assert_difference 'Group.find(10).users.count', 2 do
post :add_users, :params => {
:id => 10,
:user_ids => ['2', '3']
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_match /John Smith/, response.body
end
def test_remove_user
assert_difference 'Group.find(10).users.count', -1 do
delete :remove_user, :params => {
:id => 10,
:user_id => '8'
}
end
end
def test_xhr_remove_user
assert_difference 'Group.find(10).users.count', -1 do
delete :remove_user, :params => {
:id => 10,
:user_id => '8'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
end
def test_autocomplete_for_user
get :autocomplete_for_user, :params => {
:id => 10,
:q => 'smi',
:format => 'js'
},
:xhr => true
assert_response :success
assert_include 'John Smith', response.body
end
end

View file

@ -0,0 +1,266 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class ImportsControllerTest < Redmine::ControllerTest
fixtures :projects, :enabled_modules,
:users, :email_addresses,
:roles, :members, :member_roles,
:issues, :issue_statuses,
:trackers, :projects_trackers,
:versions,
:issue_categories,
:enumerations,
:workflows,
:custom_fields,
:custom_values,
:custom_fields_projects,
:custom_fields_trackers
def setup
User.current = nil
@request.session[:user_id] = 2
end
def teardown
Import.destroy_all
end
def test_new_should_display_the_upload_form
get :new
assert_response :success
assert_select 'input[name=?]', 'file'
end
def test_create_should_save_the_file
import = new_record(Import) do
post :create, :params => {
:file => uploaded_test_file('import_issues.csv', 'text/csv')
}
assert_response 302
end
assert_equal 2, import.user_id
assert_match /\A[0-9a-f]+\z/, import.filename
assert import.file_exists?
end
def test_get_settings_should_display_settings_form
import = generate_import
get :settings, :params => {
:id => import.to_param
}
assert_response :success
assert_select 'select[name=?]', 'import_settings[separator]'
assert_select 'select[name=?]', 'import_settings[wrapper]'
assert_select 'select[name=?]', 'import_settings[encoding]'
assert_select 'select[name=?]', 'import_settings[date_format]'
end
def test_post_settings_should_update_settings
import = generate_import
post :settings, :params => {
:id => import.to_param,
:import_settings => {
:separator => ":",
:wrapper => "|",
:encoding => "UTF-8",
:date_format => '%m/%d/%Y'
}
}
assert_redirected_to "/imports/#{import.to_param}/mapping"
import.reload
assert_equal ":", import.settings['separator']
assert_equal "|", import.settings['wrapper']
assert_equal "UTF-8", import.settings['encoding']
assert_equal '%m/%d/%Y', import.settings['date_format']
end
def test_post_settings_should_update_total_items_count
import = generate_import('import_iso8859-1.csv')
post :settings, :params => {
:id => import.to_param,
:import_settings => {
:separator => ";",
:wrapper => '"',
:encoding => "ISO-8859-1"
}
}
assert_response 302
import.reload
assert_equal 2, import.total_items
end
def test_post_settings_with_wrong_encoding_should_display_error
import = generate_import('import_iso8859-1.csv')
post :settings, :params => {
:id => import.to_param,
:import_settings => {
:separator => ";",
:wrapper => '"',
:encoding => "UTF-8"
}
}
assert_response 200
import.reload
assert_nil import.total_items
assert_select 'div#flash_error', /not a valid UTF-8 encoded file/
end
def test_post_settings_with_invalid_encoding_should_display_error
import = generate_import('invalid-Shift_JIS.csv')
post :settings, :params => {
:id => import.to_param,
:import_settings => {
:separator => ";",
:wrapper => '"',
:encoding => "Shift_JIS"
}
}
assert_response 200
import.reload
assert_nil import.total_items
assert_select 'div#flash_error', /not a valid Shift_JIS encoded file/
end
def test_get_mapping_should_display_mapping_form
import = generate_import('import_iso8859-1.csv')
import.settings = {'separator' => ";", 'wrapper' => '"', 'encoding' => "ISO-8859-1"}
import.save!
get :mapping, :params => {
:id => import.to_param
}
assert_response :success
assert_select 'select[name=?]', 'import_settings[mapping][subject]' do
assert_select 'option', 4
assert_select 'option[value="0"]', :text => 'column A'
end
assert_select 'table.sample-data' do
assert_select 'tr', 3
assert_select 'td', 9
end
end
def test_post_mapping_should_update_mapping
import = generate_import('import_iso8859-1.csv')
post :mapping, :params => {
:id => import.to_param,
:import_settings => {
:mapping => {
:project_id => '1',
:tracker_id => '2',
:subject => '0'}
}
}
assert_redirected_to "/imports/#{import.to_param}/run"
import.reload
mapping = import.settings['mapping']
assert mapping
assert_equal '1', mapping['project_id']
assert_equal '2', mapping['tracker_id']
assert_equal '0', mapping['subject']
end
def test_get_run
import = generate_import_with_mapping
get :run, :params => {
:id => import
}
assert_response :success
assert_select '#import-progress'
end
def test_post_run_should_import_the_file
import = generate_import_with_mapping
assert_difference 'Issue.count', 3 do
post :run, :params => {
:id => import
}
assert_redirected_to "/imports/#{import.to_param}"
end
import.reload
assert_equal true, import.finished
assert_equal 3, import.items.count
issues = Issue.order(:id => :desc).limit(3).to_a
assert_equal ["Child of existing issue", "Child 1", "First"], issues.map(&:subject)
end
def test_post_run_should_import_max_items_and_resume
ImportsController.any_instance.stubs(:max_items_per_request).returns(2)
import = generate_import_with_mapping
assert_difference 'Issue.count', 2 do
post :run, :params => {
:id => import
}
assert_redirected_to "/imports/#{import.to_param}/run"
end
assert_difference 'Issue.count', 1 do
post :run, :params => {
:id => import
}
assert_redirected_to "/imports/#{import.to_param}"
end
issues = Issue.order(:id => :desc).limit(3).to_a
assert_equal ["Child of existing issue", "Child 1", "First"], issues.map(&:subject)
end
def test_show_without_errors
import = generate_import_with_mapping
import.run
assert_equal 0, import.unsaved_items.count
get :show, :params => {
:id => import.to_param
}
assert_response :success
assert_select 'ul#saved-items'
assert_select 'ul#saved-items li', import.saved_items.count
assert_select 'table#unsaved-items', 0
end
def test_show_with_errors_should_show_unsaved_items
import = generate_import_with_mapping
import.mapping.merge! 'subject' => 20
import.run
assert_not_equal 0, import.unsaved_items.count
get :show, :params => {
:id => import.to_param
}
assert_response :success
assert_select 'table#unsaved-items'
assert_select 'table#unsaved-items tbody tr', import.unsaved_items.count
end
end

View file

@ -0,0 +1,196 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class IssueCategoriesControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :members, :member_roles, :roles, :enabled_modules, :issue_categories,
:issues
def setup
User.current = nil
@request.session[:user_id] = 2
end
def test_new
@request.session[:user_id] = 2 # manager
get :new, :params => {
:project_id => '1'
}
assert_response :success
assert_select 'input[name=?]', 'issue_category[name]'
end
def test_new_from_issue_form
@request.session[:user_id] = 2 # manager
get :new, :params => {
:project_id => '1'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
def test_create
@request.session[:user_id] = 2 # manager
assert_difference 'IssueCategory.count' do
post :create, :params => {
:project_id => '1',
:issue_category => {
:name => 'New category'
}
}
end
assert_redirected_to '/projects/ecookbook/settings/categories'
category = IssueCategory.find_by_name('New category')
assert_not_nil category
assert_equal 1, category.project_id
end
def test_create_failure
@request.session[:user_id] = 2
post :create, :params => {
:project_id => '1',
:issue_category => {
:name => ''
}
}
assert_response :success
assert_select_error /Name cannot be blank/i
end
def test_create_from_issue_form
@request.session[:user_id] = 2 # manager
assert_difference 'IssueCategory.count' do
post :create, :params => {
:project_id => '1',
:issue_category => {
:name => 'New category'
}
},
:xhr => true
end
category = IssueCategory.order('id DESC').first
assert_equal 'New category', category.name
assert_response :success
assert_equal 'text/javascript', response.content_type
end
def test_create_from_issue_form_with_failure
@request.session[:user_id] = 2 # manager
assert_no_difference 'IssueCategory.count' do
post :create, :params => {
:project_id => '1',
:issue_category => {
:name => ''
}
},
:xhr => true
end
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include 'Name cannot be blank', response.body
end
def test_edit
@request.session[:user_id] = 2
get :edit, :params => {
:id => 2
}
assert_response :success
assert_select 'input[name=?][value=?]', 'issue_category[name]', 'Recipes'
end
def test_update
assert_no_difference 'IssueCategory.count' do
put :update, :params => {
:id => 2,
:issue_category => {
:name => 'Testing'
}
}
end
assert_redirected_to '/projects/ecookbook/settings/categories'
assert_equal 'Testing', IssueCategory.find(2).name
end
def test_update_failure
put :update, :params => {
:id => 2,
:issue_category => {
:name => ''
}
}
assert_response :success
assert_select_error /Name cannot be blank/i
end
def test_update_not_found
put :update, :params => {
:id => 97,
:issue_category => {
:name => 'Testing'
}
}
assert_response 404
end
def test_destroy_category_not_in_use
delete :destroy, :params => {
:id => 2
}
assert_redirected_to '/projects/ecookbook/settings/categories'
assert_nil IssueCategory.find_by_id(2)
end
def test_destroy_category_in_use
delete :destroy, :params => {
:id => 1
}
assert_response :success
assert_not_nil IssueCategory.find_by_id(1)
assert_select 'select[name=?]', 'reassign_to_id'
end
def test_destroy_category_in_use_with_reassignment
issue = Issue.where(:category_id => 1).first
delete :destroy, :params => {
:id => 1,
:todo => 'reassign',
:reassign_to_id => 2
}
assert_redirected_to '/projects/ecookbook/settings/categories'
assert_nil IssueCategory.find_by_id(1)
# check that the issue was reassign
assert_equal 2, issue.reload.category_id
end
def test_destroy_category_in_use_without_reassignment
issue = Issue.where(:category_id => 1).first
delete :destroy, :params => {
:id => 1,
:todo => 'nullify'
}
assert_redirected_to '/projects/ecookbook/settings/categories'
assert_nil IssueCategory.find_by_id(1)
# check that the issue category was nullified
assert_nil issue.reload.category_id
end
end

View file

@ -0,0 +1,222 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class IssueRelationsControllerTest < Redmine::ControllerTest
fixtures :projects,
:users,
:roles,
:members,
:member_roles,
:issues,
:issue_statuses,
:issue_relations,
:enabled_modules,
:enumerations,
:trackers,
:projects_trackers
def setup
User.current = nil
@request.session[:user_id] = 3
end
def test_create
assert_difference 'IssueRelation.count' do
post :create, :params => {
:issue_id => 1,
:relation => {
:issue_to_id => '2',
:relation_type => 'relates',
:delay => ''
}
}
end
relation = IssueRelation.order('id DESC').first
assert_equal 1, relation.issue_from_id
assert_equal 2, relation.issue_to_id
assert_equal 'relates', relation.relation_type
end
def test_create_on_invalid_issue
assert_no_difference 'IssueRelation.count' do
post :create, :params => {
:issue_id => 999,
:relation => {
:issue_to_id => '2',
:relation_type => 'relates',
:delay => ''
}
}
assert_response 404
end
end
def test_create_xhr
assert_difference 'IssueRelation.count' do
post :create, :params => {
:issue_id => 3,
:relation => {
:issue_to_id => '1',
:relation_type => 'relates',
:delay => ''
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
relation = IssueRelation.order('id DESC').first
assert_equal 1, relation.issue_from_id
assert_equal 3, relation.issue_to_id
assert_include 'Bug #1', response.body
end
def test_create_should_accept_id_with_hash
assert_difference 'IssueRelation.count' do
post :create, :params => {
:issue_id => 1,
:relation => {
:issue_to_id => '#2',
:relation_type => 'relates',
:delay => ''
}
}
end
relation = IssueRelation.order('id DESC').first
assert_equal 2, relation.issue_to_id
end
def test_create_should_strip_id
assert_difference 'IssueRelation.count' do
post :create, :params => {
:issue_id => 1,
:relation => {
:issue_to_id => ' 2 ',
:relation_type => 'relates',
:delay => ''
}
}
end
relation = IssueRelation.order('id DESC').first
assert_equal 2, relation.issue_to_id
end
def test_create_should_not_break_with_non_numerical_id
assert_no_difference 'IssueRelation.count' do
assert_nothing_raised do
post :create, :params => {
:issue_id => 1,
:relation => {
:issue_to_id => 'foo',
:relation_type => 'relates',
:delay => ''
}
}
end
end
end
def test_create_follows_relation_should_update_relations_list
issue1 = Issue.generate!(:subject => 'Followed issue', :start_date => Date.yesterday, :due_date => Date.today)
issue2 = Issue.generate!
assert_difference 'IssueRelation.count' do
post :create, :params => {
:issue_id => issue2.id,
:relation => {
:issue_to_id => issue1.id,
:relation_type => 'follows',
:delay => ''
}
},
:xhr => true
end
assert_include 'Followed issue', response.body
end
def test_should_create_relations_with_visible_issues_only
Setting.cross_project_issue_relations = '1'
assert_nil Issue.visible(User.find(3)).find_by_id(4)
assert_no_difference 'IssueRelation.count' do
post :create, :params => {
:issue_id => 1,
:relation => {
:issue_to_id => '4',
:relation_type => 'relates',
:delay => ''
}
}
end
end
def test_create_xhr_with_failure
assert_no_difference 'IssueRelation.count' do
post :create, :params => {
:issue_id => 3,
:relation => {
:issue_to_id => '999',
:relation_type => 'relates',
:delay => ''
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_include 'Related issue cannot be blank', response.body
end
def test_destroy
assert_difference 'IssueRelation.count', -1 do
delete :destroy, :params => {
:id => '2'
}
end
end
def test_destroy_invalid_relation
assert_no_difference 'IssueRelation.count' do
delete :destroy, :params => {
:id => '999'
}
assert_response 404
end
end
def test_destroy_xhr
IssueRelation.create!(:relation_type => IssueRelation::TYPE_RELATES) do |r|
r.issue_from_id = 3
r.issue_to_id = 1
end
assert_difference 'IssueRelation.count', -1 do
delete :destroy, :params => {
:id => '2'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include 'relation-2', response.body
end
end
end

View file

@ -0,0 +1,160 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class IssueStatusesControllerTest < Redmine::ControllerTest
fixtures :issue_statuses, :issues, :users, :trackers
def setup
User.current = nil
@request.session[:user_id] = 1 # admin
end
def test_index
get :index
assert_response :success
assert_select 'table.issue_statuses'
end
def test_index_by_anonymous_should_redirect_to_login_form
@request.session[:user_id] = nil
get :index
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fissue_statuses'
end
def test_index_by_user_should_respond_with_406
@request.session[:user_id] = 2
get :index
assert_response 406
end
def test_new
get :new
assert_response :success
assert_select 'input[name=?]', 'issue_status[name]'
end
def test_create
assert_difference 'IssueStatus.count' do
post :create, :params => {
:issue_status => {
:name => 'New status'
}
}
end
assert_redirected_to :action => 'index'
status = IssueStatus.order('id DESC').first
assert_equal 'New status', status.name
end
def test_create_with_failure
post :create, :params => {
:issue_status => {
:name => ''
}
}
assert_response :success
assert_select_error /name cannot be blank/i
end
def test_edit
get :edit, :params => {
:id => '3'
}
assert_response :success
assert_select 'input[name=?][value=?]', 'issue_status[name]', 'Resolved'
end
def test_update
put :update, :params => {
:id => '3',
:issue_status => {
:name => 'Renamed status'
}
}
assert_redirected_to :action => 'index'
status = IssueStatus.find(3)
assert_equal 'Renamed status', status.name
end
def test_update_with_failure
put :update, :params => {
:id => '3',
:issue_status => {
:name => ''
}
}
assert_response :success
assert_select_error /name cannot be blank/i
end
def test_destroy
Issue.where(:status_id => 1).delete_all
Tracker.where(:default_status_id => 1).delete_all
assert_difference 'IssueStatus.count', -1 do
delete :destroy, :params => {
:id => '1'
}
end
assert_redirected_to :action => 'index'
assert_nil IssueStatus.find_by_id(1)
end
def test_destroy_should_block_if_status_is_used_by_issues
assert Issue.where(:status_id => 1).any?
Tracker.where(:default_status_id => 1).delete_all
assert_no_difference 'IssueStatus.count' do
delete :destroy, :params => {
:id => '1'
}
end
assert_redirected_to :action => 'index'
assert_not_nil IssueStatus.find_by_id(1)
end
def test_destroy_should_block_if_status_is_used_as_tracker_default_status
Issue.where(:status_id => 1).delete_all
assert Tracker.where(:default_status_id => 1).any?
assert_no_difference 'IssueStatus.count' do
delete :destroy, :params => {
:id => '1'
}
end
assert_redirected_to :action => 'index'
assert_not_nil IssueStatus.find_by_id(1)
end
def test_update_issue_done_ratio_with_issue_done_ratio_set_to_issue_field
with_settings :issue_done_ratio => 'issue_field' do
post :update_issue_done_ratio
assert_match /not updated/, flash[:error].to_s
assert_redirected_to '/issue_statuses'
end
end
def test_update_issue_done_ratio_with_issue_done_ratio_set_to_issue_status
with_settings :issue_done_ratio => 'issue_status' do
post :update_issue_done_ratio
assert_match /Issue done ratios updated/, flash[:notice].to_s
assert_redirected_to '/issue_statuses'
end
end
end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,339 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
require 'issues_controller'
class IssuesControllerTransactionTest < Redmine::ControllerTest
tests IssuesController
fixtures :projects,
:users,
:roles,
:members,
:member_roles,
:issues,
:issue_statuses,
:versions,
:trackers,
:projects_trackers,
:issue_categories,
:enabled_modules,
:enumerations,
:attachments,
:workflows,
:custom_fields,
:custom_values,
:custom_fields_projects,
:custom_fields_trackers,
:time_entries,
:journals,
:journal_details,
:queries
self.use_transactional_fixtures = false
def setup
User.current = nil
end
def test_update_stale_issue_should_not_update_the_issue
issue = Issue.find(2)
@request.session[:user_id] = 2
assert_no_difference 'Journal.count' do
assert_no_difference 'TimeEntry.count' do
put :update, :params => {
:id => issue.id,
:issue => {
:fixed_version_id => 4,
:notes => 'My notes',
:lock_version => (issue.lock_version - 1)
},
:time_entry => {
:hours => '2.5',
:comments => '',
:activity_id => TimeEntryActivity.first.id
}
}
end
end
assert_response :success
assert_select 'div.conflict'
assert_select 'input[name=?][value=?]', 'conflict_resolution', 'overwrite'
assert_select 'input[name=?][value=?]', 'conflict_resolution', 'add_notes'
assert_select 'label' do
assert_select 'input[name=?][value=?]', 'conflict_resolution', 'cancel'
assert_select 'a[href="/issues/2"]'
end
end
def test_update_stale_issue_should_save_attachments
set_tmp_attachments_directory
issue = Issue.find(2)
@request.session[:user_id] = 2
assert_no_difference 'Journal.count' do
assert_no_difference 'TimeEntry.count' do
assert_difference 'Attachment.count' do
put :update, :params => {
:id => issue.id,
:issue => {
:fixed_version_id => 4,
:notes => 'My notes',
:lock_version => (issue.lock_version - 1)
},
:attachments => {
'1' => {
'file' => uploaded_test_file('testfile.txt', 'text/plain')}
},
:time_entry => {
:hours => '2.5',
:comments => '',
:activity_id => TimeEntryActivity.first.id
}
}
end
end
end
assert_response :success
attachment = Attachment.order('id DESC').first
assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
end
def test_update_stale_issue_without_notes_should_not_show_add_notes_option
issue = Issue.find(2)
@request.session[:user_id] = 2
put :update, :params => {
:id => issue.id,
:issue => {
:fixed_version_id => 4,
:notes => '',
:lock_version => (issue.lock_version - 1)
}
}
assert_response :success
assert_select 'div.conflict'
assert_select 'input[name=conflict_resolution][value=overwrite]'
assert_select 'input[name=conflict_resolution][value=add_notes]', 0
assert_select 'input[name=conflict_resolution][value=cancel]'
end
def test_update_stale_issue_should_show_conflicting_journals
@request.session[:user_id] = 2
put :update, :params => {
:id => 1,
:issue => {
:fixed_version_id => 4,
:notes => '',
:lock_version => 2
},
:last_journal_id => 1
}
assert_response :success
assert_select '.conflict-journal', 1
assert_select 'div.conflict', :text => /Some notes with Redmine links/
end
def test_update_stale_issue_without_previous_journal_should_show_all_journals
@request.session[:user_id] = 2
put :update, :params => {
:id => 1,
:issue => {
:fixed_version_id => 4,
:notes => '',
:lock_version => 2
},
:last_journal_id => ''
}
assert_response :success
assert_select '.conflict-journal', 2
assert_select 'div.conflict', :text => /Some notes with Redmine links/
assert_select 'div.conflict', :text => /Journal notes/
end
def test_update_stale_issue_should_show_private_journals_with_permission_only
journal = Journal.create!(:journalized => Issue.find(1), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
@request.session[:user_id] = 2
put :update, :params => {
:id => 1,
:issue => {
:fixed_version_id => 4,
:lock_version => 2
},
:last_journal_id => ''
}
assert_response :success
assert_select '.conflict-journal', :text => /Privates notes/
Role.find(1).remove_permission! :view_private_notes
put :update, :params => {
:id => 1,
:issue => {
:fixed_version_id => 4,
:lock_version => 2
},
:last_journal_id => ''
}
assert_response :success
assert_select '.conflict-journal', :text => /Privates notes/, :count => 0
end
def test_update_stale_issue_with_overwrite_conflict_resolution_should_update
@request.session[:user_id] = 2
assert_difference 'Journal.count' do
put :update, :params => {
:id => 1,
:issue => {
:fixed_version_id => 4,
:notes => 'overwrite_conflict_resolution',
:lock_version => 2
},
:conflict_resolution => 'overwrite'
}
end
assert_response 302
issue = Issue.find(1)
assert_equal 4, issue.fixed_version_id
journal = Journal.order('id DESC').first
assert_equal 'overwrite_conflict_resolution', journal.notes
assert journal.details.any?
end
def test_update_stale_issue_with_add_notes_conflict_resolution_should_update
@request.session[:user_id] = 2
assert_difference 'Journal.count' do
put :update, :params => {
:id => 1,
:issue => {
:fixed_version_id => 4,
:notes => 'add_notes_conflict_resolution',
:lock_version => 2
},
:conflict_resolution => 'add_notes'
}
end
assert_response 302
issue = Issue.find(1)
assert_nil issue.fixed_version_id
journal = Journal.order('id DESC').first
assert_equal 'add_notes_conflict_resolution', journal.notes
assert_equal false, journal.private_notes
assert journal.details.empty?
end
def test_update_stale_issue_with_add_notes_conflict_resolution_should_preserve_private_notes
@request.session[:user_id] = 2
journal = new_record(Journal) do
put :update, :params => {
:id => 1,
:issue => {
:fixed_version_id => 4,
:notes => 'add_privates_notes_conflict_resolution',
:private_notes => '1',
:lock_version => 2
},
:conflict_resolution => 'add_notes'
}
end
assert_response 302
assert_equal 'add_privates_notes_conflict_resolution', journal.notes
assert_equal true, journal.private_notes
assert journal.details.empty?
end
def test_update_stale_issue_with_cancel_conflict_resolution_should_redirect_without_updating
@request.session[:user_id] = 2
assert_no_difference 'Journal.count' do
put :update, :params => {
:id => 1,
:issue => {
:fixed_version_id => 4,
:notes => 'add_notes_conflict_resolution',
:lock_version => 2
},
:conflict_resolution => 'cancel'
}
end
assert_redirected_to '/issues/1'
issue = Issue.find(1)
assert_nil issue.fixed_version_id
end
def test_put_update_with_spent_time_and_failure_should_not_add_spent_time
@request.session[:user_id] = 2
assert_no_difference('TimeEntry.count') do
put :update, :params => {
:id => 1,
:issue => {
:subject => ''
},
:time_entry => {
:hours => '2.5',
:comments => 'should not be added',
:activity_id => TimeEntryActivity.first.id
}
}
assert_response :success
end
assert_select 'input[name=?][value=?]', 'time_entry[hours]', '2.50'
assert_select 'input[name=?][value=?]', 'time_entry[comments]', 'should not be added'
assert_select 'select[name=?]', 'time_entry[activity_id]' do
assert_select 'option[value=?][selected=selected]', TimeEntryActivity.first.id.to_s
end
end
def test_index_should_rescue_invalid_sql_query
IssueQuery.any_instance.stubs(:statement).returns("INVALID STATEMENT")
get :index
assert_response 500
assert_select 'p', :text => /An error occurred/
assert_nil session[:query]
assert_nil session[:issues_index_sort]
end
end

View file

@ -0,0 +1,368 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class IssuesCustomFieldsVisibilityTest < Redmine::ControllerTest
tests IssuesController
fixtures :projects,
:users, :email_addresses, :user_preferences,
:roles,
:members,
:member_roles,
:issue_statuses,
:trackers,
:projects_trackers,
:enabled_modules,
:enumerations,
:workflows
def setup
CustomField.delete_all
Issue.delete_all
field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :trackers => Tracker.all}
@fields = []
@fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
@fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
@fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
@issue = Issue.generate!(
:author_id => 1,
:project_id => 1,
:tracker_id => 1,
:custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
)
@user_with_role_on_other_project = User.generate!
User.add_to_project(@user_with_role_on_other_project, Project.find(2), Role.find(3))
@users_to_test = {
User.find(1) => [@field1, @field2, @field3],
User.find(3) => [@field1, @field2],
@user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
User.generate! => [@field1],
User.anonymous => [@field1]
}
Member.where(:project_id => 1).each do |member|
member.destroy unless @users_to_test.keys.include?(member.principal)
end
end
def test_show_should_show_visible_custom_fields_only
@users_to_test.each do |user, fields|
@request.session[:user_id] = user.id
get :show, :params => {
:id => @issue.id
}
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_select '.value', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name}"
else
assert_select '.value', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name}"
end
end
end
end
def test_show_should_show_visible_custom_fields_only_in_api
@users_to_test.each do |user, fields|
with_settings :rest_api_enabled => '1' do
get :show, :params => {
:id => @issue.id,
:format => 'xml',
:include => 'custom_fields',
:key => user.api_key
}
end
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_select "custom_field[id=?] value", field.id.to_s, {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name} in API"
else
assert_select "custom_field[id=?] value", field.id.to_s, {:text => "Value#{i}", :count => 0}, "User #{user.id} was not able to view #{field.name} in API"
end
end
end
end
def test_show_should_show_visible_custom_fields_only_in_history
@issue.init_journal(User.find(1))
@issue.custom_field_values = {@field1.id => 'NewValue0', @field2.id => 'NewValue1', @field3.id => 'NewValue2'}
@issue.save!
@users_to_test.each do |user, fields|
@request.session[:user_id] = user.id
get :show, :params => {
:id => @issue.id
}
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_select 'ul.details i', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name} change"
else
assert_select 'ul.details i', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name} change"
end
end
end
end
def test_show_should_show_visible_custom_fields_only_in_history_api
@issue.init_journal(User.find(1))
@issue.custom_field_values = {@field1.id => 'NewValue0', @field2.id => 'NewValue1', @field3.id => 'NewValue2'}
@issue.save!
@users_to_test.each do |user, fields|
with_settings :rest_api_enabled => '1' do
get :show, :params => {
:id => @issue.id,
:format => 'xml',
:include => 'journals',
:key => user.api_key
}
end
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_select 'details old_value', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name} change in API"
else
assert_select 'details old_value', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name} change in API"
end
end
end
end
def test_edit_should_show_visible_custom_fields_only
Role.anonymous.add_permission! :edit_issues
@users_to_test.each do |user, fields|
@request.session[:user_id] = user.id
get :edit, :params => {
:id => @issue.id
}
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_select 'input[value=?]', "Value#{i}", 1, "User #{user.id} was not able to edit #{field.name}"
else
assert_select 'input[value=?]', "Value#{i}", 0, "User #{user.id} was able to edit #{field.name}"
end
end
end
end
def test_update_should_update_visible_custom_fields_only
Role.anonymous.add_permission! :edit_issues
@users_to_test.each do |user, fields|
@request.session[:user_id] = user.id
put :update, :params => {
:id => @issue.id,
:issue => {
:custom_field_values => {
@field1.id.to_s => "User#{user.id}Value0",
@field2.id.to_s => "User#{user.id}Value1",
@field3.id.to_s => "User#{user.id}Value2",
}
}
}
@issue.reload
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_equal "User#{user.id}Value#{i}", @issue.custom_field_value(field), "User #{user.id} was not able to update #{field.name}"
else
assert_not_equal "User#{user.id}Value#{i}", @issue.custom_field_value(field), "User #{user.id} was able to update #{field.name}"
end
end
end
end
def test_index_should_show_visible_custom_fields_only
@users_to_test.each do |user, fields|
@request.session[:user_id] = user.id
get :index, :params => {
:c => (["subject"] + @fields.map{|f| "cf_#{f.id}"})
}
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_select 'td', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name}"
else
assert_select 'td', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name}"
end
end
end
end
def test_index_as_csv_should_show_visible_custom_fields_only
@users_to_test.each do |user, fields|
@request.session[:user_id] = user.id
get :index, :params => {
:c => (["subject"] + @fields.map{|f| "cf_#{f.id}"}),
:format => 'csv'
}
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_include "Value#{i}", response.body, "User #{user.id} was not able to view #{field.name} in CSV"
else
assert_not_include "Value#{i}", response.body, "User #{user.id} was able to view #{field.name} in CSV"
end
end
end
end
def test_index_with_partial_custom_field_visibility
Issue.delete_all
p1 = Project.generate!
p2 = Project.generate!
user = User.generate!
User.add_to_project(user, p1, Role.where(:id => [1, 3]).to_a)
User.add_to_project(user, p2, Role.where(:id => 3).to_a)
Issue.generate!(:project => p1, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueA'})
Issue.generate!(:project => p2, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueB'})
Issue.generate!(:project => p1, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueC'})
@request.session[:user_id] = user.id
get :index, :params => {
:c => ["subject", "cf_#{@field2.id}"]
}
assert_select 'td', :text => 'ValueA'
assert_select 'td', :text => 'ValueB', :count => 0
assert_select 'td', :text => 'ValueC'
get :index, :params => {
:sort => "cf_#{@field2.id}"
}
# ValueB is not visible to user and ignored while sorting
assert_equal %w(ValueB ValueA ValueC), issues_in_list.map{|i| i.custom_field_value(@field2)}
get :index, :params => {
:set_filter => '1', "cf_#{@field2.id}" => '*',
:sort => "cf_#{@field2.id}"
}
assert_equal %w(ValueA ValueC), issues_in_list.map{|i| i.custom_field_value(@field2)}
CustomField.update_all(:field_format => 'list')
get :index, :params => {
:group => "cf_#{@field2.id}"
}
assert_equal %w(ValueA ValueC), issues_in_list.map{|i| i.custom_field_value(@field2)}
end
def test_create_should_send_notifications_according_custom_fields_visibility
# anonymous user is never notified
users_to_test = @users_to_test.reject {|k,v| k.anonymous?}
ActionMailer::Base.deliveries.clear
@request.session[:user_id] = 1
with_settings :bcc_recipients => '1' do
assert_difference 'Issue.count' do
post :create, :params => {
:project_id => 1,
:issue => {
:tracker_id => 1,
:status_id => 1,
:subject => 'New issue',
:priority_id => 5,
:custom_field_values => {
@field1.id.to_s => 'Value0', @field2.id.to_s => 'Value1', @field3.id.to_s => 'Value2'
},
:watcher_user_ids => users_to_test.keys.map(&:id)
}
}
assert_response 302
end
end
assert_equal users_to_test.values.uniq.size, ActionMailer::Base.deliveries.size
# tests that each user receives 1 email with the custom fields he is allowed to see only
users_to_test.each do |user, fields|
mails = ActionMailer::Base.deliveries.select {|m| m.bcc.include? user.mail}
assert_equal 1, mails.size
mail = mails.first
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_mail_body_match "Value#{i}", mail, "User #{user.id} was not able to view #{field.name} in notification"
else
assert_mail_body_no_match "Value#{i}", mail, "User #{user.id} was able to view #{field.name} in notification"
end
end
end
end
def test_update_should_send_notifications_according_custom_fields_visibility
# anonymous user is never notified
users_to_test = @users_to_test.reject {|k,v| k.anonymous?}
users_to_test.keys.each do |user|
Watcher.create!(:user => user, :watchable => @issue)
end
ActionMailer::Base.deliveries.clear
@request.session[:user_id] = 1
with_settings :bcc_recipients => '1' do
put :update, :params => {
:id => @issue.id,
:issue => {
:custom_field_values => {
@field1.id.to_s => 'NewValue0', @field2.id.to_s => 'NewValue1', @field3.id.to_s => 'NewValue2'
}
}
}
assert_response 302
end
assert_equal users_to_test.values.uniq.size, ActionMailer::Base.deliveries.size
# tests that each user receives 1 email with the custom fields he is allowed to see only
users_to_test.each do |user, fields|
mails = ActionMailer::Base.deliveries.select {|m| m.bcc.include? user.mail}
assert_equal 1, mails.size
mail = mails.first
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_mail_body_match "Value#{i}", mail, "User #{user.id} was not able to view #{field.name} in notification"
else
assert_mail_body_no_match "Value#{i}", mail, "User #{user.id} was able to view #{field.name} in notification"
end
end
end
end
def test_updating_hidden_custom_fields_only_should_not_notifiy_user
# anonymous user is never notified
users_to_test = @users_to_test.reject {|k,v| k.anonymous?}
users_to_test.keys.each do |user|
Watcher.create!(:user => user, :watchable => @issue)
end
ActionMailer::Base.deliveries.clear
@request.session[:user_id] = 1
with_settings :bcc_recipients => '1' do
put :update, :params => {
:id => @issue.id,
:issue => {
:custom_field_values => {
@field2.id.to_s => 'NewValue1', @field3.id.to_s => 'NewValue2'
}
}
}
assert_response 302
end
users_to_test.each do |user, fields|
mails = ActionMailer::Base.deliveries.select {|m| m.bcc.include? user.mail}
if (fields & [@field2, @field3]).any?
assert_equal 1, mails.size, "User #{user.id} was not notified"
else
assert_equal 0, mails.size, "User #{user.id} was notified"
end
end
end
end

View file

@ -0,0 +1,324 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class JournalsControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :members, :member_roles, :roles, :issues, :journals, :journal_details, :enabled_modules,
:trackers, :issue_statuses, :enumerations, :custom_fields, :custom_values, :custom_fields_projects, :projects_trackers
def setup
User.current = nil
end
def test_index
get :index, :params => {
:project_id => 1
}
assert_response :success
assert_equal 'application/atom+xml', @response.content_type
end
def test_index_with_invalid_query_id
get :index, :params => {
:project_id => 1,
:query_id => 999
}
assert_response 404
end
def test_index_should_return_privates_notes_with_permission_only
journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
@request.session[:user_id] = 2
get :index, :params => {
:project_id => 1
}
assert_response :success
assert_select 'entry>id', :text => "http://test.host/issues/2?journal_id=#{journal.id}"
Role.find(1).remove_permission! :view_private_notes
get :index, :params => {
:project_id => 1
}
assert_response :success
assert_select 'entry>id', :text => "http://test.host/issues/2?journal_id=#{journal.id}", :count => 0
end
def test_index_should_show_visible_custom_fields_only
Issue.destroy_all
Journal.delete_all
field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :trackers => Tracker.all}
@fields = []
@fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
@fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
@fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
@issue = Issue.generate!(
:author_id => 1,
:project_id => 1,
:tracker_id => 1,
:custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
)
@issue.init_journal(User.find(1))
@issue.custom_field_values = {@field1.id => 'NewValue0', @field2.id => 'NewValue1', @field3.id => 'NewValue2'}
@issue.save!
user_with_role_on_other_project = User.generate!
User.add_to_project(user_with_role_on_other_project, Project.find(2), Role.find(3))
users_to_test = {
User.find(1) => [@field1, @field2, @field3],
User.find(3) => [@field1, @field2],
user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
User.generate! => [@field1],
User.anonymous => [@field1]
}
users_to_test.each do |user, visible_fields|
get :index, :params => {
:format => 'atom',
:key => user.rss_key
}
@fields.each_with_index do |field, i|
if visible_fields.include?(field)
assert_select "content[type=html]", { :text => /NewValue#{i}/, :count => 1 }, "User #{user.id} was not able to view #{field.name} in API"
else
assert_select "content[type=html]", { :text => /NewValue#{i}/, :count => 0 }, "User #{user.id} was able to view #{field.name} in API"
end
end
end
end
def test_diff_for_description_change
get :diff, :params => {
:id => 3,
:detail_id => 4
}
assert_response :success
assert_select 'span.diff_out', :text => /removed/
assert_select 'span.diff_in', :text => /added/
end
def test_diff_for_custom_field
field = IssueCustomField.create!(:name => "Long field", :field_format => 'text')
journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Notes', :user_id => 1)
detail = JournalDetail.create!(:journal => journal, :property => 'cf', :prop_key => field.id,
:old_value => 'Foo', :value => 'Bar')
get :diff, :params => {
:id => journal.id,
:detail_id => detail.id
}
assert_response :success
assert_select 'span.diff_out', :text => /Foo/
assert_select 'span.diff_in', :text => /Bar/
end
def test_diff_for_custom_field_should_be_denied_if_custom_field_is_not_visible
field = IssueCustomField.create!(:name => "Long field", :field_format => 'text', :visible => false, :role_ids => [1])
journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Notes', :user_id => 1)
detail = JournalDetail.create!(:journal => journal, :property => 'cf', :prop_key => field.id,
:old_value => 'Foo', :value => 'Bar')
get :diff, :params => {
:id => journal.id,
:detail_id => detail.id
}
assert_response 302
end
def test_diff_should_default_to_description_diff
get :diff, :params => {
:id => 3
}
assert_response :success
assert_select 'span.diff_out', :text => /removed/
assert_select 'span.diff_in', :text => /added/
end
def test_reply_to_issue
@request.session[:user_id] = 2
get :new, :params => {
:id => 6
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include '> This is an issue', response.body
end
def test_reply_to_issue_without_permission
@request.session[:user_id] = 7
get :new, :params => {
:id => 6
},
:xhr => true
assert_response 403
end
def test_reply_to_note
@request.session[:user_id] = 2
get :new, :params => {
:id => 6,
:journal_id => 4
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include '> A comment with a private version', response.body
end
def test_reply_to_private_note_should_fail_without_permission
journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true)
@request.session[:user_id] = 2
get :new, :params => {
:id => 2,
:journal_id => journal.id
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include '> Privates notes', response.body
Role.find(1).remove_permission! :view_private_notes
get :new, :params => {
:id => 2,
:journal_id => journal.id
},
:xhr => true
assert_response 404
end
def test_edit_xhr
@request.session[:user_id] = 1
get :edit, :params => {
:id => 2
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include 'textarea', response.body
end
def test_edit_private_note_should_fail_without_permission
journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true)
@request.session[:user_id] = 2
Role.find(1).add_permission! :edit_issue_notes
get :edit, :params => {
:id => journal.id
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include 'textarea', response.body
Role.find(1).remove_permission! :view_private_notes
get :edit, :params => {
:id => journal.id
},
:xhr => true
assert_response 404
end
def test_update_xhr
@request.session[:user_id] = 1
post :update, :params => {
:id => 2,
:journal => {
:notes => 'Updated notes'
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_equal 'Updated notes', Journal.find(2).notes
assert_include 'journal-2-notes', response.body
end
def test_update_xhr_with_private_notes_checked
@request.session[:user_id] = 1
post :update, :params => {
:id => 2,
:journal => {
:private_notes => '1'
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_equal true, Journal.find(2).private_notes
assert_include 'change-2', response.body
assert_include 'journal-2-private_notes', response.body
end
def test_update_xhr_with_private_notes_unchecked
Journal.find(2).update_attributes(:private_notes => true)
@request.session[:user_id] = 1
post :update, :params => {
:id => 2,
:journal => {
:private_notes => '0'
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_equal false, Journal.find(2).private_notes
assert_include 'change-2', response.body
assert_include 'journal-2-private_notes', response.body
end
def test_update_xhr_without_set_private_notes_permission_should_ignore_private_notes
@request.session[:user_id] = 2
Role.find(1).add_permission! :edit_issue_notes
Role.find(1).add_permission! :view_private_notes
Role.find(1).remove_permission! :set_notes_private
post :update, :params => {
:id => 2,
:journal => {
:private_notes => '1'
}
},
:xhr => true
assert_response :success
assert_equal false, Journal.find(2).private_notes
end
def test_update_xhr_with_empty_notes_should_delete_the_journal
@request.session[:user_id] = 1
assert_difference 'Journal.count', -1 do
post :update, :params => {
:id => 2,
:journal => {
:notes => ''
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_nil Journal.find_by_id(2)
assert_include 'change-2', response.body
end
end

View file

@ -0,0 +1,116 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class MailHandlerControllerTest < Redmine::ControllerTest
fixtures :users, :email_addresses, :projects, :enabled_modules, :roles, :members, :member_roles, :issues, :issue_statuses,
:trackers, :projects_trackers, :enumerations
FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
def setup
User.current = nil
end
def test_should_create_issue
# Enable API and set a key
Setting.mail_handler_api_enabled = 1
Setting.mail_handler_api_key = 'secret'
assert_difference 'Issue.count' do
post :index, :params => {
:key => 'secret',
:email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
}
end
assert_response 201
end
def test_should_create_issue_with_options
# Enable API and set a key
Setting.mail_handler_api_enabled = 1
Setting.mail_handler_api_key = 'secret'
assert_difference 'Issue.count' do
post :index, :params => {
:key => 'secret',
:email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml')),
:issue => {
:is_private => '1'
}
}
end
assert_response 201
issue = Issue.order(:id => :desc).first
assert_equal true, issue.is_private
end
def test_should_respond_with_422_if_not_created
Project.find('onlinestore').destroy
Setting.mail_handler_api_enabled = 1
Setting.mail_handler_api_key = 'secret'
assert_no_difference 'Issue.count' do
post :index, :params => {
:key => 'secret',
:email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
}
end
assert_response 422
end
def test_should_not_allow_with_api_disabled
# Disable API
Setting.mail_handler_api_enabled = 0
Setting.mail_handler_api_key = 'secret'
assert_no_difference 'Issue.count' do
post :index, :params => {
:key => 'secret',
:email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
}
end
assert_response 403
assert_include 'Access denied', response.body
end
def test_should_not_allow_with_wrong_key
Setting.mail_handler_api_enabled = 1
Setting.mail_handler_api_key = 'secret'
assert_no_difference 'Issue.count' do
post :index, :params => {
:key => 'wrong',
:email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
}
end
assert_response 403
assert_include 'Access denied', response.body
end
def test_new
Setting.mail_handler_api_enabled = 1
Setting.mail_handler_api_key = 'secret'
get :new, :params => {
:key => 'secret'
}
assert_response :success
end
end

View file

@ -0,0 +1,320 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class MembersControllerTest < Redmine::ControllerTest
fixtures :projects, :members, :member_roles, :roles, :users
def setup
User.current = nil
@request.session[:user_id] = 2
end
def test_new
get :new, :params => {
:project_id => 1
}
assert_response :success
end
def test_new_should_propose_managed_roles_only
role = Role.find(1)
role.update! :all_roles_managed => false
role.managed_roles = Role.where(:id => [2, 3]).to_a
get :new, :params => {
:project_id => 1
}
assert_response :success
assert_select 'div.roles-selection' do
assert_select 'label', :text => 'Manager', :count => 0
assert_select 'label', :text => 'Developer'
assert_select 'label', :text => 'Reporter'
end
end
def test_xhr_new
get :new, :params => {
:project_id => 1
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
def test_create
assert_difference 'Member.count' do
post :create, :params => {
:project_id => 1,
:membership => {
:role_ids => [1],
:user_id => 7
}
}
end
assert_redirected_to '/projects/ecookbook/settings/members'
assert User.find(7).member_of?(Project.find(1))
end
def test_create_multiple
assert_difference 'Member.count', 3 do
post :create, :params => {
:project_id => 1,
:membership => {
:role_ids => [1],
:user_ids => [7, 8, 9]
}
}
end
assert_redirected_to '/projects/ecookbook/settings/members'
assert User.find(7).member_of?(Project.find(1))
end
def test_create_should_ignore_unmanaged_roles
role = Role.find(1)
role.update! :all_roles_managed => false
role.managed_roles = Role.where(:id => [2, 3]).to_a
assert_difference 'Member.count' do
post :create, :params => {
:project_id => 1,
:membership => {
:role_ids => [1, 2],
:user_id => 7
}
}
end
member = Member.order(:id => :desc).first
assert_equal [2], member.role_ids
end
def test_create_should_be_allowed_for_admin_without_role
User.find(1).members.delete_all
@request.session[:user_id] = 1
assert_difference 'Member.count' do
post :create, :params => {
:project_id => 1,
:membership => {
:role_ids => [1, 2],
:user_id => 7
}
}
end
member = Member.order(:id => :desc).first
assert_equal [1, 2], member.role_ids
end
def test_xhr_create
assert_difference 'Member.count', 3 do
post :create, :params => {
:project_id => 1,
:membership => {
:role_ids => [1],
:user_ids => [7, 8, 9]
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert User.find(7).member_of?(Project.find(1))
assert User.find(8).member_of?(Project.find(1))
assert User.find(9).member_of?(Project.find(1))
assert_include 'tab-content-members', response.body
end
def test_xhr_create_with_failure
assert_no_difference 'Member.count' do
post :create, :params => {
:project_id => 1,
:membership => {
:role_ids => [],
:user_ids => [7, 8, 9]
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_match /alert/, response.body, "Alert message not sent"
end
def test_edit
get :edit, :params => {
:id => 2
}
assert_response :success
assert_select 'input[name=?][value=?][checked=checked]', 'membership[role_ids][]', '2'
end
def test_xhr_edit
get :edit, :params => {
:id => 2
},
:xhr => true
assert_response :success
end
def test_update
assert_no_difference 'Member.count' do
put :update, :params => {
:id => 2,
:membership => {
:role_ids => [1],
:user_id => 3
}
}
end
assert_redirected_to '/projects/ecookbook/settings/members'
end
def test_update_locked_member_should_be_allowed
User.find(3).lock!
put :update, :params => {
:id => 2,
:membership => {
:role_ids => [1]
}
}
assert_response 302
member = Member.find(2)
assert member.user.locked?
assert_equal [1], member.role_ids
end
def test_update_should_not_add_unmanaged_roles
role = Role.find(1)
role.update! :all_roles_managed => false
role.managed_roles = Role.where(:id => [2, 3]).to_a
member = Member.create!(:user => User.find(9), :role_ids => [3], :project_id => 1)
put :update, :params => {
:id => member.id,
:membership => {
:role_ids => [1, 2, 3]
}
}
assert_equal [2, 3], member.reload.role_ids.sort
end
def test_update_should_not_remove_unmanaged_roles
role = Role.find(1)
role.update! :all_roles_managed => false
role.managed_roles = Role.where(:id => [2, 3]).to_a
member = Member.create!(:user => User.find(9), :role_ids => [1, 3], :project_id => 1)
put :update, :params => {
:id => member.id,
:membership => {
:role_ids => [2]
}
}
assert_equal [1, 2], member.reload.role_ids.sort
end
def test_xhr_update
assert_no_difference 'Member.count' do
put :update, :params => {
:id => 2,
:membership => {
:role_ids => [1],
:user_id => 3
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
member = Member.find(2)
assert_equal [1], member.role_ids
assert_equal 3, member.user_id
assert_include 'tab-content-members', response.body
end
def test_destroy
assert_difference 'Member.count', -1 do
delete :destroy, :params => {
:id => 2
}
end
assert_redirected_to '/projects/ecookbook/settings/members'
assert !User.find(3).member_of?(Project.find(1))
end
def test_destroy_locked_member_should_be_allowed
assert User.find(3).lock!
assert_difference 'Member.count', -1 do
delete :destroy, :params => {
:id => 2
}
end
end
def test_destroy_should_fail_with_unmanaged_roles
role = Role.find(1)
role.update! :all_roles_managed => false
role.managed_roles = Role.where(:id => [2, 3]).to_a
member = Member.create!(:user => User.find(9), :role_ids => [1, 3], :project_id => 1)
assert_no_difference 'Member.count' do
delete :destroy, :params => {
:id => member.id
}
end
end
def test_destroy_should_succeed_with_managed_roles_only
role = Role.find(1)
role.update! :all_roles_managed => false
role.managed_roles = Role.where(:id => [2, 3]).to_a
member = Member.create!(:user => User.find(9), :role_ids => [3], :project_id => 1)
assert_difference 'Member.count', -1 do
delete :destroy, :params => {
:id => member.id
}
end
end
def test_xhr_destroy
assert_difference 'Member.count', -1 do
delete :destroy, :params => {
:id => 2
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_nil Member.find_by_id(2)
assert_include 'tab-content-members', response.body
end
def test_autocomplete
get :autocomplete, :params => {
:project_id => 1,
:q => 'mis',
:format => 'js'
},
:xhr => true
assert_response :success
assert_include 'User Misc', response.body
end
end

View file

@ -0,0 +1,289 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class MessagesControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :email_addresses, :user_preferences, :members, :member_roles, :roles, :boards, :messages, :enabled_modules
def setup
User.current = nil
end
def test_show
get :show, :params => {
:board_id => 1,
:id => 1
}
assert_response :success
assert_select 'h2', :text => 'First post'
end
def test_show_should_contain_reply_field_tags_for_quoting
@request.session[:user_id] = 2
get :show, :params => {
:board_id => 1,
:id => 1
}
assert_response :success
# tags required by MessagesController#quote
assert_select 'input#message_subject'
assert_select 'textarea#message_content'
assert_select 'div#reply'
end
def test_show_with_pagination
message = Message.find(1)
assert_difference 'Message.count', 30 do
30.times do
message.children << Message.new(:subject => 'Reply',
:content => 'Reply body',
:author_id => 2,
:board_id => 1)
end
end
reply_ids = message.children.map(&:id).sort
get :show, :params => {
:board_id => 1,
:id => 1,
:r => reply_ids.last
}
assert_response :success
assert_select 'a[href=?]', "/boards/1/topics/1?r=#{reply_ids.last}#message-#{reply_ids.last}"
assert_select 'a[href=?]', "/boards/1/topics/1?r=#{reply_ids.first}#message-#{reply_ids.first}", 0
end
def test_show_with_reply_permission
@request.session[:user_id] = 2
get :show, :params => {
:board_id => 1,
:id => 1
}
assert_response :success
assert_select 'div#reply textarea#message_content'
end
def test_show_message_not_found
get :show, :params => {
:board_id => 1,
:id => 99999
}
assert_response 404
end
def test_show_message_from_invalid_board_should_respond_with_404
get :show, :params => {
:board_id => 999,
:id => 1
}
assert_response 404
end
def test_get_new
@request.session[:user_id] = 2
get :new, :params => {
:board_id => 1
}
assert_response :success
assert_select 'input[name=?]', 'message[subject]'
end
def test_get_new_with_invalid_board
@request.session[:user_id] = 2
get :new, :params => {
:board_id => 99
}
assert_response 404
end
def test_post_new
@request.session[:user_id] = 2
ActionMailer::Base.deliveries.clear
with_settings :notified_events => %w(message_posted) do
post :new, :params => {
:board_id => 1,
:message => {
:subject => 'Test created message',
:content => 'Message body'
}
}
end
message = Message.find_by_subject('Test created message')
assert_not_nil message
assert_redirected_to "/boards/1/topics/#{message.to_param}"
assert_equal 'Message body', message.content
assert_equal 2, message.author_id
assert_equal 1, message.board_id
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
assert_equal "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] Test created message", mail.subject
assert_mail_body_match 'Message body', mail
# author
assert mail.bcc.include?('jsmith@somenet.foo')
# project member
assert mail.bcc.include?('dlopper@somenet.foo')
end
def test_get_edit
@request.session[:user_id] = 2
get :edit, :params => {
:board_id => 1,
:id => 1
}
assert_response :success
assert_select 'input[name=?][value=?]', 'message[subject]', 'First post'
end
def test_post_edit
@request.session[:user_id] = 2
post :edit, :params => {
:board_id => 1,
:id => 1,
:message => {
:subject => 'New subject',
:content => 'New body'
}
}
assert_redirected_to '/boards/1/topics/1'
message = Message.find(1)
assert_equal 'New subject', message.subject
assert_equal 'New body', message.content
end
def test_post_edit_sticky_and_locked
@request.session[:user_id] = 2
post :edit, :params => {
:board_id => 1,
:id => 1,
:message => {
:subject => 'New subject',
:content => 'New body',
:locked => '1',
:sticky => '1'
}
}
assert_redirected_to '/boards/1/topics/1'
message = Message.find(1)
assert_equal true, message.sticky?
assert_equal true, message.locked?
end
def test_post_edit_should_allow_to_change_board
@request.session[:user_id] = 2
post :edit, :params => {
:board_id => 1,
:id => 1,
:message => {
:subject => 'New subject',
:content => 'New body',
:board_id => 2
}
}
assert_redirected_to '/boards/2/topics/1'
message = Message.find(1)
assert_equal Board.find(2), message.board
end
def test_reply
@request.session[:user_id] = 2
post :reply, :params => {
:board_id => 1,
:id => 1,
:reply => {
:content => 'This is a test reply',
:subject => 'Test reply'
}
}
reply = Message.order('id DESC').first
assert_redirected_to "/boards/1/topics/1?r=#{reply.id}"
assert Message.find_by_subject('Test reply')
end
def test_destroy_topic
@request.session[:user_id] = 2
assert_difference 'Message.count', -3 do
post :destroy, :params => {
:board_id => 1,
:id => 1
}
end
assert_redirected_to '/projects/ecookbook/boards/1'
assert_nil Message.find_by_id(1)
end
def test_destroy_reply
@request.session[:user_id] = 2
assert_difference 'Message.count', -1 do
post :destroy, :params => {
:board_id => 1,
:id => 2
}
end
assert_redirected_to '/boards/1/topics/1?r=2'
assert_nil Message.find_by_id(2)
end
def test_quote
@request.session[:user_id] = 2
get :quote, :params => {
:board_id => 1,
:id => 3
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include 'RE: First post', response.body
assert_include '> An other reply', response.body
end
def test_preview_new
@request.session[:user_id] = 2
post :preview, :params => {
:board_id => 1,
:message => {
:subject => "",
:content => "Previewed text"
}
}
assert_response :success
assert_include 'Previewed text', response.body
end
def test_preview_edit
@request.session[:user_id] = 2
post :preview, :params => {
:id => 4,
:board_id => 1,
:message => {
:subject => "",
:content => "Previewed text"
}
}
assert_response :success
assert_include 'Previewed text', response.body
end
end

View file

@ -0,0 +1,521 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class MyControllerTest < Redmine::ControllerTest
fixtures :users, :email_addresses, :user_preferences, :roles, :projects, :members, :member_roles,
:issues, :issue_statuses, :trackers, :enumerations, :custom_fields, :auth_sources, :queries
def setup
@request.session[:user_id] = 2
end
def test_index
get :index
assert_response :success
assert_select 'h2', 'My page'
end
def test_page
get :page
assert_response :success
assert_select 'h2', 'My page'
end
def test_page_with_timelog_block
preferences = User.find(2).pref
preferences[:my_page_layout] = {'top' => ['timelog']}
preferences.save!
with_issue = TimeEntry.create!(:user => User.find(2), :spent_on => Date.yesterday, :hours => 2.5, :activity_id => 10, :issue_id => 1)
without_issue = TimeEntry.create!(:user => User.find(2), :spent_on => Date.yesterday, :hours => 3.5, :activity_id => 10, :project_id => 1)
get :page
assert_response :success
assert_select "tr#time-entry-#{with_issue.id}" do
assert_select 'td.subject a[href="/issues/1"]'
assert_select 'td.hours', :text => '2.50'
end
assert_select "tr#time-entry-#{without_issue.id}" do
assert_select 'td.hours', :text => '3.50'
end
end
def test_page_with_assigned_issues_block_and_no_custom_settings
preferences = User.find(2).pref
preferences.my_page_layout = {'top' => ['issuesassignedtome']}
preferences.my_page_settings = nil
preferences.save!
get :page
assert_select '#block-issuesassignedtome' do
assert_select 'table.issues' do
assert_select 'th a[data-remote=true][data-method=post]', :text => 'Tracker'
end
assert_select '#issuesassignedtome-settings' do
assert_select 'select[name=?]', 'settings[issuesassignedtome][columns][]'
end
end
end
def test_page_with_assigned_issues_block_and_custom_columns
preferences = User.find(2).pref
preferences.my_page_layout = {'top' => ['issuesassignedtome']}
preferences.my_page_settings = {'issuesassignedtome' => {:columns => ['tracker', 'subject', 'due_date']}}
preferences.save!
get :page
assert_select '#block-issuesassignedtome' do
assert_select 'table.issues td.due_date'
end
end
def test_page_with_assigned_issues_block_and_custom_sort
preferences = User.find(2).pref
preferences.my_page_layout = {'top' => ['issuesassignedtome']}
preferences.my_page_settings = {'issuesassignedtome' => {:sort => 'due_date'}}
preferences.save!
get :page
assert_select '#block-issuesassignedtome' do
assert_select 'table.issues.sort-by-due-date'
end
end
def test_page_with_issuequery_block_and_no_settings
user = User.find(2)
user.pref.my_page_layout = {'top' => ['issuequery']}
user.pref.save!
get :page
assert_response :success
assert_select '#block-issuequery' do
assert_select 'h3', :text => 'Issues'
assert_select 'select[name=?]', 'settings[issuequery][query_id]' do
assert_select 'option[value="5"]', :text => 'Open issues by priority and tracker'
end
end
end
def test_page_with_issuequery_block_and_global_query
user = User.find(2)
query = IssueQuery.create!(:name => 'All issues', :user => user, :column_names => [:tracker, :subject, :status, :assigned_to])
user.pref.my_page_layout = {'top' => ['issuequery']}
user.pref.my_page_settings = {'issuequery' => {:query_id => query.id}}
user.pref.save!
get :page
assert_response :success
assert_select '#block-issuequery' do
assert_select 'a[href=?]', "/issues?query_id=#{query.id}"
# assert number of columns (columns from query + id column + checkbox column)
assert_select 'table.issues th', 6
# assert results limit
assert_select 'table.issues tr.issue', 10
assert_select 'table.issues td.assigned_to'
end
end
def test_page_with_issuequery_block_and_project_query
user = User.find(2)
query = IssueQuery.create!(:name => 'All issues', :project => Project.find(1), :user => user, :column_names => [:tracker, :subject, :status, :assigned_to])
user.pref.my_page_layout = {'top' => ['issuequery']}
user.pref.my_page_settings = {'issuequery' => {:query_id => query.id}}
user.pref.save!
get :page
assert_response :success
assert_select '#block-issuequery' do
assert_select 'a[href=?]', "/projects/ecookbook/issues?query_id=#{query.id}"
# assert number of columns (columns from query + id column + checkbox column)
assert_select 'table.issues th', 6
# assert results limit
assert_select 'table.issues tr.issue', 10
assert_select 'table.issues td.assigned_to'
end
end
def test_page_with_issuequery_block_and_query_should_display_custom_columns
user = User.find(2)
query = IssueQuery.create!(:name => 'All issues', :user => user, :column_names => [:tracker, :subject, :status, :assigned_to])
user.pref.my_page_layout = {'top' => ['issuequery']}
user.pref.my_page_settings = {'issuequery' => {:query_id => query.id, :columns => [:subject, :due_date]}}
user.pref.save!
get :page
assert_response :success
assert_select '#block-issuequery' do
# assert number of columns (columns from query + id column + checkbox column)
assert_select 'table.issues th', 4
assert_select 'table.issues th', :text => 'Due date'
end
end
def test_page_with_multiple_issuequery_blocks
user = User.find(2)
query1 = IssueQuery.create!(:name => 'All issues', :user => user, :column_names => [:tracker, :subject, :status, :assigned_to])
query2 = IssueQuery.create!(:name => 'Other issues', :user => user, :column_names => [:tracker, :subject, :priority])
user.pref.my_page_layout = {'top' => ['issuequery__1', 'issuequery']}
user.pref.my_page_settings = {
'issuequery' => {:query_id => query1.id, :columns => [:subject, :due_date]},
'issuequery__1' => {:query_id => query2.id}
}
user.pref.save!
get :page
assert_response :success
assert_select '#block-issuequery' do
assert_select 'h3', :text => /All issues/
assert_select 'table.issues th', :text => 'Due date'
end
assert_select '#block-issuequery__1' do
assert_select 'h3', :text => /Other issues/
assert_select 'table.issues th', :text => 'Priority'
end
assert_select '#block-select' do
assert_select 'option[value=?]:not([disabled])', 'issuequery__2', :text => 'Issues'
end
end
def test_page_with_all_blocks
blocks = Redmine::MyPage.blocks.keys
preferences = User.find(2).pref
preferences[:my_page_layout] = {'top' => blocks}
preferences.save!
get :page
assert_response :success
assert_select 'div.mypage-box', blocks.size
end
def test_my_account_should_show_editable_custom_fields
get :account
assert_response :success
assert_select 'input[name=?]', 'user[custom_field_values][4]'
end
def test_my_account_should_not_show_non_editable_custom_fields
UserCustomField.find(4).update_attribute :editable, false
get :account
assert_response :success
assert_select 'input[name=?]', 'user[custom_field_values][4]', 0
end
def test_my_account_should_show_language_select
get :account
assert_response :success
assert_select 'select[name=?]', 'user[language]'
end
def test_my_account_should_not_show_language_select_with_force_default_language_for_loggedin
with_settings :force_default_language_for_loggedin => '1' do
get :account
assert_response :success
assert_select 'select[name=?]', 'user[language]', 0
end
end
def test_update_account
post :account, :params => {
:user => {
:firstname => "Joe",
:login => "root",
:admin => 1,
:group_ids => ['10'],
:custom_field_values => {
"4" => "0100562500"
}
}
}
assert_redirected_to '/my/account'
user = User.find(2)
assert_equal "Joe", user.firstname
assert_equal "jsmith", user.login
assert_equal "0100562500", user.custom_value_for(4).value
# ignored
assert !user.admin?
assert user.groups.empty?
end
def test_update_account_should_send_security_notification
ActionMailer::Base.deliveries.clear
post :account, :params => {
:user => {
:mail => 'foobar@example.com'
}
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match '0.0.0.0', mail
assert_mail_body_match I18n.t(:mail_body_security_notification_change_to, field: I18n.t(:field_mail), value: 'foobar@example.com'), mail
assert_select_email do
assert_select 'a[href^=?]', 'http://localhost:3000/my/account', :text => 'My account'
end
# The old email address should be notified about the change for security purposes
assert [mail.bcc, mail.cc].flatten.include?(User.find(2).mail)
assert [mail.bcc, mail.cc].flatten.include?('foobar@example.com')
end
def test_my_account_should_show_destroy_link
get :account
assert_select 'a[href="/my/account/destroy"]'
end
def test_get_destroy_should_display_the_destroy_confirmation
get :destroy
assert_response :success
assert_select 'form[action="/my/account/destroy"]' do
assert_select 'input[name=confirm]'
end
end
def test_post_destroy_without_confirmation_should_not_destroy_account
assert_no_difference 'User.count' do
post :destroy
end
assert_response :success
end
def test_post_destroy_without_confirmation_should_destroy_account
assert_difference 'User.count', -1 do
post :destroy, :params => {
:confirm => '1'
}
end
assert_redirected_to '/'
assert_match /deleted/i, flash[:notice]
end
def test_post_destroy_with_unsubscribe_not_allowed_should_not_destroy_account
User.any_instance.stubs(:own_account_deletable?).returns(false)
assert_no_difference 'User.count' do
post :destroy, :params => {
:confirm => '1'
}
end
assert_redirected_to '/my/account'
end
def test_change_password
get :password
assert_response :success
assert_select 'input[type=password][name=password]'
assert_select 'input[type=password][name=new_password]'
assert_select 'input[type=password][name=new_password_confirmation]'
end
def test_update_password
post :password, :params => {
:password => 'jsmith',
:new_password => 'secret123',
:new_password_confirmation => 'secret123'
}
assert_redirected_to '/my/account'
assert User.try_to_login('jsmith', 'secret123')
end
def test_update_password_with_non_matching_confirmation
post :password, :params => {
:password => 'jsmith',
:new_password => 'secret123',
:new_password_confirmation => 'secret1234'
}
assert_response :success
assert_select_error /Password doesn.*t match confirmation/
assert User.try_to_login('jsmith', 'jsmith')
end
def test_update_password_with_wrong_password
# wrong password
post :password, :params => {
:password => 'wrongpassword',
:new_password => 'secret123',
:new_password_confirmation => 'secret123'
}
assert_response :success
assert_equal 'Wrong password', flash[:error]
assert User.try_to_login('jsmith', 'jsmith')
end
def test_change_password_should_redirect_if_user_cannot_change_its_password
User.find(2).update_attribute(:auth_source_id, 1)
get :password
assert_not_nil flash[:error]
assert_redirected_to '/my/account'
end
def test_update_password_should_send_security_notification
ActionMailer::Base.deliveries.clear
post :password, :params => {
:password => 'jsmith',
:new_password => 'secret123',
:new_password_confirmation => 'secret123'
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_no_match 'secret123', mail # just to be sure: pw should never be sent!
assert_select_email do
assert_select 'a[href^=?]', 'http://localhost:3000/my/password', :text => 'Change password'
end
end
def test_update_page_with_blank_preferences
user = User.generate!(:language => 'en')
@request.session[:user_id] = user.id
post :update_page, :params => {
:settings => {
'issuesassignedtome' => {
'columns' => ['subject', 'due_date']}
}
},
:xhr => true
assert_response :success
assert_include '$("#block-issuesassignedtome").replaceWith(', response.body
assert_include 'Due date', response.body
assert_equal({:columns => ['subject', 'due_date']}, user.reload.pref.my_page_settings('issuesassignedtome'))
end
def test_add_block
post :add_block, :params => {
:block => 'issueswatched'
}
assert_redirected_to '/my/page'
assert User.find(2).pref[:my_page_layout]['top'].include?('issueswatched')
end
def test_add_block_xhr
post :add_block, :params => {
:block => 'issueswatched'
},
:xhr => true
assert_response :success
assert_include 'issueswatched', User.find(2).pref[:my_page_layout]['top']
end
def test_add_invalid_block_should_error
post :add_block, :params => {
:block => 'invalid'
}
assert_response 422
end
def test_remove_block
post :remove_block, :params => {
:block => 'issuesassignedtome'
}
assert_redirected_to '/my/page'
assert !User.find(2).pref[:my_page_layout].values.flatten.include?('issuesassignedtome')
end
def test_remove_block_xhr
post :remove_block, :params => {
:block => 'issuesassignedtome'
},
:xhr => true
assert_response :success
assert_include '$("#block-issuesassignedtome").remove();', response.body
assert !User.find(2).pref[:my_page_layout].values.flatten.include?('issuesassignedtome')
end
def test_order_blocks
pref = User.find(2).pref
pref.my_page_layout = {'left' => ['news', 'calendar','documents']}
pref.save!
post :order_blocks, :params => {
:group => 'left',
:blocks => ['documents', 'calendar', 'news']
},
:xhr => true
assert_response :success
assert_equal ['documents', 'calendar', 'news'], User.find(2).pref.my_page_layout['left']
end
def test_move_block
pref = User.find(2).pref
pref.my_page_layout = {'left' => ['news','documents'], 'right' => ['calendar']}
pref.save!
post :order_blocks, :params => {
:group => 'left',
:blocks => ['news', 'calendar', 'documents']
},
:xhr => true
assert_response :success
assert_equal({'left' => ['news', 'calendar', 'documents'], 'right' => []}, User.find(2).pref.my_page_layout)
end
def test_reset_rss_key_with_existing_key
@previous_token_value = User.find(2).rss_key # Will generate one if it's missing
post :reset_rss_key
assert_not_equal @previous_token_value, User.find(2).rss_key
assert User.find(2).rss_token
assert_match /reset/, flash[:notice]
assert_redirected_to '/my/account'
end
def test_reset_rss_key_without_existing_key
Token.delete_all
assert_nil User.find(2).rss_token
post :reset_rss_key
assert User.find(2).rss_token
assert_match /reset/, flash[:notice]
assert_redirected_to '/my/account'
end
def test_show_api_key
get :show_api_key
assert_response :success
assert_select 'pre', User.find(2).api_key
end
def test_reset_api_key_with_existing_key
@previous_token_value = User.find(2).api_key # Will generate one if it's missing
post :reset_api_key
assert_not_equal @previous_token_value, User.find(2).api_key
assert User.find(2).api_token
assert_match /reset/, flash[:notice]
assert_redirected_to '/my/account'
end
def test_reset_api_key_without_existing_key
assert_nil User.find(2).api_token
post :reset_api_key
assert User.find(2).api_token
assert_match /reset/, flash[:notice]
assert_redirected_to '/my/account'
end
end

View file

@ -0,0 +1,233 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class NewsControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
:enabled_modules, :news, :comments,
:attachments
def setup
User.current = nil
end
def test_index
get :index
assert_response :success
assert_select 'h3 a', :text => 'eCookbook first release !'
end
def test_index_with_project
get :index, :params => {
:project_id => 1
}
assert_response :success
assert_select 'h3 a', :text => 'eCookbook first release !'
end
def test_index_with_invalid_project_should_respond_with_404
get :index, :params => {
:project_id => 999
}
assert_response 404
end
def test_index_without_permission_should_fail
Role.all.each {|r| r.remove_permission! :view_news}
@request.session[:user_id] = 2
get :index
assert_response 403
end
def test_show
get :show, :params => {
:id => 1
}
assert_response :success
assert_select 'h2', :text => 'eCookbook first release !'
end
def test_show_should_show_attachments
attachment = Attachment.first
attachment.container = News.find(1)
attachment.save!
get :show, :params => {
:id => 1
}
assert_response :success
assert_select 'a', :text => attachment.filename
end
def test_show_with_comments_in_reverse_order
user = User.find(1)
user.pref[:comments_sorting] = 'desc'
user.pref.save!
@request.session[:user_id] = 1
get :show, :params => {
:id => 1
}
assert_response :success
comments = css_select('#comments .wiki').map(&:text).map(&:strip)
assert_equal ["This is an other comment", "my first comment"], comments
end
def test_show_not_found
get :show, :params => {
:id => 999
}
assert_response 404
end
def test_get_new
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 1
}
assert_response :success
assert_select 'input[name=?]', 'news[title]'
end
def test_post_create
ActionMailer::Base.deliveries.clear
@request.session[:user_id] = 2
with_settings :notified_events => %w(news_added) do
post :create, :params => {
:project_id => 1,
:news => {
:title => 'NewsControllerTest',
:description => 'This is the description',
:summary => ''
}
}
end
assert_redirected_to '/projects/ecookbook/news'
news = News.find_by_title('NewsControllerTest')
assert_not_nil news
assert_equal 'This is the description', news.description
assert_equal User.find(2), news.author
assert_equal Project.find(1), news.project
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_post_create_with_attachment
set_tmp_attachments_directory
@request.session[:user_id] = 2
assert_difference 'News.count' do
assert_difference 'Attachment.count' do
post :create, :params => {
:project_id => 1,
:news => {
:title => 'Test',
:description => 'This is the description'
},
:attachments => {
'1' => {
'file' => uploaded_test_file('testfile.txt', 'text/plain')}
}
}
end
end
attachment = Attachment.order('id DESC').first
news = News.order('id DESC').first
assert_equal news, attachment.container
end
def test_post_create_with_validation_failure
@request.session[:user_id] = 2
post :create, :params => {
:project_id => 1,
:news => {
:title => '',
:description => 'This is the description',
:summary => ''
}
}
assert_response :success
assert_select_error /title cannot be blank/i
end
def test_get_edit
@request.session[:user_id] = 2
get :edit, :params => {
:id => 1
}
assert_response :success
assert_select 'input[name=?][value=?]', 'news[title]', 'eCookbook first release !'
end
def test_put_update
@request.session[:user_id] = 2
put :update, :params => {
:id => 1,
:news => {
:description => 'Description changed by test_post_edit'
}
}
assert_redirected_to '/news/1'
news = News.find(1)
assert_equal 'Description changed by test_post_edit', news.description
end
def test_put_update_with_attachment
set_tmp_attachments_directory
@request.session[:user_id] = 2
assert_no_difference 'News.count' do
assert_difference 'Attachment.count' do
put :update, :params => {
:id => 1,
:news => {
:description => 'This is the description'
},
:attachments => {
'1' => {
'file' => uploaded_test_file('testfile.txt', 'text/plain')}
}
}
end
end
attachment = Attachment.order('id DESC').first
assert_equal News.find(1), attachment.container
end
def test_update_with_failure
@request.session[:user_id] = 2
put :update, :params => {
:id => 1,
:news => {
:description => ''
}
}
assert_response :success
assert_select_error /description cannot be blank/i
end
def test_destroy
@request.session[:user_id] = 2
delete :destroy, :params => {
:id => 1
}
assert_redirected_to '/projects/ecookbook/news'
assert_nil News.find_by_id(1)
end
end

View file

@ -0,0 +1,144 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class PreviewsControllerTest < Redmine::ControllerTest
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :users, :issue_categories,
:projects_trackers,
:roles,
:member_roles,
:members,
:enabled_modules,
:journals, :journal_details,
:news
def test_preview_new_issue
@request.session[:user_id] = 2
post :issue, :params => {
:project_id => '1',
:issue => {
:description => 'Foo'
}
}
assert_response :success
assert_select 'fieldset' do
assert_select 'legend', :text => 'Description'
assert_select 'p', :text => 'Foo'
end
end
def test_preview_issue_notes_with_no_change_to_description
@request.session[:user_id] = 2
post :issue, :params => {
:project_id => '1',
:id => 1,
:issue => {
:description => Issue.find(1).description,
:notes => 'Foo'
}
}
assert_response :success
assert_select 'legend', :text => 'Description', :count => 0
assert_select 'legend', :text => 'Notes'
end
def test_preview_issue_notes_with_change_to_description
@request.session[:user_id] = 2
post :issue, :params => {
:project_id => '1',
:id => 1,
:issue => {
:description => 'Changed description',
:notes => 'Foo'
}
}
assert_response :success
assert_select 'legend', :text => 'Description'
assert_select 'legend', :text => 'Notes'
end
def test_preview_journal_notes_for_update
@request.session[:user_id] = 2
post :issue, :params => {
:project_id => '1',
:id => 1,
:journal => {
:notes => 'Foo'
}
}
assert_response :success
assert_select 'legend', :text => 'Notes'
assert_select 'p', :text => 'Foo'
end
def test_preview_issue_notes_should_support_links_to_existing_attachments
Attachment.generate!(:container => Issue.find(1), :filename => 'foo.bar')
@request.session[:user_id] = 2
post :issue, :params => {
:project_id => '1',
:id => 1,
:issue => {
:notes => 'attachment:foo.bar'
}
}
assert_response :success
assert_select 'a.attachment', :text => 'foo.bar'
end
def test_preview_issue_with_project_changed
@request.session[:user_id] = 2
post :issue, :params => {
:project_id => '1',
:id => 1,
:issue => {
:notes => 'notes',
:project_id => 2
}
}
assert_response :success
assert_select 'legend', :text => 'Notes'
end
def test_preview_new_news
get :news, :params => {
:project_id => 1,
:news => {
:title => '',
:description => 'News description',
:summary => ''
}
}
assert_response :success
assert_select 'fieldset.preview', :text => /News description/
end
def test_preview_existing_news
get :news, :params => {
:project_id => 1,
:id => 2,
:news => {
:title => '',
:description => 'News description',
:summary => ''
}
}
assert_response :success
assert_select 'fieldset.preview', :text => /News description/
end
end

View file

@ -0,0 +1,323 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class PrincipalMembershipsControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :members, :member_roles, :roles, :groups_users
def setup
@request.session[:user_id] = 1
end
def test_new_user_membership
get :new, :params => {
:user_id => 7
}
assert_response :success
assert_select 'label', :text => 'eCookbook' do
assert_select 'input[name=?][value="1"]:not([disabled])', 'membership[project_ids][]'
end
end
def test_new_user_membership_should_disable_user_projects
Member.create!(:user_id => 7, :project_id => 1, :role_ids => [1])
get :new, :params => {
:user_id => 7
}
assert_response :success
assert_select 'label', :text => 'eCookbook' do
assert_select 'input[name=?][value="1"][disabled=disabled]', 'membership[project_ids][]'
end
end
def test_xhr_new_user_membership
get :new, :params => {
:user_id => 7
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
def test_create_user_membership
assert_difference 'Member.count' do
post :create, :params => {
:user_id => 7,
:membership => {
:project_ids => [3],
:role_ids => [2]
}
}
end
assert_redirected_to '/users/7/edit?tab=memberships'
member = Member.order('id DESC').first
assert_equal User.find(7), member.principal
assert_equal [2], member.role_ids
assert_equal 3, member.project_id
end
def test_create_user_membership_with_multiple_roles
assert_difference 'Member.count' do
post :create, :params => {
:user_id => 7,
:membership => {
:project_ids => [3],
:role_ids => [2, 3]
}
}
end
member = Member.order('id DESC').first
assert_equal User.find(7), member.principal
assert_equal [2, 3], member.role_ids.sort
assert_equal 3, member.project_id
end
def test_create_user_membership_with_multiple_projects_and_roles
assert_difference 'Member.count', 2 do
post :create, :params => {
:user_id => 7,
:membership => {
:project_ids => [1, 3],
:role_ids => [2, 3]
}
}
end
members = Member.order('id DESC').limit(2).sort_by(&:project_id)
assert_equal 1, members[0].project_id
assert_equal 3, members[1].project_id
members.each do |member|
assert_equal User.find(7), member.principal
assert_equal [2, 3], member.role_ids.sort
end
end
def test_xhr_create_user_membership
assert_difference 'Member.count' do
post :create, :params => {
:user_id => 7,
:membership => {
:project_ids => [3],
:role_ids => [2]
},
:format => 'js'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
member = Member.order('id DESC').first
assert_equal User.find(7), member.principal
assert_equal [2], member.role_ids
assert_equal 3, member.project_id
assert_include 'tab-content-memberships', response.body
end
def test_xhr_create_user_membership_with_failure
assert_no_difference 'Member.count' do
post :create, :params => {
:user_id => 7,
:membership => {
:project_ids => [3]
},
:format => 'js'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_include 'alert', response.body, "Alert message not sent"
assert_include 'Role cannot be empty', response.body, "Error message not sent"
end
def test_edit_user_membership
get :edit, :params => {
:user_id => 2,
:id => 1
}
assert_response :success
assert_select 'input[name=?][value=?][checked=checked]', 'membership[role_ids][]', '1'
end
def test_xhr_edit_user_membership
get :edit, :params => {
:user_id => 2,
:id => 1
},
:xhr => true
assert_response :success
end
def test_update_user_membership
assert_no_difference 'Member.count' do
put :update, :params => {
:user_id => 2,
:id => 1,
:membership => {
:role_ids => [2]
}
}
assert_redirected_to '/users/2/edit?tab=memberships'
end
assert_equal [2], Member.find(1).role_ids
end
def test_xhr_update_user_membership
assert_no_difference 'Member.count' do
put :update, :params => {
:user_id => 2,
:id => 1,
:membership => {
:role_ids => [2]
},
:format => 'js'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_equal [2], Member.find(1).role_ids
assert_include '$("#member-1-roles").html("Developer").show();', response.body
end
def test_destroy_user_membership
assert_difference 'Member.count', -1 do
delete :destroy, :params => {
:user_id => 2,
:id => 1
}
end
assert_redirected_to '/users/2/edit?tab=memberships'
assert_nil Member.find_by_id(1)
end
def test_xhr_destroy_user_membership_js_format
assert_difference 'Member.count', -1 do
delete :destroy, :params => {
:user_id => 2,
:id => 1
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_nil Member.find_by_id(1)
assert_include 'tab-content-memberships', response.body
end
def test_xhr_new_group_membership
get :new, :params => {
:group_id => 10
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
def test_create_group_membership
assert_difference 'Group.find(10).members.count' do
post :create, :params => {
:group_id => 10,
:membership => {
:project_ids => [2],
:role_ids => ['1', '2']
}
}
end
end
def test_xhr_create_group_membership
assert_difference 'Group.find(10).members.count' do
post :create, :params => {
:group_id => 10,
:membership => {
:project_ids => [2],
:role_ids => ['1', '2']
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_match /OnlineStore/, response.body
end
def test_xhr_create_group_membership_with_failure
assert_no_difference 'Group.find(10).members.count' do
post :create, :params => {
:group_id => 10,
:membership => {
:project_ids => [999],
:role_ids => ['1', '2']
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_match /alert/, response.body, "Alert message not sent"
end
def test_update_group_membership
assert_no_difference 'Group.find(10).members.count' do
put :update, :params => {
:group_id => 10,
:id => 6,
:membership => {
:role_ids => ['1', '3']
}
}
end
end
def test_xhr_update_group_membership
assert_no_difference 'Group.find(10).members.count' do
post :update, :params => {
:group_id => 10,
:id => 6,
:membership => {
:role_ids => ['1', '3']
}
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
end
def test_destroy_group_membership
assert_difference 'Group.find(10).members.count', -1 do
delete :destroy, :params => {
:group_id => 10,
:id => 6
}
end
end
def test_xhr_destroy_group_membership
assert_difference 'Group.find(10).members.count', -1 do
delete :destroy, :params => {
:group_id => 10,
:id => 6
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
end
end

View file

@ -0,0 +1,254 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class ProjectEnumerationsControllerTest < Redmine::ControllerTest
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :users, :issue_categories,
:projects_trackers,
:roles,
:member_roles,
:members,
:enabled_modules,
:custom_fields, :custom_fields_projects,
:custom_fields_trackers, :custom_values,
:time_entries
self.use_transactional_fixtures = false
def setup
@request.session[:user_id] = nil
Setting.default_language = 'en'
end
def test_update_to_override_system_activities
@request.session[:user_id] = 2 # manager
billable_field = TimeEntryActivityCustomField.find_by_name("Billable")
put :update, :params => {
:project_id => 1,
:enumerations => {
"9"=> {"parent_id"=>"9", "custom_field_values"=> {"7" => "1"}, "active"=>"0"}, # Design, De-activate
"10"=> {"parent_id"=>"10", "custom_field_values"=>{"7"=>"0"}, "active"=>"1"}, # Development, Change custom value
"14"=>{"parent_id"=>"14", "custom_field_values"=>{"7"=>"1"}, "active"=>"1"}, # Inactive Activity, Activate with custom value
"11"=>{"parent_id"=>"11", "custom_field_values"=>{"7"=>"1"}, "active"=>"1"} # QA, no changes
}
}
assert_response :redirect
assert_redirected_to '/projects/ecookbook/settings/activities'
# Created project specific activities...
project = Project.find('ecookbook')
# ... Design
design = project.time_entry_activities.find_by_name("Design")
assert design, "Project activity not found"
assert_equal 9, design.parent_id # Relate to the system activity
assert_not_equal design.parent.id, design.id # Different records
assert_equal design.parent.name, design.name # Same name
assert !design.active?
# ... Development
development = project.time_entry_activities.find_by_name("Development")
assert development, "Project activity not found"
assert_equal 10, development.parent_id # Relate to the system activity
assert_not_equal development.parent.id, development.id # Different records
assert_equal development.parent.name, development.name # Same name
assert development.active?
assert_equal "0", development.custom_value_for(billable_field).value
# ... Inactive Activity
previously_inactive = project.time_entry_activities.find_by_name("Inactive Activity")
assert previously_inactive, "Project activity not found"
assert_equal 14, previously_inactive.parent_id # Relate to the system activity
assert_not_equal previously_inactive.parent.id, previously_inactive.id # Different records
assert_equal previously_inactive.parent.name, previously_inactive.name # Same name
assert previously_inactive.active?
assert_equal "1", previously_inactive.custom_value_for(billable_field).value
# ... QA
assert_nil project.time_entry_activities.find_by_name("QA"), "Custom QA activity created when it wasn't modified"
end
def test_update_will_update_project_specific_activities
@request.session[:user_id] = 2 # manager
project_activity = TimeEntryActivity.new({
:name => 'Project Specific',
:parent => TimeEntryActivity.first,
:project => Project.find(1),
:active => true
})
assert project_activity.save
project_activity_two = TimeEntryActivity.new({
:name => 'Project Specific Two',
:parent => TimeEntryActivity.last,
:project => Project.find(1),
:active => true
})
assert project_activity_two.save
put :update, :params => {
:project_id => 1,
:enumerations => {
project_activity.id => {"custom_field_values"=> {"7" => "1"}, "active"=>"0"}, # De-activate
project_activity_two.id => {"custom_field_values"=>{"7" => "1"}, "active"=>"0"} # De-activate
}
}
assert_response :redirect
assert_redirected_to '/projects/ecookbook/settings/activities'
# Created project specific activities...
project = Project.find('ecookbook')
assert_equal 2, project.time_entry_activities.count
activity_one = project.time_entry_activities.find_by_name(project_activity.name)
assert activity_one, "Project activity not found"
assert_equal project_activity.id, activity_one.id
assert !activity_one.active?
activity_two = project.time_entry_activities.find_by_name(project_activity_two.name)
assert activity_two, "Project activity not found"
assert_equal project_activity_two.id, activity_two.id
assert !activity_two.active?
end
def test_update_when_creating_new_activities_will_convert_existing_data
assert_equal 3, TimeEntry.where(:activity_id => 9, :project_id => 1).count
@request.session[:user_id] = 2 # manager
put :update, :params => {
:project_id => 1,
:enumerations => {
"9"=> {
"parent_id"=>"9", "custom_field_values"=> {
"7" => "1"}, "active"=>"0"} # Design, De-activate
}
}
assert_response :redirect
# No more TimeEntries using the system activity
assert_equal 0, TimeEntry.where(:activity_id => 9, :project_id => 1).count,
"Time Entries still assigned to system activities"
# All TimeEntries using project activity
project_specific_activity = TimeEntryActivity.find_by_parent_id_and_project_id(9, 1)
assert_equal 3, TimeEntry.where(:activity_id => project_specific_activity.id,
:project_id => 1).count
"No Time Entries assigned to the project activity"
end
def test_update_when_creating_new_activities_will_not_convert_existing_data_if_an_exception_is_raised
# TODO: Need to cause an exception on create but these tests
# aren't setup for mocking. Just create a record now so the
# second one is a dupicate
parent = TimeEntryActivity.find(9)
TimeEntryActivity.create!({:name => parent.name, :project_id => 1,
:position => parent.position, :active => true, :parent_id => 9})
TimeEntry.create!({:project_id => 1, :hours => 1.0, :user => User.find(1),
:issue_id => 3, :activity_id => 10, :spent_on => '2009-01-01'})
assert_equal 3, TimeEntry.where(:activity_id => 9, :project_id => 1).count
assert_equal 1, TimeEntry.where(:activity_id => 10, :project_id => 1).count
@request.session[:user_id] = 2 # manager
put :update, :params => {
:project_id => 1,
:enumerations => {
# Design
"9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"},
# Development, Change custom value
"10"=> {"parent_id"=>"10", "custom_field_values"=>{"7"=>"0"}, "active"=>"1"}
}
}
assert_response :redirect
# TimeEntries shouldn't have been reassigned on the failed record
assert_equal 3, TimeEntry.where(:activity_id => 9,
:project_id => 1).count
"Time Entries are not assigned to system activities"
# TimeEntries shouldn't have been reassigned on the saved record either
assert_equal 1, TimeEntry.where(:activity_id => 10,
:project_id => 1).count
"Time Entries are not assigned to system activities"
end
def test_destroy
@request.session[:user_id] = 2 # manager
project_activity = TimeEntryActivity.new({
:name => 'Project Specific',
:parent => TimeEntryActivity.first,
:project => Project.find(1),
:active => true
})
assert project_activity.save
project_activity_two = TimeEntryActivity.new({
:name => 'Project Specific Two',
:parent => TimeEntryActivity.last,
:project => Project.find(1),
:active => true
})
assert project_activity_two.save
delete :destroy, :params => {
:project_id => 1
}
assert_response :redirect
assert_redirected_to '/projects/ecookbook/settings/activities'
assert_nil TimeEntryActivity.find_by_id(project_activity.id)
assert_nil TimeEntryActivity.find_by_id(project_activity_two.id)
end
def test_destroy_should_reassign_time_entries_back_to_the_system_activity
@request.session[:user_id] = 2 # manager
project_activity = TimeEntryActivity.new({
:name => 'Project Specific Design',
:parent => TimeEntryActivity.find(9),
:project => Project.find(1),
:active => true
})
assert project_activity.save
assert TimeEntry.where(["project_id = ? AND activity_id = ?", 1, 9]).
update_all("activity_id = '#{project_activity.id}'")
assert_equal 3, TimeEntry.where(:activity_id => project_activity.id,
:project_id => 1).count
delete :destroy, :params => {
:project_id => 1
}
assert_response :redirect
assert_redirected_to '/projects/ecookbook/settings/activities'
assert_nil TimeEntryActivity.find_by_id(project_activity.id)
assert_equal 0, TimeEntry.where(
:activity_id => project_activity.id,
:project_id => 1
).count,
"TimeEntries still assigned to project specific activity"
assert_equal 3, TimeEntry.where(
:activity_id => 9,
:project_id => 1
).count,
"TimeEntries still assigned to project specific activity"
end
end

View file

@ -0,0 +1,982 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class ProjectsControllerTest < Redmine::ControllerTest
fixtures :projects, :versions, :users, :email_addresses, :roles, :members,
:member_roles, :issues, :journals, :journal_details,
:trackers, :projects_trackers, :issue_statuses,
:enabled_modules, :enumerations, :boards, :messages,
:attachments, :custom_fields, :custom_values, :time_entries,
:wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
def setup
@request.session[:user_id] = nil
Setting.default_language = 'en'
end
def test_index_by_anonymous_should_not_show_private_projects
get :index
assert_response :success
assert_select 'ul' do
assert_select 'li' do
assert_select 'a', :text => 'eCookbook'
assert_select 'ul' do
assert_select 'a', :text => 'Child of private child'
end
end
end
assert_select 'a', :text => /Private child of eCookbook/, :count => 0
end
def test_index_atom
get :index, :params => {
:format => 'atom'
}
assert_response :success
assert_select 'feed>title', :text => 'Redmine: Latest projects'
assert_select 'feed>entry', :count => Project.visible(User.current).count
end
def test_autocomplete_js
get :autocomplete, :params => {
:format => 'js',
:q => 'coo'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
test "#index by non-admin user with view_time_entries permission should show overall spent time link" do
@request.session[:user_id] = 3
get :index
assert_select 'a[href=?]', '/time_entries'
end
test "#index by non-admin user without view_time_entries permission should not show overall spent time link" do
Role.find(2).remove_permission! :view_time_entries
Role.non_member.remove_permission! :view_time_entries
Role.anonymous.remove_permission! :view_time_entries
@request.session[:user_id] = 3
get :index
assert_select 'a[href=?]', '/time_entries', 0
end
test "#index by non-admin user with permission should show add project link" do
Role.find(1).add_permission! :add_project
@request.session[:user_id] = 2
get :index
assert_select 'a[href=?]', '/projects/new'
end
test "#new by admin user should accept get" do
@request.session[:user_id] = 1
get :new
assert_response :success
assert_select 'input[name=?]', 'project[name]'
assert_select 'select[name=?]', 'project[parent_id]'
end
test "#new by non-admin user with add_project permission should accept get" do
Role.non_member.add_permission! :add_project
@request.session[:user_id] = 9
get :new
assert_response :success
assert_select 'input[name=?]', 'project[name]'
assert_select 'select[name=?]', 'project[parent_id]', 0
end
test "#new by non-admin user with add_subprojects permission should accept get" do
Role.find(1).remove_permission! :add_project
Role.find(1).add_permission! :add_subprojects
@request.session[:user_id] = 2
get :new, :params => {
:parent_id => 'ecookbook'
}
assert_response :success
assert_select 'select[name=?]', 'project[parent_id]' do
# parent project selected
assert_select 'option[value="1"][selected=selected]'
# no empty value
assert_select 'option[value=""]', 0
end
end
def test_new_by_non_admin_should_display_modules_if_default_role_is_allowed_to_select_modules
Role.non_member.add_permission!(:add_project)
default_role = Role.generate!(:permissions => [:view_issues])
user = User.generate!
@request.session[:user_id] = user.id
with_settings :new_project_user_role_id => default_role.id.to_s do
get :new
assert_select 'input[name=?]', 'project[enabled_module_names][]', 0
default_role.add_permission!(:select_project_modules)
get :new
assert_select 'input[name=?]', 'project[enabled_module_names][]'
end
end
def test_new_should_not_display_invalid_search_link
@request.session[:user_id] = 1
get :new
assert_response :success
assert_select '#quick-search form[action=?]', '/search'
assert_select '#quick-search a[href=?]', '/search'
end
test "#create by admin user should create a new project" do
@request.session[:user_id] = 1
post :create, :params => {
:project => {
:name => "blog",
:description => "weblog",
:homepage => 'http://weblog',
:identifier => "blog",
:is_public => 1,
:custom_field_values => {
'3' => 'Beta'
},
:tracker_ids => ['1', '3'],
# an issue custom field that is not for all project
:issue_custom_field_ids => ['9'],
:enabled_module_names => ['issue_tracking', 'news', 'repository']
}
}
assert_redirected_to '/projects/blog/settings'
project = Project.find_by_name('blog')
assert_kind_of Project, project
assert project.active?
assert_equal 'weblog', project.description
assert_equal 'http://weblog', project.homepage
assert_equal true, project.is_public?
assert_nil project.parent
assert_equal 'Beta', project.custom_value_for(3).value
assert_equal [1, 3], project.trackers.map(&:id).sort
assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
assert project.issue_custom_fields.include?(IssueCustomField.find(9))
end
test "#create by admin user should create a new subproject" do
@request.session[:user_id] = 1
assert_difference 'Project.count' do
post :create, :params => {
:project => {
:name => "blog",
:description => "weblog",
:identifier => "blog",
:is_public => 1,
:custom_field_values => {
'3' => 'Beta'
},
:parent_id => 1
}
}
assert_redirected_to '/projects/blog/settings'
end
project = Project.find_by_name('blog')
assert_kind_of Project, project
assert_equal Project.find(1), project.parent
end
test "#create by admin user should continue" do
@request.session[:user_id] = 1
assert_difference 'Project.count' do
post :create, :params => {
:project => {
:name => "blog",
:identifier => "blog"
},
:continue => 'Create and continue'
}
end
assert_redirected_to '/projects/new'
end
test "#create by non-admin user with add_project permission should create a new project" do
Role.non_member.add_permission! :add_project
@request.session[:user_id] = 9
post :create, :params => {
:project => {
:name => "blog",
:description => "weblog",
:identifier => "blog",
:is_public => 1,
:custom_field_values => {
'3' => 'Beta'
},
:tracker_ids => ['1', '3'],
:enabled_module_names => ['issue_tracking', 'news', 'repository']
}
}
assert_redirected_to '/projects/blog/settings'
project = Project.find_by_name('blog')
assert_kind_of Project, project
assert_equal 'weblog', project.description
assert_equal true, project.is_public?
assert_equal [1, 3], project.trackers.map(&:id).sort
assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
# User should be added as a project member
assert User.find(9).member_of?(project)
assert_equal 1, project.members.size
end
test "#create by non-admin user with add_project permission should fail with parent_id" do
Role.non_member.add_permission! :add_project
User.find(9).update! :language => 'en'
@request.session[:user_id] = 9
assert_no_difference 'Project.count' do
post :create, :params => {
:project => {
:name => "blog",
:description => "weblog",
:identifier => "blog",
:is_public => 1,
:custom_field_values => {
'3' => 'Beta'
},
:parent_id => 1
}
}
end
assert_response :success
assert_select_error /Subproject of is invalid/
end
test "#create by non-admin user with add_subprojects permission should create a project with a parent_id" do
Role.find(1).remove_permission! :add_project
Role.find(1).add_permission! :add_subprojects
@request.session[:user_id] = 2
post :create, :params => {
:project => {
:name => "blog",
:description => "weblog",
:identifier => "blog",
:is_public => 1,
:custom_field_values => {
'3' => 'Beta'
},
:parent_id => 1
}
}
assert_redirected_to '/projects/blog/settings'
project = Project.find_by_name('blog')
assert_equal 1, project.parent_id
end
test "#create by non-admin user with add_subprojects permission should fail without parent_id" do
Role.find(1).remove_permission! :add_project
Role.find(1).add_permission! :add_subprojects
@request.session[:user_id] = 2
assert_no_difference 'Project.count' do
post :create, :params => {
:project => {
:name => "blog",
:description => "weblog",
:identifier => "blog",
:is_public => 1,
:custom_field_values => {
'3' => 'Beta'
}
}
}
end
assert_response :success
assert_select_error /Subproject of is invalid/
end
test "#create by non-admin user with add_subprojects permission should fail with unauthorized parent_id" do
Role.find(1).remove_permission! :add_project
Role.find(1).add_permission! :add_subprojects
@request.session[:user_id] = 2
assert !User.find(2).member_of?(Project.find(6))
assert_no_difference 'Project.count' do
post :create, :params => {
:project => {
:name => "blog",
:description => "weblog",
:identifier => "blog",
:is_public => 1,
:custom_field_values => {
'3' => 'Beta'
},
:parent_id => 6
}
}
end
assert_response :success
assert_select_error /Subproject of is invalid/
end
def test_create_by_non_admin_should_accept_modules_if_default_role_is_allowed_to_select_modules
Role.non_member.add_permission!(:add_project)
default_role = Role.generate!(:permissions => [:view_issues, :add_project])
user = User.generate!
@request.session[:user_id] = user.id
with_settings :new_project_user_role_id => default_role.id.to_s, :default_projects_modules => %w(news files) do
project = new_record(Project) do
post :create, :params => {
:project => {
:name => "blog1",
:identifier => "blog1",
:enabled_module_names => ["issue_tracking", "repository"]
}
}
end
assert_equal %w(files news), project.enabled_module_names.sort
default_role.add_permission!(:select_project_modules)
project = new_record(Project) do
post :create, :params => {
:project => {
:name => "blog2",
:identifier => "blog2",
:enabled_module_names => ["issue_tracking", "repository"]
}
}
end
assert_equal %w(issue_tracking repository), project.enabled_module_names.sort
end
end
def test_create_subproject_with_inherit_members_should_inherit_members
Role.find_by_name('Manager').add_permission! :add_subprojects
parent = Project.find(1)
@request.session[:user_id] = 2
assert_difference 'Project.count' do
post :create, :params => {
:project => {
:name => 'inherited',
:identifier => 'inherited',
:parent_id => parent.id,
:inherit_members => '1'
}
}
assert_response 302
end
project = Project.order('id desc').first
assert_equal 'inherited', project.name
assert_equal parent, project.parent
assert project.memberships.count > 0
assert_equal parent.memberships.count, project.memberships.count
end
def test_create_should_preserve_modules_on_validation_failure
with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
@request.session[:user_id] = 1
assert_no_difference 'Project.count' do
post :create, :params => {
:project => {
:name => "blog",
:identifier => "",
:enabled_module_names => %w(issue_tracking news)
}
}
end
assert_response :success
%w(issue_tracking news).each do |mod|
assert_select 'input[name=?][value=?][checked=checked]', 'project[enabled_module_names][]', mod
end
assert_select 'input[name=?][checked=checked]', 'project[enabled_module_names][]', :count => 2
end
end
def test_show_by_id
get :show, :params => {
:id => 1
}
assert_response :success
assert_select '#header h1', :text => "eCookbook"
end
def test_show_by_identifier
get :show, :params => {
:id => 'ecookbook'
}
assert_response :success
assert_select '#header h1', :text => "eCookbook"
end
def test_show_should_not_display_empty_sidebar
p = Project.find(1)
p.enabled_module_names = []
p.save!
get :show, :params => {
:id => 'ecookbook'
}
assert_response :success
assert_select '#main.nosidebar'
end
def test_show_should_display_visible_custom_fields
ProjectCustomField.find_by_name('Development status').update_attribute :visible, true
get :show, :params => {
:id => 'ecookbook'
}
assert_response :success
assert_select 'li', :text => /Development status/
end
def test_show_should_not_display_hidden_custom_fields
ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
get :show, :params => {
:id => 'ecookbook'
}
assert_response :success
assert_select 'li', :text => /Development status/, :count => 0
end
def test_show_should_not_display_blank_custom_fields_with_multiple_values
f1 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Foo Bar), :multiple => true
f2 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Baz Qux), :multiple => true
project = Project.generate!(:custom_field_values => {f2.id.to_s => %w(Qux)})
get :show, :params => {
:id => project.id
}
assert_response :success
assert_select 'li', :text => /#{f1.name}/, :count => 0
assert_select 'li', :text => /#{f2.name}/
end
def test_show_should_not_display_blank_text_custom_fields
f1 = ProjectCustomField.generate! :field_format => 'text'
get :show, :params => {
:id => 1
}
assert_response :success
assert_select 'li', :text => /#{f1.name}/, :count => 0
end
def test_show_should_not_fail_when_custom_values_are_nil
project = Project.find_by_identifier('ecookbook')
project.custom_values.first.update_attribute(:value, nil)
get :show, :params => {
:id => 'ecookbook'
}
assert_response :success
end
def show_archived_project_should_be_denied
project = Project.find_by_identifier('ecookbook')
project.archive!
get :show, :params => {
:id => 'ecookbook'
}
assert_response 403
assert_select 'p', :text => /archived/
assert_not_include project.name, response.body
end
def test_show_should_not_show_private_subprojects_that_are_not_visible
get :show, :params => {
:id => 'ecookbook'
}
assert_response :success
assert_select 'a', :text => /Private child/, :count => 0
end
def test_show_should_show_private_subprojects_that_are_visible
@request.session[:user_id] = 2 # manager who is a member of the private subproject
get :show, :params => {
:id => 'ecookbook'
}
assert_response :success
assert_select 'a', :text => /Private child/
end
def test_show_by_member_on_leaf_project_should_display_issue_counts
@request.session[:user_id] = 2
get :show, :params => {
:id => 'onlinestore'
}
assert_response :success
# Make sure there's a > 0 issue count
assert_select 'table.issue-report td.total a', :text => %r{\A[1-9]\d*\z}
end
def test_settings
@request.session[:user_id] = 2 # manager
get :settings, :params => {
:id => 1
}
assert_response :success
assert_select 'input[name=?]', 'project[name]'
end
def test_settings_of_subproject
@request.session[:user_id] = 2
get :settings, :params => {
:id => 'private-child'
}
assert_response :success
assert_select 'input[type=checkbox][name=?]', 'project[inherit_members]'
end
def test_settings_should_be_denied_for_member_on_closed_project
Project.find(1).close
@request.session[:user_id] = 2 # manager
get :settings, :params => {
:id => 1
}
assert_response 403
end
def test_settings_should_be_denied_for_anonymous_on_closed_project
Project.find(1).close
get :settings, :params => {
:id => 1
}
assert_response 302
end
def test_setting_with_wiki_module_and_no_wiki
Project.find(1).wiki.destroy
Role.find(1).add_permission! :manage_wiki
@request.session[:user_id] = 2
get :settings, :params => {
:id => 1
}
assert_response :success
assert_select 'form[action=?]', '/projects/ecookbook/wiki' do
assert_select 'input[name=?]', 'wiki[start_page]'
end
end
def test_settings_should_accept_version_status_filter
@request.session[:user_id] = 2
get :settings, :params => {
:id => 'ecookbook',
:tab => 'versions',
:version_status => 'locked'
}
assert_response :success
assert_select 'select[name=version_status]' do
assert_select 'option[value=locked][selected=selected]'
end
assert_select 'table.versions tbody' do
assert_select 'tr', 1
assert_select 'td.name', :text => '1.0'
end
assert_select 'a#tab-versions[href=?]', '/projects/ecookbook/settings/versions?version_status=locked'
end
def test_settings_should_accept_version_name_filter
@request.session[:user_id] = 2
get :settings, :params => {
:id => 'ecookbook',
:tab => 'versions',
:version_status => '',
:version_name => '.1'
}
assert_response :success
assert_select 'input[name=version_name][value=?]', '.1'
assert_select 'table.versions tbody' do
assert_select 'tr', 1
assert_select 'td.name', :text => '0.1'
end
assert_select 'a#tab-versions[href=?]', '/projects/ecookbook/settings/versions?version_name=.1&version_status='
end
def test_settings_should_show_locked_members
user = User.generate!
member = User.add_to_project(user, Project.find(1))
user.lock!
assert user.reload.locked?
@request.session[:user_id] = 2
get :settings, :params => {
:id => 'ecookbook',
:tab => 'members'
}
assert_response :success
assert_select "tr#member-#{member.id}"
end
def test_update
@request.session[:user_id] = 2 # manager
post :update, :params => {
:id => 1,
:project => {
:name => 'Test changed name',
:issue_custom_field_ids => ['']
}
}
assert_redirected_to '/projects/ecookbook/settings'
project = Project.find(1)
assert_equal 'Test changed name', project.name
end
def test_update_with_failure
@request.session[:user_id] = 2 # manager
post :update, :params => {
:id => 1,
:project => {
:name => ''
}
}
assert_response :success
assert_select_error /name cannot be blank/i
end
def test_update_should_be_denied_for_member_on_closed_project
Project.find(1).close
@request.session[:user_id] = 2 # manager
post :update, :params => {
:id => 1,
:project => {
:name => 'Closed'
}
}
assert_response 403
assert_equal 'eCookbook', Project.find(1).name
end
def test_update_should_be_denied_for_anonymous_on_closed_project
Project.find(1).close
post :update, :params => {
:id => 1,
:project => {
:name => 'Closed'
}
}
assert_response 302
assert_equal 'eCookbook', Project.find(1).name
end
def test_update_child_project_without_parent_permission_should_not_show_validation_error
child = Project.generate_with_parent!
user = User.generate!
User.add_to_project(user, child, Role.generate!(:permissions => [:edit_project]))
@request.session[:user_id] = user.id
post :update, :params => {
:id => child.id,
:project => {
:name => 'Updated'
}
}
assert_response 302
assert_match /Successful update/, flash[:notice]
end
def test_modules
@request.session[:user_id] = 2
Project.find(1).enabled_module_names = ['issue_tracking', 'news']
post :modules, :params => {
:id => 1,
:enabled_module_names => ['issue_tracking', 'repository', 'documents']
}
assert_redirected_to '/projects/ecookbook/settings/modules'
assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
end
def test_destroy_leaf_project_without_confirmation_should_show_confirmation
@request.session[:user_id] = 1 # admin
assert_no_difference 'Project.count' do
delete :destroy, :params => {
:id => 2
}
assert_response :success
end
assert_select '.warning', :text => /Are you sure you want to delete this project/
end
def test_destroy_without_confirmation_should_show_confirmation_with_subprojects
@request.session[:user_id] = 1 # admin
assert_no_difference 'Project.count' do
delete :destroy, :params => {
:id => 1
}
assert_response :success
end
assert_select 'strong',
:text => ['Private child of eCookbook',
'Child of private child, eCookbook Subproject 1',
'eCookbook Subproject 2'].join(', ')
end
def test_destroy_with_confirmation_should_destroy_the_project_and_subprojects
@request.session[:user_id] = 1 # admin
assert_difference 'Project.count', -5 do
delete :destroy, :params => {
:id => 1,
:confirm => 1
}
assert_redirected_to '/admin/projects'
end
assert_nil Project.find_by_id(1)
end
def test_archive
@request.session[:user_id] = 1 # admin
post :archive, :params => {
:id => 1
}
assert_redirected_to '/admin/projects'
assert !Project.find(1).active?
end
def test_archive_with_failure
@request.session[:user_id] = 1
Project.any_instance.stubs(:archive).returns(false)
post :archive, :params => {
:id => 1
}
assert_redirected_to '/admin/projects'
assert_match /project cannot be archived/i, flash[:error]
end
def test_unarchive
@request.session[:user_id] = 1 # admin
Project.find(1).archive
post :unarchive, :params => {
:id => 1
}
assert_redirected_to '/admin/projects'
assert Project.find(1).active?
end
def test_close
@request.session[:user_id] = 2
post :close, :params => {
:id => 1
}
assert_redirected_to '/projects/ecookbook'
assert_equal Project::STATUS_CLOSED, Project.find(1).status
end
def test_reopen
Project.find(1).close
@request.session[:user_id] = 2
post :reopen, :params => {
:id => 1
}
assert_redirected_to '/projects/ecookbook'
assert Project.find(1).active?
end
def test_project_breadcrumbs_should_be_limited_to_3_ancestors
CustomField.delete_all
parent = nil
6.times do |i|
p = Project.generate_with_parent!(parent)
get :show, :params => {
:id => p
}
assert_select '#header h1' do
assert_select 'a', :count => [i, 3].min
end
parent = p
end
end
def test_get_copy
@request.session[:user_id] = 1 # admin
orig = Project.find(1)
get :copy, :params => {
:id => orig.id
}
assert_response :success
assert_select 'textarea[name=?]', 'project[description]', :text => orig.description
assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1
end
def test_get_copy_with_invalid_source_should_respond_with_404
@request.session[:user_id] = 1
get :copy, :params => {
:id => 99
}
assert_response 404
end
def test_get_copy_should_preselect_custom_fields
field1 = IssueCustomField.generate!(:is_for_all => false)
field2 = IssueCustomField.generate!(:is_for_all => false)
source = Project.generate!(:issue_custom_fields => [field1])
@request.session[:user_id] = 1
get :copy, :params => {
:id => source.id
}
assert_response :success
assert_select 'fieldset#project_issue_custom_fields' do
assert_select 'input[type=checkbox][value=?][checked=checked]', field1.id.to_s
assert_select 'input[type=checkbox][value=?]:not([checked])', field2.id.to_s
end
end
def test_post_copy_should_copy_requested_items
@request.session[:user_id] = 1 # admin
CustomField.delete_all
assert_difference 'Project.count' do
post :copy, :params => {
:id => 1,
:project => {
:name => 'Copy',
:identifier => 'unique-copy',
:tracker_ids => ['1', '2', '3', ''],
:enabled_module_names => %w(issue_tracking time_tracking)
},
:only => %w(issues versions)
}
end
project = Project.find('unique-copy')
source = Project.find(1)
assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
assert_equal source.versions.count, project.versions.count, "All versions were not copied"
assert_equal source.issues.count, project.issues.count, "All issues were not copied"
assert_equal 0, project.members.count
end
def test_post_copy_should_redirect_to_settings_when_successful
@request.session[:user_id] = 1 # admin
post :copy, :params => {
:id => 1,
:project => {
:name => 'Copy',
:identifier => 'unique-copy'
}
}
assert_response :redirect
assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
end
def test_post_copy_with_failure
@request.session[:user_id] = 1
post :copy, :params => {
:id => 1,
:project => {
:name => 'Copy',
:identifier => ''
}
}
assert_response :success
assert_select_error /Identifier cannot be blank/
end
def test_jump_without_project_id_should_redirect_to_active_tab
get :index, :params => {
:jump => 'issues'
}
assert_redirected_to '/issues'
end
def test_jump_should_not_redirect_to_unknown_tab
get :index, :params => {
:jump => 'foobar'
}
assert_response :success
end
def test_jump_should_redirect_to_active_tab
get :show, :params => {
:id => 1,
:jump => 'issues'
}
assert_redirected_to '/projects/ecookbook/issues'
end
def test_jump_should_not_redirect_to_inactive_tab
get :show, :params => {
:id => 3,
:jump => 'documents'
}
assert_response :success
end
def test_jump_should_not_redirect_to_unknown_tab
get :show, :params => {
:id => 3,
:jump => 'foobar'
}
assert_response :success
end
def test_body_should_have_project_css_class
get :show, :params => {
:id => 1
}
assert_select 'body.project-ecookbook'
end
end

View file

@ -0,0 +1,599 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class QueriesControllerTest < Redmine::ControllerTest
fixtures :projects, :enabled_modules,
:users, :email_addresses,
:members, :member_roles, :roles,
:trackers, :issue_statuses, :issue_categories, :enumerations, :versions,
:issues, :custom_fields, :custom_values,
:queries
def setup
User.current = nil
end
def test_index
get :index
# HTML response not implemented
assert_response 406
end
def test_new_project_query
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 1
}
assert_response :success
assert_select 'input[name=?][value="0"][checked=checked]', 'query[visibility]'
assert_select 'input[name=query_is_for_all][type=checkbox]:not([checked]):not([disabled])'
assert_select 'select[name=?]', 'c[]' do
assert_select 'option[value=tracker]'
assert_select 'option[value=subject]'
end
end
def test_new_global_query
@request.session[:user_id] = 2
get :new
assert_response :success
assert_select 'input[name=?]', 'query[visibility]', 0
assert_select 'input[name=query_is_for_all][type=checkbox][checked]:not([disabled])'
end
def test_new_on_invalid_project
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 'invalid'
}
assert_response 404
end
def test_new_time_entry_query
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 1,
:type => 'TimeEntryQuery'
}
assert_response :success
assert_select 'input[name=type][value=?]', 'TimeEntryQuery'
end
def test_new_time_entry_query_with_issue_tracking_module_disabled_should_be_allowed
Project.find(1).disable_module! :issue_tracking
@request.session[:user_id] = 2
get :new, :params => {
:project_id => 1,
:type => 'TimeEntryQuery'
}
assert_response :success
end
def test_create_project_public_query
@request.session[:user_id] = 2
post :create, :params => {
:project_id => 'ecookbook',
:default_columns => '1',
:f => ["status_id", "assigned_to_id"],
:op => {
"assigned_to_id" => "=", "status_id" => "o"
},
:v => {
"assigned_to_id" => ["1"], "status_id" => ["1"]
},
:query => {
"name" => "test_new_project_public_query", "visibility" => "2"
}
}
q = Query.find_by_name('test_new_project_public_query')
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :query_id => q
assert q.is_public?
assert q.has_default_columns?
assert q.valid?
end
def test_create_project_private_query
@request.session[:user_id] = 3
post :create, :params => {
:project_id => 'ecookbook',
:default_columns => '1',
:fields => ["status_id", "assigned_to_id"],
:operators => {
"assigned_to_id" => "=", "status_id" => "o"
},
:values => {
"assigned_to_id" => ["1"], "status_id" => ["1"]
},
:query => {
"name" => "test_new_project_private_query", "visibility" => "0"
}
}
q = Query.find_by_name('test_new_project_private_query')
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :query_id => q
assert !q.is_public?
assert q.has_default_columns?
assert q.valid?
end
def test_create_project_roles_query
@request.session[:user_id] = 2
post :create, :params => {
:project_id => 'ecookbook',
:default_columns => '1',
:fields => ["status_id", "assigned_to_id"],
:operators => {
"assigned_to_id" => "=", "status_id" => "o"
},
:values => {
"assigned_to_id" => ["1"], "status_id" => ["1"]
},
:query => {
"name" => "test_create_project_roles_query", "visibility" => "1", "role_ids" => ["1", "2", ""]
}
}
q = Query.find_by_name('test_create_project_roles_query')
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :query_id => q
assert_equal Query::VISIBILITY_ROLES, q.visibility
assert_equal [1, 2], q.roles.ids.sort
end
def test_create_global_private_query_with_custom_columns
@request.session[:user_id] = 3
post :create, :params => {
:fields => ["status_id", "assigned_to_id"],
:operators => {
"assigned_to_id" => "=", "status_id" => "o"
},
:values => {
"assigned_to_id" => ["me"], "status_id" => ["1"]
},
:query => {
"name" => "test_new_global_private_query", "visibility" => "0"
},
:c => ["", "tracker", "subject", "priority", "category"]
}
q = Query.find_by_name('test_new_global_private_query')
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => nil, :query_id => q
assert !q.is_public?
assert !q.has_default_columns?
assert_equal [:id, :tracker, :subject, :priority, :category], q.columns.collect {|c| c.name}
assert q.valid?
end
def test_create_global_query_with_custom_filters
@request.session[:user_id] = 3
post :create, :params => {
:fields => ["assigned_to_id"],
:operators => {
"assigned_to_id" => "="
},
:values => {
"assigned_to_id" => ["me"]
},
:query => {
"name" => "test_new_global_query"
}
}
q = Query.find_by_name('test_new_global_query')
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => nil, :query_id => q
assert !q.is_public?
assert !q.has_filter?(:status_id)
assert_equal ['assigned_to_id'], q.filters.keys
assert q.valid?
end
def test_create_with_sort
@request.session[:user_id] = 1
post :create, :params => {
:default_columns => '1',
:operators => {
"status_id" => "o"
},
:values => {
"status_id" => ["1"]
},
:query => {
:name => "test_new_with_sort",
:visibility => "2",
:sort_criteria => {
"0" => ["due_date", "desc"], "1" => ["tracker", ""]}
}
}
query = Query.find_by_name("test_new_with_sort")
assert_not_nil query
assert_equal [['due_date', 'desc'], ['tracker', 'asc']], query.sort_criteria
end
def test_create_with_failure
@request.session[:user_id] = 2
assert_no_difference '::Query.count' do
post :create, :params => {
:project_id => 'ecookbook',
:query => {
:name => ''
}
}
end
assert_response :success
assert_select 'input[name=?]', 'query[name]'
end
def test_create_global_query_from_gantt
@request.session[:user_id] = 1
assert_difference 'IssueQuery.count' do
post :create, :params => {
:gantt => 1,
:operators => {
"status_id" => "o"
},
:values => {
"status_id" => ["1"]
},
:query => {
:name => "test_create_from_gantt",
:draw_relations => '1',
:draw_progress_line => '1'
}
}
assert_response 302
end
query = IssueQuery.order('id DESC').first
assert_redirected_to "/issues/gantt?query_id=#{query.id}"
assert_equal true, query.draw_relations
assert_equal true, query.draw_progress_line
end
def test_create_project_query_from_gantt
@request.session[:user_id] = 1
assert_difference 'IssueQuery.count' do
post :create, :params => {
:project_id => 'ecookbook',
:gantt => 1,
:operators => {
"status_id" => "o"
},
:values => {
"status_id" => ["1"]
},
:query => {
:name => "test_create_from_gantt",
:draw_relations => '0',
:draw_progress_line => '0'
}
}
assert_response 302
end
query = IssueQuery.order('id DESC').first
assert_redirected_to "/projects/ecookbook/issues/gantt?query_id=#{query.id}"
assert_equal false, query.draw_relations
assert_equal false, query.draw_progress_line
end
def test_create_project_public_query_should_force_private_without_manage_public_queries_permission
@request.session[:user_id] = 3
query = new_record(Query) do
post :create, :params => {
:project_id => 'ecookbook',
:query => {
"name" => "name", "visibility" => "2"
}
}
assert_response 302
end
assert_not_nil query.project
assert_equal Query::VISIBILITY_PRIVATE, query.visibility
end
def test_create_global_public_query_should_force_private_without_manage_public_queries_permission
@request.session[:user_id] = 3
query = new_record(Query) do
post :create, :params => {
:project_id => 'ecookbook',
:query_is_for_all => '1',
:query => {
"name" => "name", "visibility" => "2"
}
}
assert_response 302
end
assert_nil query.project
assert_equal Query::VISIBILITY_PRIVATE, query.visibility
end
def test_create_project_public_query_with_manage_public_queries_permission
@request.session[:user_id] = 2
query = new_record(Query) do
post :create, :params => {
:project_id => 'ecookbook',
:query => {
"name" => "name", "visibility" => "2"
}
}
assert_response 302
end
assert_not_nil query.project
assert_equal Query::VISIBILITY_PUBLIC, query.visibility
end
def test_create_global_public_query_should_force_private_with_manage_public_queries_permission
@request.session[:user_id] = 2
query = new_record(Query) do
post :create, :params => {
:project_id => 'ecookbook',
:query_is_for_all => '1',
:query => {
"name" => "name", "visibility" => "2"
}
}
assert_response 302
end
assert_nil query.project
assert_equal Query::VISIBILITY_PRIVATE, query.visibility
end
def test_create_global_public_query_by_admin
@request.session[:user_id] = 1
query = new_record(Query) do
post :create, :params => {
:project_id => 'ecookbook',
:query_is_for_all => '1',
:query => {
"name" => "name", "visibility" => "2"
}
}
assert_response 302
end
assert_nil query.project
assert_equal Query::VISIBILITY_PUBLIC, query.visibility
end
def test_create_project_public_time_entry_query
@request.session[:user_id] = 2
q = new_record(TimeEntryQuery) do
post :create, :params => {
:project_id => 'ecookbook',
:type => 'TimeEntryQuery',
:default_columns => '1',
:f => ["spent_on"],
:op => {
"spent_on" => "="
},
:v => {
"spent_on" => ["2016-07-14"]
},
:query => {
"name" => "test_new_project_public_query", "visibility" => "2"
}
}
end
assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => 'ecookbook', :query_id => q.id
assert q.is_public?
assert q.has_default_columns?
assert q.valid?
end
def test_edit_global_public_query
@request.session[:user_id] = 1
get :edit, :params => {
:id => 4
}
assert_response :success
assert_select 'input[name=?][value="2"][checked=checked]', 'query[visibility]'
assert_select 'input[name=query_is_for_all][type=checkbox][checked=checked]'
end
def test_edit_global_private_query
@request.session[:user_id] = 3
get :edit, :params => {
:id => 3
}
assert_response :success
assert_select 'input[name=?]', 'query[visibility]', 0
assert_select 'input[name=query_is_for_all][type=checkbox][checked=checked]'
end
def test_edit_project_private_query
@request.session[:user_id] = 3
get :edit, :params => {
:id => 2
}
assert_response :success
assert_select 'input[name=?]', 'query[visibility]', 0
assert_select 'input[name=query_is_for_all][type=checkbox]:not([checked])'
end
def test_edit_project_public_query
@request.session[:user_id] = 2
get :edit, :params => {
:id => 1
}
assert_response :success
assert_select 'input[name=?][value="2"][checked=checked]', 'query[visibility]'
assert_select 'input[name=query_is_for_all][type=checkbox]:not([checked])'
end
def test_edit_sort_criteria
@request.session[:user_id] = 1
get :edit, :params => {
:id => 5
}
assert_response :success
assert_select 'select[name=?]', 'query[sort_criteria][0][]' do
assert_select 'option[value=priority][selected=selected]'
assert_select 'option[value=desc][selected=selected]'
end
end
def test_edit_invalid_query
@request.session[:user_id] = 2
get :edit, :params => {
:id => 99
}
assert_response 404
end
def test_udpate_global_private_query
@request.session[:user_id] = 3
put :update, :params => {
:id => 3,
:default_columns => '1',
:fields => ["status_id", "assigned_to_id"],
:operators => {
"assigned_to_id" => "=", "status_id" => "o"
},
:values => {
"assigned_to_id" => ["me"], "status_id" => ["1"]
},
:query => {
"name" => "test_edit_global_private_query", "visibility" => "2"
}
}
assert_redirected_to :controller => 'issues', :action => 'index', :query_id => 3
q = Query.find_by_name('test_edit_global_private_query')
assert !q.is_public?
assert q.has_default_columns?
assert q.valid?
end
def test_update_global_public_query
@request.session[:user_id] = 1
put :update, :params => {
:id => 4,
:default_columns => '1',
:fields => ["status_id", "assigned_to_id"],
:operators => {
"assigned_to_id" => "=", "status_id" => "o"
},
:values => {
"assigned_to_id" => ["1"], "status_id" => ["1"]
},
:query => {
"name" => "test_edit_global_public_query", "visibility" => "2"
}
}
assert_redirected_to :controller => 'issues', :action => 'index', :query_id => 4
q = Query.find_by_name('test_edit_global_public_query')
assert q.is_public?
assert q.has_default_columns?
assert q.valid?
end
def test_update_with_failure
@request.session[:user_id] = 1
put :update, :params => {
:id => 4,
:query => {
:name => ''
}
}
assert_response :success
assert_select_error /Name cannot be blank/
end
def test_destroy
@request.session[:user_id] = 2
delete :destroy, :params => {
:id => 1
}
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :set_filter => 1, :query_id => nil
assert_nil Query.find_by_id(1)
end
def test_backslash_should_be_escaped_in_filters
@request.session[:user_id] = 2
get :new, :params => {
:subject => 'foo/bar'
}
assert_response :success
assert_include 'addFilter("subject", "=", ["foo\/bar"]);', response.body
end
def test_filter_with_project_id_should_return_filter_values
@request.session[:user_id] = 2
get :filter, :params => {
:project_id => 1,
:name => 'fixed_version_id'
}
assert_response :success
assert_equal 'application/json', response.content_type
json = ActiveSupport::JSON.decode(response.body)
assert_include ["eCookbook - 2.0", "3", "open"], json
end
def test_version_filter_time_entries_with_project_id_should_return_filter_values
@request.session[:user_id] = 2
get :filter, :params => {
:project_id => 1,
:type => 'TimeEntryQuery',
:name => 'issue.fixed_version_id'
}
assert_response :success
assert_equal 'application/json', response.content_type
json = ActiveSupport::JSON.decode(response.body)
assert_include ["eCookbook - 2.0", "3", "open"], json
end
def test_filter_without_project_id_should_return_filter_values
@request.session[:user_id] = 2
get :filter, :params => {
:name => 'fixed_version_id'
}
assert_response :success
assert_equal 'application/json', response.content_type
json = ActiveSupport::JSON.decode(response.body)
assert_include ["OnlineStore - Systemwide visible version", "7", "open"], json
end
def test_subproject_filter_time_entries_with_project_id_should_return_filter_values
@request.session[:user_id] = 2
get :filter, :params => {
:project_id => 1,
:type => 'TimeEntryQuery',
:name => 'subproject_id'
}
assert_response :success
assert_equal 'application/json', response.content_type
json = ActiveSupport::JSON.decode(response.body)
assert_equal 4, json.count
assert_include ["Private child of eCookbook","5"], json
end
end

View file

@ -0,0 +1,75 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class ReportsControllerTest < Redmine::ControllerTest
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :users, :issue_categories,
:projects_trackers,
:roles,
:member_roles,
:members,
:enabled_modules,
:versions
def test_get_issue_report
get :issue_report, :params => {
:id => 1
}
assert_response :success
end
def test_get_issue_report_details
%w(tracker version priority category assigned_to author subproject).each do |detail|
get :issue_report_details, :params => {
:id => 1,
:detail => detail
}
assert_response :success
end
end
def test_get_issue_report_details_by_tracker_should_show_issue_count
Issue.delete_all
Issue.generate!(:tracker_id => 1)
Issue.generate!(:tracker_id => 1)
Issue.generate!(:tracker_id => 1, :status_id => 5)
Issue.generate!(:tracker_id => 2)
get :issue_report_details, :params => {
:id => 1,
:detail => 'tracker'
}
assert_select 'table.list tbody :nth-child(1)' do
assert_select 'td', :text => 'Bug'
assert_select ':nth-child(2)', :text => '2' # status:1
assert_select ':nth-child(3)', :text => '-' # status:2
assert_select ':nth-child(8)', :text => '2' # open
assert_select ':nth-child(9)', :text => '1' # closed
assert_select ':nth-child(10)', :text => '3' # total
end
end
def test_get_issue_report_details_with_an_invalid_detail
get :issue_report_details, :params => {
:id => 1,
:detail => 'invalid'
}
assert_response 404
end
end

View file

@ -0,0 +1,265 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class RepositoriesBazaarControllerTest < Redmine::ControllerTest
tests RepositoriesController
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
:repositories, :enabled_modules
REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s
REPOSITORY_PATH_TRUNK = File.join(REPOSITORY_PATH, "trunk")
PRJ_ID = 3
CHAR_1_UTF8_HEX = "\xc3\x9c".dup.force_encoding('UTF-8')
def setup
User.current = nil
@project = Project.find(PRJ_ID)
@repository = Repository::Bazaar.create(
:project => @project,
:url => REPOSITORY_PATH_TRUNK,
:log_encoding => 'UTF-8')
assert @repository
end
if File.directory?(REPOSITORY_PATH)
def test_get_new
@request.session[:user_id] = 1
@project.repository.destroy
get :new, :params => {
:project_id => 'subproject1',
:repository_scm => 'Bazaar'
}
assert_response :success
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Bazaar'
end
end
def test_browse_root
get :show, :params => {
:id => PRJ_ID
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 2
assert_select 'tr.dir td.filename a', :text => 'directory'
assert_select 'tr.file td.filename a', :text => 'doc-mkdir.txt'
end
end
def test_browse_directory
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['directory'])[:param]
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 3
assert_select 'tr.file td.filename a', :text => 'doc-ls.txt'
assert_select 'tr.file td.filename a', :text => 'document.txt'
assert_select 'tr.file td.filename a', :text => 'edit.png'
end
end
def test_browse_at_given_revision
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash([])[:param],
:rev => 3
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 4
assert_select 'tr.dir td.filename a', :text => 'directory'
assert_select 'tr.file td.filename a', :text => 'doc-deleted.txt'
assert_select 'tr.file td.filename a', :text => 'doc-ls.txt'
assert_select 'tr.file td.filename a', :text => 'doc-mkdir.txt'
end
end
def test_changes
get :changes, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['doc-mkdir.txt'])[:param]
}
assert_response :success
assert_select 'h2', :text => /doc-mkdir.txt/
end
def test_entry_show
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['directory', 'doc-ls.txt'])[:param]
}
assert_response :success
# Line 19
assert_select 'tr#L29 td.line-code', :text => /Show help message/
end
def test_entry_download
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['directory', 'doc-ls.txt'])[:param],
:format => 'raw'
}
assert_response :success
# File content
assert @response.body.include?('Show help message')
end
def test_directory_entry
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['directory'])[:param]
}
assert_response :success
assert_select 'table.entries tbody'
end
def test_diff
# Full diff of changeset 3
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => 3,
:type => dt
}
assert_response :success
# Line 11 removed
assert_select 'th.line-num:contains(11) ~ td.diff_out', :text => /Display more information/
end
end
def test_annotate
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['doc-mkdir.txt'])[:param]
}
assert_response :success
assert_select "th.line-num", :text => '2' do
assert_select "+ td.revision" do
assert_select "a", :text => '3'
assert_select "+ td.author", :text => "jsmith@" do
assert_select "+ td",
:text => "Main purpose:"
end
end
end
end
def test_annotate_author_escaping
repository = Repository::Bazaar.create(
:project => @project,
:url => File.join(REPOSITORY_PATH, "author_escaping"),
:identifier => 'author_escaping',
:log_encoding => 'UTF-8')
assert repository
get :annotate, :params => {
:id => PRJ_ID,
:repository_id => 'author_escaping',
:path => repository_path_hash(['author-escaping-test.txt'])[:param]
}
assert_response :success
assert_select "th.line-num", :text => '1' do
assert_select "+ td.revision" do
assert_select "a", :text => '2'
assert_select "+ td.author", :text => "test &" do
assert_select "+ td",
:text => "author escaping test"
end
end
end
end
def test_annotate_author_non_ascii
log_encoding = nil
if Encoding.locale_charmap == "UTF-8" ||
Encoding.locale_charmap == "ISO-8859-1"
log_encoding = Encoding.locale_charmap
end
unless log_encoding.nil?
repository = Repository::Bazaar.create(
:project => @project,
:url => File.join(REPOSITORY_PATH, "author_non_ascii"),
:identifier => 'author_non_ascii',
:log_encoding => log_encoding)
assert repository
get :annotate, :params => {
:id => PRJ_ID,
:repository_id => 'author_non_ascii',
:path => repository_path_hash(['author-non-ascii-test.txt'])[:param]
}
assert_response :success
assert_select "th.line-num", :text => '1' do
assert_select "+ td.revision" do
assert_select "a", :text => '2'
assert_select "+ td.author", :text => "test #{CHAR_1_UTF8_HEX}" do
assert_select "+ td",
:text => "author non ASCII test"
end
end
end
end
end
def test_destroy_valid_repository
@request.session[:user_id] = 1 # admin
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
assert @repository.changesets.count > 0
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
def test_destroy_invalid_repository
@request.session[:user_id] = 1 # admin
@project.repository.destroy
@repository = Repository::Bazaar.create!(
:project => @project,
:url => "/invalid",
:log_encoding => 'UTF-8')
@repository.fetch_changesets
@repository.reload
assert_equal 0, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
else
puts "Bazaar test repository NOT FOUND. Skipping functional tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,411 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class RepositoriesControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles, :enabled_modules,
:repositories, :issues, :issue_statuses, :changesets, :changes,
:issue_categories, :enumerations, :custom_fields, :custom_values, :trackers
def setup
User.current = nil
end
def test_new
@request.session[:user_id] = 1
get :new, :params => {
:project_id => 'subproject1'
}
assert_response :success
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Subversion'
end
assert_select 'input[name=?]:not([disabled])', 'repository[url]'
end
def test_new_should_propose_enabled_scm_only
@request.session[:user_id] = 1
with_settings :enabled_scm => ['Mercurial', 'Git'] do
get :new, :params => {
:project_id => 'subproject1'
}
end
assert_response :success
assert_select 'select[name=repository_scm]' do
assert_select 'option', 3
assert_select 'option[value=Mercurial][selected=selected]'
assert_select 'option[value=Git]:not([selected])'
end
end
def test_get_new_with_type
@request.session[:user_id] = 1
get :new, :params => {
:project_id => 'subproject1',
:repository_scm => 'Git'
}
assert_response :success
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Git'
end
end
def test_create
@request.session[:user_id] = 1
assert_difference 'Repository.count' do
post :create, :params => {
:project_id => 'subproject1',
:repository_scm => 'Subversion',
:repository => {
:url => 'file:///test',
:is_default => '1',
:identifier => ''
}
}
end
assert_response 302
repository = Repository.order('id DESC').first
assert_kind_of Repository::Subversion, repository
assert_equal 'file:///test', repository.url
end
def test_create_with_failure
@request.session[:user_id] = 1
assert_no_difference 'Repository.count' do
post :create, :params => {
:project_id => 'subproject1',
:repository_scm => 'Subversion',
:repository => {
:url => 'invalid'
}
}
end
assert_response :success
assert_select_error /URL is invalid/
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Subversion'
end
end
def test_edit
@request.session[:user_id] = 1
get :edit, :params => {
:id => 11
}
assert_response :success
assert_select 'input[name=?][value=?][disabled=disabled]', 'repository[url]', 'svn://localhost/test'
end
def test_update
@request.session[:user_id] = 1
put :update, :params => {
:id => 11,
:repository => {
:password => 'test_update'
}
}
assert_response 302
assert_equal 'test_update', Repository.find(11).password
end
def test_update_with_failure
@request.session[:user_id] = 1
put :update, :params => {
:id => 11,
:repository => {
:password => 'x'*260
}
}
assert_response :success
assert_select_error /Password is too long/
end
def test_destroy
@request.session[:user_id] = 1
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => 11
}
end
assert_response 302
assert_nil Repository.find_by_id(11)
end
def test_show_with_autofetch_changesets_enabled_should_fetch_changesets
Repository::Subversion.any_instance.expects(:fetch_changesets).once
with_settings :autofetch_changesets => '1' do
get :show, :params => {
:id => 1
}
end
end
def test_show_with_autofetch_changesets_disabled_should_not_fetch_changesets
Repository::Subversion.any_instance.expects(:fetch_changesets).never
with_settings :autofetch_changesets => '0' do
get :show, :params => {
:id => 1
}
end
end
def test_show_with_closed_project_should_not_fetch_changesets
Repository::Subversion.any_instance.expects(:fetch_changesets).never
Project.find(1).close
with_settings :autofetch_changesets => '1' do
get :show, :params => {
:id => 1
}
end
end
def test_revisions
get :revisions, :params => {
:id => 1
}
assert_response :success
assert_select 'table.changesets'
end
def test_revisions_for_other_repository
repository = Repository::Subversion.create!(:project_id => 1, :identifier => 'foo', :url => 'file:///foo')
get :revisions, :params => {
:id => 1,
:repository_id => 'foo'
}
assert_response :success
assert_select 'table.changesets'
end
def test_revisions_for_invalid_repository
get :revisions, :params => {
:id => 1,
:repository_id => 'foo'
}
assert_response 404
end
def test_revision
get :revision, :params => {
:id => 1,
:rev => 1
}
assert_response :success
assert_select 'h2', :text => 'Revision 1'
end
def test_revision_should_not_format_comments_when_disabled
Changeset.where(:id => 100).update_all(:comments => 'Simple *text*')
with_settings :commit_logs_formatting => '0' do
get :revision, :params => {
:id => 1,
:rev => 1
}
assert_response :success
assert_select '.changeset-comments', :text => 'Simple *text*'
end
end
def test_revision_should_show_add_related_issue_form
Role.find(1).add_permission! :manage_related_issues
@request.session[:user_id] = 2
get :revision, :params => {
:id => 1,
:rev => 1
}
assert_response :success
assert_select 'form[action=?]', '/projects/ecookbook/repository/revisions/1/issues' do
assert_select 'input[name=?]', 'issue_id'
end
end
def test_revision_should_not_change_the_project_menu_link
get :revision, :params => {
:id => 1,
:rev => 1
}
assert_response :success
assert_select '#main-menu a.repository[href=?]', '/projects/ecookbook/repository'
end
def test_revision_with_before_nil_and_afer_normal
get :revision, :params => {
:id => 1,
:rev => 1
}
assert_response :success
assert_select 'div.contextual' do
assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/0', 0
assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/2'
end
end
def test_add_related_issue
@request.session[:user_id] = 2
assert_difference 'Changeset.find(103).issues.size' do
post :add_related_issue, :params => {
:id => 1,
:rev => 4,
:issue_id => 2,
:format => 'js'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_equal [2], Changeset.find(103).issue_ids
assert_include 'related-issues', response.body
assert_include 'Feature request #2', response.body
end
def test_add_related_issue_should_accept_issue_id_with_sharp
@request.session[:user_id] = 2
assert_difference 'Changeset.find(103).issues.size' do
post :add_related_issue, :params => {
:id => 1,
:rev => 4,
:issue_id => "#2",
:format => 'js'
},
:xhr => true
end
assert_equal [2], Changeset.find(103).issue_ids
end
def test_add_related_issue_with_invalid_issue_id
@request.session[:user_id] = 2
assert_no_difference 'Changeset.find(103).issues.size' do
post :add_related_issue, :params => {
:id => 1,
:rev => 4,
:issue_id => 9999,
:format => 'js'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_include 'alert("Issue is invalid")', response.body
end
def test_remove_related_issue
Changeset.find(103).issues << Issue.find(1)
Changeset.find(103).issues << Issue.find(2)
@request.session[:user_id] = 2
assert_difference 'Changeset.find(103).issues.size', -1 do
delete :remove_related_issue, :params => {
:id => 1,
:rev => 4,
:issue_id => 2,
:format => 'js'
},
:xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_equal [1], Changeset.find(103).issue_ids
assert_include 'related-issue-2', response.body
end
def test_graph_commits_per_month
# Make sure there's some data to display
latest = Project.find(1).repository.changesets.maximum(:commit_date)
assert_not_nil latest
Date.stubs(:today).returns(latest.to_date + 10)
get :graph, :params => {
:id => 1,
:graph => 'commits_per_month'
}
assert_response :success
assert_equal 'image/svg+xml', @response.content_type
end
def test_graph_commits_per_author
get :graph, :params => {
:id => 1,
:graph => 'commits_per_author'
}
assert_response :success
assert_equal 'image/svg+xml', @response.content_type
end
def test_get_committers
@request.session[:user_id] = 2
# add a commit with an unknown user
Changeset.create!(
:repository => Project.find(1).repository,
:committer => 'foo',
:committed_on => Time.now,
:revision => 100,
:comments => 'Committed by foo.'
)
get :committers, :params => {
:id => 10
}
assert_response :success
assert_select 'input[value=dlopper] + select option[value="3"][selected=selected]', :text => 'Dave Lopper'
assert_select 'input[value=foo] + select option[selected=selected]', 0 # no option selected
end
def test_get_committers_without_changesets
Changeset.delete_all
@request.session[:user_id] = 2
get :committers, :params => {
:id => 10
}
assert_response :success
end
def test_post_committers
@request.session[:user_id] = 2
# add a commit with an unknown user
c = Changeset.create!(
:repository => Project.find(1).repository,
:committer => 'foo',
:committed_on => Time.now,
:revision => 100,
:comments => 'Committed by foo.'
)
assert_no_difference "Changeset.where(:user_id => 3).count" do
post :committers, :params => {
:id => 10,
:committers => {
'0' => ['foo', '2'], '1' => ['dlopper', '3']
}
}
assert_response 302
assert_equal User.find(2), c.reload.user
end
end
end

View file

@ -0,0 +1,295 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class RepositoriesCvsControllerTest < Redmine::ControllerTest
tests RepositoriesController
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
:repositories, :enabled_modules
REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s
REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
# CVS module
MODULE_NAME = 'test'
PRJ_ID = 3
NUM_REV = 7
def setup
Setting.default_language = 'en'
User.current = nil
@project = Project.find(PRJ_ID)
@repository = Repository::Cvs.create(:project => Project.find(PRJ_ID),
:root_url => REPOSITORY_PATH,
:url => MODULE_NAME,
:log_encoding => 'UTF-8')
assert @repository
end
if File.directory?(REPOSITORY_PATH)
def test_get_new
@request.session[:user_id] = 1
@project.repository.destroy
get :new, :params => {
:project_id => 'subproject1',
:repository_scm => 'Cvs'
}
assert_response :success
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Cvs'
end
end
def test_browse_root
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 3
assert_select 'tr.dir td.filename a', :text => 'images'
assert_select 'tr.file td.filename a', :text => 'README'
end
assert_select 'table.changesets tbody' do
assert_select 'tr'
end
end
def test_browse_directory
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images'])[:param]
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 3
assert_select 'tr.file td.filename a', :text => 'add.png'
assert_select 'tr.file td.filename a', :text => 'delete.png'
assert_select 'tr.file td.filename a', :text => 'edit.png'
end
end
def test_browse_at_given_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images'])[:param],
:rev => 1
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 2
assert_select 'tr.file td.filename a', :text => 'delete.png'
assert_select 'tr.file td.filename a', :text => 'edit.png'
end
end
def test_entry
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
}
assert_response :success
assert_select 'td.line-code', :text => /before_filter/, :count => 0
end
def test_entry_at_given_revision
# changesets must be loaded
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
:rev => 2
}
assert_response :success
# this line was removed in r3
assert_select 'td.line-code', :text => /before_filter/
end
def test_entry_not_found
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'zzz.c'])[:param]
}
assert_select 'p#errorExplanation', :text => /The entry or revision was not found in the repository/
end
def test_entry_download
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
:format => 'raw'
}
assert_response :success
end
def test_directory_entry
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources'])[:param]
}
assert_response :success
assert_select 'table.entries tbody'
end
def test_diff
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => 3,
:type => dt
}
assert_response :success
assert_select 'td.line-code.diff_out', :text => /before_filter :require_login/
assert_select 'td.line-code.diff_in', :text => /with one change/
end
end
def test_diff_new_files
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => 1,
:type => dt
}
assert_response :success
assert_select 'td.line-code.diff_in', :text => /watched.remove_watcher/
assert_select 'th.filename', :text => /test\/README/
assert_select 'th.filename', :text => /test\/images\/delete.png/
assert_select 'th.filename', :text => /test\/images\/edit.png/
assert_select 'th.filename', :text => /test\/sources\/watchers_controller.rb/
end
end
def test_annotate
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
}
assert_response :success
# 1.1 line
assert_select 'tr' do
assert_select 'th.line-num', :text => '21'
assert_select 'td.revision', :text => /1.1/
assert_select 'td.author', :text => /LANG/
end
# 1.2 line
assert_select 'tr' do
assert_select 'th.line-num', :text => '32'
assert_select 'td.revision', :text => /1.2/
assert_select 'td.author', :text => /LANG/
end
end
def test_destroy_valid_repository
@request.session[:user_id] = 1 # admin
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
def test_destroy_invalid_repository
@request.session[:user_id] = 1 # admin
@project.repository.destroy
@repository = Repository::Cvs.create!(
:project => Project.find(PRJ_ID),
:root_url => "/invalid",
:url => MODULE_NAME,
:log_encoding => 'UTF-8'
)
@repository.fetch_changesets
@project.reload
assert_equal 0, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
else
puts "CVS test repository NOT FOUND. Skipping functional tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,178 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class RepositoriesDarcsControllerTest < Redmine::ControllerTest
tests RepositoriesController
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
:repositories, :enabled_modules
REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s
PRJ_ID = 3
NUM_REV = 6
def setup
User.current = nil
@project = Project.find(PRJ_ID)
@repository = Repository::Darcs.create(
:project => @project,
:url => REPOSITORY_PATH,
:log_encoding => 'UTF-8'
)
assert @repository
end
if File.directory?(REPOSITORY_PATH)
def test_get_new
@request.session[:user_id] = 1
@project.repository.destroy
get :new, :params => {
:project_id => 'subproject1',
:repository_scm => 'Darcs'
}
assert_response :success
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Darcs'
end
end
def test_browse_root
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID
}
assert_select 'table.entries tbody' do
assert_select 'tr', 3
assert_select 'tr.dir td.filename a', :text => 'images'
assert_select 'tr.dir td.filename a', :text => 'sources'
assert_select 'tr.file td.filename a', :text => 'README'
end
end
def test_browse_directory
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images'])[:param]
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 2
assert_select 'tr.file td.filename a', :text => 'delete.png'
assert_select 'tr.file td.filename a', :text => 'edit.png'
end
end
def test_browse_at_given_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images'])[:param],
:rev => 1
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 1
assert_select 'tr.file td.filename a', :text => 'delete.png'
end
end
def test_changes
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :changes, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images', 'edit.png'])[:param]
}
assert_response :success
assert_select 'h2', :text => /edit.png/
end
def test_diff
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
# Full diff of changeset 5
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => 5,
:type => dt
}
assert_response :success
# Line 22 removed
assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
end
end
def test_destroy_valid_repository
@request.session[:user_id] = 1 # admin
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
def test_destroy_invalid_repository
@request.session[:user_id] = 1 # admin
@project.repository.destroy
@repository = Repository::Darcs.create!(
:project => @project,
:url => "/invalid",
:log_encoding => 'UTF-8'
)
@repository.fetch_changesets
@project.reload
assert_equal 0, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
else
puts "Darcs test repository NOT FOUND. Skipping functional tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,174 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class RepositoriesFilesystemControllerTest < Redmine::ControllerTest
tests RepositoriesController
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
:repositories, :enabled_modules
REPOSITORY_PATH = Rails.root.join('tmp/test/filesystem_repository').to_s
PRJ_ID = 3
def setup
@ruby19_non_utf8_pass = Encoding.default_external.to_s != 'UTF-8'
User.current = nil
Setting.enabled_scm << 'Filesystem' unless Setting.enabled_scm.include?('Filesystem')
@project = Project.find(PRJ_ID)
@repository = Repository::Filesystem.create(
:project => @project,
:url => REPOSITORY_PATH,
:path_encoding => ''
)
assert @repository
end
if File.directory?(REPOSITORY_PATH)
def test_get_new
@request.session[:user_id] = 1
@project.repository.destroy
get :new, :params => {
:project_id => 'subproject1',
:repository_scm => 'Filesystem'
}
assert_response :success
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Filesystem'
end
end
def test_browse_root
@repository.fetch_changesets
@repository.reload
get :show, :params => {
:id => PRJ_ID
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 3
assert_select 'tr.dir td.filename a', :text => 'dir'
assert_select 'tr.dir td.filename a', :text => 'japanese'
assert_select 'tr.file td.filename a', :text => 'test'
end
assert_select 'table.changesets tbody', 0
assert_select 'input[name=rev]', 0
assert_select 'a', :text => 'Statistics', :count => 0
assert_select 'a', :text => 'Atom', :count => 0
end
def test_show_no_extension
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['test'])[:param]
}
assert_response :success
assert_select 'tr#L1 td.line-code', :text => /TEST CAT/
end
def test_entry_download_no_extension
get :raw, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['test'])[:param]
}
assert_response :success
assert_equal 'application/octet-stream', @response.content_type
end
def test_show_non_ascii_contents
with_settings :repositories_encodings => 'UTF-8,EUC-JP' do
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['japanese', 'euc-jp.txt'])[:param]
}
assert_response :success
assert_select 'tr#L2 td.line-code', :text => /japanese/
if @ruby19_non_utf8_pass
puts "TODO: show repository file contents test fails " +
"when Encoding.default_external is not UTF-8. " +
"Current value is '#{Encoding.default_external.to_s}'"
else
str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e".force_encoding('UTF-8')
assert_select 'tr#L3 td.line-code', :text => /#{str_japanese}/
end
end
end
def test_show_utf16
enc = 'UTF-16'
with_settings :repositories_encodings => enc do
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['japanese', 'utf-16.txt'])[:param]
}
assert_response :success
assert_select 'tr#L2 td.line-code', :text => /japanese/
end
end
def test_show_text_file_should_show_other_if_too_big
with_settings :file_max_size_displayed => 1 do
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['japanese', 'big-file.txt'])[:param]
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'p.nodata'
end
end
def test_destroy_valid_repository
@request.session[:user_id] = 1 # admin
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
def test_destroy_invalid_repository
@request.session[:user_id] = 1 # admin
@project.repository.destroy
@repository = Repository::Filesystem.create!(
:project => @project,
:url => "/invalid",
:path_encoding => ''
)
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
else
puts "Filesystem test repository NOT FOUND. Skipping functional tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,667 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class RepositoriesGitControllerTest < Redmine::ControllerTest
tests RepositoriesController
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
:repositories, :enabled_modules
REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
PRJ_ID = 3
CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
FELIX_HEX = "Felix Sch\xC3\xA4fer".force_encoding('UTF-8')
NUM_REV = 28
## Git, Mercurial and CVS path encodings are binary.
## Subversion supports URL encoding for path.
## Redmine Mercurial adapter and extension use URL encoding.
## Git accepts only binary path in command line parameter.
## So, there is no way to use binary command line parameter in JRuby.
JRUBY_SKIP = (RUBY_PLATFORM == 'java')
JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
def setup
@ruby19_non_utf8_pass = Encoding.default_external.to_s != 'UTF-8'
User.current = nil
@project = Project.find(PRJ_ID)
@repository = Repository::Git.create(
:project => @project,
:url => REPOSITORY_PATH,
:path_encoding => 'ISO-8859-1'
)
assert @repository
end
def test_create_and_update
@request.session[:user_id] = 1
assert_difference 'Repository.count' do
post :create, :params => {
:project_id => 'subproject1',
:repository_scm => 'Git',
:repository => {
:url => '/test',
:is_default => '0',
:identifier => 'test-create',
:report_last_commit => '1',
}
}
end
assert_response 302
repository = Repository.order('id DESC').first
assert_kind_of Repository::Git, repository
assert_equal '/test', repository.url
assert_equal true, repository.report_last_commit
put :update, :params => {
:id => repository.id,
:repository => {
:report_last_commit => '0'
}
}
assert_response 302
repo2 = Repository.find(repository.id)
assert_equal false, repo2.report_last_commit
end
if File.directory?(REPOSITORY_PATH)
## Ruby uses ANSI api to fork a process on Windows.
## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
## and these are incompatible with ASCII.
## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
## http://code.google.com/p/msysgit/issues/detail?id=80
## So, Latin-1 path tests fail on Japanese Windows
WINDOWS_PASS = (Redmine::Platform.mswin? &&
Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
def test_get_new
@request.session[:user_id] = 1
@project.repository.destroy
get :new, :params => {
:project_id => 'subproject1',
:repository_scm => 'Git'
}
assert_response :success
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Git'
end
end
def test_browse_root
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 9
assert_select 'tr.dir td.filename_no_report a', :text => 'images'
assert_select 'tr.dir td.filename_no_report a', :text => 'this_is_a_really_long_and_verbose_directory_name'
assert_select 'tr.dir td.filename_no_report a', :text => 'sources'
assert_select 'tr.file td.filename_no_report a', :text => 'README'
assert_select 'tr.file td.filename_no_report a', :text => 'copied_README'
assert_select 'tr.file td.filename_no_report a', :text => 'new_file.txt'
assert_select 'tr.file td.filename_no_report a', :text => 'renamed_test.txt'
assert_select 'tr.file td.filename_no_report a', :text => 'filemane with spaces.txt'
assert_select 'tr.file td.filename_no_report a', :text => 'filename with a leading space.txt'
end
assert_select 'table.changesets tbody' do
assert_select 'tr'
end
end
def test_browse_branch
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:rev => 'test_branch'
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 4
assert_select 'tr.dir td.filename_no_report a', :text => 'images'
assert_select 'tr.dir td.filename_no_report a', :text => 'sources'
assert_select 'tr.file td.filename_no_report a', :text => 'README'
assert_select 'tr.file td.filename_no_report a', :text => 'test.txt'
end
assert_select 'table.changesets tbody' do
assert_select 'tr'
end
end
def test_browse_tag
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
[
"tag00.lightweight",
"tag01.annotated",
].each do |t1|
get :show, :params => {
:id => PRJ_ID,
:rev => t1
}
assert_response :success
assert_select 'table.entries tbody tr'
assert_select 'table.changesets tbody tr'
end
end
def test_browse_directory
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images'])[:param]
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 1
assert_select 'tr.file td.filename_no_report a', :text => 'edit.png'
end
assert_select 'table.changesets tbody tr'
end
def test_browse_at_given_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images'])[:param],
:rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 1
assert_select 'tr.file td.filename_no_report a', :text => 'delete.png'
end
end
def test_changes
get :changes, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images', 'edit.png'])[:param]
}
assert_response :success
assert_select 'h2', :text => /edit.png/
end
def test_entry_show
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
}
assert_response :success
# Line 11
assert_select 'tr#L11 td.line-code', :text => /WITHOUT ANY WARRANTY/
end
def test_entry_show_latin_1
if @ruby19_non_utf8_pass
puts_ruby19_non_utf8_pass()
elsif WINDOWS_PASS
puts WINDOWS_SKIP_STR
elsif JRUBY_SKIP
puts JRUBY_SKIP_STR
else
with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
:rev => r1
}
assert_response :success
assert_select 'tr#L1 td.line-code', :text => /test-#{CHAR_1_HEX}.txt/
end
end
end
end
def test_entry_download
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
:format => 'raw'
}
assert_response :success
# File content
assert @response.body.include?('WITHOUT ANY WARRANTY')
end
def test_directory_entry
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources'])[:param]
}
assert_response :success
assert_select 'h2 a', :text => 'sources'
assert_select 'table.entries tbody'
assert_select 'div.contextual > a.icon-download', false
end
def test_diff
assert_equal true, @repository.is_default
assert @repository.identifier.blank?
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
# Full diff of changeset 2f9c0091
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
:type => dt
}
assert_response :success
# Line 22 removed
assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
assert_select 'h2', :text => /2f9c0091/
end
end
def test_diff_with_rev_and_path
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
with_settings :diff_max_lines_displayed => 1000 do
# Full diff of changeset 2f9c0091
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
:type => dt
}
assert_response :success
# Line 22 removed
assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
assert_select 'h2', :text => /2f9c0091/
end
end
end
def test_diff_truncated
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
with_settings :diff_max_lines_displayed => 5 do
# Truncated diff of changeset 2f9c0091
with_cache do
with_settings :default_language => 'en' do
get :diff, :params => {
:id => PRJ_ID,
:type => 'inline',
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
}
assert_response :success
assert @response.body.include?("... This diff was truncated")
end
with_settings :default_language => 'fr' do
get :diff, :params => {
:id => PRJ_ID,
:type => 'inline',
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
}
assert_response :success
assert ! @response.body.include?("... This diff was truncated")
assert @response.body.include?("... Ce diff")
end
end
end
end
def test_diff_two_revs
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
:rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
:type => dt
}
assert_response :success
assert_select 'h2', :text => /2f9c0091:61b685fb/
assert_select 'form[action=?]', '/projects/subproject1/repository/revisions/61b685fbe55ab05b5ac68402d5720c1a6ac973d1/diff'
assert_select 'input#rev_to[type=hidden][name=rev_to][value=?]', '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
end
end
def test_diff_path_in_subrepo
repo = Repository::Git.create(
:project => @project,
:url => REPOSITORY_PATH,
:identifier => 'test-diff-path',
:path_encoding => 'ISO-8859-1'
)
assert repo
assert_equal false, repo.is_default
assert_equal 'test-diff-path', repo.identifier
get :diff, :params => {
:id => PRJ_ID,
:repository_id => 'test-diff-path',
:rev => '61b685fbe55ab05b',
:rev_to => '2f9c0091c754a91a',
:type => 'inline'
}
assert_response :success
assert_select 'form[action=?]', '/projects/subproject1/repository/test-diff-path/revisions/61b685fbe55ab05b/diff'
assert_select 'input#rev_to[type=hidden][name=rev_to][value=?]', '2f9c0091c754a91a'
end
def test_diff_latin_1
if @ruby19_non_utf8_pass
puts_ruby19_non_utf8_pass()
else
with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => r1,
:type => dt
}
assert_response :success
assert_select 'table' do
assert_select 'thead th.filename', :text => /latin-1-dir\/test-#{CHAR_1_HEX}.txt/
assert_select 'tbody td.diff_in', :text => /test-#{CHAR_1_HEX}.txt/
end
end
end
end
end
end
def test_diff_should_show_filenames
get :diff, :params => {
:id => PRJ_ID,
:rev => 'deff712f05a90d96edbd70facc47d944be5897e3',
:type => 'inline'
}
assert_response :success
# modified file
assert_select 'th.filename', :text => 'sources/watchers_controller.rb'
# deleted file
assert_select 'th.filename', :text => 'test.txt'
end
def test_save_diff_type
user1 = User.find(1)
user1.pref[:diff_type] = nil
user1.preference.save
user = User.find(1)
assert_nil user.pref[:diff_type]
@request.session[:user_id] = 1 # admin
get :diff, :params => {
:id => PRJ_ID,
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
}
assert_response :success
user.reload
assert_equal "inline", user.pref[:diff_type]
get :diff, :params => {
:id => PRJ_ID,
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
:type => 'sbs'
}
assert_response :success
user.reload
assert_equal "sbs", user.pref[:diff_type]
end
def test_annotate
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
}
assert_response :success
# Line 23, changeset 2f9c0091
assert_select 'tr' do
assert_select 'th.line-num', :text => '23'
assert_select 'td.revision', :text => /2f9c0091/
assert_select 'td.author', :text => 'jsmith'
assert_select 'td', :text => /remove_watcher/
end
end
def test_annotate_at_given_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :annotate, :params => {
:id => PRJ_ID,
:rev => 'deff7',
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
}
assert_response :success
assert_select 'h2', :text => /@ deff712f/
end
def test_annotate_binary_file
with_settings :default_language => 'en' do
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images', 'edit.png'])[:param]
}
assert_response :success
assert_select 'p#errorExplanation', :text => /cannot be annotated/
end
end
def test_annotate_error_when_too_big
with_settings :file_max_size_displayed => 1 do
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
:rev => 'deff712f'
}
assert_response :success
assert_select 'p#errorExplanation', :text => /exceeds the maximum text file size/
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['README'])[:param],
:rev => '7234cb2'
}
assert_response :success
end
end
def test_annotate_latin_1
if @ruby19_non_utf8_pass
puts_ruby19_non_utf8_pass()
elsif WINDOWS_PASS
puts WINDOWS_SKIP_STR
elsif JRUBY_SKIP
puts JRUBY_SKIP_STR
else
with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
:rev => r1
}
assert_select "th.line-num", :text => '1' do
assert_select "+ td.revision" do
assert_select "a", :text => '57ca437c'
assert_select "+ td.author", :text => "jsmith" do
assert_select "+ td",
:text => "test-#{CHAR_1_HEX}.txt"
end
end
end
end
end
end
end
def test_annotate_latin_1_author
['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', '83ca5fd546063a'].each do |r1|
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash([" filename with a leading space.txt "])[:param],
:rev => r1
}
assert_select "th.line-num", :text => '1' do
assert_select "+ td.revision" do
assert_select "a", :text => '83ca5fd5'
assert_select "+ td.author", :text => FELIX_HEX do
assert_select "+ td",
:text => "And this is a file with a leading and trailing space..."
end
end
end
end
end
def test_revisions
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :revisions, :params => {
:id => PRJ_ID
}
assert_select 'form[method=get][action=?]', '/projects/subproject1/repository/revision'
end
def test_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
get :revision, :params => {
:id => PRJ_ID,
:rev => r
}
assert_response :success
end
end
def test_empty_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['', ' ', nil].each do |r|
get :revision, :params => {
:id => PRJ_ID,
:rev => r
}
assert_response 404
assert_select_error /was not found/
end
end
def test_destroy_valid_repository
@request.session[:user_id] = 1 # admin
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
def test_destroy_invalid_repository
@request.session[:user_id] = 1 # admin
@project.repository.destroy
@repository = Repository::Git.create!(
:project => @project,
:url => "/invalid",
:path_encoding => 'ISO-8859-1'
)
@repository.fetch_changesets
@repository.reload
assert_equal 0, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
private
def puts_ruby19_non_utf8_pass
puts "TODO: This test fails " +
"when Encoding.default_external is not UTF-8. " +
"Current value is '#{Encoding.default_external.to_s}'"
end
else
puts "Git test repository NOT FOUND. Skipping functional tests !!!"
def test_fake; assert true end
end
private
def with_cache(&block)
before = ActionController::Base.perform_caching
ActionController::Base.perform_caching = true
block.call
ActionController::Base.perform_caching = before
end
end

View file

@ -0,0 +1,559 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class RepositoriesMercurialControllerTest < Redmine::ControllerTest
tests RepositoriesController
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
:repositories, :enabled_modules
REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s
CHAR_1_HEX = "\xc3\x9c"
PRJ_ID = 3
NUM_REV = 34
ruby19_non_utf8_pass = Encoding.default_external.to_s != 'UTF-8'
def setup
User.current = nil
@project = Project.find(PRJ_ID)
@repository = Repository::Mercurial.create(
:project => @project,
:url => REPOSITORY_PATH,
:path_encoding => 'ISO-8859-1'
)
assert @repository
@diff_c_support = true
@char_1 = CHAR_1_HEX.dup.force_encoding('UTF-8')
@tag_char_1 = "tag-#{CHAR_1_HEX}-00".force_encoding('UTF-8')
@branch_char_0 = "branch-#{CHAR_1_HEX}-00".force_encoding('UTF-8')
@branch_char_1 = "branch-#{CHAR_1_HEX}-01".force_encoding('UTF-8')
end
if ruby19_non_utf8_pass
puts "TODO: Mercurial functional test fails " +
"when Encoding.default_external is not UTF-8. " +
"Current value is '#{Encoding.default_external.to_s}'"
def test_fake; assert true end
elsif File.directory?(REPOSITORY_PATH)
def test_get_new
@request.session[:user_id] = 1
@project.repository.destroy
get :new, :params => {
:project_id => 'subproject1',
:repository_scm => 'Mercurial'
}
assert_response :success
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Mercurial'
end
end
def test_show_root
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 4
assert_select 'tr.dir td.filename a', :text => 'images'
assert_select 'tr.dir td.filename a', :text => 'sources'
assert_select 'tr.file td.filename a', :text => '.hgtags'
assert_select 'tr.file td.filename a', :text => 'README'
end
assert_select 'table.changesets tbody' do
assert_select 'tr'
end
end
def test_show_directory
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images'])[:param]
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 2
assert_select 'tr.file td.filename a', :text => 'delete.png'
assert_select 'tr.file td.filename a', :text => 'edit.png'
end
assert_select 'table.changesets tbody' do
assert_select 'tr'
end
end
def test_show_at_given_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
[0, '0', '0885933ad4f6'].each do |r1|
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images'])[:param],
:rev => r1
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 1
assert_select 'tr.file td.filename a', :text => 'delete.png'
end
assert_select 'table.changesets tbody' do
assert_select 'tr'
end
end
end
def test_show_directory_sql_escape_percent
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
[13, '13', '3a330eb32958'].each do |r1|
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sql_escape', 'percent%dir'])[:param],
:rev => r1
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 2
assert_select 'tr.file td.filename a', :text => 'percent%file1.txt'
assert_select 'tr.file td.filename a', :text => 'percentfile1.txt'
end
assert_select 'table.changesets tbody' do
assert_select 'tr td.id a', :text => /^13:/
assert_select 'tr td.id a', :text => /^11:/
assert_select 'tr td.id a', :text => /^10:/
assert_select 'tr td.id a', :text => /^9:/
end
end
end
def test_show_directory_latin_1_path
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
[21, '21', 'adf805632193'].each do |r1|
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['latin-1-dir'])[:param],
:rev => r1
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 4
assert_select 'tr.file td.filename a', :text => "make-latin-1-file.rb"
assert_select 'tr.file td.filename a', :text => "test-#{@char_1}-1.txt"
assert_select 'tr.file td.filename a', :text => "test-#{@char_1}-2.txt"
assert_select 'tr.file td.filename a', :text => "test-#{@char_1}.txt"
end
assert_select 'table.changesets tbody' do
assert_select 'tr td.id a', :text => /^21:/
assert_select 'tr td.id a', :text => /^20:/
assert_select 'tr td.id a', :text => /^19:/
assert_select 'tr td.id a', :text => /^18:/
assert_select 'tr td.id a', :text => /^17:/
end
end
end
def show_should_show_branch_selection_form
@repository.fetch_changesets
@project.reload
get :show, :params => {
:id => PRJ_ID
}
assert_select 'form#revision_selector[action=?]', '/projects/subproject1/repository/show' do
assert_select 'select[name=branch]' do
assert_select 'option[value=?]', 'test-branch-01'
end
end
end
def test_show_branch
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
[
'default',
@branch_char_1,
'branch (1)[2]&,%.-3_4',
@branch_char_0,
'test_branch.latin-1',
'test-branch-00',
].each do |bra|
get :show, :params => {
:id => PRJ_ID,
:rev => bra
}
assert_response :success
assert_select 'table.entries tbody tr'
assert_select 'table.changesets tbody tr'
end
end
def test_show_tag
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
[
@tag_char_1,
'tag_test.00',
'tag-init-revision'
].each do |tag|
get :show, :params => {
:id => PRJ_ID,
:rev => tag
}
assert_response :success
assert_select 'table.entries tbody tr'
assert_select 'table.changesets tbody tr'
end
end
def test_changes
get :changes, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['images', 'edit.png'])[:param]
}
assert_response :success
assert_select 'h2', :text => /edit.png/
end
def test_entry_show
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
}
assert_response :success
# Line 10
assert_select 'tr#L10 td.line-code', :text => /WITHOUT ANY WARRANTY/
end
def test_entry_show_latin_1_path
[21, '21', 'adf805632193'].each do |r1|
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['latin-1-dir', "test-#{@char_1}-2.txt"])[:param],
:rev => r1
}
assert_response :success
assert_select 'tr#L1 td.line-code', :text => /Mercurial is a distributed version control system/
end
end
def test_entry_show_latin_1_contents
with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
[27, '27', '7bbf4c738e71'].each do |r1|
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
:rev => r1
}
assert_response :success
assert_select 'tr#L1 td.line-code', :text => /test-#{@char_1}.txt/
end
end
end
def test_entry_download
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
:format => 'raw'
}
assert_response :success
# File content
assert @response.body.include?('WITHOUT ANY WARRANTY')
end
def test_entry_binary_force_download
# TODO: add a binary file which is not an image to the test repo
end
def test_directory_entry
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources'])[:param]
}
assert_response :success
assert_select 'h2 a', :text => 'sources'
assert_select 'table.entries tbody'
end
def test_diff
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
[4, '4', 'def6d2f1254a'].each do |r1|
# Full diff of changeset 4
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => r1,
:type => dt
}
assert_response :success
if @diff_c_support
# Line 22 removed
assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
assert_select 'h2', :text => /4:def6d2f1254a/
end
end
end
end
def test_diff_two_revs
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
[2, '400bb8672109', '400', 400].each do |r1|
[4, 'def6d2f1254a'].each do |r2|
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => r1,
:rev_to => r2,
:type => dt
}
assert_response :success
assert_select 'h2', :text => /4:def6d2f1254a 2:400bb8672109/
end
end
end
end
def test_diff_latin_1_path
with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
[21, 'adf805632193'].each do |r1|
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => r1,
:type => dt
}
assert_response :success
assert_select 'table' do
assert_select 'thead th.filename', :text => /latin-1-dir\/test-#{@char_1}-2.txt/
assert_select 'tbody td.diff_in', :text => /It is written in Python/
end
end
end
end
end
def test_diff_should_show_modified_filenames
get :diff, :params => {
:id => PRJ_ID,
:rev => '400bb8672109',
:type => 'inline'
}
assert_response :success
assert_select 'th.filename', :text => 'sources/watchers_controller.rb'
end
def test_diff_should_show_deleted_filenames
get :diff, :params => {
:id => PRJ_ID,
:rev => 'b3a615152df8',
:type => 'inline'
}
assert_response :success
assert_select 'th.filename', :text => 'sources/welcome_controller.rb'
end
def test_annotate
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
}
assert_response :success
# Line 22, revision 4:def6d2f1254a
assert_select 'tr' do
assert_select 'th.line-num', :text => '22'
assert_select 'td.revision', :text => '4:def6d2f1254a'
assert_select 'td.author', :text => 'jsmith'
assert_select 'td', :text => /remove_watcher/
end
end
def test_annotate_not_in_tip
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['sources', 'welcome_controller.rb'])[:param]
}
assert_response 404
assert_select_error /was not found/
end
def test_annotate_at_given_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
[2, '400bb8672109', '400', 400].each do |r1|
get :annotate, :params => {
:id => PRJ_ID,
:rev => r1,
:path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
}
assert_response :success
assert_select 'h2', :text => /@ 2:400bb8672109/
end
end
def test_annotate_latin_1_path
[21, '21', 'adf805632193'].each do |r1|
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['latin-1-dir', "test-#{@char_1}-2.txt"])[:param],
:rev => r1
}
assert_response :success
assert_select "th.line-num", :text => '1' do
assert_select "+ td.revision" do
assert_select "a", :text => '20:709858aafd1b'
assert_select "+ td.author", :text => "jsmith" do
assert_select "+ td",
:text => "Mercurial is a distributed version control system."
end
end
end
end
end
def test_annotate_latin_1_contents
with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
[27, '7bbf4c738e71'].each do |r1|
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
:rev => r1
}
assert_select 'tr#L1 td.line-code', :text => /test-#{@char_1}.txt/
end
end
end
def test_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['1', '9d5b5b', '9d5b5b004199'].each do |r|
with_settings :default_language => "en" do
get :revision, :params => {
:id => PRJ_ID,
:rev => r
}
assert_response :success
assert_select 'title',
:text => 'Revision 1:9d5b5b004199 - Added 2 files and modified one. - eCookbook Subproject 1 - Redmine'
end
end
end
def test_empty_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['', ' ', nil].each do |r|
get :revision, :params => {
:id => PRJ_ID,
:rev => r
}
assert_response 404
assert_select_error /was not found/
end
end
def test_destroy_valid_repository
@request.session[:user_id] = 1 # admin
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
assert_equal NUM_REV, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
def test_destroy_invalid_repository
@request.session[:user_id] = 1 # admin
@project.repository.destroy
@repository = Repository::Mercurial.create!(
:project => Project.find(PRJ_ID),
:url => "/invalid",
:path_encoding => 'ISO-8859-1'
)
@repository.fetch_changesets
assert_equal 0, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
else
puts "Mercurial test repository NOT FOUND. Skipping functional tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,496 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class RepositoriesSubversionControllerTest < Redmine::ControllerTest
tests RepositoriesController
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles, :enabled_modules,
:repositories, :issues, :issue_statuses, :changesets, :changes,
:issue_categories, :enumerations, :custom_fields, :custom_values, :trackers
PRJ_ID = 3
NUM_REV = 11
def setup
Setting.default_language = 'en'
User.current = nil
@project = Project.find(PRJ_ID)
@repository = Repository::Subversion.create(:project => @project,
:url => self.class.subversion_repository_url)
assert @repository
end
if repository_configured?('subversion')
def test_new
@request.session[:user_id] = 1
@project.repository.destroy
get :new, :params => {
:project_id => 'subproject1',
:repository_scm => 'Subversion'
}
assert_response :success
assert_select 'select[name=?]', 'repository_scm' do
assert_select 'option[value=?][selected=selected]', 'Subversion'
end
end
def test_show
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 1
assert_select 'tr.dir td.filename a', :text => 'subversion_test'
assert_select 'tr.dir td.filename a[href=?]', '/projects/subproject1/repository/show/subversion_test'
end
assert_select 'table.changesets tbody' do
assert_select 'tr', 10
assert_select 'tr td.id a', :text => '11'
end
assert_select 'input[name=rev]'
assert_select 'a', :text => 'Statistics'
assert_select 'a', :text => 'Atom'
assert_select 'a[href=?]', '/projects/subproject1/repository', :text => 'root'
end
def test_show_non_default
Repository::Subversion.create(:project => @project,
:url => self.class.subversion_repository_url,
:is_default => false, :identifier => 'svn')
get :show, :params => {
:id => PRJ_ID,
:repository_id => 'svn'
}
assert_response :success
assert_select 'tr.dir a[href="/projects/subproject1/repository/svn/show/subversion_test"]'
# Repository menu should link to the main repo
assert_select '#main-menu a[href="/projects/subproject1/repository"]'
end
def test_browse_directory
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test'])[:param]
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 5
assert_select 'tr.dir td.filename a', :text => '[folder_with_brackets]'
assert_select 'tr.dir td.filename a', :text => 'folder'
assert_select 'tr.file td.filename a', :text => '.project'
assert_select 'tr.file td.filename a', :text => 'helloworld.c'
assert_select 'tr.file td.filename a', :text => 'textfile.txt'
end
assert_select 'a.text-x-c', :text => 'helloworld.c'
end
def test_browse_at_given_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :show, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test'])[:param],
:rev => 4
}
assert_response :success
assert_select 'table.entries tbody' do
assert_select 'tr', 5
assert_select 'tr.dir td.filename a', :text => 'folder'
assert_select 'tr.file td.filename a', :text => '.project'
assert_select 'tr.file td.filename a', :text => 'helloworld.c'
assert_select 'tr.file td.filename a', :text => 'helloworld.rb'
assert_select 'tr.file td.filename a', :text => 'textfile.txt'
end
end
def test_file_changes
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :changes, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'folder', 'helloworld.rb'])[:param]
}
assert_response :success
assert_select 'table.changesets tbody' do
assert_select 'tr', 3
assert_select 'tr td.id a', :text => '6'
assert_select 'tr td.id a', :text => '3'
assert_select 'tr td.id a', :text => '2'
end
# svn properties displayed with svn >= 1.5 only
if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0])
assert_select 'ul li' do
assert_select 'b', :text => 'svn:eol-style'
assert_select 'span', :text => 'native'
end
end
end
def test_directory_changes
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :changes, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'folder'])[:param]
}
assert_response :success
assert_select 'table.changesets tbody' do
assert_select 'tr', 6
assert_select 'tr td.id a', :text => '10'
assert_select 'tr td.id a', :text => '9'
assert_select 'tr td.id a', :text => '7'
assert_select 'tr td.id a', :text => '6'
assert_select 'tr td.id a', :text => '5'
assert_select 'tr td.id a', :text => '2'
end
end
def test_entry
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
}
assert_response :success
assert_select 'h2 a', :text => 'subversion_test'
assert_select 'h2 a', :text => 'helloworld.c'
end
def test_entry_should_show_other_if_too_big
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
# no files in the test repo is larger than 1KB...
with_settings :file_max_size_displayed => 0 do
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
}
assert_response :success
assert_equal 'text/html', @response.content_type
assert_select 'p.nodata'
end
end
def test_entry_should_display_images
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'folder', 'subfolder', 'rubylogo.gif'])[:param]
}
assert_response :success
assert_select 'img[src=?]', '/projects/subproject1/repository/raw/subversion_test/folder/subfolder/rubylogo.gif'
end
def test_entry_at_given_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'helloworld.rb'])[:param],
:rev => 2
}
assert_response :success
# this line was removed in r3 and file was moved in r6
assert_select 'td.line-code', :text => /Here's the code/
end
def test_entry_not_found
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'zzz.c'])[:param]
}
assert_select 'p#errorExplanation', :text => /The entry or revision was not found in the repository/
end
def test_entry_download
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :raw, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
}
assert_response :success
assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition']
end
def test_directory_entry
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :entry, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'folder'])[:param]
}
assert_response :success
assert_select 'h2 a', :text => 'subversion_test'
assert_select 'h2 a', :text => 'folder'
end
# TODO: this test needs fixtures.
def test_revision
get :revision, :params => {
:id => 1,
:rev => 2
}
assert_response :success
assert_select 'ul' do
assert_select 'li' do
# link to the entry at rev 2
assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo', :text => 'repo'
# link to partial diff
assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo'
end
end
end
def test_invalid_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :revision, :params => {
:id => PRJ_ID,
:rev => 'something_weird'
}
assert_response 404
assert_select_error /was not found/
end
def test_invalid_revision_diff
get :diff, :params => {
:id => PRJ_ID,
:rev => '1',
:rev_to => 'something_weird'
}
assert_response 404
assert_select_error /was not found/
end
def test_empty_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['', ' ', nil].each do |r|
get :revision, :params => {
:id => PRJ_ID,
:rev => r
}
assert_response 404
assert_select_error /was not found/
end
end
# TODO: this test needs fixtures.
def test_revision_with_repository_pointing_to_a_subdirectory
r = Project.find(1).repository
# Changes repository url to a subdirectory
r.update_attribute :url, (r.url + '/test/some')
get :revision, :params => {
:id => 1,
:rev => 2
}
assert_response :success
assert_select 'ul' do
assert_select 'li' do
# link to the entry at rev 2
assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo', :text => 'repo'
# link to partial diff
assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo'
end
end
end
def test_revision_diff
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => 3,
:type => dt
}
assert_response :success
assert_select 'h2', :text => /Revision 3/
assert_select 'th.filename', :text => 'subversion_test/textfile.txt'
end
end
def test_revision_diff_raw_format
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :diff, :params => {
:id => PRJ_ID,
:rev => 5,
:format => 'diff'
}
assert_response :success
assert_equal 'text/x-patch', @response.content_type
assert_equal 'Index: subversion_test/folder/greeter.rb', @response.body.split(/\r?\n/).first
end
def test_directory_diff
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
['inline', 'sbs'].each do |dt|
get :diff, :params => {
:id => PRJ_ID,
:rev => 6,
:rev_to => 2,
:path => repository_path_hash(['subversion_test', 'folder'])[:param],
:type => dt
}
assert_response :success
assert_select 'h2', :text => /2:6/
# 2 files modified
assert_select 'table.filecontent', 2
assert_select 'table.filecontent thead th.filename', :text => 'greeter.rb'
assert_select 'table.filecontent thead th.filename', :text => 'helloworld.rb'
end
end
def test_annotate
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :annotate, :params => {
:id => PRJ_ID,
:path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
}
assert_response :success
assert_select 'tr' do
assert_select 'th.line-num', :text => '1'
assert_select 'td.revision', :text => '4'
assert_select 'td.author', :text => 'jp'
assert_select 'td', :text => /stdio.h/
end
# Same revision
assert_select 'tr' do
assert_select 'th.line-num', :text => '2'
assert_select 'td.revision', :text => ''
assert_select 'td.author', :text => ''
end
end
def test_annotate_at_given_revision
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
assert_equal NUM_REV, @repository.changesets.count
get :annotate, :params => {
:id => PRJ_ID,
:rev => 8,
:path => repository_path_hash(['subversion_test', 'helloworld.c'])[:param]
}
assert_response :success
assert_select 'h2', :text => /@ 8/
end
def test_destroy_valid_repository
@request.session[:user_id] = 1 # admin
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
assert_equal NUM_REV, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
def test_destroy_invalid_repository
@request.session[:user_id] = 1 # admin
@project.repository.destroy
@repository = Repository::Subversion.create!(
:project => @project,
:url => "file:///invalid")
@repository.fetch_changesets
assert_equal 0, @repository.changesets.count
assert_difference 'Repository.count', -1 do
delete :destroy, :params => {
:id => @repository.id
}
end
assert_response 302
@project.reload
assert_nil @project.repository
end
else
puts "Subversion test repository NOT FOUND. Skipping functional tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,263 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class RolesControllerTest < Redmine::ControllerTest
fixtures :roles, :users, :members, :member_roles, :workflows, :trackers
def setup
User.current = nil
@request.session[:user_id] = 1 # admin
end
def test_index
get :index
assert_response :success
assert_select 'table.roles tbody' do
assert_select 'tr', Role.count
assert_select 'a[href="/roles/1/edit"]', :text => 'Manager'
end
end
def test_new
get :new
assert_response :success
assert_select 'input[name=?]', 'role[name]'
assert_select 'input[name=?]', 'role[permissions][]'
end
def test_new_should_prefill_permissions_with_non_member_permissions
role = Role.non_member
role.permissions = [:view_issues, :view_documents]
role.save!
get :new
assert_response :success
assert_equal %w(view_documents view_issues),
css_select('input[name="role[permissions][]"][checked=checked]').map {|e| e.attr('value')}.sort
end
def test_new_with_copy
copy_from = Role.find(2)
get :new, :params => {:copy => copy_from.id.to_s}
assert_response :success
assert_select 'input[name=?]', 'role[name]'
assert_select 'form' do
# blank name
assert_select 'input[name=?][value=""]', 'role[name]'
# edit_project permission checked
assert_select 'input[type=checkbox][name=?][value=edit_project][checked=checked]', 'role[permissions][]'
# add_project permission not checked
assert_select 'input[type=checkbox][name=?][value=add_project]', 'role[permissions][]'
assert_select 'input[type=checkbox][name=?][value=add_project][checked=checked]', 'role[permissions][]', 0
# workflow copy selected
assert_select 'select[name=?]', 'copy_workflow_from' do
assert_select 'option[value="2"][selected=selected]'
end
end
end
def test_create_with_validaton_failure
post :create, :params => {
:role => {
:name => '',
:permissions => ['add_issues', 'edit_issues', 'log_time', ''],
:assignable => '0'
}
}
assert_response :success
assert_select_error /Name cannot be blank/
end
def test_create_without_workflow_copy
post :create, :params => {
:role => {
:name => 'RoleWithoutWorkflowCopy',
:permissions => ['add_issues', 'edit_issues', 'log_time', ''],
:assignable => '0'
}
}
assert_redirected_to '/roles'
role = Role.find_by_name('RoleWithoutWorkflowCopy')
assert_not_nil role
assert_equal [:add_issues, :edit_issues, :log_time], role.permissions
assert !role.assignable?
end
def test_create_with_workflow_copy
post :create, :params => {
:role => {
:name => 'RoleWithWorkflowCopy',
:permissions => ['add_issues', 'edit_issues', 'log_time', ''],
:assignable => '0'
},
:copy_workflow_from => '1'
}
assert_redirected_to '/roles'
role = Role.find_by_name('RoleWithWorkflowCopy')
assert_not_nil role
assert_equal Role.find(1).workflow_rules.size, role.workflow_rules.size
end
def test_create_with_managed_roles
role = new_record(Role) do
post :create, :params => {
:role => {
:name => 'Role',
:all_roles_managed => '0',
:managed_role_ids => ['2', '3', '']
}
}
assert_response 302
end
assert_equal false, role.all_roles_managed
assert_equal [2, 3], role.managed_role_ids.sort
end
def test_edit
get :edit, :params => {:id => 1}
assert_response :success
assert_select 'input[name=?][value=?]', 'role[name]', 'Manager'
assert_select 'select[name=?]', 'role[issues_visibility]'
end
def test_edit_anonymous
get :edit, :params => {:id => Role.anonymous.id}
assert_response :success
assert_select 'input[name=?]', 'role[name]', 0
assert_select 'select[name=?]', 'role[issues_visibility]', 0
end
def test_edit_invalid_should_respond_with_404
get :edit, :params => {:id => 999}
assert_response 404
end
def test_update
put :update, :params => {
:id => 1,
:role => {
:name => 'Manager',
:permissions => ['edit_project', ''],
:assignable => '0'
}
}
assert_redirected_to '/roles'
role = Role.find(1)
assert_equal [:edit_project], role.permissions
end
def test_update_trackers_permissions
put :update, :params => {
:id => 1,
:role => {
:permissions_all_trackers => {'add_issues' => '0'},
:permissions_tracker_ids => {'add_issues' => ['1', '3', '']}
}
}
assert_redirected_to '/roles'
role = Role.find(1)
assert_equal({'add_issues' => '0'}, role.permissions_all_trackers)
assert_equal({'add_issues' => ['1', '3']}, role.permissions_tracker_ids)
assert_equal false, role.permissions_all_trackers?(:add_issues)
assert_equal [1, 3], role.permissions_tracker_ids(:add_issues).sort
end
def test_update_with_failure
put :update, :params => {:id => 1, :role => {:name => ''}}
assert_response :success
assert_select_error /Name cannot be blank/
end
def test_destroy
r = Role.create!(:name => 'ToBeDestroyed', :permissions => [:view_wiki_pages])
delete :destroy, :params => {:id => r}
assert_redirected_to '/roles'
assert_nil Role.find_by_id(r.id)
end
def test_destroy_role_in_use
delete :destroy, :params => {:id => 1}
assert_redirected_to '/roles'
assert_equal 'This role is in use and cannot be deleted.', flash[:error]
assert_not_nil Role.find_by_id(1)
end
def test_get_permissions
get :permissions
assert_response :success
assert_select 'input[name=?][type=checkbox][value=add_issues][checked=checked]', 'permissions[3][]'
assert_select 'input[name=?][type=checkbox][value=delete_issues]:not([checked])', 'permissions[3][]'
end
def test_post_permissions
post :permissions, :params => {
:permissions => {
'0' => '',
'1' => ['edit_issues'],
'3' => ['add_issues', 'delete_issues']
}
}
assert_redirected_to '/roles'
assert_equal [:edit_issues], Role.find(1).permissions
assert_equal [:add_issues, :delete_issues], Role.find(3).permissions
assert Role.find(2).permissions.empty?
end
def test_clear_all_permissions
post :permissions, :params => {:permissions => { '0' => '' }}
assert_redirected_to '/roles'
assert Role.find(1).permissions.empty?
end
def test_move_highest
put :update, :params => {:id => 3, :role => {:position => 1}}
assert_redirected_to '/roles'
assert_equal 1, Role.find(3).position
end
def test_move_higher
position = Role.find(3).position
put :update, :params => {:id => 3, :role => {:position => position - 1}}
assert_redirected_to '/roles'
assert_equal position - 1, Role.find(3).position
end
def test_move_lower
position = Role.find(2).position
put :update, :params => {:id => 2, :role => {:position => position + 1}}
assert_redirected_to '/roles'
assert_equal position + 1, Role.find(2).position
end
def test_move_lowest
put :update, :params => {:id => 2, :role => {:position => Role.givable.count}}
assert_redirected_to '/roles'
assert_equal Role.givable.count, Role.find(2).position
end
end

View file

@ -0,0 +1,389 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class SearchControllerTest < Redmine::ControllerTest
fixtures :projects, :projects_trackers,
:enabled_modules, :roles, :users, :members, :member_roles,
:issues, :trackers, :issue_statuses, :enumerations,
:workflows,
:custom_fields, :custom_values,
:custom_fields_projects, :custom_fields_trackers,
:repositories, :changesets
def setup
User.current = nil
end
def test_search_without_q_should_display_search_form
get :index
assert_response :success
assert_select '#content input[name=q]'
end
def test_search_for_projects
get :index, :params => {:q => "cook"}
assert_response :success
assert_select '#search-results dt.project a', :text => /eCookbook/
end
def test_search_on_archived_project_should_return_404
Project.find(3).archive
get :index, :params => {:id => 3}
assert_response 404
end
def test_search_on_invisible_project_by_user_should_be_denied
@request.session[:user_id] = 7
get :index, :params => {:id => 2}
assert_response 403
end
def test_search_on_invisible_project_by_anonymous_user_should_redirect
get :index, :params => {:id => 2}
assert_response 302
end
def test_search_on_private_project_by_member_should_succeed
@request.session[:user_id] = 2
get :index, :params => {:id => 2}
assert_response :success
end
def test_search_all_projects
with_settings :default_language => 'en' do
get :index, :params => {:q => 'recipe subproject commit', :all_words => ''}
end
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue a', :text => /Feature request #2/
assert_select 'dt.issue a', :text => /Bug #5/
assert_select 'dt.changeset a', :text => /Revision 1/
assert_select 'dt.issue a', :text => /Add ingredients categories/
assert_select 'dd', :text => /should be classified by categories/
end
assert_select '#search-results-counts' do
assert_select 'a', :text => 'Changesets (5)'
end
end
def test_search_issues
get :index, :params => {:q => 'issue', :issues => 1}
assert_response :success
assert_select 'input[name=all_words][checked=checked]'
assert_select 'input[name=titles_only]:not([checked])'
assert_select '#search-results' do
assert_select 'dt.issue a', :text => /Bug #5/
assert_select 'dt.issue-closed a', :text => /Bug #8 \(Closed\)/
end
end
def test_search_issues_should_search_notes
Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
get :index, :params => {:q => 'searchkeyword', :issues => 1}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue a', :text => /Feature request #2/
end
end
def test_search_issues_with_multiple_matches_in_journals_should_return_issue_once
Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
get :index, :params => {:q => 'searchkeyword', :issues => 1}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue a', :text => /Feature request #2/
assert_select 'dt', 1
end
end
def test_search_issues_should_search_private_notes_with_permission_only
Journal.create!(:journalized => Issue.find(2), :notes => 'Private notes with searchkeyword', :private_notes => true)
@request.session[:user_id] = 2
Role.find(1).add_permission! :view_private_notes
get :index, :params => {:q => 'searchkeyword', :issues => 1}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue a', :text => /Feature request #2/
end
Role.find(1).remove_permission! :view_private_notes
get :index, :params => {:q => 'searchkeyword', :issues => 1}
assert_response :success
assert_select '#search-results' do
assert_select 'dt', :text => /Feature request #2/, :count => 0
end
end
def test_search_all_projects_with_scope_param
get :index, :params => {:q => 'issue', :scope => 'all'}
assert_response :success
assert_select '#search-results dt'
end
def test_search_my_projects
@request.session[:user_id] = 2
get :index, :params => {:id => 1, :q => 'recipe subproject', :scope => 'my_projects', :all_words => ''}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue', :text => /Bug #1/
assert_select 'dt', :text => /Bug #5/, :count => 0
end
end
def test_search_my_projects_without_memberships
# anonymous user has no memberships
get :index, :params => {:id => 1, :q => 'recipe subproject', :scope => 'my_projects', :all_words => ''}
assert_response :success
assert_select '#search-results' do
assert_select 'dt', 0
end
end
def test_search_project_and_subprojects
get :index, :params => {:id => 1, :q => 'recipe subproject', :scope => 'subprojects', :all_words => ''}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue', :text => /Bug #1/
assert_select 'dt.issue', :text => /Bug #5/
end
end
def test_search_without_searchable_custom_fields
CustomField.update_all :searchable => false
get :index, :params => {:id => 1}
assert_response :success
get :index, :params => {:id => 1, :q => "can"}
assert_response :success
end
def test_search_with_searchable_custom_fields
get :index, :params => {:id => 1, :q => "stringforcustomfield"}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue', :text => /#7/
assert_select 'dt', 1
end
end
def test_search_without_attachments
issue = Issue.generate! :subject => 'search_attachments'
attachment = Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
get :index, :params => {:id => 1, :q => 'search_attachments', :attachments => '0'}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue', :text => /##{issue.id}/
assert_select 'dt', 1
end
end
def test_search_attachments_only
issue = Issue.generate! :subject => 'search_attachments'
attachment = Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
get :index, :params => {:id => 1, :q => 'search_attachments', :attachments => 'only'}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue', :text => / #1 /
assert_select 'dt', 1
end
end
def test_search_with_attachments
issue = Issue.generate! :subject => 'search_attachments'
Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
get :index, :params => {:id => 1, :q => 'search_attachments', :attachments => '1'}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue', :text => / #1 /
assert_select 'dt.issue', :text => / ##{issue.id} /
assert_select 'dt', 2
end
end
def test_search_open_issues
Issue.generate! :subject => 'search_open'
Issue.generate! :subject => 'search_open', :status_id => 5
get :index, :params => {:id => 1, :q => 'search_open', :open_issues => '1'}
assert_response :success
assert_select '#search-results' do
assert_select 'dt', 1
end
end
def test_search_all_words
# 'all words' is on by default
get :index, :params => {:id => 1, :q => 'recipe updating saving', :all_words => '1'}
assert_response :success
assert_select 'input[name=all_words][checked=checked]'
assert_select '#search-results' do
assert_select 'dt.issue', :text => / #3 /
assert_select 'dt', 1
end
end
def test_search_one_of_the_words
get :index, :params => {:id => 1, :q => 'recipe updating saving', :all_words => ''}
assert_response :success
assert_select 'input[name=all_words]:not([checked])'
assert_select '#search-results' do
assert_select 'dt.issue', :text => / #3 /
assert_select 'dt', 3
end
end
def test_search_titles_only_without_result
get :index, :params => {:id => 1, :q => 'recipe updating saving', :titles_only => '1'}
assert_response :success
assert_select 'input[name=titles_only][checked=checked]'
assert_select '#search-results' do
assert_select 'dt', 0
end
end
def test_search_titles_only
get :index, :params => {:id => 1, :q => 'recipe', :titles_only => '1'}
assert_response :success
assert_select 'input[name=titles_only][checked=checked]'
assert_select '#search-results' do
assert_select 'dt', 2
end
end
def test_search_content
Issue.where(:id => 1).update_all("description = 'This is a searchkeywordinthecontent'")
get :index, :params => {:id => 1, :q => 'searchkeywordinthecontent', :titles_only => ''}
assert_response :success
assert_select 'input[name=titles_only]:not([checked])'
assert_select '#search-results' do
assert_select 'dt.issue', :text => / #1 /
assert_select 'dt', 1
end
end
def test_search_with_pagination
issues = (0..24).map {Issue.generate! :subject => 'search_with_limited_results'}.reverse
get :index, :params => {:q => 'search_with_limited_results'}
assert_response :success
issues[0..9].each do |issue|
assert_select '#search-results dt.issue', :text => / ##{issue.id} /
end
get :index, :params => {:q => 'search_with_limited_results', :page => 2}
assert_response :success
issues[10..19].each do |issue|
assert_select '#search-results dt.issue', :text => / ##{issue.id} /
end
get :index, :params => {:q => 'search_with_limited_results', :page => 3}
assert_response :success
issues[20..24].each do |issue|
assert_select '#search-results dt.issue', :text => / ##{issue.id} /
end
get :index, :params => {:q => 'search_with_limited_results', :page => 4}
assert_response :success
assert_select '#search-results dt', 0
end
def test_search_with_invalid_project_id
get :index, :params => {:id => 195, :q => 'recipe'}
assert_response 404
end
def test_quick_jump_to_issue
# issue of a public project
get :index, :params => {:q => "3"}
assert_redirected_to '/issues/3'
# issue of a private project
get :index, :params => {:q => "4"}
assert_response :success
end
def test_large_integer
get :index, :params => {:q => '4615713488'}
assert_response :success
end
def test_tokens_with_quotes
issue1 = Issue.generate! :subject => 'say hello'
issue2 = Issue.generate! :subject => 'say good bye'
issue3 = Issue.generate! :subject => 'say goodbye'
get :index, :params => {:q => '"good bye" hello "bye bye"', :all_words => ''}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue a', :text => / ##{issue1.id} /
assert_select 'dt.issue a', :text => / ##{issue2.id} /
assert_select 'dt.issue a', :text => / ##{issue3.id} /, :count => 0
end
end
def test_results_should_be_escaped_once
assert Issue.find(1).update_attributes(:subject => '<subject> escaped_once', :description => '<description> escaped_once')
get :index, :params => {:q => 'escaped_once'}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue a', :text => /<subject>/
assert_select 'dd', :text => /<description>/
end
end
def test_keywords_should_be_highlighted
assert Issue.find(1).update_attributes(:subject => 'subject highlighted', :description => 'description highlighted')
get :index, :params => {:q => 'highlighted'}
assert_response :success
assert_select '#search-results' do
assert_select 'dt.issue a span.highlight', :text => 'highlighted'
assert_select 'dd span.highlight', :text => 'highlighted'
end
end
end

View file

@ -0,0 +1,78 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class SearchCustomFieldsVisibilityTest < Redmine::ControllerTest
tests SearchController
fixtures :projects,
:users,
:roles,
:members,
:member_roles,
:issue_statuses,
:trackers,
:projects_trackers,
:enabled_modules,
:enumerations,
:workflows
def setup
field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :searchable => true, :trackers => Tracker.all}
@fields = []
@fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
@fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
@fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
@issue = Issue.generate!(
:author_id => 1,
:project_id => 1,
:tracker_id => 1,
:custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
)
@user_with_role_on_other_project = User.generate!
User.add_to_project(@user_with_role_on_other_project, Project.find(2), Role.find(3))
@users_to_test = {
User.find(1) => [@field1, @field2, @field3],
User.find(3) => [@field1, @field2],
@user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
User.generate! => [@field1],
User.anonymous => [@field1]
}
Member.where(:project_id => 1).each do |member|
member.destroy unless @users_to_test.keys.include?(member.principal)
end
end
def test_search_should_search_visible_custom_fields_only
@users_to_test.each do |user, fields|
@request.session[:user_id] = user.id
@fields.each_with_index do |field, i|
get :index, :params => {:q => "value#{i}"}
assert_response :success
# we should get a result only if the custom field is visible
if fields.include?(field)
assert_select '#search-results dt', 1
else
assert_select '#search-results dt', 0
end
end
end
end
end

View file

@ -0,0 +1,164 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class SessionsControllerTest < Redmine::ControllerTest
include Redmine::I18n
tests WelcomeController
fixtures :users, :email_addresses
def setup
Rails.application.config.redmine_verify_sessions = true
end
def teardown
Rails.application.config.redmine_verify_sessions = false
end
def test_session_token_should_be_updated
token = Token.create!(:user_id => 2, :action => 'session', :created_on => 10.hours.ago, :updated_on => 10.hours.ago)
created = token.reload.created_on
get :index, :session => {
:user_id => 2,
:tk => token.value
}
assert_response :success
token.reload
assert_equal created.to_i, token.created_on.to_i
assert_not_equal created.to_i, token.updated_on.to_i
assert token.updated_on > created
end
def test_user_session_should_not_be_reset_if_lifetime_and_timeout_disabled
created = 2.years.ago
token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
with_settings :session_lifetime => '0', :session_timeout => '0' do
get :index, :session => {
:user_id => 2,
:tk => token.value
}
assert_response :success
end
end
def test_user_session_without_token_should_be_reset
get :index, :session => {
:user_id => 2
}
assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
end
def test_expired_user_session_should_be_reset_if_lifetime_enabled
created = 2.days.ago
token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
with_settings :session_timeout => '720' do
get :index, :session => {
:user_id => 2,
:tk => token.value
}
assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
end
end
def test_valid_user_session_should_not_be_reset_if_lifetime_enabled
created = 3.hours.ago
token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
with_settings :session_timeout => '720' do
get :index, :session => {
:user_id => 2,
:tk => token.value
}
assert_response :success
end
end
def test_expired_user_session_should_be_reset_if_timeout_enabled
created = 4.hours.ago
token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
with_settings :session_timeout => '60' do
get :index, :session => {
:user_id => 2,
:tk => token.value
}
assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
end
end
def test_valid_user_session_should_not_be_reset_if_timeout_enabled
created = 10.minutes.ago
token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
with_settings :session_timeout => '60' do
get :index, :session => {
:user_id => 2,
:tk => token.value
}
assert_response :success
end
end
def test_expired_user_session_should_be_restarted_if_autologin
created = 2.hours.ago
token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
with_settings :session_lifetime => '720', :session_timeout => '60', :autologin => 7 do
autologin_token = Token.create!(:user_id => 2, :action => 'autologin', :created_on => 1.day.ago)
@request.cookies['autologin'] = autologin_token.value
get :index, :session => {
:user_id => 2,
:tk => token.value
}
assert_equal 2, session[:user_id]
assert_response :success
assert_not_equal token.value, session[:tk]
end
end
def test_expired_user_session_should_set_locale
set_language_if_valid 'it'
user = User.find(2)
user.language = 'fr'
user.save!
created = 4.hours.ago
token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
with_settings :session_timeout => '60' do
get :index, :session => {
:user_id => user.id,
:tk => token.value
}
assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
assert_include "Veuillez vous reconnecter", flash[:error]
assert_equal :fr, current_language
end
end
def test_anonymous_session_should_not_be_reset
with_settings :session_lifetime => '720', :session_timeout => '60' do
get :index
assert_response :success
end
end
end

View file

@ -0,0 +1,300 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class SettingsControllerTest < Redmine::ControllerTest
fixtures :projects, :trackers, :issue_statuses, :issues,
:users
def setup
User.current = nil
@request.session[:user_id] = 1 # admin
end
def teardown
Setting.delete_all
Setting.clear_cache
end
def test_index
get :index
assert_response :success
assert_select 'input[name=?][value=?]', 'settings[app_title]', Setting.app_title
end
def test_get_edit
get :edit
assert_response :success
assert_select 'input[name=?][value=""]', 'settings[enabled_scm][]'
end
def test_get_edit_should_preselect_default_issue_list_columns
with_settings :issue_list_default_columns => %w(tracker subject status updated_on) do
get :edit
assert_response :success
end
assert_select 'select[name=?]', 'settings[issue_list_default_columns][]' do
assert_select 'option', 4
assert_select 'option[value=tracker]', :text => 'Tracker'
assert_select 'option[value=subject]', :text => 'Subject'
assert_select 'option[value=status]', :text => 'Status'
assert_select 'option[value=updated_on]', :text => 'Updated'
end
assert_select 'select[name=?]', 'available_columns[]' do
assert_select 'option[value=tracker]', 0
assert_select 'option[value=priority]', :text => 'Priority'
end
end
def test_get_edit_without_trackers_should_succeed
Tracker.delete_all
get :edit
assert_response :success
end
def test_post_edit_notifications
post :edit, :params => {
:settings => {
:mail_from => 'functional@test.foo',
:bcc_recipients => '0',
:notified_events => %w(issue_added issue_updated news_added),
:emails_footer => 'Test footer'
}
}
assert_redirected_to '/settings'
assert_equal 'functional@test.foo', Setting.mail_from
assert !Setting.bcc_recipients?
assert_equal %w(issue_added issue_updated news_added), Setting.notified_events
assert_equal 'Test footer', Setting.emails_footer
end
def test_edit_commit_update_keywords
with_settings :commit_update_keywords => [
{"keywords" => "fixes, resolves", "status_id" => "3"},
{"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
] do
get :edit
end
assert_response :success
assert_select 'tr.commit-keywords', 2
assert_select 'tr.commit-keywords:nth-child(1)' do
assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'fixes, resolves'
assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
assert_select 'option[value="3"][selected=selected]'
end
end
assert_select 'tr.commit-keywords:nth-child(2)' do
assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'closes'
assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
end
assert_select 'select[name=?]', 'settings[commit_update_keywords][done_ratio][]' do
assert_select 'option[value="100"][selected=selected]', :text => '100 %'
end
assert_select 'select[name=?]', 'settings[commit_update_keywords][if_tracker_id][]' do
assert_select 'option[value="2"][selected=selected]', :text => 'Feature request'
end
end
end
def test_edit_without_commit_update_keywords_should_show_blank_line
with_settings :commit_update_keywords => [] do
get :edit
end
assert_response :success
assert_select 'tr.commit-keywords', 1 do
assert_select 'input[name=?]:not([value])', 'settings[commit_update_keywords][keywords][]'
end
end
def test_post_edit_commit_update_keywords
post :edit, :params => {
:settings => {
:commit_update_keywords => {
:keywords => ["resolves", "closes"],
:status_id => ["3", "5"],
:done_ratio => ["", "100"],
:if_tracker_id => ["", "2"]
}
}
}
assert_redirected_to '/settings'
assert_equal([
{"keywords" => "resolves", "status_id" => "3"},
{"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
], Setting.commit_update_keywords)
end
def test_post_edit_with_invalid_setting_should_not_error
post :edit, :params => {
:settings => {
:invalid_setting => '1'
}
}
assert_redirected_to '/settings'
end
def test_post_edit_should_send_security_notification_for_notified_settings
ActionMailer::Base.deliveries.clear
post :edit, :params => {
:settings => {
:login_required => 1
}
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match '0.0.0.0', mail
assert_mail_body_match I18n.t(:setting_login_required), mail
assert_select_email do
assert_select 'a[href^=?]', 'http://localhost:3000/settings'
end
# All admins should receive this
recipients = [mail.bcc, mail.cc].flatten
User.active.where(admin: true).each do |admin|
assert_include admin.mail, recipients
end
end
def test_post_edit_should_not_send_security_notification_for_non_notified_settings
ActionMailer::Base.deliveries.clear
post :edit, :params => {
:settings => {
:app_title => 'MineRed'
}
}
assert_nil (mail = ActionMailer::Base.deliveries.last)
end
def test_post_edit_should_not_send_security_notification_for_unchanged_settings
ActionMailer::Base.deliveries.clear
post :edit, :params => {
:settings => {
:login_required => 0
}
}
assert_nil (mail = ActionMailer::Base.deliveries.last)
end
def test_get_plugin_settings
ActionController::Base.append_view_path(File.join(Rails.root, "test/fixtures/plugins"))
Redmine::Plugin.register :foo do
settings :partial => "foo_plugin/foo_plugin_settings"
end
Setting.plugin_foo = {'sample_setting' => 'Plugin setting value'}
get :plugin, :params => {:id => 'foo'}
assert_response :success
assert_select 'form[action="/settings/plugin/foo"]' do
assert_select 'input[name=?][value=?]', 'settings[sample_setting]', 'Plugin setting value'
end
ensure
Redmine::Plugin.unregister(:foo)
end
def test_get_invalid_plugin_settings
get :plugin, :params => {:id => 'none'}
assert_response 404
end
def test_get_non_configurable_plugin_settings
Redmine::Plugin.register(:foo) {}
get :plugin, :params => {:id => 'foo'}
assert_response 404
ensure
Redmine::Plugin.unregister(:foo)
end
def test_post_plugin_settings
Redmine::Plugin.register(:foo) do
settings :partial => 'not blank', # so that configurable? is true
:default => {'sample_setting' => 'Plugin setting value'}
end
post :plugin, :params => {
:id => 'foo',
:settings => {'sample_setting' => 'Value'}
}
assert_redirected_to '/settings/plugin/foo'
assert_equal({'sample_setting' => 'Value'}, Setting.plugin_foo)
end
def test_post_empty_plugin_settings
Redmine::Plugin.register(:foo) do
settings :partial => 'not blank', # so that configurable? is true
:default => {'sample_setting' => 'Plugin setting value'}
end
post :plugin, :params => {
:id => 'foo'
}
assert_redirected_to '/settings/plugin/foo'
assert_equal({}, Setting.plugin_foo)
end
def test_post_non_configurable_plugin_settings
Redmine::Plugin.register(:foo) {}
post :plugin, :params => {
:id => 'foo',
:settings => {'sample_setting' => 'Value'}
}
assert_response 404
ensure
Redmine::Plugin.unregister(:foo)
end
def test_post_mail_handler_delimiters_should_not_save_invalid_regex_delimiters
post :edit, :params => {
:settings => {
:mail_handler_enable_regex_delimiters => '1',
:mail_handler_body_delimiters => 'Abc[',
}
}
assert_response :success
assert_equal '0', Setting.mail_handler_enable_regex_delimiters
assert_equal '', Setting.mail_handler_body_delimiters
assert_select_error /is not a valid regular expression/
assert_select 'textarea[name=?]', 'settings[mail_handler_body_delimiters]', :text => 'Abc['
end
def test_post_mail_handler_delimiters_should_save_valid_regex_delimiters
post :edit, :params => {
:settings => {
:mail_handler_enable_regex_delimiters => '1',
:mail_handler_body_delimiters => 'On .*, .* at .*, .* <.*<mailto:.*>> wrote:',
}
}
assert_redirected_to '/settings'
assert_equal '1', Setting.mail_handler_enable_regex_delimiters
assert_equal 'On .*, .* at .*, .* <.*<mailto:.*>> wrote:', Setting.mail_handler_body_delimiters
end
end

View file

@ -0,0 +1,135 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class SysControllerTest < Redmine::ControllerTest
fixtures :projects, :repositories, :enabled_modules
def setup
Setting.sys_api_enabled = '1'
Setting.enabled_scm = %w(Subversion Git)
end
def teardown
Setting.clear_cache
end
def test_projects_with_repository_enabled
get :projects
assert_response :success
assert_equal 'application/json', @response.content_type
data = ActiveSupport::JSON.decode(response.body)
assert_equal Project.active.has_module(:repository).count, data.size
project = data.first
assert project['identifier']
assert project['is_public']
assert_not_include 'extra-info', response.body
assert_not_include 'extra_info', response.body
end
def test_create_project_repository
assert_nil Project.find(4).repository
post :create_project_repository, :params => {
:id => 4,
:vendor => 'Subversion',
:repository => { :url => 'file:///create/project/repository/subproject2'}
}
assert_response :created
assert_equal 'application/json', @response.content_type
r = Project.find(4).repository
assert r.is_a?(Repository::Subversion)
assert_equal 'file:///create/project/repository/subproject2', r.url
data = ActiveSupport::JSON.decode(response.body)
assert data['repository-subversion']
assert_equal r.id, data['repository-subversion']['id']
assert_equal r.url, data['repository-subversion']['url']
assert_not_include 'extra-info', response.body
assert_not_include 'extra_info', response.body
end
def test_create_already_existing
post :create_project_repository, :params => {
:id => 1,
:vendor => 'Subversion',
:repository => { :url => 'file:///create/project/repository/subproject2'}
}
assert_response :conflict
end
def test_create_with_failure
post :create_project_repository, :params => {
:id => 4,
:vendor => 'Subversion',
:repository => { :url => 'invalid url'}
}
assert_response :unprocessable_entity
end
def test_fetch_changesets
Repository::Subversion.any_instance.expects(:fetch_changesets).twice.returns(true)
get :fetch_changesets
assert_response :success
end
def test_fetch_changesets_one_project_by_identifier
Repository::Subversion.any_instance.expects(:fetch_changesets).once.returns(true)
get :fetch_changesets, :params => {:id => 'ecookbook'}
assert_response :success
end
def test_fetch_changesets_one_project_by_id
Repository::Subversion.any_instance.expects(:fetch_changesets).once.returns(true)
get :fetch_changesets, :params => {:id => '1'}
assert_response :success
end
def test_fetch_changesets_unknown_project
get :fetch_changesets, :params => {:id => 'unknown'}
assert_response 404
end
def test_disabled_ws_should_respond_with_403_error
with_settings :sys_api_enabled => '0' do
get :projects
assert_response 403
assert_include 'Access denied', response.body
end
end
def test_api_key
with_settings :sys_api_key => 'my_secret_key' do
get :projects, :params => {:key => 'my_secret_key'}
assert_response :success
end
end
def test_wrong_key_should_respond_with_403_error
with_settings :sys_api_enabled => 'my_secret_key' do
get :projects, :params => {:key => 'wrong_key'}
assert_response 403
assert_include 'Access denied', response.body
end
end
end

View file

@ -0,0 +1,352 @@
# -*- coding: utf-8 -*-
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class TimeEntryReportsControllerTest < Redmine::ControllerTest
tests TimelogController
fixtures :projects, :enabled_modules, :roles, :members, :member_roles,
:email_addresses,
:issues, :time_entries, :users, :trackers, :enumerations,
:issue_statuses, :custom_fields, :custom_values,
:projects_trackers, :custom_fields_trackers,
:custom_fields_projects
include Redmine::I18n
def setup
Setting.default_language = "en"
end
def test_report_at_project_level
get :report, :params => {:project_id => 'ecookbook'}
assert_response :success
assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries/report'
end
def test_report_all_projects
get :report
assert_response :success
assert_select 'form#query_form[action=?]', '/time_entries/report'
end
def test_report_all_projects_denied
r = Role.anonymous
r.permissions.delete(:view_time_entries)
r.permissions_will_change!
r.save
get :report
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftime_entries%2Freport'
end
def test_report_all_projects_one_criteria
get :report, :params => {:columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criteria => ['project']}
assert_response :success
assert_select 'tr.total td:last', :text => '8.65'
end
def test_report_all_time
get :report, :params => {:project_id => 1, :criteria => ['project', 'issue']}
assert_response :success
assert_select 'tr.total td:last', :text => '162.90'
end
def test_report_all_time_by_day
get :report, :params => {:project_id => 1, :criteria => ['project', 'issue'], :columns => 'day'}
assert_response :success
assert_select 'tr.total td:last', :text => '162.90'
assert_select 'th', :text => '2007-03-12'
end
def test_report_one_criteria
get :report, :params => {:project_id => 1, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criteria => ['project']}
assert_response :success
assert_select 'tr.total td:last', :text => '8.65'
end
def test_report_two_criteria
get :report, :params => {:project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criteria => ["user", "activity"]}
assert_response :success
assert_select 'tr.total td:last', :text => '162.90'
end
def test_report_custom_field_criteria_with_multiple_values_on_single_value_custom_field_should_not_fail
field = TimeEntryCustomField.create!(:name => 'multi', :field_format => 'list', :possible_values => ['value1', 'value2'])
entry = TimeEntry.create!(:project => Project.find(1), :hours => 1, :activity_id => 10, :user => User.find(2), :spent_on => Date.today)
CustomValue.create!(:customized => entry, :custom_field => field, :value => 'value1')
CustomValue.create!(:customized => entry, :custom_field => field, :value => 'value2')
get :report, :params => {:project_id => 1, :columns => 'day', :criteria => ["cf_#{field.id}"]}
assert_response :success
end
def test_report_multiple_values_custom_fields_should_not_be_proposed
TimeEntryCustomField.create!(:name => 'Single', :field_format => 'list', :possible_values => ['value1', 'value2'])
TimeEntryCustomField.create!(:name => 'Multi', :field_format => 'list', :multiple => true, :possible_values => ['value1', 'value2'])
get :report, :params => {:project_id => 1}
assert_response :success
assert_select 'select[name=?]', 'criteria[]' do
assert_select 'option', :text => 'Single'
assert_select 'option', :text => 'Multi', :count => 0
end
end
def test_report_one_day
get :report, :params => {:project_id => 1, :columns => 'day', :from => "2007-03-23", :to => "2007-03-23", :criteria => ["user", "activity"]}
assert_response :success
assert_select 'tr.total td:last', :text => '4.25'
end
def test_report_by_week_should_use_commercial_year
TimeEntry.delete_all
TimeEntry.generate!(:hours => '2', :spent_on => '2009-12-25') # 2009-52
TimeEntry.generate!(:hours => '4', :spent_on => '2009-12-31') # 2009-53
TimeEntry.generate!(:hours => '8', :spent_on => '2010-01-01') # 2009-53
TimeEntry.generate!(:hours => '16', :spent_on => '2010-01-05') # 2010-1
get :report, :params => {:columns => 'week', :from => "2009-12-25", :to => "2010-01-05", :criteria => ["project"]}
assert_response :success
assert_select '#time-report thead tr' do
assert_select 'th:nth-child(1)', :text => 'Project'
assert_select 'th:nth-child(2)', :text => '2009-52'
assert_select 'th:nth-child(3)', :text => '2009-53'
assert_select 'th:nth-child(4)', :text => '2010-1'
assert_select 'th:nth-child(5)', :text => 'Total time'
end
assert_select '#time-report tbody tr' do
assert_select 'td:nth-child(1)', :text => 'eCookbook'
assert_select 'td:nth-child(2)', :text => '2.00'
assert_select 'td:nth-child(3)', :text => '12.00'
assert_select 'td:nth-child(4)', :text => '16.00'
assert_select 'td:nth-child(5)', :text => '30.00' # Total
end
end
def test_report_should_propose_association_custom_fields
get :report
assert_response :success
assert_select 'select[name=?]', 'criteria[]' do
assert_select 'option[value=cf_1]', {:text => 'Database'}, 'Issue custom field not found'
assert_select 'option[value=cf_3]', {:text => 'Development status'}, 'Project custom field not found'
assert_select 'option[value=cf_7]', {:text => 'Billable'}, 'TimeEntryActivity custom field not found'
end
end
def test_report_with_association_custom_fields
get :report, :params => {:criteria => ['cf_1', 'cf_3', 'cf_7']}
assert_response :success
assert_select 'tr.total td:last', :text => '162.90'
# Custom fields columns
assert_select 'th', :text => 'Database'
assert_select 'th', :text => 'Development status'
assert_select 'th', :text => 'Billable'
# Custom field row
assert_select 'tr' do
assert_select 'td', :text => 'MySQL'
assert_select 'td.hours', :text => '1.00'
end
end
def test_report_one_criteria_no_result
get :report, :params => {:project_id => 1, :columns => 'week', :from => "1998-04-01", :to => "1998-04-30", :criteria => ['project']}
assert_response :success
assert_select '.nodata'
end
def test_report_status_criterion
get :report, :params => {:project_id => 1, :criteria => ['status']}
assert_response :success
assert_select 'th', :text => 'Status'
assert_select 'td', :text => 'New'
end
def test_report_all_projects_csv_export
get :report, :params => {
:columns => 'month',
:from => "2007-01-01",
:to => "2007-06-30",
:criteria => ["project", "user", "activity"],
:format => "csv"
}
assert_response :success
assert_equal 'text/csv; header=present', @response.content_type
lines = @response.body.chomp.split("\n")
# Headers
assert_equal 'Project,User,Activity,2007-3,2007-4,Total time', lines.first
# Total row
assert_equal 'Total time,"","",154.25,8.65,162.90', lines.last
end
def test_report_csv_export
get :report, :params => {
:project_id => 1,
:columns => 'month',
:from => "2007-01-01",
:to => "2007-06-30",
:criteria => ["project", "user", "activity"],
:format => "csv"
}
assert_response :success
assert_equal 'text/csv; header=present', @response.content_type
lines = @response.body.chomp.split("\n")
# Headers
assert_equal 'Project,User,Activity,2007-3,2007-4,Total time', lines.first
# Total row
assert_equal 'Total time,"","",154.25,8.65,162.90', lines.last
end
def test_csv_big_5
str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88".force_encoding('UTF-8')
str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5')
user = User.find_by_id(3)
user.firstname = str_utf8
user.lastname = "test-lastname"
assert user.save
comments = "test_csv_big_5"
te1 = TimeEntry.create(:spent_on => '2011-11-11',
:hours => 7.3,
:project => Project.find(1),
:user => user,
:activity => TimeEntryActivity.find_by_name('Design'),
:comments => comments)
te2 = TimeEntry.find_by_comments(comments)
assert_not_nil te2
assert_equal 7.3, te2.hours
assert_equal 3, te2.user_id
with_settings :default_language => "zh-TW" do
get :report, :params => {
:project_id => 1,
:columns => 'day',
:from => "2011-11-11",
:to => "2011-11-11",
:criteria => ["user"],
:format => "csv"
}
end
assert_response :success
assert_equal 'text/csv; header=present', @response.content_type
lines = @response.body.chomp.split("\n")
# Headers
s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
s2 = "\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
assert_equal s1, lines.first
# Total row
assert_equal "#{str_big5} #{user.lastname},7.30,7.30", lines[1]
assert_equal "#{s2},7.30,7.30", lines[2]
str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)".force_encoding('UTF-8')
assert_equal str_tw, l(:general_lang_name)
assert_equal 'Big5', l(:general_csv_encoding)
assert_equal ',', l(:general_csv_separator)
assert_equal '.', l(:general_csv_decimal_separator)
end
def test_csv_cannot_convert_should_be_replaced_big_5
str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8')
user = User.find_by_id(3)
user.firstname = str_utf8
user.lastname = "test-lastname"
assert user.save
comments = "test_replaced"
te1 = TimeEntry.create(:spent_on => '2011-11-11',
:hours => 7.3,
:project => Project.find(1),
:user => user,
:activity => TimeEntryActivity.find_by_name('Design'),
:comments => comments)
te2 = TimeEntry.find_by_comments(comments)
assert_not_nil te2
assert_equal 7.3, te2.hours
assert_equal 3, te2.user_id
with_settings :default_language => "zh-TW" do
get :report, :params => {
:project_id => 1,
:columns => 'day',
:from => "2011-11-11",
:to => "2011-11-11",
:criteria => ["user"],
:format => "csv"
}
end
assert_response :success
assert_equal 'text/csv; header=present', @response.content_type
lines = @response.body.chomp.split("\n")
# Headers
s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
assert_equal s1, lines.first
# Total row
s2 = "\xa5H?".force_encoding('Big5')
assert_equal "#{s2} #{user.lastname},7.30,7.30", lines[1]
end
def test_csv_fr
with_settings :default_language => "fr" do
str1 = "test_csv_fr"
user = User.find_by_id(3)
te1 = TimeEntry.create(:spent_on => '2011-11-11',
:hours => 7.3,
:project => Project.find(1),
:user => user,
:activity => TimeEntryActivity.find_by_name('Design'),
:comments => str1)
te2 = TimeEntry.find_by_comments(str1)
assert_not_nil te2
assert_equal 7.3, te2.hours
assert_equal 3, te2.user_id
get :report, :params => {
:project_id => 1,
:columns => 'day',
:from => "2011-11-11",
:to => "2011-11-11",
:criteria => ["user"],
:format => "csv"
}
assert_response :success
assert_equal 'text/csv; header=present', @response.content_type
lines = @response.body.chomp.split("\n")
# Headers
s1 = "Utilisateur;2011-11-11;Temps total".force_encoding('ISO-8859-1')
s2 = "Temps total".force_encoding('ISO-8859-1')
assert_equal s1, lines.first
# Total row
assert_equal "#{user.firstname} #{user.lastname};7,30;7,30", lines[1]
assert_equal "#{s2};7,30;7,30", lines[2]
str_fr = "French (Fran\xc3\xa7ais)".force_encoding('UTF-8')
assert_equal str_fr, l(:general_lang_name)
assert_equal 'ISO-8859-1', l(:general_csv_encoding)
assert_equal ';', l(:general_csv_separator)
assert_equal ',', l(:general_csv_decimal_separator)
end
end
end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,130 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class TimelogCustomFieldsVisibilityTest < Redmine::ControllerTest
tests TimelogController
fixtures :projects,
:users,
:roles,
:members,
:member_roles,
:issue_statuses,
:trackers,
:projects_trackers,
:enabled_modules,
:enumerations,
:workflows
def setup
field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :trackers => Tracker.all}
@fields = []
@fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
@fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
@fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
@issue = Issue.generate!(
:author_id => 1,
:project_id => 1,
:tracker_id => 1,
:custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
)
TimeEntry.generate!(:issue => @issue)
@user_with_role_on_other_project = User.generate!
User.add_to_project(@user_with_role_on_other_project, Project.find(2), Role.find(3))
@users_to_test = {
User.find(1) => [@field1, @field2, @field3],
User.find(3) => [@field1, @field2],
@user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
User.generate! => [@field1],
User.anonymous => [@field1]
}
Member.where(:project_id => 1).each do |member|
member.destroy unless @users_to_test.keys.include?(member.principal)
end
end
def test_index_should_show_visible_custom_fields_only
@users_to_test.each do |user, fields|
@request.session[:user_id] = user.id
get :index, :params => {
:project_id => 1,
:issue_id => @issue.id,
:c => (['hours'] + @fields.map{|f| "issue.cf_#{f.id}"})
}
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_select 'td', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name}"
else
assert_select 'td', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name}"
end
end
end
end
def test_index_as_csv_should_show_visible_custom_fields_only
@users_to_test.each do |user, fields|
@request.session[:user_id] = user.id
get :index, :params => {
:project_id => 1,
:issue_id => @issue.id,
:c => (['hours'] + @fields.map{|f| "issue.cf_#{f.id}"}),
:format => 'csv'
}
@fields.each_with_index do |field, i|
if fields.include?(field)
assert_include "Value#{i}", response.body, "User #{user.id} was not able to view #{field.name} in CSV"
else
assert_not_include "Value#{i}", response.body, "User #{user.id} was able to view #{field.name} in CSV"
end
end
end
end
def test_index_with_partial_custom_field_visibility_should_show_visible_custom_fields_only
Issue.delete_all
TimeEntry.delete_all
p1 = Project.generate!
p2 = Project.generate!
user = User.generate!
User.add_to_project(user, p1, Role.where(:id => [1, 3]).to_a)
User.add_to_project(user, p2, Role.where(:id => 3).to_a)
TimeEntry.generate!(
:issue => Issue.generate!(:project => p1, :tracker_id => 1,
:custom_field_values => {@field2.id => 'ValueA'}))
TimeEntry.generate!(
:issue => Issue.generate!(:project => p2, :tracker_id => 1,
:custom_field_values => {@field2.id => 'ValueB'}))
TimeEntry.generate!(
:issue => Issue.generate!(:project => p1, :tracker_id => 1,
:custom_field_values => {@field2.id => 'ValueC'}))
@request.session[:user_id] = user.id
get :index, :params => {:c => ["hours", "issue.cf_#{@field2.id}"]}
assert_select 'td', {:text => 'ValueA'}, "ValueA not found in:\n#{response.body}"
assert_select 'td', :text => 'ValueB', :count => 0
assert_select 'td', {:text => 'ValueC'}, "ValueC not found in:\n#{response.body}"
get :index, :params => {:set_filter => '1', "issue.cf_#{@field2.id}" => '*', :c => ["issue.cf_#{@field2.id}"]}
assert_select 'td', :text => "ValueA"
assert_select 'td', :text => "ValueC"
assert_select 'td', :text => "ValueB", :count => 0
end
end

View file

@ -0,0 +1,243 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class TrackersControllerTest < Redmine::ControllerTest
fixtures :trackers, :projects, :projects_trackers, :users, :issues, :custom_fields, :issue_statuses
def setup
User.current = nil
@request.session[:user_id] = 1 # admin
end
def test_index
get :index
assert_response :success
assert_select 'table.trackers'
end
def test_index_by_anonymous_should_redirect_to_login_form
@request.session[:user_id] = nil
get :index
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftrackers'
end
def test_index_by_user_should_respond_with_406
@request.session[:user_id] = 2
get :index
assert_response 406
end
def test_new
get :new
assert_response :success
assert_select 'input[name=?]', 'tracker[name]'
end
def test_create
assert_difference 'Tracker.count' do
post :create, :params => {
:tracker => {
:name => 'New tracker',
:default_status_id => 1,
:project_ids => ['1', '', ''],
:custom_field_ids => ['1', '6', '']
}
}
end
assert_redirected_to :action => 'index'
tracker = Tracker.order('id DESC').first
assert_equal 'New tracker', tracker.name
assert_equal [1], tracker.project_ids.sort
assert_equal Tracker::CORE_FIELDS, tracker.core_fields
assert_equal [1, 6], tracker.custom_field_ids.sort
assert_equal 0, tracker.workflow_rules.count
end
def test_create_with_disabled_core_fields
assert_difference 'Tracker.count' do
post :create, :params => {
:tracker => {
:name => 'New tracker',
:default_status_id => 1,
:core_fields => ['assigned_to_id', 'fixed_version_id', '']
}
}
end
assert_redirected_to :action => 'index'
tracker = Tracker.order('id DESC').first
assert_equal 'New tracker', tracker.name
assert_equal %w(assigned_to_id fixed_version_id), tracker.core_fields
end
def test_create_new_with_workflow_copy
assert_difference 'Tracker.count' do
post :create, :params => {
:tracker => {
:name => 'New tracker',
:default_status_id => 1
},
:copy_workflow_from => 1
}
end
assert_redirected_to :action => 'index'
tracker = Tracker.find_by_name('New tracker')
assert_equal 0, tracker.projects.count
assert_equal Tracker.find(1).workflow_rules.count, tracker.workflow_rules.count
end
def test_create_with_failure
assert_no_difference 'Tracker.count' do
post :create, :params => {
:tracker => {
:name => '',
:project_ids => ['1', '', ''],
:custom_field_ids => ['1', '6', '']
}
}
end
assert_response :success
assert_select_error /name cannot be blank/i
end
def test_edit
Tracker.find(1).project_ids = [1, 3]
get :edit, :params => {:id => 1}
assert_response :success
assert_select 'input[name=?][value="1"][checked=checked]', 'tracker[project_ids][]'
assert_select 'input[name=?][value="2"]:not([checked])', 'tracker[project_ids][]'
assert_select 'input[name=?][value=""][type=hidden]', 'tracker[project_ids][]'
end
def test_edit_should_check_core_fields
tracker = Tracker.find(1)
tracker.core_fields = %w(assigned_to_id fixed_version_id)
tracker.save!
get :edit, :params => {:id => 1}
assert_response :success
assert_select 'input[name=?][value=assigned_to_id][checked=checked]', 'tracker[core_fields][]'
assert_select 'input[name=?][value=fixed_version_id][checked=checked]', 'tracker[core_fields][]'
assert_select 'input[name=?][value=category_id]', 'tracker[core_fields][]'
assert_select 'input[name=?][value=category_id][checked=checked]', 'tracker[core_fields][]', 0
assert_select 'input[name=?][value=""][type=hidden]', 'tracker[core_fields][]'
end
def test_update
put :update, :params => {
:id => 1,
:tracker => {
:name => 'Renamed',
:project_ids => ['1', '2', '']
}
}
assert_redirected_to :action => 'index'
assert_equal [1, 2], Tracker.find(1).project_ids.sort
end
def test_update_without_projects
put :update, :params => {
:id => 1,
:tracker => {
:name => 'Renamed',
:project_ids => ['']
}
}
assert_redirected_to :action => 'index'
assert Tracker.find(1).project_ids.empty?
end
def test_update_without_core_fields
put :update, :params => {
:id => 1,
:tracker => {
:name => 'Renamed',
:core_fields => ['']
}
}
assert_redirected_to :action => 'index'
assert Tracker.find(1).core_fields.empty?
end
def test_update_with_failure
put :update, :params => {:id => 1, :tracker => { :name => '' }}
assert_response :success
assert_select_error /name cannot be blank/i
end
def test_move_lower
tracker = Tracker.find_by_position(1)
put :update, :params => {:id => 1, :tracker => { :position => '2' }}
assert_equal 2, tracker.reload.position
end
def test_destroy
tracker = Tracker.generate!(:name => 'Destroyable')
assert_difference 'Tracker.count', -1 do
delete :destroy, :params => {:id => tracker.id}
end
assert_redirected_to :action => 'index'
assert_nil flash[:error]
end
def test_destroy_tracker_in_use
assert_no_difference 'Tracker.count' do
delete :destroy, :params => {:id => 1}
end
assert_redirected_to :action => 'index'
assert_not_nil flash[:error]
end
def test_get_fields
get :fields
assert_response :success
assert_select 'form' do
assert_select 'input[type=checkbox][name=?][value=assigned_to_id]', 'trackers[1][core_fields][]'
assert_select 'input[type=checkbox][name=?][value="2"]', 'trackers[1][custom_field_ids][]'
assert_select 'input[type=hidden][name=?][value=""]', 'trackers[1][core_fields][]'
assert_select 'input[type=hidden][name=?][value=""]', 'trackers[1][custom_field_ids][]'
end
end
def test_post_fields
post :fields, :params => {
:trackers => {
'1' => {'core_fields' => ['assigned_to_id', 'due_date', ''], 'custom_field_ids' => ['1', '2']},
'2' => {'core_fields' => [''], 'custom_field_ids' => ['']}
}
}
assert_redirected_to '/trackers/fields'
tracker = Tracker.find(1)
assert_equal %w(assigned_to_id due_date), tracker.core_fields
assert_equal [1, 2], tracker.custom_field_ids.sort
tracker = Tracker.find(2)
assert_equal [], tracker.core_fields
assert_equal [], tracker.custom_field_ids.sort
end
end

View file

@ -0,0 +1,655 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class UsersControllerTest < Redmine::ControllerTest
include Redmine::I18n
fixtures :users, :email_addresses, :projects, :members, :member_roles, :roles,
:custom_fields, :custom_values, :groups_users,
:auth_sources,
:enabled_modules,
:issues, :issue_statuses,
:trackers
def setup
User.current = nil
@request.session[:user_id] = 1 # admin
end
def test_index
get :index
assert_response :success
assert_select 'table.users'
assert_select 'tr.user.active'
assert_select 'tr.user.locked', 0
end
def test_index_with_status_filter
get :index, :params => {:status => 3}
assert_response :success
assert_select 'tr.user.active', 0
assert_select 'tr.user.locked'
end
def test_index_with_name_filter
get :index, :params => {:name => 'john'}
assert_response :success
assert_select 'tr.user td.username', :text => 'jsmith'
assert_select 'tr.user', 1
end
def test_index_with_group_filter
get :index, :params => {:group_id => '10'}
assert_response :success
assert_select 'tr.user', Group.find(10).users.count
assert_select 'select[name=group_id]' do
assert_select 'option[value="10"][selected=selected]'
end
end
def test_show
@request.session[:user_id] = nil
get :show, :params => {:id => 2}
assert_response :success
assert_select 'h2', :text => /John Smith/
end
def test_show_should_display_visible_custom_fields
@request.session[:user_id] = nil
UserCustomField.find_by_name('Phone number').update_attribute :visible, true
get :show, :params => {:id => 2}
assert_response :success
assert_select 'li', :text => /Phone number/
end
def test_show_should_not_display_hidden_custom_fields
@request.session[:user_id] = nil
UserCustomField.find_by_name('Phone number').update_attribute :visible, false
get :show, :params => {:id => 2}
assert_response :success
assert_select 'li', :text => /Phone number/, :count => 0
end
def test_show_should_not_fail_when_custom_values_are_nil
user = User.find(2)
# Create a custom field to illustrate the issue
custom_field = CustomField.create!(:name => 'Testing', :field_format => 'text')
custom_value = user.custom_values.build(:custom_field => custom_field).save!
get :show, :params => {:id => 2}
assert_response :success
end
def test_show_inactive
@request.session[:user_id] = nil
get :show, :params => {:id => 5}
assert_response 404
end
def test_show_inactive_by_admin
@request.session[:user_id] = 1
get :show, :params => {:id => 5}
assert_response 200
assert_select 'h2', :text => /Dave2 Lopper2/
end
def test_show_user_who_is_not_visible_should_return_404
Role.anonymous.update! :users_visibility => 'members_of_visible_projects'
user = User.generate!
@request.session[:user_id] = nil
get :show, :params => {:id => user.id}
assert_response 404
end
def test_show_displays_memberships_based_on_project_visibility
@request.session[:user_id] = 1
get :show, :params => {:id => 2}
assert_response :success
# membership of private project admin can see
assert_select 'li a', :text => "OnlineStore"
end
def test_show_current_should_require_authentication
@request.session[:user_id] = nil
get :show, :params => {:id => 'current'}
assert_response 302
end
def test_show_current
@request.session[:user_id] = 2
get :show, :params => {:id => 'current'}
assert_response :success
assert_select 'h2', :text => /John Smith/
end
def test_new
get :new
assert_response :success
assert_select 'input[name=?]', 'user[login]'
end
def test_create
Setting.bcc_recipients = '1'
assert_difference 'User.count' do
assert_difference 'ActionMailer::Base.deliveries.size' do
post :create, :params => {
:user => {
:firstname => 'John',
:lastname => 'Doe',
:login => 'jdoe',
:password => 'secret123',
:password_confirmation => 'secret123',
:mail => 'jdoe@gmail.com',
:mail_notification => 'none'
},
:send_information => '1'
}
end
end
user = User.order('id DESC').first
assert_redirected_to :controller => 'users', :action => 'edit', :id => user.id
assert_equal 'John', user.firstname
assert_equal 'Doe', user.lastname
assert_equal 'jdoe', user.login
assert_equal 'jdoe@gmail.com', user.mail
assert_equal 'none', user.mail_notification
assert user.check_password?('secret123')
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
assert_equal [user.mail], mail.bcc
assert_mail_body_match 'secret', mail
end
def test_create_with_preferences
assert_difference 'User.count' do
post :create, :params => {
:user => {
:firstname => 'John',
:lastname => 'Doe',
:login => 'jdoe',
:password => 'secret123',
:password_confirmation => 'secret123',
:mail => 'jdoe@gmail.com',
:mail_notification => 'none'
},
:pref => {
'hide_mail' => '1',
'time_zone' => 'Paris',
'comments_sorting' => 'desc',
'warn_on_leaving_unsaved' => '0',
'textarea_font' => 'proportional'
}
}
end
user = User.order('id DESC').first
assert_equal 'jdoe', user.login
assert_equal true, user.pref.hide_mail
assert_equal 'Paris', user.pref.time_zone
assert_equal 'desc', user.pref[:comments_sorting]
assert_equal '0', user.pref[:warn_on_leaving_unsaved]
assert_equal 'proportional', user.pref[:textarea_font]
end
def test_create_with_generate_password_should_email_the_password
assert_difference 'User.count' do
post :create, :params => {
:user => {
:login => 'randompass',
:firstname => 'Random',
:lastname => 'Pass',
:mail => 'randompass@example.net',
:language => 'en',
:generate_password => '1',
:password => '',
:password_confirmation => ''
},
:send_information => 1
}
end
user = User.order('id DESC').first
assert_equal 'randompass', user.login
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
m = mail_body(mail).match(/Password: ([a-zA-Z0-9]+)/)
assert m
password = m[1]
assert user.check_password?(password)
end
def test_create_and_continue
post :create, :params => {
:user => {
:login => 'randompass',
:firstname => 'Random',
:lastname => 'Pass',
:mail => 'randompass@example.net',
:generate_password => '1'
},
:continue => '1'
}
assert_redirected_to '/users/new?user%5Bgenerate_password%5D=1'
end
def test_create_with_failure
assert_no_difference 'User.count' do
post :create, :params => {:user => {}}
end
assert_response :success
assert_select_error /Email cannot be blank/
end
def test_create_with_failure_sould_preserve_preference
assert_no_difference 'User.count' do
post :create, :params => {
:user => {},
:pref => {
'no_self_notified' => '1',
'hide_mail' => '1',
'time_zone' => 'Paris',
'comments_sorting' => 'desc',
'warn_on_leaving_unsaved' => '0'
}
}
end
assert_response :success
assert_select 'select#pref_time_zone option[selected=selected]', :text => /Paris/
assert_select 'input#pref_no_self_notified[value="1"][checked=checked]'
end
def test_create_admin_should_send_security_notification
ActionMailer::Base.deliveries.clear
post :create, :params => {
:user => {
:firstname => 'Edgar',
:lastname => 'Schmoe',
:login => 'eschmoe',
:password => 'secret123',
:password_confirmation => 'secret123',
:mail => 'eschmoe@example.foo',
:admin => '1'
}
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match '0.0.0.0', mail
assert_mail_body_match I18n.t(:mail_body_security_notification_add, field: I18n.t(:field_admin), value: 'eschmoe'), mail
assert_select_email do
assert_select 'a[href^=?]', 'http://localhost:3000/users', :text => 'Users'
end
# All admins should receive this
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
end
end
def test_create_non_admin_should_not_send_security_notification
ActionMailer::Base.deliveries.clear
post :create, :params => {
:user => {
:firstname => 'Edgar',
:lastname => 'Schmoe',
:login => 'eschmoe',
:password => 'secret123',
:password_confirmation => 'secret123',
:mail => 'eschmoe@example.foo',
:admin => '0'
}
}
assert_nil ActionMailer::Base.deliveries.last
end
def test_edit
get :edit, :params => {:id => 2}
assert_response :success
assert_select 'input[name=?][value=?]', 'user[login]', 'jsmith'
end
def test_edit_registered_user
assert User.find(2).register!
get :edit, :params => {:id => 2}
assert_response :success
assert_select 'a', :text => 'Activate'
end
def test_edit_should_be_denied_for_anonymous
assert User.find(6).anonymous?
get :edit, :params => {:id => 6}
assert_response 404
end
def test_update
ActionMailer::Base.deliveries.clear
put :update, :params => {
:id => 2,
:user => {:firstname => 'Changed', :mail_notification => 'only_assigned'},
:pref => {:hide_mail => '1', :comments_sorting => 'desc'}
}
user = User.find(2)
assert_equal 'Changed', user.firstname
assert_equal 'only_assigned', user.mail_notification
assert_equal true, user.pref[:hide_mail]
assert_equal 'desc', user.pref[:comments_sorting]
assert ActionMailer::Base.deliveries.empty?
end
def test_update_with_failure
assert_no_difference 'User.count' do
put :update, :params => {
:id => 2,
:user => {:firstname => ''}
}
end
assert_response :success
assert_select_error /First name cannot be blank/
end
def test_update_with_group_ids_should_assign_groups
put :update, :params => {
:id => 2,
:user => {:group_ids => ['10']}
}
user = User.find(2)
assert_equal [10], user.group_ids
end
def test_update_with_activation_should_send_a_notification
u = User.new(:firstname => 'Foo', :lastname => 'Bar', :mail => 'foo.bar@somenet.foo', :language => 'fr')
u.login = 'foo'
u.status = User::STATUS_REGISTERED
u.save!
ActionMailer::Base.deliveries.clear
Setting.bcc_recipients = '1'
put :update, :params => {
:id => u.id,
:user => {:status => User::STATUS_ACTIVE}
}
assert u.reload.active?
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
assert_equal ['foo.bar@somenet.foo'], mail.bcc
assert_mail_body_match ll('fr', :notice_account_activated), mail
end
def test_update_with_password_change_should_send_a_notification
ActionMailer::Base.deliveries.clear
Setting.bcc_recipients = '1'
put :update, :params => {
:id => 2,
:user => {:password => 'newpass123', :password_confirmation => 'newpass123'},
:send_information => '1'
}
u = User.find(2)
assert u.check_password?('newpass123')
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
assert_equal [u.mail], mail.bcc
assert_mail_body_match 'newpass123', mail
end
def test_update_with_generate_password_should_email_the_password
ActionMailer::Base.deliveries.clear
Setting.bcc_recipients = '1'
put :update, :params => {
:id => 2,
:user => {
:generate_password => '1',
:password => '',
:password_confirmation => ''
},
:send_information => '1'
}
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
m = mail_body(mail).match(/Password: ([a-zA-Z0-9]+)/)
assert m
password = m[1]
assert User.find(2).check_password?(password)
end
def test_update_without_generate_password_should_not_change_password
put :update, :params => {
:id => 2, :user => {
:firstname => 'changed',
:generate_password => '0',
:password => '',
:password_confirmation => ''
},
:send_information => '1'
}
user = User.find(2)
assert_equal 'changed', user.firstname
assert user.check_password?('jsmith')
end
def test_update_user_switchin_from_auth_source_to_password_authentication
# Configure as auth source
u = User.find(2)
u.auth_source = AuthSource.find(1)
u.save!
put :update, :params => {
:id => u.id,
:user => {:auth_source_id => '', :password => 'newpass123', :password_confirmation => 'newpass123'}
}
assert_nil u.reload.auth_source
assert u.check_password?('newpass123')
end
def test_update_notified_project
get :edit, :params => {:id => 2}
assert_response :success
u = User.find(2)
assert_equal [1, 2, 5], u.projects.collect{|p| p.id}.sort
assert_equal [1, 2, 5], u.notified_projects_ids.sort
assert_select 'input[name=?][value=?]', 'user[notified_project_ids][]', '1'
assert_equal 'all', u.mail_notification
put :update, :params => {
:id => 2,
:user => {
:mail_notification => 'selected',
:notified_project_ids => [1, 2]
}
}
u = User.find(2)
assert_equal 'selected', u.mail_notification
assert_equal [1, 2], u.notified_projects_ids.sort
end
def test_update_status_should_not_update_attributes
user = User.find(2)
user.pref[:no_self_notified] = '1'
user.pref.save
put :update, :params => {
:id => 2,
:user => {:status => 3}
}
assert_response 302
user = User.find(2)
assert_equal 3, user.status
assert_equal '1', user.pref[:no_self_notified]
end
def test_update_assign_admin_should_send_security_notification
ActionMailer::Base.deliveries.clear
put :update, :params => {
:id => 2,
:user => {:admin => 1}
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match I18n.t(:mail_body_security_notification_add, field: I18n.t(:field_admin), value: User.find(2).login), mail
# All admins should receive this
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
end
end
def test_update_unassign_admin_should_send_security_notification
user = User.find(2)
user.admin = true
user.save!
ActionMailer::Base.deliveries.clear
put :update, :params => {
:id => user.id,
:user => {:admin => 0}
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match I18n.t(:mail_body_security_notification_remove, field: I18n.t(:field_admin), value: user.login), mail
# All admins should receive this
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
end
end
def test_update_lock_admin_should_send_security_notification
user = User.find(2)
user.admin = true
user.save!
ActionMailer::Base.deliveries.clear
put :update, :params => {
:id => 2,
:user => {:status => Principal::STATUS_LOCKED}
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match I18n.t(:mail_body_security_notification_remove, field: I18n.t(:field_admin), value: User.find(2).login), mail
# All admins should receive this
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
end
# if user is already locked, destroying should not send a second mail
# (for active admins see furtherbelow)
ActionMailer::Base.deliveries.clear
delete :destroy, :params => {:id => 1}
assert_nil ActionMailer::Base.deliveries.last
end
def test_update_unlock_admin_should_send_security_notification
user = User.find(5) # already locked
user.admin = true
user.save!
ActionMailer::Base.deliveries.clear
put :update, :params => {
:id => user.id,
:user => {:status => Principal::STATUS_ACTIVE}
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match I18n.t(:mail_body_security_notification_add, field: I18n.t(:field_admin), value: user.login), mail
# All admins should receive this
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
end
end
def test_update_admin_unrelated_property_should_not_send_security_notification
ActionMailer::Base.deliveries.clear
put :update, :params => {
:id => 1,
:user => {:firstname => 'Jimmy'}
}
assert_nil ActionMailer::Base.deliveries.last
end
def test_update_should_be_denied_for_anonymous
assert User.find(6).anonymous?
put :update, :params => {:id => 6}
assert_response 404
end
def test_destroy
assert_difference 'User.count', -1 do
delete :destroy, :params => {:id => 2}
end
assert_redirected_to '/users'
assert_nil User.find_by_id(2)
end
def test_destroy_should_be_denied_for_non_admin_users
@request.session[:user_id] = 3
assert_no_difference 'User.count' do
get :destroy, :params => {:id => 2}
end
assert_response 403
end
def test_destroy_should_be_denied_for_anonymous
assert User.find(6).anonymous?
assert_no_difference 'User.count' do
put :destroy, :params => {:id => 6}
end
assert_response 404
end
def test_destroy_should_redirect_to_back_url_param
assert_difference 'User.count', -1 do
delete :destroy, :params => {:id => 2, :back_url => '/users?name=foo'}
end
assert_redirected_to '/users?name=foo'
end
def test_destroy_active_admin_should_send_security_notification
user = User.find(2)
user.admin = true
user.save!
ActionMailer::Base.deliveries.clear
delete :destroy, :params => {:id => user.id}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match I18n.t(:mail_body_security_notification_remove, field: I18n.t(:field_admin), value: user.login), mail
# All admins should receive this
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
end
end
end

View file

@ -0,0 +1,260 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class VersionsControllerTest < Redmine::ControllerTest
fixtures :projects, :enabled_modules,
:trackers, :projects_trackers,
:versions, :issue_statuses, :issue_categories, :enumerations,
:issues,
:users, :email_addresses,
:roles, :members, :member_roles
def setup
User.current = nil
end
def test_index
get :index, :params => {:project_id => 1}
assert_response :success
# Version with no date set appears
assert_select 'h3', :text => Version.find(3).name
# Completed version doesn't appear
assert_select 'h3', :text => Version.find(1).name, :count => 0
# Context menu on issues
assert_select "form[data-cm-url=?]", '/issues/context_menu'
assert_select "div#sidebar" do
# Links to versions anchors
assert_select 'a[href=?]', '#2.0'
# Links to completed versions in the sidebar
assert_select 'a[href=?]', '/versions/1'
end
end
def test_index_with_completed_versions
get :index, :params => {:project_id => 1, :completed => 1}
assert_response :success
# Version with no date set appears
assert_select 'h3', :text => Version.find(3).name
# Completed version appears
assert_select 'h3', :text => Version.find(1).name
end
def test_index_with_tracker_ids
(1..3).each do |tracker_id|
Issue.generate! :project_id => 1, :fixed_version_id => 3, :tracker_id => tracker_id
end
get :index, :params => {:project_id => 1, :tracker_ids => [1, 3]}
assert_response :success
assert_select 'a.issue.tracker-1'
assert_select 'a.issue.tracker-2', 0
assert_select 'a.issue.tracker-3'
end
def test_index_showing_subprojects_versions
@subproject_version = Version.create!(:project => Project.find(3), :name => "Subproject version")
get :index, :params => {:project_id => 1, :with_subprojects => 1}
assert_response :success
# Shared version
assert_select 'h3', :text => Version.find(4).name
# Subproject version
assert_select 'h3', :text => /Subproject version/
end
def test_index_should_prepend_shared_versions
get :index, :params => {:project_id => 1}
assert_response :success
assert_select '#sidebar' do
assert_select 'a[href=?]', '#2.0', :text => '2.0'
assert_select 'a[href=?]', '#subproject1-2.0', :text => 'eCookbook Subproject 1 - 2.0'
end
assert_select '#content' do
assert_select 'a[name=?]', '2.0', :text => '2.0'
assert_select 'a[name=?]', 'subproject1-2.0', :text => 'eCookbook Subproject 1 - 2.0'
end
end
def test_show
get :show, :params => {:id => 2}
assert_response :success
assert_select 'h2', :text => /1.0/
end
def test_show_should_link_to_spent_time_on_version
version = Version.generate!
issue = Issue.generate(:fixed_version => version)
TimeEntry.generate!(:issue => issue, :hours => 7.2)
get :show, :params => {:id => version.id}
assert_response :success
assert_select '.total-hours', :text => '7.20 hours'
assert_select '.total-hours a[href=?]', "/projects/ecookbook/time_entries?issue.fixed_version_id=#{version.id}&set_filter=1"
end
def test_show_should_display_nil_counts
with_settings :default_language => 'en' do
get :show, :params => {:id => 2, :status_by => 'category'}
assert_response :success
assert_select 'div#status_by' do
assert_select 'select[name=status_by]' do
assert_select 'option[value=category][selected=selected]'
end
assert_select 'a', :text => 'none'
end
end
end
def test_new
@request.session[:user_id] = 2
get :new, :params => {:project_id => '1'}
assert_response :success
assert_select 'input[name=?]', 'version[name]'
assert_select 'select[name=?]', 'version[status]', false
end
def test_new_from_issue_form
@request.session[:user_id] = 2
get :new, :params => {:project_id => '1'}, :xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
def test_create
@request.session[:user_id] = 2 # manager
assert_difference 'Version.count' do
post :create, :params => {:project_id => '1', :version => {:name => 'test_add_version'}}
end
assert_redirected_to '/projects/ecookbook/settings/versions'
version = Version.find_by_name('test_add_version')
assert_not_nil version
assert_equal 1, version.project_id
end
def test_create_from_issue_form
@request.session[:user_id] = 2
assert_difference 'Version.count' do
post :create, :params => {:project_id => '1', :version => {:name => 'test_add_version_from_issue_form'}}, :xhr => true
end
version = Version.find_by_name('test_add_version_from_issue_form')
assert_not_nil version
assert_equal 1, version.project_id
assert_response :success
assert_equal 'text/javascript', response.content_type
assert_include 'test_add_version_from_issue_form', response.body
end
def test_create_from_issue_form_with_failure
@request.session[:user_id] = 2
assert_no_difference 'Version.count' do
post :create, :params => {:project_id => '1', :version => {:name => ''}}, :xhr => true
end
assert_response :success
assert_equal 'text/javascript', response.content_type
end
def test_get_edit
@request.session[:user_id] = 2
get :edit, :params => {:id => 2}
assert_response :success
version = Version.find(2)
assert_select 'select[name=?]', 'version[status]' do
assert_select 'option[value=?][selected="selected"]', version.status
end
assert_select 'input[name=?][value=?]', 'version[name]', version.name
end
def test_close_completed
Version.update_all("status = 'open'")
@request.session[:user_id] = 2
put :close_completed, :params => {:project_id => 'ecookbook'}
assert_redirected_to :controller => 'projects', :action => 'settings',
:tab => 'versions', :id => 'ecookbook'
assert_not_nil Version.find_by_status('closed')
end
def test_post_update
@request.session[:user_id] = 2
put :update, :params => {
:id => 2,
:version => {
:name => 'New version name',
:effective_date => Date.today.strftime("%Y-%m-%d")
}
}
assert_redirected_to :controller => 'projects', :action => 'settings',
:tab => 'versions', :id => 'ecookbook'
version = Version.find(2)
assert_equal 'New version name', version.name
assert_equal Date.today, version.effective_date
end
def test_post_update_with_validation_failure
@request.session[:user_id] = 2
put :update, :params => {
:id => 2,
:version => {
:name => '',
:effective_date => Date.today.strftime("%Y-%m-%d")
}
}
assert_response :success
assert_select_error /Name cannot be blank/
end
def test_destroy
@request.session[:user_id] = 2
assert_difference 'Version.count', -1 do
delete :destroy, :params => {:id => 3}
end
assert_redirected_to :controller => 'projects', :action => 'settings',
:tab => 'versions', :id => 'ecookbook'
assert_nil Version.find_by_id(3)
end
def test_destroy_version_in_use_should_fail
@request.session[:user_id] = 2
assert_no_difference 'Version.count' do
delete :destroy, :params => {:id => 2}
end
assert_redirected_to :controller => 'projects', :action => 'settings',
:tab => 'versions', :id => 'ecookbook'
assert flash[:error].match(/Unable to delete version/)
assert Version.find_by_id(2)
end
def test_issue_status_by
get :status_by, :params => {:id => 2}, :xhr => true
assert_response :success
end
def test_issue_status_by_status
get :status_by, :params => {:id => 2, :status_by => 'status'}, :xhr => true
assert_response :success
assert_include 'Assigned', response.body
assert_include 'Closed', response.body
end
end

View file

@ -0,0 +1,380 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class WatchersControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
:issues, :trackers, :projects_trackers, :issue_statuses, :enumerations, :watchers
def setup
User.current = nil
end
def test_watch_a_single_object_as_html
@request.session[:user_id] = 3
assert_difference('Watcher.count') do
post :watch, :params => {:object_type => 'issue', :object_id => '1'}
assert_response :success
assert_include 'Watcher added', response.body
end
assert Issue.find(1).watched_by?(User.find(3))
end
def test_watch_a_single_object
@request.session[:user_id] = 3
assert_difference('Watcher.count') do
post :watch, :params => {:object_type => 'issue', :object_id => '1'}, :xhr => true
assert_response :success
assert_include '$(".issue-1-watcher")', response.body
end
assert Issue.find(1).watched_by?(User.find(3))
end
def test_watch_a_collection_with_a_single_object
@request.session[:user_id] = 3
assert_difference('Watcher.count') do
post :watch, :params => {:object_type => 'issue', :object_id => ['1']}, :xhr => true
assert_response :success
assert_include '$(".issue-1-watcher")', response.body
end
assert Issue.find(1).watched_by?(User.find(3))
end
def test_watch_a_collection_with_multiple_objects
@request.session[:user_id] = 3
assert_difference('Watcher.count', 2) do
post :watch, :params => {:object_type => 'issue', :object_id => ['1', '3']}, :xhr => true
assert_response :success
assert_include '$(".issue-bulk-watcher")', response.body
end
assert Issue.find(1).watched_by?(User.find(3))
assert Issue.find(3).watched_by?(User.find(3))
end
def test_watch_a_news_module_should_add_watcher
@request.session[:user_id] = 7
assert_not_nil m = Project.find(1).enabled_module('news')
assert_difference 'Watcher.count' do
post :watch, :params => {:object_type => 'enabled_module', :object_id => m.id.to_s}, :xhr => true
assert_response :success
end
assert m.reload.watched_by?(User.find(7))
end
def test_watch_a_private_news_module_without_permission_should_fail
@request.session[:user_id] = 7
assert_not_nil m = Project.find(2).enabled_module('news')
assert_no_difference 'Watcher.count' do
post :watch, :params => {:object_type => 'enabled_module', :object_id => m.id.to_s}, :xhr => true
assert_response 403
end
end
def test_watch_should_be_denied_without_permission
Role.find(2).remove_permission! :view_issues
@request.session[:user_id] = 3
assert_no_difference('Watcher.count') do
post :watch, :params => {:object_type => 'issue', :object_id => '1'}, :xhr => true
assert_response 403
end
end
def test_watch_invalid_class_should_respond_with_404
@request.session[:user_id] = 3
assert_no_difference('Watcher.count') do
post :watch, :params => {:object_type => 'foo', :object_id => '1'}, :xhr => true
assert_response 404
end
end
def test_watch_invalid_object_should_respond_with_404
@request.session[:user_id] = 3
assert_no_difference('Watcher.count') do
post :watch, :params => {:object_type => 'issue', :object_id => '999'}, :xhr => true
assert_response 404
end
end
def test_unwatch_as_html
@request.session[:user_id] = 3
assert_difference('Watcher.count', -1) do
delete :unwatch, :params => {:object_type => 'issue', :object_id => '2'}
assert_response :success
assert_include 'Watcher removed', response.body
end
assert !Issue.find(1).watched_by?(User.find(3))
end
def test_unwatch
@request.session[:user_id] = 3
assert_difference('Watcher.count', -1) do
delete :unwatch, :params => {:object_type => 'issue', :object_id => '2'}, :xhr => true
assert_response :success
assert_include '$(".issue-2-watcher")', response.body
end
assert !Issue.find(1).watched_by?(User.find(3))
end
def test_unwatch_a_collection_with_multiple_objects
@request.session[:user_id] = 3
Watcher.create!(:user_id => 3, :watchable => Issue.find(1))
Watcher.create!(:user_id => 3, :watchable => Issue.find(3))
assert_difference('Watcher.count', -2) do
delete :unwatch, :params => {:object_type => 'issue', :object_id => ['1', '3']}, :xhr => true
assert_response :success
assert_include '$(".issue-bulk-watcher")', response.body
end
assert !Issue.find(1).watched_by?(User.find(3))
assert !Issue.find(3).watched_by?(User.find(3))
end
def test_new
@request.session[:user_id] = 2
get :new, :params => {:object_type => 'issue', :object_id => '2'}, :xhr => true
assert_response :success
assert_match /ajax-modal/, response.body
end
def test_new_with_multiple_objects
@request.session[:user_id] = 2
get :new, :params => {:object_type => 'issue', :object_id => ['1', '2']}, :xhr => true
assert_response :success
assert_match /ajax-modal/, response.body
end
def test_new_for_new_record_with_project_id
@request.session[:user_id] = 2
get :new, :params => {:project_id => 1}, :xhr => true
assert_response :success
assert_match /ajax-modal/, response.body
end
def test_new_for_new_record_with_project_identifier
@request.session[:user_id] = 2
get :new, :params => {:project_id => 'ecookbook'}, :xhr => true
assert_response :success
assert_match /ajax-modal/, response.body
end
def test_create_as_html
@request.session[:user_id] = 2
assert_difference('Watcher.count') do
post :create, :params => {
:object_type => 'issue', :object_id => '2',
:watcher => {:user_id => '4'}
}
assert_response :success
assert_include 'Watcher added', response.body
end
assert Issue.find(2).watched_by?(User.find(4))
end
def test_create
@request.session[:user_id] = 2
assert_difference('Watcher.count') do
post :create, :params => {
:object_type => 'issue', :object_id => '2',
:watcher => {:user_id => '4'}
}, :xhr => true
assert_response :success
assert_match /watchers/, response.body
assert_match /ajax-modal/, response.body
end
assert Issue.find(2).watched_by?(User.find(4))
end
def test_create_with_mutiple_users
@request.session[:user_id] = 2
assert_difference('Watcher.count', 2) do
post :create, :params => {
:object_type => 'issue', :object_id => '2',
:watcher => {:user_ids => ['4', '7']}
}, :xhr => true
assert_response :success
assert_match /watchers/, response.body
assert_match /ajax-modal/, response.body
end
assert Issue.find(2).watched_by?(User.find(4))
assert Issue.find(2).watched_by?(User.find(7))
end
def test_create_with_mutiple_objects
@request.session[:user_id] = 2
assert_difference('Watcher.count', 4) do
post :create, :params => {
:object_type => 'issue', :object_id => ['1', '2'],
:watcher => {:user_ids => ['4', '7']}
}, :xhr => true
assert_response :success
assert_match /watchers/, response.body
assert_match /ajax-modal/, response.body
end
assert Issue.find(1).watched_by?(User.find(4))
assert Issue.find(2).watched_by?(User.find(4))
assert Issue.find(1).watched_by?(User.find(7))
assert Issue.find(2).watched_by?(User.find(7))
end
def test_autocomplete_on_watchable_creation
@request.session[:user_id] = 2
get :autocomplete_for_user, :params => {:q => 'mi', :project_id => 'ecookbook'}, :xhr => true
assert_response :success
assert_select 'input', :count => 4
assert_select 'input[name=?][value="1"]', 'watcher[user_ids][]'
assert_select 'input[name=?][value="2"]', 'watcher[user_ids][]'
assert_select 'input[name=?][value="8"]', 'watcher[user_ids][]'
assert_select 'input[name=?][value="9"]', 'watcher[user_ids][]'
end
def test_search_non_member_on_create
@request.session[:user_id] = 2
project = Project.find_by_name("ecookbook")
user = User.generate!(:firstname => 'issue15622')
membership = user.membership(project)
assert_nil membership
get :autocomplete_for_user, :params => {:q => 'issue15622', :project_id => 'ecookbook'}, :xhr => true
assert_response :success
assert_select 'input', :count => 1
end
def test_autocomplete_on_watchable_update
@request.session[:user_id] = 2
get :autocomplete_for_user, :params => {
:object_type => 'issue', :object_id => '2',
:project_id => 'ecookbook', :q => 'mi'
}, :xhr => true
assert_response :success
assert_select 'input', :count => 3
assert_select 'input[name=?][value="2"]', 'watcher[user_ids][]'
assert_select 'input[name=?][value="8"]', 'watcher[user_ids][]'
assert_select 'input[name=?][value="9"]', 'watcher[user_ids][]'
end
def test_search_and_add_non_member_on_update
@request.session[:user_id] = 2
project = Project.find_by_name("ecookbook")
user = User.generate!(:firstname => 'issue15622')
membership = user.membership(project)
assert_nil membership
get :autocomplete_for_user, :params => {
:object_type => 'issue', :object_id => '2',
:project_id => 'ecookbook', :q => 'issue15622'
}, :xhr => true
assert_response :success
assert_select 'input', :count => 1
assert_difference('Watcher.count', 1) do
post :create, :params => {
:object_type => 'issue', :object_id => '2',
:watcher => {:user_ids => ["#{user.id}"]}
}, :xhr => true
assert_response :success
assert_match /watchers/, response.body
assert_match /ajax-modal/, response.body
end
assert Issue.find(2).watched_by?(user)
end
def test_autocomplete_for_user_should_return_visible_users
Role.update_all :users_visibility => 'members_of_visible_projects'
hidden = User.generate!(:lastname => 'autocomplete_hidden')
visible = User.generate!(:lastname => 'autocomplete_visible')
User.add_to_project(visible, Project.find(1))
@request.session[:user_id] = 2
get :autocomplete_for_user, :params => {:q => 'autocomp', :project_id => 'ecookbook'}, :xhr => true
assert_response :success
assert_include visible.name, response.body
assert_not_include hidden.name, response.body
end
def test_append
@request.session[:user_id] = 2
assert_no_difference 'Watcher.count' do
post :append, :params => {
:watcher => {:user_ids => ['4', '7']}, :project_id => 'ecookbook'
}, :xhr => true
assert_response :success
assert_include 'watchers_inputs', response.body
assert_include 'issue[watcher_user_ids][]', response.body
end
end
def test_append_without_user_should_render_nothing
@request.session[:user_id] = 2
post :append, :params => {:project_id => 'ecookbook'}, :xhr => true
assert_response :success
assert response.body.blank?
end
def test_destroy_as_html
@request.session[:user_id] = 2
assert_difference('Watcher.count', -1) do
delete :destroy, :params => {
:object_type => 'issue', :object_id => '2', :user_id => '3'
}
assert_response :success
assert_include 'Watcher removed', response.body
end
assert !Issue.find(2).watched_by?(User.find(3))
end
def test_destroy
@request.session[:user_id] = 2
assert_difference('Watcher.count', -1) do
delete :destroy, :params => {
:object_type => 'issue', :object_id => '2', :user_id => '3'
}, :xhr => true
assert_response :success
assert_match /watchers/, response.body
end
assert !Issue.find(2).watched_by?(User.find(3))
end
def test_destroy_locked_user
user = User.find(3)
user.lock!
assert user.reload.locked?
@request.session[:user_id] = 2
assert_difference('Watcher.count', -1) do
delete :destroy, :params => {
:object_type => 'issue', :object_id => '2', :user_id => '3'
}, :xhr => true
assert_response :success
assert_match /watchers/, response.body
end
assert !Issue.find(2).watched_by?(User.find(3))
end
def test_destroy_invalid_user_should_respond_with_404
@request.session[:user_id] = 2
assert_no_difference('Watcher.count') do
delete :destroy, :params => {
:object_type => 'issue', :object_id => '2', :user_id => '999'
}
assert_response 404
end
end
end

View file

@ -0,0 +1,192 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class WelcomeControllerTest < Redmine::ControllerTest
fixtures :projects, :news, :users, :members
def setup
Setting.default_language = 'en'
User.current = nil
end
def test_index
get :index
assert_response :success
assert_select 'h3', :text => 'Latest news'
end
def test_browser_language
@request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'
get :index
assert_select 'html[lang=fr]'
end
def test_browser_language_alternate
@request.env['HTTP_ACCEPT_LANGUAGE'] = 'zh-TW'
get :index
assert_select 'html[lang=zh-TW]'
end
def test_browser_language_alternate_not_valid
@request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr-CA'
get :index
assert_select 'html[lang=fr]'
end
def test_browser_language_should_be_ignored_with_force_default_language_for_anonymous
@request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'
with_settings :force_default_language_for_anonymous => '1' do
get :index
assert_select 'html[lang=en]'
end
end
def test_user_language_should_be_used
user = User.find(2).update_attribute :language, 'it'
@request.session[:user_id] = 2
@request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'
with_settings :default_language => 'fi' do
get :index
assert_select 'html[lang=it]'
end
end
def test_user_language_should_be_ignored_if_force_default_language_for_loggedin
user = User.find(2).update_attribute :language, 'it'
@request.session[:user_id] = 2
@request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'
with_settings :force_default_language_for_loggedin => '1', :default_language => 'fi' do
get :index
assert_select 'html[lang=fi]'
end
end
def test_robots
get :robots
assert_response :success
assert_equal 'text/plain', @response.content_type
assert @response.body.match(%r{^Disallow: /projects/ecookbook/issues\r?$})
end
def test_warn_on_leaving_unsaved_turn_on
user = User.find(2)
user.pref.warn_on_leaving_unsaved = '1'
user.pref.save!
@request.session[:user_id] = 2
get :index
assert_select 'script', :text => %r{warnLeavingUnsaved}
end
def test_warn_on_leaving_unsaved_turn_off
user = User.find(2)
user.pref.warn_on_leaving_unsaved = '0'
user.pref.save!
@request.session[:user_id] = 2
get :index
assert_select 'script', :text => %r{warnLeavingUnsaved}, :count => 0
end
def test_textarea_font_set_to_monospace
user = User.find(1)
user.pref.textarea_font = 'monospace'
user.pref.save!
@request.session[:user_id] = 1
get :index
assert_select 'body.textarea-monospace'
end
def test_textarea_font_set_to_proportional
user = User.find(1)
user.pref.textarea_font = 'proportional'
user.pref.save!
@request.session[:user_id] = 1
get :index
assert_select 'body.textarea-proportional'
end
def test_logout_link_should_post
@request.session[:user_id] = 2
get :index
assert_select 'a[href="/logout"][data-method=post]', :text => 'Sign out'
end
def test_call_hook_mixed_in
assert @controller.respond_to?(:call_hook)
end
def test_project_jump_box_should_escape_names_once
Project.find(1).update_attribute :name, 'Foo & Bar'
@request.session[:user_id] = 2
get :index
assert_select "#header #project-jump" do
assert_select "a", :text => 'Foo & Bar'
end
end
def test_api_offset_and_limit_without_params
assert_equal [0, 25], @controller.api_offset_and_limit({})
end
def test_api_offset_and_limit_with_limit
assert_equal [0, 30], @controller.api_offset_and_limit({:limit => 30})
assert_equal [0, 100], @controller.api_offset_and_limit({:limit => 120})
assert_equal [0, 25], @controller.api_offset_and_limit({:limit => -10})
end
def test_api_offset_and_limit_with_offset
assert_equal [10, 25], @controller.api_offset_and_limit({:offset => 10})
assert_equal [0, 25], @controller.api_offset_and_limit({:offset => -10})
end
def test_api_offset_and_limit_with_offset_and_limit
assert_equal [10, 50], @controller.api_offset_and_limit({:offset => 10, :limit => 50})
end
def test_api_offset_and_limit_with_page
assert_equal [0, 25], @controller.api_offset_and_limit({:page => 1})
assert_equal [50, 25], @controller.api_offset_and_limit({:page => 3})
assert_equal [0, 25], @controller.api_offset_and_limit({:page => 0})
assert_equal [0, 25], @controller.api_offset_and_limit({:page => -2})
end
def test_api_offset_and_limit_with_page_and_limit
assert_equal [0, 100], @controller.api_offset_and_limit({:page => 1, :limit => 100})
assert_equal [200, 100], @controller.api_offset_and_limit({:page => 3, :limit => 100})
end
def test_unhautorized_exception_with_anonymous_should_redirect_to_login
WelcomeController.any_instance.stubs(:index).raises(::Unauthorized)
get :index
assert_response 302
assert_redirected_to('/login?back_url='+CGI.escape('http://test.host/'))
end
def test_unhautorized_exception_with_anonymous_and_xmlhttprequest_should_respond_with_401_to_anonymous
WelcomeController.any_instance.stubs(:index).raises(::Unauthorized)
@request.env["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest"
get :index
assert_response 401
end
end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,89 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class WikisControllerTest < Redmine::ControllerTest
fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis
def setup
User.current = nil
end
def test_create
@request.session[:user_id] = 1
assert_nil Project.find(3).wiki
assert_difference 'Wiki.count' do
post :edit, :params => {:id => 3, :wiki => { :start_page => 'Start page' }}, :xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
wiki = Project.find(3).wiki
assert_not_nil wiki
assert_equal 'Start page', wiki.start_page
end
def test_create_with_failure
@request.session[:user_id] = 1
assert_no_difference 'Wiki.count' do
post :edit, :params => {:id => 3, :wiki => { :start_page => '' }}, :xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
assert_include 'errorExplanation', response.body
assert_include "Start page cannot be blank", response.body
end
def test_update
@request.session[:user_id] = 1
assert_no_difference 'Wiki.count' do
post :edit, :params => {:id => 1, :wiki => { :start_page => 'Other start page' }}, :xhr => true
assert_response :success
assert_equal 'text/javascript', response.content_type
end
wiki = Project.find(1).wiki
assert_equal 'Other start page', wiki.start_page
end
def test_get_destroy_should_ask_confirmation
@request.session[:user_id] = 1
assert_no_difference 'Wiki.count' do
get :destroy, :params => {:id => 1}
assert_response :success
end
end
def test_post_destroy_should_delete_wiki
@request.session[:user_id] = 1
post :destroy, :params => {:id => 1, :confirm => 1}
assert_redirected_to :controller => 'projects',
:action => 'settings', :id => 'ecookbook', :tab => 'wiki'
assert_nil Project.find(1).wiki
end
def test_not_found
@request.session[:user_id] = 1
post :destroy, :params => {:id => 999, :confirm => 1}
assert_response 404
end
end

View file

@ -0,0 +1,438 @@
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
class WorkflowsControllerTest < Redmine::ControllerTest
fixtures :roles, :trackers, :workflows, :users, :issue_statuses
def setup
User.current = nil
@request.session[:user_id] = 1 # admin
end
def test_index
get :index
assert_response :success
count = WorkflowTransition.where(:role_id => 1, :tracker_id => 2).count
assert_select 'a[href=?]', '/workflows/edit?role_id=1&tracker_id=2', :content => count.to_s
end
def test_get_edit
get :edit
assert_response :success
end
def test_get_edit_with_role_and_tracker
WorkflowTransition.delete_all
WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3)
WorkflowTransition.create!(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 5)
get :edit, :params => {:role_id => 2, :tracker_id => 1}
assert_response :success
# used status only
statuses = IssueStatus.where(:id => [2, 3, 5]).sorted.pluck(:name)
assert_equal ["New issue"] + statuses,
css_select('table.workflows.transitions-always tbody tr td:first').map(&:text).map(&:strip)
# allowed transitions
assert_select 'input[type=checkbox][name=?][value="1"][checked=checked]', 'transitions[3][5][always]'
# not allowed
assert_select 'input[type=checkbox][name=?][value="1"]:not([checked=checked])', 'transitions[3][2][always]'
# unused
assert_select 'input[type=checkbox][name=?]', 'transitions[1][1][always]', 0
end
def test_get_edit_with_role_and_tracker_should_not_include_statuses_from_roles_without_workflow_permissions
WorkflowTransition.delete_all
WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3)
reporter = Role.find(3)
reporter.remove_permission! :edit_issues
reporter.remove_permission! :add_issues
assert !reporter.consider_workflow?
WorkflowTransition.create!(:role_id => 3, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5)
get :edit, :params => {:role_id => 2, :tracker_id => 1}
assert_response :success
# statuses 1 and 5 not displayed
statuses = IssueStatus.where(:id => [2, 3]).sorted.pluck(:name)
assert_equal ["New issue"] + statuses,
css_select('table.workflows.transitions-always tbody tr td:first').map(&:text).map(&:strip)
end
def test_get_edit_should_include_allowed_statuses_for_new_issues
WorkflowTransition.delete_all
WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1)
get :edit, :params => {:role_id => 1, :tracker_id => 1}
assert_response :success
assert_select 'td', 'New issue'
assert_select 'input[type=checkbox][name=?][value="1"][checked=checked]', 'transitions[0][1][always]'
end
def test_get_edit_with_all_roles_and_all_trackers
get :edit, :params => {:role_id => 'all', :tracker_id => 'all'}
assert_response :success
assert_select 'select[name=?][multiple=multiple]', 'role_id[]' do
assert_select 'option[selected=selected]', Role.all.select(&:consider_workflow?).count
end
assert_select 'select[name=?]', 'tracker_id[]' do
assert_select 'option[selected=selected][value=all]'
end
end
def test_get_edit_with_role_and_tracker_and_all_statuses
WorkflowTransition.delete_all
get :edit, :params => {:role_id => 2, :tracker_id => 1, :used_statuses_only => '0'}
assert_response :success
statuses = IssueStatus.all.sorted.pluck(:name)
assert_equal ["New issue"] + statuses,
css_select('table.workflows.transitions-always tbody tr td:first').map(&:text).map(&:strip)
assert_select 'input[type=checkbox][name=?]', 'transitions[1][1][always]'
end
def test_post_edit
WorkflowTransition.delete_all
post :edit, :params => {
:role_id => 2,
:tracker_id => 1,
:transitions => {
'4' => {'5' => {'always' => '1'}},
'3' => {'1' => {'always' => '1'}, '2' => {'always' => '1'}}
}
}
assert_response 302
assert_equal 3, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
assert_not_nil WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2).first
assert_nil WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4).first
end
def test_post_edit_with_allowed_statuses_for_new_issues
WorkflowTransition.delete_all
post :edit, :params => {
:role_id => 2,
:tracker_id => 1,
:transitions => {
'0' => {'1' => {'always' => '1'}, '2' => {'always' => '1'}}
}
}
assert_response 302
assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1).any?
assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 2).any?
assert_equal 2, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
end
def test_post_edit_with_additional_transitions
WorkflowTransition.delete_all
post :edit, :params => {
:role_id => 2,
:tracker_id => 1,
:transitions => {
'4' => {'5' => {'always' => '1', 'author' => '0', 'assignee' => '0'}},
'3' => {'1' => {'always' => '0', 'author' => '1', 'assignee' => '0'},
'2' => {'always' => '0', 'author' => '0', 'assignee' => '1'},
'4' => {'always' => '0', 'author' => '1', 'assignee' => '1'}}
}
}
assert_response 302
assert_equal 4, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 4, :new_status_id => 5).first
assert ! w.author
assert ! w.assignee
w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 1).first
assert w.author
assert ! w.assignee
w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2).first
assert ! w.author
assert w.assignee
w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 4).first
assert w.author
assert w.assignee
end
def test_get_permissions
get :permissions
assert_response :success
end
def test_get_permissions_with_role_and_tracker
WorkflowPermission.delete_all
WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :field_name => 'assigned_to_id', :rule => 'required')
WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :field_name => 'fixed_version_id', :rule => 'required')
WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 3, :field_name => 'fixed_version_id', :rule => 'readonly')
get :permissions, :params => {:role_id => 1, :tracker_id => 2}
assert_response :success
assert_select 'input[name=?][value="1"]', 'role_id[]'
assert_select 'input[name=?][value="2"]', 'tracker_id[]'
# Required field
assert_select 'select[name=?]', 'permissions[2][assigned_to_id]' do
assert_select 'option[value=""]'
assert_select 'option[value=""][selected=selected]', 0
assert_select 'option[value=readonly]', :text => 'Read-only'
assert_select 'option[value=readonly][selected=selected]', 0
assert_select 'option[value=required]', :text => 'Required'
assert_select 'option[value=required][selected=selected]'
end
# Read-only field
assert_select 'select[name=?]', 'permissions[3][fixed_version_id]' do
assert_select 'option[value=""]'
assert_select 'option[value=""][selected=selected]', 0
assert_select 'option[value=readonly]', :text => 'Read-only'
assert_select 'option[value=readonly][selected=selected]'
assert_select 'option[value=required]', :text => 'Required'
assert_select 'option[value=required][selected=selected]', 0
end
# Other field
assert_select 'select[name=?]', 'permissions[3][due_date]' do
assert_select 'option[value=""]'
assert_select 'option[value=""][selected=selected]', 0
assert_select 'option[value=readonly]', :text => 'Read-only'
assert_select 'option[value=readonly][selected=selected]', 0
assert_select 'option[value=required]', :text => 'Required'
assert_select 'option[value=required][selected=selected]', 0
end
end
def test_get_permissions_with_required_custom_field_should_not_show_required_option
cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :tracker_ids => [1], :is_required => true)
get :permissions, :params => {:role_id => 1, :tracker_id => 1}
assert_response :success
# Custom field that is always required
# The default option is "(Required)"
assert_select 'select[name=?]', "permissions[3][#{cf.id}]" do
assert_select 'option[value=""]'
assert_select 'option[value=readonly]', :text => 'Read-only'
assert_select 'option[value=required]', 0
end
end
def test_get_permissions_should_disable_hidden_custom_fields
cf1 = IssueCustomField.generate!(:tracker_ids => [1], :visible => true)
cf2 = IssueCustomField.generate!(:tracker_ids => [1], :visible => false, :role_ids => [1])
cf3 = IssueCustomField.generate!(:tracker_ids => [1], :visible => false, :role_ids => [1, 2])
get :permissions, :params => {:role_id => 2, :tracker_id => 1}
assert_response :success
assert_select 'select[name=?]:not(.disabled)', "permissions[1][#{cf1.id}]"
assert_select 'select[name=?]:not(.disabled)', "permissions[1][#{cf3.id}]"
assert_select 'select[name=?][disabled=disabled]', "permissions[1][#{cf2.id}]" do
assert_select 'option[value=""][selected=selected]', :text => 'Hidden'
end
end
def test_get_permissions_with_missing_permissions_for_roles_should_default_to_no_change
WorkflowPermission.delete_all
WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
get :permissions, :params => {:role_id => [1, 2], :tracker_id => 2}
assert_response :success
assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
assert_select 'option[selected]', 1
assert_select 'option[selected][value=no_change]'
end
end
def test_get_permissions_with_different_permissions_for_roles_should_default_to_no_change
WorkflowPermission.delete_all
WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
WorkflowPermission.create!(:role_id => 2, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'readonly')
get :permissions, :params => {:role_id => [1, 2], :tracker_id => 2}
assert_response :success
assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
assert_select 'option[selected]', 1
assert_select 'option[selected][value=no_change]'
end
end
def test_get_permissions_with_same_permissions_for_roles_should_default_to_permission
WorkflowPermission.delete_all
WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
WorkflowPermission.create!(:role_id => 2, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
get :permissions, :params => {:role_id => [1, 2], :tracker_id => 2}
assert_response :success
assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
assert_select 'option[selected]', 1
assert_select 'option[selected][value=required]'
end
end
def test_get_permissions_with_role_and_tracker_and_all_statuses_should_show_all_statuses
WorkflowTransition.delete_all
get :permissions, :params => {:role_id => 1, :tracker_id => 2, :used_statuses_only => '0'}
assert_response :success
statuses = IssueStatus.all.sorted.pluck(:name)
assert_equal statuses,
css_select('table.workflows.fields_permissions thead tr:nth-child(2) td:not(:first-child)').map(&:text).map(&:strip)
end
def test_get_permissions_should_set_css_class
WorkflowPermission.delete_all
WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :tracker_ids => [2])
WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => cf.id, :rule => 'required')
get :permissions, :params => {:role_id => 1, :tracker_id => 2}
assert_response :success
assert_select 'td.required > select[name=?]', 'permissions[1][assigned_to_id]'
assert_select 'td.required > select[name=?]', "permissions[1][#{cf.id}]"
end
def test_post_permissions
WorkflowPermission.delete_all
post :permissions, :params => {
:role_id => 1,
:tracker_id => 2,
:permissions => {
'1' => {'assigned_to_id' => '', 'fixed_version_id' => 'required', 'due_date' => ''},
'2' => {'assigned_to_id' => 'readonly', 'fixed_version_id' => 'readonly', 'due_date' => ''},
'3' => {'assigned_to_id' => '', 'fixed_version_id' => '', 'due_date' => ''}
}
}
assert_response 302
workflows = WorkflowPermission.all
assert_equal 3, workflows.size
workflows.each do |workflow|
assert_equal 1, workflow.role_id
assert_equal 2, workflow.tracker_id
end
assert workflows.detect {|wf| wf.old_status_id == 2 && wf.field_name == 'assigned_to_id' && wf.rule == 'readonly'}
assert workflows.detect {|wf| wf.old_status_id == 1 && wf.field_name == 'fixed_version_id' && wf.rule == 'required'}
assert workflows.detect {|wf| wf.old_status_id == 2 && wf.field_name == 'fixed_version_id' && wf.rule == 'readonly'}
end
def test_get_copy
get :copy
assert_response :success
assert_select 'select[name=source_tracker_id]' do
assert_select 'option[value="1"]', :text => 'Bug'
end
assert_select 'select[name=source_role_id]' do
assert_select 'option[value="2"]', :text => 'Developer'
end
assert_select 'select[name=?]', 'target_tracker_ids[]' do
assert_select 'option[value="3"]', :text => 'Support request'
end
assert_select 'select[name=?]', 'target_role_ids[]' do
assert_select 'option[value="1"]', :text => 'Manager'
end
end
def test_post_copy_one_to_one
source_transitions = status_transitions(:tracker_id => 1, :role_id => 2)
post :copy, :params => {
:source_tracker_id => '1', :source_role_id => '2',
:target_tracker_ids => ['3'], :target_role_ids => ['1']
}
assert_response 302
assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1)
end
def test_post_copy_one_to_many
source_transitions = status_transitions(:tracker_id => 1, :role_id => 2)
post :copy, :params => {
:source_tracker_id => '1', :source_role_id => '2',
:target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
}
assert_response 302
assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 1)
assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1)
assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 3)
assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 3)
end
def test_post_copy_many_to_many
source_t2 = status_transitions(:tracker_id => 2, :role_id => 2)
source_t3 = status_transitions(:tracker_id => 3, :role_id => 2)
post :copy, :params => {
:source_tracker_id => 'any', :source_role_id => '2',
:target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
}
assert_response 302
assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 1)
assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 1)
assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 3)
assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 3)
end
def test_post_copy_with_incomplete_source_specification_should_fail
assert_no_difference 'WorkflowRule.count' do
post :copy, :params => {
:source_tracker_id => '', :source_role_id => '2',
:target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
}
assert_response 200
assert_select 'div.flash.error', :text => 'Please select a source tracker or role'
end
end
def test_post_copy_with_incomplete_target_specification_should_fail
assert_no_difference 'WorkflowRule.count' do
post :copy, :params => {
:source_tracker_id => '1', :source_role_id => '2',
:target_tracker_ids => ['2', '3']
}
assert_response 200
assert_select 'div.flash.error', :text => 'Please select target tracker(s) and role(s)'
end
end
# Returns an array of status transitions that can be compared
def status_transitions(conditions)
WorkflowTransition.
where(conditions).
order('tracker_id, role_id, old_status_id, new_status_id').
collect {|w| [w.old_status, w.new_status_id]}
end
end