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

197
test/unit/activity_test.rb Normal file
View file

@ -0,0 +1,197 @@
# 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 ActivityTest < ActiveSupport::TestCase
fixtures :projects, :versions, :attachments, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
:trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, :time_entries,
:wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
def setup
@project = Project.find(1)
end
def test_activity_without_subprojects
events = find_events(User.anonymous, :project => @project)
assert_not_nil events
assert events.include?(Issue.find(1))
assert !events.include?(Issue.find(4))
# subproject issue
assert !events.include?(Issue.find(5))
end
def test_activity_with_subprojects
events = find_events(User.anonymous, :project => @project, :with_subprojects => 1)
assert_not_nil events
assert events.include?(Issue.find(1))
# subproject issue
assert events.include?(Issue.find(5))
end
def test_global_activity_anonymous
events = find_events(User.anonymous)
assert_not_nil events
assert events.include?(Issue.find(1))
assert events.include?(Message.find(5))
# Issue of a private project
assert !events.include?(Issue.find(4))
# Private issue and comment
assert !events.include?(Issue.find(14))
assert !events.include?(Journal.find(5))
end
def test_global_activity_logged_user
events = find_events(User.find(2)) # manager
assert_not_nil events
assert events.include?(Issue.find(1))
# Issue of a private project the user belongs to
assert events.include?(Issue.find(4))
end
def test_user_activity
user = User.find(2)
events = Redmine::Activity::Fetcher.new(User.anonymous, :author => user).events(nil, nil, :limit => 10)
assert(events.size > 0)
assert(events.size <= 10)
assert_nil(events.detect {|e| e.event_author != user})
end
def test_journal_with_notes_and_changes_should_be_returned_once
f = Redmine::Activity::Fetcher.new(User.anonymous, :project => Project.find(1))
f.scope = ['issues']
events = f.events
assert_equal events, events.uniq
end
def test_files_activity
f = Redmine::Activity::Fetcher.new(User.anonymous, :project => Project.find(1))
f.scope = ['files']
events = f.events
assert_kind_of Array, events
assert events.include?(Attachment.find_by_container_type_and_container_id('Project', 1))
assert events.include?(Attachment.find_by_container_type_and_container_id('Version', 1))
assert_equal [Attachment], events.collect(&:class).uniq
assert_equal %w(Project Version), events.collect(&:container_type).uniq.sort
end
def test_event_group_for_issue
issue = Issue.find(1)
assert_equal issue, issue.event_group
end
def test_event_group_for_journal
issue = Issue.find(1)
journal = issue.journals.first
assert_equal issue, journal.event_group
end
def test_event_group_for_issue_time_entry
time = TimeEntry.where(:issue_id => 1).first
assert_equal time.issue, time.event_group
end
def test_event_group_for_project_time_entry
time = TimeEntry.where(:issue_id => nil).first
assert_equal time, time.event_group
end
def test_event_group_for_message
message = Message.find(1)
reply = message.children.first
assert_equal message, message.event_group
assert_equal message, reply.event_group
end
def test_event_group_for_wiki_content_version
content = WikiContent::Version.find(1)
assert_equal content.page, content.event_group
end
class TestActivityProviderWithPermission
def self.activity_provider_options
{'test' => {:permission => :custom_permission}}
end
end
class TestActivityProviderWithNilPermission
def self.activity_provider_options
{'test' => {:permission => nil}}
end
end
class TestActivityProviderWithoutPermission
def self.activity_provider_options
{'test' => {}}
end
end
class MockUser
def initialize(*permissions)
@permissions = permissions
end
def allowed_to?(permission, *args)
@permissions.include?(permission)
end
end
def test_event_types_should_consider_activity_provider_permission
Redmine::Activity.register 'test', :class_name => 'ActivityTest::TestActivityProviderWithPermission'
user = MockUser.new(:custom_permission)
f = Redmine::Activity::Fetcher.new(user, :project => Project.find(1))
assert_include 'test', f.event_types
ensure
Redmine::Activity.delete 'test'
end
def test_event_types_should_include_activity_provider_with_nil_permission
Redmine::Activity.register 'test', :class_name => 'ActivityTest::TestActivityProviderWithNilPermission'
user = MockUser.new()
f = Redmine::Activity::Fetcher.new(user, :project => Project.find(1))
assert_include 'test', f.event_types
ensure
Redmine::Activity.delete 'test'
end
def test_event_types_should_use_default_permission_for_activity_provider_without_permission
Redmine::Activity.register 'test', :class_name => 'ActivityTest::TestActivityProviderWithoutPermission'
user = MockUser.new()
f = Redmine::Activity::Fetcher.new(user, :project => Project.find(1))
assert_not_include 'test', f.event_types
user = MockUser.new(:view_test)
f = Redmine::Activity::Fetcher.new(user, :project => Project.find(1))
assert_include 'test', f.event_types
ensure
Redmine::Activity.delete 'test'
end
private
def find_events(user, options={})
Redmine::Activity::Fetcher.new(user, options).events(Date.today - 30, Date.today + 1)
end
end

View file

@ -0,0 +1,450 @@
# 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 AttachmentTest < ActiveSupport::TestCase
fixtures :users, :email_addresses, :projects, :roles, :members, :member_roles,
:enabled_modules, :issues, :trackers, :attachments
# TODO: remove this with Rails 5 that supports after_commit callbacks
# in transactional fixtures (https://github.com/rails/rails/pull/18458)
self.use_transactional_fixtures = false
def setup
set_tmp_attachments_directory
end
def test_container_for_new_attachment_should_be_nil
assert_nil Attachment.new.container
end
def test_filename_should_remove_eols
assert_equal "line_feed", Attachment.new(:filename => "line\nfeed").filename
assert_equal "line_feed", Attachment.new(:filename => "some\npath/line\nfeed").filename
assert_equal "carriage_return", Attachment.new(:filename => "carriage\rreturn").filename
assert_equal "carriage_return", Attachment.new(:filename => "some\rpath/carriage\rreturn").filename
end
def test_create
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1))
assert a.save
assert_equal 'testfile.txt', a.filename
assert_equal 59, a.filesize
assert_equal 'text/plain', a.content_type
assert_equal 0, a.downloads
assert_equal '6bc2eb7e87cfbf9145065689aaa8b5f513089ca0af68e2dc41f9cc025473d106', a.digest
assert a.disk_directory
assert_match %r{\A\d{4}/\d{2}\z}, a.disk_directory
assert File.exist?(a.diskfile)
assert_equal 59, File.size(a.diskfile)
end
def test_create_should_clear_content_type_if_too_long
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1),
:content_type => 'a'*300)
assert a.save
a.reload
assert_nil a.content_type
end
def test_shorted_filename_if_too_long
file = mock_file_with_options(:original_filename => "#{'a'*251}.txt")
a = Attachment.new(:container => Issue.find(1),
:file => file,
:author => User.find(1))
assert a.save
a.reload
assert_equal 12 + 1 + 32 + 4, a.disk_filename.length
assert_equal 255, a.filename.length
end
def test_copy_should_preserve_attributes
# prevent re-use of data from other attachments with equal contents
Attachment.where('id <> 1').destroy_all
a = Attachment.find(1)
copy = a.copy
assert_save copy
copy = Attachment.order('id DESC').first
%w(filename filesize content_type author_id created_on description digest disk_filename disk_directory diskfile).each do |attribute|
assert_equal a.send(attribute), copy.send(attribute), "#{attribute} was different"
end
end
def test_size_should_be_validated_for_new_file
with_settings :attachment_max_size => 0 do
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1))
assert !a.save
end
end
def test_size_should_not_be_validated_when_copying
a = Attachment.create!(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1))
with_settings :attachment_max_size => 0 do
copy = a.copy
assert copy.save
end
end
def test_filesize_greater_than_2gb_should_be_supported
with_settings :attachment_max_size => (50.gigabyte / 1024) do
a = Attachment.create!(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1))
a.filesize = 20.gigabyte
a.save!
assert_equal 20.gigabyte, a.reload.filesize
end
end
def test_extension_should_be_validated_against_allowed_extensions
with_settings :attachment_extensions_allowed => "txt, png" do
a = Attachment.new(:container => Issue.find(1),
:file => mock_file_with_options(:original_filename => "test.png"),
:author => User.find(1))
assert_save a
a = Attachment.new(:container => Issue.find(1),
:file => mock_file_with_options(:original_filename => "test.jpeg"),
:author => User.find(1))
assert !a.save
end
end
def test_extension_should_be_validated_against_denied_extensions
with_settings :attachment_extensions_denied => "txt, png" do
a = Attachment.new(:container => Issue.find(1),
:file => mock_file_with_options(:original_filename => "test.jpeg"),
:author => User.find(1))
assert_save a
a = Attachment.new(:container => Issue.find(1),
:file => mock_file_with_options(:original_filename => "test.png"),
:author => User.find(1))
assert !a.save
end
end
def test_valid_extension_should_be_case_insensitive
with_settings :attachment_extensions_allowed => "txt, Png" do
assert Attachment.valid_extension?(".pnG")
assert !Attachment.valid_extension?(".jpeg")
end
with_settings :attachment_extensions_denied => "txt, Png" do
assert !Attachment.valid_extension?(".pnG")
assert Attachment.valid_extension?(".jpeg")
end
end
def test_description_length_should_be_validated
a = Attachment.new(:description => 'a' * 300)
assert !a.save
assert_not_equal [], a.errors[:description]
end
def test_destroy
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1))
assert a.save
assert_equal 'testfile.txt', a.filename
assert_equal 59, a.filesize
assert_equal 'text/plain', a.content_type
assert_equal 0, a.downloads
assert_equal '6bc2eb7e87cfbf9145065689aaa8b5f513089ca0af68e2dc41f9cc025473d106', a.digest
diskfile = a.diskfile
assert File.exist?(diskfile)
assert_equal 59, File.size(a.diskfile)
assert a.destroy
assert !File.exist?(diskfile)
end
def test_destroy_should_not_delete_file_referenced_by_other_attachment
a = Attachment.create!(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1))
diskfile = a.diskfile
copy = a.copy
copy.save!
assert File.exists?(diskfile)
a.destroy
assert File.exists?(diskfile)
copy.destroy
assert !File.exists?(diskfile)
end
def test_create_should_auto_assign_content_type
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", ""),
:author => User.find(1))
assert a.save
assert_equal 'text/plain', a.content_type
end
def test_attachments_with_same_content_should_reuse_same_file
a1 = Attachment.create!(:container => Issue.find(1), :author => User.find(1),
:file => mock_file(:filename => 'foo', :content => 'abcd'))
a2 = Attachment.create!(:container => Issue.find(1), :author => User.find(1),
:file => mock_file(:filename => 'bar', :content => 'abcd'))
assert_equal a1.diskfile, a2.diskfile
end
def test_attachments_with_same_content_should_not_reuse_same_file_if_deleted
a1 = Attachment.create!(:container => Issue.find(1), :author => User.find(1),
:file => mock_file(:filename => 'foo', :content => 'abcd'))
a1.delete_from_disk
a2 = Attachment.create!(:container => Issue.find(1), :author => User.find(1),
:file => mock_file(:filename => 'bar', :content => 'abcd'))
assert_not_equal a1.diskfile, a2.diskfile
end
def test_attachments_with_same_filename_at_the_same_time_should_not_overwrite
a1 = Attachment.create!(:container => Issue.find(1), :author => User.find(1),
:file => mock_file(:filename => 'foo', :content => 'abcd'))
a2 = Attachment.create!(:container => Issue.find(1), :author => User.find(1),
:file => mock_file(:filename => 'foo', :content => 'efgh'))
assert_not_equal a1.diskfile, a2.diskfile
end
def test_filename_should_be_basenamed
a = Attachment.new(:file => mock_file(:original_filename => "path/to/the/file"))
assert_equal 'file', a.filename
end
def test_filename_should_be_sanitized
a = Attachment.new(:file => mock_file(:original_filename => "valid:[] invalid:?%*|\"'<>chars"))
assert_equal 'valid_[] invalid_chars', a.filename
end
def test_diskfilename
assert Attachment.disk_filename("test_file.txt") =~ /^\d{12}_test_file.txt$/
assert_equal 'test_file.txt', Attachment.disk_filename("test_file.txt")[13..-1]
assert_equal '770c509475505f37c2b8fb6030434d6b.txt', Attachment.disk_filename("test_accentué.txt")[13..-1]
assert_equal 'f8139524ebb8f32e51976982cd20a85d', Attachment.disk_filename("test_accentué")[13..-1]
assert_equal 'cbb5b0f30978ba03731d61f9f6d10011', Attachment.disk_filename("test_accentué.ça")[13..-1]
end
def test_title
a = Attachment.new(:filename => "test.png")
assert_equal "test.png", a.title
a = Attachment.new(:filename => "test.png", :description => "Cool image")
assert_equal "test.png (Cool image)", a.title
end
def test_new_attachment_should_be_editable_by_author
user = User.find(1)
a = Attachment.new(:author => user)
assert_equal true, a.editable?(user)
end
def test_prune_should_destroy_old_unattached_attachments
Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1, :created_on => 2.days.ago)
Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1, :created_on => 2.days.ago)
Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1)
assert_difference 'Attachment.count', -2 do
Attachment.prune
end
end
def test_move_from_root_to_target_directory_should_move_root_files
a = Attachment.find(20)
assert a.disk_directory.blank?
# Create a real file for this fixture
File.open(a.diskfile, "w") do |f|
f.write "test file at the root of files directory"
end
assert a.readable?
Attachment.move_from_root_to_target_directory
a.reload
assert_equal '2012/05', a.disk_directory
assert a.readable?
end
test "Attachmnet.attach_files should attach the file" do
issue = Issue.first
assert_difference 'Attachment.count' do
Attachment.attach_files(issue,
'1' => {
'file' => uploaded_test_file('testfile.txt', 'text/plain'),
'description' => 'test'
})
end
attachment = Attachment.order('id DESC').first
assert_equal issue, attachment.container
assert_equal 'testfile.txt', attachment.filename
assert_equal 59, attachment.filesize
assert_equal 'test', attachment.description
assert_equal 'text/plain', attachment.content_type
assert File.exists?(attachment.diskfile)
assert_equal 59, File.size(attachment.diskfile)
end
test "Attachmnet.attach_files should add unsaved files to the object as unsaved attachments" do
# Max size of 0 to force Attachment creation failures
with_settings(:attachment_max_size => 0) do
@project = Project.find(1)
response = Attachment.attach_files(@project, {
'1' => {'file' => mock_file, 'description' => 'test'},
'2' => {'file' => mock_file, 'description' => 'test'}
})
assert response[:unsaved].present?
assert_equal 2, response[:unsaved].length
assert response[:unsaved].first.new_record?
assert response[:unsaved].second.new_record?
assert_equal response[:unsaved], @project.unsaved_attachments
end
end
test "Attachment.attach_files should preserve the content_type of attachments added by token" do
@project = Project.find(1)
attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1, :created_on => 2.days.ago)
assert_equal 'text/plain', attachment.content_type
Attachment.attach_files(@project, { '1' => {'token' => attachment.token } })
attachment.reload
assert_equal 'text/plain', attachment.content_type
end
def test_update_digest_to_sha256_should_update_digest
set_fixtures_attachments_directory
attachment = Attachment.find 6
assert attachment.readable?
attachment.update_digest_to_sha256!
assert_equal 'ac5c6e99a21ae74b2e3f5b8e5b568be1b9107cd7153d139e822b9fe5caf50938', attachment.digest
end
def test_update_attachments
attachments = Attachment.where(:id => [2, 3]).to_a
assert Attachment.update_attachments(attachments, {
'2' => {:filename => 'newname.txt', :description => 'New description'},
3 => {:filename => 'othername.txt'}
})
attachment = Attachment.find(2)
assert_equal 'newname.txt', attachment.filename
assert_equal 'New description', attachment.description
attachment = Attachment.find(3)
assert_equal 'othername.txt', attachment.filename
end
def test_update_attachments_with_failure
attachments = Attachment.where(:id => [2, 3]).to_a
assert !Attachment.update_attachments(attachments, {
'2' => {:filename => '', :description => 'New description'},
3 => {:filename => 'othername.txt'}
})
attachment = Attachment.find(3)
assert_equal 'logo.gif', attachment.filename
end
def test_update_attachments_should_sanitize_filename
attachments = Attachment.where(:id => 2).to_a
assert Attachment.update_attachments(attachments, {
2 => {:filename => 'newname?.txt'},
})
attachment = Attachment.find(2)
assert_equal 'newname_.txt', attachment.filename
end
def test_latest_attach
set_fixtures_attachments_directory
a1 = Attachment.find(16)
assert_equal "testfile.png", a1.filename
assert a1.readable?
assert (! a1.visible?(User.anonymous))
assert a1.visible?(User.find(2))
a2 = Attachment.find(17)
assert_equal "testfile.PNG", a2.filename
assert a2.readable?
assert (! a2.visible?(User.anonymous))
assert a2.visible?(User.find(2))
assert a1.created_on < a2.created_on
la1 = Attachment.latest_attach([a1, a2], "testfile.png")
assert_equal 17, la1.id
la2 = Attachment.latest_attach([a1, a2], "Testfile.PNG")
assert_equal 17, la2.id
set_tmp_attachments_directory
end
def test_latest_attach_should_not_error_with_string_with_invalid_encoding
string = "width:50\xFE-Image.jpg".force_encoding('UTF-8')
assert_equal false, string.valid_encoding?
Attachment.latest_attach(Attachment.limit(2).to_a, string)
end
def test_thumbnailable_should_be_true_for_images
assert_equal true, Attachment.new(:filename => 'test.jpg').thumbnailable?
end
def test_thumbnailable_should_be_true_for_non_images
assert_equal false, Attachment.new(:filename => 'test.txt').thumbnailable?
end
if convert_installed?
def test_thumbnail_should_generate_the_thumbnail
set_fixtures_attachments_directory
attachment = Attachment.find(16)
Attachment.clear_thumbnails
assert_difference "Dir.glob(File.join(Attachment.thumbnails_storage_path, '*.thumb')).size" do
thumbnail = attachment.thumbnail
assert_equal "16_8e0294de2441577c529f170b6fb8f638_100.thumb", File.basename(thumbnail)
assert File.exists?(thumbnail)
end
end
def test_thumbnail_should_return_nil_if_generation_fails
Redmine::Thumbnail.expects(:generate).raises(SystemCallError, 'Something went wrong')
set_fixtures_attachments_directory
attachment = Attachment.find(16)
assert_nil attachment.thumbnail
end
else
puts '(ImageMagick convert not available)'
end
end

View file

@ -0,0 +1,76 @@
# 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 AttachmentTest < ActiveSupport::TestCase
fixtures :users, :email_addresses, :projects, :roles, :members, :member_roles,
:enabled_modules, :issues, :trackers, :attachments
self.use_transactional_fixtures = false
def setup
set_tmp_attachments_directory
end
def test_rollback_after_create_should_remove_file_from_disk
diskfile = nil
Attachment.transaction do
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1))
a.save!
diskfile = a.diskfile
assert File.exist?(diskfile)
raise ActiveRecord::Rollback
end
assert !File.exist?(diskfile)
end
def test_destroy_should_remove_file_from_disk_after_commit
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1))
a.save!
diskfile = a.diskfile
assert File.exist?(diskfile)
Attachment.transaction do
a.destroy
assert File.exist?(diskfile)
end
assert !File.exist?(diskfile)
end
def test_rollback_after_destroy_should_not_remove_file_from_disk
a = Attachment.new(:container => Issue.find(1),
:file => uploaded_test_file("testfile.txt", "text/plain"),
:author => User.find(1))
a.save!
diskfile = a.diskfile
assert File.exist?(diskfile)
Attachment.transaction do
a.destroy
raise ActiveRecord::Rollback
end
assert File.exist?(diskfile)
end
end

View file

@ -0,0 +1,234 @@
# 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 AuthSourceLdapTest < ActiveSupport::TestCase
include Redmine::I18n
fixtures :auth_sources
def setup
end
def test_initialize
auth_source = AuthSourceLdap.new
assert_nil auth_source.id
assert_equal "AuthSourceLdap", auth_source.type
assert_equal "", auth_source.name
assert_nil auth_source.host
assert_nil auth_source.port
assert_nil auth_source.account
assert_equal "", auth_source.account_password
assert_nil auth_source.base_dn
assert_nil auth_source.attr_login
assert_nil auth_source.attr_firstname
assert_nil auth_source.attr_lastname
assert_nil auth_source.attr_mail
assert_equal false, auth_source.onthefly_register
assert_equal false, auth_source.tls
assert_nil auth_source.filter
assert_nil auth_source.timeout
end
def test_create
a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName')
assert a.save
end
def test_should_strip_ldap_attributes
a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName',
:attr_firstname => 'givenName ')
assert a.save
assert_equal 'givenName', a.reload.attr_firstname
end
def test_replace_port_zero_to_389
a = AuthSourceLdap.new(
:name => 'My LDAP', :host => 'ldap.example.net', :port => 0,
:base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName',
:attr_firstname => 'givenName ')
assert a.save
assert_equal 389, a.port
end
def test_filter_should_be_validated
set_language_if_valid 'en'
a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :attr_login => 'sn')
a.filter = "(mail=*@redmine.org"
assert !a.valid?
assert_include "LDAP filter is invalid", a.errors.full_messages
a.filter = "(mail=*@redmine.org)"
assert a.valid?
end
if ldap_configured?
test '#authenticate with a valid LDAP user should return the user attributes' do
auth = AuthSourceLdap.find(1)
auth.update_attribute :onthefly_register, true
attributes = auth.authenticate('example1','123456')
assert attributes.is_a?(Hash), "An hash was not returned"
assert_equal 'Example', attributes[:firstname]
assert_equal 'One', attributes[:lastname]
assert_equal 'example1@redmine.org', attributes[:mail]
assert_equal auth.id, attributes[:auth_source_id]
attributes.keys.each do |attribute|
assert User.new.respond_to?("#{attribute}="), "Unexpected :#{attribute} attribute returned"
end
end
test '#authenticate with an invalid LDAP user should return nil' do
auth = AuthSourceLdap.find(1)
assert_nil auth.authenticate('nouser','123456')
end
test '#authenticate without a login should return nil' do
auth = AuthSourceLdap.find(1)
assert_nil auth.authenticate('','123456')
end
test '#authenticate without a password should return nil' do
auth = AuthSourceLdap.find(1)
assert_nil auth.authenticate('edavis','')
end
test '#authenticate without filter should return any user' do
auth = AuthSourceLdap.find(1)
assert auth.authenticate('example1','123456')
assert auth.authenticate('edavis', '123456')
end
test '#authenticate with filter should return user who matches the filter only' do
auth = AuthSourceLdap.find(1)
auth.filter = "(mail=*@redmine.org)"
assert auth.authenticate('example1','123456')
assert_nil auth.authenticate('edavis', '123456')
end
def test_authenticate_should_timeout
auth_source = AuthSourceLdap.find(1)
auth_source.timeout = 1
def auth_source.initialize_ldap_con(*args); sleep(5); end
assert_raise AuthSourceTimeoutException do
auth_source.authenticate 'example1', '123456'
end
end
def test_search_should_return_matching_entries
results = AuthSource.search("exa")
assert_equal 1, results.size
result = results.first
assert_kind_of Hash, result
assert_equal "example1", result[:login]
assert_equal "Example", result[:firstname]
assert_equal "One", result[:lastname]
assert_equal "example1@redmine.org", result[:mail]
assert_equal 1, result[:auth_source_id]
end
def test_search_with_no_match_should_return_an_empty_array
results = AuthSource.search("wro")
assert_equal [], results
end
def test_search_with_exception_should_return_an_empty_array
Net::LDAP.stubs(:new).raises(Net::LDAP::LdapError, 'Cannot connect')
results = AuthSource.search("exa")
assert_equal [], results
end
def test_test_connection_with_correct_host_and_port
auth_source = AuthSourceLdap.find(1)
assert_nothing_raised Net::LDAP::Error do
auth_source.test_connection
end
end
def test_test_connection_with_incorrect_host
auth_source = AuthSourceLdap.find(1)
auth_source.host = "badhost"
auth_source.save!
assert_raise Net::LDAP::Error do
auth_source.test_connection
end
end
def test_test_connection_with_incorrect_port
auth_source = AuthSourceLdap.find(1)
auth_source.port = 1234
auth_source.save!
assert_raise Net::LDAP::Error do
auth_source.test_connection
end
end
def test_test_connection_bind_with_account_and_password
auth_source = AuthSourceLdap.find(1)
auth_source.account = "cn=admin,dc=redmine,dc=org"
auth_source.account_password = "secret"
auth_source.save!
assert_equal "cn=admin,dc=redmine,dc=org", auth_source.account
assert_equal "secret", auth_source.account_password
assert_nil auth_source.test_connection
end
def test_test_connection_bind_without_account_and_password
auth_source = AuthSourceLdap.find(1)
assert_nil auth_source.account
assert_equal "", auth_source.account_password
assert_nil auth_source.test_connection
end
def test_test_connection_bind_with_incorrect_account
auth_source = AuthSourceLdap.find(1)
auth_source.account = "cn=baduser,dc=redmine,dc=org"
auth_source.account_password = "secret"
auth_source.save!
assert_equal "cn=baduser,dc=redmine,dc=org", auth_source.account
assert_equal "secret", auth_source.account_password
assert_raise AuthSourceException do
auth_source.test_connection
end
end
def test_test_connection_bind_with_incorrect_password
auth_source = AuthSourceLdap.find(1)
auth_source.account = "cn=admin,dc=redmine,dc=org"
auth_source.account_password = "badpassword"
auth_source.save!
assert_equal "cn=admin,dc=redmine,dc=org", auth_source.account
assert_equal "badpassword", auth_source.account_password
assert_raise AuthSourceException do
auth_source.test_connection
end
end
else
puts '(Test LDAP server not configured)'
end
end

125
test/unit/board_test.rb Normal file
View file

@ -0,0 +1,125 @@
# 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 BoardTest < ActiveSupport::TestCase
fixtures :projects, :boards, :messages, :attachments, :watchers
include Redmine::I18n
def setup
@project = Project.find(1)
end
def test_create
board = Board.new(:project => @project, :name => 'Test board', :description => 'Test board description')
assert board.save
board.reload
assert_equal 'Test board', board.name
assert_equal 'Test board description', board.description
assert_equal @project, board.project
assert_equal 0, board.topics_count
assert_equal 0, board.messages_count
assert_nil board.last_message
# last position
assert_equal @project.boards.size, board.position
end
def test_parent_should_be_in_same_project
set_language_if_valid 'en'
board = Board.new(:project_id => 3, :name => 'Test', :description => 'Test', :parent_id => 1)
assert !board.save
assert_include "Parent forum is invalid", board.errors.full_messages
end
def test_valid_parents_should_not_include_self_nor_a_descendant
board1 = Board.generate!(:project_id => 3)
board2 = Board.generate!(:project_id => 3, :parent => board1)
board3 = Board.generate!(:project_id => 3, :parent => board2)
board4 = Board.generate!(:project_id => 3)
assert_equal [board4], board1.reload.valid_parents.sort_by(&:id)
assert_equal [board1, board4], board2.reload.valid_parents.sort_by(&:id)
assert_equal [board1, board2, board4], board3.reload.valid_parents.sort_by(&:id)
assert_equal [board1, board2, board3], board4.reload.valid_parents.sort_by(&:id)
end
def test_position_should_be_assigned_with_parent_scope
parent1 = Board.generate!(:project_id => 3)
parent2 = Board.generate!(:project_id => 3)
child1 = Board.generate!(:project_id => 3, :parent => parent1)
child2 = Board.generate!(:project_id => 3, :parent => parent1)
assert_equal 1, parent1.reload.position
assert_equal 1, child1.reload.position
assert_equal 2, child2.reload.position
assert_equal 2, parent2.reload.position
end
def test_board_tree_should_yield_boards_with_level
parent1 = Board.generate!(:project_id => 3)
parent2 = Board.generate!(:project_id => 3)
child1 = Board.generate!(:project_id => 3, :parent => parent1)
child2 = Board.generate!(:project_id => 3, :parent => parent1)
child3 = Board.generate!(:project_id => 3, :parent => child1)
tree = Board.board_tree(Project.find(3).boards)
assert_equal [
[parent1, 0],
[child1, 1],
[child3, 2],
[child2, 1],
[parent2, 0]
], tree
end
def test_destroy
board = Board.find(1)
assert_difference 'Message.count', -6 do
assert_difference 'Attachment.count', -1 do
assert_difference 'Watcher.count', -1 do
assert board.destroy
end
end
end
assert_equal 0, Message.where(:board_id => 1).count
end
def test_destroy_should_nullify_children
parent = Board.generate!(:project => @project)
child = Board.generate!(:project => @project, :parent => parent)
assert_equal parent, child.parent
assert parent.destroy
child.reload
assert_nil child.parent
assert_nil child.parent_id
end
def test_reset_counters_should_update_attributes
Board.where(:id => 1).update_all(:topics_count => 0, :messages_count => 0, :last_message_id => 0)
Board.reset_counters!(1)
board = Board.find(1)
assert_equal board.topics.count, board.topics_count
assert_equal board.messages.count, board.messages_count
assert_equal board.messages.order("id DESC").first.id, board.last_message_id
end
end

608
test/unit/changeset_test.rb Normal file
View file

@ -0,0 +1,608 @@
# 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 ChangesetTest < ActiveSupport::TestCase
fixtures :projects, :repositories,
:issues, :issue_statuses, :issue_categories,
:journals, :journal_details,
:workflows,
:changesets, :changes,
:enumerations,
:custom_fields, :custom_values,
:users, :members, :member_roles,
:email_addresses,
:trackers, :projects_trackers,
:enabled_modules, :roles
def test_ref_keywords_any
ActionMailer::Base.deliveries.clear
Setting.commit_ref_keywords = '*'
Setting.commit_update_keywords = [{'keywords' => 'fixes , closes', 'status_id' => '5', 'done_ratio' => '90'}]
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => 'New commit (#2). Fixes #1',
:revision => '12345')
assert c.save
assert_equal [1, 2], c.issue_ids.sort
fixed = Issue.find(1)
assert fixed.closed?
assert_equal 90, fixed.done_ratio
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_ref_keywords
Setting.commit_ref_keywords = 'refs'
Setting.commit_update_keywords = ''
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => 'Ignores #2. Refs #1',
:revision => '12345')
assert c.save
assert_equal [1], c.issue_ids.sort
end
def test_ref_keywords_any_only
Setting.commit_ref_keywords = '*'
Setting.commit_update_keywords = ''
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => 'Ignores #2. Refs #1',
:revision => '12345')
assert c.save
assert_equal [1, 2], c.issue_ids.sort
end
def test_ref_keywords_any_with_timelog
Setting.commit_ref_keywords = '*'
Setting.commit_logtime_enabled = '1'
{
'2' => 2.0,
'2h' => 2.0,
'2hours' => 2.0,
'15m' => 0.25,
'15min' => 0.25,
'3h15' => 3.25,
'3h15m' => 3.25,
'3h15min' => 3.25,
'3:15' => 3.25,
'3.25' => 3.25,
'3.25h' => 3.25,
'3,25' => 3.25,
'3,25h' => 3.25,
}.each do |syntax, expected_hours|
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => 24.hours.ago,
:comments => "Worked on this issue #1 @#{syntax}",
:revision => '520',
:user => User.find(2))
assert_difference 'TimeEntry.count' do
c.scan_comment_for_issue_ids
end
assert_equal [1], c.issue_ids.sort
time = TimeEntry.order('id desc').first
assert_equal 1, time.issue_id
assert_equal 1, time.project_id
assert_equal 2, time.user_id
assert_equal expected_hours, time.hours,
"@#{syntax} should be logged as #{expected_hours} hours but was #{time.hours}"
assert_equal Date.yesterday, time.spent_on
assert time.activity.is_default?
assert time.comments.include?('r520'),
"r520 was expected in time_entry comments: #{time.comments}"
end
end
def test_ref_keywords_closing_with_timelog
Setting.commit_ref_keywords = '*'
Setting.commit_update_keywords = [{'keywords' => 'fixes , closes',
'status_id' => IssueStatus.where(:is_closed => true).first.id.to_s}]
Setting.commit_logtime_enabled = '1'
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => 'This is a comment. Fixes #1 @4.5, #2 @1',
:user => User.find(2))
assert_difference 'TimeEntry.count', 2 do
c.scan_comment_for_issue_ids
end
assert_equal [1, 2], c.issue_ids.sort
assert Issue.find(1).closed?
assert Issue.find(2).closed?
times = TimeEntry.order('id desc').limit(2)
assert_equal [1, 2], times.collect(&:issue_id).sort
end
def test_ref_keywords_any_line_start
Setting.commit_ref_keywords = '*'
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => '#1 is the reason of this commit',
:revision => '12345')
assert c.save
assert_equal [1], c.issue_ids.sort
end
def test_ref_keywords_allow_brackets_around_a_issue_number
Setting.commit_ref_keywords = '*'
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => '[#1] Worked on this issue',
:revision => '12345')
assert c.save
assert_equal [1], c.issue_ids.sort
end
def test_ref_keywords_allow_brackets_around_multiple_issue_numbers
Setting.commit_ref_keywords = '*'
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => '[#1 #2, #3] Worked on these',
:revision => '12345')
assert c.save
assert_equal [1,2,3], c.issue_ids.sort
end
def test_ref_keywords_with_large_number_should_not_error
Setting.commit_ref_keywords = '*'
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => 'Out of range #2010021810000121',
:revision => '12345')
assert_nothing_raised do
assert c.save
end
assert_equal [], c.issue_ids.sort
end
def test_update_keywords_with_changes_should_create_journal
issue = Issue.generate!(:project_id => 1, :status_id => 1)
with_settings :commit_update_keywords => [{'keywords' => 'fixes', 'status_id' => '3'}] do
assert_difference 'Journal.count' do
c = Changeset.generate!(:repository => Project.find(1).repository,:comments => "Fixes ##{issue.id}")
assert_include c.id, issue.reload.changeset_ids
journal = Journal.order('id DESC').first
assert_equal 1, journal.details.count
end
end
end
def test_update_keywords_without_change_should_not_create_journal
issue = Issue.generate!(:project_id => 1, :status_id => 3)
with_settings :commit_update_keywords => [{'keywords' => 'fixes', 'status_id' => '3'}] do
assert_no_difference 'Journal.count' do
c = Changeset.generate!(:repository => Project.find(1).repository,:comments => "Fixes ##{issue.id}")
assert_include c.id, issue.reload.changeset_ids
end
end
end
def test_update_keywords_with_multiple_rules
with_settings :commit_update_keywords => [
{'keywords' => 'fixes, closes', 'status_id' => '5'},
{'keywords' => 'resolves', 'status_id' => '3'}
] do
issue1 = Issue.generate!
issue2 = Issue.generate!
Changeset.generate!(:comments => "Closes ##{issue1.id}\nResolves ##{issue2.id}")
assert_equal 5, issue1.reload.status_id
assert_equal 3, issue2.reload.status_id
end
end
def test_update_keywords_with_multiple_rules_for_the_same_keyword_should_match_tracker
with_settings :commit_update_keywords => [
{'keywords' => 'fixes', 'status_id' => '5', 'if_tracker_id' => '2'},
{'keywords' => 'fixes', 'status_id' => '3', 'if_tracker_id' => ''}
] do
issue1 = Issue.generate!(:tracker_id => 2)
issue2 = Issue.generate!
Changeset.generate!(:comments => "Fixes ##{issue1.id}, ##{issue2.id}")
assert_equal 5, issue1.reload.status_id
assert_equal 3, issue2.reload.status_id
end
end
def test_update_keywords_with_multiple_rules_for_the_same_tracker_should_match_keyword
with_settings :commit_update_keywords => [
{'keywords' => 'Fixes, Closes', 'status_id' => '5', 'done_ratio' => '100', 'if_tracker_id' => '2'},
{'keywords' => 'Testing', 'status_id' => '3', 'done_ratio' => '90', 'if_tracker_id' => '2'}
] do
issue1 = Issue.generate!(:tracker_id => 2)
issue2 = Issue.generate!(:tracker_id => 2)
Changeset.generate!(:comments => "Testing ##{issue1.id}, Fixes ##{issue2.id}")
issue1.reload
assert_equal 3, issue1.status_id
assert_equal 90, issue1.done_ratio
issue2.reload
assert_equal 5, issue2.status_id
assert_equal 100, issue2.done_ratio
end
end
def test_update_keywords_with_multiple_rules_and_no_match
with_settings :commit_update_keywords => [
{'keywords' => 'fixes', 'status_id' => '5', 'if_tracker_id' => '2'},
{'keywords' => 'fixes', 'status_id' => '3', 'if_tracker_id' => '3'}
] do
issue1 = Issue.generate!(:tracker_id => 2)
issue2 = Issue.generate!
Changeset.generate!(:comments => "Fixes ##{issue1.id}, ##{issue2.id}")
assert_equal 5, issue1.reload.status_id
assert_equal 1, issue2.reload.status_id # no updates
end
end
def test_commit_referencing_a_subproject_issue
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => 'refs #5, a subproject issue',
:revision => '12345')
assert c.save
assert_equal [5], c.issue_ids.sort
assert c.issues.first.project != c.project
end
def test_commit_closing_a_subproject_issue
with_settings :commit_update_keywords => [{'keywords' => 'closes', 'status_id' => '5'}],
:default_language => 'en' do
issue = Issue.find(5)
assert !issue.closed?
assert_difference 'Journal.count' do
c = Changeset.new(:repository => Project.find(1).repository,
:committed_on => Time.now,
:comments => 'closes #5, a subproject issue',
:revision => '12345')
assert c.save
end
assert issue.reload.closed?
journal = Journal.order('id DESC').first
assert_equal issue, journal.issue
assert_include "Applied in changeset ecookbook:r12345.", journal.notes
end
end
def test_commit_referencing_a_parent_project_issue
# repository of child project
r = Repository::Subversion.create!(
:project => Project.find(3),
:url => 'svn://localhost/test')
c = Changeset.new(:repository => r,
:committed_on => Time.now,
:comments => 'refs #2, an issue of a parent project',
:revision => '12345')
assert c.save
assert_equal [2], c.issue_ids.sort
assert c.issues.first.project != c.project
end
def test_commit_referencing_a_project_with_commit_cross_project_ref_disabled
r = Repository::Subversion.create!(
:project => Project.find(3),
:url => 'svn://localhost/test')
with_settings :commit_cross_project_ref => '0' do
c = Changeset.new(:repository => r,
:committed_on => Time.now,
:comments => 'refs #4, an issue of a different project',
:revision => '12345')
assert c.save
assert_equal [], c.issue_ids
end
end
def test_commit_referencing_a_project_with_commit_cross_project_ref_enabled
r = Repository::Subversion.create!(
:project => Project.find(3),
:url => 'svn://localhost/test')
with_settings :commit_cross_project_ref => '1' do
c = Changeset.new(:repository => r,
:committed_on => Time.now,
:comments => 'refs #4, an issue of a different project',
:revision => '12345')
assert c.save
assert_equal [4], c.issue_ids
end
end
def test_old_commits_should_not_update_issues_nor_log_time
Setting.commit_ref_keywords = '*'
Setting.commit_update_keywords = {'fixes , closes' => {'status_id' => '5', 'done_ratio' => '90'}}
Setting.commit_logtime_enabled = '1'
repository = Project.find(1).repository
repository.created_on = Time.now
repository.save!
c = Changeset.new(:repository => repository,
:committed_on => 1.month.ago,
:comments => 'New commit (#2). Fixes #1 @1h',
:revision => '12345')
assert_no_difference 'TimeEntry.count' do
assert c.save
end
assert_equal [1, 2], c.issue_ids.sort
issue = Issue.find(1)
assert_equal 1, issue.status_id
assert_equal 0, issue.done_ratio
end
def test_2_repositories_with_same_backend_should_not_link_issue_multiple_times
Setting.commit_ref_keywords = '*'
r1 = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn1', :url => 'file:///svn1')
r2 = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn2', :url => 'file:///svn1')
now = Time.now
assert_difference 'Issue.find(1).changesets.count' do
c1 = Changeset.create!(:repository => r1, :committed_on => now, :comments => 'Fixes #1', :revision => '12345')
c1 = Changeset.create!(:repository => r2, :committed_on => now, :comments => 'Fixes #1', :revision => '12345')
end
end
def test_text_tag_revision
c = Changeset.new(:revision => '520')
assert_equal 'r520', c.text_tag
end
def test_text_tag_revision_with_same_project
c = Changeset.new(:revision => '520', :repository => Project.find(1).repository)
assert_equal 'r520', c.text_tag(Project.find(1))
end
def test_text_tag_revision_with_different_project
c = Changeset.new(:revision => '520', :repository => Project.find(1).repository)
assert_equal 'ecookbook:r520', c.text_tag(Project.find(2))
end
def test_text_tag_revision_with_repository_identifier
r = Repository::Subversion.create!(
:project_id => 1,
:url => 'svn://localhost/test',
:identifier => 'documents')
c = Changeset.new(:revision => '520', :repository => r)
assert_equal 'documents|r520', c.text_tag
assert_equal 'ecookbook:documents|r520', c.text_tag(Project.find(2))
end
def test_text_tag_hash
c = Changeset.new(
:scmid => '7234cb2750b63f47bff735edc50a1c0a433c2518',
:revision => '7234cb2750b63f47bff735edc50a1c0a433c2518')
assert_equal 'commit:7234cb2750b63f47bff735edc50a1c0a433c2518', c.text_tag
end
def test_text_tag_hash_with_same_project
c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository)
assert_equal 'commit:7234cb27', c.text_tag(Project.find(1))
end
def test_text_tag_hash_with_different_project
c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository)
assert_equal 'ecookbook:commit:7234cb27', c.text_tag(Project.find(2))
end
def test_text_tag_hash_all_number
c = Changeset.new(:scmid => '0123456789', :revision => '0123456789')
assert_equal 'commit:0123456789', c.text_tag
end
def test_text_tag_hash_with_repository_identifier
r = Repository::Subversion.new(
:project_id => 1,
:url => 'svn://localhost/test',
:identifier => 'documents')
c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => r)
assert_equal 'commit:documents|7234cb27', c.text_tag
assert_equal 'ecookbook:commit:documents|7234cb27', c.text_tag(Project.find(2))
end
def test_previous
changeset = Changeset.find_by_revision('3')
assert_equal Changeset.find_by_revision('2'), changeset.previous
end
def test_previous_nil
changeset = Changeset.find_by_revision('1')
assert_nil changeset.previous
end
def test_next
changeset = Changeset.find_by_revision('2')
assert_equal Changeset.find_by_revision('3'), changeset.next
end
def test_next_nil
changeset = Changeset.find_by_revision('10')
assert_nil changeset.next
end
def test_comments_should_be_converted_to_utf8
proj = Project.find(3)
# str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
str = "Texte encod\xe9 en ISO-8859-1.".force_encoding("ASCII-8BIT")
r = Repository::Bazaar.create!(
:project => proj,
:url => '/tmp/test/bazaar',
:log_encoding => 'ISO-8859-1' )
assert r
c = Changeset.new(:repository => r,
:committed_on => Time.now,
:revision => '123',
:scmid => '12345',
:comments => str)
assert( c.save )
str_utf8 = "Texte encod\xc3\xa9 en ISO-8859-1.".force_encoding("UTF-8")
assert_equal str_utf8, c.comments
end
def test_invalid_utf8_sequences_in_comments_should_be_replaced_latin1
proj = Project.find(3)
# str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
str1 = "Texte encod\xe9 en ISO-8859-1.".force_encoding("UTF-8")
str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test".force_encoding("ASCII-8BIT")
r = Repository::Bazaar.create!(
:project => proj,
:url => '/tmp/test/bazaar',
:log_encoding => 'UTF-8' )
assert r
c = Changeset.new(:repository => r,
:committed_on => Time.now,
:revision => '123',
:scmid => '12345',
:comments => str1,
:committer => str2)
assert( c.save )
assert_equal "Texte encod? en ISO-8859-1.", c.comments
assert_equal "?a?b?c?d?e test", c.committer
end
def test_invalid_utf8_sequences_in_comments_should_be_replaced_ja_jis
proj = Project.find(3)
str = "test\xb5\xfetest\xb5\xfe".force_encoding('ASCII-8BIT')
r = Repository::Bazaar.create!(
:project => proj,
:url => '/tmp/test/bazaar',
:log_encoding => 'ISO-2022-JP' )
assert r
c = Changeset.new(:repository => r,
:committed_on => Time.now,
:revision => '123',
:scmid => '12345',
:comments => str)
assert( c.save )
assert_equal "test??test??", c.comments
end
def test_comments_should_be_converted_all_latin1_to_utf8
s1 = "\xC2\x80"
s2 = "\xc3\x82\xc2\x80"
s4 = s2.dup
s3 = s1.dup
s1.force_encoding('ASCII-8BIT')
s2.force_encoding('ASCII-8BIT')
s3.force_encoding('ISO-8859-1')
s4.force_encoding('UTF-8')
assert_equal s3.encode('UTF-8'), s4
proj = Project.find(3)
r = Repository::Bazaar.create!(
:project => proj,
:url => '/tmp/test/bazaar',
:log_encoding => 'ISO-8859-1' )
assert r
c = Changeset.new(:repository => r,
:committed_on => Time.now,
:revision => '123',
:scmid => '12345',
:comments => s1)
assert( c.save )
assert_equal s4, c.comments
end
def test_invalid_utf8_sequences_in_paths_should_be_replaced
proj = Project.find(3)
str1 = "Texte encod\xe9 en ISO-8859-1".force_encoding("UTF-8")
str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test".force_encoding("ASCII-8BIT")
r = Repository::Bazaar.create!(
:project => proj,
:url => '/tmp/test/bazaar',
:log_encoding => 'UTF-8' )
assert r
cs = Changeset.new(
:repository => r,
:committed_on => Time.now,
:revision => '123',
:scmid => '12345',
:comments => "test")
assert(cs.save)
ch = Change.new(
:changeset => cs,
:action => "A",
:path => str1,
:from_path => str2,
:from_revision => "345")
assert(ch.save)
assert_equal "Texte encod? en ISO-8859-1", ch.path
assert_equal "?a?b?c?d?e test", ch.from_path
end
def test_comments_nil
proj = Project.find(3)
r = Repository::Bazaar.create!(
:project => proj,
:url => '/tmp/test/bazaar',
:log_encoding => 'ISO-8859-1' )
assert r
c = Changeset.new(:repository => r,
:committed_on => Time.now,
:revision => '123',
:scmid => '12345',
:comments => nil,
:committer => nil)
assert( c.save )
assert_equal "", c.comments
assert_nil c.committer
assert_equal "UTF-8", c.comments.encoding.to_s
end
def test_comments_empty
proj = Project.find(3)
r = Repository::Bazaar.create!(
:project => proj,
:url => '/tmp/test/bazaar',
:log_encoding => 'ISO-8859-1' )
assert r
c = Changeset.new(:repository => r,
:committed_on => Time.now,
:revision => '123',
:scmid => '12345',
:comments => "",
:committer => "")
assert( c.save )
assert_equal "", c.comments
assert_equal "", c.committer
assert_equal "UTF-8", c.comments.encoding.to_s
assert_equal "UTF-8", c.committer.encoding.to_s
end
def test_comments_should_accept_more_than_64k
c = Changeset.new(:repository => Repository.first,
:committed_on => Time.now,
:revision => '123',
:scmid => '12345',
:comments => "a" * 500.kilobyte)
assert c.save
c.reload
assert_equal 500.kilobyte, c.comments.size
end
def test_identifier
c = Changeset.find_by_revision('1')
assert_equal c.revision, c.identifier
end
end

57
test/unit/comment_test.rb Normal file
View file

@ -0,0 +1,57 @@
# 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 CommentTest < ActiveSupport::TestCase
fixtures :users, :email_addresses, :news, :comments, :projects, :enabled_modules
def setup
@jsmith = User.find(2)
@news = News.find(1)
end
def test_create
comment = Comment.new(:commented => @news, :author => @jsmith, :comments => "my comment")
assert comment.save
@news.reload
assert_equal 2, @news.comments_count
end
def test_create_should_send_notification
Watcher.create!(:watchable => @news, :user => @jsmith)
with_settings :notified_events => %w(news_comment_added) do
assert_difference 'ActionMailer::Base.deliveries.size' do
Comment.create!(:commented => @news, :author => @jsmith, :comments => "my comment")
end
end
end
def test_validate
comment = Comment.new(:commented => @news)
assert !comment.save
assert_equal 2, comment.errors.count
end
def test_destroy
comment = Comment.find(1)
assert comment.destroy
@news.reload
assert_equal 0, @news.comments_count
end
end

View file

@ -0,0 +1,343 @@
# 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 CustomFieldTest < ActiveSupport::TestCase
fixtures :custom_fields, :roles, :projects,
:trackers, :issue_statuses,
:issues
def test_create
field = UserCustomField.new(:name => 'Money money money', :field_format => 'float')
assert field.save
end
def test_before_validation
field = CustomField.new(:name => 'test_before_validation', :field_format => 'int')
field.searchable = true
assert field.save
assert_equal false, field.searchable
field.searchable = true
assert field.save
assert_equal false, field.searchable
end
def test_regexp_validation
field = IssueCustomField.new(:name => 'regexp', :field_format => 'text', :regexp => '[a-z0-9')
assert !field.save
assert_include I18n.t('activerecord.errors.messages.invalid'),
field.errors[:regexp]
field.regexp = '[a-z0-9]'
assert field.save
end
def test_default_value_should_be_validated
field = CustomField.new(:name => 'Test', :field_format => 'int')
field.default_value = 'abc'
assert !field.valid?
field.default_value = '6'
assert field.valid?
end
def test_default_value_should_not_be_validated_when_blank
field = CustomField.new(:name => 'Test', :field_format => 'list',
:possible_values => ['a', 'b'], :is_required => true,
:default_value => '')
assert field.valid?
end
def test_field_format_should_be_validated
field = CustomField.new(:name => 'Test', :field_format => 'foo')
assert !field.valid?
end
def test_field_format_validation_should_accept_formats_added_at_runtime
Redmine::FieldFormat.add 'foobar', Class.new(Redmine::FieldFormat::Base)
field = CustomField.new(:name => 'Some Custom Field', :field_format => 'foobar')
assert field.valid?, 'field should be valid'
ensure
Redmine::FieldFormat.delete 'foobar'
end
def test_should_not_change_field_format_of_existing_custom_field
field = CustomField.find(1)
field.field_format = 'int'
assert_equal 'list', field.field_format
end
def test_possible_values_should_accept_an_array
field = CustomField.new
field.possible_values = ["One value", ""]
assert_equal ["One value"], field.possible_values
end
def test_possible_values_should_stringify_values
field = CustomField.new
field.possible_values = [1, 2]
assert_equal ["1", "2"], field.possible_values
end
def test_possible_values_should_accept_a_string
field = CustomField.new
field.possible_values = "One value"
assert_equal ["One value"], field.possible_values
end
def test_possible_values_should_return_utf8_encoded_strings
field = CustomField.new
s = "Value".force_encoding('BINARY')
field.possible_values = s
assert_equal [s], field.possible_values
assert_equal 'UTF-8', field.possible_values.first.encoding.name
end
def test_possible_values_should_accept_a_multiline_string
field = CustomField.new
field.possible_values = "One value\nAnd another one \r\n \n"
assert_equal ["One value", "And another one"], field.possible_values
end
def test_possible_values_stored_as_binary_should_be_utf8_encoded
field = CustomField.find(11)
assert_kind_of Array, field.possible_values
assert field.possible_values.size > 0
field.possible_values.each do |value|
assert_equal "UTF-8", value.encoding.name
end
end
def test_destroy
field = CustomField.find(1)
assert field.destroy
end
def test_new_subclass_instance_should_return_an_instance
f = CustomField.new_subclass_instance('IssueCustomField')
assert_kind_of IssueCustomField, f
end
def test_new_subclass_instance_should_set_attributes
f = CustomField.new_subclass_instance('IssueCustomField', :name => 'Test')
assert_kind_of IssueCustomField, f
assert_equal 'Test', f.name
end
def test_new_subclass_instance_with_invalid_class_name_should_return_nil
assert_nil CustomField.new_subclass_instance('WrongClassName')
end
def test_new_subclass_instance_with_non_subclass_name_should_return_nil
assert_nil CustomField.new_subclass_instance('Project')
end
def test_string_field_validation_with_blank_value
f = CustomField.new(:field_format => 'string')
assert f.valid_field_value?(nil)
assert f.valid_field_value?('')
f.is_required = true
assert !f.valid_field_value?(nil)
assert !f.valid_field_value?('')
end
def test_string_field_validation_with_min_and_max_lengths
f = CustomField.new(:field_format => 'string', :min_length => 2, :max_length => 5)
assert f.valid_field_value?(nil)
assert f.valid_field_value?('')
assert !f.valid_field_value?(' ')
assert f.valid_field_value?('a' * 2)
assert !f.valid_field_value?('a')
assert !f.valid_field_value?('a' * 6)
end
def test_string_field_validation_with_regexp
f = CustomField.new(:field_format => 'string', :regexp => '^[A-Z0-9]*$')
assert f.valid_field_value?(nil)
assert f.valid_field_value?('')
assert !f.valid_field_value?(' ')
assert f.valid_field_value?('ABC')
assert !f.valid_field_value?('abc')
end
def test_date_field_validation
f = CustomField.new(:field_format => 'date')
assert f.valid_field_value?(nil)
assert f.valid_field_value?('')
assert !f.valid_field_value?(' ')
assert f.valid_field_value?('1975-07-14')
assert !f.valid_field_value?('1975-07-33')
assert !f.valid_field_value?('abc')
end
def test_list_field_validation
f = CustomField.new(:field_format => 'list', :possible_values => ['value1', 'value2'])
assert f.valid_field_value?(nil)
assert f.valid_field_value?('')
assert !f.valid_field_value?(' ')
assert f.valid_field_value?('value2')
assert !f.valid_field_value?('abc')
end
def test_int_field_validation
f = CustomField.new(:field_format => 'int')
assert f.valid_field_value?(nil)
assert f.valid_field_value?('')
assert !f.valid_field_value?(' ')
assert f.valid_field_value?('123')
assert f.valid_field_value?('+123')
assert f.valid_field_value?('-123')
assert !f.valid_field_value?('6abc')
assert f.valid_field_value?(123)
end
def test_float_field_validation
f = CustomField.new(:field_format => 'float')
assert f.valid_field_value?(nil)
assert f.valid_field_value?('')
assert !f.valid_field_value?(' ')
assert f.valid_field_value?('11.2')
assert f.valid_field_value?('-6.250')
assert f.valid_field_value?('5')
assert !f.valid_field_value?('6abc')
assert f.valid_field_value?(11.2)
end
def test_multi_field_validation
f = CustomField.new(:field_format => 'list', :multiple => 'true', :possible_values => ['value1', 'value2'])
assert f.valid_field_value?(nil)
assert f.valid_field_value?('')
assert !f.valid_field_value?(' ')
assert f.valid_field_value?([])
assert f.valid_field_value?([nil])
assert f.valid_field_value?([''])
assert !f.valid_field_value?([' '])
assert f.valid_field_value?('value2')
assert !f.valid_field_value?('abc')
assert f.valid_field_value?(['value2'])
assert !f.valid_field_value?(['abc'])
assert f.valid_field_value?(['', 'value2'])
assert !f.valid_field_value?(['', 'abc'])
assert f.valid_field_value?(['value1', 'value2'])
assert !f.valid_field_value?(['value1', 'abc'])
end
def test_changing_multiple_to_false_should_delete_multiple_values
field = ProjectCustomField.create!(:name => 'field', :field_format => 'list',
:multiple => 'true',
:possible_values => ['field1', 'field2'])
other = ProjectCustomField.create!(:name => 'other', :field_format => 'list',
:multiple => 'true',
:possible_values => ['other1', 'other2'])
item_with_multiple_values = Project.generate!(:custom_field_values =>
{field.id => ['field1', 'field2'],
other.id => ['other1', 'other2']})
item_with_single_values = Project.generate!(:custom_field_values =>
{field.id => ['field1'],
other.id => ['other2']})
assert_difference 'CustomValue.count', -1 do
field.multiple = false
field.save!
end
item_with_multiple_values = Project.find(item_with_multiple_values.id)
assert_kind_of String, item_with_multiple_values.custom_field_value(field)
assert_kind_of Array, item_with_multiple_values.custom_field_value(other)
assert_equal 2, item_with_multiple_values.custom_field_value(other).size
end
def test_value_class_should_return_the_class_used_for_fields_values
assert_equal User, CustomField.new(:field_format => 'user').value_class
assert_equal Version, CustomField.new(:field_format => 'version').value_class
end
def test_value_class_should_return_nil_for_other_fields
assert_nil CustomField.new(:field_format => 'text').value_class
assert_nil CustomField.new.value_class
end
def test_value_from_keyword_for_list_custom_field
field = CustomField.find(1)
assert_equal 'PostgreSQL', field.value_from_keyword('postgresql', Issue.find(1))
end
def test_visibile_scope_with_admin_should_return_all_custom_fields
admin = User.generate! {|user| user.admin = true}
CustomField.delete_all
fields = [
CustomField.generate!(:visible => true),
CustomField.generate!(:visible => false),
CustomField.generate!(:visible => false, :role_ids => [1, 3]),
CustomField.generate!(:visible => false, :role_ids => [1, 2]),
]
assert_equal 4, CustomField.visible(admin).count
end
def test_visibile_scope_with_non_admin_user_should_return_visible_custom_fields
CustomField.delete_all
fields = [
CustomField.generate!(:visible => true),
CustomField.generate!(:visible => false),
CustomField.generate!(:visible => false, :role_ids => [1, 3]),
CustomField.generate!(:visible => false, :role_ids => [1, 2]),
]
user = User.generate!
User.add_to_project(user, Project.first, Role.find(3))
assert_equal [fields[0], fields[2]], CustomField.visible(user).order("id").to_a
end
def test_visibile_scope_with_anonymous_user_should_return_visible_custom_fields
CustomField.delete_all
fields = [
CustomField.generate!(:visible => true),
CustomField.generate!(:visible => false),
CustomField.generate!(:visible => false, :role_ids => [1, 3]),
CustomField.generate!(:visible => false, :role_ids => [1, 2]),
]
assert_equal [fields[0]], CustomField.visible(User.anonymous).order("id").to_a
end
def test_float_cast_blank_value_should_return_nil
field = CustomField.new(:field_format => 'float')
assert_nil field.cast_value(nil)
assert_nil field.cast_value('')
end
def test_float_cast_valid_value_should_return_float
field = CustomField.new(:field_format => 'float')
assert_equal 12.0, field.cast_value('12')
assert_equal 12.5, field.cast_value('12.5')
assert_equal 12.5, field.cast_value('+12.5')
assert_equal -12.5, field.cast_value('-12.5')
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 CustomFieldUserFormatTest < ActiveSupport::TestCase
fixtures :custom_fields, :projects, :members, :users, :member_roles, :trackers, :issues
def setup
@field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user')
end
def test_possible_values_options_with_no_arguments
assert_equal [], @field.possible_values_options
assert_equal [], @field.possible_values_options(nil)
end
def test_possible_values_options_with_project_resource
project = Project.find(1)
possible_values_options = @field.possible_values_options(project.issues.first)
assert possible_values_options.any?
assert_equal project.users.sort.map {|u| [u.name, u.id.to_s]}, possible_values_options
end
def test_possible_values_options_with_array
projects = Project.find([1, 2])
possible_values_options = @field.possible_values_options(projects)
assert possible_values_options.any?
assert_equal (projects.first.users & projects.last.users).sort.map {|u| [u.name, u.id.to_s]}, possible_values_options
end
def test_possible_custom_value_options_should_not_include_locked_users
custom_value = CustomValue.new(:customized => Issue.find(1), :custom_field => @field)
assert_include '2', @field.possible_custom_value_options(custom_value).map(&:last)
assert User.find(2).lock!
assert_not_include '2', @field.possible_custom_value_options(custom_value).map(&:last)
end
def test_possible_custom_value_options_should_include_user_that_was_assigned_to_the_custom_value
user = User.generate!
custom_value = CustomValue.new(:customized => Issue.find(1), :custom_field => @field)
assert_not_include user.id.to_s, @field.possible_custom_value_options(custom_value).map(&:last)
custom_value.value = user.id
custom_value.save!
assert_include user.id.to_s, @field.possible_custom_value_options(custom_value).map(&:last)
end
def test_cast_blank_value
assert_nil @field.cast_value(nil)
assert_nil @field.cast_value("")
end
def test_cast_valid_value
user = @field.cast_value("2")
assert_kind_of User, user
assert_equal User.find(2), user
end
def test_cast_invalid_value
assert_nil @field.cast_value("187")
end
end

View file

@ -0,0 +1,61 @@
# 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 CustomFieldVersionFormatTest < ActiveSupport::TestCase
fixtures :custom_fields, :projects, :members, :users, :member_roles, :trackers, :issues, :versions
def setup
@field = IssueCustomField.create!(:name => 'Tester', :field_format => 'version')
end
def test_possible_values_options_with_no_arguments
Version.delete_all
assert_equal [], @field.possible_values_options
assert_equal [], @field.possible_values_options(nil)
end
def test_possible_values_options_with_project_resource
project = Project.find(1)
possible_values_options = @field.possible_values_options(project.issues.first)
assert possible_values_options.any?
assert_equal project.shared_versions.sort.map {|u| [u.name, u.id.to_s]}, possible_values_options
end
def test_possible_values_options_with_array
projects = Project.find([1, 2])
possible_values_options = @field.possible_values_options(projects)
assert possible_values_options.any?
assert_equal (projects.first.shared_versions & projects.last.shared_versions).sort.map {|u| [u.name, u.id.to_s]}, possible_values_options
end
def test_cast_blank_value
assert_nil @field.cast_value(nil)
assert_nil @field.cast_value("")
end
def test_cast_valid_value
version = @field.cast_value("2")
assert_kind_of Version, version
assert_equal Version.find(2), version
end
def test_cast_invalid_value
assert_nil @field.cast_value("187")
end
end

View file

@ -0,0 +1,49 @@
# 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 CustomValueTest < ActiveSupport::TestCase
fixtures :custom_fields, :custom_values, :users
def test_new_without_value_should_set_default_value
field = CustomField.generate!(:default_value => 'Default string')
v = CustomValue.new(:custom_field => field)
assert_equal 'Default string', v.value
end
def test_new_with_value_should_not_set_default_value
field = CustomField.generate!(:default_value => 'Default string')
v = CustomValue.new(:custom_field => field, :value => 'String')
assert_equal 'String', v.value
end
def test_new_with_nil_value_should_not_set_default_value
field = CustomField.generate!(:default_value => 'Default string')
v = CustomValue.new(:custom_field => field, :value => nil)
assert_nil v.value
end
def test_sti_polymorphic_association
# Rails uses top level sti class for polymorphic association. See #3978.
assert !User.find(4).custom_values.empty?
assert !CustomValue.find(2).customized.nil?
end
end

View file

@ -0,0 +1,60 @@
# 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 DefaultDataTest < ActiveSupport::TestCase
include Redmine::I18n
fixtures :roles
def test_no_data
assert !Redmine::DefaultData::Loader::no_data?
clear_data
assert Redmine::DefaultData::Loader::no_data?
end
def test_load
clear_data
assert Redmine::DefaultData::Loader::load('en')
assert_not_nil DocumentCategory.first
assert_not_nil IssuePriority.first
assert_not_nil TimeEntryActivity.first
assert_not_nil WorkflowTransition.first
end
def test_load_for_all_language
valid_languages.each do |lang|
clear_data
begin
assert Redmine::DefaultData::Loader::load(lang, :workflow => false)
assert_not_nil DocumentCategory.first
assert_not_nil IssuePriority.first
assert_not_nil TimeEntryActivity.first
rescue ActiveRecord::RecordInvalid => e
assert false, ":#{lang} default data is invalid (#{e.message})."
end
end
end
def clear_data
Role.where("builtin = 0").delete_all
Tracker.delete_all
IssueStatus.delete_all
Enumeration.delete_all
WorkflowRule.delete_all
end
end

View file

@ -0,0 +1,47 @@
# 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 DocumentCategoryTest < ActiveSupport::TestCase
fixtures :enumerations, :documents, :issues
def test_should_be_an_enumeration
assert DocumentCategory.ancestors.include?(Enumeration)
end
def test_objects_count
assert_equal 2, DocumentCategory.find_by_name("Uncategorized").objects_count
assert_equal 0, DocumentCategory.find_by_name("User documentation").objects_count
end
def test_option_name
assert_equal :enumeration_doc_categories, DocumentCategory.new.option_name
end
def test_default
assert_nil DocumentCategory.where(:is_default => true).first
e = Enumeration.find_by_name('Technical documentation')
e.update_attributes(:is_default => true)
assert_equal 3, DocumentCategory.default.id
end
def test_force_default
assert_nil DocumentCategory.where(:is_default => true).first
assert_equal 1, DocumentCategory.default.id
end
end

View file

@ -0,0 +1,68 @@
# 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 DocumentTest < ActiveSupport::TestCase
fixtures :projects, :enumerations, :documents, :attachments,
:enabled_modules,
:users, :email_addresses, :members, :member_roles, :roles,
:groups_users
def test_create
doc = Document.new(:project => Project.find(1), :title => 'New document', :category => Enumeration.find_by_name('User documentation'))
assert doc.save
end
def test_create_with_long_title
title = 'x'*255
doc = Document.new(:project => Project.find(1), :title => title, :category => DocumentCategory.first)
assert_save doc
assert_equal title, doc.reload.title
end
def test_create_should_send_email_notification
ActionMailer::Base.deliveries.clear
with_settings :notified_events => %w(document_added) do
doc = Document.new(:project => Project.find(1), :title => 'New document', :category => Enumeration.find_by_name('User documentation'))
assert doc.save
end
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_create_with_default_category
# Sets a default category
e = Enumeration.find_by_name('Technical documentation')
e.update_attributes(:is_default => true)
doc = Document.new(:project => Project.find(1), :title => 'New document')
assert_equal e, doc.category
assert doc.save
end
def test_updated_on_with_attachments
d = Document.find(1)
assert d.attachments.any?
assert_equal d.attachments.map(&:created_on).max, d.updated_on
end
def test_updated_on_without_attachments
d = Document.find(2)
assert d.attachments.empty?
assert_equal d.created_on, d.updated_on
end
end

View file

@ -0,0 +1,43 @@
# 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 EnabledModuleTest < ActiveSupport::TestCase
fixtures :projects, :trackers, :issue_statuses, :wikis
def test_enabling_wiki_should_create_a_wiki
CustomField.delete_all
project = Project.create!(:name => 'Project with wiki', :identifier => 'wikiproject', :enabled_module_names => [])
assert_nil project.wiki
project.enabled_module_names = ['wiki']
project.reload
assert_not_nil project.wiki
assert_equal 'Wiki', project.wiki.start_page
end
def test_reenabling_wiki_should_not_create_another_wiki
project = Project.find(1)
assert_not_nil project.wiki
project.enabled_module_names = []
project.reload
assert_no_difference 'Wiki.count' do
project.enabled_module_names = ['wiki']
end
assert_not_nil project.wiki
end
end

View file

@ -0,0 +1,175 @@
# 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 EnumerationTest < ActiveSupport::TestCase
fixtures :enumerations, :issues, :custom_fields, :custom_values
def test_objects_count
# low priority
assert_equal 6, Enumeration.find(4).objects_count
# urgent
assert_equal 0, Enumeration.find(7).objects_count
end
def test_in_use
# low priority
assert Enumeration.find(4).in_use?
# urgent
assert !Enumeration.find(7).in_use?
end
def test_default
e = Enumeration.default
assert e.is_a?(Enumeration)
assert e.is_default?
assert e.active?
assert_equal 'Default Enumeration', e.name
end
def test_default_non_active
e = Enumeration.find(12)
assert e.is_a?(Enumeration)
assert e.is_default?
assert e.active?
e.update_attributes(:active => false)
assert e.is_default?
assert !e.active?
end
def test_create
e = Enumeration.new(:name => 'Not default', :is_default => false)
e.type = 'Enumeration'
assert e.save
assert_equal 'Default Enumeration', Enumeration.default.name
end
def test_create_as_default
e = Enumeration.new(:name => 'Very urgent', :is_default => true)
e.type = 'Enumeration'
assert e.save
assert_equal e, Enumeration.default
end
def test_update_default
e = Enumeration.default
e.update_attributes(:name => 'Changed', :is_default => true)
assert_equal e, Enumeration.default
end
def test_update_default_to_non_default
e = Enumeration.default
e.update_attributes(:name => 'Changed', :is_default => false)
assert_nil Enumeration.default
end
def test_change_default
e = Enumeration.find_by_name('Default Enumeration')
e.update_attributes(:name => 'Changed Enumeration', :is_default => true)
assert_equal e, Enumeration.default
end
def test_destroy_with_reassign
Enumeration.find(4).destroy(Enumeration.find(6))
assert_nil Issue.where(:priority_id => 4).first
assert_equal 6, Enumeration.find(6).objects_count
end
def test_should_be_customizable
assert Enumeration.included_modules.include?(Redmine::Acts::Customizable::InstanceMethods)
end
def test_should_belong_to_a_project
association = Enumeration.reflect_on_association(:project)
assert association, "No Project association found"
assert_equal :belongs_to, association.macro
end
def test_should_act_as_tree
enumeration = Enumeration.find(4)
assert enumeration.respond_to?(:parent)
assert enumeration.respond_to?(:children)
end
def test_is_override
# Defaults to off
enumeration = Enumeration.find(4)
assert !enumeration.is_override?
# Setup as an override
enumeration.parent = Enumeration.find(5)
assert enumeration.is_override?
end
def test_get_subclasses
classes = Enumeration.get_subclasses
assert_include IssuePriority, classes
assert_include DocumentCategory, classes
assert_include TimeEntryActivity, classes
classes.each do |klass|
assert_equal Enumeration, klass.superclass
end
end
def test_list_should_be_scoped_for_each_type
Enumeration.delete_all
a = IssuePriority.create!(:name => 'A')
b = IssuePriority.create!(:name => 'B')
c = DocumentCategory.create!(:name => 'C')
assert_equal [1, 2, 1], [a, b, c].map(&:reload).map(&:position)
end
def test_override_should_be_created_with_same_position_as_parent
Enumeration.delete_all
a = IssuePriority.create!(:name => 'A')
b = IssuePriority.create!(:name => 'B')
override = IssuePriority.create!(:name => 'BB', :parent_id => b.id)
assert_equal [1, 2, 2], [a, b, override].map(&:reload).map(&:position)
end
def test_override_position_should_be_updated_with_parent_position
Enumeration.delete_all
a = IssuePriority.create!(:name => 'A')
b = IssuePriority.create!(:name => 'B')
override = IssuePriority.create!(:name => 'BB', :parent_id => b.id)
b.position -= 1
b.save!
assert_equal [2, 1, 1], [a, b, override].map(&:reload).map(&:position)
end
def test_destroying_override_should_not_update_positions
Enumeration.delete_all
a = IssuePriority.create!(:name => 'A')
b = IssuePriority.create!(:name => 'B')
c = IssuePriority.create!(:name => 'C')
override = IssuePriority.create!(:name => 'BB', :parent_id => b.id)
assert_equal [1, 2, 3, 2], [a, b, c, override].map(&:reload).map(&:position)
override.destroy
assert_equal [1, 2, 3], [a, b, c].map(&:reload).map(&:position)
end
end

169
test/unit/group_test.rb Normal file
View file

@ -0,0 +1,169 @@
# 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 GroupTest < ActiveSupport::TestCase
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :users,
:projects_trackers,
:roles,
:member_roles,
:members,
:groups_users
include Redmine::I18n
def test_create
g = Group.new(:name => 'New group')
assert g.save
g.reload
assert_equal 'New group', g.name
end
def test_name_should_accept_255_characters
name = 'a' * 255
g = Group.new(:name => name)
assert g.save
g.reload
assert_equal name, g.name
end
def test_blank_name_error_message
set_language_if_valid 'en'
g = Group.new
assert !g.save
assert_include "Name cannot be blank", g.errors.full_messages
end
def test_blank_name_error_message_fr
set_language_if_valid 'fr'
str = "Nom doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
g = Group.new
assert !g.save
assert_include str, g.errors.full_messages
end
def test_group_roles_should_be_given_to_added_user
group = Group.find(11)
user = User.find(9)
project = Project.first
Member.create!(:principal => group, :project => project, :role_ids => [1, 2])
group.users << user
assert user.member_of?(project)
end
def test_new_roles_should_be_given_to_existing_user
group = Group.find(11)
user = User.find(9)
project = Project.first
group.users << user
m = Member.create!(:principal => group, :project => project, :role_ids => [1, 2])
assert user.member_of?(project)
end
def test_user_roles_should_updated_when_updating_user_ids
group = Group.find(11)
user = User.find(9)
project = Project.first
Member.create!(:principal => group, :project => project, :role_ids => [1, 2])
group.user_ids = [user.id]
group.save!
assert User.find(9).member_of?(project)
group.user_ids = [1]
group.save!
assert !User.find(9).member_of?(project)
end
def test_user_roles_should_updated_when_updating_group_roles
group = Group.find(11)
user = User.find(9)
project = Project.first
group.users << user
m = Member.create!(:principal => group, :project => project, :role_ids => [1])
assert_equal [1], user.reload.roles_for_project(project).collect(&:id).sort
m.role_ids = [1, 2]
assert_equal [1, 2], user.reload.roles_for_project(project).collect(&:id).sort
m.role_ids = [2]
assert_equal [2], user.reload.roles_for_project(project).collect(&:id).sort
m.role_ids = [1]
assert_equal [1], user.reload.roles_for_project(project).collect(&:id).sort
end
def test_user_memberships_should_be_removed_when_removing_group_membership
assert User.find(8).member_of?(Project.find(5))
Member.find_by_project_id_and_user_id(5, 10).destroy
assert !User.find(8).member_of?(Project.find(5))
end
def test_user_roles_should_be_removed_when_removing_user_from_group
assert User.find(8).member_of?(Project.find(5))
User.find(8).groups = []
assert !User.find(8).member_of?(Project.find(5))
end
def test_destroy_should_unassign_issues
group = Group.find(10)
Issue.where(:id => 1).update_all(["assigned_to_id = ?", group.id])
assert group.destroy
assert group.destroyed?
assert_nil Issue.find(1).assigned_to_id
end
def test_builtin_groups_should_be_created_if_missing
Group.delete_all
assert_difference 'Group.count', 2 do
group = Group.anonymous
assert_equal GroupAnonymous, group.class
group = Group.non_member
assert_equal GroupNonMember, group.class
end
end
def test_builtin_in_group_should_be_uniq
group = GroupAnonymous.new
group.name = 'Foo'
assert !group.save
end
def test_builtin_in_group_should_not_accept_users
group = Group.anonymous
assert_raise RuntimeError do
group.users << User.find(1)
end
assert_equal 0, group.reload.users.count
end
def test_sorted_scope_should_sort_groups_alphabetically
Group.delete_all
b = Group.generate!(:name => 'B')
a = Group.generate!(:name => 'A')
assert_equal %w(A B), Group.sorted.to_a.map(&:name)
end
end

View file

@ -0,0 +1,102 @@
# 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 ActivitiesHelperTest < Redmine::HelperTest
include ActivitiesHelper
class MockEvent
attr_reader :event_datetime, :event_group, :name
def initialize(group=nil)
@@count ||= 0
@name = "e#{@@count}"
@event_datetime = Time.now + @@count.hours
@event_group = group || self
@@count += 1
end
def self.clear
@@count = 0
end
end
def setup
super
MockEvent.clear
end
def test_sort_activity_events_should_sort_by_datetime
events = []
events << MockEvent.new
events << MockEvent.new
events << MockEvent.new
assert_equal [
['e2', false],
['e1', false],
['e0', false]
], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
end
def test_sort_activity_events_should_group_events
events = []
events << MockEvent.new
events << MockEvent.new(events[0])
events << MockEvent.new(events[0])
assert_equal [
['e2', false],
['e1', true],
['e0', true]
], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
end
def test_sort_activity_events_with_group_not_in_set_should_group_events
e = MockEvent.new
events = []
events << MockEvent.new(e)
events << MockEvent.new(e)
assert_equal [
['e2', false],
['e1', true]
], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
end
def test_sort_activity_events_should_sort_by_datetime_and_group
events = []
events << MockEvent.new
events << MockEvent.new
events << MockEvent.new
events << MockEvent.new(events[1])
events << MockEvent.new(events[2])
events << MockEvent.new
events << MockEvent.new(events[2])
assert_equal [
['e6', false],
['e4', true],
['e2', true],
['e5', false],
['e3', false],
['e1', true],
['e0', false]
], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
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 CustomFieldsHelperTest < Redmine::HelperTest
include ApplicationHelper
include CustomFieldsHelper
include ERB::Util
def test_format_boolean_value
I18n.locale = 'en'
assert_equal 'Yes', format_value('1', CustomField.new(:field_format => 'bool'))
assert_equal 'No', format_value('0', CustomField.new(:field_format => 'bool'))
end
def test_label_tag_should_include_description_as_span_title_if_present
field = CustomField.new(:field_format => 'string', :description => 'This is the description')
tag = custom_field_label_tag('foo', CustomValue.new(:custom_field => field))
assert_select_in tag, 'label span[title=?]', 'This is the description'
end
def test_label_tag_should_not_include_title_if_description_is_blank
field = CustomField.new(:field_format => 'string')
tag = custom_field_label_tag('foo', CustomValue.new(:custom_field => field))
assert_select_in tag, 'label span[title]', 0
end
def test_label_tag_should_include_for_attribute_for_select_tag
field = CustomField.new(:name => 'Foo', :field_format => 'list')
s = custom_field_tag_with_label('foo', CustomValue.new(:custom_field => field))
assert_select_in s, 'label[for]'
end
def test_label_tag_should_not_include_for_attribute_for_checkboxes
field = CustomField.new(:name => 'Foo', :field_format => 'list', :edit_tag_style => 'check_box')
s = custom_field_tag_with_label('foo', CustomValue.new(:custom_field => field))
assert_select_in s, 'label:not([for])'
end
def test_label_tag_should_include_for_attribute_for_bool_as_select_tag
field = CustomField.new(:name => 'Foo', :field_format => 'bool')
s = custom_field_tag_with_label('foo', CustomValue.new(:custom_field => field))
assert_select_in s, 'label[for]'
end
def test_label_tag_should_include_for_attribute_for_bool_as_checkbox
field = CustomField.new(:name => 'Foo', :field_format => 'bool', :edit_tag_style => 'check_box')
s = custom_field_tag_with_label('foo', CustomValue.new(:custom_field => field))
assert_select_in s, 'label[for]'
end
def test_label_tag_should_not_include_for_attribute_for_bool_as_radio
field = CustomField.new(:name => 'Foo', :field_format => 'bool', :edit_tag_style => 'radio')
s = custom_field_tag_with_label('foo', CustomValue.new(:custom_field => field))
assert_select_in s, 'label:not([for])'
end
def test_unknow_field_format_should_be_edited_as_string
field = CustomField.new(:field_format => 'foo')
value = CustomValue.new(:value => 'bar', :custom_field => field)
field.id = 52
assert_select_in custom_field_tag('object', value),
'input[type=text][value=bar][name=?]', 'object[custom_field_values][52]'
end
def test_unknow_field_format_should_be_bulk_edited_as_string
field = CustomField.new(:field_format => 'foo')
field.id = 52
assert_select_in custom_field_tag_for_bulk_edit('object', field),
'input[type=text][value=""][name=?]', 'object[custom_field_values][52]'
end
end

View file

@ -0,0 +1,42 @@
# 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 GroupsHelperTest < Redmine::HelperTest
include ERB::Util
include GroupsHelper
include Rails.application.routes.url_helpers
fixtures :users
def test_render_principals_for_new_group_users
group = Group.generate!
result = render_principals_for_new_group_users(group)
assert_select_in result, 'input[name=?][value="2"]', 'user_ids[]'
end
def test_render_principals_for_new_group_users_with_limited_results_should_paginate
group = Group.generate!
result = render_principals_for_new_group_users(group, 3)
assert_select_in result, 'span.pagination'
assert_select_in result, 'span.pagination li.current span', :text => '1'
assert_select_in result, 'a[href=?]', "/groups/#{group.id}/autocomplete_for_user.js?page=2", :text => '2'
end
end

View file

@ -0,0 +1,332 @@
# 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 IssuesHelperTest < Redmine::HelperTest
include IssuesHelper
include CustomFieldsHelper
include ERB::Util
include Rails.application.routes.url_helpers
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :users, :issue_categories,
:projects_trackers,
:roles,
:member_roles,
:members,
:enabled_modules,
:custom_fields,
:attachments,
:versions
def test_issue_heading
assert_equal "Bug #1", issue_heading(Issue.find(1))
end
def test_issues_destroy_confirmation_message_with_one_root_issue
assert_equal l(:text_issues_destroy_confirmation),
issues_destroy_confirmation_message(Issue.find(1))
end
def test_issues_destroy_confirmation_message_with_an_arrayt_of_root_issues
assert_equal l(:text_issues_destroy_confirmation),
issues_destroy_confirmation_message(Issue.find([1, 2]))
end
def test_issues_destroy_confirmation_message_with_one_parent_issue
Issue.find(2).update! :parent_issue_id => 1
assert_equal l(:text_issues_destroy_confirmation) + "\n" +
l(:text_issues_destroy_descendants_confirmation, :count => 1),
issues_destroy_confirmation_message(Issue.find(1))
end
def test_issues_destroy_confirmation_message_with_one_parent_issue_and_its_child
Issue.find(2).update! :parent_issue_id => 1
assert_equal l(:text_issues_destroy_confirmation),
issues_destroy_confirmation_message(Issue.find([1, 2]))
end
def test_issues_destroy_confirmation_message_with_issues_that_share_descendants
root = Issue.generate!
child = Issue.generate!(:parent_issue_id => root.id)
Issue.generate!(:parent_issue_id => child.id)
assert_equal l(:text_issues_destroy_confirmation) + "\n" +
l(:text_issues_destroy_descendants_confirmation, :count => 1),
issues_destroy_confirmation_message([root.reload, child.reload])
end
test 'show_detail with no_html should show a changing attribute' do
detail = JournalDetail.new(:property => 'attr', :old_value => '40',
:value => '100', :prop_key => 'done_ratio')
assert_equal "% Done changed from 40 to 100", show_detail(detail, true)
end
test 'show_detail with no_html should show a new attribute' do
detail = JournalDetail.new(:property => 'attr', :old_value => nil,
:value => '100', :prop_key => 'done_ratio')
assert_equal "% Done set to 100", show_detail(detail, true)
end
test 'show_detail with no_html should show a deleted attribute' do
detail = JournalDetail.new(:property => 'attr', :old_value => '50',
:value => nil, :prop_key => 'done_ratio')
assert_equal "% Done deleted (50)", show_detail(detail, true)
end
test 'show_detail with html should show a changing attribute with HTML highlights' do
detail = JournalDetail.new(:property => 'attr', :old_value => '40',
:value => '100', :prop_key => 'done_ratio')
html = show_detail(detail, false)
assert_include '<strong>% Done</strong>', html
assert_include '<i>40</i>', html
assert_include '<i>100</i>', html
end
test 'show_detail with html should show a new attribute with HTML highlights' do
detail = JournalDetail.new(:property => 'attr', :old_value => nil,
:value => '100', :prop_key => 'done_ratio')
html = show_detail(detail, false)
assert_include '<strong>% Done</strong>', html
assert_include '<i>100</i>', html
end
test 'show_detail with html should show a deleted attribute with HTML highlights' do
detail = JournalDetail.new(:property => 'attr', :old_value => '50',
:value => nil, :prop_key => 'done_ratio')
html = show_detail(detail, false)
assert_include '<strong>% Done</strong>', html
assert_include '<del><i>50</i></del>', html
end
test 'show_detail with a start_date attribute should format the dates' do
detail = JournalDetail.new(
:property => 'attr',
:old_value => '2010-01-01',
:value => '2010-01-31',
:prop_key => 'start_date'
)
with_settings :date_format => '%m/%d/%Y' do
assert_match "01/31/2010", show_detail(detail, true)
assert_match "01/01/2010", show_detail(detail, true)
end
end
test 'show_detail with a due_date attribute should format the dates' do
detail = JournalDetail.new(
:property => 'attr',
:old_value => '2010-01-01',
:value => '2010-01-31',
:prop_key => 'due_date'
)
with_settings :date_format => '%m/%d/%Y' do
assert_match "01/31/2010", show_detail(detail, true)
assert_match "01/01/2010", show_detail(detail, true)
end
end
test 'show_detail should show old and new values with a project attribute' do
detail = JournalDetail.new(:property => 'attr', :prop_key => 'project_id',
:old_value => 1, :value => 2)
assert_match 'eCookbook', show_detail(detail, true)
assert_match 'OnlineStore', show_detail(detail, true)
end
test 'show_detail should show old and new values with a issue status attribute' do
detail = JournalDetail.new(:property => 'attr', :prop_key => 'status_id',
:old_value => 1, :value => 2)
assert_match 'New', show_detail(detail, true)
assert_match 'Assigned', show_detail(detail, true)
end
test 'show_detail should show old and new values with a tracker attribute' do
detail = JournalDetail.new(:property => 'attr', :prop_key => 'tracker_id',
:old_value => 1, :value => 2)
assert_match 'Bug', show_detail(detail, true)
assert_match 'Feature request', show_detail(detail, true)
end
test 'show_detail should show old and new values with a assigned to attribute' do
detail = JournalDetail.new(:property => 'attr', :prop_key => 'assigned_to_id',
:old_value => 1, :value => 2)
assert_match 'Redmine Admin', show_detail(detail, true)
assert_match 'John Smith', show_detail(detail, true)
end
test 'show_detail should show old and new values with a priority attribute' do
detail = JournalDetail.new(:property => 'attr', :prop_key => 'priority_id',
:old_value => 4, :value => 5)
assert_match 'Low', show_detail(detail, true)
assert_match 'Normal', show_detail(detail, true)
end
test 'show_detail should show old and new values with a category attribute' do
detail = JournalDetail.new(:property => 'attr', :prop_key => 'category_id',
:old_value => 1, :value => 2)
assert_match 'Printing', show_detail(detail, true)
assert_match 'Recipes', show_detail(detail, true)
end
test 'show_detail should show old and new values with a fixed version attribute' do
detail = JournalDetail.new(:property => 'attr', :prop_key => 'fixed_version_id',
:old_value => 1, :value => 2)
assert_match '0.1', show_detail(detail, true)
assert_match '1.0', show_detail(detail, true)
end
test 'show_detail should show old and new values with a estimated hours attribute' do
detail = JournalDetail.new(:property => 'attr', :prop_key => 'estimated_hours',
:old_value => '5', :value => '6.3')
assert_match '5.00', show_detail(detail, true)
assert_match '6.30', show_detail(detail, true)
end
test 'show_detail should not show values with a description attribute' do
detail = JournalDetail.new(:property => 'attr', :prop_key => 'description',
:old_value => 'Foo', :value => 'Bar')
assert_equal 'Description updated', show_detail(detail, true)
end
test 'show_detail should show old and new values with a custom field' do
detail = JournalDetail.new(:property => 'cf', :prop_key => '1',
:old_value => 'MySQL', :value => 'PostgreSQL')
assert_equal 'Database changed from MySQL to PostgreSQL', show_detail(detail, true)
end
test 'show_detail should not show values with a long text custom field' do
field = IssueCustomField.create!(:name => "Long field", :field_format => 'text')
detail = JournalDetail.new(:property => 'cf', :prop_key => field.id,
:old_value => 'Foo', :value => 'Bar')
assert_equal 'Long field updated', show_detail(detail, true)
end
test 'show_detail should show added file' do
detail = JournalDetail.new(:property => 'attachment', :prop_key => '1',
:old_value => nil, :value => 'error281.txt')
assert_match 'error281.txt', show_detail(detail, true)
end
test 'show_detail should show removed file' do
detail = JournalDetail.new(:property => 'attachment', :prop_key => '1',
:old_value => 'error281.txt', :value => nil)
assert_match 'error281.txt', show_detail(detail, true)
end
def test_show_detail_relation_added
detail = JournalDetail.new(:property => 'relation',
:prop_key => 'precedes',
:value => 1)
assert_equal "Precedes Bug #1: Cannot print recipes added", show_detail(detail, true)
str = link_to("Bug #1", "/issues/1", :class => Issue.find(1).css_classes)
assert_equal "<strong>Precedes</strong> <i>#{str}: Cannot print recipes</i> added",
show_detail(detail, false)
end
def test_show_detail_relation_added_with_inexistant_issue
inexistant_issue_number = 9999
assert_nil Issue.find_by_id(inexistant_issue_number)
detail = JournalDetail.new(:property => 'relation',
:prop_key => 'precedes',
:value => inexistant_issue_number)
assert_equal "Precedes Issue ##{inexistant_issue_number} added", show_detail(detail, true)
assert_equal "<strong>Precedes</strong> <i>Issue ##{inexistant_issue_number}</i> added", show_detail(detail, false)
end
def test_show_detail_relation_added_should_not_disclose_issue_that_is_not_visible
issue = Issue.generate!(:is_private => true)
detail = JournalDetail.new(:property => 'relation',
:prop_key => 'precedes',
:value => issue.id)
assert_equal "Precedes Issue ##{issue.id} added", show_detail(detail, true)
assert_equal "<strong>Precedes</strong> <i>Issue ##{issue.id}</i> added", show_detail(detail, false)
end
def test_show_detail_relation_deleted
detail = JournalDetail.new(:property => 'relation',
:prop_key => 'precedes',
:old_value => 1)
assert_equal "Precedes deleted (Bug #1: Cannot print recipes)", show_detail(detail, true)
str = link_to("Bug #1",
"/issues/1",
:class => Issue.find(1).css_classes)
assert_equal "<strong>Precedes</strong> deleted (<i>#{str}: Cannot print recipes</i>)",
show_detail(detail, false)
end
def test_show_detail_relation_deleted_with_inexistant_issue
inexistant_issue_number = 9999
assert_nil Issue.find_by_id(inexistant_issue_number)
detail = JournalDetail.new(:property => 'relation',
:prop_key => 'precedes',
:old_value => inexistant_issue_number)
assert_equal "Precedes deleted (Issue #9999)", show_detail(detail, true)
assert_equal "<strong>Precedes</strong> deleted (<i>Issue #9999</i>)", show_detail(detail, false)
end
def test_show_detail_relation_deleted_should_not_disclose_issue_that_is_not_visible
issue = Issue.generate!(:is_private => true)
detail = JournalDetail.new(:property => 'relation',
:prop_key => 'precedes',
:old_value => issue.id)
assert_equal "Precedes deleted (Issue ##{issue.id})", show_detail(detail, true)
assert_equal "<strong>Precedes</strong> deleted (<i>Issue ##{issue.id}</i>)", show_detail(detail, false)
end
def test_details_to_strings_with_multiple_values_removed_from_custom_field
field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true)
details = []
details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '1', :value => nil)
details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '3', :value => nil)
assert_equal ["User deleted (Dave Lopper, Redmine Admin)"], details_to_strings(details, true)
assert_equal ["<strong>User</strong> deleted (<del><i>Dave Lopper, Redmine Admin</i></del>)"], details_to_strings(details, false)
end
def test_details_to_strings_with_multiple_values_added_to_custom_field
field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true)
details = []
details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '1')
details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '3')
assert_equal ["User Dave Lopper, Redmine Admin added"], details_to_strings(details, true)
assert_equal ["<strong>User</strong> <i>Dave Lopper, Redmine Admin</i> added"], details_to_strings(details, false)
end
def test_details_to_strings_with_multiple_values_added_and_removed_from_custom_field
field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true)
details = []
details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '1')
details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '2', :value => nil)
details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '3', :value => nil)
assert_equal [
"User Redmine Admin added",
"User deleted (Dave Lopper, John Smith)"
], details_to_strings(details, true)
assert_equal [
"<strong>User</strong> <i>Redmine Admin</i> added",
"<strong>User</strong> deleted (<del><i>Dave Lopper, John Smith</i></del>)"
], details_to_strings(details, false)
end
def test_find_name_by_reflection_should_return_nil_for_missing_record
assert_nil find_name_by_reflection('status', 99)
end
end

View file

@ -0,0 +1,48 @@
# 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 JournalsHelperTest < Redmine::HelperTest
include JournalsHelper
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :issue_categories,
:projects_trackers,
:users, :roles, :member_roles, :members,
:enabled_modules,
:custom_fields,
:attachments,
:versions
def test_journal_thumbnail_attachments_should_return_thumbnailable_attachments
issue = Issue.generate!
journal = new_record(Journal) do
issue.init_journal(User.find(1))
issue.attachments << Attachment.new(:file => mock_file_with_options(:original_filename => 'image.png'), :author => User.find(1))
issue.attachments << Attachment.new(:file => mock_file_with_options(:original_filename => 'foo'), :author => User.find(1))
issue.save
end
assert_equal 2, journal.details.count
thumbnails = journal_thumbnail_attachments(journal)
assert_equal 1, thumbnails.count
assert_kind_of Attachment, thumbnails.first
assert_equal 'image.png', thumbnails.first.filename
end
end

View file

@ -0,0 +1,43 @@
# 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 MembersHelperTest < Redmine::HelperTest
include ERB::Util
include MembersHelper
include Rails.application.routes.url_helpers
fixtures :projects, :users, :members, :member_roles,
:trackers, :issue_statuses
def test_render_principals_for_new_members
project = Project.generate!
result = render_principals_for_new_members(project)
assert_select_in result, 'input[name=?][value="2"]', 'membership[user_ids][]'
end
def test_render_principals_for_new_members_with_limited_results_should_paginate
project = Project.generate!
result = render_principals_for_new_members(project, 3)
assert_select_in result, 'span.pagination'
assert_select_in result, 'span.pagination li.current span', :text => '1'
assert_select_in result, 'a[href=?]', "/projects/#{project.identifier}/memberships/autocomplete.js?page=2", :text => '2'
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 ProjectsHelperTest < Redmine::HelperTest
include ApplicationHelper
include ProjectsHelper
include ERB::Util
include Rails.application.routes.url_helpers
fixtures :projects, :trackers, :issue_statuses, :issues,
:enumerations, :users, :issue_categories,
:versions,
:projects_trackers,
:member_roles,
:members,
:groups_users,
:enabled_modules
def test_link_to_version_within_project
@project = Project.find(2)
User.current = User.find(1)
assert_equal '<a title="07/01/2006" href="/versions/5">Alpha</a>', link_to_version(Version.find(5))
end
def test_link_to_version
User.current = User.find(1)
assert_equal '<a title="07/01/2006" href="/versions/5">OnlineStore - Alpha</a>', link_to_version(Version.find(5))
end
def test_link_to_version_without_effective_date
User.current = User.find(1)
version = Version.find(5)
version.effective_date = nil
assert_equal '<a href="/versions/5">OnlineStore - Alpha</a>', link_to_version(version)
end
def test_link_to_private_version
assert_equal 'OnlineStore - Alpha', link_to_version(Version.find(5))
end
def test_link_to_version_invalid_version
assert_equal '', link_to_version(Object)
end
def test_format_version_name_within_project
@project = Project.find(1)
assert_equal "0.1", format_version_name(Version.find(1))
end
def test_format_version_name
assert_equal "eCookbook - 0.1", format_version_name(Version.find(1))
end
def test_format_version_name_for_system_version
assert_equal "OnlineStore - Systemwide visible version", format_version_name(Version.find(7))
end
def test_version_options_for_select_with_no_versions
assert_equal '', version_options_for_select([])
assert_equal '', version_options_for_select([], Version.find(1))
end
end

View file

@ -0,0 +1,96 @@
# 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 QueriesHelperTest < Redmine::HelperTest
include QueriesHelper
fixtures :projects, :enabled_modules, :users, :members,
:member_roles, :roles, :trackers, :issue_statuses,
:issue_categories, :enumerations, :issues,
:watchers, :custom_fields, :custom_values, :versions,
:queries,
:projects_trackers,
:custom_fields_trackers
def test_filters_options_for_select_should_have_a_blank_option
options = filters_options_for_select(IssueQuery.new)
assert_select_in options, 'option[value=""]'
end
def test_filters_options_for_select_should_not_group_regular_filters
with_locale 'en' do
options = filters_options_for_select(IssueQuery.new)
assert_select_in options, 'optgroup option[value=status_id]', 0
assert_select_in options, 'option[value=status_id]', :text => 'Status'
end
end
def test_filters_options_for_select_should_group_date_filters
with_locale 'en' do
options = filters_options_for_select(IssueQuery.new)
assert_select_in options, 'optgroup[label=?]', 'Date', 1
assert_select_in options, 'optgroup > option[value=due_date]', :text => 'Due date'
end
end
def test_filters_options_for_select_should_not_group_only_one_date_filter
with_locale 'en' do
options = filters_options_for_select(TimeEntryQuery.new)
assert_select_in options, 'option[value=spent_on]'
assert_select_in options, 'optgroup[label=?]', 'Date', 0
assert_select_in options, 'optgroup option[value=spent_on]', 0
end
end
def test_filters_options_for_select_should_group_relations_filters
with_locale 'en' do
options = filters_options_for_select(IssueQuery.new)
assert_select_in options, 'optgroup[label=?]', 'Relations', 1
assert_select_in options, 'optgroup[label=?] > option', 'Relations', 11
assert_select_in options, 'optgroup > option[value=relates]', :text => 'Related to'
end
end
def test_filters_options_for_select_should_group_associations_filters
CustomField.delete_all
cf1 = ProjectCustomField.create!(:name => 'Foo', :field_format => 'string', :is_filter => true)
cf2 = ProjectCustomField.create!(:name => 'Bar', :field_format => 'string', :is_filter => true)
with_locale 'en' do
options = filters_options_for_select(IssueQuery.new)
assert_select_in options, 'optgroup[label=?]', 'Project', 1
assert_select_in options, 'optgroup[label=?] > option', 'Project', 2
assert_select_in options, 'optgroup > option[value=?]', "project.cf_#{cf1.id}", :text => "Project's Foo"
end
end
def test_query_to_csv_should_translate_boolean_custom_field_values
f = IssueCustomField.generate!(:field_format => 'bool', :name => 'Boolean', :is_for_all => true, :trackers => Tracker.all)
issues = [
Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {f.id.to_s => '0'}),
Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {f.id.to_s => '1'})
]
with_locale 'fr' do
csv = query_to_csv(issues, IssueQuery.new(:column_names => ['id', "cf_#{f.id}"]))
assert_include "Oui", csv
assert_include "Non", csv
end
end
end

View file

@ -0,0 +1,43 @@
# 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 RoutesHelperTest < Redmine::HelperTest
fixtures :projects, :issues
include Rails.application.routes.url_helpers
def test_time_entries_path
assert_equal '/projects/ecookbook/time_entries', _time_entries_path(Project.find(1), nil)
assert_equal '/time_entries', _time_entries_path(nil, nil)
end
def test_report_time_entries_path
assert_equal '/projects/ecookbook/time_entries/report', _report_time_entries_path(Project.find(1), nil)
assert_equal '/time_entries/report', _report_time_entries_path(nil, nil)
end
def test_new_time_entry_path
assert_equal '/projects/ecookbook/time_entries/new', _new_time_entry_path(Project.find(1), nil)
assert_equal '/issues/1/time_entries/new', _new_time_entry_path(Project.find(1), Issue.find(1))
assert_equal '/issues/1/time_entries/new', _new_time_entry_path(nil, Issue.find(1))
assert_equal '/time_entries/new', _new_time_entry_path(nil, nil)
end
end

View file

@ -0,0 +1,48 @@
# 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 SearchHelperTest < Redmine::HelperTest
include SearchHelper
include ERB::Util
def test_highlight_single_token
assert_equal 'This is a <span class="highlight token-0">token</span>.',
highlight_tokens('This is a token.', %w(token))
end
def test_highlight_multiple_tokens
assert_equal 'This is a <span class="highlight token-0">token</span> and <span class="highlight token-1">another</span> <span class="highlight token-0">token</span>.',
highlight_tokens('This is a token and another token.', %w(token another))
end
def test_highlight_should_not_exceed_maximum_length
s = (('1234567890' * 100) + ' token ') * 100
r = highlight_tokens(s, %w(token))
assert r.include?('<span class="highlight token-0">token</span>')
assert r.length <= 1300
end
def test_highlight_multibyte
s = ('й' * 200) + ' token ' + ('й' * 200)
r = highlight_tokens(s, %w(token))
assert_equal ('й' * 45) + ' ... ' + ('й' * 44) + ' <span class="highlight token-0">token</span> ' + ('й' * 44) + ' ... ' + ('й' * 45), r
end
end

View file

@ -0,0 +1,30 @@
# 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 SettingsHelperTest < Redmine::HelperTest
include SettingsHelper
include ERB::Util
def test_date_format_setting_options_should_include_human_readable_format
Date.stubs(:today).returns(Date.parse("2015-07-14"))
options = date_format_setting_options('en')
assert_include ["2015-07-14 (yyyy-mm-dd)", "%Y-%m-%d"], options
end
end

View file

@ -0,0 +1,109 @@
# 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 SortHelperTest < Redmine::HelperTest
include SortHelper
include ERB::Util
def setup
super
@session = nil
@sort_param = nil
end
def test_default_sort_clause_with_array
sort_init 'attr1', 'desc'
sort_update(['attr1', 'attr2'])
assert_equal ['attr1 DESC'], sort_clause
end
def test_default_sort_clause_with_hash
sort_init 'attr1', 'desc'
sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
assert_equal ['table1.attr1 DESC'], sort_clause
end
def test_default_sort_clause_with_multiple_columns
sort_init 'attr1', 'desc'
sort_update({'attr1' => ['table1.attr1', 'table1.attr2'], 'attr2' => 'table2.attr2'})
assert_equal ['table1.attr1 DESC', 'table1.attr2 DESC'], sort_clause
end
def test_params_sort
@sort_param = 'attr1,attr2:desc'
sort_init 'attr1', 'desc'
sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
assert_equal ['table1.attr1 ASC', 'table2.attr2 DESC'], sort_clause
assert_equal 'attr1,attr2:desc', @session['foo_bar_sort']
end
def test_invalid_params_sort
@sort_param = 'invalid_key'
sort_init 'attr1', 'desc'
sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
assert_nil sort_clause
assert_equal 'invalid_key', @session['foo_bar_sort']
end
def test_invalid_order_params_sort
@sort_param = 'attr1:foo:bar,attr2'
sort_init 'attr1', 'desc'
sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
assert_equal ['table1.attr1 ASC', 'table2.attr2 ASC'], sort_clause
assert_equal 'attr1,attr2', @session['foo_bar_sort']
end
def test_sort_css_without_params_should_use_default_sort
sort_init 'attr1', 'desc'
sort_update(['attr1', 'attr2'])
assert_equal 'sort-by-attr1 sort-desc', sort_css_classes
end
def test_sort_css_should_use_params
@sort_param = 'attr2,attr1'
sort_init 'attr1', 'desc'
sort_update(['attr1', 'attr2'])
assert_equal 'sort-by-attr2 sort-asc', sort_css_classes
end
def test_sort_css_should_dasherize_sort_name
sort_init 'foo_bar'
sort_update(['foo_bar'])
assert_equal 'sort-by-foo-bar sort-asc', sort_css_classes
end
private
def controller_name; 'foo'; end
def action_name; 'bar'; end
def params; {:sort => @sort_param}; end
def session; @session ||= {}; end
end

View file

@ -0,0 +1,53 @@
# 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 TimelogHelperTest < Redmine::HelperTest
include TimelogHelper
include ActionView::Helpers::TextHelper
include ActionView::Helpers::DateHelper
include ERB::Util
fixtures :projects, :roles, :enabled_modules, :users,
:repositories, :changesets,
:trackers, :issue_statuses, :issues, :versions, :documents,
:wikis, :wiki_pages, :wiki_contents,
:boards, :messages,
:attachments,
:enumerations
def test_activities_collection_for_select_options_should_return_array_of_activity_names_and_ids
activities = activity_collection_for_select_options
assert activities.include?(["Design", 9])
assert activities.include?(["Development", 10])
end
def test_activities_collection_for_select_options_should_not_include_inactive_activities
activities = activity_collection_for_select_options
assert !activities.include?(["Inactive Activity", 14])
end
def test_activities_collection_for_select_options_should_use_the_projects_override
project = Project.find(1)
override_activity = TimeEntryActivity.create!({:name => "Design override", :parent => TimeEntryActivity.find_by_name("Design"), :project => project})
activities = activity_collection_for_select_options(nil, project)
assert !activities.include?(["Design", 9]), "System activity found in: " + activities.inspect
assert activities.include?(["Design override", override_activity.id]), "Override activity not found in: " + activities.inspect
end
end

View file

@ -0,0 +1,54 @@
# 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 VersionsHelperTest < Redmine::HelperTest
include Rails.application.routes.url_helpers
fixtures :projects, :versions
def test_version_filtered_issues_path_sharing_none
version = Version.new(:name => 'test', :sharing => 'none')
version.project = Project.find(5)
assert_match '/projects/private-child/issues?', version_filtered_issues_path(version)
end
def test_version_filtered_issues_path_sharing_descendants
version = Version.new(:name => 'test', :sharing => 'descendants')
version.project = Project.find(5)
assert_match '/projects/private-child/issues?', version_filtered_issues_path(version)
end
def test_version_filtered_issues_path_sharing_hierarchy
version = Version.new(:name => 'test', :sharing => 'hierarchy')
version.project = Project.find(5)
assert_match '/projects/ecookbook/issues?', version_filtered_issues_path(version)
end
def test_version_filtered_issues_path_sharing_tree
version = Version.new(:name => 'test', :sharing => 'tree')
version.project = Project.find(5)
assert_match '/projects/ecookbook/issues?', version_filtered_issues_path(version)
end
def test_version_filtered_issues_path_sharing_system
version = Version.new(:name => 'test', :sharing => 'system')
version.project = Project.find(5)
assert_match /^\/issues\?/, version_filtered_issues_path(version)
end
end

View file

@ -0,0 +1,67 @@
# 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 WatchersHelperTest < Redmine::HelperTest
include WatchersHelper
include Rails.application.routes.url_helpers
fixtures :users, :issues
test '#watcher_link with a non-watched object' do
expected = link_to(
"Watch",
"/watchers/watch?object_id=1&object_type=issue",
:remote => true, :method => 'post', :class => "issue-1-watcher icon icon-fav-off"
)
assert_equal expected, watcher_link(Issue.find(1), User.find(1))
end
test '#watcher_link with a single objet array' do
expected = link_to(
"Watch",
"/watchers/watch?object_id=1&object_type=issue",
:remote => true, :method => 'post', :class => "issue-1-watcher icon icon-fav-off"
)
assert_equal expected, watcher_link([Issue.find(1)], User.find(1))
end
test '#watcher_link with a multiple objets array' do
expected = link_to(
"Watch",
"/watchers/watch?object_id%5B%5D=1&object_id%5B%5D=3&object_type=issue",
:remote => true, :method => 'post', :class => "issue-bulk-watcher icon icon-fav-off"
)
assert_equal expected, watcher_link([Issue.find(1), Issue.find(3)], User.find(1))
end
def test_watcher_link_with_nil_should_return_empty_string
assert_equal '', watcher_link(nil, User.find(1))
end
test '#watcher_link with a watched object' do
Watcher.create!(:watchable => Issue.find(1), :user => User.find(1))
expected = link_to(
"Unwatch",
"/watchers/watch?object_id=1&object_type=issue",
:remote => true, :method => 'delete', :class => "issue-1-watcher icon icon-fav"
)
assert_equal expected, watcher_link(Issue.find(1), User.find(1))
end
end

View file

@ -0,0 +1,45 @@
# 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 WikiHelperTest < Redmine::HelperTest
include WikiHelper
include Rails.application.routes.url_helpers
fixtures :projects, :users,
:roles, :member_roles, :members,
:enabled_modules, :wikis, :wiki_pages
def test_wiki_page_edit_cancel_path_for_new_page_without_parent_should_be_wiki_index
wiki = Wiki.find(1)
page = WikiPage.new(:wiki => wiki)
assert_equal '/projects/ecookbook/wiki/index', wiki_page_edit_cancel_path(page)
end
def test_wiki_page_edit_cancel_path_for_new_page_with_parent_should_be_parent
wiki = Wiki.find(1)
page = WikiPage.new(:wiki => wiki, :parent => wiki.find_page('Another_page'))
assert_equal '/projects/ecookbook/wiki/Another_page', wiki_page_edit_cancel_path(page)
end
def test_wiki_page_edit_cancel_path_for_existing_page_should_be_the_page
wiki = Wiki.find(1)
page = wiki.find_page('Child_1')
assert_equal '/projects/ecookbook/wiki/Child_1', wiki_page_edit_cancel_path(page)
end
end

View file

@ -0,0 +1,95 @@
# 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 PatchesTest < ActiveSupport::TestCase
include Redmine::I18n
def setup
Setting.default_language = 'en'
@symbols = { :a => 1, :b => 2 }
@keys = %w( blue green red pink orange )
@values = %w( 000099 009900 aa0000 cc0066 cc6633 )
@hash = Hash.new
@ordered_hash = ActiveSupport::OrderedHash.new
@keys.each_with_index do |key, index|
@hash[key] = @values[index]
@ordered_hash[key] = @values[index]
end
end
test "ActiveRecord::Base.human_attribute_name should transform name to field_name" do
assert_equal l('field_last_login_on'), ActiveRecord::Base.human_attribute_name('last_login_on')
end
test "ActiveRecord::Base.human_attribute_name should cut extra _id suffix for better validation" do
assert_equal l('field_last_login_on'), ActiveRecord::Base.human_attribute_name('last_login_on_id')
end
test "ActiveRecord::Base.human_attribute_name should default to humanized value if no translation has been found (useful for custom fields)" do
assert_equal 'Patch name', ActiveRecord::Base.human_attribute_name('Patch name')
end
# https://github.com/rails/rails/pull/14198/files
def test_indifferent_select
hash = ActiveSupport::HashWithIndifferentAccess.new(@symbols).select { |_ ,v| v == 1 }
assert_equal({ 'a' => 1 }, hash)
assert_instance_of ((Rails::VERSION::MAJOR < 4 && RUBY_VERSION < "2.1") ?
Hash : ActiveSupport::HashWithIndifferentAccess),
hash
end
def test_indifferent_select_bang
indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@symbols)
indifferent_strings.select! { |_, v| v == 1 }
assert_equal({ 'a' => 1 }, indifferent_strings)
assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings
end
def test_indifferent_reject
hash = ActiveSupport::HashWithIndifferentAccess.new(@symbols).reject { |_, v| v != 1 }
assert_equal({ 'a' => 1 }, hash)
assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash
end
def test_indifferent_reject_bang
indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@symbols)
indifferent_strings.reject! { |_, v| v != 1 }
assert_equal({ 'a' => 1 }, indifferent_strings)
assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings
end
def test_select
assert_equal @keys, @ordered_hash.select { true }.map(&:first)
new_ordered_hash = @ordered_hash.select { true }
assert_equal @keys, new_ordered_hash.map(&:first)
assert_instance_of ((Rails::VERSION::MAJOR < 4 && RUBY_VERSION < "2.1") ?
Hash : ActiveSupport::OrderedHash),
new_ordered_hash
end
def test_reject
copy = @ordered_hash.dup
new_ordered_hash = @ordered_hash.reject { |k, _| k == 'pink' }
assert_equal copy, @ordered_hash
assert !new_ordered_hash.keys.include?('pink')
assert @ordered_hash.keys.include?('pink')
assert_instance_of ActiveSupport::OrderedHash, new_ordered_hash
end
end

View file

@ -0,0 +1,54 @@
# 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 IssueCategoryTest < ActiveSupport::TestCase
fixtures :issue_categories, :issues, :users, :groups_users
def setup
@category = IssueCategory.find(1)
end
def test_create
assert IssueCategory.new(:project_id => 2, :name => 'New category').save
category = IssueCategory.order('id DESC').first
assert_equal 'New category', category.name
end
def test_create_with_group_assignment
assert IssueCategory.new(:project_id => 2, :name => 'Group assignment', :assigned_to_id => 11).save
category = IssueCategory.order('id DESC').first
assert_kind_of Group, category.assigned_to
assert_equal Group.find(11), category.assigned_to
end
def test_destroy
issue = @category.issues.first
@category.destroy
# Make sure the category was nullified on the issue
assert_nil issue.reload.category
end
def test_destroy_with_reassign
issue = @category.issues.first
reassign_to = IssueCategory.find(2)
@category.destroy(reassign_to)
# Make sure the issue was reassigned
assert_equal reassign_to, issue.reload.category
end
end

View file

@ -0,0 +1,42 @@
# 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 IssueCustomFieldTest < ActiveSupport::TestCase
include Redmine::I18n
fixtures :roles
def test_custom_field_with_visible_set_to_false_should_validate_roles
set_language_if_valid 'en'
field = IssueCustomField.new(:name => 'Field', :field_format => 'string', :visible => false)
assert !field.save
assert_include "Roles cannot be blank", field.errors.full_messages
field.role_ids = [1, 2]
assert field.save
end
def test_changing_visible_to_true_should_clear_roles
field = IssueCustomField.create!(:name => 'Field', :field_format => 'string', :visible => false, :role_ids => [1, 2])
assert_equal 2, field.roles.count
field.visible = true
field.save!
assert_equal 0, field.roles.count
end
end

View file

@ -0,0 +1,191 @@
# 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 IssueImportTest < ActiveSupport::TestCase
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
include Redmine::I18n
def setup
set_language_if_valid 'en'
end
def test_create_versions_should_create_missing_versions
import = generate_import_with_mapping
import.mapping.merge!('fixed_version' => '9', 'create_versions' => '1')
import.save!
version = new_record(Version) do
assert_difference 'Issue.count', 3 do
import.run
end
end
assert_equal '2.1', version.name
end
def test_create_categories_should_create_missing_categories
import = generate_import_with_mapping
import.mapping.merge!('category' => '10', 'create_categories' => '1')
import.save!
category = new_record(IssueCategory) do
assert_difference 'Issue.count', 3 do
import.run
end
end
assert_equal 'New category', category.name
end
def test_mapping_with_fixed_tracker
import = generate_import_with_mapping
import.mapping.merge!('tracker' => 'value:2')
import.save!
issues = new_records(Issue, 3) { import.run }
assert_equal [2], issues.map(&:tracker_id).uniq
end
def test_mapping_with_mapped_tracker
import = generate_import_with_mapping
import.mapping.merge!('tracker' => '13')
import.save!
issues = new_records(Issue, 3) { import.run }
assert_equal [1, 2, 1], issues.map(&:tracker_id)
end
def test_should_not_import_with_default_tracker_when_tracker_is_invalid
Tracker.find_by_name('Feature request').update!(:name => 'Feature')
import = generate_import_with_mapping
import.mapping.merge!('tracker' => '13')
import.save!
import.run
assert_equal 1, import.unsaved_items.count
item = import.unsaved_items.first
assert_include "Tracker cannot be blank", item.message
end
def test_status_should_be_set
import = generate_import_with_mapping
import.mapping.merge!('status' => '14')
import.save!
issues = new_records(Issue, 3) { import.run }
assert_equal ['New', 'New', 'Assigned'], issues.map(&:status).map(&:name)
end
def test_parent_should_be_set
import = generate_import_with_mapping
import.mapping.merge!('parent_issue_id' => '5')
import.save!
issues = new_records(Issue, 3) { import.run }
assert_nil issues[0].parent
assert_equal issues[0].id, issues[1].parent_id
assert_equal 2, issues[2].parent_id
end
def test_backward_and_forward_reference_to_parent_should_work
import = generate_import('import_subtasks.csv')
import.settings = {
'separator' => ";", 'wrapper' => '"', 'encoding' => "UTF-8",
'mapping' => {'project_id' => '1', 'tracker' => '1', 'subject' => '2', 'parent_issue_id' => '3'}
}
import.save!
root, child1, grandchild, child2 = new_records(Issue, 4) { import.run }
assert_equal root, child1.parent
assert_equal child2, grandchild.parent
end
def test_assignee_should_be_set
import = generate_import_with_mapping
import.mapping.merge!('assigned_to' => '11')
import.save!
issues = new_records(Issue, 3) { import.run }
assert_equal [User.find(3), nil, nil], issues.map(&:assigned_to)
end
def test_user_custom_field_should_be_set
field = IssueCustomField.generate!(:field_format => 'user', :is_for_all => true, :trackers => Tracker.all)
import = generate_import_with_mapping
import.mapping.merge!("cf_#{field.id}" => '11')
import.save!
issues = new_records(Issue, 3) { import.run }
assert_equal '3', issues.first.custom_field_value(field)
end
def test_is_private_should_be_set_based_on_user_locale
import = generate_import_with_mapping
import.mapping.merge!('is_private' => '6')
import.save!
issues = new_records(Issue, 3) { import.run }
assert_equal [false, true, false], issues.map(&:is_private)
end
def test_dates_should_be_parsed_using_date_format_setting
field = IssueCustomField.generate!(:field_format => 'date', :is_for_all => true, :trackers => Tracker.all)
import = generate_import_with_mapping('import_dates.csv')
import.settings.merge!('date_format' => Import::DATE_FORMATS[1])
import.mapping.merge!('tracker' => 'value:1', 'subject' => '0', 'start_date' => '1', 'due_date' => '2', "cf_#{field.id}" => '3')
import.save!
issue = new_record(Issue) { import.run } # only 1 valid issue
assert_equal "Valid dates", issue.subject
assert_equal Date.parse('2015-07-10'), issue.start_date
assert_equal Date.parse('2015-08-12'), issue.due_date
assert_equal '2015-07-14', issue.custom_field_value(field)
end
def test_date_format_should_default_to_user_language
user = User.generate!(:language => 'fr')
import = Import.new
import.user = user
assert_nil import.settings['date_format']
import.set_default_settings
assert_equal '%d/%m/%Y', import.settings['date_format']
end
def test_run_should_remove_the_file
import = generate_import_with_mapping
file_path = import.filepath
assert File.exists?(file_path)
import.run
assert !File.exists?(file_path)
end
end

View file

@ -0,0 +1,96 @@
# 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 IssueNestedSetConcurrencyTest < ActiveSupport::TestCase
fixtures :projects, :users,
:trackers, :projects_trackers,
:enabled_modules,
:issue_statuses,
:enumerations
self.use_transactional_fixtures = false
def setup
skip if sqlite? || mysql?
CustomField.delete_all
end
def teardown
Issue.delete_all
end
def test_concurrency
# Generates an issue and destroys it in order
# to load all needed classes before starting threads
i = Issue.generate!
i.destroy
root = Issue.generate!
assert_difference 'Issue.count', 60 do
threaded(3) do
10.times do
i = Issue.generate! :parent_issue_id => root.id
c1 = Issue.generate! :parent_issue_id => i.id
c2 = Issue.generate! :parent_issue_id => i.id
c3 = Issue.generate! :parent_issue_id => i.id
c2.reload.destroy
c1.reload.destroy
end
end
end
end
def test_concurrent_subtasks_creation
root = Issue.generate!
assert_difference 'Issue.count', 30 do
threaded(3) do
10.times do
Issue.generate! :parent_issue_id => root.id
end
end
end
root.reload
assert_equal [1, 62], [root.lft, root.rgt]
children_bounds = root.children.sort_by(&:lft).map {|c| [c.lft, c.rgt]}.flatten
assert_equal (2..61).to_a, children_bounds
end
private
def threaded(count, &block)
with_settings :notified_events => [] do
threads = []
count.times do |i|
threads << Thread.new(i) do
ActiveRecord::Base.connection_pool.with_connection do
begin
yield
rescue Exception => e
Thread.current[:exception] = e.message
end
end
end
end
threads.each do |thread|
thread.join
assert_nil thread[:exception]
end
end
end
end

View file

@ -0,0 +1,328 @@
# 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 IssueNestedSetTest < ActiveSupport::TestCase
fixtures :projects, :users, :roles,
:trackers, :projects_trackers,
:issue_statuses, :issue_categories, :issue_relations,
:enumerations,
:issues
def test_new_record_is_leaf
i = Issue.new
assert i.leaf?
end
def test_create_root_issue
lft1 = new_issue_lft
issue1 = Issue.generate!
lft2 = new_issue_lft
issue2 = Issue.generate!
issue1.reload
issue2.reload
assert_equal [issue1.id, nil, lft1, lft1 + 1], [issue1.root_id, issue1.parent_id, issue1.lft, issue1.rgt]
assert_equal [issue2.id, nil, lft2, lft2 + 1], [issue2.root_id, issue2.parent_id, issue2.lft, issue2.rgt]
end
def test_create_child_issue
lft = new_issue_lft
parent = Issue.generate!
child = parent.generate_child!
parent.reload
child.reload
assert_equal [parent.id, nil, lft, lft + 3], [parent.root_id, parent.parent_id, parent.lft, parent.rgt]
assert_equal [parent.id, parent.id, lft + 1, lft + 2], [child.root_id, child.parent_id, child.lft, child.rgt]
end
def test_creating_a_child_in_a_subproject_should_validate
issue = Issue.generate!
child = Issue.new(:project_id => 3, :tracker_id => 2, :author_id => 1,
:subject => 'child', :parent_issue_id => issue.id)
assert_save child
assert_equal issue, child.reload.parent
end
def test_creating_a_child_in_an_invalid_project_should_not_validate
issue = Issue.generate!
child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
:subject => 'child', :parent_issue_id => issue.id)
assert !child.save
assert_not_equal [], child.errors[:parent_issue_id]
end
def test_move_a_root_to_child
lft = new_issue_lft
parent1 = Issue.generate!
parent2 = Issue.generate!
child = parent1.generate_child!
parent2.parent_issue_id = parent1.id
parent2.save!
child.reload
parent1.reload
parent2.reload
assert_equal [parent1.id, lft, lft + 5], [parent1.root_id, parent1.lft, parent1.rgt]
assert_equal [parent1.id, lft + 1, lft + 2], [parent2.root_id, parent2.lft, parent2.rgt]
assert_equal [parent1.id, lft + 3, lft + 4], [child.root_id, child.lft, child.rgt]
end
def test_move_a_child_to_root
lft1 = new_issue_lft
parent1 = Issue.generate!
lft2 = new_issue_lft
parent2 = Issue.generate!
lft3 = new_issue_lft
child = parent1.generate_child!
child.parent_issue_id = nil
child.save!
child.reload
parent1.reload
parent2.reload
assert_equal [parent1.id, lft1, lft1 + 1], [parent1.root_id, parent1.lft, parent1.rgt]
assert_equal [parent2.id, lft2, lft2 + 1], [parent2.root_id, parent2.lft, parent2.rgt]
assert_equal [child.id, lft3, lft3 + 1], [child.root_id, child.lft, child.rgt]
end
def test_move_a_child_to_another_issue
lft1 = new_issue_lft
parent1 = Issue.generate!
lft2 = new_issue_lft
parent2 = Issue.generate!
child = parent1.generate_child!
child.parent_issue_id = parent2.id
child.save!
child.reload
parent1.reload
parent2.reload
assert_equal [parent1.id, lft1, lft1 + 1], [parent1.root_id, parent1.lft, parent1.rgt]
assert_equal [parent2.id, lft2, lft2 + 3], [parent2.root_id, parent2.lft, parent2.rgt]
assert_equal [parent2.id, lft2 + 1, lft2 + 2], [child.root_id, child.lft, child.rgt]
end
def test_move_a_child_with_descendants_to_another_issue
lft1 = new_issue_lft
parent1 = Issue.generate!
lft2 = new_issue_lft
parent2 = Issue.generate!
child = parent1.generate_child!
grandchild = child.generate_child!
parent1.reload
parent2.reload
child.reload
grandchild.reload
assert_equal [parent1.id, lft1, lft1 + 5], [parent1.root_id, parent1.lft, parent1.rgt]
assert_equal [parent2.id, lft2, lft2 + 1], [parent2.root_id, parent2.lft, parent2.rgt]
assert_equal [parent1.id, lft1 + 1, lft1 + 4], [child.root_id, child.lft, child.rgt]
assert_equal [parent1.id, lft1 + 2, lft1 + 3], [grandchild.root_id, grandchild.lft, grandchild.rgt]
child.reload.parent_issue_id = parent2.id
child.save!
child.reload
grandchild.reload
parent1.reload
parent2.reload
assert_equal [parent1.id, lft1, lft1 + 1], [parent1.root_id, parent1.lft, parent1.rgt]
assert_equal [parent2.id, lft2, lft2 + 5], [parent2.root_id, parent2.lft, parent2.rgt]
assert_equal [parent2.id, lft2 + 1, lft2 + 4], [child.root_id, child.lft, child.rgt]
assert_equal [parent2.id, lft2 + 2, lft2 + 3], [grandchild.root_id, grandchild.lft, grandchild.rgt]
end
def test_move_a_child_with_descendants_to_another_project
lft1 = new_issue_lft
parent1 = Issue.generate!
child = parent1.generate_child!
grandchild = child.generate_child!
lft4 = new_issue_lft
child.reload
child.project = Project.find(2)
assert child.save
child.reload
grandchild.reload
parent1.reload
assert_equal [1, parent1.id, lft1, lft1 + 1], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt]
assert_equal [2, child.id, lft4, lft4 + 3],
[child.project_id, child.root_id, child.lft, child.rgt]
assert_equal [2, child.id, lft4 + 1, lft4 + 2],
[grandchild.project_id, grandchild.root_id, grandchild.lft, grandchild.rgt]
end
def test_moving_an_issue_to_a_descendant_should_not_validate
parent1 = Issue.generate!
parent2 = Issue.generate!
child = parent1.generate_child!
grandchild = child.generate_child!
child.reload
child.parent_issue_id = grandchild.id
assert !child.save
assert_not_equal [], child.errors[:parent_issue_id]
end
def test_updating_a_root_issue_should_not_trigger_update_nested_set_attributes_on_parent_change
issue = Issue.find(Issue.generate!.id)
issue.parent_issue_id = ""
issue.expects(:update_nested_set_attributes_on_parent_change).never
issue.save!
end
def test_updating_a_child_issue_should_not_trigger_update_nested_set_attributes_on_parent_change
issue = Issue.find(Issue.generate!(:parent_issue_id => 1).id)
issue.parent_issue_id = "1"
issue.expects(:update_nested_set_attributes_on_parent_change).never
issue.save!
end
def test_moving_a_root_issue_should_trigger_update_nested_set_attributes_on_parent_change
issue = Issue.find(Issue.generate!.id)
issue.parent_issue_id = "1"
issue.expects(:update_nested_set_attributes_on_parent_change).once
issue.save!
end
def test_moving_a_child_issue_to_another_parent_should_trigger_update_nested_set_attributes_on_parent_change
issue = Issue.find(Issue.generate!(:parent_issue_id => 1).id)
issue.parent_issue_id = "2"
issue.expects(:update_nested_set_attributes_on_parent_change).once
issue.save!
end
def test_moving_a_child_issue_to_root_should_trigger_update_nested_set_attributes_on_parent_change
issue = Issue.find(Issue.generate!(:parent_issue_id => 1).id)
issue.parent_issue_id = ""
issue.expects(:update_nested_set_attributes_on_parent_change).once
issue.save!
end
def test_destroy_should_destroy_children
lft1 = new_issue_lft
issue1 = Issue.generate!
issue2 = Issue.generate!
issue3 = issue2.generate_child!
issue4 = issue1.generate_child!
issue3.init_journal(User.find(2))
issue3.subject = 'child with journal'
issue3.save!
assert_difference 'Issue.count', -2 do
assert_difference 'Journal.count', -1 do
assert_difference 'JournalDetail.count', -1 do
Issue.find(issue2.id).destroy
end
end
end
issue1.reload
issue4.reload
assert !Issue.exists?(issue2.id)
assert !Issue.exists?(issue3.id)
assert_equal [issue1.id, lft1, lft1 + 3], [issue1.root_id, issue1.lft, issue1.rgt]
assert_equal [issue1.id, lft1 + 1, lft1 + 2], [issue4.root_id, issue4.lft, issue4.rgt]
end
def test_destroy_child_should_update_parent
lft1 = new_issue_lft
issue = Issue.generate!
child1 = issue.generate_child!
child2 = issue.generate_child!
issue.reload
assert_equal [issue.id, lft1, lft1 + 5], [issue.root_id, issue.lft, issue.rgt]
child2.reload.destroy
issue.reload
assert_equal [issue.id, lft1, lft1 + 3], [issue.root_id, issue.lft, issue.rgt]
end
def test_destroy_parent_issue_updated_during_children_destroy
parent = Issue.generate!
parent.generate_child!(:start_date => Date.today)
parent.generate_child!(:start_date => 2.days.from_now)
assert_difference 'Issue.count', -3 do
Issue.find(parent.id).destroy
end
end
def test_destroy_child_issue_with_children
root = Issue.generate!
child = root.generate_child!
leaf = child.generate_child!
leaf.init_journal(User.find(2))
leaf.subject = 'leaf with journal'
leaf.save!
assert_difference 'Issue.count', -2 do
assert_difference 'Journal.count', -1 do
assert_difference 'JournalDetail.count', -1 do
Issue.find(child.id).destroy
end
end
end
root = Issue.find(root.id)
assert root.leaf?, "Root issue is not a leaf (lft: #{root.lft}, rgt: #{root.rgt})"
end
def test_destroy_issue_with_grand_child
lft1 = new_issue_lft
parent = Issue.generate!
issue = parent.generate_child!
child = issue.generate_child!
grandchild1 = child.generate_child!
grandchild2 = child.generate_child!
assert_difference 'Issue.count', -4 do
Issue.find(issue.id).destroy
parent.reload
assert_equal [lft1, lft1 + 1], [parent.lft, parent.rgt]
end
end
def test_project_copy_should_copy_issue_tree
p = Project.create!(:name => 'Tree copy', :identifier => 'tree-copy', :tracker_ids => [1, 2])
i1 = Issue.generate!(:project => p, :subject => 'i1')
i2 = i1.generate_child!(:project => p, :subject => 'i2')
i3 = i1.generate_child!(:project => p, :subject => 'i3')
i4 = i2.generate_child!(:project => p, :subject => 'i4')
i5 = Issue.generate!(:project => p, :subject => 'i5')
c = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1, 2])
c.copy(p, :only => 'issues')
c.reload
assert_equal 5, c.issues.count
ic1, ic2, ic3, ic4, ic5 = c.issues.order('subject').to_a
assert ic1.root?
assert_equal ic1, ic2.parent
assert_equal ic1, ic3.parent
assert_equal ic2, ic4.parent
assert ic5.root?
end
def test_rebuild_single_tree
i1 = Issue.generate!
i2 = i1.generate_child!
i3 = i1.generate_child!
Issue.update_all(:lft => 7, :rgt => 7)
Issue.rebuild_single_tree!(i1.id)
i1.reload
assert_equal [1, 6], [i1.lft, i1.rgt]
i2.reload
assert_equal [2, 3], [i2.lft, i2.rgt]
i3.reload
assert_equal [4, 5], [i3.lft, i3.rgt]
other = Issue.find(1)
assert_equal [7, 7], [other.lft, other.rgt]
end
end

View file

@ -0,0 +1,102 @@
# 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 IssuePriorityTest < ActiveSupport::TestCase
fixtures :enumerations, :issues
def test_named_scope
assert_equal Enumeration.find_by_name('Normal'), Enumeration.named('normal').first
end
def test_default_should_return_the_default_priority
assert_equal Enumeration.find_by_name('Normal'), IssuePriority.default
end
def test_default_should_return_nil_when_no_default_priority
IssuePriority.update_all :is_default => false
assert_nil IssuePriority.default
end
def test_should_be_an_enumeration
assert IssuePriority.ancestors.include?(Enumeration)
end
def test_objects_count
# low priority
assert_equal 6, IssuePriority.find(4).objects_count
# urgent
assert_equal 0, IssuePriority.find(7).objects_count
end
def test_option_name
assert_equal :enumeration_issue_priorities, IssuePriority.new.option_name
end
def test_should_be_created_at_last_position
IssuePriority.delete_all
priorities = [1, 2, 3].map {|i| IssuePriority.create!(:name => "P#{i}")}
assert_equal [1, 2, 3], priorities.map(&:position)
end
def test_clear_position_names_should_set_position_names_to_nil
IssuePriority.clear_position_names
assert IssuePriority.all.all? {|priority| priority.position_name.nil?}
end
def test_compute_position_names_with_default_priority
IssuePriority.clear_position_names
IssuePriority.compute_position_names
assert_equal %w(lowest default high3 high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
end
def test_compute_position_names_without_default_priority_should_split_priorities
IssuePriority.clear_position_names
IssuePriority.update_all :is_default => false
IssuePriority.compute_position_names
assert_equal %w(lowest low2 default high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
end
def test_adding_a_priority_should_update_position_names
priority = IssuePriority.create!(:name => 'New')
assert_equal %w(lowest default high4 high3 high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
end
def test_moving_a_priority_should_update_position_names
prio = IssuePriority.first
prio.position = IssuePriority.count
prio.save!
prio.reload
assert_equal 'highest', prio.position_name
end
def test_deactivating_a_priority_should_update_position_names
prio = IssuePriority.active.order(:position).last
prio.active = false
prio.save
assert_equal 'highest', IssuePriority.active.order(:position).last.position_name
end
def test_destroying_a_priority_should_update_position_names
IssuePriority.find_by_position_name('highest').destroy
assert_equal %w(lowest default high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
end
end

View file

@ -0,0 +1,250 @@
# 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 IssueRelationTest < ActiveSupport::TestCase
fixtures :projects,
:users,
:roles,
:members,
:member_roles,
:issues,
:issue_statuses,
:issue_relations,
:enabled_modules,
:enumerations,
:trackers,
:projects_trackers
include Redmine::I18n
def test_create
from = Issue.find(1)
to = Issue.find(2)
relation = IssueRelation.new :issue_from => from, :issue_to => to,
:relation_type => IssueRelation::TYPE_PRECEDES
assert relation.save
relation.reload
assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type
assert_equal from, relation.issue_from
assert_equal to, relation.issue_to
end
def test_create_minimum
relation = IssueRelation.new :issue_from => Issue.find(1), :issue_to => Issue.find(2)
assert relation.save
assert_equal IssueRelation::TYPE_RELATES, relation.relation_type
end
def test_follows_relation_should_be_reversed
from = Issue.find(1)
to = Issue.find(2)
relation = IssueRelation.new :issue_from => from, :issue_to => to,
:relation_type => IssueRelation::TYPE_FOLLOWS
assert relation.save
relation.reload
assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type
assert_equal to, relation.issue_from
assert_equal from, relation.issue_to
end
def test_cannot_create_inverse_relates_relations
from = Issue.find(1)
to = Issue.find(2)
relation1 = IssueRelation.new :issue_from => from, :issue_to => to,
:relation_type => IssueRelation::TYPE_RELATES
assert relation1.save
relation2 = IssueRelation.new :issue_from => to, :issue_to => from,
:relation_type => IssueRelation::TYPE_RELATES
assert !relation2.save
assert_not_equal [], relation2.errors[:base]
end
def test_follows_relation_should_not_be_reversed_if_validation_fails
from = Issue.find(1)
to = Issue.find(2)
relation = IssueRelation.new :issue_from => from, :issue_to => to,
:relation_type => IssueRelation::TYPE_FOLLOWS,
:delay => 'xx'
assert !relation.save
assert_equal IssueRelation::TYPE_FOLLOWS, relation.relation_type
assert_equal from, relation.issue_from
assert_equal to, relation.issue_to
end
def test_relation_type_for
from = Issue.find(1)
to = Issue.find(2)
relation = IssueRelation.new :issue_from => from, :issue_to => to,
:relation_type => IssueRelation::TYPE_PRECEDES
assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type_for(from)
assert_equal IssueRelation::TYPE_FOLLOWS, relation.relation_type_for(to)
end
def test_set_issue_to_dates_without_issue_to
r = IssueRelation.new(:issue_from => Issue.new(:start_date => Date.today),
:relation_type => IssueRelation::TYPE_PRECEDES,
:delay => 1)
assert_nil r.set_issue_to_dates
end
def test_set_issue_to_dates_without_issues
r = IssueRelation.new(:relation_type => IssueRelation::TYPE_PRECEDES, :delay => 1)
assert_nil r.set_issue_to_dates
end
def test_validates_circular_dependency
IssueRelation.delete_all
assert IssueRelation.create!(
:issue_from => Issue.find(1), :issue_to => Issue.find(2),
:relation_type => IssueRelation::TYPE_PRECEDES
)
assert IssueRelation.create!(
:issue_from => Issue.find(2), :issue_to => Issue.find(3),
:relation_type => IssueRelation::TYPE_PRECEDES
)
r = IssueRelation.new(
:issue_from => Issue.find(3), :issue_to => Issue.find(1),
:relation_type => IssueRelation::TYPE_PRECEDES
)
assert !r.save
assert_not_equal [], r.errors[:base]
end
def test_validates_circular_dependency_of_subtask
set_language_if_valid 'en'
issue1 = Issue.generate!
issue2 = Issue.generate!
IssueRelation.create!(
:issue_from => issue1, :issue_to => issue2,
:relation_type => IssueRelation::TYPE_PRECEDES
)
child = Issue.generate!(:parent_issue_id => issue2.id)
issue1.reload
child.reload
r = IssueRelation.new(
:issue_from => child, :issue_to => issue1,
:relation_type => IssueRelation::TYPE_PRECEDES
)
assert !r.save
assert_include 'This relation would create a circular dependency', r.errors.full_messages
end
def test_subtasks_should_allow_precedes_relation
parent = Issue.generate!
child1 = Issue.generate!(:parent_issue_id => parent.id)
child2 = Issue.generate!(:parent_issue_id => parent.id)
r = IssueRelation.new(
:issue_from => child1, :issue_to => child2,
:relation_type => IssueRelation::TYPE_PRECEDES
)
assert r.valid?
assert r.save
end
def test_validates_circular_dependency_on_reverse_relations
IssueRelation.delete_all
assert IssueRelation.create!(
:issue_from => Issue.find(1), :issue_to => Issue.find(3),
:relation_type => IssueRelation::TYPE_BLOCKS
)
assert IssueRelation.create!(
:issue_from => Issue.find(1), :issue_to => Issue.find(2),
:relation_type => IssueRelation::TYPE_BLOCKED
)
r = IssueRelation.new(
:issue_from => Issue.find(2), :issue_to => Issue.find(1),
:relation_type => IssueRelation::TYPE_BLOCKED
)
assert !r.save
assert_not_equal [], r.errors[:base]
end
def test_create_with_initialized_journals_should_create_journals
from = Issue.find(1)
to = Issue.find(2)
from_journals = from.journals.size
to_journals = to.journals.size
relation = IssueRelation.new(:issue_from => from, :issue_to => to,
:relation_type => IssueRelation::TYPE_PRECEDES)
relation.init_journals User.find(1)
assert relation.save
from.reload
to.reload
relation.reload
assert_equal from.journals.size, (from_journals + 1)
assert_equal to.journals.size, (to_journals + 1)
assert_equal 'relation', from.journals.last.details.last.property
assert_equal 'precedes', from.journals.last.details.last.prop_key
assert_equal '2', from.journals.last.details.last.value
assert_nil from.journals.last.details.last.old_value
assert_equal 'relation', to.journals.last.details.last.property
assert_equal 'follows', to.journals.last.details.last.prop_key
assert_equal '1', to.journals.last.details.last.value
assert_nil to.journals.last.details.last.old_value
end
def test_destroy_with_initialized_journals_should_create_journals
relation = IssueRelation.find(1)
from = relation.issue_from
to = relation.issue_to
from_journals = from.journals.size
to_journals = to.journals.size
relation.init_journals User.find(1)
assert relation.destroy
from.reload
to.reload
assert_equal from.journals.size, (from_journals + 1)
assert_equal to.journals.size, (to_journals + 1)
assert_equal 'relation', from.journals.last.details.last.property
assert_equal 'blocks', from.journals.last.details.last.prop_key
assert_equal '9', from.journals.last.details.last.old_value
assert_nil from.journals.last.details.last.value
assert_equal 'relation', to.journals.last.details.last.property
assert_equal 'blocked', to.journals.last.details.last.prop_key
assert_equal '10', to.journals.last.details.last.old_value
assert_nil to.journals.last.details.last.value
end
def test_to_s_should_return_the_relation_string
set_language_if_valid 'en'
relation = IssueRelation.find(1)
assert_equal "Blocks #9", relation.to_s(relation.issue_from)
assert_equal "Blocked by #10", relation.to_s(relation.issue_to)
end
def test_to_s_without_argument_should_return_the_relation_string_for_issue_from
set_language_if_valid 'en'
relation = IssueRelation.find(1)
assert_equal "Blocks #9", relation.to_s
end
def test_to_s_should_accept_a_block_as_custom_issue_formatting
set_language_if_valid 'en'
relation = IssueRelation.find(1)
assert_equal "Blocks Bug #9", relation.to_s {|issue| "#{issue.tracker} ##{issue.id}"}
end
end

View file

@ -0,0 +1,69 @@
# 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 IssueScopesTest < ActiveSupport::TestCase
fixtures :projects, :users, :members, :member_roles, :roles,
:groups_users,
:trackers, :projects_trackers,
:enabled_modules,
:versions, :issue_statuses, :issue_categories, :enumerations,
:issues,
:custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values
def test_cross_project_scope_without_project_should_return_all_issues
ids = Issue.cross_project_scope(nil).pluck(:id).sort
assert_equal Issue.pluck(:id).sort, ids
end
def test_cross_project_scope_with_project_should_return_project_issues
project = Project.find(1)
ids = Issue.cross_project_scope(project).pluck(:id).sort
assert_equal project.issues.pluck(:id).sort, ids
end
def test_cross_project_scope_with_all_scope_should_return_all_issues
project = Project.find(1)
ids = Issue.cross_project_scope(project, 'all').pluck(:id).sort
assert_equal Issue.pluck(:id).sort, ids
end
def test_cross_project_scope_with_system_scope_should_return_all_issues
project = Project.find(1)
ids = Issue.cross_project_scope(project, 'system').pluck(:id).sort
assert_equal Issue.pluck(:id).sort, ids
end
def test_cross_project_scope_with_tree_scope_should_return_tree_issues
project = Project.find(5)
ids = Issue.cross_project_scope(project, 'tree').pluck(:id).sort
assert_equal project.root.self_and_descendants.map{|p| p.issues.pluck(:id)}.flatten.sort, ids
end
def test_cross_project_scope_with_hierarchy_scope_should_return_hierarchy_issues
project = Project.find(5)
ids = Issue.cross_project_scope(project, 'hierarchy').pluck(:id).sort
assert_equal (project.self_and_descendants + project.ancestors).map{|p| p.issues.pluck(:id)}.flatten.sort, ids
end
def test_cross_project_scope_with_descendants_scope_should_return_descendants_issues
project = Project.find(5)
ids = Issue.cross_project_scope(project, 'descendants').pluck(:id).sort
assert_equal project.self_and_descendants.map{|p| p.issues.pluck(:id)}.flatten.sort, ids
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 IssueStatusTest < ActiveSupport::TestCase
fixtures :projects, :users, :members, :member_roles, :roles,
:groups_users,
:trackers, :projects_trackers,
:enabled_modules,
:versions,
:issue_statuses, :issue_categories, :issue_relations, :workflows,
:enumerations,
:issues, :journals, :journal_details,
:custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values
def test_create
status = IssueStatus.new :name => "Assigned"
assert !status.save
# status name uniqueness
assert_equal 1, status.errors.count
status.name = "Test Status"
assert status.save
end
def test_destroy
status = IssueStatus.find(3)
assert_difference 'IssueStatus.count', -1 do
assert status.destroy
end
assert_nil WorkflowTransition.where(:old_status_id => status.id).first
assert_nil WorkflowTransition.where(:new_status_id => status.id).first
end
def test_destroy_status_in_use
# Status assigned to an Issue
status = Issue.find(1).status
assert_raise(RuntimeError, "Cannot delete status") { status.destroy }
end
def test_new_statuses_allowed_to
WorkflowTransition.delete_all
WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false)
WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3, :author => true, :assignee => false)
WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4, :author => false, :assignee => true)
WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5, :author => true, :assignee => true)
status = IssueStatus.find(1)
role = Role.find(1)
tracker = Tracker.find(1)
assert_equal [2], status.new_statuses_allowed_to([role], tracker, false, false).map(&:id)
assert_equal [2], status.find_new_statuses_allowed_to([role], tracker, false, false).map(&:id)
assert_equal [2, 3, 5], status.new_statuses_allowed_to([role], tracker, true, false).map(&:id)
assert_equal [2, 3, 5], status.find_new_statuses_allowed_to([role], tracker, true, false).map(&:id)
assert_equal [2, 4, 5], status.new_statuses_allowed_to([role], tracker, false, true).map(&:id)
assert_equal [2, 4, 5], status.find_new_statuses_allowed_to([role], tracker, false, true).map(&:id)
assert_equal [2, 3, 4, 5], status.new_statuses_allowed_to([role], tracker, true, true).map(&:id)
assert_equal [2, 3, 4, 5], status.find_new_statuses_allowed_to([role], tracker, true, true).map(&:id)
end
def test_update_done_ratios_with_issue_done_ratio_set_to_issue_field_should_change_nothing
IssueStatus.find(1).update_attribute(:default_done_ratio, 50)
with_settings :issue_done_ratio => 'issue_field' do
IssueStatus.update_issue_done_ratios
assert_equal 0, Issue.where(:done_ratio => 50).count
end
end
def test_update_done_ratios_with_issue_done_ratio_set_to_issue_status_should_update_issues
IssueStatus.find(1).update_attribute(:default_done_ratio, 50)
with_settings :issue_done_ratio => 'issue_status' do
IssueStatus.update_issue_done_ratios
issues = Issue.where(:status_id => 1)
assert_equal [50], issues.map {|issue| issue.read_attribute(:done_ratio)}.uniq
end
end
def test_sorted_scope
assert_equal IssueStatus.all.sort, IssueStatus.sorted.to_a
end
def test_named_scope
status = IssueStatus.named("resolved").first
assert_not_nil status
assert_equal "Resolved", status.name
end
def test_setting_status_as_closed_should_set_closed_on_for_issues_without_status_journal
issue = Issue.generate!(:status_id => 1, :created_on => 2.days.ago)
assert_nil issue.closed_on
issue.status.update! :is_closed => true
issue.reload
assert issue.closed?
assert_equal issue.created_on, issue.closed_on
end
def test_setting_status_as_closed_should_set_closed_on_for_issues_with_status_journal
issue = Issue.generate!(:status_id => 1, :created_on => 2.days.ago)
issue.init_journal(User.find(1))
issue.status_id = 2
issue.save!
issue.status.update! :is_closed => true
issue.reload
assert issue.closed?
assert_equal issue.journals.first.created_on, issue.closed_on
end
def test_setting_status_as_closed_should_not_set_closed_on_for_issues_with_other_status
issue = Issue.generate!(:status_id => 2)
IssueStatus.find(1).update! :is_closed => true
issue.reload
assert !issue.closed?
assert_nil issue.closed_on
end
end

View file

@ -0,0 +1,342 @@
# 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 IssueSubtaskingTest < ActiveSupport::TestCase
fixtures :projects, :users, :roles, :members, :member_roles,
:trackers, :projects_trackers,
:issue_statuses, :issue_categories, :enumerations,
:issues,
:enabled_modules,
:workflows
def test_leaf_planning_fields_should_be_editable
issue = Issue.generate!
user = User.find(1)
%w(priority_id done_ratio start_date due_date estimated_hours).each do |attribute|
assert issue.safe_attribute?(attribute, user)
end
end
def test_parent_dates_should_be_read_only_with_parent_issue_dates_set_to_derived
with_settings :parent_issue_dates => 'derived' do
issue = Issue.generate_with_child!
user = User.find(1)
%w(start_date due_date).each do |attribute|
assert !issue.safe_attribute?(attribute, user)
end
end
end
def test_parent_dates_should_be_lowest_start_and_highest_due_dates_with_parent_issue_dates_set_to_derived
with_settings :parent_issue_dates => 'derived' do
parent = Issue.generate!
parent.generate_child!(:start_date => '2010-01-25', :due_date => '2010-02-15')
parent.generate_child!( :due_date => '2010-02-13')
parent.generate_child!(:start_date => '2010-02-01', :due_date => '2010-02-22')
parent.reload
assert_equal Date.parse('2010-01-25'), parent.start_date
assert_equal Date.parse('2010-02-22'), parent.due_date
end
end
def test_reschuling_a_parent_should_reschedule_subtasks_with_parent_issue_dates_set_to_derived
with_settings :parent_issue_dates => 'derived' do
parent = Issue.generate!
c1 = parent.generate_child!(:start_date => '2010-05-12', :due_date => '2010-05-18')
c2 = parent.generate_child!(:start_date => '2010-06-03', :due_date => '2010-06-10')
parent.reload.reschedule_on!(Date.parse('2010-06-02'))
c1.reload
assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-08')], [c1.start_date, c1.due_date]
c2.reload
assert_equal [Date.parse('2010-06-03'), Date.parse('2010-06-10')], [c2.start_date, c2.due_date] # no change
parent.reload
assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-10')], [parent.start_date, parent.due_date]
end
end
def test_parent_priority_should_be_read_only_with_parent_issue_priority_set_to_derived
with_settings :parent_issue_priority => 'derived' do
issue = Issue.generate_with_child!
user = User.find(1)
assert !issue.safe_attribute?('priority_id', user)
end
end
def test_parent_priority_should_be_the_highest_open_child_priority
with_settings :parent_issue_priority => 'derived' do
parent = Issue.generate!(:priority => IssuePriority.find_by_name('Normal'))
# Create children
child1 = parent.generate_child!(:priority => IssuePriority.find_by_name('High'))
assert_equal 'High', parent.reload.priority.name
child2 = child1.generate_child!(:priority => IssuePriority.find_by_name('Immediate'))
assert_equal 'Immediate', child1.reload.priority.name
assert_equal 'Immediate', parent.reload.priority.name
child3 = parent.generate_child!(:priority => IssuePriority.find_by_name('Low'))
child4 = parent.generate_child!(:priority => IssuePriority.find_by_name('Urgent'))
assert_equal 'Immediate', parent.reload.priority.name
# Destroy a child
child1.destroy
assert_equal 'Urgent', parent.reload.priority.name
# Close a child
child4.status = IssueStatus.where(:is_closed => true).first
child4.save!
assert_equal 'Low', parent.reload.priority.name
# Update a child
child3.reload.priority = IssuePriority.find_by_name('Normal')
child3.save!
assert_equal 'Normal', parent.reload.priority.name
# Reopen a child
child4.status = IssueStatus.where(:is_closed => false).first
child4.save!
assert_equal 'Urgent', parent.reload.priority.name
end
end
def test_parent_priority_should_be_set_to_default_when_all_children_are_closed
with_settings :parent_issue_priority => 'derived' do
parent = Issue.generate!
child = parent.generate_child!(:priority => IssuePriority.find_by_name('High'))
assert_equal 'High', parent.reload.priority.name
child.status = IssueStatus.where(:is_closed => true).first
child.save!
assert_equal 'Normal', parent.reload.priority.name
end
end
def test_parent_priority_should_be_left_unchanged_when_all_children_are_closed_and_no_default_priority
IssuePriority.update_all :is_default => false
with_settings :parent_issue_priority => 'derived' do
parent = Issue.generate!(:priority => IssuePriority.find_by_name('Normal'))
child = parent.generate_child!(:priority => IssuePriority.find_by_name('High'))
assert_equal 'High', parent.reload.priority.name
child.status = IssueStatus.where(:is_closed => true).first
child.save!
assert_equal 'High', parent.reload.priority.name
end
end
def test_parent_done_ratio_should_be_read_only_with_parent_issue_done_ratio_set_to_derived
with_settings :parent_issue_done_ratio => 'derived' do
issue = Issue.generate_with_child!
user = User.find(1)
assert !issue.safe_attribute?('done_ratio', user)
end
end
def test_parent_done_ratio_should_be_average_done_ratio_of_leaves
with_settings :parent_issue_done_ratio => 'derived' do
parent = Issue.generate!
parent.generate_child!(:done_ratio => 20)
assert_equal 20, parent.reload.done_ratio
parent.generate_child!(:done_ratio => 70)
assert_equal 45, parent.reload.done_ratio
child = parent.generate_child!(:done_ratio => 0)
assert_equal 30, parent.reload.done_ratio
child.generate_child!(:done_ratio => 30)
assert_equal 30, child.reload.done_ratio
assert_equal 40, parent.reload.done_ratio
end
end
def test_parent_done_ratio_should_be_weighted_by_estimated_times_if_any
with_settings :parent_issue_done_ratio => 'derived' do
parent = Issue.generate!
parent.generate_child!(:estimated_hours => 10, :done_ratio => 20)
assert_equal 20, parent.reload.done_ratio
parent.generate_child!(:estimated_hours => 20, :done_ratio => 50)
assert_equal (50 * 20 + 20 * 10) / 30, parent.reload.done_ratio
end
end
def test_parent_done_ratio_should_be_weighted_by_estimated_times_if_any_with_grandchildren
# parent
# child 1 (2h estd, 0% done)
# child 2 (no estd)
# child a (2h estd, 50% done)
# child b (2h estd, 50% done)
#
# => parent should have a calculated progress of 33%
#
with_settings :parent_issue_done_ratio => 'derived' do
parent = Issue.generate!
parent.generate_child!(:estimated_hours => 2, :done_ratio => 0)
child = parent.generate_child!
child.generate_child!(:estimated_hours => 2, :done_ratio => 50)
child.generate_child!(:estimated_hours => 2, :done_ratio => 50)
assert_equal 50, child.reload.done_ratio
assert_equal 33, parent.reload.done_ratio
end
end
def test_parent_done_ratio_with_child_estimate_to_0_should_reach_100
with_settings :parent_issue_done_ratio => 'derived' do
parent = Issue.generate!
issue1 = parent.generate_child!
issue2 = parent.generate_child!(:estimated_hours => 0)
assert_equal 0, parent.reload.done_ratio
issue1.reload.close!
assert_equal 50, parent.reload.done_ratio
issue2.reload.close!
assert_equal 100, parent.reload.done_ratio
end
end
def test_done_ratio_of_parent_with_a_child_without_estimated_time_should_not_exceed_100
with_settings :parent_issue_done_ratio => 'derived' do
parent = Issue.generate!
parent.generate_child!(:estimated_hours => 40)
parent.generate_child!(:estimated_hours => 40)
parent.generate_child!(:estimated_hours => 20)
parent.generate_child!
parent.reload.children.each(&:close!)
assert_equal 100, parent.reload.done_ratio
end
end
def test_done_ratio_of_parent_with_a_child_with_estimated_time_at_0_should_not_exceed_100
with_settings :parent_issue_done_ratio => 'derived' do
parent = Issue.generate!
parent.generate_child!(:estimated_hours => 40)
parent.generate_child!(:estimated_hours => 40)
parent.generate_child!(:estimated_hours => 20)
parent.generate_child!(:estimated_hours => 0)
parent.reload.children.each(&:close!)
assert_equal 100, parent.reload.done_ratio
end
end
def test_changing_parent_should_update_previous_parent_done_ratio
with_settings :parent_issue_done_ratio => 'derived' do
first_parent = Issue.generate!
second_parent = Issue.generate!
first_parent.generate_child!(:done_ratio => 40)
child = first_parent.generate_child!(:done_ratio => 20)
assert_equal 30, first_parent.reload.done_ratio
assert_equal 0, second_parent.reload.done_ratio
child.update_attributes(:parent_issue_id => second_parent.id)
assert_equal 40, first_parent.reload.done_ratio
assert_equal 20, second_parent.reload.done_ratio
end
end
def test_done_ratio_of_parent_should_reflect_children
root = Issue.generate!
child1 = root.generate_child!
child2 = child1.generate_child!
assert_equal 0, root.done_ratio
assert_equal 0, child1.done_ratio
assert_equal 0, child2.done_ratio
with_settings :issue_done_ratio => 'issue_status' do
status = IssueStatus.find(4)
status.update_attribute :default_done_ratio, 50
child1.update_attribute :status, status
assert_equal 50, child1.done_ratio
root.reload
assert_equal 50, root.done_ratio
end
end
def test_parent_dates_should_be_editable_with_parent_issue_dates_set_to_independent
with_settings :parent_issue_dates => 'independent' do
issue = Issue.generate_with_child!
user = User.find(1)
%w(start_date due_date).each do |attribute|
assert issue.safe_attribute?(attribute, user)
end
end
end
def test_parent_dates_should_not_be_updated_with_parent_issue_dates_set_to_independent
with_settings :parent_issue_dates => 'independent' do
parent = Issue.generate!(:start_date => '2015-07-01', :due_date => '2015-08-01')
parent.generate_child!(:start_date => '2015-06-01', :due_date => '2015-09-01')
parent.reload
assert_equal Date.parse('2015-07-01'), parent.start_date
assert_equal Date.parse('2015-08-01'), parent.due_date
end
end
def test_reschuling_a_parent_should_not_reschedule_subtasks_with_parent_issue_dates_set_to_independent
with_settings :parent_issue_dates => 'independent' do
parent = Issue.generate!(:start_date => '2010-05-01', :due_date => '2010-05-20')
c1 = parent.generate_child!(:start_date => '2010-05-12', :due_date => '2010-05-18')
parent.reload.reschedule_on!(Date.parse('2010-06-01'))
assert_equal Date.parse('2010-06-01'), parent.reload.start_date
c1.reload
assert_equal [Date.parse('2010-05-12'), Date.parse('2010-05-18')], [c1.start_date, c1.due_date]
end
end
def test_parent_priority_should_be_editable_with_parent_issue_priority_set_to_independent
with_settings :parent_issue_priority => 'independent' do
issue = Issue.generate_with_child!
user = User.find(1)
assert issue.safe_attribute?('priority_id', user)
end
end
def test_parent_priority_should_not_be_updated_with_parent_issue_priority_set_to_independent
with_settings :parent_issue_priority => 'independent' do
parent = Issue.generate!(:priority => IssuePriority.find_by_name('Normal'))
child1 = parent.generate_child!(:priority => IssuePriority.find_by_name('High'))
assert_equal 'Normal', parent.reload.priority.name
end
end
def test_parent_done_ratio_should_be_editable_with_parent_issue_done_ratio_set_to_independent
with_settings :parent_issue_done_ratio => 'independent' do
issue = Issue.generate_with_child!
user = User.find(1)
assert issue.safe_attribute?('done_ratio', user)
end
end
def test_parent_done_ratio_should_not_be_updated_with_parent_issue_done_ratio_set_to_independent
with_settings :parent_issue_done_ratio => 'independent' do
parent = Issue.generate!(:done_ratio => 0)
child1 = parent.generate_child!(:done_ratio => 10)
assert_equal 0, parent.reload.done_ratio
end
end
def test_parent_total_estimated_hours_should_be_sum_of_descendants
parent = Issue.generate!
parent.generate_child!(:estimated_hours => nil)
assert_equal 0, parent.reload.total_estimated_hours
parent.generate_child!(:estimated_hours => 5)
assert_equal 5, parent.reload.total_estimated_hours
parent.generate_child!(:estimated_hours => 7)
assert_equal 12, parent.reload.total_estimated_hours
end
def test_open_issue_with_closed_parent_should_not_validate
parent = Issue.generate!(:status_id => 5)
child = Issue.generate!
child.parent_issue_id = parent.id
assert !child.save
assert_include I18n.t("activerecord.errors.messages.open_issue_with_closed_parent"), child.errors.full_messages
end
end

3067
test/unit/issue_test.rb Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,52 @@
# 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 IssueTransactionTest < ActiveSupport::TestCase
fixtures :projects, :users, :members, :member_roles, :roles,
:trackers, :projects_trackers,
:versions,
:issue_statuses, :issue_categories, :issue_relations, :workflows,
:enumerations,
:issues,
:custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
:time_entries
self.use_transactional_fixtures = false
def test_invalid_move_to_another_project
lft1 = new_issue_lft
parent1 = Issue.generate!
child = Issue.generate!(:parent_issue_id => parent1.id)
grandchild = Issue.generate!(:parent_issue_id => child.id, :tracker_id => 2)
Project.find(2).tracker_ids = [1]
parent1.reload
assert_equal [1, parent1.id, lft1, lft1 + 5], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt]
# child can not be moved to Project 2 because its child is on a disabled tracker
child = Issue.find(child.id)
child.project = Project.find(2)
assert !child.save
child.reload
grandchild.reload
parent1.reload
# no change
assert_equal [1, parent1.id, lft1, lft1 + 5], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt]
assert_equal [1, parent1.id, lft1 + 1, lft1 + 4], [child.project_id, child.root_id, child.lft, child.rgt]
assert_equal [1, parent1.id, lft1 + 2, lft1 + 3], [grandchild.project_id, grandchild.root_id, grandchild.lft, grandchild.rgt]
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 JournalObserverTest < ActiveSupport::TestCase
fixtures :issues, :issue_statuses, :journals, :journal_details, :projects,
:projects_trackers, :trackers, :enabled_modules, :enumerations,
:users, :email_addresses, :roles
def setup
ActionMailer::Base.deliveries.clear
@journal = Journal.find 1
end
# context: issue_updated notified_events
def test_create_should_send_email_notification_with_issue_updated
issue = Issue.first
user = User.first
journal = issue.init_journal(user, "some notes")
with_settings :notified_events => %w(issue_updated) do
assert journal.save
end
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_create_should_not_send_email_notification_with_notify_set_to_false
issue = Issue.first
user = User.first
journal = issue.init_journal(user, "some notes")
journal.notify = false
with_settings :notified_events => %w(issue_updated) do
assert journal.save
end
assert_equal 0, ActionMailer::Base.deliveries.size
end
def test_create_should_not_send_email_notification_without_issue_updated
issue = Issue.first
user = User.first
journal = issue.init_journal(user, "some notes")
with_settings :notified_events => [] do
assert journal.save
end
assert_equal 0, ActionMailer::Base.deliveries.size
end
def test_create_should_send_email_notification_with_issue_note_added
issue = Issue.first
user = User.first
journal = issue.init_journal(user)
journal.notes = 'This update has a note'
with_settings :notified_events => %w(issue_note_added) do
assert journal.save
end
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_create_should_not_send_email_notification_without_issue_note_added
issue = Issue.first
user = User.first
journal = issue.init_journal(user)
journal.notes = 'This update has a note'
with_settings :notified_events => [] do
assert journal.save
end
assert_equal 0, ActionMailer::Base.deliveries.size
end
def test_create_should_send_email_notification_with_issue_status_updated
issue = Issue.first
user = User.first
issue.init_journal(user)
issue.status = IssueStatus.last
with_settings :notified_events => %w(issue_status_updated) do
assert issue.save
end
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_create_should_not_send_email_notification_without_issue_status_updated
issue = Issue.first
user = User.first
issue.init_journal(user)
issue.status = IssueStatus.last
with_settings :notified_events => [] do
assert issue.save
end
assert_equal 0, ActionMailer::Base.deliveries.size
end
def test_create_without_status_update_should_not_send_email_notification_with_issue_status_updated
issue = Issue.first
user = User.first
issue.init_journal(user)
issue.subject = "No status update"
with_settings :notified_events => %w(issue_status_updated) do
assert issue.save
end
assert_equal 0, ActionMailer::Base.deliveries.size
end
def test_create_should_send_email_notification_with_issue_assignee_updated
issue = Issue.generate!(:assigned_to_id => 2)
ActionMailer::Base.deliveries.clear
user = User.first
issue.init_journal(user)
issue.assigned_to = User.find(3)
with_settings :notified_events => %w(issue_assigned_to_updated) do
assert issue.save
end
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_create_should_not_send_email_notification_without_issue_assignee_updated
issue = Issue.generate!(:assigned_to_id => 2)
ActionMailer::Base.deliveries.clear
user = User.first
issue.init_journal(user)
issue.assigned_to = User.find(3)
with_settings :notified_events => [] do
assert issue.save
end
assert_equal 0, ActionMailer::Base.deliveries.size
end
def test_create_should_send_email_notification_with_issue_priority_updated
issue = Issue.first
user = User.first
issue.init_journal(user)
issue.priority = IssuePriority.last
with_settings :notified_events => %w(issue_priority_updated) do
assert issue.save
end
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_create_should_not_send_email_notification_without_issue_priority_updated
issue = Issue.first
user = User.first
issue.init_journal(user)
issue.priority = IssuePriority.last
with_settings :notified_events => [] do
assert issue.save
end
assert_equal 0, ActionMailer::Base.deliveries.size
end
end

223
test/unit/journal_test.rb Normal file
View file

@ -0,0 +1,223 @@
# 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 JournalTest < ActiveSupport::TestCase
fixtures :projects, :issues, :issue_statuses, :journals, :journal_details,
:issue_relations, :workflows,
:users, :members, :member_roles, :roles, :enabled_modules,
:groups_users, :email_addresses,
:enumerations,
:projects_trackers, :trackers, :custom_fields
def setup
@journal = Journal.find 1
User.current = nil
end
def test_journalized_is_an_issue
issue = @journal.issue
assert_kind_of Issue, issue
assert_equal 1, issue.id
end
def test_new_status
status = @journal.new_status
assert_not_nil status
assert_kind_of IssueStatus, status
assert_equal 2, status.id
end
def test_create_should_send_email_notification
ActionMailer::Base.deliveries.clear
issue = Issue.first
user = User.first
journal = issue.init_journal(user, issue)
assert journal.save
assert_equal 1, ActionMailer::Base.deliveries.size
end
def test_should_not_save_journal_with_blank_notes_and_no_details
journal = Journal.new(:journalized => Issue.first, :user => User.first)
assert_no_difference 'Journal.count' do
assert_equal false, journal.save
end
end
def test_create_should_not_split_non_private_notes
assert_difference 'Journal.count' do
assert_no_difference 'JournalDetail.count' do
journal = Journal.generate!(:notes => 'Notes')
end
end
assert_difference 'Journal.count' do
assert_difference 'JournalDetail.count' do
journal = Journal.generate!(:notes => 'Notes', :details => [JournalDetail.new])
end
end
assert_difference 'Journal.count' do
assert_difference 'JournalDetail.count' do
journal = Journal.generate!(:notes => '', :details => [JournalDetail.new])
end
end
end
def test_create_should_split_private_notes
assert_difference 'Journal.count' do
assert_no_difference 'JournalDetail.count' do
journal = Journal.generate!(:notes => 'Notes', :private_notes => true)
journal.reload
assert_equal true, journal.private_notes
assert_equal 'Notes', journal.notes
end
end
assert_difference 'Journal.count', 2 do
assert_difference 'JournalDetail.count' do
journal = Journal.generate!(:notes => 'Notes', :private_notes => true, :details => [JournalDetail.new])
journal.reload
assert_equal true, journal.private_notes
assert_equal 'Notes', journal.notes
assert_equal 0, journal.details.size
journal_with_changes = Journal.order('id DESC').offset(1).first
assert_equal false, journal_with_changes.private_notes
assert_nil journal_with_changes.notes
assert_equal 1, journal_with_changes.details.size
assert_equal journal.created_on, journal_with_changes.created_on
end
end
assert_difference 'Journal.count' do
assert_difference 'JournalDetail.count' do
journal = Journal.generate!(:notes => '', :private_notes => true, :details => [JournalDetail.new])
journal.reload
assert_equal false, journal.private_notes
assert_equal '', journal.notes
assert_equal 1, journal.details.size
end
end
end
def test_visible_scope_for_anonymous
# Anonymous user should see issues of public projects only
journals = Journal.visible(User.anonymous).to_a
assert journals.any?
assert_nil journals.detect {|journal| !journal.issue.project.is_public?}
# Anonymous user should not see issues without permission
Role.anonymous.remove_permission!(:view_issues)
journals = Journal.visible(User.anonymous).to_a
assert journals.empty?
end
def test_visible_scope_for_user
user = User.find(9)
assert user.projects.empty?
# Non member user should see issues of public projects only
journals = Journal.visible(user).to_a
assert journals.any?
assert_nil journals.detect {|journal| !journal.issue.project.is_public?}
# Non member user should not see issues without permission
Role.non_member.remove_permission!(:view_issues)
user.reload
journals = Journal.visible(user).to_a
assert journals.empty?
# User should see issues of projects for which user has view_issues permissions only
Member.create!(:principal => user, :project_id => 1, :role_ids => [1])
user.reload
journals = Journal.visible(user).to_a
assert journals.any?
assert_nil journals.detect {|journal| journal.issue.project_id != 1}
end
def test_visible_scope_for_admin
user = User.find(1)
user.members.each(&:destroy)
assert user.projects.empty?
journals = Journal.visible(user).to_a
assert journals.any?
# Admin should see issues on private projects that admin does not belong to
assert journals.detect {|journal| !journal.issue.project.is_public?}
end
def test_preload_journals_details_custom_fields_should_set_custom_field_instance_variable
d = JournalDetail.new(:property => 'cf', :prop_key => '2')
journals = [Journal.new(:details => [d])]
d.expects(:instance_variable_set).with("@custom_field", CustomField.find(2)).once
Journal.preload_journals_details_custom_fields(journals)
end
def test_preload_journals_details_custom_fields_with_empty_set
assert_nothing_raised do
Journal.preload_journals_details_custom_fields([])
end
end
def test_details_should_normalize_dates
j = JournalDetail.create!(:old_value => Date.parse('2012-11-03'), :value => Date.parse('2013-01-02'))
j.reload
assert_equal '2012-11-03', j.old_value
assert_equal '2013-01-02', j.value
end
def test_details_should_normalize_true_values
j = JournalDetail.create!(:old_value => true, :value => true)
j.reload
assert_equal '1', j.old_value
assert_equal '1', j.value
end
def test_details_should_normalize_false_values
j = JournalDetail.create!(:old_value => false, :value => false)
j.reload
assert_equal '0', j.old_value
assert_equal '0', j.value
end
def test_custom_field_should_return_custom_field_for_cf_detail
d = JournalDetail.new(:property => 'cf', :prop_key => '2')
assert_equal CustomField.find(2), d.custom_field
end
def test_custom_field_should_return_nil_for_non_cf_detail
d = JournalDetail.new(:property => 'subject')
assert_nil d.custom_field
end
def test_visible_details_should_include_relations_to_visible_issues_only
issue = Issue.generate!
visible_issue = Issue.generate!
hidden_issue = Issue.generate!(:is_private => true)
journal = Journal.new
journal.details << JournalDetail.new(:property => 'relation', :prop_key => 'relates', :value => visible_issue.id)
journal.details << JournalDetail.new(:property => 'relation', :prop_key => 'relates', :value => hidden_issue.id)
visible_details = journal.visible_details(User.anonymous)
assert_equal 1, visible_details.size
assert_equal visible_issue.id.to_s, visible_details.first.value.to_s
visible_details = journal.visible_details(User.find(2))
assert_equal 2, visible_details.size
end
end

View file

@ -0,0 +1,59 @@
# 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 Redmine::AccessControlTest < ActiveSupport::TestCase
def setup
@access_module = Redmine::AccessControl
end
def test_permissions
perms = @access_module.permissions
assert perms.is_a?(Array)
assert perms.first.is_a?(Redmine::AccessControl::Permission)
end
def test_module_permission
perm = @access_module.permission(:view_issues)
assert perm.is_a?(Redmine::AccessControl::Permission)
assert_equal :view_issues, perm.name
assert_equal :issue_tracking, perm.project_module
assert perm.actions.is_a?(Array)
assert perm.actions.include?('issues/index')
end
def test_no_module_permission
perm = @access_module.permission(:edit_project)
assert perm.is_a?(Redmine::AccessControl::Permission)
assert_equal :edit_project, perm.name
assert_nil perm.project_module
assert perm.actions.is_a?(Array)
assert perm.actions.include?('projects/settings')
end
def test_read_action_should_return_true_for_read_actions
assert_equal true, @access_module.read_action?(:view_project)
assert_equal true, @access_module.read_action?(:controller => 'projects', :action => 'show')
end
def test_read_action_should_return_false_for_update_actions
assert_equal false, @access_module.read_action?(:edit_project)
assert_equal false, @access_module.read_action?(:controller => 'projects', :action => 'edit')
end
end

View file

@ -0,0 +1,53 @@
# 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 Redmine::Acts::PositionedWithScopeTest < ActiveSupport::TestCase
fixtures :projects, :boards
def test_create_should_default_to_last_position
b = Board.generate!(:project_id => 1)
assert_equal 3, b.reload.position
b = Board.generate!(:project_id => 3)
assert_equal 1, b.reload.position
end
def test_create_should_insert_at_given_position
b = Board.generate!(:project_id => 1, :position => 2)
assert_equal 2, b.reload.position
assert_equal [1, 3, 1, 2], Board.order(:id).pluck(:position)
end
def test_destroy_should_remove_position
b = Board.generate!(:project_id => 1, :position => 2)
b.destroy
assert_equal [1, 2, 1], Board.order(:id).pluck(:position)
end
def test_update_should_update_positions
b = Board.generate!(:project_id => 1)
assert_equal 3, b.position
b.position = 2
b.save!
assert_equal [1, 3, 1, 2], Board.order(:id).pluck(:position)
end
end

View file

@ -0,0 +1,55 @@
# 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 Redmine::Acts::PositionedWithoutScopeTest < ActiveSupport::TestCase
fixtures :trackers, :issue_statuses
def test_create_should_default_to_last_position
t = Tracker.generate
t.save!
assert_equal 4, t.reload.position
end
def test_create_should_insert_at_given_position
t = Tracker.generate
t.position = 2
t.save!
assert_equal 2, t.reload.position
assert_equal [1, 3, 4, 2], Tracker.order(:id).pluck(:position)
end
def test_destroy_should_remove_position
t = Tracker.generate!
Tracker.generate!
t.destroy
assert_equal [1, 2, 3, 4], Tracker.order(:id).pluck(:position)
end
def test_update_should_update_positions
t = Tracker.generate!
assert_equal 4, t.position
t.position = 2
t.save!
assert_equal [1, 3, 4, 2], Tracker.order(:id).pluck(:position)
end
end

View file

@ -0,0 +1,106 @@
# 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 Redmine::CipheringTest < ActiveSupport::TestCase
def test_password_should_be_encrypted
Redmine::Configuration.with 'database_cipher_key' => 'secret' do
r = Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'svn')
assert_equal 'foo', r.password
assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/)
end
end
def test_password_should_be_clear_with_blank_key
Redmine::Configuration.with 'database_cipher_key' => '' do
r = Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'svn')
assert_equal 'foo', r.password
assert_equal 'foo', r.read_attribute(:password)
end
end
def test_password_should_be_clear_with_nil_key
Redmine::Configuration.with 'database_cipher_key' => nil do
r = Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'svn')
assert_equal 'foo', r.password
assert_equal 'foo', r.read_attribute(:password)
end
end
def test_blank_password_should_be_clear
Redmine::Configuration.with 'database_cipher_key' => 'secret' do
r = Repository::Subversion.create!(:password => '', :url => 'file:///tmp', :identifier => 'svn')
assert_equal '', r.password
assert_equal '', r.read_attribute(:password)
end
end
def test_unciphered_password_should_be_readable
Redmine::Configuration.with 'database_cipher_key' => nil do
r = Repository::Subversion.create!(:password => 'clear', :url => 'file:///tmp', :identifier => 'svn')
end
Redmine::Configuration.with 'database_cipher_key' => 'secret' do
r = Repository.order('id DESC').first
assert_equal 'clear', r.password
end
end
def test_ciphered_password_with_no_cipher_key_configured_should_be_returned_ciphered
Redmine::Configuration.with 'database_cipher_key' => 'secret' do
r = Repository::Subversion.create!(:password => 'clear', :url => 'file:///tmp', :identifier => 'svn')
end
Redmine::Configuration.with 'database_cipher_key' => '' do
r = Repository.order('id DESC').first
# password can not be deciphered
assert_nothing_raised do
assert r.password.match(/\Aaes-256-cbc:.+\Z/)
end
end
end
def test_encrypt_all
Repository.delete_all
Redmine::Configuration.with 'database_cipher_key' => nil do
Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'foo')
Repository::Subversion.create!(:password => 'bar', :url => 'file:///tmp', :identifier => 'bar')
end
Redmine::Configuration.with 'database_cipher_key' => 'secret' do
assert Repository.encrypt_all(:password)
r = Repository.order('id DESC').first
assert_equal 'bar', r.password
assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/)
end
end
def test_decrypt_all
Repository.delete_all
Redmine::Configuration.with 'database_cipher_key' => 'secret' do
Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'foo')
Repository::Subversion.create!(:password => 'bar', :url => 'file:///tmp', :identifier => 'bar')
assert Repository.decrypt_all(:password)
r = Repository.order('id DESC').first
assert_equal 'bar', r.password
assert_equal 'bar', r.read_attribute(:password)
end
end
end

View file

@ -0,0 +1,104 @@
# 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 Redmine::CodesetUtilTest < ActiveSupport::TestCase
def test_to_utf8_by_setting_from_latin1
with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
s1 = "Texte encod\xc3\xa9".force_encoding("UTF-8")
s2 = "Texte encod\xe9".force_encoding("ASCII-8BIT")
s3 = s2.dup.force_encoding("UTF-8")
assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2)
assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3)
end
end
def test_to_utf8_by_setting_from_euc_jp
with_settings :repositories_encodings => 'UTF-8,EUC-JP' do
s1 = "\xe3\x83\xac\xe3\x83\x83\xe3\x83\x89\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\xb3".force_encoding("UTF-8")
s2 = "\xa5\xec\xa5\xc3\xa5\xc9\xa5\xde\xa5\xa4\xa5\xf3".force_encoding("ASCII-8BIT")
s3 = s2.dup.force_encoding("UTF-8")
assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2)
assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3)
end
end
def test_to_utf8_by_setting_should_be_converted_all_latin1
with_settings :repositories_encodings => 'ISO-8859-1' do
s1 = "\xc3\x82\xc2\x80".force_encoding("UTF-8")
s2 = "\xC2\x80".force_encoding("ASCII-8BIT")
s3 = s2.dup.force_encoding("UTF-8")
assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2)
assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3)
end
end
def test_to_utf8_by_setting_blank_string
assert_equal "", Redmine::CodesetUtil.to_utf8_by_setting("")
assert_nil Redmine::CodesetUtil.to_utf8_by_setting(nil)
end
def test_to_utf8_by_setting_returns_ascii_as_utf8
s1 = "ASCII".force_encoding("UTF-8")
s2 = s1.dup.force_encoding("ISO-8859-1")
str1 = Redmine::CodesetUtil.to_utf8_by_setting(s1)
str2 = Redmine::CodesetUtil.to_utf8_by_setting(s2)
assert_equal s1, str1
assert_equal s1, str2
assert_equal "UTF-8", str1.encoding.to_s
assert_equal "UTF-8", str2.encoding.to_s
end
def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped
with_settings :repositories_encodings => '' do
# s1 = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
s1 = "Texte encod\xe9 en ISO-8859-1.".force_encoding("ASCII-8BIT")
str = Redmine::CodesetUtil.to_utf8_by_setting(s1)
assert str.valid_encoding?
assert_equal "UTF-8", str.encoding.to_s
assert_equal "Texte encod? en ISO-8859-1.", str
end
end
def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped_ja_jis
with_settings :repositories_encodings => 'ISO-2022-JP' do
s1 = "test\xb5\xfetest\xb5\xfe".force_encoding("ASCII-8BIT")
str = Redmine::CodesetUtil.to_utf8_by_setting(s1)
assert str.valid_encoding?
assert_equal "UTF-8", str.encoding.to_s
assert_equal "test??test??", str
end
end
test "#replace_invalid_utf8 should replace invalid utf8" do
s1 = "\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xE3\x81\xFF".force_encoding("UTF-8")
s2 = Redmine::CodesetUtil.replace_invalid_utf8(s1)
assert s2.valid_encoding?
assert_equal "UTF-8", s2.encoding.to_s
assert_equal "\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1??".force_encoding("UTF-8"), s2
end
test "#to_utf8 should replace invalid non utf8" do
s1 = "\xa4\xb3\xa4\xf3\xa4\xcb\xa4\xc1\xa4".force_encoding("EUC-JP")
s2 = Redmine::CodesetUtil.to_utf8(s1, "EUC-JP")
assert s2.valid_encoding?
assert_equal "UTF-8", s2.encoding.to_s
assert_equal "\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1?".force_encoding("UTF-8"), s2
end
end

View file

@ -0,0 +1,61 @@
# 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 Redmine::ConfigurationTest < ActiveSupport::TestCase
def setup
@conf = Redmine::Configuration
end
def test_empty
assert_kind_of Hash, load_conf('empty.yml', 'test')
end
def test_default
assert_kind_of Hash, load_conf('default.yml', 'test')
assert_equal 'foo', @conf['somesetting']
end
def test_no_default
assert_kind_of Hash, load_conf('no_default.yml', 'test')
assert_equal 'foo', @conf['somesetting']
end
def test_overrides
assert_kind_of Hash, load_conf('overrides.yml', 'test')
assert_equal 'bar', @conf['somesetting']
end
def test_with
load_conf('default.yml', 'test')
assert_equal 'foo', @conf['somesetting']
@conf.with 'somesetting' => 'bar' do
assert_equal 'bar', @conf['somesetting']
end
assert_equal 'foo', @conf['somesetting']
end
private
def load_conf(file, env)
@conf.load(
:file => File.join(Rails.root, 'test', 'fixtures', 'configuration', file),
:env => env
)
end
end

View file

@ -0,0 +1,31 @@
# 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 CsvTest < ActiveSupport::TestCase
BOM = "\xEF\xBB\xBF".force_encoding('UTF-8')
def test_should_include_bom_when_utf8_encoded
with_locale 'sk' do
string = Redmine::Export::CSV.generate {|csv| csv << %w(Foo Bar)}
assert_equal 'UTF-8', string.encoding.name
assert string.starts_with?(BOM)
end
end
end

View file

@ -0,0 +1,104 @@
# 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 PdfTest < ActiveSupport::TestCase
fixtures :users, :projects, :roles, :members, :member_roles,
:enabled_modules, :issues, :trackers, :attachments
def test_fix_text_encoding_nil
assert_equal '', Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(nil, "UTF-8")
assert_equal '', Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(nil, "ISO-8859-1")
end
def test_rdm_pdf_iconv_cannot_convert_ja_cp932
utf8_txt_1 = "\xe7\x8b\x80\xe6\x85\x8b"
utf8_txt_2 = "\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80"
utf8_txt_3 = "\xe7\x8b\x80\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80"
["CP932", "SJIS"].each do |encoding|
txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding)
txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding)
txt_3 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding)
assert_equal "?\x91\xd4".force_encoding("ASCII-8BIT"), txt_1
assert_equal "?\x91\xd4?".force_encoding("ASCII-8BIT"), txt_2
assert_equal "??\x91\xd4?".force_encoding("ASCII-8BIT"), txt_3
assert_equal "ASCII-8BIT", txt_1.encoding.to_s
assert_equal "ASCII-8BIT", txt_2.encoding.to_s
assert_equal "ASCII-8BIT", txt_3.encoding.to_s
end
end
def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_en
str1 = "Texte encod\xe9 en ISO-8859-1".force_encoding("UTF-8")
str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test".force_encoding("ASCII-8BIT")
txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, 'UTF-8')
txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, 'UTF-8')
assert_equal "ASCII-8BIT", txt_1.encoding.to_s
assert_equal "ASCII-8BIT", txt_2.encoding.to_s
assert_equal "Texte encod? en ISO-8859-1", txt_1
assert_equal "?a?b?c?d?e test", txt_2
end
def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_ja
str1 = "Texte encod\xe9 en ISO-8859-1".force_encoding("UTF-8")
str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test".force_encoding("ASCII-8BIT")
encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" )
txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, encoding)
txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, encoding)
assert_equal "ASCII-8BIT", txt_1.encoding.to_s
assert_equal "ASCII-8BIT", txt_2.encoding.to_s
assert_equal "Texte encod? en ISO-8859-1", txt_1
assert_equal "?a?b?c?d?e test", txt_2
end
def test_attach
["CP932", "SJIS"].each do |encoding|
set_fixtures_attachments_directory
str2 = "\x83e\x83X\x83g".force_encoding("ASCII-8BIT")
a1 = Attachment.find(17)
a2 = Attachment.find(19)
User.current = User.find(1)
assert a1.readable?
assert a1.visible?
assert a2.readable?
assert a2.visible?
aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8")
assert_not_nil aa1
assert_equal 17, aa1.id
aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding)
assert_not_nil aa2
assert_equal 19, aa2.id
User.current = nil
assert a1.readable?
assert (! a1.visible?)
assert a2.readable?
assert (! a2.visible?)
aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8")
assert_nil aa1
aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding)
assert_nil aa2
set_tmp_attachments_directory
end
end
end

View file

@ -0,0 +1,163 @@
# 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 'redmine/field_format'
class Redmine::AttachmentFieldFormatTest < ActionView::TestCase
include ApplicationHelper
include Redmine::I18n
fixtures :users
def setup
set_language_if_valid 'en'
set_tmp_attachments_directory
end
def test_should_accept_a_hash_with_upload_on_create
field = GroupCustomField.generate!(:name => "File", :field_format => 'attachment')
group = Group.new(:name => 'Group')
attachment = nil
custom_value = new_record(CustomValue) do
attachment = new_record(Attachment) do
group.custom_field_values = {field.id => {:file => mock_file}}
assert group.save
end
end
assert_equal 'a_file.png', attachment.filename
assert_equal custom_value, attachment.container
assert_equal field, attachment.container.custom_field
assert_equal group, attachment.container.customized
end
def test_should_accept_a_hash_with_no_upload_on_create
field = GroupCustomField.generate!(:name => "File", :field_format => 'attachment')
group = Group.new(:name => 'Group')
attachment = nil
custom_value = new_record(CustomValue) do
assert_no_difference 'Attachment.count' do
group.custom_field_values = {field.id => {}}
assert group.save
end
end
assert_equal '', custom_value.value
end
def test_should_not_validate_with_invalid_upload_on_create
field = GroupCustomField.generate!(:name => "File", :field_format => 'attachment')
group = Group.new(:name => 'Group')
with_settings :attachment_max_size => 0 do
assert_no_difference 'CustomValue.count' do
assert_no_difference 'Attachment.count' do
group.custom_field_values = {field.id => {:file => mock_file}}
assert_equal false, group.save
end
end
end
end
def test_should_accept_a_hash_with_token_on_create
field = GroupCustomField.generate!(:name => "File", :field_format => 'attachment')
group = Group.new(:name => 'Group')
attachment = Attachment.create!(:file => mock_file, :author => User.find(2))
assert_nil attachment.container
custom_value = new_record(CustomValue) do
assert_no_difference 'Attachment.count' do
group.custom_field_values = {field.id => {:token => attachment.token}}
assert group.save
end
end
attachment.reload
assert_equal custom_value, attachment.container
assert_equal field, attachment.container.custom_field
assert_equal group, attachment.container.customized
end
def test_should_not_validate_with_invalid_token_on_create
field = GroupCustomField.generate!(:name => "File", :field_format => 'attachment')
group = Group.new(:name => 'Group')
assert_no_difference 'CustomValue.count' do
assert_no_difference 'Attachment.count' do
group.custom_field_values = {field.id => {:token => "123.0123456789abcdef"}}
assert_equal false, group.save
end
end
end
def test_should_replace_attachment_on_update
field = GroupCustomField.generate!(:name => "File", :field_format => 'attachment')
group = Group.new(:name => 'Group')
attachment = nil
custom_value = new_record(CustomValue) do
attachment = new_record(Attachment) do
group.custom_field_values = {field.id => {:file => mock_file}}
assert group.save
end
end
group.reload
assert_no_difference 'Attachment.count' do
assert_no_difference 'CustomValue.count' do
group.custom_field_values = {field.id => {:file => mock_file}}
assert group.save
end
end
assert !Attachment.exists?(attachment.id)
assert CustomValue.exists?(custom_value.id)
new_attachment = Attachment.order(:id => :desc).first
custom_value.reload
assert_equal custom_value, new_attachment.container
end
def test_should_delete_attachment_on_update
field = GroupCustomField.generate!(:name => "File", :field_format => 'attachment')
group = Group.new(:name => 'Group')
attachment = nil
custom_value = new_record(CustomValue) do
attachment = new_record(Attachment) do
group.custom_field_values = {field.id => {:file => mock_file}}
assert group.save
end
end
group.reload
assert_difference 'Attachment.count', -1 do
assert_no_difference 'CustomValue.count' do
group.custom_field_values = {field.id => {}}
assert group.save
end
end
assert !Attachment.exists?(attachment.id)
assert CustomValue.exists?(custom_value.id)
custom_value.reload
assert_equal '', custom_value.value
end
end

View file

@ -0,0 +1,59 @@
# 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 'redmine/field_format'
class AttachmentFormatVisibilityTest < ActionView::TestCase
fixtures :projects, :enabled_modules, :projects_trackers,
:roles, :members, :member_roles,
:users, :email_addresses,
:trackers, :issue_statuses, :enumerations, :issue_categories,
:versions, :issues
def setup
set_tmp_attachments_directory
end
def test_attachment_should_be_visible_with_visible_custom_field
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
assert attachment.visible?(manager = User.find(2))
assert attachment.visible?(developer = User.find(3))
assert attachment.visible?(non_member = User.find(7))
assert attachment.visible?(User.anonymous)
end
def test_attachment_should_be_visible_with_limited_visibility_custom_field
field = IssueCustomField.generate!(:field_format => 'attachment', :visible => false, :role_ids => [1])
attachment = new_record(Attachment) do
issue = Issue.generate
issue.custom_field_values = {field.id => {:file => mock_file}}
issue.save!
end
assert attachment.visible?(manager = User.find(2))
assert !attachment.visible?(developer = User.find(3))
assert !attachment.visible?(non_member = User.find(7))
assert !attachment.visible?(User.anonymous)
end
end

View file

@ -0,0 +1,63 @@
# 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 'redmine/field_format'
class Redmine::BoolFieldFormatTest < ActionView::TestCase
include ApplicationHelper
include Redmine::I18n
def setup
set_language_if_valid 'en'
end
def test_check_box_style_should_render_edit_tag_as_check_box
field = IssueCustomField.new(:field_format => 'bool', :is_required => false, :edit_tag_style => 'check_box')
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new)
tag = field.format.edit_tag(self, 'abc', 'xyz', value)
assert_select_in tag, 'input[name=xyz]', 2
assert_select_in tag, 'input[id=abc]', 1
assert_select_in tag, 'input[type=hidden][value="0"]'
assert_select_in tag, 'input[type=checkbox][value="1"]'
end
def test_check_box_should_be_checked_when_value_is_set
field = IssueCustomField.new(:field_format => 'bool', :is_required => false, :edit_tag_style => 'check_box')
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new, :value => '1')
tag = field.format.edit_tag(self, 'abc', 'xyz', value)
assert_select_in tag, 'input[type=checkbox][value="1"][checked=checked]'
end
def test_radio_style_should_render_edit_tag_as_radio_buttons
field = IssueCustomField.new(:field_format => 'bool', :is_required => false, :edit_tag_style => 'radio')
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new)
tag = field.format.edit_tag(self, 'abc', 'xyz', value)
assert_select_in tag, 'input[type=radio][name=xyz]', 3
end
def test_default_style_should_render_edit_tag_as_select
field = IssueCustomField.new(:field_format => 'bool', :is_required => false)
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new)
tag = field.format.edit_tag(self, 'abc', 'xyz', value)
assert_select_in tag, 'select[name=xyz]', 1
end
end

View file

@ -0,0 +1,100 @@
# 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 'redmine/field_format'
class Redmine::EnumerationFieldFormatTest < ActionView::TestCase
include ApplicationHelper
def setup
set_language_if_valid 'en'
@field = IssueCustomField.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_edit_tag_should_contain_possible_values
value = CustomFieldValue.new(:custom_field => @field, :customized => Issue.new)
tag = @field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'select' do
assert_select 'option', 3
assert_select 'option[value=""]'
assert_select 'option[value=?]', @foo.id.to_s, :text => 'Foo'
assert_select 'option[value=?]', @bar.id.to_s, :text => 'Bar'
end
end
def test_edit_tag_should_select_current_value
value = CustomFieldValue.new(:custom_field => @field, :customized => Issue.new, :value => @bar.id.to_s)
tag = @field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'select' do
assert_select 'option[selected=selected]', 1
assert_select 'option[value=?][selected=selected]', @bar.id.to_s, :text => 'Bar'
end
end
def test_edit_tag_with_multiple_should_select_current_values
@field.multiple = true
@field.save!
value = CustomFieldValue.new(:custom_field => @field, :customized => Issue.new, :value => [@foo.id.to_s, @bar.id.to_s])
tag = @field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'select[multiple=multiple]' do
assert_select 'option[selected=selected]', 2
assert_select 'option[value=?][selected=selected]', @foo.id.to_s, :text => 'Foo'
assert_select 'option[value=?][selected=selected]', @bar.id.to_s, :text => 'Bar'
end
end
def test_edit_tag_with_check_box_style_should_contain_possible_values
@field.edit_tag_style = 'check_box'
@field.save!
value = CustomFieldValue.new(:custom_field => @field, :customized => Issue.new)
tag = @field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'span' do
assert_select 'input[type=radio]', 3
assert_select 'label', :text => '(none)' do
assert_select 'input[value=""]'
end
assert_select 'label', :text => 'Foo' do
assert_select 'input[value=?]', @foo.id.to_s
end
assert_select 'label', :text => 'Bar' do
assert_select 'input[value=?]', @bar.id.to_s
end
end
end
def test_value_from_keyword_should_return_enumeration_id
assert_equal @foo.id, @field.value_from_keyword('foo', nil)
assert_nil @field.value_from_keyword('baz', nil)
end
def test_value_from_keyword_for_multiple_custom_field_should_return_enumeration_ids
@field.multiple = true
@field.save!
assert_equal [@foo.id, @bar.id], @field.value_from_keyword('foo, bar', nil)
assert_equal [@foo.id], @field.value_from_keyword('foo, baz', nil)
assert_equal [], @field.value_from_keyword('baz', nil)
end
end

View file

@ -0,0 +1,101 @@
# 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 Redmine::FieldFormatTest < ActionView::TestCase
include ApplicationHelper
def setup
set_language_if_valid 'en'
end
def test_string_field_with_text_formatting_disabled_should_not_format_text
field = IssueCustomField.new(:field_format => 'string')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "*foo*")
assert_equal "*foo*", field.format.formatted_custom_value(self, custom_value, false)
assert_equal "*foo*", field.format.formatted_custom_value(self, custom_value, true)
end
def test_string_field_with_text_formatting_enabled_should_format_text
field = IssueCustomField.new(:field_format => 'string', :text_formatting => 'full')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "*foo*")
assert_equal "*foo*", field.format.formatted_custom_value(self, custom_value, false)
assert_include "<strong>foo</strong>", field.format.formatted_custom_value(self, custom_value, true)
end
def test_text_field_with_text_formatting_disabled_should_not_format_text
field = IssueCustomField.new(:field_format => 'text')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "*foo*\nbar")
assert_equal "*foo*\nbar", field.format.formatted_custom_value(self, custom_value, false)
assert_include "*foo*\n<br />bar", field.format.formatted_custom_value(self, custom_value, true)
end
def test_text_field_with_text_formatting_enabled_should_format_text
field = IssueCustomField.new(:field_format => 'text', :text_formatting => 'full')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "*foo*\nbar")
assert_equal "*foo*\nbar", field.format.formatted_custom_value(self, custom_value, false)
assert_include "<strong>foo</strong>", field.format.formatted_custom_value(self, custom_value, true)
end
def test_should_validate_url_pattern_with_safe_scheme
field = IssueCustomField.new(:field_format => 'string', :name => 'URL', :url_pattern => 'http://foo/%value%')
assert_save field
end
def test_should_not_validate_url_pattern_with_unsafe_scheme
field = IssueCustomField.new(:field_format => 'string', :name => 'URL', :url_pattern => 'foo://foo/%value%')
assert !field.save
assert_include "URL is invalid", field.errors.full_messages
end
def test_text_field_with_url_pattern_should_format_as_link
field = IssueCustomField.new(:field_format => 'string', :url_pattern => 'http://foo/%value%')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "bar")
assert_equal "bar", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/bar">bar</a>', field.format.formatted_custom_value(self, custom_value, true)
end
def test_text_field_with_url_pattern_and_value_containing_a_space_should_format_as_link
field = IssueCustomField.new(:field_format => 'string', :url_pattern => 'http://foo/%value%')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "foo bar")
assert_equal "foo bar", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/foo%20bar">foo bar</a>', field.format.formatted_custom_value(self, custom_value, true)
end
def test_text_field_with_url_pattern_should_not_encode_url_pattern
field = IssueCustomField.new(:field_format => 'string', :url_pattern => 'http://foo/bar#anchor')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "1")
assert_equal "1", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/bar#anchor">1</a>', field.format.formatted_custom_value(self, custom_value, true)
end
def test_text_field_with_url_pattern_should_encode_values
field = IssueCustomField.new(:field_format => 'string', :url_pattern => 'http://foo/%value%#anchor')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "foo bar")
assert_equal "foo bar", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/foo%20bar#anchor">foo bar</a>', field.format.formatted_custom_value(self, custom_value, true)
end
end

View file

@ -0,0 +1,90 @@
# 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 'redmine/field_format'
class Redmine::LinkFieldFormatTest < ActionView::TestCase
def test_link_field_should_substitute_value
field = IssueCustomField.new(:field_format => 'link', :url_pattern => 'http://foo/%value%')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "bar")
assert_equal "bar", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/bar">bar</a>', field.format.formatted_custom_value(self, custom_value, true)
end
def test_link_field_should_substitute_object_id_in_url
object = Issue.new
object.stubs(:id).returns(10)
field = IssueCustomField.new(:field_format => 'link', :url_pattern => 'http://foo/%id%')
custom_value = CustomValue.new(:custom_field => field, :customized => object, :value => "bar")
assert_equal "bar", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/10">bar</a>', field.format.formatted_custom_value(self, custom_value, true)
end
def test_link_field_should_substitute_project_id_in_url
project = Project.new
project.stubs(:id).returns(52)
object = Issue.new
object.stubs(:project).returns(project)
field = IssueCustomField.new(:field_format => 'link', :url_pattern => 'http://foo/%project_id%')
custom_value = CustomValue.new(:custom_field => field, :customized => object, :value => "bar")
assert_equal "bar", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/52">bar</a>', field.format.formatted_custom_value(self, custom_value, true)
end
def test_link_field_should_substitute_project_identifier_in_url
project = Project.new
project.stubs(:identifier).returns('foo_project-00')
object = Issue.new
object.stubs(:project).returns(project)
field = IssueCustomField.new(:field_format => 'link', :url_pattern => 'http://foo/%project_identifier%')
custom_value = CustomValue.new(:custom_field => field, :customized => object, :value => "bar")
assert_equal "bar", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/foo_project-00">bar</a>', field.format.formatted_custom_value(self, custom_value, true)
end
def test_link_field_should_substitute_regexp_groups
field = IssueCustomField.new(:field_format => 'link', :regexp => /^(.+)-(.+)$/, :url_pattern => 'http://foo/%m2%/%m1%')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "56-142")
assert_equal "56-142", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/142/56">56-142</a>', field.format.formatted_custom_value(self, custom_value, true)
end
def test_link_field_without_url_pattern_should_link_to_value
field = IssueCustomField.new(:field_format => 'link')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "http://foo/bar")
assert_equal "http://foo/bar", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/bar">http://foo/bar</a>', field.format.formatted_custom_value(self, custom_value, true)
end
def test_link_field_without_url_pattern_should_link_to_value_with_http_by_default
field = IssueCustomField.new(:field_format => 'link')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "foo.bar")
assert_equal "foo.bar", field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo.bar">foo.bar</a>', field.format.formatted_custom_value(self, custom_value, true)
end
end

View file

@ -0,0 +1,188 @@
# 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 'redmine/field_format'
class Redmine::ListFieldFormatTest < ActionView::TestCase
include ApplicationHelper
include Redmine::I18n
def setup
set_language_if_valid 'en'
end
def test_possible_existing_value_should_be_valid
field = GroupCustomField.create!(:name => 'List', :field_format => 'list', :possible_values => ['Foo', 'Bar'])
group = Group.new(:name => 'Group')
group.custom_field_values = {field.id => 'Baz'}
assert group.save(:validate => false)
group = Group.order('id DESC').first
assert_equal ['Foo', 'Bar', 'Baz'], field.possible_custom_value_options(group.custom_value_for(field))
assert group.valid?
end
def test_edit_tag_should_have_id_and_name
field = IssueCustomField.new(:field_format => 'list', :possible_values => ['Foo', 'Bar'], :is_required => false)
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new)
tag = field.format.edit_tag(self, 'abc', 'xyz', value)
assert_select_in tag, 'select[id=abc][name=xyz]'
end
def test_edit_tag_should_contain_possible_values
field = IssueCustomField.new(:field_format => 'list', :possible_values => ['Foo', 'Bar'], :is_required => false)
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new)
tag = field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'select' do
assert_select 'option', 3
assert_select 'option[value=""]'
assert_select 'option[value=Foo]', :text => 'Foo'
assert_select 'option[value=Bar]', :text => 'Bar'
end
end
def test_edit_tag_should_select_current_value
field = IssueCustomField.new(:field_format => 'list', :possible_values => ['Foo', 'Bar'], :is_required => false)
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new, :value => 'Bar')
tag = field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'select' do
assert_select 'option[selected=selected]', 1
assert_select 'option[value=Bar][selected=selected]', :text => 'Bar'
end
end
def test_edit_tag_with_multiple_should_select_current_values
field = IssueCustomField.new(:field_format => 'list', :possible_values => ['Foo', 'Bar', 'Baz'], :is_required => false,
:multiple => true)
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new, :value => ['Bar', 'Baz'])
tag = field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'select[multiple=multiple]' do
assert_select 'option[selected=selected]', 2
assert_select 'option[value=Bar][selected=selected]', :text => 'Bar'
assert_select 'option[value=Baz][selected=selected]', :text => 'Baz'
end
end
def test_edit_tag_with_check_box_style_should_contain_possible_values
field = IssueCustomField.new(:field_format => 'list', :possible_values => ['Foo', 'Bar'], :is_required => false,
:edit_tag_style => 'check_box')
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new)
tag = field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'span' do
assert_select 'input[type=radio]', 3
assert_select 'label', :text => '(none)' do
assert_select 'input[value=""]'
end
assert_select 'label', :text => 'Foo' do
assert_select 'input[value=Foo]'
end
assert_select 'label', :text => 'Bar' do
assert_select 'input[value=Bar]'
end
end
end
def test_edit_tag_with_check_box_style_should_select_current_value
field = IssueCustomField.new(:field_format => 'list', :possible_values => ['Foo', 'Bar'], :is_required => false,
:edit_tag_style => 'check_box')
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new, :value => 'Bar')
tag = field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'span' do
assert_select 'input[type=radio][checked=checked]', 1
assert_select 'label', :text => 'Bar' do
assert_select 'input[value=Bar][checked=checked]'
end
end
end
def test_edit_tag_with_check_box_style_and_multiple_values_should_contain_hidden_field_to_clear_value
field = IssueCustomField.new(:field_format => 'list', :possible_values => ['Foo', 'Bar'], :is_required => false,
:edit_tag_style => 'check_box', :multiple => true)
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new)
tag = field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'span' do
assert_select 'input[type=checkbox]', 2
assert_select 'input[type=hidden]', 1
end
end
def test_field_with_url_pattern_should_link_value
field = IssueCustomField.new(:field_format => 'list', :url_pattern => 'http://localhost/%value%')
formatted = field.format.formatted_value(self, field, 'foo', Issue.new, true)
assert_equal '<a href="http://localhost/foo">foo</a>', formatted
assert formatted.html_safe?
end
def test_field_with_url_pattern_and_multiple_values_should_link_values
field = IssueCustomField.new(:field_format => 'list', :url_pattern => 'http://localhost/%value%')
formatted = field.format.formatted_value(self, field, ['foo', 'bar'], Issue.new, true)
assert_equal '<a href="http://localhost/bar">bar</a>, <a href="http://localhost/foo">foo</a>', formatted
assert formatted.html_safe?
end
def test_field_with_url_pattern_should_not_link_blank_value
field = IssueCustomField.new(:field_format => 'list', :url_pattern => 'http://localhost/%value%')
formatted = field.format.formatted_value(self, field, '', Issue.new, true)
assert_equal '', formatted
assert formatted.html_safe?
end
def test_edit_tag_with_check_box_style_and_multiple_should_select_current_values
field = IssueCustomField.new(:field_format => 'list', :possible_values => ['Foo', 'Bar', 'Baz'], :is_required => false,
:multiple => true, :edit_tag_style => 'check_box')
value = CustomFieldValue.new(:custom_field => field, :customized => Issue.new, :value => ['Bar', 'Baz'])
tag = field.format.edit_tag(self, 'id', 'name', value)
assert_select_in tag, 'span' do
assert_select 'input[type=checkbox][checked=checked]', 2
assert_select 'label', :text => 'Bar' do
assert_select 'input[value=Bar][checked=checked]'
end
assert_select 'label', :text => 'Baz' do
assert_select 'input[value=Baz][checked=checked]'
end
end
end
def test_value_from_keyword_should_return_value
field = GroupCustomField.create!(:name => 'List', :field_format => 'list', :possible_values => ['Foo', 'Bar', 'Baz,qux'])
assert_equal 'Foo', field.value_from_keyword('foo', nil)
assert_equal 'Baz,qux', field.value_from_keyword('baz,qux', nil)
assert_nil field.value_from_keyword('invalid', nil)
end
def test_value_from_keyword_for_multiple_custom_field_should_return_values
field = GroupCustomField.create!(:name => 'List', :field_format => 'list', :possible_values => ['Foo', 'Bar', 'Baz,qux'], :multiple => true)
assert_equal ['Foo','Bar'], field.value_from_keyword('foo,bar', nil)
assert_equal ['Baz,qux'], field.value_from_keyword('baz,qux', nil)
assert_equal ['Baz,qux', 'Foo'], field.value_from_keyword('baz,qux,foo', nil)
assert_equal ['Foo'], field.value_from_keyword('foo,invalid', nil)
assert_equal ['Foo'], field.value_from_keyword(',foo,', nil)
assert_equal ['Foo'], field.value_from_keyword(',foo, ,,', nil)
assert_equal [], field.value_from_keyword('invalid', nil)
end
end

View file

@ -0,0 +1,31 @@
# 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 'redmine/field_format'
class Redmine::NumericFieldFormatTest < ActionView::TestCase
include ApplicationHelper
def test_integer_field_with_url_pattern_should_format_as_link
field = IssueCustomField.new(:field_format => 'int', :url_pattern => 'http://foo/%value%')
custom_value = CustomValue.new(:custom_field => field, :customized => Issue.new, :value => "3")
assert_equal 3, field.format.formatted_custom_value(self, custom_value, false)
assert_equal '<a href="http://foo/3">3</a>', field.format.formatted_custom_value(self, custom_value, true)
end
end

View file

@ -0,0 +1,79 @@
# 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 'redmine/field_format'
class Redmine::UserFieldFormatTest < ActionView::TestCase
fixtures :projects, :roles, :users, :members, :member_roles,
:trackers,
:issue_statuses, :issue_categories, :issue_relations, :workflows,
:enumerations
def test_user_role_should_reject_blank_values
field = IssueCustomField.new(:name => 'Foo', :field_format => 'user', :user_role => ["1", ""])
field.save!
assert_equal ["1"], field.user_role
end
def test_existing_values_should_be_valid
field = IssueCustomField.create!(:name => 'Foo', :field_format => 'user', :is_for_all => true, :trackers => Tracker.all)
project = Project.generate!
user = User.generate!
User.add_to_project(user, project, Role.find_by_name('Manager'))
issue = Issue.generate!(:project_id => project.id, :tracker_id => 1, :custom_field_values => {field.id => user.id})
field.user_role = [Role.find_by_name('Developer').id]
field.save!
issue = Issue.order('id DESC').first
assert_include [user.name, user.id.to_s], field.possible_custom_value_options(issue.custom_value_for(field))
assert issue.valid?
end
def test_possible_values_options_should_return_project_members
field = IssueCustomField.new(:field_format => 'user')
project = Project.find(1)
assert_equal ['Dave Lopper', 'John Smith'], field.possible_values_options(project).map(&:first)
end
def test_possible_values_options_should_return_project_members_with_selected_role
field = IssueCustomField.new(:field_format => 'user', :user_role => ["2"])
project = Project.find(1)
assert_equal ['Dave Lopper'], field.possible_values_options(project).map(&:first)
end
def test_value_from_keyword_should_return_user_id
field = IssueCustomField.new(:field_format => 'user')
project = Project.find(1)
assert_equal 2, field.value_from_keyword('jsmith', project)
assert_equal 3, field.value_from_keyword('Dave Lopper', project)
assert_nil field.value_from_keyword('Unknown User', project)
end
def test_value_from_keyword_for_multiple_custom_field_should_return_enumeration_ids
field = IssueCustomField.new(:field_format => 'user', :multiple => true)
project = Project.find(1)
assert_equal [2, 3], field.value_from_keyword('jsmith, Dave Lopper', project)
assert_equal [2], field.value_from_keyword('jsmith', project)
assert_equal [], field.value_from_keyword('Unknown User', project)
end
end

View file

@ -0,0 +1,105 @@
# 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 'redmine/field_format'
class Redmine::VersionFieldFormatTest < ActionView::TestCase
fixtures :projects, :versions, :trackers,
:roles, :users, :members, :member_roles,
:issue_statuses, :issue_categories, :issue_relations, :workflows,
:enumerations
def setup
super
User.current = nil
end
def test_version_status_should_reject_blank_values
field = IssueCustomField.new(:name => 'Foo', :field_format => 'version', :version_status => ["open", ""])
field.save!
assert_equal ["open"], field.version_status
end
def test_existing_values_should_be_valid
field = IssueCustomField.create!(:name => 'Foo', :field_format => 'version', :is_for_all => true, :trackers => Tracker.all)
project = Project.generate!
version = Version.generate!(:project => project, :status => 'open')
issue = Issue.generate!(:project_id => project.id, :tracker_id => 1, :custom_field_values => {field.id => version.id})
field.version_status = ["open"]
field.save!
issue = Issue.order('id DESC').first
assert_include [version.name, version.id.to_s], field.possible_custom_value_options(issue.custom_value_for(field))
assert issue.valid?
end
def test_possible_values_options_should_return_project_versions
field = IssueCustomField.new(:field_format => 'version')
project = Project.find(1)
expected = project.shared_versions.sort.map(&:name)
assert_equal expected, field.possible_values_options(project).map(&:first)
end
def test_possible_values_options_should_return_system_shared_versions_without_project
field = IssueCustomField.new(:field_format => 'version')
version = Version.generate!(:project => Project.find(1), :status => 'open', :sharing => 'system')
expected = Version.visible.where(:sharing => 'system').sort.map(&:name)
assert_include version.name, expected
assert_equal expected, field.possible_values_options.map(&:first)
end
def test_possible_values_options_should_return_project_versions_with_selected_status
field = IssueCustomField.new(:field_format => 'version', :version_status => ["open"])
project = Project.find(1)
expected = project.shared_versions.sort.select {|v| v.status == "open"}.map(&:name)
assert_equal expected, field.possible_values_options(project).map(&:first)
end
def test_cast_value_should_not_raise_error_when_array_contains_value_casted_to_nil
field = IssueCustomField.new(:field_format => 'version')
assert_nothing_raised do
field.cast_value([1,2, 42])
end
end
def test_query_filter_options_should_include_versions_with_any_status
field = IssueCustomField.new(:field_format => 'version', :version_status => ["open"])
project = Project.find(1)
version = Version.generate!(:project => project, :status => 'locked')
query = Query.new(:project => project)
full_name = "#{version.project} - #{version.name}"
assert_not_include full_name, field.possible_values_options(project).map(&:first)
assert_include full_name, field.query_filter_options(query)[:values].call.map(&:first)
end
def test_query_filter_options_should_include_version_status_for_grouping
field = IssueCustomField.new(:field_format => 'version', :version_status => ["open"])
project = Project.find(1)
version = Version.generate!(:project => project, :status => 'locked')
query = Query.new(:project => project)
full_name = "#{version.project} - #{version.name}"
assert_include [full_name, version.id.to_s, l(:version_status_locked)],
field.query_filter_options(query)[:values].call
end
end

View file

@ -0,0 +1,63 @@
# 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 CalendarTest < ActiveSupport::TestCase
def test_monthly
c = Redmine::Helpers::Calendar.new(Date.today, :fr, :month)
assert_equal [1, 7], [c.startdt.cwday, c.enddt.cwday]
c = Redmine::Helpers::Calendar.new('2007-07-14'.to_date, :fr, :month)
assert_equal ['2007-06-25'.to_date, '2007-08-05'.to_date], [c.startdt, c.enddt]
c = Redmine::Helpers::Calendar.new(Date.today, :en, :month)
assert_equal [7, 6], [c.startdt.cwday, c.enddt.cwday]
end
def test_weekly
c = Redmine::Helpers::Calendar.new(Date.today, :fr, :week)
assert_equal [1, 7], [c.startdt.cwday, c.enddt.cwday]
c = Redmine::Helpers::Calendar.new('2007-07-14'.to_date, :fr, :week)
assert_equal ['2007-07-09'.to_date, '2007-07-15'.to_date], [c.startdt, c.enddt]
c = Redmine::Helpers::Calendar.new(Date.today, :en, :week)
assert_equal [7, 6], [c.startdt.cwday, c.enddt.cwday]
end
def test_monthly_start_day
[1, 6, 7].each do |day|
with_settings :start_of_week => day do
c = Redmine::Helpers::Calendar.new(Date.today, :en, :month)
assert_equal day , c.startdt.cwday
assert_equal (day + 5) % 7 + 1, c.enddt.cwday
end
end
end
def test_weekly_start_day
[1, 6, 7].each do |day|
with_settings :start_of_week => day do
c = Redmine::Helpers::Calendar.new(Date.today, :en, :week)
assert_equal day, c.startdt.cwday
assert_equal (day + 5) % 7 + 1, c.enddt.cwday
end
end
end
end

View file

@ -0,0 +1,37 @@
# 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 DiffTest < ActiveSupport::TestCase
def test_diff
diff = Redmine::Helpers::Diff.new("foo", "bar")
assert_not_nil diff
end
def test_dont_double_escape
# 3 cases to test in the before: first word, last word, everything inbetween
before = "<stuff> with html & special chars</danger>"
# all words in after are treated equal
after = "other stuff <script>alert('foo');</alert>"
computed_diff = Redmine::Helpers::Diff.new(before, after).to_html
expected_diff = '<span class="diff_in">&lt;stuff&gt; with html &amp; special chars&lt;/danger&gt;</span> <span class="diff_out">other stuff &lt;script&gt;alert(&#39;foo&#39;);&lt;/alert&gt;</span>'
assert_equal computed_diff, expected_diff
end
end

View file

@ -0,0 +1,498 @@
# 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 Redmine::Helpers::GanttHelperTest < Redmine::HelperTest
fixtures :projects, :trackers, :issue_statuses,
:enumerations, :users, :issue_categories
include ProjectsHelper
include IssuesHelper
include ERB::Util
include Rails.application.routes.url_helpers
def setup
setup_with_controller
User.current = User.find(1)
end
def today
@today ||= Date.today
end
private :today
def gantt_start
@gantt.date_from
end
# Creates a Gantt chart for a 4 week span
def create_gantt(project=Project.generate!, options={})
@project = project
@gantt = Redmine::Helpers::Gantt.new(options)
@gantt.project = @project
@gantt.query = IssueQuery.new(:project => @project, :name => 'Gantt')
@gantt.view = self
@gantt.instance_variable_set('@date_from', options[:date_from] || (today - 14))
@gantt.instance_variable_set('@date_to', options[:date_to] || (today + 14))
end
private :create_gantt
test "#number_of_rows with one project should return the number of rows just for that project" do
p1, p2 = Project.generate!, Project.generate!
i1, i2 = Issue.generate!(:project => p1), Issue.generate!(:project => p2)
create_gantt(p1)
assert_equal 2, @gantt.number_of_rows
end
test "#number_of_rows with no project should return the total number of rows for all the projects, recursively" do
p1, p2 = Project.generate!, Project.generate!
create_gantt(nil)
# fix the return value of #number_of_rows_on_project() to an arbitrary value
# so that we really only test #number_of_rows
@gantt.stubs(:number_of_rows_on_project).returns(7)
# also fix #projects because we want to test #number_of_rows in isolation
@gantt.stubs(:projects).returns(Project.all)
# actual test
assert_equal Project.count*7, @gantt.number_of_rows
end
test "#number_of_rows should not exceed max_rows option" do
p = Project.generate!
5.times do
Issue.generate!(:project => p)
end
create_gantt(p)
@gantt.render
assert_equal 6, @gantt.number_of_rows
assert !@gantt.truncated
create_gantt(p, :max_rows => 3)
@gantt.render
assert_equal 3, @gantt.number_of_rows
assert @gantt.truncated
end
test "#number_of_rows_on_project should count 0 for an empty the project" do
create_gantt
assert_equal 0, @gantt.number_of_rows_on_project(@project)
end
test "#number_of_rows_on_project should count the number of issues without a version" do
create_gantt
@project.issues << Issue.generate!(:project => @project, :fixed_version => nil)
assert_equal 2, @gantt.number_of_rows_on_project(@project)
end
test "#number_of_rows_on_project should count the number of issues on versions, including cross-project" do
create_gantt
version = Version.generate!
@project.versions << version
@project.issues << Issue.generate!(:project => @project, :fixed_version => version)
assert_equal 3, @gantt.number_of_rows_on_project(@project)
end
def setup_subjects
create_gantt
@project.enabled_module_names = [:issue_tracking]
@tracker = Tracker.generate!
@project.trackers << @tracker
@version = Version.generate!(:effective_date => (today + 7), :sharing => 'none')
@project.versions << @version
@issue = Issue.generate!(:fixed_version => @version,
:subject => "gantt#line_for_project",
:tracker => @tracker,
:project => @project,
:done_ratio => 30,
:start_date => (today - 1),
:due_date => (today + 7))
@project.issues << @issue
end
private :setup_subjects
# TODO: more of an integration test
test "#subjects project should be rendered" do
setup_subjects
@output_buffer = @gantt.subjects
assert_select "div.project-name a", /#{@project.name}/
assert_select 'div.project-name[style*="left:4px"]'
end
test "#subjects version should be rendered" do
setup_subjects
@output_buffer = @gantt.subjects
assert_select "div.version-name a", /#{@version.name}/
assert_select 'div.version-name[style*="left:24px"]'
end
test "#subjects version without assigned issues should not be rendered" do
setup_subjects
@version = Version.generate!(:effective_date => (today + 14),
:sharing => 'none',
:name => 'empty_version')
@project.versions << @version
@output_buffer = @gantt.subjects
assert_select "div.version-name a", :text => /#{@version.name}/, :count => 0
end
test "#subjects issue should be rendered" do
setup_subjects
@output_buffer = @gantt.subjects
assert_select "div.issue-subject", /#{@issue.subject}/
assert_select 'div.issue-subject[style*="left:44px"]'
end
test "#subjects issue assigned to a shared version of another project should be rendered" do
setup_subjects
p = Project.generate!
p.enabled_module_names = [:issue_tracking]
@shared_version = Version.generate!(:sharing => 'system')
p.versions << @shared_version
# Reassign the issue to a shared version of another project
@issue = Issue.generate!(:fixed_version => @shared_version,
:subject => "gantt#assigned_to_shared_version",
:tracker => @tracker,
:project => @project,
:done_ratio => 30,
:start_date => (today - 1),
:due_date => (today + 7))
@project.issues << @issue
@output_buffer = @gantt.subjects
assert_select "div.issue-subject", /#{@issue.subject}/
end
test "#subjects issue with subtasks should indent subtasks" do
setup_subjects
attrs = {:project => @project, :tracker => @tracker, :fixed_version => @version}
@child1 = Issue.generate!(
attrs.merge(:subject => 'child1',
:parent_issue_id => @issue.id,
:start_date => (today - 1),
:due_date => (today + 2))
)
@child2 = Issue.generate!(
attrs.merge(:subject => 'child2',
:parent_issue_id => @issue.id,
:start_date => today,
:due_date => (today + 7))
)
@grandchild = Issue.generate!(
attrs.merge(:subject => 'grandchild',
:parent_issue_id => @child1.id,
:start_date => (today - 1),
:due_date => (today + 2))
)
@output_buffer = @gantt.subjects
# parent task 44px
assert_select 'div.issue-subject[style*="left:44px"]', /#{@issue.subject}/
# children 64px
assert_select 'div.issue-subject[style*="left:64px"]', /child1/
assert_select 'div.issue-subject[style*="left:64px"]', /child2/
# grandchild 84px
assert_select 'div.issue-subject[style*="left:84px"]', /grandchild/, @output_buffer
end
test "#lines" do
create_gantt
@project.enabled_module_names = [:issue_tracking]
@tracker = Tracker.generate!
@project.trackers << @tracker
@version = Version.generate!(:effective_date => (today + 7))
@project.versions << @version
@issue = Issue.generate!(:fixed_version => @version,
:subject => "gantt#line_for_project",
:tracker => @tracker,
:project => @project,
:done_ratio => 30,
:start_date => (today - 1),
:due_date => (today + 7))
@project.issues << @issue
@output_buffer = @gantt.lines
assert_select "div.project.task_todo"
assert_select "div.project.starting"
assert_select "div.project.ending"
assert_select "div.label.project", /#{@project.name}/
assert_select "div.version.task_todo"
assert_select "div.version.starting"
assert_select "div.version.ending"
assert_select "div.label.version", /#{@version.name}/
assert_select "div.task_todo"
assert_select "div.task.label", /#{@issue.done_ratio}/
assert_select "div.tooltip", /#{@issue.subject}/
end
test "#subject_for_project" do
create_gantt
@output_buffer = @gantt.subject_for_project(@project, :format => :html)
assert_select 'a[href=?]', "/projects/#{@project.identifier}", :text => /#{@project.name}/
end
test "#subject_for_project should style overdue projects" do
create_gantt
@project.stubs(:overdue?).returns(true)
@output_buffer = @gantt.subject_for_project(@project, :format => :html)
assert_select 'div span.project-overdue'
end
test "#subject_for_version" do
create_gantt
version = Version.generate!(:name => 'Foo', :effective_date => today, :project => @project)
@output_buffer = @gantt.subject_for_version(version, :format => :html)
assert_select 'a[href=?]', "/versions/#{version.to_param}", :text => /Foo/
end
test "#subject_for_version should style overdue versions" do
create_gantt
version = Version.generate!(:name => 'Foo', :effective_date => today, :project => @project)
version.stubs(:overdue?).returns(true)
@output_buffer = @gantt.subject_for_version(version, :format => :html)
assert_select 'div span.version-overdue'
end
test "#subject_for_version should style behind schedule versions" do
create_gantt
version = Version.generate!(:name => 'Foo', :effective_date => today, :project => @project)
version.stubs(:behind_schedule?).returns(true)
@output_buffer = @gantt.subject_for_version(version, :format => :html)
assert_select 'div span.version-behind-schedule'
end
test "#subject_for_issue" do
create_gantt
issue = Issue.generate!(:project => @project)
@output_buffer = @gantt.subject_for_issue(issue, :format => :html)
assert_select 'div', :text => /#{issue.subject}/
assert_select 'a[href=?]', "/issues/#{issue.to_param}", :text => /#{issue.tracker.name} ##{issue.id}/
end
test "#subject_for_issue should style overdue issues" do
create_gantt
issue = Issue.generate!(:project => @project)
issue.stubs(:overdue?).returns(true)
@output_buffer = @gantt.subject_for_issue(issue, :format => :html)
assert_select 'div span.issue-overdue'
end
test "#subject should add an absolute positioned div" do
create_gantt
@output_buffer = @gantt.subject('subject', :format => :html)
assert_select "div[style*=absolute]", :text => 'subject'
end
test "#subject should use the indent option to move the div to the right" do
create_gantt
@output_buffer = @gantt.subject('subject', :format => :html, :indent => 40)
assert_select 'div[style*="left:40"]'
end
test "#line_for_project" do
create_gantt
@project.stubs(:start_date).returns(today - 7)
@project.stubs(:due_date).returns(today + 7)
@output_buffer = @gantt.line_for_project(@project, :format => :html)
assert_select "div.project.label", :text => @project.name
end
test "#line_for_version" do
create_gantt
version = Version.generate!(:name => 'Foo', :project => @project)
version.stubs(:start_date).returns(today - 7)
version.stubs(:due_date).returns(today + 7)
version.stubs(:completed_percent).returns(30)
@output_buffer = @gantt.line_for_version(version, :format => :html)
assert_select "div.version.label", :text => /Foo/
assert_select "div.version.label", :text => /30%/
end
test "#line_for_issue" do
create_gantt
issue = Issue.generate!(:project => @project, :start_date => today - 7, :due_date => today + 7, :done_ratio => 30)
@output_buffer = @gantt.line_for_issue(issue, :format => :html)
assert_select "div.task.label", :text => /#{issue.status.name}/
assert_select "div.task.label", :text => /30%/
assert_select "div.tooltip", /#{issue.subject}/
end
test "#line todo line should start from the starting point on the left" do
create_gantt
@output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
assert_select 'div.task_todo[style*="left:28px"]', 1
end
test "#line todo line should be the total width" do
create_gantt
@output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
assert_select 'div.task_todo[style*="width:58px"]', 1
end
test "#line late line should start from the starting point on the left" do
create_gantt
@output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
assert_select 'div.task_late[style*="left:28px"]', 1
end
test "#line late line should be the total delayed width" do
create_gantt
@output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
assert_select 'div.task_late[style*="width:30px"]', 1
end
test "#line done line should start from the starting point on the left" do
create_gantt
@output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
assert_select 'div.task_done[style*="left:28px"]', 1
end
test "#line done line should be the width for the done ratio" do
create_gantt
@output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
# 15 days * 4 px * 30% - 2 px for borders = 16 px
assert_select 'div.task_done[style*="width:16px"]', 1
end
test "#line done line should be the total width for 100% done ratio" do
create_gantt
@output_buffer = @gantt.line(today - 7, today + 7, 100, false, 'line', :format => :html, :zoom => 4)
# 15 days * 4 px - 2 px for borders = 58 px
assert_select 'div.task_done[style*="width:58px"]', 1
end
test "#line done line should be the total width for 100% done ratio with same start and end dates" do
create_gantt
@output_buffer = @gantt.line(today + 7, today + 7, 100, false, 'line', :format => :html, :zoom => 4)
assert_select 'div.task_done[style*="width:2px"]', 1
end
test "#line done line should not be the total done width if the gantt starts after start date" do
create_gantt
@output_buffer = @gantt.line(today - 16, today - 2, 30, false, 'line', :format => :html, :zoom => 4)
assert_select 'div.task_done[style*="left:0px"]', 1
assert_select 'div.task_done[style*="width:8px"]', 1
end
test "#line starting marker should appear at the start date" do
create_gantt
@output_buffer = @gantt.line(today - 7, today + 7, 30, true, 'line', :format => :html, :zoom => 4)
assert_select "div.starting", 1
assert_select 'div.starting[style*="left:28px"]', 1
end
test "#line starting marker should not appear if the start date is before gantt start date" do
create_gantt
@output_buffer = @gantt.line(gantt_start - 2, today + 7, 30, true, 'line', :format => :html, :zoom => 4)
assert_select "div.starting", 0
end
test "#line ending marker should appear at the end date" do
create_gantt
@output_buffer = @gantt.line(today - 7, today + 7, 30, true, 'line', :format => :html, :zoom => 4)
assert_select "div.ending", 1
assert_select 'div.ending[style*="left:88px"]', 1
end
test "#line ending marker should not appear if the end date is before gantt start date" do
create_gantt
@output_buffer = @gantt.line(gantt_start - 30, gantt_start - 21, 30, true, 'line', :format => :html)
assert_select "div.ending", 0
end
test "#line label should appear at the far left, even if it's before gantt start date" do
create_gantt
@output_buffer = @gantt.line(gantt_start - 30, gantt_start - 21, 30, true, 'line', :format => :html)
assert_select "div.label", :text => 'line'
end
def test_sort_issues_no_date
project = Project.generate!
issue1 = Issue.generate!(:subject => "test", :project => project)
issue2 = Issue.generate!(:subject => "test", :project => project)
assert issue1.root_id < issue2.root_id
child1 = Issue.generate!(:parent_issue_id => issue1.id, :subject => 'child',
:project => project)
child2 = Issue.generate!(:parent_issue_id => issue1.id, :subject => 'child',
:project => project)
child3 = Issue.generate!(:parent_issue_id => child1.id, :subject => 'child',
:project => project)
assert_equal child1.root_id, child2.root_id
assert child1.lft < child2.lft
assert child3.lft < child2.lft
issues = [child3, child2, child1, issue2, issue1]
Redmine::Helpers::Gantt.sort_issues!(issues)
assert_equal [issue1.id, child1.id, child3.id, child2.id, issue2.id],
issues.map{|v| v.id}
end
def test_sort_issues_root_only
project = Project.generate!
issue1 = Issue.generate!(:subject => "test", :project => project)
issue2 = Issue.generate!(:subject => "test", :project => project)
issue3 = Issue.generate!(:subject => "test", :project => project,
:start_date => (today - 1))
issue4 = Issue.generate!(:subject => "test", :project => project,
:start_date => (today - 2))
issues = [issue4, issue3, issue2, issue1]
Redmine::Helpers::Gantt.sort_issues!(issues)
assert_equal [issue1.id, issue2.id, issue4.id, issue3.id],
issues.map{|v| v.id}
end
def test_sort_issues_tree
project = Project.generate!
issue1 = Issue.generate!(:subject => "test", :project => project)
issue2 = Issue.generate!(:subject => "test", :project => project,
:start_date => (today - 2))
issue1_child1 =
Issue.generate!(:parent_issue_id => issue1.id, :subject => 'child',
:project => project)
issue1_child2 =
Issue.generate!(:parent_issue_id => issue1.id, :subject => 'child',
:project => project, :start_date => (today - 10))
issue1_child1_child1 =
Issue.generate!(:parent_issue_id => issue1_child1.id, :subject => 'child',
:project => project, :start_date => (today - 8))
issue1_child1_child2 =
Issue.generate!(:parent_issue_id => issue1_child1.id, :subject => 'child',
:project => project, :start_date => (today - 9))
issue1_child1_child1_logic = Redmine::Helpers::Gantt.sort_issue_logic(issue1_child1_child1)
assert_equal [[today - 10, issue1.id], [today - 9, issue1_child1.id],
[today - 8, issue1_child1_child1.id]],
issue1_child1_child1_logic
issue1_child1_child2_logic = Redmine::Helpers::Gantt.sort_issue_logic(issue1_child1_child2)
assert_equal [[today - 10, issue1.id], [today - 9, issue1_child1.id],
[today - 9, issue1_child1_child2.id]],
issue1_child1_child2_logic
issues = [issue1_child1_child2, issue1_child1_child1, issue1_child2,
issue1_child1, issue2, issue1]
Redmine::Helpers::Gantt.sort_issues!(issues)
assert_equal [issue1.id, issue1_child1.id, issue1_child2.id,
issue1_child1_child2.id, issue1_child1_child1.id, issue2.id],
issues.map{|v| v.id}
end
def test_sort_versions
project = Project.generate!
versions = []
versions << Version.create!(:project => project, :name => 'test1')
versions << Version.create!(:project => project, :name => 'test2', :effective_date => '2013-10-25')
versions << Version.create!(:project => project, :name => 'test3')
versions << Version.create!(:project => project, :name => 'test4', :effective_date => '2013-10-02')
assert_equal versions.sort, Redmine::Helpers::Gantt.sort_versions!(versions.dup)
end
end

View file

@ -0,0 +1,189 @@
# 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 Redmine::Hook::ManagerTest < ActionView::TestCase
fixtures :projects, :users, :members, :member_roles, :roles,
:groups_users,
:email_addresses,
:trackers, :projects_trackers,
:enabled_modules,
:versions,
:issue_statuses, :issue_categories, :issue_relations,
:enumerations,
:issues
# Some hooks that are manually registered in these tests
class TestHook < Redmine::Hook::ViewListener; end
class TestHook1 < TestHook
def view_layouts_base_html_head(context)
'Test hook 1 listener.'
end
end
class TestHook2 < TestHook
def view_layouts_base_html_head(context)
'Test hook 2 listener.'
end
end
class TestHook3 < TestHook
def view_layouts_base_html_head(context)
"Context keys: #{context.keys.collect(&:to_s).sort.join(', ')}."
end
end
class TestLinkToHook < TestHook
def view_layouts_base_html_head(context)
link_to('Issues', :controller => 'issues')
end
end
class TestHookHelperController < ActionController::Base
include Redmine::Hook::Helper
end
class TestHookHelperView < ActionView::Base
include Redmine::Hook::Helper
end
Redmine::Hook.clear_listeners
def setup
@hook_module = Redmine::Hook
@hook_module.clear_listeners
end
def teardown
@hook_module.clear_listeners
end
def test_clear_listeners
assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size
@hook_module.add_listener(TestHook1)
@hook_module.add_listener(TestHook2)
assert_equal 2, @hook_module.hook_listeners(:view_layouts_base_html_head).size
@hook_module.clear_listeners
assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size
end
def test_add_listener
assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size
@hook_module.add_listener(TestHook1)
assert_equal 1, @hook_module.hook_listeners(:view_layouts_base_html_head).size
end
def test_call_hook
@hook_module.add_listener(TestHook1)
assert_equal ['Test hook 1 listener.'], hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_with_context
@hook_module.add_listener(TestHook3)
assert_equal ['Context keys: bar, controller, foo, hook_caller, project, request.'],
hook_helper.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a')
end
def test_call_hook_with_multiple_listeners
@hook_module.add_listener(TestHook1)
@hook_module.add_listener(TestHook2)
assert_equal ['Test hook 1 listener.', 'Test hook 2 listener.'], hook_helper.call_hook(:view_layouts_base_html_head)
end
# Context: Redmine::Hook::Helper.call_hook default_url
def test_call_hook_default_url_options
@hook_module.add_listener(TestLinkToHook)
assert_equal ['<a href="/issues">Issues</a>'], hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_view_hook_should_generate_links_with_relative_url_root
Redmine::Utils.relative_url_root = '/foo'
@hook_module.add_listener(TestLinkToHook)
assert_equal ['<a href="/foo/issues">Issues</a>'], hook_helper.call_hook(:view_layouts_base_html_head)
ensure
Redmine::Utils.relative_url_root = ''
end
# Context: Redmine::Hook::Helper.call_hook
def test_call_hook_with_project_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /project/i, hook_helper.call_hook(:view_layouts_base_html_head)[0]
end
def test_call_hook_from_controller_with_controller_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /controller/i, hook_helper.call_hook(:view_layouts_base_html_head)[0]
end
def test_call_hook_from_controller_with_request_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /request/i, hook_helper.call_hook(:view_layouts_base_html_head)[0]
end
def test_call_hook_from_view_with_project_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /project/i, view_hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_from_view_with_controller_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /controller/i, view_hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_from_view_with_request_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /request/i, view_hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_from_view_should_join_responses_with_a_space
@hook_module.add_listener(TestHook1)
@hook_module.add_listener(TestHook2)
assert_equal 'Test hook 1 listener. Test hook 2 listener.',
view_hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_should_not_change_the_default_url_for_email_notifications
issue = Issue.find(1)
ActionMailer::Base.deliveries.clear
Mailer.deliver_issue_add(issue)
mail = ActionMailer::Base.deliveries.last
@hook_module.add_listener(TestLinkToHook)
hook_helper.call_hook(:view_layouts_base_html_head)
ActionMailer::Base.deliveries.clear
Mailer.deliver_issue_add(issue)
mail2 = ActionMailer::Base.deliveries.last
assert_equal mail_body(mail), mail_body(mail2)
end
def hook_helper
@hook_helper ||= TestHookHelperController.new
end
def view_hook_helper
@view_hook_helper ||= TestHookHelperView.new(Rails.root.to_s + '/app/views')
end
end

View file

@ -0,0 +1,261 @@
# 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 Redmine::I18nTest < ActiveSupport::TestCase
include Redmine::I18n
include ActionView::Helpers::NumberHelper
def setup
User.current = nil
end
def teardown
set_language_if_valid 'en'
end
def test_date_format_default
set_language_if_valid 'en'
today = Date.today
with_settings :date_format => '' do
assert_equal I18n.l(today), format_date(today)
end
end
def test_date_format
set_language_if_valid 'en'
today = Date.today
with_settings :date_format => '%d %m %Y' do
assert_equal today.strftime('%d %m %Y'), format_date(today)
end
end
def test_date_format_with_month_name_should_translate_with_current_locale
set_language_if_valid 'es'
date = Date.parse('2011-02-20 14:00:00')
with_settings :date_format => '%d %B %Y' do
assert_equal '20 Febrero 2011', format_date(date)
end
end
def test_date_and_time_for_each_language
with_settings :date_format => '' do
valid_languages.each do |lang|
set_language_if_valid lang
assert_nothing_raised do
format_date(Date.today)
format_time(Time.now)
format_time(Time.now, false)
assert_not_equal 'default', ::I18n.l(Date.today, :format => :default),
"date.formats.default missing in #{lang}"
assert_not_equal 'time', ::I18n.l(Time.now, :format => :time),
"time.formats.time missing in #{lang}"
end
assert l('date.day_names').is_a?(Array)
assert_equal 7, l('date.day_names').size
assert l('date.month_names').is_a?(Array)
assert_equal 13, l('date.month_names').size
end
end
end
def test_time_for_each_zone
ActiveSupport::TimeZone.all.each do |zone|
User.current.stubs(:time_zone).returns(zone.name)
assert_nothing_raised do
format_time(Time.now)
end
end
end
def test_time_format
set_language_if_valid 'en'
now = Time.parse('2011-02-20 15:45:22')
with_settings :time_format => '%H:%M' do
with_settings :date_format => '' do
assert_equal '02/20/2011 15:45', format_time(now)
assert_equal '15:45', format_time(now, false)
end
with_settings :date_format => '%Y-%m-%d' do
assert_equal '2011-02-20 15:45', format_time(now)
assert_equal '15:45', format_time(now, false)
end
end
end
def test_time_format_default
set_language_if_valid 'en'
now = Time.parse('2011-02-20 15:45:22')
with_settings :time_format => '' do
with_settings :date_format => '' do
assert_equal '02/20/2011 03:45 PM', format_time(now)
assert_equal '03:45 PM', format_time(now, false)
end
with_settings :date_format => '%Y-%m-%d' do
assert_equal '2011-02-20 03:45 PM', format_time(now)
assert_equal '03:45 PM', format_time(now, false)
end
end
end
def test_utc_time_format
set_language_if_valid 'en'
now = Time.now
with_settings :date_format => '%d %m %Y', :time_format => '%H %M' do
assert_equal now.localtime.strftime('%d %m %Y %H %M'), format_time(now.utc), "User time zone was #{User.current.time_zone}"
assert_equal now.localtime.strftime('%H %M'), format_time(now.utc, false)
end
end
def test_number_to_human_size_for_each_language
valid_languages.each do |lang|
set_language_if_valid lang
assert_nothing_raised do
size = number_to_human_size(257024)
assert_match /251/, size, "#{lang} failure"
end
end
end
def test_day_name
set_language_if_valid 'fr'
assert_equal 'dimanche', day_name(0)
assert_equal 'jeudi', day_name(4)
end
def test_day_letter
set_language_if_valid 'fr'
assert_equal 'd', day_letter(0)
assert_equal 'j', day_letter(4)
end
def test_number_to_currency_for_each_language
valid_languages.each do |lang|
set_language_if_valid lang
assert_nothing_raised do
number_to_currency(-1000.2)
end
end
end
def test_l_hours_short
set_language_if_valid 'en'
assert_equal '2.00 h', l_hours_short(2.0)
end
def test_number_to_currency_default
set_language_if_valid 'bs'
assert_equal "KM -1000,20", number_to_currency(-1000.2)
set_language_if_valid 'de'
euro_sign = "\xe2\x82\xac".force_encoding('UTF-8')
assert_equal "-1000,20 #{euro_sign}", number_to_currency(-1000.2)
end
def test_lu_should_not_error_when_user_language_is_an_empty_string
user = User.new
user.language = ''
assert_nothing_raised do
lu(user, :label_issue)
end
end
def test_valid_languages
assert valid_languages.is_a?(Array)
assert valid_languages.first.is_a?(Symbol)
end
def test_languages_options
options = languages_options
assert options.is_a?(Array)
assert_equal valid_languages.size, options.size
assert_nil options.detect {|option| !option.is_a?(Array)}
assert_nil options.detect {|option| option.size != 2}
assert_nil options.detect {|option| !option.first.is_a?(String) || !option.last.is_a?(String)}
assert_include ["English", "en"], options
ja = "Japanese (\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e)".force_encoding('UTF-8')
assert_include [ja, "ja"], options
end
def test_languages_options_should_return_strings_with_utf8_encoding
strings = languages_options.flatten
assert_equal ["UTF-8"], strings.map(&:encoding).uniq.map(&:name).sort
end
def test_languages_options_should_ignore_locales_without_general_lang_name_key
stubs(:valid_languages).returns([:en, :foo])
assert_equal [["English", "en"]], languages_options(:cache => false)
end
def test_locales_validness
lang_files_count = Dir["#{Rails.root}/config/locales/*.yml"].size
assert_equal lang_files_count, valid_languages.size
valid_languages.each do |lang|
assert set_language_if_valid(lang)
end
set_language_if_valid('en')
end
def test_valid_language
to_test = {'fr' => :fr,
'Fr' => :fr,
'zh' => :zh,
'zh-tw' => :"zh-TW",
'zh-TW' => :"zh-TW"}
to_test.each {|lang, expected| assert_equal expected, find_language(lang)}
end
def test_find_language_with_invalid_language_should_return_nil
assert_nil find_language('zh-ZZ')
end
def test_fallback
::I18n.backend.store_translations(:en, {:untranslated => "Untranslated string"})
::I18n.locale = 'en'
assert_equal "Untranslated string", l(:untranslated)
::I18n.locale = 'fr'
assert_equal "Untranslated string", l(:untranslated)
::I18n.backend.store_translations(:fr, {:untranslated => "Pas de traduction"})
::I18n.locale = 'en'
assert_equal "Untranslated string", l(:untranslated)
::I18n.locale = 'fr'
assert_equal "Pas de traduction", l(:untranslated)
end
def test_utf8
set_language_if_valid 'ja'
str_ja_yes = "\xe3\x81\xaf\xe3\x81\x84".force_encoding('UTF-8')
i18n_ja_yes = l(:general_text_Yes)
assert_equal str_ja_yes, i18n_ja_yes
assert_equal "UTF-8", i18n_ja_yes.encoding.to_s
end
def test_traditional_chinese_locale
set_language_if_valid 'zh-TW'
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)
end
def test_french_locale
set_language_if_valid 'fr'
str_fr = "French (Fran\xc3\xa7ais)".force_encoding('UTF-8')
assert_equal str_fr, l(:general_lang_name)
end
end

View file

@ -0,0 +1,27 @@
# 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 Redmine::InfoTest < ActiveSupport::TestCase
def test_environment
env = Redmine::Info.environment
assert_kind_of String, env
assert_match 'Redmine version', env
end
end

View file

@ -0,0 +1,191 @@
# 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 Redmine::MenuManager::MapperTest < ActiveSupport::TestCase
test "Mapper#initialize should define a root MenuNode if menu is not present in items" do
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
node = menu_mapper.menu_items
assert_not_nil node
assert_equal :root, node.name
end
test "Mapper#initialize should use existing MenuNode if present" do
node = "foo" # just an arbitrary reference
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {:test_menu => node})
assert_equal node, menu_mapper.menu_items
end
def test_push_onto_root
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.exists?(:test_overview)
end
def test_push_onto_parent
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent => :test_overview}
assert menu_mapper.exists?(:test_child)
assert_equal :test_child, menu_mapper.find(:test_child).name
end
def test_push_onto_grandparent
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent => :test_overview}
menu_mapper.push :test_grandchild, { :controller => 'projects', :action => 'show'}, {:parent => :test_child}
assert menu_mapper.exists?(:test_grandchild)
grandchild = menu_mapper.find(:test_grandchild)
assert_equal :test_grandchild, grandchild.name
assert_equal :test_child, grandchild.parent.name
end
def test_push_first
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {:first => true}
root = menu_mapper.find(:root)
assert_equal 5, root.children.size
{0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
assert_not_nil root.children[position]
assert_equal name, root.children[position].name
end
end
def test_push_before
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {:before => :test_fourth}
root = menu_mapper.find(:root)
assert_equal 5, root.children.size
{0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
assert_not_nil root.children[position]
assert_equal name, root.children[position].name
end
end
def test_push_after
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {:after => :test_third}
root = menu_mapper.find(:root)
assert_equal 5, root.children.size
{0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
assert_not_nil root.children[position]
assert_equal name, root.children[position].name
end
end
def test_push_last
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {:last => true}
menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {}
root = menu_mapper.find(:root)
assert_equal 5, root.children.size
{0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
assert_not_nil root.children[position]
assert_equal name, root.children[position].name
end
end
def test_exists_for_child_node
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent => :test_overview }
assert menu_mapper.exists?(:test_child)
end
def test_exists_for_invalid_node
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
assert !menu_mapper.exists?(:nothing)
end
def test_find
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
item = menu_mapper.find(:test_overview)
assert_equal :test_overview, item.name
assert_equal({:controller => 'projects', :action => 'show'}, item.url)
end
def test_find_missing
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
item = menu_mapper.find(:nothing)
assert_nil item
end
def test_delete
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
assert_not_nil menu_mapper.delete(:test_overview)
assert_nil menu_mapper.find(:test_overview)
end
def test_delete_missing
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
assert_nil menu_mapper.delete(:test_missing)
end
test 'deleting all items' do
# Exposed by deleting :last items
Redmine::MenuManager.map :test_menu do |menu|
menu.push :not_last, Redmine::Info.help_url
menu.push :administration, { :controller => 'projects', :action => 'show'}, {:last => true}
menu.push :help, Redmine::Info.help_url, :last => true
end
assert_nothing_raised do
Redmine::MenuManager.map :test_menu do |menu|
menu.delete(:administration)
menu.delete(:help)
menu.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
end
end
end
end

View file

@ -0,0 +1,342 @@
# 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 Redmine::MenuManager::MenuHelperTest < Redmine::HelperTest
include Redmine::MenuManager::MenuHelper
include ERB::Util
include Rails.application.routes.url_helpers
fixtures :users, :members, :projects, :enabled_modules, :roles, :member_roles
def setup
setup_with_controller
# Stub the current menu item in the controller
def current_menu_item
:index
end
end
def test_render_single_menu_node
node = Redmine::MenuManager::MenuItem.new(:testing, '/test', { })
@output_buffer = render_single_menu_node(node, 'This is a test', node.url, false)
assert_select("a.testing", "This is a test")
end
def test_render_menu_node
single_node = Redmine::MenuManager::MenuItem.new(:single_node, '/test', { })
@output_buffer = render_menu_node(single_node, nil)
assert_select("li") do
assert_select("a.single-node", "Single node")
end
end
def test_render_menu_node_with_symbol_as_url
node = Redmine::MenuManager::MenuItem.new(:testing, :issues_path)
@output_buffer = render_menu_node(node, nil)
assert_select 'a[href="/issues"]', "Testing"
end
def test_render_menu_node_with_symbol_as_url_and_project
node = Redmine::MenuManager::MenuItem.new(:testing, :project_issues_path)
@output_buffer = render_menu_node(node, Project.find(1))
assert_select 'a[href="/projects/ecookbook/issues"]', "Testing"
end
def test_render_menu_node_with_nested_items
parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { })
parent_node << Redmine::MenuManager::MenuItem.new(:child_one_node, '/test', { })
parent_node << Redmine::MenuManager::MenuItem.new(:child_two_node, '/test', { })
parent_node <<
Redmine::MenuManager::MenuItem.new(:child_three_node, '/test', { }) <<
Redmine::MenuManager::MenuItem.new(:child_three_inner_node, '/test', { })
@output_buffer = render_menu_node(parent_node, nil)
assert_select("li") do
assert_select("a.parent-node", "Parent node")
assert_select("ul") do
assert_select("li a.child-one-node", "Child one node")
assert_select("li a.child-two-node", "Child two node")
assert_select("li") do
assert_select("a.child-three-node", "Child three node")
assert_select("ul") do
assert_select("li a.child-three-inner-node", "Child three inner node")
end
end
end
end
end
def test_render_menu_node_with_children
User.current = User.find(2)
parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
'/test',
{
:children => Proc.new {|p|
children = []
3.times do |time|
children << Redmine::MenuManager::MenuItem.new("test_child_#{time}",
{:controller => 'issues', :action => 'index'},
{})
end
children
}
})
@output_buffer = render_menu_node(parent_node, Project.find(1))
assert_select("li") do
assert_select("a.parent-node", "Parent node")
assert_select("ul") do
assert_select("li a.test-child-0", "Test child 0")
assert_select("li a.test-child-1", "Test child 1")
assert_select("li a.test-child-2", "Test child 2")
end
end
end
def test_render_menu_node_with_nested_items_and_children
User.current = User.find(2)
parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
{:controller => 'issues', :action => 'index'},
{
:children => Proc.new {|p|
children = []
3.times do |time|
children << Redmine::MenuManager::MenuItem.new("test_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
end
children
}
})
parent_node << Redmine::MenuManager::MenuItem.new(:child_node,
{:controller => 'issues', :action => 'index'},
{
:children => Proc.new {|p|
children = []
6.times do |time|
children << Redmine::MenuManager::MenuItem.new("test_dynamic_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
end
children
}
})
@output_buffer = render_menu_node(parent_node, Project.find(1))
assert_select("li") do
assert_select("a.parent-node", "Parent node")
assert_select("ul") do
assert_select("li a.child-node", "Child node")
assert_select("ul") do
assert_select("li a.test-dynamic-child-0", "Test dynamic child 0")
assert_select("li a.test-dynamic-child-1", "Test dynamic child 1")
assert_select("li a.test-dynamic-child-2", "Test dynamic child 2")
assert_select("li a.test-dynamic-child-3", "Test dynamic child 3")
assert_select("li a.test-dynamic-child-4", "Test dynamic child 4")
assert_select("li a.test-dynamic-child-5", "Test dynamic child 5")
end
assert_select("li a.test-child-0", "Test child 0")
assert_select("li a.test-child-1", "Test child 1")
assert_select("li a.test-child-2", "Test child 2")
end
end
end
def test_render_menu_node_with_allowed_and_unallowed_unattached_children
User.current = User.find(2)
parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
{:controller => 'issues', :action => 'index'},
{
:children => Proc.new {|p|
[
Redmine::MenuManager::MenuItem.new("test_child_allowed", {:controller => 'issues', :action => 'index'}, {}),
Redmine::MenuManager::MenuItem.new("test_child_unallowed", {:controller => 'issues', :action => 'unallowed'}, {}),
]
}
})
@output_buffer = render_menu_node(parent_node, Project.find(1))
assert_select("li") do
assert_select("a.parent-node", "Parent node")
assert_select("ul.menu-children.unattached") do
assert_select("li a.test-child-allowed", "Test child allowed")
assert_select("li a.test-child-unallowed", false)
end
end
end
def test_render_menu_node_with_allowed_and_unallowed_standard_children
User.current = User.find(6)
Redmine::MenuManager.map :some_menu do |menu|
menu.push(:parent_node, {:controller => 'issues', :action => 'index'}, { })
menu.push(:test_child_allowed, {:controller => 'issues', :action => 'index'}, {:parent => :parent_node})
menu.push(:test_child_unallowed, {:controller => 'issues', :action => 'new'}, {:parent => :parent_node})
end
@output_buffer = render_menu(:some_menu, Project.find(1))
assert_select("li") do
assert_select("a.parent-node", "Parent node")
assert_select("ul.menu-children.unattached", false)
assert_select("ul.menu-children") do
assert_select("li a.test-child-allowed", "Test child allowed")
assert_select("li a.test-child-unallowed", false)
end
end
end
def test_render_empty_virtual_menu_node_with_children
# only empty item with no click target
Redmine::MenuManager.map :menu1 do |menu|
menu.push(:parent_node, nil, { })
end
# parent with unallowed unattached child
Redmine::MenuManager.map :menu2 do |menu|
menu.push(:parent_node, nil, {:children => Proc.new {|p|
[Redmine::MenuManager::MenuItem.new("test_child_unallowed", {:controller => 'issues', :action => 'new'}, {})]
} })
end
# parent with unallowed standard child
Redmine::MenuManager.map :menu3 do |menu|
menu.push(:parent_node, nil, {})
menu.push(:test_child_unallowed, {:controller =>'issues', :action => 'new'}, {:parent => :parent_node})
end
# should not be displayed to anonymous
User.current = User.find(6)
assert_nil render_menu(:menu1, Project.find(1))
assert_nil render_menu(:menu2, Project.find(1))
assert_nil render_menu(:menu3, Project.find(1))
# should be displayed to an admin
User.current = User.find(1)
@output_buffer = render_menu(:menu2, Project.find(1))
assert_select("ul li a.parent-node", "Parent node")
@output_buffer = render_menu(:menu3, Project.find(1))
assert_select("ul li a.parent-node", "Parent node")
end
def test_render_menu_node_with_children_without_an_array
parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
'/test',
{
:children => Proc.new {|p| Redmine::MenuManager::MenuItem.new("test_child", "/testing", {})}
})
assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do
@output_buffer = render_menu_node(parent_node, Project.find(1))
end
end
def test_render_menu_node_with_incorrect_children
parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
'/test',
{
:children => Proc.new {|p| ["a string"] }
})
assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do
@output_buffer = render_menu_node(parent_node, Project.find(1))
end
end
def test_menu_items_for_should_yield_all_items_if_passed_a_block
menu_name = :test_menu_items_for_should_yield_all_items_if_passed_a_block
Redmine::MenuManager.map menu_name do |menu|
menu.push(:a_menu, '/', { })
menu.push(:a_menu_2, '/', { })
menu.push(:a_menu_3, '/', { })
end
items_yielded = []
menu_items_for(menu_name) do |item|
items_yielded << item
end
assert_equal 3, items_yielded.size
end
def test_menu_items_for_should_return_all_items
menu_name = :test_menu_items_for_should_return_all_items
Redmine::MenuManager.map menu_name do |menu|
menu.push(:a_menu, '/', { })
menu.push(:a_menu_2, '/', { })
menu.push(:a_menu_3, '/', { })
end
items = menu_items_for(menu_name)
assert_equal 3, items.size
end
def test_menu_items_for_should_skip_unallowed_items_on_a_project
menu_name = :test_menu_items_for_should_skip_unallowed_items_on_a_project
Redmine::MenuManager.map menu_name do |menu|
menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
menu.push(:a_menu_2, {:controller => 'issues', :action => 'index' }, { })
menu.push(:unallowed, {:controller => 'issues', :action => 'unallowed' }, { })
end
User.current = User.find(2)
items = menu_items_for(menu_name, Project.find(1))
assert_equal 2, items.size
end
def test_menu_items_for_should_skip_items_that_fail_the_permission
menu_name = :test_menu_items_for_should_skip_items_that_fail_the_permission
Redmine::MenuManager.map menu_name do |menu|
menu.push(:a_menu, :project_issues_path)
menu.push(:unallowed, :project_issues_path, :permission => :unallowed)
end
User.current = User.find(2)
items = menu_items_for(menu_name, Project.find(1))
assert_equal 1, items.size
end
def test_menu_items_for_should_skip_items_that_fail_the_conditions
menu_name = :test_menu_items_for_should_skip_items_that_fail_the_conditions
Redmine::MenuManager.map menu_name do |menu|
menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
menu.push(:unallowed,
{:controller => 'issues', :action => 'index' },
{ :if => Proc.new { false }})
end
User.current = User.find(2)
items = menu_items_for(menu_name, Project.find(1))
assert_equal 1, items.size
end
end

View file

@ -0,0 +1,108 @@
# 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__)
module RedmineMenuTestHelper
# Helpers
def get_menu_item(menu_name, item_name)
Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym}
end
end
class Redmine::MenuManager::MenuItemTest < ActiveSupport::TestCase
include RedmineMenuTestHelper
Redmine::MenuManager.map :test_menu do |menu|
menu.push(:parent, '/test', { })
menu.push(:child_menu, '/test', { :parent => :parent})
menu.push(:child2_menu, '/test', { :parent => :parent})
end
# context new menu item
def test_new_menu_item_should_require_a_name
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new
end
end
def test_new_menu_item_should_require_an_url
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_missing_url)
end
end
def test_new_menu_item_with_all_required_parameters
assert Redmine::MenuManager::MenuItem.new(:test_good_menu, '/test', {})
end
def test_new_menu_item_should_require_a_proc_to_use_for_the_if_condition
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_error, '/test',
{
:if => ['not_a_proc']
})
end
assert Redmine::MenuManager::MenuItem.new(:test_good_if, '/test',
{
:if => Proc.new{}
})
end
def test_new_menu_item_should_allow_a_hash_for_extra_html_options
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_error, '/test',
{
:html => ['not_a_hash']
})
end
assert Redmine::MenuManager::MenuItem.new(:test_good_html, '/test',
{
:html => { :onclick => 'doSomething'}
})
end
def test_new_menu_item_should_require_a_proc_to_use_the_children_option
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_error, '/test',
{
:children => ['not_a_proc']
})
end
assert Redmine::MenuManager::MenuItem.new(:test_good_children, '/test',
{
:children => Proc.new{}
})
end
def test_new_should_not_allow_setting_the_parent_item_to_the_current_item
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_error, '/test', { :parent => :test_error })
end
end
def test_has_children
parent_item = get_menu_item(:test_menu, :parent)
assert parent_item.children.present?
assert_equal 2, parent_item.children.size
assert_equal get_menu_item(:test_menu, :child_menu), parent_item.children[0]
assert_equal get_menu_item(:test_menu, :child2_menu), parent_item.children[1]
end
end

View file

@ -0,0 +1,34 @@
# 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 Redmine::MenuManagerTest < ActiveSupport::TestCase
def test_map_should_yield_a_mapper
assert_difference 'Redmine::MenuManager.items(:project_menu).size' do
Redmine::MenuManager.map :project_menu do |mapper|
assert_kind_of Redmine::MenuManager::Mapper, mapper
mapper.push :new_item, '/'
end
end
end
def test_items_should_return_menu_items
items = Redmine::MenuManager.items(:project_menu)
assert_kind_of Redmine::MenuManager::MenuNode, items.first
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 Redmine::MimeTypeTest < ActiveSupport::TestCase
def test_of
to_test = {'test.txt' => 'text/plain',
'test.c' => 'text/x-c',
}
to_test.each do |name, expected|
assert_equal expected, Redmine::MimeType.of(name)
end
end
def test_of_with_unknown_type
assert_nil Redmine::MimeType.of('test.unk')
end
def test_css_class_of
to_test = {'test.txt' => 'text-plain',
'test.c' => 'text-x-c',
}
to_test.each do |name, expected|
assert_equal expected, Redmine::MimeType.css_class_of(name)
end
end
def test_css_class_of_with_unknown_type
assert_nil Redmine::MimeType.css_class_of('test.unk')
end
def test_main_mimetype_of
to_test = {'test.txt' => 'text',
'test.c' => 'text',
}
to_test.each do |name, expected|
assert_equal expected, Redmine::MimeType.main_mimetype_of(name)
end
end
def test_main_mimetype_of_with_unknown_type
assert_nil Redmine::MimeType.main_mimetype_of('test.unk')
end
def test_is_type
to_test = {['text', 'test.unk'] => false,
['text', 'test.txt'] => true,
['text', 'test.c'] => true,
}
to_test.each do |args, expected|
assert_equal expected, Redmine::MimeType.is_type?(*args)
end
end
def test_should_default_to_mime_type_gem
assert !Redmine::MimeType::EXTENSIONS.keys.include?("zip")
assert_equal "application/zip", Redmine::MimeType.of("file.zip")
end
end

View file

@ -0,0 +1,29 @@
# 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 Redmine::NotifiableTest < ActiveSupport::TestCase
def setup
end
def test_all
%w(issue_added issue_updated issue_note_added issue_status_updated issue_assigned_to_updated issue_priority_updated news_added news_comment_added document_added file_added message_posted wiki_content_added wiki_content_updated).each do |notifiable|
assert Redmine::Notifiable.all.collect(&:name).include?(notifiable), "missing #{notifiable}"
end
end
end

View file

@ -0,0 +1,34 @@
# 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 PaginationHelperTest < ActionView::TestCase
include Redmine::Pagination::Helper
def test_per_page_options_should_return_usefull_values
with_settings :per_page_options => '10, 25, 50, 100' do
assert_equal [], per_page_options(10, 3)
assert_equal [], per_page_options(25, 3)
assert_equal [10, 25], per_page_options(10, 22)
assert_equal [10, 25], per_page_options(25, 22)
assert_equal [10, 25, 50], per_page_options(50, 22)
assert_equal [10, 25, 50], per_page_options(25, 26)
assert_equal [10, 25, 50, 100], per_page_options(25, 120)
end
end
end

View file

@ -0,0 +1,94 @@
# 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 Redmine::PaginationTest < ActiveSupport::TestCase
def setup
@klass = Redmine::Pagination::Paginator
end
def test_count_is_zero
p = @klass.new 0, 10, 1
assert_equal 0, p.offset
assert_equal 10, p.per_page
%w(first_page previous_page next_page last_page).each do |method|
assert_nil p.send(method), "#{method} was not nil"
end
assert_equal 0, p.first_item
assert_equal 0, p.last_item
assert_equal [], p.linked_pages
end
def test_count_is_less_than_per_page
p = @klass.new 7, 10, 1
assert_equal 0, p.offset
assert_equal 10, p.per_page
assert_equal 1, p.first_page
assert_nil p.previous_page
assert_nil p.next_page
assert_equal 1, p.last_page
assert_equal 1, p.first_item
assert_equal 7, p.last_item
assert_equal [], p.linked_pages
end
def test_count_is_equal_to_per_page
p = @klass.new 10, 10, 1
assert_equal 0, p.offset
assert_equal 10, p.per_page
assert_equal 1, p.first_page
assert_nil p.previous_page
assert_nil p.next_page
assert_equal 1, p.last_page
assert_equal 1, p.first_item
assert_equal 10, p.last_item
assert_equal [], p.linked_pages
end
def test_2_pages
p = @klass.new 16, 10, 1
assert_equal 0, p.offset
assert_equal 10, p.per_page
assert_equal 1, p.first_page
assert_nil p.previous_page
assert_equal 2, p.next_page
assert_equal 2, p.last_page
assert_equal 1, p.first_item
assert_equal 10, p.last_item
assert_equal [1, 2], p.linked_pages
end
def test_many_pages
p = @klass.new 155, 10, 1
assert_equal 0, p.offset
assert_equal 10, p.per_page
assert_equal 1, p.first_page
assert_nil p.previous_page
assert_equal 2, p.next_page
assert_equal 16, p.last_page
assert_equal 1, p.first_item
assert_equal 10, p.last_item
assert_equal [1, 2, 3, 16], p.linked_pages
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 Redmine::PluginTest < ActiveSupport::TestCase
def setup
@klass = Redmine::Plugin
# In case some real plugins are installed
@klass.clear
end
def teardown
@klass.clear
end
def test_register
@klass.register :foo do
name 'Foo plugin'
url 'http://example.net/plugins/foo'
author 'John Smith'
author_url 'http://example.net/jsmith'
description 'This is a test plugin'
version '0.0.1'
settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings'
end
assert_equal 1, @klass.all.size
plugin = @klass.find('foo')
assert plugin.is_a?(Redmine::Plugin)
assert_equal :foo, plugin.id
assert_equal 'Foo plugin', plugin.name
assert_equal 'http://example.net/plugins/foo', plugin.url
assert_equal 'John Smith', plugin.author
assert_equal 'http://example.net/jsmith', plugin.author_url
assert_equal 'This is a test plugin', plugin.description
assert_equal '0.0.1', plugin.version
end
def test_installed
@klass.register(:foo) {}
assert_equal true, @klass.installed?(:foo)
assert_equal false, @klass.installed?(:bar)
end
def test_menu
assert_difference 'Redmine::MenuManager.items(:project_menu).size' do
@klass.register :foo do
menu :project_menu, :foo_menu_item, '/foo', :caption => 'Foo'
end
end
menu_item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name == :foo_menu_item}
assert_not_nil menu_item
assert_equal 'Foo', menu_item.caption
assert_equal '/foo', menu_item.url
ensure
Redmine::MenuManager.map(:project_menu).delete(:foo_menu_item)
end
def test_delete_menu_item
Redmine::MenuManager.map(:project_menu).push(:foo_menu_item, '/foo', :caption => 'Foo')
assert_difference 'Redmine::MenuManager.items(:project_menu).size', -1 do
@klass.register :foo do
delete_menu_item :project_menu, :foo_menu_item
end
end
assert_nil Redmine::MenuManager.items(:project_menu).detect {|i| i.name == :foo_menu_item}
ensure
Redmine::MenuManager.map(:project_menu).delete(:foo_menu_item)
end
def test_directory_with_override
@klass.register(:foo) do
directory '/path/to/foo'
end
assert_equal '/path/to/foo', @klass.find('foo').directory
end
def test_directory_without_override
@klass.register(:foo) {}
assert_equal File.join(@klass.directory, 'foo'), @klass.find('foo').directory
end
def test_requires_redmine
plugin = Redmine::Plugin.register(:foo) {}
Redmine::VERSION.stubs(:to_a).returns([2, 1, 3, "stable", 10817])
# Specific version without hash
assert plugin.requires_redmine('2.1.3')
assert plugin.requires_redmine('2.1')
assert_raise Redmine::PluginRequirementError do
plugin.requires_redmine('2.1.4')
end
assert_raise Redmine::PluginRequirementError do
plugin.requires_redmine('2.2')
end
# Specific version
assert plugin.requires_redmine(:version => '2.1.3')
assert plugin.requires_redmine(:version => ['2.1.3', '2.2.0'])
assert plugin.requires_redmine(:version => '2.1')
assert_raise Redmine::PluginRequirementError do
plugin.requires_redmine(:version => '2.2.0')
end
assert_raise Redmine::PluginRequirementError do
plugin.requires_redmine(:version => ['2.1.4', '2.2.0'])
end
assert_raise Redmine::PluginRequirementError do
plugin.requires_redmine(:version => '2.2')
end
# Version range
assert plugin.requires_redmine(:version => '2.0.0'..'2.2.4')
assert plugin.requires_redmine(:version => '2.1.3'..'2.2.4')
assert plugin.requires_redmine(:version => '2.0.0'..'2.1.3')
assert plugin.requires_redmine(:version => '2.0'..'2.2')
assert plugin.requires_redmine(:version => '2.1'..'2.2')
assert plugin.requires_redmine(:version => '2.0'..'2.1')
assert_raise Redmine::PluginRequirementError do
plugin.requires_redmine(:version => '2.1.4'..'2.2.4')
end
# Version or higher
assert plugin.requires_redmine(:version_or_higher => '0.1.0')
assert plugin.requires_redmine(:version_or_higher => '2.1.3')
assert plugin.requires_redmine(:version_or_higher => '2.1')
assert_raise Redmine::PluginRequirementError do
plugin.requires_redmine(:version_or_higher => '2.2.0')
end
assert_raise Redmine::PluginRequirementError do
plugin.requires_redmine(:version_or_higher => '2.2')
end
end
def test_requires_redmine_plugin
test = self
other_version = '0.5.0'
@klass.register :other do
name 'Other'
version other_version
end
@klass.register :foo do
test.assert requires_redmine_plugin(:other, :version_or_higher => '0.1.0')
test.assert requires_redmine_plugin(:other, :version_or_higher => other_version)
test.assert requires_redmine_plugin(:other, other_version)
test.assert_raise Redmine::PluginRequirementError do
requires_redmine_plugin(:other, :version_or_higher => '99.0.0')
end
test.assert requires_redmine_plugin(:other, :version => other_version)
test.assert requires_redmine_plugin(:other, :version => [other_version, '99.0.0'])
test.assert_raise Redmine::PluginRequirementError do
requires_redmine_plugin(:other, :version => '99.0.0')
end
test.assert_raise Redmine::PluginRequirementError do
requires_redmine_plugin(:other, :version => ['98.0.0', '99.0.0'])
end
# Missing plugin
test.assert_raise Redmine::PluginNotFound do
requires_redmine_plugin(:missing, :version_or_higher => '0.1.0')
end
test.assert_raise Redmine::PluginNotFound do
requires_redmine_plugin(:missing, '0.1.0')
end
test.assert_raise Redmine::PluginNotFound do
requires_redmine_plugin(:missing, :version => '0.1.0')
end
end
end
def test_settings_warns_about_possible_partial_collision
@klass.register(:foo) { settings :partial => 'foo/settings' }
Rails.logger.expects(:warn)
@klass.register(:bar) { settings :partial => 'foo/settings' }
end
end

View file

@ -0,0 +1,102 @@
# 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 Redmine::SafeAttributesTest < ActiveSupport::TestCase
fixtures :users
class Base
def attributes=(attrs)
attrs.each do |key, value|
send("#{key}=", value)
end
end
end
class Person < Base
attr_accessor :firstname, :lastname, :login
include Redmine::SafeAttributes
safe_attributes :firstname, :lastname
safe_attributes :login, :if => lambda {|person, user| user.admin?}
end
class Book < Base
attr_accessor :title
include Redmine::SafeAttributes
safe_attributes :title
end
def test_safe_attribute_names
p = Person.new
user = User.anonymous
assert_equal ['firstname', 'lastname'], p.safe_attribute_names(user)
assert p.safe_attribute?('firstname', user)
assert !p.safe_attribute?('login', user)
p = Person.new
user = User.find(1)
assert_equal ['firstname', 'lastname', 'login'], p.safe_attribute_names(user)
assert p.safe_attribute?('firstname', user)
assert p.safe_attribute?('login', user)
end
def test_safe_attribute_names_without_user
p = Person.new
User.current = nil
assert_equal ['firstname', 'lastname'], p.safe_attribute_names
assert p.safe_attribute?('firstname')
assert !p.safe_attribute?('login')
p = Person.new
User.current = User.find(1)
assert_equal ['firstname', 'lastname', 'login'], p.safe_attribute_names
assert p.safe_attribute?('firstname')
assert p.safe_attribute?('login')
end
def test_set_safe_attributes
p = Person.new
p.send('safe_attributes=', {'firstname' => 'John', 'lastname' => 'Smith', 'login' => 'jsmith'}, User.anonymous)
assert_equal 'John', p.firstname
assert_equal 'Smith', p.lastname
assert_nil p.login
p = Person.new
User.current = User.find(1)
p.send('safe_attributes=', {'firstname' => 'John', 'lastname' => 'Smith', 'login' => 'jsmith'}, User.find(1))
assert_equal 'John', p.firstname
assert_equal 'Smith', p.lastname
assert_equal 'jsmith', p.login
end
def test_set_safe_attributes_without_user
p = Person.new
User.current = nil
p.safe_attributes = {'firstname' => 'John', 'lastname' => 'Smith', 'login' => 'jsmith'}
assert_equal 'John', p.firstname
assert_equal 'Smith', p.lastname
assert_nil p.login
p = Person.new
User.current = User.find(1)
p.safe_attributes = {'firstname' => 'John', 'lastname' => 'Smith', 'login' => 'jsmith'}
assert_equal 'John', p.firstname
assert_equal 'Smith', p.lastname
assert_equal 'jsmith', p.login
end
end

View file

@ -0,0 +1,218 @@
# 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 BazaarAdapterTest < ActiveSupport::TestCase
REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s
REPOSITORY_PATH.gsub!(/\/+/, '/')
if File.directory?(REPOSITORY_PATH)
def setup
@adapter = Redmine::Scm::Adapters::BazaarAdapter.new(
File.join(REPOSITORY_PATH, "trunk")
)
end
def test_scm_version
to_test = { "Bazaar (bzr) 2.1.2\n" => [2,1,2],
"2.1.1\n1.7\n1.8" => [2,1,1],
"2.0.1\r\n1.8.1\r\n1.9.1" => [2,0,1]}
to_test.each do |s, v|
test_scm_version_for(s, v)
end
end
def test_cat
cat = @adapter.cat('directory/document.txt')
assert cat =~ /Write the contents of a file as of a given revision to standard output/
end
def test_cat_path_invalid
assert_nil @adapter.cat('invalid')
end
def test_cat_revision_invalid
assert_nil @adapter.cat('doc-mkdir.txt', '12345678')
end
def test_diff
diff1 = @adapter.diff('doc-mkdir.txt', 3, 2)
assert_equal 21, diff1.size
buf = diff1[14].gsub(/\r\n|\r|\n/, "")
assert_equal "-Display more information.", buf
end
def test_diff_path_invalid
assert_equal [], @adapter.diff('invalid', 1)
end
def test_diff_revision_invalid
assert_equal [], @adapter.diff(nil, 12345678)
assert_equal [], @adapter.diff(nil, 12345678, 87654321)
end
def test_annotate
annotate = @adapter.annotate('doc-mkdir.txt')
assert_equal 17, annotate.lines.size
assert_equal '1', annotate.revisions[0].identifier
assert_equal 'jsmith@', annotate.revisions[0].author
assert_equal 'mkdir', annotate.lines[0]
end
def test_annotate_path_invalid
assert_nil @adapter.annotate('invalid')
end
def test_annotate_revision_invalid
assert_nil @adapter.annotate('doc-mkdir.txt', '12345678')
end
def test_branch_conf_path
p = "c:\\test\\test\\"
bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p)
assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp
p = "c:\\test\\test\\.bzr"
bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p)
assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp
p = "c:\\test\\test\\.bzr\\"
bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p)
assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp
p = "c:\\test\\test"
bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p)
assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp
p = "\\\\server\\test\\test\\"
bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p)
assert_equal File.join("\\\\server\\test\\test", ".bzr", "branch", "branch.conf"), bcp
end
def test_append_revisions_only_true
assert_equal true, @adapter.append_revisions_only
end
def test_append_revisions_only_false
adpt = Redmine::Scm::Adapters::BazaarAdapter.new(
File.join(REPOSITORY_PATH, "empty-branch")
)
assert_equal false, adpt.append_revisions_only
end
def test_append_revisions_only_shared_repo
adpt = Redmine::Scm::Adapters::BazaarAdapter.new(
REPOSITORY_PATH
)
assert_equal false, adpt.append_revisions_only
end
def test_info_not_nil
assert_not_nil @adapter.info
end
def test_info_nil
adpt = Redmine::Scm::Adapters::BazaarAdapter.new(
"/invalid/invalid/"
)
assert_nil adpt.info
end
def test_info
info = @adapter.info
assert_equal 4, info.lastrev.identifier.to_i
end
def test_info_emtpy
adpt = Redmine::Scm::Adapters::BazaarAdapter.new(
File.join(REPOSITORY_PATH, "empty-branch")
)
assert_equal 0, adpt.info.lastrev.identifier.to_i
end
def test_entries_path_invalid
assert_equal [], @adapter.entries('invalid')
end
def test_entries_revision_invalid
assert_nil @adapter.entries(nil, 12345678)
end
def test_revisions
revisions = @adapter.revisions(nil, 4, 2)
assert_equal 3, revisions.size
assert_equal 2, revisions[2].identifier
assert_equal 'jsmith@foo.bar-20071203175224-v0eog5d5wrgdrshg', revisions[2].scmid
assert_equal 4, revisions[0].identifier
assert_equal 'jsmith@foo.bar-20071203175422-t40bf8li5zz0c4cg', revisions[0].scmid
assert_equal 2, revisions[0].paths.size
assert_equal 'D', revisions[0].paths[0][:action]
assert_equal '/doc-deleted.txt', revisions[0].paths[0][:path]
assert_equal 'docdeleted.txt-20071203175320-iwwj561ojuubs3gt-1', revisions[0].paths[0][:revision]
assert_equal 'M', revisions[0].paths[1][:action]
assert_equal '/directory/doc-ls.txt', revisions[0].paths[1][:path]
assert_equal 'docls.txt-20071203175005-a3hyc3mn0shl7cgu-1', revisions[0].paths[1][:revision]
end
def test_revisions_path_invalid
assert_nil @adapter.revisions('invalid')
end
def test_revisions_revision_invalid
assert_nil @adapter.revisions(nil, 12345678)
assert_nil @adapter.revisions(nil, 12345678, 87654321)
end
def test_entry
entry = @adapter.entry()
assert_equal "", entry.path
assert_equal "dir", entry.kind
entry = @adapter.entry('')
assert_equal "", entry.path
assert_equal "dir", entry.kind
assert_nil @adapter.entry('invalid')
assert_nil @adapter.entry('/invalid')
assert_nil @adapter.entry('/invalid/')
assert_nil @adapter.entry('invalid/invalid')
assert_nil @adapter.entry('invalid/invalid/')
assert_nil @adapter.entry('/invalid/invalid')
assert_nil @adapter.entry('/invalid/invalid/')
["doc-ls.txt", "/doc-ls.txt"].each do |path|
entry = @adapter.entry(path, 2)
assert_equal "doc-ls.txt", entry.path
assert_equal "file", entry.kind
end
["directory", "/directory", "/directory/"].each do |path|
entry = @adapter.entry(path, 2)
assert_equal "directory", entry.path
assert_equal "dir", entry.kind
end
["directory/document.txt", "/directory/document.txt"].each do |path|
entry = @adapter.entry(path, 2)
assert_equal "directory/document.txt", entry.path
assert_equal "file", entry.kind
end
end
private
def test_scm_version_for(scm_command_version, version)
@adapter.class.expects(:scm_version_from_command_line).returns(scm_command_version)
assert_equal version, @adapter.class.scm_command_version
end
else
puts "Bazaar test repository NOT FOUND. Skipping unit tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,106 @@
# 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 CvsAdapterTest < ActiveSupport::TestCase
REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s
REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
MODULE_NAME = 'test'
if File.directory?(REPOSITORY_PATH)
def setup
@adapter = Redmine::Scm::Adapters::CvsAdapter.new(MODULE_NAME, REPOSITORY_PATH)
end
def test_scm_version
to_test = { "\nConcurrent Versions System (CVS) 1.12.13 (client/server)\n" => [1,12,13],
"\r\n1.12.12\r\n1.12.11" => [1,12,12],
"1.12.11\r\n1.12.10\r\n" => [1,12,11]}
to_test.each do |s, v|
test_scm_version_for(s, v)
end
end
def test_revisions_all
cnt = 0
@adapter.revisions('', nil, nil, :log_encoding => 'UTF-8') do |revision|
cnt += 1
end
assert_equal 16, cnt
end
def test_revisions_from_rev3
rev3_committed_on = Time.gm(2007, 12, 13, 16, 27, 22)
cnt = 0
@adapter.revisions('', rev3_committed_on, nil, :log_encoding => 'UTF-8') do |revision|
cnt += 1
end
assert_equal 4, cnt
end
def test_entries_rev3
rev3_committed_on = Time.gm(2007, 12, 13, 16, 27, 22)
entries = @adapter.entries('sources', rev3_committed_on)
assert_equal 2, entries.size
assert_equal entries[0].name, "watchers_controller.rb"
assert_equal entries[0].lastrev.time, Time.gm(2007, 12, 13, 16, 27, 22)
end
def test_path_encoding_default_utf8
adpt1 = Redmine::Scm::Adapters::CvsAdapter.new(
MODULE_NAME,
REPOSITORY_PATH
)
assert_equal "UTF-8", adpt1.path_encoding
adpt2 = Redmine::Scm::Adapters::CvsAdapter.new(
MODULE_NAME,
REPOSITORY_PATH,
nil,
nil,
""
)
assert_equal "UTF-8", adpt2.path_encoding
end
def test_root_url_path
to_test = {
':pserver:cvs_user:cvs_password@123.456.789.123:9876/repo' => '/repo',
':pserver:cvs_user:cvs_password@123.456.789.123/repo' => '/repo',
':pserver:cvs_user:cvs_password@cvs_server:/repo' => '/repo',
':pserver:cvs_user:cvs_password@cvs_server:9876/repo' => '/repo',
':pserver:cvs_user:cvs_password@cvs_server/repo' => '/repo',
':pserver:cvs_user:cvs_password@cvs_server/path/repo' => '/path/repo',
':ext:cvsservername:/path' => '/path'
}
to_test.each do |string, expected|
assert_equal expected, Redmine::Scm::Adapters::CvsAdapter.new('foo', string).send(:root_url_path), "#{string} failed"
end
end
private
def test_scm_version_for(scm_command_version, version)
@adapter.class.expects(:scm_version_from_command_line).returns(scm_command_version)
assert_equal version, @adapter.class.scm_command_version
end
else
puts "Cvs test repository NOT FOUND. Skipping unit tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,60 @@
# 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 DarcsAdapterTest < ActiveSupport::TestCase
REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s
if File.directory?(REPOSITORY_PATH)
def setup
@adapter = Redmine::Scm::Adapters::DarcsAdapter.new(REPOSITORY_PATH)
end
def test_darcsversion
to_test = { "1.0.9 (release)\n" => [1,0,9] ,
"2.2.0 (release)\n" => [2,2,0] }
to_test.each do |s, v|
test_darcsversion_for(s, v)
end
end
def test_revisions
id1 = '20080308225258-98289-761f654d669045eabee90b91b53a21ce5593cadf.gz'
revs = @adapter.revisions('', nil, nil, {:with_path => true})
assert_equal 6, revs.size
assert_equal id1, revs[5].scmid
paths = revs[5].paths
assert_equal 5, paths.size
assert_equal 'A', paths[0][:action]
assert_equal '/README', paths[0][:path]
assert_equal 'A', paths[1][:action]
assert_equal '/images', paths[1][:path]
end
private
def test_darcsversion_for(darcsversion, version)
@adapter.class.expects(:darcs_binary_version_from_command_line).returns(darcsversion)
assert_equal version, @adapter.class.darcs_binary_version
end
else
puts "Darcs test repository NOT FOUND. Skipping unit tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,68 @@
# 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 FilesystemAdapterTest < ActiveSupport::TestCase
REPOSITORY_PATH = Rails.root.join('tmp/test/filesystem_repository').to_s
if File.directory?(REPOSITORY_PATH)
def setup
@adapter = Redmine::Scm::Adapters::FilesystemAdapter.new(REPOSITORY_PATH)
end
def test_entries
assert_equal 3, @adapter.entries.size
assert_equal ["dir", "japanese", "test"], @adapter.entries.collect(&:name)
assert_equal ["dir", "japanese", "test"], @adapter.entries(nil).collect(&:name)
assert_equal ["dir", "japanese", "test"], @adapter.entries("/").collect(&:name)
["dir", "/dir", "/dir/", "dir/"].each do |path|
assert_equal ["subdir", "dirfile"], @adapter.entries(path).collect(&:name)
end
# If y try to use "..", the path is ignored
["/../","dir/../", "..", "../", "/..", "dir/.."].each do |path|
assert_equal ["dir", "japanese", "test"], @adapter.entries(path).collect(&:name),
".. must be ignored in path argument"
end
end
def test_cat
assert_equal "TEST CAT\n", @adapter.cat("test")
assert_equal "TEST CAT\n", @adapter.cat("/test")
# Revision number is ignored
assert_equal "TEST CAT\n", @adapter.cat("/test", 1)
end
def test_path_encoding_default_utf8
adpt1 = Redmine::Scm::Adapters::FilesystemAdapter.new(
REPOSITORY_PATH
)
assert_equal "UTF-8", adpt1.path_encoding
adpt2 = Redmine::Scm::Adapters::FilesystemAdapter.new(
REPOSITORY_PATH,
nil,
nil,
nil,
""
)
assert_equal "UTF-8", adpt2.path_encoding
end
else
puts "Filesystem test repository NOT FOUND. Skipping unit tests !!! See doc/RUNNING_TESTS."
def test_fake; assert true end
end
end

View file

@ -0,0 +1,597 @@
# 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 GitAdapterTest < ActiveSupport::TestCase
REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
FELIX_HEX = "Felix Sch\xC3\xA4fer"
CHAR_1_HEX = "\xc3\x9c"
## 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"
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 setup
adapter_class = Redmine::Scm::Adapters::GitAdapter
assert adapter_class
assert adapter_class.client_command
assert_equal true, adapter_class.client_available
assert_equal true, adapter_class.client_version_above?([1])
assert_equal true, adapter_class.client_version_above?([1, 0])
@adapter = Redmine::Scm::Adapters::GitAdapter.new(
REPOSITORY_PATH,
nil,
nil,
nil,
'ISO-8859-1'
)
assert @adapter
@char_1 = CHAR_1_HEX.dup.force_encoding('UTF-8')
@str_felix_hex = FELIX_HEX.dup.force_encoding('ASCII-8BIT')
end
def test_scm_version
to_test = { "git version 1.7.3.4\n" => [1,7,3,4],
"1.6.1\n1.7\n1.8" => [1,6,1],
"1.6.2\r\n1.8.1\r\n1.9.1" => [1,6,2]}
to_test.each do |s, v|
test_scm_version_for(s, v)
end
end
def test_branches
brs = []
@adapter.branches.each do |b|
brs << b
end
assert_equal 6, brs.length
br_issue_8857 = brs[0]
assert_equal 'issue-8857', br_issue_8857.to_s
assert_equal '2a682156a3b6e77a8bf9cd4590e8db757f3c6c78', br_issue_8857.revision
assert_equal br_issue_8857.scmid, br_issue_8857.revision
assert_equal false, br_issue_8857.is_default
br_latin_1_path = brs[1]
assert_equal 'latin-1-path-encoding', br_latin_1_path.to_s
assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', br_latin_1_path.revision
assert_equal br_latin_1_path.scmid, br_latin_1_path.revision
assert_equal false, br_latin_1_path.is_default
br_master = brs[2]
assert_equal 'master', br_master.to_s
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', br_master.revision
assert_equal br_master.scmid, br_master.revision
assert_equal false, br_master.is_default
br_master_20120212 = brs[3]
assert_equal 'master-20120212', br_master_20120212.to_s
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', br_master_20120212.revision
assert_equal br_master_20120212.scmid, br_master_20120212.revision
assert_equal true, br_master_20120212.is_default
br_latin_1 = brs[-2]
assert_equal 'test-latin-1', br_latin_1.to_s
assert_equal '67e7792ce20ccae2e4bb73eed09bb397819c8834', br_latin_1.revision
assert_equal br_latin_1.scmid, br_latin_1.revision
assert_equal false, br_latin_1.is_default
br_test = brs[-1]
assert_equal 'test_branch', br_test.to_s
assert_equal 'fba357b886984ee71185ad2065e65fc0417d9b92', br_test.revision
assert_equal br_test.scmid, br_test.revision
assert_equal false, br_test.is_default
end
def test_default_branch
assert_equal 'master-20120212', @adapter.default_branch
end
def test_tags
assert_equal [
"tag00.lightweight",
"tag01.annotated",
], @adapter.tags
end
def test_revisions_master_all
revs1 = []
@adapter.revisions('', nil, "master",{}) do |rev|
revs1 << rev
end
assert_equal 15, revs1.length
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[ 0].identifier
assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[-1].identifier
revs2 = []
@adapter.revisions('', nil, "master",
{:reverse => true}) do |rev|
revs2 << rev
end
assert_equal 15, revs2.length
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs2[-1].identifier
assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs2[ 0].identifier
end
def test_revisions_master_merged_rev
revs1 = []
@adapter.revisions('',
"713f4944648826f558cf548222f813dabe7cbb04",
"master",
{:reverse => true}) do |rev|
revs1 << rev
end
assert_equal 8, revs1.length
assert_equal 'fba357b886984ee71185ad2065e65fc0417d9b92', revs1[ 0].identifier
assert_equal '7e61ac704deecde634b51e59daa8110435dcb3da', revs1[ 1].identifier
# 4a07fe31b is not a child of 713f49446
assert_equal '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', revs1[ 2].identifier
# Merged revision
assert_equal '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', revs1[ 3].identifier
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[-1].identifier
revs2 = []
@adapter.revisions('',
"fba357b886984ee71185ad2065e65fc0417d9b92",
"master",
{:reverse => true}) do |rev|
revs2 << rev
end
assert_equal 7, revs2.length
assert_equal '7e61ac704deecde634b51e59daa8110435dcb3da', revs2[ 0].identifier
# 4a07fe31b is not a child of fba357b8869
assert_equal '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', revs2[ 1].identifier
# Merged revision
assert_equal '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', revs2[ 2].identifier
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs2[-1].identifier
end
def test_revisions_branch_latin_1_path_encoding_all
revs1 = []
@adapter.revisions('', nil, "latin-1-path-encoding",{}) do |rev|
revs1 << rev
end
assert_equal 8, revs1.length
assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[ 0].identifier
assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[-1].identifier
revs2 = []
@adapter.revisions('', nil, "latin-1-path-encoding",
{:reverse => true}) do |rev|
revs2 << rev
end
assert_equal 8, revs2.length
assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs2[-1].identifier
assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs2[ 0].identifier
end
def test_revisions_branch_latin_1_path_encoding_with_rev
revs1 = []
@adapter.revisions('',
'7234cb2750b63f47bff735edc50a1c0a433c2518',
"latin-1-path-encoding",
{:reverse => true}) do |rev|
revs1 << rev
end
assert_equal 7, revs1.length
assert_equal '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', revs1[ 0].identifier
assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[-1].identifier
revs2 = []
@adapter.revisions('',
'57ca437c0acbbcb749821fdf3726a1367056d364',
"latin-1-path-encoding",
{:reverse => true}) do |rev|
revs2 << rev
end
assert_equal 3, revs2.length
assert_equal '4fc55c43bf3d3dc2efb66145365ddc17639ce81e', revs2[ 0].identifier
assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs2[-1].identifier
end
def test_revisions_invalid_rev
assert_equal [], @adapter.revisions('', '1234abcd', "master")
assert_raise Redmine::Scm::Adapters::CommandFailed do
revs1 = []
@adapter.revisions('',
'1234abcd',
"master",
{:reverse => true}) do |rev|
revs1 << rev
end
end
end
def test_revisions_includes_master_two_revs
revs1 = []
@adapter.revisions('', nil, nil,
{:reverse => true,
:includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c'],
:excludes => ['4f26664364207fa8b1af9f8722647ab2d4ac5d43']}) do |rev|
revs1 << rev
end
assert_equal 2, revs1.length
assert_equal 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b', revs1[ 0].identifier
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[-1].identifier
end
def test_revisions_includes_master_two_revs_from_origin
revs1 = []
@adapter.revisions('', nil, nil,
{:reverse => true,
:includes => ['899a15dba03a3b350b89c3f537e4bbe02a03cdc9'],
:excludes => []}) do |rev|
revs1 << rev
end
assert_equal 2, revs1.length
assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[ 0].identifier
assert_equal '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', revs1[ 1].identifier
end
def test_revisions_includes_merged_revs
revs1 = []
@adapter.revisions('', nil, nil,
{:reverse => true,
:includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c'],
:excludes => ['fba357b886984ee71185ad2065e65fc0417d9b92']}) do |rev|
revs1 << rev
end
assert_equal 7, revs1.length
assert_equal '7e61ac704deecde634b51e59daa8110435dcb3da', revs1[ 0].identifier
assert_equal '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', revs1[ 1].identifier
assert_equal '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', revs1[ 2].identifier
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[-1].identifier
end
def test_revisions_includes_two_heads
revs1 = []
@adapter.revisions('', nil, nil,
{:reverse => true,
:includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c',
'1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127'],
:excludes => ['4f26664364207fa8b1af9f8722647ab2d4ac5d43',
'4fc55c43bf3d3dc2efb66145365ddc17639ce81e']}) do |rev|
revs1 << rev
end
assert_equal 4, revs1.length
assert_equal 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b', revs1[ 0].identifier
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[ 1].identifier
assert_equal '64f1f3e89ad1cb57976ff0ad99a107012ba3481d', revs1[-2].identifier
assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[-1].identifier
end
def test_revisions_disjointed_histories_revisions
revs1 = []
@adapter.revisions('', nil, nil,
{:reverse => true,
:includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c',
'92397af84d22f27389c822848ecd5b463c181583'],
:excludes => ['95488a44bc25f7d1f97d775a31359539ff333a63',
'4f26664364207fa8b1af9f8722647ab2d4ac5d43'] }) do |rev|
revs1 << rev
end
assert_equal 4, revs1.length
assert_equal 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b', revs1[ 0].identifier
assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[ 1].identifier
assert_equal 'bc201c95999c4f10d018b0aa03b541cd6a2ff0ee', revs1[-2].identifier
assert_equal '92397af84d22f27389c822848ecd5b463c181583', revs1[-1].identifier
end
def test_revisions_invalid_rev_excludes
assert_equal [],
@adapter.revisions('', nil, nil,
{:reverse => true,
:includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c'],
:excludes => ['0123abcd4567']})
assert_raise Redmine::Scm::Adapters::CommandFailed do
revs1 = []
@adapter.revisions('', nil, nil,
{:reverse => true,
:includes => ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c'],
:excludes => ['0123abcd4567']}) do |rev|
revs1 << rev
end
end
end
def test_getting_revisions_with_spaces_in_filename
assert_equal 1, @adapter.revisions("filemane with spaces.txt",
nil, "master").length
end
def test_parents
revs1 = []
@adapter.revisions('',
nil,
"master",
{:reverse => true}) do |rev|
revs1 << rev
end
assert_equal 15, revs1.length
assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
revs1[0].identifier
assert_nil revs1[0].parents
assert_equal "899a15dba03a3b350b89c3f537e4bbe02a03cdc9",
revs1[1].identifier
assert_equal 1, revs1[1].parents.length
assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
revs1[1].parents[0]
assert_equal "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf",
revs1[10].identifier
assert_equal 2, revs1[10].parents.length
assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8",
revs1[10].parents[0]
assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da",
revs1[10].parents[1]
end
def test_getting_revisions_with_leading_and_trailing_spaces_in_filename
assert_equal " filename with a leading space.txt ",
@adapter.revisions(" filename with a leading space.txt ",
nil, "master")[0].paths[0][:path]
end
def test_getting_entries_with_leading_and_trailing_spaces_in_filename
assert_equal " filename with a leading space.txt ",
@adapter.entries('',
'83ca5fd546063a3c7dc2e568ba3355661a9e2b2c')[3].name
end
def test_annotate
annotate = @adapter.annotate('sources/watchers_controller.rb')
assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
assert_equal 41, annotate.lines.size
assert_equal "# This program is free software; you can redistribute it and/or",
annotate.lines[4].strip
assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518",
annotate.revisions[4].identifier
assert_equal "jsmith", annotate.revisions[4].author
end
def test_annotate_moved_file
annotate = @adapter.annotate('renamed_test.txt')
assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
assert_equal 2, annotate.lines.size
end
def test_last_rev
last_rev = @adapter.lastrev("README",
"4f26664364207fa8b1af9f8722647ab2d4ac5d43")
assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.scmid
assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.identifier
assert_equal "Adam Soltys <asoltys@gmail.com>", last_rev.author
assert_equal Time.gm(2009, 6, 24, 5, 27, 38), last_rev.time
end
def test_last_rev_with_spaces_in_filename
last_rev = @adapter.lastrev("filemane with spaces.txt",
"ed5bb786bbda2dee66a2d50faf51429dbc043a7b")
last_rev_author = last_rev.author
assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.scmid
assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.identifier
assert_equal "#{@str_felix_hex} <felix@fachschaften.org>",
last_rev.author
assert_equal Time.gm(2010, 9, 18, 19, 59, 46), last_rev.time
end
def test_latin_1_path
if WINDOWS_PASS
puts WINDOWS_SKIP_STR
elsif JRUBY_SKIP
puts JRUBY_SKIP_STR
else
p2 = "latin-1-dir/test-#{@char_1}-2.txt"
['4fc55c43bf3d3dc2efb66145365ddc17639ce81e', '4fc55c43bf3'].each do |r1|
assert @adapter.diff(p2, r1)
assert @adapter.cat(p2, r1)
assert_equal 1, @adapter.annotate(p2, r1).lines.length
['64f1f3e89ad1cb57976ff0ad99a107012ba3481d', '64f1f3e89ad1cb5797'].each do |r2|
assert @adapter.diff(p2, r1, r2)
end
end
end
end
def test_latin_1_user_annotate
['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', '83ca5fd546063a'].each do |r1|
annotate = @adapter.annotate(" filename with a leading space.txt ", r1)
assert_kind_of Redmine::Scm::Adapters::Annotate, annotate
assert_equal 1, annotate.lines.size
assert_equal "And this is a file with a leading and trailing space...",
annotate.lines[0].strip
assert_equal "83ca5fd546063a3c7dc2e568ba3355661a9e2b2c",
annotate.revisions[0].identifier
assert_equal @str_felix_hex, annotate.revisions[0].author
end
end
def test_entries_tag
entries1 = @adapter.entries(nil, 'tag01.annotated',
options = {:report_last_commit => true})
assert entries1
assert_equal 3, entries1.size
assert_equal 'sources', entries1[1].name
assert_equal 'sources', entries1[1].path
assert_equal 'dir', entries1[1].kind
readme = entries1[2]
assert_equal 'README', readme.name
assert_equal 'README', readme.path
assert_equal 'file', readme.kind
assert_equal 27, readme.size
assert_equal '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', readme.lastrev.identifier
assert_equal Time.gm(2007, 12, 14, 9, 24, 1), readme.lastrev.time
end
def test_entries_branch
entries1 = @adapter.entries(nil, 'test_branch',
options = {:report_last_commit => true})
assert entries1
assert_equal 4, entries1.size
assert_equal 'sources', entries1[1].name
assert_equal 'sources', entries1[1].path
assert_equal 'dir', entries1[1].kind
readme = entries1[2]
assert_equal 'README', readme.name
assert_equal 'README', readme.path
assert_equal 'file', readme.kind
assert_equal 159, readme.size
assert_equal '713f4944648826f558cf548222f813dabe7cbb04', readme.lastrev.identifier
assert_equal Time.gm(2009, 6, 19, 4, 37, 23), readme.lastrev.time
end
def test_entries_wrong_path_encoding
adpt = Redmine::Scm::Adapters::GitAdapter.new(
REPOSITORY_PATH,
nil,
nil,
nil,
'EUC-JP'
)
entries1 = adpt.entries('latin-1-dir', '64f1f3e8')
assert entries1
assert_equal 3, entries1.size
f1 = entries1[1]
assert_nil f1.name
assert_nil f1.path
assert_equal 'file', f1.kind
end
def test_entries_latin_1_files
entries1 = @adapter.entries('latin-1-dir', '64f1f3e8')
assert entries1
assert_equal 3, entries1.size
f1 = entries1[1]
assert_equal "test-#{@char_1}-2.txt", f1.name
assert_equal "latin-1-dir/test-#{@char_1}-2.txt", f1.path
assert_equal 'file', f1.kind
end
def test_entries_latin_1_dir
if WINDOWS_PASS
puts WINDOWS_SKIP_STR
elsif JRUBY_SKIP
puts JRUBY_SKIP_STR
else
entries1 = @adapter.entries("latin-1-dir/test-#{@char_1}-subdir",
'1ca7f5ed')
assert entries1
assert_equal 3, entries1.size
f1 = entries1[1]
assert_equal "test-#{@char_1}-2.txt", f1.name
assert_equal "latin-1-dir/test-#{@char_1}-subdir/test-#{@char_1}-2.txt", f1.path
assert_equal 'file', f1.kind
end
end
def test_entry
entry = @adapter.entry()
assert_equal "", entry.path
assert_equal "dir", entry.kind
entry = @adapter.entry('')
assert_equal "", entry.path
assert_equal "dir", entry.kind
assert_nil @adapter.entry('invalid')
assert_nil @adapter.entry('/invalid')
assert_nil @adapter.entry('/invalid/')
assert_nil @adapter.entry('invalid/invalid')
assert_nil @adapter.entry('invalid/invalid/')
assert_nil @adapter.entry('/invalid/invalid')
assert_nil @adapter.entry('/invalid/invalid/')
["README", "/README"].each do |path|
entry = @adapter.entry(path, '7234cb2750b63f')
assert_equal "README", entry.path
assert_equal "file", entry.kind
end
["sources", "/sources", "/sources/"].each do |path|
entry = @adapter.entry(path, '7234cb2750b63f')
assert_equal "sources", entry.path
assert_equal "dir", entry.kind
end
["sources/watchers_controller.rb", "/sources/watchers_controller.rb"].each do |path|
entry = @adapter.entry(path, '7234cb2750b63f')
assert_equal "sources/watchers_controller.rb", entry.path
assert_equal "file", entry.kind
end
end
def test_path_encoding_default_utf8
adpt1 = Redmine::Scm::Adapters::GitAdapter.new(
REPOSITORY_PATH
)
assert_equal "UTF-8", adpt1.path_encoding
adpt2 = Redmine::Scm::Adapters::GitAdapter.new(
REPOSITORY_PATH,
nil,
nil,
nil,
""
)
assert_equal "UTF-8", adpt2.path_encoding
end
def test_cat_path_invalid
assert_nil @adapter.cat('invalid')
end
def test_cat_revision_invalid
assert @adapter.cat('README')
assert_nil @adapter.cat('README', '1234abcd5678')
end
def test_diff_path_invalid
assert_equal [], @adapter.diff('invalid', '713f4944648826f5')
end
def test_diff_revision_invalid
assert_nil @adapter.diff(nil, '1234abcd5678')
assert_nil @adapter.diff(nil, '713f4944648826f5', '1234abcd5678')
assert_nil @adapter.diff(nil, '1234abcd5678', '713f4944648826f5')
end
def test_annotate_path_invalid
assert_nil @adapter.annotate('invalid')
end
def test_annotate_revision_invalid
assert @adapter.annotate('README')
assert_nil @adapter.annotate('README', '1234abcd5678')
end
private
def test_scm_version_for(scm_command_version, version)
@adapter.class.expects(:scm_version_from_command_line).returns(scm_command_version)
assert_equal version, @adapter.class.scm_command_version
end
else
puts "Git test repository NOT FOUND. Skipping unit tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,485 @@
# 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 MercurialAdapterTest < ActiveSupport::TestCase
HELPERS_DIR = Redmine::Scm::Adapters::MercurialAdapter::HELPERS_DIR
TEMPLATE_NAME = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_NAME
TEMPLATE_EXTENSION = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_EXTENSION
HgCommandAborted = Redmine::Scm::Adapters::MercurialAdapter::HgCommandAborted
HgCommandArgumentError = Redmine::Scm::Adapters::MercurialAdapter::HgCommandArgumentError
REPOSITORY_PATH = repository_path('mercurial')
CHAR_1_HEX = "\xc3\x9c"
if File.directory?(REPOSITORY_PATH)
def setup
adapter_class = Redmine::Scm::Adapters::MercurialAdapter
assert adapter_class
assert adapter_class.client_command
assert_equal true, adapter_class.client_available
assert_equal true, adapter_class.client_version_above?([0, 9, 5])
@adapter = Redmine::Scm::Adapters::MercurialAdapter.new(
REPOSITORY_PATH,
nil,
nil,
nil,
'ISO-8859-1')
@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
def test_hgversion
to_test = { "Mercurial Distributed SCM (version 0.9.5)\n" => [0,9,5],
"Mercurial Distributed SCM (1.0)\n" => [1,0],
"Mercurial Distributed SCM (1e4ddc9ac9f7+20080325)\n" => nil,
"Mercurial Distributed SCM (1.0.1+20080525)\n" => [1,0,1],
"Mercurial Distributed SCM (1916e629a29d)\n" => nil,
"Mercurial SCM Distribuito (versione 0.9.5)\n" => [0,9,5],
"(1.6)\n(1.7)\n(1.8)" => [1,6],
"(1.7.1)\r\n(1.8.1)\r\n(1.9.1)" => [1,7,1]}
to_test.each do |s, v|
test_hgversion_for(s, v)
end
end
def test_template_path
to_test = {
[1,2] => "1.0",
[] => "1.0",
[1,2,1] => "1.0",
[1,7] => "1.0",
[1,7,1] => "1.0",
[2,0] => "1.0",
}
to_test.each do |v, template|
test_template_path_for(v, template)
end
end
def test_info
[REPOSITORY_PATH, REPOSITORY_PATH + "/",
REPOSITORY_PATH + "//"].each do |repo|
adp = Redmine::Scm::Adapters::MercurialAdapter.new(repo)
repo_path = adp.info.root_url.gsub(/\\/, "/")
assert_equal REPOSITORY_PATH, repo_path
assert_equal '33', adp.info.lastrev.revision
assert_equal '2e6d546429230f377d7d19c2078abd2dd909f235',adp.info.lastrev.scmid
end
end
def test_revisions
revisions = @adapter.revisions(nil, 2, 4)
assert_equal 3, revisions.size
assert_equal '2', revisions[0].revision
assert_equal '400bb86721098697c7d17b3724c794c57636de70', revisions[0].scmid
assert_equal '4', revisions[2].revision
assert_equal 'def6d2f1254a56fb8fbe9ec3b5c0451674dbd8b8', revisions[2].scmid
revisions = @adapter.revisions(nil, 2, 4, {:limit => 2})
assert_equal 2, revisions.size
assert_equal '2', revisions[0].revision
assert_equal '400bb86721098697c7d17b3724c794c57636de70', revisions[0].scmid
end
def test_parents
revs1 = @adapter.revisions(nil, 0, 0)
assert_equal 1, revs1.size
assert_equal [], revs1[0].parents
revs2 = @adapter.revisions(nil, 1, 1)
assert_equal 1, revs2.size
assert_equal 1, revs2[0].parents.size
assert_equal "0885933ad4f68d77c2649cd11f8311276e7ef7ce", revs2[0].parents[0]
revs3 = @adapter.revisions(nil, 30, 30)
assert_equal 1, revs3.size
assert_equal 2, revs3[0].parents.size
assert_equal "a94b0528f24fe05ebaef496ae0500bb050772e36", revs3[0].parents[0]
assert_equal "3a330eb329586ea2adb3f83237c23310e744ebe9", revs3[0].parents[1]
end
def test_diff
if @adapter.class.client_version_above?([1, 2])
assert_nil @adapter.diff(nil, '100000')
end
assert_nil @adapter.diff(nil, '100000', '200000')
[2, '400bb8672109', '400', 400].each do |r1|
diff1 = @adapter.diff(nil, r1)
if @diff_c_support
assert_equal 28, diff1.size
buf = diff1[24].gsub(/\r\n|\r|\n/, "")
assert_equal "+ return true unless klass.respond_to?('watched_by')", buf
else
assert_equal 0, diff1.size
end
[4, 'def6d2f1254a'].each do |r2|
diff2 = @adapter.diff(nil, r1, r2)
assert_equal 49, diff2.size
buf = diff2[41].gsub(/\r\n|\r|\n/, "")
assert_equal "+class WelcomeController < ApplicationController", buf
diff3 = @adapter.diff('sources/watchers_controller.rb', r1, r2)
assert_equal 20, diff3.size
buf = diff3[12].gsub(/\r\n|\r|\n/, "")
assert_equal "+ @watched.remove_watcher(user)", buf
diff4 = @adapter.diff(nil, r2, r1)
assert_equal 49, diff4.size
buf = diff4[41].gsub(/\r\n|\r|\n/, "")
assert_equal "-class WelcomeController < ApplicationController", buf
diff5 = @adapter.diff('sources/watchers_controller.rb', r2, r1)
assert_equal 20, diff5.size
buf = diff5[9].gsub(/\r\n|\r|\n/, "")
assert_equal "- @watched.remove_watcher(user)", buf
end
end
end
def test_diff_made_by_revision
if @diff_c_support
[24, '24', '4cddb4e45f52'].each do |r1|
diff1 = @adapter.diff(nil, r1)
assert_equal 5, diff1.size
buf = diff1[4].gsub(/\r\n|\r|\n/, "")
assert_equal '+0885933ad4f68d77c2649cd11f8311276e7ef7ce tag-init-revision', buf
end
end
end
def test_cat
[2, '400bb8672109', '400', 400].each do |r|
buf = @adapter.cat('sources/welcome_controller.rb', r)
assert buf
lines = buf.split("\r\n")
assert_equal 25, lines.length
assert_equal 'class WelcomeController < ApplicationController', lines[17]
end
assert_nil @adapter.cat('sources/welcome_controller.rb')
end
def test_annotate
assert_equal [], @adapter.annotate("sources/welcome_controller.rb").lines
[2, '400bb8672109', '400', 400].each do |r|
ann = @adapter.annotate('sources/welcome_controller.rb', r)
assert ann
assert_equal '1', ann.revisions[17].revision
assert_equal '9d5b5b004199', ann.revisions[17].identifier
assert_equal 'jsmith', ann.revisions[0].author
assert_equal 25, ann.lines.length
assert_equal 'class WelcomeController < ApplicationController', ann.lines[17]
end
end
def test_entries
assert_nil @adapter.entries(nil, '100000')
assert_equal 1, @adapter.entries("sources", 3).size
assert_equal 1, @adapter.entries("sources", 'b3a615152df8').size
[2, '400bb8672109', '400', 400].each do |r|
entries1 = @adapter.entries(nil, r)
assert entries1
assert_equal 3, entries1.size
assert_equal 'sources', entries1[1].name
assert_equal 'sources', entries1[1].path
assert_equal 'dir', entries1[1].kind
readme = entries1[2]
assert_equal 'README', readme.name
assert_equal 'README', readme.path
assert_equal 'file', readme.kind
assert_equal 27, readme.size
assert_equal '1', readme.lastrev.revision
assert_equal '9d5b5b00419901478496242e0768deba1ce8c51e', readme.lastrev.identifier
# 2007-12-14 10:24:01 +0100
assert_equal Time.gm(2007, 12, 14, 9, 24, 1), readme.lastrev.time
entries2 = @adapter.entries('sources', r)
assert entries2
assert_equal 2, entries2.size
assert_equal 'watchers_controller.rb', entries2[0].name
assert_equal 'sources/watchers_controller.rb', entries2[0].path
assert_equal 'file', entries2[0].kind
assert_equal 'welcome_controller.rb', entries2[1].name
assert_equal 'sources/welcome_controller.rb', entries2[1].path
assert_equal 'file', entries2[1].kind
end
end
def test_entries_tag
entries1 = @adapter.entries(nil, 'tag_test.00')
assert entries1
assert_equal 3, entries1.size
assert_equal 'sources', entries1[1].name
assert_equal 'sources', entries1[1].path
assert_equal 'dir', entries1[1].kind
readme = entries1[2]
assert_equal 'README', readme.name
assert_equal 'README', readme.path
assert_equal 'file', readme.kind
assert_equal 21, readme.size
assert_equal '0', readme.lastrev.revision
assert_equal '0885933ad4f68d77c2649cd11f8311276e7ef7ce', readme.lastrev.identifier
# 2007-12-14 10:22:52 +0100
assert_equal Time.gm(2007, 12, 14, 9, 22, 52), readme.lastrev.time
end
def test_entries_branch
entries1 = @adapter.entries(nil, 'test-branch-00')
assert entries1
assert_equal 5, entries1.size
assert_equal 'sql_escape', entries1[2].name
assert_equal 'sql_escape', entries1[2].path
assert_equal 'dir', entries1[2].kind
readme = entries1[4]
assert_equal 'README', readme.name
assert_equal 'README', readme.path
assert_equal 'file', readme.kind
assert_equal 365, readme.size
assert_equal '8', readme.lastrev.revision
assert_equal 'c51f5bb613cd60793c2a9fe9df29332e74bb949f', readme.lastrev.identifier
# 2001-02-01 00:00:00 -0900
assert_equal Time.gm(2001, 2, 1, 9, 0, 0), readme.lastrev.time
end
def test_entry
entry = @adapter.entry()
assert_equal "", entry.path
assert_equal "dir", entry.kind
entry = @adapter.entry('')
assert_equal "", entry.path
assert_equal "dir", entry.kind
assert_nil @adapter.entry('invalid')
assert_nil @adapter.entry('/invalid')
assert_nil @adapter.entry('/invalid/')
assert_nil @adapter.entry('invalid/invalid')
assert_nil @adapter.entry('invalid/invalid/')
assert_nil @adapter.entry('/invalid/invalid')
assert_nil @adapter.entry('/invalid/invalid/')
["README", "/README"].each do |path|
["0", "0885933ad4f6", "0885933ad4f68d77c2649cd11f8311276e7ef7ce"].each do |rev|
entry = @adapter.entry(path, rev)
assert_equal "README", entry.path
assert_equal "file", entry.kind
assert_equal '0', entry.lastrev.revision
assert_equal '0885933ad4f68d77c2649cd11f8311276e7ef7ce', entry.lastrev.identifier
end
end
["sources", "/sources", "/sources/"].each do |path|
["0", "0885933ad4f6", "0885933ad4f68d77c2649cd11f8311276e7ef7ce"].each do |rev|
entry = @adapter.entry(path, rev)
assert_equal "sources", entry.path
assert_equal "dir", entry.kind
end
end
["sources/watchers_controller.rb", "/sources/watchers_controller.rb"].each do |path|
["0", "0885933ad4f6", "0885933ad4f68d77c2649cd11f8311276e7ef7ce"].each do |rev|
entry = @adapter.entry(path, rev)
assert_equal "sources/watchers_controller.rb", entry.path
assert_equal "file", entry.kind
assert_equal '0', entry.lastrev.revision
assert_equal '0885933ad4f68d77c2649cd11f8311276e7ef7ce', entry.lastrev.identifier
end
end
end
def test_locate_on_outdated_repository
assert_equal 1, @adapter.entries("images", 0).size
assert_equal 2, @adapter.entries("images").size
assert_equal 2, @adapter.entries("images", 2).size
end
def test_access_by_nodeid
path = 'sources/welcome_controller.rb'
assert_equal @adapter.cat(path, 2), @adapter.cat(path, '400bb8672109')
end
def test_access_by_fuzzy_nodeid
path = 'sources/welcome_controller.rb'
# falls back to nodeid
assert_equal @adapter.cat(path, 2), @adapter.cat(path, '400')
end
def test_tags
assert_equal [@tag_char_1, 'tag_test.00', 'tag-init-revision'], @adapter.tags
end
def test_tagmap
tm = {
@tag_char_1 => 'adf805632193500ad3b615cd04f58f9b0769f576',
'tag_test.00' => '6987191f453a5f6557018d522feea2c450d5588d',
'tag-init-revision' => '0885933ad4f68d77c2649cd11f8311276e7ef7ce',
}
assert_equal tm, @adapter.tagmap
end
def test_branches
brs = []
@adapter.branches.each do |b|
brs << b
end
assert_equal 7, brs.length
assert_equal 'default', brs[0].to_s
assert_equal '31', brs[0].revision
assert_equal '31eeee7395c8c78e66dd54c50addd078d10b2355', brs[0].scmid
assert_equal 'test-branch-01', brs[1].to_s
assert_equal '30', brs[1].revision
assert_equal 'ad4dc4f80284a4f9168b77e0b6de288e5d207ee7', brs[1].scmid
assert_equal @branch_char_1, brs[2].to_s
assert_equal '27', brs[2].revision
assert_equal '7bbf4c738e7145149d2e5eb1eed1d3a8ddd3b914', brs[2].scmid
assert_equal 'branch (1)[2]&,%.-3_4', brs[3].to_s
assert_equal '25', brs[3].revision
assert_equal 'afc61e85bde74de930e5846c8451bd55b5bafc9c', brs[3].scmid
assert_equal @branch_char_0, brs[4].to_s
assert_equal '23', brs[4].revision
assert_equal 'c8d3e4887474af6a589190140508037ebaa9d9c3', brs[4].scmid
assert_equal 'test_branch.latin-1', brs[5].to_s
assert_equal '22', brs[5].revision
assert_equal 'c2ffe7da686aa3d956e59f2a2854cf8980a8b768', brs[5].scmid
assert_equal 'test-branch-00', brs[6].to_s
assert_equal '13', brs[6].revision
assert_equal '3a330eb329586ea2adb3f83237c23310e744ebe9', brs[6].scmid
end
def test_branchmap
bm = {
'default' => '31eeee7395c8c78e66dd54c50addd078d10b2355',
'test_branch.latin-1' => 'c2ffe7da686aa3d956e59f2a2854cf8980a8b768',
'branch (1)[2]&,%.-3_4' => 'afc61e85bde74de930e5846c8451bd55b5bafc9c',
'test-branch-00' => '3a330eb329586ea2adb3f83237c23310e744ebe9',
"test-branch-01" => 'ad4dc4f80284a4f9168b77e0b6de288e5d207ee7',
@branch_char_0 => 'c8d3e4887474af6a589190140508037ebaa9d9c3',
@branch_char_1 => '7bbf4c738e7145149d2e5eb1eed1d3a8ddd3b914',
}
assert_equal bm, @adapter.branchmap
end
def test_path_space
p = 'README (1)[2]&,%.-3_4'
[15, '933ca60293d7'].each do |r1|
assert @adapter.diff(p, r1)
assert @adapter.cat(p, r1)
assert_equal 1, @adapter.annotate(p, r1).lines.length
[25, 'afc61e85bde7'].each do |r2|
assert @adapter.diff(p, r1, r2)
end
end
end
def test_tag_non_ascii
p = "latin-1-dir/test-#{@char_1}-1.txt"
assert @adapter.cat(p, @tag_char_1)
assert_equal 1, @adapter.annotate(p, @tag_char_1).lines.length
end
def test_branch_non_ascii
p = "latin-1-dir/test-#{@char_1}-subdir/test-#{@char_1}-1.txt"
assert @adapter.cat(p, @branch_char_1)
assert_equal 1, @adapter.annotate(p, @branch_char_1).lines.length
end
def test_nodes_in_branch
[
'default',
@branch_char_1,
'branch (1)[2]&,%.-3_4',
@branch_char_0,
'test_branch.latin-1',
'test-branch-00',
].each do |bra|
nib0 = @adapter.nodes_in_branch(bra)
assert nib0
nib1 = @adapter.nodes_in_branch(bra, :limit => 1)
assert_equal 1, nib1.size
case bra
when 'branch (1)[2]&,%.-3_4'
if @adapter.class.client_version_above?([1, 6])
assert_equal 3, nib0.size
assert_equal 'afc61e85bde74de930e5846c8451bd55b5bafc9c', nib0[0]
nib2 = @adapter.nodes_in_branch(bra, :limit => 2)
assert_equal 2, nib2.size
assert_equal '933ca60293d78f7c7979dd123cc0c02431683575', nib2[1]
end
when @branch_char_1
if @adapter.class.client_version_above?([1, 6])
assert_equal 2, nib0.size
assert_equal '08ff3227303ec0dfcc818efa8e9cc652fe81859f', nib0[1]
nib2 = @adapter.nodes_in_branch(bra, :limit => 1)
assert_equal 1, nib2.size
assert_equal '7bbf4c738e7145149d2e5eb1eed1d3a8ddd3b914', nib2[0]
end
end
end
end
def test_path_encoding_default_utf8
adpt1 = Redmine::Scm::Adapters::MercurialAdapter.new(
REPOSITORY_PATH
)
assert_equal "UTF-8", adpt1.path_encoding
adpt2 = Redmine::Scm::Adapters::MercurialAdapter.new(
REPOSITORY_PATH,
nil,
nil,
nil,
""
)
assert_equal "UTF-8", adpt2.path_encoding
end
def test_bad_early_options
assert_nil @adapter.diff('sources/welcome_controller.rb',
'--config=alias.rhdiff=!xterm')
assert_raise HgCommandArgumentError do
@adapter.entries('--debugger')
end
assert_raise HgCommandAborted do
@adapter.revisions(nil, nil, nil, limit: '--repo=otherrepo')
end
assert_raise HgCommandAborted do
@adapter.nodes_in_branch('default', limit: '--repository=otherrepo')
end
assert_raise HgCommandAborted do
@adapter.nodes_in_branch('-Rotherrepo')
end
end
private
def test_hgversion_for(hgversion, version)
@adapter.class.expects(:hgversion_from_command_line).returns(hgversion)
if version
assert_equal version, @adapter.class.hgversion
else
assert_nil @adapter.class.hgversion
end
end
def test_template_path_for(version, template)
assert_equal "#{HELPERS_DIR}/#{TEMPLATE_NAME}-#{template}.#{TEMPLATE_EXTENSION}",
@adapter.class.template_path_for(version)
assert File.exist?(@adapter.class.template_path_for(version))
end
else
puts "Mercurial test repository NOT FOUND. Skipping unit tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,63 @@
# 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 SubversionAdapterTest < ActiveSupport::TestCase
if repository_configured?('subversion')
def setup
@adapter = Redmine::Scm::Adapters::SubversionAdapter.new(self.class.subversion_repository_url)
end
def test_client_version
v = Redmine::Scm::Adapters::SubversionAdapter.client_version
assert v.is_a?(Array)
end
def test_scm_version
to_test = { "svn, version 1.6.13 (r1002816)\n" => [1,6,13],
"svn, versione 1.6.13 (r1002816)\n" => [1,6,13],
"1.6.1\n1.7\n1.8" => [1,6,1],
"1.6.2\r\n1.8.1\r\n1.9.1" => [1,6,2]}
to_test.each do |s, v|
test_scm_version_for(s, v)
end
end
def test_info_not_nil
assert_not_nil @adapter.info
end
def test_info_nil
adpt = Redmine::Scm::Adapters::SubversionAdapter.new(
"file:///invalid/invalid/"
)
assert_nil adpt.info
end
private
def test_scm_version_for(scm_version, version)
@adapter.class.expects(:scm_version_from_command_line).returns(scm_version)
assert_equal version, @adapter.class.svn_binary_version
end
else
puts "Subversion test repository NOT FOUND. Skipping unit tests !!!"
def test_fake; assert true end
end
end

View file

@ -0,0 +1,37 @@
# 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 Redmine::SyntaxHighlighting::CodeRayTest < ActiveSupport::TestCase
def test_retrieve_supported_languages_should_return_array_of_symbols
assert_kind_of Array, Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages)
assert_kind_of Symbol, Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages).first
end
def test_retrieve_supported_languages_should_return_array_of_symbols_holding_languages
assert_includes Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages), :ruby
end
def test_retrieve_supported_languages_should_return_array_of_symbols_holding_languages_aliases
assert_includes Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages), :javascript
end
def test_retrieve_supported_languages_should_return_array_of_symbols_not_holding_internal_languages
refute_includes Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages), :default
end
end

View file

@ -0,0 +1,61 @@
# 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 Redmine::ThemesTest < ActiveSupport::TestCase
def test_themes
themes = Redmine::Themes.themes
assert_kind_of Array, themes
assert_kind_of Redmine::Themes::Theme, themes.first
end
def test_rescan
Redmine::Themes.themes.pop
assert_difference 'Redmine::Themes.themes.size' do
Redmine::Themes.rescan
end
end
def test_theme_loaded
theme = Redmine::Themes.themes.last
assert_equal theme, Redmine::Themes.theme(theme.id)
end
def test_theme_loaded_without_rescan
theme = Redmine::Themes.themes.last
assert_equal theme, Redmine::Themes.theme(theme.id, :rescan => false)
end
def test_theme_not_loaded
theme = Redmine::Themes.themes.pop
assert_equal theme, Redmine::Themes.theme(theme.id)
end
def test_theme_not_loaded_without_rescan
theme = Redmine::Themes.themes.pop
assert_nil Redmine::Themes.theme(theme.id, :rescan => false)
ensure
Redmine::Themes.rescan
end
end

View file

@ -0,0 +1,352 @@
# 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 Redmine::UnifiedDiffTest < ActiveSupport::TestCase
def test_subversion_diff
diff = Redmine::UnifiedDiff.new(read_diff_fixture('subversion.diff'))
# number of files
assert_equal 4, diff.size
assert diff.detect {|file| file.file_name =~ %r{^config/settings.yml}}
end
def test_truncate_diff
diff = Redmine::UnifiedDiff.new(read_diff_fixture('subversion.diff'), :max_lines => 20)
assert_equal 2, diff.size
end
def test_inline_partials
diff = Redmine::UnifiedDiff.new(read_diff_fixture('partials.diff'))
assert_equal 1, diff.size
diff = diff.first
assert_equal 43, diff.size
assert_equal [51, -1], diff[0].offsets
assert_equal [51, -1], diff[1].offsets
assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing <span>elit</span>', diff[0].html_line
assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing <span>xx</span>', diff[1].html_line
assert_nil diff[2].offsets
assert_equal 'Praesent et sagittis dui. Vivamus ac diam diam', diff[2].html_line
assert_equal [0, -14], diff[3].offsets
assert_equal [0, -14], diff[4].offsets
assert_equal '<span>Ut sed</span> auctor justo', diff[3].html_line
assert_equal '<span>xxx</span> auctor justo', diff[4].html_line
assert_equal [13, -19], diff[6].offsets
assert_equal [13, -19], diff[7].offsets
assert_equal [24, -8], diff[9].offsets
assert_equal [24, -8], diff[10].offsets
assert_equal [37, -1], diff[12].offsets
assert_equal [37, -1], diff[13].offsets
assert_equal [0, -38], diff[15].offsets
assert_equal [0, -38], diff[16].offsets
end
def test_side_by_side_partials
diff = Redmine::UnifiedDiff.new(read_diff_fixture('partials.diff'), :type => 'sbs')
assert_equal 1, diff.size
diff = diff.first
assert_equal 32, diff.size
assert_equal [51, -1], diff[0].offsets
assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing <span>elit</span>', diff[0].html_line_left
assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing <span>xx</span>', diff[0].html_line_right
assert_nil diff[1].offsets
assert_equal 'Praesent et sagittis dui. Vivamus ac diam diam', diff[1].html_line_left
assert_equal 'Praesent et sagittis dui. Vivamus ac diam diam', diff[1].html_line_right
assert_equal [0, -14], diff[2].offsets
assert_equal '<span>Ut sed</span> auctor justo', diff[2].html_line_left
assert_equal '<span>xxx</span> auctor justo', diff[2].html_line_right
assert_equal [13, -19], diff[4].offsets
assert_equal [24, -8], diff[6].offsets
assert_equal [37, -1], diff[8].offsets
assert_equal [0, -38], diff[10].offsets
end
def test_partials_with_html_entities
raw = <<-DIFF
--- test.orig.txt Wed Feb 15 16:10:39 2012
+++ test.new.txt Wed Feb 15 16:11:25 2012
@@ -1,5 +1,5 @@
Semicolons were mysteriously appearing in code diffs in the repository
-void DoSomething(std::auto_ptr<MyClass> myObj)
+void DoSomething(const MyClass& myObj)
DIFF
diff = Redmine::UnifiedDiff.new(raw, :type => 'sbs')
assert_equal 1, diff.size
assert_equal 'void DoSomething(<span>std::auto_ptr&lt;MyClass&gt;</span> myObj)', diff.first[2].html_line_left
assert_equal 'void DoSomething(<span>const MyClass&amp;</span> myObj)', diff.first[2].html_line_right
diff = Redmine::UnifiedDiff.new(raw, :type => 'inline')
assert_equal 1, diff.size
assert_equal 'void DoSomething(<span>std::auto_ptr&lt;MyClass&gt;</span> myObj)', diff.first[2].html_line
assert_equal 'void DoSomething(<span>const MyClass&amp;</span> myObj)', diff.first[3].html_line
end
def test_line_starting_with_dashes
diff = Redmine::UnifiedDiff.new(<<-DIFF
--- old.txt Wed Nov 11 14:24:58 2009
+++ new.txt Wed Nov 11 14:25:02 2009
@@ -1,8 +1,4 @@
-Lines that starts with dashes:
-
-------------------------
--- file.c
-------------------------
+A line that starts with dashes:
and removed.
@@ -23,4 +19,4 @@
-Another chunk of change
+Another chunk of changes
DIFF
)
assert_equal 1, diff.size
end
def test_one_line_new_files
diff = Redmine::UnifiedDiff.new(<<-DIFF
diff -r 000000000000 -r ea98b14f75f0 README1
--- /dev/null
+++ b/README1
@@ -0,0 +1,1 @@
+test1
diff -r 000000000000 -r ea98b14f75f0 README2
--- /dev/null
+++ b/README2
@@ -0,0 +1,1 @@
+test2
diff -r 000000000000 -r ea98b14f75f0 README3
--- /dev/null
+++ b/README3
@@ -0,0 +1,3 @@
+test4
+test5
+test6
diff -r 000000000000 -r ea98b14f75f0 README4
--- /dev/null
+++ b/README4
@@ -0,0 +1,3 @@
+test4
+test5
+test6
DIFF
)
assert_equal 4, diff.size
assert_equal "README1", diff[0].file_name
end
def test_both_git_diff
diff = Redmine::UnifiedDiff.new(<<-DIFF
# HG changeset patch
# User test
# Date 1348014182 -32400
# Node ID d1c871b8ef113df7f1c56d41e6e3bfbaff976e1f
# Parent 180b6605936cdc7909c5f08b59746ec1a7c99b3e
modify test1.txt
diff -r 180b6605936c -r d1c871b8ef11 test1.txt
--- a/test1.txt
+++ b/test1.txt
@@ -1,1 +1,1 @@
-test1
+modify test1
DIFF
)
assert_equal 1, diff.size
assert_equal "test1.txt", diff[0].file_name
end
def test_include_a_b_slash
diff = Redmine::UnifiedDiff.new(<<-DIFF
--- test1.txt
+++ b/test02.txt
@@ -1 +0,0 @@
-modify test1
DIFF
)
assert_equal 1, diff.size
assert_equal "b/test02.txt", diff[0].file_name
diff = Redmine::UnifiedDiff.new(<<-DIFF
--- a/test1.txt
+++ a/test02.txt
@@ -1 +0,0 @@
-modify test1
DIFF
)
assert_equal 1, diff.size
assert_equal "a/test02.txt", diff[0].file_name
diff = Redmine::UnifiedDiff.new(<<-DIFF
--- a/test1.txt
+++ test02.txt
@@ -1 +0,0 @@
-modify test1
DIFF
)
assert_equal 1, diff.size
assert_equal "test02.txt", diff[0].file_name
end
def test_utf8_ja
ja = " text_tip_issue_end_day: "
ja += "\xe3\x81\x93\xe3\x81\xae\xe6\x97\xa5\xe3\x81\xab\xe7\xb5\x82\xe4\xba\x86\xe3\x81\x99\xe3\x82\x8b<span>\xe3\x82\xbf\xe3\x82\xb9\xe3\x82\xaf</span>".force_encoding('UTF-8')
with_settings :repositories_encodings => '' do
diff = Redmine::UnifiedDiff.new(read_diff_fixture('issue-12641-ja.diff'), :type => 'inline')
assert_equal 1, diff.size
assert_equal 12, diff.first.size
assert_equal ja, diff.first[4].html_line_left
end
end
def test_utf8_ru
ru = " other: &quot;\xd0\xbe\xd0\xba\xd0\xbe\xd0\xbb\xd0\xbe %{count} \xd1\x87\xd0\xb0\xd1\x81<span>\xd0\xb0</span>&quot;".force_encoding('UTF-8')
with_settings :repositories_encodings => '' do
diff = Redmine::UnifiedDiff.new(read_diff_fixture('issue-12641-ru.diff'), :type => 'inline')
assert_equal 1, diff.size
assert_equal 8, diff.first.size
assert_equal ru, diff.first[3].html_line_left
end
end
def test_offset_range_ascii_1
raw = <<-DIFF
--- a.txt 2013-04-05 14:19:39.000000000 +0900
+++ b.txt 2013-04-05 14:19:51.000000000 +0900
@@ -1,3 +1,3 @@
aaaa
-abc
+abcd
bbbb
DIFF
diff = Redmine::UnifiedDiff.new(raw, :type => 'sbs')
assert_equal 1, diff.size
assert_equal 3, diff.first.size
assert_equal "abc<span></span>", diff.first[1].html_line_left
assert_equal "abc<span>d</span>", diff.first[1].html_line_right
end
def test_offset_range_ascii_2
raw = <<-DIFF
--- a.txt 2013-04-05 14:19:39.000000000 +0900
+++ b.txt 2013-04-05 14:19:51.000000000 +0900
@@ -1,3 +1,3 @@
aaaa
-abc
+zabc
bbbb
DIFF
diff = Redmine::UnifiedDiff.new(raw, :type => 'sbs')
assert_equal 1, diff.size
assert_equal 3, diff.first.size
assert_equal "<span></span>abc", diff.first[1].html_line_left
assert_equal "<span>z</span>abc", diff.first[1].html_line_right
end
def test_offset_range_japanese_1
ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span></span>".force_encoding('UTF-8')
ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xaa\x9e</span>".force_encoding('UTF-8')
with_settings :repositories_encodings => '' do
diff = Redmine::UnifiedDiff.new(
read_diff_fixture('issue-13644-1.diff'), :type => 'sbs')
assert_equal 1, diff.size
assert_equal 3, diff.first.size
assert_equal ja1, diff.first[1].html_line_left
assert_equal ja2, diff.first[1].html_line_right
end
end
def test_offset_range_japanese_2
ja1 = "<span></span>\xe6\x97\xa5\xe6\x9c\xac".force_encoding('UTF-8')
ja2 = "<span>\xe3\x81\xab\xe3\x81\xa3\xe3\x81\xbd\xe3\x82\x93</span>\xe6\x97\xa5\xe6\x9c\xac".force_encoding('UTF-8')
with_settings :repositories_encodings => '' do
diff = Redmine::UnifiedDiff.new(
read_diff_fixture('issue-13644-2.diff'), :type => 'sbs')
assert_equal 1, diff.size
assert_equal 3, diff.first.size
assert_equal ja1, diff.first[1].html_line_left
assert_equal ja2, diff.first[1].html_line_right
end
end
def test_offset_range_japanese_3
# UTF-8 The 1st byte differs.
ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xa8\x98</span>".force_encoding('UTF-8')
ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe5\xa8\x98</span>".force_encoding('UTF-8')
with_settings :repositories_encodings => '' do
diff = Redmine::UnifiedDiff.new(
read_diff_fixture('issue-13644-3.diff'), :type => 'sbs')
assert_equal 1, diff.size
assert_equal 3, diff.first.size
assert_equal ja1, diff.first[1].html_line_left
assert_equal ja2, diff.first[1].html_line_right
end
end
def test_offset_range_japanese_4
# UTF-8 The 2nd byte differs.
ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xa8\x98</span>".force_encoding('UTF-8')
ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xaa\x98</span>".force_encoding('UTF-8')
with_settings :repositories_encodings => '' do
diff = Redmine::UnifiedDiff.new(
read_diff_fixture('issue-13644-4.diff'), :type => 'sbs')
assert_equal 1, diff.size
assert_equal 3, diff.first.size
assert_equal ja1, diff.first[1].html_line_left
assert_equal ja2, diff.first[1].html_line_right
end
end
def test_offset_range_japanese_5
# UTF-8 The 2nd byte differs.
ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xa8\x98</span>ok".force_encoding('UTF-8')
ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xaa\x98</span>ok".force_encoding('UTF-8')
with_settings :repositories_encodings => '' do
diff = Redmine::UnifiedDiff.new(
read_diff_fixture('issue-13644-5.diff'), :type => 'sbs')
assert_equal 1, diff.size
assert_equal 3, diff.first.size
assert_equal ja1, diff.first[1].html_line_left
assert_equal ja2, diff.first[1].html_line_right
end
end
private
def read_diff_fixture(filename)
File.new(File.join(File.dirname(__FILE__), '/../../../fixtures/diffs', filename)).read
end
end

View file

@ -0,0 +1,76 @@
# 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 Redmine::Utils::DateCalculationTest < ActiveSupport::TestCase
include Redmine::Utils::DateCalculation
def test_working_days_without_non_working_week_days
with_settings :non_working_week_days => [] do
assert_working_days 18, '2012-10-09', '2012-10-27'
assert_working_days 6, '2012-10-09', '2012-10-15'
assert_working_days 5, '2012-10-09', '2012-10-14'
assert_working_days 3, '2012-10-09', '2012-10-12'
assert_working_days 3, '2012-10-14', '2012-10-17'
assert_working_days 16, '2012-10-14', '2012-10-30'
end
end
def test_working_days_with_non_working_week_days
with_settings :non_working_week_days => %w(6 7) do
assert_working_days 14, '2012-10-09', '2012-10-27'
assert_working_days 4, '2012-10-09', '2012-10-15'
assert_working_days 4, '2012-10-09', '2012-10-14'
assert_working_days 3, '2012-10-09', '2012-10-12'
assert_working_days 8, '2012-10-09', '2012-10-19'
assert_working_days 8, '2012-10-11', '2012-10-23'
assert_working_days 2, '2012-10-14', '2012-10-17'
assert_working_days 11, '2012-10-14', '2012-10-30'
end
end
def test_add_working_days_without_non_working_week_days
with_settings :non_working_week_days => [] do
assert_add_working_days '2012-10-10', '2012-10-10', 0
assert_add_working_days '2012-10-11', '2012-10-10', 1
assert_add_working_days '2012-10-12', '2012-10-10', 2
assert_add_working_days '2012-10-13', '2012-10-10', 3
assert_add_working_days '2012-10-25', '2012-10-10', 15
end
end
def test_add_working_days_with_non_working_week_days
with_settings :non_working_week_days => %w(6 7) do
assert_add_working_days '2012-10-10', '2012-10-10', 0
assert_add_working_days '2012-10-11', '2012-10-10', 1
assert_add_working_days '2012-10-12', '2012-10-10', 2
assert_add_working_days '2012-10-15', '2012-10-10', 3
assert_add_working_days '2012-10-31', '2012-10-10', 15
assert_add_working_days '2012-10-19', '2012-10-09', 8
assert_add_working_days '2012-10-23', '2012-10-11', 8
end
end
def assert_working_days(expected_days, from, to)
assert_equal expected_days, working_days(from.to_date, to.to_date)
end
def assert_add_working_days(expected_date, from, working_days)
assert_equal expected_date.to_date, add_working_days(from.to_date, working_days)
end
end

View file

@ -0,0 +1,94 @@
# 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 Redmine::Views::Builders::JsonTest < ActiveSupport::TestCase
def test_hash
assert_json_output({'person' => {'name' => 'Ryan', 'age' => 32}}) do |b|
b.person do
b.name 'Ryan'
b.age 32
end
end
end
def test_hash_hash
assert_json_output({'person' => {'name' => 'Ryan', 'birth' => {'city' => 'London', 'country' => 'UK'}}}) do |b|
b.person do
b.name 'Ryan'
b.birth :city => 'London', :country => 'UK'
end
end
assert_json_output({'person' => {'id' => 1, 'name' => 'Ryan', 'birth' => {'city' => 'London', 'country' => 'UK'}}}) do |b|
b.person :id => 1 do
b.name 'Ryan'
b.birth :city => 'London', :country => 'UK'
end
end
end
def test_array
assert_json_output({'books' => [{'title' => 'Book 1', 'author' => 'B. Smith'}, {'title' => 'Book 2', 'author' => 'G. Cooper'}]}) do |b|
b.array :books do |b|
b.book :title => 'Book 1', :author => 'B. Smith'
b.book :title => 'Book 2', :author => 'G. Cooper'
end
end
assert_json_output({'books' => [{'title' => 'Book 1', 'author' => 'B. Smith'}, {'title' => 'Book 2', 'author' => 'G. Cooper'}]}) do |b|
b.array :books do |b|
b.book :title => 'Book 1' do
b.author 'B. Smith'
end
b.book :title => 'Book 2' do
b.author 'G. Cooper'
end
end
end
end
def test_array_with_content_tags
assert_json_output({'books' => [{'value' => 'Book 1', 'author' => 'B. Smith'}, {'value' => 'Book 2', 'author' => 'G. Cooper'}]}) do |b|
b.array :books do |b|
b.book 'Book 1', :author => 'B. Smith'
b.book 'Book 2', :author => 'G. Cooper'
end
end
end
def test_nested_arrays
assert_json_output({'books' => [{'authors' => ['B. Smith', 'G. Cooper']}]}) do |b|
b.array :books do |books|
books.book do |book|
book.array :authors do |authors|
authors.author 'B. Smith'
authors.author 'G. Cooper'
end
end
end
end
end
def assert_json_output(expected, &block)
builder = Redmine::Views::Builders::Json.new(ActionDispatch::TestRequest.new, ActionDispatch::TestResponse.new)
block.call(builder)
assert_equal(expected, ActiveSupport::JSON.decode(builder.output))
end
end

View file

@ -0,0 +1,67 @@
# 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 Redmine::Views::Builders::XmlTest < ActiveSupport::TestCase
def test_hash
assert_xml_output('<person><name>Ryan</name><age>32</age></person>') do |b|
b.person do
b.name 'Ryan'
b.age 32
end
end
end
def test_array
assert_xml_output('<books type="array"><book title="Book 1"/><book title="Book 2"/></books>') do |b|
b.array :books do |b|
b.book :title => 'Book 1'
b.book :title => 'Book 2'
end
end
end
def test_array_with_content_tags
assert_xml_output('<books type="array"><book author="B. Smith">Book 1</book><book author="G. Cooper">Book 2</book></books>') do |b|
b.array :books do |b|
b.book 'Book 1', :author => 'B. Smith'
b.book 'Book 2', :author => 'G. Cooper'
end
end
end
def test_nested_arrays
assert_xml_output('<books type="array"><book><authors type="array"><author>B. Smith</author><author>G. Cooper</author></authors></book></books>') do |b|
b.array :books do |books|
books.book do |book|
book.array :authors do |authors|
authors.author 'B. Smith'
authors.author 'G. Cooper'
end
end
end
end
end
def assert_xml_output(expected, &block)
builder = Redmine::Views::Builders::Xml.new(ActionDispatch::TestRequest.new, ActionDispatch::TestResponse.new)
block.call(builder)
assert_equal('<?xml version="1.0" encoding="UTF-8"?>' + expected, builder.output)
end
end

View file

@ -0,0 +1,48 @@
# 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 Redmine::Views::LabelledFormBuilderTest < Redmine::HelperTest
include Rails.application.routes.url_helpers
def test_label_should_output_one_element
set_language_if_valid 'en'
labelled_form_for(Issue.new) do |f|
output = f.label :subject
assert_equal output, '<label for="issue_subject">Subject</label>'
end
end
def test_hours_field_should_display_formatted_value_if_valid
entry = TimeEntry.new(:hours => '2.5')
entry.validate
labelled_form_for(entry) do |f|
assert_include 'value="2.50"', f.hours_field(:hours)
end
end
def test_hours_field_should_display_entered_value_if_invalid
entry = TimeEntry.new(:hours => '2.z')
entry.validate
labelled_form_for(entry) do |f|
assert_include 'value="2.z"', f.hours_field(:hours)
end
end
end

View file

@ -0,0 +1,35 @@
# 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 Redmine::WikiFormatting::HtmlParserTest < ActiveSupport::TestCase
def setup
@parser = Redmine::WikiFormatting::HtmlParser
end
def test_convert_line_breaks
assert_equal "A html snippet with\na new line.",
@parser.to_text('<p>A html snippet with<br>a new line.</p>')
end
def test_should_remove_style_tags_from_body
assert_equal "Text",
@parser.to_text('<html><body><style>body {font-size: 0.8em;}</style>Text</body></html>')
end
end

View file

@ -0,0 +1,404 @@
# 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 Redmine::WikiFormatting::MacrosTest < Redmine::HelperTest
include ApplicationHelper
include ActionView::Helpers::TextHelper
include ActionView::Helpers::SanitizeHelper
include ERB::Util
include Rails.application.routes.url_helpers
extend ActionView::Helpers::SanitizeHelper::ClassMethods
fixtures :projects, :roles, :enabled_modules, :users,
:repositories, :changesets,
:trackers, :issue_statuses, :issues,
:versions, :documents,
:wikis, :wiki_pages, :wiki_contents,
:boards, :messages,
:attachments
def setup
super
@project = nil
end
def teardown
end
def test_macro_registration
Redmine::WikiFormatting::Macros.register do
macro :foo do |obj, args|
"Foo: #{args.size} (#{args.join(',')}) (#{args.class.name})"
end
end
assert_equal '<p>Foo: 0 () (Array)</p>', textilizable("{{foo}}")
assert_equal '<p>Foo: 0 () (Array)</p>', textilizable("{{foo()}}")
assert_equal '<p>Foo: 1 (arg1) (Array)</p>', textilizable("{{foo(arg1)}}")
assert_equal '<p>Foo: 2 (arg1,arg2) (Array)</p>', textilizable("{{foo(arg1, arg2)}}")
end
def test_macro_registration_parse_args_set_to_false_should_disable_arguments_parsing
Redmine::WikiFormatting::Macros.register do
macro :bar, :parse_args => false do |obj, args|
"Bar: (#{args}) (#{args.class.name})"
end
end
assert_equal '<p>Bar: (args, more args) (String)</p>', textilizable("{{bar(args, more args)}}")
assert_equal '<p>Bar: () (String)</p>', textilizable("{{bar}}")
assert_equal '<p>Bar: () (String)</p>', textilizable("{{bar()}}")
end
def test_macro_registration_with_3_args_should_receive_text_argument
Redmine::WikiFormatting::Macros.register do
macro :baz do |obj, args, text|
"Baz: (#{args.join(',')}) (#{text.class.name}) (#{text})"
end
end
assert_equal "<p>Baz: () (NilClass) ()</p>", textilizable("{{baz}}")
assert_equal "<p>Baz: () (NilClass) ()</p>", textilizable("{{baz()}}")
assert_equal "<p>Baz: () (String) (line1\nline2)</p>", textilizable("{{baz()\nline1\nline2\n}}")
assert_equal "<p>Baz: (arg1,arg2) (String) (line1\nline2)</p>", textilizable("{{baz(arg1, arg2)\nline1\nline2\n}}")
end
def test_macro_name_with_upper_case
Redmine::WikiFormatting::Macros.macro(:UpperCase) {|obj, args| "Upper"}
assert_equal "<p>Upper</p>", textilizable("{{UpperCase}}")
end
def test_multiple_macros_on_the_same_line
Redmine::WikiFormatting::Macros.macro :foo do |obj, args|
args.any? ? "args: #{args.join(',')}" : "no args"
end
assert_equal '<p>no args no args</p>', textilizable("{{foo}} {{foo}}")
assert_equal '<p>args: a,b no args</p>', textilizable("{{foo(a,b)}} {{foo}}")
assert_equal '<p>args: a,b args: c,d</p>', textilizable("{{foo(a,b)}} {{foo(c,d)}}")
assert_equal '<p>no args args: c,d</p>', textilizable("{{foo}} {{foo(c,d)}}")
end
def test_macro_should_receive_the_object_as_argument_when_with_object_and_attribute
issue = Issue.find(1)
issue.description = "{{hello_world}}"
assert_equal '<p>Hello world! Object: Issue, Called with no argument and no block of text.</p>', textilizable(issue, :description)
end
def test_macro_should_receive_the_object_as_argument_when_called_with_object_option
text = "{{hello_world}}"
assert_equal '<p>Hello world! Object: Issue, Called with no argument and no block of text.</p>', textilizable(text, :object => Issue.find(1))
end
def test_extract_macro_options_should_with_args
options = extract_macro_options(["arg1", "arg2"], :foo, :size)
assert_equal([["arg1", "arg2"], {}], options)
end
def test_extract_macro_options_should_with_options
options = extract_macro_options(["foo=bar", "size=2"], :foo, :size)
assert_equal([[], {:foo => "bar", :size => "2"}], options)
end
def test_extract_macro_options_should_with_args_and_options
options = extract_macro_options(["arg1", "arg2", "foo=bar", "size=2"], :foo, :size)
assert_equal([["arg1", "arg2"], {:foo => "bar", :size => "2"}], options)
end
def test_extract_macro_options_should_parse_options_lazily
options = extract_macro_options(["params=x=1&y=2"], :params)
assert_equal([[], {:params => "x=1&y=2"}], options)
end
def test_macro_exception_should_be_displayed
Redmine::WikiFormatting::Macros.macro :exception do |obj, args|
raise "My message"
end
text = "{{exception}}"
assert_include '<div class="flash error">Error executing the <strong>exception</strong> macro (My message)</div>', textilizable(text)
end
def test_macro_arguments_should_not_be_parsed_by_formatters
text = '{{hello_world(http://www.redmine.org, #1)}}'
assert_include 'Arguments: http://www.redmine.org, #1', textilizable(text)
end
def test_exclamation_mark_should_not_run_macros
text = "!{{hello_world}}"
assert_equal '<p>{{hello_world}}</p>', textilizable(text)
end
def test_exclamation_mark_should_escape_macros
text = "!{{hello_world(<tag>)}}"
assert_equal '<p>{{hello_world(&lt;tag&gt;)}}</p>', textilizable(text)
end
def test_unknown_macros_should_not_be_replaced
text = "{{unknown}}"
assert_equal '<p>{{unknown}}</p>', textilizable(text)
end
def test_unknown_macros_should_parsed_as_text
text = "{{unknown(*test*)}}"
assert_equal '<p>{{unknown(<strong>test</strong>)}}</p>', textilizable(text)
end
def test_unknown_macros_should_be_escaped
text = "{{unknown(<tag>)}}"
assert_equal '<p>{{unknown(&lt;tag&gt;)}}</p>', textilizable(text)
end
def test_html_safe_macro_output_should_not_be_escaped
Redmine::WikiFormatting::Macros.macro :safe_macro do |obj, args|
"<tag>".html_safe
end
assert_equal '<p><tag></p>', textilizable("{{safe_macro}}")
end
def test_macro_hello_world
text = "{{hello_world}}"
assert textilizable(text).match(/Hello world!/)
end
def test_macro_hello_world_should_escape_arguments
text = "{{hello_world(<tag>)}}"
assert_include 'Arguments: &lt;tag&gt;', textilizable(text)
end
def test_macro_macro_list
text = "{{macro_list}}"
assert_match %r{<code>hello_world</code>}, textilizable(text)
end
def test_macro_include
@project = Project.find(1)
# include a page of the current project wiki
text = "{{include(Another page)}}"
assert_include 'This is a link to a ticket', textilizable(text)
@project = nil
# include a page of a specific project wiki
text = "{{include(ecookbook:Another page)}}"
assert_include 'This is a link to a ticket', textilizable(text)
text = "{{include(ecookbook:)}}"
assert_include 'CookBook documentation', textilizable(text)
text = "{{include(unknowidentifier:somepage)}}"
assert_include 'Page not found', textilizable(text)
end
def test_macro_collapse
text = "{{collapse\n*Collapsed* block of text\n}}"
with_locale 'en' do
result = textilizable(text)
assert_select_in result, 'div.collapsed-text'
assert_select_in result, 'strong', :text => 'Collapsed'
assert_select_in result, 'a.collapsible.collapsed', :text => 'Show'
assert_select_in result, 'a.collapsible', :text => 'Hide'
end
end
def test_macro_collapse_with_one_arg
text = "{{collapse(Example)\n*Collapsed* block of text\n}}"
result = textilizable(text)
assert_select_in result, 'div.collapsed-text'
assert_select_in result, 'strong', :text => 'Collapsed'
assert_select_in result, 'a.collapsible.collapsed', :text => 'Example'
assert_select_in result, 'a.collapsible', :text => 'Example'
end
def test_macro_collapse_with_two_args
text = "{{collapse(Show example, Hide example)\n*Collapsed* block of text\n}}"
result = textilizable(text)
assert_select_in result, 'div.collapsed-text'
assert_select_in result, 'strong', :text => 'Collapsed'
assert_select_in result, 'a.collapsible.collapsed', :text => 'Show example'
assert_select_in result, 'a.collapsible', :text => 'Hide example'
end
def test_macro_collapse_should_not_break_toc
set_language_if_valid 'en'
text = <<-RAW
{{toc}}
h1. Title
{{collapse(Show example, Hide example)
h2. Heading
}}"
RAW
expected_toc = '<ul class="toc"><li><strong>Table of contents</strong></li><li><a href="#Title">Title</a><ul><li><a href="#Heading">Heading</a></li></ul></li></ul>'
assert_include expected_toc, textilizable(text).gsub(/[\r\n]/, '')
end
def test_macro_child_pages
expected = "<p><ul class=\"pages-hierarchy\">\n" +
"<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a>\n" +
"<ul class=\"pages-hierarchy\">\n<li><a href=\"/projects/ecookbook/wiki/Child_1_1\">Child 1 1</a></li>\n</ul>\n</li>\n" +
"<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" +
"</ul>\n</p>"
@project = Project.find(1)
# child pages of the current wiki page
assert_equal expected, textilizable("{{child_pages}}", :object => WikiPage.find(2).content)
# child pages of another page
assert_equal expected, textilizable("{{child_pages(Another_page)}}", :object => WikiPage.find(1).content)
@project = Project.find(2)
assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page)}}", :object => WikiPage.find(1).content)
end
def test_macro_child_pages_with_parent_option
expected = "<p><ul class=\"pages-hierarchy\">\n" +
"<li><a href=\"/projects/ecookbook/wiki/Another_page\">Another page</a>\n" +
"<ul class=\"pages-hierarchy\">\n" +
"<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a>\n" +
"<ul class=\"pages-hierarchy\">\n<li><a href=\"/projects/ecookbook/wiki/Child_1_1\">Child 1 1</a></li>\n</ul>\n</li>\n" +
"<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" +
"</ul>\n</li>\n</ul>\n</p>"
@project = Project.find(1)
# child pages of the current wiki page
assert_equal expected, textilizable("{{child_pages(parent=1)}}", :object => WikiPage.find(2).content)
# child pages of another page
assert_equal expected, textilizable("{{child_pages(Another_page, parent=1)}}", :object => WikiPage.find(1).content)
@project = Project.find(2)
assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page, parent=1)}}", :object => WikiPage.find(1).content)
end
def test_macro_child_pages_with_depth_option
expected = "<p><ul class=\"pages-hierarchy\">\n" +
"<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a></li>\n" +
"<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" +
"</ul>\n</p>"
@project = Project.find(1)
assert_equal expected, textilizable("{{child_pages(depth=1)}}", :object => WikiPage.find(2).content)
end
def test_macro_child_pages_without_wiki_page_should_fail
assert_match /can be called from wiki pages only/, textilizable("{{child_pages}}")
end
def test_macro_thumbnail
link = link_to('<img alt="testfile.PNG" src="/attachments/thumbnail/17" />'.html_safe,
"/attachments/17",
:class => "thumbnail",
:title => "testfile.PNG")
assert_equal "<p>#{link}</p>",
textilizable("{{thumbnail(testfile.png)}}", :object => Issue.find(14))
end
def test_macro_thumbnail_with_full_path
link = link_to('<img alt="testfile.PNG" src="http://test.host/attachments/thumbnail/17" />'.html_safe,
"http://test.host/attachments/17",
:class => "thumbnail",
:title => "testfile.PNG")
assert_equal "<p>#{link}</p>",
textilizable("{{thumbnail(testfile.png)}}", :object => Issue.find(14), :only_path => false)
end
def test_macro_thumbnail_with_size
link = link_to('<img alt="testfile.PNG" src="/attachments/thumbnail/17/200" />'.html_safe,
"/attachments/17",
:class => "thumbnail",
:title => "testfile.PNG")
assert_equal "<p>#{link}</p>",
textilizable("{{thumbnail(testfile.png, size=200)}}", :object => Issue.find(14))
end
def test_macro_thumbnail_with_title
link = link_to('<img alt="testfile.PNG" src="/attachments/thumbnail/17" />'.html_safe,
"/attachments/17",
:class => "thumbnail",
:title => "Cool image")
assert_equal "<p>#{link}</p>",
textilizable("{{thumbnail(testfile.png, title=Cool image)}}", :object => Issue.find(14))
end
def test_macro_thumbnail_with_invalid_filename_should_fail
assert_include 'test.png not found',
textilizable("{{thumbnail(test.png)}}", :object => Issue.find(14))
end
def test_macros_should_not_be_executed_in_pre_tags
text = <<-RAW
{{hello_world(foo)}}
<pre>
{{hello_world(pre)}}
!{{hello_world(pre)}}
</pre>
{{hello_world(bar)}}
RAW
expected = <<-EXPECTED
<p>Hello world! Object: NilClass, Arguments: foo and no block of text.</p>
<pre>
{{hello_world(pre)}}
!{{hello_world(pre)}}
</pre>
<p>Hello world! Object: NilClass, Arguments: bar and no block of text.</p>
EXPECTED
assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(text).gsub(%r{[\r\n\t]}, '')
end
def test_macros_should_be_escaped_in_pre_tags
text = "<pre>{{hello_world(<tag>)}}</pre>"
assert_equal "<pre>{{hello_world(&lt;tag&gt;)}}</pre>", textilizable(text)
end
def test_macros_should_not_mangle_next_macros_outputs
text = '{{macro(2)}} !{{macro(2)}} {{hello_world(foo)}}'
assert_equal '<p>{{macro(2)}} {{macro(2)}} Hello world! Object: NilClass, Arguments: foo and no block of text.</p>', textilizable(text)
end
def test_macros_with_text_should_not_mangle_following_macros
text = <<-RAW
{{hello_world
Line of text
}}
{{hello_world
Another line of text
}}
RAW
expected = <<-EXPECTED
<p>Hello world! Object: NilClass, Called with no argument and a 12 bytes long block of text.</p>
<p>Hello world! Object: NilClass, Called with no argument and a 20 bytes long block of text.</p>
EXPECTED
assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(text).gsub(%r{[\r\n\t]}, '')
end
end

View file

@ -0,0 +1,93 @@
# 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 Redmine::WikiFormatting::MarkdownFormatterTest < ActionView::TestCase
if Object.const_defined?(:Redcarpet)
def setup
@formatter = Redmine::WikiFormatting::Markdown::Formatter
end
def test_syntax_error_in_image_reference_should_not_raise_exception
assert @formatter.new("!>[](foo.png)").to_html
end
def test_empty_image_should_not_raise_exception
assert @formatter.new("![]()").to_html
end
# re-using the formatter after getting above error crashes the
# ruby interpreter. This seems to be related to
# https://github.com/vmg/redcarpet/issues/318
def test_should_not_crash_redcarpet_after_syntax_error
@formatter.new("!>[](foo.png)").to_html rescue nil
assert @formatter.new("![](foo.png)").to_html.present?
end
def test_inline_style
assert_equal "<p><strong>foo</strong></p>", @formatter.new("**foo**").to_html.strip
end
def test_not_set_intra_emphasis
assert_equal "<p>foo_bar_baz</p>", @formatter.new("foo_bar_baz").to_html.strip
end
def test_wiki_links_should_be_preserved
text = 'This is a wiki link: [[Foo]]'
assert_include '[[Foo]]', @formatter.new(text).to_html
end
def test_redmine_links_with_double_quotes_should_be_preserved
text = 'This is a redmine link: version:"1.0"'
assert_include 'version:"1.0"', @formatter.new(text).to_html
end
def test_should_support_syntax_highligth
text = <<-STR
~~~ruby
def foo
end
~~~
STR
assert_select_in @formatter.new(text).to_html, 'pre code.ruby.syntaxhl' do
assert_select 'span.keyword', :text => 'def'
end
end
def test_should_not_allow_invalid_language_for_code_blocks
text = <<-STR
~~~foo
test
~~~
STR
assert_equal "<pre>test\n</pre>", @formatter.new(text).to_html
end
def test_external_links_should_have_external_css_class
text = 'This is a [link](http://example.net/)'
assert_equal '<p>This is a <a href="http://example.net/" class="external">link</a></p>', @formatter.new(text).to_html.strip
end
def test_locals_links_should_not_have_external_css_class
text = 'This is a [link](/issues)'
assert_equal '<p>This is a <a href="/issues">link</a></p>', @formatter.new(text).to_html.strip
end
end
end

Some files were not shown because too many files have changed in this diff Show more