How to add a reporter to testthat? - r

I'm trying to add a JUnit reporter to testthat. While I can do it inside the package (https://github.com/hadley/testthat/pull/481) I cannot make it pass the same set of tests when in a separate package (https://github.com/lbartnik/testthatJUnit).
My main problem is that tests designed for reporters and present in testthat do not pass if I pull JUnit reporter code to a separate package. I'm guessing that there is something in those tests that "sets the scene" for testing reporters but I'm unable to identify this "something".
Any help much appreciated.
Details follow.
> library(devtools)
> test("testthatJUnit")
Loading testthatJUnit
Testing testthatJUnit
JUnitReporter:
DONE ==========================================================================
> test("testthat")
Loading testthat
unloadNamespace("testthat") not successful, probably because another loaded package depends on it.Forcing unload. If you encounter problems, please restart R.
Testing testthat
Bare expectations:
Colours: ..
compare.character: .................
compare.numeric: .....................
compare.time: .......
# ... lines cut ...
DONE ===========================================================================
> test("testthatJUnit")
Loading testthatJUnit
Testing testthatJUnit
JUnitReporter: .............
If I modify the test to see why the first test("testthatJUnit") is silent I see this:
> test("testthatJUnit")
Loading testthatJUnit
Testing testthatJUnit
JUnitReporter: Bare: .1
Failed -------------------------------------------------------------------------
1. Error: Junit reporter regression (#test-reporter-junit.R#13) ----------------
attempt to apply non-function
1: test_dir("test_dir") at /mnt/storage-a/lukaszb/src/third-party/testthatJUnit/tests/testthat/test-reporter-junit.R:13
2: test_files(paths, reporter = reporter, env = env, ...)
3: with_reporter(reporter = current_reporter, results <- lapply(paths, test_file, env = env,
reporter = current_reporter, start_end_reporter = FALSE, load_helpers = FALSE))
4: force(code)
5: lapply(paths, test_file, env = env, reporter = current_reporter, start_end_reporter = FALSE,
load_helpers = FALSE)
6: FUN(X[[i]], ...)
7: with_reporter(reporter = reporter, start_end_reporter = start_end_reporter, {
lister$start_file(basename(path))
source_file(path, new.env(parent = env), chdir = TRUE)
end_context()
})
8: force(code)
9: source_file(path, new.env(parent = env), chdir = TRUE)
10: eval(exprs, env)
11: eval(expr, envir, enclos)
12: expect_that(1, equals(1)) at test_dir/test-bare-expectations.R:3
13: condition(object)
14: expect_equal(x, expected, ..., expected.label = label)
15: expect(comp$equal, sprintf("%s not equal to %s.\n%s", lab_act, lab_exp, comp$message),
info = info)
16: withRestarts(if (expectation_broken(exp)) {
stop(exp)
} else {
signalCondition(exp)
}, continue_test = function(e) NULL)
17: withOneRestart(expr, restarts[[1L]])
18: doWithOneRestart(return(expr), restart)
19: signalCondition(exp)
20: (function (e)
{
register_expectation(e, frame + 11, sys.nframe() - 6)
invokeRestart("continue_test")
})(structure(list(message = "1 not equal to 1.\nEqual\n", srcref = NULL), .Names = c("message",
"srcref"), class = c("expectation_success", "expectation", "condition")))
21: register_expectation(e, frame + 11, sys.nframe() - 6)
22: get_reporter()$add_result(context = get_reporter()$.context, test = test, result = e)
23: o_apply(self$reporters, "add_result", context = context, test = test, result = result)
24: lapply(objects, function(x) x[[method]](...))
25: FUN(X[[i]], ...)
26: x[[method]](...)
But if I run test("testthat") and again test("testthatJUnit") everything comes back to normal:
> test("testthatJUnit")
Loading testthatJUnit
Testing testthatJUnit
JUnitReporter: Bare: ..
Basic: .......
empty: 1
error: 2.3456.
failures: 7.8..
helper: .
skip: S
My guess is that there is something in testthat's tests that sets up the scene for testing reporters but so far I haven't been able to identify it. Any help?

Actually, it turned out there is a bug in testthat 1.0.2 that is already fixed in the github sources (https://github.com/hadley/testthat/commit/99c25fc4efefa012a36d8fc912210ba3452a978d). With this version of testthat all tests in my package pass with no errors.

Related

rmarkdown render NSE function fails only inside callr

I seem to have a weird combination of NSE, rmarkdown and callr, similar in flavor to Is it possible to disable `callr` for RMarkdown?.
When I set a value to a variable to use it in something similar to a filter call implemented using NSE via nested evals and list calls, it fails horribly, but only in callr.
---
title: "Test CC2 Failure Reproducibly"
author: "Robert M Flight"
output: rmarkdown::md_document
editor_options:
chunk_output_type: console
---
```{r run_enrichments}
set.seed(1234)
create_go_annotation = function(db, ontology = NULL){
all_genes = keys(db)
go_all_gene = AnnotationDbi::select(db, keys = all_genes, columns = c("GOALL", "ONTOLOGYALL"))
if (!is.null(ontology)) {
go_all_gene = go_all_gene[go_all_gene$ONTOLOGYALL == ontology, ]
ontology_type = paste0("GO.", ontology)
} else {
ontology_type = "GO.all"
}
go_2_gene = split(go_all_gene$ENTREZID, go_all_gene$GOALL)
go_2_gene = lapply(go_2_gene, unique)
go_desc = AnnotationDbi::select(GO.db::GO.db, keys = names(go_2_gene), columns = "TERM", keytype = "GOID")$TERM
names(go_desc) = names(go_2_gene)
go_annotation = categoryCompare2::annotation(annotation_features = go_2_gene,
description = go_desc,
annotation_type = ontology_type,
feature_type = "ENTREZID")
go_annotation
}
library(org.Hs.eg.db)
library(GO.db)
library(categoryCompare2)
library(methods)
go_mf = create_go_annotation(org.Hs.eg.db, "MF")
all_features = unique(unlist(go_mf#annotation_features))
sig_features = sample(all_features, 500)
enrich = hypergeometric_feature_enrichment(
new("hypergeom_features", significant = sig_features,
universe = all_features,
annotation = go_mf),
p_adjust = "BH"
)
comb_enrich = combine_enrichments(sig1 = enrich)
sig_cutoff = 0.1
filter_enrich = get_significant_annotations(comb_enrich, padjust <= sig_cutoff)
```
Run it via callr:
r(function() rmarkdown::render(here::here("categoryCompare2_failure.Rmd"), output_file = "cc2_fails_1.md"), show = TRUE)
# Quitting from lines 13-57 (categoryCompare2_failure.Rmd)
#
# Error in FUN(X[[i]], ...) : object 'sig_cutoff' not found
# Error: callr subprocess failed: object 'sig_cutoff' not found
# > .Last.error.trace
# Stack trace:
# Process 221313:
# 1. callr:::r(function() rmarkdown::render(here::he ...
# 2. callr:::get_result(output = out, options)
# 3. throw(newerr, parent = remerr[[2]])
# x callr subprocess failed: object 'sig_cutoff' not found
# Process 221619:
# 15. (function () ...
# 16. rmarkdown::render(here::here("categoryCompare2_failure.Rmd"))
# 17. knitr::knit(knit_input, knit_output, envir = envir, quiet ...
# 18. knitr:::process_file(text, output)
# 19. base:::withCallingHandlers(if (tangle) process_tangle(gro ...
# 20. knitr:::process_group(group)
# 21. knitr:::process_group.block(group)
# 22. knitr:::call_block(x)
# 23. knitr:::block_exec(params)
# 24. knitr:::eng_r(options)
# 25. knitr:::in_dir(input_dir(), evaluate(code, envir = env, n ...
# 26. knitr:::evaluate(code, envir = env, new_device = FALSE, k ...
# 27. evaluate::evaluate(...)
# 28. evaluate:::evaluate_call(expr, parsed$src[[i]], envir = e ...
# 29. evaluate:::timing_fn(handle(ev <- withCallingHandlers(wit ...
# 30. base:::handle(ev <- withCallingHandlers(withVisible(eval( ...
# 31. base:::withCallingHandlers(withVisible(eval(expr, envir, ...
# 32. base:::withVisible(eval(expr, envir, enclos))
# 33. base:::eval(expr, envir, enclos)
# 34. base:::eval(expr, envir, enclos)
# 35. categoryCompare2:::get_significant_annotations(comb_enric ...
# 36. categoryCompare2:::get_significant_annotations(comb_enric ...
# 37. categoryCompare2:::.get_significant_combined_enrichment(i ...
# 38. base:::lapply(in_results#enriched, function(x) { ...
# 39. categoryCompare2:::FUN(X[[i]], ...)
# 40. categoryCompare2:::get_significant_annotations(x#statisti ...
# 41. categoryCompare2:::get_significant_annotations(x#statisti ...
# 42. categoryCompare2:::.get_significant_stat_results(in_resul ...
# 43. categoryCompare2:::multi_query_list(in_results#statistic_ ...
# 44. base:::lapply(queries, eval, list_to_query)
# 45. base:::FUN(X[[i]], ...)
# 46. base:::FUN(X[[i]], ...)
# 47. base:::.handleSimpleError(function (e) ...
# 48. h(simpleError(msg, call))
# x object 'sig_cutoff' not found
You can see that it complains that sig_cutoff is not found, but it exists in the environment, but does not seem to get passed down.
If I instead run it directly, it works:
rmarkdown::render(here::here("categoryCompare2_failure.Rmd"), output_file = "cc2_works.md")
I've put all the code in a github repo.
Interestingly, it's definitely a callr issue, because targets has the same issue.
callr v 1.0.7, rmarkdown v 2.11, R 4.1.0
Other package versions are in the renv.lock file.

devtools::check fails with cpp_object_initializer

I run devtools::test and it works:
$ RScript -e "devtools::test()"
...
OK: 24
But devtools::check fails at a test:
$ RScript -e "devtools::check()"
...
> test_check("package")
Error in cpp_object_initializer(.self, .refClassDef, ...) :
could not find function "cpp_object_initializer"
Stan model 'bayes_logit' does not contain samples.
── 1. Error: Mixture of Dirichlet Processes stick-breaking works and returns (#t
'data' must be of a vector type, was 'NULL'
1: mdp_logit_mvn_stickbreaking(n_samp = n_samp, mix_mean = NULL, mix_cov = NULL, posterior_sample = stan_sample,
prior_sample_size = 1, dataset = german, tol = 1e-08) at testthat/test_stick_breaking.R:35
2: MASS::mvrnorm(n = n_samp, mu = mix_mean, Sigma = mix_cov)
3: eigen(Sigma, symmetric = TRUE)
4: unname(as.matrix(x))
5: as.matrix(x)
6: as.matrix.default(x)
7: array(x, c(length(x), 1L), if (!is.null(names(x))) list(names(x), NULL) else NULL)
How can I fix it?
This is due to the difference between loading and attaching. I took the solution from this GitHub issue.
Add this in NAMESPACE to tell R where to find cpp_object_initialiser:
Depends:
Rcpp
This works, but it gives you a note. To avoid the note, add an Roxygen export around the function that uses the Rstan call:
#' #importFrom Rcpp cpp_object_initializer
function_name <- function(...) {...}

Error in unserialize(socklist[[n]]) : error reading from connection

I'm using R and I'm running a parallel code on 7 cores on a Linux machine.
When using a small dataset, my code takes about 2 hours and works fine.
When using a 6x larger dataset, the codes takes much longer (probably because it needs to swap), but then will randomly end, sometimes at 10%, sometimes at 18, 20, 30% or so. Looks totally random. RAM usage is usually at about 90%, SWAP usage at <50%.
I'm using foreach with the doSNOW backend.
This is the error code:
Error in unserialize(socklist[[n]]) : error reading from connection
Calls: %dopar% ... tryCatch -> tryCatchList -> tryCatchOne -> <Anonymous>
Execution halted
*** caught bus error ***
address 0x7f829d2adbd0, cause 'non-existent physical address'
An irrecoverable exception occurred. R is aborting now ...
And this is the SNOW outfile obtained by setting outfile="outfile.out" in the makeCluster call:
starting worker for localhost:11567
Type: EXEC
Loading required package: MASS
Loading required package: survival
Loading required package: sp
Attaching package: 'raster'
The following objects are masked from 'package:MASS':
area, select
Attaching package: 'data.table'
The following object is masked from 'package:raster':
shift
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
Type: EXEC
*** caught bus error ***
address 0x7ffada863636, cause 'non-existent physical address'
Traceback:
1: .Call("Rsx_nc4_get_vara_double", as.integer(ncid), as.integer(varid), as.integer(c.start), as.integer(c.count), fixmiss, imvstate, as.double(passed_missval), PACKAGE = "ncdf4")
2: ncvar_get_inner(ncid2use, varid2use, nc$var[[li]]$missval, addOffset, scaleFact, start = start, count = count, verbose = verbose, signedbyte = signedbyte, collapse_degen = collapse_degen)
3: getfun(nc, varid = zvar, start = start, count = count)
4: .readBrickCellsNetCDF(x, cells, layer, nl)
5: .cellValues(x, i)
6: .doExtract(x, i, drop = drop)
7: por[i]
8: por[i]
9: as.vector(por[i])
10: mainF(as.vector(por[i]))
11: eval(expr, envir, enclos)
12: eval(.doSnowGlobals$expr, envir = .doSnowGlobals$exportenv)
13: doTryCatch(return(expr), name, parentenv, handler)
14: tryCatchOne(expr, names, parentenv, handlers[[1L]])
15: tryCatchList(expr, classes, parentenv, handlers)
16: tryCatch(eval(.doSnowGlobals$expr, envir = .doSnowGlobals$exportenv), error = function(e) e)
17: fun(quote(list(i = 23339L)))
18: do.call("fun", lapply(args, enquote))
19: docall(msg$data$fun, msg$data$args)
20: doTryCatch(return(expr), name, parentenv, handler)
21: tryCatchOne(expr, names, parentenv, handlers[[1L]])
22: tryCatchList(expr, classes, parentenv, handlers)
23: tryCatch(docall(msg$data$fun, msg$data$args), error = handler)
24: doTryCatch(return(expr), name, parentenv, handler)
25: tryCatchOne(expr, names, parentenv, handlers[[1L]])
26: tryCatchList(expr, classes, parentenv, handlers)
27: tryCatch({ msg <- recvData(master) cat(paste("Type:", msg$type, "\n")) if (msg$type == "DONE") { closeNode(master) break } else if (msg$type == "EXEC") { success <- TRUE handler <- function(e) { success <<- FALSE structure(conditionMessage(e), class = c("snow-try-error", "try-error")) } t1 <- proc.time() value <- tryCatch(docall(msg$data$fun, msg$data$args), error = handler) t2 <- proc.time() value <- list(type = "VALUE", value = value, success = success, time = t2 - t1, tag = msg$data$tag) sendData(master, value) }}, interrupt = function(e) NULL)
28: slaveLoop(makeSOCKmaster(master, port))
29: eval(expr, envir, enclos)
30: eval(quote({ master <- "localhost" port <- "" snowlib <- Sys.getenv("R_SNOW_LIB") outfile <- Sys.getenv("R_SNOW_OUTFILE") args <- commandArgs() pos <- match("--args", args) args <- args[-(1:pos)] for (a in args) { pos <- regexpr("=", a) name <- substr(a, 1, pos - 1) value <- substr(a, pos + 1, nchar(a)) switch(name, MASTER = master <- value, PORT = port <- value, SNOWLIB = snowlib <- value, OUT = outfile <- value) } if (!(snowlib %in% .libPaths())) .libPaths(c(snowlib, .libPaths())) library(methods) library(snow) if (port == "") port <- getClusterOption("port") sinkWorkerOutput(outfile) cat("starting worker for", paste(master, port, sep = ":"), "\n") slaveLoop(makeSOCKmaster(master, port))}), new.env())
31: eval(expr, envir, enclos)
32: eval(expr, p)
33: eval.parent(substitute(eval(quote(expr), envir)))
34: local({ master <- "localhost" port <- "" snowlib <- Sys.getenv("R_SNOW_LIB") outfile <- Sys.getenv("R_SNOW_OUTFILE") args <- commandArgs() pos <- match("--args", args) args <- args[-(1:pos)] for (a in args) { pos <- regexpr("=", a) name <- substr(a, 1, pos - 1) value <- substr(a, pos + 1, nchar(a)) switch(name, MASTER = master <- value, PORT = port <- value, SNOWLIB = snowlib <- value, OUT = outfile <- value) } if (!(snowlib %in% .libPaths())) .libPaths(c(snowlib, .libPaths())) library(methods) library(snow) if (port == "") port <- getClusterOption("port") sinkWorkerOutput(outfile) cat("starting worker for", paste(master, port, sep = ":"), "\n") slaveLoop(makeSOCKmaster(master, port))})
An irrecoverable exception occurred. R is aborting now ...
The code is using 7 threads out of 8 of a local machine. The foreach call is made like so:
#Packages
packageVec <- c("RcppRoll", "FAdist", "fitdistrplus", "minpack.lm", "raster", "foreach", "data.table")
#Register cluster
cl <- makeCluster(nThreads, outfile=paste0(dischargefile, ".out"))
registerDoSNOW(cl)
#Create progress bar
pb <- txtProgressBar(max = ncells, style = 3)
progress <- function(n) setTxtProgressBar(pb, n)
SNOWopts <- list(progress = progress)
#Compute
a <-
foreach(i=cells, .packages=packageVec, .combine='rbind', .options.snow = SNOWopts) %dopar% {
mainF(as.vector(por[i]))
}
stopCluster(cl)
mainF() function description
It's hard to produce a MRE for this function, as it is complicated. The code is here, and I'll describe what the function does below. I want to stress the fact that all of this works wonderfully on a small dataset, but fails on a large dataset, even if it contains the same data of the small dataset replicated several times.
mainF() is a function whose input, por[i], is a 125000 element vector and whose output a 244 element vector. This function basically performs 240 rolling means on the input vector (using RcppRoll) and takes the maxima (using data.table) for each time slice (usually 15) for each mean, fits the data to a given distribution (using FAdist, raster and fitdistrplus), performs another loop for calculating another 240 values and fits (using minpack.lm) those values to a function to obtain more parameters. The 240 elements returned and the 4 fit parameters (2 for each fits) are returned.
How can I fix the above error? What does it mean?

Roxygenize fails with... is.call(call) is not TRUE

Every time I try to roxygenize a package I get this error:
Error: is.call(call) is not TRUE
The results of a traceback():
11: stop(sprintf(ngettext(length(r), "%s is not TRUE", "%s are not all TRUE"),
ch), call. = FALSE, domain = NA)
10: stopifnot(is.call(call))
9: standardise_call(call, env)
8: object_from_call(call, env, preref)
7: (function (call, ref, comment_ref)
{
preref <- parse.preref(as.character(comment_ref))
if (is.null(preref))
return()
preref$object <- object_from_call(call, env, preref)
preref$srcref <- list(filename = file, lloc = as.vector(ref))
add_defaults(preref)
})(dots[[1L]][[1L]], dots[[2L]][[1L]], dots[[3L]][[1L]])
6: mapply(FUN = f, ..., SIMPLIFY = FALSE)
5: Map(extract, parsed, refs, comment_refs)
4: FUN(c("/home/path/to/package/file1.r",
"/home/path/to/package/file2.r",
.... # list of files truncated
"/home/path/to/package/doc.file.r")[[25L]],
...)
3: lapply(r_files(base_path), parse_file, env = env)
2: parse_package(base_path, load_code)
1: roxygenize("~/Current/r/path/to/package/")
Has anyone experienced this problem before? I'm not even sure how to debug it further.
This error occurs if, instead of the typical NULL value that one puts at the end of the documentation for the package, one uses NA. Simply updating to NULL will remove the error.

gWidgets + tcltk - creating a simple window returns a error

I'm trying to make a small GUI to make it easier for other people to run a script.
I'm using gWidgets with tcltk on a Windows machine.
I create a simple window like this:
require(gWidgets)
require(gWidgetstcltk)
options(guiToolkit="tcltk")
win <- gwindow(title="This is a window!")
grp <- ggroup(container=win)
lbl <- glabel("Here you can write stuff:", container=grp)
txt <- gedit(text="Stuff", container=grp)
When I run it on a new session i get the error message:
Error in envRefInferField(x, what, getClass(class(x)), selfEnv) :
‘no_items’ is not a valid field or method name for reference class “Entry”
If i rerun after the error i get this:
<simpleError in envRefInferField(x, what, getClass(class(x)), selfEnv): ‘no_items’ is
not a valid field or method name for reference class “Entry”>
Anyone can explain what is going on?
EDIT:
The problem seems to only show up on RStudio and not on RGui.exe.
I'm not such an expert programmer, but I guess it is somehow related with the way RStudio manages the environments.
I guess the question now is more: How do i make this work normally in RStudio?
Traceback:
> traceback()
11: stop(gettextf("%s is not a valid field or method name for reference class %s",
sQuote(field), dQuote(thisClass#className)), domain = NA)
10: envRefInferField(x, what, getClass(class(x)), selfEnv)
9: r5_widget$no_items
8: r5_widget$no_items
7: .length(x#widget, x#toolkit)
6: .length(x#widget, x#toolkit)
5: FUN(X[[3L]], ...)
4: FUN(X[[3L]], ...)
3: lapply(X = X, FUN = FUN, ...)
2: sapply(globalValues, length, USE.NAMES = FALSE) at SessionWorkspace.R#166
1: (function ()
{
globals = ls(envir = globalenv())
globalValues = lapply(globals, function(name) {
get(name, envir = globalenv(), inherits = FALSE)
})
types = sapply(globalValues, .rs.getSingleClass, USE.NAMES = FALSE)
lengths = sapply(globalValues, length, USE.NAMES = FALSE)
values = sapply(globalValues, .rs.valueAsString, USE.NAMES = FALSE)
extra = sapply(globalValues, .rs.valueDescription, USE.NAMES = FALSE)
result = list(name = globals, type = types, len = lengths,
value = values, extra = extra)
result
})()

Resources