def test_FunctionResultToUpcase(self): theString = types.String("This_Is_a_MiXed_StrIng") theFuncCall = types.FunctionCall(types.Symbol("upcase"), self.theEnv.modulesManager, [theString]) theResult = self.theFunc.do(self.theEnv, theFuncCall) self.assertEqual(theResult.__class__, types.String) self.assertEqual(len(set(string.ascii_lowercase).intersection(set(theResult.evaluate()))), 0) self.assertEqual(theResult, self.theFunc.do(self.theEnv, theString))
def test_FunctionCallAsArgument(self): if not self.theEnv.modulesManager.currentScope.functions.has("upcase"): self.skipTest("upcase not defined") self.assertTrue( self.forInput( types.FunctionCall("upcase", self.theEnv.modulesManager, [types.String("acqua")]), types.String("acqua")).expect( types.Integer(cmp("acqua".upper(), "acqua"))))
def analyzeFunction(theFunction, patternIndex, variables, inPatternVariables=None, fakeVariables = None, realToFakeMap = None, vIndex = None, fakeNames = None): ''' Analyze a FunctionCall inside a Test-CE to replace variables name with fake names an bound locations to improve reuse of test-nodes (normalize variables names) @param theFunction: a function call to replace @type theFunction: types.FunctionCall @param patternIndex: the index of the test-pattern in the chain of ce @type patternIndex: int @param variables: a dict of variable name => VariableReferences @type variables: dict @param fakeVariables: a dict of fake variables references or None (to make a new one) @type fakeVariables: dict @param realToFakeMap: a map of real variables names to fake ones @type realToFakeMap: dict @param vIndex: the index for fake variables name generation @type vIndex: int ''' inPatternVariables = [] if inPatternVariables is None else inPatternVariables aNewFunctionCallArgs = [] fakeVariables = {} if fakeVariables is None else fakeVariables fakeNames = {} if fakeNames is None else fakeNames realToFakeMap = {} if realToFakeMap is None else realToFakeMap vIndex = [] if vIndex is None else vIndex; if isinstance(theFunction, types.FunctionCall): assert isinstance(theFunction, types.FunctionCall) for aArg in theFunction.funcArgs: # globals are resolved at function-call execution time if isinstance(aArg, (types.SingleFieldVariable, types.MultiFieldVariable)): # i've already created a fake_var for this var? if not realToFakeMap.has_key(aArg.evaluate()) : # where i found the variable first? mainReference = getVar(aArg.evaluate(), variables, inPatternVariables) if mainReference is False: raise MyClipsException("Variable %s found in the expression %s was referenced in CE #%d before being defined."%( aArg.evaluate(), theFunction.toClipsStr(), patternIndex )) varReference = VariableReference() varReference.reference = mainReference varReference.relPatternIndex = mainReference.patternIndex - patternIndex theFakeName = "%"+str(len(vIndex)) vIndex.append(None) theFakeVar = aArg.__class__(types.Symbol(theFakeName)) fakeVariables[theFakeVar.evaluate()] = varReference realToFakeMap[aArg.evaluate()] = theFakeVar.evaluate() fakeNames[aArg.evaluate()] = theFakeVar else: theFakeVar = fakeNames[aArg.evaluate()] # replace the variable name with a fake name #aArg.content = theFakeName aNewFunctionCallArgs.append(theFakeVar) elif isinstance(aArg, types.FunctionCall): # recursion: replace arguments inside the function call # fakeReferences are ignored because the dict is automatically # updated by the recursion. aInnerNewFunctionCall, _ = analyzeFunction(aArg, patternIndex, variables, inPatternVariables, fakeVariables, realToFakeMap, vIndex, fakeNames) # replace the old function call with a new one with fake variables #theFunction.funcArgs[iArg] = aInnerNewFunctionCall aNewFunctionCallArgs.append(aInnerNewFunctionCall) else: aNewFunctionCallArgs.append(aArg) # get the current scope and backup it _tmp_scope = theFunction.scope.modules.currentScope # then change it to the original function call scope theFunction.scope.modules.changeCurrentScope(theFunction.scope.moduleName) # create the new function call newFunctionCall = types.FunctionCall(theFunction.funcName, theFunction.scope.modules, aNewFunctionCallArgs) # then restore the previous scope theFunction.scope.modules.changeCurrentScope(_tmp_scope.moduleName) return (newFunctionCall, fakeVariables) else: raise TypeError("AnalyzeFunction require a FunctionCall as first argument")