Files
dingtalk-workspace-cli/test/cli_compat/calendar_test.go
2026-03-27 17:55:57 +08:00

593 lines
20 KiB
Go

package cli_compat_test
import (
"testing"
)
// ── event list ──────────────────────────────────────────────
func TestCalEventList_should_call_list_calendar_events_with_no_args(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "event", "list"}, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "list_calendar_events")
}
func TestCalEventList_should_parse_start_time_to_millis(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "event", "list"}, map[string]string{
"start": "2026-03-10T14:00:00+08:00",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolArg(t, cap, "startTime", float64(1773122400000))
}
func TestCalEventList_should_parse_end_time_to_millis(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "event", "list"}, map[string]string{
"end": "2026-03-10T18:00:00+08:00",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolArg(t, cap, "endTime", float64(1773136800000))
}
func TestCalEventList_should_return_error_for_invalid_start_format(t *testing.T) {
_ = setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "event", "list"}, map[string]string{
"start": "not-a-date",
})
if err == nil {
t.Fatal("expected error for invalid date format")
}
}
func TestCalEventList_should_pass_both_times(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "list"}, map[string]string{
"start": "2026-03-10T14:00:00+08:00",
"end": "2026-03-10T18:00:00+08:00",
})
last := cap.last()
if last == nil {
t.Fatal("no MCP call captured")
}
if last.Args["startTime"] == nil || last.Args["endTime"] == nil {
t.Error("expected both startTime and endTime")
}
}
// ── event get ───────────────────────────────────────────────
func TestCalEventGet_should_call_get_calendar_detail(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "event", "get"}, map[string]string{
"id": "EVT001",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "get_calendar_detail")
assertToolArg(t, cap, "eventId", "EVT001")
}
func TestCalEventGet_should_pass_different_event_ids(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "get"}, map[string]string{"id": "EVT_XYZ"})
assertToolArg(t, cap, "eventId", "EVT_XYZ")
}
func TestCalEventGet_should_make_single_call(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "get"}, map[string]string{"id": "E1"})
assertCallCount(t, cap, 1)
}
func TestCalEventGet_should_handle_long_event_id(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
longID := "evt_0123456789abcdef0123456789abcdef0123456789abcdef"
_ = execCmd(t, root, []string{"calendar", "event", "get"}, map[string]string{"id": longID})
assertToolArg(t, cap, "eventId", longID)
}
func TestCalEventGet_should_return_no_error(t *testing.T) {
_ = setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "event", "get"}, map[string]string{"id": "E1"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
// ── event create ────────────────────────────────────────────
func TestCalEventCreate_should_call_create_calendar_event(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "event", "create"}, map[string]string{
"title": "Q1 复盘会",
"start": "2026-03-10T14:00:00+08:00",
"end": "2026-03-10T15:00:00+08:00",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "create_calendar_event")
assertToolArg(t, cap, "summary", "Q1 复盘会")
}
func TestCalEventCreate_should_pass_start_and_end_as_strings(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "create"}, map[string]string{
"title": "会议",
"start": "2026-03-10T14:00:00+08:00",
"end": "2026-03-10T15:00:00+08:00",
})
assertToolArg(t, cap, "startDateTime", "2026-03-10T14:00:00+08:00")
assertToolArg(t, cap, "endDateTime", "2026-03-10T15:00:00+08:00")
}
func TestCalEventCreate_should_include_description_when_provided(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "create"}, map[string]string{
"title": "会议",
"start": "2026-03-10T14:00:00+08:00",
"end": "2026-03-10T15:00:00+08:00",
"desc": "讨论Q1业务",
})
assertToolArg(t, cap, "description", "讨论Q1业务")
}
func TestCalEventCreate_should_not_include_description_when_empty(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "create"}, map[string]string{
"title": "会议",
"start": "2026-03-10T14:00:00+08:00",
"end": "2026-03-10T15:00:00+08:00",
"desc": "",
})
assertArgNotPresent(t, cap, "description")
}
func TestCalEventCreate_should_make_single_call(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "create"}, map[string]string{
"title": "T", "start": "2026-03-10T14:00:00+08:00", "end": "2026-03-10T15:00:00+08:00",
})
assertCallCount(t, cap, 1)
}
// ── event update ────────────────────────────────────────────
func TestCalEventUpdate_should_call_update_calendar_event(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "event", "update"}, map[string]string{
"id": "EVT001",
"title": "新标题",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "update_calendar_event")
assertToolArg(t, cap, "eventId", "EVT001")
assertToolArg(t, cap, "summary", "新标题")
}
func TestCalEventUpdate_should_only_pass_changed_fields(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "update"}, map[string]string{
"id": "EVT001", "title": "", "start": "", "end": "",
})
assertArgNotPresent(t, cap, "summary")
assertArgNotPresent(t, cap, "startDateTime")
assertArgNotPresent(t, cap, "endDateTime")
}
func TestCalEventUpdate_should_pass_start_and_end_when_provided(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "update"}, map[string]string{
"id": "E1",
"start": "2026-04-01T09:00:00+08:00",
"end": "2026-04-01T10:00:00+08:00",
})
assertToolArg(t, cap, "startDateTime", "2026-04-01T09:00:00+08:00")
assertToolArg(t, cap, "endDateTime", "2026-04-01T10:00:00+08:00")
}
func TestCalEventUpdate_should_always_pass_event_id(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "update"}, map[string]string{"id": "EID"})
assertToolArg(t, cap, "eventId", "EID")
}
func TestCalEventUpdate_should_make_single_call(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "update"}, map[string]string{"id": "E1"})
assertCallCount(t, cap, 1)
}
// ── event delete ────────────────────────────────────────────
func TestCalEventDelete_should_not_call_mcp_when_not_confirmed(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "delete"}, map[string]string{"id": "E1"})
assertCallCount(t, cap, 0)
}
func TestCalEventDelete_should_call_delete_calendar_event_when_confirmed(t *testing.T) {
cap := setupTestDepsAutoConfirm(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "delete"}, map[string]string{"id": "E1"})
assertToolName(t, cap, "delete_calendar_event")
assertToolArg(t, cap, "eventId", "E1")
}
func TestCalEventDelete_should_return_nil_when_not_confirmed(t *testing.T) {
_ = setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "event", "delete"}, map[string]string{"id": "E1"})
if err != nil {
t.Fatalf("expected nil, got %v", err)
}
}
func TestCalEventDelete_should_pass_event_id_when_confirmed(t *testing.T) {
cap := setupTestDepsAutoConfirm(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "delete"}, map[string]string{"id": "EVT_ABC"})
assertToolArg(t, cap, "eventId", "EVT_ABC")
}
func TestCalEventDelete_should_make_single_call_when_confirmed(t *testing.T) {
cap := setupTestDepsAutoConfirm(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "event", "delete"}, map[string]string{"id": "E1"})
assertCallCount(t, cap, 1)
}
// ── participant list ────────────────────────────────────────
func TestCalParticipantList_should_call_get_calendar_participants(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "participant", "list"}, map[string]string{
"event": "EVT001",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "get_calendar_participants")
assertToolArg(t, cap, "eventId", "EVT001")
}
func TestCalParticipantList_should_handle_different_event_ids(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "participant", "list"}, map[string]string{
"event": "EVT_XYZ",
})
assertToolArg(t, cap, "eventId", "EVT_XYZ")
}
func TestCalParticipantList_should_make_single_call(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "participant", "list"}, map[string]string{
"event": "E1",
})
assertCallCount(t, cap, 1)
}
func TestCalParticipantList_should_not_pass_attendees(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "participant", "list"}, map[string]string{
"event": "E1",
})
assertArgNotPresent(t, cap, "attendeesToAdd")
}
func TestCalParticipantList_should_return_no_error(t *testing.T) {
_ = setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "participant", "list"}, map[string]string{
"event": "E1",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
// ── participant add ─────────────────────────────────────────
func TestCalParticipantAdd_should_call_add_calendar_participant(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "participant", "add"}, map[string]string{
"event": "EVT001", "users": "userId1,userId2",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "add_calendar_participant")
assertToolArg(t, cap, "attendeesToAdd", []string{"userId1", "userId2"})
}
func TestCalParticipantAdd_should_parse_single_user(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "participant", "add"}, map[string]string{
"event": "E1", "users": "uid_only",
})
assertToolArg(t, cap, "attendeesToAdd", []string{"uid_only"})
}
func TestCalParticipantAdd_should_pass_event_id(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "participant", "add"}, map[string]string{
"event": "EVT_99", "users": "u1",
})
assertToolArg(t, cap, "eventId", "EVT_99")
}
func TestCalParticipantAdd_should_trim_spaces_in_users(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "participant", "add"}, map[string]string{
"event": "E1", "users": " u1 , u2 ",
})
assertToolArg(t, cap, "attendeesToAdd", []string{"u1", "u2"})
}
func TestCalParticipantAdd_should_make_single_call(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "participant", "add"}, map[string]string{
"event": "E1", "users": "u1",
})
assertCallCount(t, cap, 1)
}
// ── room search ─────────────────────────────────────────────
func TestCalRoomSearch_should_call_query_available_meeting_room(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "room", "search"}, map[string]string{
"start": "2026-03-10T14:00:00+08:00",
"end": "2026-03-10T15:00:00+08:00",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "query_available_meeting_room")
}
func TestCalRoomSearch_should_parse_times_to_millis(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "search"}, map[string]string{
"start": "2026-03-10T14:00:00+08:00",
"end": "2026-03-10T15:00:00+08:00",
})
assertToolArg(t, cap, "startTime", float64(1773122400000))
assertToolArg(t, cap, "endTime", float64(1773126000000))
}
func TestCalRoomSearch_should_pass_groupId_when_provided(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "search"}, map[string]string{
"start": "2026-03-10T14:00:00+08:00",
"end": "2026-03-10T15:00:00+08:00",
"group-id": "group_123",
})
assertToolArg(t, cap, "groupId", "group_123")
}
func TestCalRoomSearch_should_return_error_for_bad_start_time(t *testing.T) {
_ = setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "room", "search"}, map[string]string{
"start": "bad", "end": "2026-03-10T15:00:00+08:00",
})
if err == nil {
t.Fatal("expected error for bad start time")
}
}
func TestCalRoomSearch_should_return_error_for_bad_end_time(t *testing.T) {
_ = setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "room", "search"}, map[string]string{
"start": "2026-03-10T14:00:00+08:00", "end": "bad",
})
if err == nil {
t.Fatal("expected error for bad end time")
}
}
func TestCalRoomSearch_should_make_single_call(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "search"}, map[string]string{
"start": "2026-03-10T14:00:00+08:00", "end": "2026-03-10T15:00:00+08:00",
})
assertCallCount(t, cap, 1)
}
// ── room add ────────────────────────────────────────────────
func TestCalRoomAdd_should_call_add_meeting_room(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "room", "add"}, map[string]string{
"event": "EVT001", "rooms": "room1,room2",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "add_meeting_room")
assertToolArg(t, cap, "eventId", "EVT001")
assertToolArg(t, cap, "roomIds", []string{"room1", "room2"})
}
func TestCalRoomAdd_should_handle_single_room(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "add"}, map[string]string{
"event": "E1", "rooms": "room_single",
})
assertToolArg(t, cap, "roomIds", []string{"room_single"})
}
func TestCalRoomAdd_should_trim_room_ids(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "add"}, map[string]string{
"event": "E1", "rooms": " r1 , r2 ",
})
assertToolArg(t, cap, "roomIds", []string{"r1", "r2"})
}
func TestCalRoomAdd_should_pass_event_id(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "add"}, map[string]string{
"event": "EVT_X", "rooms": "r1",
})
assertToolArg(t, cap, "eventId", "EVT_X")
}
func TestCalRoomAdd_should_make_single_call(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "add"}, map[string]string{
"event": "E1", "rooms": "r1",
})
assertCallCount(t, cap, 1)
}
// ── room list-groups ────────────────────────────────────────
func TestCalRoomListGroups_should_call_list_meeting_room_groups(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "room", "list-groups"}, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "list_meeting_room_groups")
}
func TestCalRoomListGroups_should_pass_nil_args(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "list-groups"}, nil)
assertNilArgs(t, cap)
}
func TestCalRoomListGroups_should_make_single_call(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "list-groups"}, nil)
assertCallCount(t, cap, 1)
}
func TestCalRoomListGroups_should_return_no_error(t *testing.T) {
_ = setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "room", "list-groups"}, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
func TestCalRoomListGroups_should_not_call_mcp_in_dry_run(t *testing.T) {
cap := setupTestDepsWithDryRun(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "room", "list-groups"}, nil)
assertCallCount(t, cap, 0)
}
// ── busy search ─────────────────────────────────────────────
func TestCalBusySearch_should_call_query_busy_status(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "busy", "search"}, map[string]string{
"users": "userId1,userId2",
"start": "2026-03-10T14:00:00+08:00",
"end": "2026-03-10T18:00:00+08:00",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
assertToolName(t, cap, "query_busy_status")
assertToolArg(t, cap, "userIds", []string{"userId1", "userId2"})
}
func TestCalBusySearch_should_parse_times_to_millis(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "busy", "search"}, map[string]string{
"users": "u1", "start": "2026-03-10T14:00:00+08:00", "end": "2026-03-10T18:00:00+08:00",
})
assertToolArg(t, cap, "startTime", float64(1773122400000))
assertToolArg(t, cap, "endTime", float64(1773136800000))
}
func TestCalBusySearch_should_return_error_for_bad_start(t *testing.T) {
_ = setupTestDeps(t, "calendar")
root := buildRoot()
err := execCmd(t, root, []string{"calendar", "busy", "search"}, map[string]string{
"users": "u1", "start": "bad", "end": "2026-03-10T18:00:00+08:00",
})
if err == nil {
t.Fatal("expected error")
}
}
func TestCalBusySearch_should_handle_single_user(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "busy", "search"}, map[string]string{
"users": "single_uid", "start": "2026-03-10T14:00:00+08:00", "end": "2026-03-10T18:00:00+08:00",
})
assertToolArg(t, cap, "userIds", []string{"single_uid"})
}
func TestCalBusySearch_should_make_single_call(t *testing.T) {
cap := setupTestDeps(t, "calendar")
root := buildRoot()
_ = execCmd(t, root, []string{"calendar", "busy", "search"}, map[string]string{
"users": "u1", "start": "2026-03-10T14:00:00+08:00", "end": "2026-03-10T18:00:00+08:00",
})
assertCallCount(t, cap, 1)
}