10c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport difflib
20c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom test.test_support import run_unittest, findfile
30c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport unittest
40c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport doctest
50c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport sys
60c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
70c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
80c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestWithAscii(unittest.TestCase):
90c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_one_insert(self):
100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sm = difflib.SequenceMatcher(None, 'b' * 100, 'a' + 'b' * 100)
110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertAlmostEqual(sm.ratio(), 0.995, places=3)
120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(list(sm.get_opcodes()),
130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            [   ('insert', 0, 0, 0, 1),
140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ('equal', 0, 100, 1, 101)])
150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sm = difflib.SequenceMatcher(None, 'b' * 100, 'b' * 50 + 'a' + 'b' * 50)
160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertAlmostEqual(sm.ratio(), 0.995, places=3)
170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(list(sm.get_opcodes()),
180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            [   ('equal', 0, 50, 0, 50),
190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ('insert', 50, 50, 50, 51),
200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ('equal', 50, 100, 51, 101)])
210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_one_delete(self):
230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sm = difflib.SequenceMatcher(None, 'a' * 40 + 'c' + 'b' * 40, 'a' * 40 + 'b' * 40)
240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertAlmostEqual(sm.ratio(), 0.994, places=3)
250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(list(sm.get_opcodes()),
260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            [   ('equal', 0, 40, 0, 40),
270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ('delete', 40, 41, 40, 40),
280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ('equal', 41, 81, 40, 80)])
290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestAutojunk(unittest.TestCase):
320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Tests for the autojunk parameter added in 2.7"""
330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_one_insert_homogenous_sequence(self):
340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # By default autojunk=True and the heuristic kicks in for a sequence
350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # of length 200+
360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        seq1 = 'b' * 200
370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        seq2 = 'a' + 'b' * 200
380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sm = difflib.SequenceMatcher(None, seq1, seq2)
400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertAlmostEqual(sm.ratio(), 0, places=3)
410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Now turn the heuristic off
430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sm = difflib.SequenceMatcher(None, seq1, seq2, autojunk=False)
440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertAlmostEqual(sm.ratio(), 0.9975, places=3)
450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestSFbugs(unittest.TestCase):
480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_ratio_for_null_seqn(self):
490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Check clearing of SF bug 763023
500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = difflib.SequenceMatcher(None, [], [])
510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(s.ratio(), 1)
520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(s.quick_ratio(), 1)
530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(s.real_quick_ratio(), 1)
540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_comparing_empty_lists(self):
560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Check fix for bug #979794
570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        group_gen = difflib.SequenceMatcher(None, [], []).get_grouped_opcodes()
580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(StopIteration, group_gen.next)
590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        diff_gen = difflib.unified_diff([], [])
600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(StopIteration, diff_gen.next)
610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_added_tab_hint(self):
630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Check fix for bug #1488943
640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        diff = list(difflib.Differ().compare(["\tI am a buggy"],["\t\tI am a bug"]))
650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual("- \tI am a buggy", diff[0])
660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual("?            --\n", diff[1])
670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual("+ \t\tI am a bug", diff[2])
680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual("? +\n", diff[3])
690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yipatch914575_from1 = """
710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi   1. Beautiful is beTTer than ugly.
720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi   2. Explicit is better than implicit.
730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi   3. Simple is better than complex.
740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi   4. Complex is better than complicated.
750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yipatch914575_to1 = """
780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi   1. Beautiful is better than ugly.
790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi   3.   Simple is better than complex.
800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi   4. Complicated is better than complex.
810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi   5. Flat is better than nested.
820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yipatch914575_from2 = """
850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\t\tLine 1: preceeded by from:[tt] to:[ssss]
860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  \t\tLine 2: preceeded by from:[sstt] to:[sssst]
870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  \t \tLine 3: preceeded by from:[sstst] to:[ssssss]
880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiLine 4:  \thas from:[sst] to:[sss] after :
890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiLine 5: has from:[t] to:[ss] at end\t
900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yipatch914575_to2 = """
930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Line 1: preceeded by from:[tt] to:[ssss]
940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    \tLine 2: preceeded by from:[sstt] to:[sssst]
950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi      Line 3: preceeded by from:[sstst] to:[ssssss]
960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiLine 4:   has from:[sst] to:[sss] after :
970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiLine 5: has from:[t] to:[ss] at end
980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yipatch914575_from3 = """line 0
1010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi1234567890123456789012345689012345
1020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 1
1030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 2
1040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 3
1050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 4   changed
1060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 5   changed
1070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 6   changed
1080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 7
1090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 8  subtracted
1100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 9
1110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi1234567890123456789012345689012345
1120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yishort line
1130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yijust fits in!!
1140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yijust fits in two lines yup!!
1150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yithe end"""
1160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yipatch914575_to3 = """line 0
1180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi1234567890123456789012345689012345
1190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 1
1200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 2    added
1210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 3
1220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 4   chanGEd
1230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 5a  chanGed
1240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 6a  changEd
1250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 7
1260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 8
1270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiline 9
1280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi1234567890
1290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yianother long line that needs to be wrapped
1300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yijust fitS in!!
1310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yijust fits in two lineS yup!!
1320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yithe end"""
1330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestSFpatches(unittest.TestCase):
1350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_html_diff(self):
1370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Check SF patch 914575 for generating HTML differences
1380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        f1a = ((patch914575_from1 + '123\n'*10)*3)
1390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t1a = (patch914575_to1 + '123\n'*10)*3
1400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        f1b = '456\n'*10 + f1a
1410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t1b = '456\n'*10 + t1a
1420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        f1a = f1a.splitlines()
1430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t1a = t1a.splitlines()
1440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        f1b = f1b.splitlines()
1450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t1b = t1b.splitlines()
1460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        f2 = patch914575_from2.splitlines()
1470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t2 = patch914575_to2.splitlines()
1480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        f3 = patch914575_from3
1490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t3 = patch914575_to3
1500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        i = difflib.HtmlDiff()
1510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        j = difflib.HtmlDiff(tabsize=2)
1520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        k = difflib.HtmlDiff(wrapcolumn=14)
1530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        full = i.make_file(f1a,t1a,'from','to',context=False,numlines=5)
1550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        tables = '\n'.join(
1560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            [
1570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>Context (first diff within numlines=5(default))</h2>',
1580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             i.make_table(f1a,t1a,'from','to',context=True),
1590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>Context (first diff after numlines=5(default))</h2>',
1600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             i.make_table(f1b,t1b,'from','to',context=True),
1610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>Context (numlines=6)</h2>',
1620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             i.make_table(f1a,t1a,'from','to',context=True,numlines=6),
1630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>Context (numlines=0)</h2>',
1640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             i.make_table(f1a,t1a,'from','to',context=True,numlines=0),
1650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>Same Context</h2>',
1660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             i.make_table(f1a,f1a,'from','to',context=True),
1670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>Same Full</h2>',
1680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             i.make_table(f1a,f1a,'from','to',context=False),
1690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>Empty Context</h2>',
1700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             i.make_table([],[],'from','to',context=True),
1710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>Empty Full</h2>',
1720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             i.make_table([],[],'from','to',context=False),
1730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>tabsize=2</h2>',
1740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             j.make_table(f2,t2),
1750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>tabsize=default</h2>',
1760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             i.make_table(f2,t2),
1770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>Context (wrapcolumn=14,numlines=0)</h2>',
1780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             k.make_table(f3.splitlines(),t3.splitlines(),context=True,numlines=0),
1790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>wrapcolumn=14,splitlines()</h2>',
1800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             k.make_table(f3.splitlines(),t3.splitlines()),
1810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             '<h2>wrapcolumn=14,splitlines(True)</h2>',
1820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             k.make_table(f3.splitlines(True),t3.splitlines(True)),
1830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             ])
1840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        actual = full.replace('</body>','\n%s\n</body>' % tables)
1850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # temporarily uncomment next two lines to baseline this test
1870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #with open('test_difflib_expect.html','w') as fp:
1880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #    fp.write(actual)
1890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        with open(findfile('test_difflib_expect.html')) as fp:
1910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertEqual(actual, fp.read())
1920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_recursion_limit(self):
1940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Check if the problem described in patch #1413711 exists.
1950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        limit = sys.getrecursionlimit()
1960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        old = [(i%2 and "K:%d" or "V:A:%d") % i for i in range(limit*2)]
1970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        new = [(i%2 and "K:%d" or "V:B:%d") % i for i in range(limit*2)]
1980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        difflib.SequenceMatcher(None, old, new).get_opcodes()
1990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestOutputFormat(unittest.TestCase):
2020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_tab_delimiter(self):
2030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        args = ['one', 'two', 'Original', 'Current',
2040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            '2005-01-26 23:30:50', '2010-04-02 10:20:52']
2050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ud = difflib.unified_diff(*args, lineterm='')
2060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(list(ud)[0:2], [
2070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                           "--- Original\t2005-01-26 23:30:50",
2080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                           "+++ Current\t2010-04-02 10:20:52"])
2090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        cd = difflib.context_diff(*args, lineterm='')
2100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(list(cd)[0:2], [
2110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                           "*** Original\t2005-01-26 23:30:50",
2120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                           "--- Current\t2010-04-02 10:20:52"])
2130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_no_trailing_tab_on_empty_filedate(self):
2150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        args = ['one', 'two', 'Original', 'Current']
2160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ud = difflib.unified_diff(*args, lineterm='')
2170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(list(ud)[0:2], ["--- Original", "+++ Current"])
2180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        cd = difflib.context_diff(*args, lineterm='')
2200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"])
2210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_range_format_unified(self):
2230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Per the diff spec at http://www.unix.org/single_unix_specification/
2240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        spec = '''\
2250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           Each <range> field shall be of the form:
2260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             %1d", <beginning line number>  if the range contains exactly one line,
2270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           and:
2280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "%1d,%1d", <beginning line number>, <number of lines> otherwise.
2290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           If a range is empty, its beginning line number shall be the number of
2300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           the line just before the range, or 0 if the empty range starts the file.
2310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        '''
2320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fmt = difflib._format_range_unified
2330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(3,3), '3,0')
2340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(3,4), '4')
2350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(3,5), '4,2')
2360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(3,6), '4,3')
2370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(0,0), '0,0')
2380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_range_format_context(self):
2400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Per the diff spec at http://www.unix.org/single_unix_specification/
2410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        spec = '''\
2420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           The range of lines in file1 shall be written in the following format
2430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           if the range contains two or more lines:
2440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi               "*** %d,%d ****\n", <beginning line number>, <ending line number>
2450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           and the following format otherwise:
2460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi               "*** %d ****\n", <ending line number>
2470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           The ending line number of an empty range shall be the number of the preceding line,
2480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           or 0 if the range is at the start of the file.
2490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           Next, the range of lines in file2 shall be written in the following format
2510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           if the range contains two or more lines:
2520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi               "--- %d,%d ----\n", <beginning line number>, <ending line number>
2530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           and the following format otherwise:
2540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi               "--- %d ----\n", <ending line number>
2550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        '''
2560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fmt = difflib._format_range_context
2570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(3,3), '3')
2580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(3,4), '4')
2590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(3,5), '4,5')
2600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(3,6), '4,6')
2610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(fmt(0,0), '0')
2620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef test_main():
2650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    difflib.HtmlDiff._default_prefix = 0
2660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Doctests = doctest.DocTestSuite(difflib)
2670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    run_unittest(
2680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        TestWithAscii, TestAutojunk, TestSFpatches, TestSFbugs,
2690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        TestOutputFormat, Doctests)
2700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiif __name__ == '__main__':
2720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    test_main()
273