package cursor import ( "database/sql" "encoding/json" "os" "path/filepath" "testing" _ "modernc.org/sqlite" ) func TestProjectPathFromURI(t *testing.T) { cases := []struct { name string uri string want string }{ {"windows 盘符", "file:///d:/Project/x", "d:/Project/x"}, {"编码盘符", "file:///d%3A/Project/x", "d:/Project/x"}, {"带空格编码", "file:///d:/My%20Projects/x", "d:/My Projects/x"}, {"posix 路径", "file:///home/user/x", "/home/user/x"}, {"非 file URI", "vscode-remote://ssh-remote/home/x", ""}, {"普通路径", "d:/Project/x", ""}, {"空串", "", ""}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { if got := projectPathFromURI(tc.uri); got != tc.want { t.Fatalf("projectPathFromURI(%q) = %q, want %q", tc.uri, got, tc.want) } }) } } // createStateDB 在 userDir/globalStorage 下创建含最近打开列表的 state.vscdb。 func createStateDB(t *testing.T, userDir string, uris []string) { t.Helper() if err := os.MkdirAll(filepath.Join(userDir, "globalStorage"), 0o755); err != nil { t.Fatal(err) } db, err := sql.Open("sqlite", filepath.Join(userDir, "globalStorage", "state.vscdb")) if err != nil { t.Fatal(err) } defer db.Close() if _, err := db.Exec("CREATE TABLE ItemTable (key TEXT UNIQUE, value TEXT)"); err != nil { t.Fatal(err) } entries := make([]map[string]string, 0, len(uris)) for _, uri := range uris { entries = append(entries, map[string]string{"folderUri": uri}) } raw, _ := json.Marshal(map[string]any{"entries": entries}) if _, err := db.Exec( "INSERT INTO ItemTable (key, value) VALUES ('history.recentlyOpenedPathsList', ?)", string(raw), ); err != nil { t.Fatal(err) } } func readRecentlyOpened(t *testing.T, userDir string) []string { t.Helper() db, err := sql.Open("sqlite", filepath.Join(userDir, "globalStorage", "state.vscdb")) if err != nil { t.Fatal(err) } defer db.Close() var raw string if err := db.QueryRow( "SELECT value FROM ItemTable WHERE key = 'history.recentlyOpenedPathsList'", ).Scan(&raw); err != nil { t.Fatal(err) } var payload struct { Entries []struct { FolderURI string `json:"folderUri"` } `json:"entries"` } if err := json.Unmarshal([]byte(raw), &payload); err != nil { t.Fatal(err) } result := make([]string, 0, len(payload.Entries)) for _, item := range payload.Entries { result = append(result, item.FolderURI) } return result } func TestRemoveRecentlyOpenedEntry(t *testing.T) { t.Run("命中条目被移除", func(t *testing.T) { userDir := t.TempDir() createStateDB(t, userDir, []string{"file:///d:/Proj/A", "file:///d:/Proj/B"}) removed, err := removeRecentlyOpenedEntry(userDir, "d:/Proj/A") if err != nil { t.Fatal(err) } if removed != 1 { t.Fatalf("removed = %d, want 1", removed) } remaining := readRecentlyOpened(t, userDir) if len(remaining) != 1 || remaining[0] != "file:///d:/Proj/B" { t.Fatalf("remaining = %v, want [file:///d:/Proj/B]", remaining) } }) t.Run("未命中不写库", func(t *testing.T) { userDir := t.TempDir() createStateDB(t, userDir, []string{"file:///d:/Proj/A"}) removed, err := removeRecentlyOpenedEntry(userDir, "d:/Proj/Other") if err != nil { t.Fatal(err) } if removed != 0 { t.Fatalf("removed = %d, want 0", removed) } if got := readRecentlyOpened(t, userDir); len(got) != 1 { t.Fatalf("remaining = %v, want 1 entry", got) } }) t.Run("缺失数据库返回零值无错误", func(t *testing.T) { removed, err := removeRecentlyOpenedEntry(t.TempDir(), "d:/Proj/A") if err != nil { t.Fatalf("unexpected error: %v", err) } if removed != 0 { t.Fatalf("removed = %d, want 0", removed) } }) t.Run("损坏数据库返回错误", func(t *testing.T) { userDir := t.TempDir() if err := os.MkdirAll(filepath.Join(userDir, "globalStorage"), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile( filepath.Join(userDir, "globalStorage", "state.vscdb"), []byte("not a db"), 0o644, ); err != nil { t.Fatal(err) } if _, err := removeRecentlyOpenedEntry(userDir, "d:/Proj/A"); err == nil { t.Fatal("want error for corrupt db, got nil") } }) } func TestRemoveWorkspaceStorageEntries(t *testing.T) { t.Run("命中目录被整目录删除", func(t *testing.T) { userDir := t.TempDir() target := filepath.Join(userDir, "workspaceStorage", "hash-a") other := filepath.Join(userDir, "workspaceStorage", "hash-b") for dir, folder := range map[string]string{ target: "file:///d:/Proj/A", other: "file:///d:/Proj/B", } { if err := os.MkdirAll(dir, 0o755); err != nil { t.Fatal(err) } raw, _ := json.Marshal(map[string]string{"folder": folder}) if err := os.WriteFile(filepath.Join(dir, "workspace.json"), raw, 0o644); err != nil { t.Fatal(err) } } removed, err := removeWorkspaceStorageEntries(userDir, "d:/Proj/A") if err != nil { t.Fatal(err) } if removed != 1 { t.Fatalf("removed = %d, want 1", removed) } if _, err := os.Stat(target); !os.IsNotExist(err) { t.Fatalf("target dir should be removed, stat err = %v", err) } if _, err := os.Stat(other); err != nil { t.Fatalf("other dir should remain: %v", err) } }) t.Run("缺失 workspaceStorage 返回零值无错误", func(t *testing.T) { removed, err := removeWorkspaceStorageEntries(t.TempDir(), "d:/Proj/A") if err != nil { t.Fatalf("unexpected error: %v", err) } if removed != 0 { t.Fatalf("removed = %d, want 0", removed) } }) }