/* * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH * under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright * ownership. Camunda licenses this file to you under the Apache License, * Version 2.0; 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.camunda.bpm.dmn.feel.impl; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.camunda.bpm.dmn.feel.impl.juel.FeelEngineFactoryImpl; import org.camunda.bpm.dmn.feel.impl.juel.el.FeelFunctionMapper; import org.camunda.bpm.engine.variable.VariableMap; import org.camunda.bpm.engine.variable.Variables; import org.camunda.bpm.engine.variable.value.DateValue; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class FeelEngineTest { public static final String INPUT_VARIABLE = "input"; public static FeelEngine feelEngine; public VariableMap variables; @BeforeClass public static void initFeelEngine() { feelEngine = new FeelEngineFactoryImpl().createInstance(); } @Before public void initVariables() { variables = Variables.createVariables(); } @Test public void testLong() { variables.putValue("integer", 12); variables.putValue("primitive", 12L); variables.putValue("typed", Variables.longValue(12L)); assertEvaluatesToTrue(Variables.longValue(12L), "<= typed"); assertEvaluatesToTrue(Variables.longValue(12L), "<= primitive"); assertEvaluatesToTrue(Variables.longValue(12L), "<= integer"); } @Test public void testEndpointString() { assertEvaluatesToTrue("Hello World", "\"Hello World\""); assertEvaluatesToFalse("Hello World", "\"Hello Camunda\""); assertEvaluatesToFalse("Hello World", "\"\""); assertEvaluatesToTrue("", "\"\""); assertEvaluatesToTrue("123", "\"123\""); assertEvaluatesToTrue("Why.not?", "\"Why.not?\""); } @Test public void testEndpointVariable() { variables.put("y", "a"); assertEvaluatesToTrue("a", "y"); assertEvaluatesToFalse("b", "y"); variables.put("customer", Collections.singletonMap("name", "camunda")); assertEvaluatesToTrue("camunda", "customer.name"); assertEvaluatesToFalse("hello", "customer.name"); } @Test public void testEndpointVariableGreater() { variables.put("y", 13.37); assertEvaluatesToTrue(12, "<y"); assertEvaluatesToFalse(13.38, "<y"); } @Test public void testEndpointVariableGreaterEqual() { variables.put("y", 13.37); assertEvaluatesToTrue(12, "<=y"); assertEvaluatesToTrue(13.37, "<=y"); assertEvaluatesToFalse(13.38, "<=y"); } @Test public void testEndpointVariableLess() { variables.put("y", 13.37); assertEvaluatesToFalse(12, ">y"); assertEvaluatesToTrue(13.38, ">y"); } @Test public void testEndpointVariableLessEqual() { variables.put("y", 13.37); assertEvaluatesToFalse(12, ">=y"); assertEvaluatesToTrue(13.37, ">=y"); assertEvaluatesToTrue(13.38, ">=y"); } @Test public void testEndpointBoolean() { assertEvaluatesToTrue(true, "true"); assertEvaluatesToFalse(true, "false"); assertEvaluatesToTrue(false, "false"); assertEvaluatesToFalse(false, "true"); } @Test public void testEndpointNumber() { assertEvaluatesToTrue(13, "13"); assertEvaluatesToTrue(13.37, "13.37"); assertEvaluatesToTrue(0.37, ".37"); assertEvaluatesToFalse(13.37, "23.42"); assertEvaluatesToFalse(0.42, ".37"); } @Test public void testEndpointNumberGreater() { assertEvaluatesToTrue(12, "<13"); assertEvaluatesToTrue(13.35, "<13.37"); assertEvaluatesToTrue(0.337, "<.37"); assertEvaluatesToFalse(13.37, "<13.37"); assertEvaluatesToFalse(0.37, "<.37"); } @Test public void testEndpointNumberGreaterEqual() { assertEvaluatesToTrue(13.37, "<=13.37"); assertEvaluatesToTrue(13.337, "<=13.37"); assertEvaluatesToTrue(0.37, "<=.37"); assertEvaluatesToTrue(0.337, "<=.37"); assertEvaluatesToFalse(13.42, "<=13.37"); assertEvaluatesToFalse(0.42, "<=.37"); } @Test public void testEndpointNumberLess() { assertEvaluatesToTrue(13.37, ">13"); assertEvaluatesToTrue(13.42, ">13.37"); assertEvaluatesToTrue(0.42, ">.37"); assertEvaluatesToFalse(13.37, ">13.37"); assertEvaluatesToFalse(0.37, ">.37"); } @Test public void testEndpointNumberLessEqual() { assertEvaluatesToTrue(13.37, ">=13"); assertEvaluatesToTrue(13.37, ">=13.37"); assertEvaluatesToTrue(0.37, ">=.37"); assertEvaluatesToTrue(0.42, ">=.37"); assertEvaluatesToFalse(13.337, ">=13.37"); assertEvaluatesToFalse(0.23, ">=.37"); } @Test public void testEndpointDateAndTime() { DateValue dateTime = parseDateAndTime("2015-12-12T22:12:53"); assertEvaluatesToTrue(dateTime, "date and time(\"2015-12-12T22:12:53\")"); variables.put("y", "2015-12-12T22:12:53"); assertEvaluatesToTrue(dateTime, "date and time(y)"); } @Test public void testThreadSafetyDateAndTimeParsing() throws ExecutionException, InterruptedException { int threadCount = 2; ExecutorService pool = Executors.newFixedThreadPool(threadCount); Set<Future<Date>> futureSet = new HashSet<Future<Date>>(); Set<Date> expectedDates = new HashSet<Date>(); for(int i = 1; i <= 3 * threadCount; i++) { final String dateAndTimeString = "2015-12-12T22:12:5" + i; expectedDates.add( FeelFunctionMapper.parseDateAndTime(dateAndTimeString) ); futureSet.add(pool.submit(new Callable<Date>() { public Date call() throws Exception { return FeelFunctionMapper.parseDateAndTime(dateAndTimeString); } })); } pool.shutdown(); Set<Date> actualDates = new HashSet<Date>(); for( Future<Date> dateFuture : futureSet ) { actualDates.add(dateFuture.get()); } assertThat(actualDates).hasSameElementsAs(expectedDates); } @Test public void testIntervalNumber() { assertEvaluatesToTrue(0.23, "[.12...37]"); assertEvaluatesToTrue(0.23, "[.12...37)"); assertEvaluatesToTrue(0.23, "[.12...37["); assertEvaluatesToTrue(0.23, "(.12...37]"); assertEvaluatesToTrue(0.23, "(.12...37)"); assertEvaluatesToTrue(0.23, "(.12...37["); assertEvaluatesToTrue(0.23, "].12...37]"); assertEvaluatesToTrue(0.23, "].12...37)"); assertEvaluatesToTrue(0.23, "].12...37["); assertEvaluatesToFalse(13.37, "[.12...37]"); assertEvaluatesToFalse(13.37, "[.12...37)"); assertEvaluatesToFalse(13.37, "[.12...37["); assertEvaluatesToFalse(13.37, "(.12...37]"); assertEvaluatesToFalse(13.37, "(.12...37)"); assertEvaluatesToFalse(13.37, "(.12...37["); assertEvaluatesToFalse(13.37, "].12...37]"); assertEvaluatesToFalse(13.37, "].12...37)"); assertEvaluatesToFalse(13.37, "].12...37["); } @Test public void testIntervalVariable() { variables.put("a", 10); variables.put("b", 15); assertEvaluatesToTrue(13.37, "[a..b]"); assertEvaluatesToTrue(13.37, "[a..b)"); assertEvaluatesToTrue(13.37, "[a..b["); assertEvaluatesToTrue(13.37, "(a..b]"); assertEvaluatesToTrue(13.37, "(a..b)"); assertEvaluatesToTrue(13.37, "(a..b["); assertEvaluatesToTrue(13.37, "]a..b]"); assertEvaluatesToTrue(13.37, "]a..b)"); assertEvaluatesToTrue(13.37, "]a..b["); assertEvaluatesToFalse(0.37, "[a..b]"); assertEvaluatesToFalse(0.37, "[a..b)"); assertEvaluatesToFalse(0.37, "[a..b["); assertEvaluatesToFalse(0.37, "(a..b]"); assertEvaluatesToFalse(0.37, "(a..b)"); assertEvaluatesToFalse(0.37, "(a..b["); assertEvaluatesToFalse(0.37, "]a..b]"); assertEvaluatesToFalse(0.37, "]a..b)"); assertEvaluatesToFalse(0.37, "]a..b["); } @Test public void testIntervalDateAndTime() { DateValue dateAndTime = parseDateAndTime("2016-03-03T00:00:00"); assertEvaluatesToTrue(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToTrue(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\"))"); assertEvaluatesToTrue(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")["); assertEvaluatesToTrue(dateAndTime, "(date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToTrue(dateAndTime, "(date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\"))"); assertEvaluatesToTrue(dateAndTime, "(date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")["); assertEvaluatesToTrue(dateAndTime, "]date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToTrue(dateAndTime, "]date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\"))"); assertEvaluatesToTrue(dateAndTime, "]date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")["); assertEvaluatesToTrue(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-03-03T00:00:00\")]"); assertEvaluatesToTrue(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-03-03T00:00:01\")["); assertEvaluatesToTrue(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-03-03T00:00:01\"))"); assertEvaluatesToTrue(dateAndTime, "[date and time(\"2016-03-03T00:00:00\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToTrue(dateAndTime, "]date and time(\"2016-03-02T23:59:59\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToTrue(dateAndTime, "(date and time(\"2016-03-02T23:59:59\")..date and time(\"2016-06-06T00:00:00\")]"); dateAndTime = parseDateAndTime("2013-03-03T00:00:00"); assertEvaluatesToFalse(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToFalse(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\"))"); assertEvaluatesToFalse(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")["); assertEvaluatesToFalse(dateAndTime, "(date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToFalse(dateAndTime, "(date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\"))"); assertEvaluatesToFalse(dateAndTime, "(date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")["); assertEvaluatesToFalse(dateAndTime, "]date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToFalse(dateAndTime, "]date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\"))"); assertEvaluatesToFalse(dateAndTime, "]date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-06-06T00:00:00\")["); assertEvaluatesToFalse(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-03-02T23:59:59\")]"); assertEvaluatesToFalse(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-03-03T00:00:00\")["); assertEvaluatesToFalse(dateAndTime, "[date and time(\"2015-12-12T00:00:00\")..date and time(\"2016-03-03T00:00:00\"))"); assertEvaluatesToFalse(dateAndTime, "[date and time(\"2016-03-03T00:00:01\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToFalse(dateAndTime, "]date and time(\"2016-03-03T00:00:00\")..date and time(\"2016-06-06T00:00:00\")]"); assertEvaluatesToFalse(dateAndTime, "(date and time(\"2016-03-03T00:00:00\")..date and time(\"2016-06-06T00:00:00\")]"); } @Test public void testNot() { variables.put("y", 13.37); assertEvaluatesToTrue("Hello camunda", "not(\"Hello World\")"); assertEvaluatesToTrue(0.37, "not(y)"); assertEvaluatesToFalse(0.37, "not(<y)"); assertEvaluatesToFalse(0.37, "not(<=y)"); assertEvaluatesToTrue(0.37, "not(>y)"); assertEvaluatesToTrue(0.37, "not(>=y)"); assertEvaluatesToTrue(0.37, "not(13.37)"); assertEvaluatesToFalse(0.37, "not(<13.37)"); assertEvaluatesToFalse(0.37, "not(<=13.37)"); assertEvaluatesToTrue(0.37, "not(>13.37)"); assertEvaluatesToTrue(0.37, "not(>=13.37)"); assertEvaluatesToFalse(0.37, "not(.37)"); assertEvaluatesToTrue(0.37, "not(<.37)"); assertEvaluatesToFalse(0.37, "not(<=.37)"); assertEvaluatesToTrue(0.37, "not(>.37)"); assertEvaluatesToFalse(0.37, "not(>=.37)"); } @Test public void testList() { variables.put("a", "Hello camunda"); variables.put("y", 0); assertEvaluatesToTrue("Hello World", "a,\"Hello World\""); assertEvaluatesToTrue("Hello camunda", "a,\"Hello World\""); assertEvaluatesToFalse("Hello unknown", "a,\"Hello World\""); assertEvaluatesToTrue(0, "y,12,13.37,.37"); assertEvaluatesToTrue(12, "y,12,13.37,.37"); assertEvaluatesToTrue(13.37, "y,12,13.37,.37"); assertEvaluatesToTrue(0.37, "y,12,13.37,.37"); assertEvaluatesToFalse(0.23, "y,12,13.37,.37"); assertEvaluatesToTrue(-1, "<y,>13.37,>=.37"); assertEvaluatesToTrue(0.37, "<y,>13.37,>=.37"); assertEvaluatesToFalse(0, "<y,>13.37,>=.37"); } @Test public void testNested() { variables.put("a", 23.42); assertEvaluatesToTrue(0.37, "not(>=a,13.37,].37...42),<.37)"); assertEvaluatesToFalse(23.42, "not(>=a,13.37,].37...42),<.37)"); assertEvaluatesToFalse(13.37, "not(>=a,13.37,].37...42),<.37)"); assertEvaluatesToFalse(0.38, "not(>=a,13.37,].37...42),<.37)"); assertEvaluatesToFalse(0, "not(>=a,13.37,].37...42),<.37)"); } @Test public void testDontCare() { assertEvaluatesToTrue(13.37, "-"); } @Test public void testWhitespace() { assertEvaluatesToTrue("Hello World", "'Hello World' "); assertEvaluatesToTrue("Hello World", " 'Hello World'"); assertEvaluatesToTrue("Hello World", " 'Hello World' "); assertEvaluatesToTrue(12, " 12 "); assertEvaluatesToTrue(10.2, " <12 "); assertEvaluatesToTrue(0, "< 12 "); assertEvaluatesToTrue(12.3, "\t>=12 "); assertEvaluatesToTrue(0, " not( 13 ,\t>0)\t"); } @Test public void testPojo() { variables.putValue("pojo", new TestPojo("foo", 13.37)); assertEvaluatesToTrue("foo", "pojo.foo"); assertEvaluatesToFalse("camunda", "pojo.foo"); assertEvaluatesToTrue(12, "<= pojo.bar"); assertEvaluatesToFalse(13.33, ">= pojo.bar"); } public void assertEvaluatesToTrue(Object input, String feelExpression) { boolean result = evaluateFeel(input, feelExpression); assertThat(result).isTrue(); } public void assertEvaluatesToFalse(Object input, String feelExpression) { boolean result = evaluateFeel(input, feelExpression); assertThat(result).isFalse(); } public boolean evaluateFeel(Object input, String feelExpression) { variables.putValue(INPUT_VARIABLE, input); return feelEngine.evaluateSimpleUnaryTests(feelExpression, INPUT_VARIABLE, variables.asVariableContext()); } protected DateValue parseDateAndTime(String dateAndTimeString) { Date date = FeelFunctionMapper.parseDateAndTime(dateAndTimeString); return Variables.dateValue(date); } public class TestPojo { protected String foo; protected Double bar; public TestPojo(String foo, Double bar) { this.foo = foo; this.bar = bar; } public String getFoo() { return foo; } public Double getBar() { return bar; } public String toString() { return "TestPojo{" + "foo='" + foo + '\'' + ", bar=" + bar + '}'; } } }