cmd_init_spec.lua

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