1package.path = package.path .. ";./?.lua"
2local wt = dofile("src/main.lua")
3
4describe("cmd_init", function()
5 local temp_dir
6 local original_cwd
7
8 setup(function()
9 local handle = io.popen("pwd")
10 if handle then
11 original_cwd = handle:read("*l")
12 handle:close()
13 end
14 handle = io.popen("mktemp -d")
15 if handle then
16 temp_dir = handle:read("*l")
17 handle:close()
18 end
19 end)
20
21 teardown(function()
22 if original_cwd then
23 os.execute("cd " .. original_cwd)
24 end
25 if temp_dir then
26 os.execute("rm -rf " .. temp_dir)
27 end
28 end)
29
30 describe("already wt-managed repository", function()
31 it("reports already using wt structure when .git file points to .bare", function()
32 if not temp_dir then
33 pending("temp_dir not available")
34 return
35 end
36 local project = temp_dir .. "/already-wt"
37 os.execute("mkdir -p " .. project .. "/.bare")
38 os.execute("git init --bare " .. project .. "/.bare")
39 local f = io.open(project .. "/.git", "w")
40 if f then
41 f:write("gitdir: ./.bare\n")
42 f:close()
43 end
44
45 local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init")
46 assert.are.equal(0, code)
47 assert.is_truthy(output:match("[Aa]lready"))
48 end)
49 end)
50
51 describe("inside a worktree", function()
52 it("errors when run from inside a worktree", function()
53 if not temp_dir then
54 pending("temp_dir not available")
55 return
56 end
57 local project = temp_dir .. "/wt-project"
58 local worktree = project .. "/main"
59 os.execute("mkdir -p " .. project .. "/.bare")
60 os.execute("git init --bare " .. project .. "/.bare")
61 os.execute("mkdir -p " .. worktree)
62 local f = io.open(worktree .. "/.git", "w")
63 if f then
64 f:write("gitdir: ../.bare/worktrees/main\n")
65 f:close()
66 end
67
68 local output, code = wt.run_cmd("cd " .. worktree .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
69 assert.are_not.equal(0, code)
70 assert.is_truthy(output:match("worktree") or output:match("not a git"))
71 end)
72 end)
73
74 describe("not a git repository", function()
75 it("errors when run in non-git directory", function()
76 if not temp_dir then
77 pending("temp_dir not available")
78 return
79 end
80 local project = temp_dir .. "/not-git"
81 os.execute("mkdir -p " .. project)
82
83 local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
84 assert.are_not.equal(0, code)
85 assert.is_truthy(output:match("not a git"))
86 end)
87 end)
88
89 describe(".bare exists but no .git", function()
90 it("errors and suggests creating .git file", function()
91 if not temp_dir then
92 pending("temp_dir not available")
93 return
94 end
95 local project = temp_dir .. "/bare-only"
96 os.execute("mkdir -p " .. project .. "/.bare")
97 os.execute("git init --bare " .. project .. "/.bare")
98
99 local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
100 assert.are_not.equal(0, code)
101 assert.is_truthy(output:match("%.git") or output:match("gitdir"))
102 end)
103 end)
104
105 describe("existing git worktrees", function()
106 it("errors when .git/worktrees/ exists", function()
107 if not temp_dir then
108 pending("temp_dir not available")
109 return
110 end
111 local project = temp_dir .. "/has-worktrees"
112 os.execute("mkdir -p " .. project)
113 os.execute("git init " .. project)
114 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
115 os.execute("mkdir -p " .. project .. "/.git/worktrees/feature-branch")
116
117 local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
118 assert.are_not.equal(0, code)
119 assert.is_truthy(output:match("worktree"))
120 end)
121 end)
122
123 describe("dirty repository", function()
124 it("errors when uncommitted changes exist", function()
125 if not temp_dir then
126 pending("temp_dir not available")
127 return
128 end
129 local project = temp_dir .. "/dirty-repo"
130 os.execute("mkdir -p " .. project)
131 os.execute("git init " .. project)
132 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
133 local f = io.open(project .. "/dirty.txt", "w")
134 if f then
135 f:write("uncommitted\n")
136 f:close()
137 end
138 os.execute("cd " .. project .. " && git add dirty.txt")
139
140 local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init 2>&1")
141 assert.are_not.equal(0, code)
142 assert.is_truthy(output:match("uncommitted") or output:match("stash") or output:match("commit"))
143 end)
144 end)
145
146 describe("--dry-run", function()
147 it("prints plan without modifying filesystem", function()
148 if not temp_dir then
149 pending("temp_dir not available")
150 return
151 end
152 local project = temp_dir .. "/dry-run-test"
153 os.execute("mkdir -p " .. project)
154 os.execute("git init " .. project)
155 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
156
157 local cmd = "cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init --dry-run 2>&1"
158 local output, code = wt.run_cmd(cmd)
159 assert.are.equal(0, code)
160 assert.is_truthy(output:match("[Dd]ry run") or output:match("planned"))
161
162 local git_still_dir = io.open(project .. "/.git/HEAD", "r")
163 assert.is_not_nil(git_still_dir)
164 if git_still_dir then
165 git_still_dir:close()
166 end
167
168 local bare_exists = io.open(project .. "/.bare/HEAD", "r")
169 assert.is_nil(bare_exists)
170 end)
171
172 it("lists orphaned files that would be removed", function()
173 if not temp_dir then
174 pending("temp_dir not available")
175 return
176 end
177 local project = temp_dir .. "/dry-orphans"
178 os.execute("mkdir -p " .. project)
179 os.execute("git init " .. project)
180 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
181
182 local f = io.open(project .. "/README.md", "w")
183 if f then
184 f:write("# Test\n")
185 f:close()
186 end
187 os.execute("cd " .. project .. " && git add README.md && git commit -m 'add readme'")
188
189 local cmd = "cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init --dry-run 2>&1"
190 local output, code = wt.run_cmd(cmd)
191 assert.are.equal(0, code)
192 assert.is_truthy(output:match("README") or output:match("orphan"))
193 end)
194
195 it("shows target worktree path", function()
196 if not temp_dir then
197 pending("temp_dir not available")
198 return
199 end
200 local project = temp_dir .. "/dry-worktree"
201 os.execute("mkdir -p " .. project)
202 os.execute("git init " .. project)
203 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
204
205 local cmd = "cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init --dry-run 2>&1"
206 local output, code = wt.run_cmd(cmd)
207 assert.are.equal(0, code)
208 assert.is_truthy(output:match("worktree") or output:match("main") or output:match("master"))
209 end)
210 end)
211
212 describe("-y/--yes flag", function()
213 it("bypasses confirmation prompt", function()
214 if not temp_dir then
215 pending("temp_dir not available")
216 return
217 end
218 local project = temp_dir .. "/yes-test"
219 os.execute("mkdir -p " .. project)
220 os.execute("git init " .. project)
221 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
222
223 local output, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1")
224 assert.are.equal(0, code)
225 assert.is_truthy(output:match("[Cc]onverted") or output:match("[Bb]are"))
226
227 local bare_exists = io.open(project .. "/.bare/HEAD", "r")
228 assert.is_not_nil(bare_exists)
229 if bare_exists then
230 bare_exists:close()
231 end
232
233 local git_is_file = io.open(project .. "/.git", "r")
234 if git_is_file then
235 local content = git_is_file:read("*a")
236 git_is_file:close()
237 assert.is_truthy(content:match("gitdir"))
238 end
239 end)
240 end)
241
242 describe("successful conversion", function()
243 it("moves .git to .bare", function()
244 if not temp_dir then
245 pending("temp_dir not available")
246 return
247 end
248 local project = temp_dir .. "/convert-test"
249 os.execute("mkdir -p " .. project)
250 os.execute("git init " .. project)
251 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
252
253 local _, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1")
254 assert.are.equal(0, code)
255
256 local bare_head = io.open(project .. "/.bare/HEAD", "r")
257 assert.is_not_nil(bare_head)
258 if bare_head then
259 bare_head:close()
260 end
261 end)
262
263 it("creates .git file pointing to .bare", function()
264 if not temp_dir then
265 pending("temp_dir not available")
266 return
267 end
268 local project = temp_dir .. "/git-file-test"
269 os.execute("mkdir -p " .. project)
270 os.execute("git init " .. project)
271 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
272
273 local _, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1")
274 assert.are.equal(0, code)
275
276 local git_file = io.open(project .. "/.git", "r")
277 assert.is_not_nil(git_file)
278 if git_file then
279 local content = git_file:read("*a")
280 git_file:close()
281 assert.is_truthy(content:match("gitdir:.*%.bare"))
282 end
283 end)
284
285 it("creates worktree for default branch", function()
286 if not temp_dir then
287 pending("temp_dir not available")
288 return
289 end
290 local project = temp_dir .. "/worktree-created"
291 os.execute("mkdir -p " .. project)
292 os.execute("git init " .. project)
293 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
294
295 local cmd = "cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1"
296 local _, code = wt.run_cmd(cmd)
297 assert.are.equal(0, code)
298
299 local worktrees_output, _ = wt.run_cmd("GIT_DIR=" .. project .. "/.bare git worktree list")
300 assert.is_truthy(worktrees_output:match("main") or worktrees_output:match("master"))
301 end)
302
303 it("removes orphaned files from root", function()
304 if not temp_dir then
305 pending("temp_dir not available")
306 return
307 end
308 local project = temp_dir .. "/orphan-cleanup"
309 os.execute("mkdir -p " .. project)
310 os.execute("git init " .. project)
311 local f = io.open(project .. "/tracked.txt", "w")
312 if f then
313 f:write("tracked\n")
314 f:close()
315 end
316 os.execute("cd " .. project .. " && git add tracked.txt && git commit -m 'add file'")
317
318 local _, code = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init -y 2>&1")
319 assert.are.equal(0, code)
320
321 local orphan_check = io.open(project .. "/tracked.txt", "r")
322 assert.is_nil(orphan_check)
323 end)
324 end)
325
326 describe("warnings", function()
327 it("warns about submodules", function()
328 if not temp_dir then
329 pending("temp_dir not available")
330 return
331 end
332 local project = temp_dir .. "/submodule-warn"
333 os.execute("mkdir -p " .. project)
334 os.execute("git init " .. project)
335 os.execute("cd " .. project .. " && git commit --allow-empty -m 'initial'")
336 local f = io.open(project .. "/.gitmodules", "w")
337 if f then
338 f:write("[submodule \"lib\"]\n\tpath = lib\n\turl = https://example.com/lib.git\n")
339 f:close()
340 end
341 os.execute("cd " .. project .. " && git add .gitmodules && git commit -m 'add submodules'")
342
343 local output, _ = wt.run_cmd("cd " .. project .. " && lua " .. original_cwd .. "/src/main.lua init --dry-run 2>&1")
344 assert.is_truthy(output:match("submodule") or output:match("[Ww]arning"))
345 end)
346 end)
347end)