Repository navigation
feat(software-writer): complete BATS reference and correct bash rules - #49
Merged
Merged
Conversation
The BATS reference lacked the error-path idiom, isolation scopes, test doubles, and non-deterministic-call table that the other framework references carry, and it did not name the refusal idiom, restore mechanism, or helper idiom that the generic writing-tests references promise. It is now written against bats-core 1.14 and bats-assert 2.2 and covers `run -<N>`, the exit-127 blind spot of `refute`, `run !`, and a bare `assert_failure`, and the EXIT-trap and root hazards. The bash reference said a command substitution never inherits errexit, which is false under `set -o posix`, and recommended `|| true` without saying it also hides `grep`'s exit 2 on an unreadable file. It now limits `|| true` to commands whose every non-zero status is an answer, and adds rules for restoring options, dependent `local` assignments, `read -a`, redirection order, passing data to jq and awk, octal leading zeros, and jq `// empty` bindings. writing-code now searches callers for a fallback that becomes reachable when an edit makes a function fail, and runs a comment's claims about the language, interpreter, or tool before keeping it. The other stack references now name what a construct still hides (Python exception subclasses, Go `_ =` and an unchecked `Close`, PHP `json_decode` returning null for both invalid input and a JSON `null`, TypeScript catch-alls), and every framework reference names its helper idiom and per-test temporary directory and states the version it was written against (Vitest 5, Pest 5 on PHPUnit 13, pytest 9.2).
By default `$(set +o)` runs in a subshell that drops errexit, so the saved text says `set +o errexit` and replaying it turned errexit off in the caller. The restore idiom now captures `$-` in the caller and re-asserts `set -e` after the replay. The BATS reference also stated three rules too broadly: `run -0` adds nothing only for an external command, since `run` suppresses errexit inside a function; `--no-parallelize-across-files` needs only bats' own lock, not GNU parallel or rush; and a `for` loop around `@test` works only with one iteration. The bash `|| true` rule now says that no status check separates a failure that shares its status with an answer, as BusyBox `pgrep` does for an unknown option.
The BATS reference told tests to capture a function's status with `|| code=$?`, which runs the function with errexit off, so a failing command in its middle goes unnoticed. The rule now allows that capture only for a function that propagates its own failures (`cmd || return`) and otherwise calls the function bare. The bash reference said interpolating a value into a jq filter is a compile error. A value with balanced quotes compiles and injects code instead. The awk `-v` rule now covers every awk, since POSIX requires the escape processing. Both rules, and the option-restore rule, now have their own bullets. In writing-code Step 6 the digraph checked a comment after classifying it and skipped classification once the comment was corrected. The check now runs first, a corrected comment is still classified, and a claim that cannot be run here is cut or narrowed instead of kept. The Go reference now allows `_ =` with a comment that says why the discard is safe, matching the comment rules, and states that a bare `defer f.Close()` is fine on a file opened only for reading.
The Vitest and Jest references told tests to clear mock implementations between tests with `vi.restoreAllMocks()` and `jest.restoreAllMocks()`, which restore only `vi.spyOn` and `jest.spyOn` spies and leave a `vi.fn()` or `jest.fn()` implementation in place. Both now name `vi.resetAllMocks()` and `jest.resetAllMocks()` for those mocks and keep restore for spies. bats-core 1.14.0 changed `run` to honor a `set -e` the called function turns on itself, so the BATS reference now says `run` suppresses errexit only for a function that does not enable it. A failing `< <(…)` registry read registers no tests and the run can still exit 0, since "Found no tests" only fires when the whole run has none. writing-code Step 6 now applies the run requirement to comments written, edited, or kept on the lines being written or edited, and a load-bearing workaround comment stays only once its claim has been run or narrowed.
writing-code Step 6 removed or narrowed any comment claim that could not be run on the current machine, which deleted load-bearing workaround comments and rewrote true claims about other versions into false ones. A claim now runs in an isolated probe and counts only on the version or platform it names. A run corrects only the part it refutes, and a claim that cannot be run stays and is reported to the user as unverified. The exemption check now opens Step 6, so Pre-Step-6 content runs before it. The Jest reference recommended `jest.resetAllMocks()` in `afterEach`, which replaces every `jest.fn(impl)` and `jest.mock` factory implementation with one that returns undefined. It now picks the call by where implementations are set and says the `resetMocks` and `restoreMocks` flags run the same calls before every test. The BATS error-path example now calls `bats_require_minimum_version 1.5.0`, so a copied `run -2` no longer prints BW02, and the rule says the call works anywhere before the first flagged `run`. Under `|| code=$?` a failing command runs and only its failure is ignored. The octal rule no longer claims a per-version result for an empty `10#$x`.
writing-code Step 6 corrects a comment and then classifies it, and the classification can delete the comment it just corrected, which the user never learned about. The report to the user now names such a deletion and its bucket. The step heading now reads "Check and classify each comment", and the digraph's classify node names loading `references/comments.md`, so every prose action in the step has a node.
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.
Fixes #17
Fixes #23
Summary
Completes the BATS framework reference in
writing-tests, corrects and extends the Bash rules inwriting-code, and fixes rules of the same kind in the other stack and framework references.Changes
writing-tests: BATS reference
run -<N>,run !,bats_require_minimum_version 1.5.0(anywhere before the first flaggedrun), BW01 and BW02.refute,run !and a bareassert_failurepass when the command does not exist (exit 127), so the reference asserts the exact status.teardown, exported-only variables fromsetup_file,--jobsprerequisites and opt-outs, noEXITtrap in the test shell, root ignoring file modes. TheBATS_*_TMPDIRscopes sit under helpers and temp directories.run fdoes not applyset -einside a function that does not enable it itself unless--errexitis passed (from 1.14.0,runhonors aset -ethe function turns on), sorun -0 fcan pass where a directffails;f || code=$?also runsfwith errexit off (a failing command runs and only its failure is ignored), so that capture is limited to functions that propagate their own failures; a failing< <(…)registers no tests and the run can still exit 0; duplicate names abort the file.bats-referenced-by-nametemplate listsbats_test_function … -- <function>.writing-code: Bash reference
set -o posixthe$( … )failure ends the shell on bash 3.2 through 5.3.|| trueonly when every non-zero status is an answer; otherwise branch on the exact status (grepexits 2 on an unreadable file). When a failure shares its status with an answer, no status check separates them.declare -gandlocal -as further examples.$(set +o)capture can drop),local a=x b="$a",read -areading one line, redirection order with2>, data into jq and awk through--argandENVIRON(a value interpolated into a jq filter can inject code; every awk processes-vescapes), octal leading zeros (guard digits before10#$x), jq// emptybindings.writing-code: workflow
Other stack and framework references
comments.mdsay what a named exception, a discard or a catch-all still hides. Go allows_ =only with a comment that says why the discard is safe.vi.resetAllMocks()resetsvi.fn()implementations,vi.restoreAllMocks()restoresvi.spyOnspies only. Jest: pick the call by where implementations are set;jest.restoreAllMocks()leavesjest.fn()implementations in place, andjest.resetAllMocks()replacesjest.fn(impl)andjest.mockfactory implementations with ones that returnundefined.Tests and CI
inject_extension.bats(software-writer and work-orchestrator): the unreadable-file test no longer depends onchmodas root. A directory-at-path test covers the guard for every user, and thechmod 000test skips as root.setup-bats.shpins bats-core 1.14.0 and bats-assert 2.2.4.