From d4d8c64148c9209c7c1520f6c41427d9c79e5b29 Mon Sep 17 00:00:00 2001 From: tanglearncode Date: Wed, 16 Sep 2026 09:53:09 +0800 Subject: [PATCH 1/4] test(config): cover the _ZO_* env readers with shimforge --- Cargo.lock | 22 +++++++++++++++++++++ Cargo.toml | 1 + src/config.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 16edf6e88..47d40d126 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -808,6 +808,27 @@ dependencies = [ "zmij", ] +[[package]] +name = "shimforge" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ebf7ede656bc1cbb829e0ce8e9abf91fa3d1862b7862be358bc08a5b3064b63" +dependencies = [ + "libc", + "shimforge-macros", +] + +[[package]] +name = "shimforge-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e52f9314e5203ce9e4d956d789be7457d07c0afc65448ec5e0e1d9c92cf614" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -1171,6 +1192,7 @@ dependencies = [ "rstest", "rstest_reuse", "serde", + "shimforge", "tempfile", "time", "which", diff --git a/Cargo.toml b/Cargo.toml index bfcf40864..d93aac273 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ color-print = "0.3.4" [dev-dependencies] assert_cmd = "2.0.0" +shimforge = "=0.1.1" rstest = { version = "0.26.0", default-features = false } rstest_reuse = "0.7.0" tempfile = "3.15.0" diff --git a/src/config.rs b/src/config.rs index 0aeda5c5c..ae6bb7eb3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -60,3 +60,56 @@ pub fn maxage() -> Result { pub fn resolve_symlinks() -> bool { env::var_os("_ZO_RESOLVE_SYMLINKS").is_some_and(|var| var == "1") } + +#[cfg(test)] +mod tests { + use super::*; + use shimforge::{Session, mock}; + use std::ffi::OsString; + + // Each test gets its own value for one variable, on its own thread. The + // process environment is never written, so these run in parallel with + // each other and with every other test in the suite. + fn env_var(session: &mut Session, name: &'static str, value: Option<&str>) { + let var_os = mock!(session, env::var_os::<&str>, fn(&str) -> Option); + let value = value.map(OsString::from); + var_os.expect().with(move |var| *var == name).returns(value); + } + + #[test] + fn maxage_defaults_when_unset() { + let mut session = Session::new(); + env_var(&mut session, "_ZO_MAXAGE", None); + assert_eq!(maxage().unwrap(), 10_000.0); + } + + #[test] + fn maxage_reads_the_variable() { + let mut session = Session::new(); + env_var(&mut session, "_ZO_MAXAGE", Some("500")); + assert_eq!(maxage().unwrap(), 500.0); + } + + #[test] + fn maxage_rejects_a_value_that_is_not_a_number() { + let mut session = Session::new(); + env_var(&mut session, "_ZO_MAXAGE", Some("soon")); + let error = maxage().unwrap_err().to_string(); + assert!(error.contains("unable to parse _ZO_MAXAGE"), "{error}"); + } + + #[test] + fn a_relative_data_dir_is_rejected() { + let mut session = Session::new(); + env_var(&mut session, "_ZO_DATA_DIR", Some("relative/zoxide")); + let error = data_dir().unwrap_err().to_string(); + assert!(error.contains("must be an absolute path"), "{error}"); + } + + #[test] + fn resolve_symlinks_is_opt_in() { + let mut session = Session::new(); + env_var(&mut session, "_ZO_RESOLVE_SYMLINKS", Some("1")); + assert!(resolve_symlinks()); + } +} From 8092c8b5a8288bd4857419180aeab74a198b6125 Mon Sep 17 00:00:00 2001 From: tanglearncode Date: Wed, 16 Sep 2026 09:53:09 +0800 Subject: [PATCH 2/4] ci: verify the config tests on the fork --- .github/workflows/ci-shimforge-config.yml | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/ci-shimforge-config.yml diff --git a/.github/workflows/ci-shimforge-config.yml b/.github/workflows/ci-shimforge-config.yml new file mode 100644 index 000000000..bdbad3278 --- /dev/null +++ b/.github/workflows/ci-shimforge-config.yml @@ -0,0 +1,40 @@ +name: Fork shimforge config tests + +on: + push: + branches: ['shimforge-config-tests'] + workflow_dispatch: + +permissions: + contents: read + +jobs: + verify: + if: github.repository == 'tanglearncode/zoxide' + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: false + + # zoxide's own MSRV, so this proves nothing newer is needed. + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.88.0 + + # --locked fails if the committed lockfile is not what cargo resolves. + - name: Build the config tests + run: cargo test --locked --bins config -- --list + + # Parallel, repeated: the point is that nothing is serialized. + - name: Run the config tests 20 times, 8 threads + run: | + for attempt in $(seq 1 20); do + cargo test --locked --bins config -- --test-threads=8 + done + echo 'config tests: 20 runs x 8 threads, no env mutation.' >> "$GITHUB_STEP_SUMMARY" + + # The rest of the suite still passes with the mocks present. + - name: Run the full test suite + run: cargo test --locked From 6d7cf9bdccf43f985314f80cb9f816bea3a6af48 Mon Sep 17 00:00:00 2001 From: tanglearncode Date: Wed, 16 Sep 2026 09:59:36 +0800 Subject: [PATCH 3/4] style(config): group test imports std/external/crate --- src/config.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/config.rs b/src/config.rs index ae6bb7eb3..caf6e1852 100644 --- a/src/config.rs +++ b/src/config.rs @@ -63,10 +63,12 @@ pub fn resolve_symlinks() -> bool { #[cfg(test)] mod tests { - use super::*; - use shimforge::{Session, mock}; use std::ffi::OsString; + use shimforge::{Session, mock}; + + use super::*; + // Each test gets its own value for one variable, on its own thread. The // process environment is never written, so these run in parallel with // each other and with every other test in the suite. From f3b0cab446dcfe79cd50ffff11ff9086565fac78 Mon Sep 17 00:00:00 2001 From: tanglearncode Date: Wed, 16 Sep 2026 10:04:30 +0800 Subject: [PATCH 4/4] ci: format the fork workflow for yamlfmt --- .github/workflows/ci-shimforge-config.yml | 61 ++++++++++------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci-shimforge-config.yml b/.github/workflows/ci-shimforge-config.yml index bdbad3278..3a036917b 100644 --- a/.github/workflows/ci-shimforge-config.yml +++ b/.github/workflows/ci-shimforge-config.yml @@ -1,40 +1,29 @@ name: Fork shimforge config tests - on: - push: - branches: ['shimforge-config-tests'] - workflow_dispatch: - + push: + branches: ['shimforge-config-tests'] + workflow_dispatch: permissions: - contents: read - + contents: read jobs: - verify: - if: github.repository == 'tanglearncode/zoxide' - runs-on: ubuntu-24.04 - timeout-minutes: 20 - steps: - - uses: actions/checkout@v5 - with: - persist-credentials: false - - # zoxide's own MSRV, so this proves nothing newer is needed. - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.88.0 - - # --locked fails if the committed lockfile is not what cargo resolves. - - name: Build the config tests - run: cargo test --locked --bins config -- --list - - # Parallel, repeated: the point is that nothing is serialized. - - name: Run the config tests 20 times, 8 threads - run: | - for attempt in $(seq 1 20); do - cargo test --locked --bins config -- --test-threads=8 - done - echo 'config tests: 20 runs x 8 threads, no env mutation.' >> "$GITHUB_STEP_SUMMARY" - - # The rest of the suite still passes with the mocks present. - - name: Run the full test suite - run: cargo test --locked + verify: + if: github.repository == 'tanglearncode/zoxide' + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.88.0 + - name: Build the config tests at zoxide's MSRV, with the lockfile verified + run: cargo test --locked --bins config -- --list + - name: Run the config tests 20 times at 8 threads, nothing serialized + run: | + for attempt in $(seq 1 20); do + cargo test --locked --bins config -- --test-threads=8 + done + echo 'config tests: 20 runs x 8 threads, no env mutation.' >> "$GITHUB_STEP_SUMMARY" + - name: Run the full test suite with the mocks present + run: cargo test --locked