From ee4ce15152de2ed0383c9284686cf4a79d95511a Mon Sep 17 00:00:00 2001 From: Shuhei Kitagawa Date: Thu, 15 Jul 2021 17:34:53 +0900 Subject: [PATCH] Remove empty files from a subset request (#46) * Remove empty files from a subset request * Fix manager tests --- nose_launchable/manager.py | 39 ++++++++++++++++++++++++++++++++++++-- tests/test_manager.py | 6 ++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/nose_launchable/manager.py b/nose_launchable/manager.py index fb1d8c4..41d55d4 100644 --- a/nose_launchable/manager.py +++ b/nose_launchable/manager.py @@ -1,6 +1,8 @@ import os +from types import FunctionType from types import ModuleType +from nose.case import Test from nose.failure import Failure from nose.plugins.xunit import id_split from nose.suite import ContextSuite @@ -10,7 +12,6 @@ from nose_launchable.test_path_component import TestPathComponent - # Parse tests and return a list of test names def get_test_names(test): test_names = [] @@ -18,7 +19,9 @@ def get_test_names(test): def dfs(suite): logger.debug("Parsing a test tree: suite: {}".format(suite)) if _is_leaf(suite): - test_names.append(_get_test_name(suite)) + if not is_empty(suite): + test_names.append(_get_test_name(suite)) + return suite # Access to _tests is through a generator, so iteration is not repeatable by default @@ -26,8 +29,40 @@ def dfs(suite): return suite dfs(test) + logger.debug("Test names: {}".format(test_names)) return test_names + +# Check if the test contains any test cases +# If a use uses the Attrib plugin, the file could be empty +def is_empty(test): + empty = True + + def dfs(suite): + nonlocal empty + + # Exit earlier since we already know the test contains at least one test case + if not empty: + return suite + + # 1. If type(suite) is Test the search reaches at the bottom + # 2. If type(suite.context) is function, the test is a generator and stop parsing it there to avoid executing it + if type(suite) is Test or type(getattr(suite, "context", None)) is FunctionType: + empty = False + + return suite + + suite._tests = [dfs(t) for t in suite] + return suite + + dfs(test) + + if empty: + logger.debug("Suite {} is empty".format(test)) + + return empty + + # Subset tests based on the given order def subset(test, target_tests): def dfs(suite): diff --git a/tests/test_manager.py b/tests/test_manager.py index 5ecef11..abdb65b 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -4,13 +4,15 @@ from .resources.module2 import MockTestClass2 from nose.suite import ContextSuite +from nose.suite import Test from nose_launchable.manager import get_test_names, subset class TestManager(unittest.TestCase): def setUp(self): - self.mock_suite1 = ContextSuite(tests=[ContextSuite(context=MockTestClass1), ContextSuite(context=MockTestClass2)]) - self.mock_suite0 = ContextSuite(tests=[ContextSuite(context=MockTestClass0), self.mock_suite1]) + func = lambda: print("called") + self.mock_suite1 = ContextSuite(tests=[ContextSuite(tests=[Test(func)], context=MockTestClass1), ContextSuite(tests=[Test(func)], context=MockTestClass2)]) + self.mock_suite0 = ContextSuite(tests=[ContextSuite(tests=[Test(func)], context=MockTestClass0), self.mock_suite1]) def test_get_test_names(self): want = ['tests/resources/module0.py', 'tests/resources/module1.py', 'tests/resources/module2.py']