18def findMatchedParenthesis(string: str, openchar: str, closechar: str) -> int:
19 """Find matching control token in string.
23 openchar (str): opening char e.g '{'
24 closechar (str): closing char e.g
'}'
27 int: position of matching closing char
in string.
30 if string[0] == openchar:
32 while end < len(string)
and count > 0:
33 if string[end] == openchar:
35 elif string[end] == closechar:
43 Determine metavariable types from source code
and assert correctness
49 "softwareTriggerResult":
"double",
51 "softwareTriggerResultNonPrescaled":
"double",
52 "isDaughterOfList":
"bool",
53 "isGrandDaughterOfList":
"bool",
54 "daughterDiffOf":
"double",
55 "daughterDiffOfPhi":
"double",
56 "daughterDiffOfClusterPhi":
"double",
57 "mcDaughterDiffOfPhi":
"double",
58 "grandDaughterDiffOf":
'double',
59 "grandDaughterDiffOfPhi":
"double",
60 "grandDaughterDiffOfClusterPhi":
"double",
61 "daughterDiffOfPhiCMS":
"double",
62 "daughterDiffOfClusterPhiCMS":
"double",
67 registering_regex = re.compile(
68 r"(?s)REGISTER_METAVARIABLE.*?Manager::VariableDataType::(?:c_double|c_int|c_bool)"
71 extract_regex = re.compile(
72 r'REGISTER_METAVARIABLE\(".*?",(?P<function_name>[^,]*),.*?Manager::VariableDataType::c_(?P<enumtype>double|bool|int)'
75 lambda_type_regex = re.compile(
r"-> (?P<lambdatype>double|bool|int)")
78 """Check all metavariable types for specified file.
81 filepath (str): path to file containing REGISTER_METAVARIABLE
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.
89 int: number of metavariables
in file.
90 Used
for sanity checks of the coverage.
94 with open(filepath)
as fp:
95 filecontent = fp.read()
101 registering_statements = list(
103 lambda line: line.replace(
" ",
"").replace(
"\n",
""),
104 registering_statements,
108 for statement
in registering_statements:
111 function_name = match_content.groupdict()[
"function_name"]
112 enumtype = match_content.groupdict()[
"enumtype"]
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}",
125 function_definition_regex = re.compile(
126 r"Manager::FunctionPtr %s\(.*\)[^\{]*" % function_name
129 regular_definition_regex = re.compile(
130 r"(?P<return_type>double|int|bool) %s\(.*?\)" % function_name
134 definition = function_definition_regex.search(filecontent)
135 if definition
is not None:
136 func_body_start = definition.end()
140 regular_definition_regex.search(filecontent)
144 if return_type
is not None:
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",
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."
163 func_body_end = func_body_start + findMatchedParenthesis(
164 filecontent[func_body_start:],
"{",
"}"
167 func_body = filecontent[func_body_start:func_body_end]
171 if lambdatype_match
is not None:
172 lambdatype = lambdatype_match.groupdict()[
"lambdatype"]
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.",
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"
193 return len(registering_statements)
196 """Metavariables have to be registered with the correct Manager::Variable::VariableDataType enum value. This test makes sure Metavariable definition and variable registration are correct."""
199 subprocess.run([
"grep",
"-V"], check=
True, capture_output=
True)
200 except subprocess.CalledProcessError:
201 logging.basicConfig(format=
"%(message)s")
203 "TEST SKIPPED: MetavariableDataTypeTest skipped because grep is not available."
208 analysis_module = basf2.find_file(
"analysis")
209 files = subprocess.run(
212 "REGISTER_METAVARIABLE",
221 files = files.stdout.decode().split(
"\n")
222 files = list(filter(
lambda file: file.endswith(
".cc"), files))
224 num_files = len(files)
225 print(f
"Number of files including meta-variables is {num_files}")
228 self.assertGreaterEqual(num_files, 13)
230 num_metavariables = 0
231 for filepath
in files:
235 print(f
"Number of meta-variables is {num_metavariables}")
236 self.assertGreaterEqual(num_metavariables, 237)
239if __name__ ==
"__main__":