1package.path = package.path .. ";./?.lua"
2local wt = dofile("src/main.lua")
3
4describe("find_project_root", function()
5 local temp_dir
6
7 setup(function()
8 local handle = io.popen("mktemp -d")
9 if handle then
10 temp_dir = handle:read("*l")
11 handle:close()
12 end
13 end)
14
15 teardown(function()
16 if temp_dir then
17 os.execute("rm -rf " .. temp_dir)
18 end
19 end)
20
21 describe("wt-managed repository (.bare + .git file)", function()
22 it("finds root when cwd is project root", function()
23 if not temp_dir then
24 pending("temp_dir not available")
25 return
26 end
27 local project = temp_dir .. "/project"
28 os.execute("mkdir -p " .. project .. "/.bare")
29 os.execute("git init --bare " .. project .. "/.bare")
30 local f = io.open(project .. "/.git", "w")
31 if f then
32 f:write("gitdir: ./.bare\n")
33 f:close()
34 end
35
36 local root, err = wt.find_project_root(project)
37 assert.is_nil(err)
38 assert.are.equal(project, root)
39 end)
40
41 it("finds root when cwd is inside worktree", function()
42 if not temp_dir then
43 pending("temp_dir not available")
44 return
45 end
46 local project = temp_dir .. "/project2"
47 os.execute("mkdir -p " .. project .. "/.bare")
48 os.execute("git init --bare " .. project .. "/.bare")
49 local f = io.open(project .. "/.git", "w")
50 if f then
51 f:write("gitdir: ./.bare\n")
52 f:close()
53 end
54
55 os.execute("mkdir -p " .. project .. "/main/src/lib")
56 local wt_git = io.open(project .. "/main/.git", "w")
57 if wt_git then
58 wt_git:write("gitdir: ../.bare/worktrees/main\n")
59 wt_git:close()
60 end
61
62 local root, err = wt.find_project_root(project .. "/main/src/lib")
63 assert.is_nil(err)
64 assert.are.equal(project, root)
65 end)
66
67 it("finds root when cwd is in nested branch worktree", function()
68 if not temp_dir then
69 pending("temp_dir not available")
70 return
71 end
72 local project = temp_dir .. "/nested-wt"
73 os.execute("mkdir -p " .. project .. "/.bare")
74 os.execute("git init --bare " .. project .. "/.bare")
75 local f = io.open(project .. "/.git", "w")
76 if f then
77 f:write("gitdir: ./.bare\n")
78 f:close()
79 end
80
81 os.execute("mkdir -p " .. project .. "/feature/auth/src")
82 local wt_git = io.open(project .. "/feature/auth/.git", "w")
83 if wt_git then
84 wt_git:write("gitdir: ../../.bare/worktrees/feature-auth\n")
85 wt_git:close()
86 end
87
88 local root, err = wt.find_project_root(project .. "/feature/auth/src")
89 assert.is_nil(err)
90 assert.are.equal(project, root)
91 end)
92 end)
93
94 describe("non-wt repository", function()
95 it("returns error for normal git repo", function()
96 if not temp_dir then
97 pending("temp_dir not available")
98 return
99 end
100 local project = temp_dir .. "/normal-git"
101 os.execute("mkdir -p " .. project)
102 os.execute("git init " .. project)
103
104 local root, err = wt.find_project_root(project)
105 assert.is_nil(root)
106 assert.is_not_nil(err)
107 assert.is_truthy(err:match("not in a wt%-managed repository"))
108 end)
109
110 it("returns error for non-git directory", function()
111 if not temp_dir then
112 pending("temp_dir not available")
113 return
114 end
115 local project = temp_dir .. "/not-git"
116 os.execute("mkdir -p " .. project)
117
118 local root, err = wt.find_project_root(project)
119 assert.is_nil(root)
120 assert.is_not_nil(err)
121 end)
122 end)
123
124 describe("edge cases", function()
125 it("finds root with .bare but relative .git reference", function()
126 if not temp_dir then
127 pending("temp_dir not available")
128 return
129 end
130 local project = temp_dir .. "/rel-git"
131 os.execute("mkdir -p " .. project .. "/.bare")
132 os.execute("git init --bare " .. project .. "/.bare")
133
134 local f = io.open(project .. "/.git", "w")
135 if f then
136 f:write("gitdir: .bare\n")
137 f:close()
138 end
139
140 local root, err = wt.find_project_root(project)
141 assert.is_nil(err)
142 assert.are.equal(project, root)
143 end)
144 end)
145end)
146
147describe("detect_source_worktree", function()
148 local temp_dir
149
150 setup(function()
151 local handle = io.popen("mktemp -d")
152 if handle then
153 temp_dir = handle:read("*l")
154 handle:close()
155 end
156 end)
157
158 teardown(function()
159 if temp_dir then
160 os.execute("rm -rf " .. temp_dir)
161 end
162 end)
163
164 describe("at project root", function()
165 it("returns nil when cwd equals root", function()
166 if not temp_dir then
167 pending("temp_dir not available")
168 return
169 end
170 local project = temp_dir .. "/proj1"
171 os.execute("mkdir -p " .. project .. "/.bare")
172
173 local result = wt.detect_source_worktree(project, project)
174 assert.is_nil(result)
175 end)
176 end)
177
178 describe("inside a worktree", function()
179 it("returns worktree path when cwd has .git file", function()
180 if not temp_dir then
181 pending("temp_dir not available")
182 return
183 end
184 local project = temp_dir .. "/proj2"
185 local worktree = project .. "/main"
186 os.execute("mkdir -p " .. project .. "/.bare")
187 os.execute("mkdir -p " .. worktree .. "/src")
188
189 local f = io.open(worktree .. "/.git", "w")
190 if f then
191 f:write("gitdir: ../.bare/worktrees/main\n")
192 f:close()
193 end
194
195 local result = wt.detect_source_worktree(project, worktree)
196 assert.are.equal(worktree, result)
197 end)
198
199 it("finds worktree root when cwd is deep inside worktree", function()
200 if not temp_dir then
201 pending("temp_dir not available")
202 return
203 end
204 local project = temp_dir .. "/proj3"
205 local worktree = project .. "/main"
206 local deep_path = worktree .. "/src/lib/utils"
207 os.execute("mkdir -p " .. project .. "/.bare")
208 os.execute("mkdir -p " .. deep_path)
209
210 local f = io.open(worktree .. "/.git", "w")
211 if f then
212 f:write("gitdir: ../.bare/worktrees/main\n")
213 f:close()
214 end
215
216 local result = wt.detect_source_worktree(project, deep_path)
217 assert.are.equal(worktree, result)
218 end)
219
220 it("finds nested branch worktree", function()
221 if not temp_dir then
222 pending("temp_dir not available")
223 return
224 end
225 local project = temp_dir .. "/proj4"
226 local worktree = project .. "/feature/auth"
227 os.execute("mkdir -p " .. project .. "/.bare")
228 os.execute("mkdir -p " .. worktree .. "/src")
229
230 local f = io.open(worktree .. "/.git", "w")
231 if f then
232 f:write("gitdir: ../../.bare/worktrees/feature-auth\n")
233 f:close()
234 end
235
236 local result = wt.detect_source_worktree(project, worktree .. "/src")
237 assert.are.equal(worktree, result)
238 end)
239 end)
240
241 describe("not inside a worktree", function()
242 it("returns nil when in bare repo directory", function()
243 if not temp_dir then
244 pending("temp_dir not available")
245 return
246 end
247 local project = temp_dir .. "/proj5"
248 local bare = project .. "/.bare"
249 os.execute("mkdir -p " .. bare)
250
251 local result = wt.detect_source_worktree(project, bare)
252 assert.is_nil(result)
253 end)
254 end)
255end)