@@ -451,3 +451,116 @@ def test_verbose_and_quiet_short_flags_mutually_exclusive(self, mock_default_dir
451451 relink .parse_arguments ()
452452 # Mutually exclusive arguments cause SystemExit with code 2
453453 assert exc_info .value .code == 2
454+
455+ def test_dry_run_flag (self , mock_default_dirs ):
456+ """Test that --dry-run flag is parsed correctly."""
457+ # pylint: disable=unused-argument
458+ with patch ("sys.argv" , ["relink.py" , "--dry-run" ]):
459+ args = relink .parse_arguments ()
460+ assert args .dry_run is True
461+
462+ def test_dry_run_default (self , mock_default_dirs ):
463+ """Test that dry_run defaults to False."""
464+ # pylint: disable=unused-argument
465+ with patch ("sys.argv" , ["relink.py" ]):
466+ args = relink .parse_arguments ()
467+ assert args .dry_run is False
468+
469+
470+ class TestDryRun :
471+ """Test suite for dry-run functionality."""
472+
473+ @pytest .fixture
474+ def temp_dirs (self ):
475+ """Create temporary source and target directories for testing."""
476+ source_dir = tempfile .mkdtemp (prefix = "test_source_" )
477+ target_dir = tempfile .mkdtemp (prefix = "test_target_" )
478+
479+ yield source_dir , target_dir
480+
481+ # Cleanup
482+ shutil .rmtree (source_dir , ignore_errors = True )
483+ shutil .rmtree (target_dir , ignore_errors = True )
484+
485+ def test_dry_run_no_changes (self , temp_dirs , caplog ):
486+ """Test that dry-run mode makes no actual changes."""
487+ source_dir , target_dir = temp_dirs
488+ username = os .environ ["USER" ]
489+
490+ # Create files
491+ source_file = os .path .join (source_dir , "test_file.txt" )
492+ target_file = os .path .join (target_dir , "test_file.txt" )
493+
494+ with open (source_file , "w" , encoding = "utf-8" ) as f :
495+ f .write ("source content" )
496+ with open (target_file , "w" , encoding = "utf-8" ) as f :
497+ f .write ("target content" )
498+
499+ # Get original file info
500+ with open (source_file , "r" , encoding = "utf-8" ) as f :
501+ original_content = f .read ()
502+ original_is_link = os .path .islink (source_file )
503+
504+ # Run in dry-run mode
505+ with caplog .at_level (logging .INFO ):
506+ relink .find_and_replace_owned_files (
507+ source_dir , target_dir , username , dry_run = True
508+ )
509+
510+ # Verify no changes were made
511+ assert os .path .isfile (source_file ), "Original file should still exist"
512+ assert not os .path .islink (source_file ), "File should not be a symlink"
513+ with open (source_file , "r" , encoding = "utf-8" ) as f :
514+ assert f .read () == original_content
515+ assert os .path .islink (source_file ) == original_is_link
516+
517+ def test_dry_run_shows_message (self , temp_dirs , caplog ):
518+ """Test that dry-run mode shows what would be done."""
519+ source_dir , target_dir = temp_dirs
520+ username = os .environ ["USER" ]
521+
522+ # Create files
523+ source_file = os .path .join (source_dir , "test_file.txt" )
524+ target_file = os .path .join (target_dir , "test_file.txt" )
525+
526+ with open (source_file , "w" , encoding = "utf-8" ) as f :
527+ f .write ("source" )
528+ with open (target_file , "w" , encoding = "utf-8" ) as f :
529+ f .write ("target" )
530+
531+ # Run in dry-run mode
532+ with caplog .at_level (logging .INFO ):
533+ relink .find_and_replace_owned_files (
534+ source_dir , target_dir , username , dry_run = True
535+ )
536+
537+ # Check that dry-run messages were logged
538+ assert "DRY RUN MODE" in caplog .text
539+ assert "[DRY RUN] Would create symbolic link:" in caplog .text
540+ assert f"{ source_file } -> { target_file } " in caplog .text
541+
542+ def test_dry_run_no_delete_or_create_messages (self , temp_dirs , caplog ):
543+ """Test that dry-run doesn't show delete/create messages."""
544+ source_dir , target_dir = temp_dirs
545+ username = os .environ ["USER" ]
546+
547+ # Create files
548+ source_file = os .path .join (source_dir , "test_file.txt" )
549+ target_file = os .path .join (target_dir , "test_file.txt" )
550+
551+ with open (source_file , "w" , encoding = "utf-8" ) as f :
552+ f .write ("source" )
553+ with open (target_file , "w" , encoding = "utf-8" ) as f :
554+ f .write ("target" )
555+
556+ # Run in dry-run mode
557+ with caplog .at_level (logging .INFO ):
558+ relink .find_and_replace_owned_files (
559+ source_dir , target_dir , username , dry_run = True
560+ )
561+
562+ # Verify actual operation messages are NOT logged
563+ assert "Deleted original file:" not in caplog .text
564+ assert "Created symbolic link:" not in caplog .text
565+ # But the dry-run message should be there
566+ assert "[DRY RUN] Would create symbolic link: " in caplog .text
0 commit comments