Files
dingtalk-workspace-cli/internal/helpers/todo_reminder_test.go

150 lines
4.7 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
package helpers
import (
"context"
"io"
"reflect"
"strings"
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
)
type todoReminderCall struct {
toolName string
args map[string]any
}
type todoReminderCaller struct {
calls []todoReminderCall
}
func (c *todoReminderCaller) CallTool(_ context.Context, _ string, toolName string, args map[string]any) (*edition.ToolResult, error) {
c.calls = append(c.calls, todoReminderCall{toolName: toolName, args: args})
return &edition.ToolResult{Content: []edition.ContentBlock{{Type: "text", Text: `{}`}}}, nil
}
func (*todoReminderCaller) Format() string { return "json" }
func (*todoReminderCaller) DryRun() bool { return false }
func (*todoReminderCaller) Fields() string { return "" }
func (*todoReminderCaller) JQ() string { return "" }
func runTodoReminderCommand(t *testing.T, args ...string) (*todoReminderCaller, error) {
t.Helper()
previousDeps := deps
t.Cleanup(func() { deps = previousDeps })
caller := &todoReminderCaller{}
InitDeps(caller)
deps.Out.w = io.Discard
cmd := newTodoCommand()
cmd.SilenceErrors = true
cmd.SilenceUsage = true
cmd.SetArgs(append([]string{"task", "add-reminder"}, args...))
return caller, cmd.Execute()
}
func TestTodoAddReminderValidatesModeSpecificInputsBeforeCallingTool(t *testing.T) {
tests := []struct {
name string
args []string
wantErr string
}{
{
name: "due time requires offset",
args: []string{"--task-id", "task-smoke", "--base-time", "dueTime"},
wantErr: "--due-date-offset is required",
},
{
name: "custom time requires timestamp",
args: []string{"--task-id", "task-smoke", "--base-time", "customTime"},
wantErr: "--reminder-time-stamp is required",
},
{
name: "unknown base time",
args: []string{"--task-id", "task-smoke", "--base-time", "deadline", "--due-date-offset", "-30"},
wantErr: "--base-time must be one of dueTime or customTime",
},
{
name: "custom time validates timestamp",
args: []string{"--task-id", "task-smoke", "--base-time", "customTime", "--reminder-time-stamp", "tomorrow"},
wantErr: "reminder-time-stamp",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
caller, err := runTodoReminderCommand(t, test.args...)
if err == nil || !strings.Contains(err.Error(), test.wantErr) {
t.Fatalf("error = %v, want containing %q", err, test.wantErr)
}
if len(caller.calls) != 0 {
t.Fatalf("tool call count = %d, want 0", len(caller.calls))
}
})
}
}
func TestTodoAddReminderMapsReviewedModes(t *testing.T) {
tests := []struct {
name string
args []string
wantBaseTime string
wantDueDateOffset any
wantReminderTimestamp any
}{
{
name: "due time",
args: []string{"--task-id", "task-smoke", "--base-time", "dueTime", "--due-date-offset", "-30"},
wantBaseTime: "dueTime",
wantDueDateOffset: "-30",
},
{
name: "custom time",
args: []string{"--task-id", "task-smoke", "--base-time", "customTime", "--reminder-time-stamp", "2026-03-10T18:00:00+08:00"},
wantBaseTime: "customTime",
wantReminderTimestamp: int64(1773136800000),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
caller, err := runTodoReminderCommand(t, test.args...)
if err != nil {
t.Fatalf("todo add-reminder returned error: %v", err)
}
if len(caller.calls) != 1 || caller.calls[0].toolName != "add_todo_reminder" {
t.Fatalf("tool calls = %#v, want one add_todo_reminder call", caller.calls)
}
request, ok := caller.calls[0].args["todoReminderAddRequest"].(map[string]any)
if !ok {
t.Fatalf("request = %#v, want object", caller.calls[0].args["todoReminderAddRequest"])
}
if request["taskId"] != "task-smoke" || request["baseTime"] != test.wantBaseTime {
t.Fatalf("request identity = %#v", request)
}
if request["dueDateOffset"] != test.wantDueDateOffset {
t.Fatalf("dueDateOffset = %#v, want %#v", request["dueDateOffset"], test.wantDueDateOffset)
}
if request["reminderTimeStamp"] != test.wantReminderTimestamp {
t.Fatalf("reminderTimeStamp = %#v, want %#v", request["reminderTimeStamp"], test.wantReminderTimestamp)
}
})
}
}
func TestTodoRoleTypesCSVExampleUsesRuntimeParser(t *testing.T) {
got, err := parseRoleTypes("creator,executor")
if err != nil {
t.Fatalf("parse role-types example: %v", err)
}
want := []string{"creator", "executor"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("role types = %#v, want %#v", got, want)
}
}