private void addDuplicatedMethodError(
      String message, IOpenMethod method, IOpenMethod existedMethod) {
    ISyntaxNode newMethodSyntaxNode = method.getInfo().getSyntaxNode();
    if (newMethodSyntaxNode instanceof TableSyntaxNode) {
      SyntaxNodeException error =
          SyntaxNodeExceptionUtils.createError(message, newMethodSyntaxNode);
      ((TableSyntaxNode) newMethodSyntaxNode).addError(error);

      try {
        TableSyntaxNode existedMethodSyntaxNode =
            (TableSyntaxNode) existedMethod.getInfo().getSyntaxNode();
        if (existedMethodSyntaxNode != null) {
          existedMethodSyntaxNode.addError(
              SyntaxNodeExceptionUtils.createError(message, existedMethodSyntaxNode));
        }
      } catch (Exception ex) {
        log.warn(
            "Cannot get a syntax node for the method: {}",
            MethodUtil.printMethod(existedMethod, new StringBuilder()),
            ex);
      }

      addError(error);
    } else {
      addError(new DuplicatedMethodException(message, method));
    }
  }
  @Test
  public void simpleLookup4paramNotEnoughValues() {
    IOpenMethod method =
        getJavaWrapper()
            .getOpenClass()
            .getMethod(
                "SimpleLookup4paramNotEnoughValues",
                new IOpenClass[] {
                  JavaOpenClass.STRING,
                  JavaOpenClass.getOpenClass(Double.class),
                  JavaOpenClass.INT,
                  JavaOpenClass.INT
                });
    Object wrapperInstance = getJavaWrapper().newInstance();

    assertEquals(
        new DoubleValue(0.9),
        method.invoke(wrapperInstance, new Object[] {"DE", 0d, 7, 3}, getJavaWrapper().getEnv()));
    assertEquals(
        new DoubleValue(1),
        method.invoke(wrapperInstance, new Object[] {"DE", 0d, 10, 4}, getJavaWrapper().getEnv()));
    assertEquals(
        new DoubleValue(56),
        method.invoke(wrapperInstance, new Object[] {"", 1d, 9, 3}, getJavaWrapper().getEnv()));
  }
 private TestSuiteMethod createNewTestSuiteMethod(TestSuiteMethod testSuiteMethod) {
   IOpenMethod method = testSuiteMethod.getTestedMethod();
   IOpenMethod newTargetMethod =
       getDeclaredMethod(method.getName(), method.getSignature().getParameterTypes());
   return new TestSuiteMethod(
       newTargetMethod, testSuiteMethod.getHeader(), testSuiteMethod.getBoundNode());
 }
  @Test
  public void testRangeInt() {
    IOpenMethod method =
        getJavaWrapper()
            .getOpenClass()
            .getMethod("TestRangeInt", new IOpenClass[] {JavaOpenClass.INT});
    Object wrapperInstance = getJavaWrapper().newInstance();

    assertEquals(-10, method.invoke(wrapperInstance, new Object[] {67}, getJavaWrapper().getEnv()));
    assertEquals(89, method.invoke(wrapperInstance, new Object[] {99}, getJavaWrapper().getEnv()));
    assertEquals(78, method.invoke(wrapperInstance, new Object[] {3}, getJavaWrapper().getEnv()));
  }
  @Test
  public void testArray2() {
    IOpenMethod method = getMethod("TestArray2", new IOpenClass[] {JavaOpenClass.STRING});
    Object wrapperInstance = getJavaWrapper().newInstance();

    assertEquals(
        1, method.invoke(wrapperInstance, new Object[] {"1234"}, getJavaWrapper().getEnv()));
    assertEquals(
        12, method.invoke(wrapperInstance, new Object[] {"werwe"}, getJavaWrapper().getEnv()));
    assertEquals(
        5, method.invoke(wrapperInstance, new Object[] {"asda"}, getJavaWrapper().getEnv()));
  }
  /**
   * Gets rule information of IOpenMethod instance.
   *
   * @param method IOpenMethod instance
   * @return rule info
   */
  private static RuleInfo getRuleInfoForMethod(IOpenMethod method) {

    String methodName = method.getName();
    IOpenClass[] paramClasses = method.getSignature().getParameterTypes();
    Class<?> returnType = method.getType().getInstanceClass();

    Class<?>[] paramTypes = OpenClassHelper.getInstanceClasses(paramClasses);

    RuleInfo ruleInfo = createRuleInfo(methodName, paramTypes, returnType);

    return ruleInfo;
  }
  @Test
  public void testRangeDouble1() {
    IOpenMethod method =
        getJavaWrapper()
            .getOpenClass()
            .getMethod("TestRangeDouble1", new IOpenClass[] {JavaOpenClass.DOUBLE});
    Object wrapperInstance = getJavaWrapper().newInstance();

    assertEquals(
        -10, method.invoke(wrapperInstance, new Object[] {150.005d}, getJavaWrapper().getEnv()));
    assertEquals(85, method.invoke(wrapperInstance, new Object[] {0d}, getJavaWrapper().getEnv()));
    assertEquals(
        78, method.invoke(wrapperInstance, new Object[] {6000000d}, getJavaWrapper().getEnv()));
  }
  @Test
  public void testArray1() {
    IOpenMethod method =
        getJavaWrapper()
            .getOpenClass()
            .getMethod("TestArray1", new IOpenClass[] {JavaOpenClass.STRING});
    Object wrapperInstance = getJavaWrapper().newInstance();

    assertEquals(
        0, method.invoke(wrapperInstance, new Object[] {"1234"}, getJavaWrapper().getEnv()));
    assertEquals(5, method.invoke(wrapperInstance, new Object[] {"-3"}, getJavaWrapper().getEnv()));
    assertEquals(
        0, method.invoke(wrapperInstance, new Object[] {"erty"}, getJavaWrapper().getEnv()));
  }
  @Test
  public void simpleLookupRange1() {
    IOpenMethod method =
        getJavaWrapper()
            .getOpenClass()
            .getMethod(
                "SimpleLookupRange1",
                new IOpenClass[] {JavaOpenClass.STRING, JavaOpenClass.getOpenClass(Double.class)});
    Object wrapperInstance = getJavaWrapper().newInstance();

    assertEquals(
        new DoubleValue(0.9),
        method.invoke(wrapperInstance, new Object[] {"DE", 25}, getJavaWrapper().getEnv()));
    assertEquals(
        new DoubleValue(1),
        method.invoke(wrapperInstance, new Object[] {"", 4}, getJavaWrapper().getEnv()));
    assertEquals(
        new DoubleValue(0),
        method.invoke(wrapperInstance, new Object[] {"DE", 3}, getJavaWrapper().getEnv()));
  }
  @Test
  public void simpleLookup3paramRangeArray() {
    IOpenMethod method =
        getJavaWrapper()
            .getOpenClass()
            .getMethod(
                "SimpleLookup3paramRangeArray",
                new IOpenClass[] {
                  JavaOpenClass.STRING, JavaOpenClass.getOpenClass(Double.class), JavaOpenClass.INT
                });
    Object wrapperInstance = getJavaWrapper().newInstance();

    assertEquals(
        new DoubleValue(0),
        method.invoke(wrapperInstance, new Object[] {"DE", 5d, 5}, getJavaWrapper().getEnv()));
    assertEquals(
        new DoubleValue(0.9),
        method.invoke(wrapperInstance, new Object[] {"DE", 7d, 3}, getJavaWrapper().getEnv()));
    assertEquals(
        new DoubleValue(1),
        method.invoke(wrapperInstance, new Object[] {"DE", 10d, 4}, getJavaWrapper().getEnv()));
  }
 private void validateTestSuiteMethod(IOpenMethod method, IOpenMethod existedMethod) {
   if (method instanceof TableUriMethod && existedMethod instanceof TableUriMethod) {
     String methodHashUrl = ((TableUriMethod) method).getTableUri();
     String existedMethodHashUrl = ((TableUriMethod) existedMethod).getTableUri();
     if (!methodHashUrl.equals(existedMethodHashUrl)) {
       duplicatedMethodUrls.add(method.getInfo().getSourceUrl());
       String message = ValidationMessages.getDuplicatedMethodMessage(existedMethod, method);
       addDuplicatedMethodError(message, method, existedMethod);
     }
   } else {
     throw new IllegalStateException("Implementation supports only TableUriMethod!");
   }
 }
  /**
   * Adds method to <code>XlsModuleOpenClass</code>.
   *
   * @param method method object
   */
  @Override
  public void addMethod(IOpenMethod method) {
    if (method instanceof OpenMethodDispatcher) {
      addDispatcherMethod((OpenMethodDispatcher) method);
      return;
    }
    IOpenMethod m = decorateForMultimoduleDispatching(method);

    // Workaround needed to set the module name in the method while compile
    if (m instanceof AMethod) {
      if (((AMethod) m).getModuleName() == null) {
        XlsMetaInfo metaInfo = getXlsMetaInfo();
        if (metaInfo != null) {
          IOpenSourceCodeModule sourceCodeModule = metaInfo.getXlsModuleNode().getModule();
          if (sourceCodeModule instanceof IModuleInfo) {
            ((AMethod) m).setModuleName(((IModuleInfo) sourceCodeModule).getModuleName());
          }
        }
      }
    }

    // Checks that method already exists in the class. If it already
    // exists then "overload" it using decorator; otherwise - just add to
    // the class.
    //
    IOpenMethod existedMethod =
        getDeclaredMethod(method.getName(), method.getSignature().getParameterTypes());
    if (existedMethod != null) {

      if (!existedMethod.getType().equals(method.getType())) {
        String message =
            String.format(
                "Method \"%s\" with return type \"%s\" has already been defined with another return type (\"%s\")",
                method.getName(),
                method.getType().getDisplayName(0),
                existedMethod.getType().getDisplayName(0));
        addDuplicatedMethodError(message, method, existedMethod);
        return;
      }

      if (method != existedMethod && method instanceof TestSuiteMethod) {
        validateTestSuiteMethod(method, existedMethod);
        return;
      }

      // Checks the instance of existed method. If it's the
      // OpenMethodDecorator then just add the method-candidate to
      // decorator; otherwise - replace existed method with new instance
      // of OpenMethodDecorator for existed method and add new one.
      //
      try {
        if (existedMethod instanceof OpenMethodDispatcher) {
          OpenMethodDispatcher decorator = (OpenMethodDispatcher) existedMethod;
          decorator.addMethod(undecorateForMultimoduleDispatching(m));
        } else {
          if (m != existedMethod) {
            // Create decorator for existed method.
            //
            OpenMethodDispatcher dispatcher = getOpenMethodDispatcher(existedMethod);

            IOpenMethod openMethod = decorateForMultimoduleDispatching(dispatcher);

            overrideMethod(openMethod);

            dispatcher.addMethod(undecorateForMultimoduleDispatching(m));
          }
        }
      } catch (DuplicatedMethodException e) {
        SyntaxNodeException error = null;
        if (m instanceof IMemberMetaInfo) {
          IMemberMetaInfo memberMetaInfo = (IMemberMetaInfo) m;
          if (memberMetaInfo.getSyntaxNode() != null) {
            if (memberMetaInfo.getSyntaxNode() instanceof TableSyntaxNode) {
              error =
                  SyntaxNodeExceptionUtils.createError(
                      e.getMessage(), e, memberMetaInfo.getSyntaxNode());
              ((TableSyntaxNode) memberMetaInfo.getSyntaxNode()).addError(error);
            }
          }
        }
        boolean f = false;
        for (Throwable t : getErrors()) {
          if (t.getMessage().equals(e.getMessage())) {
            f = true;
            break;
          }
        }
        if (!f) {
          if (error != null) {
            addError(error);
          } else {
            addError(e);
          }
        }
      }
    } else {
      // Just wrap original method with dispatcher functionality.
      //

      if (dispatchingValidationEnabled
          && !(m instanceof TestSuiteMethod)
          && dimensionalPropertyPresented(m)) {
        // Create dispatcher for existed method.
        //
        OpenMethodDispatcher dispatcher = getOpenMethodDispatcher(m);

        IOpenMethod openMethod = decorateForMultimoduleDispatching(dispatcher);

        super.addMethod(openMethod);

      } else {
        super.addMethod(m);
      }
    }
  }