##// END OF EJS Templates
Drop shoulda....
Jean-Philippe Lang -
r13294:f04148695a4a
parent child
Show More
@@ -1,104 +1,103
1 source 'https://rubygems.org'
1 source 'https://rubygems.org'
2
2
3 gem "rails", "4.1.8"
3 gem "rails", "4.1.8"
4 gem "jquery-rails", "~> 3.1.1"
4 gem "jquery-rails", "~> 3.1.1"
5 gem "coderay", "~> 1.1.0"
5 gem "coderay", "~> 1.1.0"
6 gem "builder", ">= 3.0.4"
6 gem "builder", ">= 3.0.4"
7 gem "request_store", "1.0.5"
7 gem "request_store", "1.0.5"
8 gem "mime-types"
8 gem "mime-types"
9 gem "awesome_nested_set", "3.0.0"
9 gem "awesome_nested_set", "3.0.0"
10 gem "protected_attributes"
10 gem "protected_attributes"
11 gem "actionpack-action_caching"
11 gem "actionpack-action_caching"
12
12
13 # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
13 # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
14 gem 'tzinfo-data', platforms: [:mingw, :x64_mingw, :mswin, :jruby]
14 gem 'tzinfo-data', platforms: [:mingw, :x64_mingw, :mswin, :jruby]
15 gem "rbpdf", "~> 1.18.2"
15 gem "rbpdf", "~> 1.18.2"
16
16
17 # Optional gem for LDAP authentication
17 # Optional gem for LDAP authentication
18 group :ldap do
18 group :ldap do
19 gem "net-ldap", "~> 0.3.1"
19 gem "net-ldap", "~> 0.3.1"
20 end
20 end
21
21
22 # Optional gem for OpenID authentication
22 # Optional gem for OpenID authentication
23 group :openid do
23 group :openid do
24 gem "ruby-openid", "~> 2.3.0", :require => "openid"
24 gem "ruby-openid", "~> 2.3.0", :require => "openid"
25 gem "rack-openid"
25 gem "rack-openid"
26 end
26 end
27
27
28 platforms :mri, :mingw, :x64_mingw do
28 platforms :mri, :mingw, :x64_mingw do
29 # Optional gem for exporting the gantt to a PNG file, not supported with jruby
29 # Optional gem for exporting the gantt to a PNG file, not supported with jruby
30 group :rmagick do
30 group :rmagick do
31 gem "rmagick", ">= 2.0.0"
31 gem "rmagick", ">= 2.0.0"
32 end
32 end
33
33
34 # Optional Markdown support, not for JRuby
34 # Optional Markdown support, not for JRuby
35 group :markdown do
35 group :markdown do
36 gem "redcarpet", "~> 3.1.2"
36 gem "redcarpet", "~> 3.1.2"
37 end
37 end
38 end
38 end
39
39
40 platforms :jruby do
40 platforms :jruby do
41 # jruby-openssl is bundled with JRuby 1.7.0
41 # jruby-openssl is bundled with JRuby 1.7.0
42 gem "jruby-openssl" if Object.const_defined?(:JRUBY_VERSION) && JRUBY_VERSION < '1.7.0'
42 gem "jruby-openssl" if Object.const_defined?(:JRUBY_VERSION) && JRUBY_VERSION < '1.7.0'
43 gem "activerecord-jdbc-adapter", "~> 1.3.2"
43 gem "activerecord-jdbc-adapter", "~> 1.3.2"
44 end
44 end
45
45
46 # Include database gems for the adapters found in the database
46 # Include database gems for the adapters found in the database
47 # configuration file
47 # configuration file
48 require 'erb'
48 require 'erb'
49 require 'yaml'
49 require 'yaml'
50 database_file = File.join(File.dirname(__FILE__), "config/database.yml")
50 database_file = File.join(File.dirname(__FILE__), "config/database.yml")
51 if File.exist?(database_file)
51 if File.exist?(database_file)
52 database_config = YAML::load(ERB.new(IO.read(database_file)).result)
52 database_config = YAML::load(ERB.new(IO.read(database_file)).result)
53 adapters = database_config.values.map {|c| c['adapter']}.compact.uniq
53 adapters = database_config.values.map {|c| c['adapter']}.compact.uniq
54 if adapters.any?
54 if adapters.any?
55 adapters.each do |adapter|
55 adapters.each do |adapter|
56 case adapter
56 case adapter
57 when 'mysql2'
57 when 'mysql2'
58 gem "mysql2", "~> 0.3.11", :platforms => [:mri, :mingw, :x64_mingw]
58 gem "mysql2", "~> 0.3.11", :platforms => [:mri, :mingw, :x64_mingw]
59 gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
59 gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
60 when 'mysql'
60 when 'mysql'
61 gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
61 gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
62 when /postgresql/
62 when /postgresql/
63 gem "pg", ">= 0.11.0", :platforms => [:mri, :mingw, :x64_mingw]
63 gem "pg", ">= 0.11.0", :platforms => [:mri, :mingw, :x64_mingw]
64 gem "activerecord-jdbcpostgresql-adapter", :platforms => :jruby
64 gem "activerecord-jdbcpostgresql-adapter", :platforms => :jruby
65 when /sqlite3/
65 when /sqlite3/
66 gem "sqlite3", :platforms => [:mri, :mingw, :x64_mingw]
66 gem "sqlite3", :platforms => [:mri, :mingw, :x64_mingw]
67 gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
67 gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
68 when /sqlserver/
68 when /sqlserver/
69 gem "tiny_tds", "~> 0.6.2", :platforms => [:mri, :mingw, :x64_mingw]
69 gem "tiny_tds", "~> 0.6.2", :platforms => [:mri, :mingw, :x64_mingw]
70 gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw, :x64_mingw]
70 gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw, :x64_mingw]
71 else
71 else
72 warn("Unknown database adapter `#{adapter}` found in config/database.yml, use Gemfile.local to load your own database gems")
72 warn("Unknown database adapter `#{adapter}` found in config/database.yml, use Gemfile.local to load your own database gems")
73 end
73 end
74 end
74 end
75 else
75 else
76 warn("No adapter found in config/database.yml, please configure it first")
76 warn("No adapter found in config/database.yml, please configure it first")
77 end
77 end
78 else
78 else
79 warn("Please configure your config/database.yml first")
79 warn("Please configure your config/database.yml first")
80 end
80 end
81
81
82 group :development do
82 group :development do
83 gem "rdoc", ">= 2.4.2"
83 gem "rdoc", ">= 2.4.2"
84 gem "yard"
84 gem "yard"
85 end
85 end
86
86
87 group :test do
87 group :test do
88 gem "minitest"
88 gem "minitest"
89 gem "shoulda-context"
90 gem "mocha", "~> 1.0.0", :require => 'mocha/api'
89 gem "mocha", "~> 1.0.0", :require => 'mocha/api'
91 # For running UI tests
90 # For running UI tests
92 gem "capybara", "~> 2.1.0"
91 gem "capybara", "~> 2.1.0"
93 gem "selenium-webdriver"
92 gem "selenium-webdriver"
94 end
93 end
95
94
96 local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")
95 local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")
97 if File.exists?(local_gemfile)
96 if File.exists?(local_gemfile)
98 eval_gemfile local_gemfile
97 eval_gemfile local_gemfile
99 end
98 end
100
99
101 # Load plugins' Gemfiles
100 # Load plugins' Gemfiles
102 Dir.glob File.expand_path("../plugins/*/{Gemfile,PluginGemfile}", __FILE__) do |file|
101 Dir.glob File.expand_path("../plugins/*/{Gemfile,PluginGemfile}", __FILE__) do |file|
103 eval_gemfile file
102 eval_gemfile file
104 end
103 end
@@ -1,293 +1,289
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 #require 'shoulda'
19 ENV["RAILS_ENV"] = "test"
18 ENV["RAILS_ENV"] = "test"
20 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
21 require 'rails/test_help'
20 require 'rails/test_help'
22 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
21 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
23
22
24 require File.expand_path(File.dirname(__FILE__) + '/object_helpers')
23 require File.expand_path(File.dirname(__FILE__) + '/object_helpers')
25 include ObjectHelpers
24 include ObjectHelpers
26
25
27 require 'awesome_nested_set/version'
26 require 'awesome_nested_set/version'
28 require 'net/ldap'
27 require 'net/ldap'
29
28
30 class ActionView::TestCase
29 class ActionView::TestCase
31 helper :application
30 helper :application
32 include ApplicationHelper
31 include ApplicationHelper
33 end
32 end
34
33
35 class ActiveSupport::TestCase
34 class ActiveSupport::TestCase
36 include ActionDispatch::TestProcess
35 include ActionDispatch::TestProcess
37 include Shoulda::Context::Assertions
38 include Shoulda::Context::InstanceMethods
39 extend Shoulda::Context::ClassMethods
40
36
41 self.use_transactional_fixtures = true
37 self.use_transactional_fixtures = true
42 self.use_instantiated_fixtures = false
38 self.use_instantiated_fixtures = false
43
39
44 #ESCAPED_CANT = 'can&#x27;t'
40 #ESCAPED_CANT = 'can&#x27;t'
45 #ESCAPED_UCANT = 'Can&#x27;t'
41 #ESCAPED_UCANT = 'Can&#x27;t'
46 # Rails 4.0.2
42 # Rails 4.0.2
47 ESCAPED_CANT = 'can&#39;t'
43 ESCAPED_CANT = 'can&#39;t'
48 ESCAPED_UCANT = 'Can&#39;t'
44 ESCAPED_UCANT = 'Can&#39;t'
49
45
50 def log_user(login, password)
46 def log_user(login, password)
51 User.anonymous
47 User.anonymous
52 get "/login"
48 get "/login"
53 assert_equal nil, session[:user_id]
49 assert_equal nil, session[:user_id]
54 assert_response :success
50 assert_response :success
55 assert_template "account/login"
51 assert_template "account/login"
56 post "/login", :username => login, :password => password
52 post "/login", :username => login, :password => password
57 assert_equal login, User.find(session[:user_id]).login
53 assert_equal login, User.find(session[:user_id]).login
58 end
54 end
59
55
60 def uploaded_test_file(name, mime)
56 def uploaded_test_file(name, mime)
61 fixture_file_upload("files/#{name}", mime, true)
57 fixture_file_upload("files/#{name}", mime, true)
62 end
58 end
63
59
64 def credentials(user, password=nil)
60 def credentials(user, password=nil)
65 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
61 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
66 end
62 end
67
63
68 # Mock out a file
64 # Mock out a file
69 def self.mock_file
65 def self.mock_file
70 file = 'a_file.png'
66 file = 'a_file.png'
71 file.stubs(:size).returns(32)
67 file.stubs(:size).returns(32)
72 file.stubs(:original_filename).returns('a_file.png')
68 file.stubs(:original_filename).returns('a_file.png')
73 file.stubs(:content_type).returns('image/png')
69 file.stubs(:content_type).returns('image/png')
74 file.stubs(:read).returns(false)
70 file.stubs(:read).returns(false)
75 file
71 file
76 end
72 end
77
73
78 def mock_file
74 def mock_file
79 self.class.mock_file
75 self.class.mock_file
80 end
76 end
81
77
82 def mock_file_with_options(options={})
78 def mock_file_with_options(options={})
83 file = ''
79 file = ''
84 file.stubs(:size).returns(32)
80 file.stubs(:size).returns(32)
85 original_filename = options[:original_filename] || nil
81 original_filename = options[:original_filename] || nil
86 file.stubs(:original_filename).returns(original_filename)
82 file.stubs(:original_filename).returns(original_filename)
87 content_type = options[:content_type] || nil
83 content_type = options[:content_type] || nil
88 file.stubs(:content_type).returns(content_type)
84 file.stubs(:content_type).returns(content_type)
89 file.stubs(:read).returns(false)
85 file.stubs(:read).returns(false)
90 file
86 file
91 end
87 end
92
88
93 # Use a temporary directory for attachment related tests
89 # Use a temporary directory for attachment related tests
94 def set_tmp_attachments_directory
90 def set_tmp_attachments_directory
95 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
91 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
96 unless File.directory?("#{Rails.root}/tmp/test/attachments")
92 unless File.directory?("#{Rails.root}/tmp/test/attachments")
97 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
93 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
98 end
94 end
99 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
95 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
100 end
96 end
101
97
102 def set_fixtures_attachments_directory
98 def set_fixtures_attachments_directory
103 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
99 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
104 end
100 end
105
101
106 def with_settings(options, &block)
102 def with_settings(options, &block)
107 saved_settings = options.keys.inject({}) do |h, k|
103 saved_settings = options.keys.inject({}) do |h, k|
108 h[k] = case Setting[k]
104 h[k] = case Setting[k]
109 when Symbol, false, true, nil
105 when Symbol, false, true, nil
110 Setting[k]
106 Setting[k]
111 else
107 else
112 Setting[k].dup
108 Setting[k].dup
113 end
109 end
114 h
110 h
115 end
111 end
116 options.each {|k, v| Setting[k] = v}
112 options.each {|k, v| Setting[k] = v}
117 yield
113 yield
118 ensure
114 ensure
119 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
115 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
120 end
116 end
121
117
122 # Yields the block with user as the current user
118 # Yields the block with user as the current user
123 def with_current_user(user, &block)
119 def with_current_user(user, &block)
124 saved_user = User.current
120 saved_user = User.current
125 User.current = user
121 User.current = user
126 yield
122 yield
127 ensure
123 ensure
128 User.current = saved_user
124 User.current = saved_user
129 end
125 end
130
126
131 def with_locale(locale, &block)
127 def with_locale(locale, &block)
132 saved_localed = ::I18n.locale
128 saved_localed = ::I18n.locale
133 ::I18n.locale = locale
129 ::I18n.locale = locale
134 yield
130 yield
135 ensure
131 ensure
136 ::I18n.locale = saved_localed
132 ::I18n.locale = saved_localed
137 end
133 end
138
134
139 def change_user_password(login, new_password)
135 def change_user_password(login, new_password)
140 user = User.where(:login => login).first
136 user = User.where(:login => login).first
141 user.password, user.password_confirmation = new_password, new_password
137 user.password, user.password_confirmation = new_password, new_password
142 user.save!
138 user.save!
143 end
139 end
144
140
145 def self.ldap_configured?
141 def self.ldap_configured?
146 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
142 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
147 return @test_ldap.bind
143 return @test_ldap.bind
148 rescue Exception => e
144 rescue Exception => e
149 # LDAP is not listening
145 # LDAP is not listening
150 return nil
146 return nil
151 end
147 end
152
148
153 def self.convert_installed?
149 def self.convert_installed?
154 Redmine::Thumbnail.convert_available?
150 Redmine::Thumbnail.convert_available?
155 end
151 end
156
152
157 # Returns the path to the test +vendor+ repository
153 # Returns the path to the test +vendor+ repository
158 def self.repository_path(vendor)
154 def self.repository_path(vendor)
159 path = Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
155 path = Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
160 # Unlike ruby, JRuby returns Rails.root with backslashes under Windows
156 # Unlike ruby, JRuby returns Rails.root with backslashes under Windows
161 path.tr("\\", "/")
157 path.tr("\\", "/")
162 end
158 end
163
159
164 # Returns the url of the subversion test repository
160 # Returns the url of the subversion test repository
165 def self.subversion_repository_url
161 def self.subversion_repository_url
166 path = repository_path('subversion')
162 path = repository_path('subversion')
167 path = '/' + path unless path.starts_with?('/')
163 path = '/' + path unless path.starts_with?('/')
168 "file://#{path}"
164 "file://#{path}"
169 end
165 end
170
166
171 # Returns true if the +vendor+ test repository is configured
167 # Returns true if the +vendor+ test repository is configured
172 def self.repository_configured?(vendor)
168 def self.repository_configured?(vendor)
173 File.directory?(repository_path(vendor))
169 File.directory?(repository_path(vendor))
174 end
170 end
175
171
176 def repository_path_hash(arr)
172 def repository_path_hash(arr)
177 hs = {}
173 hs = {}
178 hs[:path] = arr.join("/")
174 hs[:path] = arr.join("/")
179 hs[:param] = arr.join("/")
175 hs[:param] = arr.join("/")
180 hs
176 hs
181 end
177 end
182
178
183 def assert_save(object)
179 def assert_save(object)
184 saved = object.save
180 saved = object.save
185 message = "#{object.class} could not be saved"
181 message = "#{object.class} could not be saved"
186 errors = object.errors.full_messages.map {|m| "- #{m}"}
182 errors = object.errors.full_messages.map {|m| "- #{m}"}
187 message << ":\n#{errors.join("\n")}" if errors.any?
183 message << ":\n#{errors.join("\n")}" if errors.any?
188 assert_equal true, saved, message
184 assert_equal true, saved, message
189 end
185 end
190
186
191 def assert_select_error(arg)
187 def assert_select_error(arg)
192 assert_select '#errorExplanation', :text => arg
188 assert_select '#errorExplanation', :text => arg
193 end
189 end
194
190
195 def assert_include(expected, s, message=nil)
191 def assert_include(expected, s, message=nil)
196 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
192 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
197 end
193 end
198
194
199 def assert_not_include(expected, s, message=nil)
195 def assert_not_include(expected, s, message=nil)
200 assert !s.include?(expected), (message || "\"#{expected}\" found in \"#{s}\"")
196 assert !s.include?(expected), (message || "\"#{expected}\" found in \"#{s}\"")
201 end
197 end
202
198
203 def assert_select_in(text, *args, &block)
199 def assert_select_in(text, *args, &block)
204 d = HTML::Document.new(CGI::unescapeHTML(String.new(text))).root
200 d = HTML::Document.new(CGI::unescapeHTML(String.new(text))).root
205 assert_select(d, *args, &block)
201 assert_select(d, *args, &block)
206 end
202 end
207
203
208 def assert_mail_body_match(expected, mail, message=nil)
204 def assert_mail_body_match(expected, mail, message=nil)
209 if expected.is_a?(String)
205 if expected.is_a?(String)
210 assert_include expected, mail_body(mail), message
206 assert_include expected, mail_body(mail), message
211 else
207 else
212 assert_match expected, mail_body(mail), message
208 assert_match expected, mail_body(mail), message
213 end
209 end
214 end
210 end
215
211
216 def assert_mail_body_no_match(expected, mail, message=nil)
212 def assert_mail_body_no_match(expected, mail, message=nil)
217 if expected.is_a?(String)
213 if expected.is_a?(String)
218 assert_not_include expected, mail_body(mail), message
214 assert_not_include expected, mail_body(mail), message
219 else
215 else
220 assert_no_match expected, mail_body(mail), message
216 assert_no_match expected, mail_body(mail), message
221 end
217 end
222 end
218 end
223
219
224 def mail_body(mail)
220 def mail_body(mail)
225 mail.parts.first.body.encoded
221 mail.parts.first.body.encoded
226 end
222 end
227
223
228 # awesome_nested_set new node lft and rgt value changed this refactor revision.
224 # awesome_nested_set new node lft and rgt value changed this refactor revision.
229 # https://github.com/collectiveidea/awesome_nested_set/commit/199fca9bb938e40200cd90714dc69247ef017c61
225 # https://github.com/collectiveidea/awesome_nested_set/commit/199fca9bb938e40200cd90714dc69247ef017c61
230 # The reason of behavior change is that "self.class.base_class.unscoped" was added to this line.
226 # The reason of behavior change is that "self.class.base_class.unscoped" was added to this line.
231 # https://github.com/collectiveidea/awesome_nested_set/commit/199fca9bb9#diff-f61b59a5e6319024e211b0ffdd0e4ef1R273
227 # https://github.com/collectiveidea/awesome_nested_set/commit/199fca9bb9#diff-f61b59a5e6319024e211b0ffdd0e4ef1R273
232 # It seems correct behavior because of this line comment.
228 # It seems correct behavior because of this line comment.
233 # https://github.com/collectiveidea/awesome_nested_set/blame/199fca9bb9/lib/awesome_nested_set/model.rb#L278
229 # https://github.com/collectiveidea/awesome_nested_set/blame/199fca9bb9/lib/awesome_nested_set/model.rb#L278
234 def new_issue_lft
230 def new_issue_lft
235 # ::AwesomeNestedSet::VERSION > "2.1.6" ? Issue.maximum(:rgt) + 1 : 1
231 # ::AwesomeNestedSet::VERSION > "2.1.6" ? Issue.maximum(:rgt) + 1 : 1
236 Issue.maximum(:rgt) + 1
232 Issue.maximum(:rgt) + 1
237 end
233 end
238 end
234 end
239
235
240 module Redmine
236 module Redmine
241 class RoutingTest < ActionDispatch::IntegrationTest
237 class RoutingTest < ActionDispatch::IntegrationTest
242 def should_route(arg)
238 def should_route(arg)
243 arg = arg.dup
239 arg = arg.dup
244 request = arg.keys.detect {|key| key.is_a?(String)}
240 request = arg.keys.detect {|key| key.is_a?(String)}
245 raise ArgumentError unless request
241 raise ArgumentError unless request
246 options = arg.slice!(request)
242 options = arg.slice!(request)
247
243
248 raise ArgumentError unless request =~ /\A(GET|POST|PUT|PATCH|DELETE)\s+(.+)\z/
244 raise ArgumentError unless request =~ /\A(GET|POST|PUT|PATCH|DELETE)\s+(.+)\z/
249 method, path = $1.downcase.to_sym, $2
245 method, path = $1.downcase.to_sym, $2
250
246
251 raise ArgumentError unless arg.values.first =~ /\A(.+)#(.+)\z/
247 raise ArgumentError unless arg.values.first =~ /\A(.+)#(.+)\z/
252 controller, action = $1, $2
248 controller, action = $1, $2
253
249
254 assert_routing(
250 assert_routing(
255 {:method => method, :path => path},
251 {:method => method, :path => path},
256 options.merge(:controller => controller, :action => action)
252 options.merge(:controller => controller, :action => action)
257 )
253 )
258 end
254 end
259 end
255 end
260
256
261 module ApiTest
257 module ApiTest
262 API_FORMATS = %w(json xml).freeze
258 API_FORMATS = %w(json xml).freeze
263
259
264 # Base class for API tests
260 # Base class for API tests
265 class Base < ActionDispatch::IntegrationTest
261 class Base < ActionDispatch::IntegrationTest
266 end
262 end
267
263
268 class Routing < Redmine::RoutingTest
264 class Routing < Redmine::RoutingTest
269 def should_route(arg)
265 def should_route(arg)
270 arg = arg.dup
266 arg = arg.dup
271 request = arg.keys.detect {|key| key.is_a?(String)}
267 request = arg.keys.detect {|key| key.is_a?(String)}
272 raise ArgumentError unless request
268 raise ArgumentError unless request
273 options = arg.slice!(request)
269 options = arg.slice!(request)
274
270
275 API_FORMATS.each do |format|
271 API_FORMATS.each do |format|
276 format_request = request.sub /$/, ".#{format}"
272 format_request = request.sub /$/, ".#{format}"
277 super options.merge(format_request => arg[request], :format => format)
273 super options.merge(format_request => arg[request], :format => format)
278 end
274 end
279 end
275 end
280 end
276 end
281 end
277 end
282 end
278 end
283
279
284 # URL helpers do not work with config.threadsafe!
280 # URL helpers do not work with config.threadsafe!
285 # https://github.com/rspec/rspec-rails/issues/476#issuecomment-4705454
281 # https://github.com/rspec/rspec-rails/issues/476#issuecomment-4705454
286 ActionView::TestCase::TestController.instance_eval do
282 ActionView::TestCase::TestController.instance_eval do
287 helper Rails.application.routes.url_helpers
283 helper Rails.application.routes.url_helpers
288 end
284 end
289 ActionView::TestCase::TestController.class_eval do
285 ActionView::TestCase::TestController.class_eval do
290 def _routes
286 def _routes
291 Rails.application.routes
287 Rails.application.routes
292 end
288 end
293 end
289 end
@@ -1,952 +1,952
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2014 Jean-Philippe Lang
4 # Copyright (C) 2006-2014 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 require File.expand_path('../../test_helper', __FILE__)
20 require File.expand_path('../../test_helper', __FILE__)
21
21
22 class MailHandlerTest < ActiveSupport::TestCase
22 class MailHandlerTest < ActiveSupport::TestCase
23 fixtures :users, :projects, :enabled_modules, :roles,
23 fixtures :users, :projects, :enabled_modules, :roles,
24 :members, :member_roles, :users,
24 :members, :member_roles, :users,
25 :issues, :issue_statuses,
25 :issues, :issue_statuses,
26 :workflows, :trackers, :projects_trackers,
26 :workflows, :trackers, :projects_trackers,
27 :versions, :enumerations, :issue_categories,
27 :versions, :enumerations, :issue_categories,
28 :custom_fields, :custom_fields_trackers, :custom_fields_projects,
28 :custom_fields, :custom_fields_trackers, :custom_fields_projects,
29 :boards, :messages
29 :boards, :messages
30
30
31 FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
31 FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
32
32
33 def setup
33 def setup
34 ActionMailer::Base.deliveries.clear
34 ActionMailer::Base.deliveries.clear
35 Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
35 Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
36 end
36 end
37
37
38 def teardown
38 def teardown
39 Setting.clear_cache
39 Setting.clear_cache
40 end
40 end
41
41
42 def test_add_issue
42 def test_add_issue
43 ActionMailer::Base.deliveries.clear
43 ActionMailer::Base.deliveries.clear
44 lft1 = new_issue_lft
44 lft1 = new_issue_lft
45 # This email contains: 'Project: onlinestore'
45 # This email contains: 'Project: onlinestore'
46 issue = submit_email('ticket_on_given_project.eml')
46 issue = submit_email('ticket_on_given_project.eml')
47 assert issue.is_a?(Issue)
47 assert issue.is_a?(Issue)
48 assert !issue.new_record?
48 assert !issue.new_record?
49 issue.reload
49 issue.reload
50 assert_equal Project.find(2), issue.project
50 assert_equal Project.find(2), issue.project
51 assert_equal issue.project.trackers.first, issue.tracker
51 assert_equal issue.project.trackers.first, issue.tracker
52 assert_equal 'New ticket on a given project', issue.subject
52 assert_equal 'New ticket on a given project', issue.subject
53 assert_equal User.find_by_login('jsmith'), issue.author
53 assert_equal User.find_by_login('jsmith'), issue.author
54 assert_equal IssueStatus.find_by_name('Resolved'), issue.status
54 assert_equal IssueStatus.find_by_name('Resolved'), issue.status
55 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
55 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
56 assert_equal '2010-01-01', issue.start_date.to_s
56 assert_equal '2010-01-01', issue.start_date.to_s
57 assert_equal '2010-12-31', issue.due_date.to_s
57 assert_equal '2010-12-31', issue.due_date.to_s
58 assert_equal User.find_by_login('jsmith'), issue.assigned_to
58 assert_equal User.find_by_login('jsmith'), issue.assigned_to
59 assert_equal Version.find_by_name('Alpha'), issue.fixed_version
59 assert_equal Version.find_by_name('Alpha'), issue.fixed_version
60 assert_equal 2.5, issue.estimated_hours
60 assert_equal 2.5, issue.estimated_hours
61 assert_equal 30, issue.done_ratio
61 assert_equal 30, issue.done_ratio
62 assert_equal [issue.id, lft1, lft1 + 1], [issue.root_id, issue.lft, issue.rgt]
62 assert_equal [issue.id, lft1, lft1 + 1], [issue.root_id, issue.lft, issue.rgt]
63 # keywords should be removed from the email body
63 # keywords should be removed from the email body
64 assert !issue.description.match(/^Project:/i)
64 assert !issue.description.match(/^Project:/i)
65 assert !issue.description.match(/^Status:/i)
65 assert !issue.description.match(/^Status:/i)
66 assert !issue.description.match(/^Start Date:/i)
66 assert !issue.description.match(/^Start Date:/i)
67 # Email notification should be sent
67 # Email notification should be sent
68 mail = ActionMailer::Base.deliveries.last
68 mail = ActionMailer::Base.deliveries.last
69 assert_not_nil mail
69 assert_not_nil mail
70 assert mail.subject.include?("##{issue.id}")
70 assert mail.subject.include?("##{issue.id}")
71 assert mail.subject.include?('New ticket on a given project')
71 assert mail.subject.include?('New ticket on a given project')
72 end
72 end
73
73
74 def test_add_issue_with_default_tracker
74 def test_add_issue_with_default_tracker
75 # This email contains: 'Project: onlinestore'
75 # This email contains: 'Project: onlinestore'
76 issue = submit_email(
76 issue = submit_email(
77 'ticket_on_given_project.eml',
77 'ticket_on_given_project.eml',
78 :issue => {:tracker => 'Support request'}
78 :issue => {:tracker => 'Support request'}
79 )
79 )
80 assert issue.is_a?(Issue)
80 assert issue.is_a?(Issue)
81 assert !issue.new_record?
81 assert !issue.new_record?
82 issue.reload
82 issue.reload
83 assert_equal 'Support request', issue.tracker.name
83 assert_equal 'Support request', issue.tracker.name
84 end
84 end
85
85
86 def test_add_issue_with_status
86 def test_add_issue_with_status
87 # This email contains: 'Project: onlinestore' and 'Status: Resolved'
87 # This email contains: 'Project: onlinestore' and 'Status: Resolved'
88 issue = submit_email('ticket_on_given_project.eml')
88 issue = submit_email('ticket_on_given_project.eml')
89 assert issue.is_a?(Issue)
89 assert issue.is_a?(Issue)
90 assert !issue.new_record?
90 assert !issue.new_record?
91 issue.reload
91 issue.reload
92 assert_equal Project.find(2), issue.project
92 assert_equal Project.find(2), issue.project
93 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
93 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
94 end
94 end
95
95
96 def test_add_issue_with_attributes_override
96 def test_add_issue_with_attributes_override
97 issue = submit_email(
97 issue = submit_email(
98 'ticket_with_attributes.eml',
98 'ticket_with_attributes.eml',
99 :allow_override => 'tracker,category,priority'
99 :allow_override => 'tracker,category,priority'
100 )
100 )
101 assert issue.is_a?(Issue)
101 assert issue.is_a?(Issue)
102 assert !issue.new_record?
102 assert !issue.new_record?
103 issue.reload
103 issue.reload
104 assert_equal 'New ticket on a given project', issue.subject
104 assert_equal 'New ticket on a given project', issue.subject
105 assert_equal User.find_by_login('jsmith'), issue.author
105 assert_equal User.find_by_login('jsmith'), issue.author
106 assert_equal Project.find(2), issue.project
106 assert_equal Project.find(2), issue.project
107 assert_equal 'Feature request', issue.tracker.to_s
107 assert_equal 'Feature request', issue.tracker.to_s
108 assert_equal 'Stock management', issue.category.to_s
108 assert_equal 'Stock management', issue.category.to_s
109 assert_equal 'Urgent', issue.priority.to_s
109 assert_equal 'Urgent', issue.priority.to_s
110 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
110 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
111 end
111 end
112
112
113 def test_add_issue_with_group_assignment
113 def test_add_issue_with_group_assignment
114 with_settings :issue_group_assignment => '1' do
114 with_settings :issue_group_assignment => '1' do
115 issue = submit_email('ticket_on_given_project.eml') do |email|
115 issue = submit_email('ticket_on_given_project.eml') do |email|
116 email.gsub!('Assigned to: John Smith', 'Assigned to: B Team')
116 email.gsub!('Assigned to: John Smith', 'Assigned to: B Team')
117 end
117 end
118 assert issue.is_a?(Issue)
118 assert issue.is_a?(Issue)
119 assert !issue.new_record?
119 assert !issue.new_record?
120 issue.reload
120 issue.reload
121 assert_equal Group.find(11), issue.assigned_to
121 assert_equal Group.find(11), issue.assigned_to
122 end
122 end
123 end
123 end
124
124
125 def test_add_issue_with_partial_attributes_override
125 def test_add_issue_with_partial_attributes_override
126 issue = submit_email(
126 issue = submit_email(
127 'ticket_with_attributes.eml',
127 'ticket_with_attributes.eml',
128 :issue => {:priority => 'High'},
128 :issue => {:priority => 'High'},
129 :allow_override => ['tracker']
129 :allow_override => ['tracker']
130 )
130 )
131 assert issue.is_a?(Issue)
131 assert issue.is_a?(Issue)
132 assert !issue.new_record?
132 assert !issue.new_record?
133 issue.reload
133 issue.reload
134 assert_equal 'New ticket on a given project', issue.subject
134 assert_equal 'New ticket on a given project', issue.subject
135 assert_equal User.find_by_login('jsmith'), issue.author
135 assert_equal User.find_by_login('jsmith'), issue.author
136 assert_equal Project.find(2), issue.project
136 assert_equal Project.find(2), issue.project
137 assert_equal 'Feature request', issue.tracker.to_s
137 assert_equal 'Feature request', issue.tracker.to_s
138 assert_nil issue.category
138 assert_nil issue.category
139 assert_equal 'High', issue.priority.to_s
139 assert_equal 'High', issue.priority.to_s
140 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
140 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
141 end
141 end
142
142
143 def test_add_issue_with_spaces_between_attribute_and_separator
143 def test_add_issue_with_spaces_between_attribute_and_separator
144 issue = submit_email(
144 issue = submit_email(
145 'ticket_with_spaces_between_attribute_and_separator.eml',
145 'ticket_with_spaces_between_attribute_and_separator.eml',
146 :allow_override => 'tracker,category,priority'
146 :allow_override => 'tracker,category,priority'
147 )
147 )
148 assert issue.is_a?(Issue)
148 assert issue.is_a?(Issue)
149 assert !issue.new_record?
149 assert !issue.new_record?
150 issue.reload
150 issue.reload
151 assert_equal 'New ticket on a given project', issue.subject
151 assert_equal 'New ticket on a given project', issue.subject
152 assert_equal User.find_by_login('jsmith'), issue.author
152 assert_equal User.find_by_login('jsmith'), issue.author
153 assert_equal Project.find(2), issue.project
153 assert_equal Project.find(2), issue.project
154 assert_equal 'Feature request', issue.tracker.to_s
154 assert_equal 'Feature request', issue.tracker.to_s
155 assert_equal 'Stock management', issue.category.to_s
155 assert_equal 'Stock management', issue.category.to_s
156 assert_equal 'Urgent', issue.priority.to_s
156 assert_equal 'Urgent', issue.priority.to_s
157 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
157 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
158 end
158 end
159
159
160 def test_add_issue_with_attachment_to_specific_project
160 def test_add_issue_with_attachment_to_specific_project
161 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
161 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
162 assert issue.is_a?(Issue)
162 assert issue.is_a?(Issue)
163 assert !issue.new_record?
163 assert !issue.new_record?
164 issue.reload
164 issue.reload
165 assert_equal 'Ticket created by email with attachment', issue.subject
165 assert_equal 'Ticket created by email with attachment', issue.subject
166 assert_equal User.find_by_login('jsmith'), issue.author
166 assert_equal User.find_by_login('jsmith'), issue.author
167 assert_equal Project.find(2), issue.project
167 assert_equal Project.find(2), issue.project
168 assert_equal 'This is a new ticket with attachments', issue.description
168 assert_equal 'This is a new ticket with attachments', issue.description
169 # Attachment properties
169 # Attachment properties
170 assert_equal 1, issue.attachments.size
170 assert_equal 1, issue.attachments.size
171 assert_equal 'Paella.jpg', issue.attachments.first.filename
171 assert_equal 'Paella.jpg', issue.attachments.first.filename
172 assert_equal 'image/jpeg', issue.attachments.first.content_type
172 assert_equal 'image/jpeg', issue.attachments.first.content_type
173 assert_equal 10790, issue.attachments.first.filesize
173 assert_equal 10790, issue.attachments.first.filesize
174 end
174 end
175
175
176 def test_add_issue_with_custom_fields
176 def test_add_issue_with_custom_fields
177 issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'onlinestore'})
177 issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'onlinestore'})
178 assert issue.is_a?(Issue)
178 assert issue.is_a?(Issue)
179 assert !issue.new_record?
179 assert !issue.new_record?
180 issue.reload
180 issue.reload
181 assert_equal 'New ticket with custom field values', issue.subject
181 assert_equal 'New ticket with custom field values', issue.subject
182 assert_equal 'PostgreSQL', issue.custom_field_value(1)
182 assert_equal 'PostgreSQL', issue.custom_field_value(1)
183 assert_equal 'Value for a custom field', issue.custom_field_value(2)
183 assert_equal 'Value for a custom field', issue.custom_field_value(2)
184 assert !issue.description.match(/^searchable field:/i)
184 assert !issue.description.match(/^searchable field:/i)
185 end
185 end
186
186
187 def test_add_issue_with_version_custom_fields
187 def test_add_issue_with_version_custom_fields
188 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3])
188 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3])
189
189
190 issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'ecookbook'}) do |email|
190 issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'ecookbook'}) do |email|
191 email << "Affected version: 1.0\n"
191 email << "Affected version: 1.0\n"
192 end
192 end
193 assert issue.is_a?(Issue)
193 assert issue.is_a?(Issue)
194 assert !issue.new_record?
194 assert !issue.new_record?
195 issue.reload
195 issue.reload
196 assert_equal '2', issue.custom_field_value(field)
196 assert_equal '2', issue.custom_field_value(field)
197 end
197 end
198
198
199 def test_add_issue_should_match_assignee_on_display_name
199 def test_add_issue_should_match_assignee_on_display_name
200 user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz')
200 user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz')
201 User.add_to_project(user, Project.find(2))
201 User.add_to_project(user, Project.find(2))
202 issue = submit_email('ticket_on_given_project.eml') do |email|
202 issue = submit_email('ticket_on_given_project.eml') do |email|
203 email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz')
203 email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz')
204 end
204 end
205 assert issue.is_a?(Issue)
205 assert issue.is_a?(Issue)
206 assert_equal user, issue.assigned_to
206 assert_equal user, issue.assigned_to
207 end
207 end
208
208
209 def test_add_issue_should_set_default_start_date
209 def test_add_issue_should_set_default_start_date
210 with_settings :default_issue_start_date_to_creation_date => '1' do
210 with_settings :default_issue_start_date_to_creation_date => '1' do
211 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
211 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
212 assert issue.is_a?(Issue)
212 assert issue.is_a?(Issue)
213 assert_equal Date.today, issue.start_date
213 assert_equal Date.today, issue.start_date
214 end
214 end
215 end
215 end
216
216
217 def test_add_issue_with_cc
217 def test_add_issue_with_cc
218 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
218 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
219 assert issue.is_a?(Issue)
219 assert issue.is_a?(Issue)
220 assert !issue.new_record?
220 assert !issue.new_record?
221 issue.reload
221 issue.reload
222 assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
222 assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
223 assert_equal 1, issue.watcher_user_ids.size
223 assert_equal 1, issue.watcher_user_ids.size
224 end
224 end
225
225
226 def test_add_issue_by_unknown_user
226 def test_add_issue_by_unknown_user
227 assert_no_difference 'User.count' do
227 assert_no_difference 'User.count' do
228 assert_equal false,
228 assert_equal false,
229 submit_email(
229 submit_email(
230 'ticket_by_unknown_user.eml',
230 'ticket_by_unknown_user.eml',
231 :issue => {:project => 'ecookbook'}
231 :issue => {:project => 'ecookbook'}
232 )
232 )
233 end
233 end
234 end
234 end
235
235
236 def test_add_issue_by_anonymous_user
236 def test_add_issue_by_anonymous_user
237 Role.anonymous.add_permission!(:add_issues)
237 Role.anonymous.add_permission!(:add_issues)
238 assert_no_difference 'User.count' do
238 assert_no_difference 'User.count' do
239 issue = submit_email(
239 issue = submit_email(
240 'ticket_by_unknown_user.eml',
240 'ticket_by_unknown_user.eml',
241 :issue => {:project => 'ecookbook'},
241 :issue => {:project => 'ecookbook'},
242 :unknown_user => 'accept'
242 :unknown_user => 'accept'
243 )
243 )
244 assert issue.is_a?(Issue)
244 assert issue.is_a?(Issue)
245 assert issue.author.anonymous?
245 assert issue.author.anonymous?
246 end
246 end
247 end
247 end
248
248
249 def test_add_issue_by_anonymous_user_with_no_from_address
249 def test_add_issue_by_anonymous_user_with_no_from_address
250 Role.anonymous.add_permission!(:add_issues)
250 Role.anonymous.add_permission!(:add_issues)
251 assert_no_difference 'User.count' do
251 assert_no_difference 'User.count' do
252 issue = submit_email(
252 issue = submit_email(
253 'ticket_by_empty_user.eml',
253 'ticket_by_empty_user.eml',
254 :issue => {:project => 'ecookbook'},
254 :issue => {:project => 'ecookbook'},
255 :unknown_user => 'accept'
255 :unknown_user => 'accept'
256 )
256 )
257 assert issue.is_a?(Issue)
257 assert issue.is_a?(Issue)
258 assert issue.author.anonymous?
258 assert issue.author.anonymous?
259 end
259 end
260 end
260 end
261
261
262 def test_add_issue_by_anonymous_user_on_private_project
262 def test_add_issue_by_anonymous_user_on_private_project
263 Role.anonymous.add_permission!(:add_issues)
263 Role.anonymous.add_permission!(:add_issues)
264 assert_no_difference 'User.count' do
264 assert_no_difference 'User.count' do
265 assert_no_difference 'Issue.count' do
265 assert_no_difference 'Issue.count' do
266 assert_equal false,
266 assert_equal false,
267 submit_email(
267 submit_email(
268 'ticket_by_unknown_user.eml',
268 'ticket_by_unknown_user.eml',
269 :issue => {:project => 'onlinestore'},
269 :issue => {:project => 'onlinestore'},
270 :unknown_user => 'accept'
270 :unknown_user => 'accept'
271 )
271 )
272 end
272 end
273 end
273 end
274 end
274 end
275
275
276 def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
276 def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
277 lft1 = new_issue_lft
277 lft1 = new_issue_lft
278 assert_no_difference 'User.count' do
278 assert_no_difference 'User.count' do
279 assert_difference 'Issue.count' do
279 assert_difference 'Issue.count' do
280 issue = submit_email(
280 issue = submit_email(
281 'ticket_by_unknown_user.eml',
281 'ticket_by_unknown_user.eml',
282 :issue => {:project => 'onlinestore'},
282 :issue => {:project => 'onlinestore'},
283 :no_permission_check => '1',
283 :no_permission_check => '1',
284 :unknown_user => 'accept'
284 :unknown_user => 'accept'
285 )
285 )
286 assert issue.is_a?(Issue)
286 assert issue.is_a?(Issue)
287 assert issue.author.anonymous?
287 assert issue.author.anonymous?
288 assert !issue.project.is_public?
288 assert !issue.project.is_public?
289 assert_equal [issue.id, lft1, lft1 + 1], [issue.root_id, issue.lft, issue.rgt]
289 assert_equal [issue.id, lft1, lft1 + 1], [issue.root_id, issue.lft, issue.rgt]
290 end
290 end
291 end
291 end
292 end
292 end
293
293
294 def test_add_issue_by_created_user
294 def test_add_issue_by_created_user
295 Setting.default_language = 'en'
295 Setting.default_language = 'en'
296 assert_difference 'User.count' do
296 assert_difference 'User.count' do
297 issue = submit_email(
297 issue = submit_email(
298 'ticket_by_unknown_user.eml',
298 'ticket_by_unknown_user.eml',
299 :issue => {:project => 'ecookbook'},
299 :issue => {:project => 'ecookbook'},
300 :unknown_user => 'create'
300 :unknown_user => 'create'
301 )
301 )
302 assert issue.is_a?(Issue)
302 assert issue.is_a?(Issue)
303 assert issue.author.active?
303 assert issue.author.active?
304 assert_equal 'john.doe@somenet.foo', issue.author.mail
304 assert_equal 'john.doe@somenet.foo', issue.author.mail
305 assert_equal 'John', issue.author.firstname
305 assert_equal 'John', issue.author.firstname
306 assert_equal 'Doe', issue.author.lastname
306 assert_equal 'Doe', issue.author.lastname
307
307
308 # account information
308 # account information
309 email = ActionMailer::Base.deliveries.first
309 email = ActionMailer::Base.deliveries.first
310 assert_not_nil email
310 assert_not_nil email
311 assert email.subject.include?('account activation')
311 assert email.subject.include?('account activation')
312 login = mail_body(email).match(/\* Login: (.*)$/)[1].strip
312 login = mail_body(email).match(/\* Login: (.*)$/)[1].strip
313 password = mail_body(email).match(/\* Password: (.*)$/)[1].strip
313 password = mail_body(email).match(/\* Password: (.*)$/)[1].strip
314 assert_equal issue.author, User.try_to_login(login, password)
314 assert_equal issue.author, User.try_to_login(login, password)
315 end
315 end
316 end
316 end
317
317
318 def test_created_user_should_be_added_to_groups
318 def test_created_user_should_be_added_to_groups
319 group1 = Group.generate!
319 group1 = Group.generate!
320 group2 = Group.generate!
320 group2 = Group.generate!
321
321
322 assert_difference 'User.count' do
322 assert_difference 'User.count' do
323 submit_email(
323 submit_email(
324 'ticket_by_unknown_user.eml',
324 'ticket_by_unknown_user.eml',
325 :issue => {:project => 'ecookbook'},
325 :issue => {:project => 'ecookbook'},
326 :unknown_user => 'create',
326 :unknown_user => 'create',
327 :default_group => "#{group1.name},#{group2.name}"
327 :default_group => "#{group1.name},#{group2.name}"
328 )
328 )
329 end
329 end
330 user = User.order('id DESC').first
330 user = User.order('id DESC').first
331 assert_same_elements [group1, group2], user.groups
331 assert_equal [group1, group2].sort, user.groups.sort
332 end
332 end
333
333
334 def test_created_user_should_not_receive_account_information_with_no_account_info_option
334 def test_created_user_should_not_receive_account_information_with_no_account_info_option
335 assert_difference 'User.count' do
335 assert_difference 'User.count' do
336 submit_email(
336 submit_email(
337 'ticket_by_unknown_user.eml',
337 'ticket_by_unknown_user.eml',
338 :issue => {:project => 'ecookbook'},
338 :issue => {:project => 'ecookbook'},
339 :unknown_user => 'create',
339 :unknown_user => 'create',
340 :no_account_notice => '1'
340 :no_account_notice => '1'
341 )
341 )
342 end
342 end
343
343
344 # only 1 email for the new issue notification
344 # only 1 email for the new issue notification
345 assert_equal 1, ActionMailer::Base.deliveries.size
345 assert_equal 1, ActionMailer::Base.deliveries.size
346 email = ActionMailer::Base.deliveries.first
346 email = ActionMailer::Base.deliveries.first
347 assert_include 'Ticket by unknown user', email.subject
347 assert_include 'Ticket by unknown user', email.subject
348 end
348 end
349
349
350 def test_created_user_should_have_mail_notification_to_none_with_no_notification_option
350 def test_created_user_should_have_mail_notification_to_none_with_no_notification_option
351 assert_difference 'User.count' do
351 assert_difference 'User.count' do
352 submit_email(
352 submit_email(
353 'ticket_by_unknown_user.eml',
353 'ticket_by_unknown_user.eml',
354 :issue => {:project => 'ecookbook'},
354 :issue => {:project => 'ecookbook'},
355 :unknown_user => 'create',
355 :unknown_user => 'create',
356 :no_notification => '1'
356 :no_notification => '1'
357 )
357 )
358 end
358 end
359 user = User.order('id DESC').first
359 user = User.order('id DESC').first
360 assert_equal 'none', user.mail_notification
360 assert_equal 'none', user.mail_notification
361 end
361 end
362
362
363 def test_add_issue_without_from_header
363 def test_add_issue_without_from_header
364 Role.anonymous.add_permission!(:add_issues)
364 Role.anonymous.add_permission!(:add_issues)
365 assert_equal false, submit_email('ticket_without_from_header.eml')
365 assert_equal false, submit_email('ticket_without_from_header.eml')
366 end
366 end
367
367
368 def test_add_issue_with_invalid_attributes
368 def test_add_issue_with_invalid_attributes
369 with_settings :default_issue_start_date_to_creation_date => '0' do
369 with_settings :default_issue_start_date_to_creation_date => '0' do
370 issue = submit_email(
370 issue = submit_email(
371 'ticket_with_invalid_attributes.eml',
371 'ticket_with_invalid_attributes.eml',
372 :allow_override => 'tracker,category,priority'
372 :allow_override => 'tracker,category,priority'
373 )
373 )
374 assert issue.is_a?(Issue)
374 assert issue.is_a?(Issue)
375 assert !issue.new_record?
375 assert !issue.new_record?
376 issue.reload
376 issue.reload
377 assert_nil issue.assigned_to
377 assert_nil issue.assigned_to
378 assert_nil issue.start_date
378 assert_nil issue.start_date
379 assert_nil issue.due_date
379 assert_nil issue.due_date
380 assert_equal 0, issue.done_ratio
380 assert_equal 0, issue.done_ratio
381 assert_equal 'Normal', issue.priority.to_s
381 assert_equal 'Normal', issue.priority.to_s
382 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
382 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
383 end
383 end
384 end
384 end
385
385
386 def test_add_issue_with_invalid_project_should_be_assigned_to_default_project
386 def test_add_issue_with_invalid_project_should_be_assigned_to_default_project
387 issue = submit_email('ticket_on_given_project.eml', :issue => {:project => 'ecookbook'}, :allow_override => 'project') do |email|
387 issue = submit_email('ticket_on_given_project.eml', :issue => {:project => 'ecookbook'}, :allow_override => 'project') do |email|
388 email.gsub!(/^Project:.+$/, 'Project: invalid')
388 email.gsub!(/^Project:.+$/, 'Project: invalid')
389 end
389 end
390 assert issue.is_a?(Issue)
390 assert issue.is_a?(Issue)
391 assert !issue.new_record?
391 assert !issue.new_record?
392 assert_equal 'ecookbook', issue.project.identifier
392 assert_equal 'ecookbook', issue.project.identifier
393 end
393 end
394
394
395 def test_add_issue_with_localized_attributes
395 def test_add_issue_with_localized_attributes
396 User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
396 User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
397 issue = submit_email(
397 issue = submit_email(
398 'ticket_with_localized_attributes.eml',
398 'ticket_with_localized_attributes.eml',
399 :allow_override => 'tracker,category,priority'
399 :allow_override => 'tracker,category,priority'
400 )
400 )
401 assert issue.is_a?(Issue)
401 assert issue.is_a?(Issue)
402 assert !issue.new_record?
402 assert !issue.new_record?
403 issue.reload
403 issue.reload
404 assert_equal 'New ticket on a given project', issue.subject
404 assert_equal 'New ticket on a given project', issue.subject
405 assert_equal User.find_by_login('jsmith'), issue.author
405 assert_equal User.find_by_login('jsmith'), issue.author
406 assert_equal Project.find(2), issue.project
406 assert_equal Project.find(2), issue.project
407 assert_equal 'Feature request', issue.tracker.to_s
407 assert_equal 'Feature request', issue.tracker.to_s
408 assert_equal 'Stock management', issue.category.to_s
408 assert_equal 'Stock management', issue.category.to_s
409 assert_equal 'Urgent', issue.priority.to_s
409 assert_equal 'Urgent', issue.priority.to_s
410 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
410 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
411 end
411 end
412
412
413 def test_add_issue_with_japanese_keywords
413 def test_add_issue_with_japanese_keywords
414 ja_dev = "\xe9\x96\x8b\xe7\x99\xba".force_encoding('UTF-8')
414 ja_dev = "\xe9\x96\x8b\xe7\x99\xba".force_encoding('UTF-8')
415 tracker = Tracker.generate!(:name => ja_dev)
415 tracker = Tracker.generate!(:name => ja_dev)
416 Project.find(1).trackers << tracker
416 Project.find(1).trackers << tracker
417 issue = submit_email(
417 issue = submit_email(
418 'japanese_keywords_iso_2022_jp.eml',
418 'japanese_keywords_iso_2022_jp.eml',
419 :issue => {:project => 'ecookbook'},
419 :issue => {:project => 'ecookbook'},
420 :allow_override => 'tracker'
420 :allow_override => 'tracker'
421 )
421 )
422 assert_kind_of Issue, issue
422 assert_kind_of Issue, issue
423 assert_equal tracker, issue.tracker
423 assert_equal tracker, issue.tracker
424 end
424 end
425
425
426 def test_add_issue_from_apple_mail
426 def test_add_issue_from_apple_mail
427 issue = submit_email(
427 issue = submit_email(
428 'apple_mail_with_attachment.eml',
428 'apple_mail_with_attachment.eml',
429 :issue => {:project => 'ecookbook'}
429 :issue => {:project => 'ecookbook'}
430 )
430 )
431 assert_kind_of Issue, issue
431 assert_kind_of Issue, issue
432 assert_equal 1, issue.attachments.size
432 assert_equal 1, issue.attachments.size
433
433
434 attachment = issue.attachments.first
434 attachment = issue.attachments.first
435 assert_equal 'paella.jpg', attachment.filename
435 assert_equal 'paella.jpg', attachment.filename
436 assert_equal 10790, attachment.filesize
436 assert_equal 10790, attachment.filesize
437 assert File.exist?(attachment.diskfile)
437 assert File.exist?(attachment.diskfile)
438 assert_equal 10790, File.size(attachment.diskfile)
438 assert_equal 10790, File.size(attachment.diskfile)
439 assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest
439 assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest
440 end
440 end
441
441
442 def test_thunderbird_with_attachment_ja
442 def test_thunderbird_with_attachment_ja
443 issue = submit_email(
443 issue = submit_email(
444 'thunderbird_with_attachment_ja.eml',
444 'thunderbird_with_attachment_ja.eml',
445 :issue => {:project => 'ecookbook'}
445 :issue => {:project => 'ecookbook'}
446 )
446 )
447 assert_kind_of Issue, issue
447 assert_kind_of Issue, issue
448 assert_equal 1, issue.attachments.size
448 assert_equal 1, issue.attachments.size
449 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
449 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
450 attachment = issue.attachments.first
450 attachment = issue.attachments.first
451 assert_equal ja, attachment.filename
451 assert_equal ja, attachment.filename
452 assert_equal 5, attachment.filesize
452 assert_equal 5, attachment.filesize
453 assert File.exist?(attachment.diskfile)
453 assert File.exist?(attachment.diskfile)
454 assert_equal 5, File.size(attachment.diskfile)
454 assert_equal 5, File.size(attachment.diskfile)
455 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
455 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
456 end
456 end
457
457
458 def test_gmail_with_attachment_ja
458 def test_gmail_with_attachment_ja
459 issue = submit_email(
459 issue = submit_email(
460 'gmail_with_attachment_ja.eml',
460 'gmail_with_attachment_ja.eml',
461 :issue => {:project => 'ecookbook'}
461 :issue => {:project => 'ecookbook'}
462 )
462 )
463 assert_kind_of Issue, issue
463 assert_kind_of Issue, issue
464 assert_equal 1, issue.attachments.size
464 assert_equal 1, issue.attachments.size
465 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
465 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
466 attachment = issue.attachments.first
466 attachment = issue.attachments.first
467 assert_equal ja, attachment.filename
467 assert_equal ja, attachment.filename
468 assert_equal 5, attachment.filesize
468 assert_equal 5, attachment.filesize
469 assert File.exist?(attachment.diskfile)
469 assert File.exist?(attachment.diskfile)
470 assert_equal 5, File.size(attachment.diskfile)
470 assert_equal 5, File.size(attachment.diskfile)
471 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
471 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
472 end
472 end
473
473
474 def test_thunderbird_with_attachment_latin1
474 def test_thunderbird_with_attachment_latin1
475 issue = submit_email(
475 issue = submit_email(
476 'thunderbird_with_attachment_iso-8859-1.eml',
476 'thunderbird_with_attachment_iso-8859-1.eml',
477 :issue => {:project => 'ecookbook'}
477 :issue => {:project => 'ecookbook'}
478 )
478 )
479 assert_kind_of Issue, issue
479 assert_kind_of Issue, issue
480 assert_equal 1, issue.attachments.size
480 assert_equal 1, issue.attachments.size
481 u = "".force_encoding('UTF-8')
481 u = "".force_encoding('UTF-8')
482 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
482 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
483 11.times { u << u1 }
483 11.times { u << u1 }
484 attachment = issue.attachments.first
484 attachment = issue.attachments.first
485 assert_equal "#{u}.png", attachment.filename
485 assert_equal "#{u}.png", attachment.filename
486 assert_equal 130, attachment.filesize
486 assert_equal 130, attachment.filesize
487 assert File.exist?(attachment.diskfile)
487 assert File.exist?(attachment.diskfile)
488 assert_equal 130, File.size(attachment.diskfile)
488 assert_equal 130, File.size(attachment.diskfile)
489 assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest
489 assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest
490 end
490 end
491
491
492 def test_gmail_with_attachment_latin1
492 def test_gmail_with_attachment_latin1
493 issue = submit_email(
493 issue = submit_email(
494 'gmail_with_attachment_iso-8859-1.eml',
494 'gmail_with_attachment_iso-8859-1.eml',
495 :issue => {:project => 'ecookbook'}
495 :issue => {:project => 'ecookbook'}
496 )
496 )
497 assert_kind_of Issue, issue
497 assert_kind_of Issue, issue
498 assert_equal 1, issue.attachments.size
498 assert_equal 1, issue.attachments.size
499 u = "".force_encoding('UTF-8')
499 u = "".force_encoding('UTF-8')
500 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
500 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
501 11.times { u << u1 }
501 11.times { u << u1 }
502 attachment = issue.attachments.first
502 attachment = issue.attachments.first
503 assert_equal "#{u}.txt", attachment.filename
503 assert_equal "#{u}.txt", attachment.filename
504 assert_equal 5, attachment.filesize
504 assert_equal 5, attachment.filesize
505 assert File.exist?(attachment.diskfile)
505 assert File.exist?(attachment.diskfile)
506 assert_equal 5, File.size(attachment.diskfile)
506 assert_equal 5, File.size(attachment.diskfile)
507 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
507 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
508 end
508 end
509
509
510 def test_multiple_inline_text_parts_should_be_appended_to_issue_description
510 def test_multiple_inline_text_parts_should_be_appended_to_issue_description
511 issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
511 issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
512 assert_include 'first', issue.description
512 assert_include 'first', issue.description
513 assert_include 'second', issue.description
513 assert_include 'second', issue.description
514 assert_include 'third', issue.description
514 assert_include 'third', issue.description
515 end
515 end
516
516
517 def test_attachment_text_part_should_be_added_as_issue_attachment
517 def test_attachment_text_part_should_be_added_as_issue_attachment
518 issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
518 issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
519 assert_not_include 'Plain text attachment', issue.description
519 assert_not_include 'Plain text attachment', issue.description
520 attachment = issue.attachments.detect {|a| a.filename == 'textfile.txt'}
520 attachment = issue.attachments.detect {|a| a.filename == 'textfile.txt'}
521 assert_not_nil attachment
521 assert_not_nil attachment
522 assert_include 'Plain text attachment', File.read(attachment.diskfile)
522 assert_include 'Plain text attachment', File.read(attachment.diskfile)
523 end
523 end
524
524
525 def test_add_issue_with_iso_8859_1_subject
525 def test_add_issue_with_iso_8859_1_subject
526 issue = submit_email(
526 issue = submit_email(
527 'subject_as_iso-8859-1.eml',
527 'subject_as_iso-8859-1.eml',
528 :issue => {:project => 'ecookbook'}
528 :issue => {:project => 'ecookbook'}
529 )
529 )
530 str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc...".force_encoding('UTF-8')
530 str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc...".force_encoding('UTF-8')
531 assert_kind_of Issue, issue
531 assert_kind_of Issue, issue
532 assert_equal str, issue.subject
532 assert_equal str, issue.subject
533 end
533 end
534
534
535 def test_quoted_printable_utf8
535 def test_quoted_printable_utf8
536 issue = submit_email(
536 issue = submit_email(
537 'quoted_printable_utf8.eml',
537 'quoted_printable_utf8.eml',
538 :issue => {:project => 'ecookbook'}
538 :issue => {:project => 'ecookbook'}
539 )
539 )
540 assert_kind_of Issue, issue
540 assert_kind_of Issue, issue
541 str = "Freundliche Gr\xc3\xbcsse".force_encoding('UTF-8')
541 str = "Freundliche Gr\xc3\xbcsse".force_encoding('UTF-8')
542 assert_equal str, issue.description
542 assert_equal str, issue.description
543 end
543 end
544
544
545 def test_gmail_iso8859_2
545 def test_gmail_iso8859_2
546 issue = submit_email(
546 issue = submit_email(
547 'gmail-iso8859-2.eml',
547 'gmail-iso8859-2.eml',
548 :issue => {:project => 'ecookbook'}
548 :issue => {:project => 'ecookbook'}
549 )
549 )
550 assert_kind_of Issue, issue
550 assert_kind_of Issue, issue
551 str = "Na \xc5\xa1triku se su\xc5\xa1i \xc5\xa1osi\xc4\x87.".force_encoding('UTF-8')
551 str = "Na \xc5\xa1triku se su\xc5\xa1i \xc5\xa1osi\xc4\x87.".force_encoding('UTF-8')
552 assert issue.description.include?(str)
552 assert issue.description.include?(str)
553 end
553 end
554
554
555 def test_add_issue_with_japanese_subject
555 def test_add_issue_with_japanese_subject
556 issue = submit_email(
556 issue = submit_email(
557 'subject_japanese_1.eml',
557 'subject_japanese_1.eml',
558 :issue => {:project => 'ecookbook'}
558 :issue => {:project => 'ecookbook'}
559 )
559 )
560 assert_kind_of Issue, issue
560 assert_kind_of Issue, issue
561 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
561 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
562 assert_equal ja, issue.subject
562 assert_equal ja, issue.subject
563 end
563 end
564
564
565 def test_add_issue_with_korean_body
565 def test_add_issue_with_korean_body
566 # Make sure mail bodies with a charset unknown to Ruby
566 # Make sure mail bodies with a charset unknown to Ruby
567 # but known to the Mail gem 2.5.4 are handled correctly
567 # but known to the Mail gem 2.5.4 are handled correctly
568 kr = "\xEA\xB3\xA0\xEB\xA7\x99\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4.".force_encoding('UTF-8')
568 kr = "\xEA\xB3\xA0\xEB\xA7\x99\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4.".force_encoding('UTF-8')
569 issue = submit_email(
569 issue = submit_email(
570 'body_ks_c_5601-1987.eml',
570 'body_ks_c_5601-1987.eml',
571 :issue => {:project => 'ecookbook'}
571 :issue => {:project => 'ecookbook'}
572 )
572 )
573 assert_kind_of Issue, issue
573 assert_kind_of Issue, issue
574 assert_equal kr, issue.description
574 assert_equal kr, issue.description
575 end
575 end
576
576
577 def test_add_issue_with_no_subject_header
577 def test_add_issue_with_no_subject_header
578 issue = submit_email(
578 issue = submit_email(
579 'no_subject_header.eml',
579 'no_subject_header.eml',
580 :issue => {:project => 'ecookbook'}
580 :issue => {:project => 'ecookbook'}
581 )
581 )
582 assert_kind_of Issue, issue
582 assert_kind_of Issue, issue
583 assert_equal '(no subject)', issue.subject
583 assert_equal '(no subject)', issue.subject
584 end
584 end
585
585
586 def test_add_issue_with_mixed_japanese_subject
586 def test_add_issue_with_mixed_japanese_subject
587 issue = submit_email(
587 issue = submit_email(
588 'subject_japanese_2.eml',
588 'subject_japanese_2.eml',
589 :issue => {:project => 'ecookbook'}
589 :issue => {:project => 'ecookbook'}
590 )
590 )
591 assert_kind_of Issue, issue
591 assert_kind_of Issue, issue
592 ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
592 ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
593 assert_equal ja, issue.subject
593 assert_equal ja, issue.subject
594 end
594 end
595
595
596 def test_should_ignore_emails_from_locked_users
596 def test_should_ignore_emails_from_locked_users
597 User.find(2).lock!
597 User.find(2).lock!
598
598
599 MailHandler.any_instance.expects(:dispatch).never
599 MailHandler.any_instance.expects(:dispatch).never
600 assert_no_difference 'Issue.count' do
600 assert_no_difference 'Issue.count' do
601 assert_equal false, submit_email('ticket_on_given_project.eml')
601 assert_equal false, submit_email('ticket_on_given_project.eml')
602 end
602 end
603 end
603 end
604
604
605 def test_should_ignore_emails_from_emission_address
605 def test_should_ignore_emails_from_emission_address
606 Role.anonymous.add_permission!(:add_issues)
606 Role.anonymous.add_permission!(:add_issues)
607 assert_no_difference 'User.count' do
607 assert_no_difference 'User.count' do
608 assert_equal false,
608 assert_equal false,
609 submit_email(
609 submit_email(
610 'ticket_from_emission_address.eml',
610 'ticket_from_emission_address.eml',
611 :issue => {:project => 'ecookbook'},
611 :issue => {:project => 'ecookbook'},
612 :unknown_user => 'create'
612 :unknown_user => 'create'
613 )
613 )
614 end
614 end
615 end
615 end
616
616
617 def test_should_ignore_auto_replied_emails
617 def test_should_ignore_auto_replied_emails
618 MailHandler.any_instance.expects(:dispatch).never
618 MailHandler.any_instance.expects(:dispatch).never
619 [
619 [
620 "X-Auto-Response-Suppress: OOF",
620 "X-Auto-Response-Suppress: OOF",
621 "Auto-Submitted: auto-replied",
621 "Auto-Submitted: auto-replied",
622 "Auto-Submitted: Auto-Replied",
622 "Auto-Submitted: Auto-Replied",
623 "Auto-Submitted: auto-generated"
623 "Auto-Submitted: auto-generated"
624 ].each do |header|
624 ].each do |header|
625 raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
625 raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
626 raw = header + "\n" + raw
626 raw = header + "\n" + raw
627
627
628 assert_no_difference 'Issue.count' do
628 assert_no_difference 'Issue.count' do
629 assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
629 assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
630 end
630 end
631 end
631 end
632 end
632 end
633
633
634 test "should not ignore Auto-Submitted headers not defined in RFC3834" do
634 test "should not ignore Auto-Submitted headers not defined in RFC3834" do
635 [
635 [
636 "Auto-Submitted: auto-forwarded"
636 "Auto-Submitted: auto-forwarded"
637 ].each do |header|
637 ].each do |header|
638 raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
638 raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
639 raw = header + "\n" + raw
639 raw = header + "\n" + raw
640
640
641 assert_difference 'Issue.count', 1 do
641 assert_difference 'Issue.count', 1 do
642 assert_not_nil MailHandler.receive(raw), "email with #{header} header was ignored"
642 assert_not_nil MailHandler.receive(raw), "email with #{header} header was ignored"
643 end
643 end
644 end
644 end
645 end
645 end
646
646
647 def test_add_issue_should_send_email_notification
647 def test_add_issue_should_send_email_notification
648 Setting.notified_events = ['issue_added']
648 Setting.notified_events = ['issue_added']
649 ActionMailer::Base.deliveries.clear
649 ActionMailer::Base.deliveries.clear
650 # This email contains: 'Project: onlinestore'
650 # This email contains: 'Project: onlinestore'
651 issue = submit_email('ticket_on_given_project.eml')
651 issue = submit_email('ticket_on_given_project.eml')
652 assert issue.is_a?(Issue)
652 assert issue.is_a?(Issue)
653 assert_equal 1, ActionMailer::Base.deliveries.size
653 assert_equal 1, ActionMailer::Base.deliveries.size
654 end
654 end
655
655
656 def test_update_issue
656 def test_update_issue
657 journal = submit_email('ticket_reply.eml')
657 journal = submit_email('ticket_reply.eml')
658 assert journal.is_a?(Journal)
658 assert journal.is_a?(Journal)
659 assert_equal User.find_by_login('jsmith'), journal.user
659 assert_equal User.find_by_login('jsmith'), journal.user
660 assert_equal Issue.find(2), journal.journalized
660 assert_equal Issue.find(2), journal.journalized
661 assert_match /This is reply/, journal.notes
661 assert_match /This is reply/, journal.notes
662 assert_equal false, journal.private_notes
662 assert_equal false, journal.private_notes
663 assert_equal 'Feature request', journal.issue.tracker.name
663 assert_equal 'Feature request', journal.issue.tracker.name
664 end
664 end
665
665
666 def test_update_issue_should_accept_issue_id_after_space_inside_brackets
666 def test_update_issue_should_accept_issue_id_after_space_inside_brackets
667 journal = submit_email('ticket_reply_with_status.eml') do |email|
667 journal = submit_email('ticket_reply_with_status.eml') do |email|
668 assert email.sub!(/^Subject:.*$/, "Subject: Re: [Feature request #2] Add ingredients categories")
668 assert email.sub!(/^Subject:.*$/, "Subject: Re: [Feature request #2] Add ingredients categories")
669 end
669 end
670 assert journal.is_a?(Journal)
670 assert journal.is_a?(Journal)
671 assert_equal Issue.find(2), journal.journalized
671 assert_equal Issue.find(2), journal.journalized
672 end
672 end
673
673
674 def test_update_issue_should_accept_issue_id_inside_brackets
674 def test_update_issue_should_accept_issue_id_inside_brackets
675 journal = submit_email('ticket_reply_with_status.eml') do |email|
675 journal = submit_email('ticket_reply_with_status.eml') do |email|
676 assert email.sub!(/^Subject:.*$/, "Subject: Re: [#2] Add ingredients categories")
676 assert email.sub!(/^Subject:.*$/, "Subject: Re: [#2] Add ingredients categories")
677 end
677 end
678 assert journal.is_a?(Journal)
678 assert journal.is_a?(Journal)
679 assert_equal Issue.find(2), journal.journalized
679 assert_equal Issue.find(2), journal.journalized
680 end
680 end
681
681
682 def test_update_issue_should_ignore_bogus_issue_ids_in_subject
682 def test_update_issue_should_ignore_bogus_issue_ids_in_subject
683 journal = submit_email('ticket_reply_with_status.eml') do |email|
683 journal = submit_email('ticket_reply_with_status.eml') do |email|
684 assert email.sub!(/^Subject:.*$/, "Subject: Re: [12345#1][bogus#1][Feature request #2] Add ingredients categories")
684 assert email.sub!(/^Subject:.*$/, "Subject: Re: [12345#1][bogus#1][Feature request #2] Add ingredients categories")
685 end
685 end
686 assert journal.is_a?(Journal)
686 assert journal.is_a?(Journal)
687 assert_equal Issue.find(2), journal.journalized
687 assert_equal Issue.find(2), journal.journalized
688 end
688 end
689
689
690 def test_update_issue_with_attribute_changes
690 def test_update_issue_with_attribute_changes
691 # This email contains: 'Status: Resolved'
691 # This email contains: 'Status: Resolved'
692 journal = submit_email('ticket_reply_with_status.eml')
692 journal = submit_email('ticket_reply_with_status.eml')
693 assert journal.is_a?(Journal)
693 assert journal.is_a?(Journal)
694 issue = Issue.find(journal.issue.id)
694 issue = Issue.find(journal.issue.id)
695 assert_equal User.find_by_login('jsmith'), journal.user
695 assert_equal User.find_by_login('jsmith'), journal.user
696 assert_equal Issue.find(2), journal.journalized
696 assert_equal Issue.find(2), journal.journalized
697 assert_match /This is reply/, journal.notes
697 assert_match /This is reply/, journal.notes
698 assert_equal 'Feature request', journal.issue.tracker.name
698 assert_equal 'Feature request', journal.issue.tracker.name
699 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
699 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
700 assert_equal '2010-01-01', issue.start_date.to_s
700 assert_equal '2010-01-01', issue.start_date.to_s
701 assert_equal '2010-12-31', issue.due_date.to_s
701 assert_equal '2010-12-31', issue.due_date.to_s
702 assert_equal User.find_by_login('jsmith'), issue.assigned_to
702 assert_equal User.find_by_login('jsmith'), issue.assigned_to
703 assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value
703 assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value
704 # keywords should be removed from the email body
704 # keywords should be removed from the email body
705 assert !journal.notes.match(/^Status:/i)
705 assert !journal.notes.match(/^Status:/i)
706 assert !journal.notes.match(/^Start Date:/i)
706 assert !journal.notes.match(/^Start Date:/i)
707 end
707 end
708
708
709 def test_update_issue_with_attachment
709 def test_update_issue_with_attachment
710 assert_difference 'Journal.count' do
710 assert_difference 'Journal.count' do
711 assert_difference 'JournalDetail.count' do
711 assert_difference 'JournalDetail.count' do
712 assert_difference 'Attachment.count' do
712 assert_difference 'Attachment.count' do
713 assert_no_difference 'Issue.count' do
713 assert_no_difference 'Issue.count' do
714 journal = submit_email('ticket_with_attachment.eml') do |raw|
714 journal = submit_email('ticket_with_attachment.eml') do |raw|
715 raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories'
715 raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories'
716 end
716 end
717 end
717 end
718 end
718 end
719 end
719 end
720 end
720 end
721 journal = Journal.order('id DESC').first
721 journal = Journal.order('id DESC').first
722 assert_equal Issue.find(2), journal.journalized
722 assert_equal Issue.find(2), journal.journalized
723 assert_equal 1, journal.details.size
723 assert_equal 1, journal.details.size
724
724
725 detail = journal.details.first
725 detail = journal.details.first
726 assert_equal 'attachment', detail.property
726 assert_equal 'attachment', detail.property
727 assert_equal 'Paella.jpg', detail.value
727 assert_equal 'Paella.jpg', detail.value
728 end
728 end
729
729
730 def test_update_issue_should_send_email_notification
730 def test_update_issue_should_send_email_notification
731 ActionMailer::Base.deliveries.clear
731 ActionMailer::Base.deliveries.clear
732 journal = submit_email('ticket_reply.eml')
732 journal = submit_email('ticket_reply.eml')
733 assert journal.is_a?(Journal)
733 assert journal.is_a?(Journal)
734 assert_equal 1, ActionMailer::Base.deliveries.size
734 assert_equal 1, ActionMailer::Base.deliveries.size
735 end
735 end
736
736
737 def test_update_issue_should_not_set_defaults
737 def test_update_issue_should_not_set_defaults
738 journal = submit_email(
738 journal = submit_email(
739 'ticket_reply.eml',
739 'ticket_reply.eml',
740 :issue => {:tracker => 'Support request', :priority => 'High'}
740 :issue => {:tracker => 'Support request', :priority => 'High'}
741 )
741 )
742 assert journal.is_a?(Journal)
742 assert journal.is_a?(Journal)
743 assert_match /This is reply/, journal.notes
743 assert_match /This is reply/, journal.notes
744 assert_equal 'Feature request', journal.issue.tracker.name
744 assert_equal 'Feature request', journal.issue.tracker.name
745 assert_equal 'Normal', journal.issue.priority.name
745 assert_equal 'Normal', journal.issue.priority.name
746 end
746 end
747
747
748 def test_replying_to_a_private_note_should_add_reply_as_private
748 def test_replying_to_a_private_note_should_add_reply_as_private
749 private_journal = Journal.create!(:notes => 'Private notes', :journalized => Issue.find(1), :private_notes => true, :user_id => 2)
749 private_journal = Journal.create!(:notes => 'Private notes', :journalized => Issue.find(1), :private_notes => true, :user_id => 2)
750
750
751 assert_difference 'Journal.count' do
751 assert_difference 'Journal.count' do
752 journal = submit_email('ticket_reply.eml') do |email|
752 journal = submit_email('ticket_reply.eml') do |email|
753 email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>"
753 email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>"
754 end
754 end
755
755
756 assert_kind_of Journal, journal
756 assert_kind_of Journal, journal
757 assert_match /This is reply/, journal.notes
757 assert_match /This is reply/, journal.notes
758 assert_equal true, journal.private_notes
758 assert_equal true, journal.private_notes
759 end
759 end
760 end
760 end
761
761
762 def test_reply_to_a_message
762 def test_reply_to_a_message
763 m = submit_email('message_reply.eml')
763 m = submit_email('message_reply.eml')
764 assert m.is_a?(Message)
764 assert m.is_a?(Message)
765 assert !m.new_record?
765 assert !m.new_record?
766 m.reload
766 m.reload
767 assert_equal 'Reply via email', m.subject
767 assert_equal 'Reply via email', m.subject
768 # The email replies to message #2 which is part of the thread of message #1
768 # The email replies to message #2 which is part of the thread of message #1
769 assert_equal Message.find(1), m.parent
769 assert_equal Message.find(1), m.parent
770 end
770 end
771
771
772 def test_reply_to_a_message_by_subject
772 def test_reply_to_a_message_by_subject
773 m = submit_email('message_reply_by_subject.eml')
773 m = submit_email('message_reply_by_subject.eml')
774 assert m.is_a?(Message)
774 assert m.is_a?(Message)
775 assert !m.new_record?
775 assert !m.new_record?
776 m.reload
776 m.reload
777 assert_equal 'Reply to the first post', m.subject
777 assert_equal 'Reply to the first post', m.subject
778 assert_equal Message.find(1), m.parent
778 assert_equal Message.find(1), m.parent
779 end
779 end
780
780
781 def test_should_strip_tags_of_html_only_emails
781 def test_should_strip_tags_of_html_only_emails
782 issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
782 issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
783 assert issue.is_a?(Issue)
783 assert issue.is_a?(Issue)
784 assert !issue.new_record?
784 assert !issue.new_record?
785 issue.reload
785 issue.reload
786 assert_equal 'HTML email', issue.subject
786 assert_equal 'HTML email', issue.subject
787 assert_equal 'This is a html-only email.', issue.description
787 assert_equal 'This is a html-only email.', issue.description
788 end
788 end
789
789
790 test "truncate emails with no setting should add the entire email into the issue" do
790 test "truncate emails with no setting should add the entire email into the issue" do
791 with_settings :mail_handler_body_delimiters => '' do
791 with_settings :mail_handler_body_delimiters => '' do
792 issue = submit_email('ticket_on_given_project.eml')
792 issue = submit_email('ticket_on_given_project.eml')
793 assert_issue_created(issue)
793 assert_issue_created(issue)
794 assert issue.description.include?('---')
794 assert issue.description.include?('---')
795 assert issue.description.include?('This paragraph is after the delimiter')
795 assert issue.description.include?('This paragraph is after the delimiter')
796 end
796 end
797 end
797 end
798
798
799 test "truncate emails with a single string should truncate the email at the delimiter for the issue" do
799 test "truncate emails with a single string should truncate the email at the delimiter for the issue" do
800 with_settings :mail_handler_body_delimiters => '---' do
800 with_settings :mail_handler_body_delimiters => '---' do
801 issue = submit_email('ticket_on_given_project.eml')
801 issue = submit_email('ticket_on_given_project.eml')
802 assert_issue_created(issue)
802 assert_issue_created(issue)
803 assert issue.description.include?('This paragraph is before delimiters')
803 assert issue.description.include?('This paragraph is before delimiters')
804 assert issue.description.include?('--- This line starts with a delimiter')
804 assert issue.description.include?('--- This line starts with a delimiter')
805 assert !issue.description.match(/^---$/)
805 assert !issue.description.match(/^---$/)
806 assert !issue.description.include?('This paragraph is after the delimiter')
806 assert !issue.description.include?('This paragraph is after the delimiter')
807 end
807 end
808 end
808 end
809
809
810 test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do
810 test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do
811 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
811 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
812 journal = submit_email('issue_update_with_quoted_reply_above.eml')
812 journal = submit_email('issue_update_with_quoted_reply_above.eml')
813 assert journal.is_a?(Journal)
813 assert journal.is_a?(Journal)
814 assert journal.notes.include?('An update to the issue by the sender.')
814 assert journal.notes.include?('An update to the issue by the sender.')
815 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
815 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
816 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
816 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
817 end
817 end
818 end
818 end
819
819
820 test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do
820 test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do
821 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
821 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
822 journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
822 journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
823 assert journal.is_a?(Journal)
823 assert journal.is_a?(Journal)
824 assert journal.notes.include?('An update to the issue by the sender.')
824 assert journal.notes.include?('An update to the issue by the sender.')
825 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
825 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
826 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
826 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
827 end
827 end
828 end
828 end
829
829
830 test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do
830 test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do
831 with_settings :mail_handler_body_delimiters => "---\nBREAK" do
831 with_settings :mail_handler_body_delimiters => "---\nBREAK" do
832 issue = submit_email('ticket_on_given_project.eml')
832 issue = submit_email('ticket_on_given_project.eml')
833 assert_issue_created(issue)
833 assert_issue_created(issue)
834 assert issue.description.include?('This paragraph is before delimiters')
834 assert issue.description.include?('This paragraph is before delimiters')
835 assert !issue.description.include?('BREAK')
835 assert !issue.description.include?('BREAK')
836 assert !issue.description.include?('This paragraph is between delimiters')
836 assert !issue.description.include?('This paragraph is between delimiters')
837 assert !issue.description.match(/^---$/)
837 assert !issue.description.match(/^---$/)
838 assert !issue.description.include?('This paragraph is after the delimiter')
838 assert !issue.description.include?('This paragraph is after the delimiter')
839 end
839 end
840 end
840 end
841
841
842 def test_attachments_that_match_mail_handler_excluded_filenames_should_be_ignored
842 def test_attachments_that_match_mail_handler_excluded_filenames_should_be_ignored
843 with_settings :mail_handler_excluded_filenames => '*.vcf, *.jpg' do
843 with_settings :mail_handler_excluded_filenames => '*.vcf, *.jpg' do
844 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
844 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
845 assert issue.is_a?(Issue)
845 assert issue.is_a?(Issue)
846 assert !issue.new_record?
846 assert !issue.new_record?
847 assert_equal 0, issue.reload.attachments.size
847 assert_equal 0, issue.reload.attachments.size
848 end
848 end
849 end
849 end
850
850
851 def test_attachments_that_do_not_match_mail_handler_excluded_filenames_should_be_attached
851 def test_attachments_that_do_not_match_mail_handler_excluded_filenames_should_be_attached
852 with_settings :mail_handler_excluded_filenames => '*.vcf, *.gif' do
852 with_settings :mail_handler_excluded_filenames => '*.vcf, *.gif' do
853 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
853 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
854 assert issue.is_a?(Issue)
854 assert issue.is_a?(Issue)
855 assert !issue.new_record?
855 assert !issue.new_record?
856 assert_equal 1, issue.reload.attachments.size
856 assert_equal 1, issue.reload.attachments.size
857 end
857 end
858 end
858 end
859
859
860 def test_email_with_long_subject_line
860 def test_email_with_long_subject_line
861 issue = submit_email('ticket_with_long_subject.eml')
861 issue = submit_email('ticket_with_long_subject.eml')
862 assert issue.is_a?(Issue)
862 assert issue.is_a?(Issue)
863 assert_equal issue.subject, 'New ticket on a given project with a very long subject line which exceeds 255 chars and should not be ignored but chopped off. And if the subject line is still not long enough, we just add more text. And more text. Wow, this is really annoying. Especially, if you have nothing to say...'[0,255]
863 assert_equal issue.subject, 'New ticket on a given project with a very long subject line which exceeds 255 chars and should not be ignored but chopped off. And if the subject line is still not long enough, we just add more text. And more text. Wow, this is really annoying. Especially, if you have nothing to say...'[0,255]
864 end
864 end
865
865
866 def test_first_keyword_should_be_matched
866 def test_first_keyword_should_be_matched
867 issue = submit_email('ticket_with_duplicate_keyword.eml', :allow_override => 'priority')
867 issue = submit_email('ticket_with_duplicate_keyword.eml', :allow_override => 'priority')
868 assert issue.is_a?(Issue)
868 assert issue.is_a?(Issue)
869 assert_equal 'High', issue.priority.name
869 assert_equal 'High', issue.priority.name
870 end
870 end
871
871
872 def test_keyword_after_delimiter_should_be_ignored
872 def test_keyword_after_delimiter_should_be_ignored
873 with_settings :mail_handler_body_delimiters => "== DELIMITER ==" do
873 with_settings :mail_handler_body_delimiters => "== DELIMITER ==" do
874 issue = submit_email('ticket_with_keyword_after_delimiter.eml', :allow_override => 'priority')
874 issue = submit_email('ticket_with_keyword_after_delimiter.eml', :allow_override => 'priority')
875 assert issue.is_a?(Issue)
875 assert issue.is_a?(Issue)
876 assert_equal 'Normal', issue.priority.name
876 assert_equal 'Normal', issue.priority.name
877 end
877 end
878 end
878 end
879
879
880 def test_new_user_from_attributes_should_return_valid_user
880 def test_new_user_from_attributes_should_return_valid_user
881 to_test = {
881 to_test = {
882 # [address, name] => [login, firstname, lastname]
882 # [address, name] => [login, firstname, lastname]
883 ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'],
883 ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'],
884 ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'],
884 ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'],
885 ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'],
885 ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'],
886 ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'],
886 ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'],
887 ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'],
887 ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'],
888 ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh']
888 ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh']
889 }
889 }
890
890
891 to_test.each do |attrs, expected|
891 to_test.each do |attrs, expected|
892 user = MailHandler.new_user_from_attributes(attrs.first, attrs.last)
892 user = MailHandler.new_user_from_attributes(attrs.first, attrs.last)
893
893
894 assert user.valid?, user.errors.full_messages.to_s
894 assert user.valid?, user.errors.full_messages.to_s
895 assert_equal attrs.first, user.mail
895 assert_equal attrs.first, user.mail
896 assert_equal expected[0], user.login
896 assert_equal expected[0], user.login
897 assert_equal expected[1], user.firstname
897 assert_equal expected[1], user.firstname
898 assert_equal expected[2], user.lastname
898 assert_equal expected[2], user.lastname
899 assert_equal 'only_my_events', user.mail_notification
899 assert_equal 'only_my_events', user.mail_notification
900 end
900 end
901 end
901 end
902
902
903 def test_new_user_from_attributes_should_use_default_login_if_invalid
903 def test_new_user_from_attributes_should_use_default_login_if_invalid
904 user = MailHandler.new_user_from_attributes('foo+bar@example.net')
904 user = MailHandler.new_user_from_attributes('foo+bar@example.net')
905 assert user.valid?
905 assert user.valid?
906 assert user.login =~ /^user[a-f0-9]+$/
906 assert user.login =~ /^user[a-f0-9]+$/
907 assert_equal 'foo+bar@example.net', user.mail
907 assert_equal 'foo+bar@example.net', user.mail
908 end
908 end
909
909
910 def test_new_user_with_utf8_encoded_fullname_should_be_decoded
910 def test_new_user_with_utf8_encoded_fullname_should_be_decoded
911 assert_difference 'User.count' do
911 assert_difference 'User.count' do
912 issue = submit_email(
912 issue = submit_email(
913 'fullname_of_sender_as_utf8_encoded.eml',
913 'fullname_of_sender_as_utf8_encoded.eml',
914 :issue => {:project => 'ecookbook'},
914 :issue => {:project => 'ecookbook'},
915 :unknown_user => 'create'
915 :unknown_user => 'create'
916 )
916 )
917 end
917 end
918 user = User.order('id DESC').first
918 user = User.order('id DESC').first
919 assert_equal "foo@example.org", user.mail
919 assert_equal "foo@example.org", user.mail
920 str1 = "\xc3\x84\xc3\xa4".force_encoding('UTF-8')
920 str1 = "\xc3\x84\xc3\xa4".force_encoding('UTF-8')
921 str2 = "\xc3\x96\xc3\xb6".force_encoding('UTF-8')
921 str2 = "\xc3\x96\xc3\xb6".force_encoding('UTF-8')
922 assert_equal str1, user.firstname
922 assert_equal str1, user.firstname
923 assert_equal str2, user.lastname
923 assert_equal str2, user.lastname
924 end
924 end
925
925
926 def test_extract_options_from_env_should_return_options
926 def test_extract_options_from_env_should_return_options
927 options = MailHandler.extract_options_from_env({
927 options = MailHandler.extract_options_from_env({
928 'tracker' => 'defect',
928 'tracker' => 'defect',
929 'project' => 'foo',
929 'project' => 'foo',
930 'unknown_user' => 'create'
930 'unknown_user' => 'create'
931 })
931 })
932
932
933 assert_equal({
933 assert_equal({
934 :issue => {:tracker => 'defect', :project => 'foo'},
934 :issue => {:tracker => 'defect', :project => 'foo'},
935 :unknown_user => 'create'
935 :unknown_user => 'create'
936 }, options)
936 }, options)
937 end
937 end
938
938
939 private
939 private
940
940
941 def submit_email(filename, options={})
941 def submit_email(filename, options={})
942 raw = IO.read(File.join(FIXTURES_PATH, filename))
942 raw = IO.read(File.join(FIXTURES_PATH, filename))
943 yield raw if block_given?
943 yield raw if block_given?
944 MailHandler.receive(raw, options)
944 MailHandler.receive(raw, options)
945 end
945 end
946
946
947 def assert_issue_created(issue)
947 def assert_issue_created(issue)
948 assert issue.is_a?(Issue)
948 assert issue.is_a?(Issue)
949 assert !issue.new_record?
949 assert !issue.new_record?
950 issue.reload
950 issue.reload
951 end
951 end
952 end
952 end
@@ -1,954 +1,950
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class ProjectTest < ActiveSupport::TestCase
20 class ProjectTest < ActiveSupport::TestCase
21 fixtures :projects, :trackers, :issue_statuses, :issues,
21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 :journals, :journal_details,
22 :journals, :journal_details,
23 :enumerations, :users, :issue_categories,
23 :enumerations, :users, :issue_categories,
24 :projects_trackers,
24 :projects_trackers,
25 :custom_fields,
25 :custom_fields,
26 :custom_fields_projects,
26 :custom_fields_projects,
27 :custom_fields_trackers,
27 :custom_fields_trackers,
28 :custom_values,
28 :custom_values,
29 :roles,
29 :roles,
30 :member_roles,
30 :member_roles,
31 :members,
31 :members,
32 :enabled_modules,
32 :enabled_modules,
33 :versions,
33 :versions,
34 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
34 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
35 :groups_users,
35 :groups_users,
36 :boards, :messages,
36 :boards, :messages,
37 :repositories,
37 :repositories,
38 :news, :comments,
38 :news, :comments,
39 :documents,
39 :documents,
40 :workflows
40 :workflows
41
41
42 def setup
42 def setup
43 @ecookbook = Project.find(1)
43 @ecookbook = Project.find(1)
44 @ecookbook_sub1 = Project.find(3)
44 @ecookbook_sub1 = Project.find(3)
45 set_tmp_attachments_directory
45 set_tmp_attachments_directory
46 User.current = nil
46 User.current = nil
47 end
47 end
48
48
49 def test_truth
49 def test_truth
50 assert_kind_of Project, @ecookbook
50 assert_kind_of Project, @ecookbook
51 assert_equal "eCookbook", @ecookbook.name
51 assert_equal "eCookbook", @ecookbook.name
52 end
52 end
53
53
54 def test_default_attributes
54 def test_default_attributes
55 with_settings :default_projects_public => '1' do
55 with_settings :default_projects_public => '1' do
56 assert_equal true, Project.new.is_public
56 assert_equal true, Project.new.is_public
57 assert_equal false, Project.new(:is_public => false).is_public
57 assert_equal false, Project.new(:is_public => false).is_public
58 end
58 end
59
59
60 with_settings :default_projects_public => '0' do
60 with_settings :default_projects_public => '0' do
61 assert_equal false, Project.new.is_public
61 assert_equal false, Project.new.is_public
62 assert_equal true, Project.new(:is_public => true).is_public
62 assert_equal true, Project.new(:is_public => true).is_public
63 end
63 end
64
64
65 with_settings :sequential_project_identifiers => '1' do
65 with_settings :sequential_project_identifiers => '1' do
66 assert !Project.new.identifier.blank?
66 assert !Project.new.identifier.blank?
67 assert Project.new(:identifier => '').identifier.blank?
67 assert Project.new(:identifier => '').identifier.blank?
68 end
68 end
69
69
70 with_settings :sequential_project_identifiers => '0' do
70 with_settings :sequential_project_identifiers => '0' do
71 assert Project.new.identifier.blank?
71 assert Project.new.identifier.blank?
72 assert !Project.new(:identifier => 'test').blank?
72 assert !Project.new(:identifier => 'test').blank?
73 end
73 end
74
74
75 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
75 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
76 assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names
76 assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names
77 end
77 end
78 end
78 end
79
79
80 def test_default_trackers_should_match_default_tracker_ids_setting
80 def test_default_trackers_should_match_default_tracker_ids_setting
81 with_settings :default_projects_tracker_ids => ['1', '3'] do
81 with_settings :default_projects_tracker_ids => ['1', '3'] do
82 assert_equal Tracker.find(1, 3).sort, Project.new.trackers.sort
82 assert_equal Tracker.find(1, 3).sort, Project.new.trackers.sort
83 end
83 end
84 end
84 end
85
85
86 def test_default_trackers_should_be_all_trackers_with_blank_setting
86 def test_default_trackers_should_be_all_trackers_with_blank_setting
87 with_settings :default_projects_tracker_ids => nil do
87 with_settings :default_projects_tracker_ids => nil do
88 assert_equal Tracker.all.sort, Project.new.trackers.sort
88 assert_equal Tracker.all.sort, Project.new.trackers.sort
89 end
89 end
90 end
90 end
91
91
92 def test_default_trackers_should_be_empty_with_empty_setting
92 def test_default_trackers_should_be_empty_with_empty_setting
93 with_settings :default_projects_tracker_ids => [] do
93 with_settings :default_projects_tracker_ids => [] do
94 assert_equal [], Project.new.trackers
94 assert_equal [], Project.new.trackers
95 end
95 end
96 end
96 end
97
97
98 def test_default_trackers_should_not_replace_initialized_trackers
98 def test_default_trackers_should_not_replace_initialized_trackers
99 with_settings :default_projects_tracker_ids => ['1', '3'] do
99 with_settings :default_projects_tracker_ids => ['1', '3'] do
100 assert_equal Tracker.find(1, 2).sort, Project.new(:tracker_ids => [1, 2]).trackers.sort
100 assert_equal Tracker.find(1, 2).sort, Project.new(:tracker_ids => [1, 2]).trackers.sort
101 end
101 end
102 end
102 end
103
103
104 def test_update
104 def test_update
105 assert_equal "eCookbook", @ecookbook.name
105 assert_equal "eCookbook", @ecookbook.name
106 @ecookbook.name = "eCook"
106 @ecookbook.name = "eCook"
107 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
107 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
108 @ecookbook.reload
108 @ecookbook.reload
109 assert_equal "eCook", @ecookbook.name
109 assert_equal "eCook", @ecookbook.name
110 end
110 end
111
111
112 def test_validate_identifier
112 def test_validate_identifier
113 to_test = {"abc" => true,
113 to_test = {"abc" => true,
114 "ab12" => true,
114 "ab12" => true,
115 "ab-12" => true,
115 "ab-12" => true,
116 "ab_12" => true,
116 "ab_12" => true,
117 "12" => false,
117 "12" => false,
118 "new" => false}
118 "new" => false}
119
119
120 to_test.each do |identifier, valid|
120 to_test.each do |identifier, valid|
121 p = Project.new
121 p = Project.new
122 p.identifier = identifier
122 p.identifier = identifier
123 p.valid?
123 p.valid?
124 if valid
124 if valid
125 assert p.errors['identifier'].blank?, "identifier #{identifier} was not valid"
125 assert p.errors['identifier'].blank?, "identifier #{identifier} was not valid"
126 else
126 else
127 assert p.errors['identifier'].present?, "identifier #{identifier} was valid"
127 assert p.errors['identifier'].present?, "identifier #{identifier} was valid"
128 end
128 end
129 end
129 end
130 end
130 end
131
131
132 def test_identifier_should_not_be_frozen_for_a_new_project
132 def test_identifier_should_not_be_frozen_for_a_new_project
133 assert_equal false, Project.new.identifier_frozen?
133 assert_equal false, Project.new.identifier_frozen?
134 end
134 end
135
135
136 def test_identifier_should_not_be_frozen_for_a_saved_project_with_blank_identifier
136 def test_identifier_should_not_be_frozen_for_a_saved_project_with_blank_identifier
137 Project.where(:id => 1).update_all(["identifier = ''"])
137 Project.where(:id => 1).update_all(["identifier = ''"])
138 assert_equal false, Project.find(1).identifier_frozen?
138 assert_equal false, Project.find(1).identifier_frozen?
139 end
139 end
140
140
141 def test_identifier_should_be_frozen_for_a_saved_project_with_valid_identifier
141 def test_identifier_should_be_frozen_for_a_saved_project_with_valid_identifier
142 assert_equal true, Project.find(1).identifier_frozen?
142 assert_equal true, Project.find(1).identifier_frozen?
143 end
143 end
144
144
145 def test_members_should_be_active_users
145 def test_members_should_be_active_users
146 Project.all.each do |project|
146 Project.all.each do |project|
147 assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) }
147 assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) }
148 end
148 end
149 end
149 end
150
150
151 def test_users_should_be_active_users
151 def test_users_should_be_active_users
152 Project.all.each do |project|
152 Project.all.each do |project|
153 assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) }
153 assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) }
154 end
154 end
155 end
155 end
156
156
157 def test_open_scope_on_issues_association
157 def test_open_scope_on_issues_association
158 assert_kind_of Issue, Project.find(1).issues.open.first
158 assert_kind_of Issue, Project.find(1).issues.open.first
159 end
159 end
160
160
161 def test_archive
161 def test_archive
162 user = @ecookbook.members.first.user
162 user = @ecookbook.members.first.user
163 @ecookbook.archive
163 @ecookbook.archive
164 @ecookbook.reload
164 @ecookbook.reload
165
165
166 assert !@ecookbook.active?
166 assert !@ecookbook.active?
167 assert @ecookbook.archived?
167 assert @ecookbook.archived?
168 assert !user.projects.include?(@ecookbook)
168 assert !user.projects.include?(@ecookbook)
169 # Subproject are also archived
169 # Subproject are also archived
170 assert !@ecookbook.children.empty?
170 assert !@ecookbook.children.empty?
171 assert @ecookbook.descendants.active.empty?
171 assert @ecookbook.descendants.active.empty?
172 end
172 end
173
173
174 def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects
174 def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects
175 # Assign an issue of a project to a version of a child project
175 # Assign an issue of a project to a version of a child project
176 Issue.find(4).update_attribute :fixed_version_id, 4
176 Issue.find(4).update_attribute :fixed_version_id, 4
177
177
178 assert_no_difference "Project.where(:status => Project::STATUS_ARCHIVED).count" do
178 assert_no_difference "Project.where(:status => Project::STATUS_ARCHIVED).count" do
179 assert_equal false, @ecookbook.archive
179 assert_equal false, @ecookbook.archive
180 end
180 end
181 @ecookbook.reload
181 @ecookbook.reload
182 assert @ecookbook.active?
182 assert @ecookbook.active?
183 end
183 end
184
184
185 def test_unarchive
185 def test_unarchive
186 user = @ecookbook.members.first.user
186 user = @ecookbook.members.first.user
187 @ecookbook.archive
187 @ecookbook.archive
188 # A subproject of an archived project can not be unarchived
188 # A subproject of an archived project can not be unarchived
189 assert !@ecookbook_sub1.unarchive
189 assert !@ecookbook_sub1.unarchive
190
190
191 # Unarchive project
191 # Unarchive project
192 assert @ecookbook.unarchive
192 assert @ecookbook.unarchive
193 @ecookbook.reload
193 @ecookbook.reload
194 assert @ecookbook.active?
194 assert @ecookbook.active?
195 assert !@ecookbook.archived?
195 assert !@ecookbook.archived?
196 assert user.projects.include?(@ecookbook)
196 assert user.projects.include?(@ecookbook)
197 # Subproject can now be unarchived
197 # Subproject can now be unarchived
198 @ecookbook_sub1.reload
198 @ecookbook_sub1.reload
199 assert @ecookbook_sub1.unarchive
199 assert @ecookbook_sub1.unarchive
200 end
200 end
201
201
202 def test_destroy
202 def test_destroy
203 # 2 active members
203 # 2 active members
204 assert_equal 2, @ecookbook.members.size
204 assert_equal 2, @ecookbook.members.size
205 # and 1 is locked
205 # and 1 is locked
206 assert_equal 3, Member.where(:project_id => @ecookbook.id).count
206 assert_equal 3, Member.where(:project_id => @ecookbook.id).count
207 # some boards
207 # some boards
208 assert @ecookbook.boards.any?
208 assert @ecookbook.boards.any?
209
209
210 @ecookbook.destroy
210 @ecookbook.destroy
211 # make sure that the project non longer exists
211 # make sure that the project non longer exists
212 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
212 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
213 # make sure related data was removed
213 # make sure related data was removed
214 assert_nil Member.where(:project_id => @ecookbook.id).first
214 assert_nil Member.where(:project_id => @ecookbook.id).first
215 assert_nil Board.where(:project_id => @ecookbook.id).first
215 assert_nil Board.where(:project_id => @ecookbook.id).first
216 assert_nil Issue.where(:project_id => @ecookbook.id).first
216 assert_nil Issue.where(:project_id => @ecookbook.id).first
217 end
217 end
218
218
219 def test_destroy_should_destroy_subtasks
219 def test_destroy_should_destroy_subtasks
220 issues = (0..2).to_a.map {Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test')}
220 issues = (0..2).to_a.map {Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test')}
221 issues[0].update_attribute :parent_issue_id, issues[1].id
221 issues[0].update_attribute :parent_issue_id, issues[1].id
222 issues[2].update_attribute :parent_issue_id, issues[1].id
222 issues[2].update_attribute :parent_issue_id, issues[1].id
223 assert_equal 2, issues[1].children.count
223 assert_equal 2, issues[1].children.count
224
224
225 assert_nothing_raised do
225 assert_nothing_raised do
226 Project.find(1).destroy
226 Project.find(1).destroy
227 end
227 end
228 assert_equal 0, Issue.where(:id => issues.map(&:id)).count
228 assert_equal 0, Issue.where(:id => issues.map(&:id)).count
229 end
229 end
230
230
231 def test_destroying_root_projects_should_clear_data
231 def test_destroying_root_projects_should_clear_data
232 Project.roots.each do |root|
232 Project.roots.each do |root|
233 root.destroy
233 root.destroy
234 end
234 end
235
235
236 assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}"
236 assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}"
237 assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}"
237 assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}"
238 assert_equal 0, MemberRole.count
238 assert_equal 0, MemberRole.count
239 assert_equal 0, Issue.count
239 assert_equal 0, Issue.count
240 assert_equal 0, Journal.count
240 assert_equal 0, Journal.count
241 assert_equal 0, JournalDetail.count
241 assert_equal 0, JournalDetail.count
242 assert_equal 0, Attachment.count, "Attachments were not deleted: #{Attachment.all.inspect}"
242 assert_equal 0, Attachment.count, "Attachments were not deleted: #{Attachment.all.inspect}"
243 assert_equal 0, EnabledModule.count
243 assert_equal 0, EnabledModule.count
244 assert_equal 0, IssueCategory.count
244 assert_equal 0, IssueCategory.count
245 assert_equal 0, IssueRelation.count
245 assert_equal 0, IssueRelation.count
246 assert_equal 0, Board.count
246 assert_equal 0, Board.count
247 assert_equal 0, Message.count
247 assert_equal 0, Message.count
248 assert_equal 0, News.count
248 assert_equal 0, News.count
249 assert_equal 0, Query.where("project_id IS NOT NULL").count
249 assert_equal 0, Query.where("project_id IS NOT NULL").count
250 assert_equal 0, Repository.count
250 assert_equal 0, Repository.count
251 assert_equal 0, Changeset.count
251 assert_equal 0, Changeset.count
252 assert_equal 0, Change.count
252 assert_equal 0, Change.count
253 assert_equal 0, Comment.count
253 assert_equal 0, Comment.count
254 assert_equal 0, TimeEntry.count
254 assert_equal 0, TimeEntry.count
255 assert_equal 0, Version.count
255 assert_equal 0, Version.count
256 assert_equal 0, Watcher.count
256 assert_equal 0, Watcher.count
257 assert_equal 0, Wiki.count
257 assert_equal 0, Wiki.count
258 assert_equal 0, WikiPage.count
258 assert_equal 0, WikiPage.count
259 assert_equal 0, WikiContent.count
259 assert_equal 0, WikiContent.count
260 assert_equal 0, WikiContent::Version.count
260 assert_equal 0, WikiContent::Version.count
261 assert_equal 0, Project.connection.select_all("SELECT * FROM projects_trackers").count
261 assert_equal 0, Project.connection.select_all("SELECT * FROM projects_trackers").count
262 assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").count
262 assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").count
263 assert_equal 0, CustomValue.where(:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']).count
263 assert_equal 0, CustomValue.where(:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']).count
264 end
264 end
265
265
266 def test_destroy_should_delete_time_entries_custom_values
266 def test_destroy_should_delete_time_entries_custom_values
267 project = Project.generate!
267 project = Project.generate!
268 time_entry = TimeEntry.generate!(:project => project, :custom_field_values => {10 => '1'})
268 time_entry = TimeEntry.generate!(:project => project, :custom_field_values => {10 => '1'})
269
269
270 assert_difference 'CustomValue.where(:customized_type => "TimeEntry").count', -1 do
270 assert_difference 'CustomValue.where(:customized_type => "TimeEntry").count', -1 do
271 assert project.destroy
271 assert project.destroy
272 end
272 end
273 end
273 end
274
274
275 def test_move_an_orphan_project_to_a_root_project
275 def test_move_an_orphan_project_to_a_root_project
276 sub = Project.find(2)
276 sub = Project.find(2)
277 sub.set_parent! @ecookbook
277 sub.set_parent! @ecookbook
278 assert_equal @ecookbook.id, sub.parent.id
278 assert_equal @ecookbook.id, sub.parent.id
279 @ecookbook.reload
279 @ecookbook.reload
280 assert_equal 4, @ecookbook.children.size
280 assert_equal 4, @ecookbook.children.size
281 end
281 end
282
282
283 def test_move_an_orphan_project_to_a_subproject
283 def test_move_an_orphan_project_to_a_subproject
284 sub = Project.find(2)
284 sub = Project.find(2)
285 assert sub.set_parent!(@ecookbook_sub1)
285 assert sub.set_parent!(@ecookbook_sub1)
286 end
286 end
287
287
288 def test_move_a_root_project_to_a_project
288 def test_move_a_root_project_to_a_project
289 sub = @ecookbook
289 sub = @ecookbook
290 assert sub.set_parent!(Project.find(2))
290 assert sub.set_parent!(Project.find(2))
291 end
291 end
292
292
293 def test_should_not_move_a_project_to_its_children
293 def test_should_not_move_a_project_to_its_children
294 sub = @ecookbook
294 sub = @ecookbook
295 assert !(sub.set_parent!(Project.find(3)))
295 assert !(sub.set_parent!(Project.find(3)))
296 end
296 end
297
297
298 def test_set_parent_should_add_roots_in_alphabetical_order
298 def test_set_parent_should_add_roots_in_alphabetical_order
299 ProjectCustomField.delete_all
299 ProjectCustomField.delete_all
300 Project.delete_all
300 Project.delete_all
301 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(nil)
301 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(nil)
302 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil)
302 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil)
303 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil)
303 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil)
304 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil)
304 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil)
305
305
306 assert_equal 4, Project.count
306 assert_equal 4, Project.count
307 assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft)
307 assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft)
308 end
308 end
309
309
310 def test_set_parent_should_add_children_in_alphabetical_order
310 def test_set_parent_should_add_children_in_alphabetical_order
311 ProjectCustomField.delete_all
311 ProjectCustomField.delete_all
312 parent = Project.create!(:name => 'Parent', :identifier => 'parent')
312 parent = Project.create!(:name => 'Parent', :identifier => 'parent')
313 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(parent)
313 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(parent)
314 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent)
314 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent)
315 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent)
315 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent)
316 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent)
316 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent)
317
317
318 parent.reload
318 parent.reload
319 assert_equal 4, parent.children.size
319 assert_equal 4, parent.children.size
320 assert_equal parent.children.sort_by(&:name), parent.children.to_a
320 assert_equal parent.children.sort_by(&:name), parent.children.to_a
321 end
321 end
322
322
323 def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy
323 def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy
324 # Parent issue with a hierarchy project's fixed version
324 # Parent issue with a hierarchy project's fixed version
325 parent_issue = Issue.find(1)
325 parent_issue = Issue.find(1)
326 parent_issue.update_attribute(:fixed_version_id, 4)
326 parent_issue.update_attribute(:fixed_version_id, 4)
327 parent_issue.reload
327 parent_issue.reload
328 assert_equal 4, parent_issue.fixed_version_id
328 assert_equal 4, parent_issue.fixed_version_id
329
329
330 # Should keep fixed versions for the issues
330 # Should keep fixed versions for the issues
331 issue_with_local_fixed_version = Issue.find(5)
331 issue_with_local_fixed_version = Issue.find(5)
332 issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4)
332 issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4)
333 issue_with_local_fixed_version.reload
333 issue_with_local_fixed_version.reload
334 assert_equal 4, issue_with_local_fixed_version.fixed_version_id
334 assert_equal 4, issue_with_local_fixed_version.fixed_version_id
335
335
336 # Local issue with hierarchy fixed_version
336 # Local issue with hierarchy fixed_version
337 issue_with_hierarchy_fixed_version = Issue.find(13)
337 issue_with_hierarchy_fixed_version = Issue.find(13)
338 issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6)
338 issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6)
339 issue_with_hierarchy_fixed_version.reload
339 issue_with_hierarchy_fixed_version.reload
340 assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id
340 assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id
341
341
342 # Move project out of the issue's hierarchy
342 # Move project out of the issue's hierarchy
343 moved_project = Project.find(3)
343 moved_project = Project.find(3)
344 moved_project.set_parent!(Project.find(2))
344 moved_project.set_parent!(Project.find(2))
345 parent_issue.reload
345 parent_issue.reload
346 issue_with_local_fixed_version.reload
346 issue_with_local_fixed_version.reload
347 issue_with_hierarchy_fixed_version.reload
347 issue_with_hierarchy_fixed_version.reload
348
348
349 assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project"
349 assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project"
350 assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in"
350 assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in"
351 assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue."
351 assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue."
352 end
352 end
353
353
354 def test_parent
354 def test_parent
355 p = Project.find(6).parent
355 p = Project.find(6).parent
356 assert p.is_a?(Project)
356 assert p.is_a?(Project)
357 assert_equal 5, p.id
357 assert_equal 5, p.id
358 end
358 end
359
359
360 def test_ancestors
360 def test_ancestors
361 a = Project.find(6).ancestors
361 a = Project.find(6).ancestors
362 assert a.first.is_a?(Project)
362 assert a.first.is_a?(Project)
363 assert_equal [1, 5], a.collect(&:id)
363 assert_equal [1, 5], a.collect(&:id)
364 end
364 end
365
365
366 def test_root
366 def test_root
367 r = Project.find(6).root
367 r = Project.find(6).root
368 assert r.is_a?(Project)
368 assert r.is_a?(Project)
369 assert_equal 1, r.id
369 assert_equal 1, r.id
370 end
370 end
371
371
372 def test_children
372 def test_children
373 c = Project.find(1).children
373 c = Project.find(1).children
374 assert c.first.is_a?(Project)
374 assert c.first.is_a?(Project)
375 assert_equal [5, 3, 4], c.collect(&:id)
375 assert_equal [5, 3, 4], c.collect(&:id)
376 end
376 end
377
377
378 def test_descendants
378 def test_descendants
379 d = Project.find(1).descendants
379 d = Project.find(1).descendants
380 assert d.first.is_a?(Project)
380 assert d.first.is_a?(Project)
381 assert_equal [5, 6, 3, 4], d.collect(&:id)
381 assert_equal [5, 6, 3, 4], d.collect(&:id)
382 end
382 end
383
383
384 def test_allowed_parents_should_be_empty_for_non_member_user
384 def test_allowed_parents_should_be_empty_for_non_member_user
385 Role.non_member.add_permission!(:add_project)
385 Role.non_member.add_permission!(:add_project)
386 user = User.find(9)
386 user = User.find(9)
387 assert user.memberships.empty?
387 assert user.memberships.empty?
388 User.current = user
388 User.current = user
389 assert Project.new.allowed_parents.compact.empty?
389 assert Project.new.allowed_parents.compact.empty?
390 end
390 end
391
391
392 def test_allowed_parents_with_add_subprojects_permission
392 def test_allowed_parents_with_add_subprojects_permission
393 Role.find(1).remove_permission!(:add_project)
393 Role.find(1).remove_permission!(:add_project)
394 Role.find(1).add_permission!(:add_subprojects)
394 Role.find(1).add_permission!(:add_subprojects)
395 User.current = User.find(2)
395 User.current = User.find(2)
396 # new project
396 # new project
397 assert !Project.new.allowed_parents.include?(nil)
397 assert !Project.new.allowed_parents.include?(nil)
398 assert Project.new.allowed_parents.include?(Project.find(1))
398 assert Project.new.allowed_parents.include?(Project.find(1))
399 # existing root project
399 # existing root project
400 assert Project.find(1).allowed_parents.include?(nil)
400 assert Project.find(1).allowed_parents.include?(nil)
401 # existing child
401 # existing child
402 assert Project.find(3).allowed_parents.include?(Project.find(1))
402 assert Project.find(3).allowed_parents.include?(Project.find(1))
403 assert !Project.find(3).allowed_parents.include?(nil)
403 assert !Project.find(3).allowed_parents.include?(nil)
404 end
404 end
405
405
406 def test_allowed_parents_with_add_project_permission
406 def test_allowed_parents_with_add_project_permission
407 Role.find(1).add_permission!(:add_project)
407 Role.find(1).add_permission!(:add_project)
408 Role.find(1).remove_permission!(:add_subprojects)
408 Role.find(1).remove_permission!(:add_subprojects)
409 User.current = User.find(2)
409 User.current = User.find(2)
410 # new project
410 # new project
411 assert Project.new.allowed_parents.include?(nil)
411 assert Project.new.allowed_parents.include?(nil)
412 assert !Project.new.allowed_parents.include?(Project.find(1))
412 assert !Project.new.allowed_parents.include?(Project.find(1))
413 # existing root project
413 # existing root project
414 assert Project.find(1).allowed_parents.include?(nil)
414 assert Project.find(1).allowed_parents.include?(nil)
415 # existing child
415 # existing child
416 assert Project.find(3).allowed_parents.include?(Project.find(1))
416 assert Project.find(3).allowed_parents.include?(Project.find(1))
417 assert Project.find(3).allowed_parents.include?(nil)
417 assert Project.find(3).allowed_parents.include?(nil)
418 end
418 end
419
419
420 def test_allowed_parents_with_add_project_and_subprojects_permission
420 def test_allowed_parents_with_add_project_and_subprojects_permission
421 Role.find(1).add_permission!(:add_project)
421 Role.find(1).add_permission!(:add_project)
422 Role.find(1).add_permission!(:add_subprojects)
422 Role.find(1).add_permission!(:add_subprojects)
423 User.current = User.find(2)
423 User.current = User.find(2)
424 # new project
424 # new project
425 assert Project.new.allowed_parents.include?(nil)
425 assert Project.new.allowed_parents.include?(nil)
426 assert Project.new.allowed_parents.include?(Project.find(1))
426 assert Project.new.allowed_parents.include?(Project.find(1))
427 # existing root project
427 # existing root project
428 assert Project.find(1).allowed_parents.include?(nil)
428 assert Project.find(1).allowed_parents.include?(nil)
429 # existing child
429 # existing child
430 assert Project.find(3).allowed_parents.include?(Project.find(1))
430 assert Project.find(3).allowed_parents.include?(Project.find(1))
431 assert Project.find(3).allowed_parents.include?(nil)
431 assert Project.find(3).allowed_parents.include?(nil)
432 end
432 end
433
433
434 def test_users_by_role
434 def test_users_by_role
435 users_by_role = Project.find(1).users_by_role
435 users_by_role = Project.find(1).users_by_role
436 assert_kind_of Hash, users_by_role
436 assert_kind_of Hash, users_by_role
437 role = Role.find(1)
437 role = Role.find(1)
438 assert_kind_of Array, users_by_role[role]
438 assert_kind_of Array, users_by_role[role]
439 assert users_by_role[role].include?(User.find(2))
439 assert users_by_role[role].include?(User.find(2))
440 end
440 end
441
441
442 def test_rolled_up_trackers
442 def test_rolled_up_trackers
443 parent = Project.find(1)
443 parent = Project.find(1)
444 parent.trackers = Tracker.find([1,2])
444 parent.trackers = Tracker.find([1,2])
445 child = parent.children.find(3)
445 child = parent.children.find(3)
446
446
447 assert_equal [1, 2], parent.tracker_ids
447 assert_equal [1, 2], parent.tracker_ids
448 assert_equal [2, 3], child.trackers.collect(&:id)
448 assert_equal [2, 3], child.trackers.collect(&:id)
449
449
450 assert_kind_of Tracker, parent.rolled_up_trackers.first
450 assert_kind_of Tracker, parent.rolled_up_trackers.first
451 assert_equal Tracker.find(1), parent.rolled_up_trackers.first
451 assert_equal Tracker.find(1), parent.rolled_up_trackers.first
452
452
453 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id)
453 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id)
454 assert_equal [2, 3], child.rolled_up_trackers.collect(&:id)
454 assert_equal [2, 3], child.rolled_up_trackers.collect(&:id)
455 end
455 end
456
456
457 def test_rolled_up_trackers_should_ignore_archived_subprojects
457 def test_rolled_up_trackers_should_ignore_archived_subprojects
458 parent = Project.find(1)
458 parent = Project.find(1)
459 parent.trackers = Tracker.find([1,2])
459 parent.trackers = Tracker.find([1,2])
460 child = parent.children.find(3)
460 child = parent.children.find(3)
461 child.trackers = Tracker.find([1,3])
461 child.trackers = Tracker.find([1,3])
462 parent.children.each(&:archive)
462 parent.children.each(&:archive)
463
463
464 assert_equal [1,2], parent.rolled_up_trackers.collect(&:id)
464 assert_equal [1,2], parent.rolled_up_trackers.collect(&:id)
465 end
465 end
466
466
467 test "#rolled_up_trackers should ignore projects with issue_tracking module disabled" do
467 test "#rolled_up_trackers should ignore projects with issue_tracking module disabled" do
468 parent = Project.generate!
468 parent = Project.generate!
469 parent.trackers = Tracker.find([1, 2])
469 parent.trackers = Tracker.find([1, 2])
470 child = Project.generate_with_parent!(parent)
470 child = Project.generate_with_parent!(parent)
471 child.trackers = Tracker.find([2, 3])
471 child.trackers = Tracker.find([2, 3])
472
472
473 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id).sort
473 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id).sort
474
474
475 assert child.disable_module!(:issue_tracking)
475 assert child.disable_module!(:issue_tracking)
476 parent.reload
476 parent.reload
477 assert_equal [1, 2], parent.rolled_up_trackers.collect(&:id).sort
477 assert_equal [1, 2], parent.rolled_up_trackers.collect(&:id).sort
478 end
478 end
479
479
480 test "#rolled_up_versions should include the versions for the current project" do
480 test "#rolled_up_versions should include the versions for the current project" do
481 project = Project.generate!
481 project = Project.generate!
482 parent_version_1 = Version.generate!(:project => project)
482 parent_version_1 = Version.generate!(:project => project)
483 parent_version_2 = Version.generate!(:project => project)
483 parent_version_2 = Version.generate!(:project => project)
484 assert_same_elements [parent_version_1, parent_version_2], project.rolled_up_versions
484 assert_equal [parent_version_1, parent_version_2].sort,
485 project.rolled_up_versions.sort
485 end
486 end
486
487
487 test "#rolled_up_versions should include versions for a subproject" do
488 test "#rolled_up_versions should include versions for a subproject" do
488 project = Project.generate!
489 project = Project.generate!
489 parent_version_1 = Version.generate!(:project => project)
490 parent_version_1 = Version.generate!(:project => project)
490 parent_version_2 = Version.generate!(:project => project)
491 parent_version_2 = Version.generate!(:project => project)
491 subproject = Project.generate_with_parent!(project)
492 subproject = Project.generate_with_parent!(project)
492 subproject_version = Version.generate!(:project => subproject)
493 subproject_version = Version.generate!(:project => subproject)
493
494
494 assert_same_elements [
495 assert_equal [parent_version_1, parent_version_2, subproject_version].sort,
495 parent_version_1,
496 project.rolled_up_versions.sort
496 parent_version_2,
497 subproject_version
498 ], project.rolled_up_versions
499 end
497 end
500
498
501 test "#rolled_up_versions should include versions for a sub-subproject" do
499 test "#rolled_up_versions should include versions for a sub-subproject" do
502 project = Project.generate!
500 project = Project.generate!
503 parent_version_1 = Version.generate!(:project => project)
501 parent_version_1 = Version.generate!(:project => project)
504 parent_version_2 = Version.generate!(:project => project)
502 parent_version_2 = Version.generate!(:project => project)
505 subproject = Project.generate_with_parent!(project)
503 subproject = Project.generate_with_parent!(project)
506 sub_subproject = Project.generate_with_parent!(subproject)
504 sub_subproject = Project.generate_with_parent!(subproject)
507 sub_subproject_version = Version.generate!(:project => sub_subproject)
505 sub_subproject_version = Version.generate!(:project => sub_subproject)
508 project.reload
506 project.reload
509
507
510 assert_same_elements [
508 assert_equal [parent_version_1, parent_version_2, sub_subproject_version].sort,
511 parent_version_1,
509 project.rolled_up_versions.sort
512 parent_version_2,
513 sub_subproject_version
514 ], project.rolled_up_versions
515 end
510 end
516
511
517 test "#rolled_up_versions should only check active projects" do
512 test "#rolled_up_versions should only check active projects" do
518 project = Project.generate!
513 project = Project.generate!
519 parent_version_1 = Version.generate!(:project => project)
514 parent_version_1 = Version.generate!(:project => project)
520 parent_version_2 = Version.generate!(:project => project)
515 parent_version_2 = Version.generate!(:project => project)
521 subproject = Project.generate_with_parent!(project)
516 subproject = Project.generate_with_parent!(project)
522 subproject_version = Version.generate!(:project => subproject)
517 subproject_version = Version.generate!(:project => subproject)
523 assert subproject.archive
518 assert subproject.archive
524 project.reload
519 project.reload
525
520
526 assert !subproject.active?
521 assert !subproject.active?
527 assert_same_elements [parent_version_1, parent_version_2], project.rolled_up_versions
522 assert_equal [parent_version_1, parent_version_2].sort,
523 project.rolled_up_versions.sort
528 end
524 end
529
525
530 def test_shared_versions_none_sharing
526 def test_shared_versions_none_sharing
531 p = Project.find(5)
527 p = Project.find(5)
532 v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none')
528 v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none')
533 assert p.shared_versions.include?(v)
529 assert p.shared_versions.include?(v)
534 assert !p.children.first.shared_versions.include?(v)
530 assert !p.children.first.shared_versions.include?(v)
535 assert !p.root.shared_versions.include?(v)
531 assert !p.root.shared_versions.include?(v)
536 assert !p.siblings.first.shared_versions.include?(v)
532 assert !p.siblings.first.shared_versions.include?(v)
537 assert !p.root.siblings.first.shared_versions.include?(v)
533 assert !p.root.siblings.first.shared_versions.include?(v)
538 end
534 end
539
535
540 def test_shared_versions_descendants_sharing
536 def test_shared_versions_descendants_sharing
541 p = Project.find(5)
537 p = Project.find(5)
542 v = Version.create!(:name => 'descendants_sharing', :project => p, :sharing => 'descendants')
538 v = Version.create!(:name => 'descendants_sharing', :project => p, :sharing => 'descendants')
543 assert p.shared_versions.include?(v)
539 assert p.shared_versions.include?(v)
544 assert p.children.first.shared_versions.include?(v)
540 assert p.children.first.shared_versions.include?(v)
545 assert !p.root.shared_versions.include?(v)
541 assert !p.root.shared_versions.include?(v)
546 assert !p.siblings.first.shared_versions.include?(v)
542 assert !p.siblings.first.shared_versions.include?(v)
547 assert !p.root.siblings.first.shared_versions.include?(v)
543 assert !p.root.siblings.first.shared_versions.include?(v)
548 end
544 end
549
545
550 def test_shared_versions_hierarchy_sharing
546 def test_shared_versions_hierarchy_sharing
551 p = Project.find(5)
547 p = Project.find(5)
552 v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy')
548 v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy')
553 assert p.shared_versions.include?(v)
549 assert p.shared_versions.include?(v)
554 assert p.children.first.shared_versions.include?(v)
550 assert p.children.first.shared_versions.include?(v)
555 assert p.root.shared_versions.include?(v)
551 assert p.root.shared_versions.include?(v)
556 assert !p.siblings.first.shared_versions.include?(v)
552 assert !p.siblings.first.shared_versions.include?(v)
557 assert !p.root.siblings.first.shared_versions.include?(v)
553 assert !p.root.siblings.first.shared_versions.include?(v)
558 end
554 end
559
555
560 def test_shared_versions_tree_sharing
556 def test_shared_versions_tree_sharing
561 p = Project.find(5)
557 p = Project.find(5)
562 v = Version.create!(:name => 'tree_sharing', :project => p, :sharing => 'tree')
558 v = Version.create!(:name => 'tree_sharing', :project => p, :sharing => 'tree')
563 assert p.shared_versions.include?(v)
559 assert p.shared_versions.include?(v)
564 assert p.children.first.shared_versions.include?(v)
560 assert p.children.first.shared_versions.include?(v)
565 assert p.root.shared_versions.include?(v)
561 assert p.root.shared_versions.include?(v)
566 assert p.siblings.first.shared_versions.include?(v)
562 assert p.siblings.first.shared_versions.include?(v)
567 assert !p.root.siblings.first.shared_versions.include?(v)
563 assert !p.root.siblings.first.shared_versions.include?(v)
568 end
564 end
569
565
570 def test_shared_versions_system_sharing
566 def test_shared_versions_system_sharing
571 p = Project.find(5)
567 p = Project.find(5)
572 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
568 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
573 assert p.shared_versions.include?(v)
569 assert p.shared_versions.include?(v)
574 assert p.children.first.shared_versions.include?(v)
570 assert p.children.first.shared_versions.include?(v)
575 assert p.root.shared_versions.include?(v)
571 assert p.root.shared_versions.include?(v)
576 assert p.siblings.first.shared_versions.include?(v)
572 assert p.siblings.first.shared_versions.include?(v)
577 assert p.root.siblings.first.shared_versions.include?(v)
573 assert p.root.siblings.first.shared_versions.include?(v)
578 end
574 end
579
575
580 def test_shared_versions
576 def test_shared_versions
581 parent = Project.find(1)
577 parent = Project.find(1)
582 child = parent.children.find(3)
578 child = parent.children.find(3)
583 private_child = parent.children.find(5)
579 private_child = parent.children.find(5)
584
580
585 assert_equal [1,2,3], parent.version_ids.sort
581 assert_equal [1,2,3], parent.version_ids.sort
586 assert_equal [4], child.version_ids
582 assert_equal [4], child.version_ids
587 assert_equal [6], private_child.version_ids
583 assert_equal [6], private_child.version_ids
588 assert_equal [7], Version.where(:sharing => 'system').collect(&:id)
584 assert_equal [7], Version.where(:sharing => 'system').collect(&:id)
589
585
590 assert_equal 6, parent.shared_versions.size
586 assert_equal 6, parent.shared_versions.size
591 parent.shared_versions.each do |version|
587 parent.shared_versions.each do |version|
592 assert_kind_of Version, version
588 assert_kind_of Version, version
593 end
589 end
594
590
595 assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort
591 assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort
596 end
592 end
597
593
598 def test_shared_versions_should_ignore_archived_subprojects
594 def test_shared_versions_should_ignore_archived_subprojects
599 parent = Project.find(1)
595 parent = Project.find(1)
600 child = parent.children.find(3)
596 child = parent.children.find(3)
601 child.archive
597 child.archive
602 parent.reload
598 parent.reload
603
599
604 assert_equal [1,2,3], parent.version_ids.sort
600 assert_equal [1,2,3], parent.version_ids.sort
605 assert_equal [4], child.version_ids
601 assert_equal [4], child.version_ids
606 assert !parent.shared_versions.collect(&:id).include?(4)
602 assert !parent.shared_versions.collect(&:id).include?(4)
607 end
603 end
608
604
609 def test_shared_versions_visible_to_user
605 def test_shared_versions_visible_to_user
610 user = User.find(3)
606 user = User.find(3)
611 parent = Project.find(1)
607 parent = Project.find(1)
612 child = parent.children.find(5)
608 child = parent.children.find(5)
613
609
614 assert_equal [1,2,3], parent.version_ids.sort
610 assert_equal [1,2,3], parent.version_ids.sort
615 assert_equal [6], child.version_ids
611 assert_equal [6], child.version_ids
616
612
617 versions = parent.shared_versions.visible(user)
613 versions = parent.shared_versions.visible(user)
618
614
619 assert_equal 4, versions.size
615 assert_equal 4, versions.size
620 versions.each do |version|
616 versions.each do |version|
621 assert_kind_of Version, version
617 assert_kind_of Version, version
622 end
618 end
623
619
624 assert !versions.collect(&:id).include?(6)
620 assert !versions.collect(&:id).include?(6)
625 end
621 end
626
622
627 def test_shared_versions_for_new_project_should_include_system_shared_versions
623 def test_shared_versions_for_new_project_should_include_system_shared_versions
628 p = Project.find(5)
624 p = Project.find(5)
629 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
625 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
630
626
631 assert_include v, Project.new.shared_versions
627 assert_include v, Project.new.shared_versions
632 end
628 end
633
629
634 def test_next_identifier
630 def test_next_identifier
635 ProjectCustomField.delete_all
631 ProjectCustomField.delete_all
636 Project.create!(:name => 'last', :identifier => 'p2008040')
632 Project.create!(:name => 'last', :identifier => 'p2008040')
637 assert_equal 'p2008041', Project.next_identifier
633 assert_equal 'p2008041', Project.next_identifier
638 end
634 end
639
635
640 def test_next_identifier_first_project
636 def test_next_identifier_first_project
641 Project.delete_all
637 Project.delete_all
642 assert_nil Project.next_identifier
638 assert_nil Project.next_identifier
643 end
639 end
644
640
645 def test_enabled_module_names
641 def test_enabled_module_names
646 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
642 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
647 project = Project.new
643 project = Project.new
648
644
649 project.enabled_module_names = %w(issue_tracking news)
645 project.enabled_module_names = %w(issue_tracking news)
650 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
646 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
651 end
647 end
652 end
648 end
653
649
654 test "enabled_modules should define module by names and preserve ids" do
650 test "enabled_modules should define module by names and preserve ids" do
655 @project = Project.find(1)
651 @project = Project.find(1)
656 # Remove one module
652 # Remove one module
657 modules = @project.enabled_modules.slice(0..-2)
653 modules = @project.enabled_modules.slice(0..-2)
658 assert modules.any?
654 assert modules.any?
659 assert_difference 'EnabledModule.count', -1 do
655 assert_difference 'EnabledModule.count', -1 do
660 @project.enabled_module_names = modules.collect(&:name)
656 @project.enabled_module_names = modules.collect(&:name)
661 end
657 end
662 @project.reload
658 @project.reload
663 # Ids should be preserved
659 # Ids should be preserved
664 assert_equal @project.enabled_module_ids.sort, modules.collect(&:id).sort
660 assert_equal @project.enabled_module_ids.sort, modules.collect(&:id).sort
665 end
661 end
666
662
667 test "enabled_modules should enable a module" do
663 test "enabled_modules should enable a module" do
668 @project = Project.find(1)
664 @project = Project.find(1)
669 @project.enabled_module_names = []
665 @project.enabled_module_names = []
670 @project.reload
666 @project.reload
671 assert_equal [], @project.enabled_module_names
667 assert_equal [], @project.enabled_module_names
672 #with string
668 #with string
673 @project.enable_module!("issue_tracking")
669 @project.enable_module!("issue_tracking")
674 assert_equal ["issue_tracking"], @project.enabled_module_names
670 assert_equal ["issue_tracking"], @project.enabled_module_names
675 #with symbol
671 #with symbol
676 @project.enable_module!(:gantt)
672 @project.enable_module!(:gantt)
677 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
673 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
678 #don't add a module twice
674 #don't add a module twice
679 @project.enable_module!("issue_tracking")
675 @project.enable_module!("issue_tracking")
680 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
676 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
681 end
677 end
682
678
683 test "enabled_modules should disable a module" do
679 test "enabled_modules should disable a module" do
684 @project = Project.find(1)
680 @project = Project.find(1)
685 #with string
681 #with string
686 assert @project.enabled_module_names.include?("issue_tracking")
682 assert @project.enabled_module_names.include?("issue_tracking")
687 @project.disable_module!("issue_tracking")
683 @project.disable_module!("issue_tracking")
688 assert ! @project.reload.enabled_module_names.include?("issue_tracking")
684 assert ! @project.reload.enabled_module_names.include?("issue_tracking")
689 #with symbol
685 #with symbol
690 assert @project.enabled_module_names.include?("gantt")
686 assert @project.enabled_module_names.include?("gantt")
691 @project.disable_module!(:gantt)
687 @project.disable_module!(:gantt)
692 assert ! @project.reload.enabled_module_names.include?("gantt")
688 assert ! @project.reload.enabled_module_names.include?("gantt")
693 #with EnabledModule object
689 #with EnabledModule object
694 first_module = @project.enabled_modules.first
690 first_module = @project.enabled_modules.first
695 @project.disable_module!(first_module)
691 @project.disable_module!(first_module)
696 assert ! @project.reload.enabled_module_names.include?(first_module.name)
692 assert ! @project.reload.enabled_module_names.include?(first_module.name)
697 end
693 end
698
694
699 def test_enabled_module_names_should_not_recreate_enabled_modules
695 def test_enabled_module_names_should_not_recreate_enabled_modules
700 project = Project.find(1)
696 project = Project.find(1)
701 # Remove one module
697 # Remove one module
702 modules = project.enabled_modules.slice(0..-2)
698 modules = project.enabled_modules.slice(0..-2)
703 assert modules.any?
699 assert modules.any?
704 assert_difference 'EnabledModule.count', -1 do
700 assert_difference 'EnabledModule.count', -1 do
705 project.enabled_module_names = modules.collect(&:name)
701 project.enabled_module_names = modules.collect(&:name)
706 end
702 end
707 project.reload
703 project.reload
708 # Ids should be preserved
704 # Ids should be preserved
709 assert_equal project.enabled_module_ids.sort, modules.collect(&:id).sort
705 assert_equal project.enabled_module_ids.sort, modules.collect(&:id).sort
710 end
706 end
711
707
712 def test_copy_from_existing_project
708 def test_copy_from_existing_project
713 source_project = Project.find(1)
709 source_project = Project.find(1)
714 copied_project = Project.copy_from(1)
710 copied_project = Project.copy_from(1)
715
711
716 assert copied_project
712 assert copied_project
717 # Cleared attributes
713 # Cleared attributes
718 assert copied_project.id.blank?
714 assert copied_project.id.blank?
719 assert copied_project.name.blank?
715 assert copied_project.name.blank?
720 assert copied_project.identifier.blank?
716 assert copied_project.identifier.blank?
721
717
722 # Duplicated attributes
718 # Duplicated attributes
723 assert_equal source_project.description, copied_project.description
719 assert_equal source_project.description, copied_project.description
724 assert_equal source_project.enabled_modules, copied_project.enabled_modules
720 assert_equal source_project.enabled_modules, copied_project.enabled_modules
725 assert_equal source_project.trackers, copied_project.trackers
721 assert_equal source_project.trackers, copied_project.trackers
726
722
727 # Default attributes
723 # Default attributes
728 assert_equal 1, copied_project.status
724 assert_equal 1, copied_project.status
729 end
725 end
730
726
731 def test_activities_should_use_the_system_activities
727 def test_activities_should_use_the_system_activities
732 project = Project.find(1)
728 project = Project.find(1)
733 assert_equal project.activities.to_a, TimeEntryActivity.where(:active => true).to_a
729 assert_equal project.activities.to_a, TimeEntryActivity.where(:active => true).to_a
734 assert_kind_of ActiveRecord::Relation, project.activities
730 assert_kind_of ActiveRecord::Relation, project.activities
735 end
731 end
736
732
737
733
738 def test_activities_should_use_the_project_specific_activities
734 def test_activities_should_use_the_project_specific_activities
739 project = Project.find(1)
735 project = Project.find(1)
740 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project})
736 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project})
741 assert overridden_activity.save!
737 assert overridden_activity.save!
742
738
743 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
739 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
744 assert_kind_of ActiveRecord::Relation, project.activities
740 assert_kind_of ActiveRecord::Relation, project.activities
745 end
741 end
746
742
747 def test_activities_should_not_include_the_inactive_project_specific_activities
743 def test_activities_should_not_include_the_inactive_project_specific_activities
748 project = Project.find(1)
744 project = Project.find(1)
749 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
745 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
750 assert overridden_activity.save!
746 assert overridden_activity.save!
751
747
752 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found"
748 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found"
753 end
749 end
754
750
755 def test_activities_should_not_include_project_specific_activities_from_other_projects
751 def test_activities_should_not_include_project_specific_activities_from_other_projects
756 project = Project.find(1)
752 project = Project.find(1)
757 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)})
753 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)})
758 assert overridden_activity.save!
754 assert overridden_activity.save!
759
755
760 assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project"
756 assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project"
761 end
757 end
762
758
763 def test_activities_should_handle_nils
759 def test_activities_should_handle_nils
764 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(1), :parent => TimeEntryActivity.first})
760 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(1), :parent => TimeEntryActivity.first})
765 TimeEntryActivity.delete_all
761 TimeEntryActivity.delete_all
766
762
767 # No activities
763 # No activities
768 project = Project.find(1)
764 project = Project.find(1)
769 assert project.activities.empty?
765 assert project.activities.empty?
770
766
771 # No system, one overridden
767 # No system, one overridden
772 assert overridden_activity.save!
768 assert overridden_activity.save!
773 project.reload
769 project.reload
774 assert_equal [overridden_activity], project.activities
770 assert_equal [overridden_activity], project.activities
775 end
771 end
776
772
777 def test_activities_should_override_system_activities_with_project_activities
773 def test_activities_should_override_system_activities_with_project_activities
778 project = Project.find(1)
774 project = Project.find(1)
779 parent_activity = TimeEntryActivity.first
775 parent_activity = TimeEntryActivity.first
780 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity})
776 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity})
781 assert overridden_activity.save!
777 assert overridden_activity.save!
782
778
783 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
779 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
784 assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden"
780 assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden"
785 end
781 end
786
782
787 def test_activities_should_include_inactive_activities_if_specified
783 def test_activities_should_include_inactive_activities_if_specified
788 project = Project.find(1)
784 project = Project.find(1)
789 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
785 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
790 assert overridden_activity.save!
786 assert overridden_activity.save!
791
787
792 assert project.activities(true).include?(overridden_activity), "Inactive Project specific Activity not found"
788 assert project.activities(true).include?(overridden_activity), "Inactive Project specific Activity not found"
793 end
789 end
794
790
795 test 'activities should not include active System activities if the project has an override that is inactive' do
791 test 'activities should not include active System activities if the project has an override that is inactive' do
796 project = Project.find(1)
792 project = Project.find(1)
797 system_activity = TimeEntryActivity.find_by_name('Design')
793 system_activity = TimeEntryActivity.find_by_name('Design')
798 assert system_activity.active?
794 assert system_activity.active?
799 overridden_activity = TimeEntryActivity.create!(:name => "Project", :project => project, :parent => system_activity, :active => false)
795 overridden_activity = TimeEntryActivity.create!(:name => "Project", :project => project, :parent => system_activity, :active => false)
800 assert overridden_activity.save!
796 assert overridden_activity.save!
801
797
802 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found"
798 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found"
803 assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override"
799 assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override"
804 end
800 end
805
801
806 def test_close_completed_versions
802 def test_close_completed_versions
807 Version.update_all("status = 'open'")
803 Version.update_all("status = 'open'")
808 project = Project.find(1)
804 project = Project.find(1)
809 assert_not_nil project.versions.detect {|v| v.completed? && v.status == 'open'}
805 assert_not_nil project.versions.detect {|v| v.completed? && v.status == 'open'}
810 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
806 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
811 project.close_completed_versions
807 project.close_completed_versions
812 project.reload
808 project.reload
813 assert_nil project.versions.detect {|v| v.completed? && v.status != 'closed'}
809 assert_nil project.versions.detect {|v| v.completed? && v.status != 'closed'}
814 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
810 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
815 end
811 end
816
812
817 test "#start_date should be nil if there are no issues on the project" do
813 test "#start_date should be nil if there are no issues on the project" do
818 project = Project.generate!
814 project = Project.generate!
819 assert_nil project.start_date
815 assert_nil project.start_date
820 end
816 end
821
817
822 test "#start_date should be nil when issues have no start date" do
818 test "#start_date should be nil when issues have no start date" do
823 project = Project.generate!
819 project = Project.generate!
824 project.trackers << Tracker.generate!
820 project.trackers << Tracker.generate!
825 early = 7.days.ago.to_date
821 early = 7.days.ago.to_date
826 Issue.generate!(:project => project, :start_date => nil)
822 Issue.generate!(:project => project, :start_date => nil)
827
823
828 assert_nil project.start_date
824 assert_nil project.start_date
829 end
825 end
830
826
831 test "#start_date should be the earliest start date of it's issues" do
827 test "#start_date should be the earliest start date of it's issues" do
832 project = Project.generate!
828 project = Project.generate!
833 project.trackers << Tracker.generate!
829 project.trackers << Tracker.generate!
834 early = 7.days.ago.to_date
830 early = 7.days.ago.to_date
835 Issue.generate!(:project => project, :start_date => Date.today)
831 Issue.generate!(:project => project, :start_date => Date.today)
836 Issue.generate!(:project => project, :start_date => early)
832 Issue.generate!(:project => project, :start_date => early)
837
833
838 assert_equal early, project.start_date
834 assert_equal early, project.start_date
839 end
835 end
840
836
841 test "#due_date should be nil if there are no issues on the project" do
837 test "#due_date should be nil if there are no issues on the project" do
842 project = Project.generate!
838 project = Project.generate!
843 assert_nil project.due_date
839 assert_nil project.due_date
844 end
840 end
845
841
846 test "#due_date should be nil if there are no issues with due dates" do
842 test "#due_date should be nil if there are no issues with due dates" do
847 project = Project.generate!
843 project = Project.generate!
848 project.trackers << Tracker.generate!
844 project.trackers << Tracker.generate!
849 Issue.generate!(:project => project, :due_date => nil)
845 Issue.generate!(:project => project, :due_date => nil)
850
846
851 assert_nil project.due_date
847 assert_nil project.due_date
852 end
848 end
853
849
854 test "#due_date should be the latest due date of it's issues" do
850 test "#due_date should be the latest due date of it's issues" do
855 project = Project.generate!
851 project = Project.generate!
856 project.trackers << Tracker.generate!
852 project.trackers << Tracker.generate!
857 future = 7.days.from_now.to_date
853 future = 7.days.from_now.to_date
858 Issue.generate!(:project => project, :due_date => future)
854 Issue.generate!(:project => project, :due_date => future)
859 Issue.generate!(:project => project, :due_date => Date.today)
855 Issue.generate!(:project => project, :due_date => Date.today)
860
856
861 assert_equal future, project.due_date
857 assert_equal future, project.due_date
862 end
858 end
863
859
864 test "#due_date should be the latest due date of it's versions" do
860 test "#due_date should be the latest due date of it's versions" do
865 project = Project.generate!
861 project = Project.generate!
866 future = 7.days.from_now.to_date
862 future = 7.days.from_now.to_date
867 project.versions << Version.generate!(:effective_date => future)
863 project.versions << Version.generate!(:effective_date => future)
868 project.versions << Version.generate!(:effective_date => Date.today)
864 project.versions << Version.generate!(:effective_date => Date.today)
869
865
870 assert_equal future, project.due_date
866 assert_equal future, project.due_date
871 end
867 end
872
868
873 test "#due_date should pick the latest date from it's issues and versions" do
869 test "#due_date should pick the latest date from it's issues and versions" do
874 project = Project.generate!
870 project = Project.generate!
875 project.trackers << Tracker.generate!
871 project.trackers << Tracker.generate!
876 future = 7.days.from_now.to_date
872 future = 7.days.from_now.to_date
877 far_future = 14.days.from_now.to_date
873 far_future = 14.days.from_now.to_date
878 Issue.generate!(:project => project, :due_date => far_future)
874 Issue.generate!(:project => project, :due_date => far_future)
879 project.versions << Version.generate!(:effective_date => future)
875 project.versions << Version.generate!(:effective_date => future)
880
876
881 assert_equal far_future, project.due_date
877 assert_equal far_future, project.due_date
882 end
878 end
883
879
884 test "#completed_percent with no versions should be 100" do
880 test "#completed_percent with no versions should be 100" do
885 project = Project.generate!
881 project = Project.generate!
886 assert_equal 100, project.completed_percent
882 assert_equal 100, project.completed_percent
887 end
883 end
888
884
889 test "#completed_percent with versions should return 0 if the versions have no issues" do
885 test "#completed_percent with versions should return 0 if the versions have no issues" do
890 project = Project.generate!
886 project = Project.generate!
891 Version.generate!(:project => project)
887 Version.generate!(:project => project)
892 Version.generate!(:project => project)
888 Version.generate!(:project => project)
893
889
894 assert_equal 0, project.completed_percent
890 assert_equal 0, project.completed_percent
895 end
891 end
896
892
897 test "#completed_percent with versions should return 100 if the version has only closed issues" do
893 test "#completed_percent with versions should return 100 if the version has only closed issues" do
898 project = Project.generate!
894 project = Project.generate!
899 project.trackers << Tracker.generate!
895 project.trackers << Tracker.generate!
900 v1 = Version.generate!(:project => project)
896 v1 = Version.generate!(:project => project)
901 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1)
897 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1)
902 v2 = Version.generate!(:project => project)
898 v2 = Version.generate!(:project => project)
903 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2)
899 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2)
904
900
905 assert_equal 100, project.completed_percent
901 assert_equal 100, project.completed_percent
906 end
902 end
907
903
908 test "#completed_percent with versions should return the averaged completed percent of the versions (not weighted)" do
904 test "#completed_percent with versions should return the averaged completed percent of the versions (not weighted)" do
909 project = Project.generate!
905 project = Project.generate!
910 project.trackers << Tracker.generate!
906 project.trackers << Tracker.generate!
911 v1 = Version.generate!(:project => project)
907 v1 = Version.generate!(:project => project)
912 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1)
908 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1)
913 v2 = Version.generate!(:project => project)
909 v2 = Version.generate!(:project => project)
914 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2)
910 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2)
915
911
916 assert_equal 50, project.completed_percent
912 assert_equal 50, project.completed_percent
917 end
913 end
918
914
919 test "#notified_users" do
915 test "#notified_users" do
920 project = Project.generate!
916 project = Project.generate!
921 role = Role.generate!
917 role = Role.generate!
922
918
923 user_with_membership_notification = User.generate!(:mail_notification => 'selected')
919 user_with_membership_notification = User.generate!(:mail_notification => 'selected')
924 Member.create!(:project => project, :roles => [role], :principal => user_with_membership_notification, :mail_notification => true)
920 Member.create!(:project => project, :roles => [role], :principal => user_with_membership_notification, :mail_notification => true)
925
921
926 all_events_user = User.generate!(:mail_notification => 'all')
922 all_events_user = User.generate!(:mail_notification => 'all')
927 Member.create!(:project => project, :roles => [role], :principal => all_events_user)
923 Member.create!(:project => project, :roles => [role], :principal => all_events_user)
928
924
929 no_events_user = User.generate!(:mail_notification => 'none')
925 no_events_user = User.generate!(:mail_notification => 'none')
930 Member.create!(:project => project, :roles => [role], :principal => no_events_user)
926 Member.create!(:project => project, :roles => [role], :principal => no_events_user)
931
927
932 only_my_events_user = User.generate!(:mail_notification => 'only_my_events')
928 only_my_events_user = User.generate!(:mail_notification => 'only_my_events')
933 Member.create!(:project => project, :roles => [role], :principal => only_my_events_user)
929 Member.create!(:project => project, :roles => [role], :principal => only_my_events_user)
934
930
935 only_assigned_user = User.generate!(:mail_notification => 'only_assigned')
931 only_assigned_user = User.generate!(:mail_notification => 'only_assigned')
936 Member.create!(:project => project, :roles => [role], :principal => only_assigned_user)
932 Member.create!(:project => project, :roles => [role], :principal => only_assigned_user)
937
933
938 only_owned_user = User.generate!(:mail_notification => 'only_owner')
934 only_owned_user = User.generate!(:mail_notification => 'only_owner')
939 Member.create!(:project => project, :roles => [role], :principal => only_owned_user)
935 Member.create!(:project => project, :roles => [role], :principal => only_owned_user)
940
936
941 assert project.notified_users.include?(user_with_membership_notification), "should include members with a mail notification"
937 assert project.notified_users.include?(user_with_membership_notification), "should include members with a mail notification"
942 assert project.notified_users.include?(all_events_user), "should include users with the 'all' notification option"
938 assert project.notified_users.include?(all_events_user), "should include users with the 'all' notification option"
943 assert !project.notified_users.include?(no_events_user), "should not include users with the 'none' notification option"
939 assert !project.notified_users.include?(no_events_user), "should not include users with the 'none' notification option"
944 assert !project.notified_users.include?(only_my_events_user), "should not include users with the 'only_my_events' notification option"
940 assert !project.notified_users.include?(only_my_events_user), "should not include users with the 'only_my_events' notification option"
945 assert !project.notified_users.include?(only_assigned_user), "should not include users with the 'only_assigned' notification option"
941 assert !project.notified_users.include?(only_assigned_user), "should not include users with the 'only_assigned' notification option"
946 assert !project.notified_users.include?(only_owned_user), "should not include users with the 'only_owner' notification option"
942 assert !project.notified_users.include?(only_owned_user), "should not include users with the 'only_owner' notification option"
947 end
943 end
948
944
949 def test_override_roles_without_builtin_group_memberships
945 def test_override_roles_without_builtin_group_memberships
950 project = Project.generate!
946 project = Project.generate!
951 assert_equal [Role.anonymous], project.override_roles(Role.anonymous)
947 assert_equal [Role.anonymous], project.override_roles(Role.anonymous)
952 assert_equal [Role.non_member], project.override_roles(Role.non_member)
948 assert_equal [Role.non_member], project.override_roles(Role.non_member)
953 end
949 end
954 end
950 end
General Comments 0
You need to be logged in to leave comments. Login now