<=> operator should return nil when invoked with an incomparable object (#38772).

Patch by Go MAEDA.


git-svn-id: https://svn.redmine.org/redmine/trunk@22269 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Go MAEDA
2023-06-29 14:42:54 +00:00
parent ebf3fb3b4f
commit 945a82b5c0
16 changed files with 45 additions and 13 deletions

View File

@@ -263,6 +263,8 @@ class CustomField < ActiveRecord::Base
end end
def <=>(field) def <=>(field)
return nil unless field.is_a?(CustomField)
position <=> field.position position <=> field.position
end end

View File

@@ -91,6 +91,8 @@ class Enumeration < ActiveRecord::Base
end end
def <=>(enumeration) def <=>(enumeration)
return nil unless enumeration.is_a?(Enumeration)
position <=> enumeration.position position <=> enumeration.position
end end

View File

@@ -1435,9 +1435,9 @@ class Issue < ActiveRecord::Base
end end
def <=>(issue) def <=>(issue)
if issue.nil? return nil unless issue.is_a?(Issue)
-1
elsif root_id != issue.root_id if root_id != issue.root_id
(root_id || 0) <=> (issue.root_id || 0) (root_id || 0) <=> (issue.root_id || 0)
else else
(lft || 0) <=> (issue.lft || 0) (lft || 0) <=> (issue.lft || 0)

View File

@@ -43,6 +43,8 @@ class IssueCategory < ActiveRecord::Base
end end
def <=>(category) def <=>(category)
return nil unless category.is_a?(IssueCategory)
name <=> category.name name <=> category.name
end end

View File

@@ -198,6 +198,8 @@ class IssueRelation < ActiveRecord::Base
end end
def <=>(relation) def <=>(relation)
return nil unless relation.is_a?(IssueRelation)
r = TYPES[self.relation_type][:order] <=> TYPES[relation.relation_type][:order] r = TYPES[self.relation_type][:order] <=> TYPES[relation.relation_type][:order]
r == 0 ? id <=> relation.id : r r == 0 ? id <=> relation.id : r
end end

View File

@@ -82,6 +82,8 @@ class IssueStatus < ActiveRecord::Base
end end
def <=>(status) def <=>(status)
return nil unless status.is_a?(IssueStatus)
position <=> status.position position <=> status.position
end end

View File

@@ -81,6 +81,8 @@ class Member < ActiveRecord::Base
end end
def <=>(member) def <=>(member)
return nil unless member.is_a?(Member)
a, b = roles.sort, member.roles.sort a, b = roles.sort, member.roles.sort
if a == b if a == b
if principal if principal

View File

@@ -151,9 +151,11 @@ class Principal < ActiveRecord::Base
end end
def <=>(principal) def <=>(principal)
if principal.nil? # avoid an error when sorting members without roles (#10053)
-1 return -1 if principal.nil?
elsif self.class.name == principal.class.name return nil unless principal.is_a?(Principal)
if self.class.name == principal.class.name
self.to_s.casecmp(principal.to_s) self.to_s.casecmp(principal.to_s)
else else
# groups after users # groups after users

View File

@@ -671,6 +671,8 @@ class Project < ActiveRecord::Base
end end
def <=>(project) def <=>(project)
return nil unless project.is_a?(Project)
name.casecmp(project.name) name.casecmp(project.name)
end end

View File

@@ -141,6 +141,8 @@ class Repository < ActiveRecord::Base
end end
def <=>(repository) def <=>(repository)
return nil unless repository.is_a?(Repository)
if is_default? if is_default?
-1 -1
elsif repository.is_default? elsif repository.is_default?

View File

@@ -155,14 +155,14 @@ class Role < ActiveRecord::Base
end end
def <=>(role) def <=>(role)
if role # returns -1 for nil since r2726
if builtin == role.builtin return -1 if role.nil?
position <=> role.position return nil unless role.is_a?(Role)
else
builtin <=> role.builtin if builtin == role.builtin
end position <=> role.position
else else
-1 builtin <=> role.builtin
end end
end end

View File

@@ -93,6 +93,8 @@ class Tracker < ActiveRecord::Base
def to_s; name end def to_s; name end
def <=>(tracker) def <=>(tracker)
return nil unless tracker.is_a?(Tracker)
position <=> tracker.position position <=> tracker.position
end end

View File

@@ -316,6 +316,8 @@ class Version < ActiveRecord::Base
# Versions are sorted by effective_date and name # Versions are sorted by effective_date and name
# Those with no effective_date are at the end, sorted by name # Those with no effective_date are at the end, sorted by name
def <=>(version) def <=>(version)
return nil unless version.is_a?(Version)
if self.effective_date if self.effective_date
if version.effective_date if version.effective_date
if self.effective_date == version.effective_date if self.effective_date == version.effective_date

View File

@@ -187,6 +187,8 @@ module Redmine
end end
def <=>(plugin) def <=>(plugin)
return nil unless plugin.is_a?(Plugin)
self.id.to_s <=> plugin.id.to_s self.id.to_s <=> plugin.id.to_s
end end

View File

@@ -61,6 +61,8 @@ module Redmine
end end
def <=>(theme) def <=>(theme)
return nil unless theme.is_a?(Theme)
name <=> theme.name name <=> theme.name
end end

View File

@@ -179,4 +179,10 @@ class EnumerationTest < ActiveSupport::TestCase
override.destroy override.destroy
assert_equal [1, 2, 3], [a, b, c].map(&:reload).map(&:position) assert_equal [1, 2, 3], [a, b, c].map(&:reload).map(&:position)
end end
def test_spaceship_operator_with_incomparable_value_should_return_nil
e = Enumeration.first
assert_nil e <=> nil
assert_nil e <=> 'foo'
end
end end