feat(zunit): modernize core — native config, namespaced internals, signal-based timeout#8
Merged
Merged
Conversation
- 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.
There was a problem hiding this comment.
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.zshconfig loading (with.zunit.ymlfallback) 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.ymlas 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.
- 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.zunit.zsh) replaces.zunit.ymlas the primary configuration format, using plain shell variables (ZUNIT_TESTS_DIR,ZUNIT_TIME_LIMIT, etc.); legacy.zunit.ymlis preserved as a fallback for backward compatibility_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_zunit_revolver_*(eliminates dependency on an externalrevolverbinary); statefile path fixed from$PPIDto$$for correct process isolationwhile kill -0busy-wait polling loop with anALRMtrap + background timer subprocess() { ... }to prevent local variable leakage between testsPluginshash, andfpathguard added tosrc/zunit.zsh(from output calls across run/init/events.zunit.zshadded for this repositoryDeferred to a follow-up PR:
zsh/zpty-based async runner redesign (spec §3) — independent higher-risk change.Test plan
./zunit run tests/)zunit initnow generates.zunit.zsh(verified by updatedcli.zunittest).zunit.ymlfallback still recognised (config load order insrc/zunit.zsh)revolverbinary needed)zsh build.zshproduces a clean binary🤖 Generated with Claude Code