Skip to content

Commit

Permalink
extract ParsedError handling to helper (#44922)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #44922

extract ParsedError handling code into `StackTraceHelperTest`.

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D58512611

fbshipit-source-id: 959978d80907f2afba96ef249c2fddd351d099ff
  • Loading branch information
alanleedev authored and facebook-github-bot committed Jun 17, 2024
1 parent fe7e7a0 commit 4792671
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 25 deletions.
7 changes: 7 additions & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -2323,12 +2323,19 @@ public class com/facebook/react/devsupport/ReleaseDevSupportManager : com/facebo

public class com/facebook/react/devsupport/StackTraceHelper {
public static final field COLUMN_KEY Ljava/lang/String;
public static final field FILE_KEY Ljava/lang/String;
public static final field ID_KEY Ljava/lang/String;
public static final field IS_FATAL_KEY Ljava/lang/String;
public static final field LINE_NUMBER_KEY Ljava/lang/String;
public static final field MESSAGE_KEY Ljava/lang/String;
public static final field METHOD_NAME_KEY Ljava/lang/String;
public static final field STACK_KEY Ljava/lang/String;
public fun <init> ()V
public static fun convertJavaStackTrace (Ljava/lang/Throwable;)[Lcom/facebook/react/devsupport/interfaces/StackFrame;
public static fun convertJsStackTrace (Lcom/facebook/react/bridge/ReadableArray;)[Lcom/facebook/react/devsupport/interfaces/StackFrame;
public static fun convertJsStackTrace (Ljava/lang/String;)[Lcom/facebook/react/devsupport/interfaces/StackFrame;
public static fun convertJsStackTrace (Lorg/json/JSONArray;)[Lcom/facebook/react/devsupport/interfaces/StackFrame;
public static fun convertParsedError (Lcom/facebook/react/interfaces/exceptionmanager/ReactJsExceptionHandler$ParsedError;)Lcom/facebook/react/bridge/JavaOnlyMap;
public static fun formatFrameSource (Lcom/facebook/react/devsupport/interfaces/StackFrame;)Ljava/lang/String;
public static fun formatStackTrace (Ljava/lang/String;[Lcom/facebook/react/devsupport/interfaces/StackFrame;)Ljava/lang/String;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@
package com.facebook.react.devsupport;

import androidx.annotation.Nullable;
import com.facebook.react.bridge.JavaOnlyArray;
import com.facebook.react.bridge.JavaOnlyMap;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.devsupport.interfaces.StackFrame;
import com.facebook.react.interfaces.exceptionmanager.ReactJsExceptionHandler.ParsedError;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONArray;
Expand All @@ -23,8 +28,15 @@
/** Helper class converting JS and Java stack traces into arrays of {@link StackFrame} objects. */
public class StackTraceHelper {

public static final java.lang.String COLUMN_KEY = "column";
public static final java.lang.String LINE_NUMBER_KEY = "lineNumber";
public static final String COLUMN_KEY = "column";
public static final String LINE_NUMBER_KEY = "lineNumber";
public static final String FILE_KEY = "file";
public static final String METHOD_NAME_KEY = "methodName";

public static final String MESSAGE_KEY = "message";
public static final String STACK_KEY = "stack";
public static final String ID_KEY = "id";
public static final String IS_FATAL_KEY = "isFatal";

private static final Pattern STACK_FRAME_PATTERN1 =
Pattern.compile("^(?:(.*?)@)?(.*?)\\:([0-9]+)\\:([0-9]+)$");
Expand Down Expand Up @@ -246,4 +258,25 @@ public static String formatStackTrace(String title, StackFrame[] stack) {

return stackTrace.toString();
}

public static JavaOnlyMap convertParsedError(ParsedError error) {
List<ParsedError.StackFrame> frames = error.getFrames();
List<ReadableMap> readableMapList = new ArrayList<>();
for (ParsedError.StackFrame frame : frames) {
JavaOnlyMap map = new JavaOnlyMap();
map.putDouble(COLUMN_KEY, frame.getColumnNumber());
map.putDouble(LINE_NUMBER_KEY, frame.getLineNumber());
map.putString(FILE_KEY, (String) frame.getFileName());
map.putString(METHOD_NAME_KEY, (String) frame.getMethodName());
readableMapList.add(map);
}

JavaOnlyMap data = new JavaOnlyMap();
data.putString(MESSAGE_KEY, error.getMessage());
data.putArray(STACK_KEY, JavaOnlyArray.from(readableMapList));
data.putInt(ID_KEY, error.getExceptionId());
data.putBoolean(IS_FATAL_KEY, error.isFatal());

return data;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@

package com.facebook.react.runtime;

import static com.facebook.react.util.JSStackTrace.COLUMN_KEY;
import static com.facebook.react.util.JSStackTrace.FILE_KEY;
import static com.facebook.react.util.JSStackTrace.LINE_NUMBER_KEY;
import static com.facebook.react.util.JSStackTrace.METHOD_NAME_KEY;

import android.content.res.AssetManager;
import android.view.View;
import com.facebook.common.logging.FLog;
Expand All @@ -28,15 +23,13 @@
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.JSBundleLoader;
import com.facebook.react.bridge.JSBundleLoaderDelegate;
import com.facebook.react.bridge.JavaOnlyArray;
import com.facebook.react.bridge.JavaOnlyMap;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.NativeArray;
import com.facebook.react.bridge.NativeMap;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactNoCrashSoftException;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.RuntimeExecutor;
import com.facebook.react.bridge.RuntimeScheduler;
import com.facebook.react.bridge.queue.MessageQueueThread;
Expand All @@ -45,6 +38,7 @@
import com.facebook.react.bridge.queue.ReactQueueConfiguration;
import com.facebook.react.bridge.queue.ReactQueueConfigurationImpl;
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
import com.facebook.react.devsupport.StackTraceHelper;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
import com.facebook.react.fabric.Binding;
import com.facebook.react.fabric.BindingImpl;
Expand Down Expand Up @@ -332,22 +326,7 @@ private class ReactJsExceptionHandlerImpl implements ReactJsExceptionHandler {

@Override
public void reportJsException(ParsedError error) {
List<ReactJsExceptionHandler.ParsedError.StackFrame> frames = error.getFrames();
List<ReadableMap> readableMapList = new ArrayList<>();
for (ReactJsExceptionHandler.ParsedError.StackFrame frame : frames) {
JavaOnlyMap map = new JavaOnlyMap();
map.putDouble(COLUMN_KEY, frame.getColumnNumber());
map.putDouble(LINE_NUMBER_KEY, frame.getLineNumber());
map.putString(FILE_KEY, (String) frame.getFileName());
map.putString(METHOD_NAME_KEY, (String) frame.getMethodName());
readableMapList.add(map);
}

JavaOnlyMap data = new JavaOnlyMap();
data.putString("message", error.getMessage());
data.putArray("stack", JavaOnlyArray.from(readableMapList));
data.putInt("id", error.getExceptionId());
data.putBoolean("isFatal", error.isFatal());
JavaOnlyMap data = StackTraceHelper.convertParsedError(error);

// Simulate async native module method call
mNativemodulesmessagequeuethread.runOnQueue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@

package com.facebook.react.devsupport

import com.facebook.react.bridge.ReadableMap
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.interfaces.exceptionmanager.ReactJsExceptionHandler.*
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@OptIn(UnstableReactNativeAPI::class)
@RunWith(RobolectricTestRunner::class)
class StackTraceHelperTest {
@Test
Expand Down Expand Up @@ -58,4 +62,63 @@ class StackTraceHelperTest {
assertThat(frame.line).isEqualTo(-1)
assertThat(frame.column).isEqualTo(-1)
}

@Test
fun testConvertParsedError() {
val error = getParsedErrorTestData()

val data = StackTraceHelper.convertParsedError(error)
assertThat(data.getString("message")).isEqualTo("error message")
assertThat(data.getInt("id")).isEqualTo(123)
assertThat(data.getBoolean("isFatal")).isEqualTo(true)

val stack = data.getArray("stack")
assertThat(stack).isNotNull()
stack?.let {
assertThat(stack.size()).isEqualTo(2)
assertStackFrameMap(stack.getMap(0), "file1", "method1", 1, 10)
assertStackFrameMap(stack.getMap(1), "file2", "method2", 2, 20)
}
}

private fun assertStackFrameMap(
map: ReadableMap,
filename: String,
methodName: String,
lineNumber: Int,
columnNumber: Int
) {

assertThat(map.getString("file")).isEqualTo(filename)
assertThat(map.getString("methodName")).isEqualTo(methodName)
assertThat(map.getDouble("lineNumber").toInt()).isEqualTo(lineNumber)
assertThat(map.getDouble("column").toInt()).isEqualTo(columnNumber)
}

private fun getParsedErrorTestData(): ParsedError {
val frame1 =
object : ParsedError.StackFrame {
override val fileName = "file1"
override val methodName = "method1"
override val lineNumber = 1
override val columnNumber = 10
}

val frame2 =
object : ParsedError.StackFrame {
override val fileName = "file2"
override val methodName = "method2"
override val lineNumber = 2
override val columnNumber = 20
}

val frames = listOf(frame1, frame2)

return object : ParsedError {
override val frames = frames
override val message = "error message"
override val exceptionId = 123
override val isFatal = true
}
}
}

0 comments on commit 4792671

Please sign in to comment.