Skip to main content

pedalkernel_validate/
pro_pedal.rs

1//! Helpers for loading proprietary `.pedal` files from the pedalkernel-pro
2//! private repository at test time.
3//!
4//! The `.pedal` sources are proprietary and must **never** be committed to the
5//! public engine repo, nor embedded via `include_str!` (that would fail to
6//! compile on public CI where the pro repo is absent).
7//!
8//! # Usage
9//!
10//! ```rust,ignore
11//! use pedalkernel_validate::pro_pedal::{load_pro_pedal_sub, skip_if_missing};
12//!
13//! #[test]
14//! fn my_test() {
15//!     let source = skip_if_missing!(
16//!         load_pro_pedal_sub("pedals/legends/screamer.pedal"),
17//!         "pedals/legends/screamer.pedal"
18//!     );
19//!     // use source…
20//! }
21//! ```
22//!
23//! # CI behaviour
24//!
25//! When the pro repo is absent (public CI, forks, contributor machines), the
26//! `load_pro_pedal_sub` function returns `None`.  The `skip_if_missing!` macro
27//! then calls `return` — causing the test to exit silently with no failure.
28//! Rust's test harness reports such a test as passed (not failed, not skipped
29//! with the ignored attribute).
30//!
31//! # Mirror note
32//!
33//! `pedalkernel::compiler::tb303_decomposition_tests::load_pro_pedal_sub` mirrors
34//! this logic for tests in the `pedalkernel` crate.  A true shared crate is not
35//! possible because `pedalkernel-validate` depends on `pedalkernel`, so a
36//! reverse dependency would be circular.
37
38/// Try to load a file at `pro_sub_path` (relative to the pedalkernel-pro repo
39/// root, e.g. `"crates/acidattack/acidattack-core/tb303_filter.pedal"` or
40/// `"pedals/legends/screamer.pedal"`).
41///
42/// Tries several candidate `../` depths from `CARGO_MANIFEST_DIR` so that tests
43/// work in both normal checkout and git-worktree layouts.
44///
45/// Returns `None` — never panics — when the pro repo is absent, so callers can
46/// skip gracefully via [`skip_if_missing!`].
47pub fn load_pro_pedal_sub(pro_sub_path: &str) -> Option<String> {
48    let manifest_dir = env!("CARGO_MANIFEST_DIR");
49    // Try 2..=6 levels of `../` to cover:
50    //   2: normal checkout  (pedalkernel-pro/ and pedalkernel/ are siblings)
51    //   3: worktree layout  (.worktrees/<name>/ adds one extra level)
52    //   4..=6: deeper nesting in case of unusual CI layouts
53    for levels in 2..=6 {
54        let prefix: String = "../".repeat(levels);
55        let candidate = format!("{manifest_dir}/{prefix}pedalkernel-pro/{pro_sub_path}");
56        if let Ok(s) = std::fs::read_to_string(&candidate) {
57            eprintln!(
58                "  loaded {} ({} bytes) from {candidate}",
59                pro_sub_path,
60                s.len()
61            );
62            return Some(s);
63        }
64    }
65    None
66}
67
68/// Early-return a test when a pro `.pedal` file is absent.
69///
70/// ```rust,ignore
71/// let source = skip_if_missing!(
72///     load_pro_pedal_sub("pedals/legends/screamer.pedal"),
73///     "pedals/legends/screamer.pedal"
74/// );
75/// ```
76///
77/// Expands to `match $source { Some(s) => s, None => { eprintln!(…); return; } }`.
78/// The enclosing `#[test]` function returns `()`, so the harness records a pass.
79#[macro_export]
80macro_rules! skip_if_missing {
81    ($source:expr, $name:expr) => {
82        match $source {
83            Some(s) => s,
84            None => {
85                eprintln!("  SKIP: {} not found (pro repo absent)", $name);
86                return;
87            }
88        }
89    };
90}