http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/main/scripts/stellar ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/main/scripts/stellar b/metron-stellar/stellar-common/src/main/scripts/stellar new file mode 100644 index 0000000..72d3f74 --- /dev/null +++ b/metron-stellar/stellar-common/src/main/scripts/stellar @@ -0,0 +1,34 @@ +#!/bin/bash +# +# 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. +# + + +BIGTOP_DEFAULTS_DIR=${BIGTOP_DEFAULTS_DIR-/etc/default} +[ -n "${BIGTOP_DEFAULTS_DIR}" -a -r ${BIGTOP_DEFAULTS_DIR}/hbase ] && . ${BIGTOP_DEFAULTS_DIR}/hbase + +# Autodetect JAVA_HOME if not defined +if [ -e /usr/libexec/bigtop-detect-javahome ]; then + . /usr/libexec/bigtop-detect-javahome +elif [ -e /usr/lib/bigtop-utils/bigtop-detect-javahome ]; then + . /usr/lib/bigtop-utils/bigtop-detect-javahome +fi + +export HBASE_CONFIGS=/etc/hbase/conf +export METRON_VERSION=${project.version} +export METRON_HOME=/usr/metron/$METRON_VERSION +java $JVMFLAGS -cp "$HBASE_CONFIGS:$METRON_HOME/lib/*" org.apache.metron.stellar.stellar.shell.StellarShell "$@"
http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/classpath-resources/custom-1.0-SNAPSHOT.jar ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/classpath-resources/custom-1.0-SNAPSHOT.jar b/metron-stellar/stellar-common/src/test/classpath-resources/custom-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..7007eda Binary files /dev/null and b/metron-stellar/stellar-common/src/test/classpath-resources/custom-1.0-SNAPSHOT.jar differ http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/BaseStellarProcessorTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/BaseStellarProcessorTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/BaseStellarProcessorTest.java new file mode 100644 index 0000000..4caca42 --- /dev/null +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/BaseStellarProcessorTest.java @@ -0,0 +1,116 @@ +/* + * 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.metron.stellar.common; + +import org.apache.metron.stellar.dsl.Context; +import org.apache.metron.stellar.dsl.ParseException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.junit.Assert.*; + +@SuppressWarnings("ALL") +public class BaseStellarProcessorTest { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + BaseStellarProcessor<Object> processor; + + @Before + public void setUp() throws Exception { + processor = new BaseStellarProcessor<>(Object.class); + } + + @Test + public void makeSureBasicValidationIsWorking() throws Exception { + { + assertTrue(processor.validate("")); + assertTrue(processor.validate(null)); + assertTrue(processor.validate("'ah'")); + assertTrue(processor.validate("true")); + assertTrue(processor.validate("1")); + assertTrue(processor.validate("1L")); + assertTrue(processor.validate("1F")); + assertTrue(processor.validate("1 < 2 // always true")); + assertTrue(processor.validate("1 < foo")); + assertTrue(processor.validate("(1 < foo)")); + assertTrue(processor.validate("foo < bar")); + assertTrue(processor.validate("foo < TO_FLOAT(bar)", false, Context.EMPTY_CONTEXT())); + assertTrue(processor.validate("if true then b else c")); + assertTrue(processor.validate("IF false THEN b ELSE c")); + } + + { + assertFalse(processor.validate("'", false, Context.EMPTY_CONTEXT())); + assertFalse(processor.validate("(", false, Context.EMPTY_CONTEXT())); + assertFalse(processor.validate("()", false, Context.EMPTY_CONTEXT())); + assertFalse(processor.validate("'foo", false, Context.EMPTY_CONTEXT())); + assertFalse(processor.validate("foo << foo", false, Context.EMPTY_CONTEXT())); + assertFalse(processor.validate("1-1", false, Context.EMPTY_CONTEXT())); + assertFalse(processor.validate("1 -1", false, Context.EMPTY_CONTEXT())); + assertFalse(processor.validate("If a then b else c", false, Context.EMPTY_CONTEXT())); + } + } + + @Test + public void validateShouldProperlyThrowExceptionOnInvalidStellarExpression() throws Exception { + exception.expect(ParseException.class); + exception.expectMessage("Unable to parse ': "); + + processor.validate("'", true, Context.EMPTY_CONTEXT()); + } + + @Test + public void validateShouldProperlyThrowExceptionByDefaultOnInvalidStellarExpression() throws Exception { + exception.expect(ParseException.class); + exception.expectMessage("Unable to parse ': "); + + processor.validate("'", Context.EMPTY_CONTEXT()); + } + + @Test + public void validateShouldProperlyThrowExceptionByDefaultOnInvalidStellarExpression2() throws Exception { + exception.expect(ParseException.class); + exception.expectMessage("Unable to parse ': "); + + processor.validate("'"); + } + + @Test + public void validateMethodShouldFailOnUnknownFunctions() throws Exception { + exception.expect(ParseException.class); + exception.expectMessage(" Unable to resolve function named 'UNKNOWN_FUNCTION'."); + + assertTrue(processor.validate("1 < UNKNOWN_FUNCTION(3)", Context.EMPTY_CONTEXT())); + } + + @Test + public void validateMethodShouldNotFailOnUnknownvariables() throws Exception { + assertTrue(processor.validate("unknown_variable\n\n")); + assertTrue(processor.validate("unknown_variable > 2", Context.EMPTY_CONTEXT())); + } + + @Test + public void makeSureBasicLexerErrorsAreCaughtDuringValidation() throws Exception { + assertFalse(processor.validate("true â ", false, Context.EMPTY_CONTEXT())); + assertFalse(processor.validate("¢ (1 + 2)", false, Context.EMPTY_CONTEXT())); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/DefaultStellarStatefulExecutorTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/DefaultStellarStatefulExecutorTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/DefaultStellarStatefulExecutorTest.java new file mode 100644 index 0000000..8c55d7d --- /dev/null +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/DefaultStellarStatefulExecutorTest.java @@ -0,0 +1,189 @@ +/* + * + * 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.metron.stellar.common; + +import org.adrianwalker.multilinestring.Multiline; +import org.apache.metron.stellar.dsl.Context; +import org.apache.metron.stellar.dsl.functions.resolver.ClasspathFunctionResolver; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +/** + * Tests the DefaultStellarStatefulExecutor. + */ +@SuppressWarnings("unchecked") +// This test class passes raw JSONObject to the the executor, which gives unchecked cast warnings. +// Suppressing on the class level, given that every test is a typical example of use pattern. +public class DefaultStellarStatefulExecutorTest { + + /** + * { + * "ip_src_addr": "10.0.0.1", + * "ip_dst_addr": "10.0.0.20" + * } + */ + @Multiline + private String input; + + private JSONObject message; + private DefaultStellarStatefulExecutor executor; + + @Before + public void setup() throws ParseException { + + // parse the input message + JSONParser parser = new JSONParser(); + message = (JSONObject) parser.parse(input); + + // create the executor to test + executor = new DefaultStellarStatefulExecutor(); + executor.setContext(Context.EMPTY_CONTEXT()); + + ClasspathFunctionResolver resolver = new ClasspathFunctionResolver(); + executor.setFunctionResolver(resolver); + } + + /** + * Ensure that a value can be assigned to a variable. + */ + @Test + public void testAssign() { + executor.assign("foo", "2", message); + + // verify + Object var = executor.getState().get("foo"); + assertThat(var, instanceOf(Integer.class)); + assertThat(var, equalTo(2)); + } + + /** + * Ensure that a variable can be resolved from a message field. + */ + @Test + public void testAssignWithVariableResolution() { + executor.assign("foo", "ip_src_addr", message); + + // verify + Object var = executor.getState().get("foo"); + assertThat(var, instanceOf(String.class)); + assertThat(var, equalTo("10.0.0.1")); + } + + /** + * Ensure that state is maintained correctly in the execution environment. + */ + @Test + public void testState() { + executor.assign("two", "2", message); + executor.assign("four", "4", message); + executor.assign("sum", "two + four", message); + + // verify + Object var = executor.getState().get("sum"); + assertEquals(6, var); + } + + /** + * Ensure that state is maintained correctly in the execution environment. + */ + @Test + public void testClearState() { + executor.assign("two", "2", message); + executor.clearState(); + + // verify + assertThat(executor.getState().containsKey("two"), equalTo(false)); + } + + /** + * Ensure that a Transformation function can be executed. + * + * There are two sets of functions in Stellar currently. One can be executed with + * a PredicateProcessor and the other a TransformationProcessor. The StellarStatefulExecutor + * abstracts away that complication. + */ + @Test + public void testExecuteTransformation() { + String actual = executor.execute("TO_UPPER('lowercase')", message, String.class); + assertThat(actual, equalTo("LOWERCASE")); + } + + /** + * Ensure that a Predicate function can be executed. + * + * There are two sets of functions in Stellar currently. One can be executed with + * a PredicateProcessor and the other a TransformationProcessor. The StellarStatefulExecutor + * abstracts away that complication. + */ + @Ignore //until field validations avail to Stellar + @Test + public void testExecutePredicate() { + boolean actual = executor.execute("IS_INTEGER(2)", message, Boolean.class); + assertThat(actual, equalTo(true)); + } + + /** + * An exception is expected if an expression results in an unexpected type. + */ + @Test(expected = RuntimeException.class) + public void testExecuteWithWrongType() { + executor.execute("2 + 2", message, Boolean.class); + } + + /** + * A best effort should be made to do sensible type conversions. + */ + @Test + public void testExecuteWithTypeConversion() { + executor.execute("2", message, Double.class); + executor.execute("2", message, Float.class); + executor.execute("2", message, Short.class); + executor.execute("2", message, Long.class); + } + + /** + * The executor must be serializable. + */ + @Test + public void testSerializable() throws Exception { + + // serialize + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + new ObjectOutputStream(bytes).writeObject(executor); + + // deserialize - success when no exceptions + new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray())).readObject(); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarArithmeticTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarArithmeticTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarArithmeticTest.java new file mode 100644 index 0000000..841ab5b --- /dev/null +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarArithmeticTest.java @@ -0,0 +1,332 @@ +/* + * 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.metron.stellar.common; + +import com.google.common.collect.ImmutableMap; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.metron.stellar.dsl.ParseException; +import org.apache.metron.stellar.dsl.Token; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.HashMap; +import java.util.Map; + +import static org.apache.metron.stellar.common.utils.StellarProcessorUtils.run; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@SuppressWarnings("unchecked") +public class StellarArithmeticTest { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void addingLongsShouldYieldLong() throws Exception { + final long timestamp = 1452013350000L; + String query = "TO_EPOCH_TIMESTAMP('2016-01-05 17:02:30', 'yyyy-MM-dd HH:mm:ss', 'UTC') + 2"; + assertEquals(timestamp + 2, run(query, new HashMap<>())); + } + + @Test + public void addingIntegersShouldYieldAnInteger() throws Exception { + String query = "1 + 2"; + assertEquals(3, run(query, new HashMap<>())); + } + + @Test + public void addingDoublesShouldYieldADouble() throws Exception { + String query = "1.0 + 2.0"; + assertEquals(3.0, run(query, new HashMap<>())); + } + + @Test + public void addingDoubleAndIntegerWhereSubjectIsDoubleShouldYieldADouble() throws Exception { + String query = "2.1 + 1"; + assertEquals(3.1, run(query, new HashMap<>())); + } + + @Test + public void addingDoubleAndIntegerWhereSubjectIsIntegerShouldYieldADouble() throws Exception { + String query = "1 + 2.1"; + assertEquals(3.1, run(query, new HashMap<>())); + } + + @Test + public void testArithmetic() { + assertEquals(3, run("1 + 2", new HashMap<>())); + assertEquals(3.2, run("1.2 + 2", new HashMap<>())); + assertEquals(1.2e-3 + 2, run("1.2e-3 + 2", new HashMap<>())); + assertEquals(1.2f + 3.7, run("1.2f + 3.7", new HashMap<>())); + assertEquals(12L * (1.2f + 7), run("12L*(1.2f + 7)", new HashMap<>())); + assertEquals(12.2f * (1.2f + 7L), run("TO_FLOAT(12.2) * (1.2f + 7L)", new HashMap<>())); + } + + @Test + public void testNumericOperations() { + { + String query = "TO_INTEGER(1 + 2*2 + 3 - 4 - 0.5)"; + assertEquals(3, (Integer) run(query, new HashMap<>()), 1e-6); + } + { + String query = "1 + 2*2 + 3 - 4 - 0.5"; + assertEquals(3.5, (Double) run(query, new HashMap<>()), 1e-6); + } + { + String query = "2*one*(1 + 2*2 + 3 - 4)"; + assertEquals(8, run(query, ImmutableMap.of("one", 1))); + } + { + String query = "2*(1 + 2 + 3 - 4)"; + assertEquals(4, (Integer) run(query, ImmutableMap.of("one", 1, "very_nearly_one", 1.000001)), 1e-6); + } + { + String query = "1 + 2 + 3 - 4 - 2"; + assertEquals(0, (Integer) run(query, ImmutableMap.of("one", 1, "very_nearly_one", 1.000001)), 1e-6); + } + { + String query = "1 + 2 + 3 + 4"; + assertEquals(10, (Integer) run(query, ImmutableMap.of("one", 1, "very_nearly_one", 1.000001)), 1e-6); + } + { + String query = "(one + 2)*3"; + assertEquals(9, (Integer) run(query, ImmutableMap.of("one", 1, "very_nearly_one", 1.000001)), 1e-6); + } + { + String query = "TO_INTEGER((one + 2)*3.5)"; + assertEquals(10, (Integer) run(query, ImmutableMap.of("one", 1, "very_nearly_one", 1.000001)), 1e-6); + } + { + String query = "1 + 2*3"; + assertEquals(7, (Integer) run(query, ImmutableMap.of("one", 1, "very_nearly_one", 1.000001)), 1e-6); + } + { + String query = "TO_LONG(foo)"; + Assert.assertNull(run(query, ImmutableMap.of("foo", "not a number"))); + } + { + String query = "TO_LONG(foo)"; + assertEquals(232321L, run(query, ImmutableMap.of("foo", "00232321"))); + } + { + String query = "TO_LONG(foo)"; + assertEquals(Long.MAX_VALUE, run(query, ImmutableMap.of("foo", Long.toString(Long.MAX_VALUE)))); + } + } + + @Test + public void verifyExpectedReturnTypes() throws Exception { + Token<Integer> integer = mock(Token.class); + when(integer.getValue()).thenReturn(1); + + Token<Long> lng = mock(Token.class); + when(lng.getValue()).thenReturn(1L); + + Token<Double> dbl = mock(Token.class); + when(dbl.getValue()).thenReturn(1.0D); + + Token<Float> flt = mock(Token.class); + when(flt.getValue()).thenReturn(1.0F); + + Map<Pair<String, String>, Class<? extends Number>> expectedReturnTypeMappings = + new HashMap<Pair<String, String>, Class<? extends Number>>() {{ + put(Pair.of("TO_FLOAT(3.0)", "TO_LONG(1)"), Float.class); + put(Pair.of("TO_FLOAT(3)", "3.0"), Double.class); + put(Pair.of("TO_FLOAT(3)", "TO_FLOAT(3)"), Float.class); + put(Pair.of("TO_FLOAT(3)", "3"), Float.class); + + put(Pair.of("TO_LONG(1)", "TO_LONG(1)"), Long.class); + put(Pair.of("TO_LONG(1)", "3.0"), Double.class); + put(Pair.of("TO_LONG(1)", "TO_FLOAT(3)"), Float.class); + put(Pair.of("TO_LONG(1)", "3"), Long.class); + + put(Pair.of("3.0", "TO_LONG(1)"), Double.class); + put(Pair.of("3.0", "3.0"), Double.class); + put(Pair.of("3.0", "TO_FLOAT(3)"), Double.class); + put(Pair.of("3.0", "3"), Double.class); + + put(Pair.of("3", "TO_LONG(1)"), Long.class); + put(Pair.of("3", "3.0"), Double.class); + put(Pair.of("3", "TO_FLOAT(3)"), Float.class); + put(Pair.of("3", "3"), Integer.class); + }}; + + expectedReturnTypeMappings.forEach((pair, expectedClass) -> { + assertTrue(run(pair.getLeft() + " * " + pair.getRight(), ImmutableMap.of()).getClass() == expectedClass); + assertTrue(run(pair.getLeft() + " + " + pair.getRight(), ImmutableMap.of()).getClass() == expectedClass); + assertTrue(run(pair.getLeft() + " - " + pair.getRight(), ImmutableMap.of()).getClass() == expectedClass); + assertTrue(run(pair.getLeft() + " / " + pair.getRight(), ImmutableMap.of()).getClass() == expectedClass); + }); + } + + @Test + public void happyPathFloatArithmetic() throws Exception { + Object run = run(".0f * 1", ImmutableMap.of()); + assertEquals(.0f * 1, run); + assertEquals(Float.class, run.getClass()); + + Object run1 = run("0.f / 1F", ImmutableMap.of()); + assertEquals(0.f / 1F, run1); + assertEquals(Float.class, run1.getClass()); + + Object run2 = run(".0F + 1.0f", ImmutableMap.of()); + assertEquals(.0F + 1.0f, run2); + assertEquals(Float.class, run2.getClass()); + + Object run3 = run("0.0f - 0.1f", ImmutableMap.of()); + assertEquals(0.0f - 0.1f, run3); + assertEquals(Float.class, run2.getClass()); + } + + @SuppressWarnings("PointlessArithmeticExpression") + @Test + public void happyPathLongArithmetic() throws Exception { + assertEquals(0L * 1L, run("0L * 1L", ImmutableMap.of())); + assertEquals(0l / 1L, run("0l / 1L", ImmutableMap.of())); + assertEquals(1L - 1l, run("1L - 1l", ImmutableMap.of())); + assertEquals(2147483648L + 1L, run("2147483648L + 1L", ImmutableMap.of())); + } + + @SuppressWarnings("NumericOverflow") + @Test + public void checkInterestingCases() throws Exception { + assertEquals((((((1L) + .5d)))) * 6.f, run("(((((1L) + .5d)))) * 6.f", ImmutableMap.of())); + assertEquals((((((1L) + .5d)))) * 6.f / 0.f, run("(((((1L) + .5d)))) * 6.f / 0.f", ImmutableMap.of())); + assertEquals(Double.class, run("(((((1L) + .5d)))) * 6.f / 0.f", ImmutableMap.of()).getClass()); + } + + @Test + public void makeSureStellarProperlyEvaluatesLiteralsToExpectedTypes() throws Exception { + { + assertEquals(Float.class, run("6.f", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run(".0f", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run("6.0F", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run("6f", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run("6e-6f", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run("6e+6f", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run("6e6f", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run("TO_FLOAT(1231)", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run("TO_FLOAT(12.31)", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run("TO_FLOAT(12.31f)", ImmutableMap.of()).getClass()); + assertEquals(Float.class, run("TO_FLOAT(12L)", ImmutableMap.of()).getClass()); + } + { + assertEquals(Double.class, run("6.d", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("6.D", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("6.0d", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("6D", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("6e5D", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("6e-5D", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("6e+5D", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("TO_DOUBLE(1231)", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("TO_DOUBLE(12.31)", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("TO_DOUBLE(12.31f)", ImmutableMap.of()).getClass()); + assertEquals(Double.class, run("TO_DOUBLE(12L)", ImmutableMap.of()).getClass()); + } + { + assertEquals(Integer.class, run("6", ImmutableMap.of()).getClass()); + assertEquals(Integer.class, run("60000000", ImmutableMap.of()).getClass()); + assertEquals(Integer.class, run("-0", ImmutableMap.of()).getClass()); + assertEquals(Integer.class, run("-60000000", ImmutableMap.of()).getClass()); + assertEquals(Integer.class, run("TO_INTEGER(1231)", ImmutableMap.of()).getClass()); + assertEquals(Integer.class, run("TO_INTEGER(12.31)", ImmutableMap.of()).getClass()); + assertEquals(Integer.class, run("TO_INTEGER(12.31f)", ImmutableMap.of()).getClass()); + assertEquals(Integer.class, run("TO_INTEGER(12L)", ImmutableMap.of()).getClass()); + } + { + assertEquals(Long.class, run("12345678910l", ImmutableMap.of()).getClass()); + assertEquals(Long.class, run("0l", ImmutableMap.of()).getClass()); + assertEquals(Long.class, run("-0l", ImmutableMap.of()).getClass()); + assertEquals(Long.class, run("-60000000L", ImmutableMap.of()).getClass()); + assertEquals(Long.class, run("-60000000L", ImmutableMap.of()).getClass()); + assertEquals(Long.class, run("TO_LONG(1231)", ImmutableMap.of()).getClass()); + assertEquals(Long.class, run("TO_LONG(12.31)", ImmutableMap.of()).getClass()); + assertEquals(Long.class, run("TO_LONG(12.31f)", ImmutableMap.of()).getClass()); + assertEquals(Long.class, run("TO_LONG(12L)", ImmutableMap.of()).getClass()); + } + } + + @Test + public void parseExceptionMultipleLeadingZerosOnInteger() throws Exception { + exception.expect(ParseException.class); + run("000000", ImmutableMap.of()); + } + + @Test + public void parseExceptionMultipleLeadingZerosOnLong() throws Exception { + exception.expect(ParseException.class); + run("000000l", ImmutableMap.of()); + } + + @Test + public void parseExceptionMultipleLeadingZerosOnDouble() throws Exception { + exception.expect(ParseException.class); + run("000000d", ImmutableMap.of()); + } + + @Test + public void parseExceptionMultipleLeadingZerosOnFloat() throws Exception { + exception.expect(ParseException.class); + run("000000f", ImmutableMap.of()); + } + + @Test + public void parseExceptionMultipleLeadingNegativeSignsFloat() throws Exception { + exception.expect(ParseException.class); + run("--000000f", ImmutableMap.of()); + } + + @Test + public void parseExceptionMultipleLeadingNegativeSignsDouble() throws Exception { + exception.expect(ParseException.class); + run("--000000D", ImmutableMap.of()); + } + + @Test + public void parseExceptionMultipleLeadingNegativeSignsLong() throws Exception { + exception.expect(ParseException.class); + run("--000000L", ImmutableMap.of()); + } + + @Test(expected = ParseException.class) + public void unableToDivideByZeroWithIntegers() throws Exception { + run("0/0", ImmutableMap.of()); + } + + @Test(expected = ParseException.class) + public void unableToDivideByZeroWithLongs() throws Exception { + run("0L/0L", ImmutableMap.of()); + } + + @Test + public void ableToDivideByZero() throws Exception { + assertEquals(0F/0F, run("0F/0F", ImmutableMap.of())); + assertEquals(0D/0D, run("0D/0D", ImmutableMap.of())); + assertEquals(0D/0F, run("0D/0F", ImmutableMap.of())); + assertEquals(0F/0D, run("0F/0D", ImmutableMap.of())); + assertEquals(0F/0, run("0F/0", ImmutableMap.of())); + assertEquals(0D/0, run("0D/0", ImmutableMap.of())); + assertEquals(0/0D, run("0/0D", ImmutableMap.of())); + assertEquals(0/0F, run("0/0F", ImmutableMap.of())); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarAssignmentTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarAssignmentTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarAssignmentTest.java new file mode 100644 index 0000000..a2a6c14 --- /dev/null +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarAssignmentTest.java @@ -0,0 +1,64 @@ +/* + * 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.metron.stellar.common; + +import com.google.common.collect.ImmutableList; +import org.apache.metron.stellar.common.StellarAssignment; +import org.junit.Assert; +import org.junit.Test; + +public class StellarAssignmentTest { + + @Test + public void testAssignment() { + for(String statement : ImmutableList.of( "foo := bar + grok" + , "foo := bar + grok" + , "foo := bar + grok " + ) + ) + { + StellarAssignment assignment = StellarAssignment.from(statement); + Assert.assertEquals("foo", assignment.getKey()); + Assert.assertEquals("foo", assignment.getVariable()); + Assert.assertEquals("bar + grok", assignment.getStatement()); + Assert.assertEquals("bar + grok", assignment.getValue()); + } + } + + @Test + public void testNonAssignment() { + for(String statement : ImmutableList.of( "bar + grok" + , " bar + grok" + , "bar + grok " + ) + ) + { + StellarAssignment assignment = StellarAssignment.from(statement); + Assert.assertNull( assignment.getKey()); + Assert.assertNull( assignment.getVariable()); + Assert.assertEquals("bar + grok", assignment.getStatement()); + Assert.assertEquals("bar + grok", assignment.getValue()); + } + } + + @Test(expected=UnsupportedOperationException.class) + public void testImmutability() { + StellarAssignment assignment = StellarAssignment.from("foo := bar"); + assignment.setValue("myval"); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarComparisonExpressionWithOperatorTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarComparisonExpressionWithOperatorTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarComparisonExpressionWithOperatorTest.java new file mode 100644 index 0000000..44bffbc --- /dev/null +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarComparisonExpressionWithOperatorTest.java @@ -0,0 +1,293 @@ +/* + * 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.metron.stellar.common; + +import com.google.common.collect.ImmutableMap; +import org.apache.metron.stellar.dsl.ParseException; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import static org.apache.metron.stellar.common.utils.StellarProcessorUtils.run; +import static org.apache.metron.stellar.common.utils.StellarProcessorUtils.runPredicate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@SuppressWarnings("ALL") +public class StellarComparisonExpressionWithOperatorTest { + @SuppressWarnings({"RedundantConditionalExpression", "ConstantConditions"}) + @Test + public void checkLessThanComparisonOperators() throws Exception { + assertEquals(1 < 2, run("1 < 2", ImmutableMap.of())); + assertEquals(1f < 2, run("1f < 2", ImmutableMap.of())); + assertEquals(1f < 2d, run("1f < 2d", ImmutableMap.of())); + assertEquals(1f < 2e-4d, run("1f < 2e-4d", ImmutableMap.of())); + assertEquals(1L < 2e-4d, run("1L < 2e-4d", ImmutableMap.of())); + assertEquals(1 < 2e-4d, run("1 < 2e-4d", ImmutableMap.of())); + assertEquals(1 < 2L, run("1 < 2L", ImmutableMap.of())); + assertEquals(1.0f < 2.0f, run("1.0f < 2.0f", ImmutableMap.of())); + assertEquals(1L < 3.0f, run("1L < 3.0f", ImmutableMap.of())); + assertEquals(1 < 3.0f, run("1 < 3.0f", ImmutableMap.of())); + assertEquals(1.0 < 3.0f, run("1.0 < 3.0f", ImmutableMap.of())); + assertEquals(false, run("foo < 3.0f", ImmutableMap.of())); + assertEquals(false, run("foo < foo", ImmutableMap.of())); + assertEquals(1L < 3.0f ? true : false, run("if 1L < 3.0f then true else false", ImmutableMap.of())); + } + + @SuppressWarnings("ConstantConditions") + @Test + public void checkComparisonOperationsWithFunctions() throws Exception { + assertEquals(1f >= 2, run("TO_FLOAT(1) >= 2", ImmutableMap.of())); + assertEquals(1f <= 2, run("TO_FLOAT(1) <= TO_FLOAT(2)", ImmutableMap.of())); + assertEquals(1f == 2, run("TO_FLOAT(1) == TO_LONG(2)", ImmutableMap.of())); + assertEquals(12.31f == 10.2f, run("TO_FLOAT(12.31) < 10.2f", ImmutableMap.of())); + } + + @Test + public void testSimpleOps() throws Exception { + final Map<String, String> variableMap = new HashMap<String, String>() {{ + put("foo", "casey"); + put("empty", ""); + put("spaced", "metron is great"); + put("foo.bar", "casey"); + }}; + + assertTrue(runPredicate("'casey' == foo.bar", variableMap::get)); + assertTrue(runPredicate("'casey' == foo", variableMap::get)); + assertFalse(runPredicate("'casey' != foo", variableMap::get)); + assertTrue(runPredicate("'stella' == 'stella'", variableMap::get)); + assertFalse(runPredicate("'stella' == foo", variableMap::get)); + assertTrue(runPredicate("foo== foo", variableMap::get)); + assertTrue(runPredicate("empty== ''", variableMap::get)); + assertTrue(runPredicate("spaced == 'metron is great'", variableMap::get)); + assertTrue(runPredicate(null, variableMap::get)); + assertTrue(runPredicate("", variableMap::get)); + assertTrue(runPredicate(" ", variableMap::get)); + } + + @Test + public void compareNumberAndStringWithSameValueShouldBeFalse() throws Exception { + assertFalse(runPredicate("1 == '1'", new HashMap<>()::get)); + assertFalse(runPredicate("'1' == 1", new HashMap<>()::get)); + } + + @Test + public void comparingNullShouldNotCauseNullPointer() throws Exception { + assertFalse(runPredicate("null == '1'", new HashMap<>()::get)); + assertFalse(runPredicate("\"1\" == null", new HashMap<>()::get)); + assertTrue(runPredicate("null == null", new HashMap<>()::get)); + } + + @Test + public void makeSureSingleQuotesAndDoubleQuotesAreEqual() throws Exception { + assertTrue(runPredicate("\"1\" == '1'", new HashMap<>()::get)); + assertTrue(runPredicate("'1' == \"1\"", new HashMap<>()::get)); + assertTrue(runPredicate("'1' == \"1\"", new HashMap<>()::get)); + } + + @Test + public void makeSureSingleQuoteStringsAreEvaluatedAsStrings() throws Exception { + assertFalse(runPredicate("55 == '7'", new HashMap<>()::get)); + assertFalse(runPredicate("97 == 'a'", new HashMap<>()::get)); + } + + @Test + public void testNumericComparisonFunctions() throws Exception { + final Map<String, Object> variableMap = new HashMap<String, Object>() {{ + put("foo", "casey"); + put("bar", "bar.casey.grok"); + put("ip", "192.168.0.1"); + put("num", 7); + put("num2", 8.5); + put("num3", 7); + put("num4", "8.5"); + put("empty", ""); + put("spaced", "metron is great"); + }}; + assertTrue(runPredicate("num == 7", variableMap::get)); + assertTrue(runPredicate("num < num2", variableMap::get)); + assertTrue(runPredicate("num < TO_DOUBLE(num2)", variableMap::get)); + assertTrue(runPredicate("num < TO_DOUBLE(num4)", variableMap::get)); + assertTrue(runPredicate("num < 100", variableMap::get)); + assertTrue(runPredicate("num == num3", variableMap::get)); + assertFalse(runPredicate("num == num2", variableMap::get)); + assertTrue(runPredicate("num == num2 || true", variableMap::get)); + assertFalse(runPredicate("num > num2", variableMap::get)); + assertTrue(runPredicate("num == 7 && num > 2", variableMap::get)); + } + + @Test + public void positiveAndNegativeZeroAreEqual() throws Exception { + final Map<String, Object> variableMap = new HashMap<String, Object>() {{ + put("num", -0); + }}; + + Arrays.asList("!=", "==").forEach(op -> { + assertEquals("==".equals(op), runPredicate("num " + op + " 0", variableMap::get)); + assertEquals("==".equals(op), runPredicate("0 " + op + " -0", variableMap::get)); + assertEquals("==".equals(op), runPredicate("0 " + op + " -0d", variableMap::get)); + assertEquals("==".equals(op), runPredicate("-0 " + op + " 0", variableMap::get)); + assertEquals("==".equals(op), runPredicate("-0F " + op + " 0D", variableMap::get)); + assertEquals("==".equals(op), runPredicate("-0.F " + op + " 0", variableMap::get)); + assertEquals("==".equals(op), runPredicate("-0.F " + op + " 0F", variableMap::get)); + assertEquals("==".equals(op), runPredicate("-0.D " + op + " 0D", variableMap::get)); + }); + } + + @Test + public void naNIsNotEqualToNaN() throws Exception { + final Map<String, Object> variableMap = new HashMap<>(); + Arrays.asList("!=", "==").forEach(op -> { + assertEquals("!=".equals(op), runPredicate("(0f/0f) " + op + " (0f/0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(-0f/0f) " + op + " (0f/0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(-0f/-0f) " + op + " (0f/0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(-0f/-0f) " + op + " (-0f/0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(-0f/-0f) " + op + " (-0f/-0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(0f/-0f) " + op + " (0f/0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(0f/-0f) " + op + " (-0f/0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(0f/-0f) " + op + " (-0f/-0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(0f/0f) " + op + " (-0f/0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(0f/0d) " + op + " (-0f/-0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(0d/-0f) " + op + " (0f/-0f)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(-0f/0f) " + op + " (0f/-0d)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(-0d/-0d) " + op + " (0d/-0d)", variableMap::get)); + assertEquals("!=".equals(op), runPredicate("(0d/0d) " + op + " (0d/0d)", variableMap::get)); + }); + } + + @Test + public void booleanComparisonTests() throws Exception { + final Map<String, Object> variableMap = new HashMap<String, Object>() {{ + put("t", true); + put("f", false); + }}; + + assertTrue(runPredicate("t != f", variableMap::get)); + assertTrue(runPredicate("f != t", variableMap::get)); + assertTrue(runPredicate("true != false", variableMap::get)); + assertFalse(runPredicate("true != true", variableMap::get)); + assertTrue(runPredicate("false != true", variableMap::get)); + assertFalse(runPredicate("false != false", variableMap::get)); + + assertFalse(runPredicate("t == f", variableMap::get)); + assertFalse(runPredicate("f == t", variableMap::get)); + assertFalse(runPredicate("true == false", variableMap::get)); + assertTrue(runPredicate("true == true", variableMap::get)); + assertFalse(runPredicate("false == true", variableMap::get)); + assertTrue(runPredicate("false == false", variableMap::get)); + + assertFalse(runPredicate("null == false", variableMap::get)); + assertFalse(runPredicate("null == true", variableMap::get)); + assertFalse(runPredicate("true == NULL", variableMap::get)); + assertFalse(runPredicate("false == NULL", variableMap::get)); + } + + @Test + public void nullComparisonTests() throws Exception { + final Map<String, Object> variableMap = new HashMap<>(); + + assertFalse(runPredicate("null == false", variableMap::get)); + assertFalse(runPredicate("null == true", variableMap::get)); + assertFalse(runPredicate("true == NULL", variableMap::get)); + assertFalse(runPredicate("false == NULL", variableMap::get)); + assertFalse(runPredicate("1 == NULL", variableMap::get)); + assertFalse(runPredicate("'null' == NULL", variableMap::get)); + assertFalse(runPredicate("'' == NULL", variableMap::get)); + assertFalse(runPredicate("null == ''", variableMap::get)); + + assertTrue(runPredicate("NULL == null", variableMap::get)); + } + + @Test + public void precisionEqualityTests() throws Exception { + final Map<String, Object> variableMap = new HashMap<>(); + assertEquals(0.1 + 0.2 == 0.3, runPredicate("0.1 + 0.2 == 0.3", variableMap::get)); + } + + @Test(expected = ParseException.class) + public void differentTypesShouldThrowErrorWhenUsingLT() throws Exception { + final Map<String, Object> variableMap = new HashMap<>(); + runPredicate("1 < '1'", variableMap::get); + } + + @Test(expected = ParseException.class) + public void differentTypesShouldThrowErrorWhenUsingLTE() throws Exception { + final Map<String, Object> variableMap = new HashMap<>(); + runPredicate("'1' <= 1", variableMap::get); + } + + @Test(expected = ParseException.class) + public void differentTypesShouldThrowErrorWhenUsingGT() throws Exception { + final Map<String, Object> variableMap = new HashMap<>(); + runPredicate("1 > '1'", variableMap::get); + } + + @Test(expected = ParseException.class) + public void differentTypesShouldThrowErrorWhenUsingGTE() throws Exception { + final Map<String, Object> variableMap = new HashMap<>(); + runPredicate("'1' >= 1", variableMap::get); + } + + @Test + public void differentTypesShouldThrowErrorWhenUsingComparisons() throws Exception { + final Map<String, Object> variableMap = new HashMap<>(); + final Integer[] result = {0}; + + Stream.of("<", "<=", ">", ">=").forEach(op -> { + assertFalse(runPredicate("'1' " + op + " null", variableMap::get)); + }); + } + + @Test + public void makeSurePrecisionIsProperlyHandled() throws Exception { + final Map<String, Object> variableMap = new HashMap<>(); + { + assertEquals(1 == 1.00000001, runPredicate("1 == 1.00000001", variableMap::get)); + assertEquals(1 < 1.00000001, runPredicate("1 < 1.00000001", variableMap::get)); + assertEquals(1 <= 1.00000001, runPredicate("1 <= 1.00000001", variableMap::get)); + assertEquals(1 > 1.00000001, runPredicate("1 > 1.00000001", variableMap::get)); + assertEquals(1 >= 1.00000001, runPredicate("1 >= 1.00000001", variableMap::get)); + } + { + assertEquals(1 == 1.00000001F, runPredicate("1 == 1.00000001F", variableMap::get)); + assertEquals(1 < 1.00000001F, runPredicate("1 < 1.00000001F", variableMap::get)); + assertEquals(1 <= 1.00000001F, runPredicate("1 <= 1.00000001F", variableMap::get)); + assertEquals(1 > 1.00000001F, runPredicate("1 > 1.00000001F", variableMap::get)); + assertEquals(1 >= 1.00000001F, runPredicate("1 >= 1.00000001F", variableMap::get)); + } + { + assertEquals(1.00000001F == 1.00000001, runPredicate("1.00000001F == 1.00000001", variableMap::get)); + assertEquals(1.00000001F < 1.00000001, runPredicate("1.00000001F < 1.00000001", variableMap::get)); + assertEquals(1.00000001F <= 1.00000001, runPredicate("1.00000001F <= 1.00000001", variableMap::get)); + assertEquals(1.00000001F > 1.00000001, runPredicate("1.00000001F > 1.00000001", variableMap::get)); + assertEquals(1.00000001F >= 1.00000001, runPredicate("1.00000001F >= 1.00000001", variableMap::get)); + } + { + assertEquals(-1L == -1.00000001F, runPredicate("-1L == -1.00000001F", variableMap::get)); + assertEquals(-1L < -1.00000001F, runPredicate("-1L < -1.00000001F", variableMap::get)); + assertEquals(-1L <= -1.00000001F, runPredicate("-1L <= -1.00000001F", variableMap::get)); + assertEquals(-1L > -1.00000001F, runPredicate("-1L > -1.00000001F", variableMap::get)); + assertEquals(-1L >= -1.00000001F, runPredicate("-1L >= -1.00000001F", variableMap::get)); + } + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarInterpreterTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarInterpreterTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarInterpreterTest.java new file mode 100644 index 0000000..36a7116 --- /dev/null +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarInterpreterTest.java @@ -0,0 +1,169 @@ +/* + * 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.metron.stellar.common; + +import org.apache.metron.stellar.dsl.Context; +import org.apache.metron.stellar.dsl.Token; +import org.apache.metron.stellar.dsl.VariableResolver; +import org.apache.metron.stellar.dsl.functions.resolver.FunctionResolver; +import org.apache.metron.stellar.common.evaluators.ArithmeticEvaluator; +import org.apache.metron.stellar.common.evaluators.ComparisonExpressionWithOperatorEvaluator; +import org.apache.metron.stellar.common.evaluators.NumberLiteralEvaluator; +import org.apache.metron.stellar.common.generated.StellarParser; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.ArrayDeque; +import java.util.Deque; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; +import static org.powermock.api.mockito.PowerMockito.*; + + +@RunWith(PowerMockRunner.class) +@PrepareForTest({Deque.class, ArithmeticEvaluator.class, NumberLiteralEvaluator.class, ComparisonExpressionWithOperatorEvaluator.class}) +public class StellarInterpreterTest { + VariableResolver variableResolver; + FunctionResolver functionResolver; + Context context; + Deque<Token<?>> tokenStack; + ArithmeticEvaluator arithmeticEvaluator; + NumberLiteralEvaluator numberLiteralEvaluator; + ComparisonExpressionWithOperatorEvaluator comparisonExpressionWithOperatorEvaluator; + StellarCompiler compiler; + StellarCompiler.Expression expression; + + @SuppressWarnings("unchecked") + @Before + public void setUp() throws Exception { + variableResolver = mock(VariableResolver.class); + functionResolver = mock(FunctionResolver.class); + context = mock(Context.class); + tokenStack = new ArrayDeque<>(); + arithmeticEvaluator = mock(ArithmeticEvaluator.class); + numberLiteralEvaluator = mock(NumberLiteralEvaluator.class); + comparisonExpressionWithOperatorEvaluator = mock(ComparisonExpressionWithOperatorEvaluator.class); + expression = new StellarCompiler.Expression(tokenStack); + compiler = new StellarCompiler(expression, arithmeticEvaluator, numberLiteralEvaluator, comparisonExpressionWithOperatorEvaluator); + } + + @Test + public void exitIntLiteralShouldProperlyParseStringsAsIntegers() throws Exception { + StellarParser.IntLiteralContext ctx = mock(StellarParser.IntLiteralContext.class); + Token result = mock(Token.class); + when(ctx.getText()).thenReturn("1000"); + when(numberLiteralEvaluator.evaluate(ctx, null)).thenReturn(result); + compiler.exitIntLiteral(ctx); + verify(numberLiteralEvaluator).evaluate(ctx, null); + Assert.assertEquals(1, tokenStack.size()); + Assert.assertEquals(tokenStack.getFirst(), result); + verifyZeroInteractions(variableResolver); + verifyZeroInteractions(functionResolver); + verifyZeroInteractions(context); + verifyZeroInteractions(arithmeticEvaluator); + verifyZeroInteractions(comparisonExpressionWithOperatorEvaluator); + } + + @Test + public void exitDoubleLiteralShouldProperlyParseStringsAsDoubles() throws Exception { + StellarParser.DoubleLiteralContext ctx = mock(StellarParser.DoubleLiteralContext.class); + Token result = mock(Token.class); + when(numberLiteralEvaluator.evaluate(ctx, null)).thenReturn(result); + when(ctx.getText()).thenReturn("1000D"); + + compiler.exitDoubleLiteral(ctx); + + verify(numberLiteralEvaluator).evaluate(ctx, null); + Assert.assertEquals(1, tokenStack.size()); + Assert.assertEquals(tokenStack.getFirst(), result); + verifyZeroInteractions(variableResolver); + verifyZeroInteractions(functionResolver); + verifyZeroInteractions(context); + verifyZeroInteractions(arithmeticEvaluator); + verifyZeroInteractions(comparisonExpressionWithOperatorEvaluator); + } + + @Test + public void exitFloatLiteralShouldProperlyParseStringsAsFloats() throws Exception { + StellarParser.FloatLiteralContext ctx = mock(StellarParser.FloatLiteralContext.class); + when(ctx.getText()).thenReturn("1000f"); + Token result = mock(Token.class); + when(numberLiteralEvaluator.evaluate(ctx, null)).thenReturn(result); + + compiler.exitFloatLiteral(ctx); + + verify(numberLiteralEvaluator).evaluate(ctx, null); + Assert.assertEquals(1, tokenStack.size()); + Assert.assertEquals(tokenStack.getFirst(), result); + verifyZeroInteractions(variableResolver); + verifyZeroInteractions(functionResolver); + verifyZeroInteractions(context); + verifyZeroInteractions(arithmeticEvaluator); + verifyZeroInteractions(comparisonExpressionWithOperatorEvaluator); + } + + @Test + public void exitLongLiteralShouldProperlyParseStringsAsLongs() throws Exception { + StellarParser.LongLiteralContext ctx = mock(StellarParser.LongLiteralContext.class); + when(ctx.getText()).thenReturn("1000l"); + Token result = mock(Token.class); + when(numberLiteralEvaluator.evaluate(ctx, null)).thenReturn(result); + + compiler.exitLongLiteral(ctx); + + verify(numberLiteralEvaluator).evaluate(ctx, null); + Assert.assertEquals(1, tokenStack.size()); + Assert.assertEquals(tokenStack.getFirst(), result); + verifyZeroInteractions(variableResolver); + verifyZeroInteractions(functionResolver); + verifyZeroInteractions(context); + verifyZeroInteractions(arithmeticEvaluator); + verifyZeroInteractions(comparisonExpressionWithOperatorEvaluator); + } + + @Test + public void properlyCompareTwoNumbers() throws Exception { + StellarParser.ComparisonExpressionWithOperatorContext ctx = mock(StellarParser.ComparisonExpressionWithOperatorContext.class); + StellarParser.ComparisonOpContext mockOp = mock(StellarParser.ComparisonOpContext.class); + when(ctx.comp_operator()).thenReturn(mockOp); + Token result = mock(Token.class); + when(comparisonExpressionWithOperatorEvaluator.evaluate(any(Token.class), any(Token.class), any(StellarParser.ComparisonOpContext.class), any())).thenReturn(result); + + compiler.exitComparisonExpressionWithOperator(ctx); + Assert.assertEquals(1, tokenStack.size()); + StellarCompiler.DeferredFunction func = (StellarCompiler.DeferredFunction) tokenStack.pop().getValue(); + tokenStack.push(new Token<>(1000, Integer.class, null)); + tokenStack.push(new Token<>(1500f, Float.class, null)); + func.apply(tokenStack, new StellarCompiler.ExpressionState(context, functionResolver, variableResolver)); + Assert.assertEquals(1, tokenStack.size()); + Assert.assertEquals(tokenStack.getFirst(), result); + verify(comparisonExpressionWithOperatorEvaluator).evaluate(any(Token.class), any(Token.class), eq(mockOp), any()); + verifyZeroInteractions(numberLiteralEvaluator); + verifyZeroInteractions(variableResolver); + verifyZeroInteractions(functionResolver); + verifyZeroInteractions(context); + verifyZeroInteractions(arithmeticEvaluator); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarPredicateProcessorTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarPredicateProcessorTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarPredicateProcessorTest.java new file mode 100644 index 0000000..5c5abd4 --- /dev/null +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/StellarPredicateProcessorTest.java @@ -0,0 +1,36 @@ +/* + * 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.metron.stellar.common; + +import org.apache.metron.stellar.dsl.ParseException; +import org.junit.Test; + +import static org.junit.Assert.fail; + +public class StellarPredicateProcessorTest { + @SuppressWarnings("EmptyCatchBlock") + @Test + public void testValidation() throws Exception { + StellarPredicateProcessor processor = new StellarPredicateProcessor(); + try { + processor.validate("enrichedField1 == 'enrichedValue1"); + fail("Invalid rule found to be valid - unclosed single quotes."); + } catch(ParseException e) {} + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/evaluators/ArithmeticEvaluatorTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/evaluators/ArithmeticEvaluatorTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/evaluators/ArithmeticEvaluatorTest.java new file mode 100644 index 0000000..c92591a --- /dev/null +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/evaluators/ArithmeticEvaluatorTest.java @@ -0,0 +1,412 @@ +/* + * 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.metron.stellar.common.evaluators; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.metron.stellar.dsl.Token; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@SuppressWarnings("unchecked") +public class ArithmeticEvaluatorTest { + ArithmeticEvaluator evaluator = ArithmeticEvaluator.INSTANCE; + + @Test + public void evaluateDoubleShouldReturnDoubleAdd() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(1); + + Token<Double> r = mock(Token.class); + when(r.getValue()).thenReturn(2D); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.addition(null), p); + + assertTrue(evaluated.getValue() instanceof Double); + assertEquals(3.0D, evaluated.getValue()); + } + + @Test + public void evaluateIntegerShouldReturnIntegerAdd() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(1); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.addition(null), p); + + assertTrue(evaluated.getValue() instanceof Integer); + assertEquals(3, evaluated.getValue()); + } + + @Test + public void evaluateFloatsShouldReturnFloatAdd() throws Exception { + Token<Float> l = mock(Token.class); + when(l.getValue()).thenReturn(1F); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.addition(null), p); + + assertTrue(evaluated.getValue() instanceof Float); + assertEquals(3F, evaluated.getValue()); + } + + @Test + public void evaluateLongsShouldReturnLongAdd() throws Exception { + Token<Long> l = mock(Token.class); + when(l.getValue()).thenReturn(1L); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.addition(null), p); + + assertTrue(evaluated.getValue() instanceof Long); + assertEquals(3L, evaluated.getValue()); + } + + @Test + public void evaluateIntegerShouldReturnDoubleMul() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(1); + + Token<Double> r = mock(Token.class); + when(r.getValue()).thenReturn(2D); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.multiplication(null), p); + + assertTrue(evaluated.getValue() instanceof Double); + assertEquals(2.0D, evaluated.getValue()); + } + + @Test + public void evaluateIntegerShouldReturnIntegerMul() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(1); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.multiplication(null), p); + + assertTrue(evaluated.getValue() instanceof Integer); + assertEquals(2, evaluated.getValue()); + } + + @Test + public void evaluateFloatsShouldReturnFloatMul() throws Exception { + Token<Float> l = mock(Token.class); + when(l.getValue()).thenReturn(1F); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.multiplication(null), p); + + assertTrue(evaluated.getValue() instanceof Float); + assertEquals(2F, evaluated.getValue()); + } + + @Test + public void evaluateLongsShouldReturnLongMul() throws Exception { + Token<Long> l = mock(Token.class); + when(l.getValue()).thenReturn(1L); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.multiplication(null), p); + + assertTrue(evaluated.getValue() instanceof Long); + assertEquals(2L, evaluated.getValue()); + } + + @Test + public void evaluateDoubleShouldReturnDoubleSub() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(1); + + Token<Double> r = mock(Token.class); + when(r.getValue()).thenReturn(2D); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.subtraction(null), p); + + assertTrue(evaluated.getValue() instanceof Double); + assertEquals(-1.0D, evaluated.getValue()); + } + + @Test + public void evaluateIntegerShouldReturnIntegerSub() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(1); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.subtraction(null), p); + + assertTrue(evaluated.getValue() instanceof Integer); + assertEquals(-1, evaluated.getValue()); + } + + @Test + public void evaluateFloatsShouldReturnFloatSub() throws Exception { + Token<Float> l = mock(Token.class); + when(l.getValue()).thenReturn(1F); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.subtraction(null), p); + + assertTrue(evaluated.getValue() instanceof Float); + assertEquals(-1F, evaluated.getValue()); + } + + @Test + public void evaluateLongsShouldReturnLongSub() throws Exception { + Token<Long> l = mock(Token.class); + when(l.getValue()).thenReturn(1L); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.subtraction(null), p); + + assertTrue(evaluated.getValue() instanceof Long); + assertEquals(-1L, evaluated.getValue()); + } + + @Test + public void evaluateDoubleShouldReturnDoubleDiv() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(1); + + Token<Double> r = mock(Token.class); + when(r.getValue()).thenReturn(2D); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.division(null), p); + + assertTrue(evaluated.getValue() instanceof Double); + assertEquals(1 / 2D, evaluated.getValue()); + } + + @Test + public void evaluateIntegerShouldReturnIntegerDiv() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(1); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.division(null), p); + + assertTrue(evaluated.getValue() instanceof Integer); + assertEquals(1 / 2, evaluated.getValue()); + } + + @Test + public void evaluateFloatsShouldReturnFloatDiv() throws Exception { + Token<Float> l = mock(Token.class); + when(l.getValue()).thenReturn(1F); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.division(null), p); + + assertTrue(evaluated.getValue() instanceof Float); + assertEquals(0.5F, evaluated.getValue()); + } + + @Test + public void evaluateLongsShouldReturnLongDiv() throws Exception { + Token<Long> l = mock(Token.class); + when(l.getValue()).thenReturn(1L); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.division(null), p); + + assertTrue(evaluated.getValue() instanceof Long); + assertEquals(0L, evaluated.getValue()); + } + + @Test(expected = IllegalArgumentException.class) + public void evaluateShouldThroughIllegalArgumentExceptionWhenInputIsNull() throws Exception { + evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.division(null), null); + } + + @Test(expected = IllegalArgumentException.class) + public void evaluateShouldThroughIllegalArgumentExceptionWhenInputsKeyIsNull() throws Exception { + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(null, mock(Token.class)); + evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.division(null), p); + } + + @Test(expected = IllegalArgumentException.class) + public void evaluateShouldThroughIllegalArgumentExceptionWhenInputsValueIsNull() throws Exception { + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(mock(Token.class), null); + evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.division(null), p); + } + + @Test + public void evaluateShouldConvertShortsToIntegersType() throws Exception { + Token<Short> l = mock(Token.class); + when(l.getValue()).thenReturn((short) 2); + + Token<Short> r = mock(Token.class); + when(r.getValue()).thenReturn((short) 3); + + Token<? extends Number> evaluated0 = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.addition(null), Pair.of(l, r)); + Token<? extends Number> evaluated1 = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.subtraction(null), Pair.of(l, r)); + Token<? extends Number> evaluated2 = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.multiplication(null), Pair.of(l, r)); + Token<? extends Number> evaluated3 = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.division(null), Pair.of(l, r)); + + assertTrue(evaluated0.getValue() instanceof Integer); + assertEquals(5, evaluated0.getValue()); + + assertTrue(evaluated1.getValue() instanceof Integer); + assertEquals(-1, evaluated1.getValue()); + + assertTrue(evaluated2.getValue() instanceof Integer); + assertEquals(6, evaluated2.getValue()); + + assertTrue(evaluated3.getValue() instanceof Integer); + assertEquals(0, evaluated3.getValue()); + } + + @Test + public void evaluateIntegerShouldReturnIntegerWhenLeftsValueIsNull() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(null); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(2); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.addition(null), p); + + assertTrue(evaluated.getValue() instanceof Integer); + assertEquals(2, evaluated.getValue()); + } + + @Test + public void evaluateIntegerShouldReturnIntegerWhenRightsValueIsNull() throws Exception { + Token<Integer> l = mock(Token.class); + when(l.getValue()).thenReturn(1); + + Token<Integer> r = mock(Token.class); + when(r.getValue()).thenReturn(null); + + Pair<Token<? extends Number>, Token<? extends Number>> p = Pair.of(l, r); + + Token<? extends Number> evaluated = evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.addition(null), p); + + assertTrue(evaluated.getValue() instanceof Integer); + assertEquals(1, evaluated.getValue()); + } + + @Test + public void verifyExpectedReturnTypes() throws Exception { + Token<Integer> integer = mock(Token.class); + when(integer.getValue()).thenReturn(1); + + Token<Long> lng = mock(Token.class); + when(lng.getValue()).thenReturn(1L); + + Token<Double> dbl = mock(Token.class); + when(dbl.getValue()).thenReturn(1.0D); + + Token<Float> flt = mock(Token.class); + when(flt.getValue()).thenReturn(1.0F); + + Map<Pair<Token<? extends Number>, Token<? extends Number>>, Class<? extends Number>> expectedReturnTypeMappings = + new HashMap<Pair<Token<? extends Number>, Token<? extends Number>>, Class<? extends Number>>() {{ + put(Pair.of(flt, lng), Float.class); + put(Pair.of(flt, dbl), Double.class); + put(Pair.of(flt, flt), Float.class); + put(Pair.of(flt, integer), Float.class); + + put(Pair.of(lng, lng), Long.class); + put(Pair.of(lng, dbl), Double.class); + put(Pair.of(lng, flt), Float.class); + put(Pair.of(lng, integer), Long.class); + + put(Pair.of(dbl, lng), Double.class); + put(Pair.of(dbl, dbl), Double.class); + put(Pair.of(dbl, flt), Double.class); + put(Pair.of(dbl, integer), Double.class); + + put(Pair.of(integer, lng), Long.class); + put(Pair.of(integer, dbl), Double.class); + put(Pair.of(integer, flt), Float.class); + put(Pair.of(integer, integer), Integer.class); + }}; + + expectedReturnTypeMappings.forEach( (pair, expectedClass) -> { + assertTrue(evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.addition(null), pair).getValue().getClass() == expectedClass); + assertTrue(evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.division(null), pair).getValue().getClass() == expectedClass); + assertTrue(evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.subtraction(null), pair).getValue().getClass() == expectedClass); + assertTrue(evaluator.evaluate(ArithmeticEvaluator.ArithmeticEvaluatorFunctions.multiplication(null), pair).getValue().getClass() == expectedClass); + }); + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/a5b13777/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/evaluators/ComparisonExpressionWithOperatorEvaluatorTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/evaluators/ComparisonExpressionWithOperatorEvaluatorTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/evaluators/ComparisonExpressionWithOperatorEvaluatorTest.java new file mode 100644 index 0000000..4afd4df --- /dev/null +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/common/evaluators/ComparisonExpressionWithOperatorEvaluatorTest.java @@ -0,0 +1,126 @@ +/* + * 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.metron.stellar.common.evaluators; + +import org.antlr.v4.runtime.tree.TerminalNode; +import org.apache.metron.stellar.dsl.ParseException; +import org.apache.metron.stellar.dsl.Token; +import org.apache.metron.stellar.common.generated.StellarParser; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +@SuppressWarnings({"unchecked"}) +@RunWith(PowerMockRunner.class) +@PrepareForTest({ComparisonExpressionWithOperatorEvaluator.class, ComparisonExpressionWithOperatorEvaluator.Strategy.class}) +public class ComparisonExpressionWithOperatorEvaluatorTest { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + final ComparisonExpressionWithOperatorEvaluator evaluator = ComparisonExpressionWithOperatorEvaluator.INSTANCE; + + @Test + public void evaluateEqShouldProperlyCallEqualityOperatorsEvaluator() throws Exception { + Token<Double> left = mock(Token.class); + when(left.getValue()).thenReturn(1D); + + Token<Double> right = mock(Token.class); + when(right.getValue()).thenReturn(1D); + + StellarParser.ComparisonOpContext op = mock(StellarParser.ComparisonOpContext.class); + when(op.EQ()).thenReturn(mock(TerminalNode.class)); + + Token<Boolean> evaluated = evaluator.evaluate(left, right, op, null); + + assertTrue(evaluated.getValue()); + } + + @Test + public void evaluateNotEqShouldProperlyCallEqualityOperatorsEvaluator() throws Exception { + Token<Double> left = mock(Token.class); + when(left.getValue()).thenReturn(1D); + + Token<Double> right = mock(Token.class); + when(right.getValue()).thenReturn(1D); + + StellarParser.ComparisonOpContext op = mock(StellarParser.ComparisonOpContext.class); + when(op.NEQ()).thenReturn(mock(TerminalNode.class)); + + Token<Boolean> evaluated = evaluator.evaluate(left, right, op, null); + + assertFalse(evaluated.getValue()); + } + + @Test + public void evaluateLessThanEqShouldProperlyCallEqualityOperatorsEvaluator() throws Exception { + Token<Double> left = mock(Token.class); + when(left.getValue()).thenReturn(0D); + + Token<Double> right = mock(Token.class); + when(right.getValue()).thenReturn(1D); + + StellarParser.ComparisonOpContext op = mock(StellarParser.ComparisonOpContext.class); + when(op.LTE()).thenReturn(mock(TerminalNode.class)); + + Token<Boolean> evaluated = evaluator.evaluate(left, right, op, null); + + assertTrue(evaluated.getValue()); + } + + @Test + public void unexpectedOperatorShouldThrowException() throws Exception { + exception.expect(ParseException.class); + exception.expectMessage("Unsupported operations. The following expression is invalid: "); + + Token<Double> left = mock(Token.class); + when(left.getValue()).thenReturn(0D); + + Token<Double> right = mock(Token.class); + when(right.getValue()).thenReturn(1D); + + StellarParser.ComparisonOpContext op = mock(StellarParser.ComparisonOpContext.class); + + evaluator.evaluate(left, right, op, null); + } + + @Test + public void nonExpectedOperatorShouldThrowException() throws Exception { + exception.expect(ParseException.class); + exception.expectMessage("Unsupported operations. The following expression is invalid: "); + + Token<String> left = mock(Token.class); + when(left.getValue()).thenReturn("adsf"); + + Token<Double> right = mock(Token.class); + when(right.getValue()).thenReturn(1D); + + StellarParser.ComparisonOpContext op = mock(StellarParser.ComparisonOpContext.class); + when(op.LTE()).thenReturn(mock(TerminalNode.class)); + + evaluator.evaluate(left, right, op, null); + } +}
