Add argument type checking tests for io library
This commit is contained in:
@@ -63,6 +63,15 @@ public class IoLib extends LFunction {
|
||||
*/
|
||||
abstract protected File openFile(String filename, String mode) throws IOException;
|
||||
|
||||
/**
|
||||
* Start a new process and return a file for input or output
|
||||
* @param prog the program to execute
|
||||
* @param mode "r" to read, "w" to write
|
||||
* @return File to read to or write from
|
||||
* @throws IOException if an i/o exception occurs
|
||||
*/
|
||||
abstract protected File openProgram(String prog, String mode) throws IOException;
|
||||
|
||||
|
||||
public static final String[] NAMES = {
|
||||
"io",
|
||||
@@ -130,10 +139,6 @@ public class IoLib extends LFunction {
|
||||
PackageLib.setIsLoaded("io", io);
|
||||
}
|
||||
|
||||
private static final char DEFVAL_NONE = 0;
|
||||
private static final char DEFVAL_STDIN = 'r';
|
||||
private static final char DEFVAL_STDOUT= 'w';
|
||||
|
||||
private final int id;
|
||||
|
||||
protected IoLib() {
|
||||
@@ -182,7 +187,6 @@ public class IoLib extends LFunction {
|
||||
|
||||
public boolean luaStackCall( LuaState vm ) {
|
||||
File f;
|
||||
String s;
|
||||
int n;
|
||||
try {
|
||||
switch ( id ) {
|
||||
@@ -191,7 +195,10 @@ public class IoLib extends LFunction {
|
||||
initialize(vm._G);
|
||||
break;
|
||||
case IO_CLOSE:
|
||||
optfile(vm,2,DEFVAL_STDOUT).close();
|
||||
f = vm.isnoneornil(2)?
|
||||
output(vm):
|
||||
checkfile(vm,2);
|
||||
f.close();
|
||||
vm.resettop();
|
||||
vm.pushboolean(true);
|
||||
break;
|
||||
@@ -202,15 +209,17 @@ public class IoLib extends LFunction {
|
||||
vm.pushboolean(true);
|
||||
break;
|
||||
case IO_INPUT:
|
||||
INPUT = ((s = vm.optstring(1, null)) != null)?
|
||||
ioopenfile(vm,s,"r"):
|
||||
optfile(vm,2,DEFVAL_STDIN);
|
||||
INPUT = vm.isnoneornil(2)?
|
||||
input(vm):
|
||||
vm.isstring(2)?
|
||||
ioopenfile(vm,vm.checkstring(2),"r"):
|
||||
checkfile(vm,2);
|
||||
setresult(vm, INPUT);
|
||||
break;
|
||||
case IO_LINES:
|
||||
INPUT = ((s = vm.optstring(1, null)) != null)?
|
||||
ioopenfile(vm,s,"r"):
|
||||
optfile(vm,2,DEFVAL_STDIN);
|
||||
INPUT = vm.isnoneornil(2)?
|
||||
input(vm):
|
||||
ioopenfile(vm,vm.checkstring(2),"r");
|
||||
vm.resettop();
|
||||
vm.pushlvalue(lines(INPUT));
|
||||
break;
|
||||
@@ -218,12 +227,15 @@ public class IoLib extends LFunction {
|
||||
setresult(vm, openFile(vm.checkstring(2), vm.optstring(3,"r")));
|
||||
break;
|
||||
case IO_OUTPUT:
|
||||
OUTPUT = ((s = vm.optstring(2, null)) != null)?
|
||||
ioopenfile(vm,s,"w"):
|
||||
optfile(vm,2,DEFVAL_STDOUT);
|
||||
OUTPUT = vm.isnoneornil(2)?
|
||||
output(vm):
|
||||
vm.isstring(2)?
|
||||
ioopenfile(vm,vm.checkstring(2),"w"):
|
||||
checkfile(vm,2);
|
||||
setresult(vm, OUTPUT);
|
||||
break;
|
||||
case IO_POPEN:
|
||||
setresult(vm, openProgram(vm.checkstring(2),vm.optstring(3, "r")));
|
||||
break;
|
||||
case IO_READ:
|
||||
ioread( vm, INPUT );
|
||||
@@ -231,7 +243,7 @@ public class IoLib extends LFunction {
|
||||
case IO_TMPFILE:
|
||||
break;
|
||||
case IO_TYPE:
|
||||
f = optfile(vm,2,DEFVAL_NONE);
|
||||
f = optfile(vm,2);
|
||||
vm.resettop();
|
||||
if ( f != null )
|
||||
vm.pushstring(f.isclosed()? "closed file": "file");
|
||||
@@ -262,7 +274,9 @@ public class IoLib extends LFunction {
|
||||
ioread(vm, f);
|
||||
break;
|
||||
case FILE_SEEK:
|
||||
n = checkfile(vm,2).seek(vm.optstring(1,"cur"),vm.optint(3, 0));
|
||||
f = checkfile(vm,2);
|
||||
vm.remove(2);
|
||||
n = f.seek(vm.optstring(2,"cur"),vm.optint(3, 0));
|
||||
vm.resettop();
|
||||
vm.pushinteger(n);
|
||||
break;
|
||||
@@ -303,7 +317,7 @@ public class IoLib extends LFunction {
|
||||
private static void iowrite(LuaState vm, File f) throws IOException {
|
||||
checkopen(vm,f);
|
||||
for ( int i=2, n=vm.gettop(); i<=n; i++ )
|
||||
f.write( vm.tolstring(i) );
|
||||
f.write( vm.checklstring(i) );
|
||||
vm.resettop();
|
||||
vm.pushboolean(true);
|
||||
}
|
||||
@@ -334,12 +348,9 @@ public class IoLib extends LFunction {
|
||||
return (File) vm.checkudata(index, File.class);
|
||||
}
|
||||
|
||||
private File optfile(LuaState vm, int index, char defval) {
|
||||
private File optfile(LuaState vm, int index) {
|
||||
Object u = vm.touserdata(index);
|
||||
return (u instanceof File? (File) u:
|
||||
defval==DEFVAL_STDOUT? output(vm):
|
||||
defval==DEFVAL_STDIN? input(vm):
|
||||
null);
|
||||
return (u instanceof File? (File) u: null);
|
||||
}
|
||||
|
||||
private static void checkopen(LuaState vm, File file) {
|
||||
|
||||
@@ -22,11 +22,6 @@
|
||||
package org.luaj.lib.j2se;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -69,8 +64,12 @@ public class J2seIoLib extends IoLib {
|
||||
// TODO: handle update mode
|
||||
// boolean isupdate = mode.endsWith("+");
|
||||
RandomAccessFile f = new RandomAccessFile(filename,isreadmode? "r": "rw");
|
||||
if ( isappend )
|
||||
if ( isappend ) {
|
||||
f.seek(f.length());
|
||||
} else {
|
||||
if ( ! isreadmode )
|
||||
f.setLength(0);
|
||||
}
|
||||
return new FileImpl( f );
|
||||
}
|
||||
|
||||
@@ -82,41 +81,42 @@ public class J2seIoLib extends IoLib {
|
||||
private final RandomAccessFile file;
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
private final Closeable closer;
|
||||
private final DataInput din;
|
||||
private final DataOutput dout;
|
||||
private boolean closed = false;
|
||||
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os, DataInput din, DataOutput dout, Closeable closer ) {
|
||||
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) {
|
||||
this.file = file;
|
||||
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
|
||||
this.os = os;
|
||||
this.din = din;
|
||||
this.dout = dout;
|
||||
this.closer = closer;
|
||||
}
|
||||
private FileImpl( RandomAccessFile f ) {
|
||||
this( f, null, null, f, f, f );
|
||||
this( f, null, null );
|
||||
}
|
||||
private FileImpl( InputStream i ) {
|
||||
this( null, i, null, new DataInputStream(i), null, i );
|
||||
this( null, i, null );
|
||||
}
|
||||
private FileImpl( OutputStream o ) {
|
||||
this( null, null, o, null, new DataOutputStream(o), o );
|
||||
this( null, null, o );
|
||||
}
|
||||
public String toString() {
|
||||
return "file ("+this.hashCode()+")";
|
||||
}
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
closer.close();
|
||||
if ( file != null )
|
||||
file.close();
|
||||
else if ( os != null )
|
||||
os.close();
|
||||
else if ( is != null )
|
||||
is.close();
|
||||
}
|
||||
public void flush() throws IOException {
|
||||
if ( os != null )
|
||||
os.flush();
|
||||
}
|
||||
public void write(LString s) throws IOException {
|
||||
if ( dout != null )
|
||||
dout.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
if ( os != null )
|
||||
os.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else if ( file != null )
|
||||
file.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else
|
||||
notimplemented();
|
||||
}
|
||||
@@ -125,21 +125,24 @@ public class J2seIoLib extends IoLib {
|
||||
}
|
||||
public int seek(String option, int pos) throws IOException {
|
||||
if ( file != null ) {
|
||||
if ( "set".equals(option) )
|
||||
if ( "set".equals(option) ) {
|
||||
file.seek(pos);
|
||||
else if ( "end".equals(option) )
|
||||
file.seek(file.length()+pos);
|
||||
else
|
||||
return (int) file.getFilePointer();
|
||||
} else if ( "end".equals(option) ) {
|
||||
file.seek(file.length()+1+pos);
|
||||
return (int) file.length()+1;
|
||||
} else {
|
||||
file.seek(file.getFilePointer()+pos);
|
||||
return (int) file.getFilePointer();
|
||||
return (int) file.getFilePointer();
|
||||
}
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
public LValue readBytes(int count) throws IOException {
|
||||
if ( din != null ) {
|
||||
if ( file != null ) {
|
||||
byte[] b = new byte[count];
|
||||
din.readFully(b);
|
||||
file.readFully(b);
|
||||
return new LString(b);
|
||||
}
|
||||
notimplemented();
|
||||
@@ -208,4 +211,10 @@ public class J2seIoLib extends IoLib {
|
||||
}
|
||||
}
|
||||
|
||||
protected File openProgram(String prog, String mode) throws IOException {
|
||||
final Process p = Runtime.getRuntime().exec(prog);
|
||||
return "w".equals(mode)?
|
||||
new FileImpl( p.getOutputStream() ):
|
||||
new FileImpl( p.getInputStream() );
|
||||
}
|
||||
}
|
||||
|
||||
68
src/test/errors/iolibargs.lua
Normal file
68
src/test/errors/iolibargs.lua
Normal file
@@ -0,0 +1,68 @@
|
||||
package.path = "?.lua;src/test/errors/?.lua"
|
||||
require 'args'
|
||||
|
||||
-- arg type tests for io library functions
|
||||
local f
|
||||
|
||||
-- io.close ([file])
|
||||
banner('io.close')
|
||||
f = io.open("abc.txt","w")
|
||||
checkallpass('io.close',{{f}})
|
||||
checkallerrors('io.close',{notanil},'bad argument #1')
|
||||
|
||||
-- io.input ([file])
|
||||
checkallpass('io.input',{{nil,f,"abc.txt"}})
|
||||
checkallerrors('io.input',{nonstring},'bad argument #1')
|
||||
|
||||
-- io.lines ([filename])
|
||||
io.input("abc.txt")
|
||||
checkallpass('io.lines',{{nil,"abc.txt"}})
|
||||
checkallerrors('io.lines',{{f}},'bad argument #1')
|
||||
checkallerrors('io.lines',{nonstring},'bad argument #1')
|
||||
|
||||
-- io.open (filename [, mode])
|
||||
checkallpass('io.open',{{"abc.txt"},{nil,"r","w","a","r+","w+","a+"}})
|
||||
checkallerrors('io.open',{notastring},'bad argument #1')
|
||||
checkallerrors('io.open',{{"abc.txt"},{nonstring}},'bad argument #2')
|
||||
|
||||
-- io.output ([file])
|
||||
checkallpass('io.output',{{nil,f,"abc.txt"}})
|
||||
checkallerrors('io.output',{nonstring},'bad argument #1')
|
||||
|
||||
-- io.popen (prog [, mode])
|
||||
checkallpass('io.popen',{{"hostname"},{nil,"r","w","a","r+","w+","a+"}})
|
||||
checkallerrors('io.popen',{notastring},'bad argument #1')
|
||||
checkallerrors('io.popen',{{"hostname"},{nonstring}},'bad argument #2')
|
||||
|
||||
-- io.read (···)
|
||||
local areadfmt = {2,"*n","*a","*l","3"}
|
||||
checkallpass('io.read',{})
|
||||
checkallpass('io.read',{areadfmt})
|
||||
checkallpass('io.read',{areadfmt,areadfmt})
|
||||
checkallerrors('io.read',{{aboolean,afunction,atable}},'bad argument #1')
|
||||
|
||||
-- io.read (···)
|
||||
checkallpass('io.write',{})
|
||||
checkallpass('io.write',{somestring})
|
||||
checkallpass('io.write',{somestring,somestring})
|
||||
checkallerrors('io.write',{nonstring},'bad argument #1')
|
||||
checkallerrors('io.write',{somestring,nonstring},'bad argument #2')
|
||||
|
||||
-- file:write ()
|
||||
file = io.open("seektest.txt","w")
|
||||
checkallpass('file.write',{{file},somestring})
|
||||
checkallpass('file.write',{{file},somestring,somestring})
|
||||
checkallerrors('file.write',{},'bad argument #1')
|
||||
checkallerrors('file.write',{{file},nonstring},'bad argument #1')
|
||||
checkallerrors('file.write',{{file},somestring,nonstring},'bad argument #2')
|
||||
pcall( file.close, file )
|
||||
|
||||
-- file:seek ([whence] [, offset])
|
||||
file = io.open("seektest.txt","r")
|
||||
checkallpass('file.seek',{{file}})
|
||||
checkallpass('file.seek',{{file},{"set","cur","end"}})
|
||||
checkallpass('file.seek',{{file},{"set","cur","end"},{2,"3"}})
|
||||
checkallerrors('file.seek',{},'bad argument #1')
|
||||
checkallerrors('file.seek',{{file},nonstring},'bad argument #1')
|
||||
checkallerrors('file.seek',{{file},{"set","cur","end"},nonnumber},'bad argument #2')
|
||||
|
||||
@@ -24,3 +24,40 @@ for i,v in ipairs(t) do
|
||||
print( string.format("%q",tostring(v)), type(v))
|
||||
end
|
||||
|
||||
local h = io.open("abc.txt", "a")
|
||||
print( 'h', io.type(h) )
|
||||
print( 'write', h:write('\nmore text\neven more text\n') )
|
||||
print( 'close', h:close() )
|
||||
|
||||
local j = io.open( "abc.txt", "r" )
|
||||
print( 'j', io.type(j) )
|
||||
print( 'seek', j:seek("set", 3) )
|
||||
print( 'read', j:read(4), j:read(3) )
|
||||
print( 'seek', j:seek("set", 2) )
|
||||
print( 'read', j:read(4), j:read(3) )
|
||||
print( 'seek', j:seek("cur", -8 ) )
|
||||
print( 'read', j:read(4), j:read(3) )
|
||||
print( 'seek(cur,0)', j:seek("cur",0) )
|
||||
print( 'seek(cur,20)', j:seek("cur",20) )
|
||||
print( 'seek(end,-5)', j:seek("end", -5) )
|
||||
print( 'read(4)', string.format("%q", tostring(j:read(4))) )
|
||||
print( 'read(4)', string.format("%q", tostring(j:read(4))) )
|
||||
print( 'read(4)', string.format("%q", tostring(j:read(4))) )
|
||||
|
||||
for l in io.lines("abc.txt") do
|
||||
print( string.format('%q',l) )
|
||||
end
|
||||
io.input("abc.txt")
|
||||
for l in io.lines() do
|
||||
print( string.format('%q',l) )
|
||||
end
|
||||
io.input(io.open("abc.txt","r"))
|
||||
for l in io.lines() do
|
||||
print( string.format('%q',l) )
|
||||
end
|
||||
io.input("abc.txt")
|
||||
io.input(io.input())
|
||||
for l in io.lines() do
|
||||
print( string.format('%q',l) )
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user