diff --git a/DESCRIPTION b/DESCRIPTION index a0194c5..c79a752 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -27,4 +27,4 @@ Suggests: Config/testthat/edition: 3 Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.2 diff --git a/R/create_pipework.R b/R/create_pipework.R index 35931ab..d010ee6 100644 --- a/R/create_pipework.R +++ b/R/create_pipework.R @@ -1,5 +1,5 @@ -#' Create a {mariobox} project to package a {plumber} API +#' Create a 'mariobox' project to package a 'plumber' API #' #' This function will create a prepopulated package #' with all the necessary elements to publish a {plumber} API as a package. @@ -8,7 +8,7 @@ #' the package in. The folder name will also be used as the package name. #' @param open A logical. Should the new project be open? #' @param overwrite A logical. Should the already existing project be overwritten ? -#' @param package_name Package name to use. By default, {mariobox} uses +#' @param package_name Package name to use. By default, 'mariobox' uses #' `basename(path)`. If `path == '.'` & `package_name` is not explicitly set, #' then `basename(getwd())` will be used. #' @@ -36,11 +36,6 @@ create_mariobox <- function( overwrite = FALSE, package_name = basename(path) ) { - # if (check_name) { - # cat_rule("Checking package name") - # getFromNamespace("check_package_name", "usethis")(package_name) - # cat_green_tick("Valid package name") - # } if (dir.exists(path)) { if (!isTRUE(overwrite)) { @@ -58,43 +53,17 @@ create_mariobox <- function( } } else { cat_rule("Creating dir") - usethis::create_project( - path = path, - open = FALSE, + fs::dir_create( + path = path ) cat_green_tick("Created package directory") } cat_rule("Copying package skeleton") - marioboxexample_path <- mariobox_sys("marioboxexample") - dir_copy( - path = marioboxexample_path, - new_path = path, - overwrite = TRUE + copy_empty_mariobox( + path, + package_name ) - # Listing copied files ***from source directory*** - copied_files <- list.files( - path = marioboxexample_path, - full.names = FALSE, - all.files = TRUE, - recursive = TRUE - ) - # Going through copied files to replace package name - for (file in copied_files) { - copied_file <- file.path(path, file) - if (grepl("^REMOVEME", file)) { - file.rename( - from = copied_file, - to = file.path(path, gsub("REMOVEME", "", file)) - ) - copied_file <- file.path(path, gsub("REMOVEME", "", file)) - } - replace_word( - file = copied_file, - pattern = "marioboxexample", - replace = package_name - ) - } cat_green_tick("Copied app skeleton") cat_rule("Done") @@ -123,3 +92,37 @@ create_mariobox <- function( ) ) } + + +copy_empty_mariobox <- function(path, package_name){ + marioboxexample_path <- mariobox_sys("marioboxexample") + dir_copy( + path = marioboxexample_path, + new_path = path, + overwrite = TRUE + ) + # Listing copied files ***from source directory*** + copied_files <- list.files( + path = marioboxexample_path, + full.names = FALSE, + all.files = TRUE, + recursive = TRUE + ) + # Going through copied files to replace package name + for (file in copied_files) { + copied_file <- file.path(path, file) + if (grepl("^REMOVEME", file)) { + file.rename( + from = copied_file, + to = file.path(path, gsub("REMOVEME", "", file)) + ) + copied_file <- file.path(path, gsub("REMOVEME", "", file)) + } + replace_word( + file = copied_file, + pattern = "marioboxexample", + replace = package_name + ) + } + return(path) +} \ No newline at end of file diff --git a/R/http_error.R b/R/http_error.R index ad27ce6..c49a490 100644 --- a/R/http_error.R +++ b/R/http_error.R @@ -2,35 +2,35 @@ #' #' @noRd http_error_codes <- structure( - list(category = c("Client Error", "Client Error", "Client Error", - "Client Error", "Client Error", "Client Error", "Client Error", - "Client Error", "Client Error", "Client Error", "Client Error", - "Client Error", "Client Error", "Client Error", "Client Error", - "Client Error", "Client Error", "Client Error", "Client Error", - "Client Error", "Client Error", "Client Error", "Client Error", - "Client Error", "Client Error", "Client Error", "Client Error", - "Client Error", "Client Error", "Server Error", "Server Error", - "Server Error", "Server Error", "Server Error", "Server Error", - "Server Error", "Server Error", "Server Error", "Server Error", - "Server Error"), status = c(400L, 401L, 402L, 403L, 404L, 405L, - 406L, 407L, 408L, 409L, 410L, 411L, 412L, 413L, 414L, 415L, 416L, - 417L, 418L, 421L, 422L, 423L, 424L, 425L, 426L, 428L, 429L, 431L, - 451L, 500L, 501L, 502L, 503L, 504L, 505L, 506L, 507L, 508L, 510L, - 511L), message = c("Bad Request", "Unauthorized", "Payment Required", - "Forbidden", "Not Found", "Method Not Allowed", "Not Acceptable", - "Proxy Authentication Required", "Request Timeout", "Conflict", - "Gone", "Length Required", "Precondition Failed", "Payload Too Large", - "URI Too Long", "Unsupported Media Type", "Range Not Satisfiable", - "Expectation Failed", "I'm a teapot", "Misdirected Request", - "Unprocessable Entity", "Locked", "Failed Dependency", "Too Early", - "Upgrade Required", "Precondition Required", "Too Many Requests", - "Request Header Fields Too Large", "Unavailable For Legal Reasons", - "Internal Server Error", "Not Implemented", "Bad Gateway", "Service Unavailable", - "Gateway Timeout", "HTTP Version Not Supported", "Variant Also Negotiates", + list(category = c("Client Error", "Client Error", "Client Error", + "Client Error", "Client Error", "Client Error", "Client Error", + "Client Error", "Client Error", "Client Error", "Client Error", + "Client Error", "Client Error", "Client Error", "Client Error", + "Client Error", "Client Error", "Client Error", "Client Error", + "Client Error", "Client Error", "Client Error", "Client Error", + "Client Error", "Client Error", "Client Error", "Client Error", + "Client Error", "Client Error", "Server Error", "Server Error", + "Server Error", "Server Error", "Server Error", "Server Error", + "Server Error", "Server Error", "Server Error", "Server Error", + "Server Error"), status = c(400L, 401L, 402L, 403L, 404L, 405L, + 406L, 407L, 408L, 409L, 410L, 411L, 412L, 413L, 414L, 415L, 416L, + 417L, 418L, 421L, 422L, 423L, 424L, 425L, 426L, 428L, 429L, 431L, + 451L, 500L, 501L, 502L, 503L, 504L, 505L, 506L, 507L, 508L, 510L, + 511L), message = c("Bad Request", "Unauthorized", "Payment Required", + "Forbidden", "Not Found", "Method Not Allowed", "Not Acceptable", + "Proxy Authentication Required", "Request Timeout", "Conflict", + "Gone", "Length Required", "Precondition Failed", "Payload Too Large", + "URI Too Long", "Unsupported Media Type", "Range Not Satisfiable", + "Expectation Failed", "I'm a teapot", "Misdirected Request", + "Unprocessable Entity", "Locked", "Failed Dependency", "Too Early", + "Upgrade Required", "Precondition Required", "Too Many Requests", + "Request Header Fields Too Large", "Unavailable For Legal Reasons", + "Internal Server Error", "Not Implemented", "Bad Gateway", "Service Unavailable", + "Gateway Timeout", "HTTP Version Not Supported", "Variant Also Negotiates", "Insufficient Storage", "Loop Detected", "Not Extended", "Network Authentication Required" - )), row.names = c(400L, 401L, 402L, 403L, 404L, 405L, 406L, 407L, - 408L, 409L, 410L, 411L, 412L, 413L, 414L, 415L, 416L, 417L, 418L, - 421L, 422L, 423L, 424L, 425L, 426L, 428L, 429L, 431L, 451L, 500L, + )), row.names = c(400L, 401L, 402L, 403L, 404L, 405L, 406L, 407L, + 408L, 409L, 410L, 411L, 412L, 413L, 414L, 415L, 416L, 417L, 418L, + 421L, 422L, 423L, 424L, 425L, 426L, 428L, 429L, 431L, 451L, 500L, 501L, 502L, 503L, 504L, 505L, 506L, 507L, 508L, 510L, 511L), class = "data.frame") #' Produce HTTP errors @@ -40,7 +40,7 @@ http_error_codes <- structure( #' #' @param status Integer, HTTP status code for the error (4xx or 5xx). #' @param message Character, the error message (can be a vector). -#' +#' #' @return A condition object of class `"http_error"`. #' #' @export @@ -48,13 +48,13 @@ http_error_codes <- structure( #' @examples #' ## R's default error #' str(attr(try(stop("Hey, stop!")), "condition")) -#' +#' #' ## default status code 500 with default error message #' str(attr(try(http_error()), "condition")) -#' +#' #' ## custom status code with default error message #' str(attr(try(http_error(501L)), "condition")) -#' +#' #' ## custom status code for client error #' str(attr(try(http_error(400L, "Provide valid email address.")), "condition")) #' @@ -71,16 +71,16 @@ http_error <- function(status = 500L, message = NULL) { #' Try an expression in a Plumber endpoint allowing error recovery #' -#' This function is similar to [try()] and is called inside a Plumber API endpoint +#' This function is similar to [try()] and is called inside a Plumber API endpoint #' definition. The function needs access to Plumbers response object. #' Use [http_error()] to automate the handling of HTTP status codes #' and differentiate between server vs. client errors. #' #' @param res The HTTP response object. #' @param expr An R expression to try. -#' @param message Logical, should the report of error messages be suppressed? +#' @param silent Logical, should the report of error messages be suppressed? #' @param ... Other arguments passed to [try()]. -#' +#' #' @return The value of the expression if 'expr' is evaluated without error, #' but an invisible object of class ‘"try-error"’ containing the #' error message, and the error condition as the ‘"condition"’ diff --git a/man/mario_try.Rd b/man/mario_try.Rd index 6b941a2..6e63391 100644 --- a/man/mario_try.Rd +++ b/man/mario_try.Rd @@ -11,9 +11,9 @@ mario_try(res, expr, silent = TRUE, ...) \item{expr}{An R expression to try.} -\item{...}{Other arguments passed to \code{\link[=try]{try()}}.} +\item{silent}{Logical, should the report of error messages be suppressed?} -\item{message}{Logical, should the report of error messages be suppressed?} +\item{...}{Other arguments passed to \code{\link[=try]{try()}}.} } \value{ The value of the expression if 'expr' is evaluated without error, diff --git a/tests/testthat/helpers.R b/tests/testthat/helpers.R deleted file mode 100644 index d27896c..0000000 --- a/tests/testthat/helpers.R +++ /dev/null @@ -1,8 +0,0 @@ - -dir_remove <- function(path) { - unlink( - x = path, - recursive = TRUE, - force = TRUE - ) -} diff --git a/tests/testthat/setup.R b/tests/testthat/setup.R new file mode 100644 index 0000000..a674b71 --- /dev/null +++ b/tests/testthat/setup.R @@ -0,0 +1,38 @@ +run_quietly_in_a_dummy_mariobox <- function(expr) { + on.exit( + { + dir_remove( + dummy_mariobox + ) + }, + add = TRUE + ) + withr::with_options( + c("usethis.quiet" = TRUE), + { + dummy_mariobox <- create_dummy_mariobox() + withr::with_dir( + dummy_mariobox, + expr + ) + } + ) +} + +dir_remove <- function(path) { + unlink( + x = path, + recursive = TRUE, + force = TRUE + ) +} + +create_dummy_mariobox <- function(){ + copy_empty_mariobox( + file.path( + tempdir(), + "dummymariobox" + ), + "dummymariobox" + ) +} \ No newline at end of file diff --git a/tests/testthat/test-R.R b/tests/testthat/test-R.R new file mode 100644 index 0000000..61b508a --- /dev/null +++ b/tests/testthat/test-R.R @@ -0,0 +1,5 @@ +test_that("",{ + expect_true( + (1 + 1) == 2 + ) +}) \ No newline at end of file diff --git a/tests/testthat/test-build_plumber_file.R b/tests/testthat/test-build_plumber_file.R new file mode 100644 index 0000000..8849056 --- /dev/null +++ b/tests/testthat/test-build_plumber_file.R @@ -0,0 +1,3 @@ +test_that("multiplication works", { + expect_equal(2 * 2, 4) +}) diff --git a/tests/testthat/test-create_pipework.R b/tests/testthat/test-create_pipework.R index 7806f35..db1d372 100644 --- a/tests/testthat/test-create_pipework.R +++ b/tests/testthat/test-create_pipework.R @@ -1,90 +1,50 @@ - is_properly_populated_mariobox <- function(path) { - # All files excepts *.Rproj which changes based on the project name - expected_files <- c( - "DESCRIPTION", - "LICENSE", - "LICENSE.md", - "dev/run_dev.R", - "inst/mariobox.yml", - "man/get_health.Rd", - "man/run_api.Rd", - "NAMESPACE", - "R/get_health.R", - "R/run_plumber.R", - "tests/testthat.R", - "tests/testthat/test-health.R", - "tests/testthat/test-run_plumber.R" + expected_files <- list.files( + mariobox_sys( + "marioboxexample" + ), + recursive = TRUE ) - if (rstudioapi::isAvailable()) { - expected_files <- c( - expected_files, - paste0(basename(path), ".Rproj") - ) - } - - actual_files <- list.files(path, recursive = TRUE) + expected_files <- expected_files[!grepl( + "Rproj", + expected_files + )] + expected_files <- expected_files[!grepl( + "vscode-R", + expected_files + )] - # browser() - # waldo::compare(sort(expected_files), sort(actual_files)) - identical(sort(expected_files), sort(actual_files)) -} + expected_files <- expected_files[!grepl( + "REMOVEME.Rbuildignore", + expected_files + )] -keep_only_non_pdf_related_warnings <- function(check_output_warnings) { - grep( - "pdf", - check_output_warnings, - ignore.case = TRUE, - invert = TRUE, - value = TRUE + actual_files <- list.files(path, recursive = TRUE) + actual_files <- actual_files[!grepl( + "vscode-R", + actual_files + )] + identical( + sort(expected_files), + sort(actual_files) ) } -path_dummy <- tempfile(pattern = "dummy") -dir.create(path_dummy) -dummy_mariobox_path <- file.path(path_dummy, "pipo") -path_pkg <- create_mariobox( - path = dummy_mariobox_path, - open = FALSE -) -test_that("create_mariobox() works", { - usethis::with_project(dummy_mariobox_path, { - usethis::use_mit_license(copyright_holder = "Babar") - - check_output <- rcmdcheck::rcmdcheck( - path = dummy_mariobox_path, - quiet = TRUE, - args = c("--no-manual") - ) - - expect_equal( - check_output[["errors"]], - character(0) - ) - expect_lte( - length( - keep_only_non_pdf_related_warnings(check_output[["warnings"]]) - ), - 1 - ) - if (length(check_output[["warnings"]]) == 1) { - expect_true(grepl("there is no package called", check_output[["warnings"]])) - } - expect_lte( - length(check_output[["notes"]]), - 1 - ) - if (length(check_output[["notes"]]) == 1) { - expect_true( - grepl("\\.here", check_output[["notes"]][1]) +test_that("copy_empty_mariobox works", { + on.exit( + { + dir_remove( + dummy_mariobox ) - } - expect_true( - is_properly_populated_mariobox(path_pkg) + }, + add = TRUE + ) + dummy_mariobox <- create_dummy_mariobox() + expect_true( + is_properly_populated_mariobox( + path = dummy_mariobox ) - }) + ) }) - -dir_remove(path_dummy) diff --git a/tests/testthat/test-manage_endpoints.R b/tests/testthat/test-manage_endpoints.R index 1d363b8..a407a71 100644 --- a/tests/testthat/test-manage_endpoints.R +++ b/tests/testthat/test-manage_endpoints.R @@ -1,15 +1,6 @@ test_that("Managing endpoints", { - path_dummy <- tempfile(pattern = "dummy") - dir.create(path_dummy) - - dummy_mariobox_path <- file.path(path_dummy, "pipo") - path_pkg <- create_mariobox( - path = dummy_mariobox_path, - open = FALSE - ) - - withr::with_dir(dummy_mariobox_path, { - # Adding endpoint + run_quietly_in_a_dummy_mariobox({ + # Adding endpoint mariobox_yaml_path <- "inst/mariobox.yml" endpoint_name <- "michel" r_file <- sprintf("R/get_%s.R", endpoint_name) @@ -127,6 +118,4 @@ test_that("Managing endpoints", { default_yaml ) }) - - dir_remove(path_dummy) }) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index f61758c..6f6f9e2 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -14,3 +14,40 @@ test_that("silent_lapply() works", { as.list(LETTERS) ) }) + + +test_that("replace_word replaces pattern correctly in a file", { + temp_file <- tempfile() + writeLines(c("Hello world", "Hello again"), temp_file) + replace_word(temp_file, "Hello", "Hi") + modified_content <- readLines(temp_file) + expect_equal(modified_content, c("Hi world", "Hi again")) + unlink(temp_file) +}) + +test_that("replace_word handles files with no matching pattern", { + temp_file <- tempfile() + writeLines(c("Goodbye world", "Goodbye again"), temp_file) + replace_word(temp_file, "Hello", "Hi") + modified_content <- readLines(temp_file) + expect_equal(modified_content, c("Goodbye world", "Goodbye again")) + unlink(temp_file) +}) + +test_that("replace_word works with empty files", { + temp_file <- tempfile() + file.create(temp_file) + replace_word(temp_file, "Hello", "Hi") + modified_content <- readLines(temp_file) + expect_equal(modified_content, character(0)) + unlink(temp_file) +}) + +test_that("replace_word works with complex patterns", { + temp_file <- tempfile() + writeLines(c("abc123", "xyz789"), temp_file) + replace_word(temp_file, "[a-z]{3}[0-9]{3}", "replaced") + modified_content <- readLines(temp_file) + expect_equal(modified_content, c("replaced", "replaced")) + unlink(temp_file) +})