RUnit/0000755000175100001440000000000015024244447011337 5ustar hornikusersRUnit/tests/0000755000175100001440000000000013267374743012513 5ustar hornikusersRUnit/tests/README0000644000175100001440000000012113267374743013365 0ustar hornikusers unit tests have been moved to inst/unitTests in the source package structure RUnit/.Rinstignore0000644000175100001440000000002214561532231013631 0ustar hornikusersinst/doc/Makefile RUnit/MD50000644000175100001440000000541315024244447011652 0ustar hornikusers393a5ca445f6965873eca0259a17f833 *COPYING 6b94a58ea79e6ef655370420f985c731 *ChangeLog 2b3eeb6404107e01f4ec6e2db33cc0a2 *DESCRIPTION d67ace25e05eec76fdb91401cd1b461a *NAMESPACE d5e61c4fb2e03e331699c99b589b56c3 *NEWS fdfb94feb8fae5d9b5085d808b592de1 *R/00Init.r e09d7eb635cd67aee843dbe167e69727 *R/checkFuncs.r 0af7c3a4b469fd74ae00feb78ebf85d5 *R/exportHTML.r 683a514df0cc07ffe238287faecd22f2 *R/html.r 7d37388f85a1c445e4c11fca01dee7da *R/htmlProtocol.r a18fca4276409763b6d2ed72d63282e8 *R/inspector.r dac8cdcb71213d0766b2e7421cb6d5e4 *R/junitProtocol.r d2259ad7818d1a12586f84dc0a34b390 *R/options.r 008c7654ad519fa9de7af8e431ab9098 *R/runit.r 1946f1e7a4090ffe510d99f82c91b58b *R/testLogger.r 3ad2fcf437829b6b6bb7d198df8fadd5 *R/textProtocol.r 35fb76293a8cddc0e2d0d0b247ee9744 *README.md 2c21327ac730bb34e3ce350f2df36e5c *build/stage23.rdb 9417a2d6f70f7f7fff6d25723d515bdd *build/vignette.rds 4f62202a93b4588883bd6cf6c53adc2d *inst/doc/Makefile 4b3f61d679e4bbea1dce9fcfa690aa62 *inst/doc/RUnit.R 2352b006ecb7a74230bf757319b3d4d4 *inst/doc/RUnit.Rnw 5b0545a6f19f59953d1646734d2d61fa *inst/doc/RUnit.pdf 42b28300a717f74028c32c0a87b8adfe *inst/examples/correctTestCase.r 0d450a1fca30e1c3e193d3b2d117b423 *inst/examples/runitVirtualClassTest.r 3df11b61be3a51c4cd3f2aaa62b4c005 *inst/examples/runitc2f.r 4201d80ec130d66cbc544f78522c3608 *inst/share/R/checkCode.r fa963471970494c4d471175456202d27 *inst/share/R/compareRUnitTestData.r e97e7c5dda56971910efb622ab8c71b5 *inst/unitTests/Makefile 87db5d27b6c4cc1dfd0182e6d1872113 *inst/unitTests/runalltests.R 20fea06109317e04deac5f348245dfac *inst/unitTests/runitHTMLProtocol.r 8c83fe548809a81699e4c05483e8171b *inst/unitTests/runitInspect.r 3416f47fd504913d182aaba77ffdd14d *inst/unitTests/runitJUnitProtocol.r 376b320c3d1576b1dfe0d6dc6925c83c *inst/unitTests/runitPlotConnection.r 3f947455879084d9eafa9d7ea6663b73 *inst/unitTests/runitRUnit.r 713c2b0f3142caaf4a0ebfaf69b5c8c3 *inst/unitTests/runitS4.r f58c90583929b356cc16862b3fd87ce0 *inst/unitTests/runitSetUp.r 1ab9a24c678577d379c64bc455139134 *inst/unitTests/runitTearDown.r d2406b7de7c13f3d5b31bdd5c8fc226a *inst/unitTests/runitTestLogger.r 128d52ea94c7462f871e3242e39566f1 *inst/unitTests/runitTextProtocol.r 9aaab36a3a42fda03d01ad73df977fcc *man/RUnit-internal.Rd 31d29f6382dc390328ca14c36d5fa6e5 *man/RUnit-intro.Rd 04138fda366b5447fc26c40ac83e9d61 *man/RUnit-options.Rd 549b0f02d2ae37b3033251260640f6e7 *man/checkFuncs.Rd c0b777e713d145c47f051a6915916e55 *man/inspect.Rd bcc10620027dc39f2018453dcbacf935 *man/printHTML.Rd bd9d34629232ebd1ed9f98ad7acb4080 *man/runit.Rd a6390ca77a460a8b3791ff4c50b8f4e0 *man/testCaseSetUp.Rd e7107c7dcae672ec729fa662a8697449 *man/textProtocol.Rd 9d79fea474c52eb8ef81bf8ee8c6835e *man/tracker.Rd aad073d2afa8c98edc05a00dddc8dac7 *tests/README 2352b006ecb7a74230bf757319b3d4d4 *vignettes/RUnit.Rnw RUnit/R/0000755000175100001440000000000014563457515011551 5ustar hornikusersRUnit/R/options.r0000644000175100001440000000274113267374743013434 0ustar hornikusers## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ .buildRUnitOptions <- function() { ##@bdescr ## Internal function ## adds an entry to R's default global option list ## modelled after version in package Biobase (BioC) ##@edescr ## ##@ret : [list] extended options() list ## ##@codestatus : internal RUnit <- getOption("RUnit") if (is.null(RUnit)) { RUnit <- list() class(RUnit) <- "RUnitOptions" } if (is.null( RUnit$verbose)) { ## integer: == 0: silent, >= 1: add comments to test case log RUnit$verbose <- 1L } if (is.null(RUnit$silent)) { RUnit$silent <- FALSE } if (is.null(RUnit$outfile)) { RUnit$outfile <- NULL } options("RUnit"=RUnit) } RUnit/R/testLogger.r0000644000175100001440000002565014563457515014063 0ustar hornikusers## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ .newTestLogger <- function(useOwnErrorHandler) { ##@bdescr ## creates a new, empty TestLogger 'object'. ## TestLogger is an object based on the 'closure trick'. It has the task ## to store, administrate and print the test protocol. ##@edescr ##@in useOwnErrorHandler : [logical] ##@ret : [list] ## ##@codestatus : internal ## private data: ## ----------------------- .testData <- list() class(.testData) <- "RUnitTestData" .currentTestSuiteName <- NULL .currentSourceFileName <- NULL ## book keeping variables for individual test functions ## can be reset by function cleanup .currentTraceBack <- NULL .failure <- FALSE .deactivationMsg <- NULL ## if non-NULL test function is deactivated .checkNum <- 0 ## verbosity level: 0: silent .verbosity <- 1L ## define own error handler ## ----------------------- errorHandler <- function() { ##@bdescr ## used as default error handler during test case execution iff ## the user specified 'useOwnErrorHandler' as TRUE (default). ## called in case an error condition, typically stop() has been signalled. ## tries to create a traceback object, currently only used by addError(). ## ## not provided via testLogger but used by R's error handler. ##@edescr ## ##@ret : [NULL] used for it's side effect ## ##@codestatus : internal res <- try(dump.frames()) if (inherits(res, "try-error")) { .currentTraceBack <<- "traceback not available (dump.frames failed)." } else { .currentTraceBack <<- names(last.dump)[-length(last.dump)] } } if(useOwnErrorHandler) { options(error=errorHandler) } ## public methods: ## ----------------------- .getTestData <- function() { ##@bdescr ## return the protocol data collected during the test runs ##@edescr return(.testData) } .setCurrentTestSuite <- function(testSuite) { ##@bdescr ## record the test suite that is currently executed. ##@edescr ##@in testSuite : [testSuite - list] the current testSuite if(is.null(testSuite)) { .currentTestSuiteName <<- NULL } else { if(is.element(testSuite$name, names(.testData))) { stop(paste("Duplicate test suite:", testSuite$name)) } .currentTestSuiteName <<- testSuite$name .testData[[testSuite$name]] <<- list(nTestFunc = 0L, nDeactivated = 0L, nErr = 0, nFail = 0, dirs = testSuite[["dirs"]], testFileRegexp = testSuite[["testFileRegexp"]], testFuncRegexp = testSuite[["testFuncRegexp"]], sourceFileResults = list()) } } .setCurrentSourceFile <- function(sourceFileName) { ##@bdescr ## record the source file whose test functions are currently executed ##@edescr ##@in sourceFileName : [character] name of current source file if(is.null(sourceFileName)) { .currentSourceFileName <<- NULL } else { .currentSourceFileName <<- sourceFileName .testData[[.currentTestSuiteName]]$sourceFileResults[[sourceFileName]] <<- list() } } .addSuccess <- function(testFuncName, secs) { ##@bdescr ## add a successful test function run. ##@edescr ##@in testFuncName : [character] name of test function ##@in secs : [numeric] time in seconds needed by the test function to complete .testData[[.currentTestSuiteName]]$nTestFunc <<- 1 + .testData[[.currentTestSuiteName]]$nTestFunc .testData[[.currentTestSuiteName]]$sourceFileResults[[.currentSourceFileName]][[testFuncName]] <<- list(kind="success", checkNum=.checkNum, time=secs) } .addError <- function(testFuncName, errorMsg) { ##@bdescr ## add a test function that generated an error. ##@edescr ##@in testFuncName : [character] name of test function ##@in errorMsg : [character] the error message .testData[[.currentTestSuiteName]]$nTestFunc <<- 1 + .testData[[.currentTestSuiteName]]$nTestFunc .testData[[.currentTestSuiteName]]$nErr <<- 1 + .testData[[.currentTestSuiteName]]$nErr .testData[[.currentTestSuiteName]]$sourceFileResults[[.currentSourceFileName]][[testFuncName]] <<- list(kind="error", msg=errorMsg, checkNum=.checkNum, traceBack=.currentTraceBack) } .addFailure <- function(testFuncName, failureMsg) { ##@bdescr ## add a test function that generated an error. ##@edescr ##@in testFuncName : [character] name of test function ##@in failureMsg : [character] the failure message .testData[[.currentTestSuiteName]]$nTestFunc <<- 1 + .testData[[.currentTestSuiteName]]$nTestFunc .testData[[.currentTestSuiteName]]$nFail <<- 1 + .testData[[.currentTestSuiteName]]$nFail .testData[[.currentTestSuiteName]]$sourceFileResults[[.currentSourceFileName]][[testFuncName]] <<- list(kind="failure", msg=failureMsg, checkNum=.checkNum, traceBack=NULL) ## traceBack is useless in this case } .addDeactivated <- function(testFuncName) { ##@bdescr ## add a deactivated test function that generated an error. ##@edescr ##@in testFuncName : [character] name of test function .testData[[.currentTestSuiteName]]$nDeactivated <<- 1 + .testData[[.currentTestSuiteName]]$nDeactivated .testData[[.currentTestSuiteName]]$sourceFileResults[[.currentSourceFileName]][[testFuncName]] <<- list(kind="deactivated", msg=.deactivationMsg, checkNum=.checkNum) } .addCheckNum <- function(testFuncName) { ##@bdescr ## add total number of checks performed ##@edescr ##@in testFuncName : [character] name of test function .testData[[.currentTestSuiteName]]$sourceFileResults[[.currentSourceFileName]][[testFuncName]]$checkNum <<- .checkNum } .cleanup <- function() { ##@bdescr ## reset book keeping variables like .failure, ... ## should be called before each test function execution ##@edescr .currentTraceBack <<- NULL .failure <<- FALSE .deactivationMsg <<- NULL .checkNum <<- 0 } .isFailure <- function() { ##@bdescr ## return current failure status ##@edescr return(.failure) } .setFailure <- function() { ##@bdescr ## set failure status to TRUE ##@edescr .failure <<- TRUE } .isDeactivated <- function() { ##@bdescr ## return current deactivation message ##@edescr ##@ret : [logical] TRUE if deactivation msg is not NULL return(!is.null(.deactivationMsg)) } .setDeactivated <- function(msg) { ##@bdescr ## set deactivation message variable, indicating a deactivated test case ##@edescr ##@in msg : [character] message string if (length(msg) > 1) { msg <- paste(msg, collapse=" ") } .deactivationMsg <<- msg } .incrementCheckNum <- function() { ##@bdescr ## increment internal counter of total num of test cases ##@edescr .checkNum <<- 1 + .checkNum } .getCheckNum <- function() { ##@bdescr ## return counter value for total num of test cases ##@edescr return(.checkNum) } .getVerbosity <- function() { ##@bdescr ## return verbosity level for output log messages ##@edescr return(.verbosity) } .setVerbosity <- function(level) { ##@bdescr ## set verbosity level for output log messages ##@edescr ##@in level : [integer] 0: omit output log messages, 1 >= : write begin/end comments for each test case if (length(level) > 1) { level <- level[1] } .verbosity <<- level } tl <- list(getTestData = .getTestData, setCurrentTestSuite = .setCurrentTestSuite, setCurrentSourceFile = .setCurrentSourceFile, addSuccess = function(testFuncName, secs) .addSuccess(testFuncName, secs), addError = function(testFuncName, errorMsg) .addError(testFuncName, errorMsg), addFailure = function(testFuncName, failureMsg) .addFailure(testFuncName, failureMsg), addDeactivated = function(testFuncName) .addDeactivated(testFuncName), addCheckNum = function(testFuncName) .addCheckNum(testFuncName), isFailure = .isFailure, setFailure = .setFailure, isDeactivated = .isDeactivated, setDeactivated = function(msg) .setDeactivated(msg), incrementCheckNum = .incrementCheckNum, getCheckNum = .getCheckNum, getVerbosity = .getVerbosity, setVerbosity = .setVerbosity, cleanup = .cleanup) class(tl) <- "TestLogger" return(invisible(tl)) } getErrors <- function(testData) { ##@bdescr ## return a brief summary of the test case execution result, ## computed from the testData listOfListsOfLists ## ##@edescr ## ##@in testData : [list] S3 RUnitTestData class object ##@ret : [list] containing no of errors, deactivated, failed, and total test functions ## ##@codestatus : testing if(!is(testData, "RUnitTestData")) { stop("getErrors needs an object of class 'RUnitTestData' as argument.") } ret <- list(nErr=0, nDeactivated=0, nFail=0, nTestFunc=0) for(i in seq_along(testData)) { ret$nErr <- ret$nErr + testData[[i]]$nErr ret$nDeactivated <- ret$nDeactivated + testData[[i]]$nDeactivated ret$nFail <- ret$nFail + testData[[i]]$nFail ret$nTestFunc <- ret$nTestFunc + testData[[i]]$nTestFunc } return(ret) } .existsTestLogger <- function(envir=RUnitEnv) { ##@bdescr ## Internal Function ## checks if .testLogger object is available in specified environment ## and if present if this object is of class 'TestLogger' ## ##@edescr ## ##@in envir : [environment] to search within ##@ret : [logical] TRUE iff .testLogger list object is found in specified environment ## ##@codestatus : internal exists(".testLogger", envir=envir) && inherits(get(".testLogger", envir=envir), "TestLogger") } RUnit/R/junitProtocol.r0000644000175100001440000001013313267374743014606 0ustar hornikusers## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA printJUnitProtocol <- function(testData, fileName = "") { ##@bdescr ## Report generator ## Extracts the log information stored in the 'RUnitTestData' test run object ## and generates a JUnit-style formated XML output. ##@edescr ## ##@in testData : [RUnitTestData] S3 class object ##@in fileName : [character] string, full path + file name to be written to ##@ret : [logical] TRUE if execution completed without error ## ##@codestatus : testing ## preconditions if (!is(testData, "RUnitTestData")) { stop("Argument 'testData' must be of class 'RUnitTestData'.") } if (!is.character(fileName)) { stop("Argument 'fileName' has to be of type character.") } if (length(fileName) != 1) { stop("Argument 'fileName' must contain exactly one element.") } errInfo <- getErrors(testData) # Create entry fro all test suites xml.testsuites <- XML::newXMLNode("testsuites", attrs = c( errors=errInfo$nErr, failures=errInfo$nFail, tests=errInfo$nTestFunc) ) for (tsName in names(testData)) { # Create entry for test suite xml.testsuite <- XML::newXMLNode("testsuite", attrs = c( errors = testData[[tsName]]$nErr, failures = testData[[tsName]]$nFail, name = tsName, tests = testData[[tsName]]$nTestFunc )) XML::addChildren(xml.testsuites, kids=c(xml.testsuite)) if (testData[[tsName]]$nErr + testData[[tsName]]$nFail >= 0) { srcFileRes <- testData[[tsName]][["sourceFileResults"]] for (i in seq_along(srcFileRes)) { testFuncNames <- names(srcFileRes[[i]]) for (j in seq_along(testFuncNames)) { funcList <- srcFileRes[[i]][[testFuncNames[j]]] # Each tested function gets a testcase xml.testcase <- XML::newXMLNode("testcase", attrs=c(name=testFuncNames[j], time=funcList$time[['elapsed']])) XML::addChildren(xml.testsuite, kids=c(xml.testcase)) if (funcList$kind == "success") { } else if (funcList$kind == "error") { xml.error <- XML::newXMLNode("error", attrs=c( "message"=funcList$msg, "type"="ERROR")) XML::addChildren(xml.testcase, kids=c(xml.error)) } else if (funcList$kind == "failure") { xml.error <- XML::newXMLNode("failure", attrs=c( "message"=funcList$msg, "type"="FAILURE")) XML::addChildren(xml.testcase, kids=c(xml.error)) } else if (funcList$kind == "deactivated") { xml.skipped <- XML::newXMLNode("skipped") XML::addChildren(xml.testcase, kids=c(xml.skipped)) } } } } } xml <- XML::saveXML(xml.testsuites) if(fileName=="") { write(xml, stdout()) } else { dir.create(dirname(fileName), showWarnings=FALSE, recursive=TRUE) fileConn <- file(fileName) write(xml, fileConn) close(fileConn) } return(invisible(TRUE)) } RUnit/R/html.r0000644000175100001440000003104613267374743012705 0ustar hornikusers## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ writeRaw <- function(htmlStr,htmlFile,append=TRUE) { ##@bdescr ## private function ## write raw text in a html file ##@bdescr ##@in htmlStr : [character] text ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal cat(htmlStr,file=htmlFile,append=append) invisible(TRUE) } writeRawCR <- function(htmlStr,htmlFile,append=TRUE) { ##@bdescr ## private function ## write raw text in a html file with a cr at end ##@bdescr ##@in htmlStr : [character] text ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRaw(htmlStr,htmlFile,append) cat("\n",file=htmlFile,append=TRUE) invisible(TRUE) } writeTitle <- function(htmlStr,htmlFile,append=TRUE) { ##@bdescr ## private function ## write title tags and title text ##@bdescr ##@in htmlStr : [character] title ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRaw("",htmlFile,append) writeRaw(htmlStr,htmlFile) writeRaw("\n",htmlFile) } writeBeginHead <- function(htmlFile,append=TRUE) { ##@bdescr ## private function ## write ##@bdescr ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRaw("",htmlFile,append) } writeEndHead <- function(htmlFile,append=TRUE) { ##@bdescr ## private function ## write ##@bdescr ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRaw("\n",htmlFile,append) } writeBeginHtml <- function(htmlFile,append=TRUE) { ##@bdescr ## private function ## write ##@bdescr ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRaw("",htmlFile,append) } writeEndHtml <- function(htmlFile,append=TRUE) { ##@bdescr ## private function ## write ##@bdescr ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRaw("\n",htmlFile,append) } writeBeginBody <- function(htmlFile,append=TRUE) { ##@bdescr ## private function ## write ##@bdescr ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRaw("",htmlFile,append) } writeEndBody <- function(htmlFile,append=TRUE) { ##@bdescr ## private function ## write ##@bdescr ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRaw("\n",htmlFile,append) } writeBeginTag <- function(htmlTag,htmlFile,para="",append=TRUE) { ##@bdescr ## private function ## write begin of a tag, with parameters ##@bdescr ##@in htmlTag : [character] name of the tag ##@in htmlFile : [character] name of the html file ##@in para : [character] parameters as string ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal if(all(para =="")) { writeRaw(paste("<",htmlTag,">",sep=""),htmlFile,append) } else { writeRaw(paste("<",htmlTag," ",para,">",sep=""),htmlFile,append) } } writeEndTag <- function(htmlTag,htmlFile,append=TRUE) { ##@bdescr ## private function ## write end of tag ##@bdescr ##@in htmlTag : [character] name of the tag ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRaw(paste("",sep=""),htmlFile,append) } writeCR <- function(htmlFile,append=TRUE) { ##@bdescr ## private function ## write CR in html file for better formatting of the html source ##@bdescr ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal cat("\n",file=htmlFile,append=append) invisible(TRUE) } writeBeginTable <- function(header,htmlFile,border=1, width="100%",append=TRUE, columnWidth=NULL) { ##@bdescr ## private function ## write begin of a table ##@bdescr ##@in header : [character] title for columns ##@in htmlFile : [character] name of the html file ##@in border : [integer] border of table ##@in width : [character] width of table ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal tablePara <- paste("border=\"",border,"\" width=\"",width,"\"",sep="") writeRawCR(paste("",sep=""),htmlFile,append) ## if header is provided if (length(header) > 0) { writeBeginTag("tr",htmlFile) for(i in seq_along(header)) { para <- "" if(!is.null(columnWidth)) { if (length(columnWidth) == length(header)) { para = paste("width=\"", columnWidth[i], "\"", sep="") } else { ## recycle first para = paste("width=\"", columnWidth[1], "\"", sep="") } } writeBeginTag("th",htmlFile, para=para) writeRaw(header[i],htmlFile) writeEndTag("th",htmlFile) writeCR(htmlFile) } writeEndTag("tr",htmlFile,append) } writeCR(htmlFile) } writeTableRow <- function(row,htmlFile,append=TRUE,bgcolor="") { ##@bdescr ## private function ## write a table row ##@bdescr ##@in row : [character] data for table cells in row ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@in bgcolor : [character] color for table cells ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeBeginTag("tr",htmlFile) if(length(bgcolor) == 1) { bgcolor <- rep(bgcolor,length(row)) } for(i in seq_along(row)) { if(bgcolor[i] == "") { writeBeginTag("td",htmlFile) } else { writeBeginTag("td",htmlFile,para=paste("bgcolor=\"",bgcolor[i],"\"",sep="")) } writeRaw(row[i],htmlFile) writeEndTag("td",htmlFile) writeCR(htmlFile) } writeEndTag("tr",htmlFile,append) writeCR(htmlFile) } writeLink <- function(target,name,htmlFile,append=TRUE) { ##@bdescr ## private function ## write a link ##@bdescr ##@in target : [character] target of the link ##@in name : [character] name of the target ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeBeginTag("a",htmlFile,paste("href=\"",target,"\"",sep=""),append=append) writeRaw(name,htmlFile,append=TRUE) writeEndTag("a",htmlFile,append=TRUE) } writeEndTable <- function(htmlFile,append=TRUE) { ##@bdescr ## private function ## close an
enviroment by adding
#@bdescr ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeEndTag("table",htmlFile,append) writeCR(htmlFile) } writeHtmlHeader <- function(header,htmlFile) { ##@bdescr ## private function ## write a HTML file header ## - DOCTYPE ## - ## - </head> ## - <body> ## ## should be finished by writeHtmlEnd ##@bdescr ##@in header : [character] title of the document ##@in htmlFile : [character] name of the link ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRawCR("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"", htmlFile,FALSE) writeRawCR("\"http://www.w3.org/TR/html4/transitional.dtd\">",htmlFile) writeBeginHtml(htmlFile) writeBeginHead(htmlFile) writeTitle(header,htmlFile) writeEndHead(htmlFile) writeBeginBody(htmlFile) } writeHtmlEnd <- function(htmlFile) { ##@bdescr ## private function ## write end of html code ##@bdescr ##@in htmlFile : [character] name of the html file ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeEndBody(htmlFile) writeEndHtml(htmlFile) } writeHtmlSep <- function(htmlFile) { ##@bdescr ## private function ## write horizontal seperator ##@bdescr ##@in htmlFile : [character] name of the html file ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeRawCR("<hr>",htmlFile) } writeImage <- function(img,htmlFile,append=TRUE) { ##@bdescr ## private function ## write image tags ##@bdescr ##@in img : [character] name of the image file ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal writeBeginTag("img",htmlFile,para=paste("src=\"",img,"\"",sep=""),append) writeEndTag("img",htmlFile) } writeHtmlSection <- function(title,sec,htmlFile,append=TRUE) { ##@bdescr ## private function ## write titles for section ##@bdescr ##@in title : [character] title of the section ##@in sec : [integer] size of title (between 1-6) ##@in htmlFile : [character] name of the html file ##@in append : [logical] append the html code ##@ret : [logical] TRUE if execution completes ## ##@codestatus : internal secTag <- paste("h",sec,sep="") writeBeginTag(secTag,htmlFile,append) writeRaw(title,htmlFile,append) writeEndTag(secTag,htmlFile,append) writeCR(htmlFile,append) } writeHtmlTable <- function(dataFrame, htmlFile, border=1, width="100%", append=TRUE) { ##@bdescr ## private function ## write a data frame to a HTML table ##@bdescr ## ##@in dataFrame : [data frame] size of title (between 1-6) ##@in htmlFile : [character] name of the html file ##@in border : [integer] 1 (default) table borders will be shown ##@in width : [character] width of table ##@in append : [logical] if TRUE append the tabel to an existing HTML file ##@ret : [logical] TRUE if execution completed ## ##@codestatus : internal header <- NULL colNames <- colnames(dataFrame) if (!is.null(colNames)) { if (length(colNames) == dim(dataFrame)[2]) { header <- colNames } else { ## don't write column names header <- NULL } } rowNames <- rownames(dataFrame) if (!is.null(rowNames)) { header <- c("Name", header) dataFrame <- cbind(rowNames, dataFrame) } writeBeginTable(header, htmlFile, border=border, width=width, append=append, columnWidth=NULL) for (ti in 1:dim(dataFrame)[1]) { writeTableRow(dataFrame[ti, ], htmlFile, append=TRUE, bgcolor="") } writeEndTable(htmlFile,append=TRUE) } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/R/exportHTML.r��������������������������������������������������������������������������������0000644�0001751�0000144�00000023137�14563457515�013750� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2010 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ plotConnection.trackInfo <- function(con, pngfile, ...) { ##@bdescr ## create a plot displaying the execution flow as a graph ##@edescr ## ##@in con : [matrix] counts of execution calls for previous functions ##@in pngfile : [character] string specifying the full path & file name of the ## plot file (PNG) to be generate ##@ret : [NULL] used for its side effect ## ##@codestatus : testing #stopifnot(require(graphics)) ## experimental 2nd order connections ## color for arrows color <- c("black","lightgreen","green","lightblue","blue","orangered","red") ## create nothing if if(all(con==0)) { ## open png device grDevices::png(filename=pngfile,width=1024,height=960) graphics::plot(1:10,axes=FALSE,xlab="",ylab="",main="",type="n") graphics::text(5,5,labels="No connection graph available") grDevices::dev.off() return(invisible()) } ## overall connections allCon <- sum(con) ## connections with percent con <- ceiling(con/sum(con)*100) ## normalize for colors con <- (con + 14) %/% 15 ## open png device grDevices::png(filename=pngfile,width=1024,height=960) ## basic plot plot(x=1:nrow(con), y=1:nrow(con), type="n",axes=FALSE,ylab="# line",xlab="", ylim=c(nrow(con),1)) ## draw text lines text(x=1, y=1:nrow(con), labels=1:nrow(con)) ## offset, to avoid complete overlay offset <- rep(3,length.out=nrow(con)) ## minimal x xmin <- 2 ## check all connections for(i in 1:nrow(con)) { for(j in 1:ncol(con)) { ## check for an existing connection if(con[i,j] != 0) { colDraw <- color[con[i,j]] from <- j to <- i ## circular if(from == to) { top <- from + 0.5 bot <- from - 0.5 middle <- (xmin+offset[from])/2 ## top spline splTop <- stats::spline(c(xmin,middle,offset[from]), c(from + 0.2,top,from)) ## bottom spline splBot <- stats::spline(c(xmin,middle,offset[from]), c(from - 0.2,bot,from)) lines(splTop$x, splTop$y, col=colDraw) lines(splBot$x, splBot$y, col=colDraw) l <- length(splTop$y) ## draw arrow tips arrows(splTop$x[l-1], splTop$y[l-1], splTop$x[l], splTop$y[l], length=0.04, col=colDraw) offset[from] <- offset[from] + 1 } else { ## "regular" case middle <- (i+j)/2; splxy <- stats::spline(c(from - 0.2, middle, to + 0.2), c(xmin - 0.2, offset[from], xmin + 0.2)) lines(splxy$y, splxy$x, col=colDraw) if(i < j) { l <- length(splxy$y) ## draw an arrow tip arrows(splxy$y[l-1], splxy$x[l-1], splxy$y[l], splxy$x[l], length=0.06, col=colDraw) } else { ## draw "inverse" arrow tip arrows(splxy$y[2], splxy$x[2], splxy$y[1], splxy$x[1], length=0.06, col=colDraw) } ## set offset higher offset[from] <- offset[from] + 1 } } } } legposx <- nrow(con) leg.txt <- c("0-15%","15-30%","30-45%","45-60%","60-75%","75-90%","90-100%") legend(x=legposx,y=1,legend=leg.txt,lty=1,xjust=1,col=color) grDevices::dev.off() return(invisible()) } printHTML <- function(object, baseDir=".") UseMethod("printHTML") printHTML.default <- function(object, baseDir=".") NextMethod("printHTML") printHTML.trackInfo <- function(object, baseDir=".") { ##@bdescr ## create a HTML representation of the TrackInfo object data ##@edescr ## ##@in object : [list] trackInfo object ##@in baseDir : [character] string specifying the full path to the root directory to hold the HTML pages ## ## ##@codestatus : untested ## preconditions if (!is(object, "trackInfo")) { stop("argument 'object' has to be a list of class 'trackInfo'.") } if (!is.character(baseDir)) { stop("argument 'baseDir' has to be of type 'character'.") } if (length(baseDir) != 1) { stop("argument 'baseDir' has to contain exactly one element.") } if (is.na(baseDir)) { stop("argument 'baseDir' may not be missing value.") } path <- file.path(baseDir,"results") if (!file.exists(path)) { ok <- dir.create(path) if(!ok) { stop(paste("could not create", path) ) } } htmlFile <- file.path(path,"index.html") footerString <- paste("RUnit ", packageDescription("RUnit", fields="Version"), as.character(Sys.time())) ## create index.html writeHtmlHeader("RUnit Code Inspection - Overview",htmlFile) writeHtmlSection("Overview",2,htmlFile) writeBeginTable(c("Categ.","Name","Signature"),htmlFile) for(i in seq_along(object)) { funcID <- strsplit(names(object)[i],"/")[[1]] funcCat <- funcID[1] funcName <- funcID[2] if(length(funcID) > 2) { sig <- funcID[3:length(funcID)] funcSig <- paste(funcName,"(",paste(sig,collapse=", "),")",sep="") } else { funcSig <- "" } writeBeginTag("tr",htmlFile) writeCR(htmlFile) ## write function category writeBeginTag("td",htmlFile) writeRaw(funcCat,htmlFile) writeEndTag("td",htmlFile) writeCR(htmlFile) ## write function name writeBeginTag("td",htmlFile) writeLink(file.path(".", paste("result",i,".html",sep="")), funcName, htmlFile) writeEndTag("td",htmlFile) writeCR(htmlFile) ## write function signature writeBeginTag("td",htmlFile) writeRaw(funcSig,htmlFile) writeEndTag("td",htmlFile) writeCR(htmlFile) writeEndTag("tr",htmlFile) } writeEndTable(htmlFile) writeRaw(footerString, htmlFile) writeHtmlEnd(htmlFile) writeLinkRef <- function(htmlFile,leftLink,leftName,rightLink,rightName) { writeBeginTable(c("",""),htmlFile,border=0,width="100%") writeBeginTag("tr",htmlFile) writeCR(htmlFile) writeBeginTag("td",htmlFile) writeLink(leftLink,leftName,htmlFile) writeEndTag("td",htmlFile) writeCR(htmlFile) writeBeginTag("td",htmlFile,"align=\"right\""); writeLink(rightLink,rightName,htmlFile) writeEndTag("td",htmlFile) writeEndTag("tr",htmlFile) writeCR(htmlFile) writeEndTable(htmlFile) } ## create result pages for(i in seq_along(object)) { absGraphImg <- file.path(path, paste("con",i,".png",sep="")) absGraphFile <- file.path(path, paste("con",i,".html",sep="")) relGraphImg <- file.path(".", paste("con",i,".png",sep="")) relGraphFile <- file.path(".", paste("con",i,".html",sep="")) relHTMLFile <- file.path(".", paste("result",i,".html",sep="")) htmlFile <- file.path(path, paste("result",i,".html",sep="")) ## begin result page writeHtmlHeader("RUnit Code Inspection - Result",htmlFile) writeLinkRef(htmlFile,"index.html","index",relGraphFile,"graph") writeHtmlSep(htmlFile) writeHtmlSection("Result",2,htmlFile) funcName <- strsplit(names(object)[i],"/")[[1]][2] writeRaw("Function: ",htmlFile) writeBeginTag("b",htmlFile) writeRaw(funcName,htmlFile) writeEndTag("b",htmlFile) writeCR(htmlFile) writeRaw("Runs: ",htmlFile) writeBeginTag("b",htmlFile) writeRaw(object[[i]]$nrRuns,htmlFile) writeEndTag("b",htmlFile) writeCR(htmlFile) writeCR(htmlFile) writeBeginTable(c("line","code","calls","time"),htmlFile) for(j in seq_along(object[[i]]$src)) { srcLine <- object[[i]]$src[j] leadingSpaceNr <- attr(regexpr("^( )*",srcLine),"match.length") if(leadingSpaceNr > 0) { srcLine <- gsub("^( )*","",srcLine) srcLine <- paste(paste(rep(" ",leadingSpaceNr),collapse=""), srcLine,collapse="",sep="") } if(object[[i]]$run[j] > 0) { bgcolor <- "#00D000" } else { bgcolor <- "#D00000" } writeTableRow(c(j,srcLine,object[[i]]$run[j],round(object[[i]]$time[j],2)), htmlFile,bgcolor=bgcolor) } writeEndTable(htmlFile) writeHtmlSep(htmlFile) writeLinkRef(htmlFile,"index.html","index",relGraphFile,"graph") writeHtmlSep(htmlFile) writeRaw(footerString, htmlFile) writeHtmlEnd(htmlFile) ## Conncetion plot plotConnection.trackInfo(object[[i]]$graph, absGraphImg) writeHtmlHeader("RUnit Code Inspection - Connection Graph",absGraphFile) writeLinkRef(absGraphFile,"index.html","index",relHTMLFile,"Function") writeHtmlSep(absGraphFile) writeHtmlSection("Connection Graph",2,absGraphFile) writeImage(relGraphImg,absGraphFile) writeCR(absGraphFile) writeHtmlSep(absGraphFile) writeLinkRef(absGraphFile,"index.html","index",relHTMLFile,"Function") writeRaw(footerString, absGraphFile) writeHtmlEnd(absGraphFile) } return(invisible()) } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/R/inspector.r���������������������������������������������������������������������������������0000644�0001751�0000144�00000035312�13267374743�013747� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ includeTracker <- function(fbody, track=track) { ##@bdescr ## Internal function ## ##@edescr ## ##@in fbody : [character] vector of code lines of function to track ##@in track : [trackInfo] list ##@ret : [list] with elements list(modFunc=c(sig,newBody),newSource = newCode) ## ##@codestatus : internal ## get the signature sig <- fbody[1] ## get the block structure (important for if, for, while, else with one line) block <- sapply(fbody[-1],function(x) regexpr("[^ ]",x)[1], USE.NAMES=FALSE) ## vector of keywords kwOpen <- c("for","while","repeat","if","else") ## keyword at begin kwGrep <- paste("(",paste(kwOpen,sep="",collapse="|"),")",sep="") oneLiner <- function(code) { ##@bdescr ## utility ## search a character vector ie. the vector of lines of a function body ## for block structures e.g. for|while|repeat|if|else { } code block ##@edescr ## ##@in code : [character] vector of function body code lines ##@ret : [logical] vector of length of code, indication which are one line control blocks ## ##@codestatus : internal return(sapply(code, function(line) { opBr <- grep(paste("^[ ]*",kwGrep,".*[ ]+$",sep=""), line) ## special case if combined with assignment or math operators opBr2 <- grep(paste("(<-|=|\\+|\\-|\\*|\\/)[ ]*if[ ]*\\(",sep=""), line) if(length(opBr) > 0 || length(opBr2) > 0) { return(TRUE) } return(FALSE) }, USE.NAMES=FALSE)) } ## set Brackets setBrackets <- function(potLine,block,env) { ##@bdescr ## ##@edescr ## ##@in potLine : [logical] mask vector which line contains a one-line control construct ##@in block : [integer] vector ##@in env : [logical] mask vector: which line already contains a opening brace ##@ret : [list] with matching element vectors: openBr & clodeBr ## ##@codestatus : internal oBr <- character(length(potLine)) clBr <- character(length(potLine)) lineIdx <- 1L while(lineIdx < length(potLine)) { if(potLine[lineIdx] && !(potLine[lineIdx+1])) { oBr[lineIdx] <- "{" if (!env[lineIdx+1]) { clBr[lineIdx+2] <- paste(clBr[lineIdx+2],"}") } else { bbl <- block[lineIdx] endBlockIdx <- min(which((bbl >= block) & (seq_along(block) > lineIdx))) clBr[endBlockIdx] <- paste(clBr[endBlockIdx],"}") } } else if(potLine[lineIdx] && (potLine[lineIdx+1]) ) { oBr[lineIdx] <- "{" bbl <- block[lineIdx] endBlockIdx <- min(which((bbl >= block) & (seq_along(block) > lineIdx))) clBr[endBlockIdx] <- paste(clBr[endBlockIdx],"}") } lineIdx <- lineIdx + 1L } return(list(openBr=oBr, closeBr=clBr)) } ## check for new environments env <- sapply(fbody[-1], function(code) { envIdx <- grep("\\{$",code) if(length(envIdx) > 0) { return(TRUE) } return(FALSE) },USE.NAMES=FALSE) ## check the block structure block <- sapply(fbody[-1], function(x) regexpr("[^ ]",x)[1], USE.NAMES=FALSE) ## is 4 a convention or a rule? block <- (block %/% 4) + 1 ## check for if's, while's, etc. ol <- oneLiner(fbody[-1]) ## create brackets for control structures without new environments br <- setBrackets(ol,block,env) ## create new Code newCode <- paste(as.vector(rbind(br$closeBr,fbody[-1],br$openBr))) newCode <- newCode[newCode != ""] ## include the breakpoint function bpVec <- sapply(newCode, function(line) { nobp <- grep("^[ ]*(else |\\{|\\})",line) if(length(nobp) == 0) { return("track$bp();") } return("") },USE.NAMES=FALSE) for(i in seq_along(bpVec)) { bpVec[i] <- gsub("\\(\\)",paste("(",i,")",sep=""),bpVec[i]) } ## create the mainpulated body of the function newBody <- paste(bpVec,newCode) ## return signature and body return(list(modFunc=c(sig,newBody), newSource=newCode)) } tracker <- function() { ##@bdescr ## initialization of the central tracking object ## which stores all information related to inspection results and code execution structure ## defines accessor functions ## - addFunc (fId,src,callExpr): add specified function to the track list ## - getSource(nr): get the source code (character) for function nr on track list ## - init ## - bp ## - getTrackInfo ## - isValidTrackInfo ##@edescr ## ##@ret : [list] OO object with functions addFunc, getSourcee, init, bp, getTrackInfo ## ##@codestatus : testing ## object for information trackInfo <- list() class(trackInfo) <- "trackInfo" ## current function index fIdx <- 0 ## old time oldTime <- NULL ## old src line oldSrcLine <- 0 addFunc <- function(fId,src,callExpr) { ##@bdescr ## ## accessor function ##@edescr ## ##@in fId : [character] function name ##@in src : [character] source code character vector ##@in callExpr : [character] function call ##@ret : [NULL] returns invisible, used for its side effects ## ## codestatus : internal ## preconditions if( length(fId) != 1) { stop("fId must be one character string: function name") } isThere <- which(fId == names(trackInfo)) if(length(isThere) == 1) { ## already in tracking list fIdx <<- isThere } else { fIdx <<- fIdx + 1 newFuncInfo <- list(src=src, run=integer(length(src)), time=numeric(length(src)), graph=matrix(0,nrow=length(src),ncol=length(src)), nrRuns=as.integer(0), funcCall=callExpr) ## append strips class attribute trackInfo <- append(trackInfo,list(newFuncInfo)) names(trackInfo)[fIdx] <- fId class(trackInfo) <- "trackInfo" ## update global state trackInfo <<- trackInfo } ## increment run number trackInfo[[fIdx]]$nrRuns <<- trackInfo[[fIdx]]$nrRuns + 1 ## initialize local variables oldSrcLine <<- 0 oldTime <<- NULL return(invisible()) } getTrackInfo <- function() { ##@bdescr ## ## accessor function ## returns the main inspection result list with ## elements ## - src ## - run ## - time ## - graph ## - nrRuns ## - funCall ##@edescr ## ##@ret : [trackInfo] S3 class list (see description above) ## ## codestatus : internal return(trackInfo) } init <- function() { ##@bdescr ## ## initalisation function ## sets/resets variables run and fIdx ##@edescr ## ##@ret : [NULL] returns invisible, used for its side effects ## ## codestatus : internal trackInfoInit <- list() class(trackInfoInit) <- "trackInfo" trackInfo <<- trackInfoInit fIdx <<- 0L return(invisible()) } bp <- function(nr) { ##@bdescr ## ## accessor function ##@edescr ## ##@in : [integer] index, function run number ##@ret : [NULL] returns invisible, used for its side effects ## ## codestatus : internal ## preconditions if (length(nr) != 1) { stop("argument 'nr' has to be of length 1.") } if (is.na(nr)) { stop("argument 'nr' may not contain missing value (NA).") } trackInfo[[fIdx]]$run[nr] <<- trackInfo[[fIdx]]$run[nr] + 1 ## cumulative processing time if(!is.null(oldTime)) { dtime <- proc.time()[1] - oldTime trackInfo[[fIdx]]$time[nr] <<- trackInfo[[fIdx]]$time[nr] + dtime } oldTime <<- proc.time()[1] ## graph if(oldSrcLine != 0) { trackInfo[[fIdx]]$graph[oldSrcLine,nr] <<- trackInfo[[fIdx]]$graph[oldSrcLine,nr] + 1 } ## store the old line oldSrcLine <<- nr return(invisible()) } getSource <- function(nr) { ##@bdescr ## ## accessor function ## returns the source code as character string ##@edescr ## ##@in : [integer] index, function run number ##@ret : [character] string, source code ## ##@codestatus : untested ## preconditions if (length(nr) != 1) { stop("argument 'nr' has to be of length 1.") } if (is.na(nr)) { stop("argument 'nr' may not contain missing value (NA).") } return(trackInfo[[nr]]$src) } isValidTrackInfo <- function(trackInfo) { ##@bdescr ## test function ## returns TRUE iff trackInfo object fullfils S3 class definition constraints ## - S3 class 'trackInfo' ## - with elements ## - src [character] vector of function source code lines ## - run [integer] vector of no. of times this function was called ## - time [numeric] vector of function execution times in seconds per call ## - graph [matrix] connection matrix (# code linbes x # of execution calls) ## - nrRuns [integer] ## - funcCall [character] function call ##@edescr ## ##@in : [trackInfo] S3 class object ##@ret : [logical] TRUE, iff object fullfils class definition constraints ## ##@codestatus : untested if (!is(trackInfo,"trackInfo")) { return(FALSE) } checkElements <- function(x) { if (!all(c("src", "run", "time", "graph", "nrRuns", "funcCall") %in% names(x))) { return(FALSE) } if (length(x[["run"]]) < 1 || any(is.na(x[["run"]])) || any(x[["run"]] < 0)) { return(FALSE) } if (length(x[["time"]]) < 1 || any(is.na(x[["time"]])) || any(x[["time"]] < 0)) { return(FALSE) } ## TODO: graph if (length(x[["nrRuns"]]) != 1 || is.na(x[["nrRuns"]]) || x[["nrRuns"]] < 0) { return(FALSE) } if (length(x[["funcCall"]]) != 1 || is.na(x[["funcCall"]])) { return(FALSE) } } ok <- sapply(trackInfo, checkElements) if (!all(ok)) { return(FALSE) } return(TRUE) } return(list(addFunc=addFunc, getSource=getSource, init=init, bp=bp, getTrackInfo=getTrackInfo, isValid=isValidTrackInfo)) } inspect <- function(expr, track=track) { ##@bdescr ## inspector function ## an attempt is made to parse the expression or function ## insert track info statements to be used for subsequent ## code execution structure displays ## ## can handle functions aswell as generics ##@edescr ## ##@in expr : [call] ##@in track : [list] tracker object ##@ret : [expression|ANY] either the unevaluated expression of the function or the result of the function call ## ##@codestatus : testing ## get the call and its parameters fCall <- as.character(substitute(expr)) ## get the original call callExpr <- deparse(substitute(expr)) ## get the name of the function fname <- fCall[1] ## check for generic function if(isGeneric(fname)) { ## get type of arguments selType <- sapply(fCall[-1], function(x) { if(exists(x, envir=sys.parent(sys.parent()))) { varSig <- is(get(x,envir=sys.parent(sys.parent())))[1] } else { varSig <- is(eval(parse(text=x)))[1] } return(varSig) },USE.NAMES=FALSE) ## we have to check for missing arguments formalArg <- names(formals(getGeneric(fCall[1]))) ## number of missing arguments nrMissing <- length(formalArg) - length(selType) if(nrMissing > 0) { ## check for ... ellipseIdx <- which(formalArg == "...") if(length(ellipseIdx) != 0) { selType <- c(selType,rep("missing",nrMissing -1 )) } else { selType <- c(selType,rep("missing",nrMissing)) } } ## select function selFunc <- selectMethod(fname, selType) ## deparse the function fbody <- deparse(selFunc@.Data, width.cutoff=500) ## create an identifier for the generic function fNameId <- paste("S4",fname,paste(selFunc@defined@.Data, collapse="/"), sep="/") } else { ## deparse the function fbody <- try(deparse(get(fname), width.cutoff=500), silent=TRUE) if (inherits(fbody, "try-error")) { ## in case the function is defined ## in the test case file fbody <- try(deparse(get(fname, envir=sys.parent()), width.cutoff=500)) if (inherits(fbody, "try-error")) { stop("function not found.") } } ## create an identifier for the generic function fNameId <- paste("R/",fname,sep="") } ## generate the new body of the function newFunc <- includeTracker(fbody, track=track) track$addFunc(fNameId, newFunc$newSource, callExpr) ## build the test function eval(parse(text=c("testFunc <- ",newFunc$modFunc)),envir=sys.frame()) ## create function call newFunCall <- paste("testFunc(",paste(fCall[-1], collapse=","), ")",sep="") parsedFunc <- try(parse(text=newFunCall)) ## check for an error if(!inherits(parsedFunc,"try-error")) { ## call the new function res <- eval(parsedFunc, envir=parent.frame()) } else { ## no parsing possible ## simple call without tracking res <- expr } ## do here some error checking return(res) } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/R/htmlProtocol.r������������������������������������������������������������������������������0000644�0001751�0000144�00000041413�13267374743�014426� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ printHTMLProtocol <- function(testData, fileName = "", separateFailureList = TRUE, traceBackCutOff=9, testFileToLinkMap=function(x) x) { ##@bdescr ## Report generator ## Extracts the log information stored in the 'RUnitTestData' test run object ## and generates a well formated HTML output. ##@edescr ## ##@in testData : [RUnitTestData] S3 class object ##@in fileName : [character] ##@in separateFailureList : [logical] if TRUE (default) add a list of all failures ##@in traceBackCutOff : [integer] number of steps back in the trace back stack to be displayed ##@in testFileToLinkMap : [function] a function transforming the full name of the test file to a link location ##@ret : [logical] TRUE if execution completed w/o error ## ##@codestatus : testing ## -------------------------------- ## CHECK OF INPUT DATA ## -------------------------------- if (!is(testData, "RUnitTestData")) { stop("Argument 'testData' must be of class 'RUnitTestData'.") } if (!is.character(fileName)) { stop("Argument 'fileName' has to be of type character.") } if (length(fileName) != 1) { stop("Argument 'fileName' must contain exactly one element.") } if (!is.logical(separateFailureList)) { stop("Argument 'separateFailureList' has to be of type logical.") } if (length(separateFailureList) != 1) { stop("Argument 'separateFailureList' must contain exactly one element.") } if (!is.numeric(traceBackCutOff)) { stop("Argument 'traceBackCutOff' has to be of type logical.") } if (length(traceBackCutOff) != 1) { stop("Argument 'traceBackCutOff' must contain exactly one element.") } if (traceBackCutOff < 0 || traceBackCutOff > 100) { stop("Argument 'traceBackCutOff' out of valid range [0, 100].") } ## -------------------------------- ## HELPER FUNCTIONS ## -------------------------------- ## get singular or plural right sop <- function(number, word, plext="s") { ifelse(number == 1, paste(number, word), paste(number, paste(word, plext, sep=""))) } pr <- function(...) { writeRaw(paste(...), htmlFile=fileName) writeRaw("<br/>", htmlFile=fileName) } writeP <- function(string, para="") { writeBeginTag("p", para=para, htmlFile=fileName) writeRaw(string, htmlFile=fileName) writeEndTag("p", htmlFile=fileName) writeCR(htmlFile=fileName) } writeLi <- function(..., para="") { writeBeginTag("li", para=para, htmlFile=fileName) writeRaw(paste(...), htmlFile=fileName) writeEndTag("li", htmlFile=fileName) } createTestFuncRef <- function(testSuite, srcFileName, testFuncName, asAnchor=FALSE) { tmp <- paste(testSuite, srcFileName, testFuncName, sep="_") if(asAnchor) { return(paste("#", gsub("/", "_", tmp), sep="")) } else { return(gsub("/", "_", tmp)) } } printTraceBack <- function(traceBack) { if(length(traceBack) > 0) { writeRaw("Call Stack:<br/>", htmlFile=fileName) if(traceBackCutOff > length(testFuncInfo$traceBack)) { writeRaw("(traceBackCutOff argument larger than length of trace back: full trace back printed)<br/>", htmlFile=fileName) writeBeginTag("ol", htmlFile=fileName) for(i in seq_along(traceBack)) { writeBeginTag("li", htmlFile=fileName) writeRaw(traceBack[i], htmlFile=fileName) writeEndTag("li", htmlFile=fileName) } } else { writeBeginTag("ol", htmlFile=fileName) for(i in traceBackCutOff:length(traceBack)) { writeBeginTag("li", htmlFile=fileName) writeRaw(traceBack[i], htmlFile=fileName) writeEndTag("li", htmlFile=fileName) } } writeEndTag("ol", htmlFile=fileName) } } errorStyle <- "color:red" deactivatedStyle <- "color:black" ## -------------------------------------------- ## PART 1: TITLE AND BASIC ERROR INFORMATION ## -------------------------------------------- ## title title <- paste("RUNIT TEST PROTOCOL", date(), sep="--") writeHtmlHeader(title, htmlFile=fileName) writeHtmlSection(title, 1, htmlFile=fileName) if(length(testData) == 0) { writeP(" no test cases :-(") return(invisible(TRUE)) } ## basic Info errInfo <- getErrors(testData) writeP(paste("Number of test functions:", errInfo$nTestFunc)) if(errInfo$nDeactivated > 0) { writeP(paste("Number of deactivated test functions:", errInfo$nDeactivated), para=ifelse(errInfo$nDeactivated == 0, "", paste("style", deactivatedStyle, sep="="))) } writeP(paste("Number of errors:", errInfo$nErr), para=ifelse(errInfo$nErr == 0, "", paste("style", errorStyle, sep="="))) writeP(paste("Number of failures:", errInfo$nFail), para=ifelse(errInfo$nFail == 0, "", paste("style", errorStyle, sep="="))) writeHtmlSep(htmlFile=fileName) ## -------------------------------- ## PART 2: TABLE OF TEST SUITES ## -------------------------------- ## summary of test suites writeHtmlSection(sop(length(testData), "Test suite"), 3, htmlFile=fileName) ## table of test suites if(errInfo$nDeactivated > 0) { writeBeginTable(c("Name", "Test functions", "Deactivated", "Errors", "Failures"), width="80%", htmlFile=fileName, columnWidth=c("20%", "20%", "20%", "20%", "20%")) for(tsName in names(testData)) { rowString <- c(paste("<a href=\"#", tsName, "\">", tsName, "</a>", sep=""), testData[[tsName]]$nTestFunc, testData[[tsName]]$nDeactivated, testData[[tsName]]$nErr, testData[[tsName]]$nFail) rowCols <- c("", "", ifelse(testData[[tsName]]$nDeactivated==0, "", "yellow"), ifelse(testData[[tsName]]$nErr==0, "", "red"), ifelse(testData[[tsName]]$nFail==0, "", "red")) writeTableRow(row=rowString, bgcolor=rowCols, htmlFile=fileName) } writeEndTable(htmlFile=fileName) } else { ## skip 'deactivated' column if no function has been deactivated writeBeginTable(c("Name", "Test functions", "Errors", "Failures"), width="60%", htmlFile=fileName, columnWidth=c("30%", "30%", "20%", "20%")) for(tsName in names(testData)) { rowString <- c(paste("<a href=\"#", tsName, "\">", tsName, "</a>", sep=""), testData[[tsName]]$nTestFunc, testData[[tsName]]$nErr, testData[[tsName]]$nFail) rowCols <- c("", "", ifelse(testData[[tsName]]$nErr==0, "", "red"), ifelse(testData[[tsName]]$nFail==0, "", "red")) writeTableRow(row=rowString, bgcolor=rowCols, htmlFile=fileName) } writeEndTable(htmlFile=fileName) } writeHtmlSep(htmlFile=fileName) ## ------------------------------------------------ ## PART 3: ERROR, FAILURE AND DEACTIVATED TABLES ## ------------------------------------------------- ## error table if(separateFailureList && (errInfo$nErr > 0)) { writeHtmlSection("Errors", 3, htmlFile=fileName) writeBeginTable(c("Test suite : test function", "message"), htmlFile=fileName, columnWidth=c("30%", "70%")) for(tsName in names(testData)) { if(testData[[tsName]]$nErr > 0) { srcFileRes <- testData[[tsName]]$sourceFileResults srcFileNames <- names(srcFileRes) for(i in seq_along(srcFileRes)) { testFuncNames <- names(srcFileRes[[i]]) for(j in seq_along(testFuncNames)) { funcList <- srcFileRes[[i]][[testFuncNames[j]]] if(funcList$kind == "error") { lnk <- paste("<a href=\"", createTestFuncRef(tsName, srcFileNames[i], testFuncNames[j], asAnchor=TRUE), "\">", paste(tsName, testFuncNames[j], sep=" : "), "</a>", sep="") writeTableRow(row=c(lnk, funcList$msg), htmlFile=fileName) } } } } } writeEndTable(htmlFile=fileName) writeHtmlSep(htmlFile=fileName) } ## failure table if(separateFailureList && (errInfo$nFail > 0)) { writeHtmlSection("Failures", 3, htmlFile=fileName) writeBeginTable(c("Test suite : test function", "message"), htmlFile=fileName, columnWidth=c("30%", "70%")) for(tsName in names(testData)) { if(testData[[tsName]]$nFail > 0) { srcFileRes <- testData[[tsName]]$sourceFileResults srcFileNames <- names(srcFileRes) for(i in seq_along(srcFileRes)) { testFuncNames <- names(srcFileRes[[i]]) for(j in seq_along(testFuncNames)) { funcList <- srcFileRes[[i]][[testFuncNames[j]]] if(funcList$kind == "failure") { lnk <- paste("<a href=\"", createTestFuncRef(tsName, srcFileNames[i], testFuncNames[j], asAnchor=TRUE), "\">", paste(tsName, testFuncNames[j], sep=" : "), "</a>", sep="") writeTableRow(row=c(lnk, funcList$msg), htmlFile=fileName) } } } } } writeEndTable(htmlFile=fileName) writeHtmlSep(htmlFile=fileName) } ## deactivated table if(separateFailureList && (errInfo$nDeactivated > 0)) { writeHtmlSection("Deactivated", 3, htmlFile=fileName) writeBeginTable(c("Test suite : test function", "message"), htmlFile=fileName, columnWidth=c("30%", "70%")) for(tsName in names(testData)) { if(testData[[tsName]]$nDeactivated > 0) { srcFileRes <- testData[[tsName]]$sourceFileResults srcFileNames <- names(srcFileRes) for(i in seq_along(srcFileNames)) { testFuncNames <- names(srcFileRes[[i]]) for(j in seq_along(testFuncNames)) { funcList <- srcFileRes[[i]][[testFuncNames[j]]] if(funcList$kind == "deactivated") { lnk <- paste("<a href=\"", createTestFuncRef(tsName, srcFileNames[i], testFuncNames[j], asAnchor=TRUE), "\">", paste(tsName, testFuncNames[j], sep=" : "), "</a>", sep="") writeTableRow(row=c(lnk, funcList$msg), htmlFile=fileName) } } } } } writeEndTable(htmlFile=fileName) writeHtmlSep(htmlFile=fileName) } ## -------------------------------- ## PART 4: DETAILS ## -------------------------------- writeHtmlSection("Details", 3, htmlFile=fileName) ## loop over all test suites for(tsName in names(testData)) { tsList <- testData[[tsName]] writeBeginTag("p", htmlFile=fileName) writeBeginTag("a", para=paste("name=\"", tsName, "\"", sep=""), htmlFile=fileName) writeHtmlSection(paste("Test Suite:", tsName), 5, htmlFile=fileName) writeEndTag("a", htmlFile=fileName) pr("Test function regexp:", tsList$testFuncRegexp) pr("Test file regexp:", tsList$testFileRegexp) if(length(tsList$dirs) == 0) { pr("No directories !") } else { if(length(tsList$dirs) == 1) { pr("Involved directory:") } else { pr("Involved directories:") } for(dir in tsList$dirs) { pr(dir) } res <- tsList$sourceFileResults testFileNames <- names(res) if(length(res) == 0) { pr(" no test files") } else { ## loop over all source files writeBeginTag("ul", htmlFile=fileName) for(testFileName in testFileNames) { testFuncNames <- names(res[[testFileName]]) if(length(testFuncNames) > 0) { writeBeginTag("li", htmlFile=fileName) writeLink(target=testFileToLinkMap(testFileName), name=paste("Test file:", basename(testFileName)), htmlFile=fileName) ## loop over all test functions in the test file writeBeginTag("ul", htmlFile=fileName) for(testFuncName in testFuncNames) { writeBeginTag("li", htmlFile=fileName) testFuncInfo <- res[[testFileName]][[testFuncName]] anchorName <- createTestFuncRef(tsName, testFileName, testFuncName) writeBeginTag("a", para=paste("name=\"", anchorName, "\"", sep=""), htmlFile=fileName) if(testFuncInfo$kind == "success") { pr(paste(testFuncName, ": (",testFuncInfo$checkNum, " checks) ... OK (", testFuncInfo$time, " seconds)", sep="")) writeEndTag("a", htmlFile=fileName) } else { if(testFuncInfo$kind == "error") { writeBeginTag("u", para=paste("style", errorStyle, sep="="), htmlFile=fileName) writeRaw(paste(testFuncName, ": ERROR !! ", sep=""), htmlFile=fileName) writeEndTag("u", htmlFile=fileName) writeEndTag("a", htmlFile=fileName) } else if (testFuncInfo$kind == "failure") { writeBeginTag("u", para=paste("style", errorStyle, sep="="), htmlFile=fileName) writeRaw(paste(testFuncName, ": FAILURE !! (check number ", testFuncInfo$checkNum, ") ", sep=""), htmlFile=fileName) writeEndTag("u", htmlFile=fileName) writeEndTag("a", htmlFile=fileName) } else if (testFuncInfo$kind == "deactivated") { writeBeginTag("u", para=paste("style", deactivatedStyle, sep="="), htmlFile=fileName) writeRaw(paste(testFuncName, ": DEACTIVATED, ", sep=""), htmlFile=fileName) writeEndTag("a", htmlFile=fileName) } else { writeLi(paste(testFuncName, ": unknown error kind", sep="")) writeEndTag("a", htmlFile=fileName) } pr(testFuncInfo$msg) printTraceBack(testFuncInfo$traceBack) } writeEndTag("li", htmlFile=fileName) } writeEndTag("ul", htmlFile=fileName) } writeEndTag("li", htmlFile=fileName) } writeEndTag("ul", htmlFile=fileName) } } writeHtmlSep(htmlFile=fileName) } ver <- cbind(unlist(version)) ## add host name ver <- rbind(ver, Sys.info()["nodename"]) rownames(ver)[dim(ver)[1]] <- "host" colnames(ver) <- "Value" ## compiler used (under *nix) rhome <- Sys.getenv("R_HOME") ## on Windows Makeconf does not exist ## other than that we have no indication which compiler ## would be used for R CMD INSTALL so we report NA gccVersion <- as.character(NA) makeconfFile <- file.path(rhome, "etc", "Makeconf") if (file.exists(makeconfFile) && identical(.Platform$OS.type, "unix")) { gccVersion <- system(paste("cat ", makeconfFile," | grep \"^CXX =\" "), intern=TRUE) gccVersion <- sub("^CXX[ ]* =[ ]*", "", gccVersion) } ver <- rbind(ver, gccVersion) rownames(ver)[dim(ver)[1]] <- "compiler" writeHtmlTable(ver, htmlFile=fileName, border=0, width="80%", append=TRUE) ## finish html document writeHtmlEnd(htmlFile=fileName) return(invisible(TRUE)) } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/R/00Init.r������������������������������������������������������������������������������������0000644�0001751�0000144�00000002524�13267374743�013003� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������###################################################################### ## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ RUnitEnv <- new.env() .onLoad <- function(libname, pkgname) { ##@bdescr ## Internal Function. ## Not to be called by users. ##@edescr ## runitVersion <- packageDescription("RUnit", lib.loc=libname, fields="Version") assign(".testLogger", NULL, envir=RUnitEnv) ## add options to R's global options list .buildRUnitOptions() } .onUnload <- function(libpath) { ## drop RUnit specific options from global options list options("RUnit"=NULL) } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/R/runit.r�������������������������������������������������������������������������������������0000644�0001751�0000144�00000036427�14561532231�013074� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ defineTestSuite <- function(name, dirs, testFileRegexp="^runit.+\\.[rR]$", testFuncRegexp="^test.+", rngKind="Marsaglia-Multicarry", rngNormalKind="Kinderman-Ramage") { ##@bdescr ## Convenience functions to handle test suites ##@edescr ## ##@in name : [character] test suite title used in protocol ##@in dirs : [character] vector of paths to search for test case files ##@in testFileRegexp : [character] regular expression string to match file names ##@in testFuncRegexp : [character] (vector) regular expression string(s) to match test case functions within all test case files ##@in rngKind : [character] name of the RNG version, see RNGversion() ##@in rngNormalKind : [character] name of the RNG version for the rnorm, see RNGversion() ##@ret : [RUnitTestSuite] S3 class (list) object, ready for test runner ## ##@codestatus : testing if (missing(dirs)) { stop("argument 'dirs' is missing without a default.") } if (missing(name)) { warning("argument 'name' is missing. using basename(dirs)[1] instead.") name <- basename(dirs)[1] } ret <- list(name=name, dirs=dirs, testFileRegexp=testFileRegexp, testFuncRegexp=testFuncRegexp, rngKind=rngKind, rngNormalKind=rngNormalKind) class(ret) <- "RUnitTestSuite" return(invisible(ret)) } isValidTestSuite <- function(testSuite) { ##@bdescr ## Helper function ## checks 'RUnitTestSuite' class object features ##@edescr ## ##@in testSuite : [RUnitTestSuite] S3 class (list) object, input object for test runner ##@ret : [logical] TRUE if testSuite is valid ## ##@codestatus : testing if(!is(testSuite, "RUnitTestSuite")) { warning(paste("'testSuite' object is not of class 'RUnitTestSuite'.")) return(FALSE) } ## check required elements, irrespective of order, allow for additional elements requiredNames <- c("name", "dirs", "testFileRegexp", "testFuncRegexp", "rngKind", "rngNormalKind") if(!all(requiredNames %in% names(testSuite))) { warning("'testSuite' object does not conform to S3 class definition. Not all list elements present.") return(FALSE) } for(i in seq_along(testSuite)) { if(!is.character(testSuite[[i]])) { warning(paste("'testSuite' object does not conform to S3 class definition.\n", "'", names(testSuite)[i],"' element has to be of type 'character'.", sep="")) return(FALSE) } if(any(testSuite[[i]] == "")) { warning(paste("'testSuite' object does not conform to S3 class definition.\n", "'",names(testSuite)[i],"' element may not contain empty string.", sep="")) return(FALSE) } } notFound <- !file.exists(testSuite[["dirs"]]) if (any(notFound)) { warning(paste("specified directory", paste(testSuite[["dirs"]][notFound], collapse=", "), "not found.")) return(FALSE) } if (length(testSuite[["name"]]) != 1) { warning(paste("'name' element may only contain exactly one name.")) return(FALSE) } if (length(testSuite[["testFileRegexp"]]) != 1) { warning(paste("'testFileRegexp' element may only contain exactly one string.")) return(FALSE) } if (length(testSuite[["testFuncRegexp"]]) != 1) { warning(paste("'testFuncRegexp' element may only contain exactly one string.")) return(FALSE) } ## RNGkind has an internal list of valid names which cannot be accessed ## programmatically. Furthermore, users can define their own RNG and select that one ## so we have to leave it to RNGkind() to check if the arguments are valid. if (length(testSuite[["rngKind"]]) != 1) { warning(paste("'rngKind' element may only contain exactly one name.")) return(FALSE) } if (length(testSuite[["rngNormalKind"]]) != 1) { warning(paste("'rngNormalKind' element may only contain exactly one name.")) return(FALSE) } return(TRUE) } .setUp <- function() { ##@bdescr ## Internal Function. ## Default function to be executed once for each test case before the test case gets executed. ## This function can be adopted to specific package requirements for a given project. ## Need to replace this default with a new function definition. ## Function cannot take arguments and does not have a return value. ##@edescr ## ##@codestatus : internal return(invisible()) } .tearDown <- function() { ##@bdescr ## Internal Function. ## Default function to be executed once for each test case after the test case got executed. ## This function can be adopted to specific package requirements for a given project. ## Need to replace this default with a new function definition. ## Function cannot take arguments and does not have a return value. ##@edescr ## ##@codestatus : internal return(invisible()) } .executeTestCase <- function(funcName, envir, setUpFunc, tearDownFunc) { ##@bdescr ## Internal Function. ## Execute individual test case, record logs and change state of global TestLogger object. ##@edescr ## ##@in funcName : [character] name of test case function ##@in envir : [environment] ##@in setUpFunc : [function] ##@in tearDownFunc : [function] ##@ret : [NULL] ## ##@codestatus : internal ## write to stdout for logging func <- get(funcName, envir=envir) ## anything else than a function is ignored. if(mode(func) != "function") { return(invisible()) } if (RUnitEnv$.testLogger$getVerbosity() > 0) { cat("\n\nExecuting test function", funcName, " ... ") } ## safe execution of setup function res <- try(setUpFunc()) if (inherits(res, "try-error")) { message <- paste("Error executing .setUp before",funcName, ":", geterrmessage()) RUnitEnv$.testLogger$addError(testFuncName=paste(".setUp (before ", funcName, ")", sep=""), errorMsg=message) return(invisible()) } ## reset book keeping variables in RUnitEnv$.testLogger RUnitEnv$.testLogger$cleanup() ## ordinary test function execution: timing <- try(system.time(func(), gcFirst=RUnitEnv$.gcBeforeTest)) if (inherits(timing, "try-error")) { if(RUnitEnv$.testLogger$isFailure()) { RUnitEnv$.testLogger$addFailure(testFuncName=funcName, failureMsg=geterrmessage()) } else if(RUnitEnv$.testLogger$isDeactivated()) { RUnitEnv$.testLogger$addDeactivated(testFuncName=funcName) } else { RUnitEnv$.testLogger$addError(testFuncName=funcName, errorMsg=geterrmessage()) } } else { RUnitEnv$.testLogger$addSuccess(testFuncName=funcName, secs=round(timing[3], 2)) } ## add number of check function calls within test case RUnitEnv$.testLogger$addCheckNum(testFuncName=funcName) ## safe execution of tearDown function res <- try(tearDownFunc()) if (inherits(res, "try-error")) { message <- paste("Error executing .tearDown after",funcName, ":", geterrmessage()) RUnitEnv$.testLogger$addError(testFuncName=paste(".tearDown (after ", funcName, ")", sep=""), errorMsg=message) return(invisible()) } if (RUnitEnv$.testLogger$getVerbosity() > 0) { cat(" done successfully.\n\n") } return(invisible()) } .sourceTestFile <- function(absTestFileName, testFuncRegexp) { ##@bdescr ## This function sources a file, finds all the test functions in it, executes them ## and reports the results to the TestLogger. ## No return value, called for its side effects on TestLogger object ##@edescr ## ##@in absTestFileName : [character] absolute path name of the file to test ##@in testFuncRegexp : [character] a regular expression identifying the names of test functions ##@ret : [NULL] ## ##@codestatus : internal RUnitEnv$.testLogger$setCurrentSourceFile(absTestFileName) if (!file.exists(absTestFileName)) { msgText <- paste("Test case file ", absTestFileName," not found.") RUnitEnv$.testLogger$addError(testFuncName=absTestFileName, errorMsg=msgText) return(invisible()) } sandbox <- new.env(parent=.GlobalEnv) ## will be destroyed after function closure is left ## catch syntax errors in test case file res <- try(sys.source(absTestFileName, envir=sandbox)) if (inherits(res, "try-error")) { message <- paste("Error while sourcing ",absTestFileName,":",geterrmessage()) RUnitEnv$.testLogger$addError(testFuncName=absTestFileName, errorMsg=message) return(invisible()) } ## test file provides definition of .setUp/.tearDown if (exists(".setUp", envir=sandbox, inherits=FALSE)) { .setUp <- get(".setUp", envir=sandbox) } if (exists(".tearDown", envir=sandbox, inherits=FALSE)) { .tearDown <- get(".tearDown", envir=sandbox) } testFunctions <- ls(pattern=testFuncRegexp, envir=sandbox) for (funcName in testFunctions) { .executeTestCase(funcName, envir=sandbox, setUpFunc=.setUp, tearDownFunc=.tearDown) } } runTestSuite <- function(testSuites, useOwnErrorHandler=TRUE, verbose=getOption("RUnit")$verbose, gcBeforeTest=FALSE) { ##@bdescr ## This is the main function of the RUnit framework. It identifies all specified ## test files and triggers all required actions. At the end it creates a test ## protocol data object. ## IMPORTANT to note, the random number generator is (re-)set to the default ## methods specified in defineTestSuite() before each new test case *file* is sourced. ## This guarantees that each new test case set defined together in on file can rely ## on the default, even if the random number generator version is being reconfigured in some ## previous test case file(s). ##@edescr ## ##@in testSuites : [list] list of test suite lists ##@in useOwnErrorHandler : [logical] TRUE (default) : use the RUnit error handler ##@in verbose : [integer] >= 1: (default) write begin/end comments for each test case, 0: omit begin/end comment ##@in gcBeforeTest : [logical] FALSE (default) : garbage collect before timing each test ##@ret : [list] 'RUnitTestData' S3 class object ## ##@codestatus : testing ## preconditions if (!is.logical(useOwnErrorHandler)) { stop("argument 'useOwnErrorHandler' has to be of type logical.") } if (length(useOwnErrorHandler) != 1) { stop("argument 'useOwnErrorHandler' has to be of length 1.") } if (is.na(useOwnErrorHandler)) { stop("argument 'useOwnErrorHandler' may not contain NA.") } if (!is.logical(gcBeforeTest)) { stop("argument 'gcBeforeTest' has to be of type logical.") } if (length(gcBeforeTest) != 1) { stop("argument 'gcBeforeTest' has to be of length 1.") } if (is.na(gcBeforeTest)) { stop("argument 'gcBeforeTest' may not contain NA.") } oFile <- getOption("RUnit")$outfile if (!is.null(oFile)) { if(is.character(oFile)) { ## connection has to be open when handed on to sink oFile <- file(oFile, "w") } else if(!inherits(oFile, "connection")) { stop("'outfile' must be a connection or a character string.") } sink(file=oFile) sink(file=oFile, type="message") resetStream <- function() { sink(type="message") sink() flush(oFile) close(oFile) ##close(oFile) } on.exit(resetStream()) } ## record RNGkind and reinstantiate on exit rngDefault <- RNGkind() on.exit(RNGkind(kind=rngDefault[1], normal.kind=rngDefault[2]), add=TRUE) oldErrorHandler <- getOption("error") ## reinstall error handler on.exit(options(error=oldErrorHandler), add=TRUE) ## initialize TestLogger assign(".testLogger", .newTestLogger(useOwnErrorHandler), envir=RUnitEnv) RUnitEnv$.testLogger$setVerbosity(verbose) ## store the information about GC before test assign(".gcBeforeTest", gcBeforeTest, envir=RUnitEnv) ## main loop if (isValidTestSuite(testSuites)) { testSuites <- list(testSuites) } else if (isValidTestSuite(testSuites[[1]])) { ## do nothing } else { stop("invalid test suite supplied.") } for (i in seq_along(testSuites)) { testSuite <- testSuites[[i]] if(!isValidTestSuite(testSuite)) { errMsg <- paste("Invalid test suite",testSuite$name,". Test run aborted.") stop(errMsg) } RUnitEnv$.testLogger$setCurrentTestSuite(testSuite) testFiles <- list.files(testSuite$dirs, pattern = testSuite$testFileRegexp, full.names=TRUE) for(testFile in testFiles) { ## set a standard random number generator. RNGkind(kind=testSuite$rngKind, normal.kind=testSuite$rngNormalKind) .sourceTestFile(testFile, testSuite$testFuncRegexp) } } ret <- RUnitEnv$.testLogger$getTestData() return(ret) } runTestFile <- function(absFileName, useOwnErrorHandler=TRUE, testFuncRegexp="^test.+", rngKind="Marsaglia-Multicarry", rngNormalKind="Kinderman-Ramage", verbose=getOption("RUnit")$verbose, gcBeforeTest=FALSE) { ##@bdescr ## Convenience function. ##@edescr ## ##@in absFileName : [character] complete file name of test cases code file ##@in useOwnErrorHandler : [logical] if TRUE RUnits error handler will be used ##@in testFuncRegexp : [character] ##@in rngKind : [character] name of the RNG, see RNGkind for avialbale options ##@in rngNormalKind : [character] name of the RNG for rnorm, see RNGkind for avialbale options ##@in verbose : [integer] >= 1: (default) write begin/end comments for each test case, 0: ommit begin/end comment (passed on to function runTestSuite) ##@in gcBeforeTest : [logical] FALSE (default) : garbage collect before timing each test ##@ret : [list] 'RUnitTestData' S3 class object ## ##@codestatus : testing ## preconditions ## all error checking and handling is delegated to function runTestSuite fn <- basename(absFileName) nn <- strsplit(fn, "\\.")[[1]][1] dn <- dirname(absFileName) ts <- defineTestSuite(name=nn, dirs=dn, testFileRegexp=paste("^", fn, "$", sep=""), testFuncRegexp=testFuncRegexp, rngKind=rngKind, rngNormalKind=rngNormalKind) return(runTestSuite(ts, useOwnErrorHandler=useOwnErrorHandler, verbose=verbose, gcBeforeTest=gcBeforeTest)) } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/R/checkFuncs.r��������������������������������������������������������������������������������0000644�0001751�0000144�00000017550�14561530024�014001� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ checkEquals <- function(target, current, msg="", tolerance = .Machine$double.eps^0.5, checkNames=TRUE, ...) { ##@bdescr ## checks if two objects are equal, thin wrapper around 'all.equal' ## with tolerance one can adjust to and allow for numerical imprecision ##@edescr ##@in target : [ANY] one thing to be compared ##@in current : [ANY] second object to be compared ##@in msg : [character] an optional message to further identify and document the call ##@in tolerance : [numeric] directly passed to 'all.equal', see there for further documentation ##@in checkNames: [logical] iff TRUE do not strip names attributes from current and target prior to the comparison ##@ret : [logical] TRUE iff check was correct ## ##@codestatus : testing if (missing(current)) { stop("argument 'current' is missing") } if(!is.numeric(tolerance)) { stop("'tolerance' has to be a numeric value") } if (length(tolerance) != 1) { stop("'tolerance' has to be a scalar") } if(!is.logical(checkNames)) { stop("'checkNames' has to be a logical value") } if (length(checkNames) != 1) { stop("'checkNames' has to be a scalar") } if(.existsTestLogger()) { RUnitEnv$.testLogger$incrementCheckNum() } if (!identical(TRUE, checkNames)) { names(target) <- NULL names(current) <- NULL } result <- all.equal(target, current, tolerance=tolerance, ...) if (!identical(result, TRUE)) { if(.existsTestLogger()) { RUnitEnv$.testLogger$setFailure() } stop(paste(result, collapse="\n"), "\n", msg) } else { return(TRUE) } } checkEqualsNumeric <- function(target, current, msg="", tolerance = .Machine$double.eps^0.5, ...) { ##@bdescr ## checks if two objects are equal, thin wrapper around 'all.equal.numeric' ## with tolerance one can adjust to and allow for numerical imprecision. ## current and target are converted via as.vector() thereby stripping all attributes. ##@edescr ##@in target : [ANY] one thing to be compared ##@in current : [ANY] second object to be compared ##@in tolerance : [numeric] directly passed to 'all.equal.numeric', see there for further documentation ##@in msg : [character] an optional message to further identify and document the call ## ##@ret : [logical] TRUE, if objects 'target' and 'current' are equal w.r.t. specified numerical tolerance, else a stop signal is issued ## ##@codestatus : testing if (missing(current)) { stop("argument 'current' is missing") } if(!is.numeric(tolerance)) { stop("'tolerance' has to be a numeric value") } if (length(tolerance) != 1) { stop("'tolerance' has to be a scalar") } if(.existsTestLogger()) { RUnitEnv$.testLogger$incrementCheckNum() } ## Fix for R>4.1.2 where as.vector.data.frame returns a list instead of vector if(is.data.frame(target)) { target <- unlist(as.list(target), use.names=FALSE) } if(is.data.frame(current)) { current <- unlist(as.list(current), use.names=FALSE) } ## R 2.3.0: changed behaviour of all.equal ## strip attributes before comparing current and target result <- all.equal.numeric(as.vector(target), as.vector(current), tolerance=tolerance, ...) if (!identical(result, TRUE)) { if(.existsTestLogger()) { RUnitEnv$.testLogger$setFailure() } stop(paste(result, collapse="\n"), "\n", msg) } else { return(TRUE) } } checkIdentical <- function(target, current, msg="") { ##@bdescr ## checks if two objects are exactly identical, thin convenience wrapper around 'identical' ## ##@edescr ##@in target : [ANY] one object to be compared ##@in current : [ANY] second object to be compared ##@in msg : [character] an optional message to further identify and document the call ## ##@ret : [logical] TRUE, if objects 'target' and 'current' are identical ## ##@codestatus : testing if (missing(current)) { stop("argument 'current' is missing") } if(.existsTestLogger()) { RUnitEnv$.testLogger$incrementCheckNum() } result <- identical(target, current) if (!identical(TRUE, result)) { if(.existsTestLogger()) { RUnitEnv$.testLogger$setFailure() } stop(paste(paste(result, collapse="\n"), "\n", msg)) } else { return(TRUE) } } checkTrue <- function(expr, msg="") { ##@bdescr ## checks whether or not something is true ##@edescr ##@in expr : [expression] the logical expression to be checked to be TRUE ##@in msg : [character] optional message to further identify and document the call ## ##@ret : [logical] TRUE, if the expression in a evaluates to TRUE, else a stop signal is issued ## ##@codestatus : testing if (missing(expr)) { stop("'expr' is missing") } if(.existsTestLogger()) { RUnitEnv$.testLogger$incrementCheckNum() } ## allow named logical argument 'expr' result <- eval(expr) names(result) <- NULL if (!identical(result, TRUE)) { if(.existsTestLogger()) { RUnitEnv$.testLogger$setFailure() } stop("Test not TRUE\n", msg) } else { return(TRUE) } } checkException <- function(expr, msg="", silent=getOption("RUnit")$silent) { ##@bdescr ## checks if a function call creates an error. The passed function must be parameterless. ## If you want to check a function with arguments, call it like this: ## 'checkException(function() func(args...))' ## ## adding argument silent was suggested by Seth Falcon <sfalcon@fhcrc.org> ## who provided a patch. ##@edescr ##@in expr : [parameterless function] the function to be checked ##@in msg : [character] an optional message to further identify and document the call ##@in silent : [logical] passed on to try, iff TRUE error messages will be suppressed ## ##@ret : [logical] TRUE, if evaluation of the expression results in a 'try-error', else a stop signal is issued ## ##@codestatus : testing if (missing(expr)) { stop("'expr' is missing") } if(is.null(silent)) { silent <- FALSE warning("'silent' has to be of type 'logical'. Was NULL. Set to FALSE.") } if(.existsTestLogger()) { RUnitEnv$.testLogger$incrementCheckNum() } if (!inherits(try(eval(expr, envir=parent.frame()), silent=silent), "try-error")) { if(.existsTestLogger()) { RUnitEnv$.testLogger$setFailure() } stop("Error not generated as expected\n", msg) } else { return(TRUE) } } DEACTIVATED <- function(msg="") { ##@bdescr ## Convenience function, for maintaining test suites. ## If placed in an existing test case call ## the test will be executed normally until occurrence of the call ## after which execution will leave the test case (so all code will ## be checked and errors or failures reported as usual). ## An entry for a separate table in the log will be added ## for this test case. ## ##@edescr ##@in msg : [character] optional message to further identify and document the call ## ##@codestatus : testing if(.existsTestLogger()) { RUnitEnv$.testLogger$setDeactivated(paste(msg, "\n", sep="")) } stop(msg) } ��������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/R/textProtocol.r������������������������������������������������������������������������������0000644�0001751�0000144�00000021101�13267374743�014436� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ printTextProtocol <- function(testData, fileName = "", separateFailureList = TRUE, showDetails = TRUE, traceBackCutOff=9) { ##@bdescr ## Report generator ## Extracts the log information stored in the 'RUnitTestData' test run object ## and generates a well formated protocol output. ##@edescr ## ##@in testData : [RUnitTestData] S3 class object ##@in fileName : [character] string, full path + file name to be written to ##@in separateFailureList : [logical] if TRUE (default) add a failure list ##@in showDetails : [logical] if TRUE (default) add detailed traceback for each error incurred ##@in traceBackCutOff : [integer] number of steps back in the trace back stack to display ##@ret : [logical] TRUE if execution completed without error ## ##@codestatus : testing ## preconditions if (!is(testData, "RUnitTestData")) { stop("Argument 'testData' must be of class 'RUnitTestData'.") } if (!is.character(fileName)) { stop("Argument 'fileName' has to be of type character.") } if (length(fileName) != 1) { stop("Argument 'fileName' must contain exactly one element.") } if (!is.logical(separateFailureList)) { stop("Argument 'separateFailureList' has to be of type logical.") } if (length(separateFailureList) != 1) { stop("Argument 'separateFailureList' must contain exactly one element.") } if (!is.logical(showDetails)) { stop("Argument 'showDetails' has to be of type logical.") } if (length(showDetails) != 1) { stop("Argument 'showDetails' must contain exactly one element.") } if (!is.numeric(traceBackCutOff)) { stop("Argument 'traceBackCutOff' has to be of type logical.") } if (length(traceBackCutOff) != 1) { stop("Argument 'traceBackCutOff' must contain exactly one element.") } if (traceBackCutOff < 0 || traceBackCutOff > 100) { stop("Argument 'traceBackCutOff' out of valid range [0, 100].") } ## just a convenience function pr <- function(..., sep=" ", nl=TRUE) { if(nl) { cat(... , "\n", file = fileName, append=TRUE, sep=sep) } else { cat(... , file = fileName, append=TRUE, sep=sep) } } ## get singular or plural right sop <- function(number, word, plext="s") { ifelse(number == 1, paste(number, word), paste(number, paste(word, plext, sep=""))) } ## header part cat("RUNIT TEST PROTOCOL --", date(), "\n", file = fileName) pr("***********************************************") if(length(testData) == 0) { pr("no test cases :-(") return(invisible(TRUE)) } errInfo <- getErrors(testData) pr("Number of test functions:", errInfo$nTestFunc) if(errInfo$nDeactivated > 0) { pr("Number of deactivated test functions:", errInfo$nDeactivated) } pr("Number of errors:", errInfo$nErr) pr("Number of failures:", errInfo$nFail, "\n\n") ## summary of test suites pr(sop(length(testData), "Test Suite"), ":") for(tsName in names(testData)) { pr(tsName, " - ", sop(testData[[tsName]]$nTestFunc, "test function"), ", ", sop(testData[[tsName]]$nErr, "error"), ", ", sop(testData[[tsName]]$nFail, "failure"), sep="") if(separateFailureList && (testData[[tsName]]$nErr + testData[[tsName]]$nFail > 0)) { srcFileRes <- testData[[tsName]][["sourceFileResults"]] for(i in seq_along(srcFileRes)) { testFuncNames <- names(srcFileRes[[i]]) for(j in seq_along(testFuncNames)) { funcList <- srcFileRes[[i]][[testFuncNames[j]]] if(funcList$kind == "error") { pr("ERROR in ", testFuncNames[j], ": ", funcList$msg, nl=FALSE, sep="") } else if(funcList$kind == "failure") { pr("FAILURE in ", testFuncNames[j], ": ", funcList$msg, sep="", nl=FALSE) } else if(funcList$kind == "deactivated") { pr("DEACTIVATED ", testFuncNames[j], ": ", funcList$msg, sep="", nl=FALSE) } } } } } ## if no details are required, we are done. if(!showDetails) { return(invisible(TRUE)) } pr("\n\n\nDetails") ## loop over all test suites for(tsName in names(testData)) { tsList <- testData[[tsName]] pr("***************************") pr("Test Suite:", tsName) pr("Test function regexp:", tsList$testFuncRegexp) pr("Test file regexp:", tsList$testFileRegexp) if(length(tsList$dirs) == 0) { pr("No directories !") } else { if(length(tsList$dirs) == 1) { pr("Involved directory:") } else { pr("Involved directories:") } for(dir in tsList$dirs) { pr(dir) } res <- tsList$sourceFileResults testFileNames <- names(res) if(length(res) == 0) { pr("no test files") } else { ## loop over all source files for(testFileName in testFileNames) { testFuncNames <- names(res[[testFileName]]) if(length(testFuncNames) > 0) { pr("---------------------------") pr("Test file:", testFileName) ## loop over all test functions in the test file for(testFuncName in testFuncNames) { testFuncInfo <- res[[testFileName]][[testFuncName]] if(testFuncInfo$kind == "success") { pr(testFuncName, ": (",testFuncInfo$checkNum, " checks) ... OK (", testFuncInfo$time, " seconds)", sep="") } else { if(testFuncInfo$kind == "error") { pr(testFuncName, ": ERROR !! ", sep="") } else if (testFuncInfo$kind == "failure") { pr(testFuncName, ": FAILURE !! (check number ", testFuncInfo$checkNum, ")", sep="") } else if (testFuncInfo$kind == "deactivated") { pr(testFuncName, ": DEACTIVATED, ", nl=FALSE) } else { pr(testFuncName, ": unknown error kind", sep="") } pr(testFuncInfo$msg, nl=FALSE) if(length(testFuncInfo$traceBack) > 0) { pr(" Call Stack:") if(traceBackCutOff > length(testFuncInfo$traceBack)) { pr(" (traceBackCutOff argument larger than length of ", "trace back: full trace back printed)") for(i in 1:length(testFuncInfo$traceBack)) { pr(" ", i, ": ", testFuncInfo$traceBack[i], sep="") } } else { for(i in traceBackCutOff:length(testFuncInfo$traceBack)) { pr(" ", 1+i-traceBackCutOff, ": ", testFuncInfo$traceBack[i], sep="") } } } } } } } } } } ## return type return(invisible(TRUE)) } print.RUnitTestData <- function(x, ...) { ##@bdescr ## Generic print method ##@edescr ## ##@in x : [RUnitTestData] S3 class object ##@in ... : [ANY] currently ignored ##@ret : [NULL] ## ##@codestatus : untested errInfo <- getErrors(x) cat("Number of test functions:", errInfo$nTestFunc, "\n") if(errInfo$nDeactivated > 0) { cat("Number of deactivated test functions:", errInfo$nDeactivated, "\n") } cat("Number of errors:", errInfo$nErr, "\n") cat("Number of failures:", errInfo$nFail, "\n") } summary.RUnitTestData <- function(object, ...) { ##@bdescr ## Generic summary method ##@edescr ## ##@in object : [RUnitTestData] S3 class object ##@in ... : [ANY] ##@ret : [logical] return valof from printTextProtocol ## ##@codestatus : untested printTextProtocol(object, ...) } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/NEWS������������������������������������������������������������������������������������������0000644�0001751�0000144�00000015547�14561532231�012046� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ Dear Emacs, please make this -*-Text-*- mode! ************************************************** * * * RUnit * * * ************************************************** Changes in RUnit 0.4.33 o checkEqualsNumeric functions when given two one-column data.frames Changes in RUnit 0.4.32 o runTestSuite and runTestFile takes additional gcBeforeTest parameter (default FALSE). This disables running garbage collector before timing the test. This setting speeds up the test suite at the cost of making individual test timing less reliable. When trying to optimize tests for speed, set gcBeforeTest to TRUE for more reliable timing information. o added .Rinstignore to cut down on warnings when building the package o removed Biobase specific tests, replaced with direct S4 class creation o fixed CRAN URLs in README.md Changes in RUnit 0.4.31 o checkEquals and others output optional message on separate line Changes in RUnit 0.4.30 o printJUnitProtocol added for JUnit-style output Changes in RUnit 0.4.29 o changed maintainer to Roman Zenka o .testLogger global variable now stored in package environment RUnitEnv o added imports of graphics package to NAMESPACE Changes in RUnit 0.4.26 o isValidTestSuite: fixed insufficient if expression handling, reported by Rich Calaway; extended validity checks Changes in RUnit 0.4.25 o enable redirection of error and log messages to file, controlled via new global option 'outfile', (following a suggestion by Seth Falcon) Changes in RUnit 0.4.24 o added RUnit specific options 'verbose' and 'silent' to global options list to allow control of test log output o moved unit tests from tests/ to inst/unitTests o added Makefile for executing unit tests (using R wiki example) Changes in RUnit 0.4.23 o vignette: fixed function name in example code, reported by Blair Christian o init .testLogger to avoid R CMD check NOTE messages o allow verbosity of console output log to be controlled: added 'verbose' argument to runTestFile and runTestSuite (following a suggestion by Seth Falcon) o test logger object declared as S3 class 'TestLogger' Changes in RUnit 0.4.22 o clarified applicable license: GPL 2 o defineTestSuite: gained some argument checks o isValidTestSuite: check for empty name o includeTracker: fix `<- if` handling Changes in RUnit 0.4.21 o documentation issues corrected, identified by new R 2.9.0 devel Rd parser Changes in RUnit 0.4.20 o test protocol generation on Mac OS X failed due to incorrect code to identify 'gcc' version o Rd documentation updated Changes in RUnit 0.4.19 o test protocol now states check number per test case o changed check for object class to is() to allow derived class objects to pass (suggested by Philippe Grosjean) o removed start up message Changes in RUnit 0.4.18 o seq_along introduced instead of seq( ) for efficiency and R version dependency set to 2.4.0 when seq_along was introduced o some small changes to avoid warnings with options(warnPartialMatchArgs=TRUE) Changes in RUnit 0.4.17 o corrected documentation example code Changes in RUnit 0.4.16 o changed the environment test code files are evaluated, now a new environment outside the RUnit namespace is utilized, allowing e.g. setClass calls without specifying where=.GlobalEnv o updated documentation to use encoding latin1 o use LazyLoad: yes instead of SaveImage:yes (to be deprecated for R 2.6.0) o internal error handler rewritten to be more failure robust o added new test cases for .setUp and .tearDown, extended tests to cover S4 class and method behaviour in check* functions o example on S4 virtual class testing added o utility function to compare to RUnitTestResult objects added: concept idea for comparing and optimizing test suite performance (share/R/checkCode.r) Changes in RUnit 0.4.15 o compatibility to R 1.9.0 as declared in DESCRIPTION: removed calls to isTRUE as this was introduced only in R 2.1.0, replaced where needed by identical(TRUE, x) o fixed printHTMLProtocol: on Windows Makeconf does not exist so CC compiler used by R cannot be queried this way (reported by Tobias Verbeke) Changes in RUnit 0.4.14 o stated all package dependencies in DESCRIPTION, required for R 2.4.0 compatibility Changes in RUnit 0.4.13 o allow the RNG to be set by the user via new arguments 'rngKind' and 'rngNormalKind' to functions defineTestSuite and runTestFile (patch by Seth Falcon) o fixed exit status: RNG kind was left changed after runTestSuite execution in user workspace o email contact address modified Changes in RUnit 0.4.12 o allow *.R test case file extension (suggested by Gregor Gorjanc) o fixed code typo in example vignette (spotted by Gregor Gorjanc) Changes in RUnit 0.4.11 o checkException: argument silent added to allow to suppress error messages emitted by the failing function o inspect: added argument track, which _has_ to be provided at each invocation to avoid recursive default argument reference call errors (experimental: subject to change if this leads to new incompatibilities) Changes in RUnit 0.4.9 o checkEquals has new compatibility argument checkNames Changes in RUnit 0.4.8 o checkIdentical added, to allow to check for exact identity Changes in RUnit 0.4.7 o update for checkEqualsNumeric to be compatible with R 2.3.0 Changes in RUnit 0.4.5 o improvements to error detection in runTestSuite Changes in RUnit 0.4.4 o changed maintainer Changes in RUnit 0.4.2 o checkTrue: corrected handling of named logical arguments Changes in RUnit 0.4.1 o printHTMLProtocol has new parameter 'testFileToLinkMap' to allow to provide a function to add dynamically generated URLs for each test case file, e.g. for use with CVSweb Changes in RUnit 0.4.0 o New 'error' category DEACTIVATED introduced: If the function DEACTIVATED is inserted into a test function the function stops at that point and is reported as deactivated in the test protocol. o New function 'getErrors' which takes a list of type 'RUnitTestData' and returns some very basic error information of a test run. o The name of the currently executed test function is written to standard out. o 'printHTMLProtocol' fixed such that it does not produce a warning anymore. o Dependency on package 'splines' removed. o Various small fixes of the documentation. ���������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/COPYING���������������������������������������������������������������������������������������0000644�0001751�0000144�00000043131�13267374743�012406� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/vignettes/������������������������������������������������������������������������������������0000755�0001751�0000144�00000000000�15024242132�013334� 5����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/vignettes/RUnit.Rnw���������������������������������������������������������������������������0000644�0001751�0000144�00000050422�14563457515�015114� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������% -*- mode: noweb; noweb-default-code-mode: R-mode; -*- % % $Id: RUnit.Rnw,v 1.22 2009/11/25 15:12:11 burgerm Exp $ % % %\VignetteIndexEntry{RUnit primer} %\VignetteKeywords{Unit Testing, Code Inspection, Programming} %\VignetteDepends{methods, splines} %\VignettePackage{RUnit} \documentclass[12pt, a4paper]{article} %\usepackage{amsmath,pstricks} \usepackage{hyperref} %\usepackage[authoryear,round]{natbib} %\parskip=.3cm \oddsidemargin=.1in \evensidemargin=.1in \headheight=-.3in \newcommand{\scscst}{\scriptscriptstyle} \newcommand{\scst}{\scriptstyle} \newcommand{\Rfunction}[1]{{\texttt{#1}}} \newcommand{\Robject}[1]{{\texttt{#1}}} \newcommand{\Rpackage}[1]{{\textit{#1}}} %\makeindex % \begin{document} \title{RUnit - A Unit Test Framework for R} \author{Thomas K\"onig, Klaus J\"unemann, and Matthias Burger\\Epigenomics AG} \maketitle \tableofcontents \section*{Abstract} \label{section:abstract} Software development for production systems presents a challenge to the development team as the quality of the coded package(s) has to be constantly monitored and verified. We present a generic approach to software testing for the R language modelled after successful examples such as JUnit, CppUnit, and PerlUnit. The aim of our approach is to facilitate development of reliable software packages and provide a set of tools to analyse and report the software quality status. The presented framework is completely implemented within R and does not rely on external tools or other language systems. The basic principle is that every function or method is accompanied with a test case that queries many calling situations including incorrect invocations. A test case can be executed instantly without reinstalling the whole package - a feature that is necessary for parallel development of functionality and test cases. On a second level one or more packages can be tested in a single test run, the result of which is reported in an well structured test protocol. To verify the coverage of the test framework a code inspector is provided that monitors the code coverage of executed test cases. The result of individual test invocations as well as package wide evaluations can be compiled into a summary report exported to HTML. This report details the executed tests, their failure or success, as well as the code coverage. Taking it one step further and combining the build system with a development and release procedure with defined code status description this approach opens the way for a principled software quality monitoring and risk assessment of the developed application. For our code development we have utilised the described system with great benefit w.r.t.\ code reliability and maintenance efforts in a medium sized development team. \section{Introduction} The importance of software testing can hardly be overrated. This is all the more true for interpreted languages where not even a compiler checks the basic consistency of a program. Nonetheless, testing is often perceived more as a burden than a help by the programmer. Therefore it is necessary to provide tools that make the task of testing as simple and systematic as possible. The key goal of such a testing framework should be to promote the creation and execution of test cases to become an integral part of the software development process. Experience shows that such a permanently repeated code - test - simplify cycle leads to faster and more successful software development than the usually futile attempt to add test cases once the software is largely finished. This line of thought has been pushed furthest by the Extreme Programming \cite{xp} and Test-First paradigms where test cases are viewed as the essential guidelines for the development process. These considerations lead to various requirements that a useful testing framework should satisfy: \begin {itemize} \item {Tests should be easy to execute.} \item {The results should be accessible through a well structured test protocol.} \item{It should be possible to execute only small portions of the test cases during the development process.} \item{It should be possible to estimate the amount of code that is covered by some test case.} \end {itemize} %\paragraph{Background} %\label{paragraph:Background} Testing frameworks that address these aspects have been written in a variety of languages such as Smalltalk, Java, C++ and Python. In particular, the approach described in \cite{beck} has turned out to be very successful, leading -- among others -- to the popular JUnit library for Java \cite{junit}, which has been ported to many other languages (see \cite{xp} for an extensive list of testing frameworks for all kinds of languages). Accordingly, the RUnit package (available at sourceforge \cite{runit-sf}) is our version of porting JUnit to R, supplemented by additional functionality to inspect the test coverage of some function under question. %\paragraph{Motivation} %\label{paragraph:Motivation} One may wonder why R would need yet another testing framework even though the standard method, namely executing {\it R CMD check} on ones complete package at the shell prompt, is widely accepted and applied. We think, however, that the RUnit approach is more in line with the above listed requirements and can be seen as a complement to the existing process in that: \begin{itemize} \item{test cases are called and executed from the R prompt} \item{the programmer decides which result or functionality to put under testing, e.g.\ formating issues of textual output do not need to matter} \item{test and reference data files need not be maintained separately but are combined into one file} \item{test cases need not be limited to testing/using functionality from one package checked at a time} \end{itemize} Moreover, testing frameworks based on JUnit ports seem to have become a quasi standard in many programming languages. Therefore, programmers new to R but familiar with other languages might appreciate a familiar testing environment. And finally, offering more than one alternative in the important field of code testing is certainly not a bad idea and could turn out useful. Before explaining the components of the RUnit package in detail, we would like to list some of the lessons learned in the attempt of writing useful test suites for our software (a more complete collection of tips relating to a Test-First development approach can be found in \cite{tfg}): \begin{itemize} \item {Develop test cases parallel to implementing your functionality. Keep testing all the time (code - test - simplify cycle). Do not wait until the software is complete and attempt to add test cases at the very end. This typically leads to poor quality and incomplete test cases.} \item{Distinguish between unit and integration tests: Unit tests should be as small as possible and check one unit of functionality that cannot be further decomposed. Integration tests, on the other hand, run through a whole analysis workflow and check the interplay of various software components.} \item{Good test coverage enables refactoring, by which a reorganisation of the implementation is meant. Without regular testing the attitude {\it `I better do not touch this code anymore`} once some piece of software appears to be working is frequently encountered. It is very pleasing and time-saving just to run a test suite after some improvement or simplification of the implementation to see that all test cases are still passing (or possibly reveal some newly introduced bug). This refactoring ability is a key benefit of unit testing leading not only to better software quality but also to better design.} \item{Do not test internal functions but just the public interface of a library. Since R does not provide very much language support for this distinction, the first step here is to clarify which functions are meant to be called by a user of a package and which are not (namespaces in R provide a useful directive for making this distinction, if the export list is selected carefully and maintained). If internal functions are directly tested, the ability of refactoring gets lost because this typically involves reorganisation of the internal part of a library.} \item {Once a bug has been found, add a corresponding test case.} \item{We greatly benefitted from an automated test system: A shell script, running nightly, checks out and installs all relevant packages. After that all test suites are run and the resulting test protocol is stored in a central location. This provides an excellent overview over the current status of the system and the collection of nightly test protocols documents the development progress.} \end{itemize} \section{The RUnit package} \label{section:RUnitPackage} This section contains a detailed explanation of the RUnit package and examples how to use it. As has already been mentioned the package contains two independent components: a framework for test case execution and a tool that allows to inspect the flow of execution inside a function in order to analyse which portions of code are covered by some test case. Both components are now discussed in turn. \subsection{Test case execution} \label{subsection:Testcaseexecution} The basic idea of this component is to execute a set of test functions defined through naming conventions, store whether or not the test succeeded in a central logger object and finally write a test protocol that allows to precisely identify the problems. {\bf Note, that RUnit - by default - sets the version for normal, and all other RNGs to 'Kinderman-Ramage', and 'Marsaglia-Multicarry', respectively. If you like to change these defaults please see {\tt ?defineTestSuite} for argument 'rngNormalKind' and 'rngKind'.} As an example consider a function that converts centigrade to Fahrenheit: \begin{Sinput} c2f <- function(c) return(9/5 * c + 32) \end{Sinput} A corresponding test function could look like this: \begin{Sinput} test.c2f <- function() { checkEquals(c2f(0), 32) checkEquals(c2f(10), 50) checkException(c2f("xx")) } \end{Sinput} The default naming convention for test functions in the RUnit package is {\tt test...} as is standard in JUnit. To perform the actual checks that the function to be tested works correctly a set of functions called {\tt check ...} is provided. The purpose of these {\tt check} functions is two-fold: they make sure that a possible failure is reported to the central test logger so that it will appear properly in the final test protocol and they are supposed to make explicit the actual checks in a test case as opposed to other code used to set up the test scenario. Note that {\tt checkException} fails if the passed expression does not generate an error. This kind of test is useful to make sure that a function correctly recognises error situations instead of silently creating inappropriate results. These check functions are direct equivalents to the various {\tt assert} functions of the JUnit framework. More information can be found in the online help. Before running the test function it is necessary to create a test suite which is a collection of test functions and files relating to one topic. One could, for instance, create one test suite for one R package. A test suite is just a list containing a name, an array of absolute directories containing the locations of the test files, a regular expression identifying the test files and a regular expression identifying the test functions. In our example assume that the test function is located in a file {\tt runitc2f.r} located in a directory {\tt /foo/bar/}. To create the corresponding test suite we can use a helper function: \begin{Sinput} testsuite.c2f <- defineTestSuite("c2f", dirs = file.path(.path.package(package="RUnit"), "examples"), testFileRegexp = "^runit.+\\.r", testFuncRegexp = "^test.+", rngKind = "Marsaglia-Multicarry", rngNormalKind = "Kinderman-Ramage") \end{Sinput} All that remains is to run the test suite and print the test protocol: \begin{Sinput} testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult) \end{Sinput} The resulting test protocol should be self explanatory and can also be printed as HTML version. See the online help for further information. Note that for executing just one test file there is also a shortcut in order to make test case execution as easy as possible: \begin{Sinput} runTestFile(file.path(.path.package(package="RUnit"), "examples/runitc2f.r")) \end{Sinput} The creation and execution of test suites can be summarised by the following recipe: \begin{enumerate} \item{create as many test functions in as many test files as necessary } \item{create one or more test suites using the helper function {\tt defineTestSuite}} \item{run the test suites with {\tt runTestSuite}} \item{print the test protocol either with {\tt printTextProtocol} or with {\tt printHTMLProtocol} (or with a generic method like {\tt print} or {\tt summary})} \end{enumerate} We conclude this section with some further comments on various aspects of the test execution framework: \begin{itemize} \item{A test file can contain an arbitrary number of test functions. A test directory can contain an arbitrary number of test files, a test suite can contain an arbitrary number of test directories and the test runner can run an arbitrary number of test suites -- all resulting in one test protocol. The test function and file names of a test suite must, however, obey a naming convention expressible through regular expressions. As default test functions start with {\tt test} and files with {\tt runit}.} \item{RUnit makes a distinction between failure and error. A failure occurs if one of the check functions fail (e.g.~{\tt checkTrue(FALSE)} creates a failure). An error is reported if an ordinary R error (usually created by {\tt stop}) occurs.} \item{Since version 0.4.0 there is a function {\tt DEACTIVATED} which can be used to deactivate test cases temporarily. This might be useful in the case of a major refactoring. In particular, the deactivated test cases are reported in the test protocol so that they cannot fall into oblivion.} \item{The test runner tries hard to leave a clean R session behind. Therefore all objects created during test case execution will be deleted after a test file has been processed.} \item{In order to prevent mysterious errors the random number generator is reset to a standard setting before sourcing a test file. If a particular setting is needed to generate reproducible results it is fine to configure the random number generator at the beginning of a test file. This setting applies during the execution of all test functions of that test file but is reset before the next test file is sourced.} \item{In each source file one can define the parameterless functions {\tt .setUp()} and {\tt .tearDown()}. which are then executed directly before and after each test function. This can, for instance, be used to control global settings or create addition log information.} \end{itemize} \subsection{R Code Inspection} \label{subsection:RCodeInspection} The Code Inspector is an additional tool for checking detailed test case coverage and getting profiling information. It records how often a code line will be executed. We utilise this information for improving our test cases, because we can identify code lines not executed by the current test case code. The Code Inspector is able to handle S4 methods. During the development of the Code Inspector, we noticed, that the syntax of R is very flexible. Because our coding philosophy has an emphasis of maintenance and a clear style, we developed style guides for our R coding. Therefore, one goal for the Code Inspector was to handle our coding styles in a correct manner. This leads to the consequence that not all R expression can be handled correctly. In our implementation the Code Inspector has two main functional parts. The first part is responsible for parsing and modifying the code of the test function. The second part, called the Tracker, holds the result of the code tracking. The result of the tracking process allows further analysis of the executed code. \subsubsection{Usage} The usage of the Code Inspector and the Tracker object is very simple. The following code snippet is an example: <<eval=FALSE>>= library(RUnit) ## define sample functions to be tested foo <- function(x) { x <- x*x x <- 2*x return(x) } test.foo <- function() { checkTrue(is.numeric(foo(1:10))) checkEquals(length(foo(1:10)), 10) checkEqualsNumeric(foo(1), 2) } bar <- function(x, y=NULL) { if (is.null(y)) { y <- x } if (all(y > 100)) { ## subtract 100 y <- y - 100 } res <- x^y return(res) } track <- tracker(); ## initialize a tracking "object" track$init(); ## initialize the tracker a <- 1:10 d <- seq(0,1,0.1) resFoo <- inspect(foo(a), track=track); ## execute the test function and track resBar <- inspect(bar(d), track=track); ## execute the test function and track resTrack <- track$getTrackInfo(); ## get the result of Code Inspector (a list) printHTML(resTrack, baseDir=tempdir()) ; ## create HTML sites @ Note, that the tracking object is an global object and must have the name {\tt track}. The {\tt inspect} function awaits a function call as argument and executes and tracks the function. The results will be stored in the tracking object. The result of the function (not of the Tracker) will be returned as usual. The tracking results will received by tr\$getResult(). With {\tt printHTML} the result of the tracking process will be presented as HTML pages. \subsubsection{Technical Details} The general idea for the code tracking is to modify the source code of the function. Therefore, we use the {\tt parse} and {\tt deparse} functions and the capability of R to generate functions on runtime. To track the function we try to include a hook in every code line. That hook calls a function of the tracked object. The information of the tracking will be stored in the closure of the tracking object (actually a function). Because the R parser allows very nested expressions, we didn't try to modify every R expression. This is a task for the future. A simple example for the modifying process is as follow:\\ original: <<eval=FALSE>>= foo <- function(x) { y <- 0 for(i in 1:x) { y <- y + x } return(y) } @ modified: <<eval=FALSE>>= foo.mod <- function(x) { track$bp(1) ; y <- 0 track$bp(2); for(i in 1:x) { track$bp(4) ; y <- y +x } track$bp(6); return(y) } @ Problematic code lines are: <<eval=FALSE>>= if(any(a==1)) { print("do TRUE") } else print ("do FALSE"); @ This must be modified to <<eval=FALSE>>= if(any(a==1)) { track$bp(2); print("do TRUE") }else{ track$bp(3); print("do FALSE"); } @ The problem is the \textit{else} branch, that cannot be modified in the current version. \section{Future Development Ideas} Here we briefly list -- in an unordered manner -- some of the avenues for future development we or someone interested in this package could take: \begin{itemize} \item{extend the {\tt checkEquals} function to handle complex S4 class objects correctly in comparisons. To this end R core has modified check.equal to handle S4 objects.} \item{reimplement the internal structures storing the test suite as well as the test result data as S4 classes.} \item{record all warnings generated during the execution of a test function.} \item{add tools to create test cases automatically. This is a research project but -- given the importance of testing -- worth the effort. See \cite{junit} for various approaches in other languages.} \item{improve the export of test suite execution data e.g.~by adding XML data export support.} \item{add some evaluation methods to the code inspector e.g.~use software metrics to estimate standard measures of code quality, complexity, and performance.} \item{overcome the problem of nested calls to registered functions for code inspection.} \item{allow automatic registration of functions \& methods.} \end{itemize} \begin{thebibliography}{99} % \bibliographystyle{plainnat} \bibitem{xp} http://www.xprogramming.com \bibitem{beck} http://www.xprogramming.com/testfram.htm \bibitem{junit} http://www.junit.org/ \bibitem{tfg} http://www.xprogramming.com/xpmag/testFirstGuidelines.htm \bibitem{runit-sf} https://sourceforge.net/projects/runit/ \end{thebibliography} \end{document} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/ChangeLog�������������������������������������������������������������������������������������0000644�0001751�0000144�00000121005�14563457515�013121� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������2024-02-15 12:15 zenkar * cleaned up minor CRAN check notes 2009-04-22 15:52 burgerm * tests/runitInspect.r: added test cases for more complex functions to track 2009-04-22 15:50 burgerm * R/inspector.r: includeTracker: fix `<- if` call handling which caused the inspect mechanism to fail 2009-04-22 15:48 burgerm * R/runit.r: isValidTestSuite: check for empty name string as this will cause subsequent failure which is harder to understand 2009-04-22 15:46 burgerm * NAMESPACE: declare S3 print and summary methods for RUnitTestData 2009-04-22 11:37 burgerm * inst/doc/RUnit.pdf: removed: use R CMD build to generate, no need to store in repository 2009-04-16 11:54 burgerm * DESCRIPTION: patch level 0.4.22: clarified GPL version 2009-04-16 11:49 burgerm * R/textProtocol.r: specified license to be version 2 of the GPL 2009-04-16 11:48 burgerm * R/testLogger.r: specified license to be version 2 of the GPL; extended function descriptions 2009-04-16 11:44 burgerm * R/: checkFuncs.r, exportHTML.r, html.r, htmlProtocol.r, inspector.r, runit.r: specified license to be version 2 of the GPL 2009-04-16 11:39 burgerm * R/00Init.r: specified license to be version 2 of the GPL 2009-04-16 11:23 burgerm * inst/: examples/correctTestCase.r, examples/runitVirtualClassTest.r, share/R/checkCode.r, share/R/compareRUnitTestData.r: specified license to be version 2 of the GPL 2009-04-16 11:18 burgerm * tests/: runitHTMLProtocol.r, runitInspect.r, runitPlotConnection.r, runitRUnit.r, runitS4.r, runitSetUp.r, runitTearDown.r, runitTextProtocol.r: specified license to be version 2 of the GPL 2009-04-16 11:13 burgerm * man/: RUnit-internal.Rd, RUnit-intro.Rd, checkFuncs.Rd, inspect.Rd, printHTML.trackinfo.Rd, runit.Rd, textProtocol.Rd, tracker.Rd: specified license to be version 2 of the GPL 2009-03-16 17:38 burgerm * R/inspector.r: always coninue if-else on the same line removed semicolon at line ends 2009-03-16 17:36 burgerm * R/runit.r: defineTestSuite: gained some argument checks isValidTestSuite: warning messages modified to handle multiple names some typos in inline documentation fixed 2009-03-16 17:29 burgerm * R/checkFuncs.r: always coninue if else on the same line checkIdentical: added precondition check 2009-03-16 17:26 burgerm * R/exportHTML.r: always coninue if-else on the same line removed semicolon at line ends 2009-03-16 17:24 burgerm * R/html.r: always coninue if else on the same line html.r removed semicolon at line ends 2009-03-16 17:21 burgerm * inst/doc/RUnit.Rnw: minute corrections 2009-03-05 16:58 burgerm * DESCRIPTION: License field updated according to R-ext for R 2.8.1 2009-01-23 19:13 burgerm * man/: checkFuncs.Rd, inspect.Rd, printHTML.trackinfo.Rd, runit.Rd, textProtocol.Rd, tracker.Rd: corrected typos, changed formating of code chunks to allow for proper display in pdf reference manual (suggested by Terry Therneau) 2009-01-23 17:23 burgerm * NEWS: typos corrected 2009-01-15 14:47 burgerm * DESCRIPTION: patch level 0.4.21 2009-01-15 14:46 burgerm * ChangeLog: update for 0.4.21 submission 2009-01-15 14:46 burgerm * NEWS: updated for 0.4.21 submission 2009-01-15 14:26 burgerm * man/tracker.Rd: enclosed \item statements within \describe environment: identified by new R 2.9.0 Rd parser 2009-01-15 14:23 burgerm * man/runit.Rd: defineTestSuite default argument value: use \ escape to display \\ in resulting help page after parsing 2008-11-07 14:49 burgerm * R/htmlProtocol.r: compiler detection failed on MacOS, fixed, thanks to report by Steffen Neumann 2008-11-07 12:20 burgerm * R/inspector.r: use seq_along 2008-11-07 12:19 burgerm * R/checkFuncs.r: check for missing arguments 2008-11-07 12:15 burgerm * DESCRIPTION: patch level 0.4.20 2008-06-20 17:51 burgerm * R/textProtocol.r: printTextProtocol rewritten by Klaus using toText; getErrors moved here, TODO replace with S4 method 2008-06-20 17:49 burgerm * NAMESPACE: adopt S4 classes and methods; removed some outdated functions 2008-06-20 17:36 burgerm * R/runit.r: rewritten by Klaus, using S4 design and condition mechanism 2008-06-20 17:29 burgerm * R/00Init.r: added generics definition used for S4 methods 2008-06-20 17:27 burgerm * R/testLogger.r: removed; will eventually be replaced 2008-06-20 17:26 burgerm * R/: TestFileResult.r, TestFunctionResult.r, TestResult.r, TestSuite.r, TestSuiteResult.r: S4 class based design of RUnit 2008-06-20 17:26 burgerm * R/checkFuncs.r: rewritten by Klaus using conditions 2008-06-20 17:24 burgerm * R/utility.r: utility functions not attributed to one class; miscellaneous 2008-06-19 15:57 burgerm * ChangeLog: updated 2008-06-19 13:49 burgerm * tests/runitInspect.r: added 2nd example function 2008-06-19 13:46 burgerm * man/textProtocol.Rd: details section updated; example on RUnit test suite execution added in a dontrun clause: works only on source package as tests/ folder is not copied to installed package 2008-06-19 13:42 burgerm * man/runit.Rd: runTestFile example call added 2008-06-19 10:07 burgerm * DESCRIPTION: patch version 0.4.19 2008-06-18 19:18 burgerm * R/textProtocol.r: details section: output check number per test case 2008-06-18 19:17 burgerm * R/htmlProtocol.r: details section: output check number per test case; improved compiler detection 2008-06-18 19:16 burgerm * R/runit.r: isValidTestSuite: changed check for object class to is() to allow derived class objects to pass (suggested by Philippe Grosjean); use addCheckNum to set number of checks performed within test function 2008-06-18 19:13 burgerm * R/testLogger.r: added addCheckNum, getCheckNum functions to allow check number output in summary 2008-06-18 19:12 burgerm * R/checkFuncs.r: checkEquals: argument checkNames checked for correct type; not required paste calls around error message removed (suggested by Philippe Grosjean) 2008-06-18 19:09 burgerm * R/00Init.r: removed start up message 2008-04-29 10:06 burgerm * inst/share/R/compareRUnitTestData.r: check for empty test case results and exclude them from comparison; replaced seq with seq_along 2007-11-30 15:13 burgerm * tests/runitRUnit.r: error introduced in last commit corrected; some more check conditions added 2007-11-30 14:57 burgerm * R/htmlProtocol.r: fixed errors introduced in last commit: replaced seq_len with seq_along 2007-11-27 20:07 burgerm * ChangeLog: updated 2007-11-27 20:05 burgerm * DESCRIPTION: patch level 0.4.18; R dependency set to 2.4.0 were seq_along was introduced 2007-11-27 19:56 burgerm * tests/runitRUnit.r: seq_along introduced; partial argument names expanded 2007-11-27 19:55 burgerm * R/runit.r: seq_along introduced 2007-11-27 19:53 burgerm * R/exportHTML.r: seq_along introduced; partial argument names expanded 2007-11-27 19:52 burgerm * R/: html.r, htmlProtocol.r, testLogger.r, textProtocol.r: seq_along introduced 2007-05-21 13:42 burgerm * NEWS: updated for 0.4.17 CRAN submission 2007-05-21 13:37 burgerm * DESCRIPTION: patch level 0.4.17 2007-05-21 13:33 burgerm * man/: textProtocol.Rd, runit.Rd: changed example code to work with installed package test case example path 2007-05-18 14:58 burgerm * R/runit.r: try harder to ensure previous error handler is reinstantiated after test runner execution 2007-05-18 14:56 burgerm * DESCRIPTION: patch level 0.4.16 2007-05-18 14:55 burgerm * NEWS: updated for 0.4.16 2007-05-16 15:17 burgerm * DESCRIPTION: SaveImage replaced by LazyLoad 2007-05-16 14:27 burgerm * inst/share/R/compareRUnitTestData.r: initial prototype: comare two RUnitTestData objects: intended for test run time performance evaluation 2007-05-16 14:24 burgerm * R/runit.r: .sourceTestFile: updated to observe - after sandbox introduction - test case file defined .setUp and .tearDown functions 2007-05-16 14:21 burgerm * tests/runitS4.r: check S4 setClass + removeClass chain with new sandbox implementation 2007-05-16 14:19 burgerm * tests/: runitSetUp.r, runitTearDown.r: added for focused check of .setUp and .tearDown functioning 2007-05-16 14:16 burgerm * tests/runitRUnit.r: class names changed; clean up operation revised: try harder to reset to previous global state 2007-05-16 14:15 burgerm * tests/runitInspect.r: .tearDown added: cleanup 2007-05-16 10:49 burgerm * DESCRIPTION: dev patch level 0.4.15-2 2007-05-16 00:46 burgerm * man/runit.Rd: added encoding latin1 to display umlaut correctly if available; make use of describe command to format details section 2007-05-16 00:42 burgerm * man/checkFuncs.Rd: added encoding latin1 to display umlaut correctly if available; added paragraph on S4 classes and methods to details section 2007-05-15 23:46 burgerm * man/inspect.Rd: added encoding latin1 to display umlaut correctly if available 2007-05-15 23:45 burgerm * man/textProtocol.Rd: added encoding latin1 to display umlaut correctly if available; added header; added \pkg command around RUnit phrase 2007-05-15 23:43 burgerm * man/: RUnit-intro.Rd, tracker.Rd, printHTML.trackinfo.Rd: added encoding latin1 to display umlaut correctly if available 2007-05-15 17:33 burgerm * R/runit.r: make use of a new environment defined as child of .GlobalEnv to allow setClass calls wo where argument 2007-04-25 08:46 burgerm * R/TestCaseMethods.r: construct method added; verify method checks partially switched off 2007-04-25 08:39 burgerm * R/TestCaseTestResultData.r: slots checkNum, traceBack and warnMessageStack added 2007-04-23 00:14 burgerm * R/testLogger.r: replaced by condition signals 2007-04-23 00:10 burgerm * R/TestCaseTestResultDataMethods.r: .printTextProtocol added: used in recursive call chain 2007-04-23 00:08 burgerm * R/: SourceFileTestResultDataMethods.r, TestSuiteTestResultDataMethods.r: .printTextProtocol, getError and getTestCaseNum added: used in recursive call chain 2007-04-23 00:05 burgerm * R/runit.r: removed .testLogger; added warning handler; switched to condition signals; use testCaseCheckCount for check call counting 2007-04-23 00:03 burgerm * R/checkFuncs.r: removed .testLogger 2007-04-23 00:00 burgerm * DESCRIPTION: removed .testLogger; added experimental condition signaling 2007-04-15 12:50 burgerm * DESCRIPTION: patch level 0.6.0-2 exploration stage; NOT FIT FOR PUBLIC USE 2007-04-15 12:48 burgerm * NAMESPACE: new S4 classes and methods added 2007-04-15 12:47 burgerm * R/runit.r: experimental: enabled new S4 class based result collection IN PARALLEL to exiting logger mechanism for exploration; NOT FIT FOR PUBLIC USE 2007-04-15 12:45 burgerm * R/Logger.r: getSealed added to exported accessors 2007-04-15 12:40 burgerm * R/checkFuncs.r: RUnit specific signals/conditions implemented and enabled in check* functions 2007-04-15 12:38 burgerm * R/zzz.r: log statement added; TestResultData method def enabled 2007-04-15 12:37 burgerm * R/TestSuiteTestResultDataMethods.r: method implementation added, accessor methods added 2007-04-15 12:36 burgerm * R/TestSuiteTestResultData.r: slots error & errorMsg added to cover suite level errors 2007-04-15 12:35 burgerm * R/TestResultData.r: slot name changed 2007-04-15 12:34 burgerm * R/TestCaseTestResultDataMethods.r: method implementation added, accessor methods added 2007-04-15 12:33 burgerm * R/TestCaseTestResultData.r: class definition reworked, slots renamed and added: NOT FINAL DESIGN 2007-04-15 12:31 burgerm * R/SourceFileTestResultDataMethods.r: method implementation added, getTestResultData added 2007-04-15 12:29 burgerm * R/SourceFileTestResultData.r: slot name renamed to sourceFileName, slots error & errorMsg added to cover source file level errors 2007-04-15 12:28 burgerm * R/htmlProtocol.r: regexpr fixed for R 2.5.0 2007-04-12 10:29 burgerm * R/inspector.r: unused variables removed 2007-04-09 19:42 burgerm * tests/runitRUnit.r: all check* test cases reviewed and extended to cover more failure conditions; checkEquals extended to be checked for all basic R types and S4 objects 2007-04-09 19:38 burgerm * R/testLogger.r: errorHandler: rewritten to be more failure robust; docu added 2007-04-09 19:25 burgerm * R/checkFuncs.r: checkEqualsNumeric: one more argument check added (now identical to checkEquals; docu description made more clear 2007-04-08 14:14 burgerm * R/runit.r: runTestSuite docu make more clear 2007-04-08 14:11 burgerm * R/00Init.r: pass lib argument on to packageDescription to load correct DESCRITPION file 2007-04-05 16:28 burgerm * R/htmlProtocol.r: included deactivatedStyle tag to HTML output: non-visible change 2007-04-02 00:08 burgerm * R/zzz.r: class and method init calls added/updated 2007-04-02 00:04 burgerm * R/00Init.r: packageDescription now observes the library path for the currently loaded package version 2007-04-02 00:02 burgerm * R/TestCaseTestResultData.r: sealed argument controlled by .GLOBAL state; slot failed renamed to failure 2007-04-01 23:59 burgerm * R/: TestResultData.r, SourceFileTestResultData.r, TestSuiteTestResultData.r: sealed argument controlled by .GLOBAL state 2007-04-01 23:53 burgerm * R/: TestCase.r, TestCaseMethods.r, TestLogger.r, TestLoggerMethods.r: playground extended 2007-04-01 23:51 burgerm * R/ArrayMethods.r: - code formating changes ArrayMethods.r - setNames: unnecessary precondition check removed - concat: precondition check added method definition also added to Array base class - printObject rewritten to use show - show method added - array class constructor: sealed argument controlled by .GLOBAL state - applyFun method definition added to array class generator 2007-04-01 23:43 burgerm * R/Array.r: allow sealed argument to be controlled by .GLOBAL state 2007-04-01 23:42 burgerm * R/classUtilities.r: in setGeneric avoid assigning to temp variable value as no postprocessing is intended here and this assignment has a small memory penalty as shown by memprof 2007-04-01 23:38 burgerm * DESCRIPTION: patch level 0.6.0-1: more exploratory code chunks added 2007-03-31 23:15 burgerm * inst/examples/runitVirtualClassTest.r: S4 class example 2007-03-29 09:26 burgerm * inst/share/R/checkCode.r: utility wrappers around checkUsage (package codetools) to check no default location code files; experimental 2007-03-23 15:18 burgerm * tests/runitPlotConnection.r: deactivate test case if R is run in non-interactive mode i.e. most likely no X server is present but require by the png device 2007-03-19 21:08 burgerm * tests/runitPlotConnection.r: simple run test 2007-03-19 01:54 burgerm * R/htmlProtocol.r: fixed gcc query under Windows: report NA 2007-03-19 01:52 burgerm * NEWS: printHTMLProtocol fixed (Windows) 2007-03-19 00:55 burgerm * man/runit.Rd: added header 2007-03-19 00:54 burgerm * tests/runitRUnit.r: added exception check for call object: R 2.5.0 devel issue with new try implementation 2007-03-19 00:51 burgerm * tests/: runitTextProtocol.r, runitHTMLProtocol.r: added check for successful execution, taking care of nested test suite calls 2007-03-19 00:49 burgerm * inst/examples/correctTestCase.r: R 1.9.0 compatibility: replace isTRUE by identical 2007-03-19 00:45 burgerm * R/inspector.r: docu updated/extended; tracker closure functions revised: internal object now is always of S3 class trackInfo, renamed to trackInfo for clarity, addFunc simplified, reinit of oldTime was not written to closure variable; several precondition checks added 2007-03-19 00:40 burgerm * R/exportHTML.r: functions now return invisible; HTML head info updated; result page file names changed; HTML footer added 2007-03-19 00:36 burgerm * man/printHTML.trackinfo.Rd: header added; details text description corrected 2007-03-19 00:34 burgerm * man/tracker.Rd: header added; moved closure functions to new section to avoid R CMD check warning; added isValid 2007-03-16 12:25 burgerm * NEWS: updated for 0.4.15 2007-03-16 12:22 burgerm * DESCRIPTION: patch level 0.4.15 2007-03-16 12:08 burgerm * R/checkFuncs.r: compatibility to R 1.9.0 as declared in DESCRIPTION: removed calls to isTRUE as this was introduced only in R 2.1.0, replaced where needed by identical(TRUE, x) 2007-03-16 12:07 burgerm * R/htmlProtocol.r: createTestFuncRef: removed unnecessary escape characters in gsub call 2007-03-16 12:05 burgerm * tests/runitRUnit.r: compatibility to R 1.9.0 as declared in DESCRIPTION: removed calls to isTRUE as this was introduced only in R 2.1.0, replaced where needed by identical(TRUE, x) 2006-08-30 01:13 burgerm * DESCRIPTION: patch level 0.6.0-0: start new minor level 0.6.0.x for development, first public release will be 0.6.0; 0.5.x is reserved for potential S3 implementation updates; class layout as described in dia 2006-08-30 01:11 burgerm * NAMESPACE: initial commit: class layout as described in dia 2006-08-30 00:58 burgerm * R/TestSuiteTestResultDataMethods.r: initial commit: class layout as described in dia 2006-08-30 00:54 burgerm * R/: ArrayMethods.r, Logger.r, SignalHandler.r, SourceFileTestResultDataMethods.r, TestCaseTestResultDataMethods.r, TestSuiteMethods.r, classUtilities.r, zzz.r: initial commit: class layout as described in dia 2006-08-30 00:51 burgerm * R/: Array.r, SourceFileTestResultData.r, TestCaseTestResultData.r, TestResultData.r, TestSuite.r, TestSuiteTestResultData.r: initial commit: class layout as described in dia 2006-08-22 11:21 burgerm * NEWS: 0.4.14 update log added 2006-08-17 09:12 burgerm * DESCRIPTION: patch level 0.4.14: package utils dependency made explicit in DESCRIPTION and NAMESPACE 2006-08-17 01:14 burgerm * NAMESPACE: import of package utils added (required for R 2.4.0) 2006-08-16 17:39 burgerm * inst/doc/RUnit.Rnw: added a note on the new arguments rngKind, and rngNormalKind; replaced path construction via paste by the more protable file.path (Gregor Gorjanc) 2006-08-16 17:36 burgerm * inst/doc/RUnit.pdf: updated 2006-08-15 18:52 burgerm * ChangeLog: updated 2006-08-15 18:51 burgerm * R/textProtocol.r: return type enforced (a bit more) to be logical 2006-08-15 18:50 burgerm * R/runit.r: defineTestSuite, runTestFile: added arguments rngKind, rngNormalKind to allow configuartion of default RNG configuration, docu tag updated 2006-08-15 18:48 burgerm * R/testLogger.r: documentaion tags added 2006-08-15 18:47 burgerm * R/htmlProtocol.r: return type enforced (a bit more) to be logical, documentation updated 2006-08-15 18:41 burgerm * R/textProtocol.r: documentation updated; printTextProtocol return type changed to logical 2006-08-15 18:34 burgerm * R/html.r: documentation tags updated 2006-08-15 18:33 burgerm * R/exportHTML.r: file I/O: replaced paste call by more protable file.path 2006-08-15 18:31 burgerm * tests/runitRUnit.r: defineTestSuite test case added 2006-08-15 18:29 burgerm * man/runit.Rd: runTestFile, defineTestSuite: documented new arguments rngKind, rngNormalKind 2006-08-15 18:27 burgerm * NEWS: updated: added recent releases 2006-08-15 18:26 burgerm * DESCRIPTION: patch level: 0.4.12 2006-08-08 00:58 burger * R/runit.r: defineTestSuite - allow file extension .R 2006-08-08 00:57 burger * DESCRIPTION: patch level 0.4.12 - allow file extension .R (runit.r) 2006-07-17 19:27 burger * R/00Init.r: package version added to startup message 2006-05-22 10:33 burger * R/checkFuncs.r: DEACTIVATED - fixed typo in var name 2006-04-05 13:47 burger * R/checkFuncs.r: checkException: added comment on contributing author 2006-04-04 19:25 burger * R/TestResultClass.r: License header text added 2006-04-04 19:25 burger * R/TestLogger.r: initial commit 2006-04-04 19:24 burger * R/: TestResultMethods.r, TestSuiteResult.r, TestSuiteResultMethods.r: Lincence header text added 2006-04-04 17:38 burger * NEWS, inst/doc/RUnit.pdf: updated 2006-04-04 17:08 burger * man/inspect.Rd: updated inspect call and argument documentation 2006-04-04 17:08 burger * man/printHTML.trackinfo.Rd: updated inspect call 2006-04-04 17:07 burger * man/tracker.Rd: updated inspect calls 2006-04-04 17:07 burger * inst/doc/RUnit.Rnw: updated inspect calls, added some line to recomendations 2006-04-03 18:35 burger * tests/runitRUnit.r: checkException: silent added to checks 2006-04-03 18:34 burger * R/checkFuncs.r: checkException: argument silent added 2006-04-03 18:32 burger * man/checkFuncs.Rd: checkException, checkEquals documentation updated 2006-04-03 18:31 burger * DESCRIPTION: patch level 0.4.11: checkException arg added 2006-04-03 14:40 burger * inst/examples/runitfoo.r: example function 2006-03-21 15:47 burger * tests/runitRUnit.r: unsuccessful attempt to extend runTestSuite test case 2006-03-21 15:37 burger * R/runit.r: isValidTestSuite: error message texts added 2006-03-21 15:34 burger * R/inspector.r: inspect, and includeTracker have new argument track, which defaults to track for consitency; API docu enhanced and extended 2006-03-21 15:32 burger * tests/runitInspect.r: reactivated both test cases after changes to inspect, and includeTracker 2006-03-21 15:31 burger * DESCRIPTION: patch level 0.4.10 2006-03-07 20:41 burger * R/checkFuncs.r: checkEquals: new compatibility argument to allow to workaround stricter all.equal checks; tolerance precondtion added 2006-03-07 20:39 burger * DESCRIPTION: patch level 0.4.9: checkEquals has new compatibility argument 2006-01-20 18:25 burger * tests/runitRUnit.r: checkIdentical added; checkEquals test case extended 2006-01-20 18:24 burger * man/checkFuncs.Rd: checkIdentical added; arguments a,b, renamed consitent with all.equal 2006-01-20 18:23 burger * R/checkFuncs.r: checkIdentical added; msg argument default added; msg added to stop calls; arguments a,b, renamed consitent with all.equal 2006-01-20 18:21 burger * NAMESPACE: checkIdentical added 2006-01-20 18:18 burger * DESCRIPTION: patch version 0.4.8: checkIdentical added 2006-01-05 15:09 burger * R/checkFuncs.r: checkEqualsNumeric: update to be compatible with R 2.3.0 2006-01-05 15:08 burger * DESCRIPTION: patch level 0.4.7: update for checkEqualsNumeric to be compattible with R 2.3.0 2005-12-12 10:35 burger * DESCRIPTION: patch level 0.4.6 2005-12-12 10:32 burger * R/htmlProtocol.r: replaced HOST query by supposedly platform independent Sys.info variant 2005-12-05 14:44 burger * R/htmlProtocol.r: system info table format changed 2005-12-05 14:44 burger * R/html.r: writeHtmlTable added; API tags updated 2005-11-21 15:29 burger * DESCRIPTION: patch level 0.5.0 added - temporary - dependency on EpiR.base (arrayTemplate class) 2005-11-21 15:28 burger * R/zzz.r: class & method init currently required arrayTemplate and thus relies on EpiR.base FIXME: remove dependency on EpiR.base once design has matured 2005-11-21 15:28 burgerm * R/zzz.r: file zzz.r was added on branch S4-devel-branch-2006-08 on 2006-08-29 22:54:46 +0000 2005-11-21 15:26 burger * R/Logger.r: first exploration 2005-11-21 15:26 burgerm * R/Logger.r: file Logger.r was added on branch S4-devel-branch-2006-08 on 2006-08-29 22:54:46 +0000 2005-11-21 15:15 burger * R/textProtocol.r: added execTime S3 method 2005-11-21 15:15 burger * R/: TestFileResult.r, TestFunctionResult.r, TestResultMethods.r, TestSuiteResult.r, TestFileResultMethods.r, TestSuiteResultMethods.r: first prototype 2005-11-21 15:13 burger * R/TestResultClass.r: first prototype: virtual base class: the mother of all test results 2005-11-14 13:40 burger * DESCRIPTION: patch level 0.4.5 improvements to error detection in runTestSuite & new test cases 2005-11-14 13:39 burger * tests/runitRUnit.r: added isValidTestSuite, runTestFile, and runTestSuite test cases added test case description 2005-11-14 13:37 burger * R/runit.r: runTestSuite: added preconditions runTestFile: pass on error handler flag 2005-11-14 13:36 burger * inst/examples/correctTestCase.r: used for unit test cases 2005-11-14 11:37 burger * R/runit.r: added codestatus API tag runTestSuite: modified error msg 2005-11-14 11:36 burger * R/checkFuncs.r: added codestatus API tag, set to testing 2005-10-27 10:44 burger * .cvsignore: initial commit ignaore eclipse project file 2005-09-29 14:19 burger * DESCRIPTION: changed Klaus email address 2005-09-29 14:16 burger * inst/doc/Makefile: initial commit: utility 2005-08-30 16:28 burger * DESCRIPTION: patch level 0.4.4: changed maintainer 2005-04-07 16:17 burger * tests/runitInspect.r: added & deactivated 2 test cases: environment issues to be addressed by Thomas 2005-04-07 16:04 burger * tests/runitRUnit.r: DEACTIVATED test added 2005-04-07 16:03 burger * R/inspector.r: includeTracker: modifed regexp in grep to comply to R 2.1.0; removed semi-colons; added docu tags 2005-04-07 16:02 burger * R/checkFuncs.r: checkTrue: argument renmaed to match docu: R 2.1.0 CMD check issue 2005-04-07 16:00 burger * R/runit.r: isValidTestSuite: added check on folder existance; docu tags added 2005-04-07 15:59 burger * R/testLogger.r: setDeactivated: added handling of msg with string length > 1; docu extended 2005-04-07 15:41 burger * DESCRIPTION: patch level 0.4.2: fixed R 2.1.0 inspect regexp problem 2005-02-02 13:38 kjuen * R/: htmlProtocol.r, textProtocol.r: the protocol now doesn't mention test files that do not contain any test functions 2005-01-17 19:03 kjuen * R/htmlProtocol.r: minor formatting modifications 2004-12-13 15:34 burger * R/checkFuncs.r: checkTrue: had to add explicit eval to ensure the argument gets evaluated before attempting to set the names attribute to NULL 2004-12-13 14:58 burger * man/checkFuncs.Rd: updated help text for checkTrue 2004-12-13 14:49 burger * R/checkFuncs.r, tests/runitRUnit.r: checkTrue: extended: correct handling of named logical arguments 2004-12-13 14:48 burger * DESCRIPTION: patch level 0.4.2: corrected deficient checkTrue 2004-11-29 19:53 burger * DESCRIPTION: patch level: 0.4.1: http URL mapped 2004-11-29 18:12 kjuen * R/htmlProtocol.r, man/textProtocol.Rd: 'testFileToLinkMap' parameter added to the printHTMLProtocol function added 2004-09-30 15:19 kjuen * inst/doc/: RUnit.Rnw, RUnit.pdf: typos fixed 2004-09-29 18:53 burger * DESCRIPTION: added methods dependency, again 2004-09-29 14:18 kjuen * DESCRIPTION: changes for new release 2004-09-29 14:17 kjuen * inst/doc/RUnit.pdf: hopefully readable for everybody 2004-09-28 11:11 kjuen * R/htmlProtocol.r: deactivated table cells are now printed yellow 2004-09-22 15:27 burger * DESCRIPTION: patch level 0.3.8: RC 0.4.0; removed package splines dependency; added SaveImage directive 2004-09-22 15:24 burger * NAMESPACE: removed splines import 2004-09-22 15:23 burger * R/00Init.r: added .onLoad hook for loading methods prior to RUnit attachment: recommended for R 2.0.0 2004-09-22 15:23 burger * R/inspector.r: removed library calls for methods & splines; added 00Init.r file for this 2004-09-22 15:22 burger * NEWS: replaced tabs; corrected typo, added splines dependency removal 2004-09-22 14:40 kjuen * NEWS: news for release 0.4.0 2004-09-15 15:07 kjuen * NAMESPACE: DEACTIVATED added 2004-09-15 15:07 kjuen * man/: RUnit-internal.Rd, RUnit-intro.Rd, checkFuncs.Rd, inspect.Rd, printHTML.trackinfo.Rd, runit.Rd, textProtocol.Rd, tracker.Rd: some very small cleanups to avoid warnings with R-2 2004-09-09 12:21 kjuen * R/: htmlProtocol.r, testLogger.r, textProtocol.r: .getErrors completely removed 2004-09-08 18:05 burger * DESCRIPTION: updated patch level to 0.3.7 2004-09-08 18:03 burger * NAMESPACE: added getErrors to namespace exports 2004-09-08 18:02 burger * R/testLogger.r: copied .getErrors to getErrors, added to namespace exports, .getErrors set deprecated 2004-09-08 14:20 kjuen * R/htmlProtocol.r: deactivated column in testsuite table is included only when there are any deactivated test functions 2004-09-07 17:28 kjuen * R/: checkFuncs.r, htmlProtocol.r, runit.r, testLogger.r, textProtocol.r: several small cleanups, DEACTIVATED function added 2004-09-06 15:32 burger * inst/NAMESPACE: removed, moved to from inst/ folder 2004-09-06 15:32 burger * NAMESPACE: moved here from inst/ folder as promoted by R 2.0.0 docu 2004-09-06 15:21 burger * R/runit.r: .executeTestCase: added log output: test function call 2004-09-06 15:13 burger * R/textProtocol.r: added braces 2004-08-05 13:34 burger * R/htmlProtocol.r: added braces; added col.names=FALSE to write.table for printing out R version info 2004-07-13 18:16 burger * inst/doc/RUnit.pdf: created via R 1.9.1 buildVignettes("RUnit", "~/src/R/Runit", quiet=FALSE) call, package tools 2004-07-13 16:07 burger * inst/doc/: RUnit.Rnw, RUnit.pdf: set VignetteDepends; commented out LaTeX dependencies; added bibliography with URL for SF RUnit site 2004-07-13 16:04 burger * DESCRIPTION: added SF URL; fixed vignette PDF problem; updated patch level to 0.3.6 2004-06-29 17:17 burger * R/htmlProtocol.r: added colnames(ver) <- "" to avoid warning in R >= 1.9.0 2004-06-10 11:01 burger * R/htmlProtocol.r: added writeCR to writeP function: creates better structured HTML code, relevant also for the internal built script 2004-06-09 20:40 burger * R/html.r: corrected writeEndHead & writeEndHtml: both wrote start instead of end tags 2004-06-08 11:01 burger * DESCRIPTION: updated patch level to 0.3.4, corrected R CMD check warning on man page files 2004-06-08 09:27 burger * man/: RUnit-intro.Rd, RUnit.Rd: renamed RUnit.Rd to RUnit-intro.Rd 2004-06-08 09:24 burger * man/: RUnit.Rd, checkFuncs.Rd, inspect.Rd, printHTML.trackinfo.Rd, runit.Rd, textProtocol.Rd, tracker.Rd: replaced keyword{RUnit} by concept{RUnit}, suggested by Kurt Hornik 2004-06-07 11:41 koenig * inst/doc/RUnit.Rnw: some formatting changes and better descriptions 2004-06-04 22:44 burger * man/checkFuncs.Rd: renamed f to fun 2004-06-04 22:44 burger * DESCRIPTION: updated patch level to 0.3.3, fixed last failing R CMD check tests: ready for CRAN submission 2004-06-04 22:33 burger * man/tracker.Rd: only example text format changed 2004-06-04 22:32 burger * man/printHTML.trackinfo.Rd: updated to new argument name 2004-06-04 22:31 burger * R/exportHTML.r: fixed error introduced with the check on the successful directory creation: renamed res input argument to trackInfo 2004-06-04 20:16 burger * R/htmlProtocol.r: added R version output at end of HTML page 2004-06-03 17:41 burger * R/exportHTML.r: added preconditions and handling of the case the directory results exists already 2004-06-03 17:40 burger * man/tracker.Rd: modified useage to be consistent with required default name for tracker object 2004-06-03 17:32 burger * man/inspect.Rd: added seealso section 2004-06-03 17:32 burger * man/tracker.Rd: added sealso section, clarified comments, added one sentence to description 2004-06-03 16:54 burger * R/inspector.r: added methods dependency 2004-06-03 16:50 burger * man/RUnit-internal.Rd: added writeBeginHtml & writeEndHtml 2004-06-03 16:37 burger * INDEX: initial commit 2004-06-03 16:35 burger * inst/doc/00Index.dcf: updated 2004-06-03 16:05 kjuen * inst/examples/runitc2f.r: example extended 2004-06-03 16:05 kjuen * man/runit.Rd: small improvements 2004-06-03 15:30 kjuen * man/runit.Rd: random number generator behaviour documented 2004-06-03 15:15 kjuen * inst/doc/RUnit.Rnw: junk character that made texi2dvi fail removed 2004-06-03 15:13 kjuen * man/: runit.Rd, textProtocol.Rd: print and summary documentation improved 2004-06-03 13:59 burger * tests/runitRUnit.r: added test cases 2004-06-03 13:47 burger * tests/: runitHTMLProtocol.r, runitTextProtocol.r: initial commit, simple test cases, currently only checked if all input arguments are checked correctly 2004-06-02 18:53 burger * R/: htmlProtocol.r, textProtocol.r: added precondition checks 2004-06-02 18:51 burger * DESCRIPTION: updated patch level to 0.3.2: updated Seawve file, added preconditon checks 2004-06-02 18:40 burger * inst/doc/RUnit.Rnw: corrected errors in R code which incurred R CMD check error 2004-06-01 18:11 burger * inst/examples/runitc2f.r: initial commit, simple example test case, required for correct automatic Sweave translation 2004-05-27 11:37 koenig * R/runit.r: random generator set to kind=Marsaglia-Multicarry, normal.kind=Kinderman-Ramage (default before R-1.8.1 2004-05-25 11:07 kjuen * inst/NAMESPACE: exports of generic print and summary functions corrected 2004-05-25 11:07 kjuen * R/textProtocol.r: type fixed in summary function 2004-05-25 11:06 kjuen * R/runit.r: code that attempts to clean up the global environment after the test runs removed, because it did not work with R-1.9 (because of some namespace stuff that I do not understand) 2004-05-25 11:04 kjuen * R/htmlProtocol.r: junk code removed 2004-05-19 21:08 burger * DESCRIPTION: updated patch level to 0.3.1, version presented at useR 2004-05-19 14:42 koenig * inst/doc/RUnit.Rnw: E-Mail adresses changed 2004-05-19 14:39 koenig * inst/doc/RUnit.Rnw: company name and E-Mail added 2004-05-19 14:12 kjuen * inst/doc/RUnit.Rnw: some details improved and section that explains test case execution added 2004-05-19 12:48 kjuen * R/testLogger.r: debug print statement removed 2004-05-19 11:26 burger * inst/doc/RUnit.Rnw: added library(RUnit) before example code 2004-05-19 11:24 burger * man/RUnit-internal.Rd: added newline 2004-05-19 11:24 burger * R/exportHTML.r: added API doc tags, code polish for better readability 2004-05-19 11:12 burger * man/RUnit.Rd: updated, added links, removed unused tags 2004-05-19 11:09 burger * man/: tracker.Rd, printHTML.trackinfo.Rd: added CVS header 2004-05-19 11:08 burger * man/: tracker.Rd, inspect.Rd: minor text changes 2004-05-19 11:07 burger * man/printHTML.trackinfo.Rd: fixed spelling of function name 2004-05-19 11:04 burger * man/RUnit-internal.Rd: initial commit, list all private functions not covered in the docs 2004-05-19 09:46 koenig * man/: inspect.Rd, printHTML.trackinfo.Rd, tracker.Rd: initial release for the documentation of the inspector 2004-05-18 23:17 burger * inst/doc/RUnit.pdf: updated 2004-05-18 23:17 burger * inst/doc/RUnit.Rnw: corrected missing end closure 2004-05-18 21:46 burger * man/: runit.Rd, textProtocol.Rd: typo corrections 2004-05-18 21:45 burger * inst/doc/RUnit.Rnw: removed duplicate abstract, typo corrections 2004-05-18 19:58 burger * inst/NAMESPACE: removed Copyright notice, removed class &method export directive 2004-05-18 19:49 burger * man/: RUnit.Rd, checkFuncs.Rd, runit.Rd: added newline in lats line: suggested by R CMD check 2004-05-18 19:47 burger * DESCRIPTION: removed 2nd maintainer entry: not allowed by R CMD check 2004-05-18 19:02 burger * DESCRIPTION: added splines dependency, added poster, added more Rd files 2004-05-18 16:58 burger * inst/doc/RUnit.Rnw: added some lines to Motivation, added Future Ideas 2004-05-18 16:34 koenig * inst/doc/RUnit.Rnw: enhanced for the code inspector 2004-05-18 13:24 kjuen * R/runit.r: sanity check of looking for a 'runit' call in a test function removed because it is not necessary anymore 2004-05-18 13:22 kjuen * R/testLogger.r: a dot prepended to getError and newTestLogger to mark them as internal functions 2004-05-18 13:21 kjuen * R/runit.r: bugfix in .executeTestCase: setUp and tearDown are now checked for errors. typo fixed in the code that copes with errors occuring while sourcing a test file 2004-05-18 13:18 kjuen * R/: htmlProtocol.r, textProtocol.r: trace back writing improved 2004-05-18 13:16 kjuen * man/textProtocol.Rd: documentation of printHTMLProtocol added 2004-05-18 13:15 kjuen * inst/doc/RUnit.Rnw: my version of the introduction added 2004-05-17 19:54 burger * inst/doc/RUnit.Rnw: added abstract 2004-05-17 19:53 burger * inst/doc/RUnit.pdf: initial commit 2004-05-17 15:40 kjuen * R/htmlProtocol.r: some minor modifications 2004-05-17 15:40 kjuen * R/runit.r: default test file regexp in defineTestSuite improved 2004-05-17 15:16 burger * R/: exportHTML.r, html.r, inspector.r: added GPL preamble 2004-05-14 18:38 kjuen * R/textProtocol.r: useless code deleted 2004-05-14 18:38 kjuen * R/runit.r: small bugfix in isValidTestSuite 2004-05-14 18:37 kjuen * R/htmlProtocol.r: first usable version 2004-05-14 18:29 kjuen * R/html.r: small improvement of writeBeginTable 2004-05-11 15:34 koenig * R/exportHTML.r: moved html helper function to html.r 2004-05-11 15:33 koenig * R/html.r: initial release. helper function for generating html pages 2004-05-10 23:09 burger * R/: checkFuncs.r, runit.r, testLogger.r, textProtocol.r: added CVS tag 2004-05-10 22:58 burger * R/runit.r: renamed argument to isValid to testSuite; ts is a time series object 2004-05-10 22:57 burger * R/textProtocol.r: added API documentation tags; renamed arguments to required defaults for print & summary methods 2004-05-10 22:56 burger * man/runit.Rd: added authors and keyword paragraphs; changed ts to testSuite argument name and documented it 2004-05-10 22:54 burger * man/textProtocol.Rd: added authors and keyword paragraphs; added ... argument description 2004-05-10 22:52 burger * man/checkFuncs.Rd: added authors and keyword paragraphs 2004-05-10 22:22 burger * inst/doc/RUnit.Rnw: fixed broken LaTeX code: missing begin environment 2004-05-10 22:21 burger * inst/doc/00Index.dcf: initial commit, required by R CMD check; needs to be updated with this directories contents 2004-05-10 22:07 burger * DESCRIPTION: updated to minor level 0.2.0: CodeInspector code added, documentation pages added; package passes R CMD check 2004-05-10 22:05 burger * man/: checkFuncs.Rd, runit.Rd, textProtocol.Rd: changed examples such that no Errors are thrown, and packages passes R CMD check 2004-05-10 18:51 kjuen * R/: 00Init.r, initGeneratedRUnit.r, utilities.r: removed 2004-05-10 18:49 koenig * R/inspector.r: initial release for tracking tool 2004-05-10 18:48 koenig * R/exportHTML.r: initial release for exporting results to HTML pages 2004-05-10 16:52 kjuen * man/: checkFuncs.Rd, runit.Rd, textProtocol.Rd: first attempt to cope with Rs documentation tool 2004-05-10 16:51 kjuen * R/runit.r: test suite objects now have a class attribute 2004-05-10 16:50 kjuen * R/testProtocol.r: renamed to textProtocol 2004-05-10 16:50 kjuen * R/textProtocol.r: renamed from testProtocol 2004-05-07 17:51 kjuen * R/checkFuncs.r: ... added to checkEquals so that further args can be passed to all.equal 2004-05-07 15:45 kjuen * R/testProtocol.r: S3 generic methods 'print' and 'summary' added 2004-05-07 15:44 kjuen * R/testLogger.r: getErrors improved 2004-05-06 20:46 burger * DESCRIPTION: added GPL 2 licence text, some code improvements 2004-05-06 20:43 burger * COPYING: GPL 2, downloaded from http://www.gnu.org/copyleft/gpl.html 2004-05-06 19:39 kjuen * R/testProtocol.r: license header added, optional args added to configure printTextProtocol 2004-05-06 19:38 kjuen * R/testLogger.r: license header added, traceback removed for Failures 2004-05-06 19:37 kjuen * R/runit.r: license header added, file regexp in runTestFile improved 2004-05-06 19:37 kjuen * R/checkFuncs.r: license header added 2004-05-05 21:35 burger * R/runit.r: changed to default set in R >= 1.8.0 2004-05-05 20:08 burger * DESCRIPTION: updated version to 0.1.0, runit test framework from EpiR.tools revised and commited here 2004-05-05 19:30 kjuen * R/: checkFuncs.r, runit.r, testLogger.r, testProtocol.r: initial check in of rewritten version 2004-04-06 11:27 burger * DESCRIPTION, R/00Init.r, R/initGeneratedRUnit.r, R/utilities.r, inst/NAMESPACE, inst/doc/RUnit.Rnw, man/RUnit.Rd, tests/runitRUnit.r: Initial revision 2004-04-06 11:27 burger * DESCRIPTION, R/00Init.r, R/initGeneratedRUnit.r, R/utilities.r, inst/NAMESPACE, inst/doc/RUnit.Rnw, man/RUnit.Rd, tests/runitRUnit.r: initial import: preparation for public CRAN package, will take on most of EpiR.tools functionality ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/NAMESPACE�������������������������������������������������������������������������������������0000644�0001751�0000144�00000002026�14565677274�012577� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������###################################################################### ## ## RUnit ## ===================================== ## ## inst/NAMESPACE ## ===================================== ## initialization of classes, namespace, ... ## ## ## ## ## Version ## ===================================== ## $Id$ ## ## ###################################################################### import(utils) import(methods) importFrom("graphics", "arrows", "legend", "lines", "plot", "text") export(".setUp", ".tearDown", "checkTrue", "checkEquals", "checkEqualsNumeric", "checkException", "checkIdentical", "DEACTIVATED", "defineTestSuite", "getErrors", "inspect", "isValidTestSuite", "printTextProtocol", "printHTMLProtocol", "printJUnitProtocol", "printHTML", "runTestSuite", "runTestFile", "tracker") S3method(print, RUnitTestData) S3method(summary, RUnitTestData) S3method(printHTML, trackInfo) S3method(printHTML, default) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/�����������������������������������������������������������������������������������������0000755�0001751�0000144�00000000000�13267374743�012326� 5����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/examples/��������������������������������������������������������������������������������0000755�0001751�0000144�00000000000�13267374743�014144� 5����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/examples/runitVirtualClassTest.r���������������������������������������������������������0000644�0001751�0000144�00000010013�13267374743�020660� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ ## example code for test cases for S4 virtual class methods ## the following class definition code would be part of a package or script ## ## execute these test cases via e.g. ## testSuite <- defineTestSuite("VirtualClassTest", ## file.path(yourSrcPath, "RUnit/inst/examples"), ## "runitVirtual") ## testData <- runTestSuite(testSuite) ## printTextProtocol(testData) ## package 'methods' is usually loaded, but make sure it is checkTrue(require(methods)) ## define class className <- "MyVirtualBaseClass" setClass(className, representation("VIRTUAL", x = "numeric", y = "numeric", description = "character"), validity = NULL, sealed = FALSE, where = .GlobalEnv) if (!isGeneric("getX")) { setGeneric("getX", function(object, ...) standardGeneric("getX"), useAsDefault=TRUE, where=.GlobalEnv, valueClass="numeric") } setMethod("getX", signature=className, function(object) return(object@x), where=.GlobalEnv) if (!isGeneric("setX<-")) { setGeneric("setX<-", function(object, value) standardGeneric("setX<-"), useAsDefault=TRUE, where=.GlobalEnv) } setMethod("setX<-", signature=signature(object=className, value="numeric"), function(object, value) { if (length(value) < 1) { stop("value has to contain at least one element.") } if (any(is.na(value))) { stop("value may not contain NA(s).") } object@x <- value return(object) }, where=.GlobalEnv) testMyVirtualBaseClass.getX <- function() { ##@bdescr ## create a derived class with no own method definitions ## which inherits parent class methods that can then be checked ## ## getter test case ##@edescr testClassName <- "MyDerivedTestClass" setClass(testClassName, representation("MyVirtualBaseClass"), validity = NULL, sealed = FALSE, where = .GlobalEnv) on.exit(removeClass(testClassName, where=.GlobalEnv)) ## system constructor this <- new(testClassName) ## constructor call succeeded? checkTrue( is(this, testClassName)) ret <- getX(this) checkTrue( is(ret, "numeric")) ## class default checkEquals( ret, numeric(0)) } testMyVirtualBaseClass.setX <- function() { ##@bdescr ## setter test case ## also check correct handling of invalid arguments ##@edescr testClassName <- "MyDerivedTestClass" setClass(testClassName, representation("MyVirtualBaseClass"), validity = NULL, sealed = FALSE, where = .GlobalEnv) on.exit(removeClass(testClassName, where=.GlobalEnv)) ## system constructor this <- new(testClassName) ## constructor call succeeded? checkTrue( is(this, testClassName)) testSeq <- 1:23 setX(this) <- testSeq ret <- getX(this) checkTrue( is(ret, "numeric")) checkEquals( ret, testSeq) ## error handling checkException( setX(this) <- numeric(0)) checkException( setX(this) <- as.numeric(NA)) checkException( setX(this) <- c(1:4, NA)) } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/examples/runitc2f.r����������������������������������������������������������������������0000644�0001751�0000144�00000003135�13267374743�016065� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## This is a very trivial demo of ## the RUnit test case execution system: ## --------------------------------- ## functions to be tested (usually defined in a different ## file from where the test cases are located): ## centigrade to Fahrenheit c2f <- function(c) return(9/5 * c + 32) ## Fahrenheit to centigrade f2c <- function(f) return(5/9 * f - 32) ## ups, a bug (brackets missing) ## test functions: ## --------------------- .setUp <- function() { ## called before each test case, see also .tearDown() print(".setUp") } test.c2f <- function() { checkEquals(c2f(0), 32) checkEquals(c2f(10), 50) ## check that an error is created for a bogus argument checkException(c2f("xx")) } test.f2c <- function() { checkEquals(f2c(32), 0) checkEquals(f2c(50), 10) ## check that an error is created for a bogus argument checkException(f2c("xx")) } test.errordemo <- function() { stop("this is just to show what an error looks like as opposed to a failure") } ## How to run the tests (do not uncomment in this file, ## but execute the commands at the R prompt): ## All you have to do is to adapt the directory locations. ## ------------------------------------------------ ## define the test suite: #testsuite.cf <- defineTestSuite("cfConversion", dirs="directoryOfThisFile") ## run test suite: #testResult <- runTestSuite(testsuite.cf) ## print text protocol to console: #printTextProtocol(testResult) ## print HTML version to a file: #printHTMLProtocol(testResult, fileName="someFileName.html") ## In this case we also have a shortcut #runTestFile("directoryOfThisFile/runitcfConversion.r") �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/examples/correctTestCase.r���������������������������������������������������������������0000644�0001751�0000144�00000001637�13267374743�017433� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ test.correctTestCase <- function() { checkTrue( TRUE) checkTrue( !identical(TRUE, FALSE)) } �������������������������������������������������������������������������������������������������RUnit/inst/share/�����������������������������������������������������������������������������������0000755�0001751�0000144�00000000000�13267374743�013430� 5����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/share/R/���������������������������������������������������������������������������������0000755�0001751�0000144�00000000000�13267374743�013631� 5����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/share/R/compareRUnitTestData.r�����������������������������������������������������������0000644�0001751�0000144�00000010671�13267374743�020063� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������###################################################################### ## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ compare <- function(td1, td2, tolerance=100) { ##@bdescr ## compare two test suite result data objects obtained ## on the same test suite ## identify timing differences exceeding 'tolerance' [seconds] ##@edescr ## ## ##@in td1 : [list] of S3 class 'RUnitTestData' ##@in td2 : [list] of S3 class 'RUnitTestData' ##@in tolerance : [numeric] positive scalar ##@ret : [data.frame] ## ##@codestatus : untested ## preconditions if (!is(td1, "RUnitTestData")) { stop("argument 'td1' has to be of class 'RUnitTestData'.") } if (!is(td2, "RUnitTestData")) { stop("argument 'td2' has to be of class 'RUnitTestData'.") } if (length(tolerance) != 1 || is.na(tolerance) || tolerance < 0) { stop("argument 'tolerance' has to be positive scalar.") } ## helper functions commonNames <- function(x1, x2) { return(intersect(names(x1), names(x2))) } compareTiming <- function(x1, x2, tol=0) { d <- x1 - x2 if (abs(d) > tol) { return(d) } else { return(as.numeric(0)) } } comparePerSourceFile <- function(sf1,sf2, tol=0) { ## FIXME ## check if test case file was considered in this suite ## i.e. test case file name can be in list albeit it ## was not executed in the scenario ## thus list is empty if (length(sf1) == 0 | length(sf2) == 0) { cat("\n skipped empty result set:", sf1) return(NULL) } commonTests <- commonNames(sf1, sf2) t(sapply(commonTests, function(x, obj1, obj2) { ##cat("\n test:", x, "\n") if(obj1[[x]][["kind"]] == obj2[[x]][["kind"]]) { if (obj1[[x]][["kind"]] == "success") { return(c(x, obj1[[x]][["kind"]], obj1[[x]][["time"]], obj2[[x]][["kind"]], obj2[[x]][["time"]], compareTiming(obj1[[x]][["time"]], obj2[[x]][["time"]], tol=tol))) } else { return(c(x, obj1[[x]][["kind"]], as.numeric(NA), obj2[[x]][["kind"]], as.numeric(NA), as.numeric(NA))) } } else { ## no timing delta ## should check for timing in second case ## obj2[[x]][["time"]]) return(c(x, obj1[[x]][["kind"]], as.numeric(NA), obj2[[x]][["kind"]], as.numeric(NA), as.numeric(NA))) } }, obj1=sf1, obj2=sf2)) } comparePerSuite <- function(s1,s2, tol=0) { ## absolute file names recorded, strip path commonFiles <- intersect(basename(names(s1[["sourceFileResults"]])), basename(names(s2[["sourceFileResults"]]))) do.call("rbind", sapply(commonFiles, function(x, obj1, obj2) { ## match exact file name in abs. name idx1 <- match(x, basename(names(obj1))) idx2 <- match(x, basename(names(obj2))) if (length(idx1) != 1 || is.na(idx1) || length(idx2) != 1 || is.na(idx2)) { stop("ambiguous file name.") next; } comparePerSourceFile(obj1[[idx1]], obj2[[idx2]], tol=tol) }, obj1=s1[["sourceFileResults"]], obj2=s2[["sourceFileResults"]]) ) } ## main ## test suites to compare commonTestSuites <- commonNames(td1, td2) res <- matrix(ncol=6, nrow=0) colnames(res) <- c("TestCase", "Suite1 State", "Suite1 Timing", "Suite2 State", "Suite2 Timing", "Delta") for (ti in seq_along(commonTestSuites)) { res <- rbind(res, comparePerSuite(td1[[commonTestSuites[ti]]], td2[[commonTestSuites[ti]]], tol=tolerance)) } ## postcondition return(res) } �����������������������������������������������������������������������RUnit/inst/share/R/checkCode.r����������������������������������������������������������������������0000644�0001751�0000144�00000011656�13267374743�015675� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������###################################################################### ## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## $Id$ checkCodeFiles <- function(fileName) { ##@bdescr ## utility function for code checks of files outside usual R/ folder structure ## requires package codetools ##@edescr ## ##@in fileName : [character] vector of file names (including path, relative to pwd or absolute) ##@ret : [list] with elements per function, that incurred any warning ## ##@depends : codetools ## ##@codestatus : untested ## return list retList <- list() ## initialized before ls() call to avoid listing ok <- x <- c() tmpRetEnv <- new.env() tmpRet <- NULL ## generate listing of existing objects before first source'ing lsTmp <- lsInit <- ls() sapply(fileName, function(x) { cat("\n file ",x) ok <- try(utils::capture.output(source(x, local=TRUE, echo=FALSE))) if (inherits(ok, "try-error")) { cat("\n file",x,"could not be sourced:", geterrmessage(), "\n") return() } newElements <- setdiff(ls(), lsTmp) cat("\n functions",paste(newElements, collapse=", ")) lsTmp <- ls() sapply(newElements, function(x) { ok <- try(get(x)) if (!inherits(ok, "try-error") && identical(mode(ok), "function")) { cat("\n ",x," (",is(ok)[1],"): ",sep="") ## this function will be used in signalUsageIssue w$warn reportFunc <- function(x) { cat(x) assign("tmpRet", c(tmpRet, x), pos=parent.env(tmpRetEnv)) } codetools::checkUsage(ok, report=reportFunc, all=TRUE) if (!is.null(tmpRet)) { retList[[length(retList) + 1]] <<- tmpRet names(retList)[length(retList)] <<- x } tmpRet <<- NULL } }) }) return(invisible(retList)) } checkCodeFolders <- function(path=".") { ##@bdescr ## utility function ## code checks of all .[RrSs] files found in one or more folders ## requires package codetools ##@edescr ## ##@in path : [character] ##@ret : [list] ## ##@depends : codetools ## ##@codestatus : untested stopifnot(require(codetools)) if (!is(path, "character")) { stop("argument 'path' has to be of type 'character'.") } if (!all(file.exists(path))) { stop("argument 'path' has to contain existing folder(s).") } fNames <- list.files(path=path, pattern="\\.[rRsS]$", full.names=TRUE) checkCodeFiles(fNames) } checkCodeSweave <- function(path=".") { ##@bdescr ## utility function ## code checks of all .[RS]nw files found in one or more folders ## experimental: does not convert extracted code chunks to closures ## thus only functions defined inside a chunk but nut all of the chunk code is checked ## ## requires package codetools ##@edescr ## ##@in path : [character] ##@ret : [list] ##@depends : codetools ## ##@codestatus : untested ## Issue: ## local path e.g. 'RUnit/inst/doc' ## is no expanded to full path ## which I would wnat to use as absolute path ## in the Stangle call stopifnot(require(utils)) stopifnot(require(codetools)) if (!is(path, "character")) { stop("argument 'path' has to be of type 'character'.") } if (!all(file.exists(path))) { stop("argument 'path' has to contain existing folder(s).") } browser() path <- path.expand(path) pwd <- getwd() if (length(path)) { if (path == ".") { path <- pwd } ## do we have a local path rather then an absolute ## how to infer correct absolute path? } fName <- list.files(path=path, pattern="\\.[RS]nw$", full.names=TRUE) timeStamp <- format(Sys.time(), "%y%m%d-%H%M") tmpDir <- file.path(tempdir(), timeStamp) print(tmpDir) if(!file.exists(tmpDir)) { stopifnot(dir.create(tmpDir, recursive=TRUE)) } #on.exit(unlink(tmpDir, recursive=TRUE)) ## change to temp folder to dump Stangle output therein setwd(tmpDir) on.exit(setwd(pwd), add=TRUE) codeFiles <- unlist(sapply(fName, function(x) { Stangle(x) x <- basename(x) gsub("[RS]nw$", "R", x) })) ## codeFiles <- file.path(tmpDir, codeFiles) checkCodeFiles(codeFiles) } ����������������������������������������������������������������������������������RUnit/inst/doc/�������������������������������������������������������������������������������������0000755�0001751�0000144�00000000000�14565700136�013062� 5����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/doc/Makefile�����������������������������������������������������������������������������0000644�0001751�0000144�00000000626�15024242133�014513� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## ## RUnit ## ## utility ## create PDF document from dvi (usefull if R CMD INSTALL fails to build the pdf) ## $Id$ ## all: RUnit.pdf clean RUnit.pdf: RUnit.ps ps2pdf -dEncodeColorImages=false -dColorImageFilter=/FlateEncode -dAutoRotatePages=/None RUnit.ps RUnit.ps: RUnit.dvi dvips RUnit RUnit.dvi: RUnit.tex latex RUnit latex RUnit clean: rm -f RUnit.aux RUnit.log RUnit.toc ����������������������������������������������������������������������������������������������������������RUnit/inst/doc/RUnit.Rnw����������������������������������������������������������������������������0000644�0001751�0000144�00000050422�14563457515�014626� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������% -*- mode: noweb; noweb-default-code-mode: R-mode; -*- % % $Id: RUnit.Rnw,v 1.22 2009/11/25 15:12:11 burgerm Exp $ % % %\VignetteIndexEntry{RUnit primer} %\VignetteKeywords{Unit Testing, Code Inspection, Programming} %\VignetteDepends{methods, splines} %\VignettePackage{RUnit} \documentclass[12pt, a4paper]{article} %\usepackage{amsmath,pstricks} \usepackage{hyperref} %\usepackage[authoryear,round]{natbib} %\parskip=.3cm \oddsidemargin=.1in \evensidemargin=.1in \headheight=-.3in \newcommand{\scscst}{\scriptscriptstyle} \newcommand{\scst}{\scriptstyle} \newcommand{\Rfunction}[1]{{\texttt{#1}}} \newcommand{\Robject}[1]{{\texttt{#1}}} \newcommand{\Rpackage}[1]{{\textit{#1}}} %\makeindex % \begin{document} \title{RUnit - A Unit Test Framework for R} \author{Thomas K\"onig, Klaus J\"unemann, and Matthias Burger\\Epigenomics AG} \maketitle \tableofcontents \section*{Abstract} \label{section:abstract} Software development for production systems presents a challenge to the development team as the quality of the coded package(s) has to be constantly monitored and verified. We present a generic approach to software testing for the R language modelled after successful examples such as JUnit, CppUnit, and PerlUnit. The aim of our approach is to facilitate development of reliable software packages and provide a set of tools to analyse and report the software quality status. The presented framework is completely implemented within R and does not rely on external tools or other language systems. The basic principle is that every function or method is accompanied with a test case that queries many calling situations including incorrect invocations. A test case can be executed instantly without reinstalling the whole package - a feature that is necessary for parallel development of functionality and test cases. On a second level one or more packages can be tested in a single test run, the result of which is reported in an well structured test protocol. To verify the coverage of the test framework a code inspector is provided that monitors the code coverage of executed test cases. The result of individual test invocations as well as package wide evaluations can be compiled into a summary report exported to HTML. This report details the executed tests, their failure or success, as well as the code coverage. Taking it one step further and combining the build system with a development and release procedure with defined code status description this approach opens the way for a principled software quality monitoring and risk assessment of the developed application. For our code development we have utilised the described system with great benefit w.r.t.\ code reliability and maintenance efforts in a medium sized development team. \section{Introduction} The importance of software testing can hardly be overrated. This is all the more true for interpreted languages where not even a compiler checks the basic consistency of a program. Nonetheless, testing is often perceived more as a burden than a help by the programmer. Therefore it is necessary to provide tools that make the task of testing as simple and systematic as possible. The key goal of such a testing framework should be to promote the creation and execution of test cases to become an integral part of the software development process. Experience shows that such a permanently repeated code - test - simplify cycle leads to faster and more successful software development than the usually futile attempt to add test cases once the software is largely finished. This line of thought has been pushed furthest by the Extreme Programming \cite{xp} and Test-First paradigms where test cases are viewed as the essential guidelines for the development process. These considerations lead to various requirements that a useful testing framework should satisfy: \begin {itemize} \item {Tests should be easy to execute.} \item {The results should be accessible through a well structured test protocol.} \item{It should be possible to execute only small portions of the test cases during the development process.} \item{It should be possible to estimate the amount of code that is covered by some test case.} \end {itemize} %\paragraph{Background} %\label{paragraph:Background} Testing frameworks that address these aspects have been written in a variety of languages such as Smalltalk, Java, C++ and Python. In particular, the approach described in \cite{beck} has turned out to be very successful, leading -- among others -- to the popular JUnit library for Java \cite{junit}, which has been ported to many other languages (see \cite{xp} for an extensive list of testing frameworks for all kinds of languages). Accordingly, the RUnit package (available at sourceforge \cite{runit-sf}) is our version of porting JUnit to R, supplemented by additional functionality to inspect the test coverage of some function under question. %\paragraph{Motivation} %\label{paragraph:Motivation} One may wonder why R would need yet another testing framework even though the standard method, namely executing {\it R CMD check} on ones complete package at the shell prompt, is widely accepted and applied. We think, however, that the RUnit approach is more in line with the above listed requirements and can be seen as a complement to the existing process in that: \begin{itemize} \item{test cases are called and executed from the R prompt} \item{the programmer decides which result or functionality to put under testing, e.g.\ formating issues of textual output do not need to matter} \item{test and reference data files need not be maintained separately but are combined into one file} \item{test cases need not be limited to testing/using functionality from one package checked at a time} \end{itemize} Moreover, testing frameworks based on JUnit ports seem to have become a quasi standard in many programming languages. Therefore, programmers new to R but familiar with other languages might appreciate a familiar testing environment. And finally, offering more than one alternative in the important field of code testing is certainly not a bad idea and could turn out useful. Before explaining the components of the RUnit package in detail, we would like to list some of the lessons learned in the attempt of writing useful test suites for our software (a more complete collection of tips relating to a Test-First development approach can be found in \cite{tfg}): \begin{itemize} \item {Develop test cases parallel to implementing your functionality. Keep testing all the time (code - test - simplify cycle). Do not wait until the software is complete and attempt to add test cases at the very end. This typically leads to poor quality and incomplete test cases.} \item{Distinguish between unit and integration tests: Unit tests should be as small as possible and check one unit of functionality that cannot be further decomposed. Integration tests, on the other hand, run through a whole analysis workflow and check the interplay of various software components.} \item{Good test coverage enables refactoring, by which a reorganisation of the implementation is meant. Without regular testing the attitude {\it `I better do not touch this code anymore`} once some piece of software appears to be working is frequently encountered. It is very pleasing and time-saving just to run a test suite after some improvement or simplification of the implementation to see that all test cases are still passing (or possibly reveal some newly introduced bug). This refactoring ability is a key benefit of unit testing leading not only to better software quality but also to better design.} \item{Do not test internal functions but just the public interface of a library. Since R does not provide very much language support for this distinction, the first step here is to clarify which functions are meant to be called by a user of a package and which are not (namespaces in R provide a useful directive for making this distinction, if the export list is selected carefully and maintained). If internal functions are directly tested, the ability of refactoring gets lost because this typically involves reorganisation of the internal part of a library.} \item {Once a bug has been found, add a corresponding test case.} \item{We greatly benefitted from an automated test system: A shell script, running nightly, checks out and installs all relevant packages. After that all test suites are run and the resulting test protocol is stored in a central location. This provides an excellent overview over the current status of the system and the collection of nightly test protocols documents the development progress.} \end{itemize} \section{The RUnit package} \label{section:RUnitPackage} This section contains a detailed explanation of the RUnit package and examples how to use it. As has already been mentioned the package contains two independent components: a framework for test case execution and a tool that allows to inspect the flow of execution inside a function in order to analyse which portions of code are covered by some test case. Both components are now discussed in turn. \subsection{Test case execution} \label{subsection:Testcaseexecution} The basic idea of this component is to execute a set of test functions defined through naming conventions, store whether or not the test succeeded in a central logger object and finally write a test protocol that allows to precisely identify the problems. {\bf Note, that RUnit - by default - sets the version for normal, and all other RNGs to 'Kinderman-Ramage', and 'Marsaglia-Multicarry', respectively. If you like to change these defaults please see {\tt ?defineTestSuite} for argument 'rngNormalKind' and 'rngKind'.} As an example consider a function that converts centigrade to Fahrenheit: \begin{Sinput} c2f <- function(c) return(9/5 * c + 32) \end{Sinput} A corresponding test function could look like this: \begin{Sinput} test.c2f <- function() { checkEquals(c2f(0), 32) checkEquals(c2f(10), 50) checkException(c2f("xx")) } \end{Sinput} The default naming convention for test functions in the RUnit package is {\tt test...} as is standard in JUnit. To perform the actual checks that the function to be tested works correctly a set of functions called {\tt check ...} is provided. The purpose of these {\tt check} functions is two-fold: they make sure that a possible failure is reported to the central test logger so that it will appear properly in the final test protocol and they are supposed to make explicit the actual checks in a test case as opposed to other code used to set up the test scenario. Note that {\tt checkException} fails if the passed expression does not generate an error. This kind of test is useful to make sure that a function correctly recognises error situations instead of silently creating inappropriate results. These check functions are direct equivalents to the various {\tt assert} functions of the JUnit framework. More information can be found in the online help. Before running the test function it is necessary to create a test suite which is a collection of test functions and files relating to one topic. One could, for instance, create one test suite for one R package. A test suite is just a list containing a name, an array of absolute directories containing the locations of the test files, a regular expression identifying the test files and a regular expression identifying the test functions. In our example assume that the test function is located in a file {\tt runitc2f.r} located in a directory {\tt /foo/bar/}. To create the corresponding test suite we can use a helper function: \begin{Sinput} testsuite.c2f <- defineTestSuite("c2f", dirs = file.path(.path.package(package="RUnit"), "examples"), testFileRegexp = "^runit.+\\.r", testFuncRegexp = "^test.+", rngKind = "Marsaglia-Multicarry", rngNormalKind = "Kinderman-Ramage") \end{Sinput} All that remains is to run the test suite and print the test protocol: \begin{Sinput} testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult) \end{Sinput} The resulting test protocol should be self explanatory and can also be printed as HTML version. See the online help for further information. Note that for executing just one test file there is also a shortcut in order to make test case execution as easy as possible: \begin{Sinput} runTestFile(file.path(.path.package(package="RUnit"), "examples/runitc2f.r")) \end{Sinput} The creation and execution of test suites can be summarised by the following recipe: \begin{enumerate} \item{create as many test functions in as many test files as necessary } \item{create one or more test suites using the helper function {\tt defineTestSuite}} \item{run the test suites with {\tt runTestSuite}} \item{print the test protocol either with {\tt printTextProtocol} or with {\tt printHTMLProtocol} (or with a generic method like {\tt print} or {\tt summary})} \end{enumerate} We conclude this section with some further comments on various aspects of the test execution framework: \begin{itemize} \item{A test file can contain an arbitrary number of test functions. A test directory can contain an arbitrary number of test files, a test suite can contain an arbitrary number of test directories and the test runner can run an arbitrary number of test suites -- all resulting in one test protocol. The test function and file names of a test suite must, however, obey a naming convention expressible through regular expressions. As default test functions start with {\tt test} and files with {\tt runit}.} \item{RUnit makes a distinction between failure and error. A failure occurs if one of the check functions fail (e.g.~{\tt checkTrue(FALSE)} creates a failure). An error is reported if an ordinary R error (usually created by {\tt stop}) occurs.} \item{Since version 0.4.0 there is a function {\tt DEACTIVATED} which can be used to deactivate test cases temporarily. This might be useful in the case of a major refactoring. In particular, the deactivated test cases are reported in the test protocol so that they cannot fall into oblivion.} \item{The test runner tries hard to leave a clean R session behind. Therefore all objects created during test case execution will be deleted after a test file has been processed.} \item{In order to prevent mysterious errors the random number generator is reset to a standard setting before sourcing a test file. If a particular setting is needed to generate reproducible results it is fine to configure the random number generator at the beginning of a test file. This setting applies during the execution of all test functions of that test file but is reset before the next test file is sourced.} \item{In each source file one can define the parameterless functions {\tt .setUp()} and {\tt .tearDown()}. which are then executed directly before and after each test function. This can, for instance, be used to control global settings or create addition log information.} \end{itemize} \subsection{R Code Inspection} \label{subsection:RCodeInspection} The Code Inspector is an additional tool for checking detailed test case coverage and getting profiling information. It records how often a code line will be executed. We utilise this information for improving our test cases, because we can identify code lines not executed by the current test case code. The Code Inspector is able to handle S4 methods. During the development of the Code Inspector, we noticed, that the syntax of R is very flexible. Because our coding philosophy has an emphasis of maintenance and a clear style, we developed style guides for our R coding. Therefore, one goal for the Code Inspector was to handle our coding styles in a correct manner. This leads to the consequence that not all R expression can be handled correctly. In our implementation the Code Inspector has two main functional parts. The first part is responsible for parsing and modifying the code of the test function. The second part, called the Tracker, holds the result of the code tracking. The result of the tracking process allows further analysis of the executed code. \subsubsection{Usage} The usage of the Code Inspector and the Tracker object is very simple. The following code snippet is an example: <<eval=FALSE>>= library(RUnit) ## define sample functions to be tested foo <- function(x) { x <- x*x x <- 2*x return(x) } test.foo <- function() { checkTrue(is.numeric(foo(1:10))) checkEquals(length(foo(1:10)), 10) checkEqualsNumeric(foo(1), 2) } bar <- function(x, y=NULL) { if (is.null(y)) { y <- x } if (all(y > 100)) { ## subtract 100 y <- y - 100 } res <- x^y return(res) } track <- tracker(); ## initialize a tracking "object" track$init(); ## initialize the tracker a <- 1:10 d <- seq(0,1,0.1) resFoo <- inspect(foo(a), track=track); ## execute the test function and track resBar <- inspect(bar(d), track=track); ## execute the test function and track resTrack <- track$getTrackInfo(); ## get the result of Code Inspector (a list) printHTML(resTrack, baseDir=tempdir()) ; ## create HTML sites @ Note, that the tracking object is an global object and must have the name {\tt track}. The {\tt inspect} function awaits a function call as argument and executes and tracks the function. The results will be stored in the tracking object. The result of the function (not of the Tracker) will be returned as usual. The tracking results will received by tr\$getResult(). With {\tt printHTML} the result of the tracking process will be presented as HTML pages. \subsubsection{Technical Details} The general idea for the code tracking is to modify the source code of the function. Therefore, we use the {\tt parse} and {\tt deparse} functions and the capability of R to generate functions on runtime. To track the function we try to include a hook in every code line. That hook calls a function of the tracked object. The information of the tracking will be stored in the closure of the tracking object (actually a function). Because the R parser allows very nested expressions, we didn't try to modify every R expression. This is a task for the future. A simple example for the modifying process is as follow:\\ original: <<eval=FALSE>>= foo <- function(x) { y <- 0 for(i in 1:x) { y <- y + x } return(y) } @ modified: <<eval=FALSE>>= foo.mod <- function(x) { track$bp(1) ; y <- 0 track$bp(2); for(i in 1:x) { track$bp(4) ; y <- y +x } track$bp(6); return(y) } @ Problematic code lines are: <<eval=FALSE>>= if(any(a==1)) { print("do TRUE") } else print ("do FALSE"); @ This must be modified to <<eval=FALSE>>= if(any(a==1)) { track$bp(2); print("do TRUE") }else{ track$bp(3); print("do FALSE"); } @ The problem is the \textit{else} branch, that cannot be modified in the current version. \section{Future Development Ideas} Here we briefly list -- in an unordered manner -- some of the avenues for future development we or someone interested in this package could take: \begin{itemize} \item{extend the {\tt checkEquals} function to handle complex S4 class objects correctly in comparisons. To this end R core has modified check.equal to handle S4 objects.} \item{reimplement the internal structures storing the test suite as well as the test result data as S4 classes.} \item{record all warnings generated during the execution of a test function.} \item{add tools to create test cases automatically. This is a research project but -- given the importance of testing -- worth the effort. See \cite{junit} for various approaches in other languages.} \item{improve the export of test suite execution data e.g.~by adding XML data export support.} \item{add some evaluation methods to the code inspector e.g.~use software metrics to estimate standard measures of code quality, complexity, and performance.} \item{overcome the problem of nested calls to registered functions for code inspection.} \item{allow automatic registration of functions \& methods.} \end{itemize} \begin{thebibliography}{99} % \bibliographystyle{plainnat} \bibitem{xp} http://www.xprogramming.com \bibitem{beck} http://www.xprogramming.com/testfram.htm \bibitem{junit} http://www.junit.org/ \bibitem{tfg} http://www.xprogramming.com/xpmag/testFirstGuidelines.htm \bibitem{runit-sf} https://sourceforge.net/projects/runit/ \end{thebibliography} \end{document} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/doc/RUnit.pdf����������������������������������������������������������������������������0000644�0001751�0000144�00000246660�15024242132�014620� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 3690 /Filter /FlateDecode /N 71 /First 572 >> stream x[[s6~_vg'$NfNu6ݝ<(2mTt~UdQv �wppHƙbBxecVkeLH -5ȲH:c?o2L&4+d QLJTT!L[K9fA=ό h<0+5¬#a[<K8Q90R͜B#0=:Y| `! s3/*n7D+-4Dq\iǂx,X# 4 ChB!KpQc,HX ar1_CzEPcH84bh $nti`H2@ 4.ȡyhJ`-+aHiH(h=%aPPzք2Э$ZV}_d=^3T̟LbC35{++fNW?0fXO(?B{8v}Xoe1ޞM?%p4\~7u=zx>kv?~^,/VMtWs@{O_׋z5]֘Lul\ JU#8Zģ62N)+af&[RHeW|-Yl>_':Vu|]Q**.T& LZd{jw rT`o5OC 㮄}(BrfiH w zY.*wI<C<H$@GQa1Mw%:pn Νƅ,, *PԊ4RV#h5̤fj=!$)NL4hHC4F´qcVIsAwHZoL p։Ů$ ۤ4ND DʫuQy7{̽=ۇ3MYɷcZ]RTUKZ T5JQ@5T6o}5Uy;la9eމv#M;I[3PN+U~HeN=cp(͹Мa֙j3TڶF'eUlibRdEW.1SPi^UbJR j}}?v?=˿O忔'UfDwt=Y{,FGAu4rֱwy9%7֋X_'66Z7 [q )ҧ'iHړ<n,]&y&)M<O/~zh͟Y~O"d_?7<_| >&W+ڏ 9*i!*wgCOSq9+ 弞#sC9}28YV8+qJg,[j�ko^{r.'@}XSXšځ5ikDh#U?suM#:Ko.Swߎ/9詖52ڏe=EpN'W$$ U~ *ŲX|1/Ox?/bYX@6L^(`rRy@Tƪ[S@aH-{N8,X{R9 \NerUF.Kuڬou{D=yu6 u>61CʭK)@ZpeD!{?Rr,&� [6:EQa>,.XisQ>,&,0 KX*q',0`_$РUF F5N%^.0ֻQ&zGhcrpi>p1cGF`oIjt}mRe<CgPXgIz )TU*=q /ȭJ*C;%>nԾcrK8OŲ\\.H1v K�x;NVtn�_?< n^t&�z5tѐLX}Zµ UM, ݩ޾t}8l,EAZ cNe¢J}Z s"xS qG*ɫnI`�zlPi/lWS~R:;]TfÃ1 -Gr�ȗy)&?F&7 j2�>,'ӏԗ:D|- +/d rFb~1Y]SLNl5̝ nC_^c*YqvI`/jF]oRs>$BGPs, `77?`N; ˋbYHG4)~0G-Gө()xY?D'>&6SXӤgAՒ B=ɂ{^gRe6ꌎG(^aQ٬,$τ&[35Ɇ%pQׂ 3(&3AT}i:i!-6nP(Y$a�=w&)z(5}5P-}1P=}-F&n '5tq: ^Uu]!B퇻$:u,bY ڕ3ܿj_78aEheυ- NTUzVPY e;eu&m`j8&*{בlPLAqYN@r{SCV&KsۄTP7ݓis~al5KmKDmvq6ªRIQܶ(@cj:yʡ=ծj|l)4բ-Iڍ;Ow?~ 8rn*,@DoӲ6zy3(a2k[8 h?w2=7B'P;nmIVlU>>i&6C)`AxMN)^uŽ@qRMj%|S@r<n3Ќ;?^Yj+pkdD3dvj>x:;,i"<}XTjYKL'_*~<na(HQݞTFV́˗ށihX(X96Zyz-i~f鐫K8{@/#ZG7C3>/8:7C?,kva+-a#}~!z5gKJ@"OϽs;G<,�bbyu/r7Fzތt[HR] Og] &U5<qJG?>Eo|5 f7v}4mvzFp >ܶxxؕbm$~OVӲ ^}d1уE/ ~;Q<>FS/pXژC\W{/>̪M#7S*j{juH$GrZh ˲RC[?N6ߕc`~[+mNM N}V>KMpł6wd֢γ�I@YhgLS!moEn= <PGCL$U�{m<endstream endobj 73 0 obj << /Subtype /XML /Type /Metadata /Length 1658 >> stream <?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?> <?adobe-xap-filters esc="CRLF"?> <x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='XMP toolkit 2.9.1-13, framework 1.6'> <rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:iX='http://ns.adobe.com/iX/1.0/'> <rdf:Description rdf:about="" xmlns:pdf='http://ns.adobe.com/pdf/1.3/'><pdf:Producer>GPL Ghostscript 10.05.1</pdf:Producer> <pdf:Keywords></pdf:Keywords> </rdf:Description> <rdf:Description rdf:about="" xmlns:xmp='http://ns.adobe.com/xap/1.0/'><xmp:ModifyDate>2025-06-17T12:32:58+02:00</xmp:ModifyDate> <xmp:CreateDate>2025-06-17T12:32:58+02:00</xmp:CreateDate> <xmp:MetadataDate>2025-06-17T12:32:58+02:00</xmp:MetadataDate> <xmp:CreatorTool>LaTeX with hyperref</xmp:CreatorTool></rdf:Description> <rdf:Description rdf:about="" xmlns:xmpMM='http://ns.adobe.com/xap/1.0/mm/' xmpMM:DocumentID='uuid:fc7f767b-8382-11fb-0000-a7f38e4f0403'/> <rdf:Description rdf:about="" xmlns:xmpMM='http://ns.adobe.com/xap/1.0/mm/' xmpMM:RenditionClass='default'/> <rdf:Description rdf:about="" xmlns:xmpMM='http://ns.adobe.com/xap/1.0/mm/' xmpMM:VersionID='1'/> <rdf:Description rdf:about="" xmlns:dc='http://purl.org/dc/elements/1.1/' dc:format='application/pdf'><dc:title><rdf:Alt><rdf:li xml:lang='x-default'></rdf:li></rdf:Alt></dc:title><dc:creator><rdf:Seq><rdf:li></rdf:li></rdf:Seq></dc:creator><dc:description><rdf:Alt><rdf:li xml:lang='x-default'></rdf:li></rdf:Alt></dc:description></rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end='w'?>endstream endobj 74 0 obj << /Filter /FlateDecode /Length 3558 >> stream xZr9gLrLʮgn[>P%3Kky@4HJJh4_ݘ_O5;7]zz.'N}':xJv*UJmeO]YW[:i|ezMJ_MZ|],OJhjԺin|ŘdiOT'We2NH'5|, ׾kIxpnmqr*t$Œid L [cfYti>j"~Q/oejLn?.FV4͓ ;9YY-ֽ3'9ǃFxcXo؈A%7XJn[5 S2/a_Bw"l"iuTcUQ%uOVES:%s\C`4Dia2,)yۃ g?j%sU=>A[uvc?<#'7X1{YN) 7Pv#,d:@N S%EeX՚q q:6 NvہWSC C=a17�#VǮF Z/�vw<]U_W?(dd֤�.cMd/C?5šoMIJ0p; 6eMN.7:>LpeǺi"ddaigXb*EއsL@Mz#|*69raTiEz;W)pZt*±ܞ+;'x TK!QnfD )f 戋m!D_H̗8r�@C\c܇`ZU"q 4w@ȣdP@'Im? @Z^-o e"/GiC^n2|Ƈ9Qh^E,87]f= *r 0Ō_T2zPA.|Qos :.1(Y2L{qMt.[epl#qhf k1iQ0.?=+/,0͋qpV,5ۺ=. =wҴ.03y~{.2q �>#*ș̌ekiZ6̨sU o 7 `c.+!q8DXf@FJLis$Z@\ ]ּ( S6@qgRȱVɧt]]ce+` w  lºw`Il6j4Үa*ň]Y|ܴN8 NLW�T� Y9u<wW9% nα+#0IÕ'U`?EYr ic5$,*"G "7~`!}+RaS"aĮUyr8&3 Hup0U* >ŅA'l^ZXKB�ɔYgMU&0],1eq6J;nYI-Xe<Ioq$&b=vCF�d aB<0K`�QdfMh#x ^e=w B#'7/4raYA\G2Ƨ Cb(Bm#k:H{q[v"�AEY ebԴKnK(]+y!VEpϒ 4zvcM\my?kWtRBmԢ-y> Zx RJ7"BBY0n-V[T@�etG-ÞX|BC/SUz|+(((4ۃD~CD_sE!ٯTZ�T+l<w"u5.mdDx`x>IIC+=ŽL7B4](]>�,6ZPq 1Gn=K_SkQ\V"ilf(tm!rH˸+D>'Nyd7/*D ()'TIV>6l1ATR)c zuqFYHDK;ŅD~v< u9JpuTRdvyC[YYm(JE.^ DFD AbI_MT[6ePӪ"N'�_Z>PGM9( | ^Cj}GK&M+W%ZU@(5wM$}[ Foe&7LE:\bpɤKaxAfz7\r`׏&8>M�r3J_xL 1 r g�B�IF`|:~-ToW4xS˔ a>f% tJ^&$Uql<~&4<J=B4W2QR(<?fGmC'*k= S;~?eODD/ dw/ 1kGBM/ʂb"-(H잆(mّǒbZzY EZZU { R&V_ Z;y<'sݥ뮅oti\\byLW4}n a];HZk@oqqt׶ԉ6&\:v.i 2xM<ulvLRCJVZ9J+6EP`!/)v7FE?�(yE*Lu=%9@?CpH(~h;ahۆz~q*:{xUqSHoJ>hiRBv®KZ|�$UDO1d_i:xqM}gW^[H<72uQՀ2^ksN!Z߉'͘Y$=<�u-~+o,-s@$9 q'|1aY٧Qނkױ:U,8'^/6b얤՟ۄN ɺٍ(7"; S[{Jyj9pR�ćz> C.|7Dz}:~!B>OVߨx:j ӻGǡ)m%DA@�sHty%܅c^<l6}K m! 8اrB&fq?bرp'nY{wZiKI&-u.΄т+A N]˵Nu.Mܩ^>oZ4j.Hbt[hP^6Y_hP [GylhkMV?/YY PK*ďسkQwRg'_ǿ y/uWmHVg4X[ 5|Jljc&X.C!99Uj%+. W1Zj=qMaUUZx_ endstream endobj 75 0 obj << /Filter /FlateDecode /Length 3531 >> stream xZK6o}cG"sKE , dhdݚ4T=ВX,w宺//.w]E_r?vޘpS{ow-})wlB&=~)ou++XUS'|SEohC{ܔ;qkKmEzy>C8'A||㦆qUug Džԑ$t"s NSP 6߇Uzu_-4r]i/.eiKhиv#>eKA :89dڋV:m>L4b՞ThTwVh~9ܶ2%4ovVNۃe3S?}xȍ7:^�TUMih/�#E-ʾ2${(g1zC\VK`2GBSP0ѡ9;̖yj_[ErSFVZfw)ݐ&ڑ)Ҫ Xf]~*Qt�!yEI; �)+X.&fꝎ%WYLIjyЎqc0-k%l?6*ز꜃IYkOrq*[~V'C'lljWi?+DDؙ;M!!=D~>#Mzy^,E" QcE1qaO_UzBZE뚢ӗC"10<TS$9%%ja10*!!<(ʂxuu#GW`d=~l[7(J31nMC>K afdt8 n%Cwq-Hdo`P2yCԐ1YyOƶJʋhΧF 8`fC˚"<z6ĭU \w}ˁgJd##_>l^s$'mhb9eiAN^;+Aj,a qn#fNYYh!1@ٓJh.n l:.&n]1 ,k"q&)�5DjcJ E?e"i۴x.$V&;9Sg�qU,�NhӦKZȴwgij[(c>U2u.CAƙ #`PtIaR}~h, h>AgsCNy+)~!&0G2<)vV~nn2B]یW$W0 2N-ըBN%PkI!fwPcW5HՐjq:??$/(JHFYWʀ8y*Nm|G0b\n/y9M@Ͷfc՘d;UIJ KE+Q@ꨨxXgIHU%hyŅnEyJ 4k܀bERTay9''i`8kC KEULqIGJ';/1)]mɫvCr Q-.|8@�,Q V\ߑ 'KE 9tPaT'k�4 ;+kz_U^eOy;D^,"v`w eQ| `N`G1_M ]όHQ$؟ ĝUda0!ܣ9TY EeIcXLF|9 fmRDK<cAܲE*I=/΃:[B,,;~(S {.Pc^}["Nrշ1a*Lo%IZCo|߯Heu0`xbdGD*L?U˼q._dbjYZ8Fn_Tq\K! P0l`>-#iKL͢ 3!4g'J,|ٚSַ'g`l(( 6Mdı[jijw,N̚Dy*vliE:G8P=qΌÓ|٩c슙S)Jn8V3+%jeq 5FQѮjV' ?rҖVj* [- y1Z, ]R Ⱥd I!zѩ!ԏ 9M_UiNu#uX ?_%[m "&Ӕj.0>(b<B "Z܀|u;Pܺ? -qRܳw{x?L_lX5j,Ti^Č|4 m,Tϭ~->u^XhuA�:*z[S; :eMqEH@%Z"WJS[#&ۼ3RBR'K`uammy.f@h-ϭ '.`lS $Ɉ9ys1Wͮ<Z]muk9K֐?@)PCY>OOرϰZͲ`D7[qUSc{/>e4e6sl cdVYЬ5aHŸn#ܬ )L%ݕ7tI *LEO묺4#/g*val/۷\s< RHcE&juT܈bR$21c'AV!okGq2")a6sOw+Lx3zn`JWnJ$']ka1%%|LBRt{ի$"͎KKRW_bϚź ;7ذbky.AX\̙tgK .RS$2maC\:ثi2}VIT@Jx:'Ti9BDc47iР Q8y1(R+L/K4$eur${rpMF| :na+a`9$M,<ه[Y`Ŋ^nk0p鹣,skb&UO'ArTF=YLh@mQO#btM3ZzД6P$8-CnO`Qq ^͞�lBٰ| )m5zg͒]0_ǻ)4|{diI}/~1`nAt?h#F{˓0t [:91]d)&BH:& W?$*-0_07Bƫ/@$UIl|LzU-f:3|1䡴XP5cܧmq@�= {=w4^%e"/9BLJS%eH$7Z_BOa'%xc/pD�f玗Ǝ~Hendstream endobj 76 0 obj << /Filter /FlateDecode /Length 3436 >> stream xZKoTV A<HaSd$;3+I@6(zJaFyW|+vw?izW?Ncpܝx|vǪ0N{"}AwX*uy>`=:_?j?7֪h6ݱ(>.<U:=BBVr gO{Yo]ֵԷgZ6NN6ln* +G[j,r9.CQQ=V&R6h-)0J*ll^S} c|mJu Ȅx=jj)*jl8EyT?4å{,v,InWLp<~ܗ5^MՆqu2>V$h۹dzyOvG%ͺ߫a>F@g^_h2}�GuUU00Qhnri$C:i2?'g@Wu@|trxt2�=u Hҿa}`J6!YHYU ==w<)u>i3ŅWk=ǡ.8OIJ=4]Zp�tڜP84 U_9zJ0.^/ AU5լQlQHႇ (D#U;niza9A > mGWz8.W, N˂NTKWW¡W~lnв'P_kH7D-;:0NZT/ +k]ksϑ72Z!{NWt.H˛䖵Si5cr+ξ{=w �g8XE&I ;gMaO촁[HFu`zx}!*\顆b4{w1ଇD{VC]ԩT,AF+Q9Cаj@Jifۂc %GmSЄ&Mz ~:5 n,&l>ށ/O/x& II^j8ߌ7!I 44NARL)4by3=XPD”V:}H%Ixu*.W{rK"Ƶk̶j撚Wn.SR=skL4w3XF xZf(ޒ9 7f!]Xµ?`Wt'Д(A'81{+ 5 ?9GZ�6b,Qڬʖyʊ"-Ev?m\q71aCrp![{-+b+|˯>pµ[u]/PeYTәWwj\Fȉ3&Lqud^{=;1Hά%kɋ w)Sĝas$z 3JzUlkh.!n):PJ!]]˅o3'982^j17ۦ3xeZY:UzUx0zT.)8bdd^4yo-Js2hT1F+l еȊ*l|'AeTH|ui!/ ڿT,OlunO2vOz(�H]H/g~W�;@od�1 PJʫD,`K\L`1SlaA3o\[8˲緩�S |y,$m*.UVaksÜr9 xLK,n %,/oܘsVY8R/hqId ]! Ȱz2qcC2Qz[@rj6XBXW06TsLЊ)J co{VF{/Ol02sl9"OFJ[> ZWd1TlrHT7&O7N0.m=?g+:ciJB)OBq-\:JQ\;ohS>h@mIa483ʐzJ#-ֈS*'h!y˔kE3=ІƪM̚<m2S&?;KG�N۵ҧ�;@H4}#β6էňV:- 6xbo1Cs羦ĸft t.#ɋ \V?2 fTʯ_44m)E18@Hn?slB-ֆ/q|_JPFowRatIQևq5HnZQg)n@N\N2 qN,IT(N@넸/r$ n/:(ˢs ܀+O%F&@S+`K=ZF'/2'Έ.ʂ>& Z2F *f#]bs0=0&^VJGXYNG,ǁ(a!,p l(O,Qz%^r1>VTM{[8OOcjoy?rX%@dZ}/t[P1BWd3L$ݬ<+ %w 0A�dºc)ʀUk6`(#! \XK2 WڜqK76C\i& eP!wHK444Yՙ1GT"H�xNb5 dۉP)=.PbkX1yb=kIFdH|:$x]Y!\g[<"$x 2 զBP C,;vzT7Kt$Zq({s1:cNw=;?0救\v2dZSj<- iL$gTLgh_e"9 `0=wٜ/!&[7rJ旮a/0/|S~=RWɄu2x{0Jbƻ;!D[`1;f(pyj {]!,6 IsVC.E�[8OE0�tR++݄&4AX}2&Ђ ݃ 813dzY ṽ0L?t}&,&{ uB @\)QuLYU_N YxI74Œ�=H MRb]61"<~If[/̙:ƀV@<'p`doc3�<Wn"BwLEE oacoHNVDǺO9Y�$rgZZP jrDo,Uo,DYrN<,-oQu莌  > fn 9eEM}pbg =ᙖ0_{[I6B1q|T}ӷ�(endstream endobj 77 0 obj << /Filter /FlateDecode /Length 1697 >> stream xZ[o6~0=Pm"K[fh P pu+[l͆Q.<28 CbR~ޮG~Wo&t5P;7g7A<Krix4b܋|6M73xGҀ{IL%I`I"I茤yģD2=rr(Jg$_VR 0Se}A$0F.Z2-mFNURJK91.y2vl.j6!sIľlZS CFFNsrA>H .%c1++֛KCl9.gTҍ/ r"j̳,w# WG $̕!{6)m0c˚ҧ5ueO'fB- �%NP$"&1l٘C/7f1[o[EE(9`:'4D~`/ak*hxXD76fld{�rFm3!s-E͐ 8=d{jKp/0̴|廞Öy#4%ߚn'hK=1~ϟO%g<U~1=v0 /4e١n.QWLƬ2u!C_�;)aA(Byqߔ-QaMASh\ �֨s<4-2Hbt;5O/>7h=_POʖ,X"{s}c']JOΠ^6&`΃^i|(,kW6Qc뒓nYOQK8ά!()Ex/BX=-vWԋtD@DAu}�ݺxnJ�aGL J XQk8HtFtѷ8:/'>~B"Cn,5wgM셽̢GS`~m&!Hf;+doOC`NY)w0Iu*h!y 1Zjrjם22A֝8]NFCXС+q3z_e7`3вpfe00 ǂo.eŌ#sg6jǥEöq=.{"Y짨;faҲdXan:pFn.邔 uꎦlXL>% Yu^Lvn(f+5@ԷS0>*nm#| xfq|{sF8dTXYlsT><> çh׫jo:M[آl[Գ=h0_6 b{ÙS"=WD *riY74[Ҹ r+~ia<;f˭aڜVr/U@mdP// mQ 6~'vƶ ywŀe?"5QeDU$yB$SW&I4R_wOr!=ȓzc>Ix#Yȫ>T~}o@Ƭ͗Fz$z57H_VɔU_ɐiZ\]L&-J^2|I4S}A7IRCZs=:eԣǕI&o@endstream endobj 78 0 obj << /Filter /FlateDecode /Length 2131 >> stream xYK7䠃baߛ @0!9x|JYzњ>A{&Ej8 svU_U}5::ǿZ/+NoZ[N@ϜRzSڸX!3=m,FXy6?Zdaqt-)5iL7B-<3v6[i]d@؂q"V8Nw}Jmx6ESW̖&FĽ>.`ӎ )3DyShpͱO²Z|< a/.&2'x y6qV藐ЖMa\In6ֱ)sDo\v {74`\W<;`/ 5 M+V؝N%"}GA[)JدXSрvK#q>Մ,ڔ[f;B*vs~ J^RH-��(OI){_v վ_5w`VX0S?v�Ȓ)֒/e}e~ ̃-vЂ]D�|o":FB`4piSuM 'E ܁*Al i<" ⒄@3N0y-2 E27?ШU`ƐJipܱ0kzqJw~CHuB_ܗ<*2n]=1Oi.m~H[7s<{&Q"$o1iҢD*�Y?Z16g3Ij0DP) %56H L :0cJcfNcnrPTL~##%\lWpxR@.0+c;ˢȸGonCWP=V UC;+PNev`vGng_tt(2$ԌtlZ݆@9) %ad``{NʰGx03l wkP>t?tʸ<DPOi�`iPzz_ھ{96͔=,fQU/h/2%$שX] ѫâfd4~�*c|?T$cO}AI1QsCMҨuG\0~ƣQ RI>:HX?4 |Z]5aPlL'YVP729ޫs4\ ѕI p@8 Mgh77'],kC`Uv r敞RKoi]� Q6'[#.d.a N#џB[TO:D͎#*툙w NefM#= BRHܻ <'/8Qȉ@R˄+DeаWR wO4DI1Oe0W֛ 7)~rSh\(&.x�y<#y\0;&C C 8IyHD"=+]Rݐ4-uzdtM9݈9ICz!߂,@�DlhǬ0n*AϞ-4? }&QCRU׉(K6=[<sKexH(&0Jn9.HzF DЋZ^JwaI-~#  -bE�m6Q wٲ}^@M9)<jF iiݿU^֧E*8 2)1Iϛ$j)u\@^g:\gR'ӛù`8?sS?&|X_E7UDd%<󤡀nod8F?,~~Gǟϋ ܳyj3wzp_5W Io>deXeꈸf-i_JtsL7<@0u}j&frI3J<_Ej4S;/XXzTT{HfI8YC#KѰC 0Ж2ы\Y7URTS"i>뢭II]#/b1/%$/CrEXE^fB" rSƍy~ۙLT}{^l \H⏜ sϫV�endstream endobj 79 0 obj << /Filter /FlateDecode /Length 2042 >> stream xXKS@|h%~A$v]+hdKY =?U ǫ btُz||, ,E/,x]i.9/bY)|YB,+iaEXZ/Um9i}-U %vE^|B)×EJ]MF~BcUnBYf'm^pqƱ?aZKal+ C*Y͎a?Iխt-;vݛP% <@pjڸN}rҟl i+9-ITV(%I8̜bAHS6v$`6g3 =Ywjk8$qTHO=K~�!}?pkR塀1-64;9``ɡJ;wԜ` X x<!)]ZBȀVdj"1{2Fmiz״qO {tTq}Lu7j cX(z y)B's\PW=[ 2 >%SjeB!"�N qA dFGrg(A)~< ^1u[GyJ9$"|)9# nc{.˲h".N!O Yja<pȹlzsa y m±D'9e-rݗ#*g$*Y6 ЩN5$@:* oPoW^Ĥ2ɯ8Imʾh#U)|2B lŎj+ˆCvo?-PHq` l3#Ri o+v6o"˹9G03.`QYu;&VڋMӦ8cT6XQ,aNcԓ))*4EBE;W7wsJ nX:*#Eq*yl%&gާ5-.J!BeKuϔ{..C)yręY4 u΋Iao ~R<̕s% !F<CCȊgGkYP 4CF} h/*u>cXCr T]"K .zža%7�cq=��*ͲyPu{8N�;Z),UZ1PG˹Yy"̈́S}zKRe.o<q+O2qn܄uU^"%X/ڤ�IK}BeMu)^e1ls}o!@ J(1 RP�_ç~.oIDPQ-uԶ# )شZ${|$N$t>" H3Yl $L|B326}\}ncd~r9e]YC=)` p2weHqsi!4ǼgOqCj}f$.ޏ@( THo9}LXG$ ZEH$$vekjJo;R ";QL |fם'0WSWRIi-)vX $ g!Ώ+~ Q|90[XXɁUn 7)gM$9V} ږ*cu|I &f "|jڬ_|^7M~FN3g% )@úْ eg0pT%<j.!Nz;А|çzjz#_9b k;@+#Di$�<END#H)` M i.~9 K;HqdbK.`|" xag z*yJ|qA|_Ξ_tUOGmT;zVƅ;%Ff5~endstream endobj 80 0 obj << /Filter /FlateDecode /Length 2528 >> stream xY=ܸ78'PW׳5ݥ3#\.@6wGˁCлM]MUzw%&s8n_Z+RW8*6ՏzlBͩ;]{)*4RLoac:iJuU+mcȞewƁa-nw8$X q6Y2MṖ?gnep5`6T8 ,-fmeכ-Ŀ81 >XodN={nq6"^ri)_t:jpC%~>h;H;T+Zq&x88tRJܠOP}vd<=Gȃ2ډߓi_ymv Lې,~<%:6,ePlDFvy6lvVU2yuR V״SG1 7s٨@,Q <<j!]+Vj#L0]giaΧ ƅu -b~"AiZ:[6RFH9ůNexyT [%LN+]SkqTD/am(^U݉#.LcġQ`Ȩ ppkDݙ?O?J5nlډ̇JeȯX: c3ِqهW ӂ;1=`pp*t&@%elHS̓LH U-nX z/_@-�a&(m~ - d��K9Mڮ7*/� a{ ` z:m Եҹu.25#r@I$~M?.tWgiRA`["`u2K.5z *?edox;ܲ.6uKcnBa5Wv' {aTtW43(!Z(%p��.ZJ9+ d? qDZ,#W]m!ShxP)[ѥf}sU$/s2N<?0gQ~ harSl  9{BXs|!vyAM}M�e {ʎa6oBKe id?Y Obit!ioX _|<O,ƩM=q3<` }4J[WC%$,V5UrEؑ>C2;ыxCش[6j8#9xj ~<o<I j']JWrj}kHfM ~;})c6&J[Րӎb[9%c[|$CzyZrcd8wE_<0k}GWo2Sς&<aE{ğo|qvTE�&rloL`>�% �,g"vGrѱ Y:?B8YͿ^�2 nsJi!�Cb~e%OGcƾ-a2Rj IN"9>3G`9Bގ&lxJ~gDV b) `wS^)۞nT 3X;'΄,F&9)(R<L DO`s*>.@ISRVi5RUTnE OWT#RxGGmd.>:98Ş9)XHEblvduiGUH(*snm XQTc�}u1Ir~ZvuLrpjaz^!$tӵMH pU*F9ߎ<T:[5%R\ɢv6!C"8|sŲK}d2M ?Fܪ)6;'鲤=M^$ m6іKw3$a dB%8b14HyLHr_V&..ƆRt/Lcy/VyaʾHLlo͢{t^us_k�ɥte) 8U5A?w8K%,bbdL@"5(9~]4'}qԎ7�AG-3gZ:mcJDlkx!3&R*JjR$#ǖr&^R<<+t> #^IT;ⰝjFʦUˢ( ۼ&^/N5 Ga v,Y) (9zg`#v|x{䝇FOc"[*bҶNҦY YH;$ZWf,/yR3><5< 4It~JOEX}(}d IvoFxqSz<ÎpJr*n[L!߽<'xhi,Bݏ E�zj ՟﯐Gendstream endobj 81 0 obj << /Filter /FlateDecode /Length 272 >> stream x]An@ EsO#!oMD,2 B}ME㯏]ί<mX%<rkeʮ0AVӵ[\qzE<ȸ{w rJ Kv" qd'y*_~|<6ںdS@bMŦP5b&`$ؐYZ:d].\ɜI&QgWD@!IőM@s0ZȨ!M"F5slFs1:=s>UfK,\E<~endstream endobj 82 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2172 >> stream xVkPT>h5agQsqةF'^Zo1 F xa_v�}Ϸ]`w]D@+Uj:ĤMbS=+&d3~>yxIq .Џ3Â|\2=Né&{#ѢQGaa<bs g':,ΛC "$EҴ鉙sbCl+`vl'cK2l3ۂM2 `U >鰟]俘j0 hbolڋ^/fbP>7 Bz:Wbu\f7x=e:Iԉ.F*oek<>RFP[hFFQ{_>hA͐@ MGtQ8&l&X{6kbhm>S?@zFKb6ٞ@bqW@V.\a+`Tqoܹ'QNOQ$,u\A+|"dqsFɈCv E|!N3X-_usX}x=g ͜ڨp>yڋN~yL[NRh.4R:FQPyr$&H(J 5ĠK s&}@ TdLY`PC O|5RS!2re Avx5~D?nu%ÚIx"T*g㪱$(mF(AAaAy$F>jwwJnad1hv.^\:�GLG&DQ # q4=AW̄%%  */elHټ(rBBCkt &`Mwۜ>Go W`x8L0)dŖm$jER(p{wNcb78 t,, $Lx~}7x7dZjCҮ)Z,rAMwgӽꎆӐ`h18XZ*$V+)JqmwJ* 0{C\$JəPk'5Fb_tQ|zYBE7 n28uհ*Ԣõ�ᅱ FBi(+wkwZmA <0Vxכk+hN#.Iܖ}"R$S�@_<Ԛ;V{*|GR6(#pmߓz�߿=$<:* wZ,GƆSX0;f^P(:nJX }%PH鎔ԭPlD%av?7[GrcfhC^}A~.x8Wﳏd;#s -+ gXon[[kaIȺFu!k_F5QV2Do]Aޫy#Q3#n:SJ,]jD<0Dz8K�(PFJ#oSmhFkH-guЁԝ]R):,lnF]`)s! c?g+Xc*'B%u(ѪAkn%{ HK`a^[6zR0b4ƙ>3ǧpAvi?0F(g =no{[S7$nUGG=5iHf*&Xɍmb@,!!ʲ衂\vp!t]UO^ ] g%,M>l_ozw"CzԀozƤj"Cb'FXکomKke~?ȮVrB( -b@ 5.CDm'X!Zg0D~PVT7`b+33x}Fhh(<2{؈Ohg7FȺSK/κS$î$=鴨R$Y)a%$ztjI";`"] >|({CjׁO!= r9خziWo$Mr 9!pY%جgwş|UFr85~S%*x~=' WDidߵvd :v5endstream endobj 83 0 obj << /Filter /FlateDecode /Length 358 >> stream x]n@{7-mE( sD"oٱ"Ŭ;Ѱr-/K|aMmSޥi*~{gn8ϒr,o9en/C.mvNY5hYэժ7*̬t ,QqgpFFF"ѽHoto/mQq0 8�wѨ0F]w6 X;bQ,\Fa 1dopx0 xpDmī$O%(`r4=(FYz9y3+*3gŨ0H42_S1Y=(o捷weqWe"endstream endobj 84 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3796 >> stream xWiXS׺!vUӴXz=mV[{8kUXPQ& f29 B 8 VkiEVk[p:hiY,ӻ"3ӏHw qa@ 2.zμy/< >!8ypNgbwh?LGY&ٓ/O͈L̈I)$g$w,o<M;vg$d}9s))j=;*@=KS L*H@-^SJj5OES1-!j*5QR I PvApKaXa߸q ?O?M Lu M\9ZP䙓~uSn*x)jaݥnP6�$ VPni7THfELn2/c%4 a/84/KDUCVP/ՖpDXldP4+4NJr j�m .KAMG@T/c %()PDKdN%;iڴ*!Kr:u~U�߯lwoM10fKYsFmh=_el*y:0 eq7Y,ݮ* jQ#V1ul"oGO 8erZQ9ooޘbJ ~%F :.Ȉ|y hg-Ka2QơjYonfZ7Q߸ɿ >R{+˨mH bPѲ3e>&Bn1ڏ}o1Ca PLJ1tհ~P}{2ދ4xRNeP*nNC'zwPݰp۪KFS�2VBꥬ2B>-7h?NG}%x㉛c8~8F[O 92u1oS'~5 5,ByP@"$dX:�S�CU�"I%.r+X[SRUM ~ nCsv]1+�n,ޕX42ːW״@9Cq;̛l[-C2&l}|FkaK%(=@W 29փ'�6Ͱ 쐷<(Vuy{2ץ%<ZGrx :Ä}ݐ_%=;|\>Haɗ̅ށzX5P+j&E�)WJz6חUKga=k:+nw2KoYŰ-Z2Uz/Qh["M mKgSET N rEilr-dlFC�v`Ml�J sM%7p+~G=3h%ѤT#k0Clup C]}~5л/m@݀9KTv\pp5:f )"�VLi@yL +ϲJ .a)O,<_R�Xb,!$^Y:΢V4#gh0.bژ=&~@_}8�sL9.?T16<]qvZ(\1Nԇ "\t]R :¡-@bDzE0 vOܰ נʂoETZT NFu! .`$:Хōqmo- x<V'770{፤ SA/ o8{T^By?G}ڹ| ~q, *LDzm޳Nݻ=b$gfVk` Kp'̂xI|Е2F֤6bLExx&kR֮00::9yɟ/%}MT7qֺMI0;znC^�fu8@=gd59}$^QSNx j Ȥ uyY5o֛!˘MQWq^:z}aZyw%,)T̈ٳgϙ=A_}l[#K͂ӃbQ+VEoSCˍGVɋD<=fC;cEoґQ) d^(};]̓“@g.lcjMBv9�va'Lj3v K8f^gXv~ Z|ֺA썎F82Y2:3rpAc{5<&60ե8sjƙjW~$p+Hkm!z3To=b9c=p:0 0o0>-HtOSs$z�kn\mv88<ݱkÕ,_k &aè]Ꮸ\5sͷ[~“Wq8d*F<CF(hRmVؖ2Zb cl_[[Ž )@ǃi hc;b91O%`ź +2n1T[SIc4dziG#qfY 6Ew:xsΊޓ~ʫ5ti]Utݲ%rFKΉ}5 Wr;gШ ުqgUlvV[)חC)9͆V} e3ĩB�;A_�;sݬLf>7lX_B&/ M9dg_'t,YG.''(W+S@hkkkj^OƊy}$~!GA"<5PIJpm9ec_羓^Ȝ݆: ̃"1-3�;3YFb%t5H[`�@+o6诳Mw3#ü:Iʱqo?{ 7kd<1rtE?,A@ӹұNދ]V̑wVrYF%-RP,~jն[r)UƼQ["0CѤ/OOcG((m{^W镲O3^h~q^!uW,a[s1 *@IŰ86 uqw$z1pװCc9:iQ<ϣkj}K]{mD ?*a9|!vvnEď7ԡTwI8NjM]iy]$}Fɪhbz4ю>0R V= BWax X-}e)x$^k?̌A.ͮb#,#T�b2i\C`UD(ܶ3,N烃D2w ŞGA[Q 2PN(^xկAS#]մy;=BTӧO9s?w$~\p#h[|E>VF[<yC!J?@"`#c_(+,4<.ψ>1x<WAoѦdd0(UkExjaʢ'$:&Ykd t@mvx^oDl]EjN W o*g!x|'i›# {p1Qaȴ>3a:N[Jl8 ʚxs&BY:|\y[:̂\ ;ߎ! ;hQ`0A+)躼)c=r.ww=K|Ϡ ڨI)?הendstream endobj 85 0 obj << /Filter /FlateDecode /Length 351 >> stream x]=n@{N �ؒ5ӸH%�,KDa@}<)Rݝt~9O?Ӗԯ:֘.}SV~ۃxKd]~C^RQ{^U8麴1cYq,KS~Dtk]U8;;(` l?7xi1 8Q@q<<� ^( .06xlFPPSXW N++hA؆x4TiБ+D( {Y:c4 {c2 Q1!WYґ##uG 7JGn)(?g=zMo뚦e˼xTeendstream endobj 86 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3654 >> stream x}Wy\Sg>!r·R{6g+V: (a ɛ@&@KZ]hjL2 =휨ӹ߽w|>>1Ns^k쓜 7 |pcxo‡n8d"&&&N<3gUb|RzZd͉) W&EL^AW$$JZ❚>#4,<"2j7z{쎸xyT‡JL'#vbO"*b5&Gcb B41KR.S;68qqq;HM"2f성9f+w:7w/}S o /ك<k ٨x?͡SUq`75 eEVՅWDK jڠ4J<e؟[R!B~@ⱌ]n[#4HE8\.l_"pt[^89x;=aD[ u8!Db/yd}^OȖ|WR^ؾ91]=ƈ)GMJ#f^ Cbn_vhHhx3la=sp3=8v9 v[%8MA? vu֙ 8d\Ԉ!Q'6"-!*7 B9ٗj&?"627'|W\ 6O~ 7?."L��<{"#UR+`$~KXbҩ2t\ 7oצ콺[ɜuNL/bW!QDյv#@25zUvG'bg,nxø筎Sᨙ~ӳ$\[380^0 vU XT@+XA,:�T :b 9>=JhlY#LZ'cdʎU-Q<-ߠZv \xr-k< 2=C> ?QtF$evƁ#6aǒrw$;wa:٭<ܧפ+)q9RǞx@֧7'4ܾQ㱓_2</G syo㮳q888Yqlǝ^=O \TtDL=h{6u\™VEwgV%o? R{<ȇKITFHR Dm,K8SHʴr\jJ)NjZ2#Wx\vN ~hW.*R!6*5!HJLzcsNoxhω 6'v{6,Vw^42A$u$P{l 䦽g{<zv*"r5 aO^;Q]a^8PWMGlź yfB-t'iV}KRRZV d((2GFjk*L?~ephj9r<B ¼Q"c˳c̣h['±(AEqDe}Wc&jܷ,謞Y,mVԁPދ9|SKl(|@* YN5F<7ŭ�CO{ [tNO{="j'C Z[*{Q_-A2XL^�3(JeRSU ɶʺ )V>:(Ļ RXHINxqDSa7*-KiՇ^۩X% ?zoz>2ISF'j _w`1۩n2.ޘz ʈ`)OىQӰ]icҵߴqǔN˄H@:AA1!FsT4?2PLʴC3!|Ovh6u'B{3/m|_"Т"Jidd6s2Rx<Y.k&{G |'GT]CtbHkP.nH v`'B옫,g=l=‰ònJ j ]pĉU9/'٤Qu;:G0ŊbFXL)O L h7%G|Gszc! 9HٙE۪uOμ y]馦H[ ŨDes@ԓp Տc_\ɣ ؃+&>ɝ \c9RvIdc 62yyB1RpC*6wST& ؠFF,iLjsk.tǝ (؟"UiEjnҐwg)Icr|wCL^ &@�"Fg@ GlMTwH![5QX_j.mp=*)ʨ̭8lI8(2 /B:ѤfL l l@XN1]d5TYFa؂do0}g:cpJUuSRJr*YeFyq\גOq0gwGߛk ;*=%v} {7,p9ߜՉ767=ĮDw:8@k{^PKqOѧݷj^ϔ' ]ЏJ|%MIE`g_GYZ{#? ܲ޲Vk\+LRM)Ng�5}p[Z %Fﳻ- /dqQIשEsg6ٽHôa6Nnl}Lg{kc%-RAgwW8%l,+l~5%`5/vFΰSb�YkpK8W1:4#ŜYYa˿گE|EU˝SQPqà/-ҒBCAZZVڵãX^"*دcQ8&& Sk~5NBZˉQW\QUQU^Ua2JK45Jm(Y%9O92sXrῲA) zɆ?5?rbMw.a_j;UEuUpt3$'wC@>[QE@O~YR@�$5#{[ۿ:;;z'/(W^ȍ{_]ɣׯ(8:`k օ'w*C|DM ވ~o.ps#c.8DmH;g <JE|/v7⿰ hRatM}7mزU.U Tup J: !HO8} a3ӼXԨ6r4RZ~XX[v]\f;d(dmk6'-ߘ#pWFi$zßXnm"s#}!X9<wà }NS}ΎmbZ<9#Ddk{}}[GjuL13/]B�SƩ#endstream endobj 87 0 obj << /Filter /FlateDecode /Length 409 >> stream x]An0D:n`&'MɢEDZDgwft~HO//rk?yY_?Mle}۰5oV[P;g/S}߆Zsו<?2zrO?X88 kqx1JICSq'a*1?&c28DYP!8DuN/BM9orΙ[e<3ܬss.1A2k l[A[[[6@2CqB ( Bw B+ b.q^WBW 6aQ&l2 ڄBFAQ(7ܙOM׈i5_ێ^כg3Q^o]7j/.ѕendstream endobj 88 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4474 >> stream xW TSw!pu-iXDʨuж}(*"J@EC¾$daD\-"juƥ]ZkXb/#ؙ3g99ɽ'>E q[CVF>xϛ^Gx0 MBj2%HJMN˒'dLې2meik ) rSRVgdg)b1a_-"n;<w^h6Em6S,j+5^Q۩ jK|j BB0j!*z@m|)?j Og)1RsHCeS:)txy7LYKGϳUB7ƄN<;w{xd&o3{N (v2q.tOQ{P s½I,kdD蓥 Ft'DѢBMUd8wEn1kJ{;kaylV(+cDM }\.E;Nb;J\:+:$#0vAxqCQgೆ3Ǐ.%\Թeukz8m[7i[mV&3[(OI(_#tq�;Z5Y.w@/Rx9~̈nT1_J{Oq xωؑ$3 V]_?O6vYϐ kg}O@Q#p\8Q3Q䞊/\#[Ft2b=4FfNiO [�y}_gnkou/c6E㒢WWnK hQ?} ;6-RL"Fg% 12\aevK鮲fbh);G!k Ey@\ )&%ݛ.s3?;:,ap$;З8Sćq0-TWtװh�QF-+]suPX gsp,\45*- ubI:i:̪ [FWjWYr`MLUwx?w }}ِZ'Ϙ {fYJIUW)"WV%ÀTVVTU)XGEiͲӈ\cT]۟\` >.<WN !ǘSw{I 7vYw.b0*>:z~_Lfӕvs֪J@@56mYdߖƷ'97Bx3\w[,V[I+.E0W N{͸8ܪ2}O'N$1/o_;ٛX 5N( ة:wJm8 r,ʌRTr$0Р)X^@9&3Y84\2- CYt!uO1 jY֬O)L@{E); M&p>/# 9Ϲk:;ŲwsiY@`*UՇjyt@yXT# hhhp9KdL %VmeE*(c{JTb,<O7^p{%W="=.q/Vk0$I2D#SxQ0zg}.Z.w Y t^`/2GSkϓYfC3 \x{kGlnnɛ<_VJmtWGs!! |fmu1ѝC>x.29LtFf{IB}GƤ>73憿ܱU6מ3obUFJ2ʁ-U.Bc!V->Z01`YY/ twz:-fK34{1MzȀzSt|/r@s=S <JzTTlK6Y:9apnobd—wg#쏘8}|jRfJB>`cyf>ҕӖKPڨfGQr%LnοQ 3uи:yen(:JI닡\baL YQZozCʾܔF﷑uTrǽ9_]Zw7u*V@QvRR)c<h+R"<A-+_ ՅMn [Nns}?c۸`_tklz@x>Rg[l*`+JԴLۉ*Ӫ m6c4;諧} <>ϙܽwK'%&f|Sj|x*?ceϵ”FSyv!B!y%^h(o0H7}!gйVka0<U65Ѕ''#3oCQqKFm8r^iV>OOdRs3$t#6_NYrH3C> X%u<A0pᾖv{;mIe2Ii"S`QFI1[u)tMJ-kQv߉9Kgm*d>kqU;P)xqBXW^)Yʌfb^Wpk'.}83x.;E>m ۿG=6}- ^/fq2֡*/2s$q;Q$j _t|w׺6� rHI.w E°_DE+?d/j5ϝs-hI T`Ewduui鹸=rﲖJJ2IHgGs,ݍwa˪W<~ UJva;;g#ΫGƗӌ.)"S7u F*зC|WzyB6A=%!Hf[E!(%Ggi%vaM򄩯ΐx@KԢk%,VjstB(}5홬nΜD]cE8cޜ:UbN;B# JOwIMfB�B�z&1X{a=,`?z@Uԣ߅}ܓGqz(<~b>4V4d6TO?T`mL"7͚)r3a1}\+X=בkqZku{p>Nؑ#̫!ƾ_/5͒� V;6=.c!I^|4 Kp&ۃCd'{QKb R};އ4E&&>бFَC;һGB ?'z/hpU@wr.d}׵,IV> "*F@&ƦoS*29|h+ \9K9Pk4")pӮk>flrр6T3 8Xf JaXɉuRi*S "::td 1vʳԽɏ̀wr<-X3ku~<݈+ۈ?48N//~}te6 :y'#fNUM.5Bd¢<]."#znОe ܆3I.RmC6ErԄ ]b롋swߓ/+Da#Ԗ8=hU|O{*l5Y3qg,[Pzs퉘~SXxxQ uaOQm%Mc")jکsFf$A Wˮ{LG:InG md!HͰ4ܠg9 qk4c� G;¾a:ّf^*sO1Pf*r֩̓EPZn[^Oǻ՜NM(UaOn'-aiOJZl{1Ӂ}dFft$=|t.t Ћ%w3=ǎt'ǚZt}t\B D/~ M6gh{MY5KBkb UcpYYz| Z;퐤 Ԯx١T?g'\wI*-߬RPV`bE?h7!O^dNbז<0p@_f[C9?^zCway&}.FהHi9E6](takZjb#1X'=Q'?ÚGiAl>Uw|{di O2^Xl8_endstream endobj 89 0 obj << /Filter /FlateDecode /Length 608 >> stream x]=nP{7?6 n\$\" Z.ř)"}^_.vOuc[lroImvokv[ǢGeiin۴0 p:ծrxURުfDA ƬGƇǪAc AA\[ 6S BP<ǪAUg,UH"BW3BHP@+,,+,,S N"@d2RLTF*He 2Q D&*#De2T"@d2Qa-`؀i -6`ڂq `܂a-؀k -8\NAK)s :r.Ae4rظF^tB:9bBA�B#@a1z QD! UPz 1z)q`ρC={Nt9s5M| הo7M&\SI߄k7pM&})ߤo5M|e:!<2<W_ש?74,ʯzL9endstream endobj 90 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 8636 >> stream xzxT sU`K#* QD{!I^R=}L2̤N*$P %4% UX"W=q{zzw}[9SDFf%!/]~` ap%DEiL0! eÓA,2/c~悬ًKDK${KcWVW%N\7i] 7O>icvĝ<e괗k3^9Eij9b-1XG' Fb"xLL"|%bLl'SETb11XB,%ˈWī 5b%x@&`OE !2'0b8!$ğD41xE#H"G V,%Qǚ:wY $[~@jTql:M!#d '>=>l0հ+I|2ON?F<==,92n=G-ukmo?1yOv>7OW?ӳ㞕<r\OQVCΟ KƄ#[$Qu\>&3|^^D;\*/T%ߦv Цo7gB zqܴnԗ 账|(z%ZZV)wJb߻p!A D3g DA"Ȫpa'D~ts|}? W5kx(LyٙYfJHPoS[b6GC3E~ᨦ Գ3OvjWm5ڌ�*&nU=kd )_MfI%TQ*,5^p;]v_T,(Bm׹4 %ޫ�\a%RY+Y\pOҪ@m0WTU]M >YaU,"ϒglR<Q l<mp\EYȲ}A^A|h�<HCMx_വ1a7 DYtR2.͐KSl,` ~5{>PD=4^Z8MWVYQsP*5KGMD_rh[|zp͙/Y2rؙ4<:*OaekVQ6!<⌍/=k1E̒ᛰa(>zi2@ ?A, }3܂}_HAo6BCkv>s/jM`3Xo^#;-Q�^1jn \H , wM GugEnE~nXf4EZ8ͅ[b6|^8�v‘*7Ͻ< s;n5 : ԝi}7�re4Y$csi%FVxt*Z!hcN D^ E",Ūa1ǐ@g-nJ0 bgdr)0F ve/%Uj9v,<roŅ?}عM(zYK۲ndu=[|~5?Aiד u^Xt]z^cW@u\*y{F}<bd< *ĉKפ4@ƖHn 8ђ\ )NC(=}\Uw|0 9[5݂Ys-h}d~}DYf:)5%Li[FSƢA= >úm@zl7d[:x�3l;p8 X]oqudcaάIRoEN[aA?;n^̮;Vc e dFV}M6 Y*KD*lZd@ Ʈ+pvdng]BYPgmS$QP Y[k9&A9P<mGSᶺ,nanv�L*uj%PP2EO &oO-0h*3d16o1pcuO|'JP3m4}B<mx1ȷ3/AA}\67own=HXB, o8 eApd:7<ō'3&jr? U�@\iB+rith6i4BZ<< erhjIP7܎F?h�3L{MmzxnEa*ZsXX1H8 xD޸ܾ͊f7iu:i8N33˛àF|Zhn7 VmLեS1tA᭫mg�8 \GD9z B.[Ojœ6gBb\ M >�708f@�>JGE!8&8!y]x=$fsȡtVym"(-Jb4V˿΃p,9FcJk=]!r6f3J*d^/F3-4 (H2-~1LI7,N#~Yq^P x #4XJQ±6:l##8Iy0hXM$HdV>{tsMŧ,/GC_XJ3hU'~[|/XkNm~a7A"[:i*PF7)3?k|#ل't=q7wr'퍼G0iF3 D7B${]>`/{ZoPGES#42B9\}dpxdsASu.S-=y%JenN:CaŨ$pe$7<G#8R $d%"r2;c[D<نY 4GZ- ed3no~O<+sb*lbM?#Ogrpi_Jl^Kkcbt<d,6acVt>Ye R$K3JPf"\[.a=a-er |yD֡DqO5-ҍyz)\mrܸ+Y{#pTAe82.0:sfhH_nE!@9vnhACȂw΁b})(w[G DH>&%UV M <ׯ|V›2EERZ"8HrZ aK?>|Yqm wu $~TJIPRxjjU55|کӑ&ڝQlᏩFr1PB`Ufd`ڬV7С#9v&>Y\ɤ|:?Ҥi$3yr0Q8 2*SC鞜EQ&|&WuY5?7LJBPBoI2TQZ3\NvhZJ&L1nIJn qQXT# b,;;$sy|P,ɤuVPj$hp8Xt73n0U. ;&׽!zGcZRa 7#CQ[WbK~bVJ8Ă A֫ b\r^=r@C^YˈpD�[^L@T_通+t0ٲϹ7݁ȝߦ)L,_Z5\,V ![Hw׬b_ + ZK| D~Hn=yw+߼m=͡K6˴ys}v?sKόFKo>FG(,F@ eRav<T(3~9*(D~K] Vv��(*- 56 { r`֣ z/tY)jr& 0s[%9萻Nȳh)40mϵK^n袦&_!油n3@ca,yB>iFbWHQb73QlY&I%DG&򚊺C)4|> 5̏]&7~.+00qm{c =ף;?UcqdLdk l*SӐX?u4>@/&X̵ 2=v }pIA+Gސ3cVsA.ff6wj �L~ 6)ar"\~!}bg,Xѵ:&-T�gx݆'Nhя+OnN]>-5˟UJ@k7,6)Ρgjyٻvn 9({ ޥ,eܛys vآa޵Pgг�Rh싶4 rRqыB۱Q( p@~OKEk F}nU`)X7 -Gs9h0NT2sTIcz2D(\(7Fq~aD~CP_TWT[Yd)^W樀ʫ}eC;C K^%$f V;&;<7 sW;>ۆYˌ7n Im8DO=;{" kȪBO5CdC(NڹV P=bp{!h z$߽oވLٙqA~}oJ(z/d8IS ՗V`ڙ+l{݆c'АҙػSh;i|Ⱒ*DKE(U*dac7 . (})eQ[sr_�] ALsn E>GP=s(-9g,U<1|u +V~s YLJ*NqezwzyuGn 5fؽӻ(.�<Gg0[ً`ywdY2�N5\nCI'(T)Yy&Z&LN%G2~1Yg�;(4 KT>`FoKAgf&Ao%A ըNR8 ?8p϶6ґF(frD⒌ ܷAEMsh4G^V4Yx,0= ]8ζ/^ 7kpM޸x7ח *,bs0ɶ*x/Z?jܔ7P߷ޙ=kF<r*x,ܸdR''$\`.HCoJea{I-*wqe3$_4LBLw D!bƘ^X(:] w*BV*RH 8vj!ς>QLr}O΄8g_k3}jY'ʐ�ZAS buIlռt>1~) :x.;ٚdKBlYn7 =;IB{ `U[i -6;ծ\ܼ2A6娨$|J{b{jep霸>u F.ٗ(I餴ɩTDk1HFt{{7s\Ә�+j`*yT_boW `K瓇 ص%9a`3֝_oH?QAa2zxd`[[2R6_hGwGXSw S}G.<xV$VcQ*v*uZ`}&3!PaxrmRvrqj~ ETv샬bĝō neh1a4ɦ& 5_siEdQeR%)h64~zU}@~ 5�GT΀sW f.sJ{HS.Ϙ'!qh>G^[h*6x;p.mrA=UU6H*E*`Rsf Anԓ Go*@Rь`AfVj`7:x6Z(*Cv6ob=&P]o0w"k GG]ߔpB`/> =:h^ ˒;N6BuA�?: BP@[Hƪ塓e.PjF5PgKdL*NFW1 B{ h#CܿA%T,?~4h -Qf K$@qm#/.0wZ$JdA1lédy\ ˸^&.`aÕ&&OYyK;(լ%]V [Ql 3S)ߨZƪpȭr `OF(V"ľg6ZHy@eS46h J>ۆ8%E # ܍w l+(#&$I l*+$*8*Qyshn'"Lj2Z+4_FFz ڬ7bنsZݍ._NحXtQVa{olI]O<m n2ܬEdf(4m x^6\WjJ&͇<L[zُ'2y[Pyc)[j=s 37&aJ+/{*fa5+/#4QCd|.^\Վ¬V\#UNTˋoQoUZEc˺ pO`͛b>=X(#Y:�rGE T`W@jvض�,Lb8qxGon(8&Nc|Fx/,)pZZS!$]OT ?R,έl;]qP\={j2y@Mla{A (f]D W׼.`ׅje鴁e0r}H1OxΞϴy{Ҟi"FsJYo0RKj8 K^dfTECxB$,5y{\ZJujE!XB}dPǃ_OߨDP YP*+ "E֑nN'8臥xS 0>:ՇEpt�ѳ(t ފ՝2QJaj en7/\ PN=C1EW$5r,N*.VsZuaMuɷԃtňd_ZQ^YZ~mDj.igTP@ ڴ"igy!BڎŔ+M z AQ}Q_A.|yu䦡X':jJlLJp-[0E"NZX4wOĥ Fgm9}>n8o}%ЧpXrbʋƒY VuNSw~�h_rԅk3( ~ Ij>yܛSQ2e:S~"U@Z^Z=]M@[/f)pĩSMv�^'K� Wgo3g^ EFp?1Lf ­ )*__%&Mϭ]$݅hKʫ 9LD)0r/v\l]- nS LF[ˌW;qW�8{+`.PYXYhI)z^ ݢeϏKшxREd.=b_\ ix*~ {}h/8 aQc"KkԜEµ~Q )qJҤ61ܮLVB!y ;E%~u,: BFjg(:$qof ] 2bM0Z Rl\E,.irW>u~I9-vbuo~_y5:Xy=zDOU.�^~%;ջ] GƄai Cr^յ klXӰw8f3z `}ueKykykq*TZjt725OVV## RT-Oِ6vѠS`)+{! C�.;gN1de`u )ee1[Vƀԋ_m6bـ xrږBL ?3XVST$HW\}xSWz˒hR%q j>XK~}ERt8^JN)$JL֫c"oEX- Խ4n1;v_eSW\|Z.nKYAqukI,xܥ_ h @+Np0:C p`2|)�QapYqf97dGI^r*4W,R12Y[ C`N`k Bޟɯ.R[ɓj* e V,ϜA �bfendstream endobj 91 0 obj << /Filter /FlateDecode /Length 161 >> stream x]O1 y�aJ(KdhU�1 B3H.D_:2WE05ө2M' jנ4FE3NgHOVgRHYy#R*MK\ >`_3cS>endstream endobj 92 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 169 >> stream xcd`ab`dd v 5420�q~H3aÏew+o_ 0012:)槤)& 2000v00tgtgvBWլuVкǟ<szKN@[{W44{N�!8endstream endobj 93 0 obj << /Filter /FlateDecode /Length 888 >> stream xU͎8"Jc)Yir 4èf ɾ>VHQ搈S(>/Si_퐿9i--&<wVVL $1(w`T#iNLUΑSqNQg8ơTk%⤹>K#܏@+2t.0YU~:&o  Қ3H=7AAS9Vx;~,F#&ɒ{wւ<o-KR4+>e\Q 뿳#V@ 9馹R2MkRMONZpL +2ĺ2צMگk?kS-PYKނCC<yL|_o(кA0YhEwDc"j9#clt<! /ێ俧aA@OXeѯ"XDԾc$D0[Yyùpˮq3z Iہ)J$msNшe" :A٧甸6`5WK`Rf!M<mY؍wa8KW@qW8v)4yޒG]E6 m*% L+*V0�: 4KatF"' 7(ệ$oij5w:T`,^sqPwa =4?y+˗-ԏ CE/7�}w+Z9\ADd6V?d*<trmEV~L ۧݵY #eVoyEmp)IEm-'43ǥi8h_&$'MyM   #>?,&endstream endobj 94 0 obj << /Filter /FlateDecode /Length 3645 >> stream xZKsܸS6U:bR,I�$lRlV41eZA~v #ۇ`_7:٧ *>^}JW;Y]]+uu;HF|$.'&wSG|Pn{s0: /Pc޹L$C\w7KytIT^L~${gMr%VՎ~0}/x\uAS?U i~YPռ7+5]=2ܨ{1i5j~a<̃t1yz}?я.-i~s@6w>na yͤ>c3x`jh,Ҫ7;,Y[4 mEgh#JTr F^`w crǰTչ١PG4AYdbL:oV/R V,0ioc-%(n1Klԩ*g<>JЉ5z\@߯wY{);u% ^:?.5U"⾭Ƙ T>!ݷlVfHC4 ZY gqZ%7 E50`@(�شG4ى~E1h|2ocDp3ځB~m sn8FѶĴ:Hv]*vl=z*lSfp"vzFi P/u6xu>]PN1IRu'u Ps3{6֣:d/C$t#7bo��)D1S:@jk)Y1%Ʒ/ `$ۯOHrӅ~WrYt�y <a e]d>LQxLfuE(LM<-SͦJC"K1Ym0VRVFܱCࢇ.o)Ŏa8s}b eZ{5m*9W\ TF_~ DD4qAWW'SNݙ(xH/la (lqjFLॣ<I%_%)U> #V0;g% }w:2WPv\Ao <Q>IM$T%Fc%to9!h]K(./l?|A?T5Ղښ=D`Ι}"�vN&fu~>X% \NU$ދ 2sOs ߠS0܎~l[/HF<J(If `\0|sd{K,J]N`'21r"!Va ( 5K9r ^j_-A5ǰ,H^9ni%._y2YTtB&nBCQg]XN FF[] mωK4Jy21>Y ބQ`;"J(%GFmj&UQf_ZbL-D~lV@Tn4�7�r7/]p*Y$nβ'5h;^҅8 B"Ȳ=v'RCIsF94H IZORb7JGI2]7MQnpEKDA/ܯ$#|Z"&ܵgwM߈:FBGMpL<w~H[&_+f%,j$FBB�߯~fGb7[�猼\+A'lTKe(Eٛ#_ 4}<#kqnzs&Ս 9v^nQ>U򭈛!b z%N ņ% ›Kڷ")ѧ)K�s}LW�3>M-[l_yƙ"`G )챐`n*Clօ~{ׁ%�Az<Z_س1 شi<v4{A+nEJp>Q*2X](vWa_#A)3ibb-c ym&^75zBl-<3(-K(PBrf KYH،fq^˲]unO-�˹H5Fo�]{ݿ�uTQi7V̀A-AQItH=9-ZvVu+fYpB,-"M0 WjxEQg: QV&ñl9M/�5q\Flue3ÐsCQ`̓EFziʋVp;ϒg60M{4l'F1T7ȅ'_UX@ٙy�T]tP6 2nn < T6Cs'xl=9_>)w֬եSJ41jW f, /&Y씞APgSo/4DE]pgY{uEueq>{>-еb2ՠ3dS)V h(,0W8QSPf~<uEmH!Q/*Maj/R,;Ώ䲞60؟Y?o2[-ga>W9i8IU|fwQw#Bidҷ*,򑳦~oѕ^{FzNy)24)woj :}i*cg`K=/R-8SMƁ^A\}s)~ 5W ѝpE]w�rߘٽ/d}EGP57qŻyʗM1"h+# )j(,Oxh\EǹAN.ID? Rύ?H Xy4\x]ohB3: E<8;vXzI8p3.=sTQ=a+=.sE]/gǔW&<3K9v;:lL-iq~RÏ|H6c8w&7ll.'RLեpBs&|PnMJDlȨ"MZG&"g(i#Н4+L\RFf.D'ˋyII_G#X >NߴM'055=Ot^&kII>eةq5@a˟\]; gΑ 7/ـ .!,uM:Mex0 ; εNz$겿'@U )c% K($Z&1)$ǹ<#x^FTIJr)BP~_}Ee6:1Cл&j9NݖxlJs8ҡKv } ~aou\O#3b3v3eӿ: sRO"wN,^:8ܺͅ8^:k302Er0M} aiFR~wT :j{Oã)jL(z{/ A&endstream endobj 95 0 obj << /Filter /FlateDecode /Length 303 >> stream x]An@ Ebn@;7&VU `"!޾NE~SϧsP~,S5 cM%i2梪C?I^ӵ?4gUCi6I6_hbf{Uo'ٺ݈'FTV<A<a/`hS-uxbD3%$K6v aDnEfExa0—ܙ̙T<@5}5 AvI6I $$C]M!.&0bBݱmZ_HeѼ}11O H +endstream endobj 96 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3829 >> stream xmW p_a!j8 @ӯ�ĹImI,KZ}c%YuXe;8$I'ʑ& R{JB:F~w bV&q59?[3S ♭w9Yp,{>O!232hUMUmScq5EՋrVǷA̯Y)goAseUDxB[mO*bXB<M!r)BG%ċeiʺ+K?kɬHy,1;ϾrWh9s{fܯ2xiS+mP *.f-gaK^N ~P5>!4m֎葨& 5r_R:P_4qySaJ bkr)Y!hvF:6vowK~{O-g̋(jGjJVIh~ +%*Oe{L+g>I[`q:p tœGb�.4ou ҉?% ൬  [5rGh"B?BGܛk�B.lBM_%r&-xXhvxh*1  < D\b;' B<vSᆚz GeϦAr+#6\6 Sdg'o`yVpcZjh ~TFB$HfB^W;Ir�R rD^m~Rf9{'im"l>Ђ/ CrrmЌh׬{.S3B. *q[ura [1$HpSGz'ՒM@+:FP󌓁 0 /u~կqwF,i<5FY_VyȞD2T<}_xv# _SgFO3H7OKY^r&3yk wE&4qW$ڮ@S?R9lF6:d7%(Auev@g:zBy؛hPnoi,%)b]f K#GF.'Ao-YJcZ"2jX||=|.+8pahQgw9óήϗOWn j&'YڪjcFWQ^Q,YRr@/Vr7qACuz FwˀE!=7V< @0~Fۭ_u)9zK,dk룺ɮ`0M-Ͻal 5 iЎ%}%JL6TnEXv_ JoPMA|qoFsSvɐ$8܎l%gǎ]%0Vd/"2_-#GӪ@aoQ8 &ۏE7|3T3%-jw-xMzrXjkn)X ,}؁!l!49[dJYڰe]vK,0>:v_]<6t{fy+7`H>[#9""c/]>w�di{d!]noyEڇ(XFz<b5͚ueHz{B?FŽJWb^Ch<p;d{zk 9/YRe^UClC/jX<w:#W֒�fI/K+ `ylKۅT@d�C;W?B 3'x^PDjsnȩZ' ; Ȧ/+25[\khon./3N-/:{x}iYJv@}\Xr r[; 'Dx˧>�&)X1ʪLbܗ>;S2wGh"DQڀfPg[$[me FA @KڬP8J7 ~8?Kk� n^h~+ $ndm!+`Z}#C?/f͌ ۊQsۯnB-|iN3Vb}X "!Z�86y'7(e/׼RPݼXtB?!;` }NOn=jOqE) O-MݣHHYU6 mqr08`t_蠘b3%8خ؉ITx3C42XΖQy+(` wąc _Zӂ-*pRV3P\,Sô + 0y9zȉh'֛ [@ſŏ R8!*@ NģCp-]qseAu[ ,;Ϯ\?wxxjc,cX- dxl44*|xOU}0PS?<R Uh2<>D@ zXO@qSpBݬ@{Pc;= nm $z:@IڧuisEK,L){ksW!9<Vl09†p,;о@8:'a\.<6woEqyM tqw?ys/zgKt}m)C/{nM?w”pA7vkuR v /E&-+'K&#;2:|X׼f8[/qk[mFՍ1oi6Z"@wQ n/E;:Q>QO\)Oxz5޸ʟJ DzU?[>[Ԟ\[d-lZ--]0UOF5HB\ ަ¾Vci64k`t lH1*l3WujlGG"c'cb'CCa8 ƴRWQ).z.w9wwS7v|>I7 |_&dTf/`.P~iN<?>6Et(k~MuD@ </z@T5|-|agf3D HF]rNyI2:p?8pMolm[~)koԼnf`lgB㮩~Tt)71)^ ]_fљ,lx,oDZeRZU52ФZ@^_@݋TcF5qSҼ{Uo;L9zu@ !Ӈ~v֥CR [};vS:~J3bOeejvtP.Lju @YUAk-o߫yLzRoH}@"V6Msq Jc OCuxCK MJA.=$t.R?5~I J+(juo+"Qy2Ukϼ<v{rVS]e] &rꃉaֵa 4̥fgϹ !endstream endobj 97 0 obj << /Filter /FlateDecode /Length 285 >> stream x]1n0 EwB7XTZ%C<D6gI':|x>W;Ny(|%uʦn0IZӭ_Lu|- <n߸]P/}+ι؍c4v2> GsQ**`lwQ*Uۨ@BW$ mH["IͤfU@/ ¼3LcTq."P $( $hPAA>{};KN^+Q U}Lv̋Lendstream endobj 98 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2237 >> stream x]T{TT?afP&HgXR733I>4yY�3"037/桄 8�8 !XhV^Re2 k9g2! ˲aI+,Y|  M<5F D0-1',/_`BX&^U./SļVŬTd$j˔E?dFZW*뷧,{a0kǙuL l`3+ML$1טt&2L0* !!E'Cׄ,,$|\"~/d2f`7‡ߙ?[&7}52E+^:^_ ׈fD̐\}gZ2Ozz]ķ4If#1I9O|{.֋t#'BW ]F]YxYCygǀG0.9]93 OxEk<pt:= %1_[[ϞnÛ-\)œPBvKLǸ{Y/3'1dd,}8 PA?vj1,];ry (ӷpN\z8F'ܼ̌7K߄aQWW[?5~'76ϟzo4T Klm#Gq7骵j~vq4~ hC%Aw5˧|o)kF |1igI8ɡ8%tArv{&?J$J2C|XȀ̎c&zb; o4U5X'̾@{}qOy>JzkG֭z_w!Ʊ[*ڮpĻa;ό%8Zз^nSc}M2kwTMZi4WI-%O4W53;a-+n=Wc4Ui8F#Zk{os;&t4o5PpF_ .!{QAc"*m@pqgG}w_I\ UB*unt.%~:FoE L0"QޅK9G D8`3Ks3Ѹ|XRVaPՋCErZL o{s%pYuy4qL#K0~cpk2^qiH`C4y1}x#7 CqG(U\X(tx:;5Z<WЇb/y%>~\O*J* ɭ t/y5ew/h:m5-wBd My/Y[:O֯uB?X'S V^ҿDی.=P[g2R}4z& K &s:{\JfI=u`r4#9tl?܍k=hmz6 F'qx/{k,ٽQ$"EtPZz&ɑ4Ҝ#oolTpuιx낗:\zK_'тnW步5_uc0w z 'ԝ jA4(Ojm ]Fml؝)c}\*=WM\ȕǏL6:ddPoKWC"d}\e\`H&0̓˻.RO"|exNlsEf8]R)OR'A'؟}+{yyb窵|ͰKA<0h=#E+2Dq^G~}XH Ȓ|}<HG_<]U La*Wlo4?k;?=<U%r}ϖVE oC>3K(Mo AVv D 2%17qNzAJN')z`! 6Ȥ_o*q0rG=Y``n A$2ֈ}ۈ{}G?cm"O >+Z9 B'bC8[Aez޾?y rG j? wP 7"0Og. qUZMO-YcXd(=31EH<džۄڼqrK]̊X~]r"Rbfސ P*x_,LpM#?}Ԙ_{WO՞Ç,06qendstream endobj 99 0 obj << /Filter /FlateDecode /Length 3663 >> stream xZKܶoaKa E�IJUNvT΁h.%r֒*~�dC$n4~.$Lw7EFo/뫋/4gm~y!e&)S}yus5LRKuf,I\á鱝&{ZSJNKMtN]x^p42U=[}{jMS3To:8WSzM#iU4 Ҫ];4W]d&1.zqϪ%â"4:{Z1O FAccs3$E^EW&ֺ5l܏ݩyRyU֯]{9t0V]d zѸ/U>4+/ոTDx c+9М0~ VߐTmwZO+7qZu}{MF%KذHBkŏ_)# $E}Qԇ3u<)zCvWG8�º; >R? J6[c){;R9Nlsy}C]fpch0P.|QrlCYa| ȡivmrvO׬loWQkO5̨6҈֒nC1M݀A3% ? A73 CVA)i͡H:Z~K~l,٨&FzE_Xz*\ˮsxa@w–0.vv.h!zh >QDq,e\?o*# XK )ׂ=}+:IH;$P. {||^[وhU.�(5Ῠ~xf�,\`tN6ˆeEz ^4bl-C0"�KQ {9j`Uxje qU\8|'5x퇃?"`ShC^kD`1+>9X<tcH= s:YO$#ÜUzDv?gDCx43Wu{#YF~y3lbQkQUY mD!賠_Sj+[ 3eg#c>`F=։,؋.R'Lx*sYn_^4B¨N1V}JJ&QߴS{@,4 f%>z Px")8mкyˌW7r^"`o 'b%�A Jh$&̋Y~T/y0?j{D!liK)jSA4R>0;|zwü0y/rBewHW^fjtV<�`96G4EE-\E t e!wxOPdN}<6S> |w:bw݄)In3Wjj>Qo<9E2@(3fzb|�]wMK7-?GY2s߷[-O|+#AXt .}}nˠ]yV%U5ӮaJzsI4dz(JtUs'u{:~y~ 27L9W%qf^KVwFl,mC[ 4~n o9G{b"*sC&VP]T V#ѮЬ=(:TgdY5sBcTٕ9Mǂ 3xCR{= d4מ%*dQ#<<ZAXaݵc"zGx5c<3IwɮRIɁ{Q`%Och=a7mu,GF B=6r۝/(0u Zîhvh;ݩoK; Veb?:[/CL%ǀ'N:!ߞqmGnsW$Y@# 9N& sSZO|8q Cs+a[.))G=a_E$O8Bֵ *zzh\HLQ14! (X<rfg^RWY�BoZՂFU)* eI3RLd)Uc1FMTIP)P]UeDpC{ i:R1oެBYd KtA(<'B6U;è7>!FG\X^pOd .\PҼlj0Ir,N0Fж6)t>ר56"K˔ 4YX[Hm,J{<'E $;}}ӼGgz)G3Cׇ9*6@3ϔKAyC�z%R1w b8(8Jqu')~).?>q̯C(w˖uu|_!q\\['p>8sMs#05(mrKݲ=s8,":\fgrA ~l6|,|H2<hy/، ZтeRӊ]KD l] _R=kP0GQMT?ѽڰpBam 2#C-N; RhL)a\zP:.+,])]_pZpSsC*Ө_)v8kX1鈕YCy”W*Z{c1~Bv 5Z/{{l1LtpE{qAcTW4y"c @pdfD˜'|3QPj%߂'la#pƕdx䑂5>qfV`DAVC|WZhӂ^n_2E\&q8.A҅G09lw+KfW<C:?6TA#r:VhE/Y?!L7_i2Ks3E^`eu։d1Wґ|LAd{B93! +n,F@dA|?EuQ\:ސ-QEI`� [WUѷ!|Mr7?,b_'wjaQt,>]8W,ssQF83Påb.U-*oϟ~/Lh:gϠz~1W번ӪxOx_l~TQ*QlKtl]x*VF;/U^=ӭOH֋Q#w>B 2ExyW}D^p3DT@@_Xgxެ:p-9~.$rJ*(.⛫ߊbendstream endobj 100 0 obj << /Filter /FlateDecode /Length 425 >> stream x]n0w=-�tРhD" 3{wN:t8'J_ǧOrk?yY]Mwle}:5c-_?KuT߶aR9si:_\WߊWڇb>bVٹXL?J+-wN=iWShO}h{\,,bB{Ug%{bюSh'̳RJ 5jdVȮU#Bvkd�i`"D!|0NT8JSd(Ld B"KVYa^.ʠ+/R'>iiD! M(D 4aQ&L"(mȒ&L" ҄j.P#av|Gx5Z4uW-kendstream endobj 101 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4923 >> stream xX teR̀lh9 .ȢE<ZXR i$}K$M~L>( Vg]/{>%{===ɠ222-iS| ӊ^ʂ#2ሡr{~4yc!y++-UIǿ\Hm|P^+pGV6/VV-+T[$yC%Jl)ܺtcO<&PPKRK2jz* ) U9j59zzzzO=AS ԓ")ejNP,5O=JhTFa!9D[Cˇ=+A<4 a}<">rȏGIGntoT{L8$cǎ!CdԨo rL"9AA,4L 4p\gPl8ves}rʋVYhu7Yehf 52(-"<u#ZY*sMV U 4:ү|Gn6[F%G<t7|lbe";&-Gs bTqOAS#*tA0< O8*4]bg-qdVXN-<xjpn.?U7mR@&2Qt&M.pOǣf{~#AP@:w?ʻO>;|w7kH$䇒M]E@�]f/ysQn�eNa'L l*uzq8�Llj^2퍡EO!ޢu\@L_LDcվ{2;I/Lwށ ^Gw0<W˷Ȏ%gWy2/I <L|p'YjnտH<I}<&a IγJG+r!zg,C�%Y'D7L PM7~%fr"ci$Z0'%XZHˍz`w!/ QQS`֩rNJ^*d0CxC04ľ}<'Y[L_'ƻDh}¦=NZAt[hy:\%S8}ېRa{SN1*YZc5RA*Cttbis 'XH-AKHx56mHt?v7e,y2^BY;?}0d[(!9%փYjYRn2>KnJWK:9+b ` uD!WƳ6jΛam]a[tX Ə.vo]\Ɋ-m(Kmll%MQ{taM92T�j@ې$WCuZ*֜:.ث3 ~+ NUMb)Zϖ>a}hnɁ\FCZ?R(?k)s{ 67kv;:m95zѠF6:6B<\w^Mg,r5[6BVqjmUtI&Fч[!F+2У<TP7(SKO}sB*JК83]|Rh8>[Tfpcy<]*h]z-hfaQ_XF2J1*ȳ4�r0vZ+CjTe -0~p;b枤 kz3!<&Un2`rx.F=[]RSv0 p,TT ý= pIH)FzWF5A7Wp0u?7�[mpZ4xdws'M TE[CTWPLH"hfnFtLK92x<~MZeT^}KS n'G&2NJ\\ǶF.x](1cu77庋5 :v;\]]L�ļ͑%HPEZLJz}d},:%, KeuiuF0 B!="<.טeJ1U*%E x==j!ez{8�O!u2ۭmy$F6!#2M$4y4*.URET-Xl6h1d:Z~M F~{i qX 'RbjQ'/W'b3i #J<Vѵp䲹K=2^~,;Y y`π]"l�Եvy7u^F{<n[DFSIHȷ#d9jXfQǢI'a6 :A%pNڙ!ÕH[z m@i MoK!j ܙ;9Vk5晀\Z_Ƴߨ<(+rYR}t=iIlˠ>4CHT7U6ʚA_-IS%M5 zbJ|7"NA/b,ew2hQ2A8".4nϏ{Pr0"1EX1-Yd( &>Q(&1lTT IuZ#%U ]=?;䬆&X[_k)|j:x\E$)֥2RQ [W/.y+^+B3уN\^/U9ե6`5p\x Έ!G1du"\/:\(t $0jBD 5Mr [RX+l*/xsfE 솎M@Bcm74ݳ�0Ĩ- Xop||قzCj0jbXեҏ=[)d Bg$hMPD%FHx&]Ե%D&<j.15~�E = ;w޴6kq컣 mu2 jO7T&1Q[/ŧ$¥PoCSLG>?cc<VHP-{VLoxtLa%]Υ$eUUiΆsNU_fl%M>෰vEeg{^CD6OSu>q&�116dFEUgR>N` yh ), mD∐=z YS7 =+a͞d.bO T=A~$uD"O �h+ݴjD>I Aʩ1 F,./k^W?#Hޝ)SٯaM|Y~&˻w@t R,4m6Pϣ E D']hT{ T2yML52IdjPEg/1)^=E;@p)}2_}1>ʿZް*>y<ѕz86O}2 a2OjRj.UqE;ׄT<$RxyxTڭ�`~)5gn�ZǓh[iuuFn'"9M^nGR% wô KʣA~Wɔ:.`M0O$P9܍̵jqu1tqat";9~nB#R5ո y ˗H<<UBk U)·#*]dJ;Ԧ @� ک6诊C7!hL$X,VhIAS>AgYtڲ61%Xʽ�4BM@]Ɣ]GZKSU 8@jz;CHQG]4q RFɜ2@Xg|*XU#ӭ+Xԧ{&[R'bhZ5A3+?AѺ8|RF?*y}Yw9>y2q2� b*0Ş.8.KM%bj^u/+#5A^cnTN9Ϊn2%]6z|ڍ:v 7F.5ã W3DI[à$:ȶ^_ыƤ~19A]pSsӓ!,׺Sft`kFX1Q}j/x4>a` ePAB35?-}gmX[U)V6p&y.-LP7wik` fVS*UuP X;ÀAîgt } bƣ*RvYoq4"Ev%Z'A)*]c;%;Zw$g, f.¥fZUڧ r @Z\ġW_kN5`PCk*jH>؟|[{Ǐ_0h c걉U-qopfFv~1hx > %m`id2A S r ~;Ԅ+uM9wO!G">s?:D35d^O qeHO NqhED<Zh<yhșL$M]r8eb8bLehhhuLWW^_NcTmh'Vfڙ{;~ d~9S\ݍ{(%FD`=?3bE Sendstream endobj 102 0 obj << /Filter /FlateDecode /Length 591 >> stream x]n@D{}@vokE PPa""[ľ7Geܺ:jn,ޯغs{,ñ.39 nmXY[omЛt4^cۆ>sݵe_qq?z<VMhUh^5P5A<1U808V 8U ت1UGD<T &ߤ`T0 V0F #lLFF#hd1 6&#dd42ؘF^bv2;x]Nfu1;.f'@\<Ku1;.f'dv𺘝^X{os!sos!sos!sos!s΢{ -*\(&TNТТТТ@1rDV b2PW= v8q;P[`uBP!P[`uQo~SM&L| הo7M&\SI߄k7雰I%6)Q&e4JؤF ,n.nضtMsYڿl|*2endstream endobj 103 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 9225 >> stream xzUw0Յǭ#"$d�g:Pշ:<0D I@]E]ӮէkuoV M9p_ 4hАes-?ᡇU(pGFPiA)88pỷ7au kM#\T7bai?jW͙Q7~V9MsO^@Sr 7V-ݴlgjj cƮ~pC '=ȝ5)M6 awa%=R^lv{{`+YXl%6{[as'<Il"6 =-bc7`7bStflv 6b_a2V6cد1 !\ALa׽Yb09)|<DC#~}ë7niЅC9;L:[wW_ 9,|{߻c֯_i*MFG9t{k]{߻2w?x:6ݻ^ R ߟp68l?,)BIi2XUT [)@/K>_KFtoNSV GDz@'9$n>0_HxIafתrpMܔ=ph&mi(TP:c̡4[݁n #-} &ʂL�}PKMFJ0)�Z]e#YWpPj[GV@҆nwwyO)_ĽIOO%L?wvW % ҞvOtsBgU*OHX8DUi'eܺ蹗TkRC{sbȜNTϾ2쬓,@Wմf_@A]cHjGktű1BR~i{)WZeҖW7gl;KA$J5sX  ɼ)OO;HO q\CMK=9mp}p{}~/ d0J_PJa�B|{yl yԧͅO-v�A=[H\IQ(ۼm]f ! S8/.Kz xbObªo?Sov( >NZv$۽On/oOōA#&B^kϡL=s6^TwP z%l1T6<лqSj0D?jCd \*h\jntVe[x;/GZ@fa>qXT: u!?m僓W7{gX`ZNjf_Fr`3E4rW=H96N 'up2a9i-+>I" ÿaA6KxJE_ %;wK Î\4 #I֙�7�#` DYBG]iTL۞d zz5IE-ѼImڿX) dv?$^;Һs' Y+]2+rTzO~_?ߵp9zI%Š^j#Qf]A2pjG`ef>æmޖqAZ5).g'.-ᜍ+!OS|Ud'@,eicB1C7XBTٛPnК૞'Be^+n ܄pE㶕+F(5SҋjZ] s' $ڀJqQ]5: Vj 64MY6EeH`y.Cʹ0.[cxTHן>85 |[2By%Ξj0 ,YH'`C/3(䬞ӳyW#9gr�ƭV¦8GGtۖ6!ByWb<-(%⥼o'j*F %܁_#Q 167S08bL�%p*pI:+]Zh`O{OK~2^50R�{vÅvFbIA,K"c6ڨ J70nmӹqMͅ �9 Bnw5�$euZ̉p{*pͪUÛQk⌜$i]]O|?0F6*k4VSTް!=!N=mep*To{{ha-wG%5Z>=({jD9_ĒObM-m5LzWM!Iù.1.`@MeY]w#.WU}&\ak+<YG\ _T 5lto!^1@dLEi_ qiݎzMTIK7 J88yH0OXve9}@mp-4ژ%6@_%rN@+fNMr&'1/wR6lSgp?@�D&ɦa-"5'GA14` A}(eEJ(c>;TҩR 8i_nTS߸ѼJ~ ;H]nB_Y^R3p Z"m\;i#2kVXy<f!WP Z s6<BxhwO`I +dv%a6qK?9#H( 7򞌷XD 7 +넲־kw ?I<+7ǑCCC3'A3D5LڣL3hOp0Af ƮY=t\(r [^]SSQ{,} ݂lhuƑ~@! owx_`)#BgxVM3 r###c$uQFH}`^J":T=*r| l>ʼ}Ujs<*$͆7EFyWO<vs0 e.ެSM M &A GFVڛhMBIsEC IE7hKT+Lk(Lfw=zbiZkSZ 9vRۮж31 /-IDX{`GэP%i\bYt;rI<gsҙ2rYgj#c3FAS@6Cz!=YRtnꕍAWy:[=V p=7!ɇnXY[K^ n1w>7L<1ש "4O ߳(~f,BB`P"I,YٔP|pm['HDAH'M hN"9#o Ѐ OO'{' xe+har=V*nhHUoaw_IxL yC x%7+Q8샽|h`Kڧť"V& -=JY(YㅹO nݛBJzx{A[imxmjFbFf3F8+CD2mACwZash;xUʈ=뤹S=/� FaP [ 䓩?ynˉ?mf~]m,u?]QdA֕eGE;n(׳e–>H:c PC}XЃG)sv] z8uy{;E1>FqNˢkHGF+>vT*iK}~?H $[CUKraHҺeMKVpH�g[[OA p..28޼pB}.c2,e»B^o[@s&jKR!H|[<!>J!֚$g j׃`@Վns;?{t<mD7PHlDMlVMԒSߗۻ^Z"(F ͏A#'VCG)@$C9zuy+UnU\FCfs*AЪ[hYy^k6�bNۯ{}嬋,O4Sh1C"'YIp7|eגMQ./nv_h$1{,+,N#a3?ZֳkfuL:ZIor2^.~Aߤ}ڃJ_>8,yu`7�W{m7|%!*-O'A.vEA$~!TT}cuv}D2!o}O�ѻbh.gx.R NTn5HNZ9- Dw&(AL"kh9_kNlq_ Da@4Te Z7烹MՋM *I6@܏+EV7 O/b MavbHyqYNے4t.0O2J4ZJoJVTn+B/^e !QȊb!+> 5+O|�yNǏ;moY-suFT2=zƫkigv%Fd95@mPrS`HboxD%T!:z`vD["ڍj$e8$>K#ͤv%ȭRuƘȤYHݱ1QSAHu\QL�bS.ooGN" dˈ e+.Deeky7(~ѺTώp}syCv+z&$6IQS/cLfOf@U1iZYGF7gj'Zr@}°~?�<S8~KgM{2|%h zmրմ m/;WST2r0Z3=1O 6ݮ4!G޹^H sq,F%g%:e�(xȹE_\nP9T@uUQIU88H1))RRDq:#پ>0E c:FyqqԪFVKqULX[E oLj՜$MK{.<VuZNI?!_;cBۙ8txnYtti+=[xs;YTJm4N (.EjT&N〷,e -5*b9@9mĬ>U'yG u5`3Z&31zۻ!> BtƧnTBU2]olkePpz'ɆN%p4 ׮ @QeDפ-|˾J9ugg39;wt{Q5{0)a<fZibOWQKzEiRtugwI߬(εhµ A,#d.å\-,Q%q›ĉiNr$;tKEտ]SWn7ѡ`V.P$l.>)R/ᢉ_2xs8iyQG59W&\#clDh@X< 6l%ϗ&6mh~/qiC�qy8K=Y/Z`ڢo:V{"F-m[[2�Ah b5gv}ƃP=1k+ݍ q@oKDŁFW< U,\ScȌ?"jGm0k)Ç_}Boa7nG C!,E8o2Z;q[QS+<A8~~cz@8r.ãlY:v* å=EGD4!@DcI瀀@*"+Dg.U(`aXs1M_@G}H89y (+kW{UBh*cИ`lk?ruf5FJ$)i&x&Φ,9s_/"5JTWAY4.TDc+I),N`?<BJm t4vPuhٺ5n2Q6Z}*JX?{C8.Ʉ v>�FIЉjS (1lJH<c�])iO\*ʥ X,Dr>ٔmȘƘMp4Cӗֆ!{QI,nq<X46Lt<Gik aW:|% tT-fL9`sYVW摄y=}#t�Q[Lc0ZfjJQ!$b显ҳAjP+^ m~&µrg<kGcn3U*{}V qstw7›IBx.ʶ5{0C;|u;# STpZ$qj\3F X2 (|`}.TXHPbulN@$Dܚq&hƴ.+/,+I[B 8r QBzz(+nc8p*ZסS*ū7^ ݙ YHFB6Pn$E<-p rqbcXFa2#S geNW[tUڍ:�=RX{r{ҼJ<l&Ř7{$f7A6n 11o"ymBwp$,ճ KZ[;ڷxE jnGYŖ_BJ*B0B4J#P�ϹíWG K&!)"Ƹ》6_ SOe wv Au'`�1O}YFV L1*J@̨{QX2'(fe?yT` <!F2D:m22 N+P?~s͝UR? 0*q=`.ZvYtN8H2FšnUxrgi!C&~fK䭂F欶mvT?'%LMěM&qhq '+z< SMO˅5;Gı!hP4FjZijc!�6!gZ/䷦rW䇂''e|C{D@8#^1`>?PR!{i^U=uS{zSUAӜO·W+a!mH#{VmY]_= oıȚM ^WM4?1Æתڨ9wF?) #`k>x`8ȈfW;e/f.G< ğ(1,):gs`M!lh;@SMĵ5]x~"; ,Ѥ3l0QQ=fv聁h賹t qhXw"k m9Y%[jNcsG'y BoEaO%U[ ,^:<}U+8MfyEW٥CBGx6Kad2ۼ}ۈRh42GTܷͿݿm?LYL/4(z'"7h iԙtP O@LhQ?m-!uEq ,x0p0xпS< !?pD2J^K )|`j^2\6|-:["̲QNpn=xIAjҪMc^Ba]~5YI8Œ %pBT,+,b�cYqd)5v~IbA9Z 0AG(7v(2c&+Aeecų?$w_#k"[Jx O6FNa_b[l[ⲲVp9o2>mcH_ޏڻ4ӤT9aƭ5?i[b83}6>xt9]Js`CA zSC8r/zM sΨ_g(oC΄/s}$ ?g :8ۻH 2֣sjf+^>G~q13gpE ‰h9uŲqJoQ"Ƭ> nyAEP/UV^{pKwh-*ſ` |oR& o_Ń%|I ģ"P!v,PCаe&oq<ۜBlA|pdJ2%8(/fjFPC]]<_Ws"?+\"ARӞӷI]R`ևO#e id O8֍Xfu_fX2e&wjrs V! t6vU$zۻ]oa6&8Kaf'M{j;7Ra Sg[&V xwDV0z`>M`Yxe UD[{ODKȫ2B_,HNW%;}oHY0^ _y$)* mIoMmI}ul[cpg�$uQ:,ہ"֨uG3 t9Q&fJ 9KS&9D 8~xY-N ,9[Ƣɸ%W,@hW3\!+_}F SY֨j,7.0jn%43@jH&ad!q^hQGJӎN=n[f:ɠWmq36ei#|p9a>WRXlU<-#9 G~1#lآHF#>h яo | B2Z"ahY$sQPחD8/^yendstream endobj 104 0 obj << /Filter /FlateDecode /Length 3037 >> stream xZKܶ=7t$Z $RaSeˑRf\9d*YњY9%t7�3~RW+F+ޯzuc2_mWf [,WifdX_gi&E}7ZvyYJ$d2ͤJOEŸo~1JpW7pw7V=7 +`AVW3Ye98J2p5+^%}@qHxgWQ}vQk&]TvedO3WEGݝhbzEDL&oY~0t-|2Jp9Ouɠ|WZ';&4c,RJ'`fIq;%I;~d4{%( olw9 vi&@ v?=&@%�j) ["XRw?èJ/wu&Kg!T\'�|^$! ~iL,oZrBLlgwɗFlNn]LA'p؞oDžv: G)W yI1Cp ^e]Ge<.cy og]x7$K .o!7Xφ7ɺ\zu 8yv<f<ykwo7|R0Jʓ*{~hjOvqi+i$F"4p tzp?/ IߍBڼy݈XNS]hIpuu6] $ͽ5cv$nnolړLOpkjDn6pe_ O 3/k `)}kgHeɐ)QexRԥtad#2wLj!V[2#1{ށ~Jߊ{@kiWȀ,fp⥮zfP d5d,�oF FxnMw8?yv\ ·_ ?2 Ix}chpy;|2(op^"NA|{D)2Dc@~88Љ ʡ<-3WףKEQ (W!;�Y?rs! 6'u>Ò* +F|X,4yo*} 8QO yhv'%>JГI耐CȀ =n+~_qq\R0 6 CtڶC}\Ҙ&#fds#uK>u}S%jaβ|2 %pL &&,H5W�r�V&UGL &!e9hzs7lTڄEGA8p ?R'xVHJٖ>fámgxHsrVU>=]OsLq"mZ֌8̌b*n N?渠` *%$kGۨ{lи Z0~5#%=xmkVQ 5P’/SUJ'/(O,O9'G/KlMIe~/g>�eKk&#!N7#YvKp2?_8Vp6jų*E%%Hp;gQ\ -7WM=ooT:Zr&ӼdyGB2 vMUg|$ n$0߶dѼ$x+Z�\o~>&P@G2╦}.t@!0s= \AKD%_Uwkk_m&M7b܉�7 -|d, $6ôڋD&c9;PJ8]0cH&#!5Hd ?0Z$a8$`LN-lj|0T3y\@9} &1v;sV GS59DG&,9hf `=.@<WT7ڹǕhWh!r FYDoz~9gPd[ @\$ e閴#RP,hkxN"(֍HNKpMoL2WPa_€*B+_FZP5`4brmpa:ٸ~ Ў�0`Fhmͩ>GR8,[ml3_ H( 咔XTJ$Q7EK27EM1{!G`hRRC. 1Ni=ƺ@(`13󼵄Mg 8z"Z&V\zZd$hT44+}A٦B+)+!o01Ac8j%%(~Dh{^콑%KJGhДaW͊&ce3 nbsckXϬ P?;UFNp2YM<Dw)_$X8&�}A܏ YrC"8.y<-)I-,- I Qd6,e\E0 ]?{rX$6%'a7 Diyc?Ņ$[]0pכG{ mh>(�}%ЊBqo7.Iilz B)K0P BLq:^۟xe[z�#1 2&}H<H6z4h\&|:v of u 25٠!ekR>敓qPn:( `M^b'adh8!oK,�‚|bkK %i׿ESyp-}NT2 beW@瓥TY!ݻ+sZ*˹>"K9^L$bƾ �Dfs7/ݺ<endstream endobj 105 0 obj << /Type /XRef /Length 142 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Info 3 0 R /Root 2 0 R /Size 106 /ID [<61441ba01d647405665314ea0b072bea><b9fa4c66b3be49a7cc1bf19b938f85f6>] >> stream xcb�&F~0 $8Jj?]@6P|I0Ds@$3`k i.�H+ yT} &@$6r9`T@XMH^u�3 endstream endobj startxref 85008 %%EOF ��������������������������������������������������������������������������������RUnit/inst/doc/RUnit.R������������������������������������������������������������������������������0000644�0001751�0000144�00000004415�15024242132�014236� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������### R code from vignette source 'RUnit.Rnw' ################################################### ### code chunk number 1: RUnit.Rnw:251-292 (eval = FALSE) ################################################### ## library(RUnit) ## ## ## define sample functions to be tested ## foo <- function(x) { ## x <- x*x ## x <- 2*x ## return(x) ## } ## test.foo <- function() { ## ## checkTrue(is.numeric(foo(1:10))) ## checkEquals(length(foo(1:10)), 10) ## checkEqualsNumeric(foo(1), 2) ## } ## ## bar <- function(x, y=NULL) { ## ## if (is.null(y)) { ## y <- x ## } ## ## if (all(y > 100)) { ## ## subtract 100 ## y <- y - 100 ## } ## ## res <- x^y ## return(res) ## } ## ## track <- tracker(); ## initialize a tracking "object" ## track$init(); ## initialize the tracker ## a <- 1:10 ## d <- seq(0,1,0.1) ## ## resFoo <- inspect(foo(a), track=track); ## execute the test function and track ## resBar <- inspect(bar(d), track=track); ## execute the test function and track ## ## resTrack <- track$getTrackInfo(); ## get the result of Code Inspector (a list) ## ## printHTML(resTrack, baseDir=tempdir()) ; ## create HTML sites ################################################### ### code chunk number 2: RUnit.Rnw:312-321 (eval = FALSE) ################################################### ## foo <- function(x) ## { ## y <- 0 ## for(i in 1:x) ## { ## y <- y + x ## } ## return(y) ## } ################################################### ### code chunk number 3: RUnit.Rnw:324-337 (eval = FALSE) ################################################### ## foo.mod <- function(x) ## { ## track$bp(1) ; ## y <- 0 ## track$bp(2); ## for(i in 1:x) ## { ## track$bp(4) ; ## y <- y +x ## } ## track$bp(6); ## return(y) ## } ################################################### ### code chunk number 4: RUnit.Rnw:342-345 (eval = FALSE) ################################################### ## if(any(a==1)) { ## print("do TRUE") ## } else print ("do FALSE"); ################################################### ### code chunk number 5: RUnit.Rnw:348-355 (eval = FALSE) ################################################### ## if(any(a==1)) { ## track$bp(2); ## print("do TRUE") ## }else{ ## track$bp(3); ## print("do FALSE"); ## } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/�������������������������������������������������������������������������������0000755�0001751�0000144�00000000000�14563457515�014327� 5����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitJUnitProtocol.r�����������������������������������������������������������0000644�0001751�0000144�00000004017�13267374743�020352� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA cat("\n\nRUnit test cases for 'printJUnitProtocol' function\n\n") testRUnit.printJUnitProtocol <- function() { ## copy baseenv() logger tmp <- get(".testLogger", envir = RUnitEnv) testCaseDir <- file.path(system.file(package="RUnit"), "examples") testSuiteInternal <- defineTestSuite("RUnit Self Test", testCaseDir, "correctTestCase.r") testData2 <- runTestSuite(testSuiteInternal, useOwnErrorHandler=FALSE) timeStamp <- format(Sys.time(), "%y%m%d-%H%M") testProtocolFile <- file.path(tempdir(), paste(timeStamp, "test_printJUnitProtocol.xml", sep="_")) ret <- printJUnitProtocol(testData2, fileName=testProtocolFile) assign(".testLogger", tmp, envir = RUnitEnv) checkTrue( file.exists(testProtocolFile)) ## input argument error handling ## missing 'testData' object checkException(printJUnitProtocol()) ## wrong class checkException(printJUnitProtocol("dummy")) ## fileName arg errors testData <- list() class(testData) <- "RUnitTestData" ## wrong type checkException(printJUnitProtocol(testData, fileName=numeric(1))) ## wrong length checkException(printJUnitProtocol(testData, fileName=character(0))) checkException(printJUnitProtocol(testData, fileName=character(2))) } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitRUnit.r�������������������������������������������������������������������0000644�0001751�0000144�00000052531�14563457515�016643� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## $Id$ cat("\n\nRUnit test cases for 'RUnit:check' functions\n\n") testRUnit.checkEquals <- function() { ##@bdescr ## test case for function checkEquals of class: none ##@edescr ## integer x <- 1:10 checkEquals(x, x) ## return value checkTrue( checkEquals(x, x)) namedInt <- 1:10 names(namedInt) <- letters[namedInt] checkEquals(namedInt, namedInt) checkEquals(namedInt, x, checkNames=FALSE) ## numeric checkEquals(pi, pi) y <- 1/0 checkEquals(Inf, y) checkEquals(y, Inf) y <- log(-1) checkEquals(NaN, y) checkEquals(rep(NaN, 23), rep(y, 23)) checkEquals(9, 9.0) checkEquals(NA, NA) checkEquals(rep(NA, 14), rep(NA, 14)) checkEquals( numeric(1), numeric(1)) checkEquals( 0.01, 0.02, tolerance=0.01) tmp <- c(0.01, NA, 0.02, Inf, -Inf, NaN, 1.0) checkEquals( tmp, tmp, tolerance=0.01) ## complex checkEquals(complex(0), complex(0)) checkEquals(complex(2), complex(2)) checkEquals(complex(2, imaginary=1), complex(2, imaginary=1)) ## character checkEquals( character(1), character(1)) checkEquals( letters, letters) ## matrix checkEquals( matrix(1, 3,5), matrix(1, 3,5)) checkEquals( matrix(1, 50000,5), matrix(1, 50000,5), "large matrix not identified as equal") ## language checkEquals( expression(2), expression(2)) checkEquals( call("mean", "median"), call("mean", "median")) ## formula simpleForm <- x ~ 1 checkEquals( simpleForm, simpleForm, "simple formula not identified as equal") compForm <- y ~ x + y + x*y + offset(x) checkEquals( compForm, compForm, "formula not identified as equal") ## factor alphaFac <- factor(letters) checkEquals( alphaFac, alphaFac, "factor not identified as equal") ## list checkEquals( list(100), list(100)) checkEquals( list(100), list(100), tolerance=1) alphaList <- seq_along(letters) names(alphaList) <- letters checkEquals( alphaList, alphaList) checkEquals( alphaList, alphaList, checkNames=FALSE) ## nested list with NA, NaN, Inf nl <- list(a=list(1), b=list(1:4), c=list(ab=1, bc=list(list(2), list(NA), list(NaN)) ), d=list(m1=matrix(NA, 2,3), m2=matrix(1+1i, 4,5)), e=list(e1=NaN, e2=list(Inf), e3=list(a=Inf, b=-Inf, c=NaN, d=-0/0))) checkEquals(nl, nl) ## example from ?glm counts <- c(18,17,15,20,10,20,25,13,12) outcome <- gl(3,1,9) treatment <- gl(3,3) lmFit <- glm(counts ~ outcome + treatment, family=poisson()) checkEquals( lmFit, lmFit, checkNames=FALSE) checkEquals( lmFit, lmFit) lmFitUnnamed <- lmFit names(lmFitUnnamed) <- NULL checkEquals( lmFit, lmFitUnnamed, checkNames=FALSE) ## POSIXct sysTime <- as.POSIXct(Sys.time()) checkEquals( sysTime, sysTime) ## raw checkEquals( raw(14), raw(14)) namedRaw <- as.raw(1:14) names(namedRaw) <- letters[1:14] checkEquals( namedRaw, namedRaw) ## formula a <- 1:10 f <- gl(2,5) checkEquals( a~f, a~f) ## S4 objects if (identical(TRUE, require(methods))) { setClass("track1", representation(x="numeric", y="numeric"), where=.GlobalEnv) on.exit(removeClass("track1", where=.GlobalEnv)) s4Obj <- try(new("track1")) s4Obj@x <- 1:10 s4Obj@y <- 10:1 checkEquals( s4Obj, s4Obj) ## S4 class containing S4 class slot setClass("trackPair", representation(trackx = "track1", tracky = "track1"), where=.GlobalEnv) on.exit(removeClass("trackPair", where=.GlobalEnv), add=TRUE) tPair <- new("trackPair") tPair@trackx <- s4Obj tPair@tracky <- s4Obj checkEquals( tPair, tPair) } ## detect differences checkException( checkEquals(1 , 1, tolerance=FALSE)) checkException( checkEquals(1 , 1, tolerance=numeric(0))) checkException( checkEquals(1 , 1, tolerance=numeric(2))) ## integer namedInt <- 1:9 names(namedInt) <- letters[namedInt] checkException( checkEquals( namedInt, 1:9)) ## numeric checkException( checkEquals( 8, 9)) checkException( checkEquals( 0.01, 0.02, tolerance=0.009)) checkException(checkEquals(NaN, NA)) checkException(checkEquals(NaN, Inf)) checkException(checkEquals(NaN, -Inf)) checkException(checkEquals(NA, Inf)) checkException(checkEquals(NA, -Inf)) checkException(checkEquals(numeric(2), numeric(3))) checkException(checkEquals(numeric(3), numeric(2))) ## complex checkException( checkEquals(complex(0), complex(1))) checkException( checkEquals(complex(2), complex(1))) checkException( checkEquals(complex(2, imaginary=1), complex(2, imaginary=0))) checkException( checkEquals(complex(2, real=1, imaginary=1), complex(2, real=1, imaginary=0))) checkException( checkEquals(complex(2, real=1, imaginary=1), complex(2, real=0, imaginary=1))) checkException( checkEquals(complex(2, real=1, imaginary=1), complex(2, real=0, imaginary=0))) ## character named <- character(1) names(named) <- "name" checkException( checkEquals( character(1), named)) checkException( checkEquals( letters, letters[-1])) ## formula checkException( checkEquals( lmFit, lmFitUnnamed)) lmFitInter <- glm(counts ~ outcome * treatment, family=poisson()) checkException( checkEquals( lmFitInter, lmFit)) ## factor alphaFacRecoded <- factor(alphaFac, labels=as.character(seq_along(levels(alphaFac)))) checkException( checkEquals(alphaFacRecoded, alphaFac)) ## list checkException( checkEquals( list(1), list("1"=1))) checkException( checkEquals( list(), list("1"=1))) checkException( checkEquals( list(list(), list(list()), list(list(list()))), list(list(), list(list()), list(list(list(), list()))))) ## POSIXct checkException( checkEquals(as.POSIXct(Sys.time()), as.POSIXct("2007-04-04 16:00:00"))) checkException( checkEquals(as.POSIXlt(Sys.time()), as.POSIXlt("2007-04-04 16:00:00"))) ## nested type sysTime <- as.POSIXct(Sys.time()) checkException( checkEquals( list(a=2, list(time=sysTime)), list(a=2, time=list(sysTime)))) ## raw checkException( checkEquals(raw(1), raw(2))) checkException( checkEquals(raw(1E5), raw(100001))) raw3 <- raw(3) raw3mod <- raw3 raw3mod[1] <- as.raw(3) checkException( checkEquals(raw3, raw3mod)) checkException( checkEquals(as.raw(1:1000), as.raw(c(1:99,-1,101:1000)) ) ) ## S4 objects if (identical(TRUE, require(methods))) { ## class defined above s4Obj <- new("track1") s4Obj@x <- 1:10 checkException( checkEquals( s4Obj, new("track1"))) tPair <- new("trackPair") tPair@trackx <- s4Obj checkException( checkEquals( tPair, new("trackPair"))) } } testRUnit.checkEqualsNumeric <- function() { ##@bdescr ## test case for function checkEqualsNumeric of class: none ##@edescr checkTrue( checkEqualsNumeric( 9,9)) checkTrue( checkEqualsNumeric( 9.1,9.2, tolerance=0.1)) x <- 1:10 attributes(x) <- list(dummy="nonsense") checkTrue( checkEqualsNumeric( x, x)) checkTrue( checkEqualsNumeric( 1:10, x, check.attributes=FALSE)) rvec <- rnorm(132) checkTrue( checkEqualsNumeric( matrix(rvec, 12, 11), matrix(rvec, 12, 11))) checkTrue( checkEqualsNumeric( rvec, rvec)) # This got broken in new R and is explicitly fixed checkTrue( checkEqualsNumeric( data.frame(a=1:10), data.frame(a=1:10))) ## special constants checkEqualsNumeric( pi, pi) checkEqualsNumeric( NA, NA) checkEqualsNumeric( c(1, NA, 3), c(1, NA, 3)) checkEqualsNumeric( NaN, NaN) checkEqualsNumeric( c(1, NaN, 3), c(1, NaN, 3)) checkEqualsNumeric( Inf, Inf) checkEqualsNumeric( c(1, Inf, 3), c(1, Inf, 3)) checkEqualsNumeric( -Inf, -Inf) checkEqualsNumeric( c(1, -Inf, 3), c(1, -Inf, 3)) ## numeric difference checkException( checkEqualsNumeric( 9, 10)) checkException( checkEqualsNumeric( list(9), list(10))) checkException( checkEqualsNumeric( matrix(9), matrix(10))) rvec2 <- rnorm(132) checkException( checkEqualsNumeric( matrix(rvec, 12, 11), matrix(rvec2, 12, 11))) ## exception handling ## type not supported checkException( checkEqualsNumeric( list(rvec), list(rvec))) ## S4 objects if (identical(TRUE, require(methods))) { ## class defined above s4Obj <- new("track1") s4Obj@x <- 1:10 checkException( checkEqualsNumeric( s4Obj, s4Obj)) tPair <- new("trackPair") tPair@trackx <- s4Obj checkException( checkEqualsNumeric( tPair, tPair)) } } testRUnit.checkIdentical <- function() { ##@bdescr ## test case for function checkIdentical of class: none ##@edescr checkIdentical( TRUE, TRUE) ## return value checkTrue( checkIdentical( TRUE, TRUE)) checkIdentical( FALSE, FALSE) ## bit representation identical checkIdentical( NA, NA) checkIdentical( c(1, NA, 3), c(1, NA, 3)) checkIdentical( NaN, NaN) checkIdentical( c(1, NaN, 3), c(1, NaN, 3)) checkIdentical( Inf, Inf) checkIdentical( c(1, Inf, 3), c(1, Inf, 3)) checkIdentical( -Inf, -Inf) checkIdentical( c(1, -Inf, 3), c(1, -Inf, 3)) checkIdentical( as.integer(2), as.integer(2)) checkIdentical( as.character(2), as.character(2)) checkIdentical( as.complex(2), as.complex(2)) checkIdentical( as.numeric(2), as.numeric(2)) checkIdentical( as.expression("2+4"), as.expression("2+4")) checkIdentical( as.expression(2+4), as.expression(2+4)) checkIdentical( as.factor(letters), factor(letters)) ## nested list with NA, NaN, Inf nl <- list(a=list(1), b=list(1:4), c=list(ab=1, bc=list(list(2), list(NA), list(NaN)) ), d=list(m1=matrix(NA, 2,3), m2=matrix(1+1i, 4,5)), e=list(e1=NaN, e2=list(Inf), e3=list(a=Inf, b=-Inf, c=NaN, d=-0/0))) checkIdentical(nl, nl) ## POSIX sysTime <- as.POSIXlt(Sys.time()) checkIdentical( sysTime, sysTime) ## raw checkIdentical( raw(14), raw(14)) namedRaw <- as.raw(1:14) names(namedRaw) <- letters[1:14] checkIdentical( namedRaw, namedRaw) ## formula a <- 1:10 f <- gl(2,5) checkIdentical( a~f, a~f) ## call cl <- call("round", 10.5) checkIdentical( cl, cl) ## S3 objects (ie. lists with attributes) ## from ?lm Example ctl <- c(4.17,5.58,5.18,6.11,4.50,4.61,5.17,4.53,5.33,5.14) trt <- c(4.81,4.17,4.41,3.59,5.87,3.83,6.03,4.89,4.32,4.69) group <- gl(2,10,20, labels=c("Ctl","Trt")) weight <- c(ctl, trt) lm.D9 <- lm(weight ~ group) checkIdentical( lm.D9, lm(weight ~ group)) ## S4 objects if (identical(TRUE, require(methods))) { setClass("track1", representation(x="numeric", y="numeric"), where=.GlobalEnv) on.exit(removeClass("track1", where=.GlobalEnv)) s4Obj <- try(new("track1")) checkIdentical( s4Obj, new("track1")) rm(s4Obj) } ## exception handling ## type mismatches checkException( checkIdentical( as.integer(2), as.numeric(2))) checkException( checkIdentical( as.integer(2), as.character(2))) checkException( checkIdentical( as.integer(2), as.list(2))) checkException( checkIdentical( as.integer(2), as.complex(2))) checkException( checkIdentical( as.integer(2), as.expression(2))) ## value mismatches checkException( checkIdentical( as.integer(2), as.integer(3))) checkException( checkIdentical( as.character(2), as.character(3))) checkException( checkIdentical( as.complex(2), as.complex(3))) checkException( checkIdentical( as.numeric(2), as.numeric(3))) checkException( checkIdentical( as.expression("2+4"), as.expression("2+3"))) checkException( checkIdentical( as.factor(letters), factor(letters[-1]))) fac <- factor(letters) levels(fac) <- c("1", letters[-1]) checkException( checkIdentical( fac, as.factor(letters))) ## nested list with NA, NaN, Inf checkException( checkIdentical( )) ## POSIX sysTime <- as.POSIXlt(Sys.time()) checkException( checkIdentical( sysTime, as.POSIXlt(Sys.time(), tz="GMT"))) ## raw checkException(checkIdentical( raw(14), raw(13))) namedRaw <- as.raw(1:14) names(namedRaw) <- letters[1:14] checkException(checkIdentical( namedRaw, as.raw(1:14))) ## S3 objects (ie. lists with attributes) ## from ?lm Example lm.D9base <- lm(weight ~ group - 1) checkException( checkIdentical( lm.D9base, lm.D9)) ## S4 objects if (identical(TRUE, require(methods))) { setClass("track2", representation(x="numeric", y="numeric"), prototype(x=as.numeric(1:23), y=as.numeric(23:1)), where=.GlobalEnv) on.exit(removeClass("track2", where=.GlobalEnv), add=TRUE) s4Obj <- try(new("track2")) s4ObjDiff <- s4Obj s4ObjDiff@y <- s4ObjDiff@x checkException( checkIdentical( s4Obj, s4ObjDiff)) } } testRUnit.checkTrue <- function() { ##@bdescr ## test case for function checkTrue of class: none ##@edescr checkEquals( checkTrue( TRUE), TRUE) ## named arguments namedArg <- TRUE names(namedArg) <- "Yes" checkEquals( checkTrue( namedArg), TRUE) ## errorr handling namedArg <- FALSE names(namedArg) <- "No" checkException( checkTrue( namedArg)) checkException( checkTrue( FALSE)) ## incorrect length checkException( checkTrue( c(TRUE, TRUE))) checkException( checkTrue( c(FALSE, TRUE))) checkException( checkTrue( logical(0))) checkException( checkTrue( logical(2))) } testRUnit.checkException <- function() { ##@bdescr ## test case for function checkException of class: none ##@edescr checkException( checkTrue( FALSE)) checkException( checkTrue( )) checkException( checkEquals( )) checkException( checkEquals( 24)) checkException( checkEquals( 24, 24, tolerance="dummy")) checkException( checkEqualsNumeric( )) checkException( checkEqualsNumeric( 24)) checkException( checkEqualsNumeric( 24, 24, tolerance="dummy")) checkException( stop("with message"), silent=FALSE) checkException( stop("wo message"), silent=TRUE) ## R 2.5.0 devel example that failed ## minimal example provided by Seth Falcon ll = list() ll[[1]] = function(x) stop("died") checkException( do.call(ll[[1]], list(1))) ## S4 objects if (identical(TRUE, require(methods))) { setClass("track2", representation(x="numeric", y="numeric"), prototype(x=as.numeric(1:23), y=as.numeric(23:1)), where=.GlobalEnv) on.exit(removeClass("track2", where=.GlobalEnv)) s4Obj <- try(new("track2")) checkException( slot(s4Obj, "z")) checkException( slot(s4Obj, "z") <- 1:10) ## missing method argument ## coerce(from, to) checkException( coerce(s4Obj)) } } testRUnit.DEACTIVATED <- function() { ##@bdescr ## test case for function DEACTIVATED of class: none ##@edescr checkException( DEACTIVATED()) checkException( DEACTIVATED("some message")) ## compound text checkException( DEACTIVATED(c("some message", "some more", "and more"))) } testRUnit.defineTestSuite <- function() { ##@bdescr ## test case for function defineTestSuite of class: none ##@edescr ## correct working testSuite <- defineTestSuite("RUnit Example", system.file("examples", package="RUnit"), testFileRegexp="correctTestCase.r") ## this also works for S3 objects checkTrue( inherits(testSuite, "RUnitTestSuite")) checkTrue( is.list(testSuite)) checkTrue( all(c("name", "dirs", "testFileRegexp", "testFuncRegexp", "rngKind", "rngNormalKind") %in% names(testSuite))) checkTrue( isValidTestSuite(testSuite)) ## error handling ## missing 'dirs' argument checkException(defineTestSuite("RUnit Example", testFileRegexp="correctTestCase.r")) } testRUnit.isValidTestSuite <- function() { ##@bdescr ## test case for function isValidTestSuite of class: none ##@edescr ## correct working testSuite <- defineTestSuite("RUnit Example", system.file("examples", package="RUnit"), testFileRegexp="correctTestCase.r") checkTrue( isValidTestSuite(testSuite)) ## error handling ## has to be S3 class 'RUnitTestSuite' testSuiteFail <- testSuite class(testSuiteFail) <- "NotUnitTestSuite" checkTrue( !isValidTestSuite(testSuiteFail)) ## expecting list elements testSuiteFail <- testSuite testSuiteFail[["dirs"]] <- NULL checkTrue( !isValidTestSuite(testSuiteFail)) ## has to be character testSuiteFail <- testSuite testSuiteFail[["name"]] <- list() checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["dirs"]] <- list() checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["testFileRegexp"]] <- list() checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["testFuncRegexp"]] <- list() checkTrue( !isValidTestSuite(testSuiteFail)) ## length 1 required testSuiteFail <- testSuite testSuiteFail[["name"]] <- character(0) checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["name"]] <- character(2) checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["testFileRegexp"]] <- character(0) checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["testFileRegexp"]] <- character(2) checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["testFuncRegexp"]] <- character(0) checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["testFuncRegexp"]] <- character(2) checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["rngKind"]] <- character(0) checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["rngKind"]] <- character(2) checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["rngNormalKind"]] <- character(0) checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["rngNormalKind"]] <- character(2) checkTrue( !isValidTestSuite(testSuiteFail)) ## director has to exist testSuiteFail <- testSuite testSuiteFail[["dirs"]] <- "doesNotExist" checkTrue( !isValidTestSuite(testSuiteFail)) testSuiteFail <- testSuite testSuiteFail[["dirs"]] <- c(tempdir(), "doesNotExist", tempdir()) checkTrue( !isValidTestSuite(testSuiteFail)) ## same, '' has to return FALSE testSuiteFail <- testSuite testSuiteFail[["dirs"]] <- c(tempdir(), "", tempdir()) checkTrue( !isValidTestSuite(testSuiteFail)) } testRUnit.runTestFile <- function() { ##@bdescr ## test case for function runTestFile of class: none ##@edescr testFile <- file.path(system.file("examples", package="RUnit"), "correctTestCase.r") checkTrue( file.exists(testFile)) ## The issue: .testLogger is the hard coded logger object ## regenerated by each new run call in the global environment ## thereby overwriting the existing logger. ## With the current implementation there seems to be no way to ## test the test suite execution *within* a test suite run # tmpFile <- tempfile() # writeLines(text=" testFile <- file.path(system.file(\"examples\", package=\"RUnit\"), \"correctTestCase.r\");\n res <- runTestFile(testFile, useOwnErrorHandler=FALSE);\n", con=tmpFile) # # execEnv <- new.env(parent=.GlobalEnv) # sys.source(tmpFile, execEnv) # unlink(tmpFile) # checkTrue(exists("res", envir=execEnv)) # checkTrue(inherits(get("res", envir=execEnv), "RUnitTestData")) # rm(execEnv) ## error handling ## all argument checks delegated to runTestSuite so no need for comprehensive check here ## check if any argument check is reached/performed ## useOwnErrorHandler ## type logical checkException( runTestFile(testFile, useOwnErrorHandler=integer(1), gcBeforeTest=TRUE)) } testRUnit.runTestSuite <- function() { ##@bdescr ## test case for function runTestSuite of class: none ##@edescr testSuiteTest <- defineTestSuite("RUnit Example", system.file("examples", package="RUnit"), testFileRegexp="correctTestCase.r") checkTrue( isValidTestSuite(testSuiteTest)) ## The issue: same as above ##res <- runTestSuite(testSuiteTest) ## ## error handling ## ## useOwnErrorHandler ## type logical tS <- testSuiteTest checkException( runTestSuite(tS, useOwnErrorHandler=integer(1))) ## length 1 checkException( runTestSuite(tS, useOwnErrorHandler=logical(0))) checkException( runTestSuite(tS, useOwnErrorHandler=logical(2))) checkException( runTestSuite(tS, useOwnErrorHandler=as.logical(NA))) ## gcBeforeTest checkException( runTestSuite(tS, gcBeforeTest = "hello")) checkException( runTestSuite(tS, gcBeforeTest = c(TRUE, FALSE))) checkException( runTestSuite(tS, gcBeforeTest = as.logical(NA))) ## testSuite } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitPlotConnection.r����������������������������������������������������������0000644�0001751�0000144�00000005402�13267374743�020534� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## $Id$ cat("\n\nRUnit test cases for 'RUnit:plotConnection' function\n\n") testRUnit.plotConnection <- function() { ##@bdescr ## test case for function plotConnection of class: none ##@edescr ## requires X server to be available for png device if (!interactive()) { DEACTIVATED("plotConnection uses png device which requires X sverer to be available.") } ## 1) no counts conMat <- matrix(0, nrow=5, ncol=5) timeStamp <- format(Sys.time(), "%y%m%d-%H%M") tmpPlotFile <- file.path(tempdir(), paste(timeStamp, "connectionPlot.png", sep="_")) ret <- RUnit:::plotConnection.trackInfo(conMat, tmpPlotFile) checkTrue( is(ret, "NULL")) checkTrue( file.exists(tmpPlotFile)) ## clean up try(unlink(tmpPlotFile)) ## 2) num <- 5 conMat <- matrix(sample(1:3, num^2, replace=TRUE), nrow=num, ncol=num) timeStamp <- format(Sys.time(), "%y%m%d-%H%M") tmpPlotFile <- file.path(tempdir(), paste(timeStamp, "connectionPlot2.png", sep="_")) ret <- RUnit:::plotConnection.trackInfo(conMat, tmpPlotFile) checkTrue( is(ret, "NULL")) checkTrue( file.exists(tmpPlotFile)) ## clean up try(unlink(tmpPlotFile)) num <- 25 colNum <- 3 conMat <- matrix(sample(1:3, num*colNum, replace=TRUE), nrow=num, ncol=colNum) timeStamp <- format(Sys.time(), "%y%m%d-%H%M") tmpPlotFile <- file.path(tempdir(), paste(timeStamp, "connectionPlot3.png", sep="_")) ret <- RUnit:::plotConnection.trackInfo(conMat, tmpPlotFile) checkTrue( is(ret, "NULL")) checkTrue( file.exists(tmpPlotFile)) ## clean up try(unlink(tmpPlotFile)) num <- 25 colNum <- 3 conMat <- matrix(sample(0:3, num*colNum, replace=TRUE), nrow=num, ncol=colNum) timeStamp <- format(Sys.time(), "%y%m%d-%H%M") tmpPlotFile <- file.path(tempdir(), paste(timeStamp, "connectionPlot4.png", sep="_")) ret <- RUnit:::plotConnection.trackInfo(conMat, tmpPlotFile) checkTrue( is(ret, "NULL")) checkTrue( file.exists(tmpPlotFile)) ## clean up try(unlink(tmpPlotFile)) } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitTearDown.r����������������������������������������������������������������0000644�0001751�0000144�00000006251�13267374743�017324� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## $Id$ cat("\n\nRUnit test cases for '.tearDown' function\n\n") ## defined for the life time of this environment warningsLengthDefault <- getOption("warnings.length") .tearDown <- function() { ## remove global variable if (exists("runitDummy", envir=.GlobalEnv)) { try(rm("runitDummy", envir=.GlobalEnv)) } ## remove temp file tempFile <- file.path(tempdir(), "runitDummyFile.txt") if (file.exists(tempFile)) { try(unlink(tempFile)) } ## reset options options(warnings.length=warningsLengthDefault) ## remove class if (length(findClass("runitDummyS4Class")) > 0) { try(removeClass("runitDummyS4Class", where=.GlobalEnv)) } } testRUnit..tearDown.Init <- function() { ##@bdescr ## testcase for function .tearDown of class: none ## setup vriables to be removed by .tearDown after test case execution ## check in subsequent test case that this operation chain succeeded ##@edescr ## define global variable checkTrue( !exists("runitDummy", where=.GlobalEnv)) assign("runitDummy", "this is a test dummy variable", envir=.GlobalEnv) checkTrue( exists("runitDummy", where=.GlobalEnv)) ## create temp file tempFile <- file.path(tempdir(), "runitDummyFile.txt") checkTrue( !file.exists(tempFile)) write.table(matrix(1:42, 6, 7), file=tempFile) checkTrue( file.exists(tempFile)) ## modify options ## current default: 1000 options(warnings.length=123) checkEqualsNumeric( getOption("warnings.length"), 123) ## define S4 class checkTrue( !isClass("runitDummyS4Class", where=.GlobalEnv)) setClass("runitDummyS4Class", representation(x = "numeric", y = "numeric"), prototype(x = 1:10, y = 10:1), where=.GlobalEnv) checkTrue( isClass("runitDummyS4Class", where=.GlobalEnv)) } testRUnit..tearDown.Test <- function() { ##@bdescr ## testcase for function .tearDown of class: none ## test that all modifications resulting from the previous test case ## have been removed as defined in .tearDown ##@edescr checkTrue( !exists("runitDummy", where=.GlobalEnv)) tempFile <- file.path(tempdir(), "runitDummyFile.txt") checkTrue( !file.exists(tempFile)) checkEqualsNumeric( getOption("warnings.length"), warningsLengthDefault) checkTrue( !isClass("runitDummyS4Class", where=.GlobalEnv)) } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/Makefile�����������������������������������������������������������������������0000644�0001751�0000144�00000000513�15024242133�015743� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������TOP = ../../.. TEST_DIR = `pwd` INST_PATH = `dirname ${TEST_DIR}` PKG_PATH = `dirname ${INST_PATH}` ## Note that 'R' was not right here: there may be no 'R' on the path. all: install test install: cd ${TOP}; \ $(R_HOME)/bin/R CMD INSTALL --clean ${PKG_PATH} && \ cd ${TEST_DIR} test: $(R_HOME)/bin/R --slave < runalltests.R �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitTextProtocol.r������������������������������������������������������������0000644�0001751�0000144�00000005130�13267374743�020242� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## $Id$ cat("\n\nRUnit test cases for 'textProtocol' function\n\n") testRUnit.printTextProtocol <- function() { ## copy baseenv() logger tmp <- get(".testLogger", envir = RUnitEnv) testCaseDir <- file.path(system.file(package="RUnit"), "examples") testSuiteInternal <- defineTestSuite("RUnit Self Test", testCaseDir, "correctTestCase.r") testData2 <- runTestSuite(testSuiteInternal, useOwnErrorHandler=FALSE) timeStamp <- format(Sys.time(), "%y%m%d-%H%M") testProtocolFile <- file.path(tempdir(), paste(timeStamp, "test_printHTMLProtocol.txt", sep="_")) ret <- printTextProtocol(testData2, fileName=testProtocolFile) assign(".testLogger", tmp, envir = RUnitEnv) checkTrue( file.exists(testProtocolFile)) ## input argument error handling ## missing 'testData' object checkException(printTextProtocol()) ## wrong class checkException(printTextProtocol("dummy")) ## fileName arg errors testData <- list() class(testData) <- "RUnitTestData" ## wrong type checkException(printTextProtocol(testData, fileName=numeric(1))) ## wrong length checkException(printTextProtocol(testData, fileName=character(0))) checkException(printTextProtocol(testData, fileName=character(2))) ## separateFailureList arg errors ## wrong type checkException(printTextProtocol(testData, separateFailureList=numeric(0))) ## wrong length checkException(printTextProtocol(testData, separateFailureList=logical(0))) checkException(printTextProtocol(testData, separateFailureList=logical(2))) ## showDetails arg errors ## wrong type checkException(printTextProtocol(testData, showDetails=numeric(0))) ## wrong length checkException(printTextProtocol(testData, showDetails=logical(0))) checkException(printTextProtocol(testData, showDetails=logical(2))) } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitSetUp.r�������������������������������������������������������������������0000644�0001751�0000144�00000007317�13267374743�016645� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## $Id$ cat("\n\nRUnit test cases for '.setUp' function\n\n") ## defined for the life time of this environment warningsLengthDefault <- getOption("warnings.length") .setUp <- function() { ## define global variable if (exists("runitDummy", where=.GlobalEnv)) { stop(".setUp found 'runitDummy'.") } assign("runitDummy", "this is a test dummy variable", envir=.GlobalEnv) if( !exists("runitDummy", where=.GlobalEnv)) { stop(".setUp failed to assign 'runitDummy'.") } ## create temp file tempFile <- file.path(tempdir(), "runitDummyFile.txt") checkTrue( !file.exists(tempFile)) write.table(matrix(1:42, 6, 7), file=tempFile) if ( !file.exists(tempFile)) { stop(paste(".setUp failed to create file", tempFile)) } ## modify options ## current default: 1000 options(warnings.length=123) if ( !identical(TRUE, all.equal.numeric(getOption("warnings.length"), 123))) { stop(paste(".setUp failed to set options.")) } ## define S4 class checkTrue( !isClass("runitDummyS4Class", where=.GlobalEnv)) setClass("runitDummyS4Class", representation(x = "numeric", y = "numeric"), prototype(x = 1:10, y = 10:1), where=.GlobalEnv) if ( !isClass("runitDummyS4Class", where=.GlobalEnv)) { stop(paste(".setUp failed to define S4 class 'runitDummyS4Class'.")) } } testRUnit..setUp.Test1 <- function() { ##@bdescr ## testcase for function .setUp of class: none ## check existance of variables, modified options, class definitions ## defined in .setUp ## remove for subsequent check ##@edescr checkTrue( exists("runitDummy", where=.GlobalEnv)) ## remove global variable rm("runitDummy", envir=.GlobalEnv) tempFile <- file.path(tempdir(), "runitDummyFile.txt") checkTrue( file.exists(tempFile)) ## remove temp file unlink(tempFile) checkEqualsNumeric( getOption("warnings.length"), 123) ## reset options options(warnings.length=warningsLengthDefault) checkTrue( isClass("runitDummyS4Class", where=.GlobalEnv)) ## remove class checkTrue( removeClass("runitDummyS4Class", where=.GlobalEnv)) } testRUnit..setUp.Test2 <- function() { ##@bdescr ## testcase for function .setUp of class: none ## same as above, only reason is to check correct invocation of .setUp ## before *each* test case function ##@edescr checkTrue( exists("runitDummy", where=.GlobalEnv)) ## remove global variable rm("runitDummy", envir=.GlobalEnv) tempFile <- file.path(tempdir(), "runitDummyFile.txt") checkTrue( file.exists(tempFile)) ## remove temp file unlink(tempFile) checkEqualsNumeric( getOption("warnings.length"), 123) ## reset options options(warnings.length=warningsLengthDefault) checkTrue( isClass("runitDummyS4Class", where=.GlobalEnv)) ## remove class checkTrue( removeClass("runitDummyS4Class", where=.GlobalEnv)) } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitInspect.r�����������������������������������������������������������������0000644�0001751�0000144�00000011014�14563457515�017176� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## $Id$ cat("\n\nRUnit test cases for 'RUnit:inspect' functions\n\n") .tearDown <- function() { if (exists("track", envir=.GlobalEnv)) { rm(track, envir=.GlobalEnv) } } bar <- function(x) { y <- 0 for(i in 1:100) { y <- y + i } return(y) } foo <- function(x) { if (length(x)) n <- length(x) len <- if(n==0) "zero" else if (n==1) "one" else if (n==2) "two" else if (n==3) "three" else "many" cat("object contains",len, "elements") return(n) } foo2 <- function(x) { if (length(x)) n <- length(x) ## should not confuse tracker len <- ifelse(n==0, "zero", "more") cat("object contains",len, "elements") } testRUnit.inspect <- function() { foo <- function(x) { y <- 0 for(i in 1:100) { y <- y + i } return(y) } ## the name track is necessary track <<- tracker() ## initialize the tracker track$init() ## inspect the function ## res will collect the result of calling foo res <- inspect(foo(10), track=track) checkEquals( res, 5050) } testRUnit.inspect.extended <- function() { ## the name track is necessary track <<- tracker() ## initialize the tracker track$init() # from ? svd hilbert <- function(n) { i <- 1:n; 1 / outer(i - 1, i, "+") } X <- hilbert(9)[,1:6] s <- svd(X) res <- inspect(svd(X), track=track) checkEquals( res, s) } testRUnit.getTrackInfo <- function() { ## the name track is necessary track <<- tracker() ## initialize the tracker track$init() ## inspect the function checkTrue( exists("bar")) ## res will collect the result of calling foo res <- inspect(bar(10), track=track) checkEquals( res, 5050) res <- inspect(foo(10), track=track) checkEquals( res, 1) res <- inspect(foo2(10), track=track) ## get the tracked function call info resTrack <- track$getTrackInfo() checkTrue( is.list(resTrack)) checkTrue( c("R/foo2") %in% names(resTrack)) checkEquals( names(resTrack$"R/foo2"), c("src", "run", "time", "graph", "nrRuns", "funcCall")) } testRUnit.printHTML <- function() { ## the name track is necessary track <<- tracker() ## initialize the tracker track$init() ## inspect the function checkTrue( exists("bar")) ## res will collect the result of calling foo res <- inspect(bar(10), track=track) checkEquals( res, 5050) ## get the tracked function call info resTrack <- track$getTrackInfo() outDir <- tempdir() ##checkTrue( is.null(printHTML(resTrack, baseDir=outDir))) checkTrue( is.null(printHTML(resTrack, baseDir=outDir))) checkTrue( "index.html" %in% dir(file.path(outDir, "results"))) inspect(foo(1:3), track=track) resTrack <- track$getTrackInfo() checkTrue( is.null(printHTML(resTrack, baseDir=outDir))) ## error handling checkException(printHTML("notCorrectClass")) ## baseDir checkException(printHTML(resTrack, baseDir=logical(1))) checkException(printHTML(resTrack, baseDir=character(0))) checkException(printHTML(resTrack, baseDir=character(2))) checkException(printHTML(resTrack, baseDir=as.character(NA))) } testRUnit.printHTML.extended <- function() { ## the name track is necessary track <<- tracker() ## initialize the tracker track$init() # from ? svd hilbert <- function(n) { i <- 1:n; 1 / outer(i - 1, i, "+") } X <- hilbert(9)[ ,1:6] s <- svd(X) res <- inspect(svd(X, LINPACK=TRUE), track=track) res <- inspect(svd(X), track=track) res <- inspect(svd(X, nu=nrow(X)), track=track) res <- inspect(svd(X, nv=ncol(X)), track=track) res <- inspect(svd(X, nv=0L), track=track) resTrack <- track$getTrackInfo() outDir <- tempdir() checkTrue( is.null(printHTML(resTrack, baseDir=outDir))) } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitHTMLProtocol.r������������������������������������������������������������0000644�0001751�0000144�00000004637�13267374743�020075� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## $Id$ cat("\n\nRUnit test cases for 'HTMLProtocol' function\n\n") testRUnit.printHTMLProtocol <- function() { ## FIXME ## this is not safe, think about assigning .logger to new environment ## copy baseenv() .logger tmp <- get(".testLogger", envir = RUnitEnv) testCaseDir <- file.path(system.file(package="RUnit"), "examples") testSuiteInternal <- defineTestSuite("RUnit Self Test", testCaseDir, "correctTestCase.r") testData2 <- runTestSuite(testSuiteInternal, useOwnErrorHandler=FALSE) timeStamp <- format(Sys.time(), "%y%m%d-%H%M") testProtocolFile <- file.path(tempdir(), paste(timeStamp, "test_printHTMLProtocol.html", sep="_")) ret <- printHTMLProtocol(testData2, fileName=testProtocolFile) assign(".testLogger", tmp, envir = RUnitEnv) checkTrue( file.exists(testProtocolFile)) ## input argument error handling ## missing 'testData' object checkException(printHTMLProtocol()) ## wrong class checkException(printHTMLProtocol("dummy")) ## fileName arg errors testData <- list() class(testData) <- "RUnitTestData" ## wrong type checkException(printHTMLProtocol(testData, fileName=numeric(1))) ## wrong length checkException(printHTMLProtocol(testData, fileName=character(0))) checkException(printHTMLProtocol(testData, fileName=character(2))) ## separateFailureList arg errors ## wrong type checkException(printHTMLProtocol(testData, separateFailureList=numeric(0))) ## wrong length checkException(printHTMLProtocol(testData, separateFailureList=logical(0))) checkException(printHTMLProtocol(testData, separateFailureList=logical(2))) } �������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runalltests.R������������������������������������������������������������������0000644�0001751�0000144�00000000564�13267374743�017040� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library("RUnit") options(warn=1) testSuite <- defineTestSuite(name="RUnit", dirs=".", testFileRegexp="runit.*\\.r$", rngKind="default", rngNormalKind="default") testData <- runTestSuite(testSuite, verbose=0L) printTextProtocol(testData, showDetails=FALSE) ��������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitTestLogger.r��������������������������������������������������������������0000644�0001751�0000144�00000005535�13267374743�017664� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## $Id$ cat("\n\nRUnit test cases for '.testLogger' object\n\n") testRUnit..testLogger <- function() { ##@bdescr ## test case for .testLogger object of class: 'TestLogger' ##@edescr ## create new temp test logger object tlTmp <- RUnit:::.newTestLogger(TRUE) checkTrue( is(tlTmp, "TestLogger")) checkTrue( all( c("getTestData", "setCurrentTestSuite" , "setCurrentSourceFile", "addSuccess", "addError", "addFailure", "addDeactivated", "addCheckNum", "isFailure", "setFailure", "isDeactivated", "setDeactivated", "incrementCheckNum", "getCheckNum", "cleanup") %in% names(tlTmp))) testSuite <- defineTestSuite(name="Test Test", dirs=tempdir()) ## need to init 1) test suite name and 2) test case file name tlTmp$setCurrentTestSuite(testSuite) tlTmp$setCurrentSourceFile("Test File") tlTmp$addSuccess("first test case", system.time(1)) checkEquals(tlTmp$getTestData()[[1]]$nTestFunc, 1) tlTmp$incrementCheckNum() checkEquals(tlTmp$getCheckNum(), 1) checkTrue( !tlTmp$isFailure()) tlTmp$setFailure() checkTrue( tlTmp$isFailure()) checkTrue( !tlTmp$isDeactivated()) tlTmp$setDeactivated("This is a deactivated test case") checkTrue( tlTmp$isDeactivated()) tlTmp$cleanup() checkEquals(tlTmp$getCheckNum(), 0) checkTrue( !tlTmp$isFailure()) } testRUnit.getErrors <- function() { ##@bdescr ## test case for getErrors function ##@edescr ## create dummy test suite result object testData <- vector(mode="list", 3) for (i in seq_along(testData)) { testData[[i]]$nErr <- i testData[[i]]$nDeactivated <- i - 1 testData[[i]]$nTestFunc <- i*13 testData[[i]]$nFail <- i + 3 } class(testData) <- "RUnitTestData" res <- getErrors(testData) checkTrue (is.list(res)) checkEquals(length(res), 4) checkEquals(res$nErr, 6) checkEquals(res$nDeactivated, 3) checkEquals(res$nTestFunc, 78) checkEquals(res$nFail, 15) ## check exception handling checkException( getErrors( list())) } �������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/inst/unitTests/runitS4.r����������������������������������������������������������������������0000644�0001751�0000144�00000005661�13267374743�016073� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## RUnit : A unit test framework for the R programming language ## Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## $Id$ cat("\n\nRUnit test cases for S4 class inheritance\n\n") testRUnit.S4classInheritance <- function() { ##@bdescr ## test case for noneof class: none ## test if S4 classes can be instantiated inside test code ## given that no where argument is specified ##@edescr className <- setClass("testVirtualClass", representation("VIRTUAL", x = "numeric", y = "numeric", xlab = "character", ylab = "character") ) checkEquals(className, "testVirtualClass") checkException( new(className)) derivedClassName <- setClass("testDerivedClass", representation(className, scale = "numeric", title = "character") ) ## Attention: ## invert inheritance order! on.exit(removeClass(derivedClassName)) on.exit(removeClass(className), add=TRUE) checkEquals(derivedClassName, "testDerivedClass") objD <- new(derivedClassName) checkTrue( is(objD, derivedClassName)) checkTrue( isS4(objD)) checkTrue(require(stats4)) ## instantiate S4 class from stats ## be sure to use a unique unused variable name here ## i.e. NOT className as this has been used before ## and the on.exit call will look up the name just *before* ## the test function exists classNameMLE <- "mle" obj <- new(classNameMLE) checkTrue( is(obj, classNameMLE)) checkTrue( isS4(obj)) derivedStats4ClassName <- setClass("mleChild", representation(classNameMLE, scale = "numeric", title = "character") ) on.exit(removeClass(derivedStats4ClassName), add=TRUE) checkEquals(derivedStats4ClassName, "mleChild") obj <- new("mleChild") checkTrue( is(obj, "mleChild")) checkTrue( isS4(obj)) } �������������������������������������������������������������������������������RUnit/README.md�������������������������������������������������������������������������������������0000644�0001751�0000144�00000004336�14563457515�012635� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# RUnit [![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/RUnit)](https://CRAN.R-project.org/package=RUnit) [![CRAN Downloads](https://cranlogs.r-pkg.org/badges/RUnit)](https://CRAN.R-project.org/package=RUnit) RUnit is a testing package for R code, inspired by the xUnit family of testing tools. Originally implemented by Thomas Koenig, Klaus Juenemann, and Matthias Burger, this package has served the R community for over a decade. Since RUnit is no longer actively developed, I provide maintenance of this package mostly to support older projects that still rely on RUnit. # Using RUnit To make RUnit work with `R CMD check`, create a following file in the `tests` subdirectory. This would run the actual tests stored in the packages `inst/tests` subdirectory. # Our package. Used for the test suite name pkgname <- "your package name" require(pkgname, quietly=TRUE, character.only=TRUE) || stop("package '", pkgname, "' not found") # How to determine which files to load (have to start with test_ and end with .R) pattern <- "^test_.*\\.R$" # Which functions to run. Have to start with 'test.' testFunctionRegexp = "^test.+" # Path to the unit tests folder in the package (assuming "inst/tests" here) dir <- system.file("tests", package=pkgname) # Define RUnit test suite suite <- defineTestSuite(name=paste(pkgname, "RUnit Tests"), dirs=dir, testFileRegexp=pattern, testFuncRegexp = testFunctionRegexp, rngKind="default", rngNormalKind="default") # Run tests result <- runTestSuite(suite) # Display result tests on the console printTextProtocol(result) # Write results in JUnit-like xml format printJUnitProtocol(result, fileName="junit.xml") A typical unit test would then live for example in `inst/tests/test.operations.R`. Each such file can contain multiple functions like so: test.additionWorks <- function() { checkEquals(2, 1+1, "one plus one must be two") } test.divisionByZeroFails <- function() { checkException(1/0, "division by zero is expected to fail") } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/build/����������������������������������������������������������������������������������������0000755�0001751�0000144�00000000000�15024242132�012423� 5����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/build/vignette.rds����������������������������������������������������������������������������0000644�0001751�0000144�00000000372�15024242132�014764� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mPJ1غUOX KY*i\Hoɚ d2sc�%3Պ [@ Mo;5dH ?f<Qe%.B_"w�N7hP�_3*u<6G:EEs\*gV~Y}Lʐ9V/nY7M'9SoE?Al[t'7VmSXޅ̍NC\gG C_i������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/build/stage23.rdb�����������������������������������������������������������������������������0000644�0001751�0000144�00000022210�15024242130�014357� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������}i{v^ĖFhgj(iDjE;%JCQD-I͝w v�Mg|'cI8f'b;_+_?7u /�捞|`[:ujA᳽L'ӷ%+%]L/2VxidӬA8ZM_Wb;̫ꎽ]3fjJC[3v_x R<lvaf)9zSOi6[W{_U [zgRKs#7;Э]YϨqh:/�}0ܿ_25W_<_UnW~ۣ^>Z?Zq 7G ,߬_kco^F%Gk5ZWs "z_>/~iqniZ=6ܵ]ַ4.3-!.X4R뎱R02blj4=uXɱgU gEwr쉩5\[:QVVT)䧉+[*xQ]#Bov+!GmKU B,buoMslnf1G/ Og<ZkVyGcuuA ?^y qWUNӝÅ!ofe(FI\\߸U̖cYCۤW"|\њgm;.Dlh6 ކ|뎄v"w0R g‚a+教a uޞG-|0MWfN]P#  !4Jw=Ħ>gߙ.>͕Um5ju,oaufEA�k4 8aIf 3 ?_nxn~iavq=/ԋ˧eyur[]]{DB)BžOŮcM:qx'S=0>p XGŏKk'wG^ Gfɣ>Y˃YfUmUsI7VyhXޞ +u?I8 yJ%WBHi[+kӷQaؚcgoy�*$^I,!4:[is[|]Ŗt셩[lB\˱ѝϦ2v=>|\*~AB\ݦ.4 4s$z6@̓6:} rS}>0 -5[lMO (n WJ6ۚŎl~Xz+?AZ.xmh%J*UfjhYe@v  -uwQ3 ͍(wPj9ݶ1$@\)dFMwy$ y$!y3J<y˺%T4 D{+vӜ9Nۦ9~d0͒ӈDY$,qdfr ~?,a`f_: M#ů6S0ǩm0HL{0;=4E-NgHN�TQ M[yDa7SÉL"(UB><3Ò3 9o!*= quYh dݽ[_y`69xBePY<Yѽ+5gI9VsWrD߃!&&:mft6ϴRհ ely~w,-ǔ' ^cW3_*ͱ|>?LS8I'>�GaÉNt.rf T:\l[y#bbǚi&</dE0\q}:( gꕐ nJҺX\ L"rsw.eʝ6#!nL;OJ";Jy\*.g.w7ӏ1Hf'  r}N_%ϥeZ]s24prM f2# <Z /rX&!?NYk^dN�!/&sfM-^eq+R 0Ѩ/P"4Ӌb߃<*} qu=4y <A, y_jpR-R2d|TDƲ]a'mR+Z0 OtUC&6C1"*Cۚ4V]0gKΠe3^5U<dٕJe2^W<Vwl.fv.1b?whïY\TG= /$Ss"N56hmvF^{Q 1hpbc9s^(ԉ!{:hY~N<c,ʶɃ 3*F&G3ofW6*g%ΐOqkixɦ/q� UzQlrW[4?rok4,0ñhQ1mAx,aꟛ~8Qc5r8y(1VCN>)<(rḴkZB�=J"U[\0$ sO hJӷSU!*2io*xHWp_Ҹ#Va˶W V!bzũGqD3VL@TZgJmNANl?*ޙ^ 3E̲w ǚ;Fo떧jQfF<0FkUT/L74࿬jgb8y.?f,k >Jvt03sQڽJ9iyZuV De8yl<w 89$鮟a qhF\n NJ 9y|g8OZ3brr Բ(dtmôDL3xhNY/v7|t"a/9i  oSq8a|'ܾx ,�X)߹G#YV\H1BL->zκjt$& ё;A%v9$AeN1,>5Ljc#^#9ɳ"V:('i Mx̺>iwQqrp ͕k5NZ1e+T?aWx)'APOE ,^2#+zܗz\wU݃e];梫欈V7?Q<� rj?sN[QT{hY ^8 y2k6tkaB*qf.m<o433c=z+w),E̎<Aſ'!j،m!e ;aWi܅Lavi:ٕN kUlXazpH׮[OTAA�0]>40<7լ-/&fxUQΑMDUcp||:LѱNٴ'f6n;ҡq2 5J:iĚtWBFLN:Oz�e&O;-X1,Xu`£=&*z!2of`. k~EKy1Lw x>4Cr7 w rsmmb0| 9wM 3Qal<crPf*lmPh&Ejs, 5_'ʊ0QgΪf5ˤy"4�xC*wMv^)wMvkmRx҅e!:<G-.g ;,GDe_Ҋi,09xڙ1܅%S*nxr%G]U[5| 0k.(zȇSsCp;wxrUw\O4a!_H7prS t89y{RJYߨw2k^ڳ Y֎U"||})lBxr#O>Vuˠ=ؚC)"t2q pU]><oQЈF4饪fnSߟc�P(ķ&zlK>9CȟtI[,b"xGƄɈ,OxC5lk#m2Tm:ȟ$fxYLrsY`܀&w I )9X}Dexr|x rr:.&'>a~F;W�3BDΰ w2gXBلە\ȠA.fK az{^ܑ LN5H.TBN*uz z-gK8a}jNC()A&ӆw/pr$s˕¨4<0f<'y9Y3襤OuSvA V?xKܝ}j@`'Q癝W ep(yd<$FY`y B6=)uO '́yk_iIsWb} rsNRd㊐(^AA.?w$<3f.1tFq\ϳ@:] lcu<yXMw@Nv k%ϦMl*]NnP];=P?65eb+E)-/k8dỠOޛ!c_/2 R)uf&Y*';Wih@ɶ>t3}ĕP+w8{bXp,)ŽU1r[ 5>rkò84X{k{ܾ[2eT0G\We呏.lmqNQQȣoY`:qՑW KPwNnLri>wߋ3ٛYA ̊cAZJ践RIwVդopeV 6AT:tMe:{q{Ta;}/)&y _HqXe+/6R6OZHymRwC~?n]6|^Eȱ>T\C&vߞK͈ʿ| :MM`Ser*m 2^+uTӛ(09-<z_h#Чw(ӭfPz$NU.Y_CgtAߪ1Mxޅ|7yRuQ6axzWfH1؝9vXݴ{ 1͒9 dwT\/GP˭�n">Tm[Du�y!hW k NxU3Lѷ˳A<xS] @yayZ:Z%azMdDMc=ʘ"@PzMc!d1N!b~I9(2{r\Cc=A̓9ȱ& wrI WhM>JU]y(R:o`?qBɄ L4) c :g)Z7 v_g.-P7Iʛ]'Lo~G2 !6|@UZu*xM9U-L ZKU-%&!N hԖyBQ NǓY%}R. od\E+e63u,&R FacoY ,R<i& :%kVikh)p  7^JL?1נ+T~V7+[k%ZQ6aQWV=v26~~eLӗoQhuhS)wZ;Wg2DCNo`4P,m&Z�cMM+[Z(͙_Ǘ Qr7`O*LQ�whUkE ?WBY5MYA{ rT{'=x8~b8QTj3Rg :V},Ǟ<3gh0u>faxŽ6 =6@ 0y\�N^NTOA6鍰M_իE=Sg3~&LN٤yw;ڧԎOB> /ԃScEP0}J+%%)t&~g/s[λyUΊ={#)CkxUۉZu!HQ qu?LRNJ2%t6ʩ!TA9g`փQ6wxrBK'7^z Ng ^c69L[ou9'!F;f(ˤu0zGW 6wEe] ^T\/0uY,t*뎹N1k[Ux@'>ě<CcM樹ᲄ3 |߇J#քpa,ey*=D(p,|y=lλAQȱTsQ AkN8*q{EX/Uk.s4y+?!IO�oCN>aMyտr+,p;(w| 'xYɶ<6MM{v)Go< J>CK(N/ ).?ܡűۃ@;_@ѿVDH�qmZ"y"t̓oX84j3x5+$K K4,sV2-ěAg\J>x១�*3'(@Mg-.__NϨtj/as0%<|"4Z&eykO?f9*x(4(+"}]A*;iБʕ5TpBJo|C{ݥY5Q1ObX&##<S"oLԢ>4>9λ /@0X#bc96ooJ,G!mG[2u7Ǟ>2kCzXM﻾)OH]ܕp {r4/Uz^~LDD eҿwϳoViɷm !8*S="< 96O5D!nLK%twuuWꃮܩQXaQ` L^7 k}c#cFRoAp�@b:},f�AKLgׇ'͠˳=1?=ZZ?JUk\^ñԕp38=(r?F9<z!:x8TO@0Tas{n nfOIa ekʵSԀ0.E ǃ 6%?!az;Dǹk#Y!㐓/\eSԴye:L?.UWS?*=slaZ kmԴM[P'g gܼU1CܟПJNW`:D&70"<9{ NubN JLf#쿃a@@g H Vuũe俉]vY12&JBCERUB0#!nKh dѻ:5u^qZ*?e@xrz;5)G ޔeJ2b"@>MxvJ}Dɻ!M+6SsF3-x؏oA[w״cA6}(ɛJomi˭v'[,ۖG{:5\ݡ_[%,Kƾxy~l{c[v[,95쬝8 ~YC7- qSYjgJz_m,z?y!bk*Krb?S ΘmN(pMڿ3>ړtpnk\v{IMYBoZƛB<ټW}m]tطݲZڜݐ/ldÑ3M*nJ. $W {)ulȾq~÷j[%ؓ;iܴy/:zT#[kw"3pEl{AB,ա3ƎwWDr3v43%B?<�njgK: Q-ro1x\Њg;arouPVߪ8jEq{zp++t4M/iҶSx^F <-&)?i[rḘtEJp[ ]& fTH 9x+۞ba/<8_gdna6QwX$lEfm7V_ԖC|ͫ#'a^TV ۶Efx%8h-nh޴Ch#VBRawݲё3wa3*ݑ b[O_sEԫ[C_f`AŖƒ6U ozQ?AHG?SԹݙZv_?n)s=^r0?Ƴmӝ,�/^yh!|++q<no{47ww~ ,ct 6{g%/p6_lgFvM?xS8RY)FƯUG QP:ꮻ</pΡЭ8𚮍]yEńǦ#=|̌!C-O؆^b9S\]/^Ώ:4wj'+"zާڒTѓ+zC7& eWo%|o|!c$8P\6+ sh|*N:z55^=B|Ls+oΏϐ]GgBVFpRNOq~;IQBL$=P)L/{ԯ٢7Uϫ/5o;+cg!=*>,xY:QtXV X⇶i hxCaջَE9ҢJdzҴ@?VjX]C_~.C/߅ԺV<8S4|!]ȍ%vq1@ӘKCU)FԘPz5r Xt=ܖ]Ԍc'45)yFε&h-Hۡק;ݾ2hr}noy\*Qe+ϩ;r1)ƾo&aG<eǷg؍(������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/man/������������������������������������������������������������������������������������������0000755�0001751�0000144�00000000000�14563457515�012123� 5����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/man/RUnit-intro.Rd����������������������������������������������������������������������������0000644�0001751�0000144�00000003624�14563665057�014613� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \encoding{utf8} \name{RUnit} \alias{RUnit} \title{RUnit - Package Description} \description{ This package models the common Unit Test framework for R and provides functionality to track results of test case execution and generate a summary report. It also provides tools for code inspection and thus for test case coverage analysis. The design is inspired by the popular JUnit unit test framework. This package comes with a set of unit tests, serving as a test battery to check correct functioning against new R versions released as well as practical examples for writing test cases (see the \file{inst/unitTests} subdirectory of the source package, or \file{unitTests} contained in the binary package version). } \references{RUnit - A Unit Test Framework for R. useR! 2004 Vienna} \author{ Thomas \enc{König}{Koenig}, Klaus \enc{Jünemann}{Juenemann} \ifelse{html}{\out{&}}{&} Matthias Burger} \seealso{ See \code{\link{defineTestSuite}}, \code{\link{runTestSuite}} for unit testing or \code{\link{inspect}} and \code{\link{tracker}} for code inspection. } \keyword{programming} \concept{RUnit} ������������������������������������������������������������������������������������������������������������RUnit/man/testCaseSetUp.Rd��������������������������������������������������������������������������0000644�0001751�0000144�00000002753�14563756534�015160� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \encoding{utf8} \name{.setUp} \alias{.setUp} \alias{.tearDown} \title{Definition of RUnit Test Case code files.} \usage{ .setUp() .tearDown() } \description{ Either one or both functions have to be provided by the test case author, take precedence over the dummy definitions provided by the RUnit package and are called once for every test case identified. } \details{ To be written ... } \value{ Functions do not return a value; called for their side effects. } \author{ Thomas \enc{König}{Koenig}, Klaus \enc{Jünemann}{Juenemann} \ifelse{html}{\out{&}}{&} Matthias Burger} \seealso{ \code{\link{runTestFile}}. } \keyword{programming} \concept{RUnit} ���������������������RUnit/man/inspect.Rd��������������������������������������������������������������������������������0000644�0001751�0000144�00000005125�14563756530�014061� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \encoding{utf8} \name{inspect} \alias{inspect} \title{Track the executed code lines of a function or method.} \usage{ inspect(expr, track = track) } \arguments{ \item{expr}{Any R function or method call.} \item{track}{list object, as returned by a call to \code{tracker}.} } \description{ \code{inspect} examines and modifies the source code of a function or method. After the modification of the source code, the modified function will be executed and the result of the tracking process will be stored. To store the information a \code{tracker} environment with the name track must exist. Note, that not all R code constructs can be handled at the current state. In some cases it is not possible to track a specific code line. Therefore, clearly structured code with consequent use of opening and closing braces to indicate conditional expressions can prevent these parser problems. } \details{The return value of \code{inspect} is the result returned by the function executed. If the function has no return value nothing is returned either.} \author{ Thomas \enc{König}{Koenig}, Klaus \enc{Jünemann}{Juenemann} \ifelse{html}{\out{&}}{&} Matthias Burger} \seealso{ \code{\link{tracker}} for the call tracking object, and \code{\link{printHTML}} for displaying results. } \examples{ ## example function foo <- function(x){ y <- 0 for(i in 1:100) { y <- y + i } return(y) } ## the name track is necessary track <- tracker() ## initialize the tracker track$init() ## inspect the function ## res will collect the result of calling foo res <- inspect(foo(10), track = track) ## get the tracked function call info resTrack <- track$getTrackInfo() ## create HTML sites printHTML(resTrack, baseDir=tempdir()) } \keyword{programming} \concept{RUnit} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/man/RUnit-options.Rd��������������������������������������������������������������������������0000644�0001751�0000144�00000004415�13267374743�015151� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \encoding{latin1} \name{options} \alias{RUnit options} \alias{RUnit-options} \title{RUnit options} \description{ RUnit uses three options available via the global R options list } \details{ RUnit specif options are added to R's global options list on package loading and removed again on pachage unloading. } \section{Options used in RUnit}{ \describe{ \item{\code{silent}:}{logical flag, default \code{FALSE}, sets the 'silent' argument for \code{checkException}. Allows to globally silence output from exception checks for all test suites excuted in one run.} \item{\code{verbose}:}{non-negative integer, default \code{1}, \code{0}: surpresses enclosing begin/end messages for each test case, \code{1}: output enclosing begin/end messages for each test case} \item{\code{outfile}:}{\code{NULL}, connection or character, default \code{NULL}. If non-null has to be an open connection or a file name. Will be used to redirect all output to specified file/connection using \code{sink}. Connection is close after test suite execution call (via \code{runTestSuite} or \code{runTestFile}) has completed. If the file exists it is overwriten.} } } \author{Matthias Burger} \seealso{\code{\link{options}}, \code{\link{getOption}}, \code{\link{sink}}.} \examples{ \dontrun{ ## quiet log output ro <- getOption("RUnit") ro$silent <- TRUE ro$verbose <- 0L options("RUnit"=ro) } } \keyword{programming} \keyword{environment} \concept{RUnit} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/man/checkFuncs.Rd�����������������������������������������������������������������������������0000644�0001751�0000144�00000016060�14563664702�014467� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \encoding{utf8} \name{checkFuncs} \alias{checkEquals} \alias{checkEqualsNumeric} \alias{checkIdentical} \alias{checkTrue} \alias{checkException} \alias{DEACTIVATED} \title{RUnit check functions} \usage{ checkEquals(target, current, msg, tolerance = .Machine$double.eps^0.5, checkNames = TRUE, ...) checkEqualsNumeric(target, current, msg, tolerance = .Machine$double.eps^0.5, ...) checkIdentical(target, current, msg) checkTrue(expr, msg) checkException(expr, msg, silent = getOption("RUnit")$silent) DEACTIVATED(msg) } \arguments{ \item{current, target}{objects to be compared (\code{checkEqualsNumeric} cannot handle S4 class objects).} \item{msg}{an optional message to document a check and to facilitate the identification of a possible failure. The message only appears as text in the test protocol, it is not further used in any of the check functions.} \item{tolerance}{numeric >= 0. A numeric check does not fail if differences are smaller than `tolerance'.} \item{checkNames}{flag, if \code{FALSE} the names attributes are set to \code{NULL} for both current and target before performing the check.} \item{expr}{syntactically valid R expression which can be evaluated and must return a logical scalar (\code{TRUE}|\code{FALSE}). A named expression is also allowed but the name is disregarded.} \item{silent}{flag passed on to \code{try}, which determines if the error message generated by the checked function is displayed. Queried from global options set for RUnit at package load.} \item{...}{optional arguments passed to \code{all.equal} or \code{all.equal.numeric}} } \description{A set of functions used to check the results of some test calculation. If these functions are called within the RUnit framework, the results of the checks are stored and reported in the test protocol. \code{checkEquals} compares two R objects by invoking \code{all.equal} on the two objects. If the objects are not equal an error is generated and the failure is reported to the test logger such that it appears in the test protocol. \code{checkEqualsNumeric} works just like \code{checkEquals} except that it invokes \code{all.equal.numeric} instead of \code{all.equal} \code{checkIdentical} is a convenience wrapper around identical using the error logging mechanism of RUnit. \code{checkTrue} uses the function \code{identical} to check if the expression provided as first argument evaluates to \code{TRUE}. If not, an error is generated and the failure is reported to the test logger such that it appears in the test protocol. \code{checkException} evaluates the passed expression and uses the \code{try} mechanism to check if the evaluation generates an error. If it does the test is OK. Otherwise an error is generated and the failure is reported to the test logger such that it appears in the test protocol. \code{DEACTIVATED} interrupts the test function and reports the test case as deactivated. In the test protocol deactivated test functions are listed separately. Test case deactivation can be useful in the case of major refactoring. Alternatively, test cases can be commented out completely but then it is easy to forget the test case altogether. } \details{ The check functions are direct equivalents of the various methods of the class junit.framework.Assert of Javas JUnit framework which served as basis for the RUnit package. For functions defined inside a package equipped with a namespace only exported functions can be accessed inside test cases directly. For functions not exported the only way to test them is to use the '\code{\link[base:ns-dblcolon]{:::}}' operator combined with the package name as a prefix. Special care is required if test cases are written for S4 classes and methods. If a new class is defined inside a test case via a \code{\link[methods]{setClass}} call the class is added to the global class cache and thus available outside the test case. It will persist until explicitly removed via a \code{\link[methods:findClass]{removeClass}} call. Same applies for new method and generic definitions. Be sure to remove methods and classes in each test case they are defined after the checks have been performed. This is an advise gained from the cumbersome experience: not doing so leads to difficult to pin down error causes incurred from previously executed test cases. For a simple example see the provided test cases in \Sexpr{file.path(system.file("examples", package="RUnit"), "runitVirtualClassTest.r")}. } \author{ Thomas \enc{König}{Koenig}, Klaus \enc{Jünemann}{Juenemann} \ifelse{html}{\out{&}}{&} Matthias Burger} \seealso{ \code{\link{all.equal}}, \code{\link{all.equal.numeric}} and \code{\link{identical}} are the underlying comparison functions. \code{\link{try}} is used for error catching. \code{\link{.setUp}} for details on test case setup. See \link{RUnit-options} for global options controlling log out. } \examples{ checkTrue(1 < 2, "check1") ## passes fine ## checkTrue(1 > 2, "check2") ## appears as failure in the test protocol v <- 1:3 w <- 1:3 checkEquals(v, w) ## passes fine names(v) <- c("A", "B", "C") ## checkEquals(v, w) ## fails because v and w have different names checkEqualsNumeric(v, w) ## passes fine because names are ignored x <- rep(1:12, 2) y <- rep(0:1, 12) res <- list(a=1:3, b=letters, LM=lm(y ~ x)) res2 <- list(a=seq(1,3,by=1), b=letters, LM=lm(y ~ x)) checkEquals( res, res2) ## passes fine checkIdentical( res, res) checkIdentical( res2, res2) ## checkIdentical( res, res2) ## fails because element 'a' differs in type fun <- function(x) { if(x) { stop("stop conditions signaled") } return() } checkException(fun(TRUE)) ## passes fine ## checkException(fun(FALSE)) ## failure, because fun raises no error checkException(fun(TRUE), silent=TRUE) ## special constants ## same behaviour as for underlying base functions checkEquals(NA, NA) checkEquals(NaN, NaN) checkEquals(Inf, Inf) checkIdentical(NA, NA) checkIdentical(NaN, NaN) checkIdentical(-Inf, -Inf) ## DEACTIVATED("here one can document on the reason for deactivation") } \keyword{programming} \concept{RUnit} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/man/tracker.Rd��������������������������������������������������������������������������������0000644�0001751�0000144�00000007353�14563756550�014056� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \encoding{utf8} \name{tracker} \alias{tracker} \title{Tracking the results of the inspect process.} \usage{tracker() } \description{ The current implementation uses the 'closure trick' to hide all details from the user and only allows to retrieve the results of the code inspection. \code{tracker} is used to create a new environment to manage and store the results of the tracking process. The \code{inspect} function requires such an environment with the name "track" (currently mandatory). The tracker records how often each and every function was called by \code{inspect} and summarizes the results of all calls. \code{tracker$init} initializes the tracker environment. \code{tracker$getTrackInfo} returns a list with the tracked results of the inspection process. } \section{Methods}{ \tabular{rll}{ \tab \code{init} \tab initializes the tracker environment\cr \tab \code{addFunc} \tab add function to the inspect tracking list (internal use)\cr \tab \code{getSource} \tab return the modified source code used for during inspection the specified index (internal use)\cr \tab \code{bp} \tab update tracking info for specified function index (internal use)\cr \tab \code{getTrackInfo} \tab return 'trackInfo' object\cr \tab \code{isValid} \tab check 'trackInfo' object for conformance to class contract \cr } } \details{The 'trackInfo' S3 class object (list) has one entry for each function on the inspect list with the following elements: \describe{ \item{src}{The source code of the function.} \item{run}{The number of executions for each line of code.} \item{graph}{A matrix. Each element in the matrix counts how often a code line was called from the previous code line in the execution flow.} \item{nrRuns}{Counts how often the function was called.} \item{funcCall}{The declaration of the function.} } } \author{ Thomas \enc{König}{Koenig}, Klaus \enc{Jünemann}{Juenemann} \ifelse{html}{\out{&}}{&} Matthias Burger} \seealso{ \code{\link{inspect}} for the registration of functions & methods to be on the tracking list, and \code{\link{printHTML}} for displaying results } \examples{ ## example functions foo <- function(x){ y <- 0 for(i in 1:100) { y <- y + i } return(y) } bar <- function(x){ y <- 0 for(i in 1:100) { y <- y - i } return(y) } ## the object name track is 'fixed' (current implementation) track <- tracker() ## initialize the tracker track$init() ## inspect the function ## resFoo1 will contain the result of calling foo(50) resFoo1 <- inspect(foo(50), track = track) resFoo2 <- inspect(foo(20), track = track) resBar1 <- inspect(bar(30), track = track) ## get the tracked function call info for all inspect calls resTrack <- track$getTrackInfo() ## create HTML sites in folder <tempdir>/results for all inspect calls printHTML(resTrack, baseDir=tempdir()) } \keyword{programming} \concept{RUnit} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/man/runit.Rd����������������������������������������������������������������������������������0000644�0001751�0000144�00000023363�14563756525�013565� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \encoding{utf8} \name{runTestSuite} \alias{runTestSuite} \concept{test suite} \alias{runTestFile} \concept{test runner} \alias{defineTestSuite} \alias{isValidTestSuite} \title{Definition and execution of RUnit test suites.} \usage{ defineTestSuite(name, dirs, testFileRegexp = "^runit.+\\\\.[rR]$", testFuncRegexp = "^test.+", rngKind = "Marsaglia-Multicarry", rngNormalKind = "Kinderman-Ramage") isValidTestSuite(testSuite) runTestSuite(testSuites, useOwnErrorHandler = TRUE, verbose = getOption("RUnit")$verbose, gcBeforeTest = FALSE) runTestFile(absFileName, useOwnErrorHandler = TRUE, testFuncRegexp = "^test.+", rngKind = "Marsaglia-Multicarry", rngNormalKind = "Kinderman-Ramage", verbose = getOption("RUnit")$verbose, gcBeforeTest = FALSE) } \arguments{ \item{name}{The name of the test suite.} \item{dirs}{Vector of absolute directory names where to look for test files.} \item{testFileRegexp}{Regular expression for matching test files.} \item{testFuncRegexp}{Regular expression for matching test functions.} \item{rngKind}{name of an available RNG (see \code{\link[base:Random]{RNGkind}} for possible options).} \item{rngNormalKind}{name of a valid rnorm RNG version (see \code{\link[base:Random]{RNGkind}} for possible options).} \item{testSuite}{A single object of class test suite.} \item{testSuites}{A single object of class test suite or a list of test suite objects.} \item{useOwnErrorHandler}{If \code{TRUE} the RUnit framework installs its own error handler during test case execution (but reinstalls the original handler before it returns). If \code{FALSE} the error handler is not touched by RUnit but then the test protocol does not contain any call stacks in the case of errors.} \item{verbose}{level of verbosity of output log messages, 0: omits begin/end comments for each test function. Queried from global options set for RUnit at package load.} \item{absFileName}{Absolute file name of a test function.} \item{gcBeforeTest}{Run garbage collector before executing a test for more precise test timing. Enabling this option makes the tests run longer, especially when testing many small tests. By default GC is disabled (since 0.4.32).} } \description{ \code{runTestSuite} is the central function of the RUnit package. Given one or more test suites it identifies and sources specified test code files one after another and executes all specified test functions defined therein. This is done sequentially for suites, test code files and test functions. During the execution information about the test function calls including the possible occurrence of failures or errors is recorded and returned at the end of the test run. The return object can then be used to create a test protocol of various formats. \code{runTestFile} is just a convenience function for executing the tests in a single test file. \code{defineTestSuite} is a helper function to define a test suite. See below for a precise definition of a test suite. \code{isValidTestSuite} checks if an object defines a valid test suite. } \details{ The basic idea of the RUnit test framework is to declare a certain set of functions to be test functions and report the results of their execution. The test functions must not take any parameter nor return anything such that their execution can be automatised. The specification which functions are taken as test functions is contained in an object of class \code{RUnitTestSuite} which is a list with the following elements. \describe{ \item{name}{A simple character string. The name of a test suite is mainly used to create a well structure test protocol.} \item{dirs}{A character vector containing the absolute names of all directories where to look for test files.} \item{testFileRegexp}{A regular expression specifying the test files. All files in the test directories whose names match this regular expression are taken as test files. Order of file names will be alphabetical but depending on the used locale.} \item{testFuncRegexp}{A regular expression specifying the test functions. All functions defined in the test files whose names match this regular expression are used as test functions. Order of test functions will be alphabetical.} } After the RUnit framework has sequentially executed all test suites it returns all data collected during the test run as an object of class \code{RUnitTestData}. This is a (deeply nested) list with one list element for each executed test suite. Each of these executed test suite lists contains the following elements: \describe{ \item{nTestFunc}{The number of test functions executed in the test suite.} \item{nErr}{The number of errors that occurred during the execution.} \item{nFail}{The number of failures that occurred during the execution.} \item{dirs}{The test directories of the test suite.} \item{testFileRegexp}{The regular expression for identifying the test files of the test suite.} \item{testFuncRegexp}{The regular expression for identifying the test functions of the test suite.} \item{sourceFileResults}{A list containing the results for each separate test file of the test suite.} } The \code{sourceFileResults} list just mentioned contains one element for each specified test function in the source file. This element is a list with the following entries: \describe{ \item{kind}{Character string with one of \code{success}, \code{error} or \code{failure} describing the outcome of the test function.} \item{msg}{the error message in case of an error or failure and \code{NULL} for a successfully executed test function.} \item{time}{The duration (measured in seconds) of the successful execution of a test function and \code{NULL} in the case of an error or failure. When running with \code{gcBeforeTest} option set to \code{FALSE} (default since 0.4.32), the timing of the tests might be misleading when garbage collector has to reclaim memory allocated by a previous test.} \item{traceBack}{The full trace back as a character vector in the case of an error and \code{NULL} otherwise.} } To further control test case execution it is possible to define two parameterless function \code{.setUp} and \code{\link{.tearDown}} in each test file. \code{.setUp()} is executed directly before and \code{.tearDown()} directly after each test function execution. Quite often, it is useful to base test cases on random numbers. To make this procedure reproducible, the function \code{runTestSuite} sets the random number generator to the default setting \code{RNGkind(kind="Marsaglia-Multicarry", normal.kind="Kinderman-Ramage")} before sourcing each test file (note that this default has been chosen due to historical reasons and differs from the current R default). This default can be overwritten by configuring the random number generator at the beginning of a test file. This setting, however, is valid only inside its own source file and gets overwritten when the next test file is sourced. } \value{ \code{runTestSuite} and \code{runTestFile} both return an object of class RUnitTestData. \code{defineTestSuite} returns an object of class \code{RUnitTestSuite}. } \author{ Thomas \enc{König}{Koenig}, Klaus \enc{Jünemann}{Juenemann} \ifelse{html}{\out{&}}{&} Matthias Burger} \seealso{ \code{\link{checkTrue}} and friends for writing test cases. \code{\link{printTextProtocol}} and \code{\link{printHTMLProtocol}} for printing the test protocol. See \link{RUnit-options} for global options controlling log out. } \examples{ ## run some test suite myTestSuite <- defineTestSuite("RUnit Example", system.file("examples", package = "RUnit"), testFileRegexp = "correctTestCase.r") testResult <- runTestSuite(myTestSuite) ## same but without the logger being involved ## source(file.path(system.file("examples", package = "RUnit"), ## "correctTestCase.r")) ## test.correctTestCase() ## prints detailed text protocol ## to standard out: printTextProtocol(testResult, showDetails = TRUE) ## use current default RNGs myTestSuite1 <- defineTestSuite("RUnit Example", system.file("examples", package = "RUnit"), testFileRegexp = "correctTestCase.r", rngKind = "Mersenne-Twister", rngNormalKind = "Inversion") testResult1 <- runTestSuite(myTestSuite) ## for single test files, e.g. outside a package context testResult2 <- runTestFile(file.path(system.file("examples", package = "RUnit"), "correctTestCase.r")) printTextProtocol(testResult2, showDetails = TRUE) } \keyword{programming} \concept{RUnit} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/man/textProtocol.Rd���������������������������������������������������������������������������0000644�0001751�0000144�00000015422�14563756551�015126� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \encoding{utf8} \name{textProtocol} \alias{printTextProtocol} \alias{printHTMLProtocol} \alias{printJUnitProtocol} \alias{print.RUnitTestData} \alias{summary.RUnitTestData} \alias{getErrors} \title{Printing a plain text, HTML or JUnit-like XML version of an RUnit test run protocol.} \usage{ printTextProtocol(testData, fileName = "", separateFailureList = TRUE, showDetails = TRUE, traceBackCutOff = 9) printHTMLProtocol(testData, fileName = "", separateFailureList = TRUE, traceBackCutOff = 9, testFileToLinkMap = function(x) x ) printJUnitProtocol(testData, fileName = "") \method{print}{RUnitTestData}(x, ...) \method{summary}{RUnitTestData}(object, ...) getErrors(testData) } \arguments{ \item{testData, x, object}{objects of class \code{RUnitTestData}, typically obtained as return value of a test run.} \item{fileName}{Connection where to print the text protocol (printing is done by the \code{cat} command).} \item{separateFailureList}{If \code{TRUE} a separate list of failures and errors is produced at the top of the protocol. Otherwise, the failures and errors are only listed in the details section.} \item{showDetails}{If \code{TRUE} the protocol contains a detailed listing of all executed test functions.} \item{traceBackCutOff}{The details section of the test protocol contains the call stack for all errors. The first few entries of the complete stack typically contain the internal RUnit function calls that execute the test cases and are irrelevant for debugging. This argument specifies how many calls are removed from the stack before it is written to the protocol. The default value is chosen such that all uninteresting RUnit calls are removed from the stack if \code{runTestSuite} has been called from the console. This argument takes effect only if \code{showDetails=TRUE}.} \item{testFileToLinkMap}{This function can be used to map the full name of the test file to a corresponding html link to be used in the html protocol. By default, this is the identity map. See example below.} \item{...}{additional arguments to summary are passed on to the printTextProtocol() call.} } \description{ \code{printTextProtocol} prints a plain text protocol of a test run. The resulting test protocol can be configured through the function arguments. \code{printHTMLProtocol} prints an HTML protocol of a test run. For long outputs this version of the test protocol is slightly more readable than the plain text version due to links in the document. The resulting test protocol can be configured through the function arguments. \code{printJUnitProtocol} prints a JUnit-style XML protocol of a test run. This feature is especially useful when running your RUnit tests through a continuous integration server that understands JUnit (like Jenkins). This machine-parseable output allows you to track errors over time, sort by execution time and similar useful tricks. To take advantage of this function, you have to have the XML package installed. \code{print} prints the number of executed test functions and the number of failures and errors. \code{summary} directly delegates the work to \code{printTextProtocol}. \code{getErrors} returns a list containing the number of test functions, the number of deactivated functions (if there are any), the number of errors and the number of failures. } \details{ The text protocol can roughly be divided into three sections with an increasing amount of information. The first section as an overview just reports the number of executed test functions and the number of failures and errors. The second section describes all test suites. Optionally, all errors and failures that occurred in some test suite are listed. In the optional third section details are given about all executed test functions in the order they were processed. For each test file all test functions executed are listed in the order they were executed. After the test function name the number of \code{check<*>} function calls inside the test case and the execution time in seconds are stated. In the case of an error or failure as much debug information as possible is provided. } \author{ Thomas \enc{König}{Koenig}, Klaus \enc{Jünemann}{Juenemann}, Matthias Burger \ifelse{html}{\out{&}}{&} Roman Zenka} \seealso{ \code{\link{runTestSuite}} } \examples{ ## run some test suite myTestSuite <- defineTestSuite("RUnit Example", system.file("examples", package = "RUnit"), testFileRegexp = "correctTestCase.r") testResult <- runTestSuite(myTestSuite) ## prints detailed text protocol ## to standard out: printTextProtocol(testResult, showDetails = TRUE) ## prints detailed html protocol ## to standard out printHTMLProtocol(testResult) ## prints JUnit-style XML protocol ## to standard out. ## You need to have XML package installed for this if(require("XML")) { printJUnitProtocol(testResult) } \dontrun{ ## example function to add links to URL of the code files in a code ## repository, here the SourceForge repository testFileToSFLinkMap <- function(testFileName, testDir = "tests") { ## get unit test file name bname <- basename(testFileName) ## figure out package name regExp <- paste("^.*/([\\.a-zA-Z0-9]*)/", testDir,"/.*$", sep = "") pack <- sub(regExp, "\\1", testFileName) return(paste("http://runit.cvs.sourceforge.net/runit/", pack, testDir, bname, sep = "/")) } ## example call for a test suite run on the RUnit package testSuite <- defineTestSuite("RUnit", "<path-to-source-folder>/RUnit/tests", testFileRegexp = "^test.+") testResult <- runTestSuite(testSuite) printHTMLProtocol(testResult, fileName = "RUnit-unit-test-log.html", testFileToLinkMap = testFileToSFLinkMap ) } } \keyword{programming} \concept{RUnit} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/man/RUnit-internal.Rd�������������������������������������������������������������������������0000644�0001751�0000144�00000002775�13267374743�015301� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \name{RUnit-internal} \alias{includeTracker} \alias{plotConnection.trackInfo} \alias{writeBeginBody} \alias{writeBeginHead} \alias{writeBeginHtml} \alias{writeBeginTag} \alias{writeBeginTable} \alias{writeCR} \alias{writeEndBody} \alias{writeEndHead} \alias{writeEndHtml} \alias{writeEndTable} \alias{writeEndTag} \alias{writeHtmlEnd} \alias{writeHtmlHeader} \alias{writeHtmlSection} \alias{writeHtmlSep} \alias{writeImage} \alias{writeLi} \alias{writeLinkRef} \alias{writeLink} \alias{writeP} \alias{writeRaw} \alias{writeRawCR} \alias{writeTableRow} \alias{writeTitle} \title{Internal functions} \description{ Helper functions and private methods not intended for direct use. } \keyword{internal} ���RUnit/man/printHTML.Rd������������������������������������������������������������������������������0000644�0001751�0000144�00000005215�14563756537�014244� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%% RUnit : A unit test framework for the R programming language %% Copyright (C) 2003-2009 Thomas Koenig, Matthias Burger, Klaus Juenemann %% %% This program is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by %% the Free Software Foundation; version 2 of the License. %% %% This program is distributed in the hope that it will be useful, %% but WITHOUT ANY WARRANTY; without even the implied warranty of %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %% GNU General Public License for more details. %% %% You should have received a copy of the GNU General Public License %% along with this program; if not, write to the Free Software %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% $Id$ \encoding{utf8} \name{printHTML} \alias{printHTML} \title{Write HTML pages of the tracking result.} \usage{ printHTML(object, baseDir = ".") } \arguments{ \item{object}{'trackInfo' S3 class object (list), containing the result of the function \code{tracker}.} \item{baseDir}{A character string, specifying the base directory for the HTML pages to be written to. Defaults to the current working directory.} } \description{ \code{printHTML} creates a subdirectory named "result" in the base directory specified via \code{baseDir}. All HTML pages and images will be put in that directory. } \details{An "index.html" page will be created in the directory "results" which is the root entry page of the HTML pages. The displayed result for every tracked function consists of two HTML pages. The first page is an overview on how often every line of code was executed. Code lines not executed are highlighted red, executed lines are shown in green. The second page is a graph representation of the execution flow of the function. Each code line has a edge pointing to the next code line that is executed subsequently. Thus loops and jumps become clearly visible. } \author{ Thomas \enc{König}{Koenig}, Klaus \enc{Jünemann}{Juenemann} \ifelse{html}{\out{&}}{&} Matthias Burger} \seealso{ \code{\link{tracker}} for the call tracking object definition. } \examples{ ## example function foo <- function(x){ y <- 0 for(i in 1:100) { y <- y + i } return(y) } ## the name track is necessary track <- tracker() ## initialize the tracker track$init() ## inspect the function ## res is the result of foo res <- inspect(foo(10), track = track) ## get the tracking info resTrack <- track$getTrackInfo() ## create HTML pages printHTML(resTrack, baseDir=tempdir()) } \keyword{programming} \concept{RUnit} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RUnit/DESCRIPTION�����������������������������������������������������������������������������������0000644�0001751�0000144�00000002442�15024244447�013047� 0����������������������������������������������������������������������������������������������������ustar �hornik��������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Package: RUnit Version: 0.4.33.1 Date: 2024-02-09 Title: R Unit Test Framework Authors@R: c(person(given = "Matthias", family = "Burger", role = "aut", email = "burgerm@users.sourceforge.net"), person(given = "Klaus", family = "Juenemann", role = "aut", email = "k.junemann@gmx.net"), person(given = "Thomas", family = "Koenig", role = "aut", email = "thomas.koenig@epigenomics.com"), person(given = "Roman", family = "Zenka", role = "cre", email = "zenka.roman@mayo.edu")) LazyLoad: yes Depends: R (>= 2.5.0), utils (>= 2.5.0), methods (>= 2.5.0), graphics (>= 2.5.0) Suggests: XML (>= 3.1.0) Description: R functions implementing a standard Unit Testing framework, with additional code inspection and report generation tools. License: GPL-2 NeedsCompilation: no Packaged: 2025-06-17 10:32:59 UTC; hornik Repository: CRAN Date/Publication: 2025-06-17 10:53:27 UTC Author: Matthias Burger [aut], Klaus Juenemann [aut], Thomas Koenig [aut], Roman Zenka [cre] Maintainer: Roman Zenka <zenka.roman@mayo.edu> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������