Skip to content

Commit

Permalink
Improve test coverage for LuaJ bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
gudzpoz committed Apr 26, 2024
1 parent 8222420 commit e78b4f7
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 45 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
[![Build Status](https://github.com/gudzpoz/luajava/actions/workflows/docs.yml/badge.svg)](https://github.com/gudzpoz/luajava/actions/workflows/docs.yml)
[![Document Version](https://img.shields.io/github/package-json/v/gudzpoz/luajava?filename=docs%2Fpackage.json&label=Documentation)](https://gudzpoz.github.io/luajava/)

[![Tests: macOS on M1](https://img.shields.io/bitrise/ace86394e12a32ad/main?label=macOS%20on%20M1&token=t-lcEHLpUl_xT-CeJYzagg)](https://app.bitrise.io/app/ace86394e12a32ad)
[![Tests: macOS on M1](https://img.shields.io/github/actions/workflow/status/gudzpoz/luajava/build-natives.yml?label=macOS%20on%20M1)](https://github.com/gudzpoz/luajava/actions/workflows/build-natives.yml)
[![Tests: Linux on arm64](https://img.shields.io/circleci/build/github/gudzpoz/luajava/main?label=Linux%20on%20arm64)](https://app.circleci.com/pipelines/github/gudzpoz/luajava)

[![Hello World Example](./docs/.vuepress/public/hello.svg)](https://gudzpoz.github.io/luajava/examples/hello-world-mod.html)
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ description: LuaJava, a scripting tool for Java
[![Build Status](https://github.com/gudzpoz/luajava/actions/workflows/docs.yml/badge.svg)](https://github.com/gudzpoz/luajava/actions/workflows/docs.yml)
[![Document Version](https://img.shields.io/github/package-json/v/gudzpoz/luajava?filename=docs%2Fpackage.json&label=Documentation)](https://gudzpoz.github.io/luajava/)

[![Tests: macOS on M1](https://img.shields.io/bitrise/ace86394e12a32ad/main?label=macOS%20on%20M1&token=t-lcEHLpUl_xT-CeJYzagg)](https://app.bitrise.io/app/ace86394e12a32ad)
[![Tests: macOS on M1](https://img.shields.io/github/actions/workflow/status/gudzpoz/luajava/build-natives.yml?label=macOS%20on%20M1)](https://github.com/gudzpoz/luajava/actions/workflows/build-natives.yml)
[![Tests: Linux on arm64](https://img.shields.io/circleci/build/github/gudzpoz/luajava/main?label=Linux%20on%20arm64)](https://app.circleci.com/pipelines/github/gudzpoz/luajava)

<style>
Expand Down
70 changes: 70 additions & 0 deletions example/src/test/java/party/iroiro/luajava/luaj/LuaJLibTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package party.iroiro.luajava.luaj;


import org.junit.jupiter.api.Test;
import party.iroiro.luajava.Lua;

import java.io.*;
import java.nio.file.Files;

import static org.junit.jupiter.api.Assertions.*;
import static party.iroiro.luajava.Lua.LuaError.OK;

public class LuaJLibTest {
@Test
public void testUnsupportedOperation() {
try (Lua L = new LuaJ()) {
L.openLibraries();
assertNotEquals(OK, L.run("return io.tmpfile()"));
assertNotEquals(OK, L.run("return io.popen('/bin/ls')"));
}
}

@Test
public void testFileOperations() {
try (Lua L = new LuaJ()) {
L.openLibraries();
File file = File.createTempFile("luajava", ".txt");
assertFalse(file.getAbsolutePath().contains("'") || file.getAbsolutePath().endsWith("\\"));
assertEquals(OK, L.run("f = io.open('" + file.getAbsolutePath() + "', 'w')"));
assertEquals(OK, L.run("f:setvbuf('line')"));
assertEquals(OK, L.run("f:write('Hello World')"));
assertEquals(OK, L.run("io.flush(f)"));
assertEquals(OK, L.run("io.close(f)"));
try (BufferedReader r = new BufferedReader(new FileReader(file))) {
assertEquals("Hello World", r.readLine());
}

assertEquals(OK, L.run("f = io.open('" + file.getAbsolutePath() + "', 'a')"));
assertEquals(OK, L.run("f:write('!!!')"));
assertEquals(OK, L.run("io.close(f)"));
try (BufferedReader r = new BufferedReader(new FileReader(file))) {
assertEquals("Hello World!!!", r.readLine());
}

assertEquals(OK, L.run("f = io.open('" + file.getAbsolutePath() + "', 'r')"));
assertNotEquals(OK, L.run("f:seek('set', 2)"));
assertEquals(OK, L.run("assert(not f:read('*n'))"));
assertEquals(OK, L.run("assert('Hello World!!!' == f:read('*l'))"));
assertEquals(OK, L.run("assert(not f:read('*l'))"));
assertEquals(OK, L.run("io.close(f)"));

assertEquals(OK, L.run("f = io.open('" + file.getAbsolutePath() + "', 'r')"));
assertEquals(OK, L.run("for l in f:lines() do assert(l == 'Hello World!!!') end"));
assertEquals(OK, L.run("io.close(f)"));

assertEquals(OK, L.run("f = io.open('" + file.getAbsolutePath() + "', 'r')"));
assertEquals(OK, L.run("assert(f:read('*a') == 'Hello World!!!')"));
assertEquals(OK, L.run("io.close(f)"));

assertEquals(OK, L.run("io.input()"));
assertEquals(OK, L.run("io.output()"));
assertEquals(OK, L.run("io.input('" + file.getAbsolutePath() + "')"));
assertEquals(OK, L.run("io.output('" + file.getAbsolutePath() + "')"));

Files.delete(file.toPath());
} catch (IOException e) {
fail(e);
}
}
}
83 changes: 83 additions & 0 deletions example/src/test/java/party/iroiro/luajava/luaj/LuaJTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package party.iroiro.luajava.luaj;

import org.junit.jupiter.api.Test;
import party.iroiro.luajava.Lua;

import static org.junit.jupiter.api.Assertions.*;
import static party.iroiro.luajava.Lua.LuaError.OK;
import static party.iroiro.luajava.Lua.LuaType.TABLE;

public class LuaJTest {
@Test
public void testLuaJGlobalNop() {
try (Lua L = new LuaJ()) {
L.getLuaNative().loadAsGlobal();
}
}

@Test
public void testLuaJConcat() {
try (Lua L = new LuaJ()) {
L.createTable(0, 0);
assertThrows(IllegalArgumentException.class, () -> L.concat(-1));
L.concat(1);
assertEquals(TABLE, L.type(-1));
}
}

@Test
public void testLuaJUnsupported() {
try (Lua L = new LuaJ()) {
LuaJNatives natives = (LuaJNatives) L.getLuaNative();
long p = L.getPointer();
assertThrows(UnsupportedOperationException.class, () -> natives.lua_topointer(p, 1));
assertThrows(UnsupportedOperationException.class, () -> natives.lua_tothread(p, 1));
assertThrows(UnsupportedOperationException.class, () -> natives.lua_touserdata(p, 1));
assertThrows(UnsupportedOperationException.class, () -> natives.lua_yield(p, 1));
assertThrows(UnsupportedOperationException.class, () -> natives.lua_gethookcount(p));
assertThrows(UnsupportedOperationException.class, () -> natives.lua_gethookmask(p));

natives.luaL_where(p, 0);
assertEquals("", L.toString(-1));
}
}

@Test
public void testLuaJTypes() {
try (Lua L = new LuaJ()) {
LuaJNatives natives = (LuaJNatives) L.getLuaNative();
L.push((J) -> 0);
natives.lua_pushlightuserdata(L.getPointer(), 1000);
assertEquals(1, natives.lua_islightuserdata(L.getPointer(), -1));
assertEquals(0, natives.lua_islightuserdata(L.getPointer(), -2));

assertEquals(1, natives.lua_iscfunction(L.getPointer(), -2));
assertEquals(0, natives.lua_iscfunction(L.getPointer(), -1));

natives.lua_newtable(L.getPointer());
assertEquals(TABLE, L.type(-1));
}
}

@Test
public void testLuaJMisc() {
try (Lua L = new LuaJ()) {
LuaJNatives natives = (LuaJNatives) L.getLuaNative();
long p = L.getPointer();
assertEquals("BBB", natives.luaL_gsub(p, "AAA", "A", "B"));

assertEquals(OK, L.run("local a = 'up'; return function() return a end"));
assertEquals("", natives.lua_getupvalue(p, -1, 0));
assertEquals("up", L.toString(-1));
L.pop(1);
L.push("down");
assertEquals("", natives.lua_setupvalue(p, -2, 0));
assertEquals(OK, L.pCall(0, 1));
assertEquals("down", L.toString(-1));

assertEquals(OK, L.run("local t = {}; setmetatable(t, { a = function() return 100 end }); return t"));
assertEquals(1, natives.luaL_callmeta(p, -1, "a"));
assertEquals(100, L.toNumber(-1));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ public static boolean isAndroid() {
}),
new ScriptTester("/suite/compatTest.lua", L ->
L.setExternalLoader(new ClassPathLoader())),
new ScriptTester("/suite/coroutineTest.lua", L -> {}),
};

public void test() {
Expand Down
15 changes: 15 additions & 0 deletions example/suite/src/main/java/party/iroiro/luajava/LuaTestSuite.java
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ public int __call(Lua L) {

private void testStackPositions() {
try (T L = constructor.get()) {
assertThrows(IllegalArgumentException.class, () -> L.toAbsoluteIndex(0));
assertEquals(
L.getLuaNative().getRegistryIndex(),
L.toAbsoluteIndex(L.getLuaNative().getRegistryIndex())
);

Random random = new Random();
// Relative stack positions
for (int i = 0; i < 1024; i++) {
Expand Down Expand Up @@ -599,6 +605,9 @@ private void testNotSupported() {
private void testStackOperations() {
Lua sub = L.newThread();
int top = L.getTop();
L.setTop(top + 1);
assertEquals(NIL, L.type(-1));
L.setTop(top);
Enumeration<Object> objectEnumeration = new Enumeration<Object>() {
@Override
public boolean hasMoreElements() {
Expand Down Expand Up @@ -700,6 +709,8 @@ private void testLuaToJavaConversions() {

luaNative.lua_pushlightuserdata(L.getPointer(), 0);
assertEquals(LIGHTUSERDATA, L.type(-1));
String typename = L.getLuaNative().luaL_typename(L.L, -1);
assertTrue("lightuserdata".equals(typename) || "userdata".equals(typename));
//noinspection resource
assertInstanceOf(LuaValue.class, L.toObject(-1));
assertNull(L.toObject(-1, Void.class));
Expand Down Expand Up @@ -966,6 +977,10 @@ private void testJavaToLuaConversions() {
L.setGlobal("object3");
assertEquals(OK, L.run("assert(object1 == object2)"));
assertEquals(OK, L.run("assert(object2 ~= object3)"));
assertEquals(OK, L.run("assert(object2 ~= 1)"));
assertEquals(OK, L.run("return object1, object2"));
assertFalse(L.rawEqual(-2, -1));
assertTrue(L.rawEqual(-1, -1));

L.push(l -> {
l.push(1024);
Expand Down
22 changes: 22 additions & 0 deletions example/suite/src/main/resources/suite/coroutineTest.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
local functions = {}
for i = 1, 10 do
functions[#functions + 1] = coroutine.wrap(function(prefix)
local i = 1
for i = 1, 5 do
prefix = coroutine.yield(prefix .. i)
end
end)
end

function assertFunctions(prefix, yields)
for _, f in ipairs(functions) do
assert(f(prefix) == yields)
end
end

assert("A", "A1")
assert("B", "B2")
assert("C", "C3")
assert("D", "D4")
assert("E", "E5")
assert("F", nil)
36 changes: 11 additions & 25 deletions luaj/src/main/java/party/iroiro/luajava/luaj/JseIoLib.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@
*/
public class JseIoLib extends IoLib {
@Override
protected File wrapStdin() throws IOException {
protected File wrapStdin() {
return new FileImpl(globals.STDIN, true);
}

@Override
protected File wrapStdout() throws IOException {
protected File wrapStdout() {
return new FileImpl(globals.STDOUT, true);
}

@Override
protected File wrapStderr() throws IOException {
protected File wrapStderr() {
return new FileImpl(globals.STDERR, true);
}

Expand All @@ -40,12 +40,12 @@ protected File openFile(String filename, boolean readMode, boolean appendMode,
}

@Override
protected File tmpFile() throws IOException {
protected File tmpFile() {
throw new UnsupportedOperationException();
}

@Override
protected File openProgram(String prog, String mode) throws IOException {
protected File openProgram(String prog, String mode) {
throw new UnsupportedOperationException();
}

Expand Down Expand Up @@ -100,7 +100,7 @@ public boolean isclosed() {
}

@Override
public int seek(String option, int bytecount) throws IOException {
public int seek(String option, int bytecount) {
throw new UnsupportedOperationException();
}

Expand All @@ -110,20 +110,20 @@ public void setvbuf(String mode, int size) {
}

@Override
public int remaining() throws IOException {
public int remaining() {
return -1;
}

@Override
public int peek() throws IOException, EOFException {
public int peek() throws IOException {
if (peeked < 0) {
peeked = Objects.requireNonNull(in).read();
}
return peeked;
}

@Override
public int read() throws IOException, EOFException {
public int read() throws IOException {
if (peeked >= 0) {
int next = peeked;
peeked = -1;
Expand All @@ -133,22 +133,8 @@ public int read() throws IOException, EOFException {
}

@Override
public int read(byte[] bytes, int offset, int length) throws IOException {
Objects.requireNonNull(in);
if (length == 0) {
return 0;
}
// Reads first char and resets peeked char
try {
bytes[offset] = (byte) read();
} catch (EOFException e) {
return -1;
}
int i, n = 0;
for (i = 1; i < length && n >= 0; i += n) {
n = in.read(bytes, offset + i, length - i);
}
return i;
public int read(byte[] bytes, int offset, int length) {
throw new UnsupportedOperationException();
}
}
}
8 changes: 6 additions & 2 deletions luaj/src/main/java/party/iroiro/luajava/luaj/LuaJNatives.java
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,12 @@ protected int luaL_callmeta(long ptr, int obj, String e) {
@Override
protected int luaL_dostring(long ptr, String str) {
LuaJState L = instances.get((int) ptr);
L.push(L.globals.load(str));
try {
L.push(L.globals.load(str));
} catch (LuaError e) {
L.push(LuaValue.valueOf(e.getMessage()));
return LUA_ERRSYNTAX;
}
return lua_pcall(ptr, 0, LUA_MULTRET, 0);
}

Expand Down Expand Up @@ -986,7 +991,6 @@ protected Object luaJ_dumptobuffer(long ptr) {
buffer.flip();
return buffer;
} catch (IOException e) {
lua_error(ptr);
return null;
}
}
Expand Down
16 changes: 0 additions & 16 deletions luajava/src/main/java/party/iroiro/luajava/value/RefLuaValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,6 @@ public void close() {
// nothing
}

@Override
public boolean equals(Object o) {
if (super.equals(o) && o instanceof RefLuaValue) {
RefLuaValue o2 = (RefLuaValue) o;
if (ref == o2.ref) {
return true;
}
push();
o2.push(L);
boolean equal = L.equal(-1, -2);
L.pop(2);
return equal;
}
return false;
}

@Override
public int getReference() {
return ref;
Expand Down

0 comments on commit e78b4f7

Please sign in to comment.