blob: 94bbb009f9d2af785f17f5e08cab4fb910174efc [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.junit.client;
import com.google.gwt.core.client.impl.Impl;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.core.shared.SerializableThrowable;
import com.google.gwt.junit.client.WithProperties.Property;
import junit.framework.AssertionFailedError;
import javaemul.internal.annotations.DoNotInline;
/**
* This class tests stack traces generated by GWTTestCase.
*/
public class GWTTestCaseStackTraceTest extends GWTTestCaseTestBase {
private static final int LINE_NUMBER_1 = 42;
private static final int LINE_NUMBER_2 = LINE_NUMBER_1 + 2;
private static final String FILE_NAME = "GWTTestCaseStackTraceTest.java";
private static final String CLASS_NAME = GWTTestCaseStackTraceTest.class.getName();
@DoNotInline
private static void throwException(boolean withCause) {
// the next line should be LINE_NUMBER_1
AssertionFailedError exception = new AssertionFailedError("stack_trace_msg");
if (withCause) {
exception.initCause(new RuntimeException("the_cause"));
}
throw exception;
}
private static void assertStackTrace(
Throwable t, String methodName, int lineNumber, boolean hasCause) {
assertSame(AssertionFailedError.class, t.getClass());
assertTrue(t.getMessage().startsWith("stack_trace_msg"));
StackTraceElement[] trace = t.getStackTrace();
assertStackTrace(trace, CLASS_NAME, "throwException", FILE_NAME, LINE_NUMBER_1);
assertStackTrace(trace, CLASS_NAME, methodName, FILE_NAME, lineNumber);
assertCause(t, hasCause);
}
private static void assertCause(Throwable t, boolean hasCause) {
Throwable cause = t.getCause();
if (hasCause) {
assertNotNull(cause);
assertCauseDetails(cause);
} else {
assertNull(cause);
}
}
private static void assertCauseDetails(Throwable t) {
assertSame(SerializableThrowable.class, t.getClass());
String type = ((SerializableThrowable) t).getDesignatedType();
assertEquals(RuntimeException.class.getName(), type);
assertTrue(t.getMessage().startsWith("the_cause"));
StackTraceElement[] trace = t.getStackTrace();
assertStackTrace(trace, CLASS_NAME, "throwException", FILE_NAME, LINE_NUMBER_2);
}
private static void assertStackTrace(StackTraceElement[] stackTrace, String className,
String methodName, String fileName, int lineNumber) {
for (StackTraceElement stackTraceElement : stackTrace) {
if (stackTraceElement.getClassName().equals(className)
&& stackTraceElement.getMethodName().equals(methodName)) {
assertEquals(fileName, stackTraceElement.getFileName());
assertEquals(lineNumber, stackTraceElement.getLineNumber());
return; // Found!!!
}
}
fail("Stack trace element not found " + className + "#" + methodName);
}
/** Asserts stack trace generated by {@link #testStackTrace} */
public static class StackTraceAsserter implements ExceptionAsserter {
public void assertException(ExpectedFailure annotation, Throwable actual) {
final int lineNumber = 101;
assertStackTrace(actual, "testStackTrace", lineNumber, false);
}
}
@ExpectedFailure(withAsserter = StackTraceAsserter.class)
public void testStackTrace() {
throwException(false);
}
/** Asserts stack trace generated by {@link #testStackTrace_withCause} */
public static class StackTraceAsserterWithCause implements ExceptionAsserter {
public void assertException(ExpectedFailure annotation, Throwable actual) {
final int lineNumber = 114;
assertStackTrace(actual, "testStackTrace_withCause", lineNumber, true);
}
}
@ExpectedFailure(withAsserter = StackTraceAsserterWithCause.class)
public void testStackTrace_withCause() {
throwException(true);
}
/** Asserts stack trace generated by {@link #testStackTrace_fromDifferentModule} */
public static class StackTraceAsserterFromDifferentModule implements ExceptionAsserter {
public void assertException(ExpectedFailure annotation, Throwable actual) {
final int lineNumber = 129;
assertStackTrace(actual, "testStackTrace_fromDifferentModule", lineNumber, false);
}
}
// @Property added just to introduce a different module name for the test
@WithProperties(@Property(name = "locale", value = "tr"))
@ExpectedFailure(withAsserter = StackTraceAsserterFromDifferentModule.class)
public void testStackTrace_fromDifferentModule() {
throwException(false);
}
/** Asserts stack trace generated by {@link #testStackTrace_jsni} */
public static class StackTraceAsserterForJsni implements ExceptionAsserter {
public void assertException(ExpectedFailure annotation, Throwable actual) {
assertEquals(1, actual.getStackTrace().length);
StackTraceElement ste = actual.getStackTrace()[0];
assertEquals("setUp", ste.getMethodName());
assertEquals(FILE_NAME, ste.getFileName());
assertEquals(9999, ste.getLineNumber());
}
}
/**
* This is asserting that {@code StacktraceDeobfuscator} trusts the stack trace emulation with the
* file name and line number (emulation knows it better for anonymous functions in JSNI).
*/
@ExpectedFailure(withAsserter = StackTraceAsserterForJsni.class)
public void testStackTrace_jsni() {
// A method name from a different file so that deobfuscator will resolve to a different file.
String methodName = !GWT.isScript() ? "setUp"
: Impl.getNameOf("com.google.gwt.junit.client.GWTTestCase::setUp()");
StackTraceElement ste = new StackTraceElement("Unknown", methodName, FILE_NAME, 9999);
AssertionFailedError exception = new AssertionFailedError("stack_trace_msg");
exception.setStackTrace(new StackTraceElement[] {ste});
throw exception;
}
}