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