1
1
import filecmp
2
+ import getopt
2
3
import os
3
4
import re
4
5
import shutil
@@ -21,7 +22,9 @@ def _create_file_shallow_equal(template_path, new_path):
21
22
assert os .stat (new_path ).st_size == os .stat (template_path ).st_size
22
23
assert os .stat (new_path ).st_mtime == os .stat (template_path ).st_mtime
23
24
25
+
24
26
class FileCompareTestCase (unittest .TestCase ):
27
+
25
28
def setUp (self ):
26
29
self .name = os_helper .TESTFN
27
30
self .name_same = os_helper .TESTFN + '-same'
@@ -367,5 +370,175 @@ def _assert_report(self, dircmp_report, expected_report_lines):
367
370
self .assertEqual (report_lines , expected_report_lines )
368
371
369
372
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
+
370
543
if __name__ == "__main__" :
371
544
unittest .main ()
0 commit comments