Major revamp of stack trace tests
Added more tests and more coverage for different modes.
Includes a small patch to Chrome collector as tests revealed
a small bug with it.
Change-Id: Ie98fe6b569b3c47e475ae0fd847cacd90a6a823a
Review-Link: https://gwt-review.googlesource.com/#/c/7771/
diff --git a/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java b/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java
index 2087943..9384bbd 100644
--- a/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java
+++ b/user/src/com/google/gwt/core/client/impl/StackTraceCreator.java
@@ -328,6 +328,9 @@
@Override
protected StackTraceElement[] getStackTrace(JsArrayString stack) {
int length = stack.length();
+ if (length == 0) {
+ return null;
+ }
StackTraceElement[] stackTrace = new StackTraceElement[length];
for (int i = 0; i < length; i++) {
String stackElements[] = stack.get(i).split("@@");
diff --git a/user/test/com/google/gwt/core/CoreSuite.java b/user/test/com/google/gwt/core/CoreSuite.java
index 95caf03..60a4ebb 100644
--- a/user/test/com/google/gwt/core/CoreSuite.java
+++ b/user/test/com/google/gwt/core/CoreSuite.java
@@ -29,8 +29,10 @@
import com.google.gwt.core.client.impl.ImplTest;
import com.google.gwt.core.client.impl.SchedulerImplTest;
import com.google.gwt.core.client.impl.StackTraceCreatorCollectorTest;
-import com.google.gwt.core.client.impl.StackTraceCreatorEmulTest;
-import com.google.gwt.core.client.impl.StackTraceCreatorTest;
+import com.google.gwt.core.client.impl.StackTraceDevTest;
+import com.google.gwt.core.client.impl.StackTraceEmulTest;
+import com.google.gwt.core.client.impl.StackTraceNativeTest;
+import com.google.gwt.core.client.impl.StackTraceStripTest;
import com.google.gwt.core.client.prefetch.RunAsyncCodeTest;
import com.google.gwt.core.shared.SerializableThrowableTest;
import com.google.gwt.junit.tools.GWTTestSuite;
@@ -60,8 +62,10 @@
suite.addTestSuite(ScriptInjectorTest.class);
suite.addTestSuite(SerializableThrowableTest.class);
suite.addTestSuite(StackTraceCreatorCollectorTest.class);
- suite.addTestSuite(StackTraceCreatorEmulTest.class);
- suite.addTestSuite(StackTraceCreatorTest.class);
+ suite.addTestSuite(StackTraceDevTest.class);
+ suite.addTestSuite(StackTraceEmulTest.class);
+ suite.addTestSuite(StackTraceNativeTest.class);
+ suite.addTestSuite(StackTraceStripTest.class);
// Uncomment to print native stack traces for different platforms
// suite.addTestSuite(com.google.gwt.core.client.impl.StackTraceGenerator.class);
diff --git a/user/test/com/google/gwt/core/StackTraceNoEmul.gwt.xml b/user/test/com/google/gwt/core/StackTraceNative.gwt.xml
similarity index 100%
rename from user/test/com/google/gwt/core/StackTraceNoEmul.gwt.xml
rename to user/test/com/google/gwt/core/StackTraceNative.gwt.xml
diff --git a/user/test/com/google/gwt/core/StackTraceStrip.gwt.xml b/user/test/com/google/gwt/core/StackTraceStrip.gwt.xml
new file mode 100644
index 0000000..cf3dd8a
--- /dev/null
+++ b/user/test/com/google/gwt/core/StackTraceStrip.gwt.xml
@@ -0,0 +1,20 @@
+<!-- -->
+<!-- Copyright 2014 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 -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <inherits name="com.google.gwt.core.Core" />
+ <!-- Make sure junit xml processed earlier so stack mode will not be overwritten -->
+ <inherits name="com.google.gwt.junit.JUnit" />
+ <set-property name="compiler.stackMode" value="strip" />
+</module>
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceCreatorCollectorTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceCreatorCollectorTest.java
index c912264..6123e16 100644
--- a/user/test/com/google/gwt/core/client/impl/StackTraceCreatorCollectorTest.java
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceCreatorCollectorTest.java
@@ -46,26 +46,6 @@
assertEquals("anonymous", extractFunctionName("abc"));
}
- public void testChromeExtractName() {
- CollectorChrome c = new CollectorChrome();
-
- assertEquals("anonymous@@file.js:1:2", c.extractName(" at file.js:1:2"));
- assertEquals("functionName@@file.js:1:2", c.extractName(" at functionName (file.js:1:2)"));
- assertEquals("functionName@@file.js:1:2", c.extractName(" at Type.functionName (file.js:1:2)"));
- assertEquals("functionName@@file.js:1:2",
- c.extractName(" at Type.functionName [as methodName] (file.js:1:2)"));
-
- // iOS style
- assertEquals("functionName@@file.js:1", c.extractName("functionName@file.js:1"));
- }
-
- public void testFirefox14ExtractName() {
- CollectorMoz c = new CollectorMoz();
-
- assertEquals("anonymous", c.extractName("@file.js:1"));
- assertEquals("functionName", c.extractName("functionName@file.js:1"));
- }
-
public void testChrome_25() {
StackTraceElement[] expected = new StackTraceElement[] {
createSTE("$third", "http://www.example.com/test/ABCD.cache.js@10", 300),
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceCreatorEmulTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceCreatorEmulTest.java
deleted file mode 100644
index 8c9782d..0000000
--- a/user/test/com/google/gwt/core/client/impl/StackTraceCreatorEmulTest.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright 2009 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.core.client.impl;
-
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.JavaScriptException;
-
-/**
- * Tests {@link StackTraceCreator} in the emulated mode.
- */
-public class StackTraceCreatorEmulTest extends StackTraceCreatorTest {
-
- public static void testJavaScriptException() {
- StackTraceElement[] start = sample();
- Throwable t = null;
- try {
- throwNative();
- fail("No exception thrown");
- } catch (JavaScriptException e) {
- /*
- * Some browsers may or may not be able to implement this at all, so we'll
- * at least make sure that an array is returned;
- */
- assertNotNull(e.getStackTrace());
- if (e.getStackTrace().length == 0) {
- assertTrue("Development Mode", GWT.isScript());
- return;
- } else {
- t = e;
- }
- }
-
- String myName = null;
- if (!GWT.isScript()) {
- myName = "testJavaScriptException";
- } else {
- myName = Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorEmulTest::testJavaScriptException()");
- }
-
- checkStack(myName, t);
-
- StackTraceElement[] end = sample();
- assertEquals(start, end);
- }
-
- /**
- * Just make sure that reentrant behavior doesn't fail.
- */
- public static void testReentrantCalls() {
- if (!GWT.isScript()) {
- // sample is useless in Development Mode
- return;
- }
-
- StackTraceElement[] start = sample();
-
- StackTraceElement[] stack = countDown(5);
- assertNotNull(stack);
- assertTrue(stack.length > 0);
-
- StackTraceElement[] end = sample();
- assertEquals(start, end);
- }
-
- public static void testStackTraces() {
- StackTraceElement[] start = sample();
-
- Throwable t;
- try {
- throw new RuntimeException();
- } catch (Throwable t2) {
- t = t2;
- }
-
- String myName = null;
- if (!GWT.isScript()) {
- myName = "testStackTraces";
- } else {
- myName = Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorEmulTest::testStackTraces()");
- }
-
- checkStack(myName, t);
-
- StackTraceElement[] end = sample();
- assertEquals(start, end);
- }
-
- private static void assertEquals(StackTraceElement[] start, StackTraceElement[] end) {
- assertEquals("length", start.length, end.length);
- for (int i = 0, j = start.length; i < j; i++) {
- assertEquals("frame " + i, start[i].getMethodName(), end[i].getMethodName());
- }
- }
-
- private static void checkStack(String myName, Throwable t) {
- assertNotNull("myName", myName);
- assertNotNull("t", t);
-
- assertEquals("Needs a trim()", myName.trim(), myName);
- assertFalse("function", myName.startsWith("function"));
- assertFalse("(", myName.contains("("));
-
- StackTraceElement[] stack = t.getStackTrace();
- assertNotNull("stack", stack);
- assertTrue("stack.length", stack.length > 0);
-
- boolean found = false;
- StringBuilder observedStack = new StringBuilder();
- for (int i = 0, j = stack.length; i < j; i++) {
- StackTraceElement elt = stack[i];
- String value = elt.getMethodName();
-
- assertNotNull("value", value);
- assertTrue("value.length", value.length() > 0);
- assertEquals("value.trim()", value.length(), value.trim().length());
-
- observedStack.append("\n").append(value);
- found |= myName.equals(value);
- }
-
- assertTrue("Did not find " + myName + " in the stack " + observedStack,
- found);
- }
-
- private static StackTraceElement[] countDown(int count) {
- if (count > 0) {
- return countDown(count - 1);
- } else {
- return sample();
- }
- }
-
- private static StackTraceElement[] sample() {
- return new Throwable().getStackTrace();
- }
-
- private static native void throwNative() /*-{
- null.a();
- }-*/;
-
- @Override
- public String getModuleName() {
- return "com.google.gwt.core.Core";
- }
-}
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java
deleted file mode 100644
index 1c423b4..0000000
--- a/user/test/com/google/gwt/core/client/impl/StackTraceCreatorTest.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2009 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.core.client.impl;
-
-import com.google.gwt.core.client.impl.StackTraceCreator.CollectorLegacy;
-import com.google.gwt.junit.DoNotRunWith;
-import com.google.gwt.junit.Platform;
-import com.google.gwt.junit.client.GWTTestCase;
-
-import junit.framework.AssertionFailedError;
-
-/**
- * Tests {@link StackTraceCreator}.
- */
-public class StackTraceCreatorTest extends GWTTestCase {
-
- @Override
- public String getModuleName() {
- return "com.google.gwt.core.StackTraceNoEmul";
- }
-
- @DoNotRunWith(Platform.Devel)
- public void testTrace() {
- Throwable t = null;
- try {
- throwException1(false /* throw java exception */);
- fail("No exception thrown");
- } catch (Throwable e) {
- t = e;
- }
-
- final String[] expected = {
- Impl.getNameOf("@java.lang.Throwable::new(Ljava/lang/String;)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException3(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException2(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException1(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::testTrace()"),
- };
-
- assertTrace(expected, t, 0);
- }
-
- @DoNotRunWith(Platform.Devel)
- public void testTraceRecursion() {
- Throwable t = null;
- try {
- throwExceptionRecursive(3);
- fail("No exception thrown");
- } catch (Throwable e) {
- t = e;
- }
-
- final String[] expectedModern = {
- Impl.getNameOf("@java.lang.Throwable::new(Ljava/lang/String;)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException3(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException2(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException1(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwExceptionRecursive(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwExceptionRecursive(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwExceptionRecursive(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::testTraceRecursion()"),
- };
-
- final String[] expectedLegacy = {
- Impl.getNameOf("@java.lang.Throwable::new(Ljava/lang/String;)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException3(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException2(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException1(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwExceptionRecursive(*)"),
- };
-
- final String[] expected = isLegacyCollector() ? expectedLegacy : expectedModern;
- assertTrace(expected, t, 0);
- }
-
- @DoNotRunWith(Platform.Devel)
- public void testTraceNative() {
- Throwable t = null;
- try {
- throwException1(true /* throw js exception */);
- fail("No exception thrown");
- } catch (Throwable e) {
- t = e;
- }
-
- String[] nativeMethodNames = throwNative(false /* don't throw - collect mode */);
- final String[] expectedModern = {
- nativeMethodNames[0],
- nativeMethodNames[1],
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwNative(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException3(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException2(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::throwException1(*)"),
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::testTraceNative()"),
- };
-
- final String[] expectedLegacy = {
- Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceCreatorTest::testTraceNative()"),
- };
-
- final String[] expected = isLegacyCollector() ? expectedLegacy : expectedModern;
-
- int offset = getTraceOffset(t.getStackTrace(), expected[0]);
- assertTrace(expected, t, offset);
- }
-
- private void assertTrace(String[] expected, Throwable t, int offset) {
- StackTraceElement[] trace = t.getStackTrace();
- for (int i = 0; i < expected.length; i++) {
- StackTraceElement actualElement = trace[i + offset];
- String methodName = actualElement == null ? "!MISSING!" : actualElement.getMethodName();
- if (expected[i].equals(methodName)) {
- continue;
- }
- AssertionFailedError e = new AssertionFailedError("Incorrect frame at " + i + " - "
- + " Expected: " + expected[i] + " Actual: " + methodName);
- e.initCause(t);
- throw e;
- }
- }
-
- protected int getTraceOffset(StackTraceElement[] trace, String firstFrame) {
- // TODO(goktug): Native exception traces are not properly stripped,
- // Working around that for now by calculating an offset.
- int offset = 0;
- for (StackTraceElement ste : trace) {
- if (ste.getMethodName().equals(firstFrame)) {
- break;
- }
- offset++;
- }
- return offset;
- }
-
- private static boolean isLegacyCollector() {
- return StackTraceCreator.collector instanceof CollectorLegacy;
- }
-
- private static void throwExceptionRecursive(int count) throws Throwable {
- if (count > 1) {
- throwExceptionRecursive(count - 1);
- } else {
- throwException1(false);
- }
- }
-
- private static void throwException1(boolean throwNative) throws Throwable {
- throwException2(throwNative);
- }
-
- private static void throwException2(boolean throwNative) throws Throwable {
- throwException3(throwNative);
- }
-
- private static void throwException3(boolean throwNative) throws Throwable {
- if (throwNative) {
- throwNative(true /* really throw exception */);
- } else {
- throw new Throwable("broken");
- }
- }
-
- private static native String[] throwNative(boolean reallyThrow) /*-{
- function native1() {
- return native2();
- }
- function native2() {
- if (reallyThrow) null.a();
-
- return [
- @StackTraceCreator::getFunctionName(*)(arguments.callee),
- @StackTraceCreator::getFunctionName(*)(arguments.callee.caller),
- ];
- }
- return native1();
- }-*/;
-}
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceDevTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceDevTest.java
new file mode 100644
index 0000000..afe494b
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceDevTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014 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.core.client.impl;
+
+import com.google.gwt.junit.DoNotRunWith;
+import com.google.gwt.junit.Platform;
+
+/**
+ * Tests {@link StackTraceCreator} in the native mode.
+ */
+@DoNotRunWith(Platform.Prod)
+public class StackTraceDevTest extends StackTraceTestBase {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.StackTraceNative";
+ }
+
+ @Override
+ protected String[] getTraceJava() {
+ return new String[] {
+ "throwException2",
+ "throwException1",
+ "getLiveException",
+ "testTraceJava",
+ };
+ }
+
+ @Override
+ protected String[] getTraceRecursion() {
+ return new String[] {
+ "throwException2",
+ "throwException1",
+ "throwRecursive",
+ "throwRecursive",
+ "throwRecursive",
+ "throwException2",
+ "throwException1",
+ "getLiveException",
+ "testTraceRecursion",
+ };
+ }
+
+ @Override
+ protected String[] getTraceJse(Object whatToThrow) {
+ return new String[] {
+ "throwJse",
+ "throwException2",
+ "throwException1",
+ "getLiveException",
+ "assertJse",
+ };
+ }
+}
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceEmulTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceEmulTest.java
new file mode 100644
index 0000000..400597b
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceEmulTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2009 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.core.client.impl;
+
+import static com.google.gwt.core.client.impl.StackTraceExamples.JAVA;
+import static com.google.gwt.core.client.impl.StackTraceExamples.TYPE_ERROR;
+
+/**
+ * Tests {@link StackTraceCreator} in the emulated mode.
+ */
+public class StackTraceEmulTest extends StackTraceNativeTest {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.Core";
+ }
+
+ /**
+ * Verifies throw/try/catch doesn't poison the emulated stack frames.
+ */
+ public static void testViaSample() {
+ StackTraceElement[] start = sample();
+
+ Exception e = StackTraceExamples.getLiveException(JAVA);
+ assertTrue(e.getStackTrace().length > 0);
+
+ StackTraceElement[] end = sample();
+ assertEquals(start, end);
+ }
+
+ /**
+ * Verifies throw/try/catch with JSE doesn't poison the emulated stack frames.
+ */
+ public void testJseViaSample() {
+ StackTraceElement[] start = sample();
+
+ Exception e = StackTraceExamples.getLiveException(TYPE_ERROR);
+ assertTrue(e.getStackTrace().length > 0);
+
+ StackTraceElement[] end = sample();
+ assertEquals(start, end);
+ }
+
+ private static void assertEquals(StackTraceElement[] start, StackTraceElement[] end) {
+ assertEquals("length", start.length, end.length);
+ for (int i = 0, j = start.length; i < j; i++) {
+ assertEquals("frame " + i, start[i].getMethodName(), end[i].getMethodName());
+ }
+ }
+
+ private static StackTraceElement[] sample() {
+ return new Throwable().getStackTrace();
+ }
+}
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceExamples.java b/user/test/com/google/gwt/core/client/impl/StackTraceExamples.java
index 2d0def3..7d6750f 100644
--- a/user/test/com/google/gwt/core/client/impl/StackTraceExamples.java
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceExamples.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.core.client.impl;
+import static junit.framework.Assert.fail;
+
import com.google.gwt.core.client.JavaScriptObject;
/**
@@ -26,16 +28,81 @@
*/
public class StackTraceExamples {
+ public static final Object JAVA = new Object();
+ public static final Object RECURSION = new Object();
+ public static final Object TYPE_ERROR = new Object();
+
+ private static final Object NO_THROW = new Object();
+ private static final int NO_OF_RECURSION = 3;
+
+ public static Exception getLiveException(Object whatToThrow) {
+ try {
+ throwException1(whatToThrow);
+ fail("No exception thrown");
+ return null; // shouldn't happen
+ } catch (Exception e) {
+ return e;
+ }
+ }
+
+ private static void throwException1(Object whatToThrow) throws Exception {
+ throwException2(whatToThrow);
+ }
+
+ private static void throwException2(Object whatToThrow) throws Exception {
+ if (whatToThrow == JAVA) {
+ throw new Exception("broken");
+ } else if (whatToThrow == RECURSION) {
+ throwRecursive(NO_OF_RECURSION);
+ } else {
+ throwJse(whatToThrow);
+ }
+ }
+
+ private static void throwRecursive(int count) throws Exception {
+ if (count > 1) {
+ throwRecursive(count - 1);
+ } else {
+ throwException1(JAVA);
+ }
+ }
+
+ public static String[] getNativeMethodNames() {
+ return throwJse(NO_THROW);
+ }
+
+ private static native String[] throwJse(Object whatToThrow) /*-{
+ function native1() {
+ return native2();
+ }
+ function native2() {
+ if (whatToThrow == @StackTraceExamples::TYPE_ERROR) {
+ null.a();
+ }
+
+ if (whatToThrow != @StackTraceExamples::NO_THROW) {
+ throw whatToThrow;
+ }
+
+ return [
+ @StackTraceCreator::getFunctionName(*)(arguments.callee),
+ @StackTraceCreator::getFunctionName(*)(arguments.callee.caller),
+ ];
+ }
+ return native1();
+ }-*/;
+
// Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko)
// Chrome/25.0.1364.97 Safari/537.22
+ // Modified to test 'xxx [as yyy]' and 'xxx.yyy' scenarios
public static native JavaScriptObject chrome_25() /*-{
return {
message: "Cannot read property 'length' of undefined",
name: "TypeError",
stack: "TypeError: Cannot read property 'length' of undefined\n" +
- " at $third (http://www.example.com/test/ABCD.cache.js:300:10)\n" +
- " at $second (http://www.example.com/test/ABCD.cache.js:200:10)\n" +
- " at $first (http://www.example.com/test/ABCD.cache.js:100:10)\n" +
+ " at C.$third [as alt2](http://www.example.com/test/ABCD.cache.js:300:10)\n" +
+ " at B.$second (http://www.example.com/test/ABCD.cache.js:200:10)\n" +
+ " at $first [as alt1] (http://www.example.com/test/ABCD.cache.js:100:10)\n" +
" at $entry0 (http://www.example.com/test/ABCD.cache.js:50:10)"
};
}-*/;
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceNativeTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceNativeTest.java
new file mode 100644
index 0000000..d00ce84
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceNativeTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014 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.core.client.impl;
+
+import static com.google.gwt.core.client.impl.StackTraceExamples.TYPE_ERROR;
+
+import com.google.gwt.core.client.impl.StackTraceCreator.CollectorLegacy;
+import com.google.gwt.junit.DoNotRunWith;
+import com.google.gwt.junit.Platform;
+
+/**
+ * Tests {@link StackTraceCreator} in the native mode.
+ */
+@DoNotRunWith(Platform.Devel)
+public class StackTraceNativeTest extends StackTraceTestBase {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.StackTraceNative";
+ }
+
+ @Override
+ protected String[] getTraceJava() {
+ return new String[] {
+ Impl.getNameOf("@java.lang.Throwable::new(Ljava/lang/String;)"),
+ Impl.getNameOf("@java.lang.Exception::new(Ljava/lang/String;)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException2(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException1(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::getLiveException(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceTestBase::testTraceJava()"),
+ };
+ }
+
+ @Override
+ protected String[] getTraceRecursion() {
+ final String[] expectedModern = {
+ Impl.getNameOf("@java.lang.Throwable::new(Ljava/lang/String;)"),
+ Impl.getNameOf("@java.lang.Exception::new(Ljava/lang/String;)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException2(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException1(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwRecursive(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwRecursive(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwRecursive(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException2(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException1(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::getLiveException(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceTestBase::testTraceRecursion()"),
+ };
+
+ final String[] expectedLegacy = {
+ Impl.getNameOf("@java.lang.Throwable::new(Ljava/lang/String;)"),
+ Impl.getNameOf("@java.lang.Exception::new(Ljava/lang/String;)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException2(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException1(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwRecursive(*)"),
+ };
+
+ return isLegacyCollector() ? expectedLegacy : expectedModern;
+ }
+
+ @Override
+ protected String[] getTraceJse(Object thrown) {
+ String[] nativeMethodNames = StackTraceExamples.getNativeMethodNames();
+ final String[] full = {
+ nativeMethodNames[0],
+ nativeMethodNames[1],
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwJse(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException2(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::throwException1(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceExamples::getLiveException(*)"),
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceTestBase::assertJse(*)"),
+ };
+
+ final String[] limited = {
+ Impl.getNameOf("@com.google.gwt.core.client.impl.StackTraceTestBase::assertJse(*)"),
+ };
+
+ // For legacy browsers and non-error javascript exceptions (e.g. throw "string"), we can only
+ // construct stack trace from the catch block and below.
+
+ return (isLegacyCollector() || thrown != TYPE_ERROR) ? limited : full;
+ }
+
+ private static boolean isLegacyCollector() {
+ return StackTraceCreator.collector instanceof CollectorLegacy;
+ }
+}
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceStripTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceStripTest.java
new file mode 100644
index 0000000..1c955ae
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceStripTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014 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.core.client.impl;
+
+import com.google.gwt.junit.DoNotRunWith;
+import com.google.gwt.junit.Platform;
+
+/**
+ * Tests {@link StackTraceCreator} in the strip mode.
+ */
+@DoNotRunWith(Platform.Devel)
+public class StackTraceStripTest extends StackTraceTestBase {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.StackTraceStrip";
+ }
+
+ @Override
+ protected String[] getTraceJava() {
+ return new String[0];
+ }
+
+ @Override
+ protected String[] getTraceRecursion() {
+ return new String[0];
+ }
+
+ @Override
+ protected String[] getTraceJse(Object whatToThrow) {
+ return new String[0];
+ }
+}
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceTestBase.java b/user/test/com/google/gwt/core/client/impl/StackTraceTestBase.java
new file mode 100644
index 0000000..67fc362
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceTestBase.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014 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.core.client.impl;
+
+import static com.google.gwt.core.client.impl.StackTraceExamples.JAVA;
+import static com.google.gwt.core.client.impl.StackTraceExamples.RECURSION;
+import static com.google.gwt.core.client.impl.StackTraceExamples.TYPE_ERROR;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+import junit.framework.AssertionFailedError;
+
+/**
+ * Tests {@link StackTraceCreator}.
+ */
+public abstract class StackTraceTestBase extends GWTTestCase {
+
+ public void testTraceJava() {
+ Exception t = StackTraceExamples.getLiveException(JAVA);
+ assertTrace(getTraceJava(), t, 0);
+ }
+
+ protected abstract String[] getTraceJava();
+
+ public void testTraceRecursion() {
+ Exception t = StackTraceExamples.getLiveException(RECURSION);
+ assertTrace(getTraceRecursion(), t, 0);
+ }
+
+ protected abstract String[] getTraceRecursion();
+
+ public void testTraceTypeError() {
+ assertJse(TYPE_ERROR);
+ }
+
+ public void testTraceString() {
+ assertJse("testing");
+ }
+
+ public void testTraceNull() {
+ assertJse(null);
+ }
+
+ private void assertJse(Object whatToThrow) {
+ Exception t = StackTraceExamples.getLiveException(whatToThrow);
+
+ String[] expected = getTraceJse(whatToThrow);
+ int offset = getTraceOffset(t.getStackTrace(), expected[0]);
+ assertTrace(expected, t, offset);
+ }
+
+ protected abstract String[] getTraceJse(Object whatToThrow);
+
+ private void assertTrace(String[] expected, Exception t, int offset) {
+ StackTraceElement[] trace = t.getStackTrace();
+ for (int i = 0; i < expected.length; i++) {
+ StackTraceElement actualElement = trace[i + offset];
+ String methodName = actualElement == null ? "!MISSING!" : actualElement.getMethodName();
+ if (expected[i].equals(methodName)) {
+ continue;
+ }
+ AssertionFailedError e = new AssertionFailedError("Incorrect frame at " + i + " - "
+ + " Expected: " + expected[i] + " Actual: " + methodName);
+ e.initCause(t);
+ throw e;
+ }
+ }
+
+ protected int getTraceOffset(StackTraceElement[] trace, String firstFrame) {
+ // TODO(goktug): Native exception traces are not properly stripped,
+ // Working around that for now by calculating an offset.
+ int offset = 0;
+ for (StackTraceElement ste : trace) {
+ if (ste.getMethodName().equals(firstFrame)) {
+ break;
+ }
+ offset++;
+ }
+ return offset;
+ }
+}