Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

154 lines
4.6 KiB
Go

package languages
import (
"testing"
"github.com/zzet/gortex/internal/graph"
)
// rnMethodMeta returns a map of method-name → (rn_module, rn_method) for
// every method node carrying React Native bridge metadata.
func rnMethodMeta(nodes []*graph.Node) map[string][2]string {
out := map[string][2]string{}
for _, n := range nodes {
if n.Kind != graph.KindMethod || n.Meta == nil {
continue
}
mod, _ := n.Meta["rn_module"].(string)
meth, _ := n.Meta["rn_method"].(string)
if meth == "" {
continue
}
out[n.Name] = [2]string{mod, meth}
}
return out
}
func TestObjCExtract_RNExports(t *testing.T) {
src := `#import "RCTBridgeModule.h"
@implementation CalendarModule
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
}
RCT_REMAP_METHOD(getThing, fetchThingWithResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
}
@end
`
r, err := NewObjCExtractor().Extract("CalendarModule.m", []byte(src))
if err != nil {
t.Fatalf("extract: %v", err)
}
meta := rnMethodMeta(r.Nodes)
// RCT_EXPORT_METHOD: selector node "addEvent:location:", JS name "addEvent".
if got, ok := meta["addEvent:location:"]; !ok || got != [2]string{"CalendarModule", "addEvent"} {
t.Errorf("addEvent export = %v (ok=%v), want module CalendarModule method addEvent", meta["addEvent:location:"], ok)
}
// RCT_REMAP_METHOD: explicit JS name "getThing", native selector
// "fetchThingWithResolver:rejecter:".
if got, ok := meta["fetchThingWithResolver:rejecter:"]; !ok || got != [2]string{"CalendarModule", "getThing"} {
t.Errorf("getThing remap = %v (ok=%v), want module CalendarModule method getThing", meta["fetchThingWithResolver:rejecter:"], ok)
}
}
func TestObjCExtract_RNModuleExplicitName(t *testing.T) {
src := `@implementation Impl
RCT_EXPORT_MODULE(MyJSName);
RCT_EXPORT_METHOD(doStuff:(NSString *)x) {}
@end
`
r, err := NewObjCExtractor().Extract("Impl.m", []byte(src))
if err != nil {
t.Fatalf("extract: %v", err)
}
meta := rnMethodMeta(r.Nodes)
if got := meta["doStuff:"]; got != [2]string{"MyJSName", "doStuff"} {
t.Errorf("doStuff = %v, want module MyJSName method doStuff", got)
}
}
func TestJavaExtract_RNReactMethod(t *testing.T) {
src := `package com.example;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;
@ReactModule(name = "Calendar")
public class CalendarModule extends ReactContextBaseJavaModule {
@Override
public String getName() { return "Calendar"; }
@ReactMethod
public void createEvent(String name, String location) {}
public void notExported() {}
}
`
r, err := NewJavaExtractor().Extract("CalendarModule.java", []byte(src))
if err != nil {
t.Fatalf("extract: %v", err)
}
meta := rnMethodMeta(r.Nodes)
if got, ok := meta["createEvent"]; !ok || got != [2]string{"Calendar", "createEvent"} {
t.Errorf("createEvent = %v (ok=%v), want module Calendar (the @ReactModule override) method createEvent", meta["createEvent"], ok)
}
if _, ok := meta["notExported"]; ok {
t.Errorf("notExported must not carry RN metadata")
}
}
// rnCallTargets returns the To-ends of every rn.native placeholder call
// edge emitted by a JS/TS extractor.
func rnCallTargets(edges []*graph.Edge) []string {
var out []string
for _, e := range edges {
if e.Kind == graph.EdgeCalls && e.Meta != nil {
if v, _ := e.Meta["via"].(string); v == rnNativeVia {
out = append(out, e.To)
}
}
}
return out
}
func TestJSExtract_RNNativeCalls(t *testing.T) {
cases := map[string]string{
"direct": `import { NativeModules } from 'react-native';
function go() { NativeModules.Calendar.createEvent('b', 'home'); }`,
"bound_var": `import { NativeModules } from 'react-native';
const Cal = NativeModules.Calendar;
function go() { Cal.createEvent('b', 'home'); }`,
"require_native": `const Cal = requireNativeModule('Calendar');
function go() { Cal.createEvent('b'); }`,
"turbomodule": `const Cal = TurboModuleRegistry.getEnforcing('Calendar');
function go() { Cal.createEvent('b'); }`,
"destructure": `import { NativeModules } from 'react-native';
const { Calendar } = NativeModules;
function go() { Calendar.createEvent('b'); }`,
}
for name, src := range cases {
t.Run(name, func(t *testing.T) {
r, err := NewJavaScriptExtractor().Extract("app.js", []byte(src))
if err != nil {
t.Fatalf("extract: %v", err)
}
targets := rnCallTargets(r.Edges)
want := "unresolved::rn::Calendar::createEvent"
found := false
for _, tg := range targets {
if tg == want {
found = true
}
}
if !found {
t.Errorf("%s: rn native call targets = %v, want %q", name, targets, want)
}
})
}
}