Skip to content

Commit 6865f1c

Browse files
joerg1985diemol
andauthored
[grid][java] do not rely on .hashCode for .equals (#12361)
Co-authored-by: Diego Molina <diemol@users.noreply.github.com>
1 parent f13370b commit 6865f1c

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

java/src/org/openqa/selenium/SharedCapabilitiesMethods.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,39 @@
1717

1818
package org.openqa.selenium;
1919

20+
import java.util.Arrays;
2021
import java.util.Collection;
2122
import java.util.Comparator;
2223
import java.util.IdentityHashMap;
2324
import java.util.Map;
24-
import java.util.Objects;
2525
import java.util.stream.Collectors;
2626
import java.util.stream.Stream;
2727
import org.openqa.selenium.logging.LogLevelMapping;
2828
import org.openqa.selenium.logging.LoggingPreferences;
2929

3030
class SharedCapabilitiesMethods {
3131

32+
private static final String[] EMPTY_ARRAY = new String[0];
33+
3234
private SharedCapabilitiesMethods() {
3335
// Utility class
3436
}
3537

3638
static int hashCode(Capabilities caps) {
37-
return caps.getCapabilityNames().stream()
38-
.sorted()
39-
.mapToInt(name -> Objects.hash(name, caps.getCapability(name)))
40-
.reduce(0, (l, r) -> l ^ r);
39+
String[] sortedNames = caps.getCapabilityNames().toArray(EMPTY_ARRAY);
40+
Arrays.sort(sortedNames, String::compareTo);
41+
// we only use the names to generate a hash code, this might result in hash collisions. thanks to the
42+
// moz:firefoxOptions, goog:chromeOptions and ms:edgeOptions, these hash collisions should not happen too often.
43+
return Arrays.hashCode(sortedNames);
4144
}
4245

4346
static boolean equals(Capabilities left, Capabilities right) {
44-
return left.hashCode() == right.hashCode();
47+
if (left == right) {
48+
return true;
49+
}
50+
// deeply compare the keys & values, usually only called when the hash codes of two objects are identical.
51+
// note: there should be no arrays (directly or nested) inside the map, otherwise the equals will not work.
52+
return left.asMap().equals(right.asMap());
4553
}
4654

4755
static void setCapability(Map<String, Object> caps, String key, Object value) {

java/test/org/openqa/selenium/CapabilitiesTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,13 @@ void ensureHashCodesAreEqual() {
129129
assertThat(one.hashCode()).isEqualTo(three.hashCode());
130130
assertThat(two.hashCode()).isEqualTo(three.hashCode());
131131
}
132+
133+
@Test
134+
void ensureEqualHashCodesMightBeNotEqual() {
135+
Capabilities one = new ImmutableCapabilities("key", "DB");
136+
Capabilities two = new ImmutableCapabilities("key", "Ca");
137+
138+
assertThat(one.hashCode()).isEqualTo(two.hashCode());
139+
assertThat(one).isNotEqualTo(two);
140+
}
132141
}

0 commit comments

Comments
 (0)