返回 DeepSeek-Reasonix
session_workspace_sidebar_test.go
根目录 / desktop / session_workspace_sidebar_test.go
1 package main
2
3 import (
4 "os"
5 "path/filepath"
6 "testing"
7
8 "reasonix/desktop/internal/workspacestate"
9 )
10
11 func TestRemoveWorkspaceDropsVisibleTabsAndPersistedEntries(t *testing.T) {
12 isolateDesktopUserDirs(t)
13 projectRoot := t.TempDir()
14 if err := addProject(projectRoot, "Project"); err != nil {
15 t.Fatalf("add project: %v", err)
16 }
17 app := &App{
18 tabs: map[string]*WorkspaceTab{
19 "project": {ID: "project", Scope: "project", WorkspaceRoot: projectRoot, TopicID: "topic-project", Ready: true, disabledMCP: map[string]ServerView{}},
20 "global": {ID: "global", Scope: "global", WorkspaceRoot: globalTabWorkspaceRoot(), TopicID: "topic-global", Ready: true, disabledMCP: map[string]ServerView{}},
21 },
22 tabOrder: []string{"project", "global"},
23 activeTabID: "project",
24 detachedSessions: map[string]*WorkspaceTab{},
25 }
26 if err := app.workspaceRegistry().EnsureWorkspace(t.Context(), workspacestate.Workspace{
27 ID: "preserved-owner", Root: projectRoot, Title: "Project", Visible: true,
28 }); err != nil {
29 t.Fatal(err)
30 }
31 app.mu.Lock()
32 app.saveTabsLocked()
33 app.mu.Unlock()
34
35 if err := app.RemoveWorkspace(projectRoot); err != nil {
36 t.Fatalf("RemoveWorkspace: %v", err)
37 }
38 assertTabIDs(t, app.ListTabs(), "global")
39 if got := app.ListWorkspaces(); len(got) != 0 {
40 t.Fatalf("workspaces after remove = %+v, want none", got)
41 }
42 if got := loadTabsFile(); len(got.Tabs) != 1 || got.Tabs[0].ID != "global" {
43 t.Fatalf("persisted tabs after workspace remove = %+v, want only global", got)
44 }
45 state, err := app.workspaceRegistry().Load(t.Context())
46 if err != nil {
47 t.Fatal(err)
48 }
49 if state.Workspaces["preserved-owner"].Visible {
50 t.Fatal("removed physical workspace remained visible in the authoritative registry")
51 }
52 }
53
54 func TestRemoveWorkspaceKeepsProjectAndTabsWhenProjectFileWriteFails(t *testing.T) {
55 isolateDesktopUserDirs(t)
56 projectRoot := t.TempDir()
57 if err := addProject(projectRoot, "Project"); err != nil {
58 t.Fatal(err)
59 }
60 app := &App{
61 tabs: map[string]*WorkspaceTab{
62 "project": {ID: "project", Scope: "project", WorkspaceRoot: projectRoot, Ready: true, disabledMCP: map[string]ServerView{}},
63 "global": {ID: "global", Scope: "global", WorkspaceRoot: globalTabWorkspaceRoot(), Ready: true, disabledMCP: map[string]ServerView{}},
64 },
65 tabOrder: []string{"project", "global"}, activeTabID: "project",
66 detachedSessions: map[string]*WorkspaceTab{},
67 }
68 if err := app.workspaceRegistry().EnsureWorkspace(t.Context(), workspacestate.Workspace{
69 ID: "project-owner", Root: projectRoot, Title: "Project", Visible: true,
70 }); err != nil {
71 t.Fatal(err)
72 }
73 tmpPath := filepath.Join(desktopConfigDir(), desktopProjectsFile+".tmp")
74 if err := os.Mkdir(tmpPath, 0o755); err != nil {
75 t.Fatal(err)
76 }
77 if err := app.RemoveWorkspace(projectRoot); err == nil {
78 t.Fatal("RemoveWorkspace succeeded despite project file write failure")
79 }
80 assertTabIDs(t, app.ListTabs(), "project", "global")
81 if got := app.ListWorkspaces(); len(got) != 1 || !sameProjectRoot(got[0].Path, projectRoot) {
82 t.Fatalf("project file changed after failed removal: %+v", got)
83 }
84 state, err := app.workspaceRegistry().Load(t.Context())
85 if err != nil {
86 t.Fatal(err)
87 }
88 if !state.Workspaces["project-owner"].Visible {
89 t.Fatal("project was hidden after removal failed")
90 }
91 if err := os.Remove(tmpPath); err != nil {
92 t.Fatal(err)
93 }
94 if err := app.RemoveWorkspace(projectRoot); err != nil {
95 t.Fatalf("retry RemoveWorkspace: %v", err)
96 }
97 }
98
99 func TestMergeCanonicalWorkspaceShellsUsesPersistedPhysicalOwner(t *testing.T) {
100 isolateDesktopUserDirs(t)
101 app := NewApp()
102 app.ctx = t.Context()
103 root := t.TempDir()
104
105 if err := app.workspaceRegistry().EnsureWorkspace(t.Context(), workspacestate.Workspace{
106 ID: "preserved-owner", Root: root, Title: "新建文件夹", Visible: true,
107 }); err != nil {
108 t.Fatal(err)
109 }
110
111 legacy := ProjectNode{Key: "project_" + root, Kind: "project", Root: root, Label: "Projects"}
112 got := app.mergeCanonicalWorkspaceShells([]ProjectNode{legacy})
113 if len(got) != 1 {
114 t.Fatalf("one physical workspace rendered %d sidebar nodes: %+v", len(got), got)
115 }
116 if got[0].Key != legacy.Key || got[0].Label != legacy.Label {
117 t.Fatalf("legacy presentation was replaced: got=%+v want=%+v", got[0], legacy)
118 }
119 }
120
121 func TestMergeCanonicalWorkspaceShellsHonorsPersistedOwnerVisibility(t *testing.T) {
122 isolateDesktopUserDirs(t)
123 app := NewApp()
124 app.ctx = t.Context()
125 root := t.TempDir()
126
127 if err := app.workspaceRegistry().EnsureWorkspace(t.Context(), workspacestate.Workspace{
128 ID: "preserved-owner", Root: root, Title: "Hidden", Visible: false,
129 }); err != nil {
130 t.Fatal(err)
131 }
132
133 legacy := ProjectNode{Key: "project_" + root, Kind: "project", Root: root, Label: "Projects"}
134 if got := app.mergeCanonicalWorkspaceShells([]ProjectNode{legacy}); len(got) != 0 {
135 t.Fatalf("hidden physical workspace remained visible: %+v", got)
136 }
137 }
138
138 lines GO