Completed
Pull Request — master (#19)
by Ionel Cristian
01:00
created

tests.a()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 2
rs 10
1
from __future__ import print_function
2
3
import inspect
4
import os
5
import subprocess
6
import sys
7
8
try:
9
    from StringIO import StringIO
10
except ImportError:
11
    from io import StringIO
12
try:
13
    from itertools import izip_longest
14
except ImportError:
15
    from itertools import zip_longest as izip_longest
16
17
import pytest
18
19
from hunter import Q
20
from hunter import And
21
from hunter import Or
22
from hunter import Query
23
from hunter import When
24
from hunter import stop
25
from hunter import trace
26
27
from hunter import CodePrinter
28
from hunter import Debugger
29
from hunter import VarsPrinter
30
31
pytest_plugins = 'pytester',
32
33
34
@pytest.yield_fixture(autouse=True, scope="function")
35
def auto_stop():
36
    try:
37
        yield
38
    finally:
39
        stop()
40
41
42
def _get_func_spec(func):
43
    spec = inspect.getargspec(func)
44
    return inspect.formatargspec(spec.args, spec.varargs)
45
46
47
def test_pth_activation():
48
    module_name = os.path.__name__
49
    expected_module = "{0}.py".format(module_name)
50
    hunter_env = "module={!r},function=\"join\"".format(module_name)
51
    func_spec = _get_func_spec(os.path.join)
52
    expected_call = "call      def join{0}:".format(func_spec)
53
54
    output = subprocess.check_output(
55
        [sys.executable, os.path.join(os.path.dirname(__file__), 'sample.py')],
56
        env=dict(os.environ, PYTHONHUNTER=hunter_env),
57
        stderr=subprocess.STDOUT,
58
    )
59
    assert expected_module.encode() in output
60
    assert expected_call.encode() in output
61
62
63
def test_pth_sample4():
64
    env = dict(os.environ, PYTHONHUNTER="CodePrinter")
65
    env.pop('COVERAGE_PROCESS_START', None)
66
    env.pop('COV_CORE_SOURCE', None)
67
    output = subprocess.check_output(
68
        [sys.executable, os.path.join(os.path.dirname(__file__), 'sample4.py')],
69
        env=env,
70
        stderr=subprocess.STDOUT,
71
    )
72
    assert output
73
74
75
def test_pth_sample2(LineMatcher):
76
    env = dict(os.environ, PYTHONHUNTER="module='__main__'")
77
    env.pop('COVERAGE_PROCESS_START', None)
78
    env.pop('COV_CORE_SOURCE', None)
79
    output = subprocess.check_output(
80
        [sys.executable, os.path.join(os.path.dirname(__file__), 'sample2.py')],
81
        env=env,
82
        stderr=subprocess.STDOUT,
83
    )
84
    lm = LineMatcher(output.decode('utf-8').splitlines())
85
    lm.fnmatch_lines([
86
        '*tests*sample2.py:* call      if __name__ == "__main__":  #*',
87
        '*tests*sample2.py:* line      if __name__ == "__main__":  #*',
88
        '*tests*sample2.py:* line          import functools',
89
        '*tests*sample2.py:* line          def deco(opt):',
90
        '*tests*sample2.py:* line          @deco(1)',
91
        '*tests*sample2.py:* call          def deco(opt):',
92
        '*tests*sample2.py:* line              def decorator(func):',
93
        '*tests*sample2.py:* line              return decorator',
94
        '*tests*sample2.py:* return            return decorator',
95
        '*                 * ...       return value: <function deco*',
96
        '*tests*sample2.py:* line          @deco(2)',
97
        '*tests*sample2.py:* call          def deco(opt):',
98
        '*tests*sample2.py:* line              def decorator(func):',
99
        '*tests*sample2.py:* line              return decorator',
100
        '*tests*sample2.py:* return            return decorator',
101
        '*                 * ...       return value: <function deco*',
102
        '*tests*sample2.py:* line          @deco(3)',
103
        '*tests*sample2.py:* call          def deco(opt):',
104
        '*tests*sample2.py:* line              def decorator(func):',
105
        '*tests*sample2.py:* line              return decorator',
106
        '*tests*sample2.py:* return            return decorator',
107
        '*                 * ...       return value: <function deco*',
108
        '*tests*sample2.py:* call              def decorator(func):',
109
        '*tests*sample2.py:* line                  @functools.wraps(func)',
110
        '*tests*sample2.py:* line                  return wrapper',
111
        '*tests*sample2.py:* return                return wrapper',
112
        '*                 * ...       return value: <function foo *',
113
        '*tests*sample2.py:* call              def decorator(func):',
114
        '*tests*sample2.py:* line                  @functools.wraps(func)',
115
        '*tests*sample2.py:* line                  return wrapper',
116
        '*tests*sample2.py:* return                return wrapper',
117
        '*                 * ...       return value: <function foo *',
118
        '*tests*sample2.py:* call              def decorator(func):',
119
        '*tests*sample2.py:* line                  @functools.wraps(func)',
120
        '*tests*sample2.py:* line                  return wrapper',
121
        '*tests*sample2.py:* return                return wrapper',
122
        '*                 * ...       return value: <function foo *',
123
        '*tests*sample2.py:* line          foo(',
124
        "*tests*sample2.py:* line              'a*',",
125
        "*tests*sample2.py:* line              'b'",
126
        '*tests*sample2.py:* call                  @functools.wraps(func)',
127
        '*                 *    |                  def wrapper(*args):',
128
        '*tests*sample2.py:* line                      return func(*args)',
129
        '*tests*sample2.py:* call                  @functools.wraps(func)',
130
        '*                 *    |                  def wrapper(*args):',
131
        '*tests*sample2.py:* line                      return func(*args)',
132
        '*tests*sample2.py:* call                  @functools.wraps(func)',
133
        '*                 *    |                  def wrapper(*args):',
134
        '*tests*sample2.py:* line                      return func(*args)',
135
        '*tests*sample2.py:* call          @deco(1)',
136
        '*                 *    |          @deco(2)',
137
        '*                 *    |          @deco(3)',
138
        '*                 *    |          def foo(*args):',
139
        '*tests*sample2.py:* line              return args',
140
        '*tests*sample2.py:* return            return args',
141
        "*                 * ...       return value: ('a*', 'b')",
142
        "*tests*sample2.py:* return                    return func(*args)",
143
        "*                 * ...       return value: ('a*', 'b')",
144
        "*tests*sample2.py:* return                    return func(*args)",
145
        "*                 * ...       return value: ('a*', 'b')",
146
        "*tests*sample2.py:* return                    return func(*args)",
147
        "*                 * ...       return value: ('a*', 'b')",
148
        "*tests*sample2.py:* line          try:",
149
        "*tests*sample2.py:* line              None(",
150
        "*tests*sample2.py:* line                  'a',",
151
        "*tests*sample2.py:* line                  'b'",
152
        "*tests*sample2.py:* exception             'b'",
153
        "*                 * ...       exception value: *",
154
        "*tests*sample2.py:* line          except:",
155
        "*tests*sample2.py:* line              pass",
156
        "*tests*sample2.py:* return            pass",
157
        "*                   ...       return value: None",
158
    ])
159
160
161
def test_repr():
162
    assert repr(Q(module='a')) == "Query(module='a')"
163
    assert str(Q(module='a')) == "Query(module='a')"
164
    assert repr(Q(module='a', action='foo')) == "When(condition=Query(module='a'), actions=['foo'])"
165
166
167
def test_nest_1():
168
    assert repr(Q(Q(module='a'))) == "Query(module='a')"
169
170
171
def test_expansion():
172
    assert Q(1, 2, module=3) == Or(1, 2, Q(module=3))
173
    assert Q(1, 2, module=3, action=4) == When(Or(1, 2, Q(module=3)), 4)
174
    assert Q(1, 2, module=3, actions=[4, 5]) == When(Or(1, 2, Q(module=3)), 4, 5)
175
176
177
def test_and():
178
    assert And(1, 2) == And(1, 2)
179
    assert Q(module=1) & Q(module=2) == And(Q(module=1), Q(module=2))
180
    assert Q(module=1) & Q(module=2) & Q(module=3) == And(Q(module=1), Q(module=2), Q(module=3))
181
182
183
def test_or():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
184
    assert Q(module=1) | Q(module=2) == Or(Q(module=1), Q(module=2))
185
    assert Q(module=1) | Q(module=2) | Q(module=3) == Or(Q(module=1), Q(module=2), Q(module=3))
186
187
188
def test_or():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
189
    assert Q(module=1) | Q(module=2) == Or(Q(module=1), Q(module=2))
190
    assert Q(module=1) | Q(module=2) | Q(module=3) == Or(Q(module=1), Q(module=2), Q(module=3))
191
192
193
def test_tracing_bare(LineMatcher):
194
    lines = StringIO()
195
    with trace(CodePrinter(stream=lines)):
196
        def a():
197
            return 1
198
199
        b = a()
200
        b = 2
201
        try:
202
            raise Exception("BOOM!")
203
        except Exception:
204
            pass
205
    print(lines.getvalue())
206
    lm = LineMatcher(lines.getvalue().splitlines())
207
    lm.fnmatch_lines([
208
        "* ...       return value: <hunter.*tracer.Tracer *",
209
        "*test_hunter.py* call              def a():",
210
        "*test_hunter.py* line                  return 1",
211
        "*test_hunter.py* return                return 1",
212
        "* ...       return value: 1",
213
    ])
214
215
216
def test_tracing_printing_failures(LineMatcher):
217
    lines = StringIO()
218
    with trace(CodePrinter(stream=lines), VarsPrinter("x", stream=lines)):
219
        class Bad(Exception):
220
            def __repr__(self):
221
                raise RuntimeError("I'm a bad class!")
222
223
        def a():
224
            x = Bad()
225
            return x
226
227
        def b():
228
            x = Bad()
229
            raise x
230
231
        a()
232
        try:
233
            b()
234
        except Exception as exc:
235
            pass
236
    lm = LineMatcher(lines.getvalue().splitlines())
237
    lm.fnmatch_lines([
238
        """* ...       return value: <hunter.*tracer.Tracer *""",
239
        """*tests*test_hunter.py:* call              class Bad(Exception):""",
240
        """*tests*test_hunter.py:* line              class Bad(Exception):""",
241
        """*tests*test_hunter.py:* line                  def __repr__(self):""",
242
        """*tests*test_hunter.py:* return                def __repr__(self):""",
243
        """* ...       return value: *""",
244
        """*tests*test_hunter.py:* call              def a():""",
245
        """*tests*test_hunter.py:* line                  x = Bad()""",
246
        """*tests*test_hunter.py:* line                  return x""",
247
        """* vars      x => !!! FAILED REPR: RuntimeError("I'm a bad class!",)""",
248
        """*tests*test_hunter.py:* return                return x""",
249
        """* ...       return value: !!! FAILED REPR: RuntimeError("I'm a bad class!",)""",
250
        """* vars      x => !!! FAILED REPR: RuntimeError("I'm a bad class!",)""",
251
        """*tests*test_hunter.py:* call              def b():""",
252
        """*tests*test_hunter.py:* line                  x = Bad()""",
253
        """*tests*test_hunter.py:* line                  raise x""",
254
        """* vars      x => !!! FAILED REPR: RuntimeError("I'm a bad class!",)""",
255
        """*tests*test_hunter.py:* exception             raise x""",
256
        """* ...       exception value: !!! FAILED REPR: RuntimeError("I'm a bad class!",)""",
257
        """* vars      x => !!! FAILED REPR: RuntimeError("I'm a bad class!",)""",
258
        """*tests*test_hunter.py:* return                raise x""",
259
        """* ...       return value: None""",
260
        """* vars      x => !!! FAILED REPR: RuntimeError("I'm a bad class!",)""",
261
    ])
262
263
264
def test_tracing_vars(LineMatcher):
265
    lines = StringIO()
266
    with trace(actions=[VarsPrinter('b', stream=lines), CodePrinter(stream=lines)]):
267
        def a():
268
            b = 1
269
            b = 2
270
            return 1
271
272
        b = a()
273
        b = 2
274
        try:
275
            raise Exception("BOOM!")
276
        except Exception:
277
            pass
278
    print(lines.getvalue())
279
    lm = LineMatcher(lines.getvalue().splitlines())
280
    lm.fnmatch_lines([
281
        "* ...       return value: <hunter.*tracer.Tracer *",
282
        "*test_hunter.py* call              def a():",
283
        "*test_hunter.py* line                  b = 1",
284
        "* vars      b => 1",
285
        "*test_hunter.py* line                  b = 2",
286
        "* vars      b => 2",
287
        "*test_hunter.py* line                  return 1",
288
        "* vars      b => 2",
289
        "*test_hunter.py* return                return 1",
290
        "* ...       return value: 1",
291
    ])
292
293
294
def test_trace_merge():
295
    trace(function="a")
296
    trace(function="b")
297
    assert trace(function="c")._handler == When(Q(function="c"), CodePrinter)
298
299
300
def test_trace_api_expansion():
301
    # simple use
302
    with trace(function="foobar") as t:
303
        assert t._handler == When(Q(function="foobar"), CodePrinter)
304
305
    # "or" by expression
306
    with trace(module="foo", function="foobar") as t:
307
        assert t._handler == When(Q(module="foo", function="foobar"), CodePrinter)
308
309
    # pdb.set_trace
310
    with trace(function="foobar", action=Debugger) as t:
311
        assert t._handler == When(Q(function="foobar"), Debugger)
312
313
    # pdb.set_trace on any hits
314
    with trace(module="foo", function="foobar", action=Debugger) as t:
315
        assert t._handler == When(Q(module="foo", function="foobar"), Debugger)
316
317
    # pdb.set_trace when function is foobar, otherwise just print when module is foo
318
    with trace(Q(function="foobar", action=Debugger), module="foo") as t:
319
        assert t._handler == When(Or(
320
            When(Q(function="foobar"), Debugger),
321
            Q(module="foo")
322
        ), CodePrinter)
323
324
    # dumping variables from stack
325
    with trace(Q(function="foobar", action=VarsPrinter("foobar")), module="foo") as t:
326
        assert t._handler == When(Or(
327
            When(Q(function="foobar"), VarsPrinter("foobar")),
328
            Q(module="foo"),
329
        ), CodePrinter)
330
331
    with trace(Q(function="foobar", action=VarsPrinter("foobar", "mumbojumbo")), module="foo") as t:
332
        assert t._handler == When(Or(
333
            When(Q(function="foobar"), VarsPrinter("foobar", "mumbojumbo")),
334
            Q(module="foo"),
335
        ), CodePrinter)
336
337
    # multiple actions
338
    with trace(Q(function="foobar", actions=[VarsPrinter("foobar"), Debugger]), module="foo") as t:
339
        assert t._handler == When(Or(
340
            When(Q(function="foobar"), VarsPrinter("foobar"), Debugger),
341
            Q(module="foo"),
342
        ), CodePrinter)
343
344
    # customization
345
    assert trace(lambda event: event.locals.get("node") == "Foobar",
346
                 module="foo", function="foobar")
347
    assert trace(Q(lambda event: event.locals.get("node") == "Foobar",
348
                   function="foobar", actions=[VarsPrinter("foobar"), Debugger]), module="foo", )
349
    assert trace(Q(function="foobar", actions=[VarsPrinter("foobar"),
350
                                               lambda event: print("some custom output")]), module="foo", )
351
352
353
def test_trace_with_class_actions():
354
    with trace(CodePrinter):
355
        def a():
356
            pass
357
358
        a()
359
360
361
def test_no_inf_recursion():
362
    assert Or(And(1)) == 1
363
    assert Or(Or(1)) == 1
364
    assert And(Or(1)) == 1
365
    assert And(And(1)) == 1
366
    predicate = Q(Q(lambda ev: 1, module='wat'))
367
    print('predicate:', predicate)
368
    predicate('foo')
369
370
371
def test_predicate_compression():
372
    print(Or(Or(1, 2), And(3)))
373
    assert Or(Or(1, 2), And(3)) == Or(1, 2, 3)
374
    assert Or(Or(1, 2), 3) == Or(1, 2, 3)
375
    assert Or(1, Or(2, 3), 4) == Or(1, 2, 3, 4)
376
    assert And(1, 2, Or(3, 4)).predicates == (1, 2, Or(3, 4))
377
378
379
@pytest.mark.parametrize('expr,inp,expected', [
380
    ({'module': "abc"}, {'module': "abc"}, True),
381
    ({'module': "abcd"}, {'module': "abc"}, False),
382
    ({'module': "abcd"}, {'module': "abce"}, False),
383
    ({'module': "abc"}, {'module': "abcd"}, False),
384
    ({'module': ("abc", "xyz")}, {'module': "abc"}, True),
385
    ({'module': ("abc", "xyz")}, {'module': "abcd"}, True),
386
    ({'module': ("abc", "xyz")}, {'module': "xyzw"}, True),
387
    ({'module': ("abc", "xyz")}, {'module': "fooabc"}, False),
388
    ({'module': ("abc", "xyz")}, {'module': 1}, False),
389
390
    ({'module': ["abc", "xyz"]}, {'module': "abc"}, True),
391
    ({'module': ["abc", "xyz"]}, {'module': "abcd"}, True),
392
    ({'module': ["abc", "xyz"]}, {'module': "xyzw"}, True),
393
    ({'module': ["abc", "xyz"]}, {'module': "fooabc"}, False),
394
    ({'module': ["abc", "xyz"]}, {'module': 1}, False),
395
396
    ({'module': {"abc", "xyz"}}, {'module': "abc"}, True),
397
    ({'module': {"abc", "xyz"}}, {'module': "abcd"}, True),
398
    ({'module': {"abc", "xyz"}}, {'module': "xyzw"}, True),
399
    ({'module': {"abc", "xyz"}}, {'module': "fooabc"}, False),
400
    ({'module': {"abc", "xyz"}}, {'module': 1}, False),
401
402
    ({'module': "abc"}, {'module': 1}, False),
403
])
404
def test_matching(expr, inp, expected):
405
    assert Query(**expr)(inp) == expected
406