summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coverage/context.py38
-rw-r--r--tests/test_context.py43
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")