tests/testthat/test-packrat.R

# Packrat tests
#
# To run these tests, set the working directory to packrat/tests and run
# test_check("packrat")
#
# Also run by R CMD CHECK.

library(testthat)

withTestContext({

  test_that("init creates project structure and installs dependencies", {
    skip_on_cran()
    projRoot <- cloneTestProject("sated")
    init(enter = FALSE, projRoot, options = list(local.repos = "packages"))
    lib <- libDir(projRoot)
    expect_true(file.exists(lockFilePath(projRoot)))
    expect_true(file.exists(srcDir(projRoot)))
    expect_true(file.exists(libDir(projRoot)))
    expect_true(file.exists(file.path(lib, "breakfast")))
    expect_true(file.exists(file.path(lib, "bread")))
    expect_true(file.exists(file.path(lib, "oatmeal")))
    expect_true(file.exists(file.path(lib, "packrat")))
    expect_true(file.exists(file.path(lib, "toast")))
  })

  test_that("init does not install dependencies when infer.dependencies is false", {
    skip_on_cran()
    projRoot <- cloneTestProject("sated")
    init(enter = FALSE, projRoot, options = list(local.repos = "packages"),
         infer.dependencies = FALSE)
    lib <- libDir(projRoot)
    expect_true(file.exists(lockFilePath(projRoot)))
    expect_true(file.exists(srcDir(projRoot)))
    expect_true(file.exists(libDir(projRoot)))
    expect_false(file.exists(file.path(lib, "breakfast")))
    expect_false(file.exists(file.path(lib, "bread")))
    expect_false(file.exists(file.path(lib, "oatmeal")))
    expect_true(file.exists(file.path(lib, "packrat")))
    expect_false(file.exists(file.path(lib, "toast")))
  })

  test_that("restore ignores dirty packages", {
    skip_on_cran()
    projRoot <- cloneTestProject("carbs")
    lib <- libDir(projRoot)
    init(projRoot, options = list(local.repos = "packages"), enter = FALSE)
    expect_true(file.exists(file.path(lib, "bread")))

    installTestPkg("oatmeal", "1.0.0", lib)
    expect_true(file.exists(file.path(lib, "oatmeal")))
    restore(projRoot, prompt = FALSE, restart = FALSE)
    expect_true(file.exists(file.path(lib, "oatmeal")))
  })

  test_that("restore installs missing packages", {
    skip_on_cran()
    projRoot <- cloneTestProject("carbs")
    lib <- libDir(projRoot)
    init(enter = FALSE, projRoot, options = list(local.repos = "packages"))
    expect_true(file.exists(file.path(lib, "bread")))

    # Remove a used package and restore
    remove.packages("bread", lib = lib)
    expect_false(file.exists(file.path(lib, "bread")))
    restore(projRoot, prompt = FALSE, restart = FALSE)
    expect_true(file.exists(file.path(lib, "bread")))
  })

  test_that("snapshot captures new dependencies", {
    skip_on_cran()
    skip_on_travis()
    skip_on_ci()
    projRoot <- cloneTestProject("healthy")
    lib <- libDir(projRoot)
    init(enter = FALSE, projRoot, options = list(local.repos = "packages"))

    # Simulate the addition of a dependency
    expect_false(file.exists(file.path(lib, "bread")))
    expect_false(file.exists(file.path(lib, "toast")))
    installTestPkg("bread", "1.0.0", lib)
    addTestDependency(projRoot, "toast")  # toast depends on bread
    expect_true(file.exists(file.path(lib, "bread")))

    # Snapshot the new state and make sure we picked up both toast and its
    # dependency, bread
    pkgs <- pkgNames(lockInfo(projRoot))
    msg <- paste0("pkgs: ", pkgs, collapse = ", ")
    expect_false("bread" %in% pkgs, msg)
    expect_false("toast" %in% pkgs, msg)
    snapshot(projRoot, ignore.stale = TRUE)
    pkgs <- pkgNames(lockInfo(projRoot))
    msg <- paste0("pkgs: ", pkgs, collapse = ", ")
    expect_true("bread" %in% pkgs, msg)
    expect_true("toast" %in% pkgs, msg)
  })

  test_that("snapshot captures only installed dependecies when infer.dependencies is FALSE", {
    skip_on_cran()
    skip_on_travis()
    skip_on_ci()
    projRoot <- cloneTestProject("healthy")
    lib <- libDir(projRoot)
    init(enter = FALSE, projRoot, options = list(local.repos = "packages"))

    # Simulate the addition of a dependency
    expect_false(file.exists(file.path(lib, "bread")))
    expect_false(file.exists(file.path(lib, "toast")))
    installTestPkg("bread", "1.0.0", lib)
    addTestDependency(projRoot, "toast")  # toast depends on bread
    expect_true(file.exists(file.path(lib, "bread")))

    # Snapshot the new state and make sure we picked up both toast and its
    # dependency, bread
    pkgs <- pkgNames(lockInfo(projRoot))
    msg <- paste0("pkgs: ", pkgs, collapse = ", ")
    expect_false("bread" %in% pkgs, msg)
    expect_false("toast" %in% pkgs, msg)
    snapshot(projRoot, infer.dependencies = FALSE, ignore.stale = TRUE)
    pkgs <- pkgNames(lockInfo(projRoot))
    msg <- paste0("pkgs: ", pkgs, collapse = ", ")
    expect_true("bread" %in% pkgs, msg)
    expect_false("toast" %in% pkgs, msg)
  })

  test_that("dependencies in library directories are ignored", {
    skip_on_cran()
    makeLibrariesProject()
    projRoot <- cloneTestProject("libraries")
    lib <- libDir(projRoot)
    init(enter = FALSE, projRoot, options = list(local.repos = "packages"))

    # This test project has a file called library.R that depends on bread, and
    # three .R files inside library/, library.old/, and library.new/ that
    # depend on oatmeal.
    expect_true(file.exists(file.path(lib, "bread")))
    expect_false(file.exists(file.path(lib, "oatmeal")))
  })

  test_that("dependencies in \"ignored.directories\" are ignored", {
    skip_on_cran()
    projRoot <- cloneTestProject("partlyignored")
    lib <- libDir(projRoot)
    init(enter = FALSE, projRoot, options = list(ignored.directories = "ignoreme"))

    # This test project has a file called notignored.R that depends on bread, and
    # another file called ignoreme/ignorethis.R that depends on toast.
    expect_true(file.exists(file.path(lib, "bread")))
    expect_false(file.exists(file.path(lib, "toast")))
  })

  test_that("clean removes libraries and sources", {
    skip_on_cran()
    projRoot <- cloneTestProject("smallbreakfast")
    lib <- libDir(projRoot)
    src <- srcDir(projRoot)
    init(enter = FALSE, projRoot, options = list(local.repos = "packages"))

    expect_true(file.exists(file.path(lib, "bread")))
    expect_true(file.exists(file.path(lib, "oatmeal")))
    expect_true(file.exists(file.path(src, "bread")))
    expect_true(file.exists(file.path(src, "oatmeal")))

    # Remove the dependency on oatmeal and clean
    removeTestDependencyFile(projRoot, "oatmeal.R")
    clean("oatmeal", project = projRoot)

    # bread should still be present, but we should have removed the orphaned
    # package oatmeal
    expect_true(file.exists(file.path(lib, "bread")))
    expect_false(file.exists(file.path(lib, "oatmeal")))
    expect_true(file.exists(file.path(src, "bread")))
  })

  test_that("init works with multiple repos", {
    skip_on_cran()

    repos <- getOption("repos")[1]
    op <- options(
      repos   = c(CRAN = repos, CUSTOM = repos),
      pkgType = "source"
    )

    on.exit(options(op), add = TRUE)

    projRoot <- cloneTestProject("empty")

    init(
      project = projRoot,
      options = list(local.repos = "packages"),
      enter = FALSE
    )

  })

  test_that("fileDependencies.R picks up '::', ':::' dependencies", {
    file <- tempfile()
    cat("library('baz')\nlibrary('bat')\nstringr::foo(1)\nKmisc::enumerate(2)\nfunction() {{plyr::bar(plyr::baz(1, 2))}}\n", file = file)
    on.exit(unlink(file))
    deps <- fileDependencies.R(file)
    expect_identical(
      intersect(deps, c("baz", "bat", "stringr", "Kmisc", "plyr")),
      union(deps, c("baz", "bat", "stringr", "Kmisc", "plyr"))
    )
  })

  test_that("init, disable handle projects that have been initted / disabled sensibly", {
    skip_on_cran()
    skip_on_os("windows")

    projRoot <- cloneTestProject("sated")
    packrat::init(enter = FALSE, projRoot, options = list(local.repos = "packages"))
    list.files(projRoot, all.files = TRUE, recursive = TRUE)
    expect_true(file.exists(file.path(projRoot, ".Rprofile")))
    packrat::disable(projRoot, restart = FALSE)
    expect_false(file.exists(file.path(projRoot, ".Rprofile")))

    unlink(projRoot, recursive = TRUE)

    projRoot <- cloneTestProject("sated")
    text <- "## Some comments\n## That should be preserved\n"
    cat(text, file = file.path(projRoot, ".Rprofile"))
    packrat::init(enter = FALSE, projRoot, options = list(local.repos = "packages"))
    list.files(projRoot, all.files = TRUE, recursive = TRUE)
    expect_true(file.exists(file.path(projRoot, ".Rprofile")))
    content <- readLines(file.path(projRoot, ".Rprofile"))
    expect_true(grepl(text, paste(content, collapse = "\n")))
    packrat::disable(projRoot, restart = FALSE)
    path <- file.path(projRoot, ".Rprofile")
    expect_true(file.exists(path))
    if (file.exists(path)) {
      content <- readChar(path, file.info(path)$size, TRUE)
      expect_true(grepl(text, paste(content, collapse = "\n")))
    }

    unlink(projRoot, recursive = TRUE)

    ## Empty .Rprofile
    projRoot <- cloneTestProject("sated")
    file.create(file.path(projRoot, ".Rprofile"))
    packrat::init(enter = FALSE, projRoot, options = list(local.repos = "packages"))
    expect_true(file.exists(file.path(projRoot, ".Rprofile")))
    content <- readLines(file.path(projRoot, ".Rprofile"))
    packrat::disable(projRoot, restart = FALSE)
    expect_false(file.exists(file.path(projRoot, ".Rprofile")))
  })

  test_that("status does not fail", {
    skip_on_cran()
    projRoot <- cloneTestProject("sated")
    init(enter = FALSE, projRoot, options = list(local.repos = "packages"))

    status(projRoot)
    unlink(file.path(projRoot, "packrat/lib/x86_64-apple-darwin13.3.0/3.2.0/bread"), recursive = TRUE)
    status(projRoot)
    unlink(file.path(projRoot, "packrat/lib/x86_64-apple-darwin13.3.0/3.2.0/breakfast"), recursive = TRUE)
    status(projRoot)

    # Try removing an item from the lockfile
    lf <- readLines(lockFilePath(projRoot))
    blanks <- which(lf == "")
    breakfastStart <- grep("Package:\\s*breakfast", lf)
    breakfastEnd <- sort(blanks[blanks > breakfastStart])[1]
    lf <- lf[-c(breakfastStart:breakfastEnd)]
    cat(lf, file = lockFilePath(projRoot), sep = "\n")
    status(projRoot)

  })

  test_that("hash does not fail if LinkingTo packages are not available", {
    skip_on_cran()
    expect_warning(hash("packages/egg/DESCRIPTION"))
  })

  test_that("snapshot succeeds with an empty DESCRIPTION", {
    skip_on_cran()
    projRoot <- cloneTestProject("emptydesc")
    .snapshotImpl(projRoot, implicit.packrat.dependency = FALSE,
                  snapshot.sources = FALSE)
  })

  test_that("Packages restored from GitLab have RemoteType+RemoteHost in their DESCRIPTION", {
    skip_on_cran()
    skip_on_os("windows") # Windows tar.exe fails to extract the archive received here.
    projRoot <- cloneTestProject("falsy-gitlab")

    # ignore R version warnings
    suppressWarnings(restore(projRoot))

    # validate the installed package has properly annotated DESCRIPTION
    descpath <- file.path(libDir(projRoot), "falsy/DESCRIPTION")
    desc <- as.data.frame(readDcf(descpath))
    expect_true(desc$RemoteType == "gitlab")
    expect_true(desc$RemoteHost == "gitlab.com")

    # confirm that packrat interprets this package as coming from gitlab.
    record <- inferPackageRecord(desc)
    expect_true(record$source == "gitlab")
  })

  test_that("Packages restored from BitBucket have RemoteType+RemoteHost in their DESCRIPTION", {
    skip_on_cran()
    projRoot <- cloneTestProject("falsy-bitbucket")

    # ignore R version warnings
    suppressWarnings(restore(projRoot))

    # validate the installed package has properly annotated DESCRIPTION
    descpath <- file.path(libDir(projRoot), "falsy/DESCRIPTION")
    desc <- as.data.frame(readDcf(descpath))
    expect_true(desc$RemoteType == "bitbucket")
    expect_true(desc$RemoteHost == "api.bitbucket.org/2.0")

    # confirm that packrat interprets this package as coming from bitbucket.
    record <- inferPackageRecord(desc)
    expect_true(record$source == "bitbucket")

    # confirm remote subdir is not in the record (unused by this lockfile)
    expect_false("remote_subdir" %in% names(record))
  })

  test_that("packrat and remotes annotated descriptions are comparable", {
    remotesDesc <- as.data.frame(readDcf("resources/descriptions/falsy.remotes"))
    remotesRecord <- inferPackageRecord(remotesDesc)
    packratDesc <- as.data.frame(readDcf("resources/descriptions/falsy.packrat"))
    packratRecord <- inferPackageRecord(packratDesc)
    diffed <- diff(list("falsy" = remotesRecord),
                   list("falsy" = packratRecord))
    expected <- c(
      structure(rep.int('remove', 0), names = c()),
      structure(rep.int('add', 0), names = c()),
      structure(c(NA), names = c("falsy")))
    expect_identical(diffed, expected)
  })
})

Try the packrat package in your browser

Any scripts or data that you put into this service are public.

packrat documentation built on Sept. 8, 2023, 5:44 p.m.