feat: add list command with global filters

This commit is contained in:
Rogee
2025-10-29 16:08:46 +08:00
parent 88563d48e2
commit fa57af8a26
29 changed files with 1892 additions and 25 deletions

View File

@@ -0,0 +1,69 @@
package integration
import (
"path/filepath"
"testing"
"github.com/spf13/cobra"
"github.com/rogeecn/renamer/internal/listing"
)
func TestScopeFlagsProduceConsistentRequests(t *testing.T) {
root := &cobra.Command{Use: "renamer"}
listing.RegisterScopeFlags(root.PersistentFlags())
listCmd := &cobra.Command{Use: "list"}
previewCmd := &cobra.Command{Use: "preview"}
root.AddCommand(listCmd, previewCmd)
tmp := t.TempDir()
mustSet := func(name, value string) {
if err := root.PersistentFlags().Set(name, value); err != nil {
t.Fatalf("set %s: %v", name, err)
}
}
mustSet("path", tmp)
mustSet("recursive", "true")
mustSet("include-dirs", "true")
mustSet("hidden", "true")
mustSet("extensions", ".jpg|.png")
reqList, err := listing.ScopeFromCmd(listCmd)
if err != nil {
t.Fatalf("list request: %v", err)
}
reqPreview, err := listing.ScopeFromCmd(previewCmd)
if err != nil {
t.Fatalf("preview request: %v", err)
}
if reqList.WorkingDir != reqPreview.WorkingDir {
t.Fatalf("working dir mismatch: %s vs %s", reqList.WorkingDir, reqPreview.WorkingDir)
}
if reqList.Recursive != reqPreview.Recursive {
t.Fatalf("recursive mismatch")
}
if reqList.IncludeDirectories != reqPreview.IncludeDirectories {
t.Fatalf("include-dirs mismatch")
}
if reqList.IncludeHidden != reqPreview.IncludeHidden {
t.Fatalf("hidden mismatch")
}
if len(reqList.Extensions) != len(reqPreview.Extensions) {
t.Fatalf("extension length mismatch: %d vs %d", len(reqList.Extensions), len(reqPreview.Extensions))
}
for i := range reqList.Extensions {
if reqList.Extensions[i] != reqPreview.Extensions[i] {
t.Fatalf("extension mismatch at %d: %s vs %s", i, reqList.Extensions[i], reqPreview.Extensions[i])
}
}
if filepath.Clean(reqList.WorkingDir) != reqList.WorkingDir {
t.Fatalf("expected cleaned working dir, got %s", reqList.WorkingDir)
}
}

View File

@@ -0,0 +1,103 @@
package integration
import (
"context"
"io"
"os"
"path/filepath"
"sort"
"testing"
"github.com/rogeecn/renamer/internal/listing"
"github.com/rogeecn/renamer/internal/output"
)
type captureFormatter struct {
paths []string
}
func (f *captureFormatter) Begin(io.Writer) error { return nil }
func (f *captureFormatter) WriteEntry(_ io.Writer, entry output.Entry) error {
f.paths = append(f.paths, entry.Path)
return nil
}
func (f *captureFormatter) WriteSummary(io.Writer, output.Summary) error { return nil }
func TestListServiceRecursiveTraversal(t *testing.T) {
tmp := t.TempDir()
mustWriteFile(t, filepath.Join(tmp, "root.txt"))
mustWriteFile(t, filepath.Join(tmp, "nested", "child.txt"))
mustWriteDir(t, filepath.Join(tmp, "nested", "inner"))
svc := listing.NewService()
req := &listing.ListingRequest{
WorkingDir: tmp,
Recursive: true,
Format: listing.FormatPlain,
}
formatter := &captureFormatter{}
summary, err := svc.List(context.Background(), req, formatter, io.Discard)
if err != nil {
t.Fatalf("List returned error: %v", err)
}
sort.Strings(formatter.paths)
expected := []string{"nested/child.txt", "root.txt"}
if len(formatter.paths) != len(expected) {
t.Fatalf("expected %d paths, got %d (%v)", len(expected), len(formatter.paths), formatter.paths)
}
for i, path := range expected {
if formatter.paths[i] != path {
t.Fatalf("expected path %q at index %d, got %q", path, i, formatter.paths[i])
}
}
if summary.Total() != len(expected) {
t.Fatalf("unexpected summary total: %d", summary.Total())
}
}
func TestListServiceDirectoryOnlyMode(t *testing.T) {
tmp := t.TempDir()
mustWriteFile(t, filepath.Join(tmp, "file.txt"))
mustWriteDir(t, filepath.Join(tmp, "folder"))
svc := listing.NewService()
req := &listing.ListingRequest{
WorkingDir: tmp,
IncludeDirectories: true,
Format: listing.FormatPlain,
}
formatter := &captureFormatter{}
_, err := svc.List(context.Background(), req, formatter, io.Discard)
if err != nil {
t.Fatalf("List returned error: %v", err)
}
if len(formatter.paths) != 1 || formatter.paths[0] != "folder" {
t.Fatalf("expected only directory entry, got %v", formatter.paths)
}
}
func mustWriteFile(t *testing.T, path string) {
t.Helper()
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatalf("mkdir %s: %v", path, err)
}
if err := os.WriteFile(path, []byte("data"), 0o644); err != nil {
t.Fatalf("write file %s: %v", path, err)
}
}
func mustWriteDir(t *testing.T, path string) {
t.Helper()
if err := os.MkdirAll(path, 0o755); err != nil {
t.Fatalf("mkdir dir %s: %v", path, err)
}
}