Files
test-samurai.nvim/runner-agents.md
M.Schirmer e315a8e8f2
All checks were successful
tests / test (push) Successful in 8s
update ai prompt for external runner creation
2026-01-03 15:20:01 +01:00

240 lines
8.4 KiB
Markdown

# runner-agents.md — test-samurai Runner-API
Ziel: Diese Datei beschreibt die öffentliche Runner-API, die ein neuer Runner
implementieren muss, damit alle Commands vollständig unterstützt werden.
## Modulform (Pflicht)
- Der Runner ist ein Lua-Modul, das eine Table mit Funktionen zurückgibt.
- Beispiel:
- `local runner = {}`
- `return runner`
- Der Modulpfad in `runner_modules` muss exakt zum Dateipfad unter `lua/` passen.
- Beispiel: `lua/test-samurai-go-runner/init.lua` -> `require("test-samurai-go-runner")`.
- `lua/init.lua` wäre `require("init")` und ist kollisionsanfällig; vermeiden.
## Pflichtfunktionen (volle Command- und Keymap-Unterstützung)
- `is_test_file(bufnr) -> boolean`
- Wird für die Runner-Auswahl genutzt.
- `find_nearest(bufnr, row, col) -> spec|nil, err?`
- Für `TSamNearest`.
- `spec.file` muss gesetzt sein.
- Bei Fehler/kein Treffer: `nil, "reason"` zurückgeben.
- `build_command(spec) -> command_spec`
- Für `TSamNearest`.
- `build_file_command(bufnr) -> command_spec`
- Für `TSamFile`.
- `build_all_command(bufnr) -> command_spec`
- Für `TSamAll`.
- `build_failed_command(last_command, failures, scope_kind) -> command_spec`
- Für `TSamFailedOnly`.
- `parse_results(output) -> results`
- Fallback-Parser für vollständigen Output.
- `output_parser() -> { on_line, on_complete }`
- Muss Streaming unterstützen (Listing wird live befüllt).
- `parse_test_output(output) -> table`
- Detail-Ausgabe pro Test (Detail-Float und `<cr>` im Listing).
- `collect_failed_locations(failures, command, scope_kind) -> items`
- Quickfix-Unterstützung (Keymap `<leader>qn`).
## Output-Parsing (Listing + Summary)
Beide Varianten müssen vorhanden sein:
- `parse_results(output) -> results`
- `results` muss enthalten:
- `passes` (Array von Namen)
- `failures` (Array von Namen)
- `skips` (Array von Namen)
- Optional:
- `display = { passes = {}, failures = {}, skips = {} }`
- `failures_all` (für Streaming-Parser, um alle bisherigen Failures zu liefern)
- Wenn `display` fehlt, werden `passes/failures/skips` direkt im Listing angezeigt.
- oder `output_parser() -> { on_line, on_complete }`
- `on_line(line, state)` kann `results` liefern (siehe oben).
- `on_complete(output, state)` kann `results` liefern (siehe oben).
- `on_line` muss Ergebnisse liefern, damit das Listing-Float immer gestreamt wird.
Hinweis: `parse_results` darf intern `output_parser().on_complete` nutzen, aber beide Funktionen müssen existieren.
## Listing-Gruppierung fuer Parent/Subtests
- Wenn Testnamen das Format `Parent/Subtest` oder verschachtelt `Parent/Sub/Subtest` haben
und der Parent ebenfalls in den Ergebnissen vorhanden ist, gruppiert das Listing:
- Parent kommt vor seinen direkten Kindern.
- Mehrstufige Subtests werden hierarchisch gruppiert (Parent -> Kind -> Enkel).
- Die Reihenfolge der Kinder folgt der Eingangsreihenfolge des Runners.
- Ohne Parent-Eintrag bleibt die normale Reihenfolge erhalten.
## Detail-Output (TSamShowOutput / <cr> im Listing)
- `parse_test_output(output) -> table`
- Rückgabeform:
- `{ [test_name] = { "line1", "line2", ... } }`
- `test_name` muss mit `results.*` korrespondieren (gleiches Namensschema).
## Quickfix-Unterstützung (Failures)
- `collect_failed_locations(failures, command, scope_kind) -> items`
- `items`: Array von Quickfix-Items
- `{ filename = "...", lnum = <number>, col = <number>, text = "..." }`
## Erwartete Datenformen
- `command_spec`:
- `{ cmd = { "binary", "arg1", ... }, cwd = "..." }`
- `cmd` darf nicht leer sein.
- `cwd` ist optional; wenn nicht gesetzt, nutzt der Core das aktuelle CWD.
- `spec` (von `find_nearest`):
- Muss mindestens `file` enthalten, z. B.:
- `{ file = "...", cwd = "...", test_name = "...", full_name = "...", kind = "..." }`
- `results` (für Listing-Float + Keymaps):
- `{ passes = { "Name1", ... }, failures = { "Name2", ... }, skips = { "Name3", ... } }`
- Optional: `display = { passes = { "DisplayName1", ... }, failures = { "DisplayName2", ... }, skips = { "DisplayName3", ... } }`
- `failures` steuert `[ FAIL ]`-Zeilen im Listing und wird von `<leader>nf`/`<leader>pf` genutzt.
- `items` (für Quickfix):
- `{ { filename = "...", lnum = 1, col = 1, text = "..." }, ... }`
- Wird von `<leader>qn` verwendet.
## Keymaps (Datenlieferung)
- `<leader>nf` / `<leader>pf`
- benötigt `[ FAIL ]`-Einträge im Listing.
- Runner muss `results.failures` (und optional `display.failures`) liefern.
- `<leader>qn`
- springt in die Quickfix-Liste.
- Runner muss `collect_failed_locations` implementieren und gültige `items` liefern.
- `<cr>` im Listing
- öffnet Detail-Float.
- Runner muss `parse_test_output` liefern und Testnamen konsistent zu `results.*` halten.
## Optional empfohlene Metadaten
- `name` (String)
- Wird in Fehlermeldungen und Logs angezeigt.
- `framework` (String)
- Wird zur Framework-Auswahl (z. B. JS) genutzt.
## Prompt-Beispiel
"Erstelle mir anhand der `runner-agents.md` einen neuen Runner für Rust."
## Minimaler Runner-Skeleton (Template)
```lua
local runner = {
name = "my-runner",
framework = "my-framework",
}
function runner.is_test_file(bufnr)
return false
end
function runner.find_nearest(bufnr, row, col)
return nil, "no test call found"
end
function runner.build_command(spec)
return { cmd = { "echo", "not-implemented" }, cwd = spec.cwd }
end
function runner.build_file_command(bufnr)
return { cmd = { "echo", "not-implemented" } }
end
function runner.build_all_command(bufnr)
return { cmd = { "echo", "not-implemented" } }
end
function runner.build_failed_command(last_command, failures, scope_kind)
return { cmd = { "echo", "not-implemented" }, cwd = last_command and last_command.cwd or nil }
end
function runner.parse_results(output)
return { passes = {}, failures = {}, skips = {}, display = { passes = {}, failures = {}, skips = {} } }
end
function runner.output_parser()
return {
on_line = function(_line, _state)
return nil
end,
on_complete = function(_output, _state)
return runner.parse_results(_output)
end,
}
end
function runner.parse_test_output(output)
return {}
end
function runner.collect_failed_locations(failures, command, scope_kind)
return {}
end
return runner
```
## Checkliste für neue Runner
- is_test_file implementiert
- find_nearest implementiert (setzt `spec.file`)
- build_command implementiert
- build_file_command implementiert
- build_all_command implementiert
- build_failed_command implementiert
- parse_results implementiert
- output_parser implementiert (Streaming)
- parse_test_output implementiert
- collect_failed_locations implementiert
- command_spec `{ cmd, cwd }` korrekt zurückgegeben
## Projekt- und Prozessanforderungen
- Rolle: **TDD-first Entwickler**.
- Jede neue Funktion, jedes neue Kommando und jede Verhaltensänderung muss durch Tests abgesichert sein.
- Nach jeder Code-Änderung Tests via `bash run_test.sh` ausführen und bei Fehlern korrigieren, bis alles grün ist.
- **Nicht raten**:
- Bei unklaren oder mehrdeutigen Anforderungen Arbeit stoppen und Klarstellung verlangen.
- TODO/NOTE im Code ist zulässig, stilles Raten nicht.
- **Keine stillen Änderungen**:
- Bestehende Features dürfen nicht unbemerkt geändert oder ersetzt werden.
- Notwendige Anpassungen zur Koexistenz mehrerer Features müssen klar erkennbar sein.
- Antworten immer auf Deutsch.
- Eine englischsprachige `README.md` ist zu erstellen und wird bei Änderungen automatisch aktualisiert.
- TDD-Vorgaben (aus `AGENTS.md`) uebernehmen:
- Neue Funktionen/Commands/Verhaltensaenderungen muessen getestet werden.
- Tests nach jeder Code-Aenderung ausfuehren.
- Im Runner erstellter Quellcode ist ebenfalls zu testen.
- Eine eigene `run_test.sh` wird im Runner-Repo angelegt.
- Eine Gitea-Action ist zu erstellen, die bei jedem Push die Tests ausfuehrt.
- Neovim wird per AppImage installiert (kein `apt`).
- Runner laeuft auf `gitea-act-runner` mit Raspberry Pi 5 (ARM).
- Beispiel (anpassbarer Workflow):
```yaml
name: tests
on:
push:
branches:
- "**"
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Neovim (AppImage)
run: |
curl -L -o nvim.appimage https://github.com/neovim/neovim/releases/download/v0.11.4/nvim.appimage
chmod +x nvim.appimage
sudo mv nvim.appimage /usr/local/bin/nvim
- name: Run tests
run: bash run_test.sh
```