###############################################################################
### allelematch test engine ###
###############################################################################

#' Returns package version
#'
#' @description
#' Displays version of this package (\link{amregtest}) and of [allelematch][allelematch::allelematch-package],
#' together with build timestamps.\cr
#' \cr
#' The version is specified in the file DESCRIPTION, tag "Version: ".
#'
#'
#' @param verbose logical. If TRUE (the default), prints additional info to stdout,
#' including versions and build timestamps of 'allelematch' and 'amregtest'.
#'
#' @return The loaded version of this package (\link{amregtest-package}) in a character vector of length one
#'
#' @examples
#' # See what version of packages 'allelematch' and 'amregtest'
#' # are currently loaded:
#' artVersion()
#'
#' # List the available tests:
#' artList()
#' \donttest{
#' # Run all the tests:
#' # artRun()  # Takes several minutes
#'
#' # Run the first of the available tests:
#' artRun(filter="allelematch_1-amDataset$")
#' }
#'
#'
#' @seealso \link{artList}, \link{artRun} and \link{amregtest}
#' @export
artVersion <- function(verbose=TRUE) {
    stopifnot(is.logical(verbose))

    installedArtVersion = toString(utils::packageVersion("amregtest"))
    installedAmVersion  = toString(utils::packageVersion("allelematch"))

    if (verbose) {
        cat("\n    Version of package 'amregtest' is", installedArtVersion)
        cat("\n    Installed (and thus tested) version of package 'allelematch' is:", installedAmVersion)
    }
    return(invisible(installedArtVersion))
}


#' Lists available tests in `amregtest` without running them
#'
#' @description
#' Use the output to select a value for parameter `filter` to \link{artRun}.
#' Useful when debugging.
#'
#' @param verbose logical. If TRUE (the default), prints additional info to stdout
#'
#' @return A character vector containing the names of all the tests
#'
#' @examples
#' # See what version of packages 'allelematch' and 'amregtest'
#' # are currently loaded:
#' artVersion()
#'
#' # List the available tests:
#' artList()
#' \donttest{
#' # Run all the tests:
#' # artRun()  # Takes several minutes
#'
#' # Run the first of the available tests:
#' artRun(filter="allelematch_1-amDataset$")
#' }
#'
#' @seealso \link{artVersion} and \link{artRun}
#'
#' @export
artList <- function(verbose=TRUE) {
    stopifnot(is.logical(verbose))

    root = paste(system.file(package = "amregtest"), "tests/testthat/", sep="/")

    all = gsub("^test-(.+?)\\.R", "\\1", grep("^test-.+?\\.R", list.files(root), value=TRUE), perl=TRUE)

    if (verbose) {
        cat('\nTests in files under "', root, '":\n', sep="")

        cat("\nTests by functions in allelematch:\n")
        print(grep("^allelematch", all, value=TRUE, perl=TRUE), width=50)

        cat("\nReproduction of the examples in 'allelematchSuppDoc.pdf':\n")
        print(grep("^amExample", all, value=TRUE, perl=TRUE))

        cat("\nOther:\n")
        print(grep("^allelematch|^amExample", all, value=TRUE, invert=TRUE, perl=TRUE))
        cat("\n")
    }

    return(invisible(all))
}


#' Runs the regression test
#'
#' @description
#' Runs regression tests on package [allelematch][allelematch::allelematch-package] to make sure it is backwards compatible.\cr
#' \cr
#' The full set of tests will take a couple of minutes. \cr
#' \cr
#' Call \link{artList} to see the available tests without running them.
#'
#' @return A list (invisibly) containing data about the test results as returned by [testthat::test_package]
#'
#' @details
#' If any of the test executed with \link{artRun} should fail, then we want to be able
#' to run that specific test under the debugger.\cr
#' \cr
#' Set a breakpoint in `allelematch.R` and call `artRun(filter="<the test that reproduces the problem>")`\cr
#' \cr
#' Note that it is the last loaded version of `allelematch` that will be executed,
#' not the last edited. In RStudio, CTRL+SHIFT+B will build, install and load.
#'
#'
#' @param filter    If specified, only tests with names matching this perl regular
#'                  expression will be executed. Character vector of length 1. See also \link{artList}
#' @param verbose   logical. If TRUE (the default), prints version of tested allelematch to stdout
#'
#' @examples
#' # See what version of packages 'allelematch' and 'amregtest'
#' # are currently loaded:
#' artVersion()
#'
#' # List the available tests:
#' artList()
#' \donttest{
#' # Run all the tests:
#' # artRun()  # Takes several minutes
#'
#' # Run the first of the available tests:
#' artRun(filter="allelematch_1-amDataset$")
#' }
#'
#' @seealso \link{artVersion} and \link{artList}
#'
#' @export
artRun <- function(filter="", verbose=TRUE) {
    stopifnot(is.character(filter) && length(filter)==1)
    stopifnot(is.logical(verbose))

    # Propagate the verbosity to the deferred cleanup code in helper-temp-leaks.R
    # withr ensures the effect lasts until the ENTIRE function returns
    env_value = if(verbose) "true" else "false"
    withr::local_envvar(c("ART_VERBOSE" = env_value))

    installedVersion = toString(utils::packageVersion("allelematch"))
    if (verbose) cat("    About to test installed version of allelematch:  <<<", installedVersion, ">>>\n", sep="")

    reporter <-
        if (!verbose) testthat::check_reporter() # Keep silent unless there are errors.
        else if(interactive()) "Progress"        # Nice interactive progress bar in RStudio
        else ColumnReporter$new()                # Nice columns to stdout

    result = list()
    if (filter != "^$") result = testthat::test_package("amregtest", reporter=reporter , filter=filter) # We can't start tests recursively, even for coverage tests
    if (verbose) cat("    Done testing installed version of allelematch:  <<<", installedVersion, ">>>\n", sep="")
    return(invisible(result))
}

