diff --git a/JsonPreprocessor/CJsonPreprocessor.py b/JsonPreprocessor/CJsonPreprocessor.py index 5a4d71c..151dba8 100644 --- a/JsonPreprocessor/CJsonPreprocessor.py +++ b/JsonPreprocessor/CJsonPreprocessor.py @@ -51,6 +51,7 @@ import sys import copy import shlex +import hashlib from PythonExtensionsCollection.String.CString import CString from enum import Enum @@ -71,6 +72,7 @@ class CNameMangling(Enum): LISTINDEX = "__IndexOfList__" SLICEINDEX = "__SlicingIndex__" STRINGVALUE = "__StringValueMake-up__" + HANDLEIMPORTED = "__CheckImportedHandling__" DYNAMICIMPORTED = "__DynamicImportedHandling__" class CPythonJSONDecoder(json.JSONDecoder): @@ -152,12 +154,65 @@ def __init__(self, keyPattern): self.errorMsg = '' def keyNameChecker(self, sKeyName: str): + if sKeyName=='' or regex.match(r'^\s+$', sKeyName): + self.errorMsg = f"Empty key name detected. Please enter a valid name." + return False if regex.match(self.keyPattern, sKeyName): return True else: self.errorMsg = f"Error: Key name '{sKeyName}' is invalid. Expected format: '{self.keyPattern}'" return False +class CTreeNode(): + """ +The CTreeNode class is a custom tree data structure that allows to create and manage hierarchical data. + """ + + def __init__(self, value, parent=None): + self.value = value + self.parent = parent + self.children = {} # Dictionary to store children + + def addChild(self, value): + """ +Add a child node to the current node. + +**Arguments:** + +* ``value`` + + / *Condition*: required / *Type*: str / + + The value for the new child node. + +**Returns:** + + The new or existing child node. + """ + if value in self.children: + return self.children[value] + childNode = CTreeNode(value, parent=self) + self.children[value] = childNode + return childNode + + def getPathToRoot(self): + """ +Retrieve the path from this node to the root. + """ + path = [] + current = self + while current: + path.append(current.value) + current = current.parent + return path[::-1] + + # def display(self, level=0): + # if self is None: + # pass + # print(" " * level + str(self.value)) + # for child in self.children.values(): + # child.display(level + 1) + class CJsonPreprocessor(): """ CJsonPreprocessor extends the JSON syntax by the following features: @@ -213,12 +268,15 @@ def __init__(self, syntax: CSyntaxType = CSyntaxType.python , currentCfg : dict self.specialCharacters = r"!#$%^&()=[]{}|;',?`~" self.lDataTypes.append(keyword.kwlist) self.jsonPath = None + self.importTree = None + self.currentNode = None self.masterFile = None self.handlingFile = [] + self.importCheck = [] + self.recursive_level = 0 + self.bDynamicImport = False self.iDynamicImport = 0 self.lDynamicImports = [] - self.lImportedFiles = [] - self.recursive_level = 0 self.syntax = syntax self.currentCfg = currentCfg self.dUpdatedParams = {} @@ -258,12 +316,15 @@ def __reset(self) -> None: Reset initial variables which are set in constructor method after master JSON file is loaded. """ self.jsonPath = None + self.importTree = None + self.currentNode = None self.masterFile = None self.handlingFile = [] + self.importCheck = [] + self.recursive_level = 0 + self.bDynamicImport = False self.iDynamicImport = 0 self.lDynamicImports = [] - self.lImportedFiles = [] - self.recursive_level = 0 self.dUpdatedParams = {} self.lDotInParamName = [] self.bJSONPreCheck = False @@ -313,7 +374,10 @@ def __processImportFiles(self, input_data : dict) -> dict: raise Exception(errorMsg) if '${' in value: if not self.bJSONPreCheck: # self.bJSONPreCheck is set True when handling pre-check JSON files by __preCheckJsonFile() - value = self.lDynamicImports.pop(0) + for item in self.lDynamicImports: + if value == next(iter(item)): + value = item[value] + break if '${' in value: dynamicImported = regex.search(rf'^(.*){CNameMangling.DYNAMICIMPORTED.value}(.*)$', value) value = self.__removeTokenStr(dynamicImported[2]) @@ -327,32 +391,40 @@ def __processImportFiles(self, input_data : dict) -> dict: else: if regex.match(r'^\[\s*import\s*\]$', key.strip()): self.iDynamicImport +=1 + tmpValue = value value = self.jsonPath + CNameMangling.DYNAMICIMPORTED.value + value out_dict[f"{key.strip()}_{self.iDynamicImport}"] = value - self.lDynamicImports.append(value) + self.lDynamicImports.append({tmpValue:value}) else: out_dict[key] = value if '${' not in value: if regex.match(r'^\[\s*import\s*\]_\d+$', key): dynamicIpmportIndex = regex.search(r'_(\d+)$', key)[1] - self.lDynamicImports[int(dynamicIpmportIndex)-1] = value + tmpValue = next(iter(self.lDynamicImports[int(dynamicIpmportIndex)-1])) + self.lDynamicImports[int(dynamicIpmportIndex)-1][tmpValue] = value currJsonPath = self.jsonPath abs_path_file = CString.NormalizePath(value, sReferencePathAbs = currJsonPath) - - # Use recursive_level and lImportedFiles to avoid cyclic import self.recursive_level = self.recursive_level + 1 # increase recursive level - - # length of lImportedFiles should equal to recursive_level - self.lImportedFiles = self.lImportedFiles[:self.recursive_level] if self.masterFile is not None else \ - self.lImportedFiles[:self.recursive_level-1] - if abs_path_file in self.lImportedFiles: - raise Exception(f"Cyclic imported json file '{abs_path_file}'!") - + if not self.bDynamicImport or not self.bJSONPreCheck or self.currentNode.value==abs_path_file: + importPath = self.currentNode.getPathToRoot() # Get the import path from importTree to check Cyclic import + if abs_path_file in importPath: + previousImport1 = importPath[0] + previousImport2 = importPath[-1] + for path in importPath: + if path == abs_path_file: + break + previousImport1 = path + if previousImport1 == abs_path_file or previousImport2 == abs_path_file: + errorMsg = f"Cyclic import detection: The file '{abs_path_file}' imports itself." + else: + errorMsg = f"Cyclic import detection: The file '{abs_path_file}' is imported by '{previousImport1}' and by file '{previousImport2}'." + raise Exception(errorMsg) oJsonImport = self.jsonLoad(abs_path_file) - bDynamicImportCheck = False + if not self.bJSONPreCheck and self.currentNode.parent is not None: + self.currentNode = self.currentNode.parent for k, v in oJsonImport.items(): - if regex.match('^\s*\[\s*import\s*\]\s*', k) and '${' in v: - bDynamicImportCheck = True + if regex.match(r'^\s*\[\s*import\s*\]\s*', k) and '${' in v: + self.bDynamicImport = True break self.jsonPath = currJsonPath tmpOutdict = copy.deepcopy(out_dict) @@ -362,8 +434,9 @@ def __processImportFiles(self, input_data : dict) -> dict: del out_dict[k1] del tmpOutdict out_dict.update(oJsonImport) - if not bDynamicImportCheck: - self.recursive_level = self.recursive_level - 1 # descrease recursive level + self.recursive_level = self.recursive_level - 1 # descrease recursive level + if len(self.handlingFile) > 1: + self.handlingFile.pop(-1) else: if not self.bJSONPreCheck: specialCharacters = r'$[]{}\'' @@ -556,7 +629,7 @@ def __parseDictPath(self, sInput : str) -> list: elif regex.match(r"^\[[^\[]+\]$", sInput): lOutput.append(regex.sub(r"^\[\s*([^\[]+)\s*\]", "\\1", sInput)) else: - if not regex.match('^\s*\[.+$', sInput): + if not regex.match(r'^\s*\[.+$', sInput): index = sInput.index("[") lOutput.append(sInput[:index]) elements = regex.findall(rf"\[\s*('*[^{regex.escape(specialCharacters)}]+'*)\s*\]", sInput) @@ -589,6 +662,7 @@ def __getNestedValue(sNestedParam : str): lElements = self.__parseDictPath(sParameter) sExec = "value = self.JPGlobals" oTmpObj = self.JPGlobals + i=0 for element in lElements: bList = False if regex.match(r"^[\s\-\+]*\d+$", element): @@ -598,7 +672,8 @@ def __getNestedValue(sNestedParam : str): try: exec(sExec) except: - sExec = f"{tmpExec}['{element}']" + if i==0: # Handle cases one digit key name + sExec = f"{tmpExec}['{element}']" pass elif regex.match(r"^'[^']+'$", element.strip()): element = element.strip("'") @@ -617,6 +692,7 @@ def __getNestedValue(sNestedParam : str): if int(element)1: + while regex.search(tmpPattern, sInputStr, regex.UNICODE) and sInputStr.count("$${")>1: sLoopCheck = sInputStr referVars = regex.findall(rf'({tmpPattern})[^\[]', sInputStr, regex.UNICODE) if len(referVars)==0: @@ -677,7 +753,7 @@ def __getNestedValue(sNestedParam : str): if (isinstance(tmpValue, list) or isinstance(tmpValue, dict)) and bConvertToStr: self.__reset() sVar = self.__removeTokenStr(sVar) - raise Exception(f"The substitution of parameter '{sVar.replace('$$', '$')}' inside the string \ + raise Exception(f"The substitution of parameter '{sVar.replace('$${', '${')}' inside the string \ value '{sNestedParam}' is not allowed! Composite data types like lists and dictionaries cannot be substituted inside strings.") while var[0] in sInputStr: sLoopCheck1 = sInputStr @@ -687,7 +763,7 @@ def __getNestedValue(sNestedParam : str): if (isinstance(tmpValue, list) or isinstance(tmpValue, dict)): self.__reset() sVar = self.__removeTokenStr(sVar) - raise Exception(f"The substitution of parameter '{sVar.replace('$$', '$')}' inside \ + raise Exception(f"The substitution of parameter '{sVar.replace('$${', '${')}' inside \ the expression '{sNestedParam}' is not allowed! Composite data types like lists and dictionaries cannot be substituted as strings.") sInputStr = regex.sub(rf"\[\s*'\s*{varPattern}\s*'\s*\]", f"['{tmpValue}']", sInputStr) elif isinstance(tmpValue, str): @@ -695,7 +771,7 @@ def __getNestedValue(sNestedParam : str): elif isinstance(tmpValue, int): sInputStr = regex.sub(rf"\[['\s]*{varPattern}['\s]*\]", f"[{tmpValue}]", sInputStr) else: - var = var[0].replace("$$", "$") + var = var[0].replace("$${", "${") sParentParam = regex.search(rf'^\s*(.+)\[[\s\']*{varPattern}.*$', sInputStr)[1] parentValue = None var = self.__removeTokenStr(var) @@ -756,18 +832,18 @@ def __getNestedValue(sNestedParam : str): except Exception as error: if self.bJSONPreCheck: sNestedParam = self.__removeTokenStr(sNestedParam) - tmpValue = sNestedParam.replace('$$', '$') + tmpValue = sNestedParam.replace('$${', '${') pass else: self.__reset() errorMsg = '' for errorType in self.pythonTypeError: if errorType in str(error): - errorMsg = f"Could not resolve expression '{sNestedParam.replace('$$', '$')}'." + errorMsg = f"Could not resolve expression '{sNestedParam.replace('$${', '${')}'." if errorMsg != '': errorMsg = f"{errorMsg} Reason: {error}" else: - errorMsg = f"The parameter '{sNestedParam.replace('$$', '$')}' is not available!" + errorMsg = f"The parameter '{sNestedParam.replace('$${', '${')}' is not available!" raise Exception(errorMsg) return tmpValue else: @@ -779,13 +855,13 @@ def __getNestedValue(sNestedParam : str): dataType = regex.sub(r"^.+'([a-zA-Z]+)'.*$", "\\1", str(type(tmpValue))) self.__reset() sVar = self.__removeTokenStr(sVar) - raise Exception(f"The substitution of parameter '{sVar.replace('$$', '$')}' inside the string \ + raise Exception(f"The substitution of parameter '{sVar.replace('$${', '${')}' inside the string \ value '{sNestedParam}' is not allowed! Composite data types like lists and dictionaries cannot be substituted inside strings.") if regex.match(rf"^\s*{tmpPattern}\s*$", sInputStr, regex.UNICODE) and not bKey: return tmpValue else: sInputStr = sInputStr.replace(var[0], str(tmpValue)) - return sInputStr.replace("$$", "$") if "$$" in sInputStr else sInputStr + return sInputStr.replace("$${", "${") if "$${" in sInputStr else sInputStr def __handleDotdictFormat(self, lInputListParams : list, lParams: list = []) -> list: """ @@ -928,11 +1004,18 @@ def __checkAndCreateNewElement(self, sKey: str, value, oJson=None, bCheck=False, if oJson is not None: exec(sExec2) except Exception as error: + if keyNested is not None: + tmpNestedKey = None + for key in self.dKeyDDictCoverted.keys(): + if key == self.__removeTokenStr(keyNested): + tmpNestedKey = self.dKeyDDictCoverted[key] + if tmpNestedKey == None: + tmpNestedKey = self.__removeTokenStr(keyNested) if isinstance(error, TypeError): # If Python's type errors occur when executing an expression for eType in self.pythonTypeError: if eType in str(error): if keyNested is not None: - errorMsg = f"Could not set parameter '{self.__removeTokenStr(keyNested)}' with value '{value}'! \ + errorMsg = f"Could not set parameter '{tmpNestedKey}' with value '{value}'! \ Reason: {str(error).replace(' or slices', '')}" else: errorMsg = f"Could not set parameter '{self.__removeTokenStr(sKey)}' with value '{value}'! \ @@ -954,7 +1037,7 @@ def __checkAndCreateNewElement(self, sKey: str, value, oJson=None, bCheck=False, except Exception as error: self.__reset() if keyNested is not None: - sKey = self.__removeTokenStr(keyNested) + sKey = tmpNestedKey if tmpNestedKey is not None else self.__removeTokenStr(keyNested) errorMsg = f"Could not set parameter '{sKey}' with value '{value}'! Reason: {error}" raise Exception(errorMsg) return True @@ -1098,10 +1181,10 @@ def __loadNestedValue(initValue: str, sInputStr: str, bKey=False, key=''): if CNameMangling.STRINGCONVERT.value in sInputStr or regex.match(r'^\[\s*import\s*\]_\d+$', key): bValueConvertString = True sInputStr = sInputStr.replace(CNameMangling.STRINGCONVERT.value, '') - sInputStr = regex.sub("\$", "$$", sInputStr) + sInputStr = sInputStr.replace('${', '$${') initValue = initValue.replace(CNameMangling.STRINGCONVERT.value, '') elif regex.match(rf"^\s*{pattern}\s*$", sInputStr, regex.UNICODE): - sInputStr = regex.sub("\$", "$$", sInputStr) + sInputStr = sInputStr.replace('${', '$${') sInputStr = self.__checkParamName(sInputStr) handledValue = self.__nestedParamHandler(sInputStr) if not bValueConvertString else \ self.__nestedParamHandler(sInputStr, bKey=bKey, bConvertToStr=bValueConvertString) @@ -1191,7 +1274,7 @@ def __handleList(lInput : list, bNested : bool, parentParams : str = '') -> list if regex.search(rf"\[\s*'*{pattern}'*\s*\]", keyNested, regex.UNICODE) or \ regex.search(rf"\.{pattern}[\.}}]+", keyNested, regex.UNICODE): bImplicitCreation = True - k = regex.sub("\$", "$$", k) + k = k.replace('${', '$${') k = self.__checkParamName(k) k = self.__nestedParamHandler(k, bKey=True) sExec = 'dummyData = self.JPGlobals' @@ -1343,7 +1426,7 @@ def __handleList(lInput : list, bNested : bool, parentParams : str = '') -> list continue keyPattern = regex.escape(k) if regex.match(rf"^.+\['{keyPattern}'\]$", parentParams, regex.UNICODE): - parentParams = regex.sub(f"\['{k}'\]", "", parentParams) + parentParams = regex.sub(rf"\['{k}'\]", "", parentParams) elif not recursive: parentParams = '' __jsonUpdated(k, v, oJson, parentParams, keyNested, paramInValue, bDuplicatedHandle, recursive) @@ -1615,25 +1698,36 @@ def __preCheckJsonFile(self, sInput, CJSONDecoder): / *Type*: str / ''' + def hashContent(sInput : str) -> str: + return hashlib.sha256(sInput.encode('utf-8')).hexdigest() + try: self.jsonCheck = json.loads(sInput, cls=CJSONDecoder, object_pairs_hook=self.__processImportFiles) except Exception as error: failedJsonDoc = self.__getFailedJsonDoc(error) jsonException = "not defined" - if failedJsonDoc is None: - jsonException = f"{error}\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else f"{error}" + if "Cyclic import detection" in str(error): + jsonException = str(error) else: - jsonException = f"{error}\nNearby: '{failedJsonDoc}'\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else \ - f"{error}\nNearby: '{failedJsonDoc}'" - self.__reset() - raise Exception(jsonException) + if failedJsonDoc is None: + jsonException = f"{error}\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else f"{error}" + else: + jsonException = f"{error}\nNearby: '{failedJsonDoc}'\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else \ + f"{error}\nNearby: '{failedJsonDoc}'" + self.__reset() + raise Exception(jsonException) self.JPGlobals = self.jsonCheck importPattern = rf'([\'|"]\s*\[\s*import\s*\](_\d+)*\s*[\'|"]\s*:\s*[\'|"][^\'"]+[\'|"])' sJson = json.dumps(self.jsonCheck) + # Check cyclic import by comparing the content of the whole JSONP configuration object. + if len(self.importCheck)>1: + for item in self.importCheck: + if item == hashContent(regex.sub(r'"(\[import\])_\d+"', '"\\1"', sJson)): + raise Exception("Cyclic import detection!!!") + self.importCheck.append(hashContent(regex.sub(r'"(\[import\])_\d+"', '"\\1"', sJson))) lImport = regex.findall(importPattern, sJson) if len(lImport)==0: sInput = sJson - return sInput else: while regex.search(importPattern, sJson): tmpJson = sJson @@ -1644,7 +1738,7 @@ def __preCheckJsonFile(self, sInput, CJSONDecoder): break sJson = self.__preCheckJsonFile(sJson, CJSONDecoder) sInput = sJson - return sInput + return sInput def jsonLoad(self, jFile : str): """ @@ -1671,6 +1765,12 @@ def jsonLoad(self, jFile : str): # Identifies the entry level when loading JSONP file in comparison with imported files levels. masterFile = True if self.recursive_level==0 else False jFile = CString.NormalizePath(jFile, sReferencePathAbs=os.path.dirname(os.path.abspath(sys.argv[0]))) + if self.importTree is None: + self.importTree = CTreeNode(jFile) + self.currentNode = self.importTree + else: + self.currentNode.addChild(jFile) + self.currentNode = self.currentNode.children[jFile] self.handlingFile.append(jFile) if masterFile: self.masterFile = jFile @@ -1678,7 +1778,6 @@ def jsonLoad(self, jFile : str): self.__reset() raise Exception(f"File '{jFile}' is not existing!") - self.lImportedFiles.append(jFile) self.jsonPath = os.path.dirname(jFile) try: sJsonData= self.__loadAndRemoveComments(jFile) @@ -1687,7 +1786,7 @@ def jsonLoad(self, jFile : str): raise Exception(f"Could not read json file '{jFile}' due to: '{reason}'!") return self.jsonLoads(sJsonData) - def jsonLoads(self, sJsonpContent : str, referenceDir : str = ''): + def jsonLoads(self, sJsonpContent : str, referenceDir : str = None): """ ``jsonLoads`` loads the JSONP content, preprocesses it and returns the preprocessed result as Python dictionary. @@ -1701,7 +1800,7 @@ def jsonLoads(self, sJsonpContent : str, referenceDir : str = ''): * ``referenceDir`` - / *Condition*: optional / *Type*: str / + / *Condition*: optional / *Type*: str / *Default*: None / A reference path for loading imported files. @@ -1754,13 +1853,13 @@ def __handleDuplicatedKey(dInput : dict, parentParams : str = '') -> dict: dictValues = {} for key in listKeys: if CNameMangling.DUPLICATEDKEY_01.value in key: - origKey = regex.sub(f"{CNameMangling.DUPLICATEDKEY_01.value}\d+\s*$", "", key) + origKey = regex.sub(rf"{CNameMangling.DUPLICATEDKEY_01.value}\d+\s*$", "", key) dictValues[origKey] = copy.deepcopy(dInput[origKey]) for key in dictValues.keys(): dInput = self.__changeDictKey(dInput, key, key + CNameMangling.DUPLICATEDKEY_00.value) tmpDict = copy.deepcopy(dInput) for k, v in tmpDict.items(): - origK = regex.sub(f"{CNameMangling.DUPLICATEDKEY_01.value}\d+\s*$", "", k) + origK = regex.sub(rf"{CNameMangling.DUPLICATEDKEY_01.value}\d+\s*$", "", k) if CNameMangling.DUPLICATEDKEY_01.value in k: dInput[k] = dictValues[origK].pop(1) parentParams = f"[{k}]" if parentParams=='' else f"{parentParams}['{k}']" @@ -1827,11 +1926,14 @@ def __handleLastElement(sInput : str) -> str: raise Exception(f'Expected a string, but got a value of type {type(sJsonpContent)}') # Identifies the entry level when loading JSONP content in comparison with imported files levels. firstLevel = True if self.recursive_level==0 else False - if referenceDir != '': + if referenceDir is not None: self.jsonPath = CString.NormalizePath(referenceDir, sReferencePathAbs=os.path.dirname(os.path.abspath(sys.argv[0]))) if not os.path.exists(self.jsonPath): self.__reset() raise Exception(f"Reference directory '{referenceDir}' is not existing!") + if self.importTree is None: + self.importTree = CTreeNode(f'Root:{self.jsonPath}') + self.currentNode = self.importTree if self.masterFile is None or not firstLevel: try: sJsonData= self.__loadAndRemoveComments(sJsonpContent, isFile=False) @@ -1867,9 +1969,9 @@ def __handleLastElement(sInput : str) -> str: param = regex.search(r'\${([^}]*)}', line) if param is not None: lNestedParams.append(param[0]) - if ':' in param[1]: - tmpList03.append(param[1]) - tmpPattern = regex.escape(param[1]) + if ':' in param[0]: + tmpList03.append(param[0]) + tmpPattern = regex.escape(param[0]) line = regex.sub(tmpPattern, CNameMangling.NESTEDPARAM.value, line) if line == tmpLine: break @@ -1883,7 +1985,7 @@ def __handleLastElement(sInput : str) -> str: if regex.search(indexPattern, line): indexList = regex.findall(indexPattern, line) line = regex.sub(f"({indexPattern})", CNameMangling.LISTINDEX.value, line) - items = regex.split("\s*:\s*", line) + items = regex.split(r"\s*:\s*", line) iItems = len(items)-1 if items[-1]=='' else len(items) newLine = '' preItem = '' @@ -1970,7 +2072,7 @@ def __handleLastElement(sInput : str) -> str: sJsonDataUpdated = f"{sJsonDataUpdated}{line}\n" lKeyName = regex.findall(r'[,\s{]*("[^:,\n]*")\s*:\s*', sJsonDataUpdated) for key in lKeyName: - if regex.match(r'^"\s+.+"$|^".+\s+"$', key): + if regex.match(r'^"\s+[^\s]+.+"$|^".+[^\s]+\s+"$', key): newKey = '"' + key.strip('"').strip() + '"' sJsonDataUpdated = sJsonDataUpdated.replace(key, newKey) key = newKey @@ -1992,10 +2094,24 @@ def __handleLastElement(sInput : str) -> str: # imported files in JSON files. if firstLevel: self.bJSONPreCheck = True - sDummyData = self.__preCheckJsonFile(sJsonDataUpdated, CJSONDecoder) + try: + sDummyData = self.__preCheckJsonFile(sJsonDataUpdated, CJSONDecoder) + except Exception as error: + if "Cyclic import detection" in str(error): + pass + else: + self.__reset() + raise Exception(error) self.iDynamicImport = 0 self.recursive_level = 0 - self.lImportedFiles = [] if self.masterFile is None else [self.masterFile] + self.bDynamicImport = False + self.handlingFile = [] if self.masterFile is None else [self.masterFile] + if not regex.match(f'^Root:.+$', self.importTree.value): + self.jsonPath = os.path.dirname(self.importTree.value) + else: + self.jsonPath = regex.sub(r'(^Root:)', '', self.importTree.value) + self.importTree.children = {} + self.currentNode = self.importTree self.bJSONPreCheck = False # Load Json object with checking duplicated keys feature is enabled. @@ -2007,15 +2123,17 @@ def __handleLastElement(sInput : str) -> str: except Exception as error: failedJsonDoc = self.__getFailedJsonDoc(error) jsonException = "not defined" - if failedJsonDoc is None: - jsonException = f"{error}\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else f"{error}" + if "Cyclic import detection" in str(error): + jsonException = str(error) else: - jsonException = f"{error}\nNearby: '{failedJsonDoc}'\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else \ - f"{error}\nNearby: '{failedJsonDoc}'" + if failedJsonDoc is None: + jsonException = f"{error}\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else f"{error}" + else: + jsonException = f"{error}\nNearby: '{failedJsonDoc}'\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else \ + f"{error}\nNearby: '{failedJsonDoc}'" if firstLevel: self.__reset() raise Exception(jsonException) - self.__checkDotInParamName(oJson) if firstLevel: @@ -2030,7 +2148,6 @@ def __handleLastElement(sInput : str) -> str: __checkKeynameFormat(oJson) oJson, bNested = self.__updateAndReplaceNestedParam(oJson) self.jsonCheck = {} - self.__reset() __removeDuplicatedKey(oJson) oJson = DotDict(oJson) diff --git a/config/robotframework_aio/release_items_JsonPreprocessor.json b/config/robotframework_aio/release_items_JsonPreprocessor.json index 7dc2ce7..f3d771c 100644 --- a/config/robotframework_aio/release_items_JsonPreprocessor.json +++ b/config/robotframework_aio/release_items_JsonPreprocessor.json @@ -178,25 +178,29 @@ ], "0.14.1.;0.15.0." : [ " -* Allowed users define a naming convention rule key names within JSONP content processed by the **JsonPreprocessor** +**Updated naming convention check** - The input parameter ``keyPattern`` is used to define the key name pattern and the ``keyPattern`` is set by users + The **JsonPreprocessor** supports a user-defined convention for key names. This is enforced using a regex pattern + passed to the constructor of the **JsonPreprocessor** class. - **Example:** + *Example* - | ``json_preprocessor = CJsonPreprocessor()`` + Assuming key names may only contain letters, digits and underscores, but must start with a letter, then the **JsonPreprocessor** + has to be initialized in this way: - The ``keyPattern`` is not set when initialized ``CJsonPreprocessor``, the naming convention check is not acitve. + | ``json_preprocessor = CJsonPreprocessor(keyPattern=r'^\\p{L}[\\p{L}\\p{Nd}_]*$')`` - | ``json_preprocessor = CJsonPreprocessor(keyPattern=r'^[\\p{L}][\\p{L}0-9]*$')`` + This feature is an option. If the user does not define the parameter ``keyPattern``, key names can contain any characters (but cannot be empty). - The ``keyPattern`` is set ``'^[\\p{L}][\\p{L}0-9]*$'`` means key names in the JONP file have to start with characters and following by characters or numbers. + *Example* -* Replaced ``re`` package by ``regex`` package to handle regular expression. + | ``json_preprocessor = CJsonPreprocessor()`` -* Improved and aligned error messages +**Maintenance** -* Added and updated the Selftest according to the changes +* Replaced ``re`` package by ``regex`` package to handle extended regular expressions +* Improved and aligned error messages +* Added and updated the self test according to the changed features " ] } diff --git a/packagedoc/additional_docs/Description.tex b/packagedoc/additional_docs/Description.tex index 0d038ab..e60d2fe 100644 --- a/packagedoc/additional_docs/Description.tex +++ b/packagedoc/additional_docs/Description.tex @@ -45,6 +45,38 @@ \section{How to execute} In chapter \hyperref[thejsonpformat]{The JSONP format} the format of JSON files used by the \pkg, is described in detail. All discussed JSON files can be tested with the example script listed above. +% -------------------------------------------------------------------------------------------------------------- + +\newpage + +\section{User defined naming convention} + +By default, key names in JSON files can contain any characters (but cannot be empty). But it might be required to limit the character set. +For this purpose the \pkg\ supports an optional user-defined convention for key names. This is enforced using a \pcode{regex} pattern +passed to the constructor of the \pkg\ class. + +Assuming key names may only contain letters, digits and underscores, but must start with a letter, then the \pkg\ has to be initialized +in this way: + +\begin{pythoncode}[linebackgroundcolor=\hlcode{3,5}] +from JsonPreprocessor.CJsonPreprocessor import CJsonPreprocessor +import pprint +import regex + +json_preprocessor = CJsonPreprocessor(keyPattern=r'^\p{L}[\p{L}\p{Nd}_]*$')) +try: + values = json_preprocessor.jsonLoad("./file.jsonp") + pprint.pprint(values) +except Exception as reason: + print(f"'{reason}'") +\end{pythoncode} + +The regular expressions \pcode{\\p\{L\}} and \pcode{\\p\{Nd\}} are provided by the \pcode{regex} module: + +\begin{itemize} + \item \pcode{\\p\{L\}} matches all Unicode characters classified as \textbf{letter} + \item \pcode{\\p\{Nd\}} matches all Unicode characters classified as \textbf{decimal digit} +\end{itemize} % -------------------------------------------------------------------------------------------------------------- diff --git a/packagedoc/additional_docs/History.tex b/packagedoc/additional_docs/History.tex index b99ff7d..bd6f11c 100644 --- a/packagedoc/additional_docs/History.tex +++ b/packagedoc/additional_docs/History.tex @@ -96,7 +96,7 @@ \historychange{- Fixed bugs, updated error messages, and improved composite data structure handling} \historyversiondate{0.9.0}{03/2025} -\historychange{- Allowed users define a naming convention rule key names\newline +\historychange{- Added support of a user-defined convention for key names\newline - Improved and aligned error messages\newline - Fixed bugs and updated the Selftest according to the changes} diff --git a/packagedoc/additional_docs/Introduction.tex b/packagedoc/additional_docs/Introduction.tex index e4c82f9..aaf1244 100644 --- a/packagedoc/additional_docs/Introduction.tex +++ b/packagedoc/additional_docs/Introduction.tex @@ -45,7 +45,7 @@ These deviations harm the syntax highlighting of editors and also cause invalid findings of JSON format related static code checkers. To avoid conflicts between the standard JSON format and the extended JSON format described here, the \pkg\ uses the alternative file extension -\pcode{.jsonp} for all JSON files. +\pcode{.jsonp} for all JSON files of extended format. \newpage diff --git a/packagedoc/additional_docs/The JSONP format.tex b/packagedoc/additional_docs/The JSONP format.tex index 021df5f..70e8748 100644 --- a/packagedoc/additional_docs/The JSONP format.tex +++ b/packagedoc/additional_docs/The JSONP format.tex @@ -151,20 +151,6 @@ \section{Comments} {'testlist': ['A1', 'D4']} \end{pythonlog} -\vspace{2ex} - -\section{Naming convention} - -All key names in JSONP files must adhere to the following rules: - -\begin{itemize} - \item Key names can only consist of letters, digits and the following special characters: \pcode{_ + - * / \\\\ @} - (\textit{backslashes are allowed but have to be masked}). - \item Key names have to start with a letter, a digit or an underscore. - \item Key names must not be empty strings. But leading and trailing blanks will be removed (and therefore do not cause errors). - Also blanks in between allowed characters are not allowed. -\end{itemize} - % -------------------------------------------------------------------------------------------------------------- \newpage diff --git a/test/JPP_TestUsecases.csv b/test/JPP_TestUsecases.csv index d526aa3..4cbf5d3 100644 --- a/test/JPP_TestUsecases.csv +++ b/test/JPP_TestUsecases.csv @@ -67,12 +67,13 @@ JPP_0369|VALUE_DETECTION|BADCASE|JSON file with expression starting with '${' an JPP_0370|VALUE_DETECTION|BADCASE|JSON file with expression starting with '${' and ending with '}', further matching '${' and '}' in between (not all nested) (invalid syntax 4) JPP_0371|VALUE_DETECTION|BADCASE|JSON file with expression starting with '${' and ending with '}', further matching '${' and '}' in between (not all nested) (invalid syntax 5) JPP_0400|NAMING_CONVENTION|GOODCASE|JSON file with several parameter names w.r.t. the naming convention -JPP_0450|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (1) -JPP_0451|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (2) -JPP_0452|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (3) -JPP_0453|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (4) -JPP_0454|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (5) -JPP_0455|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (6) +JPP_0401|NAMING_CONVENTION|GOODCASE|JSON file with several parameter names containing: blank, backslash, Unicode letters and decimal digits +JPP_0459|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (10) +JPP_0460|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (11) +JPP_0461|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (12) +JPP_0462|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (13) +JPP_0463|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (14) +JPP_0464|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (15) JPP_0500|COMPOSITE_EXPRESSIONS|GOODCASE|JSON file with composite data structure (nested lists and dictionaries 1) JPP_0501|COMPOSITE_EXPRESSIONS|GOODCASE|JSON file with composite data structure (nested lists and dictionaries 2) JPP_0502|COMPOSITE_EXPRESSIONS|GOODCASE|JSON file with composite data structure (nested lists and dictionaries 3 / some key names with dots inside) @@ -138,8 +139,6 @@ JPP_1154|FILE_IMPORTS|BADCASE|JSON file with not existing parameter within dynam JPP_1155|FILE_IMPORTS|BADCASE|JSON file with not existing import file JPP_1156|FILE_IMPORTS|BADCASE|JSON file with syntax error in import path (1) JPP_1157|FILE_IMPORTS|BADCASE|JSON file with syntax error in import path (2) -JPP_1158|FILE_IMPORTS|BADCASE|JSON file with error in [import] key (1) -JPP_1159|FILE_IMPORTS|BADCASE|JSON file with error in [import] key (2) JPP_1160|FILE_IMPORTS|BADCASE|JSON file with error in imported file JPP_1161|FILE_IMPORTS|BADCASE|JSON file with invalid data type of [import] key (1) JPP_1162|FILE_IMPORTS|BADCASE|JSON file with invalid data type of [import] key (2) @@ -199,6 +198,7 @@ JPP_2051|PARAMETER_SCOPE|BADCASE|JSON file containing a parameter with missing s JPP_2052|PARAMETER_SCOPE|BADCASE|JSON file containing a parameter with missing scope (3) JPP_2053|PARAMETER_SCOPE|BADCASE|JSON file containing a parameter with missing scope (4) JPP_2054|PARAMETER_SCOPE|BADCASE|JSON file containing a parameter with missing scope (5) +JPP_2055|PARAMETER_SCOPE|BADCASE|JSON file containing a parameter with missing scope (6) JPP_2056|PARAMETER_SCOPE|BADCASE|JSON file containing a parameter with missing scope (7) JPP_2057|PARAMETER_SCOPE|BADCASE|JSON file containing a parameter with missing scope (8) JPP_2058|PARAMETER_SCOPE|BADCASE|JSON file containing a parameter with missing scope (9) diff --git a/test/JPP_TestUsecases.html b/test/JPP_TestUsecases.html index 081a64c..d201679 100644 --- a/test/JPP_TestUsecases.html +++ b/test/JPP_TestUsecases.html @@ -2275,7 +2275,7 @@ -JPP_0450 +JPP_0401 @@ -2284,14 +2284,14 @@ - -BADCASE + +GOODCASE -JSON file with several invalid parameter names (1)
-Expected: Expected: No values are returned, and JsonPreprocessor throws an exception +JSON file with several parameter names containing: blank, backslash, Unicode letters and decimal digits
+Expected: All names are accepted (in definition and in reference)
@@ -2308,7 +2308,7 @@ -JPP_0451 +JPP_0459 @@ -2323,7 +2323,7 @@ -JSON file with several invalid parameter names (2)
+JSON file with several invalid parameter names (10)
Expected: Expected: No values are returned, and JsonPreprocessor throws an exception @@ -2341,7 +2341,7 @@ -JPP_0452 +JPP_0460 @@ -2356,7 +2356,7 @@ -JSON file with several invalid parameter names (3)
+JSON file with several invalid parameter names (11)
Expected: Expected: No values are returned, and JsonPreprocessor throws an exception @@ -2374,7 +2374,7 @@ -JPP_0453 +JPP_0461 @@ -2389,7 +2389,7 @@ -JSON file with several invalid parameter names (4)
+JSON file with several invalid parameter names (12)
Expected: Expected: No values are returned, and JsonPreprocessor throws an exception @@ -2407,7 +2407,7 @@ -JPP_0454 +JPP_0462 @@ -2422,7 +2422,7 @@ -JSON file with several invalid parameter names (5)
+JSON file with several invalid parameter names (13)
Expected: Expected: No values are returned, and JsonPreprocessor throws an exception @@ -2440,7 +2440,7 @@ -JPP_0455 +JPP_0463 @@ -2455,7 +2455,7 @@ -JSON file with several invalid parameter names (6)
+JSON file with several invalid parameter names (14)
Expected: Expected: No values are returned, and JsonPreprocessor throws an exception @@ -2470,6 +2470,39 @@ 74
+ + + +JPP_0464 + + + + +NAMING_CONVENTION + + + + +BADCASE + + + + +JSON file with several invalid parameter names (15)
+Expected: Expected: No values are returned, and JsonPreprocessor throws an exception + + +
+ + + + + + + +75 + + @@ -2501,7 +2534,7 @@ -75 +76 @@ -2535,7 +2568,7 @@ -76 +77 @@ -2569,7 +2602,7 @@ -77 +78 @@ -2602,7 +2635,7 @@ -78 +79 @@ -2635,7 +2668,7 @@ -79 +80 @@ -2668,7 +2701,7 @@ -80 +81 @@ -2701,7 +2734,7 @@ -81 +82 @@ -2734,7 +2767,7 @@ -82 +83 @@ -2767,7 +2800,7 @@ -83 +84 @@ -2800,7 +2833,7 @@ -84 +85 @@ -2833,7 +2866,7 @@ -85 +86 @@ -2866,7 +2899,7 @@ -86 +87 @@ -2899,7 +2932,7 @@ -87 +88 @@ -2932,7 +2965,7 @@ -88 +89 @@ -2965,7 +2998,7 @@ -89 +90 @@ -2998,7 +3031,7 @@ -90 +91 @@ -3031,7 +3064,7 @@ -91 +92 @@ -3065,7 +3098,7 @@ -92 +93 @@ -3099,7 +3132,7 @@ -93 +94 @@ -3132,7 +3165,7 @@ -94 +95 @@ -3165,7 +3198,7 @@ -95 +96 @@ -3198,7 +3231,7 @@ -96 +97 @@ -3231,7 +3264,7 @@ -97 +98 @@ -3264,7 +3297,7 @@ -98 +99 @@ -3297,7 +3330,7 @@ -99 +100 @@ -3330,7 +3363,7 @@ -100 +101 @@ -3363,7 +3396,7 @@ -101 +102 @@ -3396,7 +3429,7 @@ -102 +103 @@ -3429,7 +3462,7 @@ -103 +104 @@ -3462,7 +3495,7 @@ -104 +105 @@ -3495,7 +3528,7 @@ -105 +106 @@ -3528,7 +3561,7 @@ -106 +107 @@ -3561,7 +3594,7 @@ -107 +108 @@ -3594,7 +3627,7 @@ -108 +109 @@ -3627,7 +3660,7 @@ -109 +110 @@ -3660,7 +3693,7 @@ -110 +111 @@ -3693,7 +3726,7 @@ -111 +112 @@ -3726,7 +3759,7 @@ -112 +113 @@ -3759,7 +3792,7 @@ -113 +114 @@ -3792,7 +3825,7 @@ -114 +115 @@ -3825,7 +3858,7 @@ -115 +116 @@ -3858,7 +3891,7 @@ -116 +117 @@ -3891,7 +3924,7 @@ -117 +118 @@ -3924,7 +3957,7 @@ -118 +119 @@ -3957,7 +3990,7 @@ -119 +120 @@ -3990,7 +4023,7 @@ -120 +121 @@ -4023,7 +4056,7 @@ -121 +122 @@ -4056,7 +4089,7 @@ -122 +123 @@ -4089,7 +4122,7 @@ -123 +124 @@ -4122,7 +4155,7 @@ -124 +125 @@ -4156,7 +4189,7 @@ -125 +126 @@ -4190,7 +4223,7 @@ -126 +127 @@ -4223,7 +4256,7 @@ -127 +128 @@ -4256,7 +4289,7 @@ -128 +129 @@ -4289,7 +4322,7 @@ -129 +130 @@ -4322,7 +4355,7 @@ -130 +131 @@ -4355,7 +4388,7 @@ -131 +132 @@ -4389,7 +4422,7 @@ -132 +133 @@ -4423,7 +4456,7 @@ -133 +134 @@ -4457,7 +4490,7 @@ -134 +135 @@ -4491,7 +4524,7 @@ -135 +136 @@ -4524,7 +4557,7 @@ -136 +137 @@ -4557,7 +4590,7 @@ -137 +138 @@ -4590,7 +4623,7 @@ -138 +139 @@ -4618,39 +4651,6 @@
- - - - - -139 - - - - - -JPP_1158 - - - - -FILE_IMPORTS - - - - -BADCASE - - - - -JSON file with error in [import] key (1)
-Expected: No values are returned, and JsonPreprocessor throws an exception - - -
- - @@ -4659,39 +4659,6 @@ 140
- - - -JPP_1159 - - - - -FILE_IMPORTS - - - - -BADCASE - - - - -JSON file with error in [import] key (2)
-Expected: No values are returned, and JsonPreprocessor throws an exception - - -
- - - - - - - -141 - - @@ -4722,7 +4689,7 @@ -142 +141 @@ -4756,7 +4723,7 @@ -143 +142 @@ -4790,7 +4757,7 @@ -144 +143 @@ -4824,7 +4791,7 @@ -145 +144 @@ -4858,7 +4825,7 @@ -146 +145 @@ -4892,7 +4859,7 @@ -147 +146 @@ -4926,7 +4893,7 @@ -148 +147 @@ -4960,7 +4927,7 @@ -149 +148 @@ -4993,7 +4960,7 @@ -150 +149 @@ -5026,7 +4993,7 @@ -151 +150 @@ -5059,7 +5026,7 @@ -152 +151 @@ -5092,7 +5059,7 @@ -153 +152 @@ -5125,7 +5092,7 @@ -154 +153 @@ -5158,7 +5125,7 @@ -155 +154 @@ -5191,7 +5158,7 @@ -156 +155 @@ -5224,7 +5191,7 @@ -157 +156 @@ -5257,7 +5224,7 @@ -158 +157 @@ -5290,7 +5257,7 @@ -159 +158 @@ -5323,7 +5290,7 @@ -160 +159 @@ -5356,7 +5323,7 @@ -161 +160 @@ -5389,7 +5356,7 @@ -162 +161 @@ -5422,7 +5389,7 @@ -163 +162 @@ -5455,7 +5422,7 @@ -164 +163 @@ -5488,7 +5455,7 @@ -165 +164 @@ -5521,7 +5488,7 @@ -166 +165 @@ -5554,7 +5521,7 @@ -167 +166 @@ -5587,7 +5554,7 @@ -168 +167 @@ -5620,7 +5587,7 @@ -169 +168 @@ -5653,7 +5620,7 @@ -170 +169 @@ -5686,7 +5653,7 @@ -171 +170 @@ -5719,7 +5686,7 @@ -172 +171 @@ -5752,7 +5719,7 @@ -173 +172 @@ -5785,7 +5752,7 @@ -174 +173 @@ -5818,7 +5785,7 @@ -175 +174 @@ -5851,7 +5818,7 @@ -176 +175 @@ -5884,7 +5851,7 @@ -177 +176 @@ -5917,7 +5884,7 @@ -178 +177 @@ -5950,7 +5917,7 @@ -179 +178 @@ -5983,7 +5950,7 @@ -180 +179 @@ -6016,7 +5983,7 @@ -181 +180 @@ -6049,7 +6016,7 @@ -182 +181 @@ -6082,7 +6049,7 @@ -183 +182 @@ -6115,7 +6082,7 @@ -184 +183 @@ -6148,7 +6115,7 @@ -185 +184 @@ -6181,7 +6148,7 @@ -186 +185 @@ -6214,7 +6181,7 @@ -187 +186 @@ -6247,7 +6214,7 @@ -188 +187 @@ -6280,7 +6247,7 @@ -189 +188 @@ -6313,7 +6280,7 @@ -190 +189 @@ -6346,7 +6313,7 @@ -191 +190 @@ -6379,7 +6346,7 @@ -192 +191 @@ -6412,7 +6379,7 @@ -193 +192 @@ -6445,7 +6412,7 @@ -194 +193 @@ -6478,7 +6445,7 @@ -195 +194 @@ -6511,7 +6478,7 @@ -196 +195 @@ -6544,7 +6511,7 @@ -197 +196 @@ -6577,7 +6544,7 @@ -198 +197 @@ -6610,7 +6577,7 @@ -199 +198 @@ -6638,6 +6605,39 @@
+ + + + + +199 + + + + + +JPP_2055 + + + + +PARAMETER_SCOPE + + + + +BADCASE + + + + +JSON file containing a parameter with missing scope (6)
+Expected: No values are returned, and JsonPreprocessor throws an exception + + +
+ + @@ -6742,7 +6742,7 @@
 

-
Generated: 09.01.2025 - 18:56:30
+
Generated: 10.04.2025 - 17:21:06
 
diff --git a/test/JPP_TestUsecases.rst b/test/JPP_TestUsecases.rst index 4c4763e..51ec9ce 100644 --- a/test/JPP_TestUsecases.rst +++ b/test/JPP_TestUsecases.rst @@ -739,61 +739,71 @@ Test Use Cases ---- -* **Test JPP_0450** +* **Test JPP_0401** + + [NAMING_CONVENTION / GOODCASE] + + **JSON file with several parameter names containing: blank, backslash, Unicode letters and decimal digits** + + Expected: All names are accepted (in definition and in reference) + +---- + +* **Test JPP_0459** [NAMING_CONVENTION / BADCASE] - **JSON file with several invalid parameter names (1)** + **JSON file with several invalid parameter names (10)** Expected: Expected: No values are returned, and JsonPreprocessor throws an exception ---- -* **Test JPP_0451** +* **Test JPP_0460** [NAMING_CONVENTION / BADCASE] - **JSON file with several invalid parameter names (2)** + **JSON file with several invalid parameter names (11)** Expected: Expected: No values are returned, and JsonPreprocessor throws an exception ---- -* **Test JPP_0452** +* **Test JPP_0461** [NAMING_CONVENTION / BADCASE] - **JSON file with several invalid parameter names (3)** + **JSON file with several invalid parameter names (12)** Expected: Expected: No values are returned, and JsonPreprocessor throws an exception ---- -* **Test JPP_0453** +* **Test JPP_0462** [NAMING_CONVENTION / BADCASE] - **JSON file with several invalid parameter names (4)** + **JSON file with several invalid parameter names (13)** Expected: Expected: No values are returned, and JsonPreprocessor throws an exception ---- -* **Test JPP_0454** +* **Test JPP_0463** [NAMING_CONVENTION / BADCASE] - **JSON file with several invalid parameter names (5)** + **JSON file with several invalid parameter names (14)** Expected: Expected: No values are returned, and JsonPreprocessor throws an exception ---- -* **Test JPP_0455** +* **Test JPP_0464** [NAMING_CONVENTION / BADCASE] - **JSON file with several invalid parameter names (6)** + **JSON file with several invalid parameter names (15)** Expected: Expected: No values are returned, and JsonPreprocessor throws an exception @@ -1471,26 +1481,6 @@ Test Use Cases ---- -* **Test JPP_1158** - - [FILE_IMPORTS / BADCASE] - - **JSON file with error in [import] key (1)** - - Expected: No values are returned, and JsonPreprocessor throws an exception - ----- - -* **Test JPP_1159** - - [FILE_IMPORTS / BADCASE] - - **JSON file with error in [import] key (2)** - - Expected: No values are returned, and JsonPreprocessor throws an exception - ----- - * **Test JPP_1160** [FILE_IMPORTS / BADCASE] @@ -2095,6 +2085,16 @@ Test Use Cases ---- +* **Test JPP_2055** + + [PARAMETER_SCOPE / BADCASE] + + **JSON file containing a parameter with missing scope (6)** + + Expected: No values are returned, and JsonPreprocessor throws an exception + +---- + * **Test JPP_2056** [PARAMETER_SCOPE / BADCASE] @@ -2125,5 +2125,5 @@ Test Use Cases ---- -Generated: 09.01.2025 - 18:56:30 +Generated: 10.04.2025 - 17:21:06 diff --git a/test/JPP_TestUsecases.txt b/test/JPP_TestUsecases.txt index 5886a31..73e9a1c 100644 --- a/test/JPP_TestUsecases.txt +++ b/test/JPP_TestUsecases.txt @@ -310,28 +310,32 @@ Test JPP_0400 / NAMING_CONVENTION / GOODCASE Description: JSON file with several parameter names w.r.t. the naming convention Expectation: All names are accepted (in definition and in reference) ------------------------------------------------------------------------------------------------------------------------ -Test JPP_0450 / NAMING_CONVENTION / BADCASE -Description: JSON file with several invalid parameter names (1) +Test JPP_0401 / NAMING_CONVENTION / GOODCASE +Description: JSON file with several parameter names containing: blank, backslash, Unicode letters and decimal digits +Expectation: All names are accepted (in definition and in reference) +------------------------------------------------------------------------------------------------------------------------ +Test JPP_0459 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (10) Expectation: Expected: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------ -Test JPP_0451 / NAMING_CONVENTION / BADCASE -Description: JSON file with several invalid parameter names (2) +Test JPP_0460 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (11) Expectation: Expected: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------ -Test JPP_0452 / NAMING_CONVENTION / BADCASE -Description: JSON file with several invalid parameter names (3) +Test JPP_0461 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (12) Expectation: Expected: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------ -Test JPP_0453 / NAMING_CONVENTION / BADCASE -Description: JSON file with several invalid parameter names (4) +Test JPP_0462 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (13) Expectation: Expected: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------ -Test JPP_0454 / NAMING_CONVENTION / BADCASE -Description: JSON file with several invalid parameter names (5) +Test JPP_0463 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (14) Expectation: Expected: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------ -Test JPP_0455 / NAMING_CONVENTION / BADCASE -Description: JSON file with several invalid parameter names (6) +Test JPP_0464 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (15) Expectation: Expected: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------ Test JPP_0500 / COMPOSITE_EXPRESSIONS / GOODCASE @@ -605,14 +609,6 @@ Test JPP_1157 / FILE_IMPORTS / BADCASE Description: JSON file with syntax error in import path (2) Expectation: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------ -Test JPP_1158 / FILE_IMPORTS / BADCASE -Description: JSON file with error in [import] key (1) -Expectation: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------- -Test JPP_1159 / FILE_IMPORTS / BADCASE -Description: JSON file with error in [import] key (2) -Expectation: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------- Test JPP_1160 / FILE_IMPORTS / BADCASE Description: JSON file with error in imported file Expectation: No values are returned, and JsonPreprocessor throws an exception @@ -856,6 +852,10 @@ Test JPP_2054 / PARAMETER_SCOPE / BADCASE Description: JSON file containing a parameter with missing scope (5) Expectation: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------ +Test JPP_2055 / PARAMETER_SCOPE / BADCASE +Description: JSON file containing a parameter with missing scope (6) +Expectation: No values are returned, and JsonPreprocessor throws an exception +------------------------------------------------------------------------------------------------------------------------ Test JPP_2056 / PARAMETER_SCOPE / BADCASE Description: JSON file containing a parameter with missing scope (7) Expectation: No values are returned, and JsonPreprocessor throws an exception @@ -868,5 +868,5 @@ Test JPP_2058 / PARAMETER_SCOPE / BADCASE Description: JSON file containing a parameter with missing scope (9) Expectation: No values are returned, and JsonPreprocessor throws an exception ------------------------------------------------------------------------------------------------------------------------ -Generated: 09.01.2025 - 18:56:30 +Generated: 10.04.2025 - 17:21:06 diff --git a/test/component_test.py b/test/component_test.py index 4ae1183..fc53379 100644 --- a/test/component_test.py +++ b/test/component_test.py @@ -22,8 +22,8 @@ # # -------------------------------------------------------------------------------------------------------------- # -VERSION = "0.58.0" -VERSION_DATE = "25.02.2025" +VERSION = "0.59.0" +VERSION_DATE = "10.04.2025" # # -------------------------------------------------------------------------------------------------------------- #TM*** diff --git a/test/pytest/pytestfiles/test_07_NAMING_CONVENTION_GOODCASE.py b/test/pytest/pytestfiles/test_07_NAMING_CONVENTION_GOODCASE.py index d8fac78..c6fd9fd 100644 --- a/test/pytest/pytestfiles/test_07_NAMING_CONVENTION_GOODCASE.py +++ b/test/pytest/pytestfiles/test_07_NAMING_CONVENTION_GOODCASE.py @@ -18,7 +18,7 @@ # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 10.04.2025 - 17:21:06 # # -------------------------------------------------------------------------------------------------------------- @@ -37,4 +37,12 @@ class Test_NAMING_CONVENTION_GOODCASE: def test_JPP_0400(self, Description): nReturn = CExecute.Execute("JPP_0400") assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: All names are accepted (in definition and in reference) + @pytest.mark.parametrize( + "Description", ["JSON file with several parameter names containing: blank, backslash, Unicode letters and decimal digits",] + ) + def test_JPP_0401(self, Description): + nReturn = CExecute.Execute("JPP_0401") + assert nReturn == 0 # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_08_NAMING_CONVENTION_BADCASE.py b/test/pytest/pytestfiles/test_08_NAMING_CONVENTION_BADCASE.py index d40999b..86476eb 100644 --- a/test/pytest/pytestfiles/test_08_NAMING_CONVENTION_BADCASE.py +++ b/test/pytest/pytestfiles/test_08_NAMING_CONVENTION_BADCASE.py @@ -18,7 +18,7 @@ # # XC-HWP/ESW3-Queckenstedt # -# 09.01.2025 - 18:56:30 +# 10.04.2025 - 17:21:06 # # -------------------------------------------------------------------------------------------------------------- @@ -26,55 +26,55 @@ from pytestlibs.CExecute import CExecute # -------------------------------------------------------------------------------------------------------------- -# mas2hc: Commented out the Test_NAMING_CONVENTION_BADCASE test cases due to the comment out in TestConfig.py is not effective -# class Test_NAMING_CONVENTION_BADCASE: -# # -------------------------------------------------------------------------------------------------------------- -# # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception -# @pytest.mark.parametrize( -# "Description", ["JSON file with several invalid parameter names (1)",] -# ) -# def test_JPP_0450(self, Description): -# nReturn = CExecute.Execute("JPP_0450") -# assert nReturn == 0 -# # -------------------------------------------------------------------------------------------------------------- -# # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception -# @pytest.mark.parametrize( -# "Description", ["JSON file with several invalid parameter names (2)",] -# ) -# def test_JPP_0451(self, Description): -# nReturn = CExecute.Execute("JPP_0451") -# assert nReturn == 0 -# # -------------------------------------------------------------------------------------------------------------- -# # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception -# @pytest.mark.parametrize( -# "Description", ["JSON file with several invalid parameter names (3)",] -# ) -# def test_JPP_0452(self, Description): -# nReturn = CExecute.Execute("JPP_0452") -# assert nReturn == 0 -# # -------------------------------------------------------------------------------------------------------------- -# # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception -# @pytest.mark.parametrize( -# "Description", ["JSON file with several invalid parameter names (4)",] -# ) -# def test_JPP_0453(self, Description): -# nReturn = CExecute.Execute("JPP_0453") -# assert nReturn == 0 -# # -------------------------------------------------------------------------------------------------------------- -# # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception -# @pytest.mark.parametrize( -# "Description", ["JSON file with several invalid parameter names (5)",] -# ) -# def test_JPP_0454(self, Description): -# nReturn = CExecute.Execute("JPP_0454") -# assert nReturn == 0 -# # -------------------------------------------------------------------------------------------------------------- -# # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception -# @pytest.mark.parametrize( -# "Description", ["JSON file with several invalid parameter names (6)",] -# ) -# def test_JPP_0455(self, Description): -# nReturn = CExecute.Execute("JPP_0455") -# assert nReturn == 0 -# # -------------------------------------------------------------------------------------------------------------- +class Test_NAMING_CONVENTION_BADCASE: + +# -------------------------------------------------------------------------------------------------------------- + # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (10)",] + ) + def test_JPP_0459(self, Description): + nReturn = CExecute.Execute("JPP_0459") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (11)",] + ) + def test_JPP_0460(self, Description): + nReturn = CExecute.Execute("JPP_0460") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (12)",] + ) + def test_JPP_0461(self, Description): + nReturn = CExecute.Execute("JPP_0461") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (13)",] + ) + def test_JPP_0462(self, Description): + nReturn = CExecute.Execute("JPP_0462") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (14)",] + ) + def test_JPP_0463(self, Description): + nReturn = CExecute.Execute("JPP_0463") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: Expected: No values are returned, and JsonPreprocessor throws an exception + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (15)",] + ) + def test_JPP_0464(self, Description): + nReturn = CExecute.Execute("JPP_0464") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_16_FILE_IMPORTS_BADCASE.py b/test/pytest/pytestfiles/test_16_FILE_IMPORTS_BADCASE.py index 64cfc17..71e2038 100644 --- a/test/pytest/pytestfiles/test_16_FILE_IMPORTS_BADCASE.py +++ b/test/pytest/pytestfiles/test_16_FILE_IMPORTS_BADCASE.py @@ -18,7 +18,7 @@ # # XC-HWP/ESW3-Queckenstedt # -# 26.11.2024 - 12:36:07 +# 10.04.2025 - 17:21:06 # # -------------------------------------------------------------------------------------------------------------- @@ -93,24 +93,6 @@ def test_JPP_1156(self, Description): def test_JPP_1157(self, Description): nReturn = CExecute.Execute("JPP_1157") assert nReturn == 0 -# -------------------------------------------------------------------------------------------------------------- - # Expected: No values are returned, and JsonPreprocessor throws an exception - # mas2hc: Commented out this test case due to the comment out in TestConfig.py is not effective - # @pytest.mark.parametrize( - # "Description", ["JSON file with error in [import] key (1)",] - # ) - # def test_JPP_1158(self, Description): - # nReturn = CExecute.Execute("JPP_1158") - # assert nReturn == 0 -# -------------------------------------------------------------------------------------------------------------- - # Expected: No values are returned, and JsonPreprocessor throws an exception - # mas2hc: Commented out this test case due to the comment out in TestConfig.py is not effective - # @pytest.mark.parametrize( - # "Description", ["JSON file with error in [import] key (2)",] - # ) - # def test_JPP_1159(self, Description): - # nReturn = CExecute.Execute("JPP_1159") - # assert nReturn == 0 # -------------------------------------------------------------------------------------------------------------- # Expected: No values are returned, and JsonPreprocessor throws an exception @pytest.mark.parametrize( diff --git a/test/pytest/pytestfiles/test_26_PARAMETER_SCOPE_BADCASE.py b/test/pytest/pytestfiles/test_26_PARAMETER_SCOPE_BADCASE.py index 4bcda17..26505d7 100644 --- a/test/pytest/pytestfiles/test_26_PARAMETER_SCOPE_BADCASE.py +++ b/test/pytest/pytestfiles/test_26_PARAMETER_SCOPE_BADCASE.py @@ -18,7 +18,7 @@ # # XC-HWP/ESW3-Queckenstedt # -# 14.11.2024 - 15:38:04 +# 10.04.2025 - 17:21:06 # # -------------------------------------------------------------------------------------------------------------- @@ -69,6 +69,14 @@ def test_JPP_2053(self, Description): def test_JPP_2054(self, Description): nReturn = CExecute.Execute("JPP_2054") assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: No values are returned, and JsonPreprocessor throws an exception + @pytest.mark.parametrize( + "Description", ["JSON file containing a parameter with missing scope (6)",] + ) + def test_JPP_2055(self, Description): + nReturn = CExecute.Execute("JPP_2055") + assert nReturn == 0 # -------------------------------------------------------------------------------------------------------------- # Expected: No values are returned, and JsonPreprocessor throws an exception @pytest.mark.parametrize( diff --git a/test/testconfig/TestConfig.py b/test/testconfig/TestConfig.py index ed0ef96..e69d5b7 100644 --- a/test/testconfig/TestConfig.py +++ b/test/testconfig/TestConfig.py @@ -22,7 +22,7 @@ # # -------------------------------------------------------------------------------------------------------------- # -# 25.02.2025 +# 10.04.2025 # # !!! Temporarily tests are deactivated by the following line commented out: # # # listofdictUsecases.append(dictUsecase) @@ -1746,8 +1746,10 @@ del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} +# parts of jpp-test_config_0401.jsonp commented out because of +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/440 dictUsecase['TESTID'] = "JPP_0401" -dictUsecase['DESCRIPTION'] = "JSON file with several parameter names containing: blank, backslash, 4Byte character" +dictUsecase['DESCRIPTION'] = "JSON file with several parameter names containing: blank, backslash, Unicode letters and decimal digits" dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" dictUsecase['SECTION'] = "NAMING_CONVENTION" dictUsecase['SUBSECTION'] = "GOODCASE" @@ -1756,8 +1758,43 @@ dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0401.jsonp" dictUsecase['EXPECTEDEXCEPTION'] = None dictUsecase['EXPECTEDRETURN'] = """ +[DOTDICT] (27/1) > {param} [INT] : 1 +[DOTDICT] (27/2) > {p21} [INT] : 1 +[DOTDICT] (27/3) > {B} [DOTDICT] (1/1) > {param} [INT] : 1 +[DOTDICT] (27/4) > {p22} [INT] : 1 +[DOTDICT] (27/5) > {C} [LIST] (3/1) > [INT] : 1 +[DOTDICT] (27/5) > {C} [LIST] (3/2) > [DOTDICT] (1/1) > {param} [INT] : 1 +[DOTDICT] (27/5) > {C} [LIST] (3/3) > [INT] : 2 +[DOTDICT] (27/6) > {p23} [INT] : 1 +[DOTDICT] (27/7) > {par\\am} [INT] : 1 +[DOTDICT] (27/8) > {p24} [INT] : 1 +[DOTDICT] (27/9) > {path\\to\\file} [STR] : 'C:\\Users\\Example\\file.txt' +[DOTDICT] (27/10) > {par𠼭am} [INT] : 1 +[DOTDICT] (27/11) > {p27} [INT] : 1 +[DOTDICT] (27/12) > {F} [DOTDICT] (1/1) > {par𠼭am} [INT] : 1 +[DOTDICT] (27/13) > {p28} [INT] : 1 +[DOTDICT] (27/14) > {G} [LIST] (3/1) > [INT] : 1 +[DOTDICT] (27/14) > {G} [LIST] (3/2) > [DOTDICT] (1/1) > {par𠼭am} [INT] : 1 +[DOTDICT] (27/14) > {G} [LIST] (3/3) > [INT] : 2 +[DOTDICT] (27/15) > {p29} [INT] : 1 +[DOTDICT] (27/16) > {𠼭param} [INT] : 1 +[DOTDICT] (27/17) > {p30} [INT] : 1 +[DOTDICT] (27/18) > {H} [DOTDICT] (1/1) > {𠼭param} [INT] : 1 +[DOTDICT] (27/19) > {p31} [INT] : 1 +[DOTDICT] (27/20) > {K} [LIST] (3/1) > [INT] : 1 +[DOTDICT] (27/20) > {K} [LIST] (3/2) > [DOTDICT] (1/1) > {𠼭param} [INT] : 1 +[DOTDICT] (27/20) > {K} [LIST] (3/3) > [INT] : 2 +[DOTDICT] (27/21) > {p32} [INT] : 1 +[DOTDICT] (27/22) > {param൯} [INT] : 1 +[DOTDICT] (27/23) > {p33} [INT] : 1 +[DOTDICT] (27/24) > {L} [DOTDICT] (1/1) > {param൯} [INT] : 1 +[DOTDICT] (27/25) > {p34} [INT] : 1 +[DOTDICT] (27/26) > {M} [LIST] (3/1) > [INT] : 1 +[DOTDICT] (27/26) > {M} [LIST] (3/2) > [DOTDICT] (1/1) > {param൯} [INT] : 1 +[DOTDICT] (27/26) > {M} [LIST] (3/3) > [INT] : 2 +[DOTDICT] (27/27) > {p35} [INT] : 1 """ -# # # listofdictUsecases.append(dictUsecase) # several issues +listofdictUsecases.append(dictUsecase) del dictUsecase # -------------------------------------------------------------------------------------------------------------- # -------------------------------------------------------------------------------------------------------------- @@ -1770,9 +1807,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0450.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "%A". Key names have to start with a letter, digit or underscore.""" -dictUsecase['EXPECTEDRETURN'] = None -# listofdictUsecases.append(dictUsecase) # temporarily deactivated because of rework of naming conventions +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now; TODO: move this test to GOODCASE section (JPP_0401) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1784,9 +1821,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0451.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "%A". Key names have to start with a letter, digit or underscore.""" -dictUsecase['EXPECTEDRETURN'] = None -# listofdictUsecases.append(dictUsecase) # temporarily deactivated because of rework of naming conventions +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now; TODO: move this test to GOODCASE section (JPP_0401) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1798,9 +1835,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0452.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "%A". Key names have to start with a letter, digit or underscore.""" -dictUsecase['EXPECTEDRETURN'] = None -# listofdictUsecases.append(dictUsecase) # temporarily deactivated because of rework of naming conventions +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now; TODO: move this test to GOODCASE section (JPP_0401) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1812,9 +1849,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0453.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "par%am".""" # error message to be extended -dictUsecase['EXPECTEDRETURN'] = None -# listofdictUsecases.append(dictUsecase) # temporarily deactivated because of rework of naming conventions +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now; TODO: move this test to GOODCASE section (JPP_0401) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1826,9 +1863,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0454.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "par%am".""" # error message to be extended -dictUsecase['EXPECTEDRETURN'] = None -# listofdictUsecases.append(dictUsecase) # temporarily deactivated because of rework of naming conventions +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now; TODO: move this test to GOODCASE section (JPP_0401) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1840,9 +1877,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0455.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "par%am".""" # error message to be extended -dictUsecase['EXPECTEDRETURN'] = None -# listofdictUsecases.append(dictUsecase) # temporarily deactivated because of rework of naming conventions +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now; TODO: move this test to GOODCASE section (JPP_0401) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1854,9 +1891,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0456.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO -dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # blanks inside name not allowed but currently accepted +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now (blanks allowed); TODO: move this test to GOODCASE section (JPP_0401) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1868,9 +1905,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0457.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO -dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # blanks inside name not allowed but currently accepted +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now (blanks allowed); TODO: move this test to GOODCASE section (JPP_0401) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1882,9 +1919,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0458.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO -dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # blanks inside name not allowed but currently accepted +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now (blanks allowed); TODO: move this test to GOODCASE section (JPP_0401) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1896,9 +1933,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0459.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDEXCEPTION'] = "Empty key name detected. Please enter a valid name." dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # empty name not allowed but currently accepted +listofdictUsecases.append(dictUsecase) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1910,9 +1947,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0460.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDEXCEPTION'] = "Empty key name detected. Please enter a valid name." dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # empty name not allowed but currently accepted +listofdictUsecases.append(dictUsecase) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1924,9 +1961,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0461.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDEXCEPTION'] = "Empty key name detected. Please enter a valid name." dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # empty name not allowed but currently accepted +listofdictUsecases.append(dictUsecase) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1938,9 +1975,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0462.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDEXCEPTION'] = "Empty key name detected. Please enter a valid name." dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # name contains blanks only, waiting for final error message +listofdictUsecases.append(dictUsecase) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1952,9 +1989,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0463.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDEXCEPTION'] = "Empty key name detected. Please enter a valid name." dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # name contains blanks only, waiting for final error message +listofdictUsecases.append(dictUsecase) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1966,9 +2003,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0464.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDEXCEPTION'] = "Empty key name detected. Please enter a valid name." dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # name contains blanks only, waiting for final error message +listofdictUsecases.append(dictUsecase) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1980,9 +2017,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0465.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO -dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # invalid name accepted and usage causes: 'local variable 'tmpList03' referenced before assignment'! +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now; TODO: move this test to GOODCASE section del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -1994,9 +2031,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0466.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None # TODO -dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # invalid name accepted and usage causes: 'local variable 'tmpList03' referenced before assignment'! +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = None # TODO +# # # listofdictUsecases.append(dictUsecase) # 10.04.2025 / name is valid now; TODO: move this test to GOODCASE section del dictUsecase # -------------------------------------------------------------------------------------------------------------- @@ -3152,7 +3189,10 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = "Cyclic import" dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_1150.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic imported json file" +# temporary adaption +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/389 +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/393#issuecomment-2792637445 +dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic import detection while handling the file" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -3166,7 +3206,10 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = "Cyclic import" dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_1151.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic imported json file" +# temporary adaption +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/389 +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/393#issuecomment-2792637445 +dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic import detection while handling the file" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -3180,7 +3223,10 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = "Cyclic import" dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_1152.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic imported json file" +# temporary adaption +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/389 +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/393#issuecomment-2792637445 +dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic import detection while handling the file" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -3194,7 +3240,10 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = "Cyclic import" dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_1153.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic imported json file" +# temporary adaption +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/389 +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/393#issuecomment-2792637445 +dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic import detection while handling the file" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -3370,7 +3419,10 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = "Cyclic import" dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_1165.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic imported json file" # file list to be fixed +# temporary adaption +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/389 +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/393#issuecomment-2792637445 +dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic import detection while handling the file" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -3386,7 +3438,10 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = "Cyclic import" dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_1166.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic imported json file" # file list to be fixed +# temporary adaption +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/389 +# https://github.com/test-fullautomation/python-jsonpreprocessor/issues/393#issuecomment-2792637445 +dictUsecase['EXPECTEDEXCEPTION'] = "Cyclic import detection while handling the file" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -4275,7 +4330,7 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_2050.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """'Could not resolve expression '${param}'. The based parameter 'param' is not defined yet! Use the ' : ' syntax to create a new based parameter.'""" +dictUsecase['EXPECTEDEXCEPTION'] = "'Could not resolve expression '${param}'. The based parameter 'param' is not defined yet! Use the ' : ' syntax to create a new based parameter.'" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -4289,7 +4344,7 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_2051.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """'A key with name '${param}' does not exist at this position. Use the ' : ' syntax to create a new key.'""" +dictUsecase['EXPECTEDEXCEPTION'] = "'A key with name '${param}' does not exist at this position. Use the ' : ' syntax to create a new key.'" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -4303,7 +4358,7 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_2052.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """'Missing scope for parameter '${param}'. To change the value of this parameter, an absolute path must be used: '${params}['001']['param']' or '${params.001.param}'.'""" +dictUsecase['EXPECTEDEXCEPTION'] = "'Missing scope for parameter '${param}'. To change the value of this parameter, an absolute path must be used: '${params}['001']['param']' or '${params.001.param}'.'" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -4317,7 +4372,7 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_2053.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """'A key with name '${params}['001']' does not exist at this position. Use the ' : ' syntax to create a new key.'""" +dictUsecase['EXPECTEDEXCEPTION'] = "'A key with name '${params}['001']' does not exist at this position. Use the ' : ' syntax to create a new key.'" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -4331,7 +4386,7 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_2054.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """'A key with name '${params.001}' does not exist at this position. Use the ' : ' syntax to create a new key.'""" +dictUsecase['EXPECTEDEXCEPTION'] = "'A key with name '${params.001}' does not exist at this position. Use the ' : ' syntax to create a new key.'" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -4345,9 +4400,9 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_2055.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDEXCEPTION'] = "Missing scope for parameter '${C}'. To change the value of this parameter, an absolute path must be used: '${params}[1]['B'][0]['C']' or '${params.1.B.0.C}'." dictUsecase['EXPECTEDRETURN'] = None -# # # listofdictUsecases.append(dictUsecase) # https://github.com/test-fullautomation/python-jsonpreprocessor/issues/349 +listofdictUsecases.append(dictUsecase) del dictUsecase # -------------------------------------------------------------------------------------------------------------- dictUsecase = {} @@ -4359,7 +4414,7 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_2056.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """'A key with name '${C}' does not exist at this position. Use the ' : ' syntax to create a new key.'""" +dictUsecase['EXPECTEDEXCEPTION'] = "'A key with name '${C}' does not exist at this position. Use the ' : ' syntax to create a new key.'" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -4373,7 +4428,7 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_2057.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """'A key with name '${params}[1]['B'][0]['C']' does not exist at this position. Use the ' : ' syntax to create a new key.'""" +dictUsecase['EXPECTEDEXCEPTION'] = "'A key with name '${params}[1]['B'][0]['C']' does not exist at this position. Use the ' : ' syntax to create a new key.'" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase @@ -4387,7 +4442,7 @@ dictUsecase['HINT'] = None dictUsecase['COMMENT'] = None dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_2058.jsonp" -dictUsecase['EXPECTEDEXCEPTION'] = """'A key with name '${params.1.B.0.C}' does not exist at this position. Use the ' : ' syntax to create a new key.'""" +dictUsecase['EXPECTEDEXCEPTION'] = "'A key with name '${params.1.B.0.C}' does not exist at this position. Use the ' : ' syntax to create a new key.'" dictUsecase['EXPECTEDRETURN'] = None listofdictUsecases.append(dictUsecase) del dictUsecase diff --git a/test/testfiles/jpp-test_config_0401.jsonp b/test/testfiles/jpp-test_config_0401.jsonp index bdd29d2..c9fae62 100644 --- a/test/testfiles/jpp-test_config_0401.jsonp +++ b/test/testfiles/jpp-test_config_0401.jsonp @@ -13,7 +13,7 @@ // limitations under the License. //************************************************************************** { - // -- blank, backslash, 4Byte character + // -- blank, backslash " param " : 1, "p21" : ${param}, // @@ -26,14 +26,16 @@ "par\\am" : 1, "p24" : ${par\\am}, // - "D" : {"par\\am" : 1}, - "p25" : ${D}['par\\am'], + // https://github.com/test-fullautomation/python-jsonpreprocessor/issues/440 + // "D" : {"par\\am" : 1}, + // "p25" : ${D}['par\\am'], // - "E" : [1, {"par\\am" : 1}, 2], - "p26" : ${E}[1]['par\\am'], + // "E" : [1, {"par\\am" : 1}, 2], + // "p26" : ${E}[1]['par\\am'], // - "path\\to\\file" : "C:\\Users\\Example\\file.txt" + "path\\to\\file" : "C:\\Users\\Example\\file.txt", // + // -- Unicode letters "par𠼭am" : 1, "p27" : ${par𠼭am}, // @@ -51,4 +53,15 @@ // "K" : [1, {"𠼭param" : 1}, 2], "p32" : ${K}[1]['𠼭param'], + // + // -- Unicode decimal digits + "param൯" : 1, + "p33" : ${param൯}, + // + "L" : {"param൯" : 1}, + "p34" : ${L}['param൯'], + // + "M" : [1, {"param൯" : 1}, 2], + "p35" : ${M}[1]['param൯'] } +