| /* |
| * |
| * 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.dsl.functions; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import org.apache.metron.stellar.common.StellarProcessor; |
| import org.apache.metron.stellar.dsl.Context; |
| import org.apache.metron.stellar.dsl.DefaultVariableResolver; |
| import org.apache.metron.stellar.dsl.ParseException; |
| import org.apache.metron.stellar.dsl.StellarFunctions; |
| import org.junit.jupiter.api.Test; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import static org.apache.metron.stellar.common.utils.StellarProcessorUtils.runPredicate; |
| import static org.junit.jupiter.api.Assertions.*; |
| |
| public class MathFunctionsTest { |
| |
| public static final double EPSILON = 1e-7; |
| public static Map<Double, Double> baseExpectations = new HashMap<Double, Double>() {{ |
| put(Double.NaN, Double.NaN); |
| }}; |
| |
| public static Object run(String rule, Map<String, Object> variables) { |
| Context context = Context.EMPTY_CONTEXT(); |
| StellarProcessor processor = new StellarProcessor(); |
| assertTrue(processor.validate(rule, context), rule + " not valid."); |
| return processor.parse(rule, new DefaultVariableResolver(v -> variables.get(v),v -> variables.containsKey(v)), StellarFunctions.FUNCTION_RESOLVER(), context); |
| } |
| |
| @Test |
| public void testAbs() { |
| assertValues("ABS", |
| new HashMap<Double, Double>(baseExpectations) {{ |
| put(0d, 0d); |
| put(10.5d, 10.5d); |
| put(-10.5d, 10.5d); |
| }} |
| ); |
| } |
| |
| @Test |
| public void testSqrt() { |
| assertValues("SQRT", |
| new HashMap<Double, Double>(baseExpectations) {{ |
| put(0d, 0d); |
| put(25d, 5d); |
| put(-10.5d, Double.NaN); |
| }} |
| ); |
| } |
| |
| @Test |
| public void testCeiling() { |
| assertValues("CEILING", |
| new HashMap<Double, Double>(baseExpectations) {{ |
| put(0d, 0d); |
| put(10.5d, 11d); |
| put(-10.5d, -10d); |
| }} |
| ); |
| } |
| |
| @Test |
| public void testFloor() { |
| assertValues("FLOOR", |
| new HashMap<Double, Double>(baseExpectations) {{ |
| put(0d, 0d); |
| put(10.5d, 10d); |
| put(-10.5d, -11d); |
| }} |
| ); |
| } |
| |
| @Test |
| public void testSin() { |
| assertValues("SIN", |
| new HashMap<Double, Double>(baseExpectations) {{ |
| put(0d, 0d); |
| put(Math.PI/6, 0.5); |
| put(Math.PI/4, Math.sqrt(2)/2.0); |
| put(Math.PI/3, Math.sqrt(3)/2.0); |
| put(Math.PI/2, 1d); |
| }} |
| ); |
| } |
| |
| @Test |
| public void testCos() { |
| assertValues("COS", |
| new HashMap<Double, Double>(baseExpectations) {{ |
| put(0d, 1d); |
| put(Math.PI/6, Math.sqrt(3)/2.0); |
| put(Math.PI/4, Math.sqrt(2)/2.0); |
| put(Math.PI/3, 0.5d); |
| put(Math.PI/2, 0d); |
| }} |
| ); |
| } |
| |
| @Test |
| public void testTan() { |
| assertValues("TAN", |
| new HashMap<Double, Double>(baseExpectations) {{ |
| put(0d, 0d); |
| put(Math.PI/6, Math.sqrt(3)/3.0); |
| put(Math.PI/4, 1d); |
| put(Math.PI/3, Math.sqrt(3)); |
| put(Math.PI/2, Math.sin(Math.PI/2)/Math.cos(Math.PI/2)); |
| }} |
| ); |
| } |
| |
| @Test |
| public void testExp() { |
| assertValues("EXP", |
| new HashMap<Double, Double>(baseExpectations) {{ |
| put(0d, 1d); |
| put(0.5d, Math.sqrt(Math.E)); |
| put(-0.5d, 1/Math.sqrt(Math.E)); |
| put(1d, Math.E); |
| put(2d, Math.E*Math.E); |
| }} |
| ); |
| } |
| |
| @Test |
| public void testRound() { |
| assertValues("ROUND", |
| new HashMap<Double, Double>(baseExpectations) {{ |
| put(0d, 0d); |
| put(0.5d, 1d); |
| put(0.4d, 0d); |
| put(-0.5d, 0d); |
| }} |
| ); |
| } |
| |
| @Test |
| public void testNaturalLog() { |
| testLog("LN", Math.E); |
| } |
| |
| @Test |
| public void testLog2() { |
| testLog("LOG2", 2); |
| } |
| |
| @Test |
| public void testLog10() { |
| testLog("LOG10", 10); |
| } |
| |
| @Test |
| public void testIsNaN() { |
| assertTrue(runPredicate("IS_NAN(NaN)", new HashMap<>())); |
| assertFalse(runPredicate("IS_NAN(1.0)", new HashMap<>())); |
| assertTrue(runPredicate("IS_NAN(0.0/0.0)",new HashMap<>())); |
| } |
| |
| @Test |
| public void testIsNanWithNotNumberType() { |
| assertThrows(ParseException.class, () -> runPredicate("IS_NAN('casey')", new HashMap<>())); |
| } |
| |
| @Test |
| public void testIsNanWithNoArgs() { |
| assertThrows(ParseException.class, () -> runPredicate("IS_NAN()", new HashMap<>())); |
| } |
| |
| public void assertValues(String func, Map<Double, Double> expected) { |
| for(Map.Entry<Double, Double> test : expected.entrySet()) { |
| for(String expr : ImmutableList.of(func + "(value)" |
| ,func + "(" + test.getKey() + ")" |
| ) |
| ) |
| { |
| if (Double.isNaN(test.getValue())) { |
| assertTrue( |
| Double.isNaN(toDouble(run(expr, ImmutableMap.of("value", test.getKey())))), |
| expr + " != NaN, where value == " + test.getKey()); |
| } else { |
| assertEquals( |
| test.getValue(), |
| toDouble(run(expr, ImmutableMap.of("value", test.getKey()))), |
| EPSILON, |
| expr + " != " + test.getValue() + " (where value == " + test.getKey() + ")"); |
| } |
| } |
| } |
| } |
| |
| public Double toDouble(Object n) { |
| return ((Number)n).doubleValue(); |
| } |
| |
| public void testLog(String logExpr, double base) { |
| Map<Double, Double> expectedValues = new HashMap<Double, Double>(baseExpectations) {{ |
| put(base, 1d); |
| put(0d, Double.NEGATIVE_INFINITY); |
| }}; |
| for(int i = 1;i <= 10;++i) { |
| expectedValues.put(Math.pow(base, i), (double)i); |
| } |
| assertValues(logExpr, expectedValues); |
| } |
| |
| } |