diff --git a/NEWS.md b/NEWS.md index 57e440f2..17a01502 100644 --- a/NEWS.md +++ b/NEWS.md @@ -34,6 +34,8 @@ strategy. (#353) - Increased minimum R version required to 4.0 to match {admiral}. (#382) +- `addin_format_testthat` addin has been moved to `{pharmaverse4devs}` package. (#419) + # admiraldev 1.0.0 diff --git a/R/addin_format_testthat.R b/R/addin_format_testthat.R deleted file mode 100644 index df6c5b0a..00000000 --- a/R/addin_format_testthat.R +++ /dev/null @@ -1,107 +0,0 @@ -# Returns the call for updating a given test_that test file -# by adding a function name, a test number, and a section. -# Call the function either by using RStudio Addin "format_test_that_file" or -# programmatically in a for loop on the test files and running -# rstudioapi::navigateToFile and format_test_that_file -prepare_test_that_file <- function(path) { - assert_character_scalar(path) - - # check that file exists - if (!file.exists(path)) { - stop("Invalid file path, the file does not exist.") - } - - # check that testthat is used and testing file is opened - uses_test_file <- grepl("tests/testthat/test-", path, fixed = TRUE) - if (!uses_test_file) { - stop("This Addin works only on unit test files that follow a testthat structure.") - } - - # parse the name of the testing function - testing_file <- sub("^test-", "", sub(".R$", "", basename(path))) - - # get file content - file_content <- readLines(path) - - # get locations of tests - match 'test_that("' strings - test_that_loc <- grep('^test_that\\("', file_content) - - if (length(test_that_loc) == 0) { - return(invisible(NULL)) - } - - #### - ## HANDLE test_that DESCRIPTIONS - #### - - # get and parse test descriptions - test_that_lines <- file_content[test_that_loc] - test_that_desc_parsed <- stringr::str_extract( - string = test_that_lines, - pattern = paste0( - '(?<=test_that\\(")', # positive look-ahead - search matching expression after test_that(" - ".*", # matching expression - match everything - '(?=")' # positive look-behind - search matching expression before " - ) - ) - test_that_desc_cleaned <- stringr::str_remove( - string = test_that_desc_parsed, - pattern = paste0("([\\w\\.]+,? )?[Tt]est \\d{1,} ?: ") - ) - - # determine name of function which is tested - # the function name can be specified by # function_name ---- comments - function_name <- str_match(file_content, "# ([\\w\\.]+) ----")[, 2] - if (is.na(function_name[1])) { - function_name[1] <- testing_file - } - function_name <- tidyr::fill(data.frame(name = function_name), name)$name - function_name <- function_name[test_that_loc] - - # formulate new test descriptions (update only those that don't include test_title) - new_desc <- paste0( - "Test ", seq_along(test_that_loc), ": ", - test_that_desc_cleaned - ) - - # insert new test descriptions into test_that lines - test_that_lines_updated <- stringr::str_replace( - string = test_that_lines, - pattern = '(?<=test_that\\(").*"', - replacement = paste0(function_name, " ", new_desc, '"') - ) - - # modify the file content - file_content[test_that_loc] <- test_that_lines_updated - - #### - ## HANDLE HEADERS - #### - - # formulate headers according to RStudio editor functionality - headers <- paste0("## ", new_desc, " ----") - - # get locations of headers created by this function - header_loc_lgl <- grepl(paste0("^##?( ----)?( \\w+)?,? [tT]est \\d{1,} ?: "), file_content) - - # remove those headers - file_content <- file_content[!header_loc_lgl] - - # add new headers just before test_that calls - header_loc <- grep('^test_that\\("', file_content) + seq_along(headers) - 1 - file_content_new <- vector(mode = "character", length = length(file_content) + length(headers)) - file_content_new[header_loc] <- headers - file_content_new[-header_loc] <- file_content - - list(file_content = file_content_new) -} - -# Function for the RStudio Addin, see inst/rstudio/addins.dcf. -# Wrapper of prepare_test_that_file. -format_test_that_file <- function() { - file_info <- rstudioapi::getActiveDocumentContext() - rstudioapi::documentSave(id = file_info$id) - result <- prepare_test_that_file(path = file_info$path) - rstudioapi::setDocumentContents(paste0(result$file_content, collapse = "\n"), id = file_info$id) - rstudioapi::documentSave(id = file_info$id) -} diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf deleted file mode 100644 index 41efae4d..00000000 --- a/inst/rstudio/addins.dcf +++ /dev/null @@ -1,4 +0,0 @@ -Name: Format test_that test file -Description: Updates current test_that test file by adding a function name, a test number, and a section -Binding: format_test_that_file -Interactive: false diff --git a/tests/testthat/test-addin_format_testthat.R b/tests/testthat/test-addin_format_testthat.R deleted file mode 100644 index f9e10498..00000000 --- a/tests/testthat/test-addin_format_testthat.R +++ /dev/null @@ -1,49 +0,0 @@ -## Test 1: works as expected ---- -test_that("addin_format_testthat Test 1: works as expected", { - # test: file exists - expect_error( - prepare_test_that_file("file_does_not_exist"), - "Invalid file path, the file does not exist." - ) - - # test: correct file is used - tf <- tempfile() - writeLines("Hello", tf) - expect_error( - prepare_test_that_file(tf), - "This Addin works only on unit test files that follow a testthat structure" - ) - - # test: test_that not found - dir.create(file.path(tempdir(), "tests", "testthat"), recursive = TRUE) - tf <- tempfile(pattern = "tests/testthat/test-") - writeLines("Hello", tf) - expect_null(prepare_test_that_file(tf)) - - # test: headers and descriptions works as expected on dummy file - tf <- tempfile(pattern = "tests/testthat/test-") - writeLines( - c( - "# some stuff in comment", - 'test_that("my description", {', - " expect_true(TRUE)", - "}" - ), - tf - ) - expected <- list( - file_content = c( - "# some stuff in comment", - paste0( - "## Test 1: my description ----" - ), - paste0( - 'test_that("', sub("test-", "", basename(tf)), " ", - 'Test 1: my description", {' - ), - " expect_true(TRUE)", - "}" - ) - ) - expect_identical(prepare_test_that_file(tf), expected) -}) diff --git a/vignettes/admiraldev.Rmd b/vignettes/admiraldev.Rmd index fbbb88d4..06971ddf 100644 --- a/vignettes/admiraldev.Rmd +++ b/vignettes/admiraldev.Rmd @@ -24,7 +24,7 @@ Tools are loosely defined as follows: * Utility Functions used in `{admiral}` and `{admiral}` extension functions for doing custom checks and providing custom messages, warnings and errors. These custom messages, warnings and errors are succinct, but helpful messaging around what a function expects as inputs. The inputs to admiral functions are many, but generally fit into three categories: datasets, variables and arguments. Most of the functions start with `assert_`, `is_` or `get_`. -* Addins and utility functions that help with documentation, testing and checking on health of the code base in all admiral packages. +* Utility functions that help with documentation, testing and checking on health of the code base in all admiral packages. * Vignettes on working on `{admiral}` functions, developing unit testing, releases process, vignette writing and other documentation needs. These vignettes are intended for use across all admiral packages. diff --git a/vignettes/unit_test_format_tests.png b/vignettes/unit_test_format_tests.png old mode 100755 new mode 100644 index 8d2c4336..e1b4f179 Binary files a/vignettes/unit_test_format_tests.png and b/vignettes/unit_test_format_tests.png differ diff --git a/vignettes/unit_test_guidance.Rmd b/vignettes/unit_test_guidance.Rmd index 59a09f46..7770319a 100644 --- a/vignettes/unit_test_guidance.Rmd +++ b/vignettes/unit_test_guidance.Rmd @@ -211,9 +211,21 @@ knitr::include_graphics("./unit_test_toc.png") ``` -## Addin `admiraldev::format_test_that_file()` +## Addin `pharmaverse4devs::format_test_that_file()` -To ease the burden on developers for writing and adding tests we have developed an Addin for formatting test_that test files according to admiral programming standards. The Addin will add and update comments as well as number or re-numbers the tests. Just use the Addin button and select the "Format +To ease the burden on developers for writing and adding tests we have developed an Addin for formatting test_that test files according to admiral programming standards. The Addin will add and update comments as well as number or re-numbers the tests. To access the Addin, be sure to install the {pharmaverse4devs} from Github. + +To install the latest development version of the package directly from +GitHub use the following code: +```r + if (!requireNamespace("remotes", quietly = TRUE)) { + install.packages("remotes") + } + + remotes::install_github("pharmaverse/pharmaverse4devs") +``` + +Then use the Addin button and select the "Format test_that test file" as seen in the image. Be sure to have the test-file open and selected when calling the Addin. ```{r echo=FALSE, out.width='120%'} @@ -237,12 +249,12 @@ prefix and the ".R" suffix. When writing new unit tests, just provide a description in the `test_that()` call and if necessary the function name in a `# ----` comment: ``` -# arg_name ---- -test_that("arg_name works", { - expect_equal(arg_name(sym("a")), "a") - expect_equal(arg_name(call("enquo", sym("a"))), "a") - expect_error(arg_name("a"), "Could not extract argument name from") -}) +# derive_vars_merged ---- +test_that( "works if it merges all variables", { + actual <- derive_vars_merged(advs, + dataset_add = adsl, + by_vars = exprs(STUDYID, USUBJID) + ) # convert_dtm_to_dtc ---- test_that("works if dtm is in correct format", { @@ -263,13 +275,13 @@ test_that("Error is thrown if dtm is not in correct format", { Call the addin and get: ``` -# arg_name ---- -## Test 1: arg_name works ---- -test_that("arg_name Test 1: arg_name works", { - expect_equal(arg_name(sym("a")), "a") - expect_equal(arg_name(call("enquo", sym("a"))), "a") - expect_error(arg_name("a"), "Could not extract argument name from") -}) +# derive_vars_merged ---- +## Test 1: derive_vars_merged ---- +test_that( "derive_vars_merged Test 1: it merges all variables", { + actual <- derive_vars_merged(advs, + dataset_add = adsl, + by_vars = exprs(STUDYID, USUBJID) + ) # convert_dtm_to_dtc ---- ## Test 2: works if dtm is in correct format ----