Skip to content

Comments

Update make tests from examples#70

Open
FBartos wants to merge 2 commits intojasp-stats:masterfrom
FBartos:update-makeTestsFromExamples
Open

Update make tests from examples#70
FBartos wants to merge 2 commits intojasp-stats:masterfrom
FBartos:update-makeTestsFromExamples

Conversation

@FBartos
Copy link
Contributor

@FBartos FBartos commented Feb 16, 2026

Refactor makeTestsFromExamples() with source folder system

Summary

This PR refactors makeTestsFromExamples() to support a structured three-tier source folder system for JASP example files, replacing the flat examples/ folder approach.

Changes

New folder structure

  • JASP files now live in tests/testthat/jaspfiles/{library,verified,other}/
  • Generated test files are named test-{source}-{name}.R (e.g., test-library-CorrelationMatrix.R)
  • Test code references files via testthat::test_path("jaspfiles", "{source}", "file.jasp")

New source parameter

  • Controls which source folders to process: "library", "verified", "other"
  • Defaults to all three when overwrite = FALSE
  • Defaults to c("library", "other") when overwrite = TRUE (protects verified tests)
  • When overwrite = TRUE and "verified" is included, prompts user for confirmation

path parameter behavior

  • When path is provided, JASP files are always copied to tests/testthat/jaspfiles/other/
  • The source argument is ignored in this case
  • A message informs users where files are being copied

Test discovery

  • testAnalysis() now automatically discovers all source-based test files
  • Scans test-library-*, test-verified-*, and test-other-* files for matching analyses
  • No opt-out parameter (simplified from previous includeExamples approach)

Breaking Changes

⚠️ This PR intentionally breaks backwards compatibility

  • Old examples/ folder convention is removed
  • Test files must be renamed from test-example-{name}.Rtest-{source}-{name}.R
  • JASP files must be moved from examples/tests/testthat/jaspfiles/{source}/
  • Generated test code paths changed from test_path("..", "..", "examples", ...)test_path("jaspfiles", "{source}", ...)

Rationale

The three-tier system provides:

  1. Organization: Separate library examples from verified tests and ad-hoc imports
  2. Safety: Prevents accidental overwrites of verified tests (default behavior)
  3. Clarity: Test file names indicate their provenance
  4. Maintainability: Cleaner structure for growing test suites

Example Usage

# Generate tests from all source folders (library, verified, other)
makeTestsFromExamples()

# Only generate from the 'library' source folder
makeTestsFromExamples(source = "library")

# Import JASP files from external path (copies to jaspfiles/other/)
makeTestsFromExamples(path = "path/to/jasp/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)

Documentation

  • Updated roxygen docs for all modified functions
  • Regenerated man pages
  • Updated .github/copilot-instructions.md with new conventions

Files Changed

  • R/test-generator.R: Core implementation of source folder system
  • R/test.R: Updated testAnalysis() and getTestFilesMatchingName() to discover source-based tests
  • .github/copilot-instructions.md: Updated documentation
  • man/*.Rd: Regenerated documentation files

Introduce support for storing JASP example files in tests/testthat/jaspfiles/{library,verified,other} and generate tests named test-{source}-{basename}.R. makeTestsFromExamples() gains a new source argument (defaults depend on overwrite) and when path is provided files are copied into the "other" folder before generating tests. Updated makeTestsFromSingleJASPFile(), generateExampleTestFileContent(), generateExampleTestBlock*() to accept a sourceFolder and to load JASP files via testthat::test_path("jaspfiles", source, file.jasp). Added copyToJaspfiles behavior, overwrite protection/prompt for verified tests, and a summary printer (.printTestGenerationSummary). Also updated documentation/examples and adjusted test discovery (test runner) to include auto-generated source-based tests. These changes centralize example JASP storage, avoid clobbering verified tests by default, and make generated test paths explicit.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors makeTestsFromExamples() and related test discovery to support a structured, source-based organization for JASP example files and their generated testthat tests, replacing the previous flat examples/ approach.

Changes:

  • Introduces tests/testthat/jaspfiles/{library,verified,other}/ and generates test-{source}-{name}.R test files referencing JASP files via testthat::test_path("jaspfiles", ...).
  • Adds a source parameter + overwrite safeguards (defaulting away from verified when overwriting, with confirmation).
  • Updates testAnalysis() discovery to include source-based tests, and regenerates/updates documentation accordingly.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
R/test-generator.R Implements the new source-folder workflow, naming, copy behavior, and summary messaging for generated tests.
R/test.R Updates test-file selection logic to discover and include test-{library,verified,other}-* tests for a given analysis.
man/makeTestsFromExamples.Rd Documents new source parameter, folder structure, and updated examples.
man/makeTestsFromSingleJASPFile.Rd Updates parameter documentation (sourceFolder, copyToJaspfiles) for the internal helper.
man/testAnalysis.Rd Documents the expanded discovery behavior for source-based generated tests.
man/generateExampleTestFileContent.Rd Updates internal docs to reflect source-based test file generation.
man/generateExampleTestBlock.Rd Documents the new sourceFolder argument used to build correct test_path() calls.
man/generateExampleTestBlockBasic.Rd Documents the new sourceFolder argument in the basic fallback test block.
.github/copilot-instructions.md Updates repository conventions/docs for the new folder layout and test naming.
Comments suppressed due to low confidence (1)

R/test-generator.R:344

  • makeTestsFromSingleJASPFile() copies the input JASP file to tests/testthat/jaspfiles/{sourceFolder}/ before checking whether the test file already exists and overwrite is FALSE. This means an import via path= can overwrite an existing JASP file even when the corresponding test is skipped. Consider checking file.exists(testFilePath) && !overwrite (and returning) before performing the copy, or only copying when the destination file doesn’t already exist.
  # 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(destDir, basename(jaspFile))
    file.copy(jaspFile, destFile, overwrite = TRUE)
    copiedTo <- destFile
    message("  Copied to: ", destFile)
  }

  # Create tests/testthat directory if needed
  testDir <- file.path(module.dir, "tests", "testthat")

  if (!dir.exists(testDir)) {
    dir.create(testDir, recursive = TRUE)
    message("  Created directory: ", testDir)
  }

  # 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
  if (file.exists(testFilePath) && !overwrite) {
    result <- testFilePath
    attr(result, "skipped") <- TRUE
    attr(result, "copiedTo") <- copiedTo
    return(result)

Comment on lines +307 to +312
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)
}
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In getTestFilesMatchingName(), the pattern is built by interpolating name directly into a regex and then used with grepl(). If an analysis name ever contains regex metacharacters (e.g., . + (), this can produce false matches or a regex error. Escape name for regex (or otherwise ensure literal matching) before constructing pattern.

Suggested change
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)
}
escapedName <- gsub("([][{}()+*^$|\\\\?.])", "\\\\\\1", name)
pattern <- paste0('runAnalysis\\(\\s*["\']', escapedName, '["\']')
for (ef in sourceFiles) {
content <- readLines(file.path(testsDir, ef), warn = FALSE)
if (any(grepl(pattern, content)))
matchedFiles <- c(matchedFiles, ef)

Copilot uses AI. Check for mistakes.
Comment on lines +112 to +114
otherDir <- file.path(module.dir, "tests", "testthat", "jaspfiles", "other")
if (!dir.exists(otherDir)) {
dir.create(otherDir, recursive = TRUE)
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otherDir is created to ensure tests/testthat/jaspfiles/other/ exists, but the variable itself is never used afterwards. Consider removing the unused variable (or using it consistently) to reduce noise and avoid linters/CRAN checks flagging it.

Suggested change
otherDir <- file.path(module.dir, "tests", "testthat", "jaspfiles", "other")
if (!dir.exists(otherDir)) {
dir.create(otherDir, recursive = TRUE)
if (!dir.exists(file.path(module.dir, "tests", "testthat", "jaspfiles", "other"))) {
dir.create(file.path(module.dir, "tests", "testthat", "jaspfiles", "other"), recursive = TRUE)

Copilot uses AI. Check for mistakes.
Comment on lines +241 to 251
.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, "/.")
}
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When processing multiple sources, .printTestGenerationSummary() is called with sourceLabel = paste(source, collapse = ", "), but the message formats it as if it were a single folder path (.../jaspfiles/<sourceLabel>/.). This produces misleading output like .../jaspfiles/library, other/. when more than one source is used. Consider adjusting the message to either omit the path formatting for multi-source runs or print separate paths per source.

Copilot uses AI. Check for mistakes.
@FBartos
Copy link
Contributor Author

FBartos commented Feb 16, 2026

tested on jaspMetaAnalysis successfully

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant