diff --git a/testplan/testing/result.py b/testplan/testing/result.py index 6cbd1eab5..3b60fa73e 100644 --- a/testplan/testing/result.py +++ b/testplan/testing/result.py @@ -116,6 +116,11 @@ def __exit__(self, exc_type, exc_value, tb): def collect_code_context(func: Callable) -> Callable: + """ + Sets the decorated function to collect code context + """ + + @wraps(func) def wrapper(*args, **kwargs): assertion_state.collect_code_context = True func(*args, **kwargs) diff --git a/tests/functional/testplan/runnable/interactive/interactive_executable.py b/tests/functional/testplan/runnable/interactive/interactive_executable.py index 5e7bd0634..969fadc76 100644 --- a/tests/functional/testplan/runnable/interactive/interactive_executable.py +++ b/tests/functional/testplan/runnable/interactive/interactive_executable.py @@ -447,7 +447,13 @@ def main(): module_info.original_report for module_info in TEST_SUITE_MODULES ], actual_reports=_get_actual_reports(plan), - ignore=["file_path", "line_no", "machine_time", "utc_time", "code_context"], + ignore=[ + "file_path", + "line_no", + "machine_time", + "utc_time", + "code_context", + ], ) assert plan.interactive.report.passed is False @@ -491,7 +497,13 @@ def main(): module_info.updated_report for module_info in TEST_SUITE_MODULES ], actual_reports=actual_reports, - ignore=["file_path", "line_no", "machine_time", "utc_time", "code_context"], + ignore=[ + "file_path", + "line_no", + "machine_time", + "utc_time", + "code_context", + ], ) assert plan.interactive.report.passed is True diff --git a/tests/unit/testplan/testing/multitest/test_result.py b/tests/unit/testplan/testing/multitest/test_result.py index 04fe18112..3a5f0e162 100644 --- a/tests/unit/testplan/testing/multitest/test_result.py +++ b/tests/unit/testplan/testing/multitest/test_result.py @@ -26,12 +26,12 @@ matplotlib.use("agg") -def get_line_no(obj, rel_pos): +def get_code_context(obj, rel_pos): """ - Extracts absolute line number based on object and relative position. + Extracts code context based on object and relative position. """ - _, start = inspect.getsourcelines(obj) - return start + rel_pos + lines, start = inspect.getsourcelines(obj) + return (start + rel_pos, lines[rel_pos].strip()) def helper(result, description=None): @@ -43,17 +43,29 @@ def intermediary(result, description=None): helper(result, description=description) +@result_mod.collect_code_context def test_group_marking(): """ Tests, at result object level, if marking works as expected. """ result = result_mod.Result() result.equal(1, 1) - assert result.entries.pop().line_no == get_line_no(test_group_marking, 5) - helper(result) - assert result.entries.pop().line_no == get_line_no(helper, 1) - intermediary(result) - assert result.entries.pop().line_no == get_line_no(intermediary, 2) + + # Functions to test marking, with relative position of the assertions + functions = [ + (test_group_marking, 6), + (helper, 1), + (intermediary, 2), + ] + current_function = inspect.currentframe().f_code.co_name + for function, relative_position in functions: + # To prevent infinite recursion + if function.__name__ != current_function: + function(result) + result_entry = result.entries.pop() + code_context = get_code_context(function, relative_position) + assert result_entry.line_no == code_context[0] + assert result_entry.code_context == code_context[1] @testsuite @@ -102,6 +114,7 @@ def test_group_marking_multitest(mockplan, flag): testcase_report_target=flag, ) test.cfg.parent = mockplan.cfg + test.cfg.collect_code_context = True test.run() assertions = { entry["description"]: entry @@ -109,14 +122,15 @@ def test_group_marking_multitest(mockplan, flag): if isinstance(entry, dict) and entry["meta_type"] == "assertion" } expected = { - "A": get_line_no(GroupMarking.case, 2), - "B": get_line_no(GroupMarking.case, 3) + "A": get_code_context(GroupMarking.case, 2), + "B": get_code_context(GroupMarking.case, 3) if flag - else get_line_no(helper, 1), - "C": get_line_no(intermediary, 2), + else get_code_context(helper, 1), + "C": get_code_context(intermediary, 2), } - for desc, line_no in expected.items(): - assert assertions[desc]["line_no"] == line_no + for desc, code_context in expected.items(): + assert assertions[desc]["line_no"] == code_context[0] + assert assertions[desc]["code_context"] == code_context[1] @pytest.mark.parametrize("flag", [True, False]) @@ -131,6 +145,7 @@ def test_parametrized_group_marking_multitest(mockplan, flag): testcase_report_target=flag, ) test.cfg.parent = mockplan.cfg + test.cfg.collect_code_context = True test.run() assertions = { entry["description"]: entry @@ -138,11 +153,11 @@ def test_parametrized_group_marking_multitest(mockplan, flag): if isinstance(entry, dict) and entry["meta_type"] == "assertion" } expected = { - "A0": get_line_no(ParametrizedGroupMarking.case, 2), - "B0": get_line_no(ParametrizedGroupMarking.case, 3) + "A0": get_code_context(ParametrizedGroupMarking.case, 2), + "B0": get_code_context(ParametrizedGroupMarking.case, 3) if flag - else get_line_no(helper, 1), - "C0": get_line_no(intermediary, 2), + else get_code_context(helper, 1), + "C0": get_code_context(intermediary, 2), } expected.update( { @@ -151,12 +166,13 @@ def test_parametrized_group_marking_multitest(mockplan, flag): "C1": expected["C0"], } ) - for desc, line_no in expected.items(): - assert assertions[desc]["line_no"] == line_no + for desc, code_context in expected.items(): + assert assertions[desc]["line_no"] == code_context[0] + assert assertions[desc]["code_context"] == code_context[1] @pytest.mark.parametrize("flag", [True, False]) -def test_parametrized_group_marking_multitest(mockplan, flag): +def test_decorated_testcase_marking_multitest(mockplan, flag): """ Tests, at MultiTest-level, if marking works as expected for testcase which is decorated by other functions. @@ -167,6 +183,7 @@ def test_parametrized_group_marking_multitest(mockplan, flag): testcase_report_target=flag, ) test.cfg.parent = mockplan.cfg + test.cfg.collect_code_context = True test.run() assertions = { entry["description"]: entry @@ -174,12 +191,13 @@ def test_parametrized_group_marking_multitest(mockplan, flag): if isinstance(entry, dict) and entry["meta_type"] == "assertion" } expected = { - "Pre": get_line_no(pre_fn, 1), - "Case": get_line_no(PrePostTestcaseMarking.case, 4), - "Post": get_line_no(post_fn, 1), + "Pre": get_code_context(pre_fn, 1), + "Case": get_code_context(PrePostTestcaseMarking.case, 4), + "Post": get_code_context(post_fn, 1), } - for desc, line_no in expected.items(): - assert assertions[desc]["line_no"] == line_no + for desc, code_context in expected.items(): + assert assertions[desc]["line_no"] == code_context[0] + assert assertions[desc]["code_context"] == code_context[1] @testsuite