From 1e6dc6f8e5efd63c3626785982e34353a5d799f2 Mon Sep 17 00:00:00 2001 From: Tom Dalton Date: Mon, 23 Oct 2017 13:26:42 +0100 Subject: [PATCH] Working (I think) fix for #2836 --- _pytest/fixtures.py | 36 +++++++++++++++++++++++++++++++++++- testing/test_fixtures.py | 18 ++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 testing/test_fixtures.py diff --git a/_pytest/fixtures.py b/_pytest/fixtures.py index e1c2d05f4..51ccaed67 100644 --- a/_pytest/fixtures.py +++ b/_pytest/fixtures.py @@ -1130,7 +1130,41 @@ class FixtureManager: else: return tuple(self._matchfactories(fixturedefs, nodeid)) + @classmethod + def _splitnode(cls, nodeid): + """Split a nodeid into constituent 'parts'. + + Node IDs are strings, and can be things like: + '', + 'testing/code', + 'testing/code/test_excinfo.py' + 'testing/code/test_excinfo.py::TestFormattedExcinfo::()' + + """ + if nodeid == '': + return [] + sep = py.path.local.sep + parts = nodeid.split(sep) + if parts: + last_part = parts[-1] + if '::' in last_part: + namespace_parts = last_part.split("::") + parts[-1:] = namespace_parts + return parts + + @classmethod + def _ischildnode(cls, baseid, nodeid): + """Return True if the nodeid is a child node of the baseid. + + E.g. 'foo/bar::Baz::()' is a child of 'foo', 'foo/bar' and 'foo/bar::Baz', but not of 'foo/blorp' + """ + base_parts = cls._splitnode(baseid) + node_parts = cls._splitnode(nodeid) + if len(node_parts) < len(base_parts): + return False + return node_parts[:len(base_parts)] == base_parts + def _matchfactories(self, fixturedefs, nodeid): for fixturedef in fixturedefs: - if nodeid.startswith(fixturedef.baseid): + if self._ischildnode(fixturedef.baseid, nodeid): yield fixturedef diff --git a/testing/test_fixtures.py b/testing/test_fixtures.py new file mode 100644 index 000000000..8d595fe52 --- /dev/null +++ b/testing/test_fixtures.py @@ -0,0 +1,18 @@ +import pytest + +from _pytest import fixtures + + +@pytest.mark.parametrize("baseid, nodeid, expected", ( + ('', '', True), + ('', 'foo', True), + ('', 'foo/bar', True), + ('', 'foo/bar::TestBaz::()', True), + ('foo', 'food', False), + ('foo/bar::TestBaz::()', 'foo/bar', False), + ('foo/bar::TestBaz::()', 'foo/bar::TestBop::()', False), + ('foo/bar', 'foo/bar::TestBop::()', True), +)) +def test_fixturemanager_ischildnode(baseid, nodeid, expected): + result = fixtures.FixtureManager._ischildnode(baseid, nodeid) + assert result is expected