Mercurial > public > mercurial-scm > hg-stable
diff tests/test-absorb-filefixupstate.py @ 38956:5111d11b8719
absorb: import extension from Facebook's hg-experimental
absorb is a wicked-fast command to use blame information to
automatically amend edits to the correct draft revision. Originally
written by Jun Wu, this import is hgext3rd/absorb/__init__.py with:
* the `testedwith` value changed
* the linelog import updated
* some missing configitems registered
* some imports reordered per check-code.py
* some missing __future__ imports added per check-code.py
Differential Revision: https://phab.mercurial-scm.org/D3991
author | Augie Fackler <augie@google.com> |
---|---|
date | Mon, 30 Jul 2018 14:05:56 -0400 |
parents | |
children | 1aab0007a7c0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-absorb-filefixupstate.py Mon Jul 30 14:05:56 2018 -0400 @@ -0,0 +1,207 @@ +from __future__ import absolute_import, print_function + +import itertools + +from hgext import absorb + +class simplefctx(object): + def __init__(self, content): + self.content = content + + def data(self): + return self.content + +def insertreturns(x): + # insert "\n"s after each single char + if isinstance(x, str): + return ''.join(ch + '\n' for ch in x) + else: + return map(insertreturns, x) + +def removereturns(x): + # the revert of "insertreturns" + if isinstance(x, str): + return x.replace('\n', '') + else: + return map(removereturns, x) + +def assertlistequal(lhs, rhs, decorator=lambda x: x): + if lhs != rhs: + raise RuntimeError('mismatch:\n actual: %r\n expected: %r' + % tuple(map(decorator, [lhs, rhs]))) + +def testfilefixup(oldcontents, workingcopy, expectedcontents, fixups=None): + """([str], str, [str], [(rev, a1, a2, b1, b2)]?) -> None + + workingcopy is a string, of which every character denotes a single line. + + oldcontents, expectedcontents are lists of strings, every character of + every string denots a single line. + + if fixups is not None, it's the expected fixups list and will be checked. + """ + expectedcontents = insertreturns(expectedcontents) + oldcontents = insertreturns(oldcontents) + workingcopy = insertreturns(workingcopy) + state = absorb.filefixupstate(map(simplefctx, oldcontents)) + state.diffwith(simplefctx(workingcopy)) + if fixups is not None: + assertlistequal(state.fixups, fixups) + state.apply() + assertlistequal(state.finalcontents, expectedcontents, removereturns) + +def buildcontents(linesrevs): + # linesrevs: [(linecontent : str, revs : [int])] + revs = set(itertools.chain(*[revs for line, revs in linesrevs])) + return [''] + [ + ''.join([l for l, rs in linesrevs if r in rs]) + for r in sorted(revs) + ] + +# input case 0: one single commit +case0 = ['', '11'] + +# replace a single chunk +testfilefixup(case0, '', ['', '']) +testfilefixup(case0, '2', ['', '2']) +testfilefixup(case0, '22', ['', '22']) +testfilefixup(case0, '222', ['', '222']) + +# input case 1: 3 lines, each commit adds one line +case1 = buildcontents([ + ('1', [1, 2, 3]), + ('2', [ 2, 3]), + ('3', [ 3]), +]) + +# 1:1 line mapping +testfilefixup(case1, '123', case1) +testfilefixup(case1, '12c', ['', '1', '12', '12c']) +testfilefixup(case1, '1b3', ['', '1', '1b', '1b3']) +testfilefixup(case1, '1bc', ['', '1', '1b', '1bc']) +testfilefixup(case1, 'a23', ['', 'a', 'a2', 'a23']) +testfilefixup(case1, 'a2c', ['', 'a', 'a2', 'a2c']) +testfilefixup(case1, 'ab3', ['', 'a', 'ab', 'ab3']) +testfilefixup(case1, 'abc', ['', 'a', 'ab', 'abc']) + +# non 1:1 edits +testfilefixup(case1, 'abcd', case1) +testfilefixup(case1, 'ab', case1) + +# deletion +testfilefixup(case1, '', ['', '', '', '']) +testfilefixup(case1, '1', ['', '1', '1', '1']) +testfilefixup(case1, '2', ['', '', '2', '2']) +testfilefixup(case1, '3', ['', '', '', '3']) +testfilefixup(case1, '13', ['', '1', '1', '13']) + +# replaces +testfilefixup(case1, '1bb3', ['', '1', '1bb', '1bb3']) + +# (confusing) replaces +testfilefixup(case1, '1bbb', case1) +testfilefixup(case1, 'bbbb', case1) +testfilefixup(case1, 'bbb3', case1) +testfilefixup(case1, '1b', case1) +testfilefixup(case1, 'bb', case1) +testfilefixup(case1, 'b3', case1) + +# insertions at the beginning and the end +testfilefixup(case1, '123c', ['', '1', '12', '123c']) +testfilefixup(case1, 'a123', ['', 'a1', 'a12', 'a123']) + +# (confusing) insertions +testfilefixup(case1, '1a23', case1) +testfilefixup(case1, '12b3', case1) + +# input case 2: delete in the middle +case2 = buildcontents([ + ('11', [1, 2]), + ('22', [1 ]), + ('33', [1, 2]), +]) + +# deletion (optimize code should make it 2 chunks) +testfilefixup(case2, '', ['', '22', ''], + fixups=[(4, 0, 2, 0, 0), (4, 2, 4, 0, 0)]) + +# 1:1 line mapping +testfilefixup(case2, 'aaaa', ['', 'aa22aa', 'aaaa']) + +# non 1:1 edits +# note: unlike case0, the chunk is not "continuous" and no edit allowed +testfilefixup(case2, 'aaa', case2) + +# input case 3: rev 3 reverts rev 2 +case3 = buildcontents([ + ('1', [1, 2, 3]), + ('2', [ 2 ]), + ('3', [1, 2, 3]), +]) + +# 1:1 line mapping +testfilefixup(case3, '13', case3) +testfilefixup(case3, '1b', ['', '1b', '12b', '1b']) +testfilefixup(case3, 'a3', ['', 'a3', 'a23', 'a3']) +testfilefixup(case3, 'ab', ['', 'ab', 'a2b', 'ab']) + +# non 1:1 edits +testfilefixup(case3, 'a', case3) +testfilefixup(case3, 'abc', case3) + +# deletion +testfilefixup(case3, '', ['', '', '2', '']) + +# insertion +testfilefixup(case3, 'a13c', ['', 'a13c', 'a123c', 'a13c']) + +# input case 4: a slightly complex case +case4 = buildcontents([ + ('1', [1, 2, 3]), + ('2', [ 2, 3]), + ('3', [1, 2, ]), + ('4', [1, 3]), + ('5', [ 3]), + ('6', [ 2, 3]), + ('7', [ 2 ]), + ('8', [ 2, 3]), + ('9', [ 3]), +]) + +testfilefixup(case4, '1245689', case4) +testfilefixup(case4, '1a2456bbb', case4) +testfilefixup(case4, '1abc5689', case4) +testfilefixup(case4, '1ab5689', ['', '134', '1a3678', '1ab5689']) +testfilefixup(case4, 'aa2bcd8ee', ['', 'aa34', 'aa23d78', 'aa2bcd8ee']) +testfilefixup(case4, 'aa2bcdd8ee',['', 'aa34', 'aa23678', 'aa24568ee']) +testfilefixup(case4, 'aaaaaa', case4) +testfilefixup(case4, 'aa258b', ['', 'aa34', 'aa2378', 'aa258b']) +testfilefixup(case4, '25bb', ['', '34', '23678', '25689']) +testfilefixup(case4, '27', ['', '34', '23678', '245689']) +testfilefixup(case4, '28', ['', '34', '2378', '28']) +testfilefixup(case4, '', ['', '34', '37', '']) + +# input case 5: replace a small chunk which is near a deleted line +case5 = buildcontents([ + ('12', [1, 2]), + ('3', [1]), + ('4', [1, 2]), +]) + +testfilefixup(case5, '1cd4', ['', '1cd34', '1cd4']) + +# input case 6: base "changeset" is immutable +case6 = ['1357', '0125678'] + +testfilefixup(case6, '0125678', case6) +testfilefixup(case6, '0a25678', case6) +testfilefixup(case6, '0a256b8', case6) +testfilefixup(case6, 'abcdefg', ['1357', 'a1c5e7g']) +testfilefixup(case6, 'abcdef', case6) +testfilefixup(case6, '', ['1357', '157']) +testfilefixup(case6, '0123456789', ['1357', '0123456789']) + +# input case 7: change an empty file +case7 = [''] + +testfilefixup(case7, '1', case7)