1
0
mirror of https://github.com/tw93/Mole.git synced 2026-03-22 23:40:09 +00:00
Files
Mole/cmd/analyze/delete_test.go
Tw93 0d2f217f28 security: add regression tests for validatePath with special chars
- Add TestValidatePath covering Chinese, emoji, and special characters
- Add TestValidatePathWithChineseAndSpecialChars for filesystem tests
- Fix validatePath to detect .. components without rejecting valid paths

Ensures paths with $, ;, :, emoji, Chinese chars are not rejected
while still blocking path traversal attempts.
2026-03-14 08:26:45 +08:00

165 lines
4.6 KiB
Go

//go:build darwin
package main
import (
"os"
"path/filepath"
"testing"
)
func TestTrashPathWithProgress(t *testing.T) {
skipIfFinderUnavailable(t)
parent := t.TempDir()
target := filepath.Join(parent, "target")
if err := os.MkdirAll(target, 0o755); err != nil {
t.Fatalf("create target: %v", err)
}
files := []string{
filepath.Join(target, "one.txt"),
filepath.Join(target, "two.txt"),
}
for _, f := range files {
if err := os.WriteFile(f, []byte("content"), 0o644); err != nil {
t.Fatalf("write %s: %v", f, err)
}
}
var counter int64
count, err := trashPathWithProgress(target, &counter)
if err != nil {
t.Fatalf("trashPathWithProgress returned error: %v", err)
}
if count != int64(len(files)) {
t.Fatalf("expected %d files trashed, got %d", len(files), count)
}
if _, err := os.Stat(target); !os.IsNotExist(err) {
t.Fatalf("expected target to be moved to Trash, stat err=%v", err)
}
}
func TestDeleteMultiplePathsCmdHandlesParentChild(t *testing.T) {
skipIfFinderUnavailable(t)
base := t.TempDir()
parent := filepath.Join(base, "parent")
child := filepath.Join(parent, "child")
// Structure: parent/fileA, parent/child/fileC.
if err := os.MkdirAll(child, 0o755); err != nil {
t.Fatalf("mkdir: %v", err)
}
if err := os.WriteFile(filepath.Join(parent, "fileA"), []byte("a"), 0o644); err != nil {
t.Fatalf("write fileA: %v", err)
}
if err := os.WriteFile(filepath.Join(child, "fileC"), []byte("c"), 0o644); err != nil {
t.Fatalf("write fileC: %v", err)
}
var counter int64
msg := deleteMultiplePathsCmd([]string{parent, child}, &counter)()
progress, ok := msg.(deleteProgressMsg)
if !ok {
t.Fatalf("expected deleteProgressMsg, got %T", msg)
}
if progress.err != nil {
t.Fatalf("unexpected error: %v", progress.err)
}
if progress.count != 2 {
t.Fatalf("expected 2 files trashed, got %d", progress.count)
}
if _, err := os.Stat(parent); !os.IsNotExist(err) {
t.Fatalf("expected parent to be moved to Trash, err=%v", err)
}
}
func TestMoveToTrashNonExistent(t *testing.T) {
err := moveToTrash("/nonexistent/path/that/does/not/exist")
if err == nil {
t.Fatal("expected error for non-existent path")
}
}
func TestValidatePath(t *testing.T) {
tests := []struct {
name string
path string
wantErr bool
}{
// 基本合法路径
{"absolute path", "/Users/test/file.txt", false},
{"path with spaces", "/Users/test/My Documents/file.txt", false},
{"root", "/", false},
// 中文路径
{"chinese path", "/Users/test/中文文件夹/文件.txt", false},
{"chinese mixed", "/Users/test/Downloads/报告2024.pdf", false},
// Emoji 路径
{"emoji path", "/Users/test/📁文件夹/📝笔记.txt", false},
{"emoji only", "/Users/test/🎉/🎊.txt", false},
// 特殊字符路径 (之前被错误拒绝的)
{"dollar sign", "/Users/test/$HOME/workspace", false},
{"semicolon", "/Users/test/project;v2", false},
{"colon", "/Users/test/project:2024", false},
{"ampersand", "/Users/test/R&D/project", false},
{"at sign", "/Users/test/user@domain", false},
{"hash", "/Users/test/project#123", false},
{"percent", "/Users/test/100% complete", false},
{"exclamation", "/Users/test/important!.txt", false},
{"single quote", "/Users/test/user's files", false},
{"equals", "/Users/test/key=value", false},
{"plus", "/Users/test/file+v2", false},
{"brackets", "/Users/test/[2024] report", false},
{"parentheses", "/Users/test/project (copy)", false},
{"comma", "/Users/test/file, backup", false},
// 非法路径
{"empty", "", true},
{"relative", "relative/path", true},
{"relative dot", "./file.txt", true},
{"null byte", "/Users/test\x00/file", true},
{"path traversal", "/Users/test/../../../etc", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validatePath(tt.path)
if (err != nil) != tt.wantErr {
t.Errorf("validatePath(%q) error = %v, wantErr %v", tt.path, err, tt.wantErr)
}
})
}
}
func TestValidatePathWithChineseAndSpecialChars(t *testing.T) {
// 专门测试之前会导致兼容性回退的路径
parent := t.TempDir()
testCases := []struct {
name string
path string
}{
{"chinese", "中文文件夹"},
{"emoji", "📁 文档"},
{"mixed", "报告-2024_v2 (终稿) [已审核]"},
{"special", "Project$2024; Q1: R&D"},
{"complex", "用户@公司 100% 完成!"},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fullPath := filepath.Join(parent, tc.path)
if err := os.MkdirAll(fullPath, 0o755); err != nil {
t.Fatalf("mkdir %q: %v", tc.path, err)
}
if err := validatePath(fullPath); err != nil {
t.Errorf("validatePath rejected valid path %q: %v", tc.path, err)
}
})
}
}