22import os
33import re
44import shutil
5+ import sys
56import tempfile
67import unittest
78
@@ -21,7 +22,9 @@ def _create_file_shallow_equal(template_path, new_path):
2122 assert os .stat (new_path ).st_size == os .stat (template_path ).st_size
2223 assert os .stat (new_path ).st_mtime == os .stat (template_path ).st_mtime
2324
25+
2426class FileCompareTestCase (unittest .TestCase ):
27+
2528 def setUp (self ):
2629 self .name = os_helper .TESTFN
2730 self .name_same = os_helper .TESTFN + '-same'
@@ -367,5 +370,212 @@ def _assert_report(self, dircmp_report, expected_report_lines):
367370 self .assertEqual (report_lines , expected_report_lines )
368371
369372
373+ class TestFilecmpCLI (unittest .TestCase ):
374+ """Test the command line interface of filecmp module"""
375+
376+ def setUp (self ):
377+ self .temp_dir = tempfile .mkdtemp ()
378+ self .addCleanup (shutil .rmtree , self .temp_dir )
379+
380+ # Create test directories and files
381+ self .dir1 = os .path .join (self .temp_dir , 'dir1' )
382+ self .dir2 = os .path .join (self .temp_dir , 'dir2' )
383+ os .makedirs (self .dir1 )
384+ os .makedirs (self .dir2 )
385+
386+ # Create identical files
387+ with open (os .path .join (self .dir1 , 'same.txt' ), 'w' ) as f :
388+ f .write ('same content' )
389+ with open (os .path .join (self .dir2 , 'same.txt' ), 'w' ) as f :
390+ f .write ('same content' )
391+
392+ # Create different files
393+ with open (os .path .join (self .dir1 , 'different.txt' ), 'w' ) as f :
394+ f .write ('content in dir1' )
395+ with open (os .path .join (self .dir2 , 'different.txt' ), 'w' ) as f :
396+ f .write ('content in dir2' )
397+
398+ # Create file only in dir1
399+ with open (os .path .join (self .dir1 , 'only_in_dir1.txt' ), 'w' ) as f :
400+ f .write ('unique to dir1' )
401+
402+ # Create file only in dir2
403+ with open (os .path .join (self .dir2 , 'only_in_dir2.txt' ), 'w' ) as f :
404+ f .write ('unique to dir2' )
405+
406+ # Create subdirectories for recursive testing
407+ self .subdir1 = os .path .join (self .dir1 , 'subdir' )
408+ self .subdir2 = os .path .join (self .dir2 , 'subdir' )
409+ os .makedirs (self .subdir1 )
410+ os .makedirs (self .subdir2 )
411+
412+ with open (os .path .join (self .subdir1 , 'subfile.txt' ), 'w' ) as f :
413+ f .write ('sub content' )
414+ with open (os .path .join (self .subdir2 , 'subfile.txt' ), 'w' ) as f :
415+ f .write ('different sub content' )
416+
417+ def test_demo_basic_comparison (self ):
418+ """Test basic directory comparison via demo()"""
419+ import sys
420+ old_argv = sys .argv
421+ try :
422+ sys .argv = ['filecmp' , self .dir1 , self .dir2 ]
423+ with support .captured_stdout () as stdout :
424+ filecmp .__dict__ ['demo' ]()
425+ output = stdout .getvalue ()
426+
427+ # Check that output contains expected comparison results
428+ self .assertIn ('diff' , output )
429+ self .assertIn ('same.txt' , output )
430+ self .assertIn ('different.txt' , output )
431+ self .assertIn ('only_in_dir1.txt' , output )
432+ self .assertIn ('only_in_dir2.txt' , output )
433+ finally :
434+ sys .argv = old_argv
435+
436+ def test_demo_recursive_comparison (self ):
437+ """Test recursive directory comparison via demo() with -r flag"""
438+ import sys
439+ old_argv = sys .argv
440+ try :
441+ sys .argv = ['filecmp' , '-r' , self .dir1 , self .dir2 ]
442+ with support .captured_stdout () as stdout :
443+ filecmp .__dict__ ['demo' ]()
444+ output = stdout .getvalue ()
445+
446+ # Check that output contains subdirectory comparison
447+ self .assertIn ('subdir' , output )
448+ self .assertIn ('subfile.txt' , output )
449+ finally :
450+ sys .argv = old_argv
451+
452+ def test_demo_long_flag (self ):
453+ """Test demo with long --recursive flag (should fail as only -r is supported)"""
454+ import sys
455+ import getopt
456+ old_argv = sys .argv
457+ try :
458+ sys .argv = ['filecmp' , '--recursive' , self .dir1 , self .dir2 ]
459+ with self .assertRaises (getopt .GetoptError ):
460+ filecmp .__dict__ ['demo' ]()
461+ finally :
462+ sys .argv = old_argv
463+
464+ def test_demo_no_arguments (self ):
465+ """Test demo with no arguments (should raise GetoptError)"""
466+ import sys
467+ import getopt
468+ old_argv = sys .argv
469+ try :
470+ sys .argv = ['filecmp' ]
471+ with self .assertRaises (getopt .GetoptError ) as cm :
472+ filecmp .__dict__ ['demo' ]()
473+ self .assertIn ('need exactly two args' , str (cm .exception ))
474+ finally :
475+ sys .argv = old_argv
476+
477+ def test_demo_one_argument (self ):
478+ """Test demo with only one directory argument (should raise GetoptError)"""
479+ import sys
480+ import getopt
481+ old_argv = sys .argv
482+ try :
483+ sys .argv = ['filecmp' , self .dir1 ]
484+ with self .assertRaises (getopt .GetoptError ) as cm :
485+ filecmp .__dict__ ['demo' ]()
486+ self .assertIn ('need exactly two args' , str (cm .exception ))
487+ finally :
488+ sys .argv = old_argv
489+
490+ def test_demo_three_arguments (self ):
491+ """Test demo with three arguments (should raise GetoptError)"""
492+ import sys
493+ import getopt
494+ old_argv = sys .argv
495+ try :
496+ sys .argv = ['filecmp' , self .dir1 , self .dir2 , 'extra' ]
497+ with self .assertRaises (getopt .GetoptError ) as cm :
498+ filecmp .__dict__ ['demo' ]()
499+ self .assertIn ('need exactly two args' , str (cm .exception ))
500+ finally :
501+ sys .argv = old_argv
502+
503+ def test_demo_nonexistent_directory (self ):
504+ """Test demo with nonexistent directory"""
505+ import sys
506+ old_argv = sys .argv
507+ try :
508+ sys .argv = ['filecmp' , self .dir1 , '/nonexistent/path' ]
509+ # This should raise an exception during comparison
510+ with self .assertRaises ((FileNotFoundError , OSError )):
511+ filecmp .__dict__ ['demo' ]()
512+ finally :
513+ sys .argv = old_argv
514+
515+ def test_demo_identical_directories (self ):
516+ """Test demo with identical directories"""
517+ import sys
518+
519+ dir3 = os .path .join (self .temp_dir , 'dir3' )
520+ dir4 = os .path .join (self .temp_dir , 'dir4' )
521+ os .makedirs (dir3 )
522+ os .makedirs (dir4 )
523+
524+ with open (os .path .join (dir3 , 'file1.txt' ), 'w' ) as f :
525+ f .write ('same content' )
526+ with open (os .path .join (dir4 , 'file1.txt' ), 'w' ) as f :
527+ f .write ('same content' )
528+
529+ old_argv = sys .argv
530+ try :
531+ sys .argv = ['filecmp' , dir3 , dir4 ]
532+ with support .captured_stdout () as stdout :
533+ filecmp .__dict__ ['demo' ]()
534+ output = stdout .getvalue ()
535+
536+ # Should indicate identical files
537+ self .assertIn ('Identical files' , output )
538+ self .assertIn ('file1.txt' , output )
539+ finally :
540+ sys .argv = old_argv
541+
542+ def test_demo_empty_directories (self ):
543+ """Test demo with empty directories"""
544+ import sys
545+
546+ dir3 = os .path .join (self .temp_dir , 'empty1' )
547+ dir4 = os .path .join (self .temp_dir , 'empty2' )
548+ os .makedirs (dir3 )
549+ os .makedirs (dir4 )
550+
551+ old_argv = sys .argv
552+ try :
553+ sys .argv = ['filecmp' , dir3 , dir4 ]
554+ with support .captured_stdout () as stdout :
555+ filecmp .__dict__ ['demo' ]()
556+ output = stdout .getvalue ()
557+
558+ # Should handle empty directories gracefully
559+ self .assertTrue (len (output ) > 0 )
560+ finally :
561+ sys .argv = old_argv
562+
563+ def test_demo_with_files_instead_of_directories (self ):
564+ """Test demo when file paths are given instead of directories"""
565+ import sys
566+
567+ file1 = os .path .join (self .dir1 , 'same.txt' )
568+ file2 = os .path .join (self .dir2 , 'same.txt' )
569+
570+ old_argv = sys .argv
571+ try :
572+ sys .argv = ['filecmp' , file1 , file2 ]
573+ # This should raise an exception as files are not directories
574+ with self .assertRaises ((NotADirectoryError , OSError )):
575+ filecmp .__dict__ ['demo' ]()
576+ finally :
577+ sys .argv = old_argv
578+
579+
370580if __name__ == "__main__" :
371581 unittest .main ()
0 commit comments