skip_on_cran()

test_that("package compilation: local closures don't collide across quick functions", {
  pkgdir <- withr::local_tempdir(pattern = "quickr-contains-pkg-")
  pkgpath <- file.path(pkgdir, "quickr.contains.pkg")
  dir.create(pkgpath)
  dir.create(file.path(pkgpath, "R"))
  dir.create(file.path(pkgpath, "src"))

  writeLines(
    c(
      "Package: quickr.contains.pkg",
      "Title: quickr internal-proc test package",
      "Version: 0.0.0.9000",
      "Description: Internal tests for quickr package compilation.",
      "License: MIT",
      "Encoding: UTF-8",
      "RoxygenNote: 7.3.2",
      "Imports: quickr"
    ),
    file.path(pkgpath, "DESCRIPTION")
  )

  writeLines(
    c(
      "useDynLib(quickr.contains.pkg, .registration = TRUE)",
      "export(fn1)",
      "export(fn2)"
    ),
    file.path(pkgpath, "NAMESPACE")
  )

  writeLines(
    c(
      "declare <- function(...) invisible()",
      "",
      "# Two different quick functions defining the same local closure name `f`.",
      "# If local closures were emitted as global procedures, this would fail to",
      "# compile due to duplicate symbol definitions in a single compilation unit.",
      "",
      "fn1 <- quickr::quick(\"fn1\", function(x) {",
      "  declare(type(x = double(NA)))",
      "  f <- function(i) x[i] + 1.0",
      "  out <- double(length(x))",
      "  out <- sapply(seq_along(out), f)",
      "  out",
      "})",
      "",
      "fn2 <- quickr::quick(\"fn2\", function(x) {",
      "  declare(type(x = double(NA)))",
      "  f <- function(i) x[i] * 2.0",
      "  out <- double(length(x))",
      "  out <- sapply(seq_along(out), f)",
      "  out",
      "})"
    ),
    file.path(pkgpath, "R", "pkg.R")
  )

  # Compile the package using the *development* quickr currently under test,
  # without relying on pkgload/pkgbuild (which may not have build tools in test
  # environments).
  pkg_env <- new.env(parent = baseenv())
  quickr:::collector$activate("quickr.contains.pkg:quick_funcs")
  sys.source(file.path(pkgpath, "R", "pkg.R"), envir = pkg_env)
  withr::with_dir(pkgpath, suppressMessages(quickr:::dump_collected()))

  build_dir <- withr::local_tempdir(pattern = "quickr-contains-build-")
  file.copy(
    file.path(pkgpath, "src", "quickr_sub_routines.f90"),
    file.path(build_dir, "quickr_sub_routines.f90"),
    overwrite = TRUE
  )
  file.copy(
    file.path(pkgpath, "src", "quickr_entrypoints.c"),
    file.path(build_dir, "quickr_entrypoints.c"),
    overwrite = TRUE
  )

  owd <- setwd(build_dir)
  on.exit(setwd(owd), add = TRUE)

  res <- suppressWarnings(system2(
    R.home("bin/R"),
    c(
      "CMD",
      "SHLIB",
      "-o",
      paste0("quickr.contains.pkg", .Platform$dynlib.ext),
      "quickr_sub_routines.f90",
      "quickr_entrypoints.c"
    ),
    stdout = TRUE,
    stderr = TRUE
  ))
  if (!is.null(status <- attr(res, "status"))) {
    writeLines(res)
    stop("Compilation failed with status: ", status)
  }

  expect_true(file.exists(paste0("quickr.contains.pkg", .Platform$dynlib.ext)))
})
