@Override
    public ValidationResult validate(RuleBuilderStep step) {
        final RuleFragment ruleFragment = actions.get(step.function());
        FunctionDescriptor<?> functionDescriptor = ruleFragment.descriptor();
        Map<String, Object> stepParameters = step.parameters();

        //Add output to map
        String outputvariable = step.outputvariable();
        if (StringUtils.isNotBlank(outputvariable)) {

            if (functionDescriptor.returnType() == Void.class) {
                return new ValidationResult(true, f("Return type is void. No output variable allowed", functionDescriptor.name()));
            }

            storeVariable(outputvariable, functionDescriptor.returnType());
        }

        ImmutableList<ParameterDescriptor> parameterDescriptors = functionDescriptor.params();
        for (ParameterDescriptor parameterDescriptor : parameterDescriptors) {
            String parameterName = parameterDescriptor.name();
            Object value = stepParameters.get(parameterName);
            Class<?> variableType = getVariableType(value);

            if (!parameterDescriptor.optional() && value == null) {
                return new ValidationResult(true, f("Missing parameter %s", parameterName));
            }

            //$ means it is stored in another variable and we need to fetch and verify that type
            if (value instanceof String s && s.startsWith("$")) {
                String substring = s.substring(1);
                Class<?> passedVariableType = variables.get(substring);
                if (Objects.isNull(passedVariableType)) {
                    return new ValidationResult(true, f("Could not find passed variable %s", value));
                }
                variableType = passedVariableType;
            }

            //Check if variable type matches function expectation
            Class<?> paramType = parameterDescriptor.type();
            if (value != null && paramType != Object.class && variableType != paramType) {
                String errorMsg = "Found a wrong parameter type for parameter %s";
                return new ValidationResult(true, f(errorMsg, parameterName));
            }
        }

        return new ValidationResult(false, "");
    }
@Test
    void failsWhenRequiredParamMissing() {
        RuleBuilderStep stepWithValidNegation = RuleBuilderStep.builder().parameters(new HashMap<>()).function(INTEGER_FUNCTION).build();
        ValidationResult result = classUnderTest.validate(stepWithValidNegation);

        assertThat(result.failed()).isTrue();
        assertThat(result.failureReason()).isEqualTo("Missing parameter " + INT_PARAM);
    }