63 schemaFolderPath =
"./../types/schemas/"
64 schemaFolderPath = os.path.abspath(
65 os.path.join(os.path.dirname(__file__), schemaFolderPath)
68 schemaFilePath = os.path.join(schemaFolderPath, f
"{fname}.fbs")
69 if not os.path.isfile(schemaFilePath):
72 schemaFile = open(schemaFilePath,
"r")
79 for line
in schemaFile:
82 match = re.search(
r'^table [a-zA-Z_]*_fb', line)
84 line = line.strip().split()
85 tableIdx = line.index(
"table")
86 schemaTableName = line[tableIdx + 1]
89 line = line.strip().split()
90 subNameIdx = line.index(
"table")
91 subName = line[subNameIdx + 1]
92 subTables[subName] = []
95 if not inTable
and "{" in line:
110 lineParts = line.strip().rstrip(
";").split(
":")
112 type = lineParts[1].split()[0]
114 if curSubTable
is not None:
116 subTables[curSubTable].append((name, type))
118 schemaFieldInfo.append((name, type))
121 if len(subTables) == 0:
122 return schemaTableName, tuple(schemaFieldInfo)
126 newSchemaFieldInfo = []
127 for field
in schemaFieldInfo:
129 if fieldType
in subTables.keys():
130 newSchemaFieldInfo.append({field[0] : subTables[fieldType]})
132 newSchemaFieldInfo.append(field)
134 return schemaTableName, tuple(newSchemaFieldInfo)
138Quick check that the types in .fbs correspond, mainly strings match to strings,
139and vectors to vectors.
140If they do not correspond, the behavior for comparing the fb values in the tests
141is undefined, and action beyond this generator will need to be taken.
180 headerFile = open(hppFname,
"r")
181 headerLines = headerFile.readlines()
184 fNameParts = hppFname.split(
"/")
185 returnInfo[
"name"] = fNameParts[-1].strip().split(
".")[0]
186 CamelCase =
"".join([word.capitalize()
for word
in returnInfo[
"name"].split(
"_")])
187 returnInfo[
"nameCamelCase"] = CamelCase[0].lower() + CamelCase[1:]
189 returnInfo[
"genTestFname"] = f
"{returnInfo['name']}_generated_tests.cpp"
190 returnInfo[
"className"] =
"C" +
"".join([word.capitalize()
for word
in returnInfo[
"name"].split(
"_")])
191 returnInfo[
"classVarName"] =
"".join([word[0].lower()
for word
in returnInfo[
"name"].split(
"_")])
197 if returnInfo[
"name"]
not in baseTypesDict:
198 baseTypesDict[returnInfo[
"name"]] = set()
205 fbMethodName = f
"Create{returnInfo["name
"][0].upper() + returnInfo["name
"][1:]}_fb"
207 messageStructIdxs = []
208 for i
in range(len(headerLines)):
209 if "messageT(" in headerLines[i]:
210 messageStructIdxs.append(i)
211 if fbMethodName
in headerLines[i]:
215 returnInfo[
"schemaTableName"] = schemaTableName
218 if len(messageStructIdxs) == 0:
220 if returnInfo[
"baseType"]
not in baseTypesDict:
221 baseTypesDict[returnInfo[
"baseType"]] = set()
224 baseTypesDict[returnInfo[
"baseType"]].add(returnInfo[
"name"])
230 for line
in headerLines:
231 if re.search(
"^.*Create[a-zA-Z_]*_fb.*$", line)
and returnInfo[
"schemaTableName"] ==
"":
233 startIndex = line.find(
"Create") + len(
"Create")
234 endIndex = line.find(
"_fb")
235 returnInfo[
"schemaTableName"] = f
"{line[startIndex:endIndex]}_fb"
237 returnInfo[
"messageTypes"] =
getMessageFieldInfo(messageStructIdxs, headerLines, schemaFieldInfo)
242Parse out field type and name from string
246 typeIdxStart = 1
if (lineParts[0] ==
"const")
else 0
247 fieldType = lineParts[typeIdxStart]
249 if lineParts[typeIdxStart + 1] ==
"&":
250 nameIdx = (typeIdxStart + 2)
251 elif lineParts[typeIdxStart + 1] ==
"*":
252 nameIdx = (typeIdxStart + 2)
255 nameIdx = (typeIdxStart + 1)
257 name = lineParts[nameIdx].rstrip(
")").rstrip(
",")
262 name = name.lstrip(
"&*")
264 return fieldType, name
267Checks if log type has a corresponding generated .h file in ./types/generated
270 generatedFolderPath =
"./../types/generated/"
271 generatedFolderPath = os.path.abspath(
272 os.path.join(os.path.dirname(__file__), generatedFolderPath)
275 generatedFilePath = os.path.join(generatedFolderPath, f
"{logName}_generated.h")
276 if os.path.isfile(generatedFilePath):
338 if "bool" in fieldType
or (schemaFieldType
is not None and "bool" in schemaFieldType):
340 elif "string" in fieldType
or "char *" in fieldType:
341 if gIncrementingVals:
342 gNextVals[
"string"] += 1
343 return f
'"{gNextVals["string"]}"'
344 randString =
''.join(random.choices(string.ascii_lowercase + string.digits, k=10))
345 return f
'"{randString}"'
346 elif "int" in fieldType:
347 if gIncrementingVals:
351 return f
'{str(getRandInt(fieldType))}u' if "uint64_t" in fieldType
else str(
getRandInt(fieldType))
352 elif "float" in fieldType:
353 if gIncrementingVals:
354 gNextVals[
"float"] += 1
355 return str(round( (gNextVals[
"float"] / 100000), 6))
356 return str(round(random.random(), 6))
357 elif "double" in fieldType:
358 if gIncrementingVals:
359 gNextVals[
"double"] += 1
360 return str(round( (gNextVals[
"double"] / 10000000000), 14))
361 return str(round(random.random(), 14))
390 subTableDictIndex = 0
393 for i
in range(len(messageStructIdxs)):
394 structIdx = messageStructIdxs[i]
399 while not closed
and structIdx < len(lines):
401 line = lines[structIdx]
405 if (
"//" in line
and line.find(
")") > line.find(
"//")):
408 elif line.strip().strip(
")") ==
"":
415 indexStart = (line.find(
"messageT(") + len(
"messageT("))
if "messageT(" in line
else 0
419 indexEnd = line.find(
"//")
420 elif "/*" in line
and line.find(
"/*") < indexEnd:
421 indexEnd = line.find(
"/*")
424 if "=" in line
and line.find(
"=") < indexEnd:
425 indexEnd = line.find(
"=")
427 line = line[indexStart:indexEnd].strip()
429 lineParts = [part.strip().split()
for part
in line.strip().rstrip(
",").split(
",")]
431 for field
in lineParts:
433 if len(field) > 0
and "//" in field[0]:
441 fieldDict[
"type"] = type
442 fieldDict[
"name"] = name
444 if "std::vector" in fieldDict[
"type"]:
445 typeParts = fieldDict[
"type"].split(
"<")
446 vectorIdx = [i
for i, e
in enumerate(typeParts)
if "std::vector" in e][0]
447 vectorType = typeParts[vectorIdx + 1].strip(
">")
448 fieldDict[
"vectorType"] = vectorType
450 if len(schemaFieldInfo) != 0:
451 if isinstance(schemaFieldInfo[fieldCount], tuple):
452 fieldDict[
"schemaName"] = schemaFieldInfo[fieldCount][0]
453 fieldDict[
"schemaType"] = schemaFieldInfo[fieldCount][1]
457 subTableName = next(iter(schemaFieldInfo[fieldCount]))
458 schemaFieldName = schemaFieldInfo[fieldCount][subTableName][subTableDictIndex][0]
459 schemaFieldType = schemaFieldInfo[fieldCount][subTableName][subTableDictIndex][1]
460 fieldDict[
"schemaName"] = f
"{subTableName}()->{schemaFieldName}"
461 fieldDict[
"schemaType"] = schemaFieldType
462 subTableDictIndex += 1
463 if (subTableDictIndex >= len(schemaFieldInfo[fieldCount][subTableName])):
465 subTableDictIndex = 0
473 del fieldDict[
"schemaName"]
478 msgsFieldsList.append(fieldDict)
482 msgTypesList.append(msgsFieldsList)
489 baseFilePath = os.path.join(typesFolderPath, f
"{baseName}.hpp")
490 baseHFile = open(baseFilePath,
"r")
494 returnInfo[
"name"] = logName
495 returnInfo[
"genTestFname"] = f
"{returnInfo['name']}_generated_tests.cpp"
496 returnInfo[
"className"] =
"C" +
"".join([word.capitalize()
for word
in returnInfo[
"name"].split(
"_")])
497 CamelCase =
"".join([word.capitalize()
for word
in returnInfo[
"name"].split(
"_")])
498 returnInfo[
"nameCamelCase"] = CamelCase[0].lower() + CamelCase[1:]
499 returnInfo[
"classVarName"] =
"".join([word[0].lower()
for word
in returnInfo[
"name"].split(
"_")])
500 returnInfo[
"baseType"] = baseName
504 baseHLines = baseHFile.readlines()
507 messageStructIdxs = []
508 for i
in range(len(baseHLines)):
509 if "messageT(" in baseHLines[i]:
510 messageStructIdxs.append(i)
514 returnInfo[
"schemaTableName"] = schemaTableName
517 returnInfo[
"messageTypes"] = [[]]
if "empty_log" in baseName
else msgFieldInfo
527 print(
"Error: Python version must be >= 3.9")
531 global gIncrementingVals
532 gIncrementingVals =
False
536 opts, args = getopt.getopt(sys.argv[1:],
"is:")
538 print(
"Error: Only one option allowed. -s <seed> or -i for incrementing values.")
541 except getopt.GetoptError:
542 print(
"Usage: python3 ./generateTemplatedCatch2Tests.py -s <seed> | -i")
544 for opt, arg
in opts:
546 if not arg.isdigit():
547 print(f
"Error: random seed {arg} provided is not an integer.")
550 random.seed(int(arg))
552 gIncrementingVals =
True
555 env = jinja2.Environment(
556 loader = jinja2.FileSystemLoader(searchpath=os.path.dirname(__file__))
558 env.trim_blocks =
True
559 env.lstrip_blocks =
True
561 catchTemplate = env.get_template(
"catch2TestTemplate.jinja2")
564 typesFolderPath =
"./../types"
565 typesFolderPath = os.path.abspath(
566 os.path.join(os.path.dirname(__file__), typesFolderPath)
570 generatedTestsFolderPath =
"./generated_tests/"
571 generatedTestsFolderPath = os.path.abspath(
572 os.path.join(os.path.dirname(__file__), generatedTestsFolderPath)
576 pathlib.Path(generatedTestsFolderPath).mkdir(exist_ok=
True)
577 oldFiles = glob.glob(os.path.join(generatedTestsFolderPath,
"*"))
578 for file
in oldFiles:
581 types = os.listdir(typesFolderPath)
583 baseTypesDict = dict()
588 if ".hpp" not in type:
592 if "software" in type:
601 typePath = os.path.join(typesFolderPath, type)
610 renderedHeader = catchTemplate.render(info)
613 outPath = os.path.join(generatedTestsFolderPath, info[
"genTestFname"])
614 with open(outPath,
"w")
as outfile:
615 print(renderedHeader,file=outfile)
618 for baseType, inheritedTypes
in baseTypesDict.items():
620 if len(inheritedTypes) == 0:
623 for inheritedType
in inheritedTypes:
630 renderedHeader = catchTemplate.render(info)
633 outPath = os.path.join(generatedTestsFolderPath, info[
"genTestFname"])
634 with open(outPath,
"w")
as outfile:
635 print(renderedHeader,file=outfile)