Skip to content

feat(zunit): modernize core — native config, namespaced internals, signal-based timeout#8

Merged
ss-o merged 3 commits into
mainfrom
feature/zunit-modernization
May 22, 2026
Merged

feat(zunit): modernize core — native config, namespaced internals, signal-based timeout#8
ss-o merged 3 commits into
mainfrom
feature/zunit-modernization

Conversation

@ss-o
Copy link
Copy Markdown
Member

@ss-o ss-o commented May 21, 2026

Summary

  • Native Zsh config (.zunit.zsh) replaces .zunit.yml as the primary configuration format, using plain shell variables (ZUNIT_TESTS_DIR, ZUNIT_TIME_LIMIT, etc.); legacy .zunit.yml is preserved as a fallback for backward compatibility
  • Full _zunit_* namespace for all internal symbols; public test helpers (color, load, assert, pass, fail, error, skip) kept as thin wrappers — existing test files require no changes
  • Bundled revolver fully namespaced to _zunit_revolver_* (eliminates dependency on an external revolver binary); statefile path fixed from $PPID to $$ for correct process isolation
  • Signal-based async timeout replaces the while kill -0 busy-wait polling loop with an ALRM trap + background timer subprocess
  • Anonymous function test isolation wraps each test body in () { ... } to prevent local variable leakage between tests
  • Z-Shell plugin standard compliance: ZERO handling, Plugins hash, and fpath guard added to src/zunit.zsh
  • Echo correctness: removed spurious leading ( from output calls across run/init/events
  • Repo config migrated: .zunit.zsh added for this repository

Deferred to a follow-up PR: zsh/zpty-based async runner redesign (spec §3) — independent higher-risk change.

Test plan

  • All 111 existing tests pass (./zunit run tests/)
  • zunit init now generates .zunit.zsh (verified by updated cli.zunit test)
  • .zunit.yml fallback still recognised (config load order in src/zunit.zsh)
  • Revolver spinner renders correctly (no external revolver binary needed)
  • zsh build.zsh produces a clean binary

🤖 Generated with Claude Code

- Migrate configuration from YAML to native Zsh (.zunit.zsh) with
  backward-compatible fallback to .zunit.yml
- Namespace all internal symbols under _zunit_ prefix; expose public
  helpers (color, load, assert, pass, fail, error, skip) as thin
  wrappers so test code is unaffected
- Rename bundled revolver functions to _zunit_revolver_* to avoid
  collisions with any ambient revolver install; fix statefile path
  from $PPID to $$ for correct isolation
- Replace polling-based async timeout with ALRM signal trap to
  eliminate the busy-wait loop
- Wrap test body in anonymous function for scope isolation
- Add ZERO handling, Plugins hash, and fpath guard (Z-Shell plugin
  standard) to src/zunit.zsh
- Fix spurious leading '(' in echo calls throughout run/init/events
- Add .zunit.zsh config for this repository

All 111 tests pass.
Copilot AI review requested due to automatic review settings May 21, 2026 05:30
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes ZUnit’s core by switching to a native Zsh-based config format (.zunit.zsh), fully namespacing internal symbols (including bundling a namespaced revolver spinner), and replacing polling-based test timeouts with a signal-based approach—while keeping existing test helper APIs compatible via thin wrappers.

Changes:

  • Add native .zunit.zsh config loading (with .zunit.yml fallback) and migrate this repo to the new config.
  • Namespace internal helpers (_zunit_*) and bundle a namespaced revolver (_zunit_revolver_*) to remove the external dependency.
  • Replace busy-wait timeouts with an ALRM-trap + background timer and add anonymous-function wrapping around test bodies.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/cli.zunit Updates CLI tests for .zunit.zsh messaging and removes the external revolver dependency check.
src/zunit.zsh Loads .zunit.zsh config first, adds plugin-standard ZERO/Plugins/fpath handling, and checks for internal revolver.
src/helpers.zsh Keeps public helpers as wrappers while moving implementations into _zunit_* internals.
src/events.zsh Switches output styling and spinner control calls to namespaced internals.
src/commands/run.zsh Fixes output formatting, uses namespaced spinner, adds test-body isolation, and implements signal-based timeouts.
src/commands/init.zsh Generates .zunit.zsh instead of .zunit.yml and updates init examples.
lib/revolver.zsh Namespaces revolver functions and changes statefile keying from $PPID to $$.
lib/color.zsh Removes implicit execution so it behaves purely as a library in the built artifact.
.zunit.zsh Adds the repo’s new native ZUnit configuration.
Comments suppressed due to low confidence (1)

src/commands/run.zsh:556

  • This comment still mentions .zunit.yml, but config is now primarily loaded from .zunit.zsh (with .zunit.yml as fallback). Update the comment to reflect the new config filename or refer to “config” generically.
  [[ -z $tap ]] && _zunit_revolver start 'Loading tests'

  # If no arguments are passed, try to work out where the tests are
  if [[ ${#arguments} -eq 0 ]]; then
    # Check for a path defined in .zunit.yml

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/commands/init.zsh
Comment thread src/commands/init.zsh
Comment thread src/commands/init.zsh
Comment thread src/commands/init.zsh
Comment thread src/zunit.zsh Outdated
Comment thread src/commands/run.zsh
ss-o added 2 commits May 21, 2026 06:47
- Check return status of source .zunit.zsh and exit with a clear
  error if it fails, rather than silently continuing with defaults
- Fix ALRM race window in async test wrapper: set test_done=1 flag
  before disarming the trap so any signal arriving during cleanup
  becomes a no-op instead of triggering a false timeout exit
- Reorder cleanup: disarm trap before killing the timer subprocess
- Update stale .zunit.yml comment in run.zsh to "config"
Color and revolver are now bundled in the zunit binary — there are
no external binaries to chmod or add to PATH. Remove the dead
.bin/{color,revolver} mkdir/chmod lines from both CI workflows and
strip the revolver/color stub setup from cli.zunit's config-missing
test, which no longer needs them to get past the dependency check.
@ss-o ss-o merged commit 6631140 into main May 22, 2026
3 checks passed
@ss-o ss-o deleted the feature/zunit-modernization branch May 22, 2026 06:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants