Artifact 8a60201179065d722145e5bbb7d8aee987b4428c90c0a5cf0a7ac7b4ba8c7b0d:
- File
cmd/libfossil/main_test.go
— part of check-in
[725c694cb9]
at
2026-07-19 23:33:37
on branch trunk
— Add libfossil version command (#99)
* Add libfossil version command
Sources the version string from runtime/debug.ReadBuildInfo (module version for go-install/tagged builds, falling back to a short VCS commit), with a -ldflags override for release builds where BuildInfo alone would collapse to "(devel)". Output is a fixed, single-line, four-field shape ("libfossil <version> <go version> <os>/<arch>") so a caller can rely on strings.Fields(Version()) unconditionally -- the motivating consumer stamps this into every emitted benchmark record.
No global --version flag: repo extract already owns --version as a command-scoped flag (source version to extract), and kong's global flags are visible in every subcommand's context, so a root-level --version would collide with it. version is a subcommand only.
Verified kong's existing parse-error path already exits non-zero (exitUsageError, 80) for unrecognized commands and flags against the pinned kong version -- added regression tests locking that in rather than changing behavior that was already correct.
* Reject malformed -ldflags version overrides at startup
buildVersion was used verbatim with no validation, so a whitespace- or newline-containing -X override silently broke Version()'s promised single-line, four-field contract: a space produced six fields instead of four, and a newline broke the single-line guarantee outright. The stated consumer is a benchmark harness parsing this line as a stable record, so a corrupted version field silently corrupts every record from that build in exactly the field meant to identify it.
A bad -X value is a build-time operator mistake, not a runtime condition, so it's rejected at package init rather than sanitized or worked around: sanitizing would silently mangle the operator's intent, and falling back to build info would report a version that is confidently wrong. Both would hide the mistake in the one field whose job is to be trustworthy. Failing the whole binary at startup surfaces a bad build the first time it runs, for any command, not just when someone happens to run `version`.
Also simplified versionFromBuildInfo: verified empirically (go1.26, `go build .` inside this checkout, with and without -buildvcs and inside/outside a VCS checkout) that Main.Version is only ever the uninformative "(devel)" in exactly the cases where vcs.revision is also absent from BuildInfo.Settings -- whenever a VCS revision is available, Go has already folded it into Main.Version as a pseudo-version. The separate vcs.revision fallback loop was dead code that could only ever duplicate a hash already present in Main.Version; removed it along with the now-unused shortCommit helper. (user: [email protected], size: 3589) [annotate] [blame] [check-ins using]
package main import ( "bytes" "os" "os/exec" "strings" "testing" ) // TestMain lets this test binary re-exec itself as the real libfossil CLI // when invoked with LIBFOSSIL_TEST_MAIN=1: it calls main() directly and // returns, without ever entering testing's own flag parsing or m.Run(). // runCLI uses this to observe the actual process exit status main() // produces, which go test's own process does not expose. func TestMain(m *testing.M) { if os.Getenv("LIBFOSSIL_TEST_MAIN") == "1" { main() return } os.Exit(m.Run()) } // runCLI runs this test binary as a subprocess re-entering main() via // TestMain, with args passed through as if they were the real CLI's // command line, and reports what that process printed and exited with. func runCLI(t *testing.T, args ...string) (stdout, stderr string, exitCode int) { t.Helper() cmd := exec.Command(os.Args[0], args...) cmd.Env = append(os.Environ(), "LIBFOSSIL_TEST_MAIN=1") var outBuf, errBuf bytes.Buffer cmd.Stdout = &outBuf cmd.Stderr = &errBuf err := cmd.Run() switch e := err.(type) { case nil: exitCode = 0 case *exec.ExitError: exitCode = e.ExitCode() default: t.Fatalf("running subprocess: %v", err) } return outBuf.String(), errBuf.String(), exitCode } // TestVersionCommandExitsZeroWithOneLine covers the core acceptance // criterion: `libfossil version` exits 0 and prints exactly one // non-empty, parseable line. func TestVersionCommandExitsZeroWithOneLine(t *testing.T) { stdout, stderr, code := runCLI(t, "version") if code != 0 { t.Fatalf("exit code = %d, want 0; stderr=%q", code, stderr) } lines := strings.Split(strings.TrimRight(stdout, "\n"), "\n") if len(lines) != 1 || lines[0] == "" { t.Fatalf("stdout = %q, want exactly one non-empty line", stdout) } if !strings.HasPrefix(lines[0], "libfossil ") { t.Errorf("version line = %q, want prefix %q", lines[0], "libfossil ") } } // TestUnrecognizedCommandExitsNonZero locks in the exit-code half of the // issue: a caller must be able to tell "the binary didn't understand what // I asked" apart from "the binary answered". func TestUnrecognizedCommandExitsNonZero(t *testing.T) { _, stderr, code := runCLI(t, "this-command-does-not-exist") if code == 0 { t.Fatalf("exit code = 0, want non-zero for an unrecognized command; stderr=%q", stderr) } } // TestUnrecognizedFlagExitsNonZero is the flag-parsing counterpart to // TestUnrecognizedCommandExitsNonZero. func TestUnrecognizedFlagExitsNonZero(t *testing.T) { _, stderr, code := runCLI(t, "--this-flag-does-not-exist") if code == 0 { t.Fatalf("exit code = 0, want non-zero for an unrecognized flag; stderr=%q", stderr) } } // TestVersionGlobalFlagExitsNonZero documents that --version is not a // global flag: `repo extract` already owns --version (source version to // extract) as command-scoped state, and a bare `--version` at the root is // simply an unrecognized flag, same as any other -- it must fail loudly // rather than silently succeed or silently fall back to help with exit 0. func TestVersionGlobalFlagExitsNonZero(t *testing.T) { _, stderr, code := runCLI(t, "--version") if code == 0 { t.Fatalf("exit code = 0, want non-zero for the unrecognized global --version flag; stderr=%q", stderr) } } // TestNoArgsExitsNonZero covers running the bare binary with no command at // all -- also a case the caller must be able to distinguish from success. func TestNoArgsExitsNonZero(t *testing.T) { _, stderr, code := runCLI(t) if code == 0 { t.Fatalf("exit code = 0, want non-zero when no command is given; stderr=%q", stderr) } }