path_spec.lua

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