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