@@ -165,3 +165,125 @@ fn resolve_worktree_name(name: Option<String>, repo: &Repo) -> color_eyre::Resul
165165
166166 Ok ( components. join ( "/" ) )
167167}
168+
169+ #[ cfg( test) ]
170+ mod tests {
171+ use super :: * ;
172+ use std:: { env, fs, path:: Path , process:: Command as StdCommand } ;
173+
174+ use color_eyre:: eyre:: { self , WrapErr } ;
175+
176+ use tempfile:: TempDir ;
177+
178+ struct DirGuard {
179+ original : std:: path:: PathBuf ,
180+ }
181+
182+ impl DirGuard {
183+ fn change_to ( path : & Path ) -> color_eyre:: Result < Self > {
184+ let original = env:: current_dir ( ) . wrap_err ( "failed to capture current directory" ) ?;
185+ env:: set_current_dir ( path)
186+ . wrap_err_with ( || eyre:: eyre!( "failed to switch to `{}`" , path. display( ) ) ) ?;
187+ Ok ( Self { original } )
188+ }
189+ }
190+
191+ impl Drop for DirGuard {
192+ fn drop ( & mut self ) {
193+ let _ = env:: set_current_dir ( & self . original ) ;
194+ }
195+ }
196+
197+ fn init_git_repo ( dir : & TempDir ) -> color_eyre:: Result < ( ) > {
198+ run ( dir, [ "git" , "init" ] ) ?;
199+ fs:: write ( dir. path ( ) . join ( "README.md" ) , "test" ) ?;
200+ run ( dir, [ "git" , "add" , "README.md" ] ) ?;
201+ run (
202+ dir,
203+ [
204+ "git" ,
205+ "-c" ,
206+ "user.name=Test" ,
207+ "-c" ,
208+ "user.email=test@example.com" ,
209+ "commit" ,
210+ "-m" ,
211+ "Initial commit" ,
212+ ] ,
213+ ) ?;
214+ Ok ( ( ) )
215+ }
216+
217+ fn run ( dir : & TempDir , cmd : impl IntoIterator < Item = & ' static str > ) -> color_eyre:: Result < ( ) > {
218+ let mut iter = cmd. into_iter ( ) ;
219+ let program = iter. next ( ) . expect ( "command must not be empty" ) ;
220+ let status = StdCommand :: new ( program)
221+ . current_dir ( dir. path ( ) )
222+ . args ( iter)
223+ . status ( )
224+ . wrap_err_with ( || eyre:: eyre!( "failed to run `{program}`" ) ) ?;
225+
226+ if !status. success ( ) {
227+ return Err ( eyre:: eyre!( "`{program}` exited with status {status}" ) ) ;
228+ }
229+
230+ Ok ( ( ) )
231+ }
232+
233+ #[ test]
234+ fn resolve_worktree_name_returns_cli_argument_when_present ( ) -> color_eyre:: Result < ( ) > {
235+ let repo_dir = TempDir :: new ( ) ?;
236+ init_git_repo ( & repo_dir) ?;
237+ let repo = Repo :: discover_from ( repo_dir. path ( ) ) ?;
238+
239+ let resolved = resolve_worktree_name ( Some ( "feature/test" . into ( ) ) , & repo) ?;
240+ assert_eq ! ( resolved, "feature/test" ) ;
241+
242+ Ok ( ( ) )
243+ }
244+
245+ #[ test]
246+ fn resolve_worktree_name_infers_from_cwd_inside_worktree ( ) -> color_eyre:: Result < ( ) > {
247+ let repo_dir = TempDir :: new ( ) ?;
248+ init_git_repo ( & repo_dir) ?;
249+ let repo = Repo :: discover_from ( repo_dir. path ( ) ) ?;
250+ let worktree_dir = repo. ensure_worktrees_dir ( ) ?. join ( "feature/nested" ) ;
251+ fs:: create_dir_all ( & worktree_dir) ?;
252+
253+ let _guard = DirGuard :: change_to ( & worktree_dir) ?;
254+ let resolved = resolve_worktree_name ( None , & repo) ?;
255+ assert_eq ! ( resolved, "feature/nested" ) ;
256+
257+ Ok ( ( ) )
258+ }
259+
260+ #[ test]
261+ fn resolve_worktree_name_requires_running_inside_worktree ( ) -> color_eyre:: Result < ( ) > {
262+ let repo_dir = TempDir :: new ( ) ?;
263+ init_git_repo ( & repo_dir) ?;
264+ let repo = Repo :: discover_from ( repo_dir. path ( ) ) ?;
265+ let _guard = DirGuard :: change_to ( repo. root ( ) ) ?;
266+
267+ let err = resolve_worktree_name ( None , & repo) . unwrap_err ( ) ;
268+ assert ! ( err. to_string( ) . contains( "must be run from inside" ) ) ;
269+
270+ Ok ( ( ) )
271+ }
272+
273+ #[ test]
274+ fn resolve_worktree_name_rejects_rsworktree_root ( ) -> color_eyre:: Result < ( ) > {
275+ let repo_dir = TempDir :: new ( ) ?;
276+ init_git_repo ( & repo_dir) ?;
277+ let repo = Repo :: discover_from ( repo_dir. path ( ) ) ?;
278+ let worktrees_dir = repo. ensure_worktrees_dir ( ) ?;
279+ let _guard = DirGuard :: change_to ( & worktrees_dir) ?;
280+
281+ let err = resolve_worktree_name ( None , & repo) . unwrap_err ( ) ;
282+ assert ! (
283+ err. to_string( )
284+ . contains( "Run `rsworktree pr-github` from inside" )
285+ ) ;
286+
287+ Ok ( ( ) )
288+ }
289+ }
0 commit comments