custom_field_test.rb 13 KB
Newer Older
1
# frozen_string_literal: true
2

jplang's avatar
jplang committed
3
# Redmine - project management software
jplang's avatar
jplang committed
4
# Copyright (C) 2006-2017  Jean-Philippe Lang
5 6 7 8 9
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
10
#
11 12 13 14
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
15
#
16 17 18 19
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

20
require File.expand_path('../../test_helper', __FILE__)
21

edavis10's avatar
edavis10 committed
22
class CustomFieldTest < ActiveSupport::TestCase
23 24
  fixtures :custom_fields, :roles, :projects,
           :trackers, :issue_statuses,
25
           :issues, :users
26

27 28 29 30
  def setup
    User.current = nil
  end

31 32 33 34
  def test_create
    field = UserCustomField.new(:name => 'Money money money', :field_format => 'float')
    assert field.save
  end
35

36 37 38 39 40 41 42 43 44 45
  def test_before_validation
    field = CustomField.new(:name => 'test_before_validation', :field_format => 'int')
    field.searchable = true
    assert field.save
    assert_equal false, field.searchable
    field.searchable = true
    assert field.save
    assert_equal false, field.searchable
  end

jplang's avatar
jplang committed
46 47 48
  def test_regexp_validation
    field = IssueCustomField.new(:name => 'regexp', :field_format => 'text', :regexp => '[a-z0-9')
    assert !field.save
49 50
    assert_include I18n.t('activerecord.errors.messages.invalid'),
                   field.errors[:regexp]
jplang's avatar
jplang committed
51 52 53
    field.regexp = '[a-z0-9]'
    assert field.save
  end
54

55 56 57 58 59 60 61 62
  def test_default_value_should_be_validated
    field = CustomField.new(:name => 'Test', :field_format => 'int')
    field.default_value = 'abc'
    assert !field.valid?
    field.default_value = '6'
    assert field.valid?
  end

63
  def test_default_value_should_not_be_validated_when_blank
64 65 66
    field = CustomField.new(:name => 'Test', :field_format => 'list',
                            :possible_values => ['a', 'b'], :is_required => true,
                            :default_value => '')
67 68 69
    assert field.valid?
  end

70 71 72 73 74 75
  def test_field_format_should_be_validated
    field = CustomField.new(:name => 'Test', :field_format => 'foo')
    assert !field.valid?
  end

  def test_field_format_validation_should_accept_formats_added_at_runtime
76
    Redmine::FieldFormat.add 'foobar', Class.new(Redmine::FieldFormat::Base)
77 78 79 80

    field = CustomField.new(:name => 'Some Custom Field', :field_format => 'foobar')
    assert field.valid?, 'field should be valid'
  ensure
81
    Redmine::FieldFormat.delete 'foobar'
82 83
  end

84 85 86 87 88 89
  def test_should_not_change_field_format_of_existing_custom_field
    field = CustomField.find(1)
    field.field_format = 'int'
    assert_equal 'list', field.field_format
  end

90 91 92 93 94
  def test_possible_values_should_accept_an_array
    field = CustomField.new
    field.possible_values = ["One value", ""]
    assert_equal ["One value"], field.possible_values
  end
95

96 97 98 99 100 101
  def test_possible_values_should_stringify_values
    field = CustomField.new
    field.possible_values = [1, 2]
    assert_equal ["1", "2"], field.possible_values
  end

102 103 104 105 106
  def test_possible_values_should_accept_a_string
    field = CustomField.new
    field.possible_values = "One value"
    assert_equal ["One value"], field.possible_values
  end
107

108 109
  def test_possible_values_should_return_utf8_encoded_strings
    field = CustomField.new
110
    s = "Value".b
111 112 113 114 115
    field.possible_values = s
    assert_equal [s], field.possible_values
    assert_equal 'UTF-8', field.possible_values.first.encoding.name
  end

116 117 118 119 120
  def test_possible_values_should_accept_a_multiline_string
    field = CustomField.new
    field.possible_values = "One value\nAnd another one  \r\n \n"
    assert_equal ["One value", "And another one"], field.possible_values
  end
121

jplang's avatar
jplang committed
122 123 124 125 126 127
  def test_possible_values_stored_as_binary_should_be_utf8_encoded
    field = CustomField.find(11)
    assert_kind_of Array, field.possible_values
    assert field.possible_values.size > 0
    field.possible_values.each do |value|
      assert_equal "UTF-8", value.encoding.name
jplang's avatar
jplang committed
128 129 130
    end
  end

131 132 133 134
  def test_destroy
    field = CustomField.find(1)
    assert field.destroy
  end
jplang's avatar
jplang committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153

  def test_new_subclass_instance_should_return_an_instance
    f = CustomField.new_subclass_instance('IssueCustomField')
    assert_kind_of IssueCustomField, f
  end

  def test_new_subclass_instance_should_set_attributes
    f = CustomField.new_subclass_instance('IssueCustomField', :name => 'Test')
    assert_kind_of IssueCustomField, f
    assert_equal 'Test', f.name
  end

  def test_new_subclass_instance_with_invalid_class_name_should_return_nil
    assert_nil CustomField.new_subclass_instance('WrongClassName')
  end

  def test_new_subclass_instance_with_non_subclass_name_should_return_nil
    assert_nil CustomField.new_subclass_instance('Project')
  end
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

  def test_string_field_validation_with_blank_value
    f = CustomField.new(:field_format => 'string')

    assert f.valid_field_value?(nil)
    assert f.valid_field_value?('')

    f.is_required = true
    assert !f.valid_field_value?(nil)
    assert !f.valid_field_value?('')
  end

  def test_string_field_validation_with_min_and_max_lengths
    f = CustomField.new(:field_format => 'string', :min_length => 2, :max_length => 5)

    assert f.valid_field_value?(nil)
    assert f.valid_field_value?('')
171
    assert !f.valid_field_value?(' ')
172 173 174 175 176 177 178 179 180 181
    assert f.valid_field_value?('a' * 2)
    assert !f.valid_field_value?('a')
    assert !f.valid_field_value?('a' * 6)
  end

  def test_string_field_validation_with_regexp
    f = CustomField.new(:field_format => 'string', :regexp => '^[A-Z0-9]*$')

    assert f.valid_field_value?(nil)
    assert f.valid_field_value?('')
182
    assert !f.valid_field_value?(' ')
183 184 185 186 187 188 189 190 191
    assert f.valid_field_value?('ABC')
    assert !f.valid_field_value?('abc')
  end

  def test_date_field_validation
    f = CustomField.new(:field_format => 'date')

    assert f.valid_field_value?(nil)
    assert f.valid_field_value?('')
192
    assert !f.valid_field_value?(' ')
193 194 195 196 197 198 199 200 201 202
    assert f.valid_field_value?('1975-07-14')
    assert !f.valid_field_value?('1975-07-33')
    assert !f.valid_field_value?('abc')
  end

  def test_list_field_validation
    f = CustomField.new(:field_format => 'list', :possible_values => ['value1', 'value2'])

    assert f.valid_field_value?(nil)
    assert f.valid_field_value?('')
203
    assert !f.valid_field_value?(' ')
204 205 206 207 208 209 210 211 212
    assert f.valid_field_value?('value2')
    assert !f.valid_field_value?('abc')
  end

  def test_int_field_validation
    f = CustomField.new(:field_format => 'int')

    assert f.valid_field_value?(nil)
    assert f.valid_field_value?('')
213
    assert !f.valid_field_value?(' ')
214
    assert f.valid_field_value?('123')
215
    assert f.valid_field_value?(' 123 ')
216 217 218
    assert f.valid_field_value?('+123')
    assert f.valid_field_value?('-123')
    assert !f.valid_field_value?('6abc')
219
    assert f.valid_field_value?(123)
220 221 222 223 224 225 226
  end

  def test_float_field_validation
    f = CustomField.new(:field_format => 'float')

    assert f.valid_field_value?(nil)
    assert f.valid_field_value?('')
227
    assert !f.valid_field_value?(' ')
228
    assert f.valid_field_value?('11.2')
229
    assert f.valid_field_value?(' 11.2 ')
230 231 232
    assert f.valid_field_value?('-6.250')
    assert f.valid_field_value?('5')
    assert !f.valid_field_value?('6abc')
233
    assert f.valid_field_value?(11.2)
234
  end
235 236 237 238 239 240

  def test_multi_field_validation
    f = CustomField.new(:field_format => 'list', :multiple => 'true', :possible_values => ['value1', 'value2'])

    assert f.valid_field_value?(nil)
    assert f.valid_field_value?('')
241
    assert !f.valid_field_value?(' ')
242 243 244
    assert f.valid_field_value?([])
    assert f.valid_field_value?([nil])
    assert f.valid_field_value?([''])
245
    assert !f.valid_field_value?([' '])
246 247 248 249 250 251 252 253 254 255 256 257 258

    assert f.valid_field_value?('value2')
    assert !f.valid_field_value?('abc')

    assert f.valid_field_value?(['value2'])
    assert !f.valid_field_value?(['abc'])

    assert f.valid_field_value?(['', 'value2'])
    assert !f.valid_field_value?(['', 'abc'])

    assert f.valid_field_value?(['value1', 'value2'])
    assert !f.valid_field_value?(['value1', 'abc'])
  end
259

260
  def test_changing_multiple_to_false_should_delete_multiple_values
261 262 263 264 265 266 267 268 269 270 271 272
    field = ProjectCustomField.create!(:name => 'field', :field_format => 'list',
                                       :multiple => 'true',
                                       :possible_values => ['field1', 'field2'])
    other = ProjectCustomField.create!(:name => 'other', :field_format => 'list',
                                       :multiple => 'true',
                                       :possible_values => ['other1', 'other2'])
    item_with_multiple_values = Project.generate!(:custom_field_values =>
                                                   {field.id => ['field1', 'field2'],
                                                    other.id => ['other1', 'other2']})
    item_with_single_values = Project.generate!(:custom_field_values =>
                                                   {field.id => ['field1'],
                                                    other.id => ['other2']})
273 274 275 276 277 278 279 280 281 282 283
    assert_difference 'CustomValue.count', -1 do
      field.multiple = false
      field.save!
    end

    item_with_multiple_values = Project.find(item_with_multiple_values.id)
    assert_kind_of String, item_with_multiple_values.custom_field_value(field)
    assert_kind_of Array, item_with_multiple_values.custom_field_value(other)
    assert_equal 2, item_with_multiple_values.custom_field_value(other).size
  end

284
  def test_value_class_should_return_the_class_used_for_fields_values
jplang's avatar
jplang committed
285 286
    assert_equal User, CustomField.new(:field_format => 'user').value_class
    assert_equal Version, CustomField.new(:field_format => 'version').value_class
287 288 289
  end

  def test_value_class_should_return_nil_for_other_fields
jplang's avatar
jplang committed
290 291
    assert_nil CustomField.new(:field_format => 'text').value_class
    assert_nil CustomField.new.value_class
292
  end
293 294 295 296 297

  def test_value_from_keyword_for_list_custom_field
    field = CustomField.find(1)
    assert_equal 'PostgreSQL', field.value_from_keyword('postgresql', Issue.find(1))
  end
298 299

  def test_visibile_scope_with_admin_should_return_all_custom_fields
jplang's avatar
jplang committed
300
    admin = User.generate! {|user| user.admin = true}
301 302 303 304 305 306 307 308
    CustomField.delete_all
    fields = [
      CustomField.generate!(:visible => true),
      CustomField.generate!(:visible => false),
      CustomField.generate!(:visible => false, :role_ids => [1, 3]),
      CustomField.generate!(:visible => false, :role_ids => [1, 2]),
    ]

jplang's avatar
jplang committed
309
    assert_equal 4, CustomField.visible(admin).count
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
  end

  def test_visibile_scope_with_non_admin_user_should_return_visible_custom_fields
    CustomField.delete_all
    fields = [
      CustomField.generate!(:visible => true),
      CustomField.generate!(:visible => false),
      CustomField.generate!(:visible => false, :role_ids => [1, 3]),
      CustomField.generate!(:visible => false, :role_ids => [1, 2]),
    ]
    user = User.generate!
    User.add_to_project(user, Project.first, Role.find(3))

    assert_equal [fields[0], fields[2]], CustomField.visible(user).order("id").to_a
  end

  def test_visibile_scope_with_anonymous_user_should_return_visible_custom_fields
    CustomField.delete_all
    fields = [
      CustomField.generate!(:visible => true),
      CustomField.generate!(:visible => false),
      CustomField.generate!(:visible => false, :role_ids => [1, 3]),
      CustomField.generate!(:visible => false, :role_ids => [1, 2]),
    ]

    assert_equal [fields[0]], CustomField.visible(User.anonymous).order("id").to_a
  end
337 338 339

  def test_float_cast_blank_value_should_return_nil
    field = CustomField.new(:field_format => 'float')
340 341
    assert_nil field.cast_value(nil)
    assert_nil field.cast_value('')
342 343 344 345 346 347 348 349 350
  end

  def test_float_cast_valid_value_should_return_float
    field = CustomField.new(:field_format => 'float')
    assert_equal 12.0, field.cast_value('12')
    assert_equal 12.5, field.cast_value('12.5')
    assert_equal 12.5, field.cast_value('+12.5')
    assert_equal -12.5, field.cast_value('-12.5')
  end
maeda's avatar
maeda committed
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366

  def test_project_custom_field_visibility
    project_field = ProjectCustomField.generate!(:visible => false, :field_format => 'list', :possible_values => %w[a b c])
    project = Project.find(3)
    project.custom_field_values = { project_field.id => 'a' }

    # Admins can find projects with the field
    with_current_user(User.find(1)) do
      assert_includes Project.where(project_field.visibility_by_project_condition), project
    end

    # The field is not visible to normal users
    with_current_user(User.find(2)) do
      refute_includes Project.where(project_field.visibility_by_project_condition), project
    end
  end
367 368 369 370 371 372 373 374

  def test_full_text_formatting?
    field = IssueCustomField.create!(:name => 'Long text', :field_format => 'text', :text_formatting => 'full')
    assert field.full_text_formatting?

    field2 = IssueCustomField.create!(:name => 'Another long text', :field_format => 'text')
    assert !field2.full_text_formatting?
  end
375
end