Skip to content

Commit c544093

Browse files
authored
add tests for isProcessForkedChild() and archSystemFile() (#266)
* add tests for isProcessForkedChild() and archSystemFile() cover two 6.0.0 additions that previously had no automated tests: - isProcessForkedChild(): FALSE in the parent, TRUE in parallel::mclapply workers (skipped on Windows, which has no fork()) - archSystemFile(): delegates to system.file() with no arch subdir, and composes the arch-specific subdirectory when .Platform$r_arch is set * compare file paths with normalizePath() rather than identical() identical() is a byte-for-byte string comparison, but two paths can denote the same file while differing in separators, case, or symlink resolution. normalize both sides before comparing, preserving system.file()'s "" not-found sentinel (normalizePath("") would resolve to the working dir). * test archSystemFile() against 'libs', which actually uses the arch subdir the previous existence check used archSystemFile("include", ...), but the arch-specific subdirectory only ever holds compiled libraries -- headers are never installed under it. on Windows (r_arch = "x64") this looked for 'include/x64/RcppParallel.h', which does not exist; on unix (r_arch = "") the injection was a no-op, so the mistake was invisible locally. use 'libs', where the package's compiled code lives on every platform. * clarify that arch subdirs are not Windows-specific in test comments
1 parent 0a650d9 commit c544093

2 files changed

Lines changed: 75 additions & 0 deletions

File tree

tests/test-arch-system-file.R

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Unit tests for archSystemFile(), the arch-aware wrapper around system.file()
2+
# introduced when systemFile() was renamed (see #251, #252). When R is built
3+
# multi-arch -- typically Windows, but also possible on Linux and macOS -- it
4+
# installs compiled libraries under an architecture-specific subdirectory named
5+
# by .Platform$r_arch, e.g. 'libs/x64'. archSystemFile() injects that subdir,
6+
# and behaves like system.file() when r_arch is unset. Note the subdir only
7+
# ever holds compiled libraries ('lib', 'libs'); headers and other resources
8+
# are never installed under it.
9+
10+
RcppParallel:::test_init()
11+
12+
arch <- .Platform$r_arch
13+
14+
# compare two file paths for equality. system.file() returns "" when a path is
15+
# not found, so preserve that sentinel; otherwise normalize both sides, since
16+
# strings that differ only in separators, case, or symlinks can still denote
17+
# the same file (and normalizePath("") would resolve to the working directory).
18+
samePath <- function(a, b) {
19+
norm <- function(p) {
20+
if (nzchar(p)) normalizePath(p, winslash = "/", mustWork = FALSE) else p
21+
}
22+
identical(norm(a), norm(b))
23+
}
24+
25+
# with no arch subdirectory (the usual case off Windows), archSystemFile()
26+
# should be equivalent to a plain system.file() call
27+
if (!nzchar(arch)) {
28+
assert(samePath(
29+
archSystemFile("libs"),
30+
system.file("libs", package = "RcppParallel")
31+
))
32+
}
33+
34+
# the composed relative path must match what system.file() is handed: dir,
35+
# then the arch subdir when set, then the optional name -- joined with '/'
36+
expected <- function(dir, name = NULL) {
37+
parts <- c(dir, if (nzchar(arch)) arch, name)
38+
system.file(paste(parts, collapse = "/"), package = "RcppParallel")
39+
}
40+
41+
assert(samePath(archSystemFile("lib"), expected("lib")))
42+
assert(samePath(archSystemFile("lib", "libtbb.so"), expected("lib", "libtbb.so")))
43+
44+
# the package's own compiled code is installed under 'libs' (or 'libs/<arch>'
45+
# under a multi-arch R) -- exactly the arch-aware lookup archSystemFile()
46+
# exists for -- so it must resolve to an existing directory on every platform
47+
libs <- archSystemFile("libs")
48+
assert(nzchar(libs))
49+
assert(dir.exists(libs))

tests/test-fork.R

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Unit tests for isProcessForkedChild().
2+
#
3+
# The contract: it returns FALSE in the process where RcppParallel was loaded,
4+
# and TRUE in a fork() of that process (e.g. a parallel::mclapply worker). On
5+
# Windows there is no fork(), so it always returns FALSE.
6+
7+
RcppParallel:::test_init()
8+
9+
# in the parent process, we are never a forked child
10+
assert(isProcessForkedChild() == FALSE)
11+
12+
# parallel::mclapply uses fork() on unix, so its workers must report TRUE.
13+
# on Windows there is no fork() (mclapply falls back to serial), so skip: the
14+
# workers there run in the parent process and would correctly report FALSE.
15+
if (!is_windows()) {
16+
17+
results <- parallel::mclapply(1:2, function(i) {
18+
RcppParallel::isProcessForkedChild()
19+
}, mc.cores = 2L)
20+
21+
assert(all(vapply(results, isTRUE, logical(1L))))
22+
23+
}
24+
25+
# forking must not disturb the parent's own view of itself
26+
assert(isProcessForkedChild() == FALSE)

0 commit comments

Comments
 (0)