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

108 lines
4.0 KiB
Go

package helpers
import (
"context"
"io"
"os"
"path/filepath"
"strings"
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/testseam"
)
// 本文件补齐几条在默认策略改为 skip 后失去覆盖的边界分支。
// pull 自动创建目标根失败(--local-folder 指向一个常规文件)→ 明确报错,不落盘。
func TestCrossPlatformCoverageDrivePull_localRootIsFileFails(t *testing.T) {
dir := t.TempDir()
asFile := filepath.Join(dir, "not-a-dir")
mustWrite(t, asFile, "x")
caller := pullListingCaller(`{"name":"a.txt","type":"file","fileId":"A","modifyTime":1}`)
err := runDriveCmd(t, caller, "pull", "--local-folder", asFile, "--remote-folder", "ROOT")
if err == nil || !strings.Contains(err.Error(), "创建本地目录失败") {
t.Fatalf("expected local root creation failure, got %v", err)
}
}
// push 遍历远端时 list_files 在**子目录**层失败 → 错误如实上抛(walkRemoteForPush 的递归错误分支)。
func TestCrossPlatformCoverageDrivePush_remoteSubdirListFailurePropagates(t *testing.T) {
dir := t.TempDir()
mustWrite(t, filepath.Join(dir, "a.txt"), "x")
withNoopPut(t)
caller := &driveScriptCaller{reply: func(tool string, args map[string]any, _ int) (string, error) {
if tool != "list_files" {
return `{"result":{},"success":true}`, nil
}
switch args["parentId"] {
case "ROOT":
return `{"result":{"items":[{"name":"sub","type":"folder","fileId":"SUB"}],"nextToken":""}}`, nil
default:
return "", errTestList // 递归进入子目录后失败
}
}}
if err := runDriveCmd(t, caller, "push", "--local-folder", dir, "--remote-folder", "ROOT"); err == nil {
t.Fatal("expected the nested list_files failure to propagate")
}
}
// push 的远端索引跳过非 file 类型(在线文档/快捷方式),不把它们当成可覆盖的既有文件。
func TestCrossPlatformCoverageDrivePush_remoteNonFileEntriesAreSkipped(t *testing.T) {
caller := &driveScriptCaller{reply: func(tool string, args map[string]any, _ int) (string, error) {
if tool != "list_files" {
return `{"result":{},"success":true}`, nil
}
if args["parentId"] == "ROOT" {
return `{"result":{"items":[` +
`{"name":"online.adoc","type":"document","fileId":"D1"},` +
`{"name":"link","type":"shortcut","fileId":"S1"},` +
`{"name":"real.txt","type":"file","fileId":"F1"}` +
`],"nextToken":""}}`, nil
}
return `{"result":{"items":[],"nextToken":""}}`, nil
}}
testseam.Swap(t, &deps, &Deps{Caller: caller, Out: &Formatter{w: io.Discard}})
testseam.Swap(t, &os.Args, []string{"dws", "drive"})
files, _, err := fetchRemoteTreeForPush(context.Background(), "", "ROOT")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if _, ok := files["real.txt"]; !ok {
t.Error("regular file must be indexed")
}
for _, skipped := range []string{"online.adoc", "link"} {
if _, ok := files[skipped]; ok {
t.Errorf("non-file entry %q must not be indexed", skipped)
}
}
}
// list_files 是远端权威树的数据来源;缺失 result 不能伪装成空目录。
func TestCrossPlatformCoverageParseDriveList_missingResultFailsClosed(t *testing.T) {
if _, _, err := parseDriveList(`{"success":true}`); err == nil || !strings.Contains(err.Error(), "缺少 result") {
t.Fatalf("parseDriveList error = %v, want missing-result failure", err)
}
}
// push 遍历远端时返回体无法解析 → 解析错误如实上抛(与调用失败是不同分支)。
func TestCrossPlatformCoverageDrivePush_remoteListParseFailurePropagates(t *testing.T) {
dir := t.TempDir()
mustWrite(t, filepath.Join(dir, "a.txt"), "x")
withNoopPut(t)
caller := &driveScriptCaller{reply: func(tool string, _ map[string]any, _ int) (string, error) {
if tool != "list_files" {
return `{"result":{},"success":true}`, nil
}
return `{"result":"not-a-list"}`, nil // 既不是 {items:[]} 也不是数组
}}
err := runDriveCmd(t, caller, "push", "--local-folder", dir, "--remote-folder", "ROOT")
if err == nil || !strings.Contains(err.Error(), "list_files") {
t.Fatalf("expected a list_files parse error, got %v", err)
}
}