From 6f9bfc3a849d8dbb00a539a9a76a4d5b973f3983 Mon Sep 17 00:00:00 2001 From: Mick Jordan <mick.jordan@oracle.com> Date: Fri, 27 Feb 2015 11:09:41 -0800 Subject: [PATCH] more connections refactoring, add more tests --- .../builtin/base/ConnectionFunctions.java | 375 +++++++++++------- .../oracle/truffle/r/runtime/RConnection.java | 35 +- .../com/oracle/truffle/r/runtime/RError.java | 1 + .../truffle/r/test/ExpectedTestOutput.test | 66 ++- .../com/oracle/truffle/r/test/TestBase.java | 31 ++ .../oracle/truffle/r/test/all/AllTests.java | 43 +- .../truffle/r/test/failing/FailingTests.java | 6 + .../r/test/library/base/TestConnections.java | 60 ++- .../r/test/rpackages/TestRPackages.java | 24 +- 9 files changed, 424 insertions(+), 217 deletions(-) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java index bbbe96ca2f..7b0e85c045 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java @@ -140,7 +140,7 @@ public abstract class ConnectionFunctions { Terminal("terminal"), File("file"), GZFile("gzfile"), - Socket("socket"), + Socket("socketconn"), Text("textConnection"), URL("url"); @@ -193,11 +193,6 @@ public abstract class ConnectionFunctions { * in, otherwise {@link AbstractOpenMode#Lazy}. */ protected OpenMode openMode; - /** - * If {@link #opened} is {@code false} and {@link #openMode} is - * {@link AbstractOpenMode#Lazy}, the mode the connection should eventually be opened in. - */ - private final OpenMode lazyOpenMode; private final RStringVector classHr; @@ -208,28 +203,20 @@ public abstract class ConnectionFunctions { private int descriptor; - /** - * The constructor to use for a connection class whose default open mode is "read". - */ - protected BaseRConnection(ConnectionClass conClass, String modeString) throws IOException { - this(conClass, modeString, new OpenMode("r", AbstractOpenMode.Read)); - } - /** * The constructor to use for a connection class whose default open mode is not "read", but * specified explicitly by "lazyMode". */ - protected BaseRConnection(ConnectionClass conClass, String modeString, OpenMode lazyMode) throws IOException { - this(conClass, new OpenMode(modeString), lazyMode); + protected BaseRConnection(ConnectionClass conClass, String modeString) throws IOException { + this(conClass, new OpenMode(modeString)); } /** - * Primitive constructor that just assigns state. USed by {@link StdConnection}s as they are + * Primitive constructor that just assigns state. Used by {@link StdConnection}s as they are * a special case but should not be used by other connection types. */ - protected BaseRConnection(ConnectionClass conClass, OpenMode mode, OpenMode lazyMode) { + protected BaseRConnection(ConnectionClass conClass, OpenMode mode) { this.openMode = mode; - this.lazyOpenMode = lazyMode; String[] classes = new String[2]; classes[0] = conClass.printName; classes[1] = "connection"; @@ -277,7 +264,7 @@ public abstract class ConnectionFunctions { */ @Override public boolean isTextMode() { - return getRealOpenMode().isText(); + return openMode.isText(); } private void registerConnection() { @@ -294,29 +281,22 @@ public abstract class ConnectionFunctions { @Override public boolean forceOpen(String modeString) throws IOException { boolean ret = opened; - checkOpen(); - return ret; - } - - protected void checkOpen() throws IOException { if (closed) { throw new IOException(RError.Message.INVALID_CONNECTION.message); } if (!opened) { // internal closed or lazy if (openMode.abstractOpenMode == AbstractOpenMode.Lazy) { - openMode = lazyOpenMode; + // modeString may override the default + openMode = new OpenMode(modeString); } createDelegateConnection(); } + return ret; } - String getRealOpenModeAsString() { - return opened ? openMode.modeString : lazyOpenMode.modeString; - } - - OpenMode getRealOpenMode() { - return opened ? openMode : lazyOpenMode; + protected void checkOpen() { + assert !closed && opened; } protected void setDelegate(DelegateRConnection conn) { @@ -348,6 +328,18 @@ public abstract class ConnectionFunctions { theConnection.writeLines(lines, sep); } + @Override + public String readChar(int nchars, boolean useBytes) throws IOException { + checkOpen(); + return theConnection.readChar(nchars, useBytes); + } + + @Override + public void writeChar(String s, int pad, String eos, boolean useBytes) throws IOException { + checkOpen(); + theConnection.writeChar(s, pad, eos, useBytes); + } + @Override public void writeBin(ByteBuffer buffer) throws IOException { checkOpen(); @@ -459,33 +451,6 @@ public abstract class ConnectionFunctions { } } - /** - * Used by the {@code readXXX/writeXXX} builtins to force a connection open and return the - * initial state, so that it can be closed if required. - * - * TODO May need an extra argument to force text/binary depending on the caller. - */ - private static String[] readLinesHelper(BufferedReader bufferedReader, int n) throws IOException { - ArrayList<String> lines = new ArrayList<>(); - String line; - while ((line = bufferedReader.readLine()) != null) { - lines.add(line); - if (n > 0 && lines.size() == n) { - break; - } - } - String[] result = new String[lines.size()]; - lines.toArray(result); - return result; - } - - private static void writeLinesHelper(BufferedWriter bufferedWriter, RAbstractStringVector lines, String sep) throws IOException { - for (int i = 0; i < lines.getLength(); i++) { - bufferedWriter.write(lines.getDataAt(i)); - bufferedWriter.write(sep); - } - } - /** * {@code readLines} from an {@link InputStream}. It would be convenient to use a * {@link BufferedReader} but mixing binary and text operations, which is a requirement, would @@ -543,6 +508,18 @@ public abstract class ConnectionFunctions { } } + private static void writeCharHelper(OutputStream out, String s, int pad, String eos) throws IOException { + out.write(s.getBytes()); + if (pad > 0) { + for (int i = 0; i < pad; i++) { + out.write(0); + } + } + if (eos != null && eos.length() > 0) { + out.write(eos.getBytes()); + } + } + private static void writeBinHelper(ByteBuffer buffer, OutputStream outputStream) throws IOException { int n = buffer.remaining(); byte[] b = new byte[n]; @@ -583,6 +560,19 @@ public abstract class ConnectionFunctions { return totalRead; } + private static String readCharHelper(int nchars, InputStream in, @SuppressWarnings("unused") boolean useBytes) throws IOException { + byte[] bytes = new byte[nchars]; + in.read(bytes); + int j = 0; + for (; j < bytes.length; j++) { + // strings end at 0 + if (bytes[j] == 0) { + break; + } + } + return new String(bytes, 0, j); + } + private static byte[] checkBuffer(byte[] buffer, int n) { if (n > buffer.length - 1) { byte[] newBuffer = new byte[buffer.length + buffer.length / 2]; @@ -633,6 +623,11 @@ public abstract class ConnectionFunctions { throw new IOException(RError.Message.CANNOT_WRITE_CONNECTION.message); } + @Override + public void writeChar(String s, int pad, String eos, boolean useBytes) throws IOException { + throw new IOException(RError.Message.CANNOT_WRITE_CONNECTION.message); + } + @Override public void writeBin(ByteBuffer buffer) throws IOException { throw new IOException(RError.Message.CANNOT_WRITE_CONNECTION.message); @@ -669,6 +664,11 @@ public abstract class ConnectionFunctions { throw new IOException(RError.Message.CANNOT_READ_CONNECTION.message); } + @Override + public String readChar(int nchars, boolean useBytes) throws IOException { + throw new IOException(RError.Message.CANNOT_READ_CONNECTION.message); + } + @Override public int readBin(ByteBuffer buffer) throws IOException { throw new IOException(RError.Message.CANNOT_READ_CONNECTION.message); @@ -695,12 +695,29 @@ public abstract class ConnectionFunctions { } } + private abstract static class DelegateReadWriteRConnection extends DelegateRConnection { + protected DelegateReadWriteRConnection(BaseRConnection base) { + super(base); + } + + @Override + public boolean canRead() { + return true; + } + + @Override + public boolean canWrite() { + return true; + } + + } + /** * Subclasses are special in that they do not use delegation as the connection is always open. */ private abstract static class StdConnection extends BaseRConnection { StdConnection(OpenMode openMode) { - super(ConnectionClass.Terminal, openMode, null); + super(ConnectionClass.Terminal, openMode); this.opened = true; } @@ -887,11 +904,6 @@ public abstract class ConnectionFunctions { this.path = Utils.tildeExpand(path); } - protected BasePathRConnection(String path, ConnectionClass conClass, String modeString, OpenMode lazyMode) throws IOException { - super(conClass, modeString, lazyMode); - this.path = Utils.tildeExpand(path); - } - @Override public String getSummaryDescription() { return path; @@ -940,12 +952,10 @@ public abstract class ConnectionFunctions { private static class FileReadTextRConnection extends DelegateReadRConnection { private BufferedInputStream inputStream; - private BufferedReader bufferedReader; FileReadTextRConnection(BasePathRConnection base) throws IOException { super(base); inputStream = new BufferedInputStream(new FileInputStream(base.path)); - bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); } @Override @@ -961,7 +971,12 @@ public abstract class ConnectionFunctions { @TruffleBoundary @Override public String[] readLinesInternal(int n) throws IOException { - return readLinesHelper(bufferedReader, n); + return readLinesHelper(inputStream, n); + } + + @Override + public String readChar(int nchars, boolean useBytes) throws IOException { + return readCharHelper(nchars, inputStream, useBytes); } @Override @@ -977,19 +992,22 @@ public abstract class ConnectionFunctions { @Override public void internalClose() throws IOException { - bufferedReader.close(); + inputStream.close(); } } private static class FileWriteTextRConnection extends DelegateWriteRConnection { private BufferedOutputStream outputStream; - private BufferedWriter bufferedWriter; FileWriteTextRConnection(FileRConnection base, boolean append) throws IOException { super(base); outputStream = new BufferedOutputStream(new FileOutputStream(base.path, append)); - bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); + } + + @Override + public void writeChar(String s, int pad, String eos, boolean useBytes) throws IOException { + writeCharHelper(outputStream, s, pad, eos); } @Override @@ -999,7 +1017,7 @@ public abstract class ConnectionFunctions { @Override public void writeLines(RAbstractStringVector lines, String sep) throws IOException { - writeLinesHelper(bufferedWriter, lines, sep); + writeLinesHelper(outputStream, lines, sep); flush(); } @@ -1016,12 +1034,12 @@ public abstract class ConnectionFunctions { @Override public void internalClose() throws IOException { - bufferedWriter.close(); + outputStream.close(); } @Override public void flush() throws IOException { - bufferedWriter.flush(); + outputStream.flush(); } } @@ -1033,6 +1051,11 @@ public abstract class ConnectionFunctions { inputStream = new FileInputStream(base.path); } + @Override + public String readChar(int nchars, boolean useBytes) throws IOException { + return readCharHelper(nchars, inputStream, useBytes); + } + @Override public int readBin(ByteBuffer buffer) throws IOException { return inputStream.getChannel().read(buffer); @@ -1064,6 +1087,7 @@ public abstract class ConnectionFunctions { public void internalClose() throws IOException { inputStream.close(); } + } private static class FileWriteBinaryConnection extends DelegateWriteRConnection { @@ -1074,6 +1098,11 @@ public abstract class ConnectionFunctions { outputStream = new FileOutputStream(base.path, append); } + @Override + public void writeChar(String s, int pad, String eos, boolean useBytes) throws IOException { + writeCharHelper(outputStream, s, pad, eos); + } + @Override public void writeBin(ByteBuffer buffer) throws IOException { outputStream.getChannel().write(buffer); @@ -1118,8 +1147,10 @@ public abstract class ConnectionFunctions { @TruffleBoundary @SuppressWarnings("unused") protected Object file(RAbstractStringVector description, RAbstractStringVector open, byte blocking, RAbstractStringVector encoding, byte raw) { - // temporarily return to avoid missing print support controlVisibility(); + if (!RRuntime.fromLogical(blocking)) { + throw RError.nyi(getEncapsulatingSourceSection(), " non-blocking mode not supported"); + } try { return new FileRConnection(description.getDataAt(0), open.getDataAt(0)); } catch (IOException ex) { @@ -1141,7 +1172,7 @@ public abstract class ConnectionFunctions { */ private static class GZIPRConnection extends BasePathRConnection { GZIPRConnection(String path, String modeString) throws IOException { - super(path, ConnectionClass.GZFile, modeString, new OpenMode("rb", AbstractOpenMode.ReadBinary)); + super(path, ConnectionClass.GZFile, modeString); if (openMode.abstractOpenMode != AbstractOpenMode.Lazy) { createDelegateConnection(); } @@ -1178,6 +1209,11 @@ public abstract class ConnectionFunctions { inputStream = new GZIPInputStream(new FileInputStream(base.path), RConnection.GZIP_BUFFER_SIZE); } + @Override + public String readChar(int nchars, boolean useBytes) throws IOException { + return readCharHelper(nchars, inputStream, useBytes); + } + @Override public int readBin(ByteBuffer buffer) throws IOException { return readBinHelper(buffer, inputStream); @@ -1241,6 +1277,11 @@ public abstract class ConnectionFunctions { writeLinesHelper(outputStream, lines, sep); } + @Override + public void writeChar(String s, int pad, String eos, boolean useBytes) throws IOException { + writeCharHelper(outputStream, s, pad, eos); + } + @Override public void writeBin(ByteBuffer buffer) throws IOException { writeBinHelper(buffer, outputStream); @@ -1378,6 +1419,11 @@ public abstract class ConnectionFunctions { throw RError.nyi(null, " readBinChars on text connection"); } + @Override + public String readChar(int nchars, boolean useBytes) throws IOException { + throw RError.nyi(null, " readChar on text connection"); + } + } @RBuiltin(name = "textConnection", kind = INTERNAL, parameterNames = {"nm", "object", "open", "env", "type"}) @@ -1400,74 +1446,100 @@ public abstract class ConnectionFunctions { * While binary operations, e.g. {@code writeBin} are only legal on binary connections, text * operations are legal on text and binary connections. * - * TODO Non-blocking support. Also, while not the default, and evidently rare, GnuR does support - * lazy opening of a socket. + * TODO Non-blocking support. */ - private abstract static class RSocketConnection extends BaseRConnection { - protected String host; - protected Socket socket; - protected InputStream inputStream; - protected OutputStream outputStream; - - protected RSocketConnection(String modeString, String host) throws IOException { + private static class RSocketConnection extends BaseRConnection { + protected final boolean server; + protected final String host; + protected final int port; + protected final boolean blocking; + protected final int timeout; + + protected RSocketConnection(String modeString, boolean server, String host, int port, boolean blocking, int timeout) throws IOException { super(ConnectionClass.Socket, modeString); + this.server = server; this.host = host; + this.port = port; + this.blocking = blocking; + this.timeout = timeout; + if (openMode.abstractOpenMode != AbstractOpenMode.Lazy) { + createDelegateConnection(); + } } @Override protected void createDelegateConnection() throws IOException { - throw RInternalError.shouldNotReachHere(); + DelegateRConnection delegate = server ? new RServerSocketConnection(this) : new RClientSocketConnection(this); + setDelegate(delegate); } - protected String getBasicSummaryData() { - return host + ":" + socket.getPort(); + @Override + public String getSummaryDescription() { + return (server ? "<-" : "->") + host + ":" + port; + } + } + private abstract static class RSocketReadWriteConnection extends DelegateReadWriteRConnection { + protected Socket socket; + protected InputStream inputStream; + protected OutputStream outputStream; + protected final RSocketConnection thisBase; + + protected RSocketReadWriteConnection(RSocketConnection base) { + super(base); + this.thisBase = base; } protected void openStreams() throws IOException { + if (!thisBase.blocking) { + socket.setSoTimeout(thisBase.timeout * 1000); + } inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); } @Override public String[] readLinesInternal(int n) throws IOException { - checkOpen(); return readLinesHelper(inputStream, n); } @Override public InputStream getInputStream() throws IOException { - checkOpen(); return inputStream; } @Override public OutputStream getOutputStream() throws IOException { - checkOpen(); return outputStream; } @Override public void writeLines(RAbstractStringVector lines, String sep) throws IOException { - checkOpen(); writeLinesHelper(outputStream, lines, sep); } @Override public void writeBin(ByteBuffer buffer) throws IOException { - checkOpen(); writeBinHelper(buffer, outputStream); } @Override public int readBin(ByteBuffer buffer) throws IOException { - checkOpen(); return readBinHelper(buffer, inputStream); } + @Override + public void writeChar(String s, int pad, String eos, boolean useBytes) throws IOException { + writeCharHelper(outputStream, s, pad, eos); + } + + @Override + public String readChar(int nchars, boolean useBytes) throws IOException { + return readCharHelper(nchars, inputStream, useBytes); + } + @Override public byte[] readBinChars() throws IOException { - checkOpen(); return readBinCharsHelper(inputStream); } @@ -1478,45 +1550,39 @@ public abstract class ConnectionFunctions { @Override public void close() throws IOException { + base.closed = true; + internalClose(); + } + + @Override + public void internalClose() throws IOException { socket.close(); - closed = true; } + } - private static class RServerSocketConnection extends RSocketConnection { + private static class RServerSocketConnection extends RSocketReadWriteConnection { private ServerSocket serverSocket; - RServerSocketConnection(String modeString, String host, int port) throws IOException { - super(modeString, host); - serverSocket = new ServerSocket(port); + RServerSocketConnection(RSocketConnection base) throws IOException { + super(base); + serverSocket = new ServerSocket(base.port); socket = serverSocket.accept(); openStreams(); - opened = true; - } - - @Override - public String getSummaryDescription() { - return "<-" + getBasicSummaryData(); } @Override - public void close() throws IOException { - super.close(); + public void internalClose() throws IOException { + super.internalClose(); serverSocket.close(); } } - private static class RClientSocketConnection extends RSocketConnection { - RClientSocketConnection(String modeString, String host, int port) throws IOException { - super(modeString, host); - socket = new Socket(host, port); + private static class RClientSocketConnection extends RSocketReadWriteConnection { + RClientSocketConnection(RSocketConnection base) throws IOException { + super(base); + socket = new Socket(base.host, base.port); openStreams(); - opened = true; - } - - @Override - public String getSummaryDescription() { - return "->" + getBasicSummaryData(); } } @@ -1526,24 +1592,21 @@ public abstract class ConnectionFunctions { @CreateCast("arguments") public RNode[] castArguments(RNode[] arguments) { arguments[1] = CastIntegerNodeGen.create(arguments[1], false, false, false); - arguments[6] = CastDoubleNodeGen.create(arguments[6], false, false, false); + arguments[6] = CastIntegerNodeGen.create(arguments[6], false, false, false); return arguments; } @SuppressWarnings("unused") @TruffleBoundary @Specialization - protected Object socketConnection(RAbstractStringVector host, RAbstractIntVector portVec, byte server, byte blocking, RAbstractStringVector open, RAbstractStringVector encoding, double timeout) { + protected Object socketConnection(RAbstractStringVector host, RAbstractIntVector portVec, byte server, byte blocking, RAbstractStringVector open, RAbstractStringVector encoding, int timeout) { int port = portVec.getDataAt(0); String modeString = open.getDataAt(0); - if (modeString.length() == 0) { - throw RError.nyi(getEncapsulatingSourceSection(), " lazy open for sockets"); - } try { if (RRuntime.fromLogical(server)) { - return new RServerSocketConnection(modeString, host.getDataAt(0), port); + return new RSocketConnection(modeString, true, host.getDataAt(0), port, RRuntime.fromLogical(blocking), timeout); } else { - return new RClientSocketConnection(modeString, host.getDataAt(0), port); + return new RSocketConnection(modeString, false, host.getDataAt(0), port, RRuntime.fromLogical(blocking), timeout); } } catch (IOException ex) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.CANNOT_OPEN_CONNECTION); @@ -1583,14 +1646,12 @@ public abstract class ConnectionFunctions { private static class URLReadRConnection extends DelegateReadRConnection { - private InputStream inputStream; - private BufferedReader bufferedReader; + private BufferedInputStream inputStream; protected URLReadRConnection(URLRConnection base) throws MalformedURLException, IOException { super(base); URL url = new URL(base.urlString); - inputStream = url.openStream(); - bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + inputStream = new BufferedInputStream(url.openStream()); } @Override @@ -1605,7 +1666,7 @@ public abstract class ConnectionFunctions { @Override public String[] readLinesInternal(int n) throws IOException { - return readLinesHelper(bufferedReader, n); + return readLinesHelper(inputStream, n); } @Override @@ -1621,7 +1682,12 @@ public abstract class ConnectionFunctions { @Override public void internalClose() throws IOException { - bufferedReader.close(); + inputStream.close(); + } + + @Override + public String readChar(int nchars, boolean useBytes) throws IOException { + return readCharHelper(nchars, inputStream, useBytes); } } @@ -1673,7 +1739,7 @@ public abstract class ConnectionFunctions { Object[] data = new Object[NAMES.getLength()]; data[0] = baseCon.getSummaryDescription(); data[1] = baseCon.classHr.getDataAt(0); - data[2] = baseCon.getRealOpenModeAsString(); + data[2] = baseCon.openMode.modeString; data[3] = baseCon.getSummaryText(); data[4] = baseCon.closed || !baseCon.opened ? "closed" : "opened"; data[5] = baseCon.canRead() ? "yes" : "no"; @@ -1966,12 +2032,17 @@ public abstract class ConnectionFunctions { } @Specialization(guards = {"!ncharsEmpty", "!useBytesEmpty"}) + @TruffleBoundary protected RStringVector readChar(RConnection con, RAbstractIntVector nchars, RAbstractLogicalVector useBytes) { controlVisibility(); boolean wasOpen = true; try { - wasOpen = con.forceOpen("rt"); - return con.readChar(nchars, useBytes.getDataAt(0) == RRuntime.LOGICAL_TRUE); + wasOpen = con.forceOpen("rb"); + String[] data = new String[nchars.getLength()]; + for (int i = 0; i < data.length; i++) { + data[i] = con.readChar(nchars.getDataAt(i), useBytes.getDataAt(0) == RRuntime.LOGICAL_TRUE); + } + return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); } catch (IOException x) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_READING_CONNECTION, x.getMessage()); } finally { @@ -1992,6 +2063,37 @@ public abstract class ConnectionFunctions { } + @RBuiltin(name = "writeChar", kind = INTERNAL, parameterNames = {"object", "con", "nchars", "eos", "useBytes"}) + public abstract static class WriteChar extends InternalCloseHelper { + @TruffleBoundary + @Specialization + protected RNull writeChar(RAbstractStringVector object, RConnection con, RAbstractIntVector nchars, RAbstractStringVector eos, byte useBytes) { + controlVisibility(); + boolean wasOpen = true; + try { + wasOpen = con.forceOpen("wb"); + int length = object.getLength(); + for (int i = 0; i < length; i++) { + String s = object.getDataAt(i); + int nc = nchars.getDataAt(i % length); + int pad = nc - s.length(); + if (pad > 0) { + RContext.getInstance().setEvalWarning(RError.Message.MORE_CHARACTERS.message); + } + con.writeChar(s, pad, eos.getDataAt(i % length), RRuntime.fromLogical(useBytes)); + } + } catch (IOException x) { + throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_READING_CONNECTION, x.getMessage()); + } finally { + if (!wasOpen) { + internalClose(con); + } + } + forceVisibility(false); + return RNull.instance; + } + } + /** * Sets the order of the given {@code ByteBuffer} from value of {@code swap}. The value of * {@code swap} will be {@code true} iff the original requested order was the opposite of the @@ -2186,9 +2288,10 @@ public abstract class ConnectionFunctions { public abstract static class WriteBin extends InternalCloseHelper { @TruffleBoundary @Specialization - protected Object writeBin(RAbstractVector object, RConnection con, int size, byte swapArg, @SuppressWarnings("unused") byte useBytesArg) { + protected Object writeBin(RAbstractVector object, RConnection con, int size, byte swapArg, byte useBytesArg) { boolean swap = RRuntime.fromLogical(swapArg); boolean wasOpen = true; + boolean useBytes = RRuntime.fromLogical(useBytesArg); if (object.getLength() > 0) { try { if (getBaseConnection(con).isTextMode()) { @@ -2202,7 +2305,7 @@ public abstract class ConnectionFunctions { } else if (object instanceof RAbstractComplexVector) { writeComplex((RAbstractComplexVector) object, con, size, swap); } else if (object instanceof RAbstractStringVector) { - writeString((RAbstractStringVector) object, con, size, swap); + writeString((RAbstractStringVector) object, con, size, swap, useBytes); } else if (object instanceof RAbstractStringVector) { writeLogical((RAbstractLogicalVector) object, con, size, swap); } else if (object instanceof RRawVector) { @@ -2265,7 +2368,7 @@ public abstract class ConnectionFunctions { } @SuppressWarnings("unused") - private static void writeString(RAbstractStringVector object, RConnection con, int size, boolean swap) throws IOException { + private static void writeString(RAbstractStringVector object, RConnection con, int size, boolean swap, boolean useBytes) throws IOException { int length = object.getLength(); byte[][] data = new byte[length][]; int totalLength = 0; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RConnection.java index b0a39f635f..0441903b68 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RConnection.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RConnection.java @@ -242,27 +242,24 @@ public abstract class RConnection implements RClassHierarchy { public abstract void flush() throws IOException; - public RStringVector readChar(RAbstractIntVector nchars, @SuppressWarnings("unused") boolean useBytes) throws IOException { - InputStream inputStream = getInputStream(); - String[] data = new String[nchars.getLength()]; - for (int i = 0; i < data.length; i++) { - byte[] bytes = new byte[nchars.getDataAt(i)]; - inputStream.read(bytes); - int j = 0; - for (; j < bytes.length; j++) { - // strings end at 0 - if (bytes[j] == 0) { - break; - } - } - data[i] = new String(bytes, 0, j, "US-ASCII"); - } - - return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); + public abstract int getDescriptor(); - } + /** + * Internal connection-specific support for the {@code writeChar} builtin. + * + * @param s string to output + * @param pad number of (zero) pad bytes + * @param eos string to append to s + * @param useBytes TODO + */ + public abstract void writeChar(String s, int pad, String eos, boolean useBytes) throws IOException; - public abstract int getDescriptor(); + /** + * Internal connection-specific support for the {@code readChar} builtin. + * + * @param nchars number of characters to read + */ + public abstract String readChar(int nchars, boolean useBytes) throws IOException; /** * Internal connection-specific support for the {@code writeBin} builtin. The implementation diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java index 18f6321987..eac08f9cc0 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java @@ -297,6 +297,7 @@ public final class RError extends RuntimeException { CANNOT_WRITE_CONNECTION("cannot write to this connection"), ONLY_READ_BINARY_CONNECTION("can only read from a binary connection"), ONLY_WRITE_BINARY_CONNECTION("can only write to a binary connection"), + MORE_CHARACTERS("more characters requested than are in the string - will zero-pad"), TOO_FEW_LINES_READ_LINES("too few lines read in readLineWRITE_ONs"), INVALID_CONNECTION("invalid connection"), OUT_OF_RANGE("out-of-range values treated as 0 in coercion to raw"), diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 058623b032..bd3fa51716 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -1,76 +1,104 @@ -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testFileWriteReadBin +#{ readBin(file("com.oracle.truffle.r.test/library.base.conn/wb1", "rb"), 3) } +numeric(0) + +##com.oracle.truffle.r.test.library.base.TestConnections.testFileWriteReadBin +#{ writeBin("abc", file("com.oracle.truffle.r.test/library.base.conn/wb1", open="wb")) } + +##com.oracle.truffle.r.test.library.base.TestConnections.testFileWriteReadChar +#{ readChar(file("com.oracle.truffle.r.test/library.base.conn/wc1"), 3) } +[1] "abc" + +##com.oracle.truffle.r.test.library.base.TestConnections.testFileWriteReadChar +#{ writeChar("abc", file("com.oracle.truffle.r.test/library.base.conn/wc1")) } + +##com.oracle.truffle.r.test.library.base.TestConnections.testFileWriteReadLines +#{ con <- file("com.oracle.truffle.r.test/library.base.conn/wl2"); readLines(con, 2) } +[1] "line1" "line2" + +##com.oracle.truffle.r.test.library.base.TestConnections.testFileWriteReadLines +#{ con <- file("com.oracle.truffle.r.test/library.base.conn/wl2"); writeLines(c("line1", "line2"), con) } + +##com.oracle.truffle.r.test.library.base.TestConnections.testFileWriteReadLines +#{ readLines(file("com.oracle.truffle.r.test/library.base.conn/wl1"), 2) } +[1] "line1" "line2" + +##com.oracle.truffle.r.test.library.base.TestConnections.testFileWriteReadLines +#{ writeLines(c("line1", "line2"), file("com.oracle.truffle.r.test/library.base.conn/wl1")) } + +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack("G", con); clearPushBack(con); pushBackLength(con) } [1] 0 -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack("G", con); pushBackLength(con) } [1] 1 -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack("G", con); readLines(con, 1) } [1] "G" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack("G", con); readLines(con, 2) } [1] "G" "a" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack("G", con, newLine=FALSE); readLines(con, 1) } [1] "Ga" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack("G", con, newLine=FALSE); readLines(con, 2) } [1] "Ga" "b" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G", "H"), con); pushBackLength(con) } [1] 2 -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G", "H"), con); readLines(con, 1) } [1] "G" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G", "H"), con); readLines(con, 2) } [1] "G" "H" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G", "H"), con, newLine=FALSE); pushBackLength(con) } [1] 2 -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G", "H"), con, newLine=FALSE); readLines(con, 1) } [1] "GHa" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G", "H"), con, newLine=FALSE); readLines(con, 2) } [1] "GHa" "b" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G\nH"), con); pushBackLength(con) } [1] 1 -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G\nH"), con); readLines(con, 1) } [1] "G" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G\nH"), con); readLines(con, 2) } [1] "G" "H" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G\nH"), con, newLine=FALSE); pushBackLength(con) } [1] 1 -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G\nH"), con, newLine=FALSE); readLines(con, 1) } [1] "G" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBack(c("G\nH"), con, newLine=FALSE); readLines(con, 2) } [1] "G" "Ha" -##com.oracle.truffle.r.test.library.base.TestConnections.testPushBack +##com.oracle.truffle.r.test.library.base.TestConnections.testPushBackTextConnection #{ con<-textConnection(c("a","b","c","d")); pushBackLength(con) } [1] 0 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java index d5d0249726..c9a6ac21c1 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java @@ -13,6 +13,7 @@ package com.oracle.truffle.r.test; import java.io.*; import java.net.*; import java.nio.file.*; +import java.nio.file.attribute.*; import static org.junit.Assert.fail; @@ -703,4 +704,34 @@ public class TestBase { quiet = true; } } + + protected static boolean deleteDir(Path dir) { + try { + Files.walkFileTree(dir, DELETE_VISITOR); + } catch (Exception e) { + return false; + } + return true; + } + + private static final class DeleteVisitor extends SimpleFileVisitor<Path> { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + return del(file); + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + return del(dir); + } + + private static FileVisitResult del(Path p) throws IOException { + Files.delete(p); + return FileVisitResult.CONTINUE; + } + + } + + private static final DeleteVisitor DELETE_VISITOR = new DeleteVisitor(); } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java index 4728f5e3a8..eeb5adc9da 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java @@ -10,97 +10,97 @@ import com.oracle.truffle.r.test.*; public class AllTests extends TestBase { @Test - public void TestConnections_testPushBack_57eb33ce24132c578875659c3672161c() { + public void TestConnections_testPushBackTextConnection_57eb33ce24132c578875659c3672161c() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBackLength(con) }"); } @Test - public void TestConnections_testPushBack_9ab94443d4655966c16600edc46013db() { + public void TestConnections_testPushBackTextConnection_9ab94443d4655966c16600edc46013db() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(\"G\", con); pushBackLength(con) }"); } @Test - public void TestConnections_testPushBack_fb83ddf08b850f1fb0fcfa825768f88c() { + public void TestConnections_testPushBackTextConnection_fb83ddf08b850f1fb0fcfa825768f88c() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(\"G\", con); clearPushBack(con); pushBackLength(con) }"); } @Test - public void TestConnections_testPushBack_55ed6d0b83e86e1385de091582e4af8d() { + public void TestConnections_testPushBackTextConnection_55ed6d0b83e86e1385de091582e4af8d() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(\"G\", con); readLines(con, 1) }"); } @Test - public void TestConnections_testPushBack_d91ddfe61c4e439f5209ecaba013916d() { + public void TestConnections_testPushBackTextConnection_d91ddfe61c4e439f5209ecaba013916d() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(\"G\", con); readLines(con, 2) }"); } @Test - public void TestConnections_testPushBack_94a34439238e4c99bceeda15b2b188e9() { + public void TestConnections_testPushBackTextConnection_94a34439238e4c99bceeda15b2b188e9() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(\"G\", con, newLine=FALSE); readLines(con, 1) }"); } @Test - public void TestConnections_testPushBack_4fdcb63fc43fe75d3bcbc2d474febfd7() { + public void TestConnections_testPushBackTextConnection_4fdcb63fc43fe75d3bcbc2d474febfd7() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(\"G\", con, newLine=FALSE); readLines(con, 2) }"); } @Test - public void TestConnections_testPushBack_db52df62c6e2dbab91e2a3304e913e32() { + public void TestConnections_testPushBackTextConnection_db52df62c6e2dbab91e2a3304e913e32() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\", \"H\"), con); pushBackLength(con) }"); } @Test - public void TestConnections_testPushBack_c5817008fe12a3cea146ab439cf253d0() { + public void TestConnections_testPushBackTextConnection_c5817008fe12a3cea146ab439cf253d0() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\", \"H\"), con); readLines(con, 1) }"); } @Test - public void TestConnections_testPushBack_fd6725165764cf8a366286d2f48fd0bd() { + public void TestConnections_testPushBackTextConnection_fd6725165764cf8a366286d2f48fd0bd() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\", \"H\"), con); readLines(con, 2) }"); } @Test - public void TestConnections_testPushBack_196e9a486c227dad1cbdeb22ca8fbcb9() { + public void TestConnections_testPushBackTextConnection_196e9a486c227dad1cbdeb22ca8fbcb9() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\", \"H\"), con, newLine=FALSE); pushBackLength(con) }"); } @Test - public void TestConnections_testPushBack_29dbbd688316a533cf6a889c7313ebf4() { + public void TestConnections_testPushBackTextConnection_29dbbd688316a533cf6a889c7313ebf4() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\", \"H\"), con, newLine=FALSE); readLines(con, 1) }"); } @Test - public void TestConnections_testPushBack_76de44fe978f208462151f57d1ee3aed() { + public void TestConnections_testPushBackTextConnection_76de44fe978f208462151f57d1ee3aed() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\", \"H\"), con, newLine=FALSE); readLines(con, 2) }"); } @Test - public void TestConnections_testPushBack_e4b327628b569f903a3f239f5a226fb7() { + public void TestConnections_testPushBackTextConnection_e4b327628b569f903a3f239f5a226fb7() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\\nH\"), con); pushBackLength(con) }"); } @Test - public void TestConnections_testPushBack_d4d6eb9b95b2dee91619746ab87657ca() { + public void TestConnections_testPushBackTextConnection_d4d6eb9b95b2dee91619746ab87657ca() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\\nH\"), con); readLines(con, 1) }"); } @Test - public void TestConnections_testPushBack_6f6542b9ba9f30da8906fc36a12e7b6f() { + public void TestConnections_testPushBackTextConnection_6f6542b9ba9f30da8906fc36a12e7b6f() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\\nH\"), con); readLines(con, 2) }"); } @Test - public void TestConnections_testPushBack_3452d401d4b77d0a5da3cec670b75dd6() { + public void TestConnections_testPushBackTextConnection_3452d401d4b77d0a5da3cec670b75dd6() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\\nH\"), con, newLine=FALSE); pushBackLength(con) }"); } @Test - public void TestConnections_testPushBack_ef4bb1fb2afbe783e73c8f6450c67c32() { + public void TestConnections_testPushBackTextConnection_ef4bb1fb2afbe783e73c8f6450c67c32() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\\nH\"), con, newLine=FALSE); readLines(con, 1) }"); } @Test - public void TestConnections_testPushBack_e0fcd304300ae2e3c775fa989d5a667d() { + public void TestConnections_testPushBackTextConnection_e0fcd304300ae2e3c775fa989d5a667d() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\\nH\"), con, newLine=FALSE); readLines(con, 2) }"); } @@ -124,6 +124,11 @@ public class AllTests extends TestBase { assertEval("{ con <- textConnection(c(\"1\", \"2\", \"3\",\"4\")); readLines(con, 2); readLines(con, 2); readLines(con, 2) }"); } + @Test + public void TestConnections_testWriteTextReadConnection_a7a7cde7deb5eff04d965a6084a4b5a3() { + assertEvalError("{ writeChar(\"x\", textConnection(\"abc\")) }"); + } + @Test public void TestPromiseOptimizations_testDeoptimization_78a373f06df48fb5d5c96a3d4827ae94() { assertEval("{ f <- function(x) { function() {x} } ; a <- 1 ; b <- f( a ) ; a <- 10 ; b() }"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java index 2f6789f302..fb793ee6b7 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java @@ -27,6 +27,12 @@ public class FailingTests extends TestBase { } } + @Test + public void TestConnections_testWriteTextReadConnection_a7a7cde7deb5eff04d965a6084a4b5a3() { + assertEvalError("{ writeChar(\"x\", textConnection(\"abc\")) }"); + check("TestConnections_testWriteTextReadConnection_a7a7cde7deb5eff04d965a6084a4b5a3"); + } + @Test public void TestSimpleArithmetic_testIntegerOverflow_e56646664ed3ccebd0b978a474ccae3c() { assertEvalWarning("{ x <- 2147483647L ; x + 1L }"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConnections.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConnections.java index bad94918a6..443c673408 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConnections.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConnections.java @@ -22,11 +22,68 @@ */ package com.oracle.truffle.r.test.library.base; +import java.nio.file.*; + import org.junit.*; +import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.test.*; public class TestConnections extends TestBase { + private static final class TestDir { + private final Path testDirPath; + + TestDir() { + Path rpackages = Paths.get(REnvVars.rHome(), "com.oracle.truffle.r.test"); + testDirPath = TestBase.relativize(rpackages.resolve("library.base.conn")); + if (!testDirPath.toFile().exists()) { + testDirPath.toFile().mkdir(); + } + } + + String[] subDir(String p) { + return new String[]{testDirPath.resolve(p).toString()}; + } + } + + private static TestDir testDir; + + @BeforeClass + public static void setupTestDir() { + testDir = new TestDir(); + } + + @AfterClass + public static void teardownTestDir() { + assertTrue(deleteDir(testDir.testDirPath)); + } + + @Test + public void testFileWriteReadLines() { + assertTemplateEval(TestBase.template("{ writeLines(c(\"line1\", \"line2\"), file(\"%0\")) }", testDir.subDir("wl1"))); + assertTemplateEval(TestBase.template("{ readLines(file(\"%0\"), 2) }", testDir.subDir("wl1"))); + assertTemplateEval(TestBase.template("{ con <- file(\"%0\"); writeLines(c(\"line1\", \"line2\"), con) }", testDir.subDir("wl2"))); + assertTemplateEval(TestBase.template("{ con <- file(\"%0\"); readLines(con, 2) }", testDir.subDir("wl2"))); + } + + @Test + public void testFileWriteReadChar() { + assertTemplateEval(TestBase.template("{ writeChar(\"abc\", file(\"%0\")) }", testDir.subDir("wc1"))); + assertTemplateEval(TestBase.template("{ readChar(file(\"%0\"), 3) }", testDir.subDir("wc1"))); + } + + @Test + public void testFileWriteReadBin() { + assertTemplateEval(TestBase.template("{ writeBin(\"abc\", file(\"%0\", open=\"wb\")) }", testDir.subDir("wb1"))); + assertTemplateEval(TestBase.template("{ readBin(file(\"%0\", \"rb\"), 3) }", testDir.subDir("wb1"))); + } + + @Test + @Ignore + public void testWriteTextReadConnection() { + assertEvalError("{ writeChar(\"x\", textConnection(\"abc\")) }"); + } + @Test public void testTextReadConnection() { assertEval("{ con <- textConnection(c(\"1\", \"2\", \"3\",\"4\")); readLines(con) }"); @@ -36,7 +93,7 @@ public class TestConnections extends TestBase { } @Test - public void testPushBack() { + public void testPushBackTextConnection() { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBackLength(con) }"); assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(\"G\", con); pushBackLength(con) }"); assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(\"G\", con); clearPushBack(con); pushBackLength(con) }"); @@ -57,4 +114,5 @@ public class TestConnections extends TestBase { assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\\nH\"), con, newLine=FALSE); readLines(con, 1) }"); assertEval("{ con<-textConnection(c(\"a\",\"b\",\"c\",\"d\")); pushBack(c(\"G\\nH\"), con, newLine=FALSE); readLines(con, 2) }"); } + } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRPackages.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRPackages.java index d16c38c80d..7586df6964 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRPackages.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRPackages.java @@ -22,9 +22,7 @@ */ package com.oracle.truffle.r.test.rpackages; -import java.io.*; import java.nio.file.*; -import java.nio.file.attribute.*; import java.util.*; import org.junit.*; @@ -94,33 +92,13 @@ public class TestRPackages extends TestBase { private boolean uninstallPackage(String packageName) { Path packageDir = rpackagesLibs.resolve(packageName); try { - Files.walkFileTree(packageDir, DELETE_VISITOR); + deleteDir(packageDir); } catch (Exception e) { return false; } return true; } - private static final class DeleteVisitor extends SimpleFileVisitor<Path> { - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - return del(file); - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - return del(dir); - } - - private static FileVisitResult del(Path p) throws IOException { - Files.delete(p); - return FileVisitResult.CONTINUE; - } - - } - - private static final DeleteVisitor DELETE_VISITOR = new DeleteVisitor(); } private static final PackagePaths packagePaths = new PackagePaths(); -- GitLab