Files
dingtalk-workspace-cli/internal/helpers/drive_list_modes_test.go
T
玉澜andCursor 7773eb27f1 refactor(corecmd): rename package and finish ContractFinal leaf migration
Move cmdcore to corecmd, declare attendance ContractFinal in helpers, keep
Sheet destructive commands --yes-only, and align catalog/policy provenance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 14:13:46 +08:00

228 lines
7.7 KiB
Go

package helpers
import (
"context"
"io"
"strings"
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
"github.com/spf13/cobra"
)
type depthArgsRecordingCaller struct {
steps []scriptedToolStep
index int
calls []map[string]any
}
func (c *depthArgsRecordingCaller) CallTool(_ context.Context, _, _ string, args map[string]any) (*edition.ToolResult, error) {
c.calls = append(c.calls, args)
index := c.index
if index >= len(c.steps) {
index = len(c.steps) - 1
}
c.index++
return textToolResult(c.steps[index].text), nil
}
func (*depthArgsRecordingCaller) Format() string { return "json" }
func (*depthArgsRecordingCaller) DryRun() bool { return false }
func (*depthArgsRecordingCaller) Fields() string { return "" }
func (*depthArgsRecordingCaller) JQ() string { return "" }
func executeDriveCommand(t *testing.T, caller edition.ToolCaller, args ...string) error {
t.Helper()
previousDeps := deps
t.Cleanup(func() { deps = previousDeps })
InitDeps(caller)
deps.Out.w = io.Discard
deps.Out.errW = io.Discard
root := newDriveCommand()
root.SilenceErrors = true
root.SilenceUsage = true
root.SetArgs(args)
return root.Execute()
}
func TestCrossPlatformCoverageDriveListVersionsMode(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
"list", "--versions", "--node", "node-1", "--limit", "5", "--cursor", "cur-1")
if err != nil {
t.Fatal(err)
}
if len(caller.calls) != 1 {
t.Fatalf("calls = %#v", caller.calls)
}
call := caller.calls[0]
if call.productID != "drive" || call.toolName != "list_file_versions" {
t.Fatalf("call = %#v", call)
}
if call.args["nodeId"] != "node-1" || call.args["maxResults"] != 5 || call.args["nextCursor"] != "cur-1" {
t.Fatalf("args = %#v", call.args)
}
}
func TestCrossPlatformCoverageDriveListVersionsModeRequiresNode(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newDriveCommand, "list", "--versions")
if err == nil {
t.Fatal("versions without --node returned nil")
}
if len(caller.calls) != 0 {
t.Fatalf("calls = %#v", caller.calls)
}
}
func TestCrossPlatformCoverageDriveListWorkspaceDepthRoutesDocBFS(t *testing.T) {
caller := &depthArgsRecordingCaller{steps: []scriptedToolStep{
{text: `{"nodes":[{"nodeId":"n1","name":"doc1","nodeType":"doc"}],"hasMore":false}`},
}}
err := executeDriveCommand(t, caller,
"list", "--workspace", "ws-1", "--depth", "2", "--node", "folder-1")
if err != nil {
t.Fatal(err)
}
if len(caller.calls) != 1 {
t.Fatalf("calls = %#v, want 1", caller.calls)
}
args := caller.calls[0]
if args["workspaceId"] != "ws-1" || args["folderId"] != "folder-1" || args["pageSize"] != float64(docDepthPageSize) {
t.Fatalf("doc BFS args = %#v", args)
}
}
func TestCrossPlatformCoverageDriveListWorkspaceDepthRejectsNumericFolder(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
"list", "--workspace", "ws-1", "--depth", "2", "--node", "12345")
if err == nil {
t.Fatal("numeric doc folder returned nil")
}
}
func TestCrossPlatformCoverageDriveListPanDepthBuildsBaseArgs(t *testing.T) {
useDriveDepthArgs(t)
caller := &depthArgsRecordingCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"f1","name":"a.txt","type":"FILE"}]}`},
}}
err := executeDriveCommand(t, caller,
"list", "--depth", "2", "--space-id", "sp-1", "--order-by", "name", "--order", "asc", "--thumbnail", "--folder", "root-folder")
if err != nil {
t.Fatal(err)
}
if len(caller.calls) != 1 {
t.Fatalf("calls = %#v, want 1", caller.calls)
}
args := caller.calls[0]
if args["spaceId"] != "sp-1" || args["orderBy"] != "name" || args["order"] != "asc" ||
args["withThumbnail"] != true || args["parentId"] != "root-folder" || args["maxResults"] != float64(driveDepthPageSize) {
t.Fatalf("pan BFS args = %#v", args)
}
}
func TestCrossPlatformCoverageDriveListPanDepthRejectsNumericFolder(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
"list", "--depth", "2", "--folder", "12345")
if err == nil {
t.Fatal("numeric drive folder returned nil")
}
}
func TestCrossPlatformCoverageDriveTransferOwnerDryRun(t *testing.T) {
caller := &guardedMutationCaller{dryRun: true}
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
"permission", "transfer-owner", "--node", "node-1", "--new-owner", "user-1", "--dry-run")
if err != nil {
t.Fatal(err)
}
if len(caller.calls) != 0 {
t.Fatalf("dry-run calls = %#v", caller.calls)
}
}
func TestCrossPlatformCoverageDriveTransferOwnerYesRequiresRecursive(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
"permission", "transfer-owner", "--node", "node-1", "--new-owner", "user-1", "--reserve-role", "EDITOR", "--yes")
if err == nil || !strings.Contains(err.Error(), "--recursive is required") {
t.Fatalf("err = %v, want --recursive required", err)
}
}
func TestCrossPlatformCoverageDriveTransferOwnerWorkspaceTarget(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
"permission", "transfer-owner", "--workspace", "ws-1", "--new-owner", "user-1", "--reserve-role", "EDITOR", "--recursive", "--yes")
if err != nil {
t.Fatal(err)
}
if len(caller.calls) != 1 {
t.Fatalf("calls = %#v", caller.calls)
}
call := caller.calls[0]
if call.productID != "doc" || call.toolName != "transfer_owner" {
t.Fatalf("call = %#v", call)
}
if call.args["workspaceId"] != "ws-1" || call.args["newOwnerId"] != "user-1" ||
call.args["reserveOldOwnerRole"] != "EDITOR" || call.args["recursiveChange"] != true {
t.Fatalf("args = %#v", call.args)
}
if _, ok := call.args["nodeId"]; ok {
t.Fatalf("unexpected nodeId in %#v", call.args)
}
}
func TestCrossPlatformCoverageDriveTransferOwnerDeclined(t *testing.T) {
caller := &guardedMutationCaller{}
root := newDriveCommand()
root.SetIn(strings.NewReader("no\n"))
err := executeGuardedMutationCommand(t, caller, func() *cobra.Command { return root },
"permission", "transfer-owner", "--node", "node-1", "--new-owner", "user-1")
if err == nil || !strings.Contains(err.Error(), "用户取消了操作") {
t.Fatalf("declined transfer error = %v, want 用户取消了操作", err)
}
if len(caller.calls) != 0 {
t.Fatalf("declined calls = %#v", caller.calls)
}
}
func TestCrossPlatformCoverageDriveCoverRequiresNode(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newDriveCommand, "cover")
if err == nil {
t.Fatal("cover without --node returned nil")
}
if len(caller.calls) != 0 {
t.Fatalf("calls = %#v", caller.calls)
}
}
func TestCrossPlatformCoverageDriveRevertDeclined(t *testing.T) {
caller := &guardedMutationCaller{}
root := newDriveCommand()
root.SetIn(strings.NewReader("no\n"))
err := executeGuardedMutationCommand(t, caller, func() *cobra.Command { return root },
"revert", "--node", "node-1", "--version", "3")
if err == nil || !strings.Contains(err.Error(), "用户取消了操作") {
t.Fatalf("declined revert error = %v, want 用户取消了操作", err)
}
if len(caller.calls) != 0 {
t.Fatalf("declined revert calls = %#v", caller.calls)
}
}
func TestCrossPlatformCoverageDriveTransferOwnerRejectsBothTargets(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newDriveCommand,
"permission", "transfer-owner", "--node", "node-1", "--workspace", "ws-1", "--new-owner", "user-1", "--yes")
if err == nil || !strings.Contains(err.Error(), "mutually exclusive") {
t.Fatalf("err = %v, want mutual exclusion", err)
}
if len(caller.calls) != 0 {
t.Fatalf("calls = %#v, want none", caller.calls)
}
}