diff --git a/DESCRIPTION b/DESCRIPTION index ffb3e86..1535afc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: box.linters Title: Linters for 'box' Modules -Version: 0.9.0.9005 +Version: 0.9.0.9006 Authors@R: c( person("Ricardo Rodrigo", "Basa", role = c("aut", "cre"), email = "opensource+rodrigo@appsilon.com"), diff --git a/NEWS.md b/NEWS.md index 546d921..ad42bfe 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # box.linters (development version) +* Handle `box` recommended method of testing private methods. * Added handler for `glue` string templates. * Added box_mod_fun_exists_linter() to default linters * [bug fix] box_trailing_commas_linter() now properly handles a #nolint for other linters diff --git a/R/box_unused_attached_mod_linter.R b/R/box_unused_attached_mod_linter.R index 903d0ce..615eab8 100644 --- a/R/box_unused_attached_mod_linter.R +++ b/R/box_unused_attached_mod_linter.R @@ -83,6 +83,7 @@ box_unused_attached_mod_linter <- function() { attached_three_dots <- get_attached_mod_three_dots(xml) function_calls <- get_function_calls(xml) glue_object_calls <- get_objects_in_strings(xml) + possible_module_calls <- get_object_calls(xml) all_calls_text <- c(function_calls$text, glue_object_calls) @@ -97,8 +98,9 @@ box_unused_attached_mod_linter <- function() { ) functions_used <- length(intersect(func_list, all_calls_text)) + modules_used <- length(intersect(aliased_module_text, possible_module_calls$text)) - if (functions_used == 0) { + if (functions_used == 0 && modules_used == 0) { lintr::xml_nodes_to_lints( attached_module, source_expression = source_expression, diff --git a/tests/testthat/test-box_unused_attached_mod_linter.R b/tests/testthat/test-box_unused_attached_mod_linter.R index 738662c..f9f14e9 100644 --- a/tests/testthat/test-box_unused_attached_mod_linter.R +++ b/tests/testthat/test-box_unused_attached_mod_linter.R @@ -269,3 +269,41 @@ test_that("box_unused_attached_mod_linter blocks unused objects in glue string t lintr::expect_lint(bad_box_usage, list(message = lint_message), linters = linter) }) + + +# Box test interfaces, not implementations + +test_that("box_unused_attached_mod_linter skips module call as implementation test", { + linter <- box_unused_attached_mod_linter() + + code <- "box::use( + path/to/module_a, + ) + + impl = attr(module_a, \"namespace\") + + test_that(\"implementation detail X works\", { + expect_true(impl$a_fun_c()) + }) + " + + lintr::expect_lint(code, NULL, linter = linter) +}) + +test_that("box_unused_attached_mod_linter blocks unused module call as implementation test", { + linter <- box_unused_attached_mod_linter() + lint_message <- rex::rex("Attached module unused.") + + code <- "box::use( + path/to/module_a, + ) + + impl = attr(module_b, \"namespace\") + + test_that(\"implementation detail X works\", { + expect_true(impl$a_fun_c()) + }) + " + + lintr::expect_lint(code, list(message = lint_message), linter = linter) +}) diff --git a/tests/testthat/test-e2e_testthat.R b/tests/testthat/test-e2e_testthat.R new file mode 100644 index 0000000..472235e --- /dev/null +++ b/tests/testthat/test-e2e_testthat.R @@ -0,0 +1,24 @@ +options(box.path = file.path(getwd(), "mod")) + +test_that("all linters skip valid box test for interface", { + linters <- lintr::linters_with_defaults( + defaults = box.linters::rhino_default_linters + ) + + code <- " +box::use( + testthat[expect_true, test_that], +) + +box::use( + path/to/module_a, +) + +impl <- attr(module_a, \"namespace\") + +test_that(\"implementation detail X works\", { + expect_true(impl$this_works()) +})" + + lintr::expect_lint(code, NULL, linters = linters) +})