From f783c8d62089fb23751c5ec2c886c5c162a9f92a Mon Sep 17 00:00:00 2001 From: mpadge Date: Fri, 26 Aug 2022 12:22:28 +0200 Subject: [PATCH 01/11] add R/typetrace-package.R for #76 --- DESCRIPTION | 5 +++- R/typetrace-package.R | 68 +++++++++++++++++++++++++++++++++++++++++++ codemeta.json | 2 +- 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 R/typetrace-package.R diff --git a/DESCRIPTION b/DESCRIPTION index 4b058ee..225efcc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.195 +Version: 0.0.2.196 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), @@ -24,6 +24,7 @@ Imports: rlang, testthat, tibble, + typetracer, withr, yaml Suggests: @@ -38,6 +39,8 @@ Suggests: usethis VignetteBuilder: knitr +Remotes: + mpadge/typetracer Encoding: UTF-8 Language: en-GB LazyData: true diff --git a/R/typetrace-package.R b/R/typetrace-package.R new file mode 100644 index 0000000..f39b263 --- /dev/null +++ b/R/typetrace-package.R @@ -0,0 +1,68 @@ +# Trace a package with 'typetracer' + +get_typetrace_dir <- function () { + + td <- getOption ("typetracedir") + if (is.null (td)) { + td <- tempdir () + } + return (td) +} + +autotest_trace_package <- function (package) { + + Sys.setenv ("TYPETRACER_LEAVE_TRACES" = "true") + + package <- dot_to_package (package) + pkg_name <- preload_package (package) + if (pkg_name != package) { + if (!dir.exists (package)) { + stop ("'package' should be a local directory.") + } + traces <- typetracer::trace_package (pkg_dir = package) + } else { + traces <- typetracer::trace_package (package = package) + } + + trace_files <- list.files ( + get_typetrace_dir (), + pattern = "^typetrace\\_.*\\.Rds$", + full.names = TRUE + ) + + Sys.unsetenv ("TYPETRACER_LEAVE_TRACES") + + return (trace_files) +} + +#' Get all (unique) parameter names from all traced functions. +#' +#' @param traces Result of 'typetracer::trace_package()' call. +#' @return Reduced version of 'traces' with only unique parameter names. +#' @noRd +get_unique_fn_pars <- function (traces) { + + fn_pars <- unique (traces [, c ("fn_name", "par_name")]) + + par_types <- lapply (seq (nrow (fn_pars)), function (i) { + index <- which (traces$fn_name == fn_pars$fn_name [i] & + traces$par_name == fn_pars$par_name [i]) + onecol <- function (traces, index, what = "classes") { + res <- traces [[what]] [index] + if (is.list (res)) { + res <- do.call (c, res) + } + res <- unique (res) + paste0 (res [which (!res == "NULL")], collapse = ", ") + } + data.frame ( + class = onecol (traces, index, "class"), + typeof = onecol (traces, index, "typeof"), + mode = onecol (traces, index, "mode"), + storage_mode = onecol (traces, index, "storage_mode"), + length = onecol (traces, index, "length") + ) + }) + + return (cbind (fn_pars, do.call (rbind, par_types))) +} diff --git a/codemeta.json b/codemeta.json index 8adbd4b..2e7e1ae 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.195", + "version": "0.0.2.196", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", From f6ec03acbb281a8c27d6d089a0dc36e13f7fb34a Mon Sep 17 00:00:00 2001 From: mpadge Date: Fri, 26 Aug 2022 12:34:04 +0200 Subject: [PATCH 02/11] add exclude & functions param to typetracer for #76 --- DESCRIPTION | 2 +- R/typetrace-package.R | 26 ++++++++++++++++++++------ codemeta.json | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 225efcc..4722787 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.196 +Version: 0.0.2.197 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), diff --git a/R/typetrace-package.R b/R/typetrace-package.R index f39b263..f6e927f 100644 --- a/R/typetrace-package.R +++ b/R/typetrace-package.R @@ -9,20 +9,36 @@ get_typetrace_dir <- function () { return (td) } -autotest_trace_package <- function (package) { +autotest_trace_package <- function (package, + functions = NULL, + exclude = NULL) { - Sys.setenv ("TYPETRACER_LEAVE_TRACES" = "true") package <- dot_to_package (package) pkg_name <- preload_package (package) + + exclude <- exclude_functions (package, functions, exclude) + if (!is.null (exclude)) { + functions <- ls (paste0 ("package:", pkg_name)) + functions <- functions [which (!functions %in% exclude)] + } + + Sys.setenv ("TYPETRACER_LEAVE_TRACES" = "true") if (pkg_name != package) { if (!dir.exists (package)) { stop ("'package' should be a local directory.") } - traces <- typetracer::trace_package (pkg_dir = package) + args <- list (pkg_dir = package) } else { - traces <- typetracer::trace_package (package = package) + args <- list (package = package) } + if (!is.null (functions)) { + args$functions = functions + } + + traces <- do.call (typetracer::trace_package, args) + + Sys.unsetenv ("TYPETRACER_LEAVE_TRACES") # traces are still there trace_files <- list.files ( get_typetrace_dir (), @@ -30,8 +46,6 @@ autotest_trace_package <- function (package) { full.names = TRUE ) - Sys.unsetenv ("TYPETRACER_LEAVE_TRACES") - return (trace_files) } diff --git a/codemeta.json b/codemeta.json index 2e7e1ae..c73875f 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.196", + "version": "0.0.2.197", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", From 2c7dd80b26bb8b9de3066d67165ab81a70d4a85a Mon Sep 17 00:00:00 2001 From: mpadge Date: Fri, 26 Aug 2022 12:44:13 +0200 Subject: [PATCH 03/11] add include_functions fn to pass params to typetracer call for #76 --- DESCRIPTION | 2 +- R/typetrace-package.R | 35 ++++++++++++++++++++++++++++++----- codemeta.json | 2 +- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 4722787..e89b6eb 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.197 +Version: 0.0.2.198 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), diff --git a/R/typetrace-package.R b/R/typetrace-package.R index f6e927f..f61751a 100644 --- a/R/typetrace-package.R +++ b/R/typetrace-package.R @@ -17,11 +17,7 @@ autotest_trace_package <- function (package, package <- dot_to_package (package) pkg_name <- preload_package (package) - exclude <- exclude_functions (package, functions, exclude) - if (!is.null (exclude)) { - functions <- ls (paste0 ("package:", pkg_name)) - functions <- functions [which (!functions %in% exclude)] - } + functions <- include_functions (package, functions, exclude) Sys.setenv ("TYPETRACER_LEAVE_TRACES" = "true") if (pkg_name != package) { @@ -49,6 +45,35 @@ autotest_trace_package <- function (package, return (trace_files) } +# combine lists of `functions` to include and `exclude` into single vector +include_functions <- function (package, functions = NULL, exclude = NULL) { + + fns <- m_get_pkg_functions (package) + + err_chk <- function (fn_arg, fns, package) { + if (!all (fn_arg %in% fns)) { + fn_arg <- fn_arg [which (!fn_arg %in% fns)] + stop ("The following functions are not in the namespace of ", + "package:", package, ": [", + paste0 (fn_arg, collapse = ", "), "]", + call. = FALSE) + } + } + + if (!is.null (functions)) { + + err_chk (functions, fns, package) + fns <- fns [which (fns %in% functions)] + + } else if (!is.null (exclude)) { + + err_chk (exclude, fns, package) + fns <- fns [which (!fns %in% exclude)] + } + + return (fns) +} + #' Get all (unique) parameter names from all traced functions. #' #' @param traces Result of 'typetracer::trace_package()' call. diff --git a/codemeta.json b/codemeta.json index c73875f..ca557d4 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.197", + "version": "0.0.2.198", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", From b83cb88f728516d8b3454cd07e35295dd21d8593 Mon Sep 17 00:00:00 2001 From: mpadge Date: Fri, 26 Aug 2022 12:55:06 +0200 Subject: [PATCH 04/11] update roxygen -> 7.2.1 --- DESCRIPTION | 4 ++-- codemeta.json | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index e89b6eb..503d2f1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.198 +Version: 0.0.2.199 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), @@ -45,4 +45,4 @@ Encoding: UTF-8 Language: en-GB LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.1.1 +RoxygenNote: 7.2.1 diff --git a/codemeta.json b/codemeta.json index ca557d4..db70006 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.198", + "version": "0.0.2.199", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -278,6 +278,12 @@ "sameAs": "https://CRAN.R-project.org/package=tibble" }, "12": { + "@type": "SoftwareApplication", + "identifier": "typetracer", + "name": "typetracer", + "sameAs": "https://github.com/mpadge/typetracer" + }, + "13": { "@type": "SoftwareApplication", "identifier": "withr", "name": "withr", @@ -289,7 +295,7 @@ }, "sameAs": "https://CRAN.R-project.org/package=withr" }, - "13": { + "14": { "@type": "SoftwareApplication", "identifier": "yaml", "name": "yaml", @@ -303,7 +309,7 @@ }, "SystemRequirements": {} }, - "fileSize": "570.294KB", + "fileSize": "16400.82KB", "readme": "https://github.com/ropensci-review-tools/autotest/blob/main/README.md", "contIntegration": [ "https://github.com/ropensci-review-tools/autotest/actions?query=workflow%3AR-CMD-check", From 6ac354d6b60f640f939a4ba4fe6bfcbf4145f9a1 Mon Sep 17 00:00:00 2001 From: mpadge Date: Fri, 26 Aug 2022 13:19:14 +0200 Subject: [PATCH 05/11] first cut of autotest_package fn with typetracer for #76 --- DESCRIPTION | 2 +- NAMESPACE | 1 - R/autotest-functions.R | 349 ++++++++++++++++++---------------------- R/typetrace-package.R | 8 +- codemeta.json | 2 +- man/at_yaml_template.Rd | 1 - man/autotest-package.Rd | 7 +- man/autotest_package.Rd | 2 +- man/autotest_yaml.Rd | 54 ------- man/examples_to_yaml.Rd | 3 +- 10 files changed, 164 insertions(+), 265 deletions(-) delete mode 100644 man/autotest_yaml.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 503d2f1..4a18960 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.199 +Version: 0.0.2.200 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), diff --git a/NAMESPACE b/NAMESPACE index 982e021..c89ce52 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -5,7 +5,6 @@ export(at_yaml_template) export(autotest_obj) export(autotest_package) export(autotest_types) -export(autotest_yaml) export(examples_to_yaml) export(expect_autotest_no_err) export(expect_autotest_no_testdata) diff --git a/R/autotest-functions.R b/R/autotest-functions.R index fcd68b8..c98def6 100644 --- a/R/autotest-functions.R +++ b/R/autotest-functions.R @@ -1,177 +1,8 @@ -#' autotest_yaml -#' -#' Automatically test inputs to functions specified in a 'yaml' template. -#' -#' @param yaml A 'yaml' template as a character vector, either hand-coded or -#' potentially loaded via \link{readLines} function or similar. Should generally -#' be left at default of 'NULL', with template specified by 'filename' -#' parameter. -#' @param filename Name (potentially including path) of file containing 'yaml' -#' template. See \link{at_yaml_template} for details of template. Default uses -#' template generated by that function, and held in local './tests' directory. -#' @param test If `FALSE`, return only descriptions of tests which would be run -#' with `test = TRUE`, without actually running them. -#' @param test_data Result returned from calling either \link{autotest_types} or -#' \link{autotest_package} with `test = FALSE` that contains a list of all tests -#' which would be conducted. These tests have an additional flag, `test`, which -#' defaults to `TRUE`. Setting any tests to `FALSE` will avoid running them when -#' `test = TRUE`. -#' @param quiet If 'FALSE', provide printed output on screen. -#' @return An `autotest_pkg` object, derived from a \pkg{tibble}, detailing -#' instances of unexpected behaviour for every parameter of every function. -#' @family yaml -#' -#' @examples -#' \dontrun{ -#' yaml_list <- examples_to_yaml (package = "stats", functions = "reshape") -#' res <- autotest_yaml (yaml = yaml_list) -#' } -#' @export -autotest_yaml <- function (yaml = NULL, - filename = NULL, - test = TRUE, - test_data = NULL, - quiet = FALSE) { - - if (is.null (yaml) & is.null (filename)) { - stop ("either yaml or filename must be given") - } else if (!is.null (filename)) { - yaml <- readLines (filename) - pkg <- strsplit (yaml [grep ("^package:", yaml)], - "^package: ") [[1]] [2] - attr (yaml, "package") <- pkg - } - - if (is.character (yaml) & !is.null (attr (yaml, "package"))) { - yaml <- list (yaml) - } - - msg <- paste0 ("yaml must be either a single character vector ", - "representing a yaml 'autotest' object, or a list ", - "of such objects") - if (!is.list (yaml)) - stop (msg) - - # Ensure anything passed as list represents valid yaml input: - if (!is.character (yaml [[1]]) & !is.null (attr (yaml [[1]], "package"))) - stop (msg) - - reports <- lapply (yaml, function (i) - autotest_single_yaml (i, - filename, - test, - test_data, - quiet)) - reports <- do.call (rbind, reports) - - if (!is.null (reports)) { - reports <- tibble::tibble (reports) - class (reports) <- c ("autotest_package", class (reports)) - } - - return (reports) -} - -#' Test one 'yaml' input file -#' -#' @inheritParams autotest_yaml -#' @noRd -autotest_single_yaml <- function (yaml = NULL, - filename = NULL, - test = TRUE, - test_data = NULL, - quiet = FALSE) { - - # yaml templates can be preprocessing only, with no direct function calls: - if (!any (grepl ("- parameters:$", yaml))) - return (NULL) - - res <- parse_yaml_template (yaml = yaml, filename = filename) - - # are parameters exclusively used as single-valued, or vectors? - par_lengths <- single_or_vec (res) - # are numeric parameters exclusively used as integers? - int_val <- double_or_int (res) - - reports <- NULL - - for (i in seq_along (res$parameters)) { - - this_fn <- names (res$parameters) [i] - params <- get_params (res, i, this_fn) - params <- params [which (!(params == "NULL" | names (params) == "..."))] - param_types <- get_param_types (this_fn, params, - par_lengths) - - param_class <- vapply (params, - function (i) - ifelse (inherits (i, "data.frame"), - "data.frame", - class (i) [1]), - character (1)) - index <- which (!param_class %in% c (atomic_modes (), - "data.frame")) - param_class <- param_class [index] - if (length (param_class) == 0L) - param_class <- NULL - - test_obj <- autotest_obj (package = res$package, - package_loc = attr (yaml, "package"), - fn_name = names (res$parameters) [i], - parameters = params, - parameter_types = param_types, - class = param_class, - classes = res$classes [[i]], - env = new.env (), - test = test, - quiet = quiet) - - test_obj <- add_int_attrs (test_obj, int_val) - - if (grepl ("\\:\\:\\:", test_obj$fn)) { - test_obj$fn <- rm_internal_namespace (test_obj$fn) - } - - if (length (params) > 0L) { - - reports <- rbind (reports, autotest_rectangular (test_obj, test_data)) - - reports <- rbind (reports, autotest_vector (test_obj, test_data)) - - reports <- rbind (reports, autotest_single (test_obj, test_data)) - - reports <- rbind (reports, autotest_return (test_obj, test_data)) - } - - reports <- rbind (reports, test_param_documentation (test_obj)) - - if (!quiet) - message (cli::col_green (cli::symbol$tick, " ", this_fn)) - } - - if (!is.null (reports)) { - - # add hash to reports - if (is.null (yaml) & !is.null (filename)) - yaml <- readLines (filename) - reports$yaml_hash <- digest::digest (yaml) - - reports <- reports [which (!duplicated (reports)), ] - - # rm "no_test" tests switched off from "test_data" - if (test) - reports <- reports [which (!reports$type == "no_test"), ] - - rownames (reports) <- NULL - } - - return (reports) -} #' autotest_package #' #' Automatically test an entire package by converting examples to `yaml` format -#' and submitting each to the \link{autotest_yaml} function. +#' and submitting each to the \link{autotest_single_trace} function. #' #' @param package Name of package, as either #' \enumerate{ @@ -185,7 +16,14 @@ autotest_single_yaml <- function (yaml = NULL, #' nominated package to be included in 'autotesting'. #' @param exclude Optional character vector containing names of any functions of #' nominated package to be excluded from 'autotesting'. -#' @inheritParams autotest_yaml +#' @param test If `FALSE`, return only descriptions of tests which would be run +#' with `test = TRUE`, without actually running them. +#' @param test_data Result returned from calling either \link{autotest_types} or +#' \link{autotest_package} with `test = FALSE` that contains a list of all tests +#' which would be conducted. These tests have an additional flag, `test`, which +#' defaults to `TRUE`. Setting any tests to `FALSE` will avoid running them when +#' `test = TRUE`. +#' @param quiet If 'FALSE', provide printed output on screen. #' @return An `autotest_package` object which is derived from a \pkg{tibble} #' `tbl_df` object. This has one row for each test, and the following nine #' columns: @@ -227,37 +65,42 @@ autotest_package <- function (package = ".", package <- dot_to_package (package) pkg_name <- preload_package (package) + pkg_dir <- get_package_loc (package) - exclude <- exclude_functions (package, functions, exclude) + traces <- autotest_trace_package (package, functions = functions, exclude = exclude) - exs <- examples_to_yaml (package, exclude = exclude, quiet = quiet) + trace_files <- list.files ( + get_typetrace_dir (), + pattern = "^typetrace\\_.*\\.Rds$", + full.names = TRUE + ) - if (!quiet) { - txt <- paste0 ("autotesting ", get_package_name (package)) - cli::cli_h2 (cli::col_green (txt)) - } + fn_pars <- get_unique_fn_pars (traces) res <- NULL - for (i in seq_along (exs)) { - yaml <- exs [[i]] - attr (yaml, "package") <- package - fn_name <- fn_from_yaml (yaml) - res <- rbind (res, - autotest_yaml (yaml = yaml, - test = test, - test_data = test_data, - quiet = TRUE)) + for (i in seq_along (trace_files)) { - if (!quiet) + res <- rbind (res, + autotest_single_trace (package, + readRDS (trace_files [i]), + fn_pars, + test = test, + test_data = test_data, + quiet = TRUE)) + + if (!quiet) { message (cli::col_green (cli::symbol$tick, " [", - i, " / ", length (exs), - "]: ", fn_name [1])) + i, " / ", length (trace_files), "]")) + } } + + typetracer::clear_traces () + res <- res [which (!duplicated (res)), ] - res <- test_untested_params (exs, res) - res <- test_fns_wo_example (package, res, names (exs)) + #res <- test_untested_params (exs, res) + #res <- test_fns_wo_example (package, res, names (exs)) if (is.null (res)) return (res) @@ -282,15 +125,129 @@ autotest_package <- function (package = ".", return (order_at_rows (res)) } -# Extract function name from yaml; used only to screen dump in autootest_package -fn_from_yaml <- function (yaml) { +get_package_loc <- function (package) { - x <- yaml::yaml.load (yaml) - nms <- vapply (x$functions, names, character (1)) - return (unique (nms)) + pkg_dir <- tryCatch (find.package (package), error = function (e) NULL) + + if (is.null (pkg_dir)) { + if (!dir.exists (package)) { + stop ("Directory ['", package, "'] does not exist", call. = FALSE) + } + } else { + package <- pkg_dir + } + return (package) } + +#' Test one 'typetracer' trace file +#' +#' @param traces A 'typetracer' trace file of function and parameter traces. +#' @param fn_pars Reduced version of 'typetracer' traces containing only unique +#' function and parameter name combinations. +#' @param test If `FALSE`, return only descriptions of tests which would be run +#' with `test = TRUE`, without actually running them. +#' @param test_data Result returned from calling either \link{autotest_types} or +#' \link{autotest_package} with `test = FALSE` that contains a list of all tests +#' which would be conducted. These tests have an additional flag, `test`, which +#' defaults to `TRUE`. Setting any tests to `FALSE` will avoid running them when +#' `test = TRUE`. +#' @param quiet If 'FALSE', provide printed output on screen. +#' @return An `autotest_pkg` object, derived from a \pkg{tibble}, detailing +#' instances of unexpected behaviour for every parameter of every function. +#' @noRd +autotest_single_trace <- function (pkg_dir = NULL, + trace_data = NULL, + fn_pars, + test = TRUE, + test_data = NULL, + quiet = FALSE) { + + # get parameter values: + par_index <- which (!nzchar (names (trace_data))) + par_names_i <- vapply (trace_data [par_index], function (j) j$par, character (1L)) + par_vals_i <- lapply (trace_data [par_index], function (j) j$par_eval) + names (par_vals_i) <- par_names_i + index <- which (!vapply (par_vals_i, is.null, logical (1L))) + par_vals_i <- par_vals_i [index] + par_names_i <- par_names_i [index] + + # get parameter classes & types: + index <- which (fn_pars$fn_name == trace_data$fn_name & + fn_pars$par_name %in% par_names_i) + fn_pars_i <- fn_pars [index, ] + fn_pars_i <- fn_pars_i [match (fn_pars_i$par_name, par_names_i), ] + + # param_types are in [single, vector, tabular] + param_types <- rep (NA_character_, nrow (fn_pars_i)) + is_single <- vapply (fn_pars_i$length, function (j) + all (as.integer (strsplit (j, ",") [[1]]) <= 1L), + logical (1L)) + param_types [which (is_single)] <- "single" + is_rect <- vapply (trace_data [par_index], function (j) + j$typeof == "list" && length (dim (j$par_eval)) == 2, + logical (1L)) + param_types [which (is_rect)] <- "tabular" + + # reduce class to first value only + param_class <- gsub (",\\s.*$", "", fn_pars_i$class) + names (param_class) <- fn_pars_i$par_name + index <- which (!param_class %in% c (atomic_modes (), "data.frame")) + param_class <- param_class [index] + + test_obj <- autotest_obj (package = package, + package_loc = pkg_dir, + fn_name = trace_data$fn_name, + parameters = par_vals_i, + parameter_types = param_types, + class = param_class, + classes = param_class, + env = new.env (), + test = test, + quiet = quiet) + int_val <- data.frame ( + fn = trace_data$fn_name, + par = fn_pars_i$par_name, + int_val = fn_pars_i$storage_mode == "integer" + ) + test_obj <- add_int_attrs (test_obj, int_val) + + reports <- NULL + + if (length (test_obj$params) > 0L) { + + reports <- rbind (reports, autotest_rectangular (test_obj, test_data)) + + reports <- rbind (reports, autotest_vector (test_obj, test_data)) + + reports <- rbind (reports, autotest_single (test_obj, test_data)) + + reports <- rbind (reports, autotest_return (test_obj, test_data)) + } + + reports <- rbind (reports, test_param_documentation (test_obj)) + + if (!quiet) { + message (cli::col_green (cli::symbol$tick, " ", this_fn)) + } + + if (!is.null (reports)) { + + reports <- reports [which (!duplicated (reports)), ] + + # rm "no_test" tests switched off from "test_data" + if (test) { + reports <- reports [which (!reports$type == "no_test"), ] + } + + rownames (reports) <- NULL + } + + return (reports) +} + + #' autotest_types #' #' List all types of 'autotests' currently implemented. diff --git a/R/typetrace-package.R b/R/typetrace-package.R index f61751a..6402572 100644 --- a/R/typetrace-package.R +++ b/R/typetrace-package.R @@ -36,13 +36,7 @@ autotest_trace_package <- function (package, Sys.unsetenv ("TYPETRACER_LEAVE_TRACES") # traces are still there - trace_files <- list.files ( - get_typetrace_dir (), - pattern = "^typetrace\\_.*\\.Rds$", - full.names = TRUE - ) - - return (trace_files) + return (traces) } # combine lists of `functions` to include and `exclude` into single vector diff --git a/codemeta.json b/codemeta.json index db70006..829d51e 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.199", + "version": "0.0.2.200", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", diff --git a/man/at_yaml_template.Rd b/man/at_yaml_template.Rd index c18822f..2532737 100644 --- a/man/at_yaml_template.Rd +++ b/man/at_yaml_template.Rd @@ -16,7 +16,6 @@ Generate a 'yaml' template for an 'autotest'. } \seealso{ Other yaml: -\code{\link{autotest_yaml}()}, \code{\link{examples_to_yaml}()} } \concept{yaml} diff --git a/man/autotest-package.Rd b/man/autotest-package.Rd index fdff875..d1dd4a3 100644 --- a/man/autotest-package.Rd +++ b/man/autotest-package.Rd @@ -18,7 +18,12 @@ Useful links: } \author{ -\strong{Maintainer}: Mark Padgham \email{mark.padgham@email.com} +\strong{Maintainer}: Mark Padgham \email{mark.padgham@email.com} (\href{https://orcid.org/0000-0003-2172-5265}{ORCID}) + +Other contributors: +\itemize{ + \item Jouni Helske (\href{https://orcid.org/0000-0001-7130-793X}{ORCID}) [contributor] +} } \keyword{internal} diff --git a/man/autotest_package.Rd b/man/autotest_package.Rd index 17dce43..40b64ae 100644 --- a/man/autotest_package.Rd +++ b/man/autotest_package.Rd @@ -64,7 +64,7 @@ Some columns may contain NA values, as explained in the Note. } \description{ Automatically test an entire package by converting examples to \code{yaml} format -and submitting each to the \link{autotest_yaml} function. +and submitting each to the \link{autotest_single_trace} function. } \note{ Some columns may contain NA values, including: diff --git a/man/autotest_yaml.Rd b/man/autotest_yaml.Rd deleted file mode 100644 index e55b159..0000000 --- a/man/autotest_yaml.Rd +++ /dev/null @@ -1,54 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/autotest-functions.R -\name{autotest_yaml} -\alias{autotest_yaml} -\title{autotest_yaml} -\usage{ -autotest_yaml( - yaml = NULL, - filename = NULL, - test = TRUE, - test_data = NULL, - quiet = FALSE -) -} -\arguments{ -\item{yaml}{A 'yaml' template as a character vector, either hand-coded or -potentially loaded via \link{readLines} function or similar. Should generally -be left at default of 'NULL', with template specified by 'filename' -parameter.} - -\item{filename}{Name (potentially including path) of file containing 'yaml' -template. See \link{at_yaml_template} for details of template. Default uses -template generated by that function, and held in local './tests' directory.} - -\item{test}{If \code{FALSE}, return only descriptions of tests which would be run -with \code{test = TRUE}, without actually running them.} - -\item{test_data}{Result returned from calling either \link{autotest_types} or -\link{autotest_package} with \code{test = FALSE} that contains a list of all tests -which would be conducted. These tests have an additional flag, \code{test}, which -defaults to \code{TRUE}. Setting any tests to \code{FALSE} will avoid running them when -\code{test = TRUE}.} - -\item{quiet}{If 'FALSE', provide printed output on screen.} -} -\value{ -An \code{autotest_pkg} object, derived from a \pkg{tibble}, detailing -instances of unexpected behaviour for every parameter of every function. -} -\description{ -Automatically test inputs to functions specified in a 'yaml' template. -} -\examples{ -\dontrun{ -yaml_list <- examples_to_yaml (package = "stats", functions = "reshape") -res <- autotest_yaml (yaml = yaml_list) -} -} -\seealso{ -Other yaml: -\code{\link{at_yaml_template}()}, -\code{\link{examples_to_yaml}()} -} -\concept{yaml} diff --git a/man/examples_to_yaml.Rd b/man/examples_to_yaml.Rd index 136bba1..bddc1e4 100644 --- a/man/examples_to_yaml.Rd +++ b/man/examples_to_yaml.Rd @@ -35,7 +35,6 @@ automatically test package. } \seealso{ Other yaml: -\code{\link{at_yaml_template}()}, -\code{\link{autotest_yaml}()} +\code{\link{at_yaml_template}()} } \concept{yaml} From 2507de83235bf4ddb3d63fb43670cb71383ea36e Mon Sep 17 00:00:00 2001 From: mpadge Date: Fri, 26 Aug 2022 13:39:00 +0200 Subject: [PATCH 06/11] fix pkg_dir param in autotest_single_trace for #76 --- DESCRIPTION | 2 +- R/autotest-functions.R | 4 +++- codemeta.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 4a18960..0d6c89b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.200 +Version: 0.0.2.201 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), diff --git a/R/autotest-functions.R b/R/autotest-functions.R index c98def6..ef9f4e3 100644 --- a/R/autotest-functions.R +++ b/R/autotest-functions.R @@ -83,6 +83,7 @@ autotest_package <- function (package = ".", res <- rbind (res, autotest_single_trace (package, + pkg_dir, readRDS (trace_files [i]), fn_pars, test = test, @@ -157,7 +158,8 @@ get_package_loc <- function (package) { #' @return An `autotest_pkg` object, derived from a \pkg{tibble}, detailing #' instances of unexpected behaviour for every parameter of every function. #' @noRd -autotest_single_trace <- function (pkg_dir = NULL, +autotest_single_trace <- function (package, + pkg_dir = NULL, trace_data = NULL, fn_pars, test = TRUE, diff --git a/codemeta.json b/codemeta.json index 829d51e..19cd73f 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.200", + "version": "0.0.2.201", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", From 89958790cd76f63ad65a3f032c54d71055919e54 Mon Sep 17 00:00:00 2001 From: mpadge Date: Mon, 5 Sep 2022 10:23:13 +0200 Subject: [PATCH 07/11] fix #80; thanks @maelle --- DESCRIPTION | 2 +- codemeta.json | 9 ++++++--- vignettes/autotest-control.Rmd | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 0d6c89b..acfe57c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.201 +Version: 0.0.2.202 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), diff --git a/codemeta.json b/codemeta.json index 48fec0a..7859698 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.201", + "version": "0.0.2.202", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -307,10 +307,13 @@ }, "sameAs": "https://CRAN.R-project.org/package=yaml" }, - "SystemRequirements": null + "SystemRequirements": {} }, "fileSize": "16405.362KB", "readme": "https://github.com/ropensci-review-tools/autotest/blob/main/README.md", - "contIntegration": ["https://github.com/ropensci-review-tools/autotest/actions?query=workflow%3AR-CMD-check", "https://codecov.io/gh/ropensci-review-tools/autotest"], + "contIntegration": [ + "https://github.com/ropensci-review-tools/autotest/actions?query=workflow%3AR-CMD-check", + "https://codecov.io/gh/ropensci-review-tools/autotest" + ], "developmentStatus": "https://www.repostatus.org/#concept" } diff --git a/vignettes/autotest-control.Rmd b/vignettes/autotest-control.Rmd index 4493e1f..4ac70ab 100644 --- a/vignettes/autotest-control.Rmd +++ b/vignettes/autotest-control.Rmd @@ -276,7 +276,7 @@ clicking on the listed object. The different types of tests which produced unexpected responses were: ```{r xt-operations} -table (xt$operation) +table (xt1$operation) ``` Two of those reflect the previous results regarding parameters unable to be @@ -434,7 +434,7 @@ the `test_data` object called `"note"` (case-insensitive), and include a note for each row which has `test = FALSE` explaining why those tests have been switched off. Lines in your test directory should look something like this: -```{r testthat-demo-testdata, collapse = TRUE, echo = TRUE, eval = FALSE} +```{r testthat-demo-testdata, collapse = TRUE, message = FALSE, echo = TRUE, eval = FALSE} library (testthat) # as called in your test suite # For example, to switch off vector-to-list-column tests: test_data <- autotest_types (notest = "vector_to_list_col") From 157a42e1496faeb27ea2643f32a58a1d0fdd6396 Mon Sep 17 00:00:00 2001 From: mpadge Date: Thu, 8 Sep 2022 13:32:18 +0200 Subject: [PATCH 08/11] restructure function-param-types.R to get types from traces for #76 --- DESCRIPTION | 2 +- R/autotest-functions.R | 45 ++------ R/function-param-types.R | 231 +++++++++------------------------------ codemeta.json | 9 +- 4 files changed, 66 insertions(+), 221 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index acfe57c..13f0a6c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.202 +Version: 0.0.2.203 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), diff --git a/R/autotest-functions.R b/R/autotest-functions.R index ef9f4e3..db2182c 100644 --- a/R/autotest-functions.R +++ b/R/autotest-functions.R @@ -166,52 +166,23 @@ autotest_single_trace <- function (package, test_data = NULL, quiet = FALSE) { - # get parameter values: - par_index <- which (!nzchar (names (trace_data))) - par_names_i <- vapply (trace_data [par_index], function (j) j$par, character (1L)) - par_vals_i <- lapply (trace_data [par_index], function (j) j$par_eval) - names (par_vals_i) <- par_names_i - index <- which (!vapply (par_vals_i, is.null, logical (1L))) - par_vals_i <- par_vals_i [index] - par_names_i <- par_names_i [index] - - # get parameter classes & types: - index <- which (fn_pars$fn_name == trace_data$fn_name & - fn_pars$par_name %in% par_names_i) - fn_pars_i <- fn_pars [index, ] - fn_pars_i <- fn_pars_i [match (fn_pars_i$par_name, par_names_i), ] - - # param_types are in [single, vector, tabular] - param_types <- rep (NA_character_, nrow (fn_pars_i)) - is_single <- vapply (fn_pars_i$length, function (j) - all (as.integer (strsplit (j, ",") [[1]]) <= 1L), - logical (1L)) - param_types [which (is_single)] <- "single" - is_rect <- vapply (trace_data [par_index], function (j) - j$typeof == "list" && length (dim (j$par_eval)) == 2, - logical (1L)) - param_types [which (is_rect)] <- "tabular" - - # reduce class to first value only - param_class <- gsub (",\\s.*$", "", fn_pars_i$class) - names (param_class) <- fn_pars_i$par_name - index <- which (!param_class %in% c (atomic_modes (), "data.frame")) - param_class <- param_class [index] + param_info <- get_param_info (trace_data, fn_pars) test_obj <- autotest_obj (package = package, package_loc = pkg_dir, fn_name = trace_data$fn_name, - parameters = par_vals_i, - parameter_types = param_types, - class = param_class, - classes = param_class, + parameters = param_info$value, + parameter_types = param_info$type, + class = param_info$class, + classes = param_info$class, env = new.env (), test = test, quiet = quiet) + int_val <- data.frame ( fn = trace_data$fn_name, - par = fn_pars_i$par_name, - int_val = fn_pars_i$storage_mode == "integer" + par = param_info$name, + int_val = param_info$storage_mode == "integer" ) test_obj <- add_int_attrs (test_obj, int_val) diff --git a/R/function-param-types.R b/R/function-param-types.R index bc49ac5..73b317b 100644 --- a/R/function-param-types.R +++ b/R/function-param-types.R @@ -1,187 +1,58 @@ - -get_param_types <- function (fn, params, par_lengths) { - - if (any (params == "NULL")) { - params <- params [params != "NULL"] - } - - single_index <- single_params (params) - vec_index <- vector_params (params) - rect_index <- tabular_params (params) - - param_types <- rep (NA_character_, length (params)) - param_types [vec_index] <- "vector" - param_types [single_index] <- "single" - param_types [rect_index] <- "tabular" - - # use par_lengths to set any parameters identified as single through usage - # in present example to vector - index <- which (par_lengths$par %in% names (params) & !par_lengths$single) - if (length (index) > 0) { - par_lengths <- par_lengths [index, , drop = FALSE] - param_types [match (par_lengths$par, names (params))] <- "vector" - } - - return (param_types) -} - -single_params <- function (params) { - - is_single <- function (j) { - chk <- FALSE - if (is.null (dim (j)) && length (j) == 1) { - if (methods::is (j, "name")) { - val <- tryCatch (eval (parse (text = j)), - error = function (e) NULL) - if (!is.null (val)) - chk <- length (val) == 1 - } else if (!isS4 (j)) { - # single objects can still be almost anything, so only - # consider as truly single those objects which have - # attribute lists each element of which have at most two - # elements. This is entirely arbitrary, and should be - # modified once more is known about the kinds of things - # thrown at this function. - lens <- vapply (attributes (j), length, integer (1)) - chk <- !any (lens > 2) - } - } else if (methods::is (j, "formula")) { - chk <- TRUE - } - return (chk) - } - - return (which (vapply (params, function (j) - is_single (j), - logical (1)))) -} - -vector_params <- function (params) { - - return (which (vapply (params, function (i) - length (i) > 1 && - is.null (dim (i)) && - is.atomic (i) && - length (class (i) <= 1L) && - any (grepl (atomic_modes (collapse = TRUE), - class (i))), - logical (1)))) -} - -tabular_params <- function (params) { - - return (which (vapply (params, function (i) - length (dim (i)) == 2 & - !(inherits (i, "Matrix") | - inherits (i, "matrix")), - logical (1)))) -} - -#' single_or_vec +#' Get names, values, types and classes of parameters #' -#' Do different usages within a single yaml indicate whether a parameter is -#' restricted to length one, or whether it can be a vector with length > 1? -#' @param res The parsed yaml returned from `parse_yaml_template`. +#' @param trace_data Result of a single 'typetracer' trace. +#' @param fn_pars Result of \link{get_unique_fn_pars} applied to a single trace. +#' @return A `list` of 4 item of "value", "type" and "class", and "storage_mode" +#' of each parameter, where "type" is one of "single", "vector", or "tabular" +#' (or otherwise NA). #' @noRd -single_or_vec <- function (res) { - - fns <- unique (names (res$parameters)) - - pkg_namespace <- paste0 ("package:", res$package) - pkg_env <- new.env (parent = as.environment (pkg_namespace)) - - pars <- lapply (fns, function (f) { - - pars <- res$parameters [names (res$parameters) == f] - pars <- lapply (pars, function (i) { - nms <- names (unlist (i)) - lens <- vapply (nms, function (j) { - ij <- unlist (i) [[j]] - out <- length (ij) - if (methods::is (ij, "name")) { - tmp <- tryCatch ( - eval (parse (text = ij), - envir = pkg_env), - error = function (e) NULL) - if (!is.null (tmp)) - out <- length (tmp) - } - return (out) - }, - integer (1)) - data.frame (name = nms, - len = lens) }) - - pars <- data.frame (do.call (rbind, unname (pars))) - pars <- lapply (split (pars, f = as.factor (pars$name)), - function (i) - i [which.max (i$len), , drop = FALSE]) - - pars <- do.call (rbind, pars) - - data.frame (fn = f, - par = pars$name, - single = pars$len == 1, - stringsAsFactors = FALSE) - }) - - return (do.call (rbind, pars)) +get_param_info <- function (trace_data, fn_pars) { + + # get parameter values: + par_index <- which (!nzchar (names (trace_data))) + par_names_i <- vapply (trace_data [par_index], function (j) j$par, character (1L)) + par_vals_i <- lapply (trace_data [par_index], function (j) j$par_eval) + names (par_vals_i) <- par_names_i + index <- which (!vapply (par_vals_i, is.null, logical (1L))) + par_vals_i <- par_vals_i [index] + par_names_i <- par_names_i [index] + + # get parameter classes & types: + index <- which (fn_pars$fn_name == trace_data$fn_name & + fn_pars$par_name %in% par_names_i) + fn_pars_i <- fn_pars [index, ] + fn_pars_i <- fn_pars_i [match (fn_pars_i$par_name, par_names_i), ] + + index <- which (par_names_i %in% fn_pars_i$par_name) + par_vals_i <- par_vals_i [index] + par_names_i <- par_names_i [index] + + # param_types are in [single, vector, tabular] + param_types <- rep (NA_character_, nrow (fn_pars_i)) + is_single <- vapply (fn_pars_i$length, function (j) + all (as.integer (strsplit (j, ",") [[1]]) <= 1L), + logical (1L)) + param_types [which (is_single)] <- "single" + is_rect <- vapply (trace_data [par_index], function (j) + j$typeof == "list" && length (dim (j$par_eval)) == 2, + logical (1L)) + param_types [which (is_rect)] <- "tabular" + + # reduce class to first value only + param_class <- gsub (",\\s.*$", "", fn_pars_i$class) + names (param_class) <- fn_pars_i$par_name + index <- which (!param_class %in% c (atomic_modes (), "data.frame")) + param_class <- param_class [index] + + list ( + name = par_names_i, + value = par_vals_i, + type = param_types, + class = param_class, + storage_mode = fn_pars_i$storage_mode + ) } -#' double_or_int -#' -#' Do different usages within a single yaml indicate whether a single-length -#' parameter is intended to be an integer, yet without `L`, or whether it is -#' indeed a double? -#' @param res The parsed yaml returned from `parse_yaml_template`. -#' @noRd -double_or_int <- function (res) { - - fns <- unique (names (res$parameters)) - - is_par_int <- function (p) { - ret <- FALSE - if (is.numeric (p)) - ret <- all (abs (p - round (p)) < .Machine$double.eps) - if (!is.null (attr (p, "is_int"))) - if (!attr (p, "is_int")) - ret <- FALSE - return (ret) - } - - pars <- lapply (fns, function (f) { - - pars <- res$parameters [names (res$parameters) == f] [[1]] - nms <- vapply (pars, names, character (1)) - pars <- lapply (pars, function (i) i [[1]]) - names (pars) <- nms - - pars <- lapply (seq_along (pars), function (i) { - nms <- names (pars) [i] - int_val <- is_par_int (pars [[i]]) - data.frame (name = nms, - int_val = int_val) - }) - - pars <- data.frame (do.call (rbind, unname (pars))) - pars <- lapply (split (pars, f = as.factor (pars$name)), - function (i) { - int_val <- all (i$int_val) - i <- i [1, ] - i$int_val <- int_val - return (i) - }) - - pars <- do.call (rbind, pars) - - data.frame (fn = f, - par = pars$name, - int_val = pars$int_val, - stringsAsFactors = FALSE) - }) - - return (do.call (rbind, pars)) -} # add attributes to elements of `autotest_object` `x` identifying any parameters # which are exclusively used as `int`, but not explicitly specified as such diff --git a/codemeta.json b/codemeta.json index 7fe1900..3b0d7de 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.202", + "version": "0.0.2.203", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -313,10 +313,13 @@ }, "sameAs": "https://CRAN.R-project.org/package=yaml" }, - "SystemRequirements": null + "SystemRequirements": {} }, "fileSize": "487.484KB", "readme": "https://github.com/ropensci-review-tools/autotest/blob/main/README.md", - "contIntegration": ["https://github.com/ropensci-review-tools/autotest/actions?query=workflow%3AR-CMD-check", "https://codecov.io/gh/ropensci-review-tools/autotest"], + "contIntegration": [ + "https://github.com/ropensci-review-tools/autotest/actions?query=workflow%3AR-CMD-check", + "https://codecov.io/gh/ropensci-review-tools/autotest" + ], "developmentStatus": "https://www.repostatus.org/#concept" } From f688d321b9298bbe84ceef9cdde23e0f43f8ccbe Mon Sep 17 00:00:00 2001 From: mpadge Date: Thu, 8 Sep 2022 13:52:46 +0200 Subject: [PATCH 09/11] add vector type to get_param info fn for #76 --- DESCRIPTION | 2 +- R/function-param-types.R | 7 +++++++ codemeta.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 13f0a6c..a5a9aa7 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.203 +Version: 0.0.2.204 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), diff --git a/R/function-param-types.R b/R/function-param-types.R index 73b317b..e76c910 100644 --- a/R/function-param-types.R +++ b/R/function-param-types.R @@ -29,10 +29,17 @@ get_param_info <- function (trace_data, fn_pars) { # param_types are in [single, vector, tabular] param_types <- rep (NA_character_, nrow (fn_pars_i)) + is_single <- vapply (fn_pars_i$length, function (j) all (as.integer (strsplit (j, ",") [[1]]) <= 1L), logical (1L)) param_types [which (is_single)] <- "single" + + is_vector <- vapply (fn_pars_i$length, function (j) + any (as.integer (strsplit (j, ",") [[1]]) > 1L), + logical (1L)) + param_types [which (is_vector)] <- "vector" + is_rect <- vapply (trace_data [par_index], function (j) j$typeof == "list" && length (dim (j$par_eval)) == 2, logical (1L)) diff --git a/codemeta.json b/codemeta.json index 3b0d7de..a941d7e 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.203", + "version": "0.0.2.204", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", From 43949cccda433f05cddddb6060c20ec98928288a Mon Sep 17 00:00:00 2001 From: mpadge Date: Thu, 8 Sep 2022 14:58:13 +0200 Subject: [PATCH 10/11] fix extraction of param_call from get_param_info for #76 --- DESCRIPTION | 2 +- R/function-param-types.R | 20 +++++++++++++------- codemeta.json | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index a5a9aa7..ad4a251 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.204 +Version: 0.0.2.205 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), diff --git a/R/function-param-types.R b/R/function-param-types.R index e76c910..bc9e4a0 100644 --- a/R/function-param-types.R +++ b/R/function-param-types.R @@ -45,15 +45,21 @@ get_param_info <- function (trace_data, fn_pars) { logical (1L)) param_types [which (is_rect)] <- "tabular" - # reduce class to first value only - param_class <- gsub (",\\s.*$", "", fn_pars_i$class) - names (param_class) <- fn_pars_i$par_name - index <- which (!param_class %in% c (atomic_modes (), "data.frame")) - param_class <- param_class [index] + # reduce class to first non-generic value only + # start by removing generic classes, which may be first of several items, so + # first remove all ", " versions. + atomics <- paste0 (atomic_modes (), collapse = "|") + atomics <- paste0 (atomics, "|matrix|array|data\\.frame") + ptn <- paste0 ("(", atomics, "),\\s*") + param_class <- gsub (ptn, "", fn_pars_i$class) + param_class <- gsub (atomics, "", param_class) + param_class <- gsub ("^\\,\\s+", "", param_class) - list ( + param_class [which (!nzchar (param_class))] <- NA_character_ + + data.frame ( name = par_names_i, - value = par_vals_i, + value = I (par_vals_i), type = param_types, class = param_class, storage_mode = fn_pars_i$storage_mode diff --git a/codemeta.json b/codemeta.json index a941d7e..88eeee1 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.204", + "version": "0.0.2.205", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", From 845895a3fa9c734db50bcb27fbbb0105f83237b6 Mon Sep 17 00:00:00 2001 From: mpadge Date: Thu, 8 Sep 2022 15:18:20 +0200 Subject: [PATCH 11/11] fix verbose message in autotest_single_trace --- DESCRIPTION | 2 +- R/autotest-functions.R | 2 +- codemeta.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index ad4a251..771f4ed 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: autotest Title: Automatic Package Testing -Version: 0.0.2.205 +Version: 0.0.2.206 Authors@R: c( person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2172-5265")), diff --git a/R/autotest-functions.R b/R/autotest-functions.R index db2182c..c523067 100644 --- a/R/autotest-functions.R +++ b/R/autotest-functions.R @@ -202,7 +202,7 @@ autotest_single_trace <- function (package, reports <- rbind (reports, test_param_documentation (test_obj)) if (!quiet) { - message (cli::col_green (cli::symbol$tick, " ", this_fn)) + message (cli::col_green (cli::symbol$tick, " ", trace_data$fn_name)) } if (!is.null (reports)) { diff --git a/codemeta.json b/codemeta.json index 88eeee1..1982df0 100644 --- a/codemeta.json +++ b/codemeta.json @@ -8,7 +8,7 @@ "codeRepository": "https://github.com/ropensci-review-tools/autotest", "issueTracker": "https://github.com/ropensci-review-tools/autotest/issues", "license": "https://spdx.org/licenses/GPL-3.0", - "version": "0.0.2.205", + "version": "0.0.2.206", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R",