diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-14 10:05:43 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-14 10:05:43 +0300 |
| commit | 806ff16a0ad70ae2883a666bdc4158ba20ca4d4f (patch) | |
| tree | 69be449899e449e50a591138f46a32d53207b4c6 /internal/cli/cli_test.go | |
| parent | 4d9004ab31a6064af741fbb73758bd8844964c6f (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.go | 149 |
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) + } + } +} |
