Nothing
## 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)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.