diff options
-rw-r--r-- | coverage/context.py | 38 | ||||
-rw-r--r-- | tests/test_context.py | 43 |
2 files changed, 80 insertions, 1 deletions
diff --git a/coverage/context.py b/coverage/context.py index 24d01f2a..f167de36 100644 --- a/coverage/context.py +++ b/coverage/context.py @@ -7,5 +7,41 @@ def should_start_context_test_function(frame): """Is this frame calling a test_* function?""" fn_name = frame.f_code.co_name if fn_name.startswith("test"): - return fn_name + return qualname_from_frame(frame) return None + + +def qualname_from_frame(frame): + """Get a qualified name for the code running in `frame`.""" + co = frame.f_code + fname = co.co_name + if not co.co_varnames: + return fname + + locs = frame.f_locals + first_arg = co.co_varnames[0] + if co.co_argcount and first_arg == "self": + self = locs["self"] + #elif co.co_flags & 0x04: # *args syntax + # self = locs[first_arg][0] + else: + return fname + + method = getattr(self, fname, None) + if method is None: + return fname + + func = method.__func__ + if hasattr(func, '__qualname__'): + qname = func.__qualname__ + else: + for cls in self.__class__.__mro__: + f = cls.__dict__.get(fname, None) + if f is None: + continue + if f is func: + qname = cls.__name__ + "." + fname + break + else: + qname = fname + return qname diff --git a/tests/test_context.py b/tests/test_context.py index 4339d336..eeca81cd 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -3,10 +3,12 @@ """Tests for context support.""" +import inspect import os.path import coverage from coverage import env +from coverage.context import qualname_from_frame from coverage.data import CoverageData from coverage.misc import CoverageException @@ -182,3 +184,44 @@ class DynamicContextWithPythonTracerTest(CoverageTest): msg = r"Can't support dynamic contexts with PyTracer" with self.assertRaisesRegex(CoverageException, msg): cov.start() + + +def get_qualname(): + """Helper to return qualname_from_frame for the caller.""" + caller_frame = inspect.stack()[1][0] + return qualname_from_frame(caller_frame) + + +class Parent(object): # pylint: disable=missing-docstring + def meth(self): + return get_qualname() + +class Child(Parent): # pylint: disable=missing-docstring + pass + +class SomethingElse(object): # pylint: disable=missing-docstring + pass + +class MultiChild(SomethingElse, Child): # pylint: disable=missing-docstring + pass + +def fake_out(self): # pylint: disable=missing-docstring + return get_qualname() + + +class QualnameTest(CoverageTest): + """Tests of qualname_from_frame.""" + + run_in_temp_dir = False + + def test_method(self): + self.assertEqual(Parent().meth(), "Parent.meth") + + def test_inherited_method(self): + self.assertEqual(Child().meth(), "Parent.meth") + + def test_mi_inherited_method(self): + self.assertEqual(MultiChild().meth(), "Parent.meth") + + def test_fake_out(self): + self.assertEqual(fake_out(0), "fake_out") |