test-util.py
143 lines
| 4.2 KiB
| text/x-python
|
PythonLexer
/ tests / test-util.py
Martijn Pieters
|
r38833 | # unit tests for mercuril.util utilities | ||
import contextlib | ||||
Gregory Szorc
|
r49728 | import io | ||
Martijn Pieters
|
r38833 | import itertools | ||
import unittest | ||||
from mercurial import pycompat, util, utils | ||||
Augie Fackler
|
r43346 | |||
Martijn Pieters
|
r38833 | @contextlib.contextmanager | ||
def mocktimer(incr=0.1, *additional_targets): | ||||
"""Replaces util.timer and additional_targets with a mock | ||||
The timer starts at 0. On each call the time incremented by the value | ||||
of incr. If incr is an iterable, then the time is incremented by the | ||||
next value from that iterable, looping in a cycle when reaching the end. | ||||
additional_targets must be a sequence of (object, attribute_name) tuples; | ||||
the mock is set with setattr(object, attribute_name, mock). | ||||
""" | ||||
time = [0] | ||||
try: | ||||
incr = itertools.cycle(incr) | ||||
except TypeError: | ||||
incr = itertools.repeat(incr) | ||||
def timer(): | ||||
time[0] += next(incr) | ||||
return time[0] | ||||
# record original values | ||||
orig = util.timer | ||||
additional_origs = [(o, a, getattr(o, a)) for o, a in additional_targets] | ||||
# mock out targets | ||||
util.timer = timer | ||||
for obj, attr in additional_targets: | ||||
setattr(obj, attr, timer) | ||||
try: | ||||
yield | ||||
finally: | ||||
# restore originals | ||||
util.timer = orig | ||||
for args in additional_origs: | ||||
setattr(*args) | ||||
Augie Fackler
|
r43346 | |||
Martijn Pieters
|
r38833 | # attr.s default factory for util.timedstats.start binds the timer we | ||
# need to mock out. | ||||
Matt Harbison
|
r50537 | _start_default = (util.timedcmstats.__attrs_attrs__.start.default, 'factory') | ||
Martijn Pieters
|
r38833 | |||
Augie Fackler
|
r43346 | |||
Martijn Pieters
|
r38833 | @contextlib.contextmanager | ||
def capturestderr(): | ||||
Gregory Szorc
|
r49728 | """Replace utils.procutil.stderr with an io.BytesIO instance | ||
Martijn Pieters
|
r38833 | |||
The instance is made available as the return value of __enter__. | ||||
This contextmanager is reentrant. | ||||
""" | ||||
orig = utils.procutil.stderr | ||||
Gregory Szorc
|
r49728 | utils.procutil.stderr = io.BytesIO() | ||
Martijn Pieters
|
r38833 | try: | ||
yield utils.procutil.stderr | ||||
finally: | ||||
utils.procutil.stderr = orig | ||||
Augie Fackler
|
r43346 | |||
Martijn Pieters
|
r38833 | class timedtests(unittest.TestCase): | ||
def testtimedcmstatsstr(self): | ||||
stats = util.timedcmstats() | ||||
self.assertEqual(str(stats), '<unknown>') | ||||
Martijn Pieters
|
r38848 | self.assertEqual(bytes(stats), b'<unknown>') | ||
Martijn Pieters
|
r38833 | stats.elapsed = 12.34 | ||
Martijn Pieters
|
r38848 | self.assertEqual(str(stats), pycompat.sysstr(util.timecount(12.34))) | ||
self.assertEqual(bytes(stats), util.timecount(12.34)) | ||||
Martijn Pieters
|
r38833 | |||
def testtimedcmcleanexit(self): | ||||
# timestamps 1, 4, elapsed time of 4 - 1 = 3 | ||||
with mocktimer([1, 3], _start_default): | ||||
Augie Fackler
|
r39294 | with util.timedcm('pass') as stats: | ||
Martijn Pieters
|
r38833 | # actual context doesn't matter | ||
pass | ||||
self.assertEqual(stats.start, 1) | ||||
self.assertEqual(stats.elapsed, 3) | ||||
self.assertEqual(stats.level, 1) | ||||
def testtimedcmnested(self): | ||||
# timestamps 1, 3, 6, 10, elapsed times of 6 - 3 = 3 and 10 - 1 = 9 | ||||
with mocktimer([1, 2, 3, 4], _start_default): | ||||
Augie Fackler
|
r39294 | with util.timedcm('outer') as outer_stats: | ||
with util.timedcm('inner') as inner_stats: | ||||
Martijn Pieters
|
r38833 | # actual context doesn't matter | ||
pass | ||||
self.assertEqual(outer_stats.start, 1) | ||||
self.assertEqual(outer_stats.elapsed, 9) | ||||
self.assertEqual(outer_stats.level, 1) | ||||
self.assertEqual(inner_stats.start, 3) | ||||
self.assertEqual(inner_stats.elapsed, 3) | ||||
self.assertEqual(inner_stats.level, 2) | ||||
def testtimedcmexception(self): | ||||
# timestamps 1, 4, elapsed time of 4 - 1 = 3 | ||||
with mocktimer([1, 3], _start_default): | ||||
try: | ||||
Augie Fackler
|
r39294 | with util.timedcm('exceptional') as stats: | ||
Martijn Pieters
|
r38833 | raise ValueError() | ||
except ValueError: | ||||
pass | ||||
self.assertEqual(stats.start, 1) | ||||
self.assertEqual(stats.elapsed, 3) | ||||
self.assertEqual(stats.level, 1) | ||||
def testtimeddecorator(self): | ||||
@util.timed | ||||
def testfunc(callcount=1): | ||||
callcount -= 1 | ||||
if callcount: | ||||
testfunc(callcount) | ||||
# timestamps 1, 2, 3, 4, elapsed time of 3 - 2 = 1 and 4 - 1 = 3 | ||||
with mocktimer(1, _start_default): | ||||
with capturestderr() as out: | ||||
testfunc(2) | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
out.getvalue(), | ||||
(b' testfunc: 1.000 s\n' b' testfunc: 3.000 s\n'), | ||||
) | ||||
Martijn Pieters
|
r38833 | |||
if __name__ == '__main__': | ||||
import silenttestrunner | ||||
Augie Fackler
|
r43346 | |||
Martijn Pieters
|
r38833 | silenttestrunner.main(__name__) | ||