def test_backlog_filter(): class MyAction(ColorStreamAction): def __eq__(self, other): return True assert Backlog(Q(), action=MyAction).filter(function=1) == _Backlog( condition=Q(), filter=Query(function=1), action=MyAction) assert Backlog(Q(), action=MyAction, filter=Q(module=1)).filter(function=2) == _Backlog( condition=Q(), filter=And(Query(module=1), Query(function=2)), action=MyAction) def blabla(): pass assert Backlog(Q(), action=MyAction, filter=blabla).filter(function=1) == _Backlog( condition=Q(), filter=And(blabla, Query(function=1)), action=MyAction) assert Backlog(Q(), action=MyAction, filter=Q(module=1)).filter( blabla, function=2) == _Backlog(condition=Q(), filter=And(Query(module=1), blabla, Query(function=2)), action=MyAction)
def test_trace_merge(): with hunter.trace(function='a'): with hunter.trace(function='b'): with hunter.trace(function='c'): assert sys.gettrace().handler == When(Q(function='c'), CallPrinter) assert sys.gettrace().handler == When(Q(function='b'), CallPrinter) assert sys.gettrace().handler == When(Q(function='a'), CallPrinter)
def test_backlog(mockevent): assert Backlog(module=__name__)(mockevent) is True class Action(ColorStreamAction): called = [] def __call__(self, event): self.called.append(event) assert Backlog(Q(module='foo') | Q(module='bar'), action=Action)(mockevent) is False assert Action.called == [] backlog = Backlog(Not(Q(module='foo') | Q(module='bar')), action=Action) assert backlog(mockevent) is True assert backlog(mockevent) is True assert Action.called == [] def predicate(ev, store=[]): store.append(1) return len(store) > 2 backlog = Backlog(predicate, action=Action, stack=0) assert backlog(mockevent) is False assert backlog(mockevent) is False assert backlog(mockevent) is True assert len(Action.called) == 1
def test_predicate_no_inf_recursion(): assert Or(And(1)) == 1 assert Or(Or(1)) == 1 assert And(Or(1)) == 1 assert And(And(1)) == 1 predicate = Q(Q(lambda ev: 1, module='wat')) print('predicate:', predicate) predicate({'module': 'foo'})
def test_trace_merge(): with hunter.trace(function="a"): with hunter.trace(function="b"): with hunter.trace(function="c"): assert sys.gettrace().handler == When(Q(function="c"), CallPrinter) assert sys.gettrace().handler == When(Q(function="b"), CallPrinter) assert sys.gettrace().handler == When(Q(function="a"), CallPrinter)
def test_no_inf_recursion(mockevent): assert Or(And(1)) == 1 assert Or(Or(1)) == 1 assert And(Or(1)) == 1 assert And(And(1)) == 1 predicate = Q(Q(lambda ev: 1, module='wat')) print('predicate:', predicate) predicate(mockevent)
def run(): output = StringIO() with t.trace( Q(Q(module="does-not-exist") | Q(module="does not exist".split()), action=CodePrinter(stream=output))): _tokenize() return output
def run(): output = StringIO() with t.trace( Q(Q(module="does-not-exist") | Q(module="does not exist".split()), action=CodePrinter(stream=output))): _bulky_func_that_use_stdlib() return output
def run(): output = StringIO() with t.trace( Q(~Q(module_contains='pytest'), ~Q(module_contains='hunter'), ~Q(filename=''), stdlib=False, action=CodePrinter(stream=output))): _bulky_func_that_use_stdlib() return output
def run(): output = StringIO() with t.trace( Q(~Q(module_in=['re', 'sre', 'sre_parse']) & ~Q(module_startswith='namedtuple') & Q(kind="call"), actions=[ CodePrinter(stream=output), VarsPrinter('line', globals=True, stream=output) ])): _bulky_func_that_use_stdlib()
def test_depth_limit(LineMatcher, tracer_impl, depth): buff = StringIO() from sample7 import one tracer = tracer_impl() predicate = When(Q(depth_lt=depth), CallPrinter(stream=buff)) try: tracer.trace(predicate) one() finally: tracer.stop() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ "* call => one()", "* line for i in range(1): # one", "* line two()", "* call => two()", "* return <= two: None", "* line for i in range(1): # one", "* return <= one: None", ]) if depth < 3: assert 'three' not in output if depth < 4: assert 'four' not in output if depth < 5: assert 'five' not in output
def test_when(mockevent): called = [] assert When(Q(module='foo'), lambda ev: called.append(ev))(mockevent) is False assert called == [] assert When(Q(module=__name__), lambda ev: called.append(ev))(mockevent) is True assert called == [mockevent] called = [] assert Q(module=__name__, action=lambda ev: called.append(ev))(mockevent) is True assert called == [mockevent] called = [[], []] predicate = (Q(module=__name__, action=lambda ev: called[0].append(ev)) | Q(module='foo', action=lambda ev: called[1].append(ev))) assert predicate(mockevent) is True assert called == [[mockevent], []] assert predicate(mockevent) is True assert called == [[mockevent, mockevent], []] called = [[], []] predicate = ( Q(module=__name__, action=lambda ev: called[0].append(ev)) & Q(function='mockevent', action=lambda ev: called[1].append(ev))) assert predicate(mockevent) is True assert called == [[mockevent], [mockevent]]
def test_from(mockevent): pytest.raises((AttributeError, TypeError), From(), 1) assert From()(mockevent) is True called = [] assert From( Q(module='foo') | Q(module='bar'), lambda ev: called.append(ev))(mockevent) is False assert called == [] assert From(Not(Q(module='foo') | Q(module='bar')), lambda ev: called.append(ev))(mockevent) is None assert called called = [] assert From(Q(module=__name__), lambda ev: called.append(ev))(mockevent) is None assert called
def test_perf_filter(tracer_impl, benchmark): impl = tracer_impl() class Counter(object): calls = 0 def inc(_): Counter.calls += 1 handler = Q(Q(module='does-not-exist') | Q(module='does not exist'.split()), action=inc) @benchmark def run(): with impl.trace(handler): _bulky_func_that_use_stdlib() assert Counter.calls == 0
def test_from_predicate_with_subpredicate(LineMatcher): buff = StringIO() from sample7 import one with trace(From(Q(source_has='# two'), Q(depth_lt=1)), action=CallPrinter(stream=buff)): one() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ '* line for i in range(1): # two', '* line three()', '* call => three()', '* return <= three: None', '* line for i in range(1): # two', ]) assert 'five' not in output assert 'four' not in output assert 'one()' not in output assert '# one' not in output assert len(lm.lines) == 5
def test_stack_printer(LineMatcher): buff = StringIO() with trace(Q(function="five", action=StackPrinter(stream=buff))): from sample7 import one one() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ "*sample7.py:30:five <= no frames available (detached=True)", ])
def test_stack_printer_2(LineMatcher): buff = StringIO() with trace(Q(function="five", action=StackPrinter(limit=2, stream=buff))): from sample7 import one one() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ "*sample7.py:??:five <= tests/sample7.py:??:four <= tests/sample7.py:??:three <= tests/sample7.py:??:two <= tests/sample7.py:?:one <= tests/test_integration.py:???:test_stack_printer*", ])
def test_q_expansion(): assert Q(C(1), C(2), module=3) == And(C(1), C(2), Q(module=3)) assert Q(C(1), C(2), module=3, action=C(4)) == When(And(C(1), C(2), Q(module=3)), C(4)) assert Q(C(1), C(2), module=3, actions=[C(4), C(5)]) == When(And(C(1), C(2), Q(module=3)), C(4), C(5))
def test_from_predicate_line_no_predicate(LineMatcher): buff = StringIO() from sample7 import one with trace(From(Q(fullsource_has='in_five')), action=CallPrinter(stream=buff)): one() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ "* line * for i in range(1): # five", "* line * return i", ]) assert 'four' not in output assert 'three' not in output assert 'two' not in output assert 'one' not in output
def test_from_predicate(LineMatcher): buff = StringIO() from sample7 import one with trace(From(Q(function='five'), CallPrinter(stream=buff))): one() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ "* call => five()", "* line for i in range(1): # five", "* line return i", "* return <= five: 0", ]) assert 'four' not in output assert 'three' not in output assert 'two' not in output assert 'one' not in output
def test_thread_filtering(LineMatcher, query): lines = StringIO() idents = set() names = set() started = threading.Event() def record(event): idents.add(event.threadid) names.add(event.threadname) return True with hunter.trace(~Q(**query), record, actions=[ CodePrinter(stream=lines), VarsPrinter('a', stream=lines), CallPrinter(stream=lines) ], threading_support=True): def foo(a=1): started.set() print(a) def main(): foo() t = threading.Thread(target=foo) t.start() started.wait(10) main() lm = LineMatcher(lines.getvalue().splitlines()) print(lines.getvalue()) assert None not in idents assert 'MainThread' not in names pprint(lm.lines) lm.fnmatch_lines_random([ 'Thread-* *test_hunter.py:* call def foo(a=1):', 'Thread-* * vars a => 1', 'Thread-* *test_hunter.py:* call => foo(a=1)', 'Thread-* * vars a => 1', ])
def test_predicate_when(): called = [] assert When(Q(module=1), lambda ev: called.append(ev))({ 'module': 2 }) == False assert called == [] assert When(Q(module=1), lambda ev: called.append(ev))({ 'module': 1 }) == True assert called == [{'module': 1}] called = [] assert Q(module=1, action=lambda ev: called.append(ev))({ 'module': 1 }) == True assert called == [{'module': 1}] called = [[], []] predicate = (Q(module=1, action=lambda ev: called[0].append(ev)) | Q(module=2, action=lambda ev: called[1].append(ev))) assert predicate({'module': 1}) == True assert called == [[{'module': 1}], []] assert predicate({'module': 2}) == True assert called == [[{'module': 1}], [{'module': 2}]] called = [[], []] predicate = (Q(module=1, action=lambda ev: called[0].append(ev)) & Q(function=2, action=lambda ev: called[1].append(ev))) assert predicate({'module': 2}) == False assert called == [[], []] assert predicate({'module': 1, 'function': 2}) == True assert called == [[{ 'module': 1, 'function': 2 }], [{ 'module': 1, 'function': 2 }]]
def test_not(mockevent): assert Not(1).predicate == 1 assert ~Or(1, 2) == Not(Or(1, 2)) assert ~And(1, 2) == Not(And(1, 2)) assert ~Not(1) == 1 assert ~Query(module=1) | ~Query(module=2) == Not( And(Query(module=1), Query(module=2))) assert ~Query(module=1) & ~Query(module=2) == Not( Or(Query(module=1), Query(module=2))) assert ~Query(module=1) | Query(module=2) == Or(Not(Query(module=1)), Query(module=2)) assert ~Query(module=1) & Query(module=2) == And(Not(Query(module=1)), Query(module=2)) assert ~(Query(module=1) & Query(module=2)) == Not( And(Query(module=1), Query(module=2))) assert ~(Query(module=1) | Query(module=2)) == Not( Or(Query(module=1), Query(module=2))) assert repr(~Or(1, 2)) == repr(Not(Or(1, 2))) assert repr(~And(1, 2)) == repr(Not(And(1, 2))) assert repr(~Query(module=1) | ~Query(module=2)) == repr( Not(And(Query(module=1), Query(module=2)))) assert repr(~Query(module=1) & ~Query(module=2)) == repr( Not(Or(Query(module=1), Query(module=2)))) assert repr(~(Query(module=1) & Query(module=2))) == repr( Not(And(Query(module=1), Query(module=2)))) assert repr(~(Query(module=1) | Query(module=2))) == repr( Not(Or(Query(module=1), Query(module=2)))) assert Not(Q(module=__name__))(mockevent) is False
def test_predicate_not(): assert Not(1).predicate == 1 assert ~Or(1, 2) == Not(Or(1, 2)) assert ~And(1, 2) == Not(And(1, 2)) assert ~Not(1) == 1 assert ~Query(module=1) | ~Query(module=2) == Not( And(Query(module=1), Query(module=2))) assert ~Query(module=1) & ~Query(module=2) == Not( Or(Query(module=1), Query(module=2))) assert ~Query(module=1) | Query(module=2) == Or(Not(Query(module=1)), Query(module=2)) assert ~Query(module=1) & Query(module=2) == And(Not(Query(module=1)), Query(module=2)) assert ~(Query(module=1) & Query(module=2)) == Not( And(Query(module=1), Query(module=2))) assert ~(Query(module=1) | Query(module=2)) == Not( Or(Query(module=1), Query(module=2))) assert repr(~Or(1, 2)) == repr(Not(Or(1, 2))) assert repr(~And(1, 2)) == repr(Not(And(1, 2))) assert repr(~Query(module=1) | ~Query(module=2)) == repr( Not(And(Query(module=1), Query(module=2)))) assert repr(~Query(module=1) & ~Query(module=2)) == repr( Not(Or(Query(module=1), Query(module=2)))) assert repr(~(Query(module=1) & Query(module=2))) == repr( Not(And(Query(module=1), Query(module=2)))) assert repr(~(Query(module=1) | Query(module=2))) == repr( Not(Or(Query(module=1), Query(module=2)))) assert Not(Q(module=1))({'module': 1}) == False
def test_q_nest_1(): assert repr(Q(Q(module='a'))).endswith( "predicates.Query: query_eq=(('module', 'a'),)>")
def test_q_action_codeprinter(): out = repr(Q(action=CodePrinter())) assert 'condition=<hunter.' in out assert 'actions=(CodePrinter' in out
def test_hashing(): assert Q(module='a', function='b') in {Q(module='a', function='b')} assert ~Q(module='a', function='b') in {~Q(module='a', function='b')} assert (Q(module='a') | Q(function='b')) in {Q(module='a') | Q(function='b')} assert (Q(module='a') & Q(function='b')) in {Q(module='a') & Q(function='b')} assert Q(module='a', action=id) in {Q(module='a', action=id)} assert From(module='a', depth_gte=2) in {From(module='a', depth_gte=2)} class Foo(object): def __call__(self): pass pytest.raises(TypeError, set, Q(module=object(), action=Foo())) pytest.raises(TypeError, set, From(module=object(), depth_gte=object()))
def test_q_deduplicate_codeprinter_cls_inverted(): out = repr(Q(CodePrinter(), action=CallPrinter)) assert out.startswith('CodePrinter(')
def test_q_deduplicate_callprinter_cls(): out = repr(Q(CallPrinter(), action=CallPrinter)) assert out.startswith('CallPrinter(')
def test_q_deduplicate_codeprinter(): out = repr(Q(CodePrinter(), action=CodePrinter())) assert out.startswith('CodePrinter(')