1import filecmp
2import os
3import shutil
4import tempfile
5import unittest
6
7from test import support
8
9
10class FileCompareTestCase(unittest.TestCase):
11    def setUp(self):
12        self.name = support.TESTFN
13        self.name_same = support.TESTFN + '-same'
14        self.name_diff = support.TESTFN + '-diff'
15        data = 'Contents of file go here.\n'
16        for name in [self.name, self.name_same, self.name_diff]:
17            with open(name, 'w') as output:
18                output.write(data)
19
20        with open(self.name_diff, 'a+') as output:
21            output.write('An extra line.\n')
22        self.dir = tempfile.gettempdir()
23
24    def tearDown(self):
25        os.unlink(self.name)
26        os.unlink(self.name_same)
27        os.unlink(self.name_diff)
28
29    def test_matching(self):
30        self.assertTrue(filecmp.cmp(self.name, self.name),
31                        "Comparing file to itself fails")
32        self.assertTrue(filecmp.cmp(self.name, self.name, shallow=False),
33                        "Comparing file to itself fails")
34        self.assertTrue(filecmp.cmp(self.name, self.name_same),
35                        "Comparing file to identical file fails")
36        self.assertTrue(filecmp.cmp(self.name, self.name_same, shallow=False),
37                        "Comparing file to identical file fails")
38
39    def test_different(self):
40        self.assertFalse(filecmp.cmp(self.name, self.name_diff),
41                    "Mismatched files compare as equal")
42        self.assertFalse(filecmp.cmp(self.name, self.dir),
43                    "File and directory compare as equal")
44
45    def test_cache_clear(self):
46        first_compare = filecmp.cmp(self.name, self.name_same, shallow=False)
47        second_compare = filecmp.cmp(self.name, self.name_diff, shallow=False)
48        filecmp.clear_cache()
49        self.assertTrue(len(filecmp._cache) == 0,
50                        "Cache not cleared after calling clear_cache")
51
52class DirCompareTestCase(unittest.TestCase):
53    def setUp(self):
54        tmpdir = tempfile.gettempdir()
55        self.dir = os.path.join(tmpdir, 'dir')
56        self.dir_same = os.path.join(tmpdir, 'dir-same')
57        self.dir_diff = os.path.join(tmpdir, 'dir-diff')
58
59        # Another dir is created under dir_same, but it has a name from the
60        # ignored list so it should not affect testing results.
61        self.dir_ignored = os.path.join(self.dir_same, '.hg')
62
63        self.caseinsensitive = os.path.normcase('A') == os.path.normcase('a')
64        data = 'Contents of file go here.\n'
65        for dir in (self.dir, self.dir_same, self.dir_diff, self.dir_ignored):
66            shutil.rmtree(dir, True)
67            os.mkdir(dir)
68            if self.caseinsensitive and dir is self.dir_same:
69                fn = 'FiLe'     # Verify case-insensitive comparison
70            else:
71                fn = 'file'
72            with open(os.path.join(dir, fn), 'w') as output:
73                output.write(data)
74
75        with open(os.path.join(self.dir_diff, 'file2'), 'w') as output:
76            output.write('An extra file.\n')
77
78    def tearDown(self):
79        for dir in (self.dir, self.dir_same, self.dir_diff):
80            shutil.rmtree(dir)
81
82    def test_default_ignores(self):
83        self.assertIn('.hg', filecmp.DEFAULT_IGNORES)
84
85    def test_cmpfiles(self):
86        self.assertTrue(filecmp.cmpfiles(self.dir, self.dir, ['file']) ==
87                        (['file'], [], []),
88                        "Comparing directory to itself fails")
89        self.assertTrue(filecmp.cmpfiles(self.dir, self.dir_same, ['file']) ==
90                        (['file'], [], []),
91                        "Comparing directory to same fails")
92
93        # Try it with shallow=False
94        self.assertTrue(filecmp.cmpfiles(self.dir, self.dir, ['file'],
95                                         shallow=False) ==
96                        (['file'], [], []),
97                        "Comparing directory to itself fails")
98        self.assertTrue(filecmp.cmpfiles(self.dir, self.dir_same, ['file'],
99                                         shallow=False),
100                        "Comparing directory to same fails")
101
102        # Add different file2
103        with open(os.path.join(self.dir, 'file2'), 'w') as output:
104            output.write('Different contents.\n')
105
106        self.assertFalse(filecmp.cmpfiles(self.dir, self.dir_same,
107                                     ['file', 'file2']) ==
108                    (['file'], ['file2'], []),
109                    "Comparing mismatched directories fails")
110
111
112    def test_dircmp(self):
113        # Check attributes for comparison of two identical directories
114        left_dir, right_dir = self.dir, self.dir_same
115        d = filecmp.dircmp(left_dir, right_dir)
116        self.assertEqual(d.left, left_dir)
117        self.assertEqual(d.right, right_dir)
118        if self.caseinsensitive:
119            self.assertEqual([d.left_list, d.right_list],[['file'], ['FiLe']])
120        else:
121            self.assertEqual([d.left_list, d.right_list],[['file'], ['file']])
122        self.assertEqual(d.common, ['file'])
123        self.assertEqual(d.left_only, [])
124        self.assertEqual(d.right_only, [])
125        self.assertEqual(d.same_files, ['file'])
126        self.assertEqual(d.diff_files, [])
127        expected_report = [
128            "diff {} {}".format(self.dir, self.dir_same),
129            "Identical files : ['file']",
130        ]
131        self._assert_report(d.report, expected_report)
132
133        # Check attributes for comparison of two different directories (right)
134        left_dir, right_dir = self.dir, self.dir_diff
135        d = filecmp.dircmp(left_dir, right_dir)
136        self.assertEqual(d.left, left_dir)
137        self.assertEqual(d.right, right_dir)
138        self.assertEqual(d.left_list, ['file'])
139        self.assertEqual(d.right_list, ['file', 'file2'])
140        self.assertEqual(d.common, ['file'])
141        self.assertEqual(d.left_only, [])
142        self.assertEqual(d.right_only, ['file2'])
143        self.assertEqual(d.same_files, ['file'])
144        self.assertEqual(d.diff_files, [])
145        expected_report = [
146            "diff {} {}".format(self.dir, self.dir_diff),
147            "Only in {} : ['file2']".format(self.dir_diff),
148            "Identical files : ['file']",
149        ]
150        self._assert_report(d.report, expected_report)
151
152        # Check attributes for comparison of two different directories (left)
153        left_dir, right_dir = self.dir, self.dir_diff
154        shutil.move(
155            os.path.join(self.dir_diff, 'file2'),
156            os.path.join(self.dir, 'file2')
157        )
158        d = filecmp.dircmp(left_dir, right_dir)
159        self.assertEqual(d.left, left_dir)
160        self.assertEqual(d.right, right_dir)
161        self.assertEqual(d.left_list, ['file', 'file2'])
162        self.assertEqual(d.right_list, ['file'])
163        self.assertEqual(d.common, ['file'])
164        self.assertEqual(d.left_only, ['file2'])
165        self.assertEqual(d.right_only, [])
166        self.assertEqual(d.same_files, ['file'])
167        self.assertEqual(d.diff_files, [])
168        expected_report = [
169            "diff {} {}".format(self.dir, self.dir_diff),
170            "Only in {} : ['file2']".format(self.dir),
171            "Identical files : ['file']",
172        ]
173        self._assert_report(d.report, expected_report)
174
175        # Add different file2
176        with open(os.path.join(self.dir_diff, 'file2'), 'w') as output:
177            output.write('Different contents.\n')
178        d = filecmp.dircmp(self.dir, self.dir_diff)
179        self.assertEqual(d.same_files, ['file'])
180        self.assertEqual(d.diff_files, ['file2'])
181        expected_report = [
182            "diff {} {}".format(self.dir, self.dir_diff),
183            "Identical files : ['file']",
184            "Differing files : ['file2']",
185        ]
186        self._assert_report(d.report, expected_report)
187
188    def test_report_partial_closure(self):
189        left_dir, right_dir = self.dir, self.dir_same
190        d = filecmp.dircmp(left_dir, right_dir)
191        expected_report = [
192            "diff {} {}".format(self.dir, self.dir_same),
193            "Identical files : ['file']",
194        ]
195        self._assert_report(d.report_partial_closure, expected_report)
196
197    def test_report_full_closure(self):
198        left_dir, right_dir = self.dir, self.dir_same
199        d = filecmp.dircmp(left_dir, right_dir)
200        expected_report = [
201            "diff {} {}".format(self.dir, self.dir_same),
202            "Identical files : ['file']",
203        ]
204        self._assert_report(d.report_full_closure, expected_report)
205
206    def _assert_report(self, dircmp_report, expected_report_lines):
207        with support.captured_stdout() as stdout:
208            dircmp_report()
209            report_lines = stdout.getvalue().strip().split('\n')
210            self.assertEqual(report_lines, expected_report_lines)
211
212
213def test_main():
214    support.run_unittest(FileCompareTestCase, DirCompareTestCase)
215
216if __name__ == "__main__":
217    test_main()
218