Skip to content

Commit 11189e9

Browse files
Fix NPE when evaluating objects that can lead to cycle/infinite recursion (#1868)
1 parent a64f3fb commit 11189e9

File tree

5 files changed

+79
-3
lines changed

5 files changed

+79
-3
lines changed

src/main/java/org/assertj/core/api/recursive/comparison/DualValue.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,10 @@ private static boolean isPotentialCyclingValue(Object object) {
222222
if (object == null) return false;
223223
// java.lang are base types that can't cycle to themselves of other types
224224
// we could check more type, but that's a good start
225-
return !object.getClass().getCanonicalName().startsWith("java.lang");
225+
String canonicalName = object.getClass().getCanonicalName();
226+
// canonicalName is null for anonymous and local classes, return true as they can cycle back to other objects.
227+
if (canonicalName == null) return true;
228+
return !canonicalName.startsWith("java.lang");
226229
}
227230

228231
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3+
* the License. You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
* specific language governing permissions and limitations under the License.
10+
*
11+
* Copyright 2012-2020 the original author or authors.
12+
*/
13+
package org.assertj.core.api.recursive.comparison;
14+
15+
import static org.assertj.core.api.recursive.comparison.ColorWithCode.GREEN;
16+
17+
enum ColorWithCode {
18+
RED {
19+
@Override
20+
String code() {
21+
return "#FF0000";
22+
}
23+
},
24+
GREEN {
25+
@Override
26+
String code() {
27+
return "#00FF00";
28+
}
29+
},
30+
BLUE {
31+
@Override
32+
String code() {
33+
return "#0000FF";
34+
}
35+
};
36+
37+
abstract String code();
38+
39+
}
40+
41+
class Theme {
42+
ColorWithCode color = GREEN;
43+
44+
public Theme(ColorWithCode color) {
45+
this.color = color;
46+
}
47+
48+
}

src/test/java/org/assertj/core/api/recursive/comparison/DualValue_hasPotentialCyclingValues_Test.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
package org.assertj.core.api.recursive.comparison;
1414

1515
import static org.assertj.core.api.BDDAssertions.then;
16+
import static org.assertj.core.api.recursive.comparison.Color.GREEN;
17+
import static org.assertj.core.api.recursive.comparison.ColorWithCode.RED;
1618
import static org.assertj.core.util.Lists.list;
1719

1820
import java.util.List;
@@ -49,6 +51,13 @@ static Stream<Arguments> values() {
4951
person2.otherFriends.add(person2);
5052
person2.otherFriends.add(person1);
5153

54+
class LocalClass {
55+
@Override
56+
public String toString() {
57+
return "LocalClass";
58+
}
59+
}
60+
5261
return Stream.of(Arguments.of(null, person2, false),
5362
Arguments.of(person1, null, false),
5463
Arguments.of(person1, "abc", false),
@@ -64,6 +73,20 @@ static Stream<Arguments> values() {
6473
Arguments.of(person1, person2, true),
6574
Arguments.of(list(person1), list(person1), true),
6675
Arguments.of(list(person1), list(person2), true),
76+
Arguments.of(new LocalClass(), new LocalClass(), true),
77+
Arguments.of(new Light(GREEN), new Light(GREEN), true),
78+
Arguments.of(new Theme(RED), new Theme(RED), true), // for #1866
79+
Arguments.of(new DualValue_hasPotentialCyclingValues_Test().new Inner(),
80+
new DualValue_hasPotentialCyclingValues_Test().new Inner(), true),
6781
Arguments.of(list(person1, person2), list(person2, person1), true));
6882
}
83+
84+
class Inner {
85+
@Override
86+
public String toString() {
87+
return "Inner Class";
88+
}
89+
90+
}
91+
6992
}

src/test/java/org/assertj/core/api/recursive/comparison/RecursiveComparisonAssert_isEqualTo_Test.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static org.assertj.core.api.BDDAssertions.then;
1818
import static org.assertj.core.api.recursive.comparison.Color.BLUE;
1919
import static org.assertj.core.api.recursive.comparison.Color.GREEN;
20+
import static org.assertj.core.api.recursive.comparison.ColorWithCode.RED;
2021
import static org.assertj.core.error.ShouldBeEqual.shouldBeEqual;
2122
import static org.assertj.core.error.ShouldNotBeNull.shouldNotBeNull;
2223
import static org.assertj.core.test.AlwaysEqualComparator.ALWAY_EQUALS_STRING;
@@ -171,6 +172,7 @@ private static Stream<Arguments> recursivelyEqualObjects() {
171172
return Stream.of(arguments(person1, person2, "same data, same type"),
172173
arguments(person2, person1, "same data, same type reversed"),
173174
arguments(person3, person4, "same data, different type"),
175+
arguments(new Theme(RED), new Theme(RED), "same data with enum overriding methods - covers #1866"),
174176
arguments(person4, person3, "same data, different type"));
175177
}
176178

src/test/java/org/assertj/core/internal/objects/data/FriendlyPerson.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ public class FriendlyPerson extends Person {
2222
public Set<FriendlyPerson> otherFriends = new HashSet<>();
2323

2424
public FriendlyPerson() {
25-
super();
25+
super();
2626
}
2727

2828
public FriendlyPerson(String name) {
29-
super(name);
29+
super(name);
3030
}
3131

3232
public static FriendlyPerson friend(String name) {

0 commit comments

Comments
 (0)