summaryrefslogtreecommitdiff
path: root/tests
Commit message (Collapse)AuthorAgeFilesLines
...
* test(ai-config): cover available-backends, change-model, add-file, toggle, ↵Craig Jennings2026-05-141-0/+160
| | | | context-clear
* test(transcription-config): cover notify, start-process, sentinel bodiesCraig Jennings2026-05-141-0/+165
|
* test(dirvish-config): cover ediff-files, create-playlist, set-wallpaper wrappersCraig Jennings2026-05-141-0/+144
|
* test(org-agenda-config): cover scan-files, todo-list wrappers, main-display, ↵Craig Jennings2026-05-141-0/+162
| | | | add-timestamp
* test(org-roam-config): cover copy-todo-to-today and move-org-branch-to-roam ↵Craig Jennings2026-05-141-0/+129
| | | | bodies
* test(custom-ordering): cover the interactive arrayify/listify/sort wrappersCraig Jennings2026-05-141-0/+145
|
* test(org-refile-config): cover cj/--org-refile-scan-targets disk walkerCraig Jennings2026-05-141-0/+142
|
* test(mail-config): cover toggle-smtpmail-debug, disable-auto-composition, ↵Craig Jennings2026-05-141-0/+70
| | | | mark-all-headers
* test(ui-theme): cover switch-themes, save-to-file, get-active-nameCraig Jennings2026-05-141-0/+110
|
* test(org-drill-config): cover drill-edit, drill-capture, drill-refileCraig Jennings2026-05-141-0/+91
|
* test(host-environment): cover cj/match-localtime-to-zoneinfoCraig Jennings2026-05-141-0/+58
|
* test(ui-navigation): cover split-and-follow + undo-kill-bufferCraig Jennings2026-05-141-0/+108
| | | | | | | | | | Sibling tests covered `toggle-window-split` and the window-resize sticky map. This batch covers: - `cj/split-and-follow-right`: split-window-right + other-window + consult-buffer in order. - `cj/split-and-follow-below`: split-window-below + other-window + consult-buffer in order. - `cj/undo-kill-buffer`: with no arg, opens the head of `recentf-list` that isn't currently visited; with N=1, opens the second entry; empty list -> no-op. Top-level defvars for `recentf-mode` and `recentf-list` so let-bindings reach the dynamic vars under lexical scope.
* test(coverage-elisp): cover project-root resolution, report-path, runCraig Jennings2026-05-141-0/+113
| | | | | | | | | | Sibling `test-coverage-elisp--detect.el` covered the detect heuristic. This batch fills in the rest: - `cj/--coverage-elisp-project-root`: explicit arg wins, falls back to projectile, falls back to `default-directory`. - `cj/--coverage-elisp-report-path`: appends `.coverage/simplecov.json` to the resolved root. - `cj/--coverage-elisp-run`: launches `make coverage` via `compilation-start`, fires the callback with the report path on `finished` status, skips the callback on failure. projectile and compilation-start are stubbed; the compilation buffer is a real buffer the test creates and tears down.
* test(system-utils): cover open-file-with-command, server-shutdownCraig Jennings2026-05-141-0/+94
| | | | | | | | | Sibling `test-system-utils-eval-buffer.el` covered the eval-buffer wrapper. This batch covers: - `cj/open-file-with-command`: a launcher routes through `call-process`; a non-launcher routes through `start-process-shell-command` into a dedicated `*Open with <cmd>: <file>*` buffer; a missing file signals an error. - `cj/server-shutdown`: saves buffers and calls `kill-emacs`. Process and prompt primitives are stubbed.
* test(system-commands): cover resolve, run wrapper, exit/restart, menuCraig Jennings2026-05-141-0/+142
| | | | | | | | | | | | Sibling `test-system-commands-keymap.el` locked the keymap shape. This batch covers the runtime helpers and commands: - `cj/system-cmd--resolve`: trims strings, errors on empty/non-string-non-symbol, round-trips a symbol whose value is a non-empty string, errors on a symbol with empty value. - `cj/system-cmd`: wraps a plain string in `nohup ... &` and hands it to `start-process-shell-command`; a confirm-tagged var with an N response signals user-error. - `cj/system-cmd-exit-emacs`: declining the prompt aborts; accepting calls `kill-emacs`. - `cj/system-cmd-restart-emacs`: declining aborts before scheduling; accepting schedules two timers. - `cj/system-command-menu`: the completing-read pick routes through `call-interactively` to the right command symbol. Top-level defvars for `test-sc-my-cmd` and `test-sc-empty-cmd` make the let-bindings dynamic so `symbol-value` reaches them under lexical scope.
* test(external-open): cover xdg-open, open-this-file-with, find-file-autoCraig Jennings2026-05-141-0/+120
| | | | | | | | | | Sibling tests in `test-external-open-lib-*.el` covered the pure helpers (`cj/external-open-command`, `cj/external-open-launcher-p`). This batch covers the user-facing wrappers: - `cj/xdg-open`: posix path triggers `call-process` with the open program; errors when no file is associated; errors when no command resolves on the host. - `cj/open-this-file-with`: errors outside a file-visiting buffer; posix path spawns a detached process via `call-process-shell-command` with `nohup ... >/dev/null 2>&1 &`. - `cj/find-file-auto`: routes a `.mp4` (in `default-open-extensions`) to `cj/xdg-open`, passes `.txt` through to the original `find-file`, and falls through cleanly for a nil filename argument. Host predicates, call-process, and the underlying `cj/xdg-open` are stubbed throughout.
* test(prog-go): cover go-setup, staticcheck, debug, keybindingsCraig Jennings2026-05-141-0/+144
| | | | | | | | | | | Same shape as the prog-python and prog-webdev setup tests: company-mode + electric-pair-mode + LSP gating + buffer-local preferences. New tests cover: - `cj/go-setup`: tab-width 4, standard-indent 4, indent-tabs-mode t (Go convention); company-mode + electric-pair-mode both fire; LSP starts when gopls is on PATH, skips otherwise. - `cj/go-staticcheck`: runs `compile` with `./...` when staticcheck is on disk; messages and skips compile otherwise. - `cj/go-debug`: starts `gud-gdb` with `dlv debug` when delve is on PATH; messages otherwise. - `cj/go-mode-keybindings`: wires `C-; f` -> gofmt, `S-<f5>` -> staticcheck, `S-<f6>` -> debug. External modes and process primitives are stubbed.
* test(org-webclipper): cover lazy init, protocol handler, EWW captureCraig Jennings2026-05-141-0/+167
| | | | | | | | | | | Sibling `test-org-webclipper-process.el` covers the content-processing helper. This batch fills in the rest: - `cj/webclipper-ensure-initialized`: registers the webclip protocol entry + the W and w capture templates on first call, is idempotent on subsequent calls. - `cj/org-protocol-webclip`: stashes the url+title, triggers capture; missing title falls back to "Untitled". - `cj/org-protocol-webclip-handler`: errors when no url stashed, returns processed org content on success (with the first heading stripped + subs demoted), wraps fetch failures in a "Failed to clip" error. - `cj/org-webclipper-EWW`: routes through `org-eww-copy-for-org-mode` for eww-mode and `org-w3m-copy-for-org-mode` for w3m-mode; errors on any other source mode. Top-level defvars for `org-protocol-protocol-alist`, `org-capture-templates`, and `webclipped-file` make let-bindings dynamic under lexical scope. org-web-tools and the eww/w3m copy commands are stubbed.
* test(org-refile-config): cover refresh-targets, org-refile, refile-in-fileCraig Jennings2026-05-141-0/+82
| | | | | | | | | | Sibling tests covered the ensure-org-mode helper and the build-targets pipeline. The three wrapper commands were uncovered: - `cj/org-refile-refresh-targets`: passes the `force-rebuild` flag to `cj/build-org-refile-targets`. - `cj/org-refile`: builds the cache, then calls `org-refile` with the four positional args. - `cj/org-refile-in-file`: scopes `org-refile-targets` to the current file at maxlevel 6, then saves after the refile completes. Top-level `defvar` for `org-refile-targets` so the let-binding inside the function is dynamic under lexical scope.
* test(org-contacts-config): cover template helpers, props-matching, email ↵Craig Jennings2026-05-141-0/+129
| | | | | | | | | | | | | | aggregator Sibling tests covered the capture-finalize hook and the email-string parser. This batch fills in the rest: - `cj/org-contacts-template-name` / `-email`: fall back to `read-string` outside mu4e; pull from `mu4e-message-field` when inside. - `cj/org-contacts-new`: delegates to `org-capture` with key "C". - `cj/org-contacts--props-matching`: filters an entry's props by regexp. - `cj/get-all-contact-emails`: formats each entry as "Name <email>", expands multi-email strings. - `cj/insert-contact-email`: inserts the completing-read selection at point. mu4e and org-contacts primitives are stubbed.
* test(org-reveal-config): cover command wrappers + preview helpersCraig Jennings2026-05-141-0/+197
| | | | | | | | | | | | | | | Sibling tests covered the header template, title-to-filename slug, and the headers-remove pass. This file fills in the rest: - `cj/--reveal-preview-export-on-save`: exports in org-mode, skips otherwise. - `cj/--reveal-ensure-header`: inserts when absent, no-op (no prompt) when already present. - `cj/reveal-export`: errors outside org-mode, opens HTML in browser otherwise. - `cj/reveal-preview-start`: installs the buffer-local after-save-hook + exports once; errors outside org-mode. - `cj/reveal-preview-stop`: removes the hook + messages. - `cj/reveal-insert-header`: errors outside org-mode, errors when headers already present, inserts and reports otherwise. - `cj/reveal-remove-headers`: errors outside org-mode, messages the removed line count. - `cj/reveal-new`: errors when target file already exists. ox-reveal's `org-reveal-export-to-html` and `browse-url-of-file` are stubbed.
* test(org-noter-config): cover document path, find/create, session, start, insertCraig Jennings2026-05-141-0/+243
| | | | | | | | | | | | | | | Sibling tests covered the preferred-split, title-to-slug, notes-template, and in-document / in-notes-file predicates. This batch fills in the rest: - `cj/org-noter--get-document-path`: pdf-view-mode uses buffer-file-name, nov-mode uses `nov-file-name`, unrelated mode returns nil. - `cj/org-noter--extract-document-title`: strips the extension. - `cj/org-noter--find-notes-file`: returns the file containing the doc-path, nil when no doc or no match. - `cj/org-noter--create-notes-file`: writes the template when absent. - `cj/org-noter--session-active-p`: nil when unbound, non-nil when set. - `cj/org-noter--toggle-notes-window`: deletes when visible, requests start when hidden. - `cj/org-noter-start`: routes through the cond -- toggle in doc+session, switch-window in notes+session, message elsewhere. - `cj/org-noter-insert-note-dwim`: with active session inserts directly; without one, starts then inserts. org-noter / pdf-view / nov / org-id primitives are stubbed.
* test(slack-config): cover credentials, start/stop, reactions, notify, kill-allCraig Jennings2026-05-141-0/+251
| | | | | | | | | | | | | | | | Sibling `test-slack-config-reactions.el` covered the post-command-hook safety advice and the empty-buffer guard. This batch covers the rest: - `cj/slack--get-credential`: string secret, function secret, missing entry. - `cj/slack-start`: errors when token / cookie missing, registers + starts when both present. - `cj/slack-stop`: calls `slack-ws-close` + messages. - `cj/slack--reaction-candidates`: includes the (Other...) escape hatch. - `cj/slack-select-reaction`: emoji-name return for a curated pick, delegation to `slack-message-reaction-input` for Other. - `cj/slack-notify`: fires for IMs (not self), skips self-messages and non-IM non-mentions. - `cj/slack-test-notify`: fires the notify pipeline directly. - `cj/slack-mark-read-and-bury`: marks via the latest-ts + buries; outside slack, just buries. - `cj/slack-close-all-buffers`: closes buffers with `slack-current-buffer` local, leaves non-slack buffers alone. The close-all assertions check identity (the 2 slack buffers killed, the non-slack one preserved) instead of an exact total -- ERT-internal buffers leaking into `(buffer-list)` from earlier tests would otherwise inflate the count, and `cl-letf` over the `buffer-list` subr is unreliable under native-comp.
* test(org-roam-config): cover tag predicate, find-node, finalize hook, ↵Craig Jennings2026-05-141-0/+167
| | | | | | | | | | | | | | | insert-immediate Sibling tests covered the slug helper, link-description, demote-subtree, format-roam-node, and the copy-todo-to-today hook. This batch covers the tag/find/insert family: - `cj/org-roam-filter-by-tag`: returns a predicate; keeps matching nodes, rejects non-matching. - `cj/org-roam-list-notes-by-tag`: returns file paths for matches, empty list when no matches. - `cj/org-roam-add-node-to-agenda-files-finalize-hook`: removes itself, adds the captured buffer's file to `org-agenda-files` when not aborted, skips on abort. - `cj/org-roam-find-node`: calls `org-roam-node-find` with a filter predicate + templates. - `cj/org-roam-find-node-topic` / `-recipe`: delegate with the right tag + key (+ subdir). - `cj/org-roam-node-insert-immediate`: appends `:immediate-finish t` to the first capture template before calling `org-roam-node-insert`. Top-level `defvar`s for `org-note-abort`, `org-agenda-files`, `org-roam-capture-templates`, and `org-capture-after-finalize-hook` make the let-bindings reach the dynamic vars under lexical scope.
* test(hugo-config): cover new-post, export, navigation, preview, publishCraig Jennings2026-05-141-0/+235
| | | | | | | | | | | | | | | Sibling tests covered the pure helpers (`cj/hugo--post-file-path`, `cj/hugo--post-template`, `cj/hugo--post-metadata`, `cj/hugo--collect-drafts`, `cj/hugo-open-blog-dir-external`, `cj/hugo-toggle-draft`). This batch covers the remaining commands and preview helpers: - `cj/hugo-new-post`: writes the template to a slugged file, errors when one already exists. - `cj/hugo-export-post`: errors outside org-mode, delegates to `org-hugo-export-to-md` otherwise. - `cj/hugo-open-blog-dir`: ensures the dir exists and opens dired on it. - `cj/hugo-open-draft`: messages when no drafts, otherwise picks via `completing-read` and opens. - `cj/hugo--preview-filter`: opens the browser when Hugo prints "Web Server is available", ignores arbitrary output. - `cj/hugo--preview-sentinel`: clears the process var on clean exit, messages on a non-zero exit. - `cj/hugo-preview`: stops a running server, starts one when stopped (verifying `start-process` got the "server" arg). - `cj/hugo-publish`: hands off to `magit-status-setup-buffer` on `website-dir`. ox-hugo's `org-hugo-slug` is stubbed via `defun` (the package isn't installed in batch); `require`, `org-hugo-export-to-md`, `dired`, `find-file`, `browse-url`, `start-process`, `kill-process`, and `magit-status-setup-buffer` are stubbed per-test.
* test(ai-config): cover gptel switch/add/toggle commands + small helpersCraig Jennings2026-05-141-0/+152
| | | | | | | | | | | | | Second pass on ai-config. First batch covered the auth-source, API-key caching, file-context, clear-buffer, context-clear, and model-heading helpers. This batch covers the gptel command wrappers and a couple of small helpers: - `cj/gptel--refresh-org-prefix`: refreshes the org-mode entry in `gptel-prompt-prefix-alist`. - `cj/gptel-backend-and-model`: formats a vector-backend's name + the current model + a timestamp; falls back to "AI:" when no backend is bound. - `cj/gptel-switch-backend`: picks a backend and one of its models, updates both gptel vars; errors on an invalid backend choice. - `cj/gptel-add-buffer-file`: hands the visited file off to `cj/gptel--add-file-to-context`, messages otherwise. - `cj/gptel-add-this-buffer`: calls `gptel-add` with the (4) prefix-arg. - `cj/toggle-gptel`: deletes the window when *AI-Assistant* is already shown. gptel and projectile primitives are stubbed throughout.
* test(music-config): cover playlist commands + random-aware navigationCraig Jennings2026-05-141-0/+261
| | | | | | | | | | | | | Second pass on music-config. The first batch covered assertion guards, the M3U picker, EMMS lazy setup, and the smaller commands. This batch covers the remaining interactive playlist commands and the random-history navigation pair: - `cj/music-playlist-load`: loads the selected file via `emms-play-playlist`, errors when the chosen file isn't on disk. - `cj/music-playlist-reload`: replays the buffer-local playlist file, errors when none is associated. - `cj/music-playlist-edit`: opens the M3U file in another window when the buffer is clean. - `cj/music-next`: delegates to `emms-next` or `emms-random` based on `emms-random-playlist`. - `cj/music-previous`: emms-previous when not random; with random + history pops the top, finds it in the playlist, selects + starts; with random + no history messages; with random and a missing track, messages. - `cj/music--consume-track`: no-op when consume-mode is off, kills the selected track when on. EMMS primitives (`emms-playlist-clear`, `emms-play-playlist`, `emms-stop`, `emms-random`, `emms-next`, `emms-previous`, `emms-start`, `emms-playlist-select`, `emms-playlist-mode-kill-track`) are stubbed throughout.
* test(test-runner): cover per-project state + small interactive wrappersCraig Jennings2026-05-141-0/+273
| | | | | | | | | | | | | | | | | | | `test-test-runner.el` covered the `cj/test--do-*` helpers and the focus-add / focus-remove / extract-test-names families. The state machinery and small wrappers were the gap. 22 new tests cover: - `cj/test--project-root`: nil when projectile is absent, expanded trailing-slash when present. - `cj/test--state-key`: falls back to `default-directory` without a project root. - `cj/test--project-state`: creates the entry lazily, reuses on second call. - `cj/test--state-get` / `cj/test--state-put`: roundtrip + default fallback. - `cj/test--current-focused-files` / `cj/test--current-mode` getter/setter pairs. - `cj/test--sync-legacy-state`: mirrors per-project state into the public legacy vars. - `cj/test--remember-loaded-project-root`: pushes once via `cl-pushnew`, no-op without a root. - `cj/test--file-in-directory-p`: true for a subpath, false for a sibling. - `cj/test--get-test-directory`: prefers `tests/` subdir, falls back to the global default. - `cj/test--get-test-files`: lists `test-*.el` files only, basenames. - `cj/test--ensure-test-dir-in-load-path`: adds the dir. - `cj/test-focus-clear` / `cj/test-toggle-mode` / `cj/test-view-focused` / `cj/test-run-all`: behavior + messaging.
* test(custom-buffer-file): cover print spooler, diff, eww, email helpersCraig Jennings2026-05-141-0/+189
| | | | | | | | | | | | | Sibling tests cover the move/rename/copy/clear family. The remaining helpers and dispatchers were uncovered: - `cj/print--resolve-spooler`: explicit-string on PATH, explicit-string missing (error), `auto` prefers lpr, `auto` falls back to lp, `auto` with nothing on PATH (error), `auto` returns cached value, invalid spooler symbol (error). - `cj/copy-buffer-name`: places the current buffer's name on the kill ring with a confirmation message. - `cj/view-buffer-in-eww`: hands the file off to `eww-open-file` when visiting a file, errors otherwise. - `cj/--email-handle-is-type-p`: prefix-matches content-types, handles nil handle without signaling. - `cj/--diff-with-regular-diff`: writes a unified diff into the target buffer with header + diff output. - `cj/diff-buffer-with-file`: errors when not visiting a file, messages "No differences" when diff -q returns 0. 16 new tests total. `call-process`, `executable-find`, `eww-open-file`, `mm-handle-type`, `diff-mode` are stubbed.
* test(prog-python+webdev): cover the per-buffer setup mode hooksCraig Jennings2026-05-142-0/+191
| | | | | | | | | | | | `cj/python-setup` and `cj/webdev-setup` are the per-buffer preference functions wired into `python-ts-mode` / `typescript-ts-mode` / `tsx-ts-mode` / `js-ts-mode`. Sibling tests covered the command builders and prettier/mypy wrappers but not these. 9 new tests across two files cover, for each setup: - the setq-local pairs (fill-column, tab-width, standard-indent, indent-tabs-mode) land at the language's defaults (Python: 80/4/4/nil; webdev: 100/2/2/nil), - the mode helpers (company, flyspell-prog, superword, electric-pair-local) all get called, - LSP gating: starts when the language server binary is on PATH, skips otherwise. Plus a check that `cj/webdev-keybindings` binds `C-; f` to the prettier wrapper. External modes and `executable-find` / `lsp-deferred` are stubbed so the tests run without a Python or Node toolchain.
* test(transcription-config): cover status helpers + interactive commandsCraig Jennings2026-05-141-0/+194
| | | | | | | | | | | | | Sibling tests cover the audio-file predicate, path/duration helpers, log cleanup, sentinel helpers, and the process-environment builder. The gap was the running-list helpers and the interactive commands. 15 new tests cover: - `cj/--running-transcriptions`: filters by `running` status, handles empty list. - `cj/--cleanup-completed-transcriptions`: prunes the list down to running entries only. - `cj/--count-active-transcriptions`: counts running, zero when empty. - `cj/--transcription-modeline-string`: nil when idle, includes the active count when busy. - `cj/transcriptions-buffer`: renders the empty-state message or per-entry rows. - `cj/transcription-kill`: errors with no entries, calls `kill-process` on a live one. - `cj/transcription-switch-backend`: completing-read picks the new backend, var + message updated. - `cj/transcribe-audio-at-point`: errors outside dired / when no file at point, delegates otherwise.
* test(dirvish-config): cover five interactive wrappersCraig Jennings2026-05-141-0/+209
| | | | | | | | | | | | Sibling tests covered the pure helpers; the interactive wrappers were the gap. 13 new tests cover: - `cj/dirvish-open-html-in-eww`: HTML file -> `eww-open-file`, non-HTML -> message. - `cj/dirvish-duplicate-file`: copies file with `-copy` suffix, errors on no-file / directory / declined-overwrite. - `cj/dired-mark-all-visible-files`: marks file lines, skips directory lines (via `cj/--dired-line-is-directory-p`). - `cj/dired-copy-path-as-kill`: errors outside dired-mode, kills resolved path, formats as org-link when asked. - `cj/dirvish-open-file-manager-here`: uses `cj/external-open-command` when available, falls back to `xdg-open` shell command otherwise, messages when current dir can't be resolved. The decline-overwrite test uses real temp files instead of `cl-letf`-overriding `file-directory-p` + `file-exists-p` -- native-comp's trampoline cache breaks when several built-ins get redefined in the same test.
* test(custom-comments): cover the eight interactive comment wrappersCraig Jennings2026-05-141-0/+192
| | | | | | The internal `cj/--comment-*` helpers were covered in the sibling test files; their interactive wrappers were the gap. 11 new tests drive each wrapper through its full prompt cycle (read-string / read-from-minibuffer / completing-read all stubbed) and assert the wrapper produces output containing the supplied text. The length-option branches for `cj/comment-simple-divider` are exercised across all three values (fill-column / half-column / match-text), and `cj/comment-hyphen`'s thin delegate to `cj/comment-inline-border` with "-" is covered too. The wrappers split between `read-string` and `read-from-minibuffer` for their text input (box uses minibuffer; the rest use read-string); the tests stub each function explicitly to drive the right path.
* test(music-config): cover assertion guards, M3U picker, EMMS lazy setupCraig Jennings2026-05-141-0/+224
| | | | | | | | | | | | | | music-config has a large sibling-test fleet for the pure helpers; the gap was a handful of small dispatchers and assertion guards. 13 new tests, EMMS primitives stubbed throughout: - `cj/music--assert-m3u-files-exist`: passes a non-empty list through, errors on empty. - `cj/music--sync-playlist-file`: sets the buffer-local file ref + resets point. - `cj/music--select-m3u-file`: returns the chosen path, returns nil on Cancel, errors when no files exist. - `cj/emms--setup`: no-ops when emms already loaded, requires when absent. - `cj/music-playlist-clear`: stops playback, clears the playlist, nils the file ref. - `cj/music-add-directory-recursive`: calls `emms-add-directory-tree` for an existing dir, user-errors for non-dirs. - `cj/music--find-track-in-playlist`: returns the buffer position when present, nil when absent.
* fix(ai-vterm): force buffer swap after F9 toggle-off in lone windowCraig Jennings2026-05-141-30/+46
| | | | | | The original fix (9600611) set a flag at toggle-off and let the next toggle-on detect it. The flag mechanism is right, but the toggle-off itself wasn't observable when bury-buffer couldn't switch the lone window onto a different buffer -- `bury-buffer' falls back to `switch-to-prev-buffer', which no-ops when the window's prev-buffer history contains only the agent itself (common right after a `C-x 1' that cleared the surrounding windows' histories). Without an observable swap, the second F9 found the agent still displayed and routed back through toggle-off, looping the user with no visible effect. Dispatcher now explicitly forces the window onto another buffer (`(other-buffer agent-buf t)`) when the lone window is still showing the agent after `bury-buffer'. The round-trip test now exercises the real `bury-buffer' path instead of simulating it; a new test asserts the lone window's buffer is non-agent after toggle-off.
* feat(org-agenda): add VERIFICATION and IN-PROGRESS blocks around SCHEDULECraig Jennings2026-05-131-0/+86
| | | | | | | | | | The main "d" agenda view grows two new blocks. A VERIFICATION block lists tasks in the VERIFY TODO state, placed just above the day's SCHEDULE. An IN-PROGRESS block lists tasks in the DOING TODO state, placed just under SCHEDULE. The full block order is now: OVERDUE -> HIGH PRIORITY -> VERIFICATION -> SCHEDULE -> IN-PROGRESS -> PRIORITY B. Scope matches the other blocks (every entry in `org-agenda-files`). Scheduled and deadlined entries are included -- a VERIFY task with a date appears in both VERIFICATION and SCHEDULE, mirroring how HIGH PRIORITY behaves. Habits are skipped via `cj/org-skip-subtree-if-habit`; PROJECT-keyword parents wouldn't match `(todo "VERIFY")` exact-state filters anyway, so no extra skip there. Two new header defvars (`cj/main-agenda-verify-title`, `cj/main-agenda-doing-title`) for symmetry with the existing four. Both blocks reference the shared `cj/--main-agenda-prefix-format` so a format tweak still lands in one place. Five new tests in `test-org-agenda-config-skip-functions.el` lock the block order, each new block's header / prefix-format / skip-function, and the include-scheduled-entries contract.
* test(custom-text-enclose): cover the seven interactive wrappersCraig Jennings2026-05-131-0/+225
| | | | The internal `cj/--*` helpers were already tested; the public dispatchers (`cj/surround-word-or-region`, `cj/wrap-word-or-region`, `cj/unwrap-word-or-region`, and the four `*-in-region-or-buffer` line helpers) were the gap. 18 new tests cover the region-active branch, the thing-at-point-word branch, and the no-word-no-region message branch for the first three; the region-vs-whole-buffer branches for the line-oriented four; plus a tab-vs-space pair for indent and a partial-dedent assertion. `read-string` is stubbed for the prompt-driven wrappers; `transient-mark-mode` is let-bound on so `use-region-p` returns t in batch.
* test(ai-config): cover auth-source, api-key caching, context, clear-bufferCraig Jennings2026-05-131-0/+183
| | | | | | | | | | | | | The big-module coverage push starts with ai-config (was 53/191, 27.7%). New test file covers seven helpers that don't depend on a live gptel install: - `cj/auth-source-secret`: returns string secrets, funcall's function secrets, errors on missing. - `cj/anthropic-api-key` / `cj/openai-api-key`: cache the result so subsequent calls don't re-hit auth-source. - `cj/gptel--add-file-to-context`: adds existing files, skips nil and missing paths. - `cj/gptel-clear-buffer`: erases in a gptel-org buffer and reinserts the fresh prefix; no-ops + messages elsewhere. - `cj/gptel-context-clear`: three cond branches (`remove-all`, `clear`, alist-fallback) with appropriate `fboundp` stubs. - `cj/gptel-insert-model-heading`: inserts at the response-begin position with the backend/model heading. External primitives (`auth-source-search`, `gptel-add-file`, `gptel-context-remove-all`, etc.) are stubbed. The fallback test declares `gptel-context--alist` as a top-level `defvar` so `setq` inside the function reaches the dynamic binding under lexical scoping.
* test(jumper): cover the three interactive wrappers + setup-keysCraig Jennings2026-05-131-0/+175
| | | | `test-jumper.el` covered the internal helpers (`jumper--do-store-location`, `jumper--do-jump-to-location`, `jumper--do-remove-location`) thoroughly. The interactive entry points (`jumper-store-location`, `jumper-jump-to-location`, `jumper-remove-location`) and `jumper-setup-keys` were the gap. 10 new tests capture `message` and stub `completing-read` to cover: fresh-store messaging, duplicate detection, no-space full-registers path, no-locations / already-there / multi-prompt jump branches, no-locations / prompt-and-delete / cancel remove branches, and the prefix-key wiring.
* test(custom-whitespace): cover the six interactive dispatchersCraig Jennings2026-05-131-0/+183
| | | | The internal `cj/--*` helpers were exhaustively tested; the public dispatchers (`cj/remove-leading-trailing-whitespace`, `cj/collapse-whitespace-line-or-region`, `cj/ensure-single-blank-line`, `cj/delete-blank-lines-region-or-buffer`, `cj/delete-all-whitespace`, `cj/hyphenate-whitespace-in-region`) were not. 15 new tests cover the region / line / whole-buffer branches plus the two `yes-or-no-p` prompt paths (accept and decline). `transient-mark-mode` is let-bound on so `use-region-p` returns t in batch.
* test(ui-config): cover transparency apply/toggle and cursor-type setterCraig Jennings2026-05-131-0/+126
| | | | The previous test file covered only `cj/--buffer-cursor-state` and the cursor-color hook. `cj/apply-transparency`, `cj/toggle-transparency`, and `cj/set-cursor-type` were the gap. New tests stub the frame-mutating primitives so they run in batch and cover: alpha cons construction in both enabled and disabled states, the terminal-frame skip, the error-message path on `set-frame-parameter` failure, the toggle's flip + re-apply, double-toggle idempotence, and the cursor-type pass-through (including nil for invisible).
* test(system-defaults): cover the helper functionsCraig Jennings2026-05-131-0/+155
| | | | | | system-defaults.el is mostly `setq` configuration, but the testable helpers (`cj/disabled`, the two minibuffer-gc hooks, `unpropertize-kill-ring`, `cj/log-comp-warning`) were uncovered. New test file mirrors the sandbox pattern from test-system-defaults-vc-follow-symlinks.el and asserts each function's observable behavior: gc-threshold flip on minibuffer entry/exit, kill-ring property strip with empty-ring boundary, comp warning written with timestamp + non-comp type ignored so the default *Warnings* path still works. 8 new tests across Normal / Boundary cases.
* test(browser-config): cover the public wrappersCraig Jennings2026-05-131-0/+68
| | | | The internal `cj/--do-*` helpers were already tested. The `cj/apply-browser-choice` and `cj/initialize-browser` wrappers were the gap -- they call `cj/--do-*` then `message` and own the wiring logic. New tests stub `message` and `cj/--do-apply-browser-choice` to cover each branch (success, invalid plist, loaded, first-available, no-browsers).
* refactor(org-agenda): extract main-agenda prefix format into a defvarCraig Jennings2026-05-131-0/+17
| | | | | | `org-agenda-custom-commands` inlined ` %i %-15:c%?-15t% s` four times across the "d" command's overdue / high-priority / schedule / priority-B blocks. New `cj/--main-agenda-prefix-format` defvar holds the literal once; every block now references the symbol so a format tweak lands in one place. Regression test walks the "d" command's blocks and asserts each `org-agenda-prefix-format` cell resolves to the shared symbol -- a block that silently diverges fails the check.
* feat(setup): scripts/setup-telega.sh prepares the docker environment for telegaCraig Jennings2026-05-131-0/+87
| | | | | | Verifies docker is installed and the daemon is reachable, then either pulls a public image (when `TELEGA_DOCKER_IMAGE` is set) or announces the in-Emacs build path (`M-x telega-server-build`) for the user to run once. Telegram auth (phone + verification code) is interactive on first `M-x telega` and not scripted here. Same shape as setup-email.sh: helpers are sourceable for bats, `main` runs only under direct execution. 7 bats tests stub `docker` and `command` so the suite never talks to the real daemon.
* feat(telega): add telega.el module with docker-backed TDLibCraig Jennings2026-05-131-0/+25
| | | | | | | | New `modules/telega-config.el` configures telega.el as an in-Emacs Telegram client. `telega-use-docker' is on so TDLib runs in a container instead of needing a system-level build -- pairs with a follow-up `scripts/setup-telega.sh' for fresh-clone installs. First-run auth (phone + verification code) is interactive inside `M-x telega' and isn't scripted here. Launcher binding: `C-; G` (mnemonic: teleGram). `C-; t` and `C-; m t` were both taken (test-runner, music's "repeat track"), so the launcher landed on a free top-level letter. Two tests cover the wiring: module loads, launcher is bound.
* feat(vterm): show tmux scrollback history in placeCraig Jennings2026-05-131-8/+40
| | | | | | `cj/vterm-tmux-history' previously used `pop-to-buffer', which routed the history view through display-buffer-alist -- in an agent window that often meant a split or a hand-off to another window, costing the agent its frame slot. `switch-to-buffer' instead drops the history into the selected window directly; the existing quit handler already restores the origin in that same window via `set-window-buffer'. New test asserts the in-place behavior: starting single-window with a vterm origin, invoking the command leaves `(one-window-p)` t with the history buffer in the original slot. The existing render test no longer needs its `pop-to-buffer' stub since `switch-to-buffer' works in batch.
* fix(ai-vterm): preserve single-window layout across F9 toggleCraig Jennings2026-05-131-0/+170
| | | | | | | | When the agent buffer is the only window in the frame, F9 buries it (correct) but the next F9 redisplayed it as a side split instead of restoring the full-frame layout -- the display-saved path always called `display-buffer-in-direction`, which insists on a split. New `cj/--ai-vterm-last-was-bury` flag tracks which toggle-off path ran. `cj/ai-vterm` sets it to t in the bury branch (one-window-p) and nil in the delete-window branch. `cj/--ai-vterm-display-saved` checks the flag at toggle-on: if t and the frame is still single-window, it replaces the selected window's buffer in place rather than splitting. Either branch consumes the flag so it never stays stale. 5 tests in test-ai-vterm--single-window-toggle.el cover the flag's set/clear paths, the still-one-window guard, and the end-to-end roundtrip.
* feat(org-agenda): use project name as todo.org categoryCraig Jennings2026-05-131-0/+137
| | | | | | The %c column on agenda blocks rendered every project's todo.org as "todo:" -- org defaults the buffer category to the filename without extension, so every entry looked alike. An org-mode-hook now overrides org-category with the parent directory's basename (stripping a single leading dot, so ~/.emacs.d/todo.org reads as "emacs.d") whenever a todo.org file opens and its category is still the filename default. Explicit #+CATEGORY: keywords still win. 14 tests in test-org-agenda-config-category.el cover the helper's normal/boundary/error paths and the hook's override + explicit-category-preserved cases.
* fix(ui-navigation): clear dedicated before toggling window splitCraig Jennings2026-05-131-0/+110
| | | | | | | | toggle-window-split swapped buffers between two windows via two set-window-buffer calls. If either window was strongly dedicated (e.g. *Org Agenda* via the display-buffer-alist rule), the dedicated window rejected the second swap. Both panes ended up showing the dedicated buffer. The non-dedicated buffer never made it across. The fix clears dedicated on both windows before the swap. The user explicitly invoked a layout change, so preserving per-window dedicated through the operation would just re-trigger the same wedge on the next toggle. Tests in tests/test-ui-navigation--toggle-window-split.el cover the no-dedicated baseline, the bug-trigger (dedicated selected window), the post-toggle cleared state, and the one-window / three-window no-op boundaries.