diff --git a/shortcuts/im/builders_test.go b/shortcuts/im/builders_test.go index d44570d88..cb32d78f8 100644 --- a/shortcuts/im/builders_test.go +++ b/shortcuts/im/builders_test.go @@ -29,7 +29,42 @@ func newTestRuntimeContext(t *testing.T, stringFlags map[string]string, boolFlag t.Helper() cmd := &cobra.Command{Use: "test"} + cmd.Flags().Int("page-limit", 20, "") for name := range stringFlags { + if name == "page-limit" { + continue + } + cmd.Flags().String(name, "", "") + } + for name := range boolFlags { + cmd.Flags().Bool(name, false, "") + } + if err := cmd.ParseFlags(nil); err != nil { + t.Fatalf("ParseFlags() error = %v", err) + } + for name, val := range stringFlags { + if err := cmd.Flags().Set(name, val); err != nil { + t.Fatalf("Flags().Set(%q) error = %v", name, err) + } + } + for name, val := range boolFlags { + if err := cmd.Flags().Set(name, map[bool]string{true: "true", false: "false"}[val]); err != nil { + t.Fatalf("Flags().Set(%q) error = %v", name, err) + } + } + return &common.RuntimeContext{Cmd: cmd} +} + +func newMessagesSearchTestRuntimeContext(t *testing.T, stringFlags map[string]string, boolFlags map[string]bool) *common.RuntimeContext { + t.Helper() + + cmd := &cobra.Command{Use: "test"} + cmd.Flags().Int("page-size", 20, "") + cmd.Flags().Int("page-limit", 20, "") + for name := range stringFlags { + if name == "page-size" || name == "page-limit" { + continue + } cmd.Flags().String(name, "", "") } for name := range boolFlags { @@ -460,7 +495,7 @@ func TestShortcutValidateBranches(t *testing.T) { }) t.Run("ImMessagesSearch invalid page size", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ "query": "incident", "page-size": "0", }, nil) @@ -471,7 +506,7 @@ func TestShortcutValidateBranches(t *testing.T) { }) t.Run("ImMessagesSearch invalid page limit", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ "query": "incident", "page-limit": "41", }, nil) @@ -482,7 +517,7 @@ func TestShortcutValidateBranches(t *testing.T) { }) t.Run("ImMessagesSearch invalid sender id", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ "sender": "user_1", }, nil) err := ImMessagesSearch.Validate(context.Background(), runtime) @@ -492,7 +527,7 @@ func TestShortcutValidateBranches(t *testing.T) { }) t.Run("ImMessagesSearch invalid chat id", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ "chat-id": "bad_chat", }, nil) err := ImMessagesSearch.Validate(context.Background(), runtime) @@ -502,7 +537,7 @@ func TestShortcutValidateBranches(t *testing.T) { }) t.Run("ImMessagesSearch invalid time range", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ "start": "2025-01-02T00:00:00Z", "end": "2025-01-01T00:00:00Z", }, nil) @@ -515,7 +550,7 @@ func TestShortcutValidateBranches(t *testing.T) { func TestMessagesSearchPaginationConfig(t *testing.T) { t.Run("default single page", func(t *testing.T) { - runtime := newTestRuntimeContext(t, nil, nil) + runtime := newMessagesSearchTestRuntimeContext(t, nil, nil) autoPaginate, pageLimit := messagesSearchPaginationConfig(runtime) if autoPaginate { t.Fatal("messagesSearchPaginationConfig() autoPaginate = true, want false") @@ -526,7 +561,7 @@ func TestMessagesSearchPaginationConfig(t *testing.T) { }) t.Run("page all uses max limit", func(t *testing.T) { - runtime := newTestRuntimeContext(t, nil, map[string]bool{ + runtime := newMessagesSearchTestRuntimeContext(t, nil, map[string]bool{ "page-all": true, }) autoPaginate, pageLimit := messagesSearchPaginationConfig(runtime) @@ -539,9 +574,13 @@ func TestMessagesSearchPaginationConfig(t *testing.T) { }) t.Run("explicit page limit enables auto pagination", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ + "query": "incident", "page-limit": "3", }, nil) + if err := ImMessagesSearch.Validate(context.Background(), runtime); err != nil { + t.Fatalf("ImMessagesSearch.Validate() error = %v, want valid explicit --page-limit", err) + } autoPaginate, pageLimit := messagesSearchPaginationConfig(runtime) if !autoPaginate { t.Fatal("messagesSearchPaginationConfig() autoPaginate = false, want true") @@ -585,7 +624,7 @@ func TestShortcutDryRunShapes(t *testing.T) { }) t.Run("ImMessagesSearch dry run uses messages search endpoint", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ "query": "incident", "page-size": "51", "page-token": "next_page", diff --git a/shortcuts/im/coverage_additional_test.go b/shortcuts/im/coverage_additional_test.go index 2a1b44112..5671116b6 100644 --- a/shortcuts/im/coverage_additional_test.go +++ b/shortcuts/im/coverage_additional_test.go @@ -324,7 +324,7 @@ func TestResolveChatIDForMessagesList(t *testing.T) { func TestBuildMessagesSearchRequest(t *testing.T) { t.Run("valid request", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ "query": "hello", "chat-id": "oc_1,oc_2", "sender": "ou_1,ou_2", @@ -374,7 +374,7 @@ func TestBuildMessagesSearchRequest(t *testing.T) { }) t.Run("start later than end", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ "start": "2026-03-03T00:00:00+08:00", "end": "2026-03-02T00:00:00+08:00", }, nil) @@ -385,7 +385,7 @@ func TestBuildMessagesSearchRequest(t *testing.T) { }) t.Run("invalid sender id", func(t *testing.T) { - runtime := newTestRuntimeContext(t, map[string]string{ + runtime := newMessagesSearchTestRuntimeContext(t, map[string]string{ "sender": "bad_sender", }, nil) _, err := buildMessagesSearchRequest(runtime) diff --git a/shortcuts/im/im_messages_search.go b/shortcuts/im/im_messages_search.go index d122cc23b..d6491a851 100644 --- a/shortcuts/im/im_messages_search.go +++ b/shortcuts/im/im_messages_search.go @@ -9,7 +9,6 @@ import ( "io" "net/http" "strconv" - "strings" "github.com/larksuite/cli/internal/output" "github.com/larksuite/cli/shortcuts/common" @@ -45,7 +44,7 @@ var ImMessagesSearch = common.Shortcut{ {Name: "is-at-me", Type: "bool", Desc: "only messages that @me"}, {Name: "start", Desc: "start time(ISO 8601) with local timezone offset (e.g. 2026-03-24T00:00:00+08:00)"}, {Name: "end", Desc: "end time(ISO 8601) with local timezone offset (e.g. 2026-03-25T23:59:59+08:00)"}, - {Name: "page-size", Default: "20", Desc: "page size (1-50)"}, + {Name: "page-size", Type: "int", Default: "20", Desc: "page size (1-50)"}, {Name: "page-token", Desc: "page token"}, {Name: "page-all", Type: "bool", Desc: "automatically paginate search results"}, {Name: "page-limit", Type: "int", Default: "20", Desc: "max search pages when auto-pagination is enabled (default 20, max 40)"}, @@ -248,13 +247,11 @@ func buildMessagesSearchRequest(runtime *common.RuntimeContext) (*messagesSearch excludeSenderTypeFlag := runtime.Str("exclude-sender-type") startFlag := runtime.Str("start") endFlag := runtime.Str("end") - pageSizeStr := runtime.Str("page-size") pageToken := runtime.Str("page-token") - pageLimitStr := strings.TrimSpace(runtime.Str("page-limit")) if runtime.Cmd != nil && runtime.Cmd.Flags().Changed("page-limit") { - pageLimit, err := strconv.Atoi(pageLimitStr) - if err != nil || pageLimit < 1 || pageLimit > messagesSearchMaxPageLimit { + pageLimit := runtime.Int("page-limit") + if pageLimit < 1 || pageLimit > messagesSearchMaxPageLimit { return nil, output.ErrValidation("--page-limit must be an integer between 1 and 40") } } @@ -333,16 +330,12 @@ func buildMessagesSearchRequest(runtime *common.RuntimeContext) (*messagesSearch body["filter"] = filter } - pageSize := messagesSearchDefaultPageSize - if pageSizeStr != "" { - n, err := strconv.Atoi(pageSizeStr) - if err != nil || n < 1 { - return nil, output.ErrValidation("--page-size must be an integer between 1 and 50") - } - if n > messagesSearchMaxPageSize { - n = messagesSearchMaxPageSize - } - pageSize = n + pageSize := runtime.Int("page-size") + if pageSize < 1 { + return nil, output.ErrValidation("--page-size must be an integer between 1 and 50") + } + if pageSize > messagesSearchMaxPageSize { + pageSize = messagesSearchMaxPageSize } params := larkcore.QueryParams{ @@ -366,9 +359,7 @@ func messagesSearchPaginationConfig(runtime *common.RuntimeContext) (autoPaginat pageLimit = messagesSearchDefaultPageLimit if runtime.Cmd != nil && runtime.Cmd.Flags().Changed("page-limit") { - if n, err := strconv.Atoi(strings.TrimSpace(runtime.Str("page-limit"))); err == nil && n > 0 { - pageLimit = min(n, messagesSearchMaxPageLimit) - } + pageLimit = min(runtime.Int("page-limit"), messagesSearchMaxPageLimit) } else if runtime.Bool("page-all") { pageLimit = messagesSearchMaxPageLimit } diff --git a/shortcuts/im/im_messages_search_execute_test.go b/shortcuts/im/im_messages_search_execute_test.go index e11c41fcf..1ef87144b 100644 --- a/shortcuts/im/im_messages_search_execute_test.go +++ b/shortcuts/im/im_messages_search_execute_test.go @@ -24,15 +24,12 @@ func newMessagesSearchRuntime(t *testing.T, stringFlags map[string]string, boolF runtime := newBotShortcutRuntime(t, rt) cmd := &cobra.Command{Use: "test"} - stringFlagNames := []string{ - "query", - "page-size", - "page-token", - "page-limit", - } + stringFlagNames := []string{"query", "page-token"} for _, name := range stringFlagNames { cmd.Flags().String(name, "", "") } + cmd.Flags().Int("page-size", 20, "") + cmd.Flags().Int("page-limit", 20, "") boolFlagNames := []string{"page-all"} for _, name := range boolFlagNames { cmd.Flags().Bool(name, false, "")