11import filecmp
2+ import getopt
23import os
34import re
45import shutil
@@ -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,175 @@ 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+ @classmethod
377+ def setUpClass (cls ):
378+ cls .temp_dir = tempfile .mkdtemp ()
379+ cls .dir1 = os .path .join (cls .temp_dir , 'dir1' )
380+ cls .dir2 = os .path .join (cls .temp_dir , 'dir2' )
381+ os .makedirs (cls .dir1 )
382+ os .makedirs (cls .dir2 )
383+
384+ @classmethod
385+ def tearDownClass (cls ):
386+ shutil .rmtree (cls .temp_dir )
387+
388+ def tearDown (self ):
389+ # Clean up any files created in individual tests
390+ for item in os .listdir (self .dir1 ):
391+ path = os .path .join (self .dir1 , item )
392+ if os .path .isfile (path ):
393+ os .unlink (path )
394+ elif os .path .isdir (path ):
395+ shutil .rmtree (path )
396+ for item in os .listdir (self .dir2 ):
397+ path = os .path .join (self .dir2 , item )
398+ if os .path .isfile (path ):
399+ os .unlink (path )
400+ elif os .path .isdir (path ):
401+ shutil .rmtree (path )
402+
403+ def test_demo_basic_comparison (self ):
404+ """Test basic directory comparison via demo()"""
405+ # Create test files for this test
406+ with open (os .path .join (self .dir1 , 'same.txt' ), 'w' ) as f :
407+ f .write ('same content' )
408+ with open (os .path .join (self .dir2 , 'same.txt' ), 'w' ) as f :
409+ f .write ('same content' )
410+
411+ with open (os .path .join (self .dir1 , 'different.txt' ), 'w' ) as f :
412+ f .write ('content in dir1' )
413+ with open (os .path .join (self .dir2 , 'different.txt' ), 'w' ) as f :
414+ f .write ('content in dir2' )
415+
416+ with open (os .path .join (self .dir1 , 'only_in_dir1.txt' ), 'w' ) as f :
417+ f .write ('unique to dir1' )
418+
419+ with open (os .path .join (self .dir2 , 'only_in_dir2.txt' ), 'w' ) as f :
420+ f .write ('unique to dir2' )
421+
422+ with support .captured_stdout () as stdout :
423+ filecmp .demo ([self .dir1 , self .dir2 ])
424+ output = stdout .getvalue ()
425+
426+ # Check that output contains expected comparison results
427+ self .assertIn ('diff' , output )
428+ self .assertIn ('same.txt' , output )
429+ self .assertIn ('different.txt' , output )
430+ self .assertIn ('only_in_dir1.txt' , output )
431+ self .assertIn ('only_in_dir2.txt' , output )
432+
433+ def test_demo_recursive_comparison (self ):
434+ """Test recursive directory comparison via demo() with -r flag"""
435+ # Create subdirectories and files for recursive test
436+ subdir1 = os .path .join (self .dir1 , 'subdir' )
437+ subdir2 = os .path .join (self .dir2 , 'subdir' )
438+ os .makedirs (subdir1 )
439+ os .makedirs (subdir2 )
440+
441+ with open (os .path .join (subdir1 , 'subfile.txt' ), 'w' ) as f :
442+ f .write ('sub content' )
443+ with open (os .path .join (subdir2 , 'subfile.txt' ), 'w' ) as f :
444+ f .write ('sub content' )
445+
446+ with support .captured_stdout () as stdout :
447+ filecmp .demo (['-r' , self .dir1 , self .dir2 ])
448+ output = stdout .getvalue ()
449+
450+ # Check that output contains subdirectory comparison
451+ self .assertIn ('subdir' , output )
452+ self .assertIn ('subfile.txt' , output )
453+
454+ def test_demo_long_flag (self ):
455+ """Test demo with long --recursive flag (should fail as only -r is supported)"""
456+ with self .assertRaises (getopt .GetoptError ):
457+ filecmp .demo (['--recursive' , self .dir1 , self .dir2 ])
458+
459+ def test_demo_no_arguments (self ):
460+ """Test demo with no arguments (should raise GetoptError)"""
461+ with self .assertRaises (getopt .GetoptError ) as cm :
462+ filecmp .demo ([])
463+ self .assertIn ('need exactly two args' , str (cm .exception ))
464+
465+ def test_demo_one_argument (self ):
466+ """Test demo with only one directory argument (should raise GetoptError)"""
467+ with self .assertRaises (getopt .GetoptError ) as cm :
468+ filecmp .demo ([self .dir1 ])
469+ self .assertIn ('need exactly two args' , str (cm .exception ))
470+
471+ def test_demo_three_arguments (self ):
472+ """Test demo with three arguments (should raise GetoptError)"""
473+ with self .assertRaises (getopt .GetoptError ) as cm :
474+ filecmp .demo ([self .dir1 , self .dir2 , 'extra' ])
475+ self .assertIn ('need exactly two args' , str (cm .exception ))
476+
477+ def test_demo_nonexistent_directory (self ):
478+ """Test demo with nonexistent directory"""
479+ # This should raise an exception during comparison
480+ with self .assertRaises ((FileNotFoundError , OSError )):
481+ filecmp .demo ([self .dir1 , '/nonexistent/path' ])
482+
483+ def test_demo_identical_directories (self ):
484+ """Test demo with identical directories"""
485+ dir3 = os .path .join (self .temp_dir , 'dir3' )
486+ dir4 = os .path .join (self .temp_dir , 'dir4' )
487+ os .makedirs (dir3 )
488+ os .makedirs (dir4 )
489+
490+ with open (os .path .join (dir3 , 'file1.txt' ), 'w' ) as f :
491+ f .write ('same content' )
492+ with open (os .path .join (dir4 , 'file1.txt' ), 'w' ) as f :
493+ f .write ('same content' )
494+
495+ try :
496+ with support .captured_stdout () as stdout :
497+ filecmp .demo ([dir3 , dir4 ])
498+ output = stdout .getvalue ()
499+
500+ # Should indicate identical files
501+ self .assertIn ('Identical files' , output )
502+ self .assertIn ('file1.txt' , output )
503+ finally :
504+ # Clean up the extra directories
505+ shutil .rmtree (dir3 )
506+ shutil .rmtree (dir4 )
507+
508+ def test_demo_empty_directories (self ):
509+ """Test demo with empty directories"""
510+ dir3 = os .path .join (self .temp_dir , 'empty1' )
511+ dir4 = os .path .join (self .temp_dir , 'empty2' )
512+ os .makedirs (dir3 )
513+ os .makedirs (dir4 )
514+
515+ try :
516+ with support .captured_stdout () as stdout :
517+ filecmp .demo ([dir3 , dir4 ])
518+ output = stdout .getvalue ()
519+
520+ # Should handle empty directories gracefully
521+ self .assertTrue (len (output ) > 0 )
522+ finally :
523+ # Clean up the extra directories
524+ shutil .rmtree (dir3 )
525+ shutil .rmtree (dir4 )
526+
527+ def test_demo_with_files_instead_of_directories (self ):
528+ """Test demo when file paths are given instead of directories"""
529+ file1 = os .path .join (self .dir1 , 'same.txt' )
530+ file2 = os .path .join (self .dir2 , 'same.txt' )
531+
532+ # Create the files first
533+ with open (file1 , 'w' ) as f :
534+ f .write ('content' )
535+ with open (file2 , 'w' ) as f :
536+ f .write ('content' )
537+
538+ # This should raise an exception as files are not directories
539+ with self .assertRaises ((NotADirectoryError , OSError )):
540+ filecmp .demo ([file1 , file2 ])
541+
542+
370543if __name__ == "__main__" :
371544 unittest .main ()
0 commit comments