tl;dr
To test the branch followed when use require(knitr)
fails, use trace()
to temporarily modify require()
so that it won't find knitr, even if it is present on .libPaths()
. Specifically, in the body of require()
, reset the value of lib.loc=
to point to R.home()
-- an existing directory that does not contain a knitr
package.
This seems to work just as well in a package as it will in an interactive session in which you run the following:
find.package("knitr")
trace("require", quote(lib.loc <- R.home()), at=1)
isTRUE(suppressMessages(suppressWarnings(require(knitr))))
untrace("require")
isTRUE(suppressMessages(suppressWarnings(require(knitr))))
As I understand this, you have a function with two branches, one to be performed in R sessions for which require(knitr)
succeeds, and the other to be performed in sessions where it fails. You are then wanting to test this function "both ways" from a single R instance in which knitr actually is on .libPaths()
.
So basically you are needing some way to temporarily blind the call require(knitr)
to the actual presence of knitr. Completely and temporarily resetting the value returned by .libPaths()
looked promising, but doesn't seem to be possible.
Another promising avenue is to somehow reset the default value of lib.loc
in calls to require()
from NULL
(which means "use the value of .libPaths()
) to some other location where knitr is not available. You can't accomplish this by overwriting base::require()
, nor (in a package) can you get there by defining a local masking version of require()
with the desired value of lib.loc
.
It does, though, look like you can get away with using trace()
to temporarily modify require()
(blinding it to knitr's availability by setting lib.loc=R.home()
). Then do untrace()
to restore require()
to the vanilla version which will go ahead and find knitr.
Here's what that looked like in the dummy package I tested this with. First an R function that allows us to test for success along the two branches
## $PKG_SRC/R/hello.R
hello <- function(x=1) {
if(require(knitr)) {
x==2
} else {
x==3
}
}
Then a couple of tests, one for each branch:
## $PKG_SRC/inst/tests/testme.R
## Test the second branch, run when require(knitr) fails
trace("require", quote(lib.loc <- R.home()), at=1)
stopifnot(hello(3))
untrace("require")
## Test the first branch, run when require(knitr) succeeds
stopifnot(hello(2))
To test this, I used pkgKitten::kitten("dummy")
to set up a source directory, copied in these two files, added Suggests: knitr
to the DESCRIPTION
file, and then ran devtools::install()
and devtools::check()
from the appropriate directory. The package installs just fine, and passes all of the checks.
dir
on the entries in.libPaths()
and then usingfile.rename
to rename the knitr folder to something like knitr_BALEETED (or whatever you want) and then renaming it back to knitr after the tests are done. I'm not sure how CRAN compliant this would be... – Dragropesystem.file()
to tell me the location. To be honest, I'd be happy to disable the test on CRAN (easy to do withtestthat
) conditional on the test working locally and on Travis. – Mucoviscidosisfind.package("knitr", quiet=TRUE)
to find an installedknitr
, orlength(find.package("knitr", quiet=TRUE))
as a test for its presence on.libPaths()
. – Irfanskip_if_not_installed()
, but that won't help here. I'd make the function being tested switch behaviours based on an explicit argument, e.g.knitr_installed = system.file(package="knitr") != ""
. Then you test could more easily evaluate both cases – Lanielanierskip_on_cran
), but you can put the suggested packages in a separate library and as part of the test setup make sure that library is/is not on the search path to test the two different cases. – Dogooder