tests/test-absorb-filefixupstate.py
changeset 38917 5111d11b8719
child 38988 1aab0007a7c0
equal deleted inserted replaced
38916:49b51f41fb46 38917:5111d11b8719
       
     1 from __future__ import absolute_import, print_function
       
     2 
       
     3 import itertools
       
     4 
       
     5 from hgext import absorb
       
     6 
       
     7 class simplefctx(object):
       
     8     def __init__(self, content):
       
     9         self.content = content
       
    10 
       
    11     def data(self):
       
    12         return self.content
       
    13 
       
    14 def insertreturns(x):
       
    15     # insert "\n"s after each single char
       
    16     if isinstance(x, str):
       
    17         return ''.join(ch + '\n' for ch in x)
       
    18     else:
       
    19         return map(insertreturns, x)
       
    20 
       
    21 def removereturns(x):
       
    22     # the revert of "insertreturns"
       
    23     if isinstance(x, str):
       
    24         return x.replace('\n', '')
       
    25     else:
       
    26         return map(removereturns, x)
       
    27 
       
    28 def assertlistequal(lhs, rhs, decorator=lambda x: x):
       
    29     if lhs != rhs:
       
    30         raise RuntimeError('mismatch:\n actual:   %r\n expected: %r'
       
    31                            % tuple(map(decorator, [lhs, rhs])))
       
    32 
       
    33 def testfilefixup(oldcontents, workingcopy, expectedcontents, fixups=None):
       
    34     """([str], str, [str], [(rev, a1, a2, b1, b2)]?) -> None
       
    35 
       
    36     workingcopy is a string, of which every character denotes a single line.
       
    37 
       
    38     oldcontents, expectedcontents are lists of strings, every character of
       
    39     every string denots a single line.
       
    40 
       
    41     if fixups is not None, it's the expected fixups list and will be checked.
       
    42     """
       
    43     expectedcontents = insertreturns(expectedcontents)
       
    44     oldcontents = insertreturns(oldcontents)
       
    45     workingcopy = insertreturns(workingcopy)
       
    46     state = absorb.filefixupstate(map(simplefctx, oldcontents))
       
    47     state.diffwith(simplefctx(workingcopy))
       
    48     if fixups is not None:
       
    49         assertlistequal(state.fixups, fixups)
       
    50     state.apply()
       
    51     assertlistequal(state.finalcontents, expectedcontents, removereturns)
       
    52 
       
    53 def buildcontents(linesrevs):
       
    54     # linesrevs: [(linecontent : str, revs : [int])]
       
    55     revs = set(itertools.chain(*[revs for line, revs in linesrevs]))
       
    56     return [''] + [
       
    57         ''.join([l for l, rs in linesrevs if r in rs])
       
    58         for r in sorted(revs)
       
    59     ]
       
    60 
       
    61 # input case 0: one single commit
       
    62 case0 = ['', '11']
       
    63 
       
    64 # replace a single chunk
       
    65 testfilefixup(case0, '', ['', ''])
       
    66 testfilefixup(case0, '2', ['', '2'])
       
    67 testfilefixup(case0, '22', ['', '22'])
       
    68 testfilefixup(case0, '222', ['', '222'])
       
    69 
       
    70 # input case 1: 3 lines, each commit adds one line
       
    71 case1 = buildcontents([
       
    72     ('1', [1, 2, 3]),
       
    73     ('2', [   2, 3]),
       
    74     ('3', [      3]),
       
    75 ])
       
    76 
       
    77 # 1:1 line mapping
       
    78 testfilefixup(case1, '123', case1)
       
    79 testfilefixup(case1, '12c', ['', '1', '12', '12c'])
       
    80 testfilefixup(case1, '1b3', ['', '1', '1b', '1b3'])
       
    81 testfilefixup(case1, '1bc', ['', '1', '1b', '1bc'])
       
    82 testfilefixup(case1, 'a23', ['', 'a', 'a2', 'a23'])
       
    83 testfilefixup(case1, 'a2c', ['', 'a', 'a2', 'a2c'])
       
    84 testfilefixup(case1, 'ab3', ['', 'a', 'ab', 'ab3'])
       
    85 testfilefixup(case1, 'abc', ['', 'a', 'ab', 'abc'])
       
    86 
       
    87 # non 1:1 edits
       
    88 testfilefixup(case1, 'abcd', case1)
       
    89 testfilefixup(case1, 'ab', case1)
       
    90 
       
    91 # deletion
       
    92 testfilefixup(case1, '',   ['', '', '', ''])
       
    93 testfilefixup(case1, '1',  ['', '1', '1', '1'])
       
    94 testfilefixup(case1, '2',  ['', '', '2', '2'])
       
    95 testfilefixup(case1, '3',  ['', '', '', '3'])
       
    96 testfilefixup(case1, '13', ['', '1', '1', '13'])
       
    97 
       
    98 # replaces
       
    99 testfilefixup(case1, '1bb3', ['', '1', '1bb', '1bb3'])
       
   100 
       
   101 # (confusing) replaces
       
   102 testfilefixup(case1, '1bbb', case1)
       
   103 testfilefixup(case1, 'bbbb', case1)
       
   104 testfilefixup(case1, 'bbb3', case1)
       
   105 testfilefixup(case1, '1b', case1)
       
   106 testfilefixup(case1, 'bb', case1)
       
   107 testfilefixup(case1, 'b3', case1)
       
   108 
       
   109 # insertions at the beginning and the end
       
   110 testfilefixup(case1, '123c', ['', '1', '12', '123c'])
       
   111 testfilefixup(case1, 'a123', ['', 'a1', 'a12', 'a123'])
       
   112 
       
   113 # (confusing) insertions
       
   114 testfilefixup(case1, '1a23', case1)
       
   115 testfilefixup(case1, '12b3', case1)
       
   116 
       
   117 # input case 2: delete in the middle
       
   118 case2 = buildcontents([
       
   119     ('11', [1, 2]),
       
   120     ('22', [1   ]),
       
   121     ('33', [1, 2]),
       
   122 ])
       
   123 
       
   124 # deletion (optimize code should make it 2 chunks)
       
   125 testfilefixup(case2, '', ['', '22', ''],
       
   126               fixups=[(4, 0, 2, 0, 0), (4, 2, 4, 0, 0)])
       
   127 
       
   128 # 1:1 line mapping
       
   129 testfilefixup(case2, 'aaaa', ['', 'aa22aa', 'aaaa'])
       
   130 
       
   131 # non 1:1 edits
       
   132 # note: unlike case0, the chunk is not "continuous" and no edit allowed
       
   133 testfilefixup(case2, 'aaa', case2)
       
   134 
       
   135 # input case 3: rev 3 reverts rev 2
       
   136 case3 = buildcontents([
       
   137     ('1', [1, 2, 3]),
       
   138     ('2', [   2   ]),
       
   139     ('3', [1, 2, 3]),
       
   140 ])
       
   141 
       
   142 # 1:1 line mapping
       
   143 testfilefixup(case3, '13', case3)
       
   144 testfilefixup(case3, '1b', ['', '1b', '12b', '1b'])
       
   145 testfilefixup(case3, 'a3', ['', 'a3', 'a23', 'a3'])
       
   146 testfilefixup(case3, 'ab', ['', 'ab', 'a2b', 'ab'])
       
   147 
       
   148 # non 1:1 edits
       
   149 testfilefixup(case3, 'a', case3)
       
   150 testfilefixup(case3, 'abc', case3)
       
   151 
       
   152 # deletion
       
   153 testfilefixup(case3, '', ['', '', '2', ''])
       
   154 
       
   155 # insertion
       
   156 testfilefixup(case3, 'a13c', ['', 'a13c', 'a123c', 'a13c'])
       
   157 
       
   158 # input case 4: a slightly complex case
       
   159 case4 = buildcontents([
       
   160     ('1', [1, 2, 3]),
       
   161     ('2', [   2, 3]),
       
   162     ('3', [1, 2,  ]),
       
   163     ('4', [1,    3]),
       
   164     ('5', [      3]),
       
   165     ('6', [   2, 3]),
       
   166     ('7', [   2   ]),
       
   167     ('8', [   2, 3]),
       
   168     ('9', [      3]),
       
   169 ])
       
   170 
       
   171 testfilefixup(case4, '1245689', case4)
       
   172 testfilefixup(case4, '1a2456bbb', case4)
       
   173 testfilefixup(case4, '1abc5689', case4)
       
   174 testfilefixup(case4, '1ab5689', ['', '134', '1a3678', '1ab5689'])
       
   175 testfilefixup(case4, 'aa2bcd8ee', ['', 'aa34', 'aa23d78', 'aa2bcd8ee'])
       
   176 testfilefixup(case4, 'aa2bcdd8ee',['', 'aa34', 'aa23678', 'aa24568ee'])
       
   177 testfilefixup(case4, 'aaaaaa', case4)
       
   178 testfilefixup(case4, 'aa258b', ['', 'aa34', 'aa2378', 'aa258b'])
       
   179 testfilefixup(case4, '25bb', ['', '34', '23678', '25689'])
       
   180 testfilefixup(case4, '27', ['', '34', '23678', '245689'])
       
   181 testfilefixup(case4, '28', ['', '34', '2378', '28'])
       
   182 testfilefixup(case4, '', ['', '34', '37', ''])
       
   183 
       
   184 # input case 5: replace a small chunk which is near a deleted line
       
   185 case5 = buildcontents([
       
   186     ('12', [1, 2]),
       
   187     ('3',  [1]),
       
   188     ('4',  [1, 2]),
       
   189 ])
       
   190 
       
   191 testfilefixup(case5, '1cd4', ['', '1cd34', '1cd4'])
       
   192 
       
   193 # input case 6: base "changeset" is immutable
       
   194 case6 = ['1357', '0125678']
       
   195 
       
   196 testfilefixup(case6, '0125678', case6)
       
   197 testfilefixup(case6, '0a25678', case6)
       
   198 testfilefixup(case6, '0a256b8', case6)
       
   199 testfilefixup(case6, 'abcdefg', ['1357', 'a1c5e7g'])
       
   200 testfilefixup(case6, 'abcdef', case6)
       
   201 testfilefixup(case6, '', ['1357', '157'])
       
   202 testfilefixup(case6, '0123456789', ['1357', '0123456789'])
       
   203 
       
   204 # input case 7: change an empty file
       
   205 case7 = ['']
       
   206 
       
   207 testfilefixup(case7, '1', case7)