path_spec.lua

  1-- SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2--
  3-- SPDX-License-Identifier: GPL-3.0-or-later
  4
  5-- Load main.lua as a module (it exports functions when required)
  6package.path = package.path .. ";./?.lua"
  7local wt = dofile("src/main.lua")
  8
  9describe("split_path", function()
 10	describe("basic paths", function()
 11		it("splits absolute path into components", function()
 12			local parts = wt.split_path("/home/user/project")
 13			assert.are.same({ "home", "user", "project" }, parts)
 14		end)
 15
 16		it("splits relative path into components", function()
 17			local parts = wt.split_path("a/b/c")
 18			assert.are.same({ "a", "b", "c" }, parts)
 19		end)
 20
 21		it("handles single component", function()
 22			local parts = wt.split_path("single")
 23			assert.are.same({ "single" }, parts)
 24		end)
 25	end)
 26
 27	describe("edge cases", function()
 28		it("returns empty table for root path", function()
 29			local parts = wt.split_path("/")
 30			assert.are.same({}, parts)
 31		end)
 32
 33		it("returns empty table for empty string", function()
 34			local parts = wt.split_path("")
 35			assert.are.same({}, parts)
 36		end)
 37
 38		it("collapses multiple slashes", function()
 39			local parts = wt.split_path("/a//b///c/")
 40			assert.are.same({ "a", "b", "c" }, parts)
 41		end)
 42
 43		it("ignores trailing slash", function()
 44			local parts = wt.split_path("/a/b/c/")
 45			assert.are.same({ "a", "b", "c" }, parts)
 46		end)
 47
 48		it("handles multiple leading slashes", function()
 49			local parts = wt.split_path("///a/b")
 50			assert.are.same({ "a", "b" }, parts)
 51		end)
 52	end)
 53
 54	describe("special characters", function()
 55		it("preserves dots in path components", function()
 56			local parts = wt.split_path("/home/user/.config")
 57			assert.are.same({ "home", "user", ".config" }, parts)
 58		end)
 59
 60		it("preserves hyphens in path components", function()
 61			local parts = wt.split_path("/my-project/sub-dir")
 62			assert.are.same({ "my-project", "sub-dir" }, parts)
 63		end)
 64
 65		it("preserves spaces in path components", function()
 66			local parts = wt.split_path("/path with/spaces here")
 67			assert.are.same({ "path with", "spaces here" }, parts)
 68		end)
 69	end)
 70end)
 71
 72describe("branch_to_path", function()
 73	describe("nested style (default)", function()
 74		it("preserves slashes in branch name", function()
 75			local path = wt.branch_to_path("/repo", "feature/auth", "nested")
 76			assert.are.equal("/repo/feature/auth", path)
 77		end)
 78
 79		it("handles simple branch name", function()
 80			local path = wt.branch_to_path("/repo", "main", "nested")
 81			assert.are.equal("/repo/main", path)
 82		end)
 83
 84		it("handles deeply nested branch", function()
 85			local path = wt.branch_to_path("/repo", "feature/auth/oauth2", "nested")
 86			assert.are.equal("/repo/feature/auth/oauth2", path)
 87		end)
 88	end)
 89
 90	describe("flat style", function()
 91		it("replaces slashes with default separator", function()
 92			local path = wt.branch_to_path("/repo", "feature/auth", "flat")
 93			assert.are.equal("/repo/feature_auth", path)
 94		end)
 95
 96		it("uses custom separator", function()
 97			local path = wt.branch_to_path("/repo", "feature/auth", "flat", "-")
 98			assert.are.equal("/repo/feature-auth", path)
 99		end)
100
101		it("handles simple branch name (no slashes)", function()
102			local path = wt.branch_to_path("/repo", "main", "flat")
103			assert.are.equal("/repo/main", path)
104		end)
105
106		it("handles multiple slashes with custom separator", function()
107			local path = wt.branch_to_path("/repo", "a/b/c", "flat", ".")
108			assert.are.equal("/repo/a.b.c", path)
109		end)
110	end)
111
112	describe("edge cases", function()
113		it("handles empty branch name", function()
114			local path = wt.branch_to_path("/repo", "", "nested")
115			assert.are.equal("/repo/", path)
116		end)
117
118		it("handles root ending with slash", function()
119			local path = wt.branch_to_path("/repo/", "main", "nested")
120			-- Results in double slash - document this behavior
121			assert.are.equal("/repo//main", path)
122		end)
123
124		it("handles separator containing percent", function()
125			assert.are.equal("/repo/a%b", wt.branch_to_path("/repo", "a/b", "flat", "%"))
126		end)
127
128		it("handles branch starting with slash", function()
129			local path = wt.branch_to_path("/repo", "/feature", "nested")
130			-- Results in double slash
131			assert.are.equal("/repo//feature", path)
132		end)
133	end)
134
135	describe("common branch naming patterns", function()
136		it("handles issue-number branches", function()
137			local path = wt.branch_to_path("/repo", "847-do-a-thing", "nested")
138			assert.are.equal("/repo/847-do-a-thing", path)
139		end)
140
141		it("handles version branches", function()
142			local path = wt.branch_to_path("/repo", "release/1.2.3", "flat", "_")
143			assert.are.equal("/repo/release_1.2.3", path)
144		end)
145
146		it("handles user prefix branches", function()
147			local path = wt.branch_to_path("/repo", "user/alice/feature", "flat", "-")
148			assert.are.equal("/repo/user-alice-feature", path)
149		end)
150	end)
151end)
152
153describe("relative_path", function()
154	describe("sibling directories", function()
155		it("computes path to sibling", function()
156			local rel = wt.relative_path("/a/b", "/a/c")
157			assert.are.equal("../c", rel)
158		end)
159
160		it("computes path to sibling's child", function()
161			local rel = wt.relative_path("/a/b", "/a/c/d")
162			assert.are.equal("../c/d", rel)
163		end)
164	end)
165
166	describe("parent/child relationships", function()
167		it("computes path to child", function()
168			local rel = wt.relative_path("/a", "/a/b")
169			assert.are.equal("./b", rel)
170		end)
171
172		it("computes path to deeply nested child", function()
173			local rel = wt.relative_path("/a", "/a/b/c/d")
174			assert.are.equal("./b/c/d", rel)
175		end)
176
177		it("computes path to parent", function()
178			local rel = wt.relative_path("/a/b/c", "/a")
179			assert.are.equal("../..", rel)
180		end)
181	end)
182
183	describe("same path", function()
184		it("returns ./ for identical paths", function()
185			local rel = wt.relative_path("/a/b", "/a/b")
186			assert.are.equal("./", rel)
187		end)
188	end)
189
190	describe("completely different paths", function()
191		it("computes path across directory tree", function()
192			local rel = wt.relative_path("/home/alice/projects", "/var/log")
193			assert.are.equal("../../../var/log", rel)
194		end)
195	end)
196
197	describe("root paths", function()
198		it("handles from root to child", function()
199			local rel = wt.relative_path("/", "/a/b")
200			assert.are.equal("./a/b", rel)
201		end)
202
203		it("handles from child to root", function()
204			local rel = wt.relative_path("/a/b", "/")
205			assert.are.equal("../..", rel)
206		end)
207	end)
208
209	describe("edge cases", function()
210		it("handles trailing slash in from path", function()
211			-- split_path normalizes trailing slashes
212			local rel = wt.relative_path("/a/b/", "/a/c")
213			assert.are.equal("../c", rel)
214		end)
215
216		it("handles paths with common deep prefix", function()
217			local rel = wt.relative_path("/repo/project/src/lib", "/repo/project/src/bin")
218			assert.are.equal("../bin", rel)
219		end)
220	end)
221
222	describe("real-world wt scenarios", function()
223		it("computes path from worktree to .bare", function()
224			local rel = wt.relative_path("/projects/myapp/feature/auth", "/projects/myapp/.bare")
225			assert.are.equal("../../.bare", rel)
226		end)
227
228		it("computes path between worktrees", function()
229			local rel = wt.relative_path("/projects/myapp/main", "/projects/myapp/feature/new")
230			assert.are.equal("../feature/new", rel)
231		end)
232	end)
233end)