test-linelog.py
240 lines
| 7.5 KiB
| text/x-python
|
PythonLexer
/ tests / test-linelog.py
Augie Fackler
|
r38831 | from __future__ import absolute_import, print_function | ||
import difflib | ||||
import random | ||||
import unittest | ||||
from mercurial import linelog | ||||
Augie Fackler
|
r43346 | vecratio = 3 # number of replacelines / number of replacelines_vec | ||
maxlinenum = 0xFFFFFF | ||||
maxb1 = 0xFFFFFF | ||||
Augie Fackler
|
r38831 | maxdeltaa = 10 | ||
maxdeltab = 10 | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r38831 | def _genedits(seed, endrev): | ||
lines = [] | ||||
random.seed(seed) | ||||
for rev in range(0, endrev): | ||||
n = len(lines) | ||||
a1 = random.randint(0, n) | ||||
a2 = random.randint(a1, min(n, a1 + maxdeltaa)) | ||||
b1 = random.randint(0, maxb1) | ||||
b2 = random.randint(b1, b1 + maxdeltab) | ||||
Augie Fackler
|
r38960 | usevec = not bool(random.randint(0, vecratio)) | ||
if usevec: | ||||
Augie Fackler
|
r43346 | blines = [ | ||
(random.randint(0, rev), random.randint(0, maxlinenum)) | ||||
for _ in range(b1, b2) | ||||
] | ||||
Augie Fackler
|
r38960 | else: | ||
blines = [(rev, bidx) for bidx in range(b1, b2)] | ||||
Augie Fackler
|
r38831 | lines[a1:a2] = blines | ||
Augie Fackler
|
r38960 | yield lines, rev, a1, a2, b1, b2, blines, usevec | ||
Augie Fackler
|
r38831 | |||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r38831 | class linelogtests(unittest.TestCase): | ||
def testlinelogencodedecode(self): | ||||
Augie Fackler
|
r43346 | program = [ | ||
linelog._eof(0, 0), | ||||
linelog._jge(41, 42), | ||||
linelog._jump(0, 43), | ||||
linelog._eof(0, 0), | ||||
linelog._jl(44, 45), | ||||
linelog._line(46, 47), | ||||
] | ||||
Augie Fackler
|
r38831 | ll = linelog.linelog(program, maxrev=100) | ||
enc = ll.encode() | ||||
# round-trips okay | ||||
self.assertEqual(linelog.linelog.fromdata(enc)._program, ll._program) | ||||
self.assertEqual(linelog.linelog.fromdata(enc), ll) | ||||
# This encoding matches the encoding used by hg-experimental's | ||||
# linelog file, or is supposed to if it doesn't. | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
enc, | ||||
( | ||||
b'\x00\x00\x01\x90\x00\x00\x00\x06' | ||||
b'\x00\x00\x00\xa4\x00\x00\x00*' | ||||
b'\x00\x00\x00\x00\x00\x00\x00+' | ||||
b'\x00\x00\x00\x00\x00\x00\x00\x00' | ||||
b'\x00\x00\x00\xb1\x00\x00\x00-' | ||||
b'\x00\x00\x00\xba\x00\x00\x00/' | ||||
), | ||||
) | ||||
Augie Fackler
|
r38831 | |||
def testsimpleedits(self): | ||||
ll = linelog.linelog() | ||||
# Initial revision: add lines 0, 1, and 2 | ||||
ll.replacelines(1, 0, 0, 0, 3) | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
[(l.rev, l.linenum) for l in ll.annotate(1)], | ||||
Augie Fackler
|
r46554 | [ | ||
(1, 0), | ||||
(1, 1), | ||||
(1, 2), | ||||
], | ||||
Augie Fackler
|
r43346 | ) | ||
Augie Fackler
|
r38831 | # Replace line 1 with a new line | ||
ll.replacelines(2, 1, 2, 1, 2) | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
[(l.rev, l.linenum) for l in ll.annotate(2)], | ||||
Augie Fackler
|
r46554 | [ | ||
(1, 0), | ||||
(2, 1), | ||||
(1, 2), | ||||
], | ||||
Augie Fackler
|
r43346 | ) | ||
Augie Fackler
|
r38831 | # delete a line out of 2 | ||
ll.replacelines(3, 1, 2, 0, 0) | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
Augie Fackler
|
r46554 | [(l.rev, l.linenum) for l in ll.annotate(3)], | ||
[ | ||||
(1, 0), | ||||
(1, 2), | ||||
], | ||||
Augie Fackler
|
r43346 | ) | ||
Augie Fackler
|
r38831 | # annotation of 1 is unchanged | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
[(l.rev, l.linenum) for l in ll.annotate(1)], | ||||
Augie Fackler
|
r46554 | [ | ||
(1, 0), | ||||
(1, 1), | ||||
(1, 2), | ||||
], | ||||
Augie Fackler
|
r43346 | ) | ||
ll.annotate(3) # set internal state to revision 3 | ||||
Augie Fackler
|
r38831 | start = ll.getoffset(0) | ||
end = ll.getoffset(1) | ||||
Augie Fackler
|
r46554 | self.assertEqual( | ||
ll.getalllines(start, end), | ||||
[ | ||||
(1, 0), | ||||
(2, 1), | ||||
(1, 1), | ||||
], | ||||
) | ||||
self.assertEqual( | ||||
ll.getalllines(), | ||||
[ | ||||
(1, 0), | ||||
(2, 1), | ||||
(1, 1), | ||||
(1, 2), | ||||
], | ||||
) | ||||
Augie Fackler
|
r38831 | |||
def testparseclinelogfile(self): | ||||
# This data is what the replacements in testsimpleedits | ||||
# produce when fed to the original linelog.c implementation. | ||||
Augie Fackler
|
r43346 | data = ( | ||
b'\x00\x00\x00\x0c\x00\x00\x00\x0f' | ||||
b'\x00\x00\x00\x00\x00\x00\x00\x02' | ||||
b'\x00\x00\x00\x05\x00\x00\x00\x06' | ||||
b'\x00\x00\x00\x06\x00\x00\x00\x00' | ||||
b'\x00\x00\x00\x00\x00\x00\x00\x07' | ||||
b'\x00\x00\x00\x06\x00\x00\x00\x02' | ||||
b'\x00\x00\x00\x00\x00\x00\x00\x00' | ||||
b'\x00\x00\x00\t\x00\x00\x00\t' | ||||
b'\x00\x00\x00\x00\x00\x00\x00\x0c' | ||||
b'\x00\x00\x00\x08\x00\x00\x00\x05' | ||||
b'\x00\x00\x00\x06\x00\x00\x00\x01' | ||||
b'\x00\x00\x00\x00\x00\x00\x00\x05' | ||||
b'\x00\x00\x00\x0c\x00\x00\x00\x05' | ||||
b'\x00\x00\x00\n\x00\x00\x00\x01' | ||||
b'\x00\x00\x00\x00\x00\x00\x00\t' | ||||
) | ||||
Augie Fackler
|
r38831 | llc = linelog.linelog.fromdata(data) | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
[(l.rev, l.linenum) for l in llc.annotate(1)], | ||||
Augie Fackler
|
r46554 | [ | ||
(1, 0), | ||||
(1, 1), | ||||
(1, 2), | ||||
], | ||||
Augie Fackler
|
r43346 | ) | ||
self.assertEqual( | ||||
[(l.rev, l.linenum) for l in llc.annotate(2)], | ||||
Augie Fackler
|
r46554 | [ | ||
(1, 0), | ||||
(2, 1), | ||||
(1, 2), | ||||
], | ||||
Augie Fackler
|
r43346 | ) | ||
self.assertEqual( | ||||
Augie Fackler
|
r46554 | [(l.rev, l.linenum) for l in llc.annotate(3)], | ||
[ | ||||
(1, 0), | ||||
(1, 2), | ||||
], | ||||
Augie Fackler
|
r43346 | ) | ||
Augie Fackler
|
r38831 | # Check we emit the same bytecode. | ||
ll = linelog.linelog() | ||||
# Initial revision: add lines 0, 1, and 2 | ||||
ll.replacelines(1, 0, 0, 0, 3) | ||||
# Replace line 1 with a new line | ||||
ll.replacelines(2, 1, 2, 1, 2) | ||||
# delete a line out of 2 | ||||
ll.replacelines(3, 1, 2, 0, 0) | ||||
Augie Fackler
|
r43346 | diff = '\n ' + '\n '.join( | ||
difflib.unified_diff( | ||||
ll.debugstr().splitlines(), | ||||
llc.debugstr().splitlines(), | ||||
'python', | ||||
'c', | ||||
lineterm='', | ||||
) | ||||
) | ||||
Augie Fackler
|
r38831 | self.assertEqual(ll._program, llc._program, 'Program mismatch: ' + diff) | ||
# Done as a secondary step so we get a better result if the | ||||
# program is where the mismatch is. | ||||
self.assertEqual(ll, llc) | ||||
self.assertEqual(ll.encode(), data) | ||||
def testanothersimplecase(self): | ||||
ll = linelog.linelog() | ||||
ll.replacelines(3, 0, 0, 0, 2) | ||||
ll.replacelines(4, 0, 2, 0, 0) | ||||
Augie Fackler
|
r43346 | self.assertEqual([(l.rev, l.linenum) for l in ll.annotate(4)], []) | ||
self.assertEqual( | ||||
[(l.rev, l.linenum) for l in ll.annotate(3)], [(3, 0), (3, 1)] | ||||
) | ||||
Augie Fackler
|
r38831 | # rev 2 is empty because contents were only ever introduced in rev 3 | ||
Augie Fackler
|
r43346 | self.assertEqual([(l.rev, l.linenum) for l in ll.annotate(2)], []) | ||
Augie Fackler
|
r38831 | |||
def testrandomedits(self): | ||||
# Inspired by original linelog tests. | ||||
seed = random.random() | ||||
numrevs = 2000 | ||||
ll = linelog.linelog() | ||||
# Populate linelog | ||||
Augie Fackler
|
r38960 | for lines, rev, a1, a2, b1, b2, blines, usevec in _genedits( | ||
Augie Fackler
|
r43346 | seed, numrevs | ||
): | ||||
Augie Fackler
|
r38960 | if usevec: | ||
ll.replacelines_vec(rev, a1, a2, blines) | ||||
else: | ||||
ll.replacelines(rev, a1, a2, b1, b2) | ||||
Matt Harbison
|
r44444 | ll.annotate(rev) | ||
Augie Fackler
|
r38831 | self.assertEqual(ll.annotateresult, lines) | ||
# Verify we can get back these states by annotating each rev | ||||
Augie Fackler
|
r38960 | for lines, rev, a1, a2, b1, b2, blines, usevec in _genedits( | ||
Augie Fackler
|
r43346 | seed, numrevs | ||
): | ||||
Augie Fackler
|
r38831 | ar = ll.annotate(rev) | ||
self.assertEqual([(l.rev, l.linenum) for l in ar], lines) | ||||
Jun Wu
|
r38970 | def testinfinitebadprogram(self): | ||
ll = linelog.linelog.fromdata( | ||||
b'\x00\x00\x00\x00\x00\x00\x00\x02' # header | ||||
b'\x00\x00\x00\x00\x00\x00\x00\x01' # JUMP to self | ||||
) | ||||
with self.assertRaises(linelog.LineLogError): | ||||
# should not be an infinite loop and raise | ||||
ll.annotate(1) | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r38831 | if __name__ == '__main__': | ||
import silenttestrunner | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r38831 | silenttestrunner.main(__name__) | ||