@@ -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't' |
|
40 | #ESCAPED_CANT = 'can't' | |
45 | #ESCAPED_UCANT = 'Can't' |
|
41 | #ESCAPED_UCANT = 'Can't' | |
46 | # Rails 4.0.2 |
|
42 | # Rails 4.0.2 | |
47 | ESCAPED_CANT = 'can't' |
|
43 | ESCAPED_CANT = 'can't' | |
48 | ESCAPED_UCANT = 'Can't' |
|
44 | ESCAPED_UCANT = 'Can'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_ |
|
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_ |
|
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_ |
|
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