Skip to content

Commit c7ab13f

Browse files
committed
refactor: harden default command routing and help tests
1 parent 512b506 commit c7ab13f

2 files changed

Lines changed: 112 additions & 16 deletions

File tree

cmd/agent-fetch/main.go

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"io"
78
"net/http"
89
"os"
910
"strings"
@@ -73,7 +74,23 @@ func main() {
7374
}
7475

7576
defaultCfg := fetcher.DefaultConfig()
76-
cmd := &cli.Command{
77+
cmd := newRootCommand(defaultCfg)
78+
79+
if err := cmd.Run(context.Background(), routeToDefaultWeb(os.Args, cmd)); err != nil {
80+
var exitErr *exitStatusError
81+
if errors.As(err, &exitErr) {
82+
if msg := strings.TrimSpace(exitErr.msg); msg != "" {
83+
fmt.Fprintln(os.Stderr, msg)
84+
}
85+
os.Exit(exitErr.code)
86+
}
87+
// urfave/cli already prints usage/parse errors to ErrWriter by default.
88+
os.Exit(1)
89+
}
90+
}
91+
92+
func newRootCommand(defaultCfg fetcher.Config) *cli.Command {
93+
return &cli.Command{
7794
Name: "agent-fetch",
7895
Usage: "Fetch web pages as clean Markdown for AI-agent workflows",
7996
Description: "Extracts readable content from web pages and converts it to Markdown.\n" +
@@ -108,18 +125,6 @@ func main() {
108125
return &exitStatusError{code: 2}
109126
},
110127
}
111-
112-
if err := cmd.Run(context.Background(), routeToDefaultWeb(os.Args)); err != nil {
113-
var exitErr *exitStatusError
114-
if errors.As(err, &exitErr) {
115-
if msg := strings.TrimSpace(exitErr.msg); msg != "" {
116-
fmt.Fprintln(os.Stderr, msg)
117-
}
118-
os.Exit(exitErr.code)
119-
}
120-
// urfave/cli already prints usage/parse errors to ErrWriter by default.
121-
os.Exit(1)
122-
}
123128
}
124129

125130
func newWebCommand(defaultCfg fetcher.Config) *cli.Command {
@@ -240,7 +245,7 @@ func runWebFetch(ctx context.Context, c *cli.Command) error {
240245
return nil
241246
}
242247

243-
func routeToDefaultWeb(args []string) []string {
248+
func routeToDefaultWeb(args []string, root *cli.Command) []string {
244249
if len(args) <= 1 {
245250
return args
246251
}
@@ -249,8 +254,13 @@ func routeToDefaultWeb(args []string) []string {
249254
if first == "" {
250255
return args
251256
}
257+
258+
if root != nil && root.Command(first) != nil {
259+
return args
260+
}
261+
252262
switch first {
253-
case webCommandName, "doctor", "help", "h", "--help", "-h", "--version", "-v":
263+
case "help", "h", "--help", "-h", "--version", "-v":
254264
return args
255265
}
256266

@@ -260,6 +270,20 @@ func routeToDefaultWeb(args []string) []string {
260270
return rewritten
261271
}
262272

273+
func runForTest(args []string, out, errOut io.Writer) error {
274+
cli.VersionPrinter = func(cmd *cli.Command) {
275+
w := cmd.Root().Writer
276+
if w == nil {
277+
w = os.Stdout
278+
}
279+
fmt.Fprintln(w, cmd.Version)
280+
}
281+
cmd := newRootCommand(fetcher.DefaultConfig())
282+
cmd.Writer = out
283+
cmd.ErrWriter = errOut
284+
return cmd.Run(context.Background(), routeToDefaultWeb(args, cmd))
285+
}
286+
263287
func parseHeaders(raw []string) (http.Header, error) {
264288
h := make(http.Header)
265289
for _, item := range raw {

cmd/agent-fetch/main_test.go

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
package main
22

33
import (
4+
"context"
45
"reflect"
6+
"strings"
57
"testing"
8+
9+
"github.com/firede/agent-fetch/internal/fetcher"
10+
"github.com/urfave/cli/v3"
611
)
712

813
func TestRouteToDefaultWeb(t *testing.T) {
14+
root := newRootCommand(fetcher.DefaultConfig())
15+
916
tests := []struct {
1017
name string
1118
in []string
@@ -46,14 +53,79 @@ func TestRouteToDefaultWeb(t *testing.T) {
4653
in: []string{"agent-fetch", "--version"},
4754
want: []string{"agent-fetch", "--version"},
4855
},
56+
{
57+
name: "unknown token treated as web shorthand",
58+
in: []string{"agent-fetch", "https://example.net"},
59+
want: []string{"agent-fetch", "web", "https://example.net"},
60+
},
4961
}
5062

5163
for _, tc := range tests {
5264
t.Run(tc.name, func(t *testing.T) {
53-
got := routeToDefaultWeb(tc.in)
65+
got := routeToDefaultWeb(tc.in, root)
5466
if !reflect.DeepEqual(got, tc.want) {
5567
t.Fatalf("unexpected args rewrite\ngot: %#v\nwant: %#v", got, tc.want)
5668
}
5769
})
5870
}
5971
}
72+
73+
func TestRouteToDefaultWeb_RegisteredSubcommandUntouched(t *testing.T) {
74+
root := newRootCommand(fetcher.DefaultConfig())
75+
const testSubcommand = "__test_subcommand__"
76+
root.Commands = append(root.Commands, &cli.Command{Name: testSubcommand})
77+
78+
in := []string{"agent-fetch", testSubcommand, "arg1"}
79+
want := []string{"agent-fetch", testSubcommand, "arg1"}
80+
got := routeToDefaultWeb(in, root)
81+
if !reflect.DeepEqual(got, want) {
82+
t.Fatalf("unexpected args rewrite\ngot: %#v\nwant: %#v", got, want)
83+
}
84+
}
85+
86+
func TestHelpOutputContracts(t *testing.T) {
87+
t.Run("root help shows default web options", func(t *testing.T) {
88+
var out strings.Builder
89+
err := runForTest([]string{"agent-fetch", "-h"}, &out, &out)
90+
if err != nil {
91+
t.Fatalf("run help failed: %v", err)
92+
}
93+
helpText := out.String()
94+
if !strings.Contains(helpText, "DEFAULT WEB OPTIONS:") {
95+
t.Fatalf("expected default web options section, got:\n%s", helpText)
96+
}
97+
if !strings.Contains(helpText, "--format string") {
98+
t.Fatalf("expected web options in root help, got:\n%s", helpText)
99+
}
100+
})
101+
102+
t.Run("doctor help excludes web flags", func(t *testing.T) {
103+
var out strings.Builder
104+
err := runForTest([]string{"agent-fetch", "doctor", "-h"}, &out, &out)
105+
if err != nil {
106+
t.Fatalf("run doctor help failed: %v", err)
107+
}
108+
helpText := out.String()
109+
if !strings.Contains(helpText, "--browser-path string") {
110+
t.Fatalf("expected doctor option in doctor help, got:\n%s", helpText)
111+
}
112+
if strings.Contains(helpText, "--format string") {
113+
t.Fatalf("did not expect web flag in doctor help, got:\n%s", helpText)
114+
}
115+
})
116+
117+
t.Run("web help shows fetch flags", func(t *testing.T) {
118+
cmd := newRootCommand(fetcher.DefaultConfig())
119+
var out strings.Builder
120+
cmd.Writer = &out
121+
cmd.ErrWriter = &out
122+
err := cmd.Run(context.Background(), routeToDefaultWeb([]string{"agent-fetch", "web", "-h"}, cmd))
123+
if err != nil {
124+
t.Fatalf("run web help failed: %v", err)
125+
}
126+
helpText := out.String()
127+
if !strings.Contains(helpText, "--format string") {
128+
t.Fatalf("expected fetch flag in web help, got:\n%s", helpText)
129+
}
130+
})
131+
}

0 commit comments

Comments
 (0)