--- title: "Introduction" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{introduction} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(roxytest) ``` ```{r, include = FALSE} knitr::knit_engines$set(roxy = function(options) { code <- paste(options$code, collapse = '\n') code <- paste0( "# ----------------------------------------------------\n", "# The code example below....\n", "# ----------------------------------------------------\n", "\n", code ) #out <- knitr::knit_child(text = options$code) out <- roxygen2::roc_proc_text(testthat_roclet(), code) out <- unlist(lapply(out, function(l) l[[""]])) out <- paste0(out, collapse = "\n") #out <- out$tests[[""]] out <- paste0( "\n", "# ----------------------------------------------------\n", "# ...will result in a generated file in tests/ folder:\n", "# ----------------------------------------------------\n", "\n", out) # To get syntax highlight options$engine <- "r" options$comment <- NA knitr::engine_output(options, code, out) }) ``` There are a number of roclets included: * `testthat_roclet`: Write [`testthat`](https://testthat.r-lib.org/) tests in the [`roxygen2`](https://roxygen2.r-lib.org/) documentation + `@tests`: Generate test skeletons + `@testexamples`: Generate test skeletons with `@examples` included first such that e.g. variables can be reused * `tinytest_roclet`: Write [`tinytest`](https://cran.r-project.org/package=tinytest) tests in the [`roxygen2`](https://roxygen2.r-lib.org/) documentation + `@tests`: Generate test skeletons + `@testexamples`: Generate test skeletons with `@examples` included first such that e.g. variables can be reused * `param_roclet`: Checks for consistency in documentation of parameters (too many/too few) * `return_roclet`: Checks if `@export`ed functions has `@return` documentation (possibly just `@return None`) * `examples_roclet`: Checks if `@export`ed functions has `@examples` documentation To use the package in your own package you do not need to add any additional dependencies in your package's `DESCRIPTION` file apart from the usual `Suggests: testthat` that is required for testing with `testthat` or the `Suggests: tinytest` that is required for testing with `tinytest`. (If you only use `param_roclet`, `return_roclet` or `examples_roclet` you do not need to add anything to `Suggests`.) ``` Suggests: testthat # or tinytest ``` However, any developer working on your package needs to have `roxytest` installed to be able to successfully run `roxygen2::roxygenise()` (or `devtools::document()`). For this reason you may consider adding `roxytest` to `Suggests`, but this is not required. ### `testthat` roclet Add the following lines to your package's `DESCRIPTION` file (along with `Suggests: testthat`): ``` Roxygen: list(roclets = c("namespace", "rd", "roxytest::testthat_roclet")) ``` (Or make appropriate changes to obtain similar results.) Then run the following: ```r roxygen2::roxygenise() ``` Similarly for the other roclets. ### Multiple roclets You can of course also add multiple, e.g.: ``` Roxygen: list(roclets = c("namespace", "rd", "roxytest::testthat_roclet", "roxytest::param_roclet", "roxytest::return_roclet")) ``` (Or make appropriate changes to obtain similar results.) Then run the following: ```r roxygen2::roxygenise() ``` ## Examples Below we show based on `testthat`, but it is the same for `tinytest` except the output which then happens at `inst/tinytest` without `contest()` and `testthat()` boilerplate. ### `testthat` roclet As mentioned above, there are two tags available: * `@tests`: Generate test skeletons * `@testexamples`: Generate test skeletons with `@examples` included first such that e.g. variables can be reused Note that both can be used at the same time. We first demonstrate `@tests` and afterwards `@testexamples`. #### `@tests` tag For example, if the file `R/functions.R` contains this code (from [roxytestdemo](https://github.com/mikldk/roxytestdemo)): ```r #' A function to do x #' #' @param x A number #' #' @tests #' expect_equal(foo(2), sqrt(2)) #' expect_error(foo("a string")) #' #' @return something foo <- function(x) { return(sqrt(x)) } #' A function to do y #' #' @param x Character vector #' @param y Character vector #' #' @tests #' expect_equal(bar("A", "B"), paste("A", "B", sep = "/")) #' #' @export bar <- function(x, y) { paste0(x, "/", y) } ``` Then `roxygen2::roxygenise()` will generate (with the `testthat_roclet` roclet) the file `tests/testthat/test-roxytest-tests-functions.R` with this content: ```r # Generated by roxytest: Do not edit by hand! context("File R/functions.R: @tests") test_that("Function foo() @ L10", { expect_equal(foo(2), sqrt(2)) expect_error(foo("a string")) }) test_that("Function bar() @ L23", { expect_equal(bar("A", "B"), paste("A", "B", sep = "/")) }) ``` #### `@testexamples` tag For example, if the file `R/functions.R` contains this code (from [roxytestdemo](https://github.com/mikldk/roxytestdemo)): ```r #' A function to do w #' #' @param x A number #' #' @examples #' x <- 2 #' foo(x) #' #' @testexamples #' expect_equal(foo(x), foo(2)) #' #' @return something foo2 <- function(x) { return(sqrt(x)) } ``` Then `roxygen2::roxygenise()` will generate (with the `testthat_roclet` roclet) the file `tests/testthat/test-roxytest-testexamples-functions.R` with this content: ```r # Generated by roxytest: Do not edit by hand! context("File R/functions.R: @testexamples") test_that("Function foo2() @ L13", { x <- 2 foo(x) expect_equal(foo(x), foo(2)) }) ``` Note that: * `\dontrun`: Everything including content is removed * `\donttest`: Only the tag itself is removed * `\dontshow`: Only the tag itself is removed ### `param` roclet To demonstrate the `param_roclet` roclet assume that this block of documentation exists: ```r #' Summing two numbers #' #' @param x A number foobar <- function(x, y) { x + y } ``` When the package is documented, the following output will be displayed: ``` Functions with @param inconsistency: * Function 'foobar' with title 'Summing two numbers': - Missing @param's: y ``` Similarly if there are too many documented arguments. ### `return` roclet To demonstrate the `return_roclet` roclet assume that this block of documentation exists: ```r #' Summing two numbers #' #' @param x A number #' #' @export foobar2 <- function(x, y) { x + y } ``` When the package is documented, the following output will be displayed: ``` Functions with @export but no @return: * Function 'foobar2()' with title 'Summing two numbers' ``` ### `examples` roclet To demonstrate the `examples_roclet` roclet assume that this block of documentation exists: ```r #' Summing two numbers #' #' @param x A number #' #' @export foobar2 <- function(x, y) { x + y } ``` When the package is documented, the following output will be displayed: ``` Functions with @export but no @example(s): * Function 'foobar2()' with title 'Summing two numbers' ```