The platform coverage gate runs only TestAllShortcuts and TestCrossPlatformCoverage*, so several changed statements had no platform test exercising them: - drive_pull.go: the smart-policy re-check that skips publication when the target is refreshed in place (same inode) while the download is running. - drive_pull.go: the post-publish verifyParent failure, where the result is already on disk and must not be rolled back. - drive_replace_unix.go: rename(2) replacement of an existing target; the Windows side already had the symmetric test. - drive_status_windows.go: the filepath.Clean rewrite guard had no input reaching it, because isSafeRemoteSegment filters separators upstream. macOS changed-code coverage: 99.8053% -> 100.0000% (1541 statements).
237 lines
10 KiB
Go
237 lines
10 KiB
Go
package helpers
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/testseam"
|
|
)
|
|
|
|
// forceCaseInsensitiveFS 在当前用例内把大小写探测钉成不敏感,使等价路径冲突分支
|
|
// 在大小写敏感的 CI 文件系统(ext4)上同样可达。
|
|
func forceCaseInsensitiveFS(t *testing.T) {
|
|
t.Helper()
|
|
testseam.Swap(t, &isCaseInsensitiveFS, func(string) bool { return true })
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// 等价路径冲突:pull / sync 都必须全部记 failed 且一个都不落盘
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
// 远端 A.txt 与 a.txt 在大小写不敏感目标上映射到同一本地文件 → 两项都 failed,
|
|
// 绝不顺序覆盖导致静默丢文件。
|
|
func TestCrossPlatformCoverageDrivePull_equivalentPathCollisionFailsBoth(t *testing.T) {
|
|
forceCaseInsensitiveFS(t)
|
|
root := t.TempDir()
|
|
|
|
caller := pullListingCaller(
|
|
`{"name":"A.txt","type":"file","fileId":"UP","modifyTime":1},` +
|
|
`{"name":"a.txt","type":"file","fileId":"LOW","modifyTime":2}`)
|
|
swapPullDownloadPath(t, func(context.Context, string, map[string]string, string) error {
|
|
t.Error("collided entries must not be downloaded")
|
|
return nil
|
|
})
|
|
|
|
err := runDriveCmd(t, caller, "pull", "--local-folder", root, "--remote-folder", "ROOT")
|
|
var pf *drivePartialFailure
|
|
if !errors.As(err, &pf) {
|
|
t.Fatalf("expected drivePartialFailure, got %T %v", err, err)
|
|
}
|
|
for _, name := range []string{"A.txt", "a.txt"} {
|
|
if _, statErr := os.Stat(filepath.Join(root, name)); !os.IsNotExist(statErr) {
|
|
t.Errorf("%s must not be written on collision", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// sync 的 new_remote 阶段同样拒绝等价冲突项。
|
|
func TestCrossPlatformCoverageDriveSync_equivalentPathCollisionFailsBoth(t *testing.T) {
|
|
forceCaseInsensitiveFS(t)
|
|
root := t.TempDir()
|
|
withSyncTransport(t, "remote")
|
|
|
|
caller := syncCaller(map[string]string{
|
|
"ROOT": `{"result":{"items":[` +
|
|
`{"name":"A.txt","type":"file","fileId":"UP","modifyTime":1},` +
|
|
`{"name":"a.txt","type":"file","fileId":"LOW","modifyTime":2}` +
|
|
`],"nextToken":""}}`,
|
|
})
|
|
err := runDriveCmd(t, caller, "sync", "--local-folder", root, "--remote-folder", "ROOT", "--quick")
|
|
var sf *driveSyncFailure
|
|
if !errors.As(err, &sf) {
|
|
t.Fatalf("expected driveSyncFailure, got %T %v", err, err)
|
|
}
|
|
if sf.failed != 2 {
|
|
t.Errorf("failed = %d, want 2 (both collided entries)", sf.failed)
|
|
}
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// detectCaseInsensitiveFS:探针名无大小写差异时回退平台默认
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
func TestCrossPlatformCoverageDetectCaseInsensitiveFS_caselessProbeFallsBackToPlatformDefault(t *testing.T) {
|
|
// 纯数字模板:ToUpper 与原名相同,无法据此判定。
|
|
testseam.Swap(t, &caseProbePattern, "1234567890*")
|
|
|
|
dir := t.TempDir()
|
|
got := detectCaseInsensitiveFS(dir)
|
|
// 回退值即平台默认;这里只断言它与平台默认一致,不写死具体布尔。
|
|
want := runtime.GOOS == "windows" || runtime.GOOS == "darwin"
|
|
if got != want {
|
|
t.Errorf("detectCaseInsensitiveFS = %v, want platform default %v", got, want)
|
|
}
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// isSafeRemoteSegmentPlatform:非 Windows 平台无额外约束
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
func TestCrossPlatformCoverageIsSafeRemoteSegmentPlatform_allowsPlainNames(t *testing.T) {
|
|
for _, name := range []string{"a.txt", "报告.pdf", "with space.md"} {
|
|
if !isSafeRemoteSegmentPlatform(name) {
|
|
t.Errorf("isSafeRemoteSegmentPlatform(%q) = false, want true", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageIsSafeRemoteSegmentPlatform_rejectsNonCanonicalWindowsName(t *testing.T) {
|
|
if runtime.GOOS != "windows" {
|
|
return
|
|
}
|
|
for _, name := range []string{
|
|
`C:relative`, `a?.txt`, `a*.txt`, `a:stream`, `a<.txt`, `a>.txt`, `a|.txt`, `a".txt`,
|
|
"name.", "name ", "...", "CON", "con.txt", "PRN", "AUX", "NUL", "COM1", "LPT9", "COM¹", "CONIN$",
|
|
// 调用方 isSafeRemoteSegment 已先过滤分隔符,所以只有直接调用才会走到
|
|
// filepath.Clean 改写这条防御分支;平台函数本身仍必须 fail closed。
|
|
`a/b`, `.\a`,
|
|
} {
|
|
if isSafeRemoteSegmentPlatform(name) {
|
|
t.Errorf("Windows unsafe segment %q must be rejected", name)
|
|
}
|
|
}
|
|
for _, name := range []string{"report.txt", "报告 2026.pdf", "COM10", "LPT0"} {
|
|
if !isSafeRemoteSegmentPlatform(name) {
|
|
t.Errorf("Windows ordinary segment %q must be accepted", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ──────────────────────────────────────────────────────────
|
|
// WalkDir 单条目处理:Info() 与 filepath.Rel 的失败分支
|
|
// ──────────────────────────────────────────────────────────
|
|
|
|
// errDirEntry 是一个 Info() 必然报错的 fs.DirEntry。
|
|
type errDirEntry struct{ dir bool }
|
|
|
|
func (e errDirEntry) Name() string { return "entry" }
|
|
func (e errDirEntry) IsDir() bool { return e.dir }
|
|
func (e errDirEntry) Type() fs.FileMode { return 0 }
|
|
func (e errDirEntry) Info() (fs.FileInfo, error) { return nil, errTestInfo }
|
|
|
|
var errTestInfo = errors.New("simulated DirEntry.Info failure")
|
|
|
|
// irregularDirEntry 的 Info() 成功,但报告为非常规文件(如设备文件)。
|
|
type irregularDirEntry struct{}
|
|
|
|
func (irregularDirEntry) Name() string { return "dev" }
|
|
func (irregularDirEntry) IsDir() bool { return false }
|
|
func (irregularDirEntry) Type() fs.FileMode { return fs.ModeDevice }
|
|
func (irregularDirEntry) Info() (fs.FileInfo, error) { return irregularFileInfo{}, nil }
|
|
|
|
type irregularFileInfo struct{}
|
|
|
|
func (irregularFileInfo) Name() string { return "dev" }
|
|
func (irregularFileInfo) Size() int64 { return 0 }
|
|
func (irregularFileInfo) Mode() fs.FileMode { return fs.ModeDevice }
|
|
func (irregularFileInfo) ModTime() time.Time { return time.Unix(0, 0) }
|
|
func (irregularFileInfo) IsDir() bool { return false }
|
|
func (irregularFileInfo) Sys() any { return nil }
|
|
|
|
func TestCrossPlatformCoverageWalkLocalTreeEntry_errorBranches(t *testing.T) {
|
|
files := map[string]*localFile{}
|
|
|
|
// WalkDir 自身报错原样上抛。
|
|
if err := walkLocalTreeEntry("/root", "/root/a", errDirEntry{}, errTestInfo, files); !errors.Is(err, errTestInfo) {
|
|
t.Errorf("incoming error must propagate, got %v", err)
|
|
}
|
|
// 目录条目直接跳过。
|
|
if err := walkLocalTreeEntry("/root", "/root/sub", errDirEntry{dir: true}, nil, files); err != nil {
|
|
t.Errorf("directory entry must be skipped, got %v", err)
|
|
}
|
|
// Info() 失败上抛。
|
|
if err := walkLocalTreeEntry("/root", "/root/a", errDirEntry{}, nil, files); !errors.Is(err, errTestInfo) {
|
|
t.Errorf("Info() error must propagate, got %v", err)
|
|
}
|
|
// 非常规文件忽略。
|
|
if err := walkLocalTreeEntry("/root", "/root/dev", irregularDirEntry{}, nil, files); err != nil {
|
|
t.Errorf("irregular entry must be skipped, got %v", err)
|
|
}
|
|
// filepath.Rel 失败(root 绝对、path 相对)上抛。
|
|
if err := walkLocalTreeEntry("/root", "relative/path", regularDirEntry{}, nil, files); err == nil {
|
|
t.Error("filepath.Rel error must propagate")
|
|
}
|
|
if len(files) != 0 {
|
|
t.Errorf("no entry should have been indexed, got %v", files)
|
|
}
|
|
}
|
|
|
|
// regularDirEntry 的 Info() 返回一个常规文件,用于走到 filepath.Rel。
|
|
type regularDirEntry struct{}
|
|
|
|
func (regularDirEntry) Name() string { return "a" }
|
|
func (regularDirEntry) IsDir() bool { return false }
|
|
func (regularDirEntry) Type() fs.FileMode { return 0 }
|
|
func (regularDirEntry) Info() (fs.FileInfo, error) { return regularFileInfo{}, nil }
|
|
|
|
type regularFileInfo struct{}
|
|
|
|
func (regularFileInfo) Name() string { return "a" }
|
|
func (regularFileInfo) Size() int64 { return 1 }
|
|
func (regularFileInfo) Mode() fs.FileMode { return 0o644 }
|
|
func (regularFileInfo) ModTime() time.Time { return time.Unix(1, 0) }
|
|
func (regularFileInfo) IsDir() bool { return false }
|
|
func (regularFileInfo) Sys() any { return nil }
|
|
|
|
func TestCrossPlatformCoverageWalkLocalForPushEntry_errorBranches(t *testing.T) {
|
|
var dirs []string
|
|
var files []localPushFile
|
|
|
|
// WalkDir 自身报错原样上抛。
|
|
if err := walkLocalForPushEntry("/root", "/root/a", regularDirEntry{}, errTestInfo, &dirs, &files); !errors.Is(err, errTestInfo) {
|
|
t.Errorf("incoming error must propagate, got %v", err)
|
|
}
|
|
// filepath.Rel 失败上抛。
|
|
if err := walkLocalForPushEntry("/root", "relative/path", regularDirEntry{}, nil, &dirs, &files); err == nil {
|
|
t.Error("filepath.Rel error must propagate")
|
|
}
|
|
// 根目录本身跳过。
|
|
if err := walkLocalForPushEntry("/root", "/root", regularDirEntry{}, nil, &dirs, &files); err != nil {
|
|
t.Errorf("root itself must be skipped, got %v", err)
|
|
}
|
|
// Info() 失败上抛。
|
|
if err := walkLocalForPushEntry("/root", "/root/a", errDirEntry{}, nil, &dirs, &files); !errors.Is(err, errTestInfo) {
|
|
t.Errorf("Info() error must propagate, got %v", err)
|
|
}
|
|
// 非常规文件忽略。
|
|
if err := walkLocalForPushEntry("/root", "/root/dev", irregularDirEntry{}, nil, &dirs, &files); err != nil {
|
|
t.Errorf("irregular entry must be skipped, got %v", err)
|
|
}
|
|
// 目录条目进 dirs。
|
|
if err := walkLocalForPushEntry("/root", "/root/sub", errDirEntry{dir: true}, nil, &dirs, &files); err != nil {
|
|
t.Errorf("directory entry must be recorded, got %v", err)
|
|
}
|
|
if len(dirs) != 1 || dirs[0] != "sub" {
|
|
t.Errorf("dirs = %v, want [sub]", dirs)
|
|
}
|
|
if len(files) != 0 {
|
|
t.Errorf("files = %v, want empty", files)
|
|
}
|
|
}
|