# Fixtures fixtures <- list() fixtures$retrieve_lint <- function() { file_name <- "R/test.R" lines <- c("foobar1", "foobar2", "foobar3") lints <- list( Lint(file_name, 1L, line = "foobar1"), Lint(file_name, 2L, line = "foobar2"), Lint(file_name, 3L, line = "foobar3") ) expr <- list(content = paste(collapse = "\n", lines)) list( lines = lines, linters = list(), lints = lints, expr = expr ) } # Run tests with a temporary cache directory, so we don't leave files behind # after running withr::local_options(lintr.cache_directory = withr::local_tempdir()) # Helper functions fhash <- function(filename) { digest::digest(filename, algo = "sha1") } # Tests # `clear_cache` test_that("clear_cache deletes the file if a file is given", { skip_if_not_installed("mockery") mockery::stub(clear_cache, "read_settings", function(...) invisible(...)) mockery::stub(clear_cache, "unlink", function(...) list(...)) e1 <- new.env(parent = emptyenv()) d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) want <- list(file.path(d1, fhash("R/test.R")), recursive = TRUE) expect_identical(clear_cache(f1, d1), want) expect_identical(clear_cache(file = f1, path = d1), want) }) test_that("clear_cache deletes the directory if no file is given", { skip_if_not_installed("mockery") mockery::stub(clear_cache, "read_settings", function(...) invisible(...)) mockery::stub(clear_cache, "unlink", function(...) list(...)) expect_identical(clear_cache(file = NULL, path = "."), list(".", recursive = TRUE)) }) # `load_cache` test_that("load_cache loads the saved file in a new empty environment", { e1 <- new.env(parent = emptyenv()) e1[["x"]] <- "foobar" d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) e2 <- lintr:::load_cache(file = f1, path = d1) expect_identical(e2, e1) }) test_that("load_cache returns an empty environment if no cache file exists", { e1 <- new.env(parent = emptyenv()) d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" f2 <- "test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) e2 <- lintr:::load_cache(file = f2, path = d1) expect_identical(e2, e1) }) test_that("load_cache returns an empty environment if reading cache file fails", { e1 <- new.env(parent = emptyenv()) e1[["x"]] <- "foobar" d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) cache_f1 <- file.path(d1, fhash(f1)) writeLines(character(), cache_f1) expect_warning( { e2 <- lintr:::load_cache(file = f1, path = d1) }, "Could not load cache file" ) saveRDS(e1, cache_f1) expect_warning( { e3 <- lintr:::load_cache(file = f1, path = d1) }, "Could not load cache file" ) expect_identical(ls(e2), character()) expect_identical(ls(e3), character()) }) # `save_cache` test_that("save_cache creates a directory if needed", { e1 <- new.env(parent = emptyenv()) d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" expect_false(file.exists(d1)) expect_false(file.exists(file.path(d1, fhash(f1)))) lintr:::save_cache(cache = e1, file = f1, path = d1) expect_true(file.exists(d1)) expect_true(file.info(d1)$isdir) expect_true(file.exists(file.path(d1, fhash(f1)))) }) test_that("save_cache uses unambiguous cache file names", { e1 <- new.env(parent = emptyenv()) d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" f2 <- "test.R" expect_false(file.exists(file.path(d1, fhash(f1)))) expect_false(file.exists(file.path(d1, fhash(f2)))) lintr:::save_cache(cache = e1, file = f1, path = d1) lintr:::save_cache(cache = e1, file = f2, path = d1) expect_true(fhash(f1) != fhash(f2)) expect_true(file.exists(file.path(d1, fhash(f1)))) expect_true(file.exists(file.path(d1, fhash(f2)))) }) test_that("save_cache saves all non-hidden objects from the environment", { e1 <- new.env(parent = emptyenv()) e1$t1 <- 1L e1$t2 <- 2L d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) e2 <- new.env(parent = emptyenv()) load(file = file.path(d1, fhash(f1)), envir = e2) expect_identical(e2, e1) }) # `cache_file` test_that("cache_file generates the same cache with different lints", { e1 <- new.env(parent = emptyenv()) f1 <- withr::local_tempfile(lines = "foobar") lintr:::cache_file(e1, f1, list(), list()) lintr:::cache_file(e1, f1, list(), list(1L)) expect_length(ls(e1), 1L) }) test_that("cache_file generates different caches for different linters", { e1 <- new.env(parent = emptyenv()) f1 <- withr::local_tempfile(lines = "foobar") lintr:::cache_file(e1, f1, list(), list()) lintr:::cache_file(e1, f1, list(1L), list()) expect_length(ls(e1), 2L) }) # `retrieve_file` test_that("retrieve_file returns NULL if there is no cached result", { e1 <- new.env(parent = emptyenv()) f1 <- withr::local_tempfile(lines = "foobar") expect_null(lintr:::retrieve_file(e1, f1, list())) }) test_that("retrieve_file returns the cached result if found", { e1 <- new.env(parent = emptyenv()) f1 <- withr::local_tempfile(lines = "foobar") lintr:::cache_file(e1, f1, list(), list("foobar")) expect_identical(lintr:::retrieve_file(e1, f1, list()), list("foobar")) }) # `cache_lint` test_that("cache_lint generates the same cache with different lints", { e1 <- new.env(parent = emptyenv()) t1 <- list(content = "test") lintr:::cache_lint(e1, t1, list(), list()) lintr:::cache_lint(e1, t1, list(), list(1L)) expect_length(ls(e1), 1L) }) test_that("cache_lint generates different caches for different linters", { e1 <- new.env(parent = emptyenv()) t1 <- list(content = "test") lintr:::cache_lint(e1, t1, list(), list()) lintr:::cache_lint(e1, t1, list(1L), list()) expect_length(ls(e1), 2L) }) # `retrieve_lint` test_that("retrieve_lint returns the same lints if nothing has changed", { test_data <- fixtures$retrieve_lint() e1 <- new.env(parent = emptyenv()) lintr:::cache_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lints = test_data[["lints"]] ) t1 <- lintr:::retrieve_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lines = test_data[["lines"]] ) expect_identical(t1, test_data[["lints"]]) }) test_that( "retrieve_lint returns the same lints with fixed line numbers if lines added above", { test_data <- fixtures$retrieve_lint() e1 <- new.env(parent = emptyenv()) lines1 <- test_data[["lines"]] lines2 <- c("", lines1) lints <- test_data[["lints"]] lintr:::cache_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lints = lints ) t1 <- lintr:::retrieve_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lines = lines2 ) expect_identical(t1[[1L]]$line_number, lints[[1L]]$line_number + 1L) expect_identical(t1[[2L]]$line_number, lints[[2L]]$line_number + 1L) expect_identical(t1[[3L]]$line_number, lints[[3L]]$line_number + 1L) } ) test_that("retrieve_lint returns the same lints with lines added below", { test_data <- fixtures$retrieve_lint() e1 <- new.env(parent = emptyenv()) lines1 <- test_data[["lines"]] lines2 <- c(lines1, "") lintr:::cache_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lints = test_data[["lints"]] ) t1 <- lintr:::retrieve_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lines = lines2 ) expect_identical(t1, test_data[["lints"]]) }) test_that( "retrieve_lint returns the same lints with fixed line numbers if lines added between", { test_data <- fixtures$retrieve_lint() e1 <- new.env(parent = emptyenv()) lines1 <- test_data[["lines"]] lines2 <- c(lines1[1L], "", lines1[2L:3L], "") lints1 <- test_data[["lints"]] lintr:::cache_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lints = lints1 ) t1 <- lintr:::retrieve_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lines = lines2 ) expect_identical(t1[[1L]]$line_number, lints1[[1L]]$line_number) expect_identical(t1[[2L]]$line_number, lints1[[2L]]$line_number + 1L) expect_identical(t1[[3L]]$line_number, lints1[[3L]]$line_number + 1L) } ) # `has_lint` test_that("has_lint returns FALSE if there is no cached result", { e1 <- new.env(parent = emptyenv()) t1 <- list(content = "foobar") expect_false(lintr:::has_lint(e1, t1, list())) }) test_that("has_lint returns TRUE if there is a cached result", { e1 <- new.env(parent = emptyenv()) t1 <- list(content = "foobar") lintr:::cache_lint(e1, t1, list(), list()) expect_true(lintr:::has_lint(e1, t1, list())) }) test_that("has_lint distinguishes global expressions from line expression with same content", { e1 <- new.env(parent = emptyenv()) same_content <- "foobar" line_expr <- list(content = same_content, parsed_content = data.frame()) lintr:::cache_lint(e1, line_expr, list(), list()) global_expr <- list(content = same_content, file_lines = character()) expect_false(lintr:::has_lint(e1, global_expr, list())) }) # `find_new_line` test_that("find_new_line returns the same if the line is the same", { t1 <- c( "foobar1", "foobar2", "foobar3" ) expect_identical(lintr:::find_new_line(1L, "foobar1", t1), 1L) expect_identical(lintr:::find_new_line(2L, "foobar2", t1), 2L) expect_identical(lintr:::find_new_line(3L, "foobar3", t1), 3L) }) test_that("find_new_line returns the correct line if it is before the current line", { t1 <- c( "foobar1", "foobar2", "foobar3" ) expect_identical(lintr:::find_new_line(1L, "foobar1", t1), 1L) expect_identical(lintr:::find_new_line(2L, "foobar1", t1), 1L) expect_identical(lintr:::find_new_line(3L, "foobar1", t1), 1L) }) test_that("find_new_line returns the correct line if it is after the current line", { t1 <- c( "foobar1", "foobar2", "foobar3" ) expect_identical(lintr:::find_new_line(1L, "foobar3", t1), 3L) expect_identical(lintr:::find_new_line(2L, "foobar3", t1), 3L) expect_identical(lintr:::find_new_line(3L, "foobar3", t1), 3L) }) # test_that("lint with cache uses the provided relative cache directory", { path <- withr::local_tempdir("my_cache_dir") linter <- assignment_linter() # create the cache expect_lint("a <- 1", NULL, linter, cache = path) expect_true(dir.exists(path)) expect_length(list.files(file.path(path)), 1L) # read the cache expect_lint("a <- 1", NULL, linter, cache = path) expect_true(dir.exists(path)) }) test_that("it works outside of a package", { skip_if_not_installed("mockery") linter <- assignment_linter() mockery::stub(lintr:::find_default_encoding, "find_package", function(...) NULL) path <- withr::local_tempfile(pattern = "my_cache_dir_") expect_false(dir.exists(path)) expect_lint("a <- 1", NULL, linter, cache = path) expect_true(dir.exists(path)) expect_length(list.files(path), 1L) expect_lint("a <- 1", NULL, linter, cache = path) expect_true(dir.exists(path)) }) test_that("cache = TRUE workflow works", { # Need a test structure with a safe to load .lintr pkg <- "dummy_packages/package" files <- normalizePath(list.files(pkg, recursive = TRUE, full.names = TRUE)) # Manually clear cache (that function is exported) for (f in files) { clear_cache(file = f) } l1 <- lint_package(pkg, cache = TRUE) l2 <- lint_package(pkg, cache = TRUE) expect_identical(l1, l2) }) test_that("cache = TRUE works with nolint", { linters <- list(infix_spaces_linter()) file <- withr::local_tempfile() writeLines("1+1\n", file) expect_length(lint(file, linters, cache = TRUE), 1L) writeLines("1+1 # nolint\n", file) expect_length(lint(file, linters, cache = TRUE), 0L) writeLines("1+1\n", file) expect_length(lint(file, linters, cache = TRUE), 1L) writeLines("1+1 # nolint\n", file) expect_length(lint(file, linters, cache = TRUE), 0L) })