@@ -565,7 +565,7 @@ reset_options <- function(env){
565565# '
566566# ' @param file \code{[character]} File location of a .R file.
567567# ' @param at_home \code{[logical]} toggle local tests.
568- # ' @param verbose \code{[logical ]} toggle verbosity during execution
568+ # ' @param verbose \code{[integer ]} verbosity level. 0: be quiet, 1: print status per file, 2: print status per test expression.
569569# ' @param color \code{[logical]} toggle colorize counts in verbose mode (see Note)
570570# ' @param remove_side_effects \code{[logical]} toggle remove user-defined side effects? See section on side effects.
571571# '
@@ -615,15 +615,15 @@ reset_options <- function(env){
615615# ' @export
616616run_test_file <- function ( file
617617 , at_home = TRUE
618- , verbose = getOption(" tt.verbose" , TRUE )
618+ , verbose = getOption(" tt.verbose" , 2 )
619619 , color = getOption(" tt.pr.color" , TRUE )
620- , remove_side_effects = TRUE ){
620+ , remove_side_effects = TRUE
621+ , ... ){
621622
622623 if (! file_test(" -f" , file )){
623624 stop(sprintf(" '%s' does not exist or is a directory" ,file ),call. = FALSE )
624625 }
625626 # convenience print function
626- catf <- function (fmt ,... ) if (verbose ) cat(sprintf(fmt ,... ))
627627
628628 # # where to come back after running the file
629629 oldwd <- getwd()
@@ -699,6 +699,9 @@ run_test_file <- function( file
699699 }
700700 prfile <- paste(" Running" ,gsub(" " ," ." ,sprintf(" %-30s" ,basename(file ))))
701701
702+ # internal use only: load pkg if passed by run_test_dir
703+ L <- list (... )
704+ if (! is.null(L $ pkg )) require(L $ pkg , character.only = TRUE , quiet = TRUE )
702705 # evaluate expressions one by one
703706 for ( i in seq_along(parsed ) ){
704707 expr <- parsed [[i ]]
@@ -707,20 +710,27 @@ run_test_file <- function( file
707710 o $ call <- expr
708711 out <- eval(expr , envir = e )
709712
710- # print the test counter.
711- catf(" \r %s %4d tests " , prfile , o $ ntest())
712- # print status after counter
713- if ( o $ ntest() == 0 ) {} # print nothing if nothing was tested
714- else if ( o $ nfail() == 0 ) catf(if (color ) " \0 33[0;32mOK\0 33[0m" else " OK" )
715- else catf(if (color ) " \0 33[0;31m%d errors\0 33[0m" else " %d errors" , o $ nfail())
713+ if (verbose == 2 ) print_status(prfile , o , color )
716714 }
717- catf(" \n " )
715+ if (verbose == 1 ) print_status(prfile , o , color )
716+ if (verbose > = 1 ) catf(" \n " )
718717
719-
718+ # returns a 'list' of 'tinytest' objects
720719 test_output <- o $ gimme()
721720 structure(test_output , class = " tinytests" )
722721}
723722
723+ # helper functions for printing test status.
724+ catf <- function (fmt ,... ) cat(sprintf(fmt ,... ))
725+
726+ print_status <- function (filename , env , color ){
727+ catf(" \r %s %4d tests " , filename , env $ ntest())
728+ # print status after counter
729+ if ( env $ ntest() == 0 ) {} # print nothing if nothing was tested
730+ else if ( env $ nfail() == 0 ) catf(if (color ) " \0 33[0;32mOK\0 33[0m" else " OK" )
731+ else catf(if (color ) " \0 33[0;31m%d errors\0 33[0m" else " %d errors" , env $ nfail())
732+ }
733+
724734
725735
726736# ' Run all tests in a directory
@@ -738,10 +748,12 @@ run_test_file <- function( file
738748# ' @param remove_side_effects \code{[logical]} toggle remove user-defined side
739749# ' effects. Environment variables (\code{Sys.setenv()}) and options (\code{options()})
740750# ' defined in a test file are reset before running the next test file (see details).
751+ # ' @param ncpu Number of CPUs to use. Paralellizes tests over files.
741752# ' @param lc_collate \code{[character]} Locale setting used to sort the
742753# ' test files into the order of execution. The default \code{NA} ensures
743754# ' current locale is used. Set this e.g. to \code{"C"} to ensure bytewise
744755# ' and more platform-independent sorting (see details).
756+ # ' @param ... Arguments passed to \code{run_test_file}
745757# '
746758# ' @section Details:
747759# '
@@ -756,6 +768,10 @@ run_test_file <- function( file
756768# ' to survive a single file, use \code{base::Sys.setenv()} explicitly.
757769# ' Similarly, if an option setting needs to survive, use \code{base::options}
758770# '
771+ # ' @section Parallel tests:
772+ # ' If \code{ncpu > 1}
773+ # '
774+ # '
759775# ' @return A \code{tinytests} object
760776# '
761777# '
@@ -782,10 +798,12 @@ run_test_file <- function( file
782798# ' @export
783799run_test_dir <- function (dir = " inst/tinytest" , pattern = " ^test.*\\ .[rR]"
784800 , at_home = TRUE
785- , verbose = getOption(" tt.verbose" ,TRUE )
801+ , verbose = getOption(" tt.verbose" , 2 )
786802 , color = getOption(" tt.pr.color" ,TRUE )
787803 , remove_side_effects = TRUE
788- , lc_collate = getOption(" tt.collate" ,NA ) ){
804+ , ncpu = 1
805+ , lc_collate = getOption(" tt.collate" ,NA )
806+ , ... ){
789807 oldwd <- getwd()
790808 on.exit( setwd(oldwd ) )
791809 setwd(dir )
@@ -795,17 +813,21 @@ run_test_dir <- function(dir="inst/tinytest", pattern="^test.*\\.[rR]"
795813
796814
797815
798- test_output <- list ()
799-
800- for ( file in testfiles ){
801- test_output <- c(test_output
802- , run_test_file(file
803- , at_home = at_home
804- , verbose = verbose
805- , color = color
806- , remove_side_effects = remove_side_effects ))
816+ if (ncpu == 1 ){
817+ test_output <- lapply(testfiles , run_test_file
818+ , at_home = at_home
819+ , verbose = verbose
820+ , color = color
821+ , remove_side_effects = remove_side_effects
822+ , ... )
823+ } else {
824+ test_output <- parallel :: mclapply(testfiles
825+ , run_test_file , at_home = at_home , verbose = min(verbose ,1 )
826+ , color = color , remove_side_effects = TRUE , ... )
807827 }
808- structure(test_output ,class = " tinytests" )
828+ # by using '(mc)lapply' we get a list of tinytests objects. We need to unwind
829+ # one level to a list of 'tinytest' objects and class it 'tinytests'.
830+ structure(unlist(test_output ,recursive = FALSE ), class = " tinytests" )
809831}
810832
811833
@@ -847,7 +869,7 @@ locale_sort <- function(x, lc_collate=NA, ...){
847869# ' direcory where \code{DESCRIPTION} and \code{NAMESPACE} reside).
848870# ' @param testdir \code{[character]} scalar. Subdirectory where test files are
849871# ' stored.
850- # ' @param ... passed to \code{run_test_dir}.
872+ # ' @param ... passed to \code{run_test_dir} (e.g. \code{ncpu}) .
851873# '
852874# ' @rdname run_test_dir
853875# ' @export
@@ -883,7 +905,7 @@ at_home <- function(){
883905# ' @param testdir \code{[character]} scalar. Path to installed directory, relative
884906# ' to the working directory of \code{R CMD check}.
885907# ' @param at_home \code{[logical]} scalar. Are we at home? (see Details)
886- # ' @param ... extra arguments, passed to \code{\link{run_test_dir}}
908+ # ' @param ... extra arguments passed to \code{\link{run_test_dir}} (e.g. \code{ncpu}).
887909# '
888910# '
889911# ' @section Details:
@@ -908,11 +930,10 @@ at_home <- function(){
908930test_package <- function (pkgname , testdir = " tinytest" , at_home = FALSE , ... ){
909931 oldwd <- getwd()
910932 on.exit(setwd(oldwd ))
911- require(pkgname , character.only = TRUE )
912933 testdir <- system.file(testdir , package = pkgname )
913934 setwd(testdir )
914935
915- out <- run_test_dir(" ./" , at_home = at_home , ... )
936+ out <- run_test_dir(" ./" , at_home = at_home , pkg = pkgname , ... )
916937 i_fail <- sapply(out , isFALSE )
917938 if ( any(i_fail ) ){
918939 msg <- paste( sapply(out [i_fail ], format.tinytest , type = " long" ), collapse = " \n " )
@@ -938,6 +959,7 @@ test_package <- function(pkgname, testdir = "tinytest", at_home=FALSE, ...){
938959# ' @param testdir \code{[character]} Name of directory under \code{pkgdir/inst}
939960# ' containing test files.
940961# ' @param at_home \code{[logical]} toggle local tests.
962+ # ' @param ncpu Number of CPUs to use (see \code{\link{run_test_dir}} for details).
941963# ' @param verbose \code{[logical]} toggle verbosity during execution
942964# ' @param keep_tempdir \code{[logical]} keep directory where the pkg is
943965# ' installed and where tests are run? If \code{TRUE}, the directory is not deleted
@@ -955,7 +977,8 @@ test_package <- function(pkgname, testdir = "tinytest", at_home=FALSE, ...){
955977# ' @export
956978build_install_test <- function (pkgdir = " ./" , testdir = " tinytest"
957979 , at_home = TRUE
958- , verbose = getOption(" tt.verbose" ,TRUE )
980+ , verbose = getOption(" tt.verbose" ,2 )
981+ , ncpu = 1
959982 , keep_tempdir = FALSE ){
960983 oldwd <- getwd()
961984 tdir <- tempfile()
@@ -992,11 +1015,12 @@ suppressPackageStartupMessages({
9921015 library('%s', lib.loc='%s',character.only=TRUE)
9931016 library('tinytest')
9941017})
995- # testdir pkgname tdir at_home verbose
996- out <- run_test_dir(system.file('%s', package='%s', lib.loc='%s'), at_home=%s, verbose=%s)
1018+ # testdir pkgname tdir
1019+ out <- run_test_dir(system.file('%s', package='%s', lib.loc='%s')
1020+ , at_home=%s, verbose=%s, ncpu=%s, pkg='%s')
9971021saveRDS(out, file='output.RDS')
9981022"
999- scr <- sprintf(script , pkgname , tdir ,testdir , pkgname ,tdir , at_home , verbose )
1023+ scr <- sprintf(script , pkgname , tdir ,testdir , pkgname ,tdir , at_home , verbose , ncpu , pkgname )
10001024
10011025 write(scr , file = " test.R" )
10021026 system(" Rscript test.R" )
0 commit comments