diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 036ed30..4aa7992 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -98,26 +98,39 @@ The encoding process: Use `makeTestsFromExamples()` to automatically generate test files from JASP example files: ```r -# Generate tests from JASP files in the module's examples/ folder +# Generate tests from all source folders (library, verified, other) # Uses working directory as module by default makeTestsFromExamples() -# Specify module directory explicitly +# Specify the module directory explicitly makeTestsFromExamples(module.dir = "path/to/jaspModule") -# Import JASP files from external path, copy to examples/, and generate tests +# Only generate from the 'library' source folder +makeTestsFromExamples(source = "library") + +# Import JASP files from external path (copies to jaspfiles/other/ and generates tests) makeTestsFromExamples(path = "path/to/jasp/files", module.dir = "path/to/module") -# Overwrite existing test files +# Overwrite existing test files (skips verified by default) makeTestsFromExamples(overwrite = TRUE) +# Overwrite including verified (prompts for confirmation) +makeTestsFromExamples(source = c("library", "verified", "other"), overwrite = TRUE) + # Sanitize filenames (replace spaces/special chars with hyphens) makeTestsFromExamples(sanitize = TRUE) ``` +**Source Folders**: JASP example files are stored in `tests/testthat/jaspfiles/{library,verified,other}/`. The `source` argument controls which folders to process: +- `"library"` — JASP files from the analysis library +- `"verified"` — Manually verified/curated test files +- `"other"` — Other/imported JASP files (default target for `path` imports) + +**Defaults**: When `overwrite = FALSE` (default), all three sources are processed. When `overwrite = TRUE`, only `"library"` and `"other"` are processed to protect verified tests. + Generated test files: -- Named `test-example-{filename}.R` in `tests/testthat/` -- Load options and data from JASP files at runtime +- Named `test-{source}-{filename}.R` in `tests/testthat/` (e.g., `test-library-MyAnalysis.R`) +- Load options and data from JASP files at runtime via `testthat::test_path("jaspfiles", "{source}", "file.jasp")` - Include table expectations via `expect_equal_tables()` - Include plot expectations via `expect_equal_plots()` with unique names: `analysis-1_figure-1_plot-title` @@ -191,7 +204,7 @@ Check versions with `.checkUpdatesJaspCorePkgs()` on package load. - `R/rbridge.R`: RCPP bridge replacements (`.readDatasetToEndNative`, `.requestTempFileNameNative`, etc.) - `R/pkg-setup.R`: Initial setup, dependency fetching - `R/utils.R`: Module path resolution, validation, helper functions -- `R/test-generator.R`: Auto-generate test expectations from results, `makeTestsFromExamples()` +- `R/test-generator.R`: Auto-generate test expectations from results, `makeTestsFromExamples()`. JASP files live in `tests/testthat/jaspfiles/{library,verified,other}/`; generated tests are named `test-{source}-{name}.R`. - `R/testthat-helper-*.R`: Custom `expect_equal_tables()` and `expect_equal_plots()` ## Debugging Tips diff --git a/R/test-generator.R b/R/test-generator.R index 96ddd75..7d60c5c 100644 --- a/R/test-generator.R +++ b/R/test-generator.R @@ -4,10 +4,17 @@ #' #' @param path Optional string path to a directory containing JASP example files. #' If provided, the JASP files at this path will be copied to the module's -#' \code{examples/} folder before generating tests. If missing, the function processes -#' JASP files already present in the module's \code{examples/} folder. +#' \code{tests/testthat/jaspfiles/other/} folder and test files named +#' \code{test-other-{name}.R} are generated. The \code{source} argument is +#' ignored when \code{path} is provided. #' @param module.dir String path to the module directory. If missing, uses the current #' working directory. +#' @param source Character vector specifying which source folders under +#' \code{tests/testthat/jaspfiles/} to process. Allowed values are +#' \code{"library"}, \code{"verified"}, and \code{"other"}. Defaults to all +#' three when \code{overwrite = FALSE} and to \code{c("library", "other")} +#' when \code{overwrite = TRUE}. If \code{"verified"} is included and +#' \code{overwrite = TRUE}, the user is prompted for confirmation. #' @param sanitize Logical. If TRUE, sanitizes test filenames by replacing non-word characters #' with hyphens. If FALSE (default), preserves original spacing and characters in filenames. #' @param overwrite Logical. If TRUE, overwrites existing test files. If FALSE (default), @@ -19,14 +26,12 @@ #' column names replaced with their encoded equivalents using word-boundary-aware regex. #' #' @details -#' This function processes JASP example files and generates corresponding test files in -#' the module's \code{tests/testthat} directory. Each JASP file becomes a single test file -#' named "test-example-{basename}.R", where {basename} is the original JASP filename without -#' the .jasp extension. -#' -#' The JASP example files must be located in the module's \code{examples/} folder for the -#' generated tests to work at runtime. When \code{path} is provided, files are automatically -#' copied to the module's \code{examples/} folder. +#' This function processes JASP example files stored under +#' \code{tests/testthat/jaspfiles/{library,verified,other}/} and generates corresponding +#' test files in the module's \code{tests/testthat} directory. Each JASP file becomes a +#' single test file named \code{test-{source}-{basename}.R}, where \code{{source}} is the +#' source folder name (\code{library}, \code{verified}, or \code{other}) and \code{{basename}} +#' is the original JASP filename without the .jasp extension. #' #' If a JASP file contains multiple analyses, they are included as separate \code{test_that()} #' blocks within the same test file. @@ -43,17 +48,19 @@ #' library(jaspTools) #' setupJaspTools() #' -#' # Create tests from JASP files already in the module's examples/ folder -#' # (uses working directory as module) +#' # Create tests from all source folders (library, verified, other) #' makeTestsFromExamples() #' #' # Specify the module directory explicitly #' makeTestsFromExamples(module.dir = "path/to/your/module") #' -#' # Import JASP files from another directory, copy to examples/, and generate tests +#' # Only generate tests from the 'library' source folder +#' makeTestsFromExamples(source = "library") +#' +#' # Import JASP files from another directory (copies to jaspfiles/other/) #' makeTestsFromExamples(path = "path/to/jasp/files", module.dir = "path/to/module") #' -#' # Overwrite existing test files +#' # Overwrite existing test files (skips verified by default) #' makeTestsFromExamples(overwrite = TRUE) #' #' # Force encode 'model' option for analyses with embedded variable names @@ -61,10 +68,11 @@ #' } #' #' @export makeTestsFromExamples -makeTestsFromExamples <- function(path, module.dir, sanitize = FALSE, overwrite = FALSE, - forceEncode = NULL) { - # Determine module directory +makeTestsFromExamples <- function(path, module.dir, source, sanitize = FALSE, + overwrite = FALSE, forceEncode = NULL) { + validSources <- c("library", "verified", "other") + # Determine module directory if (missing(module.dir)) { module.dir <- getwd() message("Using working directory as module: ", module.dir) @@ -85,17 +93,12 @@ makeTestsFromExamples <- function(path, module.dir, sanitize = FALSE, overwrite qmlContent <- parseDescriptionQmlFromPath(qmlPath) pkgAnalyses <- setdiff(names(qmlContent), "Description") } else { - stop("Description.qml not found at path: ", qmlPath, + stop("Description.qml not found at path: ", qmlPath, ". Make sure the module contains inst/Description.qml (source) or Description.qml (installed).") } - - # Collect JASP files to process - jaspFiles <- character(0) - copyToExamples <- FALSE - + # When path is provided, always target "other" and ignore source if (!missing(path)) { - # Path provided: collect files from this path and mark them for copying if (!dir.exists(path)) { stop("Directory does not exist: ", path) } @@ -105,62 +108,146 @@ makeTestsFromExamples <- function(path, module.dir, sanitize = FALSE, overwrite stop("No .jasp files found in directory: ", path) } - copyToExamples <- TRUE - message("Will copy JASP files to module examples/ folder before generating tests.\n") - } else { - # No path provided: collect files from module's examples/ folder - examplesDir <- file.path(module.dir, "examples") - if (dir.exists(examplesDir)) { - jaspFiles <- list.files(examplesDir, pattern = "\\.jasp$", full.names = TRUE) + # Ensure destination directory exists + otherDir <- file.path(module.dir, "tests", "testthat", "jaspfiles", "other") + if (!dir.exists(otherDir)) { + dir.create(otherDir, recursive = TRUE) } - if (length(jaspFiles) == 0) { - stop("No .jasp files found in module's examples/ folder: ", examplesDir) + message("Copying JASP files to tests/testthat/jaspfiles/other/ and generating tests.\n") + + createdFiles <- character(0) + skippedFiles <- character(0) + copiedFiles <- character(0) + + for (jaspFile in jaspFiles) { + message("Processing: ", basename(jaspFile)) + + tryCatch( + { + result <- makeTestsFromSingleJASPFile(jaspFile, + module.dir = module.dir, + sourceFolder = "other", + sanitize = sanitize, + overwrite = overwrite, + copyToJaspfiles = TRUE, + pkgAnalyses = pkgAnalyses, + forceEncode = forceEncode + ) + if (!is.null(result)) { + if (!is.null(attr(result, "copiedTo"))) { + copiedFiles <- c(copiedFiles, attr(result, "copiedTo")) + } + if (isTRUE(attr(result, "skipped"))) { + skippedFiles <- c(skippedFiles, result) + message(" Skipped (already exists): ", result) + } else { + createdFiles <- c(createdFiles, result) + message(" Created: ", result) + } + } else { + message(" No tests created (all analyses were skipped)") + } + }, + error = function(e) { + warning("Failed to process ", basename(jaspFile), ": ", e$message, call. = FALSE) + } + ) + } + + .printTestGenerationSummary(createdFiles, skippedFiles, copiedFiles, "other") + return(invisible(createdFiles)) + } + + # No path provided: process source folders + if (missing(source)) { + if (overwrite) { + source <- c("library", "other") + } else { + source <- validSources + } + } + + source <- match.arg(source, validSources, several.ok = TRUE) + + # Warn if overwriting verified tests + if (overwrite && "verified" %in% source) { + if (interactive()) { + answer <- utils::menu( + choices = c("Yes", "No"), + title = "WARNING: You are about to overwrite verified test files. Are you sure?" + ) + if (answer != 1) { + message("Aborted. Remove 'verified' from source or set overwrite = FALSE.") + return(invisible(character(0))) + } + } else { + warning("Overwriting verified test files in non-interactive mode.", call. = FALSE) } } createdFiles <- character(0) skippedFiles <- character(0) - copiedFiles <- character(0) - for (jaspFile in jaspFiles) { - message("Processing: ", basename(jaspFile)) + for (src in source) { + srcDir <- file.path(module.dir, "tests", "testthat", "jaspfiles", src) - tryCatch( - { - result <- makeTestsFromSingleJASPFile(jaspFile, - module.dir = module.dir, - sanitize = sanitize, overwrite = overwrite, - copyToExamples = copyToExamples, - pkgAnalyses = pkgAnalyses, - forceEncode = forceEncode - ) - if (!is.null(result)) { - if (!is.null(attr(result, "copiedTo"))) { - copiedFiles <- c(copiedFiles, attr(result, "copiedTo")) - } - if (isTRUE(attr(result, "skipped"))) { - skippedFiles <- c(skippedFiles, result) - message(" Skipped (already exists): ", result) + if (!dir.exists(srcDir)) { + message("Source folder does not exist, skipping: ", srcDir) + next + } + + jaspFiles <- list.files(srcDir, pattern = "\\.jasp$", full.names = TRUE) + if (length(jaspFiles) == 0) { + message("No .jasp files found in: ", srcDir) + next + } + + message("\n--- Processing source: ", src, " (", length(jaspFiles), " file(s)) ---\n") + + for (jaspFile in jaspFiles) { + message("Processing: ", basename(jaspFile)) + + tryCatch( + { + result <- makeTestsFromSingleJASPFile(jaspFile, + module.dir = module.dir, + sourceFolder = src, + sanitize = sanitize, + overwrite = overwrite, + copyToJaspfiles = FALSE, + pkgAnalyses = pkgAnalyses, + forceEncode = forceEncode + ) + if (!is.null(result)) { + if (isTRUE(attr(result, "skipped"))) { + skippedFiles <- c(skippedFiles, result) + message(" Skipped (already exists): ", result) + } else { + createdFiles <- c(createdFiles, result) + message(" Created: ", result) + } } else { - createdFiles <- c(createdFiles, result) - message(" Created: ", result) + message(" No tests created (all analyses were skipped)") } - } else { - message(" No tests created (all analyses were skipped)") + }, + error = function(e) { + warning("Failed to process ", basename(jaspFile), ": ", e$message, call. = FALSE) } - }, - error = function(e) { - warning("Failed to process ", basename(jaspFile), ": ", e$message, call. = FALSE) - } - ) + ) + } } + .printTestGenerationSummary(createdFiles, skippedFiles, character(0), paste(source, collapse = ", ")) + invisible(createdFiles) +} + +.printTestGenerationSummary <- function(createdFiles, skippedFiles, copiedFiles, sourceLabel) { if (length(createdFiles) == 0 && length(skippedFiles) == 0) { warning("No test files were created.") } else { if (length(copiedFiles) > 0) { - message("\nCopied ", length(copiedFiles), " JASP file(s) to module examples/ folder(s).") + message("\nCopied ", length(copiedFiles), " JASP file(s) to tests/testthat/jaspfiles/", sourceLabel, "/.") } if (length(createdFiles) > 0) { message("Created ", length(createdFiles), " test file(s).") @@ -169,8 +256,6 @@ makeTestsFromExamples <- function(path, module.dir, sanitize = FALSE, overwrite message("Skipped ", length(skippedFiles), " existing test file(s). Use overwrite = TRUE to regenerate.") } } - - invisible(createdFiles) } @@ -180,10 +265,12 @@ makeTestsFromExamples <- function(path, module.dir, sanitize = FALSE, overwrite #' #' @param jaspFile Path to the .jasp file. #' @param module.dir Path to the module directory. +#' @param sourceFolder String indicating the source folder: \code{"library"}, +#' \code{"verified"}, or \code{"other"}. #' @param sanitize Whether to sanitize the filename. #' @param overwrite Whether to overwrite existing test files. -#' @param copyToExamples Whether to copy the JASP file to the module's examples folder. -#' +#' @param copyToJaspfiles Whether to copy the JASP file to +#' \code{tests/testthat/jaspfiles/{sourceFolder}/}. #' @param pkgAnalyses Optional character vector of allowed analysis names for this module. #' If provided, analyses not in this list will be skipped. #' @param forceEncode Optional character vector of option names to force-encode via regex. @@ -192,8 +279,9 @@ makeTestsFromExamples <- function(path, module.dir, sanitize = FALSE, overwrite #' and attr "copiedTo" if copied), or NULL if no tests were generated #' (e.g., all analyses were skipped or processing failed). #' @keywords internal -makeTestsFromSingleJASPFile <- function(jaspFile, module.dir, sanitize = FALSE, - overwrite = FALSE, copyToExamples = FALSE, +makeTestsFromSingleJASPFile <- function(jaspFile, module.dir, sourceFolder, + sanitize = FALSE, overwrite = FALSE, + copyToJaspfiles = FALSE, pkgAnalyses = NULL, forceEncode = NULL) { # Extract options from the JASP file allOptions <- analysisOptions(jaspFile) @@ -223,14 +311,14 @@ makeTestsFromSingleJASPFile <- function(jaspFile, module.dir, sanitize = FALSE, # Track if we copied the file copiedTo <- NULL - # Copy JASP file to module's examples folder if requested - if (copyToExamples) { - examplesDir <- file.path(module.dir, "examples") - if (!dir.exists(examplesDir)) { - dir.create(examplesDir, recursive = TRUE) - message(" Created directory: ", examplesDir) + # Copy JASP file to module's jaspfiles/{sourceFolder}/ if requested + if (copyToJaspfiles) { + destDir <- file.path(module.dir, "tests", "testthat", "jaspfiles", sourceFolder) + if (!dir.exists(destDir)) { + dir.create(destDir, recursive = TRUE) + message(" Created directory: ", destDir) } - destFile <- file.path(examplesDir, basename(jaspFile)) + destFile <- file.path(destDir, basename(jaspFile)) file.copy(jaspFile, destFile, overwrite = TRUE) copiedTo <- destFile message(" Copied to: ", destFile) @@ -244,8 +332,8 @@ makeTestsFromSingleJASPFile <- function(jaspFile, module.dir, sanitize = FALSE, message(" Created directory: ", testDir) } - # Determine test file path using "test-example-Name.R" format - testFileName <- paste0("test-example-", sanitizedName, ".R") + # Determine test file path using "test-{sourceFolder}-Name.R" format + testFileName <- paste0("test-", sourceFolder, "-", sanitizedName, ".R") testFilePath <- file.path(testDir, testFileName) # Check if file already exists @@ -292,6 +380,7 @@ makeTestsFromSingleJASPFile <- function(jaspFile, module.dir, sanitize = FALSE, analysisIndex = i, totalAnalyses = length(allOptions), jaspFileName = basename(jaspFile), + sourceFolder = sourceFolder, results = results, forceEncode = forceEncode ) @@ -306,6 +395,7 @@ makeTestsFromSingleJASPFile <- function(jaspFile, module.dir, sanitize = FALSE, analysisIndex = i, totalAnalyses = length(allOptions), jaspFileName = basename(jaspFile), + sourceFolder = sourceFolder, forceEncode = forceEncode ) testBlocks <<- c(testBlocks, list(testBlock)) @@ -319,7 +409,7 @@ makeTestsFromSingleJASPFile <- function(jaspFile, module.dir, sanitize = FALSE, } # Generate the test file content - testContent <- generateExampleTestFileContent(baseName, sanitizedName, testBlocks) + testContent <- generateExampleTestFileContent(baseName, sanitizedName, sourceFolder, testBlocks) # Write the test file writeLines(testContent, testFilePath) @@ -331,24 +421,27 @@ makeTestsFromSingleJASPFile <- function(jaspFile, module.dir, sanitize = FALSE, } -#' Generate test file content for example-based tests +#' Generate test file content for source-based tests #' #' @param baseName Original JASP file name without extension. #' @param sanitizedName Sanitized name for use in code. +#' @param sourceFolder String indicating the source folder: \code{"library"}, +#' \code{"verified"}, or \code{"other"}. #' @param testBlocks List of test block strings. #' #' @return Character string with complete test file content. #' @keywords internal -generateExampleTestFileContent <- function(baseName, sanitizedName, testBlocks) { +generateExampleTestFileContent <- function(baseName, sanitizedName, sourceFolder, testBlocks) { lines <- character(0) # Header - lines <- c(lines, paste0('context("Example: ', baseName, '")')) + sourceLabelCap <- paste0(toupper(substring(sourceFolder, 1, 1)), substring(sourceFolder, 2)) + lines <- c(lines, paste0('context("', sourceLabelCap, ': ', baseName, '")')) lines <- c(lines, "") # Helper comment lines <- c(lines, "# This test file was auto-generated from a JASP example file.") - lines <- c(lines, "# The JASP file is stored in the module's examples/ folder.") + lines <- c(lines, paste0("# The JASP file is stored in tests/testthat/jaspfiles/", sourceFolder, "/.")) lines <- c(lines, "") # Add each test block @@ -366,13 +459,15 @@ generateExampleTestFileContent <- function(baseName, sanitizedName, testBlocks) #' @param analysisIndex Index of this analysis in the JASP file. #' @param totalAnalyses Total number of analyses in the file. #' @param jaspFileName Name of the JASP file. +#' @param sourceFolder String indicating the source folder: \code{"library"}, +#' \code{"verified"}, or \code{"other"}. #' @param results The analysis results. #' @param forceEncode Optional character vector of option names to force-encode via regex. #' #' @return Character string with the test_that block. #' @keywords internal -generateExampleTestBlock <- function(analysisName, analysisIndex, totalAnalyses, jaspFileName, results, - forceEncode = NULL) { +generateExampleTestBlock <- function(analysisName, analysisIndex, totalAnalyses, jaspFileName, + sourceFolder, results, forceEncode = NULL) { # Extract tests from results tests <- tryCatch( { @@ -396,9 +491,9 @@ generateExampleTestBlock <- function(analysisName, analysisIndex, totalAnalyses, lines <- c(lines, paste0('test_that("', testDesc, '", {')) lines <- c(lines, "") - # Extract from JASP file in module's examples folder + # Extract from JASP file in module's jaspfiles folder lines <- c(lines, " # Load from JASP example file") - lines <- c(lines, paste0(' jaspFile <- testthat::test_path("..", "..", "examples", "', jaspFileName, '")')) + lines <- c(lines, paste0(' jaspFile <- testthat::test_path("jaspfiles", "', sourceFolder, '", "', jaspFileName, '")')) # Generate appropriate options extraction based on number of analyses if (totalAnalyses == 1) { @@ -466,12 +561,14 @@ generateExampleTestBlock <- function(analysisName, analysisIndex, totalAnalyses, #' @param analysisIndex Index of this analysis in the JASP file. #' @param totalAnalyses Total number of analyses in the file. #' @param jaspFileName Name of the JASP file. +#' @param sourceFolder String indicating the source folder: \code{"library"}, +#' \code{"verified"}, or \code{"other"}. #' @param forceEncode Optional character vector of option names to force-encode via regex. #' #' @return Character string with the test_that block. #' @keywords internal generateExampleTestBlockBasic <- function(analysisName, analysisIndex, totalAnalyses, jaspFileName, - forceEncode = NULL) { + sourceFolder, forceEncode = NULL) { lines <- character(0) # Test description @@ -484,9 +581,9 @@ generateExampleTestBlockBasic <- function(analysisName, analysisIndex, totalAnal lines <- c(lines, paste0('test_that("', testDesc, '", {')) lines <- c(lines, "") - # Extract from JASP file in module's examples folder + # Extract from JASP file in module's jaspfiles folder lines <- c(lines, " # Load from JASP example file") - lines <- c(lines, paste0(' jaspFile <- testthat::test_path("..", "..", "examples", "', jaspFileName, '")')) + lines <- c(lines, paste0(' jaspFile <- testthat::test_path("jaspfiles", "', sourceFolder, '", "', jaspFileName, '")')) # Generate appropriate options extraction based on number of analyses if (totalAnalyses == 1) { diff --git a/R/test.R b/R/test.R index 544da95..13e76c4 100644 --- a/R/test.R +++ b/R/test.R @@ -33,6 +33,11 @@ runTestsTravis <- function(modulePath) { #' Tests a specific R analysis found under module/tests/testthat. Useful to perform before #' making a pull request, to prevent failing builds. #' +#' In addition to the standard test file (e.g., \code{test-AnalysisName.R}), this function +#' also discovers auto-generated source-based test files (\code{test-library-*.R}, +#' \code{test-verified-*.R}, \code{test-other-*.R}) that contain +#' \code{runAnalysis("AnalysisName", ...)} calls. This ensures that tests +#' created by \code{\link{makeTestsFromExamples}} are included when testing an analysis. #' #' @param name String name of the analysis to test (case sensitive). #' @param onlyPlots Would you like to only run the tests for plots? This can speed up the generating of reference images in case you are not interested in the other unit tests. @@ -290,14 +295,26 @@ getTestFilesMatchingName <- function(name, modulePath) { if (length(testFiles) == 0) stop("No files found to test.") - analysisNames <- gsub("^test-(verified-)?", "", testFiles) + # Pass 1: match by file name (e.g., test-AnalysisName.R) + analysisNames <- gsub("^test-(verified-|library-|other-)?", "", testFiles) analysisNames <- gsub("\\.[rR]$", "", analysisNames) - matches <- which(tolower(basename(analysisNames)) == tolower(name)) - if (length(matches) == 0) - stop("Could not locate test-", name, ".R, found the following testfiles: ", paste(basename(testFiles), collapse = ", ")) + matchedFiles <- testFiles[matches] + + # Pass 2: scan test-{library,verified,other}-* files for runAnalysis("name", ...) calls + sourceFiles <- testFiles[grepl("^test-(library|verified|other)-.*\\.[rR]$", testFiles)] + sourceFiles <- setdiff(sourceFiles, matchedFiles) + pattern <- paste0('runAnalysis\\(\\s*["\']', name, '["\']') + for (ef in sourceFiles) { + content <- readLines(file.path(testsDir, ef), warn = FALSE) + if (any(grepl(pattern, content))) + matchedFiles <- c(matchedFiles, ef) + } + + if (length(matchedFiles) == 0) + stop("Could not locate test file for ", name, ". Found the following test files: ", paste(basename(testFiles), collapse = ", ")) - return(testFiles[matches]) + return(matchedFiles) } printSuccessFailureModules <- function(testResults) { diff --git a/man/generateExampleTestBlock.Rd b/man/generateExampleTestBlock.Rd index 09953d9..d44b314 100644 --- a/man/generateExampleTestBlock.Rd +++ b/man/generateExampleTestBlock.Rd @@ -9,6 +9,7 @@ generateExampleTestBlock( analysisIndex, totalAnalyses, jaspFileName, + sourceFolder, results, forceEncode = NULL ) @@ -22,6 +23,9 @@ generateExampleTestBlock( \item{jaspFileName}{Name of the JASP file.} +\item{sourceFolder}{String indicating the source folder: \code{"library"}, +\code{"verified"}, or \code{"other"}.} + \item{results}{The analysis results.} \item{forceEncode}{Optional character vector of option names to force-encode via regex.} diff --git a/man/generateExampleTestBlockBasic.Rd b/man/generateExampleTestBlockBasic.Rd index 2cb5947..86a87d7 100644 --- a/man/generateExampleTestBlockBasic.Rd +++ b/man/generateExampleTestBlockBasic.Rd @@ -9,6 +9,7 @@ generateExampleTestBlockBasic( analysisIndex, totalAnalyses, jaspFileName, + sourceFolder, forceEncode = NULL ) } @@ -21,6 +22,9 @@ generateExampleTestBlockBasic( \item{jaspFileName}{Name of the JASP file.} +\item{sourceFolder}{String indicating the source folder: \code{"library"}, +\code{"verified"}, or \code{"other"}.} + \item{forceEncode}{Optional character vector of option names to force-encode via regex.} } \value{ diff --git a/man/generateExampleTestFileContent.Rd b/man/generateExampleTestFileContent.Rd index 78efe7c..ea77fe6 100644 --- a/man/generateExampleTestFileContent.Rd +++ b/man/generateExampleTestFileContent.Rd @@ -2,21 +2,29 @@ % Please edit documentation in R/test-generator.R \name{generateExampleTestFileContent} \alias{generateExampleTestFileContent} -\title{Generate test file content for example-based tests} +\title{Generate test file content for source-based tests} \usage{ -generateExampleTestFileContent(baseName, sanitizedName, testBlocks) +generateExampleTestFileContent( + baseName, + sanitizedName, + sourceFolder, + testBlocks +) } \arguments{ \item{baseName}{Original JASP file name without extension.} \item{sanitizedName}{Sanitized name for use in code.} +\item{sourceFolder}{String indicating the source folder: \code{"library"}, +\code{"verified"}, or \code{"other"}.} + \item{testBlocks}{List of test block strings.} } \value{ Character string with complete test file content. } \description{ -Generate test file content for example-based tests +Generate test file content for source-based tests } \keyword{internal} diff --git a/man/makeTestsFromExamples.Rd b/man/makeTestsFromExamples.Rd index 9abe315..3a2985e 100644 --- a/man/makeTestsFromExamples.Rd +++ b/man/makeTestsFromExamples.Rd @@ -7,6 +7,7 @@ makeTestsFromExamples( path, module.dir, + source, sanitize = FALSE, overwrite = FALSE, forceEncode = NULL @@ -15,12 +16,20 @@ makeTestsFromExamples( \arguments{ \item{path}{Optional string path to a directory containing JASP example files. If provided, the JASP files at this path will be copied to the module's -\code{examples/} folder before generating tests. If missing, the function processes -JASP files already present in the module's \code{examples/} folder.} +\code{tests/testthat/jaspfiles/other/} folder and test files named +\code{test-other-{name}.R} are generated. The \code{source} argument is +ignored when \code{path} is provided.} \item{module.dir}{String path to the module directory. If missing, uses the current working directory.} +\item{source}{Character vector specifying which source folders under +\code{tests/testthat/jaspfiles/} to process. Allowed values are +\code{"library"}, \code{"verified"}, and \code{"other"}. Defaults to all +three when \code{overwrite = FALSE} and to \code{c("library", "other")} +when \code{overwrite = TRUE}. If \code{"verified"} is included and +\code{overwrite = TRUE}, the user is prompted for confirmation.} + \item{sanitize}{Logical. If TRUE, sanitizes test filenames by replacing non-word characters with hyphens. If FALSE (default), preserves original spacing and characters in filenames.} @@ -40,14 +49,12 @@ Invisibly returns a character vector of created/processed test file paths. \code{makeTestsFromExamples} transforms JASP example files into unit test files. } \details{ -This function processes JASP example files and generates corresponding test files in -the module's \code{tests/testthat} directory. Each JASP file becomes a single test file -named "test-example-{basename}.R", where {basename} is the original JASP filename without -the .jasp extension. - -The JASP example files must be located in the module's \code{examples/} folder for the -generated tests to work at runtime. When \code{path} is provided, files are automatically -copied to the module's \code{examples/} folder. +This function processes JASP example files stored under +\code{tests/testthat/jaspfiles/{library,verified,other}/} and generates corresponding +test files in the module's \code{tests/testthat} directory. Each JASP file becomes a +single test file named \code{test-{source}-{basename}.R}, where \code{{source}} is the +source folder name (\code{library}, \code{verified}, or \code{other}) and \code{{basename}} +is the original JASP filename without the .jasp extension. If a JASP file contains multiple analyses, they are included as separate \code{test_that()} blocks within the same test file. @@ -64,17 +71,19 @@ blocks within the same test file. library(jaspTools) setupJaspTools() -# Create tests from JASP files already in the module's examples/ folder -# (uses working directory as module) +# Create tests from all source folders (library, verified, other) makeTestsFromExamples() # Specify the module directory explicitly makeTestsFromExamples(module.dir = "path/to/your/module") -# Import JASP files from another directory, copy to examples/, and generate tests +# Only generate tests from the 'library' source folder +makeTestsFromExamples(source = "library") + +# Import JASP files from another directory (copies to jaspfiles/other/) makeTestsFromExamples(path = "path/to/jasp/files", module.dir = "path/to/module") -# Overwrite existing test files +# Overwrite existing test files (skips verified by default) makeTestsFromExamples(overwrite = TRUE) # Force encode 'model' option for analyses with embedded variable names diff --git a/man/makeTestsFromSingleJASPFile.Rd b/man/makeTestsFromSingleJASPFile.Rd index 6de0c5a..b689d9d 100644 --- a/man/makeTestsFromSingleJASPFile.Rd +++ b/man/makeTestsFromSingleJASPFile.Rd @@ -7,9 +7,10 @@ makeTestsFromSingleJASPFile( jaspFile, module.dir, + sourceFolder, sanitize = FALSE, overwrite = FALSE, - copyToExamples = FALSE, + copyToJaspfiles = FALSE, pkgAnalyses = NULL, forceEncode = NULL ) @@ -19,11 +20,15 @@ makeTestsFromSingleJASPFile( \item{module.dir}{Path to the module directory.} +\item{sourceFolder}{String indicating the source folder: \code{"library"}, +\code{"verified"}, or \code{"other"}.} + \item{sanitize}{Whether to sanitize the filename.} \item{overwrite}{Whether to overwrite existing test files.} -\item{copyToExamples}{Whether to copy the JASP file to the module's examples folder.} +\item{copyToJaspfiles}{Whether to copy the JASP file to +\code{tests/testthat/jaspfiles/{sourceFolder}/}.} \item{pkgAnalyses}{Optional character vector of allowed analysis names for this module. If provided, analyses not in this list will be skipped.} diff --git a/man/testAnalysis.Rd b/man/testAnalysis.Rd index af9b3e3..3d75845 100644 --- a/man/testAnalysis.Rd +++ b/man/testAnalysis.Rd @@ -15,6 +15,13 @@ testAnalysis(name, onlyPlots = FALSE) Tests a specific R analysis found under module/tests/testthat. Useful to perform before making a pull request, to prevent failing builds. } +\details{ +In addition to the standard test file (e.g., \code{test-AnalysisName.R}), this function +also discovers auto-generated source-based test files (\code{test-library-*.R}, +\code{test-verified-*.R}, \code{test-other-*.R}) that contain +\code{runAnalysis("AnalysisName", ...)} calls. This ensures that tests +created by \code{\link{makeTestsFromExamples}} are included when testing an analysis. +} \examples{ testAnalysis("AnovaBayesian")