Skip to content

Commit 68f0909

Browse files
committed
Fixed issue SeleniumHQ#644. ErrorHandler now tolerates non-Number lineNumber, and also attempts to safely parse a non-Number Object if it receives a non-Number.
If absent or non-numeric it now continues to build the StackTraceElement (instead of aborting that frame) and uses the conventional -1 for lineNumber. Signed-off-by: Brett Randall <[email protected]>
1 parent 26bf0bc commit 68f0909

File tree

2 files changed

+84
-6
lines changed

2 files changed

+84
-6
lines changed

java/client/src/org/openqa/selenium/remote/ErrorHandler.java

+16-6
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@
2121
import static org.openqa.selenium.remote.ErrorCodes.SUCCESS;
2222

2323
import com.google.common.base.Function;
24+
import com.google.common.base.Optional;
2425
import com.google.common.base.Predicates;
2526
import com.google.common.base.Throwables;
2627
import com.google.common.collect.Iterables;
28+
import com.google.common.primitives.Ints;
2729

2830
import org.openqa.selenium.UnhandledAlertException;
2931
import org.openqa.selenium.WebDriverException;
@@ -293,12 +295,20 @@ public StackTraceElement apply(Map<String, Object> frameInfo) {
293295
if (frameInfo == null) {
294296
return null;
295297
}
296-
297-
Number lineNumber = (Number) frameInfo.get(LINE_NUMBER);
298-
if (lineNumber == null) {
299-
return null;
298+
299+
Optional<Number> maybeLineNumberInteger = Optional.absent();
300+
301+
final Object lineNumberObject = frameInfo.get(LINE_NUMBER);
302+
if (lineNumberObject instanceof Number) {
303+
maybeLineNumberInteger = Optional.of((Number) lineNumberObject);
304+
} else if (lineNumberObject != null) {
305+
// might be a Number as a String
306+
maybeLineNumberInteger = Optional.fromNullable((Number) Ints.tryParse(lineNumberObject.toString()));
300307
}
301-
308+
309+
// default -1 for unknown, see StackTraceElement constructor javadoc
310+
final int lineNumber = maybeLineNumberInteger.or(-1).intValue();
311+
302312
// Gracefully handle remote servers that don't (or can't) send back
303313
// complete stack trace info. At least some of this information should
304314
// be included...
@@ -310,7 +320,7 @@ public StackTraceElement apply(Map<String, Object> frameInfo) {
310320
? toStringOrNull(frameInfo.get(FILE_NAME)) : UNKNOWN_FILE;
311321

312322
return new StackTraceElement(className, methodName, fileName,
313-
lineNumber.intValue());
323+
lineNumber);
314324
}
315325

316326
private static String toStringOrNull(Object o) {

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

+68
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,74 @@ public void testShouldStillTryToBuildWebDriverExceptionIfClassIsNotProvidedAndSt
306306
}
307307
}
308308

309+
@SuppressWarnings({"unchecked", "ThrowableInstanceNeverThrown"})
310+
@Test
311+
public void testToleratesNonNumericLineNumber() {
312+
Map<String, ?> data = ImmutableMap.of(
313+
"message", "some error message",
314+
"stackTrace", Lists.newArrayList(
315+
ImmutableMap.of("lineNumber", "some string, might be empty or 'Not avalable'",
316+
"methodName", "someMethod",
317+
"className", "MyClass",
318+
"fileName", "Resource.m")));
319+
320+
try {
321+
handler.throwIfResponseFailed(createResponse(ErrorCodes.UNHANDLED_ERROR, data), 123);
322+
fail("Should have thrown!");
323+
} catch (WebDriverException expected) {
324+
assertEquals(new WebDriverException("some error message\nCommand duration or timeout: 123 milliseconds").getMessage(),
325+
expected.getMessage());
326+
327+
StackTraceElement[] expectedTrace = {
328+
new StackTraceElement("MyClass", "someMethod", "Resource.m", -1)
329+
};
330+
WebDriverException helper = new WebDriverException("some error message");
331+
helper.setStackTrace(expectedTrace);
332+
333+
Throwable cause = expected.getCause();
334+
assertNotNull(cause);
335+
assertEquals(WebDriverException.class, cause.getClass());
336+
assertEquals(helper.getMessage(),
337+
cause.getMessage());
338+
339+
assertStackTracesEqual(expectedTrace, cause.getStackTrace());
340+
}
341+
}
342+
343+
@SuppressWarnings({"unchecked", "ThrowableInstanceNeverThrown"})
344+
@Test
345+
public void testToleratesNumericLineNumberAsString() {
346+
Map<String, ?> data = ImmutableMap.of(
347+
"message", "some error message",
348+
"stackTrace", Lists.newArrayList(
349+
ImmutableMap.of("lineNumber", "1224", // number as a string
350+
"methodName", "someMethod",
351+
"className", "MyClass",
352+
"fileName", "Resource.m")));
353+
354+
try {
355+
handler.throwIfResponseFailed(createResponse(ErrorCodes.UNHANDLED_ERROR, data), 123);
356+
fail("Should have thrown!");
357+
} catch (WebDriverException expected) {
358+
assertEquals(new WebDriverException("some error message\nCommand duration or timeout: 123 milliseconds").getMessage(),
359+
expected.getMessage());
360+
361+
StackTraceElement[] expectedTrace = {
362+
new StackTraceElement("MyClass", "someMethod", "Resource.m", 1224)
363+
};
364+
WebDriverException helper = new WebDriverException("some error message");
365+
helper.setStackTrace(expectedTrace);
366+
367+
Throwable cause = expected.getCause();
368+
assertNotNull(cause);
369+
assertEquals(WebDriverException.class, cause.getClass());
370+
assertEquals(helper.getMessage(),
371+
cause.getMessage());
372+
373+
assertStackTracesEqual(expectedTrace, cause.getStackTrace());
374+
}
375+
}
376+
309377
@SuppressWarnings({"unchecked", "ThrowableInstanceNeverThrown"})
310378
@Test
311379
public void testShouldIndicateWhenTheServerReturnedAnExceptionThatWasSuppressed()

0 commit comments

Comments
 (0)