test: add CLI testscript suite with 25 black-box tests#195
Conversation
Extract run() int from main() to enable testscript.RunMain, and add comprehensive CLI test coverage using txtar scripts for all commands: version, help, new, blocks, fix, validate, serve, build, and cli CRUD. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR Review: test: add CLI testscript suite with 25 black-box testsOverall this is a clean, well-scoped PR. The Potential Bugs
No directory argument is supplied here. If
Testscript uses a fresh tmpdir per run so this is safe today, but if the application ever pre-seeds the table (migrations, fixtures) the hardcoded Misleading Comment
The embedded Minor Style Issues
Convention is to print usage/error messages to stderr on failure. Since this is an existing behaviour exposed by the test rather than introduced by it, it's fine to leave as-is — but worth a follow-up to align with the convention in
Same as above — the What's Working Well
The 🤖 Generated with Claude Code |
There was a problem hiding this comment.
Pull request overview
This PR adds a black-box CLI test suite using github.com/rogpeppe/go-internal/testscript, enabling repeatable end-to-end validation of tinkerdown commands via .txtar scripts. It also refactors the CLI entrypoint to expose a run() int function so the CLI can be executed under testscript.Main without building an external binary.
Changes:
- Extracted
run() intfrommain()and switched the CLI to return exit codes instead of callingos.Exitdirectly in command paths. - Added a
testscript-based runner (TestMain+TestCLIScripts) and a suite of 25 black-box CLI scripts. - Added
github.com/rogpeppe/go-internalas a direct dependency to supporttestscript.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| go.mod | Adds github.com/rogpeppe/go-internal dependency for testscript. |
| cmd/tinkerdown/main.go | Refactors CLI entrypoint to run() int to support in-process testscript execution. |
| cmd/tinkerdown/cli_test.go | Adds testscript.Main registration and runs the script suite under go test. |
| cmd/tinkerdown/testdata/scripts/version.txtar | Script coverage for tinkerdown version. |
| cmd/tinkerdown/testdata/scripts/no_args.txtar | Script coverage for no-args usage output and non-zero exit. |
| cmd/tinkerdown/testdata/scripts/help.txtar | Script coverage for help flags/subcommand and unknown command behavior. |
| cmd/tinkerdown/testdata/scripts/new_basic.txtar | Script coverage for new default template behavior and output. |
| cmd/tinkerdown/testdata/scripts/new_template.txtar | Script coverage for new template flag variants (--template, -t, with/without =). |
| cmd/tinkerdown/testdata/scripts/new_errors.txtar | Script coverage for new error cases (missing name, spaces, unknown template, dir exists). |
| cmd/tinkerdown/testdata/scripts/validate_basic.txtar | Script coverage for validate success case on simple markdown. |
| cmd/tinkerdown/testdata/scripts/fix_errors.txtar | Script coverage for fix error on missing directory. |
| cmd/tinkerdown/testdata/scripts/fix_dry_run.txtar | Script coverage for fix --dry-run output behavior. |
| cmd/tinkerdown/testdata/scripts/fix_apply.txtar | Script coverage for fix applying changes and printing summary output. |
| cmd/tinkerdown/testdata/scripts/blocks.txtar | Script coverage for blocks basic output. |
| cmd/tinkerdown/testdata/scripts/blocks_verbose.txtar | Script coverage for blocks --verbose output. |
| cmd/tinkerdown/testdata/scripts/blocks_errors.txtar | Script coverage for blocks error on missing directory. |
| cmd/tinkerdown/testdata/scripts/serve_errors.txtar | Script coverage for serve error cases (missing dir, invalid port). |
| cmd/tinkerdown/testdata/scripts/build_errors.txtar | Script coverage for build error cases (missing input, missing path). |
| cmd/tinkerdown/testdata/scripts/cli_usage.txtar | Script coverage for cli usage errors with too few args. |
| cmd/tinkerdown/testdata/scripts/cli_unknown_action.txtar | Script coverage for cli unknown action error. |
| cmd/tinkerdown/testdata/scripts/cli_errors.txtar | Script coverage for cli error cases (missing path, empty config). |
| cmd/tinkerdown/testdata/scripts/cli_source_not_found.txtar | Script coverage for cli source-not-found behavior. |
| cmd/tinkerdown/testdata/scripts/cli_requires_id.txtar | Script coverage for cli update/delete requiring --id. |
| cmd/tinkerdown/testdata/scripts/cli_requires_fields.txtar | Script coverage for cli add requiring at least one field. |
| cmd/tinkerdown/testdata/scripts/cli_readonly.txtar | Script coverage for rejecting writes to read-only sources. |
| cmd/tinkerdown/testdata/scripts/cli_json_source.txtar | Script coverage for listing items from a JSON source. |
| cmd/tinkerdown/testdata/scripts/cli_csv_source.txtar | Script coverage for listing items from a CSV source. |
| cmd/tinkerdown/testdata/scripts/cli_sqlite_crud.txtar | Script coverage for SQLite-backed CRUD lifecycle via cli. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code ReviewOverall this is a well-structured addition of a black-box testscript suite. The Correctness
The diff shows
This is fine for isolated testscript runs (each gets a fresh working directory), but the assumption is fragile if the SQLite table schema or initialization ever changes. A more robust approach would capture the ID from the
Test Coverage Gaps
Minor
SummaryThe core refactor ( |
- printUsage() now takes io.Writer; error paths write to stderr, help/--help writes to stdout - Unknown command message sent to stderr instead of stdout - serve_errors.txtar explicitly passes . directory for port test Addresses Claude bot review comments. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
PR Review: CLI Testscript Suite. Overall this is solid and well-structured. Positives: run() int extraction is idiomatic Go for testable CLIs; printUsage(w io.Writer) correctly routes errors to stderr and help to stdout; testscript is an excellent black-box testing choice; good happy-path and error-path coverage across all commands. Issues: (1) go.sum is not in the diff - if rogpeppe/go-internal was not already an indirect dep, CI will fail; run go mod tidy to verify. (2) cli_sqlite_crud.txtar hardcodes --id=1 for update/delete, which is safe given testscript temp dir isolation but would break with UUID or non-sequential IDs. (3) cli_sqlite_crud.txtar supplies no .db file - this implicitly requires the implementation to auto-create the DB and table on first use; a comment explaining that contract would help future readers. (4) fix_dry_run.txtar only checks stdout, not that the file is actually unchanged - the defining property of dry-run. A cmp assertion against the original content would close that gap. (5) blocks_verbose.txtar asserts on exact strings like Type: server and Language: go, locking in the verbose output format as a public contract - worth being deliberate about. Minor: cli_requires_fields and cli_requires_id test pre-DB validation which is fast and reliable; the 4-variant flag test in new_template.txtar is thorough; serve_errors.txtar correctly avoids testing the blocking server path. Summary: run()/printUsage(w) improvements are unambiguously good. Three action items before merge: confirm go.sum is current, add file-unchanged assertion to fix_dry_run.txtar, add a comment about auto-create DB in cli_sqlite_crud.txtar. |
- fix_dry_run.txtar: verify file content unchanged after --dry-run with cmp - cli_sqlite_crud.txtar: document auto-create DB/table contract Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
run() intfrommain()to enabletestscript.Mainfor in-process CLI testing.txtartest scripts covering all CLI commands: version, help, new, blocks, fix, validate, serve, build, and cli CRUD operationsgithub.com/rogpeppe/go-internalas a direct dependency for the testscript frameworkTest plan
go test ./cmd/tinkerdown/ -run TestCLIScripts -v)go test ./internal/... -short)Closes #64
🤖 Generated with Claude Code