77 def process_file(self, filepath: str) -> int:
78 """Check all metavariable types for specified file.
79
80 Args:
81 filepath (str): path to file containing REGISTER_METAVARIABLE
82
83 Raises:
84 AssertionError: Raised if no expected function definition is found.
85 AssertionError: Rased if lambda function has no associated
86 type information, or no lambda function is defined.
87
88 Returns:
89 int: number of metavariables in file.
90 Used for sanity checks of the coverage.
91 """
92
93
94 with open(filepath) as fp:
95 filecontent = fp.read()
96
97
98 registering_statements = self.registering_regex.findall(filecontent)
99
100
101 registering_statements = list(
102 map(
103 lambda line: line.replace(" ", "").replace("\n", ""),
104 registering_statements,
105 ),
106 )
107
108 for statement in registering_statements:
109
110 match_content = self.extract_regex.match(statement)
111 function_name = match_content.groupdict()["function_name"]
112 enumtype = match_content.groupdict()["enumtype"]
113
114 if function_name in self.hardcoded:
115 self.assertEqual(
116 enumtype,
117 self.hardcoded[function_name],
118 f"Metavariable '{function_name}' in file {filepath}:\n"
119 f"Metavariable function return type and Manager::VariableDataType have to match.\n"
120 f"Expected: Manager::VariableDataType::{self.hardcoded[function_name]}, actual: Manager::VariableDataType::{enumtype}",
121 )
122 continue
123
124
125 function_definition_regex = re.compile(
126 r"Manager::FunctionPtr %s\(.*\)[^\{]*" % function_name
127 )
128
129 regular_definition_regex = re.compile(
130 r"(?P<return_type>double|int|bool) %s\(.*?\)" % function_name
131 )
132
133
134 definition = function_definition_regex.search(filecontent)
135 if definition is not None:
136 func_body_start = definition.end()
137 else:
138
139 return_type = (
140 regular_definition_regex.search(filecontent)
141 .groupdict()
142 .get("return_type")
143 )
144 if return_type is not None:
145 self.assertEqual(
146 return_type,
147 enumtype,
148 f"Metavariable '{function_name}' in file {filepath}:\n"
149 "Metavariable function return type and Manager::VariableDataType have to match."
150 f"Return type is {return_type} but it is registered as Manager::VariableDataType::c_{enumtype}.\n",
151 )
152 continue
153 else:
154 raise AssertionError(
155 f"Metavariable '{function_name}' in file {filepath}:\n"
156 "Metavariable function return type and Manager::VariableDataType have to match."
157 "Return type of function could not be automatically determined from the source code."
158 "You can add an exception by adding the expected return type information to "
159 "the 'hardcoded' dictionary of this testcase."
160 )
161
162
163 func_body_end = func_body_start + findMatchedParenthesis(
164 filecontent[func_body_start:], "{", "}"
165 )
166
167 func_body = filecontent[func_body_start:func_body_end]
168
169
170 lambdatype_match = self.lambda_type_regex.search(func_body)
171 if lambdatype_match is not None:
172 lambdatype = lambdatype_match.groupdict()["lambdatype"]
173 self.assertEqual(
174 lambdatype,
175 enumtype,
176 f"Metavariable '{function_name}' in file {filepath}:\n"
177 f"Lambda function has return type {lambdatype} "
178 f"but is registered with Manager::VariableDataType::c_{enumtype}.\n"
179 "VariableDataType and lambda return type have to match.",
180 )
181 else:
182 raise AssertionError(
183 f"Metavariable '{function_name}' in {filepath}:\n"
184 "VariableDataType and lambda definition have to match.\n"
185 "Either lambda function is missing return type information"
186 ", or lambda definition could not be found.\n"
187 "Please add return type annotation '(const Particle * particle) -> double/int/bool' to lambda.\n"
188 "Or add this metavariable as exception, by adding the expected return type information in the 'hardcoded' dictionary of this testcase\n"
189 f"{func_body}"
190 )
191
192
193 return len(registering_statements)
194