diff --git a/DESCRIPTION b/DESCRIPTION index f3a90aef..ffefa8c5 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -73,3 +73,4 @@ Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 SystemRequirements: Rust 'cargo'; the crate 'libR-sys' must compile without error +Config/rextendr/version: 0.3.1.9001 diff --git a/R/clean.R b/R/clean.R index d59c475a..0a57070f 100644 --- a/R/clean.R +++ b/R/clean.R @@ -4,76 +4,69 @@ #' invokes `cargo clean` to reset cargo target directory #' (found by default at `pkg_root/src/rust/target/`). #' Useful when Rust code should be recompiled from scratch. -#' @param path \[ string \] Path to the package root. +#' +#' @param path character scalar, path to R package root. +#' @param echo logical scalar, should cargo command and outputs be printed to +#' console (default is `TRUE`) +#' +#' @return character vector with names of all deleted files (invisibly). +#' #' @export -clean <- function(path = ".") { - root <- rprojroot::find_package_root_file(path = path) - - rust_folder <- normalizePath( - file.path(root, "src", "rust"), - winslash = "/", - mustWork = FALSE - ) +#' +#' @examples +#' \dontrun{ +#' clean() +#' } +clean <- function(path = ".", echo = TRUE) { + check_string(path, class = "rextendr_error") + check_bool(echo, class = "rextendr_error") - toml_path <- normalizePath( - file.path(rust_folder, "Cargo.toml"), - winslash = "/", - mustWork = FALSE - ) + manifest_path <- find_extendr_manifest(path = path) # Note: This should be adjusted if `TARGET_DIR` changes in `Makevars` - target_dir <- normalizePath( # nolint: object_usage_linter - file.path(rust_folder, "target"), - winslash = "/", - mustWork = FALSE + target_dir <- rprojroot::find_package_root_file( + "src", "rust", "target", + path = path ) - if (!file.exists(toml_path)) { - cli::cli_abort(c( - "Unable to clean binaries.", - "!" = "{.file Cargo.toml} not found in {.path {rust_folder}}.", + if (!dir.exists(target_dir)) { + cli::cli_abort( + c( + "Could not clean binaries.", + "Target directory not found at {.path target_dir}." + ), + call = rlang::caller_call(), class = "rextendr_error" - )) + ) } - cargo_envvars <- get_cargo_envvars() - args <- c( "clean", - glue("--manifest-path={toml_path}"), - glue("--target-dir={target_dir}"), + glue::glue("--manifest-path={manifest_path}"), + glue::glue("--target-dir={target_dir}"), if (tty_has_colors()) { "--color=always" } else { "--color=never" - }, - "--quiet" + } ) - exec_result <- processx::run( - command = "cargo", - args = args, - echo_cmd = FALSE, - windows_verbatim_args = FALSE, - stderr = "|", - stdout = "|", - error_on_status = FALSE, - env = cargo_envvars + + run_cargo( + args, + wd = find_extendr_crate(path = path), + echo = echo ) - if (!isTRUE(exec_result$status == 0)) { - if (!tty_has_colors()) { - err_msg <- cli::ansi_strip(exec_result$stderr) - } else { - err_msg <- exec_result$stderr - } + root <- rprojroot::find_package_root_file(path = path) + + if (!dir.exists(root)) { cli::cli_abort( - c( - "Unable to execute {.code cargo clean}.", - "x" = paste(err_msg, collapse = "\n") - ), - call = caller_env(), + "Could not clean binaries.", + "R package directory not found at {.path root}.", + call = rlang::caller_call(), class = "rextendr_error" ) } + pkgbuild::clean_dll(path = root) } diff --git a/R/find_extendr.R b/R/find_extendr.R index f423b5bc..033a567c 100644 --- a/R/find_extendr.R +++ b/R/find_extendr.R @@ -6,12 +6,8 @@ #' #' @return character scalar, path to Rust crate #' -#' @examples -#' \dontrun{ -#' find_extendr_crate() #' @keywords internal #' @noRd -#' } find_extendr_crate <- function( path = ".", error_call = rlang::caller_call()) { @@ -41,12 +37,8 @@ find_extendr_crate <- function( #' #' @return character scalar, path to Cargo manifest #' -#' @examples -#' \dontrun{ -#' find_extendr_manifest() #' @keywords internal #' @noRd -#' } find_extendr_manifest <- function( path = ".", error_call = rlang::caller_call()) { diff --git a/R/license_note.R b/R/license_note.R index d3c19b00..214ef961 100644 --- a/R/license_note.R +++ b/R/license_note.R @@ -1,97 +1,140 @@ #' Generate LICENSE.note file. #' -#' LICENSE.note generated by this function contains information about Rust crate dependencies. -#' To use this function, the [cargo-license](https://crates.io/crates/cargo-license) command must be installed. -#' @param force Logical indicating whether to regenerate LICENSE.note if LICENSE.note already exists. -#' @inheritParams register_extendr -#' @return No return value, called for side effects. +#' LICENSE.note generated by this function contains information about all +#' recursive dependencies in Rust crate. +#' +#' @param path character scalar, the R package directory +#' @param quiet logical scalar, whether to signal successful writing of +#' LICENSE.note (default is `FALSE`) +#' @param force logical scalar, whether to regenerate LICENSE.note if +#' LICENSE.note already exists (default is `TRUE`) +#' +#' @return text printed to LICENSE.note (invisibly). +#' #' @export -write_license_note <- function(path = ".", quiet = FALSE, force = TRUE) { - if (!cargo_command_available(c("license", "--help"))) { +#' +#' @examples +#' \dontrun{ +#' write_license_note() +#' } +write_license_note <- function( + path = ".", + quiet = FALSE, + force = TRUE) { + check_string(path, class = "rextendr_error") + check_bool(quiet, class = "rextendr_error") + check_bool(force, class = "rextendr_error") + + outfile <- rprojroot::find_package_root_file( + "LICENSE.note", + path = path + ) + + args <- c( + "metadata", + "--format-version=1" + ) + + metadata <- run_cargo( + args, + wd = find_extendr_crate(path = path), + echo = FALSE, + parse_json = TRUE + ) + + packages <- metadata[["packages"]] + + # did we actually get the recursive dependency metadata we need? + required_variables <- c("name", "repository", "authors", "license", "id") + + packages_exist <- is.data.frame(packages) && + !is.null(packages) && + nrow(packages) > 0 && + all(required_variables %in% names(packages)) + + if (!packages_exist) { cli::cli_abort( - c( - "The {.code cargo license} command is required to run the {.fun write_license_note} function.", - "*" = "Please install cargo-license ({.url https://crates.io/crates/cargo-license}) first.", - i = "Run {.code cargo install cargo-license} from your terminal." - ), + "Unable to write LICENSE.note.", + "Metadata for recursive dependencies not found.", + call = rlang::caller_call(), class = "rextendr_error" ) } - manifest_file <- rprojroot::find_package_root_file("src", "rust", "Cargo.toml", path = path) - outfile <- rprojroot::find_package_root_file("LICENSE.note", path = path) + # exclude current package from LICENSE.note + current_package <- metadata[["resolve"]][["root"]] + + current_package_exists <- length(current_package) == 1 && + is.character(current_package) && + !is.null(current_package) - if (!isTRUE(force) && file.exists(outfile)) { + if (!current_package_exists) { cli::cli_abort( - c( - "LICENSE.note already exists.", - "If you want to regenerate LICENSE.note, set `force = TRUE` to {.fun write_license_note}." - ), + "Unable to write LICENSE.note.", + "Failed to identify current Rust crate.", + call = rlang::caller_call(), class = "rextendr_error" ) } - list_license <- processx::run( - "cargo", - c( - "license", - "--authors", - "--json", - "--avoid-build-deps", - "--avoid-dev-deps", - "--manifest-path", manifest_file - ) - )$stdout %>% - jsonlite::parse_json() - - package_names <- processx::run( - "cargo", - c( - "metadata", - "--no-deps", - "--format-version", "1", - "--manifest-path", manifest_file - ) - )$stdout %>% - jsonlite::parse_json() %>% - purrr::pluck("packages") %>% - purrr::map_chr("name") - - .prep_authors <- function(authors, package) { - ifelse(!is.null(authors), authors, paste0(package, " authors")) %>% - stringi::stri_replace_all_regex(r"(\ <.+?>)", "") %>% - stringi::stri_replace_all_regex(r"(\|)", ", ") - } + packages <- packages[packages[["id"]] != current_package, ] + + # replace missing values + packages[["respository"]] <- replace_na( + packages[["repository"]], + "unknown" + ) + + packages[["licenses"]] <- replace_na( + packages[["repository"]], + "not provided" + ) + + # remove email addresses and special characters and combine all authors + # of a crate into a single character scalar + packages[["authors"]] <- unlist(Map( + prep_authors, + packages[["authors"]], + packages[["name"]] + )) separator <- "-------------------------------------------------------------" note_header <- paste0( - "The binary compiled from the source code of this package contains the following Rust crates:\n", + "The binary compiled from the source code of this package ", + "contains the following Rust crates:\n", "\n", "\n", separator ) - note_body <- list_license %>% - purrr::discard(function(x) x$name %in% package_names) %>% - purrr::map_chr( - function(x) { - paste0( - "\n", - "Name: ", x$name, "\n", - "Repository: ", x$repository, "\n", - "Authors: ", .prep_authors(x$authors, x$name), "\n", - "License: ", x$license, "\n", - "\n", - separator - ) - } - ) + note_body <- paste0( + "\n", + "Name: ", packages[["name"]], "\n", + "Repository: ", packages[["repository"]], "\n", + "Authors: ", packages[["authors"]], "\n", + "License: ", packages[["license"]], "\n", + "\n", + separator + ) write_file( text = c(note_header, note_body), path = outfile, search_root_from = path, - quiet = quiet + quiet = quiet, + overwrite = force + ) +} + +prep_authors <- function(authors, package) { + authors <- ifelse( + is.na(authors), + paste0(package, " authors"), + authors ) + + authors <- stringi::stri_replace_all_regex(authors, r"(\ <.+?>)", "") + + paste0(authors, collapse = ", ") } diff --git a/R/read_cargo_metadata.R b/R/read_cargo_metadata.R index 4e314c3d..e3c9ffb7 100644 --- a/R/read_cargo_metadata.R +++ b/R/read_cargo_metadata.R @@ -1,6 +1,10 @@ #' Retrieve metadata for packages and workspaces #' #' @param path character scalar, the R package directory +#' @param dependencies Default `FALSE`. A logical scalar, whether to include +#' all recursive dependencies in stdout. +#' @param echo Default `FALSE`. A logical scalar, should cargo command and +#' outputs be printed to the console. #' #' @details #' For more details, see @@ -8,15 +12,16 @@ #' for `cargo-metadata`. See especially "JSON Format" to get a sense of what you #' can expect to find in the returned list. #' -#' @return `list`, including the following elements: -#' - "packages" -#' - "workspace_members" -#' - "workspace_default_members" -#' - "resolve" -#' - "target_directory" -#' - "version" -#' - "workspace_root" -#' - "metadata" +#' @returns +#' A `list` including the following elements: +#' - `packages` +#' - `workspace_members` +#' - `workspace_default_members` +#' - `resolve` +#' - `target_directory` +#' - `version` +#' - `workspace_root` +#' - `metadata` #' #' @export #' @@ -25,22 +30,31 @@ #' read_cargo_metadata() #' } #' -read_cargo_metadata <- function(path = ".") { +read_cargo_metadata <- function( + path = ".", + dependencies = FALSE, + echo = FALSE) { check_string(path, class = "rextendr_error") + check_bool(dependencies, class = "rextendr_error") + check_bool(echo, class = "rextendr_error") - root <- rprojroot::find_package_root_file(path = path) - - rust_folder <- normalizePath( - file.path(root, "src", "rust"), - winslash = "/", - mustWork = FALSE + args <- c( + "metadata", + "--format-version=1", + if (!dependencies) { + "--no-deps" + }, + if (tty_has_colors()) { + "--color=always" + } else { + "--color=never" + } ) - out <- processx::run( - "cargo", - args = c("metadata", "--format-version=1", "--no-deps"), - wd = rust_folder + run_cargo( + args, + wd = find_extendr_crate(path = path), + echo = echo, + parse_json = TRUE ) - - jsonlite::fromJSON(out[["stdout"]]) } diff --git a/R/run_cargo.R b/R/run_cargo.R new file mode 100644 index 00000000..1db8ed13 --- /dev/null +++ b/R/run_cargo.R @@ -0,0 +1,80 @@ +#' Run Cargo subcommands +#' +#' This internal function allows us to maintain consistent specifications for +#' `processx::run()` everywhere it uses. +#' +#' @param args character vector, the Cargo subcommand and flags to be executed. +#' @param wd character scalar, location of the Rust crate, (default is +#' `find_extendr_crate()`). +#' @param error_on_status Default `TRUE`. A logical scalar, whether to error on a non-zero exist status. +#' @param echo_cmd Default `TRUE`. A logical scalar, whether to print Cargo subcommand and flags +#' to the console. +#' @param echo Default `TRUE`. Alogical scalar, whether to print standard output and error to the +#' console. +#' @param env character vector, environment variables of the child process. +#' @param parse_json Default `FALSE`. A logical scalar, whether to parse JSON-structured standard +#' output using [`jsonlite::parse_json()`] with `simplifyDataFrame = TRUE`. +#' @param error_call Default [`rlang::caller_call()`]. The defused call with which +#' the function running in the frame was invoked. +#' @param ... additional arguments passed to [`processx::run()`]. +#' @returns +#' A list with elements `status`, `stdout`, `stderr`, and `timeout`. +#' See [`processx::run()`]. If `parse_json = TRUE`, result of parsing +#' JSON-structured standard output. +#' +#' @keywords internal +#' @noRd +run_cargo <- function( + args, + wd = find_extendr_crate(), + error_on_status = TRUE, + echo = TRUE, + env = get_cargo_envvars(), + parse_json = FALSE, + error_call = rlang::caller_call(), + ... +) { + check_character(args, call = error_call, class = "rextendr_error") + check_string(wd, call = error_call, class = "rextendr_error") + check_bool(error_on_status, call = error_call, class = "rextendr_error") + check_bool(echo, call = error_call, class = "rextendr_error") + check_character(env, call = error_call, class = "rextendr_error") + check_bool(parse_json, call = error_call, class = "rextendr_error") + + out <- processx::run( + command = "cargo", + args = args, + error_on_status = error_on_status, + wd = wd, + echo_cmd = echo, + echo = echo, + env = env, + ... + ) + + stdout <- out[["stdout"]] + + if (length(stdout) != 1L || !is.character(stdout) || is.null(stdout)) { + cli::cli_abort( + "{.code cargo paste(args, collapse = ' ')} failed to return stdout.", + call = error_call, + class = "rextendr_error" + ) + } + + if (parse_json) { + res <- rlang::try_fetch( + jsonlite::parse_json(stdout, simplifyDataFrame = TRUE), + error = function(cnd) { + cli::cli_abort( + c("Failed to {.code stdout} as json:", " " = "{stdout}"), + parent = cnd, + class = "rextendr_error" + ) + } + ) + return(res) + } + + out +} diff --git a/R/use_crate.R b/R/use_crate.R index 66496a7c..f249c4e3 100644 --- a/R/use_crate.R +++ b/R/use_crate.R @@ -10,13 +10,15 @@ #' @param optional boolean scalar, whether to mark the dependency as optional #' (FALSE by default) #' @param path character scalar, the package directory +#' @param echo logical scalar, should cargo command and outputs be printed to +#' console (default is TRUE) #' #' @details #' For more details regarding these and other options, see the #' \href{https://doc.rust-lang.org/cargo/commands/cargo-add.html}{Cargo docs} #' for `cargo-add`. #' -#' @return `NULL`, invisibly +#' @return `NULL` (invisibly) #' #' @export #' @@ -43,14 +45,15 @@ use_crate <- function( git = NULL, version = NULL, optional = FALSE, - path = ".") { - # check args - check_string(crate) - check_character(features, allow_null = TRUE) - check_string(git, allow_null = TRUE) - check_string(version, allow_null = TRUE) - check_bool(optional) - check_string(path) + path = ".", + echo = TRUE) { + check_string(crate, class = "rextendr_error") + check_character(features, allow_null = TRUE, class = "rextendr_error") + check_string(git, allow_null = TRUE, class = "rextendr_error") + check_string(version, allow_null = TRUE, class = "rextendr_error") + check_bool(optional, class = "rextendr_error") + check_string(path, class = "rextendr_error") + check_bool(echo, class = "rextendr_error") if (!is.null(version) && !is.null(git)) { cli::cli_abort( @@ -80,21 +83,23 @@ use_crate <- function( optional <- NULL } - # get rust directory in project folder - root <- rprojroot::find_package_root_file(path = path) - - rust_folder <- normalizePath( - file.path(root, "src", "rust"), - winslash = "/", - mustWork = FALSE + args <- c( + "add", + crate, + features, + git, + optional, + if (tty_has_colors()) { + "--color=always" + } else { + "--color=never" + } ) - # run the commmand - processx::run( - "cargo", - c("add", crate, features, git, optional), - echo_cmd = TRUE, - wd = rust_folder + run_cargo( + args, + wd = find_extendr_crate(path = path), + echo = echo ) invisible() diff --git a/R/utils.R b/R/utils.R index 7b18d76f..d408c454 100644 --- a/R/utils.R +++ b/R/utils.R @@ -57,3 +57,23 @@ try_exec_cmd <- function(cmd, args = character()) { stringi::stri_split_lines1(result$stdout) } } + +#' Replace missing values in vector +#' +#' @param data vector, data with missing values to replace +#' @param replace scalar, value to substitute for missing values in data +#' @param ... currently ignored +#' +#' @keywords internal +#' @noRd +#' +replace_na <- function(data, replace = NA, ...) { + if (vctrs::vec_any_missing(data)) { + missing <- vctrs::vec_detect_missing(data) + data <- vctrs::vec_assign(data, missing, replace, + x_arg = "data", + value_arg = "replace" + ) + } + data +} diff --git a/man/clean.Rd b/man/clean.Rd index 9f0646e4..6a756a9b 100644 --- a/man/clean.Rd +++ b/man/clean.Rd @@ -4,10 +4,16 @@ \alias{clean} \title{Clean Rust binaries and package cache.} \usage{ -clean(path = ".") +clean(path = ".", echo = TRUE) } \arguments{ -\item{path}{[ string ] Path to the package root.} +\item{path}{character scalar, path to R package root.} + +\item{echo}{logical scalar, should cargo command and outputs be printed to +console (default is \code{TRUE})} +} +\value{ +character vector with names of all deleted files (invisibly). } \description{ Removes Rust binaries (such as \code{.dll}/\code{.so} libraries), C wrapper object files, @@ -15,3 +21,8 @@ invokes \verb{cargo clean} to reset cargo target directory (found by default at \verb{pkg_root/src/rust/target/}). Useful when Rust code should be recompiled from scratch. } +\examples{ +\dontrun{ +clean() +} +} diff --git a/man/read_cargo_metadata.Rd b/man/read_cargo_metadata.Rd index 70d20284..16aea079 100644 --- a/man/read_cargo_metadata.Rd +++ b/man/read_cargo_metadata.Rd @@ -4,22 +4,28 @@ \alias{read_cargo_metadata} \title{Retrieve metadata for packages and workspaces} \usage{ -read_cargo_metadata(path = ".") +read_cargo_metadata(path = ".", dependencies = FALSE, echo = FALSE) } \arguments{ \item{path}{character scalar, the R package directory} + +\item{dependencies}{Default \code{FALSE}. A logical scalar, whether to include +all recursive dependencies in stdout.} + +\item{echo}{Default \code{FALSE}. A logical scalar, should cargo command and +outputs be printed to the console.} } \value{ -\code{list}, including the following elements: +A \code{list} including the following elements: \itemize{ -\item "packages" -\item "workspace_members" -\item "workspace_default_members" -\item "resolve" -\item "target_directory" -\item "version" -\item "workspace_root" -\item "metadata" +\item \code{packages} +\item \code{workspace_members} +\item \code{workspace_default_members} +\item \code{resolve} +\item \code{target_directory} +\item \code{version} +\item \code{workspace_root} +\item \code{metadata} } } \description{ diff --git a/man/use_crate.Rd b/man/use_crate.Rd index 1500d6bd..2341681f 100644 --- a/man/use_crate.Rd +++ b/man/use_crate.Rd @@ -10,7 +10,8 @@ use_crate( git = NULL, version = NULL, optional = FALSE, - path = "." + path = ".", + echo = TRUE ) } \arguments{ @@ -27,9 +28,12 @@ crate} (FALSE by default)} \item{path}{character scalar, the package directory} + +\item{echo}{logical scalar, should cargo command and outputs be printed to +console (default is TRUE)} } \value{ -\code{NULL}, invisibly +\code{NULL} (invisibly) } \description{ Analogous to \code{usethis::use_package()} but for crate dependencies. diff --git a/man/vendor_pkgs.Rd b/man/vendor_pkgs.Rd index 98e75d57..8e133c19 100644 --- a/man/vendor_pkgs.Rd +++ b/man/vendor_pkgs.Rd @@ -30,8 +30,7 @@ compressed \code{vendor.tar.xz} which will be shipped with package itself. If you have modified your dependencies, you will need need to repackage } \examples{ - \dontrun{ - vendor_pkgs() +vendor_pkgs() } } diff --git a/man/write_license_note.Rd b/man/write_license_note.Rd index cfdfb835..6bf93d53 100644 --- a/man/write_license_note.Rd +++ b/man/write_license_note.Rd @@ -7,17 +7,23 @@ write_license_note(path = ".", quiet = FALSE, force = TRUE) } \arguments{ -\item{path}{Path from which package root is looked up.} +\item{path}{character scalar, the R package directory} -\item{quiet}{Logical indicating whether any progress messages should be -generated or not.} +\item{quiet}{logical scalar, whether to signal successful writing of +LICENSE.note (default is \code{FALSE})} -\item{force}{Logical indicating whether to regenerate LICENSE.note if LICENSE.note already exists.} +\item{force}{logical scalar, whether to regenerate LICENSE.note if +LICENSE.note already exists (default is \code{TRUE})} } \value{ -No return value, called for side effects. +text printed to LICENSE.note (invisibly). } \description{ -LICENSE.note generated by this function contains information about Rust crate dependencies. -To use this function, the \href{https://crates.io/crates/cargo-license}{cargo-license} command must be installed. +LICENSE.note generated by this function contains information about all +recursive dependencies in Rust crate. +} +\examples{ +\dontrun{ +write_license_note() +} } diff --git a/tests/testthat/_snaps/license_note.md b/tests/testthat/_snaps/license_note.md index d2757ccb..44be7cc5 100644 --- a/tests/testthat/_snaps/license_note.md +++ b/tests/testthat/_snaps/license_note.md @@ -32,42 +32,42 @@ Name: once_cell Repository: https://github.com/matklad/once_cell Authors: Aleksey Kladov - License: Apache-2.0 OR MIT + License: MIT OR Apache-2.0 ------------------------------------------------------------- Name: paste Repository: https://github.com/dtolnay/paste Authors: David Tolnay - License: Apache-2.0 OR MIT + License: MIT OR Apache-2.0 ------------------------------------------------------------- Name: proc-macro2 Repository: https://github.com/dtolnay/proc-macro2 Authors: David Tolnay, Alex Crichton - License: Apache-2.0 OR MIT + License: MIT OR Apache-2.0 ------------------------------------------------------------- Name: quote Repository: https://github.com/dtolnay/quote Authors: David Tolnay - License: Apache-2.0 OR MIT + License: MIT OR Apache-2.0 ------------------------------------------------------------- Name: syn Repository: https://github.com/dtolnay/syn Authors: David Tolnay - License: Apache-2.0 OR MIT + License: MIT OR Apache-2.0 ------------------------------------------------------------- Name: unicode-ident Repository: https://github.com/dtolnay/unicode-ident Authors: David Tolnay - License: (MIT OR Apache-2.0) AND Unicode-DFS-2016 + License: (MIT OR Apache-2.0) AND Unicode-3.0 ------------------------------------------------------------- diff --git a/tests/testthat/test-clean.R b/tests/testthat/test-clean.R index 3ee022ee..b20c8354 100644 --- a/tests/testthat/test-clean.R +++ b/tests/testthat/test-clean.R @@ -11,8 +11,15 @@ test_that("rextendr::clean() removes cargo target directory & binaries", { expect_equal(length(dir("src", pattern = "testpkg\\..*")), 1) expect_true(dir.exists(file.path("src", "rust", "target"))) + + # clean once clean() + # we expect an error the second time + expect_error(clean()) + + expect_error(clean(1L)) + expect_error(clean(echo = NULL)) expect_equal(length(dir("src", pattern = "testpkg\\..*")), 0) expect_false(dir.exists(file.path("src", "rust", "target"))) }) diff --git a/tests/testthat/test-license_note.R b/tests/testthat/test-license_note.R index 280cb870..92bf73cb 100644 --- a/tests/testthat/test-license_note.R +++ b/tests/testthat/test-license_note.R @@ -3,10 +3,15 @@ test_that("LICENSE.note is generated properly", { skip_if_cargo_unavailable(c("license", "--help")) local_package("testPackage") + + # try running write_license_note() when there is nothing present + dir.create(file.path("src", "rust"), recursive = TRUE) + expect_error(write_license_note()) + + # create license note for extendr package use_extendr() write_license_note() - expect_snapshot(cat_file("LICENSE.note")) - expect_rextendr_error(write_license_note(), NA) - expect_rextendr_error(write_license_note(force = FALSE), "LICENSE.note already exists.") + expect_error(write_license_note(path = NULL)) + expect_error(write_license_note(force = "yup")) }) diff --git a/tests/testthat/test-use_crate.R b/tests/testthat/test-use_crate.R index b3419279..8f7328ed 100644 --- a/tests/testthat/test-use_crate.R +++ b/tests/testthat/test-use_crate.R @@ -15,16 +15,15 @@ test_that("use_crate() adds dependency to package or workspace", { path = path ) - metadata <- read_cargo_metadata(path) + metadata <- read_cargo_metadata(path, echo = FALSE) dependency <- metadata[["packages"]][["dependencies"]][[1]] dependency <- dependency[dependency[["name"]] == "serde", ] expect_equal(dependency[["name"]], "serde") - expect_equal(dependency[["features"]][[1]], "derive") - expect_equal(dependency[["req"]], "^1.0.1") + }) test_that("use_crate() errors when user passes git and version arguments", { diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index bc45a226..8f975eeb 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -20,3 +20,16 @@ test_that("`try_exec_cmd()` returns stdout when command is available", { echo <- "This is an echo" expect_equal(try_exec_cmd("echo", echo), echo) }) + + +test_that("`replace_na()` respects type", { + x <- 1:5 + x[2] <- NA + expect_error(replace_na(x, "L")) +}) + +test_that("`replace_na()` replaces with the correct value", { + x <- 1:5 + x[2] <- NA_integer_ + expect_identical(replace_na(x, -99L), c(1L, -99L, 3L, 4L, 5L)) +})