lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dpg...@apache.org
Subject [11/20] lucene-solr:branch_7x: SOLR-11145, SOLR-11146: Added comprehensive unit tests for Analytics Component 2.0 as well as analytics bug fixes.
Date Tue, 17 Oct 2017 18:08:30 GMT
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/DoubleFieldsTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/DoubleFieldsTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/DoubleFieldsTest.java
new file mode 100644
index 0000000..c668b0d
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/DoubleFieldsTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.field;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.analytics.ExpressionFactory;
+import org.junit.Test;
+
+public class DoubleFieldsTest extends AbstractAnalyticsFieldTest {
+  
+  @Test
+  public void expressionFactoryCreationTest() {
+    ExpressionFactory fact = getExpressionFactory();
+
+    assertTrue(fact.createExpression("double_d_t") instanceof DoubleField);
+    assertTrue(fact.createExpression("double_d_p") instanceof DoubleField);
+    assertTrue(fact.createExpression("double_dm_t") instanceof DoubleMultiTrieField);
+    assertTrue(fact.createExpression("double_dm_p") instanceof DoubleMultiPointField);
+  }
+
+  @Test
+  public void singleValuedTrieDoubleTest() throws IOException {
+    DoubleField valueField = new DoubleField("double_d_t");
+    Map<String,Double> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      double value = valueField.getDouble();
+      if (valueField.exists()) {
+        values.put(id, value);
+      }
+      return valueField.exists();
+    });
+    
+    checkSingleFieldValues(singleDoubles, values, missing);
+  }
+
+  @Test
+  public void singleValuedPointDoubleTest() throws IOException {
+    DoubleField valueField = new DoubleField("double_d_p");
+    Map<String,Double> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      double value = valueField.getDouble();
+      if (valueField.exists()) {
+        values.put(id, value);
+      }
+      return valueField.exists();
+    });
+    
+    checkSingleFieldValues(singleDoubles, values, missing);
+  }
+
+  @Test
+  public void multiValuedTrieDoubleTest() throws IOException {
+    DoubleMultiTrieField valueField = new DoubleMultiTrieField("double_dm_t");
+    Map<String,Map<Double,Integer>> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      Map<Double, Integer> doc = new HashMap<>();
+      valueField.streamDoubles( value -> {
+        doc.put(value, doc.getOrDefault(value, 0) + 1);
+      });
+      if (doc.size() > 0) {
+        values.put(id, doc);
+      }
+      return doc.size() > 0;
+    });
+    
+    checkMultiFieldValues(multiDoubles, values, missing, true);
+  }
+
+  @Test
+  public void multiValuedPointDoubleTest() throws IOException {
+    DoubleMultiPointField valueField = new DoubleMultiPointField("double_dm_p");
+    Map<String,Map<Double,Integer>> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      Map<Double, Integer> doc = new HashMap<>();
+      valueField.streamDoubles( value -> {
+        doc.put(value, doc.getOrDefault(value, 0) + 1);
+      });
+      if (doc.size() > 0) {
+        values.put(id, doc);
+      }
+      return doc.size() > 0;
+    });
+    
+    checkMultiFieldValues(multiDoubles, values, missing, false);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/FloatFieldsTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/FloatFieldsTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/FloatFieldsTest.java
new file mode 100644
index 0000000..b1aead6
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/FloatFieldsTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.field;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.analytics.ExpressionFactory;
+import org.junit.Test;
+
+public class FloatFieldsTest extends AbstractAnalyticsFieldTest {
+  
+  @Test
+  public void expressionFactoryCreationTest() {
+    ExpressionFactory fact = getExpressionFactory();
+
+    assertTrue(fact.createExpression("float_f_t") instanceof FloatField);
+    assertTrue(fact.createExpression("float_f_p") instanceof FloatField);
+    assertTrue(fact.createExpression("float_fm_t") instanceof FloatMultiTrieField);
+    assertTrue(fact.createExpression("float_fm_p") instanceof FloatMultiPointField);
+  }
+
+  @Test
+  public void singleValuedTrieFloatTest() throws IOException {
+    FloatField valueField = new FloatField("float_f_t");
+    Map<String,Float> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      float value = valueField.getFloat();
+      if (valueField.exists()) {
+        values.put(id, value);
+      }
+      return valueField.exists();
+    });
+    
+    checkSingleFieldValues(singleFloats, values, missing);
+  }
+
+  @Test
+  public void singleValuedPointFloatTest() throws IOException {
+    FloatField valueField = new FloatField("float_f_p");
+    Map<String,Float> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      float value = valueField.getFloat();
+      if (valueField.exists()) {
+        values.put(id, value);
+      }
+      return valueField.exists();
+    });
+    
+    checkSingleFieldValues(singleFloats, values, missing);
+  }
+
+  @Test
+  public void multiValuedTrieFloatTest() throws IOException {
+    FloatMultiTrieField valueField = new FloatMultiTrieField("float_fm_t");
+    Map<String,Map<Float,Integer>> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      Map<Float, Integer> doc = new HashMap<>();
+      valueField.streamFloats( value -> {
+        doc.put(value, doc.getOrDefault(value, 0) + 1);
+      });
+      if (doc.size() > 0) {
+        values.put(id, doc);
+      }
+      return doc.size() > 0;
+    });
+    
+    checkMultiFieldValues(multiFloats, values, missing, true);
+  }
+
+  @Test
+  public void multiValuedPointFloatTest() throws IOException {
+    FloatMultiPointField valueField = new FloatMultiPointField("float_fm_p");
+    Map<String,Map<Float,Integer>> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      Map<Float, Integer> doc = new HashMap<>();
+      valueField.streamFloats( value -> {
+        doc.put(value, doc.getOrDefault(value, 0) + 1);
+      });
+      if (doc.size() > 0) {
+        values.put(id, doc);
+      }
+      return doc.size() > 0;
+    });
+    
+    checkMultiFieldValues(multiFloats, values, missing, false);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/IntFieldsTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/IntFieldsTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/IntFieldsTest.java
new file mode 100644
index 0000000..014d9d1
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/IntFieldsTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.field;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.analytics.ExpressionFactory;
+import org.junit.Test;
+
+public class IntFieldsTest extends AbstractAnalyticsFieldTest {
+  
+  @Test
+  public void expressionFactoryCreationTest() {
+    ExpressionFactory fact = getExpressionFactory();
+
+    assertTrue(fact.createExpression("int_i_t") instanceof IntField);
+    assertTrue(fact.createExpression("int_i_p") instanceof IntField);
+    assertTrue(fact.createExpression("int_im_t") instanceof IntMultiTrieField);
+    assertTrue(fact.createExpression("int_im_p") instanceof IntMultiPointField);
+  }
+
+  @Test
+  public void singleValuedTrieIntTest() throws IOException {
+    IntField valueField = new IntField("int_i_t");
+    Map<String,Integer> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      int value = valueField.getInt();
+      if (valueField.exists()) {
+        values.put(id, value);
+      }
+      return valueField.exists();
+    });
+    
+    checkSingleFieldValues(singleInts, values, missing);
+  }
+
+  @Test
+  public void singleValuedPointIntTest() throws IOException {
+    IntField valueField = new IntField("int_i_p");
+    Map<String,Integer> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      int value = valueField.getInt();
+      if (valueField.exists()) {
+        values.put(id, value);
+      }
+      return valueField.exists();
+    });
+    
+    checkSingleFieldValues(singleInts, values, missing);
+  }
+
+  @Test
+  public void multiValuedTrieIntTest() throws IOException {
+    IntMultiTrieField valueField = new IntMultiTrieField("int_im_t");
+    Map<String,Map<Integer,Integer>> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      Map<Integer, Integer> doc = new HashMap<>();
+      valueField.streamInts( value -> {
+        doc.put(value, doc.getOrDefault(value, 0) + 1);
+      });
+      if (doc.size() > 0) {
+        values.put(id, doc);
+      }
+      return doc.size() > 0;
+    });
+    
+    checkMultiFieldValues(multiInts, values, missing, true);
+  }
+
+  @Test
+  public void multiValuedPointIntTest() throws IOException {
+    IntMultiPointField valueField = new IntMultiPointField("int_im_p");
+    Map<String,Map<Integer,Integer>> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      Map<Integer, Integer> doc = new HashMap<>();
+      valueField.streamInts( value -> {
+        doc.put(value, doc.getOrDefault(value, 0) + 1);
+      });
+      if (doc.size() > 0) {
+        values.put(id, doc);
+      }
+      return doc.size() > 0;
+    });
+    
+    checkMultiFieldValues(multiInts, values, missing, false);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/LongFieldsTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/LongFieldsTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/LongFieldsTest.java
new file mode 100644
index 0000000..d1fc6b8
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/LongFieldsTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.field;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.analytics.ExpressionFactory;
+import org.junit.Test;
+
+public class LongFieldsTest extends AbstractAnalyticsFieldTest {
+  
+  @Test
+  public void expressionFactoryCreationTest() {
+    ExpressionFactory fact = getExpressionFactory();
+
+    assertTrue(fact.createExpression("long_l_t") instanceof LongField);
+    assertTrue(fact.createExpression("long_l_p") instanceof LongField);
+    assertTrue(fact.createExpression("long_lm_t") instanceof LongMultiTrieField);
+    assertTrue(fact.createExpression("long_lm_p") instanceof LongMultiPointField);
+  }
+
+  @Test
+  public void singleValuedTrieLongTest() throws IOException {
+    LongField valueField = new LongField("long_l_t");
+    Map<String,Long> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      long value = valueField.getLong();
+      if (valueField.exists()) {
+        values.put(id, value);
+      }
+      return valueField.exists();
+    });
+    
+    checkSingleFieldValues(singleLongs, values, missing);
+  }
+
+  @Test
+  public void singleValuedPointLongTest() throws IOException {
+    LongField valueField = new LongField("long_l_p");
+    Map<String,Long> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      long value = valueField.getLong();
+      if (valueField.exists()) {
+        values.put(id, value);
+      }
+      return valueField.exists();
+    });
+    
+    checkSingleFieldValues(singleLongs, values, missing);
+  }
+
+  @Test
+  public void multiValuedTrieLongTest() throws IOException {
+    LongMultiTrieField valueField = new LongMultiTrieField("long_lm_t");
+    Map<String,Map<Long,Integer>> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      Map<Long, Integer> doc = new HashMap<>();
+      valueField.streamLongs( value -> {
+        doc.put(value, doc.getOrDefault(value, 0) + 1);
+      });
+      if (doc.size() > 0) {
+        values.put(id, doc);
+      }
+      return doc.size() > 0;
+    });
+    
+    checkMultiFieldValues(multiLongs, values, missing, true);
+  }
+
+  @Test
+  public void multiValuedPointLongTest() throws IOException {
+    LongMultiPointField valueField = new LongMultiPointField("long_lm_p");
+    Map<String,Map<Long,Integer>> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      Map<Long, Integer> doc = new HashMap<>();
+      valueField.streamLongs( value -> {
+        doc.put(value, doc.getOrDefault(value, 0) + 1);
+      });
+      if (doc.size() > 0) {
+        values.put(id, doc);
+      }
+      return doc.size() > 0;
+    });
+    
+    checkMultiFieldValues(multiLongs, values, missing, false);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/StringFieldsTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/StringFieldsTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/StringFieldsTest.java
new file mode 100644
index 0000000..152a009
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/field/StringFieldsTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.field;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.analytics.ExpressionFactory;
+import org.junit.Test;
+
+public class StringFieldsTest extends AbstractAnalyticsFieldTest {
+  
+  @Test
+  public void expressionFactoryCreationTest() {
+    ExpressionFactory fact = getExpressionFactory();
+
+    assertTrue(fact.createExpression("string_s") instanceof StringField);
+    assertTrue(fact.createExpression("string_sm") instanceof StringMultiField);
+  }
+
+  @Test
+  public void singleValuedStringTest() throws IOException {
+    StringField valueField = new StringField("string_s");
+    Map<String,String> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      String value = valueField.getString();
+      if (valueField.exists()) {
+        values.put(id, value);
+      }
+      return valueField.exists();
+    });
+    
+    checkSingleFieldValues(singleStrings, values, missing);
+  }
+
+  @Test
+  public void multiValuedStringTest() throws IOException {
+    StringMultiField valueField = new StringMultiField("string_sm");
+    Map<String,Map<String,Integer>> values = new HashMap<>();
+    
+    Set<String> missing = collectFieldValues(valueField, id -> {
+      Map<String, Integer> doc = new HashMap<>();
+      valueField.streamStrings( value -> {
+        doc.put(value, doc.getOrDefault(value, 0) + 1);
+      });
+      if (doc.size() > 0) {
+        values.put(id, doc);
+      }
+      return doc.size() > 0;
+    });
+    
+    checkMultiFieldValues(multiStrings, values, missing, true);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AbsoluteValueFunctionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AbsoluteValueFunctionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AbsoluteValueFunctionTest.java
new file mode 100644
index 0000000..9996c28
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AbsoluteValueFunctionTest.java
@@ -0,0 +1,267 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.mapping;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.FloatValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestDoubleValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestFloatValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestIntValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestLongValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestDoubleValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestFloatValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestIntValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestLongValueStream;
+import org.junit.Test;
+
+public class AbsoluteValueFunctionTest extends SolrTestCaseJ4 {
+
+  @Test
+  public void singleValueIntTest() {
+    TestIntValue val = new TestIntValue();
+
+    AnalyticsValueStream uncasted = AbsoluteValueFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof IntValue);
+    IntValue func = (IntValue) uncasted;
+
+    // Value doesn't exist
+    val.setExists(false);
+    func.getInt();
+    assertFalse(func.exists());
+
+    // Value exists
+    val.setValue(21).setExists(true);
+    assertEquals(21, func.getInt());
+    assertTrue(func.exists());
+
+    val.setValue(-100).setExists(true);
+    assertEquals(100, func.getInt());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void singleValueLongTest() {
+    TestLongValue val = new TestLongValue();
+
+    AnalyticsValueStream uncasted = AbsoluteValueFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof LongValue);
+    LongValue func = (LongValue) uncasted;
+
+    // Value doesn't exist
+    val.setExists(false);
+    func.getLong();
+    assertFalse(func.exists());
+
+    // Value exists
+    val.setValue(21L).setExists(true);
+    assertEquals(21L, func.getLong());
+    assertTrue(func.exists());
+
+    val.setValue(-100L).setExists(true);
+    assertEquals(100L, func.getLong());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void singleValueFloatTest() {
+    TestFloatValue val = new TestFloatValue();
+
+    AnalyticsValueStream uncasted = AbsoluteValueFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof FloatValue);
+    FloatValue func = (FloatValue) uncasted;
+
+    // Value doesn't exist
+    val.setExists(false);
+    func.getFloat();
+    assertFalse(func.exists());
+
+    // Value exists
+    val.setValue(21.56F).setExists(true);
+    assertEquals(21.56F, func.getFloat(), 0.00001);
+    assertTrue(func.exists());
+
+    val.setValue(-100F).setExists(true);
+    assertEquals(100F, func.getFloat(), 0.00001);
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void singleValueDoubleTest() {
+    TestDoubleValue val = new TestDoubleValue();
+
+    AnalyticsValueStream uncasted = AbsoluteValueFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof DoubleValue);
+    DoubleValue func = (DoubleValue) uncasted;
+
+    // Value doesn't exist
+    val.setExists(false);
+    func.getDouble();
+    assertFalse(func.exists());
+
+    // Value exists
+    val.setValue(21.56).setExists(true);
+    assertEquals(21.56, func.getDouble(), 0.00001);
+    assertTrue(func.exists());
+
+    val.setValue(-100.1).setExists(true);
+    assertEquals(100.1, func.getDouble(), 0.00001);
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multiValueIntTest() {
+    TestIntValueStream val = new TestIntValueStream();
+    
+    AnalyticsValueStream uncasted = AbsoluteValueFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof IntValueStream);
+    IntValueStream func = (IntValueStream) uncasted;
+
+    // No values
+    val.setValues();
+    func.streamInts( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One value
+    val.setValues(-4);
+    Iterator<Integer> values1 = Arrays.asList(4).iterator();
+    func.streamInts( value -> {
+      assertTrue(values1.hasNext());
+      assertEquals(values1.next().intValue(), value);
+    });
+    assertFalse(values1.hasNext());
+    
+    // Multiple values
+    val.setValues(4, -10, 50, -74);
+    Iterator<Integer> values2 = Arrays.asList(4, 10, 50, 74).iterator();
+    func.streamInts( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next().intValue(), value);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void multiValueLongTest() {
+    TestLongValueStream val = new TestLongValueStream();
+    
+    AnalyticsValueStream uncasted = AbsoluteValueFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof LongValueStream);
+    LongValueStream func = (LongValueStream) uncasted;
+
+    // No values
+    val.setValues();
+    func.streamLongs( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One value
+    val.setValues(-4L);
+    Iterator<Long> values1 = Arrays.asList(4L).iterator();
+    func.streamLongs( value -> {
+      assertTrue(values1.hasNext());
+      assertEquals(values1.next().longValue(), value);
+    });
+    assertFalse(values1.hasNext());
+    
+    // Multiple values
+    val.setValues(4L, -10L, 50L, -74L);
+    Iterator<Long> values2 = Arrays.asList(4L, 10L, 50L, 74L).iterator();
+    func.streamLongs( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next().longValue(), value);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void multiValueFloatTest() {
+    TestFloatValueStream val = new TestFloatValueStream();
+    
+    AnalyticsValueStream uncasted = AbsoluteValueFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof FloatValueStream);
+    FloatValueStream func = (FloatValueStream) uncasted;
+
+    // No values
+    val.setValues();
+    func.streamFloats( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One value
+    val.setValues(-4.3F);
+    Iterator<Float> values1 = Arrays.asList(4.3F).iterator();
+    func.streamFloats( value -> {
+      assertTrue(values1.hasNext());
+      assertEquals(values1.next(), value, .000001);
+    });
+    assertFalse(values1.hasNext());
+    
+    // Multiple values
+    val.setValues(4.3F, -10F, 50.75F, -74.4446F);
+    Iterator<Float> values2 = Arrays.asList(4.3F, 10F, 50.75F, 74.4446F).iterator();
+    func.streamFloats( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next(), value, .000001);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void multiValueDoubleTest() {
+    TestDoubleValueStream val = new TestDoubleValueStream();
+    
+    AnalyticsValueStream uncasted = AbsoluteValueFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof DoubleValueStream);
+    DoubleValueStream func = (DoubleValueStream) uncasted;
+
+    // No values
+    val.setValues();
+    func.streamDoubles( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One value
+    val.setValues(-4.3);
+    Iterator<Double> values1 = Arrays.asList(4.3).iterator();
+    func.streamDoubles( value -> {
+      assertTrue(values1.hasNext());
+      assertEquals(values1.next(), value, .000001);
+    });
+    assertFalse(values1.hasNext());
+    
+    // Multiple values
+    val.setValues(4.3, -10, 50.75, -74.4446);
+    Iterator<Double> values2 = Arrays.asList(4.3, 10.0, 50.75, 74.4446).iterator();
+    func.streamDoubles( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next(), value, .000001);
+    });
+    assertFalse(values2.hasNext());
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AddFunctionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AddFunctionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AddFunctionTest.java
new file mode 100644
index 0000000..87b80cb
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AddFunctionTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.mapping;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.DoubleValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestDoubleValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestFloatValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestIntValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestLongValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestLongValueStream;
+import org.junit.Test;
+
+public class AddFunctionTest extends SolrTestCaseJ4 {
+  
+  @Test
+  public void twoSingleValueParametersTest() {
+    TestIntValue val1 = new TestIntValue();
+    TestFloatValue val2 = new TestFloatValue();
+    
+    AnalyticsValueStream uncasted = AddFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2});
+    assertTrue(uncasted instanceof DoubleValue);
+    DoubleValue func = (DoubleValue) uncasted;
+    
+    // Neither exists
+    val1.setExists(false);
+    val2.setExists(false);
+    func.getDouble();
+    assertFalse(func.exists());
+    
+    // One exists
+    val1.setValue(30).setExists(true);
+    val2.setExists(false);
+    func.getDouble();
+    assertFalse(func.exists());
+    
+    // Both exist
+    val1.setValue(30).setExists(true);
+    val2.setValue(21.56F).setExists(true);
+    assertEquals(51.56, func.getDouble(), 0.000001);
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void oneMultiValueParameterTest() {
+    TestLongValueStream val = new TestLongValueStream();
+    
+    AnalyticsValueStream uncasted = AddFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof DoubleValue);
+    DoubleValue func = (DoubleValue) uncasted;
+
+    // No values
+    val.setValues();
+    func.getDouble();
+    assertFalse(func.exists());
+    
+    // One value
+    val.setValues(30L);
+    assertEquals(30, func.getDouble(), 0.000001);
+    assertTrue(func.exists());
+    
+    // Multiple values
+    val.setValues(30L, 20L, 55L, 61L);
+    assertEquals(166, func.getDouble(), 0.000001);
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void oneMultiOneSingleValueParameterTest() {
+    TestLongValueStream val1 = new TestLongValueStream();
+    TestDoubleValue val2 = new TestDoubleValue();
+    
+    AnalyticsValueStream uncasted = AddFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2});
+    assertTrue(uncasted instanceof DoubleValueStream);
+    DoubleValueStream func = (DoubleValueStream) uncasted;
+
+    // No values, One value
+    val1.setValues();
+    val2.setValue(21.56F).setExists(true);
+    func.streamDoubles( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // Multiple values, no value
+    val1.setValues(4L, 10023L);
+    val2.setExists(false);
+    func.streamDoubles( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // Multiple values, one value
+    val1.setValues(4L, 10023L, 48L);
+    val2.setValue(21.56F).setExists(true);
+    Iterator<Double> values = Arrays.asList(25.56, 10044.56, 69.56).iterator();
+    func.streamDoubles( value -> {
+      assertTrue(values.hasNext());
+      assertEquals(values.next(), value, 0.000001);
+    });
+    assertFalse(values.hasNext());
+  }
+
+  @Test
+  public void multipleSingleValueParameterTest() {
+    TestLongValue val1 = new TestLongValue();
+    TestDoubleValue val2 = new TestDoubleValue();
+    TestFloatValue val3 = new TestFloatValue();
+    TestIntValue val4 = new TestIntValue();
+    
+    AnalyticsValueStream uncasted = AddFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2, val3, val4});
+    assertTrue(uncasted instanceof DoubleValue);
+    DoubleValue func = (DoubleValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getDouble();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setExists(false);
+    val2.setValue(30.56).setExists(true);
+    val3.setExists(false);
+    val4.setValue(12).setExists(true);
+    func.getDouble();
+    assertFalse(func.exists());
+    
+    // All exist values, one value
+    val1.setValue(45L).setExists(true);
+    val2.setValue(30.56).setExists(true);
+    val3.setValue(2.5F).setExists(true);
+    val4.setValue(12).setExists(true);
+    assertEquals(90.06, func.getDouble(), 0.000001);
+    assertTrue(func.exists());
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AndFunctionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AndFunctionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AndFunctionTest.java
new file mode 100644
index 0000000..d2e9a1b
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/AndFunctionTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.mapping;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.function.mapping.LogicFunction.AndFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.BooleanValue;
+import org.apache.solr.analytics.value.BooleanValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestBooleanValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestBooleanValueStream;
+import org.junit.Test;
+
+public class AndFunctionTest extends SolrTestCaseJ4 {
+  @Test
+  public void twoSingleValueParametersTest() {
+    TestBooleanValue val1 = new TestBooleanValue();
+    TestBooleanValue val2 = new TestBooleanValue();
+    
+    AnalyticsValueStream uncasted = AndFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2});
+    assertTrue(uncasted instanceof BooleanValue);
+    BooleanValue func = (BooleanValue) uncasted;
+    
+    // Neither exists
+    val1.setExists(false);
+    val2.setExists(false);
+    func.getBoolean();
+    assertFalse(func.exists());
+    
+    // One exists
+    val1.setValue(true).setExists(true);
+    val2.setExists(false);
+    func.getBoolean();
+    assertFalse(func.exists());
+    
+    // Both exist
+    val1.setValue(false).setExists(true);
+    val2.setValue(false).setExists(true);
+    assertEquals(false, func.getBoolean());
+    assertTrue(func.exists());
+    
+    val1.setValue(true).setExists(true);
+    val2.setValue(false).setExists(true);
+    assertEquals(false, func.getBoolean());
+    assertTrue(func.exists());
+    
+    val1.setValue(false).setExists(true);
+    val2.setValue(true).setExists(true);
+    assertEquals(false, func.getBoolean());
+    assertTrue(func.exists());
+
+    val1.setValue(true).setExists(true);
+    val2.setValue(true).setExists(true);
+    assertEquals(true, func.getBoolean());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void oneMultiValueParameterTest() {
+    TestBooleanValueStream val = new TestBooleanValueStream();
+    
+    AnalyticsValueStream uncasted = AndFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof BooleanValue);
+    BooleanValue func = (BooleanValue) uncasted;
+
+    // No values
+    val.setValues();
+    func.getBoolean();
+    assertFalse(func.exists());
+    
+    // One value
+    val.setValues(true);
+    assertEquals(true, func.getBoolean());
+    assertTrue(func.exists());
+
+    val.setValues(false);
+    assertEquals(false, func.getBoolean());
+    assertTrue(func.exists());
+    
+    // Multiple values
+    val.setValues(true, true, false, true);
+    assertEquals(false, func.getBoolean());
+    assertTrue(func.exists());
+    
+    val.setValues(true, true, true);
+    assertEquals(true, func.getBoolean());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void oneMultiOneSingleValueParameterTest() {
+    TestBooleanValue val1 = new TestBooleanValue();
+    TestBooleanValueStream val2 = new TestBooleanValueStream();
+    
+    AnalyticsValueStream uncasted = AndFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2});
+    assertTrue(uncasted instanceof BooleanValueStream);
+    BooleanValueStream func = (BooleanValueStream) uncasted;
+
+    // No values, One value
+    val1.setValue(false).setExists(true);
+    val2.setValues();
+    func.streamBooleans( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // Multiple values, no value
+    val1.setExists(false);
+    val2.setValues(true, false);
+    func.streamBooleans( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // Multiple values, one value
+    val1.setValue(false).setExists(true);
+    val2.setValues(true, false, true);
+    Iterator<Boolean> values1 = Arrays.asList(false, false, false).iterator();
+    func.streamBooleans( value -> {
+      assertTrue(values1.hasNext());
+      assertEquals(values1.next(), value);
+    });
+    assertFalse(values1.hasNext());
+
+    val1.setValue(true).setExists(true);
+    val2.setValues(true, false, true);
+    Iterator<Boolean> values2 = Arrays.asList(true, false, true).iterator();
+    func.streamBooleans( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next(), value);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void multipleSingleValueParameterTest() {
+    TestBooleanValue val1 = new TestBooleanValue();
+    TestBooleanValue val2 = new TestBooleanValue();
+    TestBooleanValue val3 = new TestBooleanValue();
+    TestBooleanValue val4 = new TestBooleanValue();
+    
+    AnalyticsValueStream uncasted = AndFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2, val3, val4});
+    assertTrue(uncasted instanceof BooleanValue);
+    BooleanValue func = (BooleanValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getBoolean();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setExists(false);
+    val2.setValue(true).setExists(true);
+    val3.setExists(false);
+    val4.setValue(false).setExists(true);
+    func.getBoolean();
+    assertFalse(func.exists());
+    
+    // All exist values, one value
+    val1.setValue(true).setExists(true);
+    val2.setValue(false).setExists(true);
+    val3.setValue(true).setExists(true);
+    val4.setValue(true).setExists(true);
+    assertEquals(false, func.getBoolean());
+    assertTrue(func.exists());
+
+    val1.setValue(true).setExists(true);
+    val2.setValue(true).setExists(true);
+    val3.setValue(true).setExists(true);
+    val4.setValue(true).setExists(true);
+    assertEquals(true, func.getBoolean());
+    assertTrue(func.exists());
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/BottomFunctionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/BottomFunctionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/BottomFunctionTest.java
new file mode 100644
index 0000000..feb43d8
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/BottomFunctionTest.java
@@ -0,0 +1,406 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.mapping;
+
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
+import java.util.Date;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DoubleValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestDateValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestDateValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestDoubleValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestDoubleValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestFloatValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestFloatValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestIntValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestIntValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestLongValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestLongValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestStringValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestStringValueStream;
+import org.apache.solr.analytics.value.FloatValue;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.StringValue;
+import org.junit.Test;
+
+public class BottomFunctionTest extends SolrTestCaseJ4 {
+  
+  @Test
+  public void multiValueIntTest() {
+    TestIntValueStream val = new TestIntValueStream();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof IntValue);
+    IntValue func = (IntValue) uncasted;
+    
+    // Neither exists
+    val.setValues();
+    func.getInt();
+    assertFalse(func.exists());
+    
+    // One exists
+    val.setValues(30);
+    assertEquals(30, func.getInt());
+    assertTrue(func.exists());
+    
+    // Both exist
+    val.setValues(30, 20, -10, 59);
+    assertEquals(-10, func.getInt());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multiValueLongTest() {
+    TestLongValueStream val = new TestLongValueStream();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof LongValue);
+    LongValue func = (LongValue) uncasted;
+    
+    // Neither exists
+    val.setValues();
+    func.getLong();
+    assertFalse(func.exists());
+    
+    // One exists
+    val.setValues(30L);
+    assertEquals(30L, func.getLong());
+    assertTrue(func.exists());
+    
+    // Both exist
+    val.setValues(30L, 20L, -10L, 59L);
+    assertEquals(-10L, func.getLong());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multiValueFloatTest() {
+    TestFloatValueStream val = new TestFloatValueStream();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof FloatValue);
+    FloatValue func = (FloatValue) uncasted;
+    
+    // Neither exists
+    val.setValues();
+    func.getFloat();
+    assertFalse(func.exists());
+    
+    // One exists
+    val.setValues(30.0F);
+    assertEquals(30.0F, func.getFloat(), .000001);
+    assertTrue(func.exists());
+    
+    // Both exist
+    val.setValues(30.5F, 20.01F, -10.49F, -10.48F);
+    assertEquals(-10.49F, func.getFloat(), .000001);
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multiValueDoubleTest() {
+    TestDoubleValueStream val = new TestDoubleValueStream();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof DoubleValue);
+    DoubleValue func = (DoubleValue) uncasted;
+    
+    // Neither exists
+    val.setValues();
+    func.getDouble();
+    assertFalse(func.exists());
+    
+    // One exists
+    val.setValues(30.0);
+    assertEquals(30.0, func.getDouble(), .000001);
+    assertTrue(func.exists());
+    
+    // Both exist
+    val.setValues(30.5, 20.01, -10.49, -10.48);
+    assertEquals(-10.49, func.getDouble(), .000001);
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multiValueDateTest() throws DateTimeParseException {
+    TestDateValueStream val = new TestDateValueStream();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof DateValue);
+    DateValue func = (DateValue) uncasted;
+    
+    // Neither exists
+    val.setValues();
+    func.getDate();
+    assertFalse(func.exists());
+    
+    // One exists
+    val.setValues("1950-05-03T10:30:50Z");
+    assertEquals(Date.from(Instant.parse("1950-05-03T10:30:50Z")), func.getDate());
+    assertTrue(func.exists());
+    
+    // Both exist
+    val.setValues("1950-05-03T10:30:50Z", "2200-01-01T10:00:50Z", "1800-12-31T11:30:50Z", "1930-05-020T10:45:50Z");
+    assertEquals(Date.from(Instant.parse("1800-12-31T11:30:50Z")), func.getDate());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multiValueStringTest() {
+    TestStringValueStream val = new TestStringValueStream();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof StringValue);
+    StringValue func = (StringValue) uncasted;
+    
+    // Neither exists
+    val.setValues();
+    func.getString();
+    assertFalse(func.exists());
+    
+    // One exists
+    val.setValues("abc");
+    assertEquals("abc", func.getString());
+    assertTrue(func.exists());
+    
+    // Both exist
+    val.setValues("1abcdef", "abc", "def", "1abc");
+    assertEquals("1abc", func.getString());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multipleSingleValueIntTest() {
+    TestIntValue val1 = new TestIntValue();
+    TestIntValue val2 = new TestIntValue();
+    TestIntValue val3 = new TestIntValue();
+    TestIntValue val4 = new TestIntValue();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2, val3, val4});
+    assertTrue(uncasted instanceof IntValue);
+    IntValue func = (IntValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getInt();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setValue(1000).setExists(false);
+    val2.setValue(30).setExists(true);
+    val3.setValue(-1000).setExists(false);
+    val4.setValue(12).setExists(true);
+    assertEquals(12, func.getInt());
+    assertTrue(func.exists());
+    
+    // All exist values, one value
+    val1.setValue(45).setExists(true);
+    val2.setValue(30).setExists(true);
+    val3.setValue(-2).setExists(true);
+    val4.setValue(12).setExists(true);
+    assertEquals(-2, func.getInt());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multipleSingleValueLongTest() {
+    TestLongValue val1 = new TestLongValue();
+    TestLongValue val2 = new TestLongValue();
+    TestLongValue val3 = new TestLongValue();
+    TestLongValue val4 = new TestLongValue();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2, val3, val4});
+    assertTrue(uncasted instanceof LongValue);
+    LongValue func = (LongValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getLong();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setValue(1000L).setExists(false);
+    val2.setValue(30L).setExists(true);
+    val3.setValue(-1000L).setExists(false);
+    val4.setValue(12L).setExists(true);
+    assertEquals(12L, func.getLong());
+    assertTrue(func.exists());
+    
+    // All exist values, one value
+    val1.setValue(45L).setExists(true);
+    val2.setValue(30L).setExists(true);
+    val3.setValue(-2L).setExists(true);
+    val4.setValue(12L).setExists(true);
+    assertEquals(-2L, func.getLong());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multipleSingleValueFloatTest() {
+    TestFloatValue val1 = new TestFloatValue();
+    TestFloatValue val2 = new TestFloatValue();
+    TestFloatValue val3 = new TestFloatValue();
+    TestFloatValue val4 = new TestFloatValue();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2, val3, val4});
+    assertTrue(uncasted instanceof FloatValue);
+    FloatValue func = (FloatValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getFloat();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setValue(1000.1233F).setExists(false);
+    val2.setValue(30.34F).setExists(true);
+    val3.setValue(-1000.3241F).setExists(false);
+    val4.setValue(12.123F).setExists(true);
+    assertEquals(12.123F, func.getFloat(), .000001);
+    assertTrue(func.exists());
+    
+    // All exist values, one value
+    val1.setValue(45.43F).setExists(true);
+    val2.setValue(30.231F).setExists(true);
+    val3.setValue(-2.33F).setExists(true);
+    val4.setValue(12.5F).setExists(true);
+    assertEquals(-2.33F, func.getFloat(), .000001);
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multipleSingleValueDoubleTest() {
+    TestDoubleValue val1 = new TestDoubleValue();
+    TestDoubleValue val2 = new TestDoubleValue();
+    TestDoubleValue val3 = new TestDoubleValue();
+    TestDoubleValue val4 = new TestDoubleValue();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2, val3, val4});
+    assertTrue(uncasted instanceof DoubleValue);
+    DoubleValue func = (DoubleValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getDouble();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setValue(1000.1233).setExists(false);
+    val2.setValue(30.34).setExists(true);
+    val3.setValue(-1000.3241).setExists(false);
+    val4.setValue(12.123).setExists(true);
+    assertEquals(12.123, func.getDouble(), .000001);
+    assertTrue(func.exists());
+    
+    // All exist values, one value
+    val1.setValue(45.43).setExists(true);
+    val2.setValue(30.231).setExists(true);
+    val3.setValue(-2.33).setExists(true);
+    val4.setValue(12.5).setExists(true);
+    assertEquals(-2.33, func.getDouble(), .000001);
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multipleSingleValueDateTest() throws DateTimeParseException {
+    TestDateValue val1 = new TestDateValue();
+    TestDateValue val2 = new TestDateValue();
+    TestDateValue val3 = new TestDateValue();
+    TestDateValue val4 = new TestDateValue();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2, val3, val4});
+    assertTrue(uncasted instanceof DateValue);
+    DateValue func = (DateValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getDate();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setValue("9999-05-03T10:30:50Z").setExists(false);
+    val2.setValue("1950-05-03T10:30:50Z").setExists(true);
+    val3.setValue("0000-05-03T10:30:50Z").setExists(false);
+    val4.setValue("1850-05-03T10:30:50Z").setExists(true);
+    assertEquals(Date.from(Instant.parse("1850-05-03T10:30:50Z")), func.getDate());
+    assertTrue(func.exists());
+    
+    // All exist values, one value
+    val1.setValue("2200-05-03T10:30:50Z").setExists(true);
+    val2.setValue("1950-05-03T10:30:50Z").setExists(true);
+    val3.setValue("1700-05-03T10:30:50Z").setExists(true);
+    val4.setValue("1850-05-03T10:30:50Z").setExists(true);
+    assertEquals(Date.from(Instant.parse("1700-05-03T10:30:50Z")), func.getDate());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multipleStringValueDateTest() {
+    TestStringValue val1 = new TestStringValue();
+    TestStringValue val2 = new TestStringValue();
+    TestStringValue val3 = new TestStringValue();
+    TestStringValue val4 = new TestStringValue();
+    
+    AnalyticsValueStream uncasted = BottomFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2, val3, val4});
+    assertTrue(uncasted instanceof StringValue);
+    StringValue func = (StringValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getString();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setValue("abc").setExists(true);
+    val2.setValue("1111").setExists(false);
+    val3.setValue("asdfads").setExists(true);
+    val4.setValue("zzzzzzzz").setExists(false);
+    assertEquals("abc", func.getString());
+    assertTrue(func.exists());
+    
+    // All exist values, one value
+    val1.setValue("abc").setExists(true);
+    val2.setValue("abc1234").setExists(true);
+    val3.setValue("asdfads").setExists(true);
+    val4.setValue("fdgsfg").setExists(true);
+    assertEquals("abc", func.getString());
+    assertTrue(func.exists());
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/CeilingFunctionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/CeilingFunctionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/CeilingFunctionTest.java
new file mode 100644
index 0000000..c527df8
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/CeilingFunctionTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.mapping;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.function.mapping.DecimalNumericConversionFunction.CeilingFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.IntValue;
+import org.apache.solr.analytics.value.IntValueStream;
+import org.apache.solr.analytics.value.LongValue;
+import org.apache.solr.analytics.value.LongValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestDoubleValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestDoubleValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestFloatValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestFloatValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestIntValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestIntValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestLongValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestLongValueStream;
+import org.junit.Test;
+
+public class CeilingFunctionTest extends SolrTestCaseJ4 {
+
+  @Test
+  public void singleValueFloatParameterTest() {
+    TestFloatValue val = new TestFloatValue();
+
+    AnalyticsValueStream uncasted = CeilingFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof IntValue);
+    IntValue func = (IntValue) uncasted;
+
+    // Value doesn't exist
+    val.setExists(false);
+    func.getInt();
+    assertFalse(func.exists());
+
+    // Value exists
+    val.setValue(21.56F).setExists(true);
+    assertEquals(22, func.getInt());
+    assertTrue(func.exists());
+
+    val.setValue(-100.3F).setExists(true);
+    assertEquals(-100, func.getInt());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void singleValueDoubleParameterTest() {
+    TestDoubleValue val = new TestDoubleValue();
+
+    AnalyticsValueStream uncasted = CeilingFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof LongValue);
+    LongValue func = (LongValue) uncasted;
+
+    // Value doesn't exist
+    val.setExists(false);
+    func.getLong();
+    assertFalse(func.exists());
+
+    // Value exists
+    val.setValue(21.56).setExists(true);
+    assertEquals(22L, func.getLong());
+    assertTrue(func.exists());
+
+    val.setValue(-100.3).setExists(true);
+    assertEquals(-100L, func.getLong());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multiValueFloatParameterTest() {
+    TestFloatValueStream val = new TestFloatValueStream();
+    
+    AnalyticsValueStream uncasted = CeilingFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof IntValueStream);
+    IntValueStream func = (IntValueStream) uncasted;
+
+    // No values
+    val.setValues();
+    func.streamInts( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One value
+    val.setValues(-4F);
+    Iterator<Integer> values1 = Arrays.asList(-4).iterator();
+    func.streamInts( value -> {
+      assertTrue(values1.hasNext());
+      assertEquals(values1.next().intValue(), value);
+    });
+    assertFalse(values1.hasNext());
+    
+    // Multiple values
+    val.setValues(4F, -10.9999F, 50.00001F, 74.99999F);
+    Iterator<Integer> values2 = Arrays.asList(4, -10, 51, 75).iterator();
+    func.streamInts( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next().intValue(), value);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void multiValueDoubleParameterTest() {
+    TestDoubleValueStream val = new TestDoubleValueStream();
+    
+    AnalyticsValueStream uncasted = CeilingFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof LongValueStream);
+    LongValueStream func = (LongValueStream) uncasted;
+
+    // No values
+    val.setValues();
+    func.streamLongs( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One value
+    val.setValues(-4);
+    Iterator<Long> values1 = Arrays.asList(-4L).iterator();
+    func.streamLongs( value -> {
+      assertTrue(values1.hasNext());
+      assertEquals(values1.next().longValue(), value);
+    });
+    assertFalse(values1.hasNext());
+    
+    // Multiple values
+    val.setValues(4, -10.9999, 50.000001, 74.99999);
+    Iterator<Long> values2 = Arrays.asList(4L, -10L, 51L, 75L).iterator();
+    func.streamLongs( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next().longValue(), value);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void nonDecimalParameterTest() {
+    AnalyticsValueStream result;
+    AnalyticsValueStream param;
+    
+    param = new TestIntValue();
+    result = CeilingFunction.creatorFunction.apply(new AnalyticsValueStream[] {param});
+    assertTrue(result instanceof IntValue);
+    assertEquals(param, result);
+
+    param = new TestIntValueStream();
+    result = CeilingFunction.creatorFunction.apply(new AnalyticsValueStream[] {param});
+    assertTrue(result instanceof IntValueStream);
+    assertEquals(param, result);
+
+    param = new TestLongValue();
+    result = CeilingFunction.creatorFunction.apply(new AnalyticsValueStream[] {param});
+    assertTrue(result instanceof LongValue);
+    assertEquals(param, result);
+
+    param = new TestLongValueStream();
+    result = CeilingFunction.creatorFunction.apply(new AnalyticsValueStream[] {param});
+    assertTrue(result instanceof LongValueStream);
+    assertEquals(param, result);
+  }
+  
+  
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/ConcatFunctionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/ConcatFunctionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/ConcatFunctionTest.java
new file mode 100644
index 0000000..db5b36e
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/ConcatFunctionTest.java
@@ -0,0 +1,317 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.mapping;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.function.mapping.ConcatFunction.SeparatedConcatFunction;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestStringValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestStringValueStream;
+import org.apache.solr.analytics.value.StringValue;
+import org.apache.solr.analytics.value.StringValueStream;
+import org.apache.solr.analytics.value.constant.ConstantStringValue;
+import org.junit.Test;
+
+public class ConcatFunctionTest extends SolrTestCaseJ4 {
+
+  @Test
+  public void oneMultiValueParameterUnseparatedTest() {
+    TestStringValueStream val = new TestStringValueStream();
+    
+    AnalyticsValueStream uncasted = ConcatFunction.creatorFunction.apply(new AnalyticsValueStream[] {val});
+    assertTrue(uncasted instanceof StringValue);
+    StringValue func = (StringValue) uncasted;
+
+    // No values
+    val.setValues();
+    func.getString();
+    assertFalse(func.exists());
+    
+    // One value
+    val.setValues("abc");
+    assertEquals("abc", func.getString());
+    assertTrue(func.exists());
+    
+    // Multiple values
+    val.setValues("abc", "def", "ghi");
+    assertEquals("abcdefghi", func.getString());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void oneMultiValueParameterSeparatedTest() {
+    TestStringValueStream val = new TestStringValueStream();
+    ConstantStringValue sep = new ConstantStringValue("===:---");
+    
+    AnalyticsValueStream uncasted = SeparatedConcatFunction.creatorFunction.apply(new AnalyticsValueStream[] {sep, val});
+    assertTrue(uncasted instanceof StringValue);
+    StringValue func = (StringValue) uncasted;
+
+    // No values
+    val.setValues();
+    func.getString();
+    assertFalse(func.exists());
+    
+    // One value
+    val.setValues("abc");
+    assertEquals("abc", func.getString());
+    assertTrue(func.exists());
+    
+    // Multiple values
+    val.setValues("abc", "def", "ghi");
+    assertEquals("abc===:---def===:---ghi", func.getString());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void oneSingleOneMultiValueParameterUnseperatedTest() {
+    TestStringValue val1 = new TestStringValue();
+    TestStringValueStream val2 = new TestStringValueStream();
+    
+    AnalyticsValueStream uncasted = ConcatFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2});
+    assertTrue(uncasted instanceof StringValueStream);
+    StringValueStream func = (StringValueStream) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setValues();
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One exists
+    val1.setExists(false);
+    val2.setValues("def");
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+
+    val1.setValue("abc").setExists(true);
+    val2.setValues();
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // Both exist
+    val1.setValue("abc").setExists(true);
+    val2.setValues("def", "ghi", "jkl");
+    Iterator<String> values2 = Arrays.asList("abcdef", "abcghi", "abcjkl").iterator();
+    func.streamStrings( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next(), value);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void oneSingleOneMultiValueParameterSeperatedTest() {
+    TestStringValue val1 = new TestStringValue();
+    TestStringValueStream val2 = new TestStringValueStream();
+    ConstantStringValue sep = new ConstantStringValue("+-;");
+    
+    AnalyticsValueStream uncasted = SeparatedConcatFunction.creatorFunction.apply(new AnalyticsValueStream[] {sep, val1, val2});
+    assertTrue(uncasted instanceof StringValueStream);
+    StringValueStream func = (StringValueStream) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setValues();
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One exists
+    val1.setExists(false);
+    val2.setValues("def");
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+
+    val1.setValue("abc").setExists(true);
+    val2.setValues();
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // Both exist
+    val1.setValue("abc").setExists(true);
+    val2.setValues("def", "ghi", "jkl");
+    Iterator<String> values2 = Arrays.asList("abc+-;def", "abc+-;ghi", "abc+-;jkl").iterator();
+    func.streamStrings( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next(), value);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void oneMultiOneSingleValueParameterUnseperatedTest() {
+    TestStringValueStream val1 = new TestStringValueStream();
+    TestStringValue val2 = new TestStringValue();
+    
+    AnalyticsValueStream uncasted = ConcatFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2});
+    assertTrue(uncasted instanceof StringValueStream);
+    StringValueStream func = (StringValueStream) uncasted;
+
+    // None exist
+    val1.setValues();
+    val2.setExists(false);
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One exists
+    val1.setValues("def");
+    val2.setExists(false);
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+
+    val1.setValues();
+    val2.setValue("abc").setExists(true);
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // Both exist
+    val1.setValues("def", "ghi", "jkl");
+    val2.setValue("abc").setExists(true);
+    Iterator<String> values2 = Arrays.asList("defabc", "ghiabc", "jklabc").iterator();
+    func.streamStrings( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next(), value);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void oneMultiOneSingleValueParameterSeperatedTest() {
+    TestStringValueStream val1 = new TestStringValueStream();
+    TestStringValue val2 = new TestStringValue();
+    ConstantStringValue sep = new ConstantStringValue("<");
+    
+    AnalyticsValueStream uncasted = SeparatedConcatFunction.creatorFunction.apply(new AnalyticsValueStream[] {sep, val1, val2});
+    assertTrue(uncasted instanceof StringValueStream);
+    StringValueStream func = (StringValueStream) uncasted;
+
+    // None exist
+    val1.setValues();
+    val2.setExists(false);
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One exists
+    val1.setValues("def");
+    val2.setExists(false);
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+
+    val1.setValues();
+    val2.setValue("abc").setExists(true);
+    func.streamStrings( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // Both exist
+    val1.setValues("def", "ghi", "jkl");
+    val2.setValue("abc").setExists(true);
+    Iterator<String> values2 = Arrays.asList("def<abc", "ghi<abc", "jkl<abc").iterator();
+    func.streamStrings( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next(), value);
+    });
+    assertFalse(values2.hasNext());
+  }
+
+  @Test
+  public void multipleSingleValueParameterUnseperatedTest() {
+    TestStringValue val1 = new TestStringValue();
+    TestStringValue val2 = new TestStringValue();
+    TestStringValue val3 = new TestStringValue();
+    TestStringValue val4 = new TestStringValue();
+    
+    AnalyticsValueStream uncasted = ConcatFunction.creatorFunction.apply(new AnalyticsValueStream[] {val1, val2, val3, val4});
+    assertTrue(uncasted instanceof StringValue);
+    StringValue func = (StringValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getString();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setExists(false);
+    val2.setValue("def").setExists(true);
+    val3.setExists(false);
+    val4.setValue("jkl").setExists(true);
+    assertEquals("defjkl", func.getString());
+    assertTrue(func.exists());
+    
+    // All exist values, one value
+    val1.setValue("abc").setExists(true);
+    val2.setValue("def").setExists(true);
+    val3.setValue("ghi").setExists(true);
+    val4.setValue("jkl").setExists(true);
+    assertEquals("abcdefghijkl", func.getString());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multipleSingleValueParameterSeperatedTest() {
+    TestStringValue val1 = new TestStringValue();
+    TestStringValue val2 = new TestStringValue();
+    TestStringValue val3 = new TestStringValue();
+    TestStringValue val4 = new TestStringValue();
+    ConstantStringValue sep = new ConstantStringValue("+:-");
+    
+    AnalyticsValueStream uncasted = SeparatedConcatFunction.creatorFunction.apply(new AnalyticsValueStream[] {sep, val1, val2, val3, val4});
+    assertTrue(uncasted instanceof StringValue);
+    StringValue func = (StringValue) uncasted;
+
+    // None exist
+    val1.setExists(false);
+    val2.setExists(false);
+    val3.setExists(false);
+    val4.setExists(false);
+    func.getString();
+    assertFalse(func.exists());
+    
+    // Some exist
+    val1.setExists(false);
+    val2.setValue("def").setExists(true);
+    val3.setExists(false);
+    val4.setValue("jkl").setExists(true);
+    assertEquals("def+:-jkl", func.getString());
+    assertTrue(func.exists());
+    
+    // All exist values, one value
+    val1.setValue("abc").setExists(true);
+    val2.setValue("def").setExists(true);
+    val3.setValue("ghi").setExists(true);
+    val4.setValue("jkl").setExists(true);
+    assertEquals("abc+:-def+:-ghi+:-jkl", func.getString());
+    assertTrue(func.exists());
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a6d1681a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/DateMathFunctionTest.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/DateMathFunctionTest.java b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/DateMathFunctionTest.java
new file mode 100644
index 0000000..f3802af
--- /dev/null
+++ b/solr/contrib/analytics/src/test/org/apache/solr/analytics/function/mapping/DateMathFunctionTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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
+ *
+ * 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.solr.analytics.function.mapping;
+
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.analytics.value.AnalyticsValueStream;
+import org.apache.solr.analytics.value.DateValue;
+import org.apache.solr.analytics.value.DateValueStream;
+import org.apache.solr.analytics.value.FillableTestValue.TestDateValue;
+import org.apache.solr.analytics.value.FillableTestValue.TestDateValueStream;
+import org.apache.solr.analytics.value.constant.ConstantStringValue;
+import org.junit.Test;
+
+public class DateMathFunctionTest extends SolrTestCaseJ4 {
+  
+  @Test
+  public void singleValueParameterTest() throws DateTimeParseException {
+    Date date1 = Date.from(Instant.parse("1810-12-02T10:30:15Z"));
+    Date date2 = Date.from(Instant.parse("1931-03-16T18:15:45Z"));
+    
+    TestDateValue val = new TestDateValue();
+
+    ConstantStringValue math1 = new ConstantStringValue("+1DAY");
+    ConstantStringValue math2 = new ConstantStringValue("-1MONTH");
+    ConstantStringValue math3 = new ConstantStringValue("+11YEARS");
+
+    AnalyticsValueStream uncasted = DateMathFunction.creatorFunction.apply(new AnalyticsValueStream[] {val, math1, math2, math3});
+    assertTrue(uncasted instanceof DateValue);
+    DateValue func = (DateValue) uncasted;
+
+    // Value doesn't exist
+    val.setExists(false);
+    func.getDate();
+    assertFalse(func.exists());
+    func.getLong();
+    assertFalse(func.exists());
+    
+    // Value exists
+    val.setValue("1800-01-01T10:30:15Z").setExists(true);
+    assertEquals(date1, func.getDate());
+    assertTrue(func.exists());
+    assertEquals(date1.getTime(), func.getLong());
+    assertTrue(func.exists());
+
+    val.setValue("1920-04-15T18:15:45Z").setExists(true);
+    assertEquals(date2, func.getDate());
+    assertTrue(func.exists());
+    assertEquals(date2.getTime(), func.getLong());
+    assertTrue(func.exists());
+  }
+
+  @Test
+  public void multiValueParamaterTest() throws DateTimeParseException {
+    Date date1 = Date.from(Instant.parse("1810-12-02T10:30:15Z"));
+    Date date2 = Date.from(Instant.parse("1931-03-16T18:15:45Z"));
+    Date date3 = Date.from(Instant.parse("2023-11-01T20:30:15Z"));
+    
+    TestDateValueStream val = new TestDateValueStream();
+
+    ConstantStringValue math1 = new ConstantStringValue("+1DAY");
+    ConstantStringValue math2 = new ConstantStringValue("-1MONTH");
+    ConstantStringValue math3 = new ConstantStringValue("+11YEARS");
+    
+    AnalyticsValueStream uncasted = DateMathFunction.creatorFunction.apply(new AnalyticsValueStream[] {val, math1, math2, math3});
+    assertTrue(uncasted instanceof DateValueStream);
+    DateValueStream func = (DateValueStream) uncasted;
+
+    // No values
+    val.setValues();
+    func.streamDates( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    func.streamLongs( value -> {
+      assertTrue("There should be no values to stream", false);
+    });
+    
+    // One value
+    val.setValues("1800-01-01T10:30:15Z");
+    Iterator<Date> values1 = Arrays.asList(date1).iterator();
+    func.streamDates( value -> {
+      assertTrue(values1.hasNext());
+      assertEquals(values1.next(), value);
+    });
+    assertFalse(values1.hasNext());
+    Iterator<Long> times1 = Arrays.asList(date1.getTime()).iterator();
+    func.streamLongs( value -> {
+      assertTrue(times1.hasNext());
+      assertEquals(times1.next().longValue(), value);
+    });
+    assertFalse(times1.hasNext());
+    
+    // Multiple values
+    val.setValues("1800-01-01T10:30:15Z", "1920-04-15T18:15:45Z", "2012-11-30T20:30:15Z");
+    Iterator<Date> values2 = Arrays.asList(date1, date2, date3).iterator();
+    func.streamDates( value -> {
+      assertTrue(values2.hasNext());
+      assertEquals(values2.next(), value);
+    });
+    assertFalse(values2.hasNext());
+    Iterator<Long> times2 = Arrays.asList(date1.getTime(), date2.getTime(), date3.getTime()).iterator();
+    func.streamLongs( value -> {
+      assertTrue(times2.hasNext());
+      assertEquals(times2.next().longValue(), value);
+    });
+    assertFalse(times2.hasNext());
+  }
+}


Mime
View raw message