From 594692866b4a5a630348f822fdeb4f6ea333159c Mon Sep 17 00:00:00 2001
From: Mick Jordan <mick.jordan@oracle.com>
Date: Mon, 5 Jun 2017 14:23:45 -0700
Subject: [PATCH] [GR-4344] Convert unit tests to use mx unittest.

---
 ci.hocon                                      |   2 +-
 .../r/ffi/impl/llvm/TruffleLLVM_Call.java     |  36 ++--
 .../r/ffi/impl/nfi/TruffleNFI_Call.java       |  41 +++--
 .../r/ffi/impl/nfi/TruffleNFI_DLL.java        |   2 +-
 com.oracle.truffle.r.native/fficall/Makefile  |   4 +-
 .../fficall/src/truffle_nfi/Random.c          |  46 +++++
 .../fficall/src/truffle_nfi/Rembedded.c       |   1 +
 .../fficall/src/truffle_nfi/Rinternals.c      |  25 +++
 .../fficall/src/truffle_nfi/rffiutils.h       |   2 -
 .../fficall/src/truffle_nfi/variables.c       |  26 +--
 .../builtin/EagerResourceHandlerFactory.java  |   8 +-
 .../r/nodes/builtin/RBuiltinPackage.java      |   7 +-
 .../truffle/r/runtime/FastROptions.java       |   2 +-
 .../r/runtime/LazyResourceHandlerFactory.java |  12 +-
 .../r/runtime/ResourceHandlerFactory.java     |   3 +-
 .../org.junit.runner.notification.RunListener |   1 +
 .../truffle/r/test/ExpectedTestOutput.test    | 128 +++++++------
 .../com/oracle/truffle/r/test/TestBase.java   | 137 ++++++--------
 .../com/oracle/truffle/r/test/TestRBase.java  |  81 ++++-----
 .../r/test/functions/TestS3Dispatch.java      |   2 +-
 .../truffle/r/test/generate/FastRSession.java |  20 ++-
 .../r/test/generate/TestOutputManager.java    |  24 ++-
 .../library/base/TestConditionHandling.java   |   2 +-
 .../r/test/library/base/TestConnections.java  |   2 +-
 .../base/connections}/R/fifo_GnuR_example.R   |   0
 .../connections}/R/rawConnection_readBin.R    |   0
 .../R/rawConnection_readWriteBin.R            |   0
 .../base/connections}/R/rawConnection_seek.R  |   0
 .../connections}/R/rawConnection_writeBin.R   |   0
 .../connections}/R/readLines_GnuR_example.R   |   0
 .../base/connections}/R/textConnection.R      |   0
 .../r/test/library/fastr/TestJavaInterop.java |   3 +-
 .../truffle/r/test/rffi/TestUserRNG.java      |  26 ++-
 documentation/dev/testing.md                  |  24 ++-
 mx.fastr/mx_fastr.py                          | 168 +++++-------------
 mx.fastr/mx_fastr_dists.py                    |  29 +--
 mx.fastr/suite.py                             |  35 ++--
 37 files changed, 435 insertions(+), 464 deletions(-)
 create mode 100644 com.oracle.truffle.r.native/fficall/src/truffle_nfi/Random.c
 create mode 100644 com.oracle.truffle.r.test/src/META-INF/services/org.junit.runner.notification.RunListener
 rename com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/{builtins/connection => library/base/connections}/R/fifo_GnuR_example.R (100%)
 rename com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/{builtins/connection => library/base/connections}/R/rawConnection_readBin.R (100%)
 rename com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/{builtins/connection => library/base/connections}/R/rawConnection_readWriteBin.R (100%)
 rename com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/{builtins/connection => library/base/connections}/R/rawConnection_seek.R (100%)
 rename com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/{builtins/connection => library/base/connections}/R/rawConnection_writeBin.R (100%)
 rename com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/{builtins/connection => library/base/connections}/R/readLines_GnuR_example.R (100%)
 rename com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/{builtins/connection => library/base/connections}/R/textConnection.R (100%)

diff --git a/ci.hocon b/ci.hocon
index 5c04f82cf9..2fa1678214 100644
--- a/ci.hocon
+++ b/ci.hocon
@@ -155,7 +155,7 @@ gateStyle : ${common} {
     ECLIPSE_EXE : "$ECLIPSE/eclipse"
   }
   run : [
-    ${gateCmd} ["Versions,JDKReleaseInfo,Pylint,Canonicalization Check,BuildJavaWithJavac,IDEConfigCheck,CodeFormatCheck,Checkstyle,Copyright check, UnitTests: ExpectedTestOutput file check"]
+    ${gateCmd} ["Versions,JDKReleaseInfo,Pylint,Canonicalization Check,BuildJavaWithJavac,IDEConfigCheck,CodeFormatCheck,Checkstyle,Copyright check,UnitTests: ExpectedTestOutput file check"]
   ]
 }
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java
index 483d43d2c3..e8a5046382 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java
@@ -103,25 +103,27 @@ final class TruffleLLVM_Call implements CallRFFI {
         Node executeNode = Message.createExecute(2).createNode();
         RFFIVariables[] variables = RFFIVariables.initialize();
         boolean isNullSetting = RContext.getRForeignAccessFactory().setIsNull(false);
-        for (int i = 0; i < variables.length; i++) {
-            RFFIVariables var = variables[i];
-            Object value = var.getValue();
-            if (value == null) {
-                continue;
-            }
-            try {
-                if (value instanceof Double) {
-                    ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.DOUBLE.symbolHandle.asTruffleObject(), i, value);
-                } else if (value instanceof Integer) {
-                    ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.INT.symbolHandle.asTruffleObject(), i, value);
-                } else if (value instanceof TruffleObject) {
-                    ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.OBJ.symbolHandle.asTruffleObject(), i, value);
+        try {
+            for (int i = 0; i < variables.length; i++) {
+                RFFIVariables var = variables[i];
+                Object value = var.getValue();
+                if (value == null) {
+                    continue;
+                }
+                try {
+                    if (value instanceof Double) {
+                        ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.DOUBLE.symbolHandle.asTruffleObject(), i, value);
+                    } else if (value instanceof Integer) {
+                        ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.INT.symbolHandle.asTruffleObject(), i, value);
+                    } else if (value instanceof TruffleObject) {
+                        ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.OBJ.symbolHandle.asTruffleObject(), i, value);
+                    }
+                } catch (Throwable t) {
+                    throw RInternalError.shouldNotReachHere(t);
                 }
-            } catch (Throwable t) {
-                throw RInternalError.shouldNotReachHere(t);
-            } finally {
-                RContext.getRForeignAccessFactory().setIsNull(isNullSetting);
             }
+        } finally {
+            RContext.getRForeignAccessFactory().setIsNull(isNullSetting);
         }
     }
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
index a960f40485..2cb1a0c81b 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
@@ -87,26 +87,31 @@ public class TruffleNFI_Call implements CallRFFI {
             }
         }
         Node executeNode = Message.createExecute(2).createNode();
-        RFFIVariables[] variables = RFFIVariables.values();
-        for (int i = 0; i < variables.length; i++) {
-            RFFIVariables var = variables[i];
-            Object value = var.getValue();
-            if (value == null || var.alwaysUpCall) {
-                continue;
-            }
-            try {
-                if (value instanceof Double) {
-                    ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.DOUBLE.initFunction, i, value);
-                } else if (value instanceof Integer) {
-                    ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.INT.initFunction, i, value);
-                } else if (value instanceof String) {
-                    ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.STRING.initFunction, i, value);
-                } else {
-                    ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.OBJ.initFunction, i, value);
+        RFFIVariables[] variables = RFFIVariables.initialize();
+        boolean isNullSetting = RContext.getRForeignAccessFactory().setIsNull(false);
+        try {
+            for (int i = 0; i < variables.length; i++) {
+                RFFIVariables var = variables[i];
+                Object value = var.getValue();
+                if (value == null || var.alwaysUpCall) {
+                    continue;
+                }
+                try {
+                    if (value instanceof Double) {
+                        ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.DOUBLE.initFunction, i, value);
+                    } else if (value instanceof Integer) {
+                        ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.INT.initFunction, i, value);
+                    } else if (value instanceof String) {
+                        ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.STRING.initFunction, i, value);
+                    } else {
+                        ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.OBJ.initFunction, i, value);
+                    }
+                } catch (Throwable t) {
+                    throw RInternalError.shouldNotReachHere(t);
                 }
-            } catch (Throwable t) {
-                throw RInternalError.shouldNotReachHere(t);
             }
+        } finally {
+            RContext.getRForeignAccessFactory().setIsNull(isNullSetting);
         }
     }
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DLL.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DLL.java
index e2cc8820c8..a82d35fecf 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DLL.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DLL.java
@@ -85,7 +85,7 @@ public class TruffleNFI_DLL implements DLLRFFI {
                 TruffleObject result = (TruffleObject) ForeignAccess.sendRead(lookupSymbol, nfiHandle.libHandle, symbol);
                 return new SymbolHandle(result);
             } catch (UnknownIdentifierException e) {
-                return null;
+                throw new UnsatisfiedLinkError();
             } catch (InteropException e) {
                 throw RInternalError.shouldNotReachHere();
             }
diff --git a/com.oracle.truffle.r.native/fficall/Makefile b/com.oracle.truffle.r.native/fficall/Makefile
index 5cf89be52e..99d32f1dca 100644
--- a/com.oracle.truffle.r.native/fficall/Makefile
+++ b/com.oracle.truffle.r.native/fficall/Makefile
@@ -76,12 +76,12 @@ fficall.done: common.done
 	touch fficall.done
 else
 ifeq ($(FASTR_RFFI),nfi)
-fficall.done: common.done
+fficall.done: common.done $(CACCESS_LIB)
 	$(MAKE) -C src/truffle_nfi all
 	touch fficall.done
 else
 ifeq ($(FASTR_RFFI),llvm)
-fficall.done: common.done 
+fficall.done: common.done $(CACCESS_LIB)
 	$(MAKE) -C src/truffle_llvm all
 	touch fficall.done
 else
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Random.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Random.c
new file mode 100644
index 0000000000..434bc3d580
--- /dev/null
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Random.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+#include <rffiutils.h>
+#include "../common/rffi_upcalls.h"
+
+void GetRNGstate() {
+    ((call_GetRNGstate) callbacks[GetRNGstate_x])();
+}
+
+void PutRNGstate() {
+	((call_PutRNGstate) callbacks[PutRNGstate_x])();
+}
+
+double unif_rand() {
+	return ((call_unif_rand) callbacks[unif_rand_x])();
+}
+
+double norm_rand() {
+	unimplemented("norm_rand");
+	return 0;
+}
+
+double exp_rand() {
+	unimplemented("exp_rand");
+	return 0;
+}
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
index c60dc95c6a..d611803139 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
@@ -22,6 +22,7 @@
  */
 #include <Rinterface.h>
 #include <rffiutils.h>
+#include "../common/rffi_upcalls.h"
 
 char *R_HomeDir(void) {
 	return ((call_R_HomeDir) callbacks[R_HomeDir_x])();
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rinternals.c
index 8477aed8f8..3b3f98f0e9 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rinternals.c
@@ -82,6 +82,31 @@ void return_FREE(void *address) {
 //	free(address);
 }
 
+// R_GlobalEnv et al are not a variables in FASTR as they are RContext specific
+SEXP FASTR_R_GlobalEnv() {
+	return ((call_R_GlobalEnv) callbacks[R_GlobalEnv_x])();
+}
+
+SEXP FASTR_R_BaseEnv() {
+	return ((call_R_BaseEnv) callbacks[R_BaseEnv_x])();
+}
+
+SEXP FASTR_R_BaseNamespace() {
+	return ((call_R_BaseNamespace) callbacks[R_BaseNamespace_x])();
+}
+
+SEXP FASTR_R_NamespaceRegistry() {
+	return ((call_R_NamespaceRegistry) callbacks[R_NamespaceRegistry_x])();
+}
+
+CTXT FASTR_GlobalContext() {
+	return ((call_R_GlobalContext) callbacks[R_GlobalContext_x])();
+}
+
+Rboolean FASTR_R_Interactive() {
+	return (int) ((call_R_Interactive) callbacks[R_Interactive_x])();
+}
+
 SEXP CAR(SEXP e) {
 	return checkRef(((call_CAR) callbacks[CAR_x])(e));
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.h b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.h
index 3d2a16ad3b..72765550b5 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.h
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.h
@@ -29,8 +29,6 @@
 #include <Rinternals.h>
 #include <trufflenfi.h>
 
-#include "../common/rffi_upcalls.h"
-
 extern void init_memory();
 extern void init_utils();
 
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/variables.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/variables.c
index e03bc412c4..57518bfd87 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/variables.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/variables.c
@@ -99,31 +99,6 @@ int max_contour_segments = 25000;
 static InputHandler BasicInputHandler = {2, -1, NULL};
 InputHandler *R_InputHandlers = &BasicInputHandler;
 
-// R_GlobalEnv et al are not a variables in FASTR as they are RContext specific
-SEXP FASTR_R_GlobalEnv() {
-	return ((call_R_GlobalEnv) callbacks[R_GlobalEnv_x])();
-}
-
-SEXP FASTR_R_BaseEnv() {
-	return ((call_R_BaseEnv) callbacks[R_BaseEnv_x])();
-}
-
-SEXP FASTR_R_BaseNamespace() {
-	return ((call_R_BaseNamespace) callbacks[R_BaseNamespace_x])();
-}
-
-SEXP FASTR_R_NamespaceRegistry() {
-	return ((call_R_NamespaceRegistry) callbacks[R_NamespaceRegistry_x])();
-}
-
-CTXT FASTR_GlobalContext() {
-	return ((call_R_GlobalContext) callbacks[R_GlobalContext_x])();
-}
-
-Rboolean FASTR_R_Interactive() {
-	return (int) ((call_R_Interactive) callbacks[R_Interactive_x])();
-}
-
 char *FASTR_R_Home() {
 	return (char *) R_Home_static;
 }
@@ -366,5 +341,6 @@ void Call_initvar_obj(int index, void* value) {
     	printf("Call_initvar_obj: unimplemented index %d\n", index);
     	exit(1);
 	}
+//	printf("set index %d, value %p\n", index, value);
 }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/EagerResourceHandlerFactory.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/EagerResourceHandlerFactory.java
index 701bc12f35..22c332591d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/EagerResourceHandlerFactory.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/EagerResourceHandlerFactory.java
@@ -140,16 +140,14 @@ public class EagerResourceHandlerFactory extends ResourceHandlerFactory implemen
     }
 
     @Override
-    public String[] getRFiles(Class<?> accessor, String pkgName) {
-        ArrayList<String> list = new ArrayList<>();
+    public Map<String, String> getRFiles(Class<?> accessor, String pkgName) {
+        Map<String, String> result = new HashMap<>();
         for (Map.Entry<String, FileInfo> entry : files.entrySet()) {
             if (entry.getValue().url.toString().contains(pkgName + "/R")) {
                 String content = new String(entry.getValue().data);
-                list.add(content);
+                result.put(entry.getValue().url.toString(), content);
             }
         }
-        String[] result = new String[list.size()];
-        list.toArray(result);
         return result;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java
index 980ba240c7..060ba197e4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java
@@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.builtin;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Map;
 import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Supplier;
@@ -101,7 +102,7 @@ public abstract class RBuiltinPackage {
         return name;
     }
 
-    private static final ConcurrentHashMap<String, String[]> rFilesCache = new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<String, Map<String, String>> rFilesCache = new ConcurrentHashMap<>();
 
     /**
      * Get a list of R override files for package {@code pkgName}, from the {@code pkgName/R}
@@ -109,12 +110,12 @@ public abstract class RBuiltinPackage {
      */
     public static ArrayList<Source> getRFiles(String pkgName) {
         ArrayList<Source> componentList = new ArrayList<>();
-        String[] rFileContents = rFilesCache.get(pkgName);
+        Map<String, String> rFileContents = rFilesCache.get(pkgName);
         if (rFileContents == null) {
             rFileContents = ResourceHandlerFactory.getHandler().getRFiles(RBuiltinPackage.class, pkgName);
             rFilesCache.put(pkgName, rFileContents);
         }
-        for (String rFileContent : rFileContents) {
+        for (String rFileContent : rFileContents.values()) {
             Source content = RSource.fromTextInternal(rFileContent, RSource.Internal.R_IMPL);
             componentList.add(content);
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
index 10c6e80e13..a3bac44785 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
@@ -142,7 +142,7 @@ public enum FastROptions {
 
     private static FastROptions[] VALUES = values();
 
-    static void setValue(String name, Object value) {
+    public static void setValue(String name, Object value) {
         for (FastROptions option : VALUES) {
             if (name.equals(option.name())) {
                 option.value = value;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyResourceHandlerFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyResourceHandlerFactory.java
index 1befec1946..bd1a92e970 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyResourceHandlerFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyResourceHandlerFactory.java
@@ -32,6 +32,8 @@ import java.nio.file.Paths;
 import java.security.CodeSource;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
@@ -58,9 +60,9 @@ class LazyResourceHandlerFactory extends ResourceHandlerFactory implements Handl
     }
 
     @Override
-    public String[] getRFiles(Class<?> accessor, String pkgName) {
+    public Map<String, String> getRFiles(Class<?> accessor, String pkgName) {
         CodeSource source = accessor.getProtectionDomain().getCodeSource();
-        ArrayList<String> list = new ArrayList<>();
+        Map<String, String> result = new HashMap<>();
         try {
             URL url = source.getLocation();
             Path sourcePath = Paths.get(url.toURI().getPath());
@@ -73,7 +75,7 @@ class LazyResourceHandlerFactory extends ResourceHandlerFactory implements Handl
                         while ((line = r.readLine()) != null) {
                             if (line.endsWith(".r") || line.endsWith(".R")) {
                                 final String rResource = pkgName + "/R/" + line.trim();
-                                list.add(Utils.getResourceAsString(accessor, rResource, true));
+                                result.put(sourcePath.toString(), Utils.getResourceAsString(accessor, rResource, true));
                             }
                         }
                     }
@@ -97,13 +99,11 @@ class LazyResourceHandlerFactory extends ResourceHandlerFactory implements Handl
                             while ((n = is.read(buf, totalRead, buf.length - totalRead)) > 0) {
                                 totalRead += n;
                             }
-                            list.add(new String(buf));
+                            result.put(p.toString(), new String(buf));
                         }
                     }
                 }
             }
-            String[] result = new String[list.size()];
-            list.toArray(result);
             return result;
         } catch (Exception ex) {
             Utils.rSuicide(ex.getMessage());
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ResourceHandlerFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ResourceHandlerFactory.java
index f785535b8e..ec6a3714d3 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ResourceHandlerFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ResourceHandlerFactory.java
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.runtime;
 
 import java.io.InputStream;
 import java.net.URL;
+import java.util.Map;
 
 public abstract class ResourceHandlerFactory {
     /**
@@ -49,7 +50,7 @@ public abstract class ResourceHandlerFactory {
          * Return the contents of all "R" files (ending with ".r" or ".R") relative to
          * {@code accessor} and {@code pkgname/R}. I.e. essentially a directory search.
          */
-        String[] getRFiles(Class<?> accessor, String pkgName);
+        Map<String, String> getRFiles(Class<?> accessor, String pkgName);
     }
 
     static {
diff --git a/com.oracle.truffle.r.test/src/META-INF/services/org.junit.runner.notification.RunListener b/com.oracle.truffle.r.test/src/META-INF/services/org.junit.runner.notification.RunListener
new file mode 100644
index 0000000000..463b9e7047
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/META-INF/services/org.junit.runner.notification.RunListener
@@ -0,0 +1 @@
+com.oracle.truffle.r.test.TestBase$RunListener
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 b1726a12cf..b4576743ac 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
@@ -267,12 +267,12 @@ attr(,"package")
 [1] 999
 
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/NextMethod.R") }
+#{ source("tmptest/S4/NextMethod.R") }
 foo.bar(A, D)
 foo.bar(C, D)
 
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/NextMethod1.R") }
+#{ source("tmptest/S4/NextMethod1.R") }
 foo.bar(A, D)
 foo.bar(B, D)
 foo.bar(A, D)
@@ -282,7 +282,7 @@ foo.bar(A, D)
 foo.bar(B, D)
 
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/activeBinding0.R") }
+#{ source("tmptest/S4/activeBinding0.R") }
 get
 [1] 1
 set
@@ -290,20 +290,20 @@ get
 [1] 2
 
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/activeBinding1.R") }
+#{ source("tmptest/S4/activeBinding1.R") }
 get
 1
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/activeBinding2.R") }
+#{ source("tmptest/S4/activeBinding2.R") }
 
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/activeBinding3.R") }
+#{ source("tmptest/S4/activeBinding3.R") }
 set
 get
 [1] 3
 
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/dispatch.R") }
+#{ source("tmptest/S4/dispatch.R") }
 Creating a generic function from function ‘foo.bar’ in the global environment
 [1] 1
 [1] 2
@@ -312,7 +312,7 @@ Creating a generic function from function ‘foo.bar’ in the global environmen
 [1] "primitive, B, A"
 
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#Output.IgnoreErrorContext#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/refClasses0.R") }
+#{ source("tmptest/S4/refClasses0.R") }
 Error : invalid assignment for reference class field ‘aa’, should be from class “integer” or a subclass (was class “character”)
 code for methods in class “myRefClass3” was not checked for suspicious field assignments (recommended package ‘codetools’ not available?)
 Error : invalid assignment for reference class field ‘dd’, should be from class “numeric” or a subclass (was class “character”)
@@ -321,13 +321,13 @@ code for methods in class “myRefClass5” was not checked for suspicious field
 code for methods in class “myRefClass6” was not checked for suspicious field assignments (recommended package ‘codetools’ not available?)
 
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/refClasses1.R") }
+#{ source("tmptest/S4/refClasses1.R") }
 code for methods in class “A5R5” was not checked for suspicious field assignments (recommended package ‘codetools’ not available?)
 code for methods in class “B5R5” was not checked for suspicious field assignments (recommended package ‘codetools’ not available?)
 [1] "A5R5$foo"
 
 ##com.oracle.truffle.r.test.S4.TestS4.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/S4/R/refClasses2.R") }
+#{ source("tmptest/S4/refClasses2.R") }
 code for methods in class “MatrixClass” was not checked for suspicious field assignments (recommended package ‘codetools’ not available?)
 
 ##com.oracle.truffle.r.test.S4.TestS4.testActiveBindings#
@@ -70094,7 +70094,7 @@ tracemem[0x7faf191a98a8 -> 0x7faf191a98e0]:
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.retracemem#Output.ContainsReferences#
 #x<-1:10; retracemem(x, c("first", "second")) 
-tracemem[first -> 0x1d805c0]:
+tracemem[first -> 0x7fd58944a740]:
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.vectors#Output.ContainsReferences#
 #v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; untracemem(v); y[[2]] <- 84
@@ -77016,7 +77016,7 @@ Error in foo(1, 2, 3) : unused arguments (2, 3)
 [1] TRUE
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/functions/S3/R/argMatching.R") }
+#{ source("tmptest/S3/argMatching.R") }
 dispatch
 g.c args:
 [[1]]
@@ -77101,7 +77101,7 @@ NULL
 
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/functions/S3/R/nextMethod.R") }
+#{ source("tmptest/S3/nextMethod.R") }
 called foo.default with  42
 with '' as class
 called foo.default with  42
@@ -77110,7 +77110,7 @@ called foo.baz with  42
 called foo.bar with  42
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/functions/S3/R/nextMethodAdditionalArgs1.R") }
+#{ source("tmptest/S3/nextMethodAdditionalArgs1.R") }
 called foo.baz with  42
 list()
 called foo.bar with  42
@@ -77119,7 +77119,7 @@ called foo.bar with  42
 
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/functions/S3/R/nextMethodAdditionalArgs2.R") }
+#{ source("tmptest/S3/nextMethodAdditionalArgs2.R") }
 foo.bar with:
 $x
 [1] 42
@@ -77203,7 +77203,7 @@ $named$f
 
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/functions/S3/R/nextMethodAdditionalArgs3.R") }
+#{ source("tmptest/S3/nextMethodAdditionalArgs3.R") }
 foo.baz
 foo.bar with:
 evaluated  b-from-caller
@@ -77254,7 +77254,7 @@ list()
 
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/functions/S3/R/nextMethodAdditionalArgs4.R") }
+#{ source("tmptest/S3/nextMethodAdditionalArgs4.R") }
 foo.baz
 foo.bar with:
 $x
@@ -77273,7 +77273,7 @@ $mynamed
 
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.runRSourceTests#Ignored.Unknown#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/functions/S3/R/nextMethodAdditionalArgsPromises1.R") }
+#{ source("tmptest/S3/nextMethodAdditionalArgsPromises1.R") }
 foo.bar with:
 $x
 [1] 42
@@ -77358,7 +77358,7 @@ $named$f
 
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/functions/S3/R/nextMethodArgsMatching.R") }
+#{ source("tmptest/S3/nextMethodArgsMatching.R") }
 foo.bar with:
 $x
 [1] 42
@@ -77430,7 +77430,7 @@ $named$e
 
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/functions/S3/R/numericTypes.R") }
+#{ source("tmptest/S3/numericTypes.R") }
 integer
 double
 logical
@@ -77641,7 +77641,7 @@ f first 1
 [1] "logical"
 
 ##com.oracle.truffle.r.test.library.base.TestConditionHandling.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers0.R") }
+#{ source("tmptest/condition/withCallingHandlers0.R") }
 {
     fun1("first")
     fun1("second")
@@ -77667,7 +77667,7 @@ NULL
 [1] "exit fun0"
 
 ##com.oracle.truffle.r.test.library.base.TestConditionHandling.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers1.R") }
+#{ source("tmptest/condition/withCallingHandlers1.R") }
 {
     fun1("first")
     fun1("second")
@@ -77806,30 +77806,30 @@ NULL
 <start>[1] 123 456
 
 ##com.oracle.truffle.r.test.library.base.TestConnections.runRSourceTests#Ignored.Unknown#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/builtins/connection/R/fifo_GnuR_example.R") }
+#{ source("tmptest/connections/fifo_GnuR_example.R") }
 [1] "abc"
 
 ##com.oracle.truffle.r.test.library.base.TestConnections.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_readBin.R") }
+#{ source("tmptest/connections/rawConnection_readBin.R") }
 
 ##com.oracle.truffle.r.test.library.base.TestConnections.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_readWriteBin.R") }
+#{ source("tmptest/connections/rawConnection_readWriteBin.R") }
 
 ##com.oracle.truffle.r.test.library.base.TestConnections.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_seek.R") }
+#{ source("tmptest/connections/rawConnection_seek.R") }
 
 ##com.oracle.truffle.r.test.library.base.TestConnections.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_writeBin.R") }
+#{ source("tmptest/connections/rawConnection_writeBin.R") }
 
 ##com.oracle.truffle.r.test.library.base.TestConnections.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/builtins/connection/R/readLines_GnuR_example.R") }
+#{ source("tmptest/connections/readLines_GnuR_example.R") }
 [1] "TITLE extra line" "2 3 5 7"          ""                 "11 13 17"
 [5] "123"              "abc"              "123"              "abc def"
 Warning message:
 In readLines("test1") : incomplete final line found on 'test1'
 
 ##com.oracle.truffle.r.test.library.base.TestConnections.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/builtins/connection/R/textConnection.R") }
+#{ source("tmptest/connections/textConnection.R") }
 Read 4 items
 Read 4 items
 
@@ -130445,19 +130445,19 @@ a b c d e
 [1] 42
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels1.R") }
+#{ source("tmptest/channels/channels1.R") }
 [1]  7 42
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels10.R") }
+#{ source("tmptest/channels/channels10.R") }
 [1]  7 42
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels11.R") }
+#{ source("tmptest/channels/channels11.R") }
 [1]  7 42
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels12.R") }
+#{ source("tmptest/channels/channels12.R") }
 [[1]]
 [1] 7
 
@@ -130466,7 +130466,7 @@ a b c d e
 
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels13.R") }
+#{ source("tmptest/channels/channels13.R") }
 [[1]]
 [1]  7 42
 
@@ -130475,11 +130475,11 @@ a b c d e
 
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels14.R") }
+#{ source("tmptest/channels/channels14.R") }
 [1] 42  7
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels15.R") }
+#{ source("tmptest/channels/channels15.R") }
 [[1]]
 [1] "baz" "bar"
 
@@ -130488,15 +130488,15 @@ a b c d e
 
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels16.R") }
+#{ source("tmptest/channels/channels16.R") }
 [1] 7 7
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels17.R") }
+#{ source("tmptest/channels/channels17.R") }
 [1] 42  7
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels2.R") }
+#{ source("tmptest/channels/channels2.R") }
 [[1]]
 [1] 7
 
@@ -130505,11 +130505,11 @@ a b c d e
 
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels3.R") }
+#{ source("tmptest/channels/channels3.R") }
 [1] 49
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels4.R") }
+#{ source("tmptest/channels/channels4.R") }
 [[1]]
 [1] 7
 
@@ -130518,7 +130518,7 @@ a b c d e
 
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels5.R") }
+#{ source("tmptest/channels/channels5.R") }
 [[1]]
 [1] 7
 
@@ -130527,7 +130527,7 @@ a b c d e
 
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels6.R") }
+#{ source("tmptest/channels/channels6.R") }
 [[1]]
 [1] 7
 
@@ -130536,35 +130536,35 @@ a b c d e
 
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels7.R") }
+#{ source("tmptest/channels/channels7.R") }
 [1] TRUE
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels8.R") }
+#{ source("tmptest/channels/channels8.R") }
 [1] TRUE
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels9.R") }
+#{ source("tmptest/channels/channels9.R") }
 [1]  TRUE FALSE
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/contexts1.R") }
+#{ source("tmptest/channels/contexts1.R") }
 [1]  7 42
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/sharing1.R") }
+#{ source("tmptest/channels/sharing1.R") }
 [1] 42  7
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/sharing2.R") }
+#{ source("tmptest/channels/sharing2.R") }
 [1] "object 'x' not found"
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/sharing3.R") }
+#{ source("tmptest/channels/sharing3.R") }
 [1] 42  7
 
 ##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
-#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/sharing4.R") }
+#{ source("tmptest/channels/sharing4.R") }
 [1] 24 42
 
 ##com.oracle.truffle.r.test.library.fastr.TestInterop.testChannelConnection#
@@ -131137,6 +131137,26 @@ NULL
 NULL
 
 
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testIdentical#
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { FALSE } else { b1 <- .fastr.interop.toByte(1); b2 <- .fastr.interop.toByte(1); identical(b1, b2) }
+[1] FALSE
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testIdentical#
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { FALSE } else { b1 <- .fastr.interop.toByte(1); s1 <- .fastr.interop.toShort(1); identical(b1, s1) }
+[1] FALSE
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testIdentical#
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { FALSE } else { ll <- .fastr.interop.new(.fastr.java.class('java.util.LinkedList')); al <- .fastr.interop.new(.fastr.java.class('java.util.ArrayList')); identical(al, ll) }
+[1] FALSE
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testIdentical#
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { al <- .fastr.interop.new(.fastr.java.class('java.util.ArrayList')); identical(t, t) }
+[1] TRUE
+
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testIdentical#
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { b1 <- .fastr.interop.toByte(1); identical(b1, b1) }
+[1] TRUE
+
 ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testInteroptNew#
 #if (length(grep("FastR", R.Version()$version.string)) != 1) { 'a' } else { tc <- .fastr.java.class('java.lang.Character'); t <- .fastr.interop.new(tc, .fastr.interop.toChar(97)); t }
 [1] "a"
@@ -145980,6 +146000,12 @@ non-integer value 12345678909876543212L qualified with L; using numeric value
 #'\ ' == ' '
 [1] TRUE
 
+##com.oracle.truffle.r.test.rffi.TestUserRNG.testUserRNG#
+#{ dyn.load("tmptest/userrng/liburand.so"); RNGkind("user"); print(RNGkind()); set.seed(4567); runif(10) }
+[1] "user-supplied" "Inversion"
+ [1] 0.45336386 0.38848030 0.94576608 0.11726267 0.21542351 0.08672997
+ [7] 0.35201276 0.16919220 0.93579263 0.26084486
+
 ##com.oracle.truffle.r.test.rng.TestRRNG.testDirectReadingSeed#
 #invisible(runif(1)); length(.Random.seed)
 [1] 626
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 e52b7226f0..d3f0e7489b 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
@@ -40,6 +40,7 @@ import org.junit.runner.Description;
 import org.junit.runner.Result;
 
 import com.oracle.truffle.api.vm.PolyglotEngine;
+import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ResourceHandlerFactory;
 import com.oracle.truffle.r.runtime.Utils;
@@ -139,8 +140,7 @@ public class TestBase {
     }
 
     /**
-     * Instantiated by the mx {@code JUnit} wrapper. The arguments are passed in the constructor and
-     * must be a comma-separated list of strings, i.e.:
+     * Instantiated by the mx {@code JUnit} wrapper. The arguments are passed as system properties
      * <ul>
      * <li>{@code expected=dir}: path to dir containing expected output file to be
      * read/generated/updated</li>
@@ -158,70 +158,52 @@ public class TestBase {
 
         private static File diffsOutputFile;
 
-        private static final String GEN_EXPECTED = "gen-expected";
-        private static final String GEN_EXPECTED_QUIET = "gen-expected-quiet";
-        private static final String CHECK_EXPECTED = "check-expected";
-        private static final String EXPECTED = "expected=";
-        private static final String GEN_FASTR = "gen-fastr=";
-        private static final String GEN_DIFFS = "gen-diff=";
-        private static final String KEEP_TRAILING_WHITESPACE = "keep-trailing-whitespace";
-        private static final String TRACE_TESTS = "trace-tests";
-        private static final String TEST_METHODS = "test-methods=";
-        /**
-         * The dir where 'mx' puts the output from building this project.
-         */
-        private static final String TEST_PROJECT_OUTPUT_DIR = "test-project-output-dir=";
+        private static final String PROP_BASE = "fastr.test.";
 
-        private final String arg;
+        private enum Props {
+            GEN_EXPECTED("gen.expected"),
+            GEN_EXPECTED_QUIET("gen.expected.quiet"),
+            CHECK_EXPECTED("check.expected"),
+            TRACE_TESTS("trace.tests"),
+            KEEP_TRAILING_WHITESPACE("keep.trailing.whitespace");
 
-        /**
-         * Constructor with customization arguments.
-         */
-        public RunListener(String arg) {
-            this.arg = arg;
+            private final String propSuffix;
+
+            Props(String propSuffix) {
+                this.propSuffix = propSuffix;
+            }
+        }
+
+        private static String getProperty(String baseName) {
+            String propName = PROP_BASE + baseName;
+            String val = System.getProperty(propName);
+            return val;
+        }
+
+        public static boolean getBooleanProperty(String baseName) {
+            String val = getProperty(baseName);
+            return val != null && (val.length() == 0 || val.equals("true"));
         }
 
         @Override
         public void testRunStarted(Description description) {
             try {
-                File expectedOutputFile = null;
                 File fastROutputFile = null;
                 boolean checkExpected = false;
-                boolean genExpected = false;
-                boolean genExpectedQuiet = false;
-                if (arg != null) {
-                    String[] args = arg.split(",");
-                    for (String directive : args) {
-                        if (directive.startsWith(EXPECTED)) {
-                            expectedOutputFile = new File(new File(directive.replace(EXPECTED, "")), TestOutputManager.TEST_EXPECTED_OUTPUT_FILE);
-                        } else if (directive.startsWith(GEN_FASTR)) {
-                            fastROutputFile = new File(new File(directive.replace(GEN_FASTR, "")), TestOutputManager.TEST_FASTR_OUTPUT_FILE);
-                        } else if (directive.startsWith(GEN_DIFFS)) {
-                            diffsOutputFile = new File(new File(directive.replace(GEN_DIFFS, "")), TestOutputManager.TEST_DIFF_OUTPUT_FILE);
-                        } else if (directive.equals(GEN_EXPECTED)) {
-                            genExpected = true;
-                        } else if (directive.equals(GEN_EXPECTED_QUIET)) {
-                            genExpectedQuiet = true;
-                        } else if (directive.equals(CHECK_EXPECTED)) {
-                            checkExpected = true;
-                        } else if (directive.equals(KEEP_TRAILING_WHITESPACE)) {
-                            keepTrailingWhiteSpace = true;
-                        } else if (directive.equals(TRACE_TESTS)) {
-                            traceTests = true;
-                        } else if (directive.startsWith(TEST_PROJECT_OUTPUT_DIR)) {
-                            testProjectOutputDir = Paths.get(directive.replace(TEST_PROJECT_OUTPUT_DIR, ""));
-                        } else if (directive.equals(TEST_METHODS)) {
-                            testMethodsPattern = directive.replace(TEST_METHODS, "");
-                        } else {
-                            throw new RuntimeException("RunListener arg: " + arg + " invalid");
-                        }
-                    }
-                }
-                if (genExpected) {
-                    System.setProperty("GenerateExpectedOutput", "true");
+                String genExpected = getProperty(Props.GEN_EXPECTED.propSuffix);
+                boolean genExpectedQuiet = getBooleanProperty(Props.GEN_EXPECTED_QUIET.propSuffix);
+                checkExpected = getBooleanProperty(Props.CHECK_EXPECTED.propSuffix);
+                if (genExpected != null) {
+                    File expectedOutputFile = new File(new File(genExpected), TestOutputManager.TEST_EXPECTED_OUTPUT_FILE);
+                    expectedOutputManager = new ExpectedTestOutputManager(expectedOutputFile, true, checkExpected, genExpectedQuiet);
+                } else {
+                    // read from jar
+                    URL expectedTestOutputURL = ResourceHandlerFactory.getHandler().getResource(TestBase.class, TestOutputManager.TEST_EXPECTED_OUTPUT_FILE);
+                    expectedOutputManager = new ExpectedTestOutputManager(expectedTestOutputURL, false, checkExpected, genExpectedQuiet);
+                    System.console();
                 }
-                expectedOutputManager = new ExpectedTestOutputManager(expectedOutputFile, genExpected, checkExpected, genExpectedQuiet);
                 fastROutputManager = new FastRTestOutputManager(fastROutputFile);
+                traceTests = getBooleanProperty(Props.TRACE_TESTS.propSuffix);
                 addOutputHook();
             } catch (Throwable ex) {
                 throw new AssertionError("R initialization failure", ex);
@@ -231,6 +213,7 @@ public class TestBase {
         @Override
         public void testRunFinished(Result result) {
             try {
+                deleteDir(Paths.get(TEST_OUTPUT));
                 if (expectedOutputManager.generate) {
                     boolean updated = expectedOutputManager.writeTestOutputFile();
                     if (updated) {
@@ -343,7 +326,20 @@ public class TestBase {
             }
         }
 
-        void createRSession() {
+        protected ExpectedTestOutputManager(URL urlOutput, boolean generate, boolean checkOnly, boolean genExpectedQuiet) throws IOException {
+            super(urlOutput);
+            this.checkOnly = checkOnly;
+            this.generate = generate;
+            if (genExpectedQuiet) {
+                localDiagnosticHandler.setQuiet();
+            }
+            oldExpectedOutputFileContent = readTestOutputFile();
+            if (generate) {
+                createRSession();
+            }
+        }
+
+        private void createRSession() {
             if (!haveRSession) {
                 setRSession(new GnuROneShotRSession());
                 haveRSession = true;
@@ -361,6 +357,9 @@ public class TestBase {
         FastRTestOutputManager(File outputFile) {
             super(outputFile);
             setRSessionName("FastR");
+            // no point in printing errors to file when running tests (that contain errors on
+            // purpose)
+            FastROptions.setValue("PrintErrorStacktracesToFile", false);
             fastRSession = FastRSession.create();
         }
     }
@@ -429,8 +428,6 @@ public class TestBase {
      */
     private static boolean traceTests;
 
-    private static Path testProjectOutputDir;
-
     protected static final String ERROR = "Error";
     protected static final String WARNING = "Warning message";
 
@@ -517,11 +514,7 @@ public class TestBase {
         return cwd;
     }
 
-    public static void setTestProjectOutputDir(String path) {
-        testProjectOutputDir = Paths.get(path);
-    }
-
-    private static final String TEST_OUTPUT = "tmptest";
+    protected static final String TEST_OUTPUT = "tmptest";
 
     /**
      * Return a path that is relative to the 'cwd/testoutput' when running tests.
@@ -544,24 +537,6 @@ public class TestBase {
         return relativize(dir);
     }
 
-    private static final String TEST_PROJECT = "com.oracle.truffle.r.test";
-    private static final String TEST_NATIVE_PROJECT = "com.oracle.truffle.r.test.native";
-
-    /**
-     * Returns a path to {@code baseName}, assumed to be nested in {@link #testProjectOutputDir}.
-     * The path is return relativized to the cwd.
-     */
-    public static Path getProjectFile(Path baseName) {
-        Path baseNamePath = Paths.get(TEST_PROJECT.replace('.', '/'), baseName.toString());
-        Path result = relativize(testProjectOutputDir.resolve(baseNamePath));
-        return result;
-    }
-
-    public static Path getNativeProjectFile(Path baseName) {
-        Path path = Paths.get(TEST_NATIVE_PROJECT, baseName.toString());
-        return path;
-    }
-
     private static void microTestFailed() {
         if (!ProcessFailedTests || ShowFailedTestsResults) {
             System.err.printf("%nMicro-test failure: %s%n", getTestContext());
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestRBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestRBase.java
index 6d4317791a..960eff3d5d 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestRBase.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestRBase.java
@@ -22,17 +22,17 @@
  */
 package com.oracle.truffle.r.test;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Map;
+import java.util.Map.Entry;
 
-import org.junit.Assert;
 import org.junit.Test;
 
+import com.oracle.truffle.r.runtime.ResourceHandlerFactory;
+
 /**
  * Base class for all Java test suites (in the sense of JUnit Java files) that want to run R tests
  * stored in the file system as R sources. It is expected that R test source files will be stored in
@@ -60,54 +60,45 @@ public class TestRBase extends TestBase {
         if (testDirName == null) {
             return;
         }
-        Path testDirPath = TestBase.getProjectFile(Paths.get(testDirName, "R"));
-        if (!Files.exists(testDirPath) || !Files.isDirectory(testDirPath)) {
-            return;
-        }
-        File testDir = testDirPath.toFile();
-        File[] files = testDir.listFiles((dir, name) -> name.endsWith(".R"));
-        if (files == null) {
-            return;
-        }
-        for (int i = 0; i < files.length; i++) {
-            explicitTestContext = testDirName + "/R/" + files[i].getName();
-            try {
-                BufferedReader bf = new BufferedReader(new FileReader(files[i]));
-                TestTrait testTrait = null;
-                String l = bf.readLine();
-                if (l != null) {
-                    l = l.trim();
-                    if (l.startsWith("#")) {
-                        // check the first line for configuration options
-                        if (l.contains("IgnoreErrorContext")) {
-                            testTrait = Output.IgnoreErrorContext;
-                        } else if (l.contains("IgnoreWarningContext")) {
-                            testTrait = Output.IgnoreWarningContext;
-                        } else if (l.contains("Ignored")) {
-                            for (Ignored ignoredType : Ignored.values()) {
-                                if (l.contains("Ignored." + ignoredType.name())) {
-                                    testTrait = ignoredType;
-                                    break;
-                                }
-                            }
-                            if (testTrait == null) {
-                                testTrait = Ignored.Unknown; // Retain old way for compatibility
-                            }
+        Map<String, String> rFiles = ResourceHandlerFactory.getHandler().getRFiles(this.getClass(), testDirName);
+        for (Entry<String, String> entry : rFiles.entrySet()) {
+            String entryName = entry.getKey();
+            String entryValue = entry.getValue();
+            explicitTestContext = entryName;
+            String[] lines = entryValue.split("\n");
+            String l = lines[0].trim();
+            TestTrait testTrait = null;
+            if (l.startsWith("#")) {
+                // check the first line for configuration options
+                if (l.contains("IgnoreErrorContext")) {
+                    testTrait = Output.IgnoreErrorContext;
+                } else if (l.contains("IgnoreWarningContext")) {
+                    testTrait = Output.IgnoreWarningContext;
+                } else if (l.contains("Ignored")) {
+                    for (Ignored ignoredType : Ignored.values()) {
+                        if (l.contains("Ignored." + ignoredType.name())) {
+                            testTrait = ignoredType;
+                            break;
                         }
                     }
+                    if (testTrait == null) {
+                        testTrait = Ignored.Unknown; // Retain old way for compatibility
+                    }
                 }
-                bf.close();
-                String testFilePath = testDirPath.resolve(files[i].getName()).toString();
+            }
+            try {
+                Path dir = TestBase.createTestDir(getTestDir());
+                Path p = dir.resolve(Paths.get(entryName).getFileName());
+                Files.write(p, entryValue.getBytes());
                 if (testTrait == null) {
-                    assertEval(TestBase.template("{ source(\"%0\") }", new String[]{testFilePath}));
+                    assertEval(TestBase.template("{ source(\"%0\") }", new String[]{p.toString()}));
                 } else {
-                    assertEval(testTrait, TestBase.template("{ source(\"%0\") }", new String[]{testFilePath}));
+                    assertEval(testTrait, TestBase.template("{ source(\"%0\") }", new String[]{p.toString()}));
                 }
-            } catch (IOException x) {
-                Assert.fail("error reading: " + files[i].getPath() + ": " + x);
-            } finally {
-                explicitTestContext = null;
+            } catch (IOException ex) {
+                assert false;
             }
+            explicitTestContext = null;
         }
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
index 2c8c4652b6..c59422424d 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
@@ -144,6 +144,6 @@ public class TestS3Dispatch extends TestRBase {
 
     @Override
     public String getTestDir() {
-        return "functions/S3";
+        return "S3";
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
index 6f213a4cef..507752aaef 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
@@ -53,8 +53,7 @@ import com.oracle.truffle.r.test.TestBase;
 
 public final class FastRSession implements RSession {
 
-    private static final String TEST_TIMEOUT_PROPERTY = "FastRTestTimeout";
-    private static final String DISABLE_TIMEOUT_PROPERTY = "DisableTestTimeout"; // legacy
+    private static final String TEST_TIMEOUT_PROPERTY = "fastr.test.timeout";
     private static int timeoutValue = 10000;
     /**
      * The long timeout is used for package installation and currently needs to be 5 mins for the
@@ -163,13 +162,16 @@ public final class FastRSession implements RSession {
     }
 
     private FastRSession() {
-        if (System.getProperty(DISABLE_TIMEOUT_PROPERTY) != null) {
-            timeoutValue = Integer.MAX_VALUE;
-            longTimeoutValue = Integer.MAX_VALUE;
-        } else if (System.getProperty(TEST_TIMEOUT_PROPERTY) != null) {
-            int timeoutGiven = Integer.parseInt(System.getProperty(TEST_TIMEOUT_PROPERTY));
-            timeoutValue = timeoutGiven * 1000;
-            // no need to scale longTimeoutValue
+        String timeOutProp = System.getProperty(TEST_TIMEOUT_PROPERTY);
+        if (timeOutProp != null) {
+            if (timeOutProp.length() == 0) {
+                timeoutValue = Integer.MAX_VALUE;
+                longTimeoutValue = Integer.MAX_VALUE;
+            } else {
+                int timeoutGiven = Integer.parseInt(timeOutProp);
+                timeoutValue = timeoutGiven * 1000;
+                // no need to scale longTimeoutValue
+            }
         }
         consoleHandler = new TestConsoleHandler();
         try {
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/TestOutputManager.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/TestOutputManager.java
index 11ea456977..dc89e28859 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/TestOutputManager.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/TestOutputManager.java
@@ -25,12 +25,15 @@ package com.oracle.truffle.r.test.generate;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.StringWriter;
+import java.net.URL;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -141,8 +144,16 @@ public class TestOutputManager {
      */
     public final File outputFile;
 
+    private final URL urlOutput;
+
     public TestOutputManager(File outputFile) {
         this.outputFile = outputFile;
+        this.urlOutput = null;
+    }
+
+    public TestOutputManager(URL urlOutput) {
+        this.urlOutput = urlOutput;
+        this.outputFile = null;
     }
 
     protected void setRSession(RSession session) {
@@ -214,11 +225,18 @@ public class TestOutputManager {
     }
 
     public String readTestOutputFile() throws IOException {
-        if (!outputFile.exists()) {
+        if (outputFile != null && !outputFile.exists()) {
             return null;
         }
+        InputStream is;
+        if (outputFile != null) {
+            is = new FileInputStream(outputFile);
+        } else {
+            assert urlOutput != null;
+            is = urlOutput.openStream();
+        }
         StringBuilder content = new StringBuilder();
-        try (SaveBufferedReader in = new SaveBufferedReader(new FileReader(outputFile), content)) {
+        try (SaveBufferedReader in = new SaveBufferedReader(new InputStreamReader(is), content)) {
             // line format for element name: ##elementName
             // line format for input lines: #input
             // output lines do not start with ##
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConditionHandling.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConditionHandling.java
index bafe789b1f..adf3d9e2f8 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConditionHandling.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConditionHandling.java
@@ -30,7 +30,7 @@ public class TestConditionHandling extends TestRBase {
 
     @Override
     public String getTestDir() {
-        return "library/base/condition";
+        return "condition";
     }
 
     @Test
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 f1aeb3cf9e..39ee482d5f 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
@@ -57,7 +57,7 @@ public class TestConnections extends TestRBase {
 
     @Override
     protected String getTestDir() {
-        return "builtins/connection";
+        return "connections";
     }
 
     @BeforeClass
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/fifo_GnuR_example.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/fifo_GnuR_example.R
similarity index 100%
rename from com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/fifo_GnuR_example.R
rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/fifo_GnuR_example.R
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_readBin.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/rawConnection_readBin.R
similarity index 100%
rename from com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_readBin.R
rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/rawConnection_readBin.R
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_readWriteBin.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/rawConnection_readWriteBin.R
similarity index 100%
rename from com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_readWriteBin.R
rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/rawConnection_readWriteBin.R
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_seek.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/rawConnection_seek.R
similarity index 100%
rename from com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_seek.R
rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/rawConnection_seek.R
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_writeBin.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/rawConnection_writeBin.R
similarity index 100%
rename from com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/rawConnection_writeBin.R
rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/rawConnection_writeBin.R
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/readLines_GnuR_example.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/readLines_GnuR_example.R
similarity index 100%
rename from com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/readLines_GnuR_example.R
rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/readLines_GnuR_example.R
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/textConnection.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/textConnection.R
similarity index 100%
rename from com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/connection/R/textConnection.R
rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/connections/R/textConnection.R
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java
index 557545ba6e..8e829e3893 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java
@@ -252,7 +252,7 @@ public class TestJavaInterop extends TestBase {
     }
 
     @Test
-    public void testMethods() throws IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException {
+    public void testMethods() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
         TestClass t = new TestClass();
         Method[] methods = t.getClass().getDeclaredMethods();
         for (Method m : methods) {
@@ -426,6 +426,7 @@ public class TestJavaInterop extends TestBase {
         assertEvalFastR("to <- .fastr.interop.new(.fastr.java.class('" + TEST_CLASS + "')); attr(to, which = 'a')", "cat('Error in attr(to, which = \"a\") : external object cannot be attributed\n')");
     }
 
+    @Test
     public void testIdentical() {
         assertEvalFastR("b1 <- .fastr.interop.toByte(1); identical(b1, b1)", "TRUE");
         assertEvalFastR("b1 <- .fastr.interop.toByte(1); b2 <- .fastr.interop.toByte(1); identical(b1, b2)", "FALSE");
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestUserRNG.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestUserRNG.java
index 087722ae5f..6475e412c8 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestUserRNG.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestUserRNG.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,9 +22,8 @@
  */
 package com.oracle.truffle.r.test.rffi;
 
+import java.io.IOException;
 import java.nio.file.Path;
-import java.nio.file.Paths;
-
 import org.junit.Test;
 
 import com.oracle.truffle.r.runtime.ffi.UserRngRFFI;
@@ -32,13 +31,26 @@ import com.oracle.truffle.r.test.TestBase;
 
 /**
  * Test for a user-defined random number generator. Implicitly tests {@code dyn.load} as well as the
- * {@link UserRngRFFI} interface. We take care to use relative paths so the expected output file is
- * portable.
+ * {@link UserRngRFFI} interface. The actual library is stored in a tar file, the location of which
+ * we can get from the {@code fastr.test.native} system property.
  */
 public class TestUserRNG extends TestBase {
     @Test
     public void testUserRNG() {
-        Path libPath = TestBase.getNativeProjectFile(Paths.get("urand", "lib", "liburand.so"));
-        assertEval(TestBase.template("{ dyn.load(\"%0\"); RNGkind(\"user\"); print(RNGkind()); set.seed(4567); runif(10) }", new String[]{libPath.toString()}));
+        Path dir = createTestDir("userrng");
+        String tarFile = System.getProperty("fastr.test.native");
+        assert tarFile != null;
+        String[] tarC = new String[]{"tar", "xf", tarFile};
+        ProcessBuilder pb = new ProcessBuilder(tarC);
+        pb.directory(dir.toFile());
+        try {
+            Process p = pb.start();
+            int rc = p.waitFor();
+            assert rc == 0;
+            assertEval(TestBase.template("{ dyn.load(\"%0\"); RNGkind(\"user\"); print(RNGkind()); set.seed(4567); runif(10) }", new String[]{dir.toString() + "/liburand.so"}));
+        } catch (IOException ex) {
+            assert false;
+        } catch (InterruptedException ex) {
+        }
     }
 }
diff --git a/documentation/dev/testing.md b/documentation/dev/testing.md
index a5a2718be1..bfcd1a4f90 100644
--- a/documentation/dev/testing.md
+++ b/documentation/dev/testing.md
@@ -7,18 +7,30 @@ The unit testing works by executing the R test and the comparing the output with
 
 ## Unit Tests
 
-The unit tests reside mainly in the `com.oracle.truffle.r.test` project, with a smaller number in the and `com.oracle.truffle.r.nodes.test` project. To execute the unit tests use the `mx junit` command. The standard set of unit tests is available via the `mx junitdefault` command and the following additional variants are available:
+The unit tests reside mainly in the `com.oracle.truffle.r.test` project, with a smaller number in the `com.oracle.truffle.r.nodes.test` project. The execution of the tests uses the `unittest` command that is built into `mx` and
+used by all the Truffle languages. See `mx unittest --help` for a complete description of the options. Certain system properties are used to control the test environment, a;; of which begin with `fastr.test`.
 
-1. `mx junitsimple`: everything except the package tests and the `com.oracle.truffle.r.nodes.test`
-2. `mx junit --tests list`: `list` is a comma-separated list of test patterns, where a pattern is a package or class. For example to just run the "builtin" tests run `mx junit --tests com.oracle.truffle.r.test.builtins`.
+1. `fastr.test.trace.tests`: this causes the specific test method being executed to be output to the standard output. A sometimes useful debugging tool.
+2. `fastr.test.check.expected`: this can be used in combination with `fastr.test.generate` to checked whether `ExpectedTestOutput.test` is in sync with the current set of tests.
+3. `fastr.test.generate`: Used internally by `mx rtestgen`, see below.
+4. `fastr.test.generate.quiet`; Used internally by `mx rtestgen`, see below.
 
-As with most FastR `mx` commands, additional parameters can be passed to the underlying FastR process using the `--J` option. For example to debug a unit test under an IDE, it is important to disable the internal timeout mechanism that detects looping tests, vis:
+For convenience and backwards compatibility FastR provides some wrapper commands that invoke `unittest` with specific arguments.
+In particular the standard set of unit tests is available via the `mx junitgate` command and the following additional variants are available:
 
-    mx -d junit --tests sometestclass --J @-DDisableTestTimeout
+1. `mx rutsimple`: everything except the tests in `com.oracle.truffle.r.nodes.test`
+2. `mx rutgate`: all the tests that run in the gate
+
+
+For example to debug a unit test under an IDE, it is important to disable the internal timeout mechanism that detects looping tests, vis:
+
+    mx -d unittest -Dfastr.test.timeout sometestclass
+
+Note that no value for `fastr.test.timeout` is treated as in infinite timeout. Any other value is expected to be an integer value, interpreted as seconds.
 
 ### Regenerating ExpectedTestOutput.test
 
-After adding, removing or altering units tests (including the `TestTrait` argument), it is necessary to regenerate the GNU R output, vis:
+After adding, removing or altering units tests (including the `TestTrait` argument), it is necessary to regenerate the `ExpectedTestOutput.test` file, vis:
 
     mx rtestgen
 
diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py
index a5ccfd0e27..e60ab60464 100644
--- a/mx.fastr/mx_fastr.py
+++ b/mx.fastr/mx_fastr.py
@@ -28,11 +28,11 @@ import mx_gate
 import mx_fastr_pkgs
 import mx_fastr_compile
 import mx_fastr_dists
-import mx_fastr_junit
-from mx_fastr_dists import FastRTestNativeProject, FastRReleaseProject, FastRNativeRecommendedProject #pylint: disable=unused-import
+from mx_fastr_dists import FastRReleaseProject, FastRNativeRecommendedProject #pylint: disable=unused-import
 import mx_copylib
 import mx_fastr_mkgramrd
 import mx_fastr_edinclude
+import mx_unittest
 
 import os
 
@@ -266,23 +266,19 @@ def _fastr_gate_runner(args, tasks):
     # check that the expected test output file is up to date
     with mx_gate.Task('UnitTests: ExpectedTestOutput file check', tasks) as t:
         if t:
-            if junit(['--tests', _gate_unit_tests(), '--check-expected-output']) != 0:
-                t.abort('unit tests expected output check failed')
+            mx_unittest.unittest(['-Dfastr.test.check.expected', '-Dfastr.test.generate'] + _gate_unit_tests())
 
     with mx_gate.Task('UnitTests: no specials', tasks) as t:
         if t:
-            if junit(['--J', '@-DR:-UseSpecials', '--tests', _gate_noapps_unit_tests()]) != 0:
-                t.abort('unit tests failed')
+            mx_unittest.unittest(['-DR:-UseSpecials'] + _gate_noapps_unit_tests())
 
     with mx_gate.Task('UnitTests: with specials', tasks) as t:
         if t:
-            if junit(['--tests', _gate_noapps_unit_tests()]) != 0:
-                t.abort('unit tests failed')
+            mx_unittest.unittest(_gate_noapps_unit_tests())
 
     with mx_gate.Task('UnitTests: apps', tasks) as t:
         if t:
-            if junit(['--tests', _apps_unit_tests()]) != 0:
-                t.abort('unit tests failed')
+            mx_unittest.unittest(_apps_unit_tests())
 
 mx_gate.add_gate_runner(_fastr_suite, _fastr_gate_runner)
 
@@ -294,103 +290,24 @@ def rgate(args):
     '''
     mx_gate.gate(args)
 
-def _test_srcdir():
-    tp = 'com.oracle.truffle.r.test'
-    return join(mx.project(tp).dir, 'src', tp.replace('.', sep))
-
-def _junit_r_harness(args, vmArgs, jdk, junitArgs):
-    # always pass the directory where the expected output file should reside
-    runlistener_arg = 'expected=' + _test_srcdir()
-    # there should not be any unparsed arguments at this stage
-    if args.remainder:
-        mx.abort('unexpected arguments: ' + str(args.remainder).strip('[]') + '; did you forget --tests')
-
-    def add_arg_separator():
-        # can't update in Python 2.7
-        arg = runlistener_arg
-        if len(arg) > 0:
-            arg += ','
-        return arg
-
-    if args.gen_fastr_output:
-        runlistener_arg = add_arg_separator()
-        runlistener_arg += 'gen-fastr=' + args.gen_fastr_output
-
-    if args.check_expected_output:
-        args.gen_expected_output = True
-        runlistener_arg = add_arg_separator()
-        runlistener_arg += 'check-expected'
-
-    if args.gen_expected_output:
-        runlistener_arg = add_arg_separator()
-        runlistener_arg += 'gen-expected'
-        if args.keep_trailing_whitespace:
-            runlistener_arg = add_arg_separator()
-            runlistener_arg += 'keep-trailing-whitespace'
-        if args.gen_expected_quiet:
-            runlistener_arg = add_arg_separator()
-            runlistener_arg += 'gen-expected-quiet'
-
-    if args.gen_diff_output:
-        runlistener_arg = add_arg_separator()
-        runlistener_arg += 'gen-diff=' + args.gen_diff_output
-
-    if args.trace_tests:
-        runlistener_arg = add_arg_separator()
-        runlistener_arg += 'trace-tests'
-
-#    if args.test_methods:
-#        runlistener_arg = add_arg_separator()
-#        runlistener_arg = 'test-methods=' + args.test_methods
-
-    runlistener_arg = add_arg_separator()
-    runlistener_arg += 'test-project-output-dir=' + mx.project('com.oracle.truffle.r.test').output_dir()
-
-    # use a custom junit.RunListener
-    runlistener = 'com.oracle.truffle.r.test.TestBase$RunListener'
-    if len(runlistener_arg) > 0:
-        runlistener += ':' + runlistener_arg
-
-    junitArgs += ['--runlistener', runlistener]
-
-    # on some systems a large Java stack seems necessary
-    vmArgs += ['-Xss12m']
-    # no point in printing errors to file when running tests (that contain errors on purpose)
-    vmArgs += ['-DR:-PrintErrorStacktracesToFile']
-    vmArgs += _sulong_options()
-
-    setREnvironment()
-
-    return mx.run_java(vmArgs + junitArgs, nonZeroIsFatal=False, jdk=jdk)
-
-def junit(args):
-    '''run R Junit tests'''
-    parser = ArgumentParser(prog='r junit')
-    parser.add_argument('--gen-expected-output', action='store_true', help='generate/update expected test output file')
-    parser.add_argument('--gen-expected-quiet', action='store_true', help='suppress output on new tests being added')
-    parser.add_argument('--keep-trailing-whitespace', action='store_true', help='keep trailing whitespace in expected test output file')
-    parser.add_argument('--check-expected-output', action='store_true', help='check but do not update expected test output file')
-    parser.add_argument('--gen-fastr-output', action='store', metavar='<path>', help='generate FastR test output file in given directory (e.g. ".")')
-    parser.add_argument('--gen-diff-output', action='store', metavar='<path>', help='generate difference test output file in given directory (e.g. ".")')
-    parser.add_argument('--trace-tests', action='store_true', help='trace the actual @Test methods as they are executed')
-    # parser.add_argument('--test-methods', action='store', help='pattern to match test methods in test classes')
-
-    if os.environ.has_key('R_PROFILE_USER'):
-        mx.abort('unset R_PROFILE_USER before running unit tests')
-    _unset_conflicting_envs()
-    return mx_fastr_junit.junit(args, _junit_r_harness, parser=parser, jdk_default=get_default_jdk())
+def _unittest_config_participant(config):
+    vmArgs, mainClass, mainClassArgs = config
+    # need to pass location of FASTR_UNIT_TESTS_NATIVE
+    d = mx.distribution('FASTR_UNIT_TESTS_NATIVE')
+    vmArgs = ['-Dfastr.test.native=' + d.path] + vmArgs
+    return (vmArgs, mainClass, mainClassArgs)
 
-def junit_simple(args):
-    return mx.command_function('junit')(['--tests', _simple_unit_tests()] + args)
+def ut_simple(args):
+    return mx_unittest.unittest(args + _simple_unit_tests())
 
-def junit_noapps(args):
-    return mx.command_function('junit')(['--tests', _gate_noapps_unit_tests()] + args)
+def ut_noapps(args):
+    return mx_unittest.unittest(args + _gate_noapps_unit_tests())
 
-def junit_default(args):
-    return mx.command_function('junit')(['--tests', _all_unit_tests()] + args)
+def ut_default(args):
+    return mx_unittest.unittest(args + _all_unit_tests())
 
-def junit_gate(args):
-    return mx.command_function('junit')(['--tests', _gate_unit_tests()] + args)
+def ut_gate(args):
+    return mx_unittest.unittest(args + _gate_unit_tests())
 
 def _test_package():
     return 'com.oracle.truffle.r.test'
@@ -399,38 +316,39 @@ def _test_subpackage(name):
     return '.'.join((_test_package(), name))
 
 def _simple_generated_unit_tests():
-    return ','.join(map(_test_subpackage, ['engine.shell', 'library.base', 'library.fastrGrid', 'library.methods', 'library.stats', 'library.utils', 'library.fastr', 'builtins', 'functions', 'parser', 'rng', 'runtime.data', 'S4']))
+    return map(_test_subpackage, ['engine.shell', 'library.base', 'library.fastrGrid', 'library.methods', 'library.stats', 'library.utils', 'library.fastr', 'builtins', 'functions', 'parser', 'rffi', 'rng', 'runtime.data', 'S4'])
 
 def _simple_unit_tests():
-    return ','.join([_simple_generated_unit_tests(), _test_subpackage('tck')])
+    return _simple_generated_unit_tests() + [_test_subpackage('tck')]
 
 def _nodes_unit_tests():
-    return 'com.oracle.truffle.r.nodes.test'
+    return ['com.oracle.truffle.r.nodes.test']
 
 def _apps_unit_tests():
-    return _test_subpackage('apps')
+    return [_test_subpackage('apps')]
 
 def _gate_noapps_unit_tests():
-    return ','.join([_simple_unit_tests(), _nodes_unit_tests()])
+    return _simple_unit_tests() + _nodes_unit_tests()
 
 def _gate_unit_tests():
-    return ','.join([_gate_noapps_unit_tests(), _apps_unit_tests()])
+    return _gate_noapps_unit_tests() +  _apps_unit_tests()
 
 def _all_unit_tests():
     return _gate_unit_tests()
 
 def _all_generated_unit_tests():
-    return ','.join([_simple_generated_unit_tests()])
+    return _simple_generated_unit_tests()
 
 def testgen(args):
-    '''generate the expected output for unit tests, and All/Failing test classes'''
-    parser = ArgumentParser(prog='r testgen')
-    parser.add_argument('--tests', action='store', default=_all_generated_unit_tests(), help='pattern to match test classes')
-    args = parser.parse_args(args)
+    '''generate the expected output for unit tests'''
     # check we are in the home directory
     if os.getcwd() != _fastr_suite.dir:
         mx.abort('must run rtestgen from FastR home directory')
 
+    def _test_srcdir():
+        tp = 'com.oracle.truffle.r.test'
+        return join(mx.project(tp).dir, 'src', tp.replace('.', sep))
+
     def need_version_check():
         vardef = os.environ.has_key('FASTR_TESTGEN_GNUR')
         varval = os.environ['FASTR_TESTGEN_GNUR'] if vardef else None
@@ -452,13 +370,14 @@ def testgen(args):
         except subprocess.CalledProcessError:
             mx.abort('RVersionNumber.main failed')
 
-    # now just invoke junit with the appropriate options
+    tests = _all_generated_unit_tests()
+    # now just invoke unittst with the appropriate options
     mx.log("generating expected output for packages: ")
-    for pkg in args.tests.split(','):
+    for pkg in tests:
         mx.log("    " + str(pkg))
     os.environ["TZDIR"] = "/usr/share/zoneinfo/"
     _unset_conflicting_envs()
-    junit(['--tests', args.tests, '--gen-expected-output', '--gen-expected-quiet'])
+    mx_unittest.unittest(['-Dfastr.test.gen.expected=' + _test_srcdir(), '-Dfastr.test.gen.expected.quiet', '-Dfastr.test.project.output.dir=' + mx.project('com.oracle.truffle.r.test').output_dir()] + tests)
 
 def _unset_conflicting_envs():
     # this can interfere with the recommended packages
@@ -468,9 +387,6 @@ def _unset_conflicting_envs():
     if os.environ.has_key('EDITOR'):
         del os.environ['EDITOR']
 
-def unittest(args):
-    print "use 'junit --tests testclasses' or 'junitsimple' to run FastR unit tests"
-
 def rbcheck(args):
     '''Checks FastR builtins against GnuR
 
@@ -567,6 +483,8 @@ def nativebuild(args):
 def mx_post_parse_cmd_line(opts):
     mx_fastr_dists.mx_post_parse_cmd_line(opts)
 
+mx_unittest.add_config_participant(_unittest_config_participant)
+
 _commands = {
     'r' : [rshell, '[options]'],
     'R' : [rshell, '[options]'],
@@ -574,12 +492,10 @@ _commands = {
     'Rscript' : [rscript, '[options]'],
     'rtestgen' : [testgen, ''],
     'rgate' : [rgate, ''],
-    'junit' : [junit, ['options']],
-    'junitsimple' : [junit_simple, ['options']],
-    'junitdefault' : [junit_default, ['options']],
-    'junitgate' : [junit_gate, ['options']],
-    'junitnoapps' : [junit_noapps, ['options']],
-    'unittest' : [unittest, ['options']],
+    'rutsimple' : [ut_simple, ['options']],
+    'rutdefault' : [ut_default, ['options']],
+    'rutgate' : [ut_gate, ['options']],
+    'rutnoapps' : [ut_noapps, ['options']],
     'rbcheck' : [rbcheck, '--filter [gnur-only,fastr-only,both,both-diff]'],
     'rbdiag' : [rbdiag, '(builtin)* [-v] [-n] [-m] [--sweep | --sweep=lite | --sweep=total] [--mnonly] [--noSelfTest] [--matchLevel=same | --matchLevel=error] [--maxSweeps=N] [--outMaxLev=N]'],
     'rrepl' : [rrepl, '[options]'],
diff --git a/mx.fastr/mx_fastr_dists.py b/mx.fastr/mx_fastr_dists.py
index 2f81965b06..37b9b4a7bd 100644
--- a/mx.fastr/mx_fastr_dists.py
+++ b/mx.fastr/mx_fastr_dists.py
@@ -42,32 +42,6 @@ class FastRProjectAdapter(mx.ArchivableProject):
                 if not filterfun or filterfun(f):
                     results.append(join(root, f))
 
-
-class FastRTestNativeProject(FastRProjectAdapter):
-    '''
-    Custom class for building the com.oracle.truffle.r.native project.
-    The customization is to support the creation of an exact FASTR_NATIVE_DEV distribution.
-    '''
-    def __init__(self, suite, name, deps, workingSets, theLicense, **args):
-        FastRProjectAdapter.__init__(self, suite, name, deps, workingSets, theLicense)
-
-    def getBuildTask(self, args):
-        return mx.NativeBuildTask(args, self)
-
-    def getResults(self):
-        '''
-        Capture all the files from the com.oracle.truffle.r.test.native project that are needed
-        for running unit tests in an alternate implementation.
-        '''
-        # plain files
-        results = []
-
-        self._get_files(join('packages', 'recommended'), results)
-        self._get_files(join('packages', 'repo'), results)
-
-        results.append(join(self.dir, 'urand', 'lib', 'liburand.so'))
-        return results
-
 class FastRReleaseProject(FastRProjectAdapter):
     '''
     Custom class for creating the FastR release project, which supports the
@@ -240,4 +214,5 @@ class FastRArchiveParticipant:
 
 def mx_post_parse_cmd_line(opts):
     for dist in mx_fastr._fastr_suite.dists:
-        dist.set_archiveparticipant(FastRArchiveParticipant(dist))
+        if isinstance(dist, mx.JARDistribution):
+            dist.set_archiveparticipant(FastRArchiveParticipant(dist))
diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py
index 75d0d5c3de..2df9dae115 100644
--- a/mx.fastr/suite.py
+++ b/mx.fastr/suite.py
@@ -172,10 +172,14 @@ suite = {
     },
 
     "com.oracle.truffle.r.test.native" : {
+      "native" : True,
       "sourceDirs" : [],
       "dependencies" : ["com.oracle.truffle.r.native"],
-      "class" : "FastRTestNativeProject",
-      "native" : "true",
+      "platformDependent" : True,
+      "output" : "com.oracle.truffle.r.test.native",
+      "results" :[
+         "urand/lib/liburand.so",
+       ],
       "workingSets" : "FastR",
     },
 
@@ -248,6 +252,7 @@ suite = {
 
     "com.oracle.truffle.r.native" : {
       "sourceDirs" : [],
+#      "class" : "FastRNativeProject",
       "dependencies" : [
         "GNUR",
         "GNU_ICONV",
@@ -353,27 +358,11 @@ suite = {
 
     "FASTR_UNIT_TESTS_NATIVE" : {
       "description" : "unit tests support (from test.native project)",
-      "exclude" : ["GNUR", "GNU_ICONV"],
-       "os_arch" : {
-         "linux" : {
-           "amd64" : {
-             "path" : "mxbuild/dists/linux/amd64/fastr-unit-tests-native.jar",
-           },
-           "sparcv9" : {
-             "path" : "mxbuild/dists/linux/sparcv9/fastr-unit-tests-native.jar",
-           },
-        },
-        "darwin" : {
-           "amd64" : {
-             "path" : "mxbuild/dists/darwin/amd64/fastr-unit-tests-native.jar",
-           },
-        },
-        "solaris" : {
-           "sparcv9" : {
-             "path" : "mxbuild/dists/solaris/sparcv9/fastr-unit-tests-native.jar",
-           },
-        },
-      },
+       "native" : True,
+       "platformDependent" : True,
+      "dependencies" : [
+        "com.oracle.truffle.r.test.native",
+     ],
     },
 
     "FASTR_RELEASE": {
-- 
GitLab