test_that("load_client_lib", {
  lib <- load_client_lib()

  funcs <- c("base64_decode", "set_stderr", "write_fd")
  expect_true(
    all(funcs %in% names(lib))
  )

  lib <- load_client_lib(pxdir = find.package("processx"))
  expect_true(
    all(funcs %in% names(lib))
  )
})

test_that("errors", {
  fake(load_client_lib, "system.file", "")
  expect_snapshot(error = TRUE, load_client_lib())
})

test_that("errors 2", {
  sofile <- system.file(
    "libs",
    .Platform$r_arch,
    paste0("client", .Platform$dynlib.ext),
    package = "processx"
  )
  fake(load_client_lib, "dyn.load", function(...) stop("ooops"))
  expect_snapshot(error = TRUE, load_client_lib(sofile))
})

test_that("base64", {
  lib <- load_client_lib()
  enc <- lib$base64_encode(charToRaw("hello world!"))
  expect_equal(lib$base64_decode(enc), charToRaw("hello world!"))
})

test_that("write_fd", {
  do <- function() {
    lib <- asNamespace("callr")$load_client_lib()
    f1 <- tempfile()
    c1 <- processx::conn_create_file(f1, write = TRUE)
    lib$write_fd(processx::conn_get_fileno(c1), "hello world!\n")
    close(c1)
    readLines(f1)
  }

  ret <- callr::r(do)
  expect_equal(ret, "hello world!")
})

test_that("set_stdout, set_stderr", {
  # TODO why does this not work on windows, if `set_std{out,err}_file` work?
  # Also, `set_std{out,err}` work in `r_session`.
  # But this test crashes at the `set_stdout()` call.
  skip_on_os("windows")

  do <- function() {
    lib <- asNamespace("callr")$load_client_lib()
    f1 <- tempfile()
    f2 <- tempfile()
    c1 <- processx::conn_create_file(f1, write = TRUE)
    c2 <- processx::conn_create_file(f2, write = TRUE)
    lib$set_stdout(processx::conn_get_fileno(c1))
    lib$set_stderr(processx::conn_get_fileno(c2))
    cat("this is output")
    message("this is error")
    close(c1)
    close(c2)
    c(readLines(f1), readLines(f2))
  }

  ret <- callr::r(do)
  expect_equal(ret, c("this is output", "this is error"))
})

test_that("set_stdout_file, set_setderr_file", {
  do <- function() {
    lib <- asNamespace("callr")$load_client_lib()
    f1 <- tempfile()
    f2 <- tempfile()
    lib$set_stdout_file(f1)
    lib$set_stderr_file(f2)
    cat("this is output")
    message("this is error")
    c(readLines(f1), readLines(f2))
  }

  ret <- callr::r(do)
  expect_equal(ret, c("this is output", "this is error"))
})

test_that("init function of client lib is run", {
  pxlib <- r(function() {
    as.environment("tools:callr")$`__callr_data__`$pxlib
  })

  # File name should be `client.SOEXT` so that R can match the init
  # function from the name
  expect_true(grepl("^client\\.", basename(pxlib$.path)))

  # In case R removes the `dynamicLookup` field
  skip_on_cran()

  # Should be `FALSE` since processx disables dynamic lookup in the
  # init function
  expect_false(unclass(pxlib$.lib)$dynamicLookup)
})

test_that("CALLR_NO_TEMP_DLLS", {
  skip_on_cran()
  if (.Platform$OS.type != "windows") {
    skip("Windows only")
  }

  # If not set, then it should come from the temporary location
  withr::local_envvar(CALLR_NO_TEMP_DLLS = NA_character_)
  dlls <- callr::r(function() ps::ps_shared_libs())$path
  px <- grep("processx.*client.dll", dlls)
  cr <- grep("callr.*client.dll", dlls)
  expect_true(length(px) == 0)
  expect_true(length(cr) >= 1)

  # If set, then it should come from processx
  withr::local_envvar(CALLR_NO_TEMP_DLLS = "true")
  dlls <- callr::r(function() ps::ps_shared_libs())$path
  px <- grep("processx.*client.dll", dlls)
  cr <- grep("callr.*client.dll", dlls)
  expect_true(length(px) >= 1)
  expect_true(length(cr) == 0)
})
