Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve test coverage #78

Merged
merged 8 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
java/test/out/*
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ RUN go mod download && go mod verify

COPY . .

CMD go test
CMD ./testing.sh


3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ This allows for Go to initiate the JVM or Java to start a Go runtime respectivel

Docs: https://pkg.go.dev/tekao.net/jnigi

## Pull Requests
**Please make sure**: `go test` works, add any doc comments for function signature changes.

## v1
As of 2021-12-05 the master branch will be version 2. Packages that used JNIGI before this should update their go.mod to set v1 as the
version. Or update their code to be compatible with version 2.
Expand Down
4 changes: 2 additions & 2 deletions cwrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,8 +646,8 @@ const (
JNI_VERSION_1_4 = C.JNI_VERSION_1_4
JNI_VERSION_1_6 = C.JNI_VERSION_1_6
JNI_VERSION_1_8 = C.JNI_VERSION_1_8
JNI_VERSION_9 = C.JNI_VERSION_9
JNI_VERSION_10 = C.JNI_VERSION_10
JNI_VERSION_9 = C.JNI_VERSION_9
JNI_VERSION_10 = C.JNI_VERSION_10

DEFAULT_VERSION = JNI_VERSION_1_6
)
Expand Down
4 changes: 4 additions & 0 deletions java/test/javac.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

cd $(dirname $0)
javac -d out -cp src src/local/*
7 changes: 7 additions & 0 deletions java/test/src/local/JnigiTestBase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package local;

public class JnigiTestBase {
public int meaning() {
return 42;
}
}
7 changes: 7 additions & 0 deletions java/test/src/local/JnigiTestExtend.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package local;

public class JnigiTestExtend extends JnigiTestBase {
public int meaning() {
return 1337;
}
}
5 changes: 5 additions & 0 deletions java/test/src/local/JnigiTesting.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package local;

public class JnigiTesting {
public native java.lang.String Greet(java.lang.String x);
}
121 changes: 112 additions & 9 deletions jnigi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
package jnigi

import (
"github.com/stretchr/testify/assert"
"os"
"path/filepath"
"runtime"
"strings"
"syscall"
"testing"

"github.com/stretchr/testify/assert"
)

var env *Env
Expand All @@ -28,6 +32,8 @@ func TestAll(t *testing.T) {
PTestPushPopLocalFrame(t)
PTestHandleException(t)
PTestCast(t)
PTestNonVirtual(t)
PTestRegisterNative(t)
PTestDestroy(t)
}

Expand All @@ -39,7 +45,8 @@ func PTestInit(t *testing.T) {
t.Fatal(err)
}
runtime.LockOSThread()
jvm2, e2, err := CreateJVM(NewJVMInitArgs(false, true, DEFAULT_VERSION, []string{"-Xcheck:jni"}))
cwd, _ := os.Getwd()
jvm2, e2, err := CreateJVM(NewJVMInitArgs(false, true, DEFAULT_VERSION, []string{"-Xcheck:jni", "-Djava.class.path=" + filepath.Join(cwd, "java/test/out")}))
if err != nil {
t.Fatal(err)
}
Expand All @@ -59,6 +66,7 @@ func PTestBasic(t *testing.T) {
if err := obj.CallMethod(env, "hashCode", &v); err != nil {
t.Fatal(err)
}
env.DeleteLocalRef(obj)

// test env.GetUTF8String() should be independent of PrecalculateSignature
sigStr := "dummy"
Expand All @@ -75,6 +83,7 @@ func PTestBasic(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(str)
var goBytes []byte
if err := str.CallMethod(env, "getBytes", &goBytes, env.GetUTF8String()); err != nil {
t.Fatal(err)
Expand All @@ -88,6 +97,8 @@ func PTestBasic(t *testing.T) {
if err := str.CallMethod(env, "substring", str2, 6); err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(str2)

var dummy []byte
if err := str2.CallMethod(env, "getBytes", &dummy); err != nil {
t.Fatal(err)
Expand All @@ -109,17 +120,26 @@ func PTestBasic(t *testing.T) {
}

// get static field
err = env.SetStaticField("java/util/Calendar", "APRIL", 5)
if err != nil {
t.Fatal(err)
}
var calPos int
err = env.GetStaticField("java/util/Calendar", "APRIL", &calPos)
if err != nil {
t.Fatal(err)
}
if !assert.Equal(t, 5, calPos) {
t.Fail()
}

// set/get object field
pt, err := env.NewObject("java/awt/Point")
if err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(pt)

err = pt.SetField(env, "x", 5)
if err != nil {
t.Fatal(err)
Expand All @@ -142,6 +162,7 @@ func PTestBasic(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(str)

if err := str.CallMethod(env, "getBytes", &goBytes, env.GetUTF8String()); err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -179,6 +200,8 @@ func PTestAttach(t *testing.T) {
}()

<-x
env.DeleteGlobalRef(gObj)
env.DeleteLocalRef(obj)
}

func PTestObjectArrays(t *testing.T) {
Expand All @@ -187,11 +210,12 @@ func PTestObjectArrays(t *testing.T) {
if err != nil {
t.Fatal(err)
}

defer env.DeleteLocalRef(str)
regex, err := env.NewObject("java/lang/String", []byte("X"))
if err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(regex)

v := NewObjectArrayRef("java/lang/String")
if err := str.CallMethod(env, "split", v, regex); err != nil {
Expand All @@ -217,10 +241,12 @@ func PTestObjectArrays(t *testing.T) {
if err := array.CallMethod(env, "getClass", class); err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(class)
jClassName := NewObjectRef("java/lang/String")
if err := class.CallMethod(env, "getName", jClassName); err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(jClassName)
var className []byte
if err := jClassName.CallMethod(env, "getBytes", &className); err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -260,6 +286,7 @@ func PTestConvert(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(str)

var firstWord GoString
if err := str.CallMethod(env, "substring", &firstWord, 0, 4); err != nil {
Expand All @@ -275,11 +302,14 @@ func PTestInstanceOf(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(alist)

str, err := env.NewObject("java/lang/String")
if err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(str)

var dummy bool
if err := alist.CallMethod(env, "add", &dummy, str.Cast("java/lang/Object")); err != nil {
t.Fatal(err)
Expand All @@ -289,6 +319,7 @@ func PTestInstanceOf(t *testing.T) {
if err := alist.CallMethod(env, "get", obj, 0); err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(obj)

if isInstance, err := obj.IsInstanceOf(env, "java/lang/String"); err != nil {
t.Fatal(err)
Expand All @@ -309,24 +340,32 @@ func PTestByteArray(t *testing.T) {
if !assert.Equal(t, "hello", toGoStr(t, str)) {
t.Fail()
}
env.DeleteLocalRef(str)

testStr := "hello world"
str, err = env.NewObject("java/lang/String", []byte(testStr))
if err != nil {
t.Fatal(err)
}
defer env.DeleteLocalRef(str)

arr := NewArrayRef(Byte | Array)
if err := str.CallMethod(env, "getBytes", arr, env.GetUTF8String()); err != nil {
t.Fatal(err)
}

ba2 := env.NewByteArrayFromObject(arr.ObjectRef)
bytes = ba2.GetCritical(env)

bytes = ba2.CopyBytes(env)
if !assert.Equal(t, "hello world", string(bytes)) {
t.Fail()
}
ba2.ReleaseCritical(env, bytes)

ba3 := env.NewByteArrayFromSlice([]byte("hello world!"))
bytes = ba3.CopyBytes(env)
if !assert.Equal(t, "hello world!", string(bytes)) {
t.Fail()
}
}

func PTestGetJVM(t *testing.T) {
Expand Down Expand Up @@ -400,23 +439,49 @@ func PTestPushPopLocalFrame(t *testing.T) {
}
}

func runWithStderrRedir(f func() error) error {
// redirect standard err
stdErrFd := int(os.Stderr.Fd())
newFd, err := syscall.Dup(stdErrFd)
if err != nil {
return err
}
devNull, err := os.OpenFile(os.DevNull, os.O_WRONLY, 000)
if err != nil {
return err
}
syscall.Dup2(int(devNull.Fd()), stdErrFd)
err = f()
syscall.Dup2(newFd, stdErrFd)

return err
}

func newObjWithStderrRedir(class string) error {
err := runWithStderrRedir(func() error {
_, err := env.NewObject(class)
return err
})
return err
}

func PTestHandleException(t *testing.T) {
jexceptErrMsg := "Java exception occurred. check stderr/logcat"
if _, err := env.NewObject("java/foo/bar"); err == nil {
if err := newObjWithStderrRedir("java/foo/bar"); err == nil {
t.Fatal("did not return error")
} else if !assert.Equal(t, jexceptErrMsg, err.Error()) {
t.Fatal("did not return standard error")
}

env.ExceptionHandler = ThrowableToStringExceptionHandler
if _, err := env.NewObject("java/foo/bar"); err == nil {
if err := newObjWithStderrRedir("java/foo/bar"); err == nil {
t.Fatal("did not return error")
} else if !assert.Equal(t, "java.lang.NoClassDefFoundError: java/foo/bar", err.Error()) {
t.Fatal("did not return standard error")
}

env.ExceptionHandler = ThrowableErrorExceptionHandler
if _, err := env.NewObject("java/foo/bar"); err == nil {
if err := newObjWithStderrRedir("java/foo/bar"); err == nil {
t.Fatal("did not return error")
} else {
throwableError, ok := err.(ThrowableError)
Expand Down Expand Up @@ -471,11 +536,12 @@ func PTestHandleException(t *testing.T) {

env.ExceptionHandler = nil

if _, err := env.NewObject("java/foo/bar"); err == nil {
if err := newObjWithStderrRedir("java/foo/bar"); err == nil {
t.Fatal("did not return error")
} else if !assert.Equal(t, jexceptErrMsg, err.Error()) {
t.Error("did not return standard error")
}

}

func PTestCast(t *testing.T) {
Expand All @@ -491,6 +557,43 @@ func PTestCast(t *testing.T) {
}
}

func PTestNonVirtual(t *testing.T) {
obj, err := env.NewObject("local/JnigiTestExtend")
if err != nil {
t.Fatal(err)
}
var val int
if err := obj.CallNonvirtualMethod(env, "local/JnigiTestBase", "meaning", &val); err != nil {
t.Fatal(err)
}

if !assert.Equal(t, 42, val) {
t.Fail()
}
}

func PTestRegisterNative(t *testing.T) {
if err := env.RegisterNative("local/JnigiTesting", "Greet", ObjectType("java/lang/String"), []interface{}{ObjectType("java/lang/String")}, c_go_callback_Greet); err != nil {
t.Fatal(err)
}
objRef, err := env.NewObject("local/JnigiTesting")
if err != nil {
t.Fatal(err)
}
nameRef, err := env.NewObject("java/lang/String", []byte("World"))
if err != nil {
t.Fatal(err)
}
strRef := NewObjectRef("java/lang/String")
if err := objRef.CallMethod(env, "Greet", strRef, nameRef); err != nil {
t.Fatal(err)
}
goStr := toGoStr(t, strRef)
if !assert.Equal(t, "Hello World!", goStr) {
t.Fail()
}
}

func toGoStr(t *testing.T, o *ObjectRef) string {
var goBytes []byte
if err := o.CallMethod(env, "getBytes", &goBytes); err != nil {
Expand Down
Loading
Loading