Repository: metron
Updated Branches:
  refs/heads/feature/METRON-1090-stellar-assignment 0e037edad -> 3df949877


http://git-wip-us.apache.org/repos/asf/metron/blob/3df94987/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/DefaultVariableResolver.java
----------------------------------------------------------------------
diff --git 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/DefaultVariableResolver.java
 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/DefaultVariableResolver.java
index fc2c2b7..1ac34d5 100644
--- 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/DefaultVariableResolver.java
+++ 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/DefaultVariableResolver.java
@@ -1,44 +1,75 @@
 /**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license
+ * agreements.  See the NOTICE file distributed with this work for additional 
information regarding
+ * copyright ownership.  The ASF licenses this file to you 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
+ * 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.
+ * 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.apache.metron.stellar.dsl;
 
+import java.util.function.BiConsumer;
 import java.util.function.Function;
 
-public class DefaultVariableResolver implements VariableResolver{
-  Function<String,Object> resolveFunc;
-  Function<String,Boolean> existsFunc;
+/**
+ * Simple VariableResolver implemenation using passed Functions
+ * for implementation.
+ *
+ * Support for updates is optional
+ */
+public class DefaultVariableResolver implements VariableResolver {
 
-  public DefaultVariableResolver(Function<String,Object> resolveFunc, 
Function<String,Boolean> existsFunc){
+  private Function<String, Object> resolveFunc;
+  private Function<String, Boolean> existsFunc;
+  private BiConsumer<String, Object> updateFunc;
+
+  /**
+   * DefaultVariableResolver without support for updates
+   * @param resolveFunc
+   * @param existsFunc
+   */
+  public DefaultVariableResolver(Function<String, Object> resolveFunc,
+      Function<String, Boolean> existsFunc) {
+    this(resolveFunc, existsFunc, null);
+  }
+
+  /**
+   * DefaultVariableResolver with full support for updates
+   * @param resolveFunc
+   * @param existsFunc
+   * @param updateFunc
+   */
+  public DefaultVariableResolver(Function<String, Object> resolveFunc,
+      Function<String, Boolean> existsFunc, BiConsumer<String, Object> 
updateFunc) {
     this.resolveFunc = resolveFunc;
     this.existsFunc = existsFunc;
+    this.updateFunc = updateFunc;
   }
+
   @Override
   public Object resolve(String variable) {
-    return resolveFunc.apply(variable);
+    return resolveFunc == null? null : resolveFunc.apply(variable);
   }
 
   @Override
   public boolean exists(String variable) {
-    return existsFunc.apply(variable);
+    return existsFunc == null? false : existsFunc.apply(variable);
   }
 
-  public static DefaultVariableResolver NULL_RESOLVER() {
-    return new DefaultVariableResolver(x -> null, x -> false);
+  @Override
+  public void update(String variable, Object value) {
+    if (updateFunc != null) {
+      updateFunc.accept(variable, value);
+    }
   }
+
+  public static DefaultVariableResolver NULL_RESOLVER = new 
DefaultVariableResolver(x -> null,
+      x -> false, null);
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/3df94987/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/MapVariableResolver.java
----------------------------------------------------------------------
diff --git 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/MapVariableResolver.java
 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/MapVariableResolver.java
index 872211d..e057975 100644
--- 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/MapVariableResolver.java
+++ 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/MapVariableResolver.java
@@ -66,4 +66,9 @@ public class MapVariableResolver implements VariableResolver {
   public boolean exists(String variable) {
     return true;
   }
+
+  @Override
+  public void update(String variable, Object value) {
+    // not supported, but could be useful for counters?
+  }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/3df94987/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/VariableResolver.java
----------------------------------------------------------------------
diff --git 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/VariableResolver.java
 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/VariableResolver.java
index fb95d27..d5edf3a 100644
--- 
a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/VariableResolver.java
+++ 
b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/VariableResolver.java
@@ -19,8 +19,35 @@
 package org.apache.metron.stellar.dsl;
 
 
+/**
+ * VariableResolver implementors provide support variable operations.
+ * <ul>
+ *   <li>Verifying the exists of a variable by name</li>
+ *   <li>Returning the value of a variable by name</li>
+ *   <li>Updating the value of a variable by name</li>
+ * </ul>
+ */
 public interface VariableResolver {
   public static final String ALL_FIELDS = "_";
+
+  /**
+   * Returns the value of a variable.
+   * @param variable the variable name
+   * @return the value Object
+   */
   Object resolve(String variable);
+
+  /**
+   * Returns the existance of the variable.
+   * @param variable the variable name
+   * @return true if the variable exists, false otherwise
+   */
   boolean exists(String variable);
+
+  /**
+   * Updates the value of a variable.
+   * @param variable the variable name
+   * @param value the value to update with
+   */
+  void update(String variable, Object value);
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/3df94987/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/BasicStellarTest.java
----------------------------------------------------------------------
diff --git 
a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/BasicStellarTest.java
 
b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/BasicStellarTest.java
index dec05a8..28f1ae4 100644
--- 
a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/BasicStellarTest.java
+++ 
b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/BasicStellarTest.java
@@ -19,8 +19,10 @@
 package org.apache.metron.stellar.dsl.functions;
 
 import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import java.text.DecimalFormat;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.metron.stellar.common.StellarProcessor;
 import org.apache.metron.stellar.dsl.Context;
@@ -115,6 +117,642 @@ public class BasicStellarTest {
   }
 
   @Test
+  public void testAssign(){
+    String query = "foo = 1";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(1, run(query,variables));
+    Assert.assertEquals(1, variables.get("foo"));
+
+    // test more complex, until we get +=
+    // the else is required....
+    query = "if foo == 1 then foo = foo + 1 else foo = foo - 1";
+    Assert.assertEquals(2, run(query,variables));
+    Assert.assertEquals(2, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> count = count + 1  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", 0);
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(new Integer(15), (Integer)map.get("count"));
+    }
+
+    // can we assign one variable to another?
+    {
+      String expr = "foo = bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+      put("foo",null);
+      put("bar",999);
+      }};
+      Assert.assertEquals(999,run(expr,map));
+      Assert.assertEquals(999,map.get("foo"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo = bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar","message");
+      }};
+      Assert.assertEquals("message",run(expr,map));
+      Assert.assertEquals("message",map.get("foo"));
+    }
+
+  }
+
+  @Test
+  public void testColonAssign(){
+    String query = "foo := 1";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(1, run(query,variables));
+    Assert.assertEquals(1, variables.get("foo"));
+
+    // test more complex, until we get +=
+    // the else is required....
+    query = "if foo == 1 then foo := foo + 1 else foo := foo - 1";
+    Assert.assertEquals(2, run(query,variables));
+    Assert.assertEquals(2, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> count := count + 1  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", 0);
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(new Integer(15), (Integer)map.get("count"));
+    }
+
+    // can we assign one variable to another?
+    {
+      String expr = "foo := bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar",999);
+      }};
+      Assert.assertEquals(999,run(expr,map));
+      Assert.assertEquals(999,map.get("foo"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo := bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar","message");
+      }};
+      Assert.assertEquals("message",run(expr,map));
+      Assert.assertEquals("message",map.get("foo"));
+    }
+
+  }
+
+  @Test
+  public void testMixedAssign(){
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",1);
+    }};
+
+    // test more complex, until we get +=
+    // the else is required....
+    String query = "if foo == 1 then foo := foo + 1 else foo = foo - 1";
+    Assert.assertEquals(2, run(query,variables));
+    Assert.assertEquals(2, variables.get("foo"));
+
+  }
+
+
+  @Test
+  public void testPlusAssign(){
+    String query = "foo += 1";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(1, run(query,variables));
+    Assert.assertEquals(1, variables.get("foo"));
+    // and if it already exists
+    Assert.assertEquals(2, run(query,variables));
+    Assert.assertEquals(2, variables.get("foo"));
+
+    // test more complex, until we get +=
+    // the else is required....
+    query = "if foo == 2 then foo += 1 else foo -= 1";
+    Assert.assertEquals(3, run(query,variables));
+    Assert.assertEquals(3, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> count += 1  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", 0);
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(new Integer(15), (Integer)map.get("count"));
+    }
+    // can we assign one variable to another?
+    {
+      String expr = "foo += bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar",999);
+      }};
+      Assert.assertEquals(999,run(expr,map));
+      Assert.assertEquals(999,map.get("foo"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo += bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar","message");
+      }};
+      boolean thrown = false;
+      try {
+        run(expr, map);
+      } catch (ParseException pe) {
+        thrown = true;
+        Assert.assertTrue(pe.getMessage().contains("Invalid operation, Number 
type required for numeric assignment value"));
+      }
+      Assert.assertTrue(thrown);
+    }
+
+
+  }
+
+  @Test
+  public void testMinusAssign(){
+    String query = "foo -= 1";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(-1, run(query,variables));
+    Assert.assertEquals(-1, variables.get("foo"));
+    // and if it already exists
+    Assert.assertEquals(-2, run(query,variables));
+    Assert.assertEquals(-2, variables.get("foo"));
+
+    // test more complex, until we get +=
+    // the else is required....
+    variables.put("foo",2);
+    query = "if foo == 2 then foo -= 1 else foo += 1";
+    Assert.assertEquals(1, run(query,variables));
+    Assert.assertEquals(1, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> count -= 1  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", 15);
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(new Integer(0), (Integer)map.get("count"));
+    }
+    // can we assign one variable to another?
+    {
+      String expr = "foo -= bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar",999);
+      }};
+      Assert.assertEquals(-999,run(expr,map));
+      Assert.assertEquals(-999,map.get("foo"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo -= bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar","message");
+      }};
+      boolean thrown = false;
+      try {
+        run(expr, map);
+      } catch (ParseException pe) {
+        thrown = true;
+        Assert.assertTrue(pe.getMessage().contains("Invalid operation, Number 
type required for numeric assignment value"));
+      }
+      Assert.assertTrue(thrown);
+    }
+  }
+
+  @Test
+  public void testMultiplyAssign(){
+    String query = "foo *= 2";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(0, run(query,variables));
+    Assert.assertEquals(0, variables.get("foo"));
+    variables.put("foo",2);
+    // and if it already exists
+    Assert.assertEquals(4, run(query,variables));
+    Assert.assertEquals(4, variables.get("foo"));
+
+    // test more complex, until we get +=
+    // the else is required....
+    query = "if foo == 4 then foo *= 2 else foo";
+    Assert.assertEquals(8, run(query,variables));
+    Assert.assertEquals(8, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> count *= 2  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", 1);
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(new DecimalFormat("#").format(Math.pow(2,15)), 
map.get("count").toString());
+    }
+
+    // can we assign one variable to another?
+    {
+      String expr = "foo *= bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",2);
+        put("bar",999);
+      }};
+      Assert.assertEquals((2*999),run(expr,map));
+      Assert.assertEquals((2*999),map.get("foo"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo *= bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo", null);
+        put("bar","message");
+      }};
+      boolean thrown = false;
+      try {
+        run(expr, map);
+      } catch (ParseException pe) {
+        thrown = true;
+        Assert.assertTrue(pe.getMessage().contains("Invalid operation, Number 
type required for numeric assignment value"));
+      }
+      Assert.assertTrue(thrown);
+    }
+  }
+
+  @Test
+  public void testDivideAssign(){
+    String query = "foo /= 2";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(0, run(query,variables));
+    Assert.assertEquals(0, variables.get("foo"));
+    variables.put("foo",2);
+    // and if it already exists
+    Assert.assertEquals(1, run(query,variables));
+    Assert.assertEquals(1, variables.get("foo"));
+
+    // test more complex, until we get +=
+    // the else is required....
+    variables.put("foo",4);
+    query = "if foo == 4 then foo /= 2 else foo";
+    Assert.assertEquals(2, run(query,variables));
+    Assert.assertEquals(2, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> count /= 2  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", Math.pow(2,15));
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(1.0, map.get("count"));
+    }
+    // can we assign one variable to another?
+    {
+      String expr = "foo /= bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",(999*2));
+        put("bar",999);
+      }};
+      Assert.assertEquals(2,run(expr,map));
+      Assert.assertEquals(2,map.get("foo"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo /= bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",10);
+        put("bar","message");
+      }};
+      boolean thrown = false;
+      try {
+        run(expr, map);
+      } catch (ParseException pe) {
+        thrown = true;
+        Assert.assertTrue(pe.getMessage().contains("Invalid operation, Number 
type required for numeric assignment value"));
+      }
+      Assert.assertTrue(thrown);
+    }
+  }
+
+  @Test
+  public void testPreIncrement(){
+    String query = "++foo";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(1, run(query,variables));
+    Assert.assertEquals(1, variables.get("foo"));
+    // and if it already exists
+    Assert.assertEquals(2, run(query,variables));
+    Assert.assertEquals(2, variables.get("foo"));
+
+    query = "if foo == 2 then ++foo else foo -= 1";
+    Assert.assertEquals(3, run(query,variables));
+    Assert.assertEquals(3, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> ++count  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", 0);
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(new Integer(15), (Integer)map.get("count"));
+    }
+    // can we assign one variable to another?
+    {
+      String expr = "foo = ++bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar",999);
+      }};
+      Assert.assertEquals(1000,run(expr,map));
+      Assert.assertEquals(1000,map.get("foo"));
+      Assert.assertEquals(1000,map.get("bar"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo = ++bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar","message");
+      }};
+      boolean thrown = false;
+      try {
+        run(expr, map);
+      } catch (ParseException pe) {
+        thrown = true;
+        Assert.assertTrue(pe.getMessage().contains("Invalid operation, Number 
type required for numeric pre-increment"));
+      }
+      Assert.assertTrue(thrown);
+    }
+  }
+
+  @Test
+  public void testPreDecrement(){
+    String query = "--foo";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(-1, run(query,variables));
+    Assert.assertEquals(-1, variables.get("foo"));
+    // and if it already exists
+    Assert.assertEquals(-2, run(query,variables));
+    Assert.assertEquals(-2, variables.get("foo"));
+
+    query = "if foo == -2 then --foo else foo -= 1";
+    Assert.assertEquals(-3, run(query,variables));
+    Assert.assertEquals(-3, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> --count  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", 15);
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(new Integer(0), (Integer)map.get("count"));
+    }
+    // can we assign one variable to another?
+    {
+      String expr = "foo = --bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar",1001);
+      }};
+      Assert.assertEquals(1000,run(expr,map));
+      Assert.assertEquals(1000,map.get("foo"));
+      Assert.assertEquals(1000,map.get("bar"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo = --bar";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar","message");
+      }};
+      boolean thrown = false;
+      try {
+        run(expr, map);
+      } catch (ParseException pe) {
+        thrown = true;
+        Assert.assertTrue(pe.getMessage().contains("Invalid operation, Number 
type required for numeric pre-decrement"));
+      }
+      Assert.assertTrue(thrown);
+    }
+  }
+
+
+
+  @Test
+  public void testPostIncrement(){
+    String query = "foo++";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(0, run(query,variables));
+    Assert.assertEquals(1, variables.get("foo"));
+    // and if it already exists
+    Assert.assertEquals(1, run(query,variables));
+    Assert.assertEquals(2, variables.get("foo"));
+
+    query = "if foo == 2 then foo++ else foo -= 1";
+    Assert.assertEquals(2, run(query,variables));
+    Assert.assertEquals(3, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> count++  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", 0);
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(new Integer(15), (Integer)map.get("count"));
+    }
+    // can we assign one variable to another?
+    {
+      String expr = "foo = bar++";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar",999);
+      }};
+      Assert.assertEquals(999,run(expr,map));
+      Assert.assertEquals(999,map.get("foo"));
+      Assert.assertEquals(1000,map.get("bar"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo = bar++";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar","message");
+      }};
+      boolean thrown = false;
+      try {
+        run(expr, map);
+      } catch (ParseException pe) {
+        thrown = true;
+        Assert.assertTrue(pe.getMessage().contains("Invalid operation, Number 
type required for numeric post-increment"));
+      }
+      Assert.assertTrue(thrown);
+    }
+  }
+
+  @Test
+  public void testPostDecrement(){
+    String query = "foo--";
+    Map<String,Object> variables = new HashMap<String,Object>(){{
+      put("foo",null);
+    }};
+
+    // basics, return the assign, set the var with default resolver
+    Assert.assertEquals(0, run(query,variables));
+    Assert.assertEquals(-1, variables.get("foo"));
+    // and if it already exists
+    Assert.assertEquals(-1, run(query,variables));
+    Assert.assertEquals(-2, variables.get("foo"));
+
+    query = "if foo == -2 then foo-- else foo -= 1";
+    Assert.assertEquals(-2, run(query,variables));
+    Assert.assertEquals(-3, variables.get("foo"));
+
+    // does it work in a lambda if we explicitly use var name?
+    {
+      String expr  = "MAP([ foo, bar, baz ], (item) -> count--  )";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",1);
+        put("bar",1);
+        put("baz",1);
+        put("count", 15);
+      }};
+      for(int i = 0 ; i < 5; i++){
+        run(expr, map);
+      }
+      Assert.assertEquals(new Integer(0), (Integer)map.get("count"));
+    }
+    // can we assign one variable to another?
+    {
+      String expr = "foo = bar--";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar",1001);
+      }};
+      Assert.assertEquals(1001,run(expr,map));
+      Assert.assertEquals(1001,map.get("foo"));
+      Assert.assertEquals(1000,map.get("bar"));
+    }
+
+    // can we assign one variable to another as a string?
+    {
+      String expr = "foo = bar--";
+      Map<String,Object> map = new HashMap<String,Object>(){{
+        put("foo",null);
+        put("bar","message");
+      }};
+      boolean thrown = false;
+      try {
+        run(expr, map);
+      } catch (ParseException pe) {
+        thrown = true;
+        Assert.assertTrue(pe.getMessage().contains("Invalid operation, Number 
type required for numeric post-decrement"));
+      }
+      Assert.assertTrue(thrown);
+    }
+  }
+
+  @Test
   public void testEscapedLiterals() {
     Assert.assertEquals("'bar'", run("\"'bar'\"", new HashMap<>()));
     Assert.assertEquals("'BAR'", run("TO_UPPER('\\'bar\\'')", new 
HashMap<>()));

Reply via email to