summaryrefslogtreecommitdiff
path: root/internal/cli/cli_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-14 10:05:43 +0300
committerPaul Buetow <paul@buetow.org>2026-04-14 10:05:43 +0300
commit806ff16a0ad70ae2883a666bdc4158ba20ca4d4f (patch)
tree69be449899e449e50a591138f46a32d53207b4c6 /internal/cli/cli_test.go
parent4d9004ab31a6064af741fbb73758bd8844964c6f (diff)
test(x2): codify CLI backward-compatibility contract
- Add internal/cli tests for stable entry points: -version/--version, file-based report (-stats-dir), import/query, test subcommand, -daemon/--daemon validation, and subcommand recognition. - Assert RegisterReportFlags keeps required flag names and defaults (CLI/HTTP). - Run integration import/export against a temp SQLite file instead of fixtures/test_import.db to avoid flaky readonly errors under parallel tests. Made-with: Cursor
Diffstat (limited to 'internal/cli/cli_test.go')
-rw-r--r--internal/cli/cli_test.go149
1 files changed, 149 insertions, 0 deletions
diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go
new file mode 100644
index 0000000..9fa20e5
--- /dev/null
+++ b/internal/cli/cli_test.go
@@ -0,0 +1,149 @@
+package cli
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "codeberg.org/snonux/goprecords/internal/version"
+)
+
+func moduleRoot(t *testing.T) string {
+ t.Helper()
+ dir, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ for {
+ if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
+ return dir
+ }
+ parent := filepath.Dir(dir)
+ if parent == dir {
+ t.Fatal("go.mod not found from test working directory")
+ }
+ dir = parent
+ }
+}
+
+func captureStdout(t *testing.T, fn func()) string {
+ t.Helper()
+ old := os.Stdout
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ os.Stdout = w
+ fn()
+ if err := w.Close(); err != nil {
+ os.Stdout = old
+ t.Fatal(err)
+ }
+ os.Stdout = old
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, r); err != nil {
+ t.Fatal(err)
+ }
+ if err := r.Close(); err != nil {
+ t.Fatal(err)
+ }
+ return buf.String()
+}
+
+func TestStableVersionFlags(t *testing.T) {
+ for _, arg := range []string{"-version", "--version"} {
+ arg := arg
+ t.Run(arg, func(t *testing.T) {
+ out := captureStdout(t, func() {
+ if err := Execute([]string{arg}); err != nil {
+ t.Fatalf("Execute: %v", err)
+ }
+ })
+ if !strings.Contains(out, version.Version) {
+ t.Fatalf("stdout %q should contain version %q", out, version.Version)
+ }
+ })
+ }
+}
+
+func TestStableReportFromFilesRequiresStatsDir(t *testing.T) {
+ err := Execute(nil)
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "stats-dir") {
+ t.Fatalf("expected stats-dir in error, got %v", err)
+ }
+ err = Execute([]string{})
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "stats-dir") {
+ t.Fatalf("expected stats-dir in error, got %v", err)
+ }
+}
+
+func TestStableReportFromFilesWithFixtures(t *testing.T) {
+ root := moduleRoot(t)
+ fixtures := filepath.Join(root, "fixtures")
+ out := captureStdout(t, func() {
+ if err := Execute([]string{"-stats-dir", fixtures}); err != nil {
+ t.Fatal(err)
+ }
+ })
+ if !strings.Contains(out, "earth") {
+ t.Fatalf("report output should mention fixture host earth; got len=%d", len(out))
+ }
+}
+
+func TestStableImportAndQuery(t *testing.T) {
+ root := moduleRoot(t)
+ fixtures := filepath.Join(root, "fixtures")
+ db := filepath.Join(t.TempDir(), "compat.db")
+ if err := Execute([]string{"import", "-stats-dir", fixtures, "-db", db}); err != nil {
+ t.Fatalf("import: %v", err)
+ }
+ out := captureStdout(t, func() {
+ if err := Execute([]string{"query", "-db", db, "-limit", "3"}); err != nil {
+ t.Fatal(err)
+ }
+ })
+ if len(strings.TrimSpace(out)) == 0 {
+ t.Fatal("expected non-empty query output")
+ }
+}
+
+func TestStableIntegrationTestSubcommand(t *testing.T) {
+ root := moduleRoot(t)
+ t.Chdir(root)
+ if err := Execute([]string{"test"}); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestStableDaemonRequiresStatsDir(t *testing.T) {
+ t.Setenv("GOPRECORDS_STATS_DIR", "")
+ for _, arg := range []string{"-daemon", "--daemon"} {
+ arg := arg
+ t.Run(arg, func(t *testing.T) {
+ err := Execute([]string{arg})
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "stats-dir") {
+ t.Fatalf("expected stats-dir in error, got %v", err)
+ }
+ })
+ }
+}
+
+func TestStableSubcommandsStillRecognized(t *testing.T) {
+ for _, sub := range []string{"import", "query", "test"} {
+ if err := Execute([]string{sub}); err == nil {
+ t.Fatalf("subcommand %q should fail without required args/env, not succeed silently", sub)
+ }
+ }
+}