print_code <- function(filename) {
cat(readChar(filename, file.info(filename)$size))
}
This vignette builds and tests some example projects which use mockcpp, to show you how you can include them in your package.
We have created a toy random number generator using Rcpp
print_code(
system.file('testrcpp/src/code.h', package = 'mockcpp', mustWork = TRUE)
)
#> #include <Rcpp.h>
#>
#> class Random {
#> public:
#> virtual Rcpp::NumericVector uniform(size_t size) const {
#> return Rcpp::runif(size);
#> };
#> };
Let's say we want to mock the output of our RNG. We can write a testthat test like so:
print_code(
system.file('testrcpp/src/test-example.cpp', package = 'mockcpp', mustWork = TRUE)
)
#> #include <Rcpp.h>
#> #include <testthat.h>
#> #include <mockcpp.h>
#> #include "code.h"
#>
#> class MockRandom : public Random {
#> MAKE_CONST_MOCK1(uniform, Rcpp::NumericVector(size_t), override);
#> };
#>
#> using trompeloeil::_;
#>
#> context("Can mock an RNG") {
#>
#> test_that("you can change the return value") {
#> MockRandom rng;
#> auto mock_values = Rcpp::NumericVector::create(.1, .2, .3, .4, .5);
#> REQUIRE_CALL(rng, uniform(_)).RETURN(mock_values);
#> expect_true(Rcpp::is_true(Rcpp::all(rng.uniform(5) == mock_values)));
#> }
#>
#> }
We can then build our package and run the test to ensure our mocking works:
# load test package
pkgload::load_all(
system.file('testrcpp', package = 'mockcpp', mustWork = TRUE)
)
#> ℹ Loading testrcpp
#> Re-compiling testrcpp
#>
─ installing *source* package ‘testrcpp’ ...
#>
** using staged installation
#>
** libs
#>
g++ -std=gnu++14 -I"/usr/local/lib/R/include" -DNDEBUG -I'/usr/local/lib/R/site-library/testthat/include' -I'/tmp/RtmpPc0dLV/Rinsta1b2504ff/mockcpp/include' -I'/usr/local/lib/R/site-library/Rcpp/include' -I/usr/local/include -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c test-example.cpp -o test-example.o
#>
g++ -std=gnu++14 -I"/usr/local/lib/R/include" -DNDEBUG -I'/usr/local/lib/R/site-library/testthat/include' -I'/tmp/RtmpPc0dLV/Rinsta1b2504ff/mockcpp/include' -I'/usr/local/lib/R/site-library/Rcpp/include' -I/usr/local/include -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c test-runner.cpp -o test-runner.o
#>
g++ -std=gnu++14 -shared -L/usr/local/lib/R/lib -L/usr/local/lib -o testrcpp.so test-example.o test-runner.o -L/usr/local/lib/R/lib -lR
#>
installing to /tmp/RtmptcByDM/devtools_install_647ae35f37/00LOCK-testrcpp/00new/testrcpp/libs
#>
** checking absolute paths in shared objects and dynamic libraries
#>
─ DONE (testrcpp)
#>
#> Warning: package 'testthat' was built under R version 4.0.3
# run the test
testthat::test_file(
system.file(
'testrcpp/tests/testthat/test-cpp.R',
package = 'mockcpp',
mustWork = TRUE
)
)
#>
#> ══ Testing test-cpp.R ══════════════════════════════════════════════════════════
#>
[ FAIL 0 | WARN 0 | SKIP 0 | PASS 0 ]
[ FAIL 0 | WARN 0 | SKIP 0 | PASS 0 ]
[ FAIL 0 | WARN 0 | SKIP 0 | PASS 1 ] Done!
We can create a similar test for code written using cpp11.
Here's a toy RNG:
print_code(
system.file('testcpp11/src/code.h', package = 'mockcpp', mustWork = TRUE)
)
#> #include <cpp11/doubles.hpp>
#> #include <cstdlib>
#>
#> class Random {
#> public:
#> virtual cpp11::doubles uniform(size_t size) const {
#> auto values = cpp11::writable::doubles(size);
#> // Newer GCC builds (Mac OS and Linux can use auto i = 0
#> // Older windows builds need to specify a type to avoid ambiguity errors 3/11/20 R 4.0.3
#> for (cpp11::writable::doubles::size_type i = 0; i < size; ++i) {
#> values[i] = ((double) std::rand() / (RAND_MAX)) + 1;
#> }
#> return values;
#> };
#> };
And the corresponding test:
print_code(
system.file('testcpp11/src/test-example.cpp', package = 'mockcpp', mustWork = TRUE)
)
#> #include <cpp11/doubles.hpp>
#> #include <testthat.h>
#> #include <mockcpp.h>
#> #include "code.h"
#>
#> class MockRandom : public Random {
#> MAKE_CONST_MOCK1(uniform, cpp11::doubles(size_t), override);
#> };
#>
#> using trompeloeil::_;
#>
#> context("Can mock an RNG") {
#>
#> test_that("you can change the return value") {
#> MockRandom rng;
#> auto mock_values = cpp11::writable::doubles{1, .2, .3, .4, .5};
#> auto size = mock_values.size();
#> REQUIRE_CALL(rng, uniform(_)).RETURN(mock_values);
#> auto actual = rng.uniform(size);
#> // Newer GCC builds (Mac OS and Linux can use auto i = 0
#> // Older windows builds need to specify a type to avoid ambiguity errors 3/11/20 R 4.0.3
#> for (cpp11::writable::doubles::size_type i = 0; i < size; ++i) {
#> expect_true(actual[i] == mock_values[i] );
#> }
#> }
#>
#> }
We can build and test this package in a similar way:
# load test package
pkgload::load_all(
system.file('testcpp11', package = 'mockcpp', mustWork = TRUE)
)
#> ℹ Loading testcpp11
#> Re-compiling testcpp11
#>
─ installing *source* package ‘testcpp11’ ...
#>
** using staged installation
#>
** libs
#>
g++ -std=gnu++14 -I"/usr/local/lib/R/include" -DNDEBUG -I'/usr/local/lib/R/site-library/testthat/include' -I'/tmp/RtmpPc0dLV/Rinsta1b2504ff/mockcpp/include' -I'/usr/local/lib/R/site-library/cpp11/include' -I/usr/local/include -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c test-example.cpp -o test-example.o
#>
g++ -std=gnu++14 -I"/usr/local/lib/R/include" -DNDEBUG -I'/usr/local/lib/R/site-library/testthat/include' -I'/tmp/RtmpPc0dLV/Rinsta1b2504ff/mockcpp/include' -I'/usr/local/lib/R/site-library/cpp11/include' -I/usr/local/include -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c test-runner.cpp -o test-runner.o
#>
g++ -std=gnu++14 -shared -L/usr/local/lib/R/lib -L/usr/local/lib -o testcpp11.so test-example.o test-runner.o -L/usr/local/lib/R/lib -lR
#>
installing to /tmp/RtmptcByDM/devtools_install_641a368b70/00LOCK-testcpp11/00new/testcpp11/libs
#>
** checking absolute paths in shared objects and dynamic libraries
#>
─ DONE (testcpp11)
#>
# run the test
testthat::test_file(
system.file(
'testcpp11/tests/testthat/test-cpp.R',
package = 'mockcpp',
mustWork = TRUE
)
)
#>
#> ══ Testing test-cpp.R ══════════════════════════════════════════════════════════
#>
[ FAIL 0 | WARN 0 | SKIP 0 | PASS 0 ]
[ FAIL 0 | WARN 0 | SKIP 0 | PASS 0 ]
[ FAIL 0 | WARN 0 | SKIP 0 | PASS 1 ] Done!