Skip to content

Commit f6ed21f

Browse files
committed
chore: filecmp add unittest
1 parent d4e5802 commit f6ed21f

File tree

2 files changed

+177
-2
lines changed

2 files changed

+177
-2
lines changed

Lib/filecmp.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,12 @@ def _filter(flist, skip):
304304

305305
# Demonstration and testing.
306306
#
307-
def demo():
307+
def demo(args=None):
308308
import sys
309309
import getopt
310-
options, args = getopt.getopt(sys.argv[1:], 'r')
310+
311+
args = sys.argv[1:] if args is None else args
312+
options, args = getopt.getopt(args, 'r')
311313
if len(args) != 2:
312314
raise getopt.GetoptError('need exactly two args', None)
313315
dd = dircmp(args[0], args[1])

Lib/test/test_filecmp.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import filecmp
2+
import getopt
23
import os
34
import re
45
import 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+
2426
class 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+
370543
if __name__ == "__main__":
371544
unittest.main()

0 commit comments

Comments
 (0)