Skip to content

Commit 8c356e3

Browse files
committed
Introduce an abstract base class for both Capabilities types
There's inconsitency between how `ImmutableCapabilities` and `MutableCapabilities` handle tasks such as turning themselves into strings. Since they are actually types of the same thing and they are meant to have shared behaviour, it's okay to introduce a common base class.
1 parent 80d35e0 commit 8c356e3

File tree

6 files changed

+112
-118
lines changed

6 files changed

+112
-118
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium;
19+
20+
import java.util.Collection;
21+
import java.util.Comparator;
22+
import java.util.IdentityHashMap;
23+
import java.util.Map;
24+
import java.util.TreeMap;
25+
import java.util.stream.Collectors;
26+
import java.util.stream.Stream;
27+
28+
abstract class AbstractCapabilities implements Capabilities {
29+
30+
protected final Map<String, Object> caps = new TreeMap<>();
31+
32+
@Override
33+
public String toString() {
34+
Map<Object, String> seen = new IdentityHashMap<>();
35+
return "Capabilities " + abbreviate(seen, caps);
36+
}
37+
38+
private String abbreviate(Map<Object, String> seen, Object stringify) {
39+
if (stringify == null) {
40+
return "null";
41+
}
42+
43+
StringBuilder value = new StringBuilder();
44+
45+
if (stringify.getClass().isArray()) {
46+
value.append("[");
47+
value.append(
48+
Stream.of((Object[]) stringify)
49+
.map(item -> abbreviate(seen, item))
50+
.collect(Collectors.joining(", ")));
51+
value.append("]");
52+
} else if (stringify instanceof Collection) {
53+
value.append("[");
54+
value.append(
55+
((Collection<?>) stringify).stream()
56+
.map(item -> abbreviate(seen, item))
57+
.collect(Collectors.joining(", ")));
58+
value.append("]");
59+
} else if (stringify instanceof Map) {
60+
value.append("{");
61+
value.append(
62+
((Map<?, ?>) stringify).entrySet().stream()
63+
.sorted(Comparator.comparing(entry -> String.valueOf(entry.getKey())))
64+
.map(entry -> String.valueOf(entry.getKey()) + ": " + abbreviate(seen, entry.getValue()))
65+
.collect(Collectors.joining(", ")));
66+
value.append("}");
67+
} else {
68+
String s = String.valueOf(stringify);
69+
if (s.length() > 30) {
70+
value.append(s.substring(0, 27)).append("...");
71+
} else {
72+
value.append(s);
73+
}
74+
}
75+
76+
seen.put(stringify, value.toString());
77+
return value.toString();
78+
}
79+
80+
}

java/client/src/org/openqa/selenium/BUCK

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ java_library(name = 'core',
3535
maven_coords = 'org.seleniumhq.selenium:selenium-api:' + SE_VERSION,
3636
maven_pom_template = ':template-pom',
3737
srcs = [
38+
'AbstractCapabilities.java',
3839
'Alert.java',
3940
'By.java',
4041
'Capabilities.java',

java/client/src/org/openqa/selenium/ImmutableCapabilities.java

+18-82
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,21 @@
1919

2020

2121
import java.io.Serializable;
22-
import java.lang.reflect.Array;
2322
import java.util.Collection;
2423
import java.util.Collections;
2524
import java.util.HashMap;
2625
import java.util.IdentityHashMap;
2726
import java.util.Map;
27+
import java.util.TreeMap;
28+
import java.util.stream.Collectors;
29+
import java.util.stream.Stream;
2830

29-
public class ImmutableCapabilities implements Capabilities, Serializable {
31+
public class ImmutableCapabilities extends AbstractCapabilities implements Serializable {
3032

3133
private static final long serialVersionUID = 665766108972704060L;
3234

33-
private final Map<String, Object> caps = new HashMap<>();
34-
35-
public ImmutableCapabilities() { }
35+
public ImmutableCapabilities() {
36+
}
3637

3738
public ImmutableCapabilities(String k, Object v) {
3839
caps.put(k, v);
@@ -49,16 +50,23 @@ public ImmutableCapabilities(String k1, Object v1, String k2, Object v2, String
4950
caps.put(k3, v3);
5051
}
5152

52-
public ImmutableCapabilities(String k1, Object v1, String k2, Object v2, String k3, Object v3,
53-
String k4, Object v4) {
53+
public ImmutableCapabilities(
54+
String k1, Object v1,
55+
String k2, Object v2,
56+
String k3, Object v3,
57+
String k4, Object v4) {
5458
caps.put(k1, v1);
5559
caps.put(k2, v2);
5660
caps.put(k3, v3);
5761
caps.put(k4, v4);
5862
}
5963

60-
public ImmutableCapabilities(String k1, Object v1, String k2, Object v2, String k3, Object v3,
61-
String k4, Object v4, String k5, Object v5) {
64+
public ImmutableCapabilities(
65+
String k1, Object v1,
66+
String k2, Object v2,
67+
String k3, Object v3,
68+
String k4, Object v4,
69+
String k5, Object v5) {
6270
caps.put(k1, v1);
6371
caps.put(k2, v2);
6472
caps.put(k3, v3);
@@ -128,76 +136,4 @@ public int hashCode() {
128136
return caps.hashCode();
129137
}
130138

131-
@Override
132-
public String toString() {
133-
Map<Object, String> seen = new IdentityHashMap<>();
134-
StringBuilder builder = new StringBuilder("Capabilities ");
135-
abbreviate(seen, builder, caps);
136-
return builder.toString();
137-
}
138-
139-
private void abbreviate(
140-
Map<Object, String> seen,
141-
StringBuilder builder,
142-
Object stringify) {
143-
144-
if (stringify == null) {
145-
builder.append("null");
146-
return;
147-
}
148-
149-
StringBuilder value = new StringBuilder();
150-
151-
if (stringify.getClass().isArray()) {
152-
Array ary = (Array) stringify;
153-
value.append("[");
154-
int length = Array.getLength(ary);
155-
for (int i = 0; i < length; i++) {
156-
abbreviate(seen, value, Array.get(ary, i));
157-
if (i < length - 1) {
158-
value.append(", ");
159-
}
160-
}
161-
value.append("]");
162-
} else if (stringify instanceof Collection) {
163-
Collection<?> c = (Collection<?>) stringify;
164-
value.append("[");
165-
int length = c.size();
166-
int i = 0;
167-
168-
for (Object o : c) {
169-
abbreviate(seen, value, o);
170-
if (i < length - 1) {
171-
value.append(", ");
172-
}
173-
i++;
174-
}
175-
value.append("]");
176-
} else if (stringify instanceof Map) {
177-
value.append("{");
178-
179-
Map<?, ?> m = (Map<?, ?>) stringify;
180-
int length = m.size();
181-
int i = 0;
182-
for (Map.Entry<?, ?> entry : m.entrySet()) {
183-
abbreviate(seen, value, entry.getKey());
184-
value.append("=");
185-
abbreviate(seen, value, entry.getValue());
186-
if (i < length - 1) {
187-
value.append(", ");
188-
}
189-
}
190-
value.append("}");
191-
} else {
192-
String s = String.valueOf(stringify);
193-
if (s.length() > 30) {
194-
value.append(s.substring(0, 27)).append("...");
195-
} else {
196-
value.append(s);
197-
}
198-
}
199-
200-
seen.put(stringify, value.toString());
201-
builder.append(value.toString());
202-
}
203-
}
139+
}

java/client/src/org/openqa/selenium/MutableCapabilities.java

+7-30
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,19 @@
2222
import org.openqa.selenium.logging.LoggingPreferences;
2323

2424
import java.io.Serializable;
25+
import java.util.Collection;
2526
import java.util.Collections;
26-
import java.util.HashMap;
27+
import java.util.Comparator;
2728
import java.util.HashSet;
29+
import java.util.IdentityHashMap;
2830
import java.util.Map;
2931
import java.util.Objects;
3032
import java.util.Set;
33+
import java.util.TreeMap;
34+
import java.util.stream.Collectors;
35+
import java.util.stream.Stream;
3136

32-
public class MutableCapabilities implements Capabilities, Serializable {
37+
public class MutableCapabilities extends AbstractCapabilities implements Serializable {
3338

3439
private static final long serialVersionUID = -112816287184979465L;
3540

@@ -46,9 +51,6 @@ public class MutableCapabilities implements Capabilities, Serializable {
4651
OPTION_KEYS = Collections.unmodifiableSet(keys);
4752
}
4853

49-
private final Map<String, Object> caps = new HashMap<>();
50-
51-
5254
public MutableCapabilities() {
5355
// no-arg constructor
5456
}
@@ -175,29 +177,4 @@ public void setCapability(String key, Object value) {
175177
caps.put(key, value);
176178
}
177179
}
178-
179-
@Override
180-
public String toString() {
181-
return String.format("Capabilities [%s]", shortenMapValues(asMap()));
182-
}
183-
184-
private Map<String, ?> shortenMapValues(Map<String, ?> map) {
185-
Map<String, Object> newMap = new HashMap<>();
186-
187-
for (Map.Entry<String, ?> entry : map.entrySet()) {
188-
if (entry.getValue() instanceof Map) {
189-
@SuppressWarnings("unchecked") Map<String, ?> value = (Map<String, ?>) entry.getValue();
190-
newMap.put(entry.getKey(), shortenMapValues(value));
191-
192-
} else {
193-
String value = String.valueOf(entry.getValue());
194-
if (value.length() > 1024) {
195-
value = value.substring(0, 29) + "...";
196-
}
197-
newMap.put(entry.getKey(), value);
198-
}
199-
}
200-
201-
return newMap;
202-
}
203180
}

java/client/test/org/openqa/selenium/remote/DesiredCapabilitiesTest.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.junit.Assert.assertEquals;
2121
import static org.junit.Assert.assertNotEquals;
2222
import static org.junit.Assert.assertSame;
23+
import static org.junit.Assert.assertTrue;
2324

2425
import org.junit.Test;
2526
import org.junit.runner.RunWith;
@@ -128,7 +129,8 @@ public void shouldShortenLongValues() {
128129
}};
129130

130131
DesiredCapabilities caps = new DesiredCapabilities(capabilitiesMap);
131-
assertEquals(caps.toString().length(), 53);
132+
String expected = "key: " + createString(27) + "...";
133+
assertTrue(caps.toString(), caps.toString().contains(expected));
132134
}
133135

134136
@Test
@@ -140,7 +142,8 @@ public void shouldShortenLongEnclosedValues() {
140142
}};
141143

142144
DesiredCapabilities caps = new DesiredCapabilities(capabilitiesMap);
143-
assertEquals(caps.toString().length(), 62);
145+
String expected = "{subkey: " + createString(27) + "..." + "}";
146+
assertTrue(caps.toString(), caps.toString().contains(expected));
144147
}
145148

146149
@Test

java/client/test/org/openqa/selenium/support/ui/WebDriverWaitTest.java

+1-4
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030

3131
import org.junit.Before;
3232
import org.junit.Test;
33-
import org.junit.runner.RunWith;
34-
import org.junit.runners.JUnit4;
3533
import org.mockito.Mock;
3634
import org.mockito.MockitoAnnotations;
3735
import org.openqa.selenium.Capabilities;
@@ -51,7 +49,6 @@
5149

5250
import java.io.IOException;
5351

54-
@RunWith(JUnit4.class)
5552
public class WebDriverWaitTest {
5653

5754
@Mock private WebDriver mockDriver;
@@ -80,7 +77,7 @@ public void shouldIncludeRemoteInfoForWrappedDriverTimeout() throws IOException
8077
Throwable ex = catchThrowable(() -> wait.until((d) -> false));
8178
assertNotNull(ex);
8279
assertThat(ex, instanceOf(TimeoutException.class));
83-
assertThat(ex.getMessage(), containsString("Capabilities [{javascriptEnabled=true, platformName=ANY, platform=ANY}]"));
80+
assertThat(ex.getMessage(), containsString("Capabilities {javascriptEnabled: true, platform: ANY, platformName: ANY}"));
8481
assertThat(ex.getMessage(), containsString("Session ID: foo"));
8582
}
8683

0 commit comments

Comments
 (0)