@@ -0,0 +1,180 @@
1+package projects
2+
3+import (
4+ "path/filepath"
5+ "testing"
6+ "time"
7+)
8+
9+func TestRegisterAndList(t *testing.T) {
10+ // Create a temporary directory for the test
11+ tmpDir := t.TempDir()
12+
13+ // Override the projects file path for testing
14+ t.Setenv("XDG_DATA_HOME", tmpDir)
15+
16+ // Test registering a project
17+ err := Register("/home/user/project1", "/home/user/project1/.crush")
18+ if err != nil {
19+ t.Fatalf("Register failed: %v", err)
20+ }
21+
22+ // List projects
23+ projects, err := List()
24+ if err != nil {
25+ t.Fatalf("List failed: %v", err)
26+ }
27+
28+ if len(projects) != 1 {
29+ t.Fatalf("Expected 1 project, got %d", len(projects))
30+ }
31+
32+ if projects[0].Path != "/home/user/project1" {
33+ t.Errorf("Expected path /home/user/project1, got %s", projects[0].Path)
34+ }
35+
36+ if projects[0].DataDir != "/home/user/project1/.crush" {
37+ t.Errorf("Expected data_dir /home/user/project1/.crush, got %s", projects[0].DataDir)
38+ }
39+
40+ // Register another project
41+ err = Register("/home/user/project2", "/home/user/project2/.crush")
42+ if err != nil {
43+ t.Fatalf("Register failed: %v", err)
44+ }
45+
46+ projects, err = List()
47+ if err != nil {
48+ t.Fatalf("List failed: %v", err)
49+ }
50+
51+ if len(projects) != 2 {
52+ t.Fatalf("Expected 2 projects, got %d", len(projects))
53+ }
54+
55+ // Most recent should be first
56+ if projects[0].Path != "/home/user/project2" {
57+ t.Errorf("Expected most recent project first, got %s", projects[0].Path)
58+ }
59+}
60+
61+func TestRegisterUpdatesExisting(t *testing.T) {
62+ tmpDir := t.TempDir()
63+ t.Setenv("XDG_DATA_HOME", tmpDir)
64+
65+ // Register a project
66+ err := Register("/home/user/project1", "/home/user/project1/.crush")
67+ if err != nil {
68+ t.Fatalf("Register failed: %v", err)
69+ }
70+
71+ projects, _ := List()
72+ firstAccess := projects[0].LastAccessed
73+
74+ // Wait a bit and re-register
75+ time.Sleep(10 * time.Millisecond)
76+
77+ err = Register("/home/user/project1", "/home/user/project1/.crush-new")
78+ if err != nil {
79+ t.Fatalf("Register failed: %v", err)
80+ }
81+
82+ projects, _ = List()
83+
84+ if len(projects) != 1 {
85+ t.Fatalf("Expected 1 project after update, got %d", len(projects))
86+ }
87+
88+ if projects[0].DataDir != "/home/user/project1/.crush-new" {
89+ t.Errorf("Expected updated data_dir, got %s", projects[0].DataDir)
90+ }
91+
92+ if !projects[0].LastAccessed.After(firstAccess) {
93+ t.Error("Expected LastAccessed to be updated")
94+ }
95+}
96+
97+func TestLoadEmptyFile(t *testing.T) {
98+ tmpDir := t.TempDir()
99+ t.Setenv("XDG_DATA_HOME", tmpDir)
100+
101+ // List before any projects exist
102+ projects, err := List()
103+ if err != nil {
104+ t.Fatalf("List failed: %v", err)
105+ }
106+
107+ if len(projects) != 0 {
108+ t.Errorf("Expected 0 projects, got %d", len(projects))
109+ }
110+}
111+
112+func TestProjectsFilePath(t *testing.T) {
113+ tmpDir := t.TempDir()
114+ t.Setenv("XDG_DATA_HOME", tmpDir)
115+
116+ expected := filepath.Join(tmpDir, "crush", "projects.json")
117+ actual := projectsFilePath()
118+
119+ if actual != expected {
120+ t.Errorf("Expected %s, got %s", expected, actual)
121+ }
122+}
123+
124+func TestRegisterWithParentDataDir(t *testing.T) {
125+ tmpDir := t.TempDir()
126+ t.Setenv("XDG_DATA_HOME", tmpDir)
127+
128+ // Register a project where .crush is in a parent directory.
129+ // e.g., working in /home/user/monorepo/packages/app but .crush is at /home/user/monorepo/.crush
130+ err := Register("/home/user/monorepo/packages/app", "/home/user/monorepo/.crush")
131+ if err != nil {
132+ t.Fatalf("Register failed: %v", err)
133+ }
134+
135+ projects, err := List()
136+ if err != nil {
137+ t.Fatalf("List failed: %v", err)
138+ }
139+
140+ if len(projects) != 1 {
141+ t.Fatalf("Expected 1 project, got %d", len(projects))
142+ }
143+
144+ if projects[0].Path != "/home/user/monorepo/packages/app" {
145+ t.Errorf("Expected path /home/user/monorepo/packages/app, got %s", projects[0].Path)
146+ }
147+
148+ if projects[0].DataDir != "/home/user/monorepo/.crush" {
149+ t.Errorf("Expected data_dir /home/user/monorepo/.crush, got %s", projects[0].DataDir)
150+ }
151+}
152+
153+func TestRegisterWithExternalDataDir(t *testing.T) {
154+ tmpDir := t.TempDir()
155+ t.Setenv("XDG_DATA_HOME", tmpDir)
156+
157+ // Register a project where .crush is in a completely different location.
158+ // e.g., project at /home/user/project but data stored at /var/data/crush/myproject
159+ err := Register("/home/user/project", "/var/data/crush/myproject")
160+ if err != nil {
161+ t.Fatalf("Register failed: %v", err)
162+ }
163+
164+ projects, err := List()
165+ if err != nil {
166+ t.Fatalf("List failed: %v", err)
167+ }
168+
169+ if len(projects) != 1 {
170+ t.Fatalf("Expected 1 project, got %d", len(projects))
171+ }
172+
173+ if projects[0].Path != "/home/user/project" {
174+ t.Errorf("Expected path /home/user/project, got %s", projects[0].Path)
175+ }
176+
177+ if projects[0].DataDir != "/var/data/crush/myproject" {
178+ t.Errorf("Expected data_dir /var/data/crush/myproject, got %s", projects[0].DataDir)
179+ }
180+}