Coverage for src/castep_linter/tests/has_trace_entry_exit.py: 93%
55 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-23 18:07 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-23 18:07 +0000
1"""Test that a subroutine or function has a trace_entry and trace_exit with the correct name"""
2from castep_linter.error_logging import ErrorLogger
3from castep_linter.fortran import CallExpression, FType, VariableDeclaration
4from castep_linter.fortran.fortran_node import Fortran, FortranNode, WrongNodeError
5from castep_linter.fortran.identifier import Identifier
6from castep_linter.tests import castep_identifiers
9def test_trace_entry_exit(node: FortranNode, error_log: ErrorLogger) -> None:
10 """Test that a subroutine or function has a trace_entry and trace_exit with the correct name"""
12 if node.is_type(Fortran.SUBROUTINE):
13 subroutine_name = Identifier.from_node(node.get(Fortran.SUBROUTINE_STMT).get(Fortran.NAME))
14 elif node.is_type(Fortran.FUNCTION): 14 ↛ 17line 14 didn't jump to line 17, because the condition on line 14 was never false
15 subroutine_name = Identifier.from_node(node.get(Fortran.FUNCTION_STMT).get(Fortran.NAME))
16 else:
17 err = "Wrong node type passed"
18 raise WrongNodeError(err)
20 has_trace_entry = False
21 has_trace_exit = False
23 const_string_vars = {}
25 for var_node in node.get_children_by_name(Fortran.VARIABLE_DECLARATION):
26 var_decl = VariableDeclaration(var_node)
28 if var_decl.type != FType.CHARACTER:
29 continue
31 for var_name, initial_value in var_decl.vars.items():
32 if initial_value:
33 const_string_vars[var_name] = initial_value.lower()
35 for statement in node.get_children_by_name(Fortran.SUBROUTINE_CALL):
36 routine = CallExpression(statement)
38 if routine.name == castep_identifiers.TRACE_ENTRY:
39 has_trace_entry = True
40 elif routine.name == castep_identifiers.TRACE_EXIT:
41 has_trace_exit = True
43 if routine.name in [castep_identifiers.TRACE_ENTRY, castep_identifiers.TRACE_EXIT]:
44 try:
45 _, trace_node = routine.get_arg(position=1, keyword=castep_identifiers.TRACE_STRING)
46 except KeyError:
47 err = f"Unparsable name passed to trace in {subroutine_name}"
48 error_log.add_msg("Error", statement, err)
49 continue
51 if trace_node.is_type(Fortran.STRING_LITERAL):
52 trace_string = trace_node.parse_string_literal().lower()
53 if trace_string != subroutine_name:
54 err = f"Incorrect name passed to trace in {subroutine_name}"
55 error_log.add_msg("Error", trace_node, err)
57 elif trace_node.is_type(Fortran.IDENTIFIER): 57 ↛ 74line 57 didn't jump to line 74, because the condition on line 57 was never false
58 trace_sub_text = Identifier.from_node(trace_node)
60 if trace_sub_text in const_string_vars:
61 trace_string = const_string_vars[trace_sub_text]
63 if trace_string.lower() != subroutine_name:
64 err = (
65 f"Incorrect name passed to trace in {subroutine_name} "
66 f'by variable {trace_sub_text}="{trace_string}"'
67 )
68 error_log.add_msg("Error", trace_node, err)
69 else:
70 err = f"Unidentified variable {trace_sub_text} passed to trace in {subroutine_name}"
71 error_log.add_msg("Error", trace_node, err)
73 else:
74 err = f"Unrecognisable {statement.raw} {trace_node.type=} {statement}"
75 raise ValueError(err)
77 if not has_trace_entry:
78 error_log.add_msg("Warning", node, f"Missing trace_entry in {subroutine_name}")
79 if not has_trace_exit:
80 error_log.add_msg("Warning", node, f"Missing trace_exit in {subroutine_name}")