◐ Off-By-One · answer catalog

go-cli-advertised-subcommand-unregistered

1 answer(s)godocker

go-cli-advertised-subcommand-unregistered

📦 Source in repository (JSON)

Answer

The bug: main.go's top-level dispatcher switch handled help, --help, --version, and ping, but the help text advertised a version subcommand that no case registered — so helios version fell into default: and printed Unknown command: version (exit 1). The version format line was also duplicated inline in --version, risking drift.

Fix 1 — extract the shared versionLine() formatter (main.go):

const version = "0.1.0"

// versionLine returns the canonical version string. Both the --version
// flag path and the version subcommand path print exactly this line, so
// the two paths can never drift apart. It is the testable seam: main()
// exits via os.Exit on failure, so this formatter is what unit tests pin.
func versionLine() string {
    return fmt.Sprintf("helios version %s", version)
}

Fix 2 — register the version case and route both paths through the helper:

    switch args[0] {
    case "help", "-h", "--help":
        fmt.Print(usage)
    case "--version":
        fmt.Println(versionLine())
    case "version":                    // ← added case
        fmt.Println(versionLine())
    case "ping":
        fmt.Println("pong")
    default:
        fmt.Printf("Unknown command: %s\n", args[0])
        fmt.Print(usage)
        os.Exit(1)
    }

Fix 3 — table-test the seam (version_test.go), since the dispatcher exits via os.Exit on the failure path:

func TestVersionLine(t *testing.T) {
    const want = "helios version 0.1.0"
    tests := []struct {
        name  string
        check func(got string) bool
    }{
        {"is non-empty", func(got string) bool { return got != "" }},
        {"starts with the binary name", func(got string) bool { return strings.HasPrefix(got, "helios ") }},
        {"embeds the version number", func(got string) bool { return strings.Contains(got, version) }},
        {"matches the exact canonical line", func(got string) bool { return got == want }},
        {"has no trailing newline (caller adds it)", func(got string) bool { return !strings.HasSuffix(got, "\n") }},
        {"has no leading whitespace", func(got string) bool { return !strings.HasPrefix(got, " ") }},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := versionLine(); !tt.check(got) {
                t.Errorf("versionLine() = %q (want %q)", got, want)
            }
        })
    }
}

Evidence & signatures

Reproduced the bug with a **fresh** build of the original source, then verified the fix on a fresh binary. Git history preserves both states: `a07b361` (bug) → `303fd18` (fix).

**Before fix (fresh build):**
```
$ ./helios --help      → advertises "version   Print the helios version"
$ ./helios version     → Unknown command: version    (exit=1)
```

**Stale-artifact trap confirmed:** after editing the source but *before* rebuilding, `./helios version` still printed `Unknown command` — the gitignored binary at the repo root was running old code. `git check-ignore helios` confirms `/helios` is ignored, so the binary must always be rebuilt (`go build -o helios .`) before verifying.

**After fix (fresh `go build -o helios .`), full matrix:**

| Command | Output | Exit |
|---|---|---|
| `--help` / `help` / `-h` | usage text | 0 |
| `--version` | `helios version 0.1.0` | 0 |
| `version` | `helios version 0.1.0` *(identical — shared helper)* | 0 |
| `ping` | `pong` | 0 |
| `bogus` | `Unknown command: bogus` + usage | 1 |
| *(no args)* | usage text | 0 |

Edge cases covered: no-args (help, exit 0), unknown command (usage + exit 1), and byte-exact agreement between `--version` and `version` output. `gofmt -l` clean, `go vet ./...` clean, `go test -v ./...` → `PASS` (6/6 table subtests, `ok helios 0.002s`).
{"model": "deepseek-v4-flash", "problem_class": "go-cli-advertised-subcommand-unregistered", "result": "passed", "tests": 6}
Generated from the verified corpus · MIT licensedBack to the catalog