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
192 lines
6.0 KiB
Go
192 lines
6.0 KiB
Go
package languages
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
func emitEdgeTo(edges []*graph.Edge, kind graph.EdgeKind, to string) *graph.Edge {
|
|
for _, e := range edges {
|
|
if e.Kind == kind && e.To == to {
|
|
return e
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func TestObjCExtractor_RNNativeEmit(t *testing.T) {
|
|
const objc = `#import "RCTEventEmitter.h"
|
|
|
|
@implementation BatteryModule
|
|
- (void)notify {
|
|
[self sendEventWithName:@"battery" body:@{@"level": @100}];
|
|
}
|
|
@end
|
|
`
|
|
res, err := NewObjCExtractor().Extract("BatteryModule.m", []byte(objc))
|
|
require.NoError(t, err)
|
|
|
|
topicID := "event::pubsub::rn_native_event::battery"
|
|
var topic *graph.Node
|
|
for _, n := range res.Nodes {
|
|
if n.ID == topicID {
|
|
topic = n
|
|
}
|
|
}
|
|
require.NotNil(t, topic, "native emit should materialise the rn_native_event topic node")
|
|
assert.Equal(t, graph.KindEvent, topic.Kind)
|
|
assert.Equal(t, "rn_native_event", topic.Meta["transport"])
|
|
|
|
emit := emitEdgeTo(res.Edges, graph.EdgeEmits, topicID)
|
|
require.NotNil(t, emit, "sendEventWithName: should emit an EdgeEmits to the topic")
|
|
assert.Equal(t, "BatteryModule.m::notify", emit.From, "emit attributed to the enclosing method")
|
|
}
|
|
|
|
func TestSwiftExtractor_RNNativeEmit(t *testing.T) {
|
|
const swift = `class BatteryModule {
|
|
func notify() {
|
|
sendEvent(withName: "battery", body: ["level": 100])
|
|
}
|
|
}
|
|
`
|
|
res, err := NewSwiftExtractor().Extract("BatteryModule.swift", []byte(swift))
|
|
require.NoError(t, err)
|
|
|
|
topicID := "event::pubsub::rn_native_event::battery"
|
|
emit := emitEdgeTo(res.Edges, graph.EdgeEmits, topicID)
|
|
require.NotNil(t, emit, "sendEvent(withName:) should emit an EdgeEmits to the topic")
|
|
assert.Equal(t, "BatteryModule.swift::BatteryModule.notify", emit.From, "emit attributed to the enclosing method")
|
|
}
|
|
|
|
func TestRNNativeEventEmitterListener(t *testing.T) {
|
|
// A JS NativeEventEmitter addListener re-homes onto the rn_native_event
|
|
// bridge (via the react-native import) so it shares the topic node with
|
|
// the native sendEventWithName: emitter.
|
|
src := `import { NativeEventEmitter, NativeModules } from 'react-native';
|
|
|
|
function subscribe() {
|
|
const emitter = new NativeEventEmitter(NativeModules.BatteryModule);
|
|
emitter.addListener('battery', onBattery);
|
|
}
|
|
`
|
|
fix := runTSExtractFixture(t, "app.ts", src)
|
|
|
|
events := fix.nodesByKind[graph.KindEvent]
|
|
require.Len(t, events, 1)
|
|
assert.Equal(t, "event::pubsub::rn_native_event::battery", events[0].ID)
|
|
assert.Equal(t, "rn_native_event", events[0].Meta["transport"])
|
|
assert.Len(t, fix.edgesByKind[graph.EdgeListensOn], 1)
|
|
}
|
|
|
|
func TestSwiftExtractor_RNCustomSendEventWrapper(t *testing.T) {
|
|
const swift = `class Notifier {
|
|
func emit() {
|
|
sendEvent(reactContext, "MyEvent", body)
|
|
}
|
|
}
|
|
`
|
|
res, err := NewSwiftExtractor().Extract("Notifier.swift", []byte(swift))
|
|
require.NoError(t, err)
|
|
|
|
topicID := "event::pubsub::rn_native_event::MyEvent"
|
|
emit := emitEdgeTo(res.Edges, graph.EdgeEmits, topicID)
|
|
require.NotNil(t, emit, "custom sendEvent(...) wrapper should emit an EdgeEmits to the topic")
|
|
assert.Equal(t, "Notifier.swift::Notifier.emit", emit.From, "emit attributed to the enclosing method")
|
|
|
|
count := 0
|
|
for _, e := range res.Edges {
|
|
if e.Kind == graph.EdgeEmits && e.To == topicID {
|
|
count++
|
|
}
|
|
}
|
|
assert.Equal(t, 1, count, "wrapper form must not double-count the emit edge")
|
|
}
|
|
|
|
func TestObjCExtractor_RNCustomSendEventWrapper(t *testing.T) {
|
|
const objc = `@implementation Notifier
|
|
- (void)emit {
|
|
sendEvent(self, @"MyEvent", @{});
|
|
}
|
|
@end
|
|
`
|
|
res, err := NewObjCExtractor().Extract("Notifier.m", []byte(objc))
|
|
require.NoError(t, err)
|
|
|
|
topicID := "event::pubsub::rn_native_event::MyEvent"
|
|
emit := emitEdgeTo(res.Edges, graph.EdgeEmits, topicID)
|
|
require.NotNil(t, emit, "ObjC paren-form sendEvent(...) wrapper should emit an EdgeEmits to the topic")
|
|
|
|
count := 0
|
|
for _, e := range res.Edges {
|
|
if e.Kind == graph.EdgeEmits && e.To == topicID {
|
|
count++
|
|
}
|
|
}
|
|
assert.Equal(t, 1, count, "wrapper form must not double-count the emit edge")
|
|
}
|
|
|
|
func TestKotlinExtractor_RNJVMEmit(t *testing.T) {
|
|
const kt = `package com.example
|
|
|
|
class ScoreModule(reactContext: ReactApplicationContext) {
|
|
fun broadcast() {
|
|
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java).emit("Score", params)
|
|
}
|
|
}
|
|
`
|
|
res, err := NewKotlinExtractor().Extract("ScoreModule.kt", []byte(kt))
|
|
require.NoError(t, err)
|
|
|
|
topicID := "event::pubsub::rn_native_event::Score"
|
|
emit := emitEdgeTo(res.Edges, graph.EdgeEmits, topicID)
|
|
require.NotNil(t, emit, "getJSModule(...).emit(\"Score\") should emit an EdgeEmits to the topic")
|
|
assert.NotEmpty(t, emit.From, "emit attributed to the enclosing method")
|
|
}
|
|
|
|
func TestJavaExtractor_RNJVMEmit(t *testing.T) {
|
|
const j = `package com.example;
|
|
|
|
public class ScoreModule {
|
|
void broadcast() {
|
|
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("Score", params);
|
|
}
|
|
}
|
|
`
|
|
res, err := NewJavaExtractor().Extract("ScoreModule.java", []byte(j))
|
|
require.NoError(t, err)
|
|
|
|
topicID := "event::pubsub::rn_native_event::Score"
|
|
emit := emitEdgeTo(res.Edges, graph.EdgeEmits, topicID)
|
|
require.NotNil(t, emit, "getJSModule(...).emit(\"Score\") should emit an EdgeEmits to the topic")
|
|
assert.NotEmpty(t, emit.From, "emit attributed to the enclosing method")
|
|
}
|
|
|
|
func TestKotlinExtractor_RNSendEventWrapper(t *testing.T) {
|
|
const kt = `package com.example
|
|
|
|
class ScoreModule {
|
|
fun broadcast() {
|
|
sendEvent(reactContext, "Score", params)
|
|
}
|
|
}
|
|
`
|
|
res, err := NewKotlinExtractor().Extract("ScoreModule.kt", []byte(kt))
|
|
require.NoError(t, err)
|
|
|
|
topicID := "event::pubsub::rn_native_event::Score"
|
|
emit := emitEdgeTo(res.Edges, graph.EdgeEmits, topicID)
|
|
require.NotNil(t, emit, "sendEvent(reactContext, \"Score\", ...) should emit an EdgeEmits to the topic")
|
|
|
|
count := 0
|
|
for _, e := range res.Edges {
|
|
if e.Kind == graph.EdgeEmits && e.To == topicID {
|
|
count++
|
|
}
|
|
}
|
|
assert.Equal(t, 1, count, "wrapper form must not double-count the emit edge")
|
|
}
|