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