fix(r): skip golden-fixture test in standalone package builds + document parity (#257)
## Problem The r-universe build of `wickra` 0.8.4 fails (`R CMD check` ERROR): the golden-fixture parity test added in #255 walks up from the working directory looking for `testdata/golden` and `stop()`s when it cannot find it. Standalone package builds (r-universe / CRAN) package only `bindings/r`, so the repo-root `testdata/golden` fixtures are unreachable there — whereas the monorepo CI checks out the full repo, so the walk-up succeeds and the test passes. Run: https://github.com/r-universe/wickra-lib/actions/runs/27354800361 ## Fix - **`bindings/r/tests/testthat/test-golden.R`** — the fixture-directory lookup now returns `NULL` instead of erroring when the fixtures are absent, and each test starts with `skip_if(is.null(golden_dir), ...)`. The repository CI (full repo present) still runs the parity checks; standalone builds skip them. The per-test `golden_input` read moved inside the (post-skip) test bodies so nothing runs at source time when the fixtures are missing. - **`CHANGELOG.md`** — `[Unreleased]` Fixed entry. ## Docs (B6) - **`README.md` `## Testing`** — the four C-ABI bindings (C#, Go, Java, R) were described as covering one indicator per FFI archetype; document that they additionally replay the shared golden fixture and assert exact parity with the Rust reference outputs.
This commit is contained in:
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Fixed
|
||||
- The R binding's golden-fixture parity test now skips gracefully when the shared
|
||||
`testdata/golden` fixtures are not bundled with the package — standalone
|
||||
r-universe / CRAN builds package only `bindings/r`, so the repo-root fixtures
|
||||
are unreachable there. The parity stays enforced by the repository CI, where
|
||||
the fixtures are present.
|
||||
|
||||
## [0.8.4] - 2026-06-11
|
||||
### Fixed
|
||||
|
||||
@@ -358,6 +358,12 @@ Every layer is covered; run the suites with the commands in
|
||||
- `bindings/java`: JUnit cases covering one indicator per FFI archetype
|
||||
(scalar/batch, multi-output, bars, profile, array input) plus batch equivalence.
|
||||
|
||||
The four C-ABI bindings (C#, Go, Java, R) additionally replay a shared,
|
||||
language-neutral golden fixture (`testdata/golden/*.csv`, generated by
|
||||
`cargo run -p wickra-examples --bin gen_golden`) and assert exact parity with the
|
||||
Rust reference outputs across every archetype (SMA, EMA, RSI, ATR, MACD, ADX,
|
||||
Beta), catching FFI wiring bugs the math-only core tests cannot see.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are very welcome — issues, bug reports, ideas, and pull requests
|
||||
|
||||
@@ -3,23 +3,36 @@
|
||||
# archetype test only checks finiteness, this pins exact values, catching wiring
|
||||
# bugs (swapped params, wrong multi-output field). Fixtures are generated by
|
||||
# `cargo run -p wickra-examples --bin gen_golden`.
|
||||
#
|
||||
# The fixtures live at the repository root (testdata/golden) and are present
|
||||
# during the monorepo test run, but they are NOT bundled into the standalone R
|
||||
# package. A packaged check (r-universe / CRAN) therefore cannot find them, so
|
||||
# these tests skip there; the parity is already enforced by the repository CI.
|
||||
|
||||
golden_dir <- local({
|
||||
find_golden_dir <- function() {
|
||||
d <- normalizePath(getwd(), winslash = "/", mustWork = FALSE)
|
||||
repeat {
|
||||
g <- file.path(d, "testdata", "golden")
|
||||
if (dir.exists(g)) return(g)
|
||||
parent <- dirname(d)
|
||||
if (identical(parent, d)) stop("testdata/golden not found from ", getwd())
|
||||
if (identical(parent, d)) return(NULL)
|
||||
d <- parent
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
golden_dir <- find_golden_dir()
|
||||
|
||||
skip_if_no_golden <- function() {
|
||||
skip_if(is.null(golden_dir), "golden fixtures not bundled with the package")
|
||||
}
|
||||
|
||||
read_golden <- function(name) {
|
||||
read.csv(file.path(golden_dir, paste0(name, ".csv")),
|
||||
colClasses = "character", check.names = FALSE)
|
||||
}
|
||||
|
||||
read_golden_input <- function() read.csv(file.path(golden_dir, "input.csv"))
|
||||
|
||||
gcell <- function(s) if (identical(s, "nan")) NA_real_ else as.numeric(s)
|
||||
|
||||
expect_close <- function(got, want, row, field) {
|
||||
@@ -31,9 +44,9 @@ expect_close <- function(got, want, row, field) {
|
||||
}
|
||||
}
|
||||
|
||||
golden_input <- read.csv(file.path(golden_dir, "input.csv"))
|
||||
|
||||
test_that("scalar indicators match golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
specs <- list(c("sma", 14), c("ema", 14), c("rsi", 14))
|
||||
for (spec in specs) {
|
||||
name <- spec[[1]]
|
||||
@@ -47,6 +60,8 @@ test_that("scalar indicators match golden", {
|
||||
})
|
||||
|
||||
test_that("candle Atr matches golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
atr <- Atr(14)
|
||||
exp <- read_golden("atr")
|
||||
for (i in seq_len(nrow(golden_input))) {
|
||||
@@ -57,6 +72,8 @@ test_that("candle Atr matches golden", {
|
||||
})
|
||||
|
||||
test_that("pairwise Beta matches golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
beta <- Beta(20)
|
||||
exp <- read_golden("beta")
|
||||
for (i in seq_len(nrow(golden_input))) {
|
||||
@@ -67,6 +84,8 @@ test_that("pairwise Beta matches golden", {
|
||||
})
|
||||
|
||||
test_that("multi-output MACD matches golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
macd <- MacdIndicator(12, 26, 9)
|
||||
exp <- read_golden("macd")
|
||||
for (i in seq_len(nrow(golden_input))) {
|
||||
@@ -82,6 +101,8 @@ test_that("multi-output MACD matches golden", {
|
||||
})
|
||||
|
||||
test_that("multi-output ADX matches golden", {
|
||||
skip_if_no_golden()
|
||||
golden_input <- read_golden_input()
|
||||
adx <- Adx(14)
|
||||
exp <- read_golden("adx")
|
||||
for (i in seq_len(nrow(golden_input))) {
|
||||
|
||||
Reference in New Issue
Block a user