content: /*
   * Copyright 2010-2025 Hyland Software, Inc. and its affiliates.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.activiti.core.el.juel;
  
  import static org.junit.jupiter.api.Assertions.assertEquals;
  import static org.junit.jupiter.api.Assertions.assertFalse;
  import static org.junit.jupiter.api.Assertions.assertTrue;
  import static org.junit.jupiter.api.Assertions.fail;
  
  import jakarta.el.BeanELResolver;
  import jakarta.el.PropertyNotFoundException;
  import org.activiti.core.el.juel.test.TestCase;
  import org.activiti.core.el.juel.tree.TreeStore;
  import org.activiti.core.el.juel.tree.impl.Builder;
  import org.activiti.core.el.juel.util.SimpleContext;
  import org.activiti.core.el.juel.util.SimpleResolver;
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Test;
  
  public class TreeValueExpressionTest extends TestCase {
  
      public static int foo() {
          return 0;
      }
  
      public static int bar() {
          return 0;
      }
  
      int foobar;
  
      public void setFoobar(int value) {
          foobar = value;
      }
  
      SimpleContext context;
      TreeStore store = new TreeStore(new Builder(), null);
  
      @BeforeEach
      protected void setUp() throws Exception {
          context = new SimpleContext(new SimpleResolver(new BeanELResolver()));
          context.getELResolver().setValue(context, null, "base", this);
  
          // variables var_long_1, var_long_2
          context.setVariable("var_long_1", new TreeValueExpression(store, null, null, null, "${1}", long.class));
          context.setVariable("var_long_2", new TreeValueExpression(store, null, null, null, "${1}", long.class));
          // var_var_long_1 --> var_long_1, var_var_long_2 --> var_long_1
          context.setVariable(
              "var_var_long_1",
              new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_long_1}", long.class)
          );
          context.setVariable(
              "var_var_long_2",
              new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_long_2}", long.class)
          );
  
          // functions ns:f0(), ns:f1()
          context.setFunction("", "foo", getClass().getMethod("foo"));
          context.setFunction("ns", "foo_1", getClass().getMethod("foo"));
          context.setFunction("ns", "foo_2", getClass().getMethod("foo"));
  
          context.setVariable(
              "var_foo_1",
              new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${ns:foo_1()}", long.class)
          );
          context.setVariable(
              "var_foo_2",
              new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${ns:foo_2()}", long.class)
          );
  
          context.setVariable(
              "var_foobar",
              new TreeValueExpression(store, null, context.getVariableMapper(), null, "${base.foobar}", int.class)
          );
  
          context.getELResolver().setValue(context, null, "property_foo", "foo");
      }
  
      @Test
      public void testEqualsAndHashCode() throws NoSuchMethodException {
          TreeValueExpression e1, e2;
  
          e1 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${1}", Object.class);
          e2 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${1}", Object.class);
          assertEquals(e1, e2);
          assertEquals(e1.hashCode(), e2.hashCode());
  
          e1 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_long_1}", Object.class);
          e2 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_long_2}", Object.class);
          assertEquals(e1, e2);
          assertEquals(e1.hashCode(), e2.hashCode());
  
          e1 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_var_long_1}", Object.class);
          e2 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_var_long_2}", Object.class);
          assertEquals(e1, e2);
          assertEquals(e1.hashCode(), e2.hashCode());
  
          e1 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_long_1}", Object.class);
          context
              .getVariableMapper()
              .setVariable(
                  "var_long_1",
                  new TreeValueExpression(store, null, context.getVariableMapper(), null, "${-1}", Object.class)
              );
          e2 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_long_1}", Object.class);
          assertFalse(e1.equals(e2));
  
          e1 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_foo_1}", Object.class);
          e2 = new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_foo_2}", Object.class);
          assertEquals(e1, e2);
          assertEquals(e1.hashCode(), e2.hashCode());
  
          e2 = new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${ns:foo_1()}", Object.class);
          e1 = new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${ns:foo_2()}", Object.class);
          assertEquals(e1, e2);
          assertEquals(e1.hashCode(), e2.hashCode());
  
          e2 = new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${foo()}", Object.class);
          e1 = new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${ns:foo_1()}", Object.class);
          assertEquals(e1, e2);
          assertEquals(e1.hashCode(), e2.hashCode());
  
          e2 = new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${foo()}", Object.class);
          context.setFunction("", "foo", getClass().getMethod("bar"));
          e1 = new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${foo()}", Object.class);
          assertFalse(e1.equals(e2));
  
          e2 = new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${ns:foo_1()}", Object.class);
          context.setFunction("ns", "foo_1", getClass().getMethod("bar"));
          e1 = new TreeValueExpression(store, context.getFunctionMapper(), null, null, "${ns:foo_1()}", Object.class);
          assertFalse(e1.equals(e2));
      }
  
      @Test
      public void testGetExpressionString() {
          assertEquals(
              "foo",
              new TreeValueExpression(store, null, null, null, "foo", Object.class).getExpressionString()
          );
      }
  
      @Test
      public void testIsLiteralText() {
          assertTrue(new TreeValueExpression(store, null, null, null, "foo", Object.class).isLiteralText());
          assertFalse(new TreeValueExpression(store, null, null, null, "${foo}", Object.class).isLiteralText());
      }
  
      @Test
      public void testIsDeferred() {
          assertFalse(new TreeValueExpression(store, null, null, null, "foo", Object.class).isDeferred());
          assertFalse(new TreeValueExpression(store, null, null, null, "${foo}", Object.class).isDeferred());
          assertTrue(new TreeValueExpression(store, null, null, null, "#{foo}", Object.class).isDeferred());
      }
  
      @Test
      public void testGetExpectedType() {
          assertEquals(
              Object.class,
              new TreeValueExpression(store, null, null, null, "${foo}", Object.class).getExpectedType()
          );
          assertEquals(
              String.class,
              new TreeValueExpression(store, null, null, null, "${foo}", String.class).getExpectedType()
          );
      }
  
      @Test
      public void testGetType() {
          assertFalse(
              new TreeValueExpression(store, null, null, null, "${property_foo}", Object.class).isReadOnly(context)
          );
      }
  
      @Test
      public void testIsReadOnly() {
          assertFalse(
              new TreeValueExpression(store, null, null, null, "${property_foo}", Object.class).isReadOnly(context)
          );
      }
  
      @Test
      public void testSetValue() {
          new TreeValueExpression(store, null, null, null, "${property_foo}", Object.class).setValue(context, "bar");
          assertEquals(
              "bar",
              new TreeValueExpression(store, null, null, null, "${property_foo}", Object.class).getValue(context)
          );
  
          // Test added for bug #2748538
          new TreeValueExpression(store, null, context.getVariableMapper(), null, "${var_foobar}", Object.class).setValue(
              context,
              123
          );
          assertEquals(123, foobar);
          try {
              context.getELResolver().getValue(context, null, "var_foobar");
              fail("Bug in AstIdentifierNode.setValue(...)");
          } catch (PropertyNotFoundException e) {
              // fine
          }
      }
  
      @Test
      public void testGetValue() {
          assertEquals(
              "foo",
              new TreeValueExpression(store, null, null, null, "${property_foo}", Object.class).getValue(context)
          );
      }
  
      @Test
      public void testSerialize() throws Exception {
          TreeValueExpression expression = new TreeValueExpression(
              store,
              context.getFunctionMapper(),
              context.getVariableMapper(),
              null,
              "${var_long_1 + foo()}",
              Object.class
          );
          assertEquals(expression, deserialize(serialize(expression)));
      }
  }
  