Sys.unsetenv("R_TESTS")
test_that("Some smoke tests", {
expect_equal(juliaCall("prod", c(1,2,3)), 6)
juliaEval("")
juliaCall("string", list())
juliaCall("string", list(as.integer(1), "bla" = 23L))
juliaEval("String[]")
expect(!is.null(juliaEval("using Random; Random.seed!(5)")),
"Must be able to set random seed")
expect(is.null(juliaEval("Random.seed!(5);")),
"Eval with semicolon at end returns NULL")
})
test_that("Output is transferred", {
output <- capture_output({
juliaCall("println", as.integer(22))
})
expect_match(output, "^[\n]*22[\n]*$")
output <- capture_output({
juliaCall("println", "hello world")
})
expect_match(output, "^[\n]*hello world[\n]*$")
})
test_that("Warnings are transferred", {
output <- capture.output(type = "message", {
juliaEval('@warn "This might be serious"')
})
expect_match(output[1], "This might be serious")
})
test_that("Warnings and normal output are both transferred and stable", {
stdoutput <- capture_output({
stderroutput <- capture.output(type = "message", {
juliaLet('for i = 1:100
println(join(rand(["1", "ä", "ö"], rand(1:100))));
println(stderr,join(rand(["2", "u", "a"], rand(1:100))));
end')
ret <- juliaLet('println(22); 17')
})
})
expect_match(stdoutput, "[1äö\n]+")
expect_match(stderroutput, "[2ua\n]+") # TODO problems with non-ascii-characters
stdoutput <- capture_output({
stderroutput <- capture.output(type = "message", {
ret <- juliaLet('println(22); @warn "This might be serious"; 17')
})
})
expect_equal(ret, 17)
expect_match(stdoutput[1], "^[\n]*22[\n]*$")
expect_match(stderroutput[1], "This might be serious")
})
test_that("A return value of nothing is not printed", {
output <- capture_output({
juliaEval("nothing")
juliaCall("identity", NULL)
juliaLet("x = y", y = NULL)
})
expect_match(output, "^[\n]*$")
})
test_that("Test loading and importing a complex package", {
skip_on_cran()
juliaEval('begin
using Pkg;
try
@eval import StatsBase
catch ex
Pkg.add("StatsBase")
end
end
') # tests also trailing whitespace
StatsBase <- juliaImport("StatsBase")
expect_equivalent(juliaGet(StatsBase$mean_and_var(c(1,2,3))), list(2,1))
StatsBase$renyientropy(rnorm(100), 1)
})
test_that("Error when trying to import a non-existent package or module", {
expect_error(juliaImport("NonExistingPkg"))
expect_error(capture.output({juliaImport(".NonExistingModule")}, type = "message"))
})
test_that("Error when passing multiple strings to import or using", {
expect_error(juliaImport(c("Pkg", "UUID")), regexp = "exactly one")
})
test_that("Example for juliaEval runs", {
v1 <- juliaExpr('v"1.0.5"')
v2 <- juliaExpr('v"1.3.0"')
expect(juliaCall("<", v1, v2), "Comparison must work")
})
test_that("Echo: empty R vector", {testEcho(c())})
test_that("Echo: double", {
expect(is.integer(juliaEcho(1L)), "Must be integer")
testEcho(1L)
})
test_that("Echo: Single Int", {
testEcho(1L)
expect(is.integer(juliaEval("1")), "1 is not integer")
testEcho(juliaEval("1"))
expect(is.double(juliaEval("2^52")), "2^52 is not double") # TODO inexactness?
testEcho(juliaEval("2^52"))
})
test_that("Echo: 1-element vector of Int in Julia", {testEcho(juliaEval("[1]"))})
test_that("Echo: Matrix of Int", {testEcho(matrix(1:6, nrow = 2))})
test_that("Echo: Single Float64", {
testEcho(juliaEval("1.0"))
testEcho(1)
})
test_that("UInt32, Float16, and Float32 translated to doubles in R", {
toTest <- c("Float16(1.5)", "Float16[]", "Float16[1.5]",
"Float32(1.5)", "Float32[]", "Float32[1.5]",
"UInt32(32)", "UInt32[]", "UInt32[32]")
for (expr in toTest) {
expect(is.double(juliaEval(expr)), "Must be double")
}
})
test_that("Echo: 0-element vector of Float64 in Julia", {testEcho(juliaEval("Float64[]"))})
test_that("Echo: 1-element vector of Float64 in Julia", {testEcho(juliaEval("[1.0]"))})
test_that("Echo: 2-element vector of Float64/double", {
testEcho(c(1, 2))
testEcho("[1.0; 2.0]")
})
test_that("Echo: matrix of Float64 in Julia", {
testEcho(juliaEval("[1.0 2.0; 3.0 4.0]"))
testEcho(matrix(c(1,2,3,4,4,5), nrow = 2))
})
test_that("Echo: 1-element vector of Float32 in Julia", {testEcho(juliaEval("[1.0f0]"))})
test_that("Echo: matrix of Float32 in Julia", {testEcho(juliaEval("[1.0f0 2.0f0; 3.0f0 4.0f0]"))})
test_that("Echo: 1-element vector of String in Julia", {testEcho(juliaEval('String["bla"]'))})
test_that("Echo: 0-element vector of String in Julia", {testEcho("String[]")})
test_that("Echo: 1-element vector of String in R", {testEcho("bla")})
test_that("Echo: 2-element vector of String in R", {testEcho(c("bla", "blup"))})
test_that("Echo: 2-element vector of String in Julia", {testEcho(juliaEval('String["bla", "blup"]'))})
test_that("Echo: String with missing values", {
x <- c("Yes", "No", NA)
y <- juliaEcho(x)
expect_true(is.na(y[3]))
x <- matrix(c("bla", NA, NA, "NA"), nrow = 2)
y <- juliaEcho(x)
expect_false(is.na(y[1,1]))
expect_true(is.na(y[1,2]))
expect_true(is.na(y[2,1]))
expect_false(is.na(y[2,2]))
})
test_that("Echo: Int vector with missing values", {
expect_true(juliaLet("x[1] == 1 && ismissing(x[2]) && x[3] == 3", x = c(1L,NA, 3L)))
expect_true(juliaLet("ismissing(x)", x = NA_integer_))
x <- juliaEval("[1 missing 3; 3 missing 4 ]")
expect_type(x, "integer")
expect_true(all(is.na(x[,2])))
expect_null(attr(x, "JLTYPE"))
x <- juliaEval("[2^52 missing 3; 2^53 missing 4 ]")
expect_type(x, "double")
expect_true(all(is.na(x[,2])))
expect_equal(x[1,1], 2^52)
expect_equal(x[2,1], 2^53)
testEcho(x)
x <- juliaEval("Union{Int32,Missing}[1 missing 3; 3 missing 4 ]")
expect_type(x, "integer")
expect_true(all(is.na(x[,2])))
expect_equal(x[1,1], 1)
expect_equal(x[2,1], 3)
testEcho(x)
x <- juliaEval("Union{Int16,Missing}[-1 missing 3; 3 missing 4 ]")
expect_type(x, "integer")
expect_true(all(is.na(x[,2])))
expect_equal(x[1,1], -1)
expect_equal(x[2,1], 3)
testEcho(x)
testEcho(c(1L, 2L, NA, NA))
testEcho(matrix(c(1L, 2L, NA, NA), nrow = 2))
})
test_that("Echo: Double vector with missing values", {
expect_true(juliaLet("x[1] == 1.0 && ismissing(x[2]) && x[3] == 3.0", x = c(1,NA, 3)))
expect_true(juliaLet("ismissing(x)", x = NA_integer_))
x <- juliaEval("[1.0 missing 3.0; 3.0 missing 4.0 ]")
expect_type(x, "double")
expect_true(all(is.na(x[,2])))
expect_null(attr(x, "JLTYPE"))
x <- juliaEval("Union{Float32,Missing}[1.0f0 missing 3.0f0; 3.0f0 missing 4.0f0 ]")
expect_true(all(is.na(x[,2])))
expect_equal(x[1,1], 1)
expect_equal(x[2,1], 3)
testEcho(x)
testEcho(c(1, 2, NA, NA))
testEcho(matrix(c(1, 2, NA, NA), nrow = 2))
})
test_that("Dirty missing values are recognized", {
dirtyNa <- c(as.raw(0xa2), as.raw(0x07), as.raw(0x00), as.raw(0x00),
as.raw(0x00), as.raw(0x00), as.raw(0xf8), as.raw(0x7f))
dirtyNA <- readBin(dirtyNa, what = "double", endian = "little")
expect_true(is.na(dirtyNA) && !is.nan(dirtyNA))
expect_true(juliaCall("ismissing", dirtyNA))
expect_true(juliaLet("ismissing(x[2])", x = c(1, dirtyNA)))
echoDirtyNA <- juliaEcho(dirtyNA)
expect_true(is.na(echoDirtyNA) && ! is.nan(echoDirtyNA))
dirtyComplexNA <- complex(real = dirtyNA, imaginary = dirtyNA)
expect_true(is.na(dirtyComplexNA) && !is.nan(dirtyComplexNA))
expect_true(juliaCall("ismissing", dirtyComplexNA))
x <- c(1+1i, dirtyComplexNA, NA)
expect_true(juliaLet("ismissing(x[2]) && ismissing(x[3])", x = x))
testEcho(x)
# The following doesn't work: dirtNA coerced to NA+0i, not NA+NA*i:
# expect_true(juliaLet("ismissing(x[2])", x = c(1+1i, dirtyNA)))
echoDirtyComplexNA <- juliaEcho(dirtyComplexNA)
expect_true(is.na(echoDirtyComplexNA) && !is.nan(echoDirtyComplexNA))
})
test_that("NaN and NA are handled differently", {
# NaN in R is translated to a NaN Float64 value in Julia
# NA in R is translated to a missing value in Julia
x <- juliaEval("[1; missing; NaN]")
expect_equal(x[1], 1)
expect_true(is.na(x[2]) && !is.nan(x[2]))
expect_true(is.nan(x[3]))
y <- juliaEcho(x)
expect_equal(y[1], 1)
expect_true(is.na(y[2]) && !is.nan(y[2]))
expect_true(is.nan(y[3]))
expect_equal(juliaCall("typeof", c(1, NA)),
juliaEval("Array{Union{Float64,Missing},1}"))
expect_equal(juliaCall("typeof", c(1, NaN)),
juliaEval("Array{Float64,1}"))
expect_equal(juliaCall("typeof", c(1+1i, NA)),
juliaEval("Array{Union{Complex{Float64},Missing},1}"))
expect_equal(juliaCall("typeof", c(1+1i, NaN)),
juliaEval("Array{Complex{Float64},1}"))
expect_true(juliaLet("ismissing(x[2])", x = c(1+1i, NA)))
})
test_that("Missing values transferred as NA", {
expect_true(is.na(juliaEval("missing")))
expect_true(all(is.na(juliaEval("[missing; missing]"))))
expect_true(all(is.na(juliaEval("[missing missing; missing missing]"))))
})
test_that("Logical with missing values", {
juliaLet("x[1] && !x[2] && ismissing(x[3])", x = c(TRUE, FALSE, NA))
x <- c(TRUE, FALSE, NA)
testEcho(x)
})
test_that("Complex with missing values", {
juliaLet("x[1] == 1+1im && x[2] == 2+2im && ismissing(x[3])", x = c(1 +1i, 2+2i, NA))
x <- c(1 +1i, 2+2i, NA)
testEcho(x)
x <- juliaEval("[1+1im 1+2im; 0 missing]")
expect_equivalent(x, matrix(c(1+1i, 0, 1+2i, NA), nrow = 2))
testEcho(x)
x <- juliaEval("[1.0+im 2.0+im; 0.0 missing]")
expect_equal(x, matrix(c(1+1i, 0, 2+1i, NA), nrow = 2))
expect_true(is.null(attr(x, "JLTYPE")))
testEcho(x)
})
test_that("Echo: logical vectors", {
testEcho(juliaEval('Bool[]'))
testEcho(logical())
testEcho(TRUE)
testEcho(FALSE)
testEcho(c(TRUE, FALSE))
testEcho("Bool[true]")
})
test_that("Echo: Pointers", {
arrPtr <- juliaFun("Base.pointer", list(1,2,3))
ptr <- arrPtr(2L)
expect_type(ptr, "raw")
testEcho(ptr)
ptrs <- juliaCall("map", arrPtr, as.integer(1:3))
testEcho(ptrs)
})
test_that("Echo: Ref", {
testEcho(juliaCall("Ref", list(1,2,3), 2L))
r <- juliaEval("global reftestvar = 1; Ref(reftestvar)")
testEcho(r)
})
test_that("Complex values are handled first class", {
testEcho(1i)
testEcho(juliaEval("1+im"))
testEcho(juliaEval("[1+im]"))
testEcho(juliaEval("[1+im; 2+im]"))
testEcho(c(1+1i,2 + 2i))
suppressWarnings({jla <- juliaImport("LinearAlgebra")})
testEcho(matrix(c(1, 0, 0, -1), ncol = 2))
expect(all(jla$eigvals(matrix(c(1, 0, 0, -1), ncol = 2),
matrix(c(0, 1, 1, 0), ncol = 2)) %in% c(1i, -1i)),
"")
expect(all(jla$eigmax(matrix(c(0, 1i, -1i, 0), ncol = 2)) == 1.0), "")
complexTypeParameters = c("Int8", "Int16", "Int32", "Int64",
"Float16", "Float32", "Float64")
for (complexPar in complexTypeParameters) {
juliaComplexType <- paste0("Complex{", complexPar, "}")
c <- juliaEval(paste0(juliaComplexType, "(5-3im)"))
expect_equivalent(c, 5 - 3i)
carr <- juliaEval(paste0(juliaComplexType, "[4+4im, 2-2im]"))
expect_equivalent(carr, c(4+4i, 2-2i))
if (complexPar == "Float64") {
expect_null(attr(c, "JLTYPE"))
} else {
expect_true(juliaCall("==", juliaEval(attr(c, "JLTYPE")),
juliaEval(juliaComplexType)))
}
}
})
test_that("Echo: raw vector", {
testEcho(as.raw(c(1,2,3)))
testEcho(juliaEval("[0x01]"))
testEcho(juliaEval("UInt8[]"))
expect_equivalent(juliaEval("[0x01 0x02; 0x03 0x04]"),
matrix(c(1,3,2,4), nrow = 2))
expect_equal(juliaCall("string", c(as.raw(0xca), as.raw(0xfe))),
"UInt8[0xca, 0xfe]")
})
test_that("Echo: raw vector", {
testEcho(juliaEval("Int32[1, 2]"))
testEcho(juliaEval("Int32[]"))
testEcho(juliaEval("Int32[1]"))
})
test_that("Echo: Single Int16", {testEcho(juliaEval('Int16(300)'))})
test_that("Echo: Int16 Vector", {testEcho(juliaEval('Int16[1,2,3]'))})
test_that("Echo: 1-element Int16 Vector", {
expect_equal(juliaCall("string", juliaEval('Int16[300]')),
"Int16[300]")
})
test_that("Echo: Single UInt128", {testEcho(juliaEval('UInt128(2)^100 +1'))})
test_that("Echo: UInt128 Vector", {testEcho(juliaEval('UInt128[1,2,3]'))})
test_that("Echo: 1-element UInt128 Vector", {
expect_equal(juliaCall("string", juliaEval('UInt128[1]')),
"UInt128[0x00000000000000000000000000000001]")
})
test_that("Echo: List with NULL elements", {
x <- juliaGet(juliaEcho(list(1, NULL, 3)))
expect_equal(x[[1]], 1)
expect_null(x[[2]])
expect_equal(x[[3]], 3)
expect_equal(length(x), 3)
testEcho(juliaEval('[1, nothing, 3]'))
x <- list("bla", NULL)
expect_equal(x[[1]], "bla")
expect_null(x[[2]])
x <- list(NULL, NULL)
expect_null(x[[1]])
expect_null(x[[2]])
})
test_that("Mutable struct usable by reference", {
juliaEval('mutable struct TestMutableStruct
x::Int
end')
jlRef <- juliaEval("TestMutableStruct(1)")
refEcho <- juliaEcho(jlRef)
expect_true(juliaCall("==", jlRef, refEcho))
expect_true(all(get("ref", jlRef) == get("ref", refEcho)))
expect_equal(refEcho$x, 1)
refEcho$x <- 2L
expect_equal(jlRef$x, 2)
ref <- get("ref", jlRef)
jlRef <- NULL
refEcho <- NULL
invisible(gc())
juliaEval("1")
expect_false(juliaLet("haskey(communicator.sharedheap, ref)", ref = ref,
communicator = JuliaConnectoR:::pkgLocal$communicator))
# Test behaviuor with juliaGet:
# The reference must be attached
jlRefEnv <- attr(juliaGet(juliaEval("TestMutableStruct(1)")), "JLREF")
expect_true(is.environment(jlRefEnv))
expect_true(is.raw(jlRefEnv$ref))
})
test_that("Immutable struct usable by reference and translated", {
juliaEval('struct TestImmutableStruct
x::Int
end')
jlRef <- juliaEval("TestImmutableStruct(1)")
expect_s3_class(jlRef, "JuliaStructProxy")
refEcho <- juliaEcho(jlRef)
expect_true(juliaCall("==", jlRef, refEcho))
expect_equal(refEcho$x, 1)
ref <- get("ref", jlRef)
expect_equal(juliaGet(jlRef)$x, 1)
expect_false(juliaLet("haskey(communicator.sharedheap, ref)", ref = ref,
communicator = JuliaConnectoR:::pkgLocal$communicator))
gc()
juliaEval("1")
})
test_that("Currying in juliaFun works", {
plus1 <- juliaFun("+", 1)
plus1(2)
expect_equal(juliaCall("map", plus1, c(1,2,3)), c(2,3,4))
})
test_that("Multidimensional object arrays work", {
juliaEval("struct MultiTestStruct
f::Float64
end")
content <- juliaEval("rand(4,5,6)")
testEcho(content)
x <- juliaLet("map(MultiTestStruct, c)", c = content)
testEcho(x)
expect_equivalent(dim(x), c(4,5,6))
expect_equivalent(juliaGet(x[1,1,1]), list(juliaGet(x[[1,1,1]])))
x[[1,2,3]] <- juliaEval("MultiTestStruct(17.0)")
expect_equal(x[[1,2,3]]$f, 17)
x[1,2,2] <- juliaEval("MultiTestStruct(19.0)")
expect_equal(x[[1,2,2]]$f, 19)
x[1,2,2] <- list(juliaEval("MultiTestStruct(19.0)"))
expect_equal(x[[1,2,2]]$f, 19)
expect_equal(dim(x[3:4, 4:5, 1]), c(2,2,1))
expect_equal(dim(x[3:4, as.integer(4:5), 1L]), c(2,2,1))
x[3:4, as.integer(4:5), 1L] <- juliaEval("MultiTestStruct(20.0)")
expect_equal(juliaGet(x[[3, 4, 1]])$f, 20)
expect_equal(juliaGet(x[[4, 5, 1]])$f, 20)
y <- juliaGet(x)
attr(y, "JLDIM") <- c(1L, 2L, 3L)
expect_error(juliaEcho(y), regexp = "Incorrect dimensions")
# Must also work with dimensions of zero
testEcho(juliaEval("Matrix{MultiTestStruct}(undef, 0, 0)"))
x <- juliaEval("Array{MultiTestStruct}(undef, 0, 0, 0)")
testEcho(x)
expect_equivalent(dim(x), c(0,0,0))
# Two dimensions
content <- juliaEval("rand(2,3)")
x <- juliaLet("map(MultiTestStruct, c)", c = content)
x[[1,2]] <- juliaEval("MultiTestStruct(3.0)")
expect_equal(x[[1,2]]$f, 3)
})
test_that("Arrays with undef entries are translated", {
juliaEval("mutable struct MutableTestStruct
f::Float64
end")
# all undefs
testEcho(juliaEval("Vector{MutableTestStruct}(undef, 3)"),
comparableInJulia = FALSE)
# undefs and values
juliaLet("x = Vector{MutableTestStruct}(undef, 3);
x[1] = MutableTestStruct(x1);
x[2] = MutableTestStruct(x2);
x", x1 = 1.0, x2 = 2.0)
testEcho(juliaEval("Vector{MutableTestStruct}(undef, 3)"),
comparableInJulia = FALSE)
# multidimensional arrays with undefs and values
x <- juliaLet("x = Array{MutableTestStruct}(undef, 2, 3, 4);
x[1,1,1] = MutableTestStruct(x1);
x[2,2,2] = MutableTestStruct(x2);
x", x1 = 1.0, x2 = 2.0)
testEcho(x, comparableInJulia = FALSE)
expect_equal(x[[1]]$f, 1)
})
test_that("Undefined strings are transferred as empty strings", {
expect_equal(juliaEval("Vector{String}(undef, 3)"), c("", "", ""))
})
test_that("String with null can be translated back to Julia", {
# einfacher string
jlStrWithNul <- "String([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x5a, 0x65, 0x72, 0x6f, 0x57])"
str <- juliaEval(jlStrWithNul)
expect_true(is.raw(str))
expect_equal(as.character(juliaCall("typeof", str)), "String")
expect_equal(as.character(juliaLet("String(x[1:5])", x = str)), "Hello")
# string array
strArr <- juliaLet("String[a,b]", a = str, b = str)
expect_true(is.list(strArr))
strArr <- juliaLet("String[a,b,c]", a = str, b = str, c = str)
expect_true(is.list(strArr))
expect_equal(juliaCall("typeof", strArr), juliaEval("Array{String,1}"))
})
# Test Let
test_that("Let: used like eval", {
output <- capture_output({expect(is.null(juliaLet("print(1)")), "Failed")})
expect_equal(output, "1")
})
test_that("Let: must error with no named argument", {expect_error(juliaLet("print(x)", 1), "")})
test_that("Let: basic echo", {expect(all(juliaLet("identity(x)", x=c(2, 3)) == c(2,3)), "Failed")})
test_that("Let: Simple example from documentation works", {
expect_equal(capture_output({juliaLet('println(x)', x = 1)}),
capture_output({juliaEval('let x = 1.0; println(x) end')}))
})
test_that("Let: arguments without names not accepted", {
expect_error(juliaLet("println(1)", 1), regexp = "names")
expect_error(juliaLet("println(1)", x=1, 1, y=2), regexp = "names")
})
#Test Pairs
test_that("Echo: Pairs", {
testEcho(juliaEval("(1 => 2.0)"))
testEcho(juliaEval("1 => 2.0 => 3.0"))
testEcho(juliaEval("[1 => 2.0, 2 => 3.0]"))
})
# Test Tuples
test_that("Echo: Tuples", {
x <- juliaEval("(1, 17, 18)")
expect_equal(x[[2]], 17)
expect_equal(juliaGet(x[1]), juliaGet(juliaEval("(1,)")))
expect_length(x, 3)
expect_length(x[1:2], 2)
testEcho(juliaEval("(1, 2.0)"))
testEcho(juliaEval("((1, 2.0), 3.0)"))
testEcho(juliaLet("collect(zip(x,y))", x = c(1L,2L, 3L), y = c(1,0,1)))
testEcho(juliaEval("(Ref(false), Ref(true))"))
testEcho(juliaEval("Tuple{}()"))
})
# Test Named Tuples
test_that("Echo: Named Tuples", {
namedTuple <- juliaLet("y=2*x; z = 3*u + 1; (x=y, y=z)", x=2, u=4)
expect_s3_class(namedTuple, "JuliaStructProxy")
expect_equal(namedTuple$y, 13)
expect_type(juliaGet(namedTuple), "list")
expect_equal(juliaGet(namedTuple)$y, 13)
testEcho(namedTuple)
})
# Test Module
test_that("Echo: Module", {
juliaEval("module TestModule end")
testEcho(juliaEval("TestModule"))
})
test_that("Echo: Symbol", {
x <- juliaEval(":asymbol")
expect_true(is.symbol(x))
expect_true(juliaCall("isa", as.symbol("s"), juliaExpr("Symbol")))
testEcho(x)
})
# Test Dictionary
test_that("Echo: Dictionary", {
d <- juliaEval("Dict(:bla => 1.0, :blup => 3.0)")
expect_equivalent(d[juliaExpr(":bla")][[1]], 1)
expect_equal(d[juliaExpr(":bla"), juliaExpr(":bla")], as.list(c(1, 1)))
expect_equal(d[[as.symbol("bla")]], 1)
expect_equal(d[as.symbol("blup")],list(3))
d[juliaExpr(":blup")] <- 4
expect_equal(d[[juliaExpr(":blup")]], 4)
d[[juliaExpr(":blup")]] <- 5
expect_equal(d[[juliaExpr(":blup")]], 5)
d2 <- juliaGet(d)
expect_setequal(d2[["keys"]], juliaGet(juliaEval("[:bla, :blup]")))
expect_setequal(d2[["values"]], list(1, 5))
d[juliaExpr(":hi"), juliaExpr(":hello")] <- c(15, 14)
expect_equal(d[juliaExpr(":bla"), juliaExpr(":hi")], as.list(c(1, 15)))
d[juliaExpr(":hi"), juliaExpr(":hello")] <- as.list(c(16, 17))
expect_equal(d[juliaExpr(":bla"), juliaExpr(":hello"), juliaExpr(":hi")], as.list(c(1, 17, 16)))
expect_length(d[juliaExpr(":bla"), juliaExpr(":hi"), juliaExpr(":hello"), juliaExpr(":hello")], 4)
d <- juliaLet("Dict(zip(x, y))", x = c("bla", "blup"), y = c(1,2))
expect_equal(d[["bla"]], 1)
expect_equivalent(d["blup"], list(2))
d2 <- juliaGet(d)
expect_setequal(d2[["keys"]], list("bla", "blup"))
expect_setequal(d2[["values"]], list(1, 2))
d2 <- juliaGet(d)
expect_setequal(d2[["keys"]], list("bla", "blup"))
expect_setequal(d2[["values"]], list(1,2))
d$bla <- 17
expect_equal(d$bla, 17)
d <- juliaLet("Dict(zip(x, y))", x = list("bla"), y = list(1))
expect_equal(length(juliaCall("keys", d)), 1)
testEcho(d)
d <- juliaLet("Dict(zip(x, y))", x = list(), y = list())
d2 <- juliaGet(d)
expect_length(d2[["keys"]], 0)
expect_length(d2[["values"]], 0)
testEcho(d)
})
# Test Set
test_that("Echo: Set", {
s1 <- juliaEval("Set([1; 2; 3; 4])")
s2 <- juliaEval("Set([1; 2])")
expect_length(setdiff(juliaGet(juliaEval("Set([1; 2; 3; 4])")),
c(1,2,3,4)), 0)
expect_length(setdiff(juliaGet(juliaLet("setdiff(s1, s2)", s1 = s1, s2 = s2)),
c(3,4)), 0)
testEcho(s1)
})
# Test types with bitstypes
test_that("Object with bitstype", {
uuidregex <- '^[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}$'
UUIDs <- juliaImport("UUIDs")
expect_match(juliaCall("string", UUIDs$uuid4()), uuidregex)
})
test_that("Exotic objects handled gracefully", {
x <- quote(1 + 1)
expect_type(x, "language")
expect_warning({ y <- juliaEcho(list(x = x))},
regexp = "not translatable", all = FALSE)
expect_null(y$x)
})
# Test complex constructor with all kinds of types
test_that("Complex Julia object with different member type", {
juliaEval('struct TestTypeWithAllKindsOfStuff
n::Nothing
f16::Float16
f32::Float32
f64::Float64
b::Bool
i8::Int8
ui8::UInt8
i16::Int16
ui16::UInt16
i32::Int32
ui32::UInt32
ch::Char
i64::Int64
ui64::UInt64
i128::Int128
ui128::UInt128
f16vec::Vector{Float16}
f32vec::Vector{Float32}
f64vec::Vector{Float64}
bvec::Vector{Bool}
i8vec::Vector{Int8}
ui8vec::Vector{UInt8}
i16vec::Vector{Int16}
ui16vec::Vector{UInt16}
i32vec::Vector{Int32}
ui32vec::Vector{UInt32}
chvec::Vector{Char}
i64vec::Vector{Int64}
ui64vec::Vector{UInt64}
i128vec::Vector{Int128}
ui128vec::Vector{UInt128}
end')
juliaEval('function TestTypeWithAllKindsOfStuff()
TestTypeWithAllKindsOfStuff(
nothing,
rand(Float16), rand(Float32), rand(Float64),
rand(Bool),
rand(Int8), rand(UInt8),
rand(Int16), rand(UInt16),
rand(Int32), rand(UInt32),
rand(Char),
rand(Int64), rand(UInt64),
rand(Int128), rand(UInt128),
rand(Float16, 2), rand(Float32, 2), rand(Float64, 2),
rand(Bool, 2),
rand(Int8, 2), rand(UInt8, 2),
rand(Int16, 2), rand(UInt16, 2),
rand(Int32, 2), rand(UInt32, 2),
rand(Char, 2),
rand(Int64, 2), rand(UInt64, 2),
rand(Int128, 2), rand(UInt128, 2))
end')
testEcho(juliaEval("TestTypeWithAllKindsOfStuff()"))
})
test_that("Private inner constructor is forged", {
juliaEval('struct MyPrivateX
x::Int
function MyPrivateX()
new(5)
end
end')
p <- juliaEval("MyPrivateX()")
testEcho(p)
})
test_that("Imported modules are printed", {
# a stdlib module
Pkg <- juliaImport("Pkg")
expect_match(regexp = 'Julia module "Pkg": [0-9]+ function.*',
capture.output(print(Pkg))[1])
# a user defined module
module <- juliaEval('module ImportTestModule1
export f
f(x)=1
end')
itm1 <- juliaImport(module, all = FALSE)
expectedOutput <-
'Julia module "Main.ImportTestModule1": 1 function.*'
expect_match(capture.output(print(itm1))[1], regexp = expectedOutput)
itm1_2 <- juliaImport(".ImportTestModule1", all = FALSE)
expect_match(capture.output(print(itm1_2))[1], regexp = expectedOutput)
})
test_that("Empty module does not cause problems", {
juliaEval("module EmptyTestModule end")
expect_length(ls(juliaImport(".EmptyTestModule")), 2) # (eval and include)
juliaEval("module EmptyTestModule2 end")
expect_length(ls(juliaImport(".EmptyTestModule2", all = FALSE)), 0)
})
test_that("Errors are handled gracefully", {
expect_error(juliaCall("sum", c(1,2,3, "bla")))
expect_error(juliaCall("thisisnotarealfunction", 100, 4))
expect_error(juliaCall("RConnector.thisisnotarealfunction", "haha"))
expect_error(juliaCall("NotARealModule.thisisnotarealfunction", list(1,2,3)))
})
test_that("Vectors of objects can be accessed by index via proxy", {
x <- juliaEval("[ [1;2;3], [4;5;6], [7;8;9] ]")
expect_s3_class(x, "JuliaArrayProxy")
expect_equal(x[[1]][2], 2)
expect_equal(x[[2]][2], 5)
x[[1]][1] <- 17L
expect_equal(x[[1]][1], 17)
expect_equal(x[2:3][[1]][[1]], 4)
x[2:3][[1]][[1]] <- 18L
expect_equal(x[2:3][[1]][[1]], 18)
expect_equal(x[[1]][x[[2]] == 5], 2) # logical indexing
# juliaGet version must behave in the same way as the proxy version
y <- juliaGet(x)
expect_equal(x[[2]], y[[2]])
expect_equal(x[[1]][2], y[[1]][2])
expect_equal(x[[2]][2], y[[2]][2])
x[[1]][1] <- 17L
y[[1]][1] <- 17L
expect_equal(x[[1]][1], 17)
expect_equal(y[[1]][1], 17)
x[2:3][[1]][[1]] <- 18L
y <- juliaGet(x)
expect_equal(y[2:3][[1]][[1]], 18)
expect_equal(x[2:3][[1]][1], y[2:3][[1]][1])
expect_equal(x[[2]], y[[2]])
# Multiple dimensions
y <- juliaEval("map( x-> [1;x;3], rand(2,2,2))")
expect_equivalent(y[c(1,2)][[1]], y[[1]])
expect_equivalent(y[c(1,3)][[2]], y[[3]])
y[c(1,3)] <- juliaEval("[[17.0], [18.0]]")
expect_equivalent(juliaGet(y[1]), list(17))
expect_equivalent(juliaGet(y[3]), list(18))
expect_equivalent(juliaGet(y)[c(4,5)], juliaGet(y[c(4,5)]))
})
test_that("Callback functions", {
x <- juliaEcho(function() {})
expect_equal(typeof(x), "closure")
expect_equal(x, function() {})
outputenv <- new.env(parent = emptyenv())
outputenv$output <- c()
doOutput <- function(x) {
outputenv$output <- c(outputenv$output, x)
}
# Nested callback functions
juliaEval('struct TestStruct f::Function end')
juliaEval('function testNestedFun(ts::Vector{TestStruct}) map(t -> t.f(), ts) end')
t <- juliaCall("testNestedFun",
list(juliaCall("TestStruct", function() {doOutput("a")}),
juliaCall("TestStruct", function() {doOutput("b")}),
juliaCall("TestStruct", function() {doOutput("c")})))
expect_equal(outputenv$output, c("a", "b", "c"))
# as named arguments
outputenv$output <- c()
juliaEval('function testNestedFunNamed(;ts::Vector{TestStruct}) map(t -> t.f(), ts) end')
t <- juliaCall("testNestedFunNamed", ts =
list(juliaCall("TestStruct", function() {doOutput("x")}),
juliaCall("TestStruct", function() {doOutput("y")})))
expect_equal(outputenv$output, c("x", "y"))
# test repeated call of nested functions
outputenv$output <- c()
juliaEval('function testNestedFun2(ts::Vector{TestStruct}) for i = 1:2 map(t -> t.f(), ts) end end')
t <- juliaCall("testNestedFun2",
list(juliaCall("TestStruct", function() {doOutput(1)}),
juliaCall("TestStruct", function() {doOutput(2)})))
expect_equal(outputenv$output, c(1,2,1,2))
# Test multiple arguments
outputenv$output <- c()
juliaEval('function testNestedFunArgs(ts::Vector{TestStruct}, args...) map(t -> t.f(args...), ts) end')
t <- juliaCall("testNestedFunArgs",
list(juliaCall("TestStruct", function(x, y, z) {doOutput(x)}),
juliaCall("TestStruct", function(x, y, z) {doOutput(z); return(c(5,6,7))})),
1, 2, 3)
expect_equal(outputenv$output, c(1,3))
outputenv$output <- c()
juliaEval('function testNestedAndUnnested(f::Function, ts::Vector{TestStruct}, args...)
testNestedFunArgs(ts, args...)
f(args...)
end')
t <- juliaCall("testNestedAndUnnested",
function(x, y) {doOutput(x)},
list(juliaCall("TestStruct", function(x,y) {doOutput(x)}),
juliaCall("TestStruct", function(x, y) {doOutput(y); return(list(5,6,7))})),
17,18)
expect_equal(outputenv$output, c(17, 18, 17))
})
test_that("Callback function calling Julia erroring in Julia", {
f <- juliaEval('(x) -> error("Error")')
g <- function(x) {cat("OK"); f(x); print("NotOK"); x}
output <- capture.output(expect_error(juliaCall("map", g, c(1,2,3))))
expect_equal(output, "OK")
})
test_that("Builtin functions can be used as callback functions", {
expect_equal(juliaCall("map", sqrt, c(1,4,9)), c(1,2,3))
})
test_that("Callback function might have error in R", {
fOK <- function(x) { return(x+1) }
fnotOK <- function(x) {
if (x == 2) {
stop("No even numbers please")
} else {
return(1)
}
}
expect_equal(juliaCall("map", fOK, c(1,2,3)), c(2,3,4))
expect_error(juliaCall("map", fnotOK, c(1,2,3)), class = "error")
})
test_that("Julia functions as members are transferred and usable in R", {
op1 <- juliaFun("+")
juliaEval('struct FunTestStruct f::Function end')
funTestStruct <- juliaCall("FunTestStruct", op1)
expect_equal(funTestStruct$f(1,2), 3)
})
test_that("juliaCall checks given name before running", {
expect_error(juliaCall())
expect_error(juliaCall(1))
expect_error(juliaCall(c("bla", "bla")))
})
test_that("juliaCall can handle keyword arguments with key \"name\"", {
Pkg <- juliaImport("Pkg")
# indirect via created function object
expect_equal(Pkg$PackageSpec(name = "RData", version = "v0.10")$name,
"RData")
# direct call of juliaCall
pkgspec <- juliaCall("Pkg.PackageSpec", name = "RData", version = "0.10")
expect_equal(pkgspec$name, "RData")
})
test_that("Documentation example of juliaFun", {
juliaSqrt <- juliaFun("sqrt")
expect_equal(juliaSqrt(2), sqrt(2))
expect_equal(juliaCall("map", juliaSqrt, c(1,4,9)), c(1,2,3))
})
test_that("Constructors stand for their types", {
juliaEval('module TestTypeModule
export TestType
struct TestType end
end')
TestTypeModule <- juliaImport(".TestTypeModule")
expect_equal(as.character(juliaCall("typeof", TestTypeModule$TestType)),
"DataType")
})
test_that("Parametric types are imported", {
juliaEval("module ParametricTypeTestModule
export MyParametricType
struct MyParametricType{T}
i::T
end
end")
ParametricTypeTestModule <- juliaImport(".ParametricTypeTestModule")
expect_equal(ParametricTypeTestModule$MyParametricType(2)$i, 2)
expect_equal(ParametricTypeTestModule$MyParametricType("bla")$i, "bla")
})
test_that("Starting and stopping Julia server" , {
stopJulia()
port <- startJuliaServer()
expect_match(Sys.getenv("JULIACONNECTOR_SERVER"), paste0("localhost:", port))
# starting the server twice should give a warning and not do anything
expect_warning(startJuliaServer())
expect_match(Sys.getenv("JULIACONNECTOR_SERVER"), paste0("localhost:", port))
# now the server should start successfully
expect_equal(juliaEval("1"), 1)
# set a variable in a separate process:
rPath <- file.path(R.home("bin"), "R")
if (Sys.info()["sysname"] == "Windows") {
rPath <- paste0(rPath, ".exe")
}
system2(rPath, c("-e", shQuote(
paste0("library(JuliaConnectoR); juliaEval('global x = 1')"))),
stdout = FALSE)
# check that variable is set in this Julia session,
# i.e. that the two R processes share the same Julia process
expect_equal(juliaEval("x"), 1)
stopJulia()
expect_equal(Sys.getenv("JULIACONNECTOR_SERVER"), "")
expect_null(JuliaConnectoR:::pkgLocal$con)
})
test_that("Julia startup options can be modified", {
stopJulia()
oldJuliaOpts <- Sys.getenv("JULIACONNECTOR_JULIAOPTS")
# set project directory via startup opts
projectPathWithSpaces <- file.path(tempdir(), "Dirname with Spaces")
dir.create(file.path(tempdir(), "Dirname with Spaces"))
specifyProjectOpts <- paste0('--project="', projectPathWithSpaces, '"')
Sys.setenv("JULIACONNECTOR_JULIAOPTS" = paste0('--project="',
projectPathWithSpaces, '"'))
expect_match(capture.output({juliaEval("import Pkg; Pkg.status()")}),
regexp = "Dirname with Spaces", fixed = TRUE, all = FALSE)
stopJulia()
# set two startup opts: project directory and deprecation warnings
Sys.setenv("JULIACONNECTOR_JULIAOPTS" = paste(specifyProjectOpts,
"--depwarn=no"))
juliaDepWarn <- 'Base.depwarn("there is a deprecation warning", :foo)'
expect_length(capture.output({juliaEval(juliaDepWarn)}), 0)
stopJulia()
# clean up
unlink(projectPathWithSpaces, recursive = TRUE)
if (oldJuliaOpts == '') {
Sys.unsetenv("JULIACONNECTOR_JULIAOPTS")
} else {
Sys.setenv("JULIACONNECTOR_JULIAOPTS" = oldJuliaOpts)
}
})
test_that("JULIACONNECTOR_SERVER environment variable and Killing Julia works", {
# if JULIACONNECTOR_SERVER is used, the server must be started with
# "keeprunning = true" to work.
skip_on_cran()
JuliaConnectoR:::stopJulia()
oldJuliaConnectorServer <- Sys.getenv("JULIACONNECTOR_SERVER")
# start new JuliaConnectoR server
port <- JuliaConnectoR:::startJuliaServer(12980)
expect_match(Sys.getenv("JULIACONNECTOR_SERVER"), paste0("localhost:", port))
# test with wrong variable
Sys.setenv("JULIACONNECTOR_SERVER" = "wrong form")
expect_error(JuliaConnectoR:::startJulia(), regexp = "<host>:<port>")
# now for real
Sys.setenv("JULIACONNECTOR_SERVER" = paste("localhost", port, sep = ":"))
# test some command, if it works
expect_equal(juliaCall("prod", c(1,2)), 2)
# test killing
JuliaConnectoR:::killJulia()
if (oldJuliaConnectorServer == "") {
Sys.unsetenv("JULIACONNECTOR_SERVER")
} else {
Sys.setenv("JULIACONNECTOR_SERVER" = oldJuliaConnectorServer)
}
})
test_that("Error if Julia is not setup properly", {
oldJuliaBindir <- Sys.getenv("JULIA_BINDIR")
Sys.setenv("JULIA_BINDIR" = "/this/isnot/a/directory/")
expect_error(JuliaConnectoR:::runJuliaServer(16752), "No Julia executable file found")
if (oldJuliaBindir == "") {
Sys.unsetenv("JULIA_BINDIR")
} else {
Sys.setenv("JULIA_BINDIR" = oldJuliaBindir)
}
expect_equal(1, juliaEval("1"))
})
test_that("Fallback on juliaup fails correctly", {
skip_on_cran()
juliaCmdJuliaup <- file.path(Sys.getenv("HOME"), ".juliaup", "bin", "julia")
if (!file.exists(juliaCmdJuliaup)) {
expect_error(JuliaConnectoR:::fallbackOnDefaultJuliaupPath(), regexp = "\\?`Julia-Setup`")
} else {
expect_equal(juliaCmdJuliaup, JuliaConnectoR:::fallbackOnDefaultJuliaupPath())
}
})
test_that("Circular references do not lead to a crash", {
definition <- 'mutable struct TestRecur
r::Union{TestRecur, Int}
end'
try({juliaEval(definition)}, silent = TRUE) # (ignore redefinition error)
r <- juliaEval("r1 = TestRecur(2); r2 = TestRecur(r1); r1.r = r2; r1")
expect_match(capture.output({print(juliaEcho(r))}), regex = "circular reference", all = FALSE)
expect_error(juliaEcho(juliaGet(r)), regex = "Circular reference")
# reference only
r <- juliaEval("r1 = TestRecur(2); r2 = TestRecur(r1); r1.r = r2; r1")
expect_match(capture.output({print(juliaEcho(r))}), regex = "circular reference", all = FALSE)
expect_equal(juliaCall("typeof", r$r$r), juliaCall("typeof", r))
})
test_that("Anonymous functions can be transferred", {
af1 <- juliaEval("() -> 17")
expect_equal(af1(), 17)
expect_equal(juliaEcho(af1)(), 17)
rm(af1)
af2 <- juliaEval("(args...; kwargs...) -> 19")
expect_equal(af2(list(), 3, bla = 2), 19)
rm(af2)
# Test cleaning of references
invisible(gc(verbose = FALSE))
expect_gt(length(JuliaConnectoR:::pkgLocal$finalizedRefs), 0)
juliaEval("1")
expect_null(JuliaConnectoR:::pkgLocal$finalizedRefs)
juliaEval("struct TestAnonFunStruct
f::Function
end")
afs <- juliaEval("TestAnonFunStruct(() -> 20)")
expect_equal(afs$f(), 20)
})
test_that("Test BigInt: a Julia object with external pointers", {
# Note: It is not really recommended to translate objects with
# external pointers. Nevertheless, it should work and not cause a crash.
i1 <- juliaGet(juliaCall("BigInt", 2147483647L))
i2 <- juliaGet(juliaCall("BigInt", 2147483647L))
p <- juliaGet(juliaCall("prod", list(i1, i2, i1)))
p2 <- juliaGet(juliaCall("prod", list(i1, i2, i1)))
juliaCall("GC.gc") # references in sharedheap must survive this
jldiv <- juliaFun("div")
expect_equal(juliaCall("Int", jldiv(jldiv(p,i1), i2)), 2147483647L)
expect_equal(juliaLet("Int(div(div(p,i1),i2))", p = p, i1 = i1, i2 = i2),
2147483647)
f <- juliaLet("p/i1/i2", p = p, i1 = i1, i2 = i2)
expect_equal(juliaCall("Float64", f), 2147483647)
i1Ref <- attr(i1, "JLREF")$ref
expect_true(juliaLet("communicator.sharedheap[ref].refcount > 0",
ref = i1Ref, communicator = pkgLocal$communicator))
i1 <- NULL
invisible(gc())
juliaEval("1") # after one command, the references from R should be cleaned up
# Multiple calls to the Julia garbage are necessary for a complete clean-up as
# one finalization may make another object unreachable, which will then
# be cleaned up in the next run.
juliaCall("GC.gc")
juliaCall("GC.gc")
juliaCall("GC.gc")
expect_false(juliaLet("haskey(communicator.sharedheap, ref)", ref = i1Ref,
communicator = pkgLocal$communicator))
})
test_that("Serialized mutable struct can be restored", {
juliaEval("mutable struct TestSerializationStruct
i::Int
end")
x <- juliaGet(juliaEval("TestSerializationStruct(1)"))
tmpfile <- tempfile()
save("x", file = tmpfile)
x <- NULL
#juliaEval("println(RConnector.sharedheap)")
invisible(gc())
juliaEval("1")
juliaCall("GC.gc")
load(tmpfile)
msg <- capture.output(type = "message", {
expect_equal(juliaEcho(x)$i, 1)
})
expect_match(msg, "external references", all = FALSE)
x <- NULL
juliaEval("1")
juliaCall("GC.gc") # copy of the serialized copy is cleaned up
file.remove(tmpfile)
})
test_that("Object with unexported function defined in different modules", {
juliaEval('
module FirstModule
struct FirstType
f::Function
end
f(x::FirstType) = 1
end
module SecondModule
import ..FirstModule.f
struct SecondType
f::Function
end
f(x::SecondType) = 2
end #module')
# It doesn't matter whether SecondModule.f or FirstModule.f is used
ft1 <- juliaEval("FirstModule.FirstType(SecondModule.f)")
ft2 <- juliaEval("SecondModule.SecondType(FirstModule.f)")
expect_equal(juliaLet("x.f(x)", x = ft1), 1)
expect_equal(juliaLet("x.f(x)", x = ft2), 2)
expect_equal(juliaLet("x.f(y)", x = ft1, y = ft2), 2)
expect_equal(juliaLet("x.f(y)", x = ft2, y = ft1), 1)
})
test_that("AbstractArrays are transferred by reference and can be translated to struct", {
a <- juliaEval('using SparseArrays
A = sparse([1, 2, 3], [1, 2, 3], [0, 2, 0])')
expect_s3_class(a, "JuliaArrayProxy")
# indexing
expect_equal(a[[2,2]], 2)
# backtranslation
expect_true(juliaCall("issparse", juliaGet(a)))
testEcho(a)
})
test_that("Operators can be imported and used", {
suppressWarnings({jla <- juliaImport("LinearAlgebra", all = FALSE)})
expect_equal(jla$`<cdot>`(1,2), 2)
suppressWarnings({base <- juliaImport("Base", all = FALSE)})
expect_true(base$`<subseteq>`(c(1,2), c(1,2,3)))
})
test_that("Boltzmann machine can be trained and used", {
#skip_on_cran()
juliaEval('using Pkg;
try
@eval import BoltzmannMachines
catch ex
Pkg.add(PackageSpec(name = "BoltzmannMachines", version = v"1.2"))
end')
# Set a random seed in Julia
juliaEval("using Random; Random.seed!(5);")
BM <- juliaImport("BoltzmannMachines")
# a test data set from the BoltzmannMachines-package, just to have some data
x <- BM$barsandstripes(50L, 4L)
x
# Train DBMs with
dbm <- BM$fitdbm(x, epochs = 2L, nhiddens = c(4L,3L))
dbm
dbm2 <- BM$fitdbm(x, epochs = 1L,
pretraining = list(BM$TrainLayer(nhidden = 4L),
BM$TrainLayer(nhidden = 3L)))
dbm2 <- juliaGet(dbm2)
# Use a trained model to generate samples
gensamples <- BM$samples(dbm, 10L)
expect_equal(nrow(gensamples), 10)
# Evaluate the model: Likelihood estimation ...
BM$loglikelihood(dbm2, x)
# ... or exact calculation (possible for such a small model)
BM$exactloglikelihood(dbm2, x)
})
test_that("juliaPut", {
x <- juliaPut(c(1,2,3))
expect_s3_class(x, "JuliaSimpleArrayProxy")
expect_equal(x[[1]], 1)
expect_equal(x[1:2], c(1,2))
expect_type(x[3], "double")
x[2:3] <- 0
expect_equal(juliaCall("sum", x), 1)
expect_error(juliaPut(juliaEval("(a=1,b=2,c=3)")))
x <- juliaPut("bla")
expect_equal(as.character(juliaCall("typeof", x)), "String")
# use on translated object
x <- juliaGet(juliaEval("[(1,2), (2,3)]"))
expect_s3_class(juliaPut(x), "JuliaArrayProxy")
})
test_that("Display of default printing is limited to width", {
x <- juliaEval("rand(100, 100)")
y <- juliaPut(x)
printOutput <- capture.output({print(y)})
expect_lte(nchar(printOutput[length(printOutput)]),
getOption("width"))
})
test_that("Error message for tables", {
capture.output({JuliaConnectoR:::showUpdateTablesMsg()})
x <- juliaEcho(list(c(1,2), c(1,2,3)))
expect_s3_class(x, "JuliaProxy")
expect_error({as.data.frame(x)})
})
test_that("Data frame can be translated", {
x <- data.frame(x = c(0, 2, 4), y = c("bla", "blup", "ha"),
stringsAsFactors = FALSE)
testEcho(x)
y <- juliaEcho(x)
x2 <- as.data.frame(juliaEcho(x))
expect_s3_class(x2, "data.frame")
expect_equal(x2$x, c(0,2,4))
expect_equal(x2$y, c("bla", "blup", "ha"))
testEcho(data.frame())
Pkg <- juliaImport("Pkg")
if (juliaEval('VERSION < v"1.6"')) {
subproject <- "1_0"
} else if (juliaEval('VERSION < v"1.10"')) {
subproject <- "1_6"
} else {
subproject <- "1_10"
}
Pkg$activate(system.file("examples", "IndexedTables-Project", subproject,
package = "JuliaConnectoR"))
Pkg$instantiate()
juliaEval("import IndexedTables")
x <- data.frame(x = c(0, 2, 4), y = c("bla", "blup", "ha"),
stringsAsFactors = FALSE)
y <- juliaCall("IndexedTables.table", x)
expect_equal(as.data.frame(x), x)
# Works also without column names (Issue #16)
df <- juliaCall("IndexedTables.table", 1:3, 11:13)
df <- as.data.frame(df)
expect_equal(df[, 1], 1:3)
expect_equal(df[, 2], 11:13)
})
test_that("Attempt to translate Julia Table with incompatible types results in proper error", {
juliaEval("import IndexedTables")
x <- juliaEval('IndexedTables.table(["a", 1, 2], [1,2,3])')
expect_error(as.data.frame(x), regexp = 'Column type "Any" cannot be translated')
})
test_that("Julia types are converted to r compatible types in data frames", {
x1 <- juliaEval("[1.0f0*im + 1.0f0, 0.0f0]")
x2 <- juliaEval('map(i -> SubString(i, 2,3), ["asdf", "wert"])')
x3 <- juliaEval('[true, false]')
x4 <- juliaEval("['a', 'b']")
x <- juliaLet('Dict(:x1 => x1, :x2 => x2, :x3 => x3, :x4 => x4)',
x1 = x1, x2 = x2, x3 = x3, x4 = x4)
x <- as.data.frame(x)
expect_equivalent(x$x1, x1)
expect_equal(x$x2, c("sd", "er"))
expect_equal(x$x3, x3)
expect_equivalent(x$x4, x4)
})
test_that("Broadcasting via dot syntax works", {
expect_equal(juliaCall("sin.", c(0, 1/3*pi, pi/2)),
c(0, sqrt(3)/2, 1))
juliaEval("import Statistics")
arrofarrs <- juliaEval("[[2;3], [4;5]]")
expect_equal(juliaCall("Statistics.mean.", arrofarrs), c(2.5, 4.5))
expect_equal(juliaGet(juliaCall("Statistics.mean.", arrofarrs, dims = 1L)),
juliaGet(juliaEval("[[2.5], [4.5]]")))
# Test functions with multiple arguments
juliaEval("module TestBroadcasting
function my_add(x,y) x+y end
function my_mul(x,y) x*y end
end")
expect_equal(juliaCall("TestBroadcasting.my_add.", 10, c(1,2,3)),
juliaEval("TestBroadcasting.my_add.(10, [1, 2, 3])"))
expect_equal(juliaCall("TestBroadcasting.my_mul.", c(1,2,3), c(4,5,6)),
juliaEval("TestBroadcasting.my_mul.([1, 2, 3], [4, 5, 6])"))
# Check that dimension mismatch leads to an error
expect_error(juliaCall("TestBroadcasting.my_mul.", c(1,2,3,4), c(5,6)))
})
test_that("Environemnt variables for Julia can be set", {
# prepare
os <- Sys.info()['sysname']
oldJuliaEnv <- Sys.getenv("JULIACONNECTOR_JULIAENV")
JuliaConnectoR:::stopJulia()
# Test with one variable
Sys.setenv(JULIACONNECTOR_JULIAENV = "TESTVARIABLE1=1")
if (os == "Windows") {
expect_warning(juliaEval("1+1"))
} else {
expect_equal(juliaEval('ENV["TESTVARIABLE1"]'), "1")
}
JuliaConnectoR:::stopJulia()
# Test with two variables
Sys.setenv(JULIACONNECTOR_JULIAENV = "TESTVARIABLE1=1; TESTVARIABLE2='abc'")
if (os == "Windows") {
expect_warning(juliaEval("1+1"))
} else {
expect_equal(juliaEval('ENV["TESTVARIABLE1"]'), "1")
expect_equal(juliaEval('ENV["TESTVARIABLE2"]'), "abc")
}
JuliaConnectoR:::stopJulia()
# LD_LIBRARY_PATH can be set via JULIACONNECTOR_JULIAENV
Sys.setenv(JULIACONNECTOR_JULIAENV = "LD_LIBRARY_PATH='abc'")
if (os == "Linux") {
expect_match(JuliaConnectoR:::getJuliaEnv(), "LD_LIBRARY_PATH='abc'")
}
# clean up
if (oldJuliaEnv == "") {
Sys.unsetenv("JULIACONNECTOR_JULIAENV")
} else {
Sys.setenv(JULIACONNECTOR_JULIAENV = oldJuliaEnv)
}
})
test_that("Iris/Flux example from README works", {
skip_on_cran()
skip_on_covr()
#skip_if(Sys.info()["login"] %in% c("lenz", "Stefan Lenz", "selectstern", "lenzstef"))
cat("\nExecuting README examples...\n")
if (juliaEval('VERSION < v"1.9"')) {
skip("Skip Flux example because Julia version is too old")
} else {
projectFolder <- "project_1_9"
}
Pkg <- juliaImport("Pkg")
Pkg$activate(system.file("examples", "iris-example", projectFolder,
package = "JuliaConnectoR", mustWork = TRUE))
Pkg$instantiate()
irisExampleJl <- system.file("examples", "iris-example", "iris-example.jl",
package = "JuliaConnectoR", mustWork = TRUE)
irisExampleJuliaCode <- readLines(irisExampleJl)
juliaEval(paste(irisExampleJuliaCode, collapse = "\n"))
expect_true(juliaEval("accuracy(model, testdata) > 0.9"))
irisExampleR <- system.file("examples", "iris-example", "iris-example.R",
package = "JuliaConnectoR", mustWork = TRUE)
irisExampleRCode <- readLines(irisExampleR)
scriptEnv <- new.env(emptyenv())
suppressWarnings(eval(parse(text = paste(irisExampleRCode, collapse = "\n")),
envir = scriptEnv))
# Test that training the model worked
print(juliaCall("accuracy", scriptEnv$model, scriptEnv$testdata))
expect_true(juliaCall("accuracy", scriptEnv$model, scriptEnv$testdata) > 0.9)
Pkg$activate() # use default environment again
})
test_that("Boltzmann example from README works", {
skip_on_cran()
returningError <- function(x) {
paste0("tryCatch({", x , '},',
'error = function(e) { paste("e: ",e$message) },',
'warning = function(w) { paste("w: ", w$message) })')
}
juliaEval('import Pkg;
try
@eval import BoltzmannMachines
catch ex
Pkg.add(PackageSpec(name = "BoltzmannMachines", version = v"1.3"))
end')
boltzmannExampleR <- system.file("examples", "boltzmann-example.R",
package = "JuliaConnectoR", mustWork = TRUE)
bmExample <- readLines(boltzmannExampleR)
bmExample <- sub("plot\\(.*", "", bmExample)
bmScriptEnv <- new.env(emptyenv())
code <- paste(bmExample, collapse = "\n")
code <- returningError(code)
eval(parse(text = code), envir = bmScriptEnv)
expect_s3_class(bmScriptEnv$dbm, "JuliaProxy")
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.