<!-- SPDX-License-Identifier: GPL-2.0-or-later -->
# Testing the shell completions

The completion scripts are generated by `generate-completions.py` from the
metadata `nvme utils dump-command-metadata` emits, so every shell should offer
the **same** completions. The automated suites
(`test-bash-completion.sh`, `test-zsh-completion.sh`) drive each generated
script directly and cover the generator's routing and value data. They cannot
fully cover what a shell's completion *system* renders — see
[Per-shell notes](#per-shell-notes) — so the behavior checklist below should
also be run by hand in a live shell after regenerating.

## Load the completion

Load the generated script for the shell under test, then type at a real prompt
and press <kbd>Tab</kbd> where the checklist shows `<tab>`. Run each snippet from the
repo root.

**bash**

```sh
source completions/bash-nvme-completion.sh
```

**zsh** — clear the completion cache first so a regenerated `_nvme` is picked up:

```sh
rm -f ~/.zcompdump*
fpath=($PWD/completions $fpath)
autoload -Uz compinit && compinit -u
compdef _nvme nvme
```

## Behavior checklist

Expected completions are identical across shells unless the
[per-shell notes](#per-shell-notes) say otherwise.

- [ ] **Top-level commands** — `nvme <tab>` lists builtins (`list`,
      `format`, …), plugin names (`feat`, `zns`, …), and `help`/`version`.
- [ ] **Prefix filter** — `nvme write-<tab>` narrows to `write-zeroes`,
      `write-uncor`, ….
- [ ] **Command alias** — `nvme fw ac<tab>` offers `activate` (alias of
      `commit`); `nvme fw activate --<tab>` completes `commit`'s options.
- [ ] **Plugin sub-commands** — `nvme feat <tab>` lists the plugin's
      sub-commands; `nvme zns <tab>` does too (routing is not hard-coded to one
      plugin).
- [ ] **Sub-command alias** — `nvme dera <tab>` offers both `smart-log-add` and
      its alias `stat`.
- [ ] **Option names** — `nvme id ctrl -<tab>` offers `--output-format`,
      `--help`, …
- [ ] **Option names at an empty prefix** — `nvme id ctrl <tab>` (no leading
      `-`) still lists the plain options (`--help`, `--verbose`, …) alongside
      the device, not just the `=`-valued ones. (zsh: the option groups are
      tagged `nvme-noeq-options`/`nvme-eq-options` rather than the reserved
      `options` tag, which the framework would otherwise hide here when a device
      is also offered.)
- [ ] **A command without global options** — `nvme intel lat-stats-tracking
      -<tab>` offers only `--enable`/`--disable`, *not* `--output-format`.
- [ ] **Enumerated value** — `nvme id ctrl --output-format <tab>` and
      `--output-format=<tab>` both list `normal json binary tabular`;
      `-o <tab>` too.
- [ ] **Value from a hint** — `nvme feat power-meas --sel <tab>` lists
      `0 1 2 3`.
- [ ] **Command-local value** — `nvme fw commit --action <tab>` lists `replace …
      set-active …`.
- [ ] **File-valued option** — `nvme fw download --fw <tab>` completes
      filenames.
- [ ] **Device argument** — `nvme id ctrl <tab>` offers `/dev/nvme*`.
- [ ] **No device when one is present** — `nvme id ctrl /dev/nvme0 <tab>` does
      not offer a second device.
- [ ] **No device for help/version** — `nvme help <tab>` offers no `/dev/nvme*`.
- [ ] **help completes a command** — `nvme help <tab>` lists command names (the
      same set as top-level `nvme <tab>`), since `nvme help CMD` prints that
      command's help; it does *not* fall back to filenames.
- [ ] **help takes one argument** — `nvme help id ctrl <tab>` offers nothing
      (`help` takes a single command; no filename fall-back past it).
- [ ] **version takes no argument** — `nvme version <tab>` offers nothing at all
      (no options, no commands, no filenames).

## Per-shell notes

Differences are limited to what each shell's completion framework owns; the
generated data is the same everywhere.

| Behavior | Note |
|----------|------|
| Prefix / partial-value filtering | bash filters in our generated code; zsh lets the framework filter. Result is the same to the user. |
| Completing an option whose name is a prefix of another (e.g. `--output-format` vs `--output-format-version`) | The offered candidates are identical in both shells. In zsh with menu completion (`MENU_COMPLETE`/`AUTO_MENU`, common in user setups), completing `--output-forma<tab>` inserts `--output-format=` as a *menu selection*, so a further `<tab>` cycles to `--output-format-version=` instead of descending to values -- it never re-completes the now-unambiguous word. Type the first value character (`--output-format=j`) or accept the entry to reach values. bash has no menu completion, so it stops after listing the two names. This is the shell's menu behavior (zsh's native `_arguments` does the same), not the generated script. |
| `/dev/*` given as an *option value* (e.g. `--output-file /dev/null`) is not mistaken for the device argument | Enforced in the bash script. In zsh, `_arguments` tracks positionals itself, so this case is not handled by our code. |
| Trailing-space suppression after `--opt=` | bash-specific (`compopt -o nospace`); zsh handles it via `_values`. |
| "N possibilities" count vs. lines shown | zsh only. With verbose listings (the default), `nvme <tab>` may report far more "possibilities" than it displays (e.g. "452 possibilities" for ~153 commands). `_describe` lays the described matches out in a multi-column grid and pads it with empty alignment matches that count toward the total but render as nothing; the count scales with terminal width. The displayed entries are correct — this is not duplication. |

## A note on the automated suites

`test-bash-completion.sh` drives the real bash dispatcher and inspects the real
`COMPREPLY`, so it tests what actually runs. `test-zsh-completion.sh` must stub
the zsh completion builtins (`_values`, `_describe`, `compadd`, `_arguments`) to
capture what the script offers; it therefore verifies the generator's routing
and value lists but not how the live completion system renders them. Use the
checklist above (or `zsh/zpty`) for that last mile.
