Files
wehub-resource-sync bf9395e022
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:22:54 +08:00

221 lines
6.1 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package mail
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"testing"
"github.com/spf13/cobra"
"github.com/larksuite/cli/internal/cmdutil"
"github.com/larksuite/cli/internal/httpmock"
"github.com/larksuite/cli/shortcuts/common"
)
func TestMailMessageHelpClarifiesSingleMessageOnly(t *testing.T) {
f, stdout, _, _ := mailShortcutTestFactory(t)
err := runMountedMailShortcutWithCobraOutput(t, MailMessage, []string{"+message", "-h"}, f, stdout)
if err != nil {
t.Fatalf("help returned error: %v", err)
}
help := stdout.String()
for _, want := range []string{
"Use only when reading full content for one email by one message ID",
"For multiple message IDs, use mail +messages; do not loop mail +message",
"Single email message ID only",
"mail +messages --message-ids",
} {
if !strings.Contains(help, want) {
t.Fatalf("help missing %q\n%s", want, help)
}
}
}
func TestMailMessagesHelpClarifiesBatchGetChunkingAndLimits(t *testing.T) {
f, stdout, _, _ := mailShortcutTestFactory(t)
err := runMountedMailShortcutWithCobraOutput(t, MailMessages, []string{"+messages", "-h"}, f, stdout)
if err != nil {
t.Fatalf("help returned error: %v", err)
}
help := stdout.String()
for _, want := range []string{
"multiple emails by message ID",
"handles them in batches of 20 and merges output",
"Comma-separated email message IDs",
"You may pass more than 20 IDs",
} {
if !strings.Contains(help, want) {
t.Fatalf("help missing %q\n%s", want, help)
}
}
for _, disallowed := range []string{"messages.batch_get", "OAPI Meta", "gateway config", "50 IDs", "50 个"} {
if strings.Contains(help, disallowed) {
t.Fatalf("help must not expose internal wording %q\n%s", disallowed, help)
}
}
}
func TestMailMessagesDryRunMentionsBatchGetChunkingAndMerge(t *testing.T) {
f, stdout, _, _ := mailShortcutTestFactory(t)
messageIDs := []string{
validMessageIDForTest("dry-run-1"),
validMessageIDForTest("dry-run-2"),
}
err := runMountedMailShortcut(t, MailMessages, []string{
"+messages", "--message-ids", strings.Join(messageIDs, ","), "--dry-run", "--format", "json",
}, f, stdout)
if err != nil {
t.Fatalf("dry-run returned error: %v", err)
}
out := stdout.String()
for _, want := range []string{
"chunks every 20 IDs",
"merges output",
} {
if !strings.Contains(out, want) {
t.Fatalf("dry-run missing %q\n%s", want, out)
}
}
}
func TestMailTriageTableHintRoutesSingleAndMultipleReads(t *testing.T) {
f, stdout, stderr, reg := mailShortcutTestFactory(t)
registerTriageReadHintStubs(reg)
err := runMountedMailShortcut(t, MailTriage, []string{
"+triage", "--max", "1",
}, f, stdout)
if err != nil {
t.Fatalf("triage returned error: %v", err)
}
reg.Verify(t)
errOut := stderr.String()
for _, want := range []string{
"tip: read full content:",
"single message use mail +message --message-id <id>",
"multiple messages use mail +messages --message-ids <id1>,<id2>,<id3>",
} {
if !strings.Contains(errOut, want) {
t.Fatalf("stderr missing %q\n%s", want, errOut)
}
}
}
func TestMailTriageJSONDoesNotEmitReadHint(t *testing.T) {
f, stdout, stderr, reg := mailShortcutTestFactory(t)
registerTriageReadHintStubs(reg)
err := runMountedMailShortcut(t, MailTriage, []string{
"+triage", "--format", "json", "--max", "1",
}, f, stdout)
if err != nil {
t.Fatalf("triage returned error: %v", err)
}
reg.Verify(t)
if strings.Contains(stderr.String(), "tip: read full content:") {
t.Fatalf("json output must not emit table read hint\nstderr=%s", stderr.String())
}
}
func TestMailMessagesExecuteChunksTwentyOneIDsIntoTwoBatchGetCalls(t *testing.T) {
f, stdout, _, reg := mailShortcutTestFactory(t)
stub := &httpmock.Stub{
Method: "POST",
URL: "/user_mailboxes/me/messages/batch_get",
Reusable: true,
Body: map[string]interface{}{
"code": 0,
"data": map[string]interface{}{"messages": []interface{}{}},
},
}
reg.Register(stub)
ids := make([]string, 21)
for i := range ids {
ids[i] = validMessageIDForTest(fmt.Sprintf("batch-%02d", i+1))
}
err := runMountedMailShortcut(t, MailMessages, []string{
"+messages", "--message-ids", strings.Join(ids, ","),
}, f, stdout)
if err != nil {
t.Fatalf("messages returned error: %v", err)
}
if got := len(stub.CapturedBodies); got != 2 {
t.Fatalf("expected 2 batch_get calls, got %d", got)
}
assertBatchGetMessageIDCount(t, stub.CapturedBodies[0], 20)
assertBatchGetMessageIDCount(t, stub.CapturedBodies[1], 1)
}
func registerTriageReadHintStubs(reg *httpmock.Registry) {
reg.Register(&httpmock.Stub{
Method: "GET",
URL: "/user_mailboxes/me/messages",
Body: map[string]interface{}{
"code": 0,
"data": map[string]interface{}{
"items": []interface{}{"msg_1"},
"has_more": false,
"page_token": "",
},
},
})
reg.Register(&httpmock.Stub{
Method: "POST",
URL: "/user_mailboxes/me/messages/batch_get",
Body: map[string]interface{}{
"code": 0,
"data": map[string]interface{}{
"messages": []interface{}{
map[string]interface{}{
"message_id": "msg_1",
"subject": "Quarterly update",
"date": "Thu, 04 Jun 2026 10:00:00 +0800",
"from": map[string]interface{}{"name": "Alice", "mail_address": "alice@example.com"},
},
},
},
},
})
}
func assertBatchGetMessageIDCount(t *testing.T, body []byte, want int) {
t.Helper()
var payload struct {
MessageIDs []string `json:"message_ids"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("unmarshal batch_get body: %v\n%s", err, string(body))
}
if got := len(payload.MessageIDs); got != want {
t.Fatalf("message_ids count mismatch: got %d want %d body=%s", got, want, string(body))
}
}
func runMountedMailShortcutWithCobraOutput(t *testing.T, shortcut common.Shortcut, args []string, f *cmdutil.Factory, stdout *bytes.Buffer) error {
t.Helper()
parent := &cobra.Command{Use: "test"}
parent.SetOut(stdout)
parent.SetErr(stdout)
shortcut.Mount(parent, f)
parent.SetArgs(args)
parent.SilenceErrors = true
parent.SilenceUsage = true
stdout.Reset()
return parent.Execute()
}